```
library BurstLaser requires BL, GetUnitCollision, TimerUtils, ArmorUtils, DummyRecycler
globals
private hashtable hash = InitHashtable()
private hashtable lightningStorage = InitHashtable()
private hashtable dummyStorage = InitHashtable()
private trigger interrupt_trigger = CreateTrigger()
private group DamageGroup = CreateGroup()
private location zLoc = Location(0., 0.)
private constant real MAX_COLLISION_SIZE = 196.
private constant real COLLISION_PERCENTAGE = .8
private constant real TIMEOUT = .03125
private constant real DEATH_TIME = 1.
private constant integer COUNTER_KEY = -1
//LaserInstance-specific vars
private integer MaxLasers = 0
private integer array LaserIndex
private lightning array Laser
private timer LaserTimer = CreateTimer()
endglobals
struct LaserInstance
real xLaunch
real yLaunch
real zLaunch
real xImpact
real yImpact
real zImpact
real xLaunchUpdate
real yLaunchUpdate
real zLaunchUpdate
real xImpactUpdate
real yImpactUpdate
real zImpactUpdate
real lifespan
real red
real blue
real green
real alpha
real lockAngle
real dot
real dotReset
real fadeAmount
unit source
unit target
unit sentry
boolean updateLaunchPoint
boolean updateImpactPoint
integer laserSetInstance
integer laserSlot
private method destroy takes nothing returns nothing
set this.source = null
set this.target = null
set this.sentry = null
set this.laserSetInstance = 0
call this.deallocate()
endmethod
private static method Timer takes nothing returns nothing
local integer i = 0
local integer storageIndex
local integer iRec
local thistype this
local thistype LaserSet
local BurstLaser BLSet
local real launch_x
local real launch_y
local real launch_z
local real impact_x
local real impact_y
local real impact_z
local unit mark
local boolean updateLaser = false
local boolean destroySet
loop
set i = i + 1
exitwhen i > MaxLasers
set this = LaserIndex[i]
set BLSet = this.laserSetInstance
if not BLSet.destructionPhase then
if this.updateLaunchPoint then
if this.sentry == null then
set mark = this.source
else
set mark = this.sentry
endif
set launch_x = GetUnitX(mark) - this.xLaunchUpdate
set launch_y = GetUnitY(mark) - this.yLaunchUpdate
call MoveLocation(zLoc, launch_x, launch_y)
set launch_z = (GetUnitFlyHeight(mark) + GetLocationZ(zLoc)) - this.zLaunchUpdate
set updateLaser = true
else
set launch_x = this.xLaunch
set launch_y = this.yLaunch
set launch_z = this.zLaunch
endif
if this.updateImpactPoint then
set impact_x = GetUnitX(this.target) - this.xImpactUpdate
set impact_y = GetUnitY(this.target) - this.yImpactUpdate
call MoveLocation(zLoc, impact_x, impact_y)
set impact_z = (GetUnitFlyHeight(this.target) + GetLocationZ(zLoc)) - this.zImpactUpdate
set updateLaser = true
else
set impact_x = this.xImpact
set impact_y = this.yImpact
set impact_z = this.zImpact
endif
if updateLaser then
call MoveLightningEx(Laser[i], true, launch_x, launch_y, launch_z, impact_x, impact_y, impact_z)
endif
if this.lifespan > 0. then
set this.lifespan = this.lifespan - TIMEOUT
else
set this.alpha = this.alpha - this.fadeAmount
if this.alpha <= 0. then
call DestroyLightning(Laser[i])
set Laser[i] = null
call this.destroy()
set iRec = i
loop
set Laser[iRec] = Laser[iRec + 1]
set LaserIndex[iRec] = LaserIndex[iRec + 1]
set iRec = iRec + 1
exitwhen iRec > MaxLasers
endloop
call RemoveSavedHandle(lightningStorage, BLSet, this.laserSlot)
set MaxLasers = MaxLasers - 1
//Check if all lasers from the set have been fired and have been destroyed
if BLSet.laser_count == BLSet.laser_num then
set destroySet = true
set storageIndex = 0
loop
set storageIndex = storageIndex + 1
exitwhen storageIndex > BLSet.laser_num
if LoadLightningHandle(lightningStorage, BLSet, storageIndex) != null then
set destroySet = false
endif
endloop
if destroySet then
set BLSet.destructionPhase = true
if BLSet.interval <= 0. then
set BLSet.interval = DEATH_TIME
endif
endif
endif
else
call SetLightningColor(Laser[i], this.red, this.green, this.blue, this.alpha)
endif
endif
//Lingering Laser damage will only fire if greater than 0.
if this.dotReset > 0. then
set this.dot = this.dot - TIMEOUT
if this.dot <= 0. then
set this.dot = this.dotReset
call BurstLaser.ApplySfxAndDamage(launch_x, launch_y, launch_z, impact_x, impact_y, impact_z, BLSet)
endif
endif
endif
endloop
if MaxLasers < 1 then
call PauseTimer(LaserTimer)
endif
endmethod
static method create takes real launch_x, real launch_y, real launch_z, real impact_x, real impact_y, real impact_z, BurstLaser BLSet returns thistype
local real x
local real y
local unit mark
local integer i
local thistype this = allocate()
set this.laserSetInstance = BLSet
set this.source = BLSet.source
set this.target = BLSet.target
set this.sentry = BLSet.sentry
set this.xLaunch = launch_x
set this.yLaunch = launch_y
set this.zLaunch = launch_z
set this.xImpact = impact_x
set this.yImpact = impact_y
set this.zImpact = impact_z
set this.updateLaunchPoint = BLSet.update_launch
if this.updateLaunchPoint then
if this.sentry == null then
set mark = this.source
else
set mark = this.sentry
endif
set x = GetUnitX(this.sentry)
set y = GetUnitY(this.sentry)
set this.xLaunchUpdate = x - launch_x
set this.yLaunchUpdate = y - launch_y
call MoveLocation(zLoc, launch_x, launch_y)
set this.zLaunchUpdate = (GetUnitFlyHeight(mark) + GetLocationZ(zLoc)) - launch_z
set mark = null
endif
set this.updateImpactPoint = BLSet.update_impact
if this.updateImpactPoint then
set x = GetUnitX(this.target)
set y = GetUnitY(this.target)
set this.xImpactUpdate = x - impact_x
set this.yImpactUpdate = y - impact_y
call MoveLocation(zLoc, impact_x, impact_y)
set this.zImpactUpdate = (GetUnitFlyHeight(this.target) + GetLocationZ(zLoc)) - impact_z
endif
set this.red = BLSet.red
set this.blue = BLSet.blue
set this.green = BLSet.green
set this.alpha = BLSet.alpha
set this.fadeAmount = BLSet.alpha / BLSet.fade_time * TIMEOUT
set this.dot = BLSet.laser_dot
set this.dotReset = BLSet.laser_dot
set this.lifespan = BLSet.duration
set MaxLasers = MaxLasers + 1
if MaxLasers == 1 then
call TimerStart(LaserTimer, TIMEOUT, true, function thistype.Timer)
endif
set Laser[MaxLasers] = AddLightningEx(BLSet.laser_string, true, launch_x, launch_y, launch_z, impact_x, impact_y, impact_z)
call SetLightningColor(Laser[MaxLasers], this.red, this.green, this.blue, this.alpha)
set LaserIndex[MaxLasers] = this
call SaveLightningHandle(lightningStorage, BLSet, BLSet.laser_count, Laser[MaxLasers])
set this.laserSlot = BLSet.laser_count
return this
endmethod
endstruct
struct BurstLaser
unit source
unit target
unit sentry
unit dummy_launch
unit dummy_impact
unit dummy_area
player owner
integer id
real damage
real red
real blue
real green
real alpha
real fade_amount
real fade_time
real duration
integer count
real interval
real lock_angle
real lock_distance
real lock_height
boolean fading
boolean grounded
boolean hit_all
boolean friendly_fire
boolean uninterruptible
real launch_offset
real launch_height
real launch_angle
real launch_x
real launch_y
real launch_z
real launch_scatter_x
real launch_scatter_y
real launch_scatter_z
real launch_scale
real impact_x
real impact_y
real impact_z
real impact_scatter_x
real impact_scatter_y
real impact_scatter_z
real impact_scale
real area_scale
real lock_on_angle
real target_coll
real laser_angle
boolean update_source_loc //If true, subsequent lasers in a volley will launch from the initial laser's launch point and not relative to the source.
boolean update_target_loc //If false, Lasers in a set will strike the same point instead of updating their impact location to follow a moving target.
boolean launch_from_target //If true, the launch point will be relative to the target's location, not the source.
boolean update_launch //if true then Lasers will update their launch location relative to the source's.
boolean update_impact //if true then Lasers will update their impact location relative to the target's.
boolean fixed_impact //If true lasers will impact a fixed distance from the source. range_start and range_per_laser will modify this value.
real range_start //Adds or subtracts a certain amount of distance from a laser's impact location.
real range_per_laser //Adds or substracts distance per Laser in a set.
real laser_dot //the laser's sfx and damage will repeat every laser_dot seconds until the laser ends.
string laser_string
string launch_string
string impact_string
string area_string
real aoe
attacktype attack_type
integer damage_type
real initial_x
real initial_y
timer tmr_volley
integer dummy_count
boolean reduce_launch_overhead
boolean reduce_impact_overhead
integer laser_num
integer laser_count
real deathTime
boolean destructionPhase
integer hashIndex
static code timer_volley_handler
static code interruption_event_handler
method destroy takes nothing returns nothing
local integer id = GetUnitUserData(this.source)
local integer i = 0
local unit dummy
//EVENT
set udg_BL_EVENT_Source = this.source
set udg_BL_EVENT_Target = this.target
set udg_BL_EVENT_Sentry = this.sentry
set udg_BL_EVENT_Launch_x = launch_x
set udg_BL_EVENT_Launch_y = launch_y
set udg_BL_EVENT_Launch_z = launch_z
set udg_BL_EVENT_Impact_x = impact_x
set udg_BL_EVENT_Impact_y = impact_y
set udg_BL_EVENT_Impact_z = impact_z
set udg_BL_EVENT_Damage = this.damage
set udg_BL_EVENT = 4.
set udg_BL_EVENT_Source = null
set udg_BL_EVENT_Target = null
set udg_BL_EVENT_Sentry = null
set udg_BL_EVENT_Launch_x = 0.
set udg_BL_EVENT_Launch_y = 0.
set udg_BL_EVENT_Launch_z = 0.
set udg_BL_EVENT_Impact_x = 0.
set udg_BL_EVENT_Impact_y = 0.
set udg_BL_EVENT_Impact_z = 0.
set udg_BL_EVENT_Damage = 0.
set udg_BL_EVENT = 0.
//END EVENT
set this.owner = null
set this.source = null
set this.target = null
set this.sentry = null
if this.dummy_launch != null then
set this.dummy_launch = null
endif
if this.dummy_impact != null then
set this.dummy_impact = null
endif
if this.dummy_area != null then
set this.dummy_area = null
endif
loop
set i = i + 1
exitwhen i > this.dummy_count
call RecycleDummy(LoadUnitHandle(dummyStorage, this, i))
endloop
call FlushChildHashtable(dummyStorage, this)
call ReleaseTimer(tmr_volley)
call RemoveSavedInteger(hash, id, this.hashIndex)
call this.deallocate()
endmethod
static method ApplySfxAndDamage takes real launch_x, real launch_y, real launch_z, real impact_x, real impact_y, real impact_z, BurstLaser this returns nothing
local unit u = null
//Launch
if this.reduce_launch_overhead then
if this.launch_string != null then
if this.dummy_launch == null then
set this.dummy_launch = GetRecycledDummy(launch_x, launch_y, launch_z, 0.)
set this.dummy_count = this.dummy_count + 1
call SaveUnitHandle(dummyStorage, this, this.dummy_count, this.dummy_launch)
else
call SetUnitX(this.dummy_launch, launch_x)
call SetUnitY(this.dummy_launch, launch_y)
call MoveLocation(zLoc, launch_x, launch_y)
call SetUnitFlyHeight(this.dummy_launch, launch_z + GetLocationZ(zLoc), 0.)
endif
set udg_BL_EVENT_Dummy_Launch = this.dummy_launch
call SetUnitScale(this.dummy_launch, this.launch_scale, 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(this.launch_string, this.dummy_launch, "origin"))
endif
else
if this.launch_string != null then
set this.dummy_launch = GetRecycledDummy(launch_x, launch_y, launch_z, 0.)
call SetUnitScale(this.dummy_launch, this.launch_scale, 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(this.launch_string, this.dummy_launch, "origin"))
set this.dummy_count = this.dummy_count + 1
call SaveUnitHandle(dummyStorage, this, this.dummy_count, this.dummy_launch)
set udg_BL_EVENT_Dummy_Launch = this.dummy_launch
set this.dummy_launch = null
endif
endif
//Impact and Area
if this.reduce_impact_overhead then
call MoveLocation(zLoc, impact_x, impact_y)
if this.impact_string != null then
if this.dummy_impact == null then
set this.dummy_impact = GetRecycledDummy(impact_x, impact_y, impact_z, 0.)
set this.dummy_count = this.dummy_count + 1
call SaveUnitHandle(dummyStorage, this, this.dummy_count, this.dummy_impact)
else
call SetUnitX(this.dummy_impact, impact_x)
call SetUnitY(this.dummy_impact, impact_y)
call SetUnitFlyHeight(this.dummy_impact, impact_z + GetLocationZ(zLoc), 0.)
endif
set udg_BL_EVENT_Dummy_Impact = this.dummy_impact
call SetUnitScale(this.dummy_impact, this.impact_scale, 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(this.impact_string, this.dummy_impact, "origin"))
endif
if this.area_string != null then
if this.area_scale != this.impact_scale then
if this.dummy_area == null then
set this.dummy_area = GetRecycledDummy(impact_x, impact_y, impact_z, 0.)
set this.dummy_count = this.dummy_count + 1
call SaveUnitHandle(dummyStorage, this, this.dummy_count, this.dummy_area)
else
call SetUnitX(this.dummy_area, impact_x)
call SetUnitY(this.dummy_area, impact_y)
call SetUnitFlyHeight(this.dummy_area, impact_z + GetLocationZ(zLoc), 0.)
endif
set udg_BL_EVENT_Dummy_Area = this.dummy_area
call SetUnitScale(this.dummy_impact, this.area_scale, 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(this.area_string, this.dummy_area, "origin"))
else
if this.dummy_impact == null then
set this.dummy_impact = GetRecycledDummy(impact_x, impact_y, impact_z, 0.)
set this.dummy_count = this.dummy_count + 1
call SaveUnitHandle(dummyStorage, this, this.dummy_count, this.dummy_impact)
else
call SetUnitX(this.dummy_impact, impact_x)
call SetUnitY(this.dummy_impact, impact_y)
call SetUnitFlyHeight(this.dummy_impact, impact_z + GetLocationZ(zLoc), 0.)
endif
set udg_BL_EVENT_Dummy_Impact = this.dummy_impact
call SetUnitScale(this.dummy_impact, this.impact_scale, 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(this.area_string, this.dummy_impact, "origin"))
endif
endif
else
if this.impact_string != null then
set this.dummy_impact = GetRecycledDummy(impact_x, impact_y, impact_z, 0.)
set this.dummy_count = this.dummy_count + 1
call SaveUnitHandle(dummyStorage, this, this.dummy_count, this.dummy_impact)
call DestroyEffect(AddSpecialEffectTarget(this.impact_string, this.dummy_impact, "origin"))
set udg_BL_EVENT_Dummy_Impact = this.dummy_impact
endif
if this.area_string != null then
if this.area_scale != this.impact_scale then
set this.dummy_area = GetRecycledDummy(impact_x, impact_y, impact_z, 0.)
set this.dummy_count = this.dummy_count + 1
call SaveUnitHandle(dummyStorage, this, this.dummy_count, this.dummy_area)
set udg_BL_EVENT_Dummy_Area = this.dummy_area
call SetUnitScale(this.dummy_area, this.area_scale, 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(this.area_string, this.dummy_area, "origin"))
set this.dummy_area = null
else
if this.dummy_impact == null then
set this.dummy_impact = GetRecycledDummy(impact_x, impact_y, impact_z, 0.)
set this.dummy_count = this.dummy_count + 1
call SaveUnitHandle(dummyStorage, this, this.dummy_count, this.dummy_impact)
endif
call SetUnitScale(this.dummy_impact, this.impact_scale, 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(this.area_string, this.dummy_impact, "origin"))
endif
if this.dummy_impact != null then
set this.dummy_impact = null
endif
endif
endif
//Damage
if this.aoe > 0. then
call GroupEnumUnitsInRange(DamageGroup, impact_x, impact_y, this.aoe + MAX_COLLISION_SIZE, null)
loop
set u = FirstOfGroup(DamageGroup)
call GroupRemoveUnit(DamageGroup, u)
exitwhen u == null
if IsUnitInRangeXY(u, impact_x, impact_y, this.aoe) and UnitAlive(u) and /*
[Friendly Fire] */( (this.friendly_fire and (IsUnitEnemy(u, this.owner) or IsUnitAlly(u, this.owner))) or /*
[Enemy] */ ( (not this.friendly_fire and IsUnitEnemy(u, this.owner)) or /*
[Friendly] */ (not this.friendly_fire and IsUnitAlly(u, this.owner) and u == this.target) ) ) and /*
[Magic Immune] */( (this.attack_type == ATTACK_TYPE_MAGIC and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) or /*
[Ethereal] */ (this.attack_type != ATTACK_TYPE_MAGIC and not IsUnitType(u, UNIT_TYPE_ETHEREAL)) ) then
if not this.hit_all and /*
[Ground] */ ( (not IsUnitType(u, UNIT_TYPE_FLYING) and not IsUnitType(this.target, UNIT_TYPE_FLYING)) or /*
[Flying] */ (IsUnitType(u, UNIT_TYPE_FLYING) and IsUnitType(this.target, UNIT_TYPE_FLYING)) ) then
set udg_NextDamageType = this.damage_type
call UnitDamageTarget(this.source, u, this.damage, true, true, this.attack_type, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
elseif this.hit_all then
set udg_NextDamageType = this.damage_type
call UnitDamageTarget(this.source, u, this.damage, true, true, this.attack_type, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
endif
endif
endloop
else
set udg_NextDamageType = this.damage_type
call UnitDamageTarget(this.source, this.target, this.damage, true, true, this.attack_type, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
endif
endmethod
private static method Interruption_Event takes nothing returns nothing
local integer id = GetUnitUserData(GetTriggerUnit())
local integer counter = LoadInteger(hash, id, COUNTER_KEY)
//local integer i = 0
local thistype this
loop
exitwhen counter < 1
set this = LoadInteger(hash, id, counter)
if not this.uninterruptible and this.interval > 0. then
/*call PauseTimer(this.tmr_volley)
loop
exitwhen i >= this.laser_num
set this.lifespan <= 0.
set this.alpha = true
set i = i + 1
endloop*/
set this.laser_num = this.laser_count //This is set in case of interruption
endif
set counter = counter - 1
endloop
call SaveInteger(hash, id, COUNTER_KEY, 0)
endmethod
private static method BurstLaser_Volley takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local integer id = GetUnitUserData(this.source)
local integer counter = LoadInteger(hash, id, COUNTER_KEY)
local real source_x = GetUnitX(this.source)
local real source_y = GetUnitY(this.source)
local real target_x = GetUnitX(this.target)
local real target_y = GetUnitY(this.target)
local real angle
local real xLaunch
local real yLaunch
local real zLaunch
local real launch_scatter_x
local real launch_scatter_y
local real launch_scatter_z
local real xImpact
local real yImpact
local real zImpact
local boolean destroySet
local integer i
if not this.destructionPhase then
if this.laser_count < this.laser_num and UnitAlive(this.source) then //If there are still lasers in the set to be fired
if this.sentry == null then
if this.launch_from_target then
if this.update_source_loc then
set angle = this.lock_on_angle//Atan2(this.launch_y - target_y, this.launch_x - target_x) + this.launch_angle
set xLaunch = target_x + Cos(angle) * this.launch_offset
set yLaunch = target_y + Sin(angle) * this.launch_offset
call MoveLocation(zLoc, xLaunch, yLaunch)
set zLaunch = GetUnitFlyHeight(this.source) + this.launch_height + GetLocationZ(zLoc)
else
set xLaunch = this.launch_x
set yLaunch = this.launch_y
set zLaunch = this.launch_z
endif
else
if this.update_source_loc then
set angle = Atan2(target_y - source_y, target_x - source_x) + this.launch_angle
set xLaunch = source_x + Cos(angle + this.launch_angle) * this.launch_offset
set yLaunch = source_y + Sin(angle + this.launch_angle) * this.launch_offset
call MoveLocation(zLoc, xLaunch, yLaunch)
set zLaunch = GetUnitFlyHeight(this.source) + this.launch_height + GetLocationZ(zLoc)
else
set xLaunch = this.launch_x
set yLaunch = this.launch_y
set zLaunch = this.launch_z
endif
endif
else
if this.update_source_loc then
set angle = Atan2(target_y - source_y, target_x - source_x) + this.launch_angle
set xLaunch = GetUnitX(this.sentry) + Cos(angle + this.launch_angle) * this.launch_offset
set yLaunch = GetUnitY(this.sentry) + Sin(angle + this.launch_angle) * this.launch_offset
call MoveLocation(zLoc, xLaunch, yLaunch)
set zLaunch = GetUnitFlyHeight(this.sentry) + this.launch_height + GetLocationZ(zLoc)
else
set xLaunch = this.launch_x
set yLaunch = this.launch_y
set zLaunch = this.launch_z
endif
endif
set launch_scatter_x = GetRandomReal(this.launch_scatter_x*-1, this.launch_scatter_x)
set launch_scatter_y = GetRandomReal(this.launch_scatter_y*-1, this.launch_scatter_y)
set launch_scatter_z = GetRandomReal(this.launch_scatter_z*-1, this.launch_scatter_z)
set xLaunch = xLaunch + launch_scatter_x
set yLaunch = yLaunch + launch_scatter_y
set zLaunch = zLaunch + launch_scatter_z
if this.fixed_impact then //if true, start from the source's point
if this.update_target_loc then
if this.range_per_laser != 0. then
set angle = Atan2(target_y - yLaunch, target_x - xLaunch)
set this.impact_x = this.impact_x + Cos(angle) * this.range_per_laser
set this.impact_y = this.impact_y + Sin(angle) * this.range_per_laser
set xImpact = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set yImpact = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
else
set angle = Atan2(yLaunch - target_y, xLaunch - target_x)
set this.impact_x = target_x + Cos(angle) * (this.target_coll * COLLISION_PERCENTAGE)
set this.impact_y = target_y + Sin(angle) * (this.target_coll * COLLISION_PERCENTAGE)
set xImpact = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set yImpact = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
endif
call MoveLocation(zLoc, xImpact, yImpact)
if this.grounded then
set this.impact_z = 0. + GetLocationZ(zLoc)
set zImpact = 0. + GetLocationZ(zLoc)
else
set this.impact_z = GetUnitFlyHeight(this.target) + GetLocationZ(zLoc)
set zImpact = this.impact_z + GetRandomReal(this.impact_scatter_z*-1, this.impact_scatter_z) + this.target_coll * COLLISION_PERCENTAGE
endif
else
if this.range_per_laser != 0. then
set this.impact_x = this.impact_x + Cos(this.laser_angle) * this.range_per_laser
set this.impact_y = this.impact_y + Sin(this.laser_angle) * this.range_per_laser
set xImpact = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set yImpact = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
else
set angle = Atan2(yLaunch - this.initial_y, xLaunch - this.initial_x)
set this.impact_x = target_x + Cos(angle) * (this.target_coll * COLLISION_PERCENTAGE)
set this.impact_y = target_y + Sin(angle) * (this.target_coll * COLLISION_PERCENTAGE)
set xImpact = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set yImpact = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
call MoveLocation(zLoc, impact_x, yImpact)
set this.impact_z = GetUnitFlyHeight(this.target) + GetLocationZ(zLoc)
endif
call MoveLocation(zLoc, xImpact, yImpact)
if this.grounded then
set this.impact_z = 0. + GetLocationZ(zLoc)
set zImpact = 0. + GetLocationZ(zLoc)
else
set zImpact = this.impact_z + GetRandomReal(this.impact_scatter_z*-1, this.impact_scatter_z) + this.target_coll * COLLISION_PERCENTAGE
endif
endif
else
if this.update_target_loc then
if this.range_per_laser != 0. then
set angle = Atan2(target_y - yLaunch, target_x - xLaunch)
set this.impact_x = this.impact_x + Cos(angle) * this.range_per_laser
set this.impact_y = this.impact_y + Sin(angle) * this.range_per_laser
set xImpact = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set yImpact = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
else
set angle = Atan2(yLaunch - target_y, xLaunch - target_x)
set this.impact_x = target_x + Cos(angle) * (this.target_coll * COLLISION_PERCENTAGE)
set this.impact_y = target_y + Sin(angle) * (this.target_coll * COLLISION_PERCENTAGE)
set xImpact = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set yImpact = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
endif
call MoveLocation(zLoc, xImpact, yImpact)
if this.grounded then
set this.impact_z = 0. + GetLocationZ(zLoc)
set zImpact = 0. + GetLocationZ(zLoc)
else
set this.impact_z = GetUnitFlyHeight(this.target) + GetLocationZ(zLoc)
set zImpact = this.impact_z + GetRandomReal(this.impact_scatter_z*-1, this.impact_scatter_z) + this.target_coll * COLLISION_PERCENTAGE
endif
else
if this.range_per_laser != 0. then
set this.impact_x = this.impact_x + Cos(this.laser_angle) * this.range_per_laser
set this.impact_y = this.impact_y + Sin(this.laser_angle) * this.range_per_laser
set xImpact = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set yImpact = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
else
set angle = Atan2(yLaunch - this.initial_y, xLaunch - this.initial_x)
set this.impact_x = target_x + Cos(angle) * (this.target_coll * COLLISION_PERCENTAGE)
set this.impact_y = target_y + Sin(angle) * (this.target_coll * COLLISION_PERCENTAGE)
set xImpact = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set yImpact = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
call MoveLocation(zLoc, xImpact, yImpact)
set this.impact_z = GetUnitFlyHeight(this.target) + GetLocationZ(zLoc)
endif
call MoveLocation(zLoc, xImpact, yImpact)
if this.grounded then
set this.impact_z = 0. + GetLocationZ(zLoc)
set zImpact = 0. + GetLocationZ(zLoc)
else
set zImpact = this.impact_z + GetRandomReal(this.impact_scatter_z*-1, this.impact_scatter_z) + this.target_coll * COLLISION_PERCENTAGE
endif
endif
endif
call BurstLaser.ApplySfxAndDamage(xLaunch, yLaunch, zLaunch, xImpact, yImpact, zImpact, this)
//Laser
if this.laser_string != null then
call LaserInstance.create(xLaunch, yLaunch, zLaunch, xImpact, yImpact, zImpact, this)
endif
set this.laser_count = this.laser_count + 1
//EVENT
set udg_BL_EVENT_Source = this.source
set udg_BL_EVENT_Target = this.target
set udg_BL_EVENT_Sentry = this.sentry
set udg_BL_EVENT_Launch_x = xLaunch
set udg_BL_EVENT_Launch_y = yLaunch
set udg_BL_EVENT_Launch_z = zLaunch
set udg_BL_EVENT_Impact_x = xImpact
set udg_BL_EVENT_Impact_y = yImpact
set udg_BL_EVENT_Impact_z = zImpact
set udg_BL_EVENT_Damage = this.damage
set udg_BL_EVENT = 2.
set udg_BL_EVENT_Source = null
set udg_BL_EVENT_Target = null
set udg_BL_EVENT_Sentry = null
set udg_BL_EVENT_Launch_x = 0.
set udg_BL_EVENT_Launch_y = 0.
set udg_BL_EVENT_Launch_z = 0.
set udg_BL_EVENT_Impact_x = 0.
set udg_BL_EVENT_Impact_y = 0.
set udg_BL_EVENT_Impact_z = 0.
set udg_BL_EVENT_Damage = 0.
set udg_BL_EVENT_Dummy_Launch = null
set udg_BL_EVENT_Dummy_Impact = null
set udg_BL_EVENT = 0.
//END EVENT
elseif this.laser_count == this.laser_num or not UnitAlive(this.source) then
//EVENT
set udg_BL_EVENT_Source = this.source
set udg_BL_EVENT_Target = this.target
set udg_BL_EVENT_Sentry = this.sentry
set udg_BL_EVENT_Launch_x = xLaunch
set udg_BL_EVENT_Launch_y = yLaunch
set udg_BL_EVENT_Launch_z = zLaunch
set udg_BL_EVENT_Impact_x = xImpact
set udg_BL_EVENT_Impact_y = yImpact
set udg_BL_EVENT_Impact_z = zImpact
set udg_BL_EVENT_Damage = this.damage
set udg_BL_EVENT = 3.
set udg_BL_EVENT_Source = null
set udg_BL_EVENT_Target = null
set udg_BL_EVENT_Sentry = null
set udg_BL_EVENT_Launch_x = 0.
set udg_BL_EVENT_Launch_y = 0.
set udg_BL_EVENT_Launch_z = 0.
set udg_BL_EVENT_Impact_x = 0.
set udg_BL_EVENT_Impact_y = 0.
set udg_BL_EVENT_Impact_z = 0.
set udg_BL_EVENT_Damage = 0.
set udg_BL_EVENT = 0.
//END EVENT
call PauseTimer(this.tmr_volley)
call SaveInteger(hash, id, COUNTER_KEY, LoadInteger(hash, id, counter) - 1) // decrease counter
set this.laser_num = this.laser_count //This is set in case of interruption.
set i = 0
set destroySet = true
loop
set i = i + 1
exitwhen i > this.laser_num
if LoadLightningHandle(lightningStorage, this, i) != null then
set destroySet = false
endif
if destroySet then
//destructionPhase is used to terminate the instance slightly after
//the last laser in a set has been destroyed to allow special effects
//on dummies to play out.
set this.destructionPhase = true
if this.interval <= 0. then
set this.interval = DEATH_TIME
endif
endif
endloop
endif
else
set this.deathTime = this.deathTime - this.interval
if this.deathTime <= 0. then
call this.destroy()
endif
endif
endmethod
static method create takes unit unit_source, unit unit_target, unit unit_sentry, BLAssignWeapon wpn, integer id, real damage returns thistype
local thistype this = allocate()
local integer idSource = GetUnitUserData(unit_source)
local integer counter = LoadInteger(hash, idSource, COUNTER_KEY) // get instance counter
local real source_x = GetUnitX(unit_source)
local real source_y = GetUnitY(unit_source)
local real target_x = GetUnitX(unit_target)
local real target_y = GetUnitY(unit_target)
local real sentry_x = 0.
local real sentry_y = 0.
local real startangle
local real range_offset = 0.
local real launch_spread_x = 0.
local real launch_spread_y = 0.
local real launch_spread_z = 0.
local real impact_spread_x = 0.
local real impact_spread_y = 0.
local real impact_spread_z = 0.
local integer iLoop = 0
local unit u = null
set counter = counter + 1
call SaveInteger(hash, idSource, COUNTER_KEY, counter) // increase instance counter
call SaveInteger(hash, idSource, counter, this) // bind instance to unit id
set this.hashIndex = counter // so the instance knows where it's stored
set this.owner = GetOwningPlayer(unit_source)
set this.source = unit_source
set this.target = unit_target
set this.sentry = unit_sentry
set this.target_coll = GetUnitCollision(unit_target)
set this.laser_string = wpn.LaserString[id]
set this.red = wpn.RED[id]
set this.blue = wpn.BLUE[id]
set this.green = wpn.GREEN[id]
set this.alpha = wpn.ALPHA[id]
set this.launch_string = wpn.LaserLaunchFX[id]
set this.impact_string = wpn.LaserImpactFX[id]
set this.area_string = wpn.LaserAreaFX[id]
set this.launch_scale = wpn.LaserLaunchScale[id]
set this.impact_scale = wpn.LaserImpactScale[id]
set this.area_scale = wpn.LaserAreaScale[id]
set this.duration = wpn.LaserDuration[id]
set this.fade_time = wpn.LaserFadeTime[id]
set this.interval = wpn.LaserInterval[id]
set this.laser_dot = wpn.LaserDoT[id]
set this.aoe = wpn.LaserAOE[id]
set this.grounded = wpn.IsLaserGrounded[id]
set this.launch_offset = wpn.LaserLaunchOffset[id]
set this.launch_height = wpn.LaserLaunchHeight[id]
set this.launch_angle = wpn.LaserLaunchAngle[id]
set this.launch_scatter_x = wpn.LaserLaunchScatterX[id]
set this.launch_scatter_y = wpn.LaserLaunchScatterY[id]
set this.launch_scatter_z = wpn.LaserLaunchScatterZ[id]
set this.impact_scatter_x = wpn.LaserImpactScatterX[id]
set this.impact_scatter_y = wpn.LaserImpactScatterY[id]
set this.impact_scatter_z = wpn.LaserImpactScatterZ[id]
set this.update_target_loc = wpn.UpdateTargetLoc[id]
set this.update_source_loc = wpn.UpdateSourceLoc[id]
set this.launch_from_target = wpn.LaunchFromTargetLoc[id]
set this.update_launch = wpn.UpdateLaunchPoint[id]
set this.update_impact = wpn.UpdateImpactPoint[id]
set this.fixed_impact = wpn.FixedImpactLoc[id]
set this.range_start = wpn.LaserRangeStart[id]
set this.range_per_laser = wpn.LaserRangePerLaser[id]
set this.attack_type = wpn.LaserAttackType[id]
set this.damage_type = wpn.LaserDamageType[id]
set this.uninterruptible = wpn.Uninterruptible[id]
set this.hit_all = wpn.LaserHitAll[id]
set this.friendly_fire = wpn.LaserFriendlyFire[id]
set this.reduce_launch_overhead = wpn.ReduceLaunchOverhead[id]
set this.reduce_impact_overhead = wpn.ReduceImpactOverhead[id]
set this.destructionPhase = false
set this.deathTime = DEATH_TIME
set this.laser_num = wpn.NumberOfLasers[id]
set this.laser_count = 0
if this.sentry == null then
if this.launch_from_target then
set startangle = Atan2(source_y - target_y, source_x - target_x) + this.launch_angle
if this.update_source_loc then
set this.lock_on_angle = startangle
endif
if this.launch_offset > 0. then
set this.launch_x = target_x + Cos(startangle) * this.launch_offset
set this.launch_y = target_y + Sin(startangle) * this.launch_offset
else
set this.launch_x = target_x
set this.launch_y = target_y
endif
call MoveLocation(zLoc, this.launch_x, this.launch_y)
set this.launch_z = GetUnitFlyHeight(this.target) + this.launch_height + GetLocationZ(zLoc)
else
set startangle = Atan2(target_y - source_y, target_x - source_x) + this.launch_angle
if this.launch_offset > 0. then
set this.launch_x = source_x + Cos(startangle) * this.launch_offset
set this.launch_y = source_y + Sin(startangle) * this.launch_offset
else
set this.launch_x = source_x
set this.launch_y = source_y
endif
call MoveLocation(zLoc, this.launch_x, this.launch_y)
set this.launch_z = GetUnitFlyHeight(this.source) + this.launch_height + GetLocationZ(zLoc)
endif
else
set sentry_x = GetUnitX(this.sentry)
set sentry_y = GetUnitY(this.sentry)
set startangle = Atan2(target_y - sentry_y, target_x - sentry_x) + this.launch_angle
if this.launch_offset > 0. then
set this.launch_x = sentry_x + Cos(startangle) * this.launch_offset
set this.launch_y = sentry_y + Sin(startangle) * this.launch_offset
else
set this.launch_x = sentry_x
set this.launch_y = sentry_y
endif
call MoveLocation(zLoc, this.launch_x, this.launch_y)
set this.launch_z = GetUnitFlyHeight(this.sentry) + this.launch_height + GetLocationZ(zLoc)
endif
set launch_spread_x = this.launch_x + GetRandomReal(this.launch_scatter_x*-1, this.launch_scatter_x)
set launch_spread_y = this.launch_y + GetRandomReal(this.launch_scatter_y*-1, this.launch_scatter_y)
set launch_spread_z = this.launch_z + GetRandomReal(this.launch_scatter_z*-1, this.launch_scatter_z)
set range_offset = ((this.laser_num-1) * this.range_per_laser + this.range_start) * .5
if this.fixed_impact then //if true, start from the source's point
set startangle = Atan2(target_y - source_y, target_x - source_x)
set this.impact_x = source_x + Cos(startangle) * (range_offset + this.range_start)
set this.impact_y = source_y + Sin(startangle) * (range_offset + this.range_start)
set startangle = startangle + wpn.LaserDirectionalTilt[id]
set this.impact_x = this.impact_x + Cos(startangle) * (range_offset)
set this.impact_y = this.impact_y + Sin(startangle) * (range_offset)
set impact_spread_x = this.impact_x + GetRandomReal(this.impact_scatter_x*-1, this.impact_scatter_x)
set impact_spread_y = this.impact_y + GetRandomReal(this.impact_scatter_y*-1, this.impact_scatter_y)
call MoveLocation(zLoc, impact_spread_x, impact_spread_y)
if this.grounded then
set this.impact_z = 0. + GetLocationZ(zLoc)
set impact_spread_z = 0.
else
set this.impact_z = GetUnitFlyHeight(this.target) + GetLocationZ(zLoc)
set impact_spread_z = this.impact_z + GetRandomReal(this.impact_scatter_z*-1, this.impact_scatter_z) + this.target_coll * COLLISION_PERCENTAGE
endif
else
set startangle = Atan2(target_y - source_y, target_x - source_x) + wpn.LaserDirectionalTilt[id] + 3.14159
if this.range_per_laser != 0. then
set this.impact_x = target_x + Cos(startangle) * (range_offset + this.range_start)
set this.impact_y = target_y + Sin(startangle) * (range_offset + this.range_start)
else
set this.impact_x = target_x + Cos(startangle) * (this.target_coll * COLLISION_PERCENTAGE)
set this.impact_y = target_y + Sin(startangle) * (this.target_coll * COLLISION_PERCENTAGE)
endif
set impact_spread_x = this.impact_x + GetRandomReal(this.impact_scatter_x * -1, this.impact_scatter_x)
set impact_spread_y = this.impact_y + GetRandomReal(this.impact_scatter_y * -1, this.impact_scatter_y)
call MoveLocation(zLoc, impact_spread_x, impact_spread_y)
if this.grounded then
set this.impact_z = 0. + GetLocationZ(zLoc)
set impact_spread_z = 0.
else
set this.impact_z = GetUnitFlyHeight(this.target) + GetLocationZ(zLoc)
set impact_spread_z = this.impact_z + GetRandomReal(this.impact_scatter_z*-1, this.impact_scatter_z) + this.target_coll * COLLISION_PERCENTAGE
endif
endif
//If lasers can inflict DoT, diving the damage by the maximum number of hits the laser can inflict.
if wpn.LaserDoT[id] > 0. then
set this.damage = damage / ((wpn.LaserDuration[id] + wpn.LaserFadeTime[id]) / wpn.LaserDoT[id])
else
set this.damage = damage
endif
set this.dummy_count = 0
call BurstLaser.ApplySfxAndDamage(launch_spread_x, launch_spread_y, launch_spread_z, impact_spread_x, impact_spread_y, impact_spread_z, this)
//Laser
if this.laser_string != null then
call LaserInstance.create(launch_spread_x, launch_spread_y, launch_spread_z, impact_spread_x, impact_spread_y, impact_spread_z, this)
endif
set this.laser_count = this.laser_count + 1
//EVENT
set udg_BL_EVENT_Source = this.source
set udg_BL_EVENT_Target = this.target
set udg_BL_EVENT_Sentry = this.sentry
set udg_BL_EVENT_Launch_x = launch_x
set udg_BL_EVENT_Launch_y = launch_y
set udg_BL_EVENT_Launch_z = launch_z
set udg_BL_EVENT_Impact_x = impact_x
set udg_BL_EVENT_Impact_y = impact_y
set udg_BL_EVENT_Impact_z = impact_z
set udg_BL_EVENT_Damage = this.damage
set udg_BL_EVENT = 1.
set udg_BL_EVENT_Source = null
set udg_BL_EVENT_Target = null
set udg_BL_EVENT_Sentry = null
set udg_BL_EVENT_Launch_x = 0.
set udg_BL_EVENT_Launch_y = 0.
set udg_BL_EVENT_Launch_z = 0.
set udg_BL_EVENT_Impact_x = 0.
set udg_BL_EVENT_Impact_y = 0.
set udg_BL_EVENT_Impact_z = 0.
set udg_BL_EVENT_Damage = 0.
set udg_BL_EVENT = 0.
//END EVENT
set this.laser_angle = startangle + 3.14159
set this.initial_x = this.impact_x
set this.initial_y = this.impact_y
set this.count = this.laser_num - 1
if this.laser_num > 1 then
set this.tmr_volley = NewTimerEx(this)
call TimerStart(this.tmr_volley, this.interval, true, timer_volley_handler)
endif
return this
endmethod
private static method onInit takes nothing returns nothing
local integer iLoop = 0
set timer_volley_handler = function thistype.BurstLaser_Volley
set interruption_event_handler = function thistype.Interruption_Event
loop
call TriggerRegisterPlayerUnitEvent(interrupt_trigger, Player(iLoop), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
call TriggerRegisterPlayerUnitEvent(interrupt_trigger, Player(iLoop), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
call TriggerRegisterPlayerUnitEvent(interrupt_trigger, Player(iLoop), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
set iLoop = iLoop + 1
exitwhen iLoop == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(interrupt_trigger, interruption_event_handler)
endmethod
endstruct
endlibrary
```