- Joined
- Jan 9, 2005
- Messages
- 2,130
There was a bug in the onIndex trigger file. I've updated the system to 3.2. Try it now.
Burst Laser v3.2 by Spellbound
Special thanks to
Aniki for introducing me to structs,
ADG for helping, big time, to understant said structs,
and IcemanBo for being very patient with debugging this system like a pro.
Burst Laser is an attempt to expand the concept of lightning attacks, giving you the ability to customise it to have multiple volleys of 'lasers' with a launch and impact effect.
While this system was initially meant to be exclusively a custom attack system, I was given the idea to make it more open to other possibilities like spells, and as such I rewrote
the whole thing to run with BurstLaser.create(), which can be used for spells. See USAGE - ADVANCED below and check Arcane Lasers for more information.
http://www.hiveworkshop.com/threads/burst-laser-v1-1.290007/
REQUIREMENTS
Okay, so this I think is the biggest problem with the system because it has a lot of requirements. The setup can be slightly daunting, but most of the fields are optional. Just
read the descriptions and it should all be smooth sailing.
For starters, this is vJASS, so WEX is your first requirement.
https://www.hiveworkshop.com/threads/sharpcraft-world-editor-extended-bundle.292127/
- ArmorUtils -------------- by Rising_Dusk http://www.wc3c.net/showthread.php?t=105849
- Logarithm ----------- by Vexorian http://www.wc3c.net/showthread.php?t=101346
- TimerUtils -------------- by Vexorian http://www.wc3c.net/showthread.php?t=101322
- GetUnitCollision -------- by Nestharus http://www.thehelper.net/threads/getunitcollision.153722/
- Table --------------- by Bribe http://www.hiveworkshop.com/threads/snippet-new-table.188084/
- DummyRecylcer ----------- by Flux http://www.hiveworkshop.com/threads/dummy-recycler-v1-25.277659/
- [opt] WorldBounds --- by Nestharus https://github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
- Damage Engine ----------- by Bribe http://www.hiveworkshop.com/threads/gui-damage-engine-v3-6-0-1.201016/
Pick ONE of the follwing two. The both do the same thing, but Unit Event has some neat added functionality that you can use, like detecting unit transformation, etc.
They are required for Damage Engine to work.
- GUI Unit Indexer -------- by Bribe http://www.hiveworkshop.com/threads/gui-unit-indexer-1-2-0-2.197329/
- GUI Unit Event ---------- by Bribe http://www.hiveworkshop.com/threads/gui-unit-event-v2-2-1-0.201641/#resource-45995
INSTALLATION
* Make sure your editor can automatically generate variables. File > Preferences, under General, tick 'Automatically create unknown variables while pasting trigger data'.
* Go to the Object Editor and under Abilities, copy the Cheat Death, Detect Spell, and GetUnitArmorLifeBonus spells. If you're using Unit Event instead of Unit Indexer,
copy the other two abilities as well. Make your life easy and set their Ids to DEa1, DEa2, lif&, UErd (Removal Detect) and UEtd (Transform Detect) respectively.
* Copy over the Requirements folder.
* Copy over the Burst Laser folder.
USAGE - BASIC
BurstLaser works by assigning weapons to units. For starters, in the Object editor, the missile art of the unit must be none and the projectile speed set to the maximum. Then,
a BurstLaser weapon must be assigned to it. This can be done on indexing, like I have in this demo map, or in any other circumstance. For example, you are making an RPG and you
wish for your hero to obtain a new weapon. He/She/It picks up a gun, and now they can attack using BurstLaser!
Before you assign a weapon, however, you must set it up for. In the BurstLaser Setup Arsenal trigger, you create weapons that have a specific number attachmed to the. This way,
when you assign a weapon, you need only referrence that number and, voila, those parameters are copied over to your unit.
The last thing to know about assigning weapons is that your unit can have multiple BurstLaser weapons. This way, you can assign multiple ones and the moment it needs to be fired,
you need only point to the weapon slot and that specific weapon will be used. Chech USUAGE - ADVANCED to see how it is done.
call BLAssignWeapon.create(the unit, the weapon slot, the arsenal number)
If you desire to have your lasers launch from something other than your attacker, you can make use of the BL_LaserSentry[Index] variable. If that value is not null, the unit
stored in that variable will act as the source of the lasers. All usual modifiers like height offset, distance offset, angle offset, launch scatter, etc apply normally. See
the Spellbreaker for an example. SentryCreate onIndex creates the sentry and Sentry Orbit makes it go around the Spellbreaker.
USAGE - ADVANCED
The trigger BL Module onAttack uses Bribe's Damage Engine' to detect when a unit has inflicted damage and then fires a BurstLaser weapon. This is done by calling:
call BurstLaser.create(unit Source, unit Target, unit Sentry [optional], integer Instance Index, integer Weapon Number, real The Damage Inflicted)
KNOWN BUGS
• call BurstLaser.create() on spell effect event eventually stops working. The more lasers fired per set, the fewer casts are allowed. When it ceases to work, all BurstLaser
weapons on that one unit stops working. I haven't the faintest idea why something so bizarre would happen at all.
EVENTS
You also have access to events through "Game - BL_EVENT becomes Equal to 1.00" or "call TriggerRegisterVariableEvent( YourTrigger, "udg_BL_EVENT", EQUAL, 1.00 )"
These variables are meant to be readonly, so DO NOT SET THEM TO ANYTHING.
When udg_BL_EVENT = 1.00 -------- A Laser set starts. This triggers on the very first Laser in a set.
When udg_BL_EVENT = 2.00 -------- Every time a laser in a set fires.
When udg_BL_EVENT = 3.00 -------- When the last Laser fires.
When udg_BL_EVENT = 4.00 -------- When the Laser set instance ends.
The values you can use following an EVENT are:
udg_BL_EVENT_Source
udg_BL_EVENT_Target
udg_BL_EVENT_Sentry
udg_BL_EVENT_Launch_x
udg_BL_EVENT_Launch_y
udg_BL_EVENT_Launch_z
udg_BL_EVENT_Impact_x
udg_BL_EVENT_Impact_y
udg_BL_EVENT_Impact_z
udg_BL_EVENT_DummyLaunch - this give you access to the launch dummy, should you want to add effects to it and such.
udg_BL_EVENT_DummyImpact - same as above
udg_BL_EVENT_DummyArea - this one is ONLY available if your impact and area scales are different. Otherwise simply refer to udg_BL_EVENT_DummyImpact
since they share the exact same co-ordinates.
udg_BL_EVENT_Damage - this is affected by LaserDivideDamage[ID]. If true, udg_BL_EVENT_Damage == your base damage / number of lasers in a set.
I assume the use of those variables are self-explanatory. Setting them to anything does nothing.
LIGHTNING EFFECTS
The lightning effect I use in this demo map are of my own making. You can download there here: https://www.hiveworkshop.com/threads/lightning-effect-pack.290740/
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
library BL
/*** If you're getting a duplicate of UnitAlive, you can delete or comment out this one ***/
native UnitAlive takes unit id returns boolean
globals
public boolean array UsesBurstLaser
public unit array LaserSentry
private constant integer MAX_WEAPONS = 3
endglobals
struct BLAssignWeapon
integer instance
boolean array Uninterruptible[MAX_WEAPONS] //If true, lasers will keep firing even if the source is stunned or dead.
boolean array IsLaserGrounded[MAX_WEAPONS] //If true, then your Lasers will always strike the ground. Invalidates LaserSpreadZ. Can be useful for AoE ground attacks.
boolean array UpdateImpactPoint[MAX_WEAPONS] //If true, the Laser will latch on to it's impact point relative to it's target. That can cause weird behaviour, use trial and error.
integer array NumberOfLasers[MAX_WEAPONS] //The number of lasers that will be shot per attack. Will default to 1 if the value it less than 1.
real array LaserDuration[MAX_WEAPONS] //How long an individual laser will last before it starts to fade. 32 == 1 second.
real array LaserFadeTime[MAX_WEAPONS] //How long it takes for each laser to fade. 32 == 1 second.
real array LaserInterval[MAX_WEAPONS] //Time between laser in seconds.
real array LaserDoT[MAX_WEAPONS] //the number of intervals that will pass before the sfx and damage are repeated PER LASER. Set to <= 0 to ignore. Useful for impact-locked lasers.
string array LaserLaunchFX[MAX_WEAPONS] //The string of the special effect that plays on the launch dummy.
string array LaserImpactFX[MAX_WEAPONS] //The string of the special effect that plays on the impact dummy.
string array LaserAreaFX[MAX_WEAPONS] //The string of the special effect that plays on the impact dummy in addition to the ImpactFX. Works better with an AOE laser.
string array LaserString[MAX_WEAPONS] //The string of lightning effect itself.
real array LaserAOE[MAX_WEAPONS] //If greater that 0. will deal damage in an area around the impact.
real array LaserLaunchOffset[MAX_WEAPONS] //How far forward with the Launch effect be. Use negative values to move backwards.
real array LaserLaunchHeight[MAX_WEAPONS] //Adjusts the Launch effect along the Z axis. Positive value go up, negative values go down.
real array LaserLaunchAngle[MAX_WEAPONS] //By how many radians will the Launch effect be offset by? Positive values adjust the angle counter-clockwise.
real array LaserLaunchScatterX[MAX_WEAPONS] //How much your laser's launch will scatter along the X axis.
real array LaserLaunchScatterY[MAX_WEAPONS] //How much your laser's launch will scatter along the Y axis.
real array LaserLaunchScatterZ[MAX_WEAPONS] //How much your laser's launch will scatter along the Z axis.
real array LaserLaunchScale[MAX_WEAPONS] //The size of your launch special effects. 1. is 100%.
real array LaserImpactScatterX[MAX_WEAPONS] //How much your laser will spread out along the X axis.
real array LaserImpactScatterY[MAX_WEAPONS] //How much your laser will spread out along the Y axis.
real array LaserImpactScatterZ[MAX_WEAPONS] //How much your laser will spread out along the Z axis.
real array LaserImpactScale[MAX_WEAPONS] //The size of your impact special effects. 1. is 100%.
real array LaserAreaScale[MAX_WEAPONS] //Setting this value different from LaserImpactScale will mean a new dummy will have to be created.
//Unless really necessary, it's recommended to keep this the same value as LaserImpactScale.
boolean array LaserDivideDamage[MAX_WEAPONS] //If true, the total damage will be divided amoung the number of lasers.
boolean array UpdateTargetLoc[MAX_WEAPONS] //If false, Lasers in a set will strike the same point instead of updating their impact location to follow a moving target.
boolean array UpdateSourceLoc[MAX_WEAPONS] //If false, consequence shots in a volley will launch from the initial point
boolean array UpdateLaunchPoint[MAX_WEAPONS] //If true, lasers will follow source if it moves away.
boolean array LaunchFromTargetLoc[MAX_WEAPONS] //If true, then launch point will be relative to the target rather than the source. Sentries take priority, however.
boolean array FixedImpactLoc[MAX_WEAPONS] //If true will set LaserRangeStart's starting point to the attacker (source of the laser) instead of the target
real array LaserRangeStart[MAX_WEAPONS] //Adds or subtracts a certain amount of distance from it's starting point.
real array LaserRangePerLaser[MAX_WEAPONS] //Adds or substracts distance per Laser in a set.
real array LaserDirectionalTilt[MAX_WEAPONS] //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.
attacktype array LaserAttackType[MAX_WEAPONS] //Vanilla attack type like ATTACK_TYPE_HERO, ATTACK_TYPE_PIERCE, etc
integer array LaserDamageType[MAX_WEAPONS] //The damage type from Damage Engine
boolean array LaserHitAll[MAX_WEAPONS] //The laser will harm all units in the LaserAOE. If LaserAOE is <= 0. this does nothing.
boolean array LaserFriendlyFire[MAX_WEAPONS] //AOE damage will damage allies
unit array LaserSentry[MAX_WEAPONS] //This is optional. If something is set as the Sentry, the lasers will shoot from that unit instead.
real array RED[MAX_WEAPONS] //Red tint of the Laser. 1. is 100%, and 0. is 0%.
real array BLUE[MAX_WEAPONS] //Blue tint of the Laser. 1. is 100%, and 0. is 0%.
real array GREEN[MAX_WEAPONS] //Green tint of the Laser. 1. is 100%, and 0. is 0%.
real array ALPHA[MAX_WEAPONS] //Transparency of the Laser. 1. fully visible. 0. is completely transparent.
boolean array ReduceLaunchOverhead[MAX_WEAPONS] //If true, only 1 dummy will be used for your launch special effect, but if the launch scatters per volley, the
//special effects may jump around since they're bound to only one unit. Some special effects don't have that
//problem, so it's preferrable to test lasers with this set to true first, as the alternative means a new dummy
//per laser per launch, which creates a lot of overhead.
boolean array ReduceImpactOverhead[MAX_WEAPONS] //Same as above, but for impacts and area special effects.
method destroy takes nothing returns nothing
local integer iLoop = 0
loop
exitwhen iLoop > MAX_WEAPONS
set this.LaserString[iLoop] = null
set this.RED[iLoop] = 1.
set this.BLUE[iLoop] = 1.
set this.GREEN[iLoop] = 1.
set this.ALPHA[iLoop] = 1.
set this.LaserLaunchFX[iLoop] = null
set this.LaserImpactFX[iLoop] = null
set this.LaserAreaFX[iLoop] = null
set this.LaserLaunchScale[iLoop] = 1.
set this.LaserImpactScale[iLoop] = 1.
set this.LaserAreaScale[iLoop] = 1.
set this.NumberOfLasers[iLoop] = 1
set this.LaserDuration[iLoop] = 0.
set this.LaserFadeTime[iLoop] = 0.
set this.LaserInterval[iLoop] = 0.
set this.LaserDoT[iLoop] = 0.
set this.LaserAOE[iLoop] = 0.
set this.IsLaserGrounded[iLoop] = false
set this.LaserLaunchOffset[iLoop] = 0.
set this.LaserLaunchHeight[iLoop] = 0.
set this.LaserLaunchAngle[iLoop] = 0.
set this.LaserLaunchScatterX[iLoop] = 0.
set this.LaserLaunchScatterY[iLoop] = 0.
set this.LaserLaunchScatterZ[iLoop] = 0.
set this.LaserImpactScatterX[iLoop] = 0.
set this.LaserImpactScatterY[iLoop] = 0.
set this.LaserImpactScatterZ[iLoop] = 0.
set this.UpdateTargetLoc[iLoop] = false
set this.UpdateLaunchPoint[iLoop] = false
set this.UpdateImpactPoint[iLoop] = false
set this.LaunchFromTargetLoc[iLoop] = false
set this.UpdateSourceLoc[iLoop] = false
set this.FixedImpactLoc[iLoop] = false
set this.LaserRangeStart[iLoop] = 0.
set this.LaserRangePerLaser[iLoop] = 0.
set this.LaserDirectionalTilt[iLoop] = 0.
set this.LaserAttackType[iLoop] = null
set this.LaserDamageType[iLoop] = 0
set this.LaserDivideDamage[iLoop] = false
set this.Uninterruptible[iLoop] = false
set this.LaserHitAll[iLoop] = false
set this.LaserFriendlyFire[iLoop] = false
set this.ReduceLaunchOverhead[iLoop] = true
set this.ReduceImpactOverhead[iLoop] = true
set iLoop = iLoop + 1
endloop
call this.deallocate()
endmethod
static method operator [] takes unit u returns thistype
return thistype(GetUnitUserData(u)).instance
endmethod
static method create takes unit u, integer wpn_num, integer arsenal_num returns thistype
local integer id = GetUnitUserData(u)
local thistype this
if thistype(id).instance == 0 then
set this = allocate()
set thistype(id).instance = this
set UsesBurstLaser[id] = true
else
set this = thistype(id).instance
endif
if BL_NumberOfLasers[arsenal_num] > 0 then
set this.NumberOfLasers[wpn_num] = BL_NumberOfLasers[arsenal_num]
else
set this.NumberOfLasers[wpn_num] = 1
endif
set this.LaserString[wpn_num] = BL_LaserString[arsenal_num]
set this.RED[wpn_num] = BL_RED[arsenal_num]
set this.BLUE[wpn_num] = BL_BLUE[arsenal_num]
set this.GREEN[wpn_num] = BL_GREEN[arsenal_num]
set this.ALPHA[wpn_num] = BL_ALPHA[arsenal_num]
set this.LaserLaunchFX[wpn_num] = BL_LaserLaunchFX[arsenal_num]
set this.LaserImpactFX[wpn_num] = BL_LaserImpactFX[arsenal_num]
set this.LaserAreaFX[wpn_num] = BL_LaserAreaFX[arsenal_num]
set this.LaserLaunchScale[wpn_num] = BL_LaserLaunchScale[arsenal_num]
set this.LaserImpactScale[wpn_num] = BL_LaserImpactScale[arsenal_num]
set this.LaserAreaScale[wpn_num] = BL_LaserAreaScale[arsenal_num]
set this.LaserDuration[wpn_num] = BL_LaserDuration[arsenal_num]
set this.LaserFadeTime[wpn_num] = BL_LaserFadeTime[arsenal_num]
set this.LaserInterval[wpn_num] = BL_LaserInterval[arsenal_num]
set this.LaserDoT[wpn_num] = BL_LaserDoT[arsenal_num]
set this.LaserAOE[wpn_num] = BL_LaserAOE[arsenal_num]
set this.IsLaserGrounded[wpn_num] = BL_IsLaserGrounded[arsenal_num]
set this.LaserLaunchOffset[wpn_num] = BL_LaserLaunchOffset[arsenal_num]
set this.LaserLaunchHeight[wpn_num] = BL_LaserLaunchHeight[arsenal_num]
set this.LaserLaunchAngle[wpn_num] = BL_LaserLaunchAngle[arsenal_num]
set this.LaserLaunchScatterX[wpn_num] = BL_LaserLaunchScatterX[arsenal_num]
set this.LaserLaunchScatterY[wpn_num] = BL_LaserLaunchScatterY[arsenal_num]
set this.LaserLaunchScatterZ[wpn_num] = BL_LaserLaunchScatterZ[arsenal_num]
set this.LaserImpactScatterX[wpn_num] = BL_LaserImpactScatterX[arsenal_num]
set this.LaserImpactScatterY[wpn_num] = BL_LaserImpactScatterY[arsenal_num]
set this.LaserImpactScatterZ[wpn_num] = BL_LaserImpactScatterZ[arsenal_num]
set this.UpdateTargetLoc[wpn_num] = BL_UpdateTargetLoc[arsenal_num]
set this.UpdateSourceLoc[wpn_num] = BL_UpdateSourceLoc[arsenal_num]
set this.UpdateLaunchPoint[wpn_num] = BL_UpdateLaunchPoint[arsenal_num]
set this.UpdateImpactPoint[wpn_num] = BL_UpdateImpactPoint[arsenal_num]
set this.LaunchFromTargetLoc[wpn_num] = BL_LaunchFromTargetLoc[arsenal_num]
set this.FixedImpactLoc[wpn_num] = BL_FixedImpactLoc[arsenal_num]
set this.LaserRangeStart[wpn_num] = BL_LaserRangeStart[arsenal_num]
set this.LaserRangePerLaser[wpn_num] = BL_LaserRangePerLaser[arsenal_num]
set this.LaserDirectionalTilt[wpn_num] = BL_LaserDirectionalTilt[arsenal_num]
set this.LaserAttackType[wpn_num] = BL_LaserAttackType[arsenal_num]
set this.LaserDamageType[wpn_num] = BL_LaserDamageType[arsenal_num]
set this.LaserDivideDamage[wpn_num] = BL_LaserDivideDamage[arsenal_num]
set this.Uninterruptible[wpn_num] = BL_Uninterruptible[arsenal_num]
set this.LaserHitAll[wpn_num] = BL_LaserHitAll[arsenal_num]
set this.LaserFriendlyFire[wpn_num] = BL_LaserFriendlyFire[arsenal_num]
set this.ReduceLaunchOverhead[wpn_num] = BL_ReduceLaunchOverhead[arsenal_num]
set this.ReduceImpactOverhead[wpn_num] = BL_ReduceImpactOverhead[arsenal_num]
return this
endmethod
endstruct
//Weapon Setup variables
globals
string array BL_LaserString
real array BL_RED
real array BL_BLUE
real array BL_GREEN
real array BL_ALPHA
string array BL_LaserLaunchFX
string array BL_LaserImpactFX
string array BL_LaserAreaFX
real array BL_LaserLaunchScale
real array BL_LaserImpactScale
real array BL_LaserAreaScale
integer array BL_NumberOfLasers
real array BL_LaserDuration
real array BL_LaserFadeTime
real array BL_LaserInterval
real array BL_LaserDoT
real array BL_LaserAOE
boolean array BL_IsLaserGrounded
real array BL_LaserLaunchOffset
real array BL_LaserLaunchHeight
real array BL_LaserLaunchAngle
real array BL_LaserLaunchScatterX
real array BL_LaserLaunchScatterY
real array BL_LaserLaunchScatterZ
real array BL_LaserImpactScatterX
real array BL_LaserImpactScatterY
real array BL_LaserImpactScatterZ
boolean array BL_UpdateTargetLoc
boolean array BL_UpdateSourceLoc
boolean array BL_UpdateLaunchPoint
boolean array BL_UpdateImpactPoint
boolean array BL_LaunchFromTargetLoc
boolean array BL_FixedImpactLoc
real array BL_LaserRangeStart
real array BL_LaserRangePerLaser
real array BL_LaserDirectionalTilt
attacktype array BL_LaserAttackType
integer array BL_LaserDamageType
boolean array BL_LaserDivideDamage
boolean array BL_Uninterruptible
boolean array BL_LaserHitAll
boolean array BL_LaserFriendlyFire
boolean array BL_ReduceLaunchOverhead
boolean array BL_ReduceImpactOverhead
endglobals
endlibrary
library BurstLaserOnAttackModule initializer init requires BurstLaser
globals
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 Weapon_Index = 1
local BLAssignWeapon blwpn
//local integer Struct_ID = BLAssignWeapon[udg_DamageEventSource]
if BL_UsesBurstLaser[Source_ID] and udg_DamageEventType == 0 and not udg_IsDamageSpell then
set udg_DamageEventAmount = 0.
//If you want to have temporary sentries, you may create them here and apply an expiration timer to them. Used mostly for very conplex launch effects.
//Here you can change the Weapon_Index to a different value to switch the laser weapon used. For example, the Gryphon Rider has 2 laser weapons, and
//Weapon_Index 2 is used against air units. Otherwise, the defaul index is 1.
if GetUnitTypeId(udg_DamageEventSource) == 'hgry' then
if IsUnitType(udg_DamageEventTarget, UNIT_TYPE_FLYING) then
set Weapon_Index = 2
endif
endif
//Here we check if the damage will be split per laser in a set or not.
set blwpn = BLAssignWeapon[udg_DamageEventSource]
if blwpn.LaserDivideDamage[Weapon_Index] then
set Damage = GetFullDamage(udg_DamageEventPrevAmt, GetUnitArmor(udg_DamageEventTarget)) / blwpn.NumberOfLasers[Weapon_Index]
else
set Damage = GetFullDamage(udg_DamageEventPrevAmt, GetUnitArmor(udg_DamageEventTarget))
endif
call BurstLaser.create(udg_DamageEventSource, udg_DamageEventTarget, BL_LaserSentry[Source_ID], blwpn, Weapon_Index, 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