- Joined
- Jan 9, 2005
- Messages
- 2,121
Trying to fix my Burst Laser system by remaking it with structs. I can't get the lightning effects to destroy properly, so I'm not sure what I'm doing wrong.
I'm using this mostly as a way to pre-set the variables instead of having to add a million things when calling StructName.create()
The main code. I'm not sure if I do have to call deallocate(this), but things seem to be overlapping and getting overwritten and timers are getting screwed up or something. It's worth noting that there are two timers running, BurstLaser_Volley and LaserFade_Timer. If the latter runs, it will always be last so the deallocation will take place then. Otherwise, if it doesn't run, the deallocation takes place the the BurstLaser_Volley method.
The system was initially meant to be a custom attack system and this just calls a .create on the struct. Kinda splits the code in two, but allows for more stuff to be done with the system. I'm not entirely sure I'm doing this properlly, though.
I'm using this mostly as a way to pre-set the variables instead of having to add a million things when calling StructName.create()
JASS:
library BL initializer BurstLaser_Setup// requires IdAlloc
/*** If you're getting a duplicate of UnitAlive, you can delete or comment out this one ***/
native UnitAlive takes unit id returns boolean
globals
private trigger BurstLaserTrigger = CreateTrigger()
public boolean array UsesBurstLaser //Must always be true or the system won't work.
public boolean array Uninterruptible //If true, lasers will keep firing even if the target is stunned or dead.
public boolean array IsLaserGrounded //If true, then your Lasers will always strike the ground. Invalidates LaserSpreadZ. Can be useful for AoE ground attacks.
public boolean array LaserImpactLock //If true, the Laser with latch on to it's impact point relative to it's target. That can cause weird behaviour, use trial and error.
public integer array NumberOfLasers //CANNOT BE LESS THAN 1 or you will deal no damage. The number of lasers that will be shot per attack. CANNOT BE LESS THAN 1
public integer array LaserDuration //How long an individual laser will last before it starts to fade. 32 == 1 second.
public integer array LaserFadeTime //How long it takes for each laser to fade. 32 == 1 second.
public real array LaserInterval //Time between laser in seconds.
public string array LaserLaunchFX //The string of the special effect that plays on the launch dummy.
public string array LaserImpactFX //The string of the special effect that plays on the impact dummy.
public string array LaserAreaFX //The string of the special effect that plays on the impact dummy in addition to the ImpactFX. Works better with an AOE laser.
public string array LaserString //The string of lightning effect itself.
public real array LaserAOE //If greater that 0. will deal damage in an area around the impact.
public real array LaserLaunchOffset //How far forward with the Launch effect be. Use negative values to move backwards.
public real array LaserLaunchHeight //Adjusts the Launch effect along the Z axis. Positive value go up, negative values go down.
public real array LaserLaunchAngle //By how many radians will the Launch effect be offset by? Positive values adjust the angle counter-clockwise.
public real array LaserSpreadXY //How much your laser will spread out along the X and Y axis.
public real array LaserSpreadZ //How much your laser will spread out along the Z axis.
public boolean array LaserDivideDamage //If true, the total damage will be divide amoung the number of lasers.
public boolean array FollowTarget //If false, Lasers in a set will strike the same point instead of updating their impact location to follow a moving target.
public boolean array LaserRangeLock //If true will set LaserRangeStart's starting point to the attacker (source of the laser) instead of the taret
public real array LaserRangeStart //Adds or subtracts a certain amount of distance from it's starting point.
public real array LaserRangePerLaser //Adds or substracts distance per Laser in a set.
public real array LaserDirectionalTilt //This pivots the angle of the Laser by a certain amount so that the direction from which the Laser starts is rotated. Uses radians.
//A value of 1.5708 radians (90°) with make a laser start from right to left, for example.
//-0.785398 radians (-45°) will start the laser from left to right, moving diagonally.
//This is only useful if LaserRangePerLaser is > 0.
public attacktype array LaserAttackType //Vanilla attack type like ATTACK_TYPE_HERO, ATTACK_TYPE_PIERCE, etc
public integer array LaserDamageType //The damage type from Damage Engine
public boolean array LaserHitAll //The laser will harm all units in the LaserAOE. If LaserAOE is <= 0. this does nothing.
public boolean array LaserFriendlyFire //AOE damage will damage allies
public unit array LaserSentry //This is optional. If something is set as the Sentry, the lasers will shoot from that unit instead.
public real array RED //Red tint of the Laser. 1. is 100%, and 0. is 0%.
public real array BLUE //Blue tint of the Laser. 1. is 100%, and 0. is 0%.
public real array GREEN //Green tint of the Laser. 1. is 100%, and 0. is 0%.
public real array ALPHA //Transparency of the Laser. 1. fully visible. 0. is completely transparent.
public integer array LaserIndex //Binding all values to the custom value of the unit can cause problems if using IndexIndexAllocate() so that's just a safety measure.
//Events
public real EVENT = 0.
public unit EVENT_Source = null
public unit EVENT_Target = null
public unit EVENT_Sentry = null
public real EVENT_Launch_x = 0.
public real EVENT_Launch_y = 0.
public real EVENT_Launch_z = 0.
public real EVENT_Impact_x = 0.
public real EVENT_Impact_y = 0.
public real EVENT_Impact_z = 0.
endglobals
function BurstLaser_onIndex takes nothing returns boolean
local unit Source = udg_UDexUnits[udg_UDex]
local integer ID = udg_UDex
if udg_UnitIndexEvent == 1. then
//Rifleman
if GetUnitTypeId(Source) == 'hrif' then
//set LaserIndex[udg_UDex] = IndexAllocate() //This must not be changed.
//set ID = LaserIndex[udg_UDex]
set UsesBurstLaser[ID] = true //This must always be true or this unit type will not use this system.
set LaserString[ID] = "YLLN" //This is the lightning effect that will be used. Can be null.
set RED[ID] = 1. //This is the red tint of your lightning effect. 1.0 is 100% and 0.0 is 0%.
set BLUE[ID] = 1. //This is the blue tint of your lightning effect. 1.0 is 100% and 0.0 is 0%.
set GREEN[ID] = 1. //This is the green tint of your lightning effect. 1.0 is 100% and 0.0 is 0%.
set ALPHA[ID] = .85 //This is the opacity of your lightning effect. 1.0 is fully visible and 0.0 is completely invisible.
set LaserLaunchFX[ID] = "Abilities\\Weapons\\ProcMissile\\ProcMissile.mdl" //The special effect that plays at the launch coordinates.
set LaserImpactFX[ID] = "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdl" //The special effect that plays at the impact coordinates.
set LaserAreaFX[ID] = null //The special effect that plays at the imapct coordinates - useful if you want to add an AOE effect on top of an impact effect.
set NumberOfLasers[ID] = 3 //Number of lasers that get fired. CANNOT BE LOWER THATN 1.
set LaserDuration[ID] = 5 //This is the duration before the lightning effect begins to fade. 32 == 1 second. 5 == .15625 seconds.
set LaserFadeTime[ID] = 5 //This is how long it will take for the lightning effect to fade completely.
set LaserInterval[ID] = 0.075 //This is the interval, in seconds, between shots.
set LaserAOE[ID] = 0. //If greater that 0., will deal damage in an area.
set IsLaserGrounded[ID] = false //If true, all your lasers will impact the terrain, regardless of what you're attacking
set LaserLaunchOffset[ID] = 70. //This moves your launch coordinate towards or away from your target.
set LaserLaunchHeight[ID] = 45. //This raises or lowers your launch coordinate.
set LaserLaunchAngle[ID] = 0. //This pivots your launch coordinates to align with off-center weapons on your unit model, for example. USES RADIANS.
set LaserSpreadXY[ID] = 20. //This scatters your lasers' impact along the X and Y axis.
set LaserSpreadZ[ID] = 20. //This scatters your lasers' impact along the Z axis.
set LaserRangeStart[ID] = 0. //This offsets the IMPACT of your lasers by a certain amount. Leave at 0. if your lasers are not striking a symmetrical pattern.
set LaserRangePerLaser[ID] = 0. //This updates the IMPACT of consequent lasers in a set so that it can move. See the Gryphon Riders' and Gargoyls' attack.
set LaserDirectionalTilt[ID]= 0. //This pivots the beam so that it can travel in a different direction. USES RADIANS.
set FollowTarget[ID] = true //If false, consequent lasers for a set will continue along the same angle the initial beam was fired.
set LaserImpactLock[ID] = false //If true, the laser will maintain a lock on their impact location, moving along with their target.
set LaserRangeLock[ID] = false //If true, the lasers will originate relative to the attacker's location instead of the target's. Works with forwards line attacks.
set LaserAttackType[ID] = ATTACK_TYPE_PIERCE //Your attack type.
set LaserDamageType[ID] = udg_DamageTypeCode //This uses Damage Engine's Damage Type mechanic to allow you to do custom damage types, the effects of which can be triggered.
set LaserDivideDamage[ID] = true //If set to true, then the unit's damage displayed on the UI will be divide between all the lasers in a set.
set Uninterruptible[ID] = false //If false, a laser set will end prematurely if the attacker moves or dies or is ordered to stop.
set LaserHitAll[ID] = false //If true, and LaserAOE[ID] is > 0., then the area damage will apply to both ground and flying units.
set LaserFriendlyFire[ID] = false //If true, and LaserAOE[ID] is > 0., area damage attacks will affect friendly units and allies as well.
//Gryphon Rider
elseif GetUnitTypeId(Source) == 'hgry' then
//set LaserIndex[udg_UDex] = IndexAllocate()
//set ID = LaserIndex[udg_UDex]
set UsesBurstLaser[ID] = true
set LaserString[ID] = "SLSB"
set RED[ID] = 1.
set BLUE[ID] = 1.
set GREEN[ID] = 1.
set ALPHA[ID] = 1.
set LaserLaunchFX[ID] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
set LaserImpactFX[ID] = "Abilities\\Weapons\\GryphonRiderMissile\\GryphonRiderMissile.mdl"
set LaserAreaFX[ID] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
set NumberOfLasers[ID] = 8
set LaserDuration[ID] = 7
set LaserFadeTime[ID] = 5
set LaserInterval[ID] = .0624
set LaserAOE[ID] = 100.
set IsLaserGrounded[ID] = true
set LaserLaunchOffset[ID] = 80.
set LaserLaunchHeight[ID] = 80.
set LaserLaunchAngle[ID] = 0.
set LaserSpreadXY[ID] = 50.
set LaserSpreadZ[ID] = 0.
set FollowTarget[ID] = false
set LaserImpactLock[ID] = false
set LaserRangeLock[ID] = true
set LaserRangeStart[ID] = 80.
set LaserRangePerLaser[ID] = 80.
set LaserDirectionalTilt[ID]= 3.14159
set LaserAttackType[ID] = ATTACK_TYPE_PIERCE
set LaserDamageType[ID] = udg_DamageTypeCode
set LaserDivideDamage[ID] = false
set Uninterruptible[ID] = false
set LaserHitAll[ID] = false
set LaserFriendlyFire[ID] = false
//Gargoyle
elseif GetUnitTypeId(Source) == 'ugar' then
//set LaserIndex[udg_UDex] = IndexAllocate()
//set ID = LaserIndex[udg_UDex]
set UsesBurstLaser[ID] = true
set LaserString[ID] = "GRLN"
set RED[ID] = 1.
set BLUE[ID] = 1.
set GREEN[ID] = 1.
set ALPHA[ID] = 1.
set LaserLaunchFX[ID] = "Abilities\\Weapons\\KeeperGroveMissile\\KeeperGroveMissile.mdl"
set LaserImpactFX[ID] = "Abilities\\Weapons\\KeeperGroveMissile\\KeeperGroveMissile.mdl"
set LaserAreaFX[ID] = null
set NumberOfLasers[ID] = 13
set LaserDuration[ID] = 7
set LaserFadeTime[ID] = 5
set LaserInterval[ID] = 0.
set LaserAOE[ID] = 70.
set IsLaserGrounded[ID] = false
set LaserLaunchOffset[ID] = 40.
set LaserLaunchHeight[ID] = 20.
set LaserLaunchAngle[ID] = 0.
set LaserSpreadXY[ID] = 50.
set LaserSpreadZ[ID] = 50.
set FollowTarget[ID] = false
set LaserImpactLock[ID] = false
set LaserRangeLock[ID] = false
set LaserRangeStart[ID] = 0.
set LaserRangePerLaser[ID] = 35.
set LaserDirectionalTilt[ID]= 1.5708
set LaserAttackType[ID] = ATTACK_TYPE_PIERCE
set LaserDamageType[ID] = udg_DamageTypeCode
set LaserDivideDamage[ID] = false
set Uninterruptible[ID] = false
set LaserHitAll[ID] = false
set LaserFriendlyFire[ID] = false
//Spellbreaker
elseif GetUnitTypeId(Source) == 'hspt' then
//set LaserIndex[udg_UDex] = IndexAllocate()
//set ID = LaserIndex[udg_UDex]
set UsesBurstLaser[ID] = true
set LaserString[ID] = "SLSB"
set RED[ID] = 1.
set BLUE[ID] = 1.
set GREEN[ID] = 1.
set ALPHA[ID] = 1.
set LaserLaunchFX[ID] = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
set LaserImpactFX[ID] = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
set LaserAreaFX[ID] = null
set NumberOfLasers[ID] = 5
set LaserDuration[ID] = 7
set LaserFadeTime[ID] = 5
set LaserInterval[ID] = 0.1
set LaserAOE[ID] = 0.
set IsLaserGrounded[ID] = false
set LaserLaunchOffset[ID] = 0.
set LaserLaunchHeight[ID] = 0.
set LaserLaunchAngle[ID] = 0.
set LaserSpreadXY[ID] = 30.
set LaserSpreadZ[ID] = 30.
set FollowTarget[ID] = true
set LaserImpactLock[ID] = true
set LaserRangeLock[ID] = false
set LaserRangeStart[ID] = 0.
set LaserRangePerLaser[ID] = 0.
set LaserDirectionalTilt[ID]= 0.
set LaserAttackType[ID] = ATTACK_TYPE_PIERCE
set LaserDamageType[ID] = udg_DamageTypeCode
set LaserDivideDamage[ID] = true
set Uninterruptible[ID] = true
set LaserHitAll[ID] = false
set LaserFriendlyFire[ID] = false
endif
else
//set ID = LaserIndex[udg_UDex]
set UsesBurstLaser[ID] = false
set LaserString[ID] = null
set RED[ID] = 1.
set BLUE[ID] = 1.
set GREEN[ID] = 1.
set ALPHA[ID] = 1.
set LaserLaunchFX[ID] = null
set LaserImpactFX[ID] = null
set LaserAreaFX[ID] = null
set NumberOfLasers[ID] = 1
set LaserDuration[ID] = 1
set LaserFadeTime[ID] = 1
set LaserInterval[ID] = 1
set LaserAOE[ID] = 0.
set IsLaserGrounded[ID] = false
set LaserLaunchOffset[ID] = 0.
set LaserLaunchHeight[ID] = 0.
set LaserLaunchAngle[ID] = 0.
set LaserSpreadXY[ID] = 0.
set LaserSpreadZ[ID] = 0.
set FollowTarget[ID] = false
set LaserImpactLock[ID] = false
set LaserRangeLock[ID] = false
set LaserRangeStart[ID] = 0.
set LaserRangePerLaser[ID] = 0.
set LaserAttackType[ID] = null
set LaserDamageType[ID] = 0
set LaserDivideDamage[ID] = false
set Uninterruptible[ID] = false
set LaserHitAll[ID] = false
set LaserFriendlyFire[ID] = false
//call IndexDeallocate(LaserIndex[udg_UDex])
//set LaserIndex[udg_UDex] = 0
endif
set Source = null
return false
endfunction
function BurstLaser_Setup takes nothing returns nothing
call TriggerRegisterVariableEvent( BurstLaserTrigger, "udg_UnitIndexEvent", EQUAL, 1.00 )
call TriggerRegisterVariableEvent( BurstLaserTrigger, "udg_UnitIndexEvent", EQUAL, 2.00 )
call TriggerAddCondition( BurstLaserTrigger, function BurstLaser_onIndex)
endfunction
endlibrary
The main code. I'm not sure if I do have to call deallocate(this), but things seem to be overlapping and getting overwritten and timers are getting screwed up or something. It's worth noting that there are two timers running, BurstLaser_Volley and LaserFade_Timer. If the latter runs, it will always be last so the deallocation will take place then. Otherwise, if it doesn't run, the deallocation takes place the the BurstLaser_Volley method.
JASS:
library BurstLaser requires BL, GetUnitCollision, ZLibrary, TimerUtils, ArmorUtils, SpecialEffectZ
globals
private group DamageGroup = CreateGroup()
private constant real MAX_COLLISION_SIZE = 196.
private constant real COLLISION_PERCENTAGE = .8
private constant integer MAX_LASERS = 20 //Maximum number of lasers per set. Feel free to increase.
endglobals
struct BurstLaser
unit source
unit target
unit sentry
player owner
integer id
real damage
real red
real blue
real green
real alpha
real fade_amount
real fade_time
integer duration
integer count
integer fx_interval
real interval
//boolean locked_to_target
real lock_angle
real lock_distance
real lock_height
lightning laser
boolean fading
boolean grounded
boolean hit_all
boolean friendly_fire
boolean uninterruptible
real launch_offset
real launch_height
real launch_angle
real spread_xy
real spread_z
//real source_x
//real source_y
//real source_z
real launch_x
real launch_y
real launch_z
real impact_x
real impact_y
real impact_z
real impact_spread_x
real impact_spread_y
real impact_spread_z
real target_coll
real laser_angle
boolean follow_target //If false, Lasers in a set will strike the same point instead of updating their impact location to follow a moving target.
boolean impact_lock //if true then Lasers that have struck a target will follow it around until they have been destroyed.
boolean range_lock //If true will set LaserRangeStart's starting point to the attacker (source of the laser) instead of the taret
real range_start //Adds or subtracts a certain amount of distance from it's starting point.
real range_per_laser //Adds or substracts distance per Laser in a set.
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
timer tmr_laserfade
boolean failsafe_check
boolean force_end
integer laser_num
integer laser_index
//Fade Laser Timer Variables
//unit array f_source[MAX_LASERS]
//unit array f_target[MAX_LASERS]
//unit array f_sentry[MAX_LASERS]
lightning array f_laser[MAX_LASERS]
//real array f_red[MAX_LASERS]
//real array f_blue[MAX_LASERS]
//real array f_green[MAX_LASERS]
real array f_alpha[MAX_LASERS]
real array f_fade_amount[MAX_LASERS]
boolean array f_is_laser_dead[MAX_LASERS]
real array f_lock_angle[MAX_LASERS]
real array f_lock_distance[MAX_LASERS]
real array f_lock_height[MAX_LASERS]
//real array f_launch_offset[MAX_LASERS]
//real array f_launch_height[MAX_LASERS]
//real array f_launch_angle[MAX_LASERS]
real array f_impact_x[MAX_LASERS]
real array f_impact_y[MAX_LASERS]
real array f_impact_z[MAX_LASERS]
real array f_duration[MAX_LASERS]
boolean array f_fading[MAX_LASERS]
boolean array f_uninterruptible[MAX_LASERS]
static code timer_volley_handler
static code timer_laserfade_handler
static method LaserFade_Timer takes nothing returns nothing
//local timer t = GetExpiredTimer()
local thistype this = GetTimerData(GetExpiredTimer())
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 = Atan2(target_y - source_y, target_x - source_x) + this.launch_angle
local real launch_x = 0.
local real launch_y = 0.
local real launch_z = 0.
local real impact_x = 0.
local real impact_y = 0.
local real impact_z = 0.
local integer iLoop = 0
local boolean set_is_ongoing = false
loop
set iLoop = iLoop + 1
if not this.f_is_laser_dead[iLoop] then
if this.sentry == null then
set launch_x = source_x + Cos(angle) * this.launch_offset
set launch_y = source_y + Sin(angle) * this.launch_offset
set launch_z = GetUnitZ(this.source) + this.launch_height
else
set launch_x = GetUnitX(this.sentry) + Cos(angle) * this.launch_offset
set launch_y = GetUnitY(this.sentry) + Sin(angle) * this.launch_offset
set launch_z = GetUnitZ(this.sentry) + this.launch_height
endif
if this.impact_lock then
set impact_x = target_x + Cos(this.f_lock_angle[iLoop]) * this.f_lock_distance[iLoop]
set impact_y = target_y + Sin(this.f_lock_angle[iLoop]) * this.f_lock_distance[iLoop]
set impact_z = GetUnitZ(this.target) + this.f_lock_height[iLoop]
if this.f_laser[iLoop] != null then //I set this if.then.else here because I want the IMPACTS to be set for the EVENTS below.
call MoveLightningEx(this.f_laser[iLoop], true, launch_x, launch_y, launch_z, impact_x, impact_y, impact_z)
endif
else
set impact_x = this.f_impact_x[iLoop]
set impact_y = this.f_impact_y[iLoop]
set impact_z = this.f_impact_z[iLoop]
if this.f_laser[iLoop] != null then
call MoveLightningEx(this.f_laser[iLoop], true, launch_x, launch_y, launch_z, this.f_impact_x[iLoop], this.f_impact_y[iLoop], this.f_impact_z[iLoop])
endif
endif
if this.f_fading[iLoop] then
set this.f_alpha[iLoop] = this.f_alpha[iLoop] - this.fade_amount
if this.f_laser[iLoop] != null then
call SetLightningColor(this.f_laser[iLoop], this.red, this.blue, this.green, this.f_alpha[iLoop])
endif
if this.f_alpha[iLoop] <= 0. then
//EVENT
/*set BL_EVENT_Source = LaserSource[NewTimerID]
set BL_EVENT_Target = LaserTarget[NewTimerID]
set BL_EVENT_Sentry = LaserSentry[NewTimerID]
set BL_EVENT_Launch_x = LAUNCH_X
set BL_EVENT_Launch_y = LAUNCH_Y
set BL_EVENT_Launch_z = LAUNCH_Z
set BL_EVENT_Impact_x = IMPACT_X
set BL_EVENT_Impact_y = IMPACT_Y
set BL_EVENT_Impact_z = IMPACT_Z
set BL_EVENT = 2.5
set BL_EVENT_Source = null
set BL_EVENT_Target = null
set BL_EVENT_Sentry = null
set BL_EVENT_Launch_x = 0.
set BL_EVENT_Launch_y = 0.
set BL_EVENT_Launch_z = 0.
set BL_EVENT_Impact_x = 0.
set BL_EVENT_Impact_y = 0.
set BL_EVENT_Impact_z = 0.
set BL_EVENT = 0.*/
//END EVENT
set this.f_is_laser_dead[iLoop] = true
if this.f_laser[iLoop] != null then
call DestroyLightning(this.f_laser[iLoop])
set this.f_laser[iLoop] = null
endif
//call IndexDeallocate(NewTimerID)
endif
else
set this.f_duration[iLoop] = this.f_duration[iLoop] - 1
if this.f_duration[iLoop] <= 0 then
set this.f_fading[iLoop] = true
endif
endif//if this.f_fading[iLoop] then
endif//if not this.f_is_laser_dead[iLoop] then
exitwhen iLoop >= this.laser_num
endloop
set iLoop = 0
loop
set iLoop = iLoop + 1
if not this.f_is_laser_dead[iLoop] then
set set_is_ongoing = true
endif
exitwhen iLoop >= this.laser_num
endloop
if not set_is_ongoing then
call ReleaseTimer(this.tmr_laserfade)
call BJDebugMsg("fade end")
call deallocate(this)
//call this.destroy()
endif
//set t = null
endmethod
static method BurstLaser_Volley takes nothing returns nothing
//local timer t = GetExpiredTimer()
local thistype this = GetTimerData(GetExpiredTimer())
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 = Atan2(target_y - source_y, target_x - source_x) + this.launch_angle
local real launch_x = 0.
local real launch_y = 0.
local real launch_z = 0.
local real impact_x = 0.
local real impact_y = 0.
local real impact_z = 0.
local boolean b = false
local unit u = null
if this.sentry == null then
set launch_x = source_x + Cos(angle + this.launch_angle) * this.launch_offset
set launch_y = source_y + Sin(angle + this.launch_angle) * this.launch_offset
set launch_z = GetUnitZ(this.source) + this.launch_height
else
set launch_x = GetUnitX(this.sentry) + Cos(angle + this.launch_angle) * this.launch_offset
set launch_y = GetUnitY(this.sentry) + Sin(angle + this.launch_angle) * this.launch_offset
set launch_z = GetUnitZ(this.sentry) + this.launch_height
endif
if this.range_lock then //if true, start from the source's point
if this.follow_target then
set angle = Atan2(target_y - this.initial_y, target_x - this.initial_x)
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 impact_x = this.impact_x + GetRandomReal(this.spread_xy*-1, this.spread_xy)
set impact_y = this.impact_y + GetRandomReal(this.spread_xy*-1, this.spread_xy)
if this.grounded then
set this.impact_z = 0.
set impact_z = 0.
else
set this.impact_z = GetUnitZ(this.target)
set impact_z = this.impact_z + GetRandomReal(this.spread_z*-1, this.spread_z) + this.target_coll * .8
endif
else
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 impact_x = this.impact_x + GetRandomReal(this.spread_xy*-1, this.spread_xy)
set impact_y = this.impact_y + GetRandomReal(this.spread_xy*-1, this.spread_xy)
if this.grounded then
set this.impact_z = 0.
set impact_z = 0.
else
set impact_z = this.impact_z + GetRandomReal(this.spread_z*-1, this.spread_z) + this.target_coll * .8
endif
endif
else
if this.follow_target then
set angle = Atan2(target_y - this.initial_y, target_x - this.initial_x)
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 impact_x = this.impact_x + GetRandomReal(this.spread_xy*-1, this.spread_xy)
set impact_y = this.impact_y + GetRandomReal(this.spread_xy*-1, this.spread_xy)
if this.grounded then
set this.impact_z = 0.
set impact_z = 0.
else
set this.impact_z = GetUnitZ(this.target)
set impact_z = this.impact_z + GetRandomReal(this.spread_z*-1, this.spread_z) + this.target_coll * .8
endif
else
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 impact_x = this.impact_x + GetRandomReal(this.spread_xy*-1, this.spread_xy)
set impact_y = this.impact_y + GetRandomReal(this.spread_xy*-1, this.spread_xy)
if this.grounded then
set this.impact_z = 0.
set impact_z = 0.
else
set impact_z = this.impact_z + GetRandomReal(this.spread_z*-1, this.spread_z) + this.target_coll * .8
endif
endif
endif
//Launch
if this.launch_string != null then
set b = true
call DestroyEffect(AddSpecialEffectZ(this.launch_string, this.launch_x, this.launch_y, this.launch_z))
endif
//Impact
if this.impact_string != null then
set b = true
if this.grounded then
call DestroyEffect(AddSpecialEffect(this.impact_string, impact_x, impact_y))
else
call DestroyEffect(AddSpecialEffectZ(this.impact_string, impact_x, impact_y, impact_z))
endif
endif
//Area
if this.area_string != null then
set b = true
if this.grounded then
call DestroyEffect(AddSpecialEffect(this.area_string, impact_x, impact_y))
else
call DestroyEffect(AddSpecialEffectZ(this.area_string, impact_x, impact_y, impact_z))
endif
endif
//Laser
if this.laser_string != null then
set b = true
set this.f_impact_x[this.laser_index] = impact_x
set this.f_impact_y[this.laser_index] = impact_y
set this.f_impact_z[this.laser_index] = impact_z
set this.f_alpha[this.laser_index] = this.alpha
set this.f_fading[this.laser_index] = false
if this.impact_lock then
set this.f_lock_angle[this.laser_index] = Atan2(impact_y - target_y, impact_x - target_x)
set this.f_lock_distance[this.laser_index] = SquareRoot( (impact_x-target_x)*(impact_x-target_x) + (impact_y-target_y)*(impact_y-target_y) )
set this.f_lock_height[this.laser_index] = impact_z - GetUnitZ(this.target)
endif
set this.fade_amount = this.alpha / this.fade_time
set this.f_laser[this.laser_index] = AddLightningEx(this.laser_string, true, this.launch_x, this.launch_y, this.launch_z, this.impact_spread_x, this.impact_spread_y, this.impact_spread_z)
call SetLightningColor(this.f_laser[this.laser_index], this.red, this.green, this.blue, this.f_alpha[this.laser_index])
set this.laser_index = this.laser_index + 1
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
//EVENT
/*set BL_EVENT_Source = LaserSource[tID]
set BL_EVENT_Target = LaserTarget[tID]
set BL_EVENT_Sentry = LaserSentry[tID]
set BL_EVENT_Launch_x = LAUNCH_X
set BL_EVENT_Launch_y = LAUNCH_Y
set BL_EVENT_Launch_z = LAUNCH_Z
set BL_EVENT_Impact_x = IMPACT_X
set BL_EVENT_Impact_y = IMPACT_Y
set BL_EVENT_Impact_z = IMPACT_Z
set BL_EVENT = 2.
set BL_EVENT_Source = null
set BL_EVENT_Target = null
set BL_EVENT_Sentry = null
set BL_EVENT_Launch_x = 0.
set BL_EVENT_Launch_y = 0.
set BL_EVENT_Launch_z = 0.
set BL_EVENT_Impact_x = 0.
set BL_EVENT_Impact_y = 0.
set BL_EVENT_Impact_z = 0.
set BL_EVENT = 0.*/
//END EVENT
set this.count = this.count - 1
if this.count <= 0 or not UnitAlive(this.source) or ( this.uninterruptible and /*
[Move] */ (GetUnitCurrentOrder(this.source) == 851986 or /*
[Stunned] */ GetUnitCurrentOrder(this.source) == 851973 or /*
[Stop] */ GetUnitCurrentOrder(this.source) == 851972) ) then
//EVENT
/*set BL_EVENT_Source = LaserSource[tID]
set BL_EVENT_Target = LaserTarget[tID]
set BL_EVENT_Sentry = LaserSentry[tID]
set BL_EVENT_Launch_x = LAUNCH_X
set BL_EVENT_Launch_y = LAUNCH_Y
set BL_EVENT_Launch_z = LAUNCH_Z
set BL_EVENT_Impact_x = IMPACT_X
set BL_EVENT_Impact_y = IMPACT_Y
set BL_EVENT_Impact_z = IMPACT_Z
set BL_EVENT = 3.
set BL_EVENT_Source = null
set BL_EVENT_Target = null
set BL_EVENT_Sentry = null
set BL_EVENT_Launch_x = 0.
set BL_EVENT_Launch_y = 0.
set BL_EVENT_Launch_z = 0.
set BL_EVENT_Impact_x = 0.
set BL_EVENT_Impact_y = 0.
set BL_EVENT_Impact_z = 0.
set BL_EVENT = 0.*/
//END EVENT
call ReleaseTimer(this.tmr_volley)
set this.tmr_volley = null
call BJDebugMsg("volley end")
if not this.failsafe_check then
call deallocate(this)
//call this.destroy()
endif
endif
//set t = null
endmethod
static method create takes unit unit_source, unit unit_target, unit unit_sentry, integer id, real damage returns thistype
local thistype this = allocate()
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 = Atan2(target_y - source_y, target_x - source_x)
local real range_offset = 0.
local real impact_spread_x = 0.
local real impact_spread_y = 0.
local real impact_spread_z = 0.
local boolean b = false
local unit u = null
set this.owner = GetOwningPlayer(unit_source)
set this.source = unit_source
set this.target = unit_target
set this.sentry = unit_sentry
//set this.id = id
set this.damage = damage
set this.target_coll = GetUnitCollision(unit_target)
set this.laser_string = BL_LaserString[id]
set this.red = BL_RED[id]
set this.blue = BL_BLUE[id]
set this.green = BL_GREEN[id]
set this.alpha = BL_ALPHA[id]
set this.launch_string = BL_LaserLaunchFX[id]
set this.impact_string = BL_LaserImpactFX[id]
set this.area_string = BL_LaserAreaFX[id]
set this.duration = BL_LaserDuration[id]
set this.fade_time = BL_LaserFadeTime[id]
set this.interval = BL_LaserInterval[id]
set this.aoe = BL_LaserAOE[id]
set this.grounded = BL_IsLaserGrounded[id]
set this.launch_offset = BL_LaserLaunchOffset[id]
set this.launch_height = BL_LaserLaunchHeight[id]
set this.launch_angle = BL_LaserLaunchAngle[id]
set this.spread_xy = BL_LaserSpreadXY[id]
set this.spread_z = BL_LaserSpreadZ[id]
set this.follow_target = BL_FollowTarget[id]
set this.impact_lock = BL_LaserImpactLock[id]
set this.range_lock = BL_LaserRangeLock[id]
set this.range_start = BL_LaserRangeStart[id]
set this.range_per_laser = BL_LaserRangePerLaser[id]
set this.attack_type = BL_LaserAttackType[id]
set this.damage_type = BL_LaserDamageType[id]
set this.uninterruptible = BL_Uninterruptible[id]
set this.hit_all = BL_LaserHitAll[id]
set this.friendly_fire = BL_LaserFriendlyFire[id]
//there's a hard limit to how many lasers you may have per set. This is because you have to declare the size of arrays of variables in a struct
//if you want to have more that 20 lasers per set, feel free to change the value of MAX_LASERS at the top.
if BL_NumberOfLasers[id] > MAX_LASERS then
set this.laser_num = MAX_LASERS
else
set this.laser_num = BL_NumberOfLasers[id]
endif
if this.sentry == null then
if this.launch_offset > 0. then
set this.launch_x = source_x + Cos(startangle + this.launch_angle) * this.launch_offset
set this.launch_y = source_y + Sin(startangle + this.launch_angle) * this.launch_offset
else
set this.launch_x = source_x
set this.launch_y = source_y
endif
set this.launch_z = GetUnitZ(this.source) + this.launch_height
else
set sentry_x = GetUnitX(this.sentry)
set sentry_y = GetUnitY(this.sentry)
if this.launch_offset > 0. then
set this.launch_x = sentry_x + Cos(startangle + this.launch_angle) * this.launch_offset
set this.launch_y = sentry_y + Sin(startangle + this.launch_angle) * this.launch_offset
else
set this.launch_x = sentry_x
set this.launch_y = sentry_y
endif
set this.launch_z = GetUnitZ(this.sentry) + this.launch_height
endif
set range_offset = ((this.laser_num-1) * this.range_per_laser + this.range_start) * .5
if this.range_lock then //if true, start from the source's point
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 + BL_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 this.impact_spread_x = this.impact_x + GetRandomReal(this.spread_xy*-1, this.spread_xy)
set this.impact_spread_y = this.impact_y + GetRandomReal(this.spread_xy*-1, this.spread_xy)
if this.grounded then
set this.impact_z = 0.
set this.impact_spread_z = 0.
else
set this.impact_z = GetUnitZ(this.target)
set this.impact_spread_z = this.impact_z + GetRandomReal(this.spread_z*-1, this.spread_z) + this.target_coll * COLLISION_PERCENTAGE
endif
else
set startangle = startangle + BL_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 this.impact_spread_x = this.impact_x + GetRandomReal(this.spread_xy * -1, this.spread_xy)
set this.impact_spread_y = this.impact_y + GetRandomReal(this.spread_xy * -1, this.spread_xy)
if this.grounded then
set this.impact_z = 0.
set this.impact_spread_z = 0.
else
set this.impact_z = GetUnitZ(this.target)
set this.impact_spread_z = this.impact_z + GetRandomReal(this.spread_z*-1, this.spread_z) + this.target_coll * COLLISION_PERCENTAGE
endif
endif
//Launch
if this.launch_string != null then
set b = true
call DestroyEffect(AddSpecialEffectZ(this.launch_string, this.launch_x, this.launch_y, this.launch_z))
endif
//Impact
if this.impact_string != null then
set b = true
if this.grounded then
call DestroyEffect(AddSpecialEffect(this.impact_string, impact_spread_x, impact_spread_y))
else
call DestroyEffect(AddSpecialEffectZ(this.impact_string, impact_spread_x, impact_spread_y, impact_spread_z))
endif
endif
//Area
if this.area_string != null then
set b = true
if this.grounded then
call DestroyEffect(AddSpecialEffect(this.area_string, impact_spread_x, impact_spread_y))
else
call DestroyEffect(AddSpecialEffectZ(this.area_string, impact_spread_x, impact_spread_y, impact_spread_z))
endif
endif
//Laser
if this.laser_string != null then
set b = true
//set this.f_source[this.laser_index] = this.source
//set this.f_target[this.laser_index] = this.arget
//set this.f_sentry[this.laser_index] = this.entry
//set this.f_launch_offset[this.laser_index] = this.launch_offset
//set this.f_launch_height[this.laser_index] = this.launch_height
//set this.f_launch_angle[this.laser_index] = this.launch_angle
//set this.f_impact_lock[this.laser_index] = this.impact_lock
set this.f_impact_x[this.laser_index] = impact_x
set this.f_impact_y[this.laser_index] = impact_y
set this.f_impact_z[this.laser_index] = impact_z
//set this.f_red[this.laser_index] = this.red
//set this.f_blue[this.laser_index] = this.blue
//set this.f_green[this.laser_index] = this.green
set this.f_alpha[this.laser_index] = this.alpha
set this.f_fading[this.laser_index] = false
if this.impact_lock then
set this.f_lock_angle[this.laser_index] = Atan2(impact_y - target_y, impact_x - target_x)
set this.f_lock_distance[this.laser_index] = SquareRoot( (impact_x-target_x)*(impact_x-target_x) + (impact_y-target_y)*(impact_y-target_y) )
set this.f_lock_height[this.laser_index] = impact_z - GetUnitZ(this.target)
endif
set this.fade_amount = this.alpha / this.fade_time
set this.f_laser[this.laser_index] = AddLightningEx(this.laser_string, true, this.launch_x, this.launch_y, this.launch_z, this.impact_spread_x, this.impact_spread_y, this.impact_spread_z)
call SetLightningColor(this.f_laser[this.laser_index], this.red, this.green, this.blue, this.f_alpha[this.laser_index])
set this.laser_index = this.laser_index + 1
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
//Volley
if this.laser_num > 1 then
if b then
set this.failsafe_check = true
endif
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
set this.tmr_volley = NewTimerEx(this)
call TimerStart(this.tmr_volley, this.interval, true, timer_volley_handler)
endif
//Timer
if b then
set this.failsafe_check = true
set this.tmr_laserfade = NewTimerEx(this)
call TimerStart(this.tmr_laserfade, .03125, true, timer_laserfade_handler)
set b = false
endif
return this
endmethod
static method onInit takes nothing returns nothing
set timer_volley_handler = function thistype.BurstLaser_Volley
set timer_laserfade_handler = function thistype.LaserFade_Timer
endmethod
endstruct
endlibrary
The system was initially meant to be a custom attack system and this just calls a .create on the struct. Kinda splits the code in two, but allows for more stuff to be done with the system. I'm not entirely sure I'm doing this properlly, though.
JASS:
library BurstLaserOnAttackModule initializer init requires BurstLaser
globals
private BurstLaser burstlaser
private trigger BL_Module_onAttack = CreateTrigger()
endglobals
function BL_Module_onAttack_Actions takes nothing returns boolean
local real Damage = 0.
local integer Source_ID = GetUnitUserData(udg_DamageEventSource)
//local integer Laser_ID = BL_LaserIndex[Source_ID]
if BL_UsesBurstLaser[Source_ID] and udg_DamageEventType == 0 and not udg_IsDamageSpell then
set udg_DamageEventAmount = 0.
if BL_LaserDivideDamage[Source_ID] then
set Damage = GetFullDamage(udg_DamageEventPrevAmt, GetUnitArmor(udg_DamageEventTarget)) / BL_NumberOfLasers[Source_ID]
else
set Damage = GetFullDamage(udg_DamageEventPrevAmt, GetUnitArmor(udg_DamageEventTarget))
endif
//You may add new stuff here, like creating a timed LaserSentry[Source_ID] for a specific unit if you want the laser's launch to remain fixed, for example.
//Or you may make a unit fire different types of Burst Laser for ground and flying.
set burstlaser = BurstLaser.create(udg_DamageEventSource, udg_DamageEventTarget, BL_LaserSentry[Source_ID], Source_ID, Damage)
endif
return false
endfunction
//===========================================================================
function init takes nothing returns nothing
call TriggerRegisterVariableEvent( BL_Module_onAttack, "udg_DamageModifierEvent", EQUAL, 1.00 )
call TriggerAddCondition( BL_Module_onAttack, function BL_Module_onAttack_Actions )
endfunction
endlibrary