Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
BL_EVENT | real | No | |
BL_EVENT_Damage | real | No | |
BL_EVENT_Dummy_Area | unit | No | |
BL_EVENT_Dummy_Impact | unit | No | |
BL_EVENT_Dummy_Launch | unit | No | |
BL_EVENT_Impact_x | real | No | |
BL_EVENT_Impact_y | real | No | |
BL_EVENT_Impact_z | real | No | |
BL_EVENT_Launch_x | real | No | |
BL_EVENT_Launch_y | real | No | |
BL_EVENT_Launch_z | real | No | |
BL_EVENT_Sentry | unit | No | |
BL_EVENT_Source | unit | No | |
BL_EVENT_Target | unit | No | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
ClearDamageEvent | trigger | No | |
DAMAGE_FACTOR_BRACERS | real | No | |
DAMAGE_FACTOR_ELUNES | real | No | |
DAMAGE_FACTOR_ETHEREAL | real | No | |
DamageBlockingAbility | abilcode | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventsWasted | integer | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageModifierEvent | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypeHealFriendly | integer | No | |
DamageTypeReduced | integer | No | |
DamageTypeSlow | integer | No | |
DamageTypeSpell | integer | No | |
DeathEvent | real | No | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
DmgEvBracers | itemcode | No | |
DmgEvRecursionN | integer | No | |
DmgEvRunning | boolean | No | |
DmgEvStarted | boolean | No | |
DmgEvTimer | timer | No | |
DmgEvTrig | trigger | No | |
HideDamageFrom | boolean | Yes | |
IsDamageSpell | boolean | No | |
IsUnitAlive | boolean | Yes | |
IsUnitBeingUnloaded | boolean | Yes | |
IsUnitNew | boolean | Yes | |
IsUnitPreplaced | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
IsUnitRemoved | boolean | Yes | |
IsUnitTransforming | boolean | Yes | |
KillerOfUnit | unit | Yes | |
LastDamageHP | real | No | |
LastDmgPrevAmount | real | Yes | |
LastDmgPrevType | integer | Yes | |
LastDmgSource | unit | Yes | |
LastDmgTarget | unit | Yes | |
LastDmgValue | real | Yes | |
LastDmgWasSpell | boolean | Yes | |
NextDamageOverride | boolean | No | |
NextDamageType | integer | No | |
SpellDamageAbility | abilcode | No | |
SummonerOfUnit | unit | Yes | |
UDex | integer | No | |
UDexLastRecycled | integer | No | |
UDexMax | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexUnits | unit | Yes | |
UnitDamageRegistered | boolean | Yes | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
WorldMaxX | real | No | |
WorldMaxY | real | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
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 BLSetupArsenal initializer init requires BL
private function setupArsenal takes nothing returns boolean
local integer LASER_ID
//Rifleman
set LASER_ID = 1
set BL_LaserString[LASER_ID] = "YENL"
set BL_RED[LASER_ID] = 1.
set BL_BLUE[LASER_ID] = 1.
set BL_GREEN[LASER_ID] = 1.
set BL_ALPHA[LASER_ID] = .5
set BL_LaserLaunchFX[LASER_ID] = "war3mapImported\\FaerieDragonMissile_Lesser_NoMS.mdx"
set BL_LaserImpactFX[LASER_ID] = "war3mapImported\\FaerieDragonMissile_Lesser_NoMS.mdx"
set BL_LaserAreaFX[LASER_ID] = null
set BL_LaserLaunchScale[LASER_ID] = 1.
set BL_LaserImpactScale[LASER_ID] = 1.
set BL_LaserAreaScale[LASER_ID] = 1.
set BL_NumberOfLasers[LASER_ID] = 3
set BL_LaserDuration[LASER_ID] = .3
set BL_LaserFadeTime[LASER_ID] = .15
set BL_LaserInterval[LASER_ID] = 0.075
set BL_LaserDoT[LASER_ID] = 0.
set BL_LaserAOE[LASER_ID] = 0.
set BL_IsLaserGrounded[LASER_ID] = false
set BL_LaserLaunchOffset[LASER_ID] = 70.
set BL_LaserLaunchHeight[LASER_ID] = 45.
set BL_LaserLaunchAngle[LASER_ID] = 0.
set BL_LaserLaunchScatterX[LASER_ID] = 0.
set BL_LaserLaunchScatterY[LASER_ID] = 0.
set BL_LaserLaunchScatterZ[LASER_ID] = 0.
set BL_LaserImpactScatterX[LASER_ID] = 20.
set BL_LaserImpactScatterY[LASER_ID] = 20.
set BL_LaserImpactScatterZ[LASER_ID] = 20.
set BL_UpdateSourceLoc[LASER_ID] = false
set BL_UpdateTargetLoc[LASER_ID] = true
set BL_UpdateLaunchPoint[LASER_ID] = false
set BL_UpdateImpactPoint[LASER_ID] = false
set BL_LaunchFromTargetLoc[LASER_ID] = false
set BL_FixedImpactLoc[LASER_ID] = false
set BL_LaserRangeStart[LASER_ID] = 0.
set BL_LaserRangePerLaser[LASER_ID] = 0.
set BL_LaserDirectionalTilt[LASER_ID] = 0.
set BL_LaserAttackType[LASER_ID] = ATTACK_TYPE_PIERCE
set BL_LaserDamageType[LASER_ID] = udg_DamageTypeCode
set BL_LaserDivideDamage[LASER_ID] = true
set BL_Uninterruptible[LASER_ID] = false
set BL_LaserHitAll[LASER_ID] = false
set BL_LaserFriendlyFire[LASER_ID] = false
set BL_ReduceLaunchOverhead[LASER_ID] = true
set BL_ReduceImpactOverhead[LASER_ID] = true
//Gryphon Rider
/*
This example shows how you can make lasers strike in a line. It's worth noting that this
method is extremely heavy in performance because:
A) It has 8 lasers per set, but the reason this is a problem, per se, is that
ReduceImpactOverhead is false, which means it will create an impact dummy PER laser.
B) The LaserImpactScale and LaserAreaScale both have effects and are of different values,
which means that instead of tacking on the Area special effects onto the the Impact
dummies, it will create its own Area dummies. So already that's 16 dummes + 1 for
launch for ONE gruphon rider. It's excessive, and should only be reserved for
something like boss battles.
*/
set LASER_ID = 2 //Line Attack Lightning
set BL_LaserString[LASER_ID] = "BLNL"
set BL_RED[LASER_ID] = 1.
set BL_BLUE[LASER_ID] = 1.
set BL_GREEN[LASER_ID] = 1.
set BL_ALPHA[LASER_ID] = .5
set BL_LaserLaunchFX[LASER_ID] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
set BL_LaserImpactFX[LASER_ID] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
set BL_LaserAreaFX[LASER_ID] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
set BL_LaserLaunchScale[LASER_ID] = 1.
set BL_LaserImpactScale[LASER_ID] = 1.75
set BL_LaserAreaScale[LASER_ID] = 1.5
set BL_NumberOfLasers[LASER_ID] = 8
set BL_LaserDuration[LASER_ID] = .35
set BL_LaserFadeTime[LASER_ID] = .07
set BL_LaserInterval[LASER_ID] = 0.0624
set BL_LaserDoT[LASER_ID] = 0.
set BL_LaserAOE[LASER_ID] = 100.
set BL_IsLaserGrounded[LASER_ID] = true
set BL_LaserLaunchOffset[LASER_ID] = 80.
set BL_LaserLaunchHeight[LASER_ID] = 80.
set BL_LaserLaunchAngle[LASER_ID] = 0.
set BL_LaserLaunchScatterX[LASER_ID] = 0.
set BL_LaserLaunchScatterY[LASER_ID] = 0.
set BL_LaserLaunchScatterZ[LASER_ID] = 0.
set BL_LaserImpactScatterX[LASER_ID] = 50.
set BL_LaserImpactScatterY[LASER_ID] = 50.
set BL_LaserImpactScatterZ[LASER_ID] = 0.
set BL_UpdateSourceLoc[LASER_ID] = false
set BL_UpdateTargetLoc[LASER_ID] = false
set BL_UpdateLaunchPoint[LASER_ID] = false
set BL_UpdateImpactPoint[LASER_ID] = false
set BL_LaunchFromTargetLoc[LASER_ID] = false
set BL_FixedImpactLoc[LASER_ID] = true
set BL_LaserRangeStart[LASER_ID] = 80.
set BL_LaserRangePerLaser[LASER_ID] = 80.
set BL_LaserDirectionalTilt[LASER_ID] = 3.14159
set BL_LaserAttackType[LASER_ID] = ATTACK_TYPE_PIERCE
set BL_LaserDamageType[LASER_ID] = udg_DamageTypeCode
set BL_LaserDivideDamage[LASER_ID] = false
set BL_Uninterruptible[LASER_ID] = true
set BL_LaserHitAll[LASER_ID] = false
set BL_LaserFriendlyFire[LASER_ID] = false
set BL_ReduceLaunchOverhead[LASER_ID] = true
set BL_ReduceImpactOverhead[LASER_ID] = false
/*
This here is the Gryphon's secondary laser weapon, used exclusively versus flying units.
To switch between the two, simply refer to the LASER_ID that's used for that particular
weapon. In this case, the integer is 2.
*/
set LASER_ID = 3 //Skythunder
set BL_LaserString[LASER_ID] = "BLNL"
set BL_RED[LASER_ID] = 1.
set BL_BLUE[LASER_ID] = 1.
set BL_GREEN[LASER_ID] = 1.
set BL_ALPHA[LASER_ID] = 1.
set BL_LaserLaunchFX[LASER_ID] = null
set BL_LaserImpactFX[LASER_ID] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
set BL_LaserAreaFX[LASER_ID] = "war3mapImported\\Arcane Nova.mdx"
set BL_LaserLaunchScale[LASER_ID] = 1.
set BL_LaserImpactScale[LASER_ID] = 1.
set BL_LaserAreaScale[LASER_ID] = 1.
set BL_NumberOfLasers[LASER_ID] = 1
set BL_LaserDuration[LASER_ID] = .4
set BL_LaserFadeTime[LASER_ID] = .15
set BL_LaserInterval[LASER_ID] = 0.1
set BL_LaserDoT[LASER_ID] = 0.
set BL_LaserAOE[LASER_ID] = 250.
set BL_IsLaserGrounded[LASER_ID] = false
set BL_LaserLaunchOffset[LASER_ID] = 0.
set BL_LaserLaunchHeight[LASER_ID] = 1000.
set BL_LaserLaunchAngle[LASER_ID] = 0.
set BL_LaserLaunchScatterX[LASER_ID] = 0.
set BL_LaserLaunchScatterY[LASER_ID] = 0.
set BL_LaserLaunchScatterZ[LASER_ID] = 0.
set BL_LaserImpactScatterX[LASER_ID] = 0.
set BL_LaserImpactScatterY[LASER_ID] = 0.
set BL_LaserImpactScatterZ[LASER_ID] = 0.
set BL_UpdateSourceLoc[LASER_ID] = false
set BL_UpdateTargetLoc[LASER_ID] = true
set BL_UpdateLaunchPoint[LASER_ID] = false
set BL_UpdateImpactPoint[LASER_ID] = true
set BL_LaunchFromTargetLoc[LASER_ID] = true
set BL_FixedImpactLoc[LASER_ID] = true
set BL_LaserRangeStart[LASER_ID] = 0.
set BL_LaserRangePerLaser[LASER_ID] = .001
set BL_LaserDirectionalTilt[LASER_ID] = 0.
set BL_LaserAttackType[LASER_ID] = ATTACK_TYPE_PIERCE
set BL_LaserDamageType[LASER_ID] = udg_DamageTypeCode
set BL_LaserDivideDamage[LASER_ID] = false
set BL_Uninterruptible[LASER_ID] = false
set BL_LaserHitAll[LASER_ID] = false
set BL_LaserFriendlyFire[LASER_ID] = false
set BL_ReduceLaunchOverhead[LASER_ID] = true
set BL_ReduceImpactOverhead[LASER_ID] = true
//Gargoyle
/*
This is a variation on the gryphon's line attack, but strikes in a perpendicular line
instead, similar to the Colossus from Starcraft II. This is achieved by setting
LaserDirectionalTilt to 1.5708 radians (90°). Note that all lasers fire simultaneously
because LaserInterval is set to 0.
*/
set LASER_ID = 4
set BL_LaserString[LASER_ID] = "GRNL"
set BL_RED[LASER_ID] = 1.
set BL_BLUE[LASER_ID] = 1.
set BL_GREEN[LASER_ID] = 1.
set BL_ALPHA[LASER_ID] = 1.
set BL_LaserLaunchFX[LASER_ID] = "Abilities\\Weapons\\KeeperGroveMissile\\KeeperGroveMissile.mdl"
set BL_LaserImpactFX[LASER_ID] = "Abilities\\Weapons\\KeeperGroveMissile\\KeeperGroveMissile.mdl"
set BL_LaserAreaFX[LASER_ID] = null
set BL_LaserLaunchScale[LASER_ID] = 1.
set BL_LaserImpactScale[LASER_ID] = 1.
set BL_LaserAreaScale[LASER_ID] = 1.
set BL_NumberOfLasers[LASER_ID] = 13
set BL_LaserDuration[LASER_ID] = .3
set BL_LaserFadeTime[LASER_ID] = .1
set BL_LaserInterval[LASER_ID] = 0.
set BL_LaserDoT[LASER_ID] = 0.
set BL_LaserAOE[LASER_ID] = 70.
set BL_IsLaserGrounded[LASER_ID] = false
set BL_LaserLaunchOffset[LASER_ID] = 40.
set BL_LaserLaunchHeight[LASER_ID] = 20.
set BL_LaserLaunchAngle[LASER_ID] = 0.
set BL_LaserLaunchScatterX[LASER_ID] = 0.
set BL_LaserLaunchScatterY[LASER_ID] = 0.
set BL_LaserLaunchScatterZ[LASER_ID] = 0.
set BL_LaserImpactScatterX[LASER_ID] = 50.
set BL_LaserImpactScatterY[LASER_ID] = 50.
set BL_LaserImpactScatterZ[LASER_ID] = 50.
set BL_UpdateSourceLoc[LASER_ID] = false
set BL_UpdateTargetLoc[LASER_ID] = false
set BL_UpdateLaunchPoint[LASER_ID] = false
set BL_UpdateImpactPoint[LASER_ID] = false
set BL_LaunchFromTargetLoc[LASER_ID] = false
set BL_FixedImpactLoc[LASER_ID] = false
set BL_LaserRangeStart[LASER_ID] = 0.
set BL_LaserRangePerLaser[LASER_ID] = 35.
set BL_LaserDirectionalTilt[LASER_ID] = 1.5708
set BL_LaserAttackType[LASER_ID] = ATTACK_TYPE_PIERCE
set BL_LaserDamageType[LASER_ID] = udg_DamageTypeCode
set BL_LaserDivideDamage[LASER_ID] = false
set BL_Uninterruptible[LASER_ID] = false
set BL_LaserHitAll[LASER_ID] = false
set BL_LaserFriendlyFire[LASER_ID] = false
set BL_ReduceLaunchOverhead[LASER_ID] = true
set BL_ReduceImpactOverhead[LASER_ID] = false
//Spellbreaker
/*
While not visible in this trigger, it's possible to bind a Sentry to a unit, causing the
lasers to fire from that dummy unit instead. Refer to SentryCreate onIndex and SentryOrbit.
Essentially, LaserSentry[id] must be set to a unit for this to work.
*/
set LASER_ID = 5
set BL_LaserString[LASER_ID] = "BLSB"
set BL_RED[LASER_ID] = 1.
set BL_BLUE[LASER_ID] = 1.
set BL_GREEN[LASER_ID] = 1.
set BL_ALPHA[LASER_ID] = 1.
set BL_LaserLaunchFX[LASER_ID] = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
set BL_LaserImpactFX[LASER_ID] = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
set BL_LaserAreaFX[LASER_ID] = null
set BL_LaserLaunchScale[LASER_ID] = 1.
set BL_LaserImpactScale[LASER_ID] = 1.
set BL_LaserAreaScale[LASER_ID] = 1.
set BL_NumberOfLasers[LASER_ID] = 5
set BL_LaserDuration[LASER_ID] = .5
set BL_LaserFadeTime[LASER_ID] = .15
set BL_LaserInterval[LASER_ID] = .1
set BL_LaserDoT[LASER_ID] = 0.
set BL_LaserAOE[LASER_ID] = 0.
set BL_IsLaserGrounded[LASER_ID] = false
set BL_LaserLaunchOffset[LASER_ID] = 0.
set BL_LaserLaunchHeight[LASER_ID] = 0.
set BL_LaserLaunchAngle[LASER_ID] = 0.
set BL_LaserLaunchScatterX[LASER_ID] = 0.
set BL_LaserLaunchScatterY[LASER_ID] = 0.
set BL_LaserLaunchScatterZ[LASER_ID] = 0.
set BL_LaserImpactScatterX[LASER_ID] = 30.
set BL_LaserImpactScatterY[LASER_ID] = 30.
set BL_LaserImpactScatterZ[LASER_ID] = 30.
set BL_UpdateSourceLoc[LASER_ID] = true
set BL_UpdateTargetLoc[LASER_ID] = true
set BL_UpdateLaunchPoint[LASER_ID] = true
set BL_UpdateImpactPoint[LASER_ID] = true
set BL_LaunchFromTargetLoc[LASER_ID] = false
set BL_FixedImpactLoc[LASER_ID] = false
set BL_LaserRangeStart[LASER_ID] = 0.
set BL_LaserRangePerLaser[LASER_ID] = 0.
set BL_LaserDirectionalTilt[LASER_ID] = 0.
set BL_LaserAttackType[LASER_ID] = ATTACK_TYPE_PIERCE
set BL_LaserDamageType[LASER_ID] = udg_DamageTypeCode
set BL_LaserDivideDamage[LASER_ID] = true
set BL_Uninterruptible[LASER_ID] = true
set BL_LaserHitAll[LASER_ID] = false
set BL_LaserFriendlyFire[LASER_ID] = false
set BL_ReduceLaunchOverhead[LASER_ID] = true
set BL_ReduceImpactOverhead[LASER_ID] = true
//Archmage
/*
The Archmage is an example of scattering your launch coordinates.
*/
set LASER_ID = 6
set BL_LaserString[LASER_ID] = "MYNL"
set BL_RED[LASER_ID] = 1.
set BL_BLUE[LASER_ID] = 1.
set BL_GREEN[LASER_ID] = 1.
set BL_ALPHA[LASER_ID] = 1.
set BL_LaserLaunchFX[LASER_ID] = "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
set BL_LaserImpactFX[LASER_ID] = "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
set BL_LaserAreaFX[LASER_ID] = null
set BL_LaserLaunchScale[LASER_ID] = 1.
set BL_LaserImpactScale[LASER_ID] = 1.
set BL_LaserAreaScale[LASER_ID] = 1.
set BL_NumberOfLasers[LASER_ID] = 4
set BL_LaserDuration[LASER_ID] = .8
set BL_LaserFadeTime[LASER_ID] = .4
set BL_LaserInterval[LASER_ID] = .175
set BL_LaserDoT[LASER_ID] = .1
set BL_LaserAOE[LASER_ID] = 0.
set BL_IsLaserGrounded[LASER_ID] = false
set BL_LaserLaunchOffset[LASER_ID] = 0.
set BL_LaserLaunchHeight[LASER_ID] = 180.
set BL_LaserLaunchAngle[LASER_ID] = 0.
set BL_LaserLaunchScatterX[LASER_ID] = 90.
set BL_LaserLaunchScatterY[LASER_ID] = 90.
set BL_LaserLaunchScatterZ[LASER_ID] = 50.
set BL_LaserImpactScatterX[LASER_ID] = 10.
set BL_LaserImpactScatterY[LASER_ID] = 10.
set BL_LaserImpactScatterZ[LASER_ID] = 10.
set BL_UpdateSourceLoc[LASER_ID] = true
set BL_UpdateTargetLoc[LASER_ID] = true
set BL_UpdateLaunchPoint[LASER_ID] = false
set BL_UpdateImpactPoint[LASER_ID] = true
set BL_LaunchFromTargetLoc[LASER_ID] = false
set BL_FixedImpactLoc[LASER_ID] = false
set BL_LaserRangeStart[LASER_ID] = 0.
set BL_LaserRangePerLaser[LASER_ID] = 0.
set BL_LaserDirectionalTilt[LASER_ID] = 0.
set BL_LaserAttackType[LASER_ID] = ATTACK_TYPE_HERO
set BL_LaserDamageType[LASER_ID] = udg_DamageTypeCode
set BL_LaserDivideDamage[LASER_ID] = true
set BL_Uninterruptible[LASER_ID] = false
set BL_LaserHitAll[LASER_ID] = false
set BL_LaserFriendlyFire[LASER_ID] = false
set BL_ReduceLaunchOverhead[LASER_ID] = true
set BL_ReduceImpactOverhead[LASER_ID] = true
//Arcane Barrage spell
set LASER_ID = 7
set BL_LaserString[LASER_ID] = "MYSB"
set BL_RED[LASER_ID] = 1.
set BL_BLUE[LASER_ID] = 1.
set BL_GREEN[LASER_ID] = 1.
set BL_ALPHA[LASER_ID] = 1.
set BL_LaserLaunchFX[LASER_ID] = "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
set BL_LaserImpactFX[LASER_ID] = "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
set BL_LaserAreaFX[LASER_ID] = null
set BL_LaserLaunchScale[LASER_ID] = 1.
set BL_LaserImpactScale[LASER_ID] = 1.
set BL_LaserAreaScale[LASER_ID] = 1.
set BL_NumberOfLasers[LASER_ID] = 11
set BL_LaserDuration[LASER_ID] = .2
set BL_LaserFadeTime[LASER_ID] = .2
set BL_LaserInterval[LASER_ID] = 0.
set BL_LaserDoT[LASER_ID] = 0.
set BL_LaserAOE[LASER_ID] = 70.
set BL_IsLaserGrounded[LASER_ID] = true
set BL_LaserLaunchOffset[LASER_ID] = 0.
set BL_LaserLaunchHeight[LASER_ID] = 240.
set BL_LaserLaunchAngle[LASER_ID] = 0.
set BL_LaserLaunchScatterX[LASER_ID] = 0.
set BL_LaserLaunchScatterY[LASER_ID] = 0.
set BL_LaserLaunchScatterZ[LASER_ID] = 0.
set BL_LaserImpactScatterX[LASER_ID] = 50.
set BL_LaserImpactScatterY[LASER_ID] = 50.
set BL_LaserImpactScatterZ[LASER_ID] = 50.
set BL_UpdateSourceLoc[LASER_ID] = false
set BL_UpdateTargetLoc[LASER_ID] = false
set BL_UpdateLaunchPoint[LASER_ID] = false
set BL_UpdateImpactPoint[LASER_ID] = false
set BL_LaunchFromTargetLoc[LASER_ID] = false
set BL_FixedImpactLoc[LASER_ID] = false
set BL_LaserRangeStart[LASER_ID] = 0.
set BL_LaserRangePerLaser[LASER_ID] = 35.
set BL_LaserDirectionalTilt[LASER_ID] = 1.5708
set BL_LaserAttackType[LASER_ID] = ATTACK_TYPE_MAGIC
set BL_LaserDamageType[LASER_ID] = udg_DamageTypeCode
set BL_LaserDivideDamage[LASER_ID] = false
set BL_Uninterruptible[LASER_ID] = false
set BL_LaserHitAll[LASER_ID] = false
set BL_LaserFriendlyFire[LASER_ID] = false
set BL_ReduceLaunchOverhead[LASER_ID] = true
set BL_ReduceImpactOverhead[LASER_ID] = false
//Thunderspire
set LASER_ID = 8
set BL_LaserString[LASER_ID] = "BLNL"
set BL_RED[LASER_ID] = 1.
set BL_BLUE[LASER_ID] = 1.
set BL_GREEN[LASER_ID] = 1.
set BL_ALPHA[LASER_ID] = 1.
set BL_LaserLaunchFX[LASER_ID] = null
set BL_LaserImpactFX[LASER_ID] = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
set BL_LaserAreaFX[LASER_ID] = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
set BL_LaserLaunchScale[LASER_ID] = 1.
set BL_LaserImpactScale[LASER_ID] = 2.
set BL_LaserAreaScale[LASER_ID] = 2.
set BL_NumberOfLasers[LASER_ID] = 3
set BL_LaserDuration[LASER_ID] = .2
set BL_LaserFadeTime[LASER_ID] = .1
set BL_LaserInterval[LASER_ID] = 0.35
set BL_LaserDoT[LASER_ID] = 0.
set BL_LaserAOE[LASER_ID] = 650.
set BL_IsLaserGrounded[LASER_ID] = true
set BL_LaserLaunchOffset[LASER_ID] = 0.
set BL_LaserLaunchHeight[LASER_ID] = 1000.
set BL_LaserLaunchAngle[LASER_ID] = 0.
set BL_LaserLaunchScatterX[LASER_ID] = 0.
set BL_LaserLaunchScatterY[LASER_ID] = 0.
set BL_LaserLaunchScatterZ[LASER_ID] = 0.
set BL_LaserImpactScatterX[LASER_ID] = 0.
set BL_LaserImpactScatterY[LASER_ID] = 0.
set BL_LaserImpactScatterZ[LASER_ID] = 0.
set BL_UpdateSourceLoc[LASER_ID] = false
set BL_UpdateTargetLoc[LASER_ID] = false
set BL_UpdateLaunchPoint[LASER_ID] = false
set BL_UpdateImpactPoint[LASER_ID] = false
set BL_LaunchFromTargetLoc[LASER_ID] = false
set BL_FixedImpactLoc[LASER_ID] = true
set BL_LaserRangeStart[LASER_ID] = 0.
set BL_LaserRangePerLaser[LASER_ID] = .001
set BL_LaserDirectionalTilt[LASER_ID] = 0.
set BL_LaserAttackType[LASER_ID] = ATTACK_TYPE_MAGIC
set BL_LaserDamageType[LASER_ID] = udg_DamageTypeCode
set BL_LaserDivideDamage[LASER_ID] = false
set BL_Uninterruptible[LASER_ID] = false
set BL_LaserHitAll[LASER_ID] = false
set BL_LaserFriendlyFire[LASER_ID] = false
set BL_ReduceLaunchOverhead[LASER_ID] = true
set BL_ReduceImpactOverhead[LASER_ID] = true
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEvent(t, 0., false)
call TriggerAddCondition(t, function setupArsenal)
set t = null
endfunction
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 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
//TESH.scrollpos=0
//TESH.alwaysfold=0
library BLIndex initializer BurstLaser_Indexing requires BL
globals
private trigger BurstLaserIndexTrigger = CreateTrigger()
private group PreplacedUnits = CreateGroup()
endglobals
/*
Unfortunately, there is an issue where the damage type (from Bribe's Damage Engine) of
arsenals are not assigned at map initialisation, so the damage dealt by BurstLaser weapons
will returns an integer of 0, which will loop infinitely, which will then crash your game.
This unfortunate side-effect can be resolved by assigned BurstLaser weapons after a short
timer, which is what the function below is for. This happens only on map start, so the group
PreplacedUnits can be safely destroyed after it's been run.
Any BLAssignWeapon.create() setup in the BurstLaser_onIndex function have to be repeated
here, or else preplaced units will not have any BurstLasers.
*/
private function BurstLaser_onIndex_Preplaced takes nothing returns boolean
local unit Source
loop
set Source = FirstOfGroup(PreplacedUnits)
call GroupRemoveUnit(PreplacedUnits, Source)
exitwhen Source == null
if GetUnitTypeId(Source) == 'hrif' then
call BLAssignWeapon.create(Source, 1, 1)
elseif GetUnitTypeId(Source) == 'hgry' then
call BLAssignWeapon.create(Source, 1, 2)
call BLAssignWeapon.create(Source, 2, 3)
elseif GetUnitTypeId(Source) == 'ugar' then
call BLAssignWeapon.create(Source, 1, 4)
elseif GetUnitTypeId(Source) == 'hspt' then
call BLAssignWeapon.create(Source, 1, 5)
elseif GetUnitTypeId(Source) == 'Hamg' then
call BLAssignWeapon.create(Source, 1, 6)
call BLAssignWeapon.create(Source, 2, 7)
elseif GetUnitTypeId(Source) == 'hatw' then
call BLAssignWeapon.create(Source, 1, 8)
endif
endloop
call DestroyGroup(PreplacedUnits)
return true
endfunction
private function BurstLaser_onIndex takes nothing returns boolean
local unit Source = udg_UDexUnits[udg_UDex]
local integer LASER_ID = 0
if udg_UnitIndexEvent == 1. then
//Rifleman
if GetUnitTypeId(Source) == 'hrif' then
if udg_IsUnitPreplaced[udg_UDex] then
call GroupAddUnit(PreplacedUnits, Source)
else
call BLAssignWeapon.create(Source, 1, 1)
endif
//To describe the above setup, Source is the Rifleman itself, 1 is the slot of the
//weapon, and the final 1 is the arsenal used. Unless you're going to assigne
//multiple BurstLaser weapons to a unit (see below), the argument directly after
//the unit should be 1. The final argument will correspond to whichever arsenal is
//in the BurstLaser Setup Arsenal trigger.
//Gryphon Rider
/*
The Gryphon Rider has 2 BurstLaser weapons. The first one uses weapon 2 in the
BurstLaser Setuo Arsenal trigger, and the second one uses weapon 3.
*/
elseif GetUnitTypeId(Source) == 'hgry' then
if udg_IsUnitPreplaced[udg_UDex] then
call GroupAddUnit(PreplacedUnits, Source)
else
call BLAssignWeapon.create(Source, 1, 2) //The first weapon is slotted in slot 1 and uses arsenal 2
call BLAssignWeapon.create(Source, 2, 3) //The second weapon is slotted in slot 2 and uses arsenal 3
endif
//Gargoyle
/*
This is a variation on the gryphon's line attack, but strikes in a perpendicular
line instead, similar to the Colossus from Starcraft II. This is achieved by
setting LaserDirectionalTilt to 1.5708 radians (90°). Note that all lasers fire
simultaneously because LaserInterval is set to 0.
See arsenal 4 to find out how it was set up
*/
elseif GetUnitTypeId(Source) == 'ugar' then
if udg_IsUnitPreplaced[udg_UDex] then
call GroupAddUnit(PreplacedUnits, Source)
else
call BLAssignWeapon.create(Source, 1, 4)
endif
//Spellbreaker
/*
While not visible in this trigger, it's possible to bind a Sentry to a unit,
causing the lasers to fire from that dummy unit instead. Refer to SentryCreate onInde
and SentryOrbit. Essentially, LaserSentry[id] must be set to a unit for this to work.
*/
elseif GetUnitTypeId(Source) == 'hspt' then
if udg_IsUnitPreplaced[udg_UDex] then
call GroupAddUnit(PreplacedUnits, Source)
else
call BLAssignWeapon.create(Source, 1, 5)
endif
//Archmage
/*
The Archmage is an example of scattering your launch coordinates.
See arsenal 4 to find out how it was set up
*/
elseif GetUnitTypeId(Source) == 'Hamg' then
if udg_IsUnitPreplaced[udg_UDex] then
call GroupAddUnit(PreplacedUnits, Source)
else
call BLAssignWeapon.create(Source, 1, 6)
call BLAssignWeapon.create(Source, 2, 7)
endif
//Arcane Tower
/*
Similar to Skythunder, but hits ground.
*/
elseif GetUnitTypeId(Source) == 'hatw' then
if udg_IsUnitPreplaced[udg_UDex] then
call GroupAddUnit(PreplacedUnits, Source)
else
call BLAssignWeapon.create(Source, 1, 8)
endif
endif
else
if BLAssignWeapon[Source] != null then
call BLAssignWeapon[Source].destroy()
set BL_UsesBurstLaser[udg_UDex] = false
endif
endif
set Source = null
return false
endfunction
function BurstLaser_Indexing takes nothing returns nothing
local trigger PreplacedTrig = CreateTrigger()
call TriggerRegisterTimerEvent(PreplacedTrig, 1., false)
call TriggerAddCondition(PreplacedTrig, function BurstLaser_onIndex_Preplaced)
set PreplacedTrig = null
call TriggerRegisterVariableEvent( BurstLaserIndexTrigger, "udg_UnitIndexEvent", EQUAL, 1.00 )
call TriggerRegisterVariableEvent( BurstLaserIndexTrigger, "udg_UnitIndexEvent", EQUAL, 2.00 )
call TriggerAddCondition( BurstLaserIndexTrigger, function BurstLaser_onIndex)
endfunction
endlibrary
//TESH.scrollpos=13
//TESH.alwaysfold=0
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
//===========================================================================
function UnitEventDestroyGroup takes integer i returns nothing
if udg_CargoTransportGroup[i] != null then
call DestroyGroup(udg_CargoTransportGroup[i])
set udg_CargoTransportGroup[i] = null
endif
endfunction
function UnitEventCheckAfter takes nothing returns nothing
local integer i = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = 0
loop
exitwhen i == 0
if udg_IsUnitNew[i] then
//The unit was just created.
set udg_IsUnitNew[i] = false
elseif udg_IsUnitTransforming[i] then
//Added 21 July 2017 to fix the issue re-adding this ability in the same instant
set udg_UDex = i
set udg_UnitTypeEvent = 0.00
set udg_UnitTypeEvent = 1.00
set udg_UnitTypeOf[i] = GetUnitTypeId(udg_UDexUnits[i]) //Set this afterward to give the user extra reference
set udg_IsUnitTransforming[i] = false
call UnitAddAbility(udg_UDexUnits[i], udg_DetectTransformAbility)
elseif udg_IsUnitAlive[i] then
//The unit has started reincarnating.
set udg_IsUnitReincarnating[i] = true
set udg_IsUnitAlive[i] = false
set udg_UDex = i
set udg_DeathEvent = 0.50
set udg_DeathEvent = 0.00
endif
set i = udg_CheckDeathList[i]
endloop
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
if udg_CheckDeathList[0] == 0 then
call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
endif
set udg_CheckDeathList[i] = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = i
endfunction
function UnitEventOnUnload takes nothing returns nothing
local integer i = udg_UDex
call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
set udg_IsUnitBeingUnloaded[i] = true
set udg_CargoEvent = 0.00
set udg_CargoEvent = 2.00
set udg_CargoEvent = 0.00
set udg_IsUnitBeingUnloaded[i] = false
if not IsUnitLoaded(udg_UDexUnits[i]) or IsUnitType(udg_CargoTransportUnit[i], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CargoTransportUnit[i]) == 0 then
set udg_CargoTransportUnit[i] = null
endif
endfunction
function UnitEventOnDeath takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_UDex != 0 then
set udg_KillerOfUnit[udg_UDex] = GetKillingUnit() //Added 29 May 2017 for GIMLI_2
set udg_IsUnitAlive[udg_UDex] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
set udg_KillerOfUnit[udg_UDex] = null
if udg_CargoTransportUnit[udg_UDex] != null then
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnOrder takes nothing returns boolean
local integer pdex = udg_UDex
local unit u = GetFilterUnit()
local integer i = GetUnitUserData(u)
if i > 0 then
set udg_UDex = i
if GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
if not udg_IsUnitRemoved[i] then
set udg_IsUnitRemoved[i] = true
set udg_IsUnitAlive[i] = false
set udg_SummonerOfUnit[i] = null
//For backwards-compatibility:
set udg_DeathEvent = 0.00
set udg_DeathEvent = 3.00
set udg_DeathEvent = 0.00
//Fire deindex event for UDex:
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 2.00
set udg_UnitIndexEvent = 0.00
set udg_UDexNext[udg_UDexPrev[i]] = udg_UDexNext[i]
set udg_UDexPrev[udg_UDexNext[i]] = udg_UDexPrev[i]
// Recycle the index for later use
set udg_UDexUnits[i] = null
set udg_UDexPrev[i] = udg_UDexLastRecycled
set udg_UDexLastRecycled = i
call UnitEventDestroyGroup(i)
endif
elseif not udg_IsUnitAlive[i] then
if not IsUnitType(u, UNIT_TYPE_DEAD) then
set udg_IsUnitAlive[i] = true
set udg_DeathEvent = 0.00
set udg_DeathEvent = 2.00
set udg_DeathEvent = 0.00
set udg_IsUnitReincarnating[i] = false
endif
elseif IsUnitType(u, UNIT_TYPE_DEAD) then
if udg_IsUnitNew[i] then
//This unit was created as a corpse.
set udg_IsUnitAlive[i] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
elseif udg_CargoTransportUnit[i] == null or not IsUnitType(u, UNIT_TYPE_HERO) then
//The unit may have just started reincarnating.
call UnitEventCheckAfterProxy(i)
endif
elseif GetUnitAbilityLevel(u, udg_DetectTransformAbility) == 0 and not udg_IsUnitTransforming[i] then
set udg_IsUnitTransforming[i] = true
call UnitEventCheckAfterProxy(i) //This block has been updated on 21 July 2017
endif
if udg_CargoTransportUnit[i] != null and not udg_IsUnitBeingUnloaded[i] and not IsUnitLoaded(u) or IsUnitType(u, UNIT_TYPE_DEAD) then
call UnitEventOnUnload()
endif
set udg_UDex = pdex
endif
set u = null
return false
endfunction
function UnitEventOnSummon takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_IsUnitNew[udg_UDex] then
set udg_SummonerOfUnit[udg_UDex] = GetSummoningUnit()
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 0.50
set udg_UnitIndexEvent = 0.00
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnLoad takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = GetUnitUserData(GetTriggerUnit())
local integer index
if i != 0 then
set udg_UDex = i
if udg_CargoTransportUnit[i] != null then
call UnitEventOnUnload()
endif
//Loaded corpses do not issue an order when unloaded, therefore must
//use the enter-region event method taken from Jesus4Lyf's Transport.
if not udg_IsUnitAlive[i] then
call SetUnitX(udg_UDexUnits[i], udg_WorldMaxX)
call SetUnitY(udg_UDexUnits[i], udg_WorldMaxY)
endif
set udg_CargoTransportUnit[i] = GetTransportUnit()
set index = GetUnitUserData(udg_CargoTransportUnit[i])
if udg_CargoTransportGroup[index] == null then
set udg_CargoTransportGroup[index] = CreateGroup()
endif
call GroupAddUnit(udg_CargoTransportGroup[index], udg_UDexUnits[i])
set udg_CargoEvent = 0.00
set udg_CargoEvent = 1.00
set udg_CargoEvent = 0.00
set udg_UDex = pdex
endif
return false
endfunction
function UnitEventEnter takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = udg_UDexLastRecycled
local unit u = GetFilterUnit()
if udg_UnitIndexerEnabled and GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
//Generate a unique integer index for this unit
if i == 0 then
set i = udg_UDexMax + 1
set udg_UDexMax = i
else
set udg_UDexLastRecycled = udg_UDexPrev[i]
endif
//Link index to unit, unit to index
set udg_UDexUnits[i] = u
call SetUnitUserData(u, i)
//For backwards-compatibility, add the unit to a linked list
set udg_UDexNext[i] = udg_UDexNext[0]
set udg_UDexPrev[udg_UDexNext[0]] = i
set udg_UDexNext[0] = i
set udg_UDexPrev[i] = 0
call UnitAddAbility(u, udg_DetectRemoveAbility)
call UnitMakeAbilityPermanent(u, true, udg_DetectRemoveAbility)
call UnitAddAbility(u, udg_DetectTransformAbility)
set udg_UnitTypeOf[i] = GetUnitTypeId(u)
set udg_IsUnitNew[i] = true
set udg_IsUnitAlive[i] = true
set udg_IsUnitRemoved[i] = false
set udg_IsUnitReincarnating[i] = false
set udg_IsUnitPreplaced[i] = udg_IsUnitPreplaced[0] //Added 29 May 2017 for Spellbound
call UnitEventCheckAfterProxy(i)
//Fire index event for UDex
set udg_UDex = i
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 1.00
set udg_UnitIndexEvent = 0.00
else
set udg_UDex = GetUnitUserData(u)
if udg_CargoTransportUnit[udg_UDex] != null and not IsUnitLoaded(u) then
//The unit was dead, but has re-entered the map.
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
set u = null
return false
endfunction
//===========================================================================
function UnitEventInit takes nothing returns nothing
local integer i = 16
local player p
local trigger t = CreateTrigger()
local trigger load = CreateTrigger()
local trigger death = CreateTrigger()
local trigger summon = CreateTrigger()
local rect r = GetWorldBounds()
local region re = CreateRegion()
local boolexpr enterB = Filter(function UnitEventEnter)
local boolexpr orderB = Filter(function UnitEventOnOrder)
set udg_WorldMaxX = GetRectMaxX(r)
set udg_WorldMaxY = GetRectMaxY(r)
call RegionAddRect(re, r)
call RemoveRect(r)
call UnitEventDestroyGroup(0)
call UnitEventDestroyGroup(1)
set udg_UnitIndexerEnabled = true
call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
call TriggerAddCondition(load, Filter(function UnitEventOnLoad))
call TriggerAddCondition(death, Filter(function UnitEventOnDeath))
call TriggerAddCondition(summon, Filter(function UnitEventOnSummon))
loop
set i = i - 1
set p = Player(i)
call SetPlayerAbilityAvailable(p, udg_DetectRemoveAbility, false)
call SetPlayerAbilityAvailable(p, udg_DetectTransformAbility, false)
call TriggerRegisterPlayerUnitEvent(summon, p, EVENT_PLAYER_UNIT_SUMMON, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
call TriggerRegisterPlayerUnitEvent(death, p, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(load, p, EVENT_PLAYER_UNIT_LOADED, null)
call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
exitwhen i == 0
endloop
set summon = null
set death = null
set load = null
set re = null
set enterB = null
set orderB = null
set p = null
set r = null
set t = null
endfunction
function InitTrig_Unit_Event takes nothing returns nothing
endfunction
//===========================================================================
// Damage Engine lets you detect, amplify, block or nullify damage. It even
// lets you detect if the damage was physical or from a spell. Just reference
// DamageEventAmount/Source/Target or the boolean IsDamageSpell, to get the
// necessary damage event data.
//
// - Detect damage: use the event "DamageEvent Equal to 1.00"
// - To change damage before it's dealt: use the event "DamageModifierEvent Equal to 1.00"
// - Detect damage after it was applied, use the event "AfterDamageEvent Equal to 1.00"
// - Detect spell damage: use the condition "IsDamageSpell Equal to True"
// - Detect zero-damage: use the event "DamageEvent Equal to 2.00" (an AfterDamageEvent will not fire for this)
//
// You can specify the DamageEventType before dealing triggered damage. To prevent an already-improbable error, I recommend running the trigger "ClearDamageEvent (Checking Conditions)" after dealing triggered damage from within a damage event:
// - Set NextDamageType = DamageTypeWhatever
// - Unit - Cause...
// - Trigger - Run ClearDamageEvent (Checking Conditions)
//
// You can modify the DamageEventAmount and the DamageEventType from a "DamageModifierEvent Equal to 1.00" trigger.
// - If the amount is modified to negative, it will count as a heal.
// - If the amount is set to 0, no damage will be dealt.
//
// If you need to reference the original in-game damage, use the variable "DamageEventPrevAmt".
//
//===========================================================================
// Programming note about "integer i" and "udg_DmgEvRecursionN": integer i
// ranges from -1 upwards. "udg_DmgEvRecursionN" ranges from 0 upwards.
// "integer i" is always 1 less than "udg_DmgEvRecursionN"
//
function DmgEvResetVars takes nothing returns nothing
local integer i = udg_DmgEvRecursionN - 2
set udg_DmgEvRecursionN = i + 1
if i >= 0 then
set udg_DamageEventPrevAmt = udg_LastDmgPrevAmount[i]
set udg_DamageEventAmount = udg_LastDmgValue[i]
set udg_DamageEventSource = udg_LastDmgSource[i]
set udg_DamageEventTarget = udg_LastDmgTarget[i]
set udg_IsDamageSpell = udg_LastDmgWasSpell[i]
set udg_DamageEventType = udg_LastDmgPrevType[i]
endif
endfunction
function CheckDamagedLifeEvent takes boolean clear returns nothing
if clear then
set udg_NextDamageOverride = false
set udg_NextDamageType = 0
endif
if udg_DmgEvTrig != null then
call DestroyTrigger(udg_DmgEvTrig)
set udg_DmgEvTrig = null
if udg_IsDamageSpell then
call SetWidgetLife(udg_DamageEventTarget, RMaxBJ(udg_LastDamageHP, 0.41))
if udg_LastDamageHP <= 0.405 then
if udg_DamageEventType < 0 then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
//Kill the unit
call DisableTrigger(udg_DamageEventTrigger)
call UnitDamageTarget(udg_DamageEventSource, udg_DamageEventTarget, -999, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
call EnableTrigger(udg_DamageEventTrigger)
endif
elseif GetUnitAbilityLevel(udg_DamageEventTarget, udg_DamageBlockingAbility) > 0 then
call UnitRemoveAbility(udg_DamageEventTarget, udg_DamageBlockingAbility)
call SetWidgetLife(udg_DamageEventTarget, udg_LastDamageHP)
endif
if udg_DamageEventAmount != 0.00 and not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_AfterDamageEvent = 0.00
set udg_AfterDamageEvent = 1.00
set udg_AfterDamageEvent = 0.00
endif
call DmgEvResetVars()
endif
endfunction
function DmgEvOnExpire takes nothing returns nothing
set udg_DmgEvStarted = false
call CheckDamagedLifeEvent(true)
endfunction
function PreCheckDamagedLifeEvent takes nothing returns boolean
call CheckDamagedLifeEvent(true)
return false
endfunction
function OnUnitDamage takes nothing returns boolean
local boolean override = udg_DamageEventOverride
local integer i
local string s
local real prevAmount
local real life
local real prevLife
local unit u
call CheckDamagedLifeEvent(false) //in case the unit state event failed and the 0.00 second timer hasn't yet expired
set i = udg_DmgEvRecursionN - 1 //Had to be moved here due to false recursion tracking
if i >= 0 then
if i < 16 then
set udg_LastDmgPrevAmount[i]= udg_DamageEventPrevAmt
set udg_LastDmgValue[i] = udg_DamageEventAmount
set udg_LastDmgSource[i] = udg_DamageEventSource
set udg_LastDmgTarget[i] = udg_DamageEventTarget
set udg_LastDmgWasSpell[i] = udg_IsDamageSpell
set udg_LastDmgPrevType[i] = udg_DamageEventType
else
set s = "WARNING: Recursion error when dealing damage! Make sure when you deal damage from within a DamageEvent trigger, do it like this:\n\n"
set s = s + "Trigger - Turn off (This Trigger)\n"
set s = s + "Unit - Cause...\n"
set s = s + "Trigger - Turn on (This Trigger)"
//Delete the next couple of lines to disable the in-game recursion crash warnings
call ClearTextMessages()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, 999.00, s)
return false
endif
endif
set udg_DmgEvRecursionN = i + 2
set u = GetTriggerUnit()
set prevAmount = GetEventDamage()
set udg_DamageEventSource = GetEventDamageSource()
set udg_DamageEventAmount = prevAmount
set udg_DamageEventTarget = u
set udg_DamageEventType = udg_NextDamageType
set udg_NextDamageType = 0
set udg_DamageEventOverride = udg_NextDamageOverride
set udg_NextDamageOverride = false
if prevAmount == 0.00 then
if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_DamageEventPrevAmt = 0.00
set udg_DamageEvent = 0.00
set udg_DamageEvent = 2.00
set udg_DamageEvent = 0.00
endif
call DmgEvResetVars()
else
if not udg_DmgEvStarted then
set udg_DmgEvStarted = true
call TimerStart(udg_DmgEvTimer, 0.00, false, function DmgEvOnExpire)
endif
set udg_IsDamageSpell = prevAmount < 0.00
if udg_IsDamageSpell then
set prevAmount = -udg_DamageEventAmount
set life = 1.00
if IsUnitType(u, UNIT_TYPE_ETHEREAL) and not IsUnitType(u, UNIT_TYPE_HERO) then
set life = life*udg_DAMAGE_FACTOR_ETHEREAL //1.67
endif
if GetUnitAbilityLevel(u, 'Aegr') > 0 then
set life = life*udg_DAMAGE_FACTOR_ELUNES //0.80
endif
if udg_DmgEvBracers != 0 and IsUnitType(u, UNIT_TYPE_HERO) then
//Inline of UnitHasItemOfTypeBJ without the potential handle ID leak.
set i = 6
loop
set i = i - 1
if GetItemTypeId(UnitItemInSlot(u, i)) == udg_DmgEvBracers then
set life = life*udg_DAMAGE_FACTOR_BRACERS //0.67
exitwhen true
endif
exitwhen i == 0
endloop
endif
set udg_DamageEventAmount = prevAmount*life
endif
set udg_DamageEventPrevAmt = prevAmount
set udg_DamageModifierEvent = 0.00
if not udg_DamageEventOverride then
set udg_DamageModifierEvent = 1.00
if not udg_DamageEventOverride then
set udg_DamageModifierEvent = 2.00
set udg_DamageModifierEvent = 3.00
endif
endif
set udg_DamageEventOverride = override
if udg_DamageEventAmount > 0.00 then
set udg_DamageModifierEvent = 4.00
endif
set udg_DamageModifierEvent = 0.00
if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_DamageEvent = 0.00
set udg_DamageEvent = 1.00
set udg_DamageEvent = 0.00
endif
call CheckDamagedLifeEvent(true) //in case the unit state event failed from a recursive damage event
//All events have run and the damage amount is finalized.
set life = GetWidgetLife(u)
set udg_DmgEvTrig = CreateTrigger()
call TriggerAddCondition(udg_DmgEvTrig, Filter(function PreCheckDamagedLifeEvent))
if not udg_IsDamageSpell then
if udg_DamageEventAmount != prevAmount then
set life = life + prevAmount - udg_DamageEventAmount
if GetUnitState(u, UNIT_STATE_MAX_LIFE) < life then
set udg_LastDamageHP = life - prevAmount
call UnitAddAbility(u, udg_DamageBlockingAbility)
endif
call SetWidgetLife(u, RMaxBJ(life, 0.42))
endif
call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, LESS_THAN, RMaxBJ(0.41, life - prevAmount/2.00))
else
set udg_LastDamageHP = GetUnitState(u, UNIT_STATE_MAX_LIFE)
set prevLife = life
if life + prevAmount*0.75 > udg_LastDamageHP then
set life = RMaxBJ(udg_LastDamageHP - prevAmount/2.00, 1.00)
call SetWidgetLife(u, life)
set life = (life + udg_LastDamageHP)/2.00
else
set life = life + prevAmount*0.50
endif
set udg_LastDamageHP = prevLife - (prevAmount - (prevAmount - udg_DamageEventAmount))
call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, GREATER_THAN, life)
endif
set u = null
endif
return false
endfunction
function CreateDmgEvTrg takes nothing returns nothing
set udg_DamageEventTrigger = CreateTrigger()
call TriggerAddCondition(udg_DamageEventTrigger, Filter(function OnUnitDamage))
endfunction
function SetupDmgEv takes nothing returns boolean
local integer i = udg_UDex
local unit u
if udg_UnitIndexEvent == 1.00 then
set u = udg_UDexUnits[i]
if GetUnitAbilityLevel(u, 'Aloc') == 0 and TriggerEvaluate(gg_trg_Damage_Engine_Config) then
set udg_UnitDamageRegistered[i] = true
call TriggerRegisterUnitEvent(udg_DamageEventTrigger, u, EVENT_UNIT_DAMAGED)
call UnitAddAbility(u, udg_SpellDamageAbility)
call UnitMakeAbilityPermanent(u, true, udg_SpellDamageAbility)
endif
set u = null
else
set udg_HideDamageFrom[i] = false
if udg_UnitDamageRegistered[i] then
set udg_UnitDamageRegistered[i] = false
set udg_DamageEventsWasted = udg_DamageEventsWasted + 1
if udg_DamageEventsWasted == 32 then //After 32 registered units have been removed...
set udg_DamageEventsWasted = 0
//Rebuild the mass EVENT_UNIT_DAMAGED trigger:
call DestroyTrigger(udg_DamageEventTrigger)
call CreateDmgEvTrg()
set i = udg_UDexNext[0]
loop
exitwhen i == 0
if udg_UnitDamageRegistered[i] then
call TriggerRegisterUnitEvent(udg_DamageEventTrigger, udg_UDexUnits[i], EVENT_UNIT_DAMAGED)
endif
set i = udg_UDexNext[i]
endloop
endif
endif
endif
return false
endfunction
//===========================================================================
function InitTrig_Damage_Engine takes nothing returns nothing
local unit u = CreateUnit(Player(15), 'uloc', 0, 0, 0)
local integer i = 16
//Create this trigger with UnitIndexEvents in order add and remove units
//as they are created or removed.
local trigger t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 1.00)
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 2.00)
call TriggerAddCondition(t, Filter(function SetupDmgEv))
set t = null
//Run the configuration trigger to set all configurables:
if gg_trg_Damage_Engine_Config == null then
//It's possible this InitTrig_ function ran first, in which case use ExecuteFunc.
call ExecuteFunc("Trig_Damage_Engine_Config_Actions")
else
call TriggerExecute(gg_trg_Damage_Engine_Config)
endif
//Create trigger for storing all EVENT_UNIT_DAMAGED events.
call CreateDmgEvTrg()
//Create GUI-friendly trigger for cleaning up after UnitDamageTarget.
set udg_ClearDamageEvent = CreateTrigger()
call TriggerAddCondition(udg_ClearDamageEvent, Filter(function PreCheckDamagedLifeEvent))
//Disable SpellDamageAbility for every player.
loop
set i = i - 1
call SetPlayerAbilityAvailable(Player(i), udg_SpellDamageAbility, false)
exitwhen i == 0
endloop
//Preload abilities.
call UnitAddAbility(u, udg_DamageBlockingAbility)
call UnitAddAbility(u, udg_SpellDamageAbility)
call RemoveUnit(u)
set u = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Logarithm
globals
private constant integer ITERATIONS=20
endglobals
function Log takes real x returns real
local real min=-88.0
local real max= 88.0
local real mid
local integer i=ITERATIONS
loop
set mid=(min+max)/2
exitwhen(i<=0)
set i=i-1
if (Pow(bj_E,mid)>=x) then
set max=mid
else
set min=mid
endif
endloop
return mid
endfunction
function Logarithm takes real base, real x returns real
local real min=-88.0
local real max= 88.0
local real mid
local integer i=ITERATIONS
loop
set mid=(min+max)/2
exitwhen(i<=0)
set i=i-1
if (Pow(base,mid)>=x) then
set max=mid
else
set min=mid
endif
endloop
return mid
endfunction
endlibrary
//TESH.scrollpos=5
//TESH.alwaysfold=0
library ArmorUtils requires Logarithm, optional IntuitiveDamageSystem
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This is used to get the exact armor of a given unit. It deals damage to the
//* unit in order to determine armor, meaning that damage detection systems will
//* detect it. If your map has the Intuitive Damage Detection System (IDDS) in
//* it, it will use that system's internal ignored damage type for the check.
//* Using that removes the need to disable/enable any damage detection triggers
//* to avoid infinite loops.
//*
//* The attacktype constant, ATTACK_TYPE_USED, is by default set to use
//* ATTACK_TYPE_CHAOS. Chaos is used because it deals 100% to all types, so if
//* you change it in your map, make sure you update the constant to some type
//* with 100% damage to all armor types.
//*
//* This system can also be used as a means to detect if a unit is invulnerable
//* or not. If GetUnitArmor returns ARMOR_INVULNERABLE, then the unit is
//* invulnerable. The value for it is entirely random and will never be the
//* actual armor value for a unit, so there should be no conflicts.
//*
//* Damage reduction in WC3 due to negative armor is capped at -71%, which has
//* an equivalent armor value of -20. If you have a unit with less than -20
//* armor, this system will always return exactly -20.
//*
//* Default WC3 gameplay constants have the 'Armor Damage Reduction Multiplier'
//* set to 0.06. If you change this constant for your map, be sure to adjust the
//* ARMOR_REDUCTION_MULTIPLIER constant in this script to match.
//*
//* Example Usage:
//* local real armor = GetUnitArmor(MyUnit)
//*
//* Two other functions are included in this library. They are used for
//* calculating a unit's base damage knowing armor-factoring damage and a unit's
//* armor-factoring damage knowing its base damage. These functions do not
//* consider armor type in their calculations. If you want armor type damage
//* adjusting, it is recommended to trigger it.
//*
//* Example Usage:
//* local real basedmg = GetFullDamage(MyUnit, Armor)
//* local real armodmg = GetReducedDamage(MyUnit, Armor)
//*
//* An objectmerger call is included in this script to automatically generate
//* the bonus life ability if necessary. If you do not modify the 'AIlz' ability
//* in your map, you can replace the LIFE_BONUS_SPELL_ID constant with it and
//* not use the objectmerger call. The
//*
globals
//Values that should be changed for your map
private constant real ARMOR_REDUCTION_MULTIPLIER = 0.06
private constant integer LIFE_BONUS_SPELL_ID = 'lif&'
private constant attacktype ATTACK_TYPE_USED = ATTACK_TYPE_CHAOS
//Values that do not need to be changed
constant real ARMOR_INVULNERABLE = 917451.519
private constant real DAMAGE_TEST = 16.
private constant real DAMAGE_LIFE = 30.
private constant real NATLOG_094 =-0.061875
endglobals
////! external ObjectMerger w3a AIlz lif& anam "GetUnitArmorLifeBonus" ansf "" Ilif 1 30 aite 0
function GetUnitArmor takes unit u returns real
local real life = GetWidgetLife(u)
local real test = life
local real redc = 0.
local boolean enab = false
local trigger trig = GetTriggeringTrigger()
if u != null and life >= 0.405 then
if GetUnitState(u, UNIT_STATE_MAX_LIFE) <= DAMAGE_TEST then
//Add max life to keep it alive
call UnitAddAbility(u, LIFE_BONUS_SPELL_ID)
endif
if life <= DAMAGE_LIFE then
//If under the threshold, heal it for the moment
call SetWidgetLife(u, DAMAGE_LIFE)
set test = DAMAGE_LIFE
endif
static if LIBRARY_IntuitiveDamageSystem then
//Use the IGNORED type in the IDDS if present so it is 100% ignored
call UnitDamageTargetEx(u, u, DAMAGE_TEST, ATTACK_TYPE_USED, DAMAGE_TYPE_IGNORED, true)
else
if trig != null and IsTriggerEnabled(trig) then
//Disable the trigger to prevent it registering with damage detection systems
call DisableTrigger(trig)
set enab = true
endif
call UnitDamageTarget(u, u, DAMAGE_TEST, true, false, ATTACK_TYPE_USED, DAMAGE_TYPE_NORMAL, null)
if enab then
//Re-enable the trigger
call EnableTrigger(trig)
endif
endif
set redc = (DAMAGE_TEST-test+GetWidgetLife(u))/DAMAGE_TEST
//Remove the max life ability
call UnitRemoveAbility(u, LIFE_BONUS_SPELL_ID)
call SetWidgetLife(u, life)
set trig = null
if redc >= 1. then
//Invulnerable
return ARMOR_INVULNERABLE
elseif redc < 0. then
//Negative Armor
return -Log(redc+1.)/NATLOG_094
else
//Positive Armor
return redc/(ARMOR_REDUCTION_MULTIPLIER*(1.-redc))
endif
endif
set trig = null
return 0.
endfunction
function GetReducedDamage takes real baseDamage, real armor returns real
if armor >= 0. then
return baseDamage*(1.-((armor*ARMOR_REDUCTION_MULTIPLIER)/(1.+ARMOR_REDUCTION_MULTIPLIER*armor)))
else
return baseDamage*(2.-Pow(0.94,-armor))
endif
endfunction
function GetFullDamage takes real damage, real armor returns real
if armor >= 0. then
return damage/(1.-((armor*ARMOR_REDUCTION_MULTIPLIER)/(1.+ARMOR_REDUCTION_MULTIPLIER*armor)))
else
return damage/(2.-Pow(0.94,-armor))
endif
endfunction
endlibrary
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
library GetUnitCollision /* v2.0.1.0
*************************************************************************************
*
* Retrieves collision size for a unit (different from pathing map)
*
* Assumes collision will always be an integer
*
* 100% accurate to 1 decimal for collision sizes >= 5.1
*
*************************************************************************************
*
* */uses/*
*
* */ Table /* hiveworkshop.com/forums/jass-functions-413/snippet-new-table-188084/
*
*************************************************************************************
*
* Functions
*
* function GetUnitCollision takes unit whichUnit returns real
*
************************************************************************************/
globals
private Table uc
endglobals
private function C takes unit u, real x, real y, integer i returns real
local real l = 0
local real h = 300
local real m = 150
local real nm
loop
if (IsUnitInRangeXY(u, x+m, y, 0)) then
set l = m
else
set h = m
endif
set nm = (l+h)/2
exitwhen nm+.001 > m and nm-.001 < m
set m = nm
endloop
set m = R2I(m*10)/10.
set uc.real[i] = m
return m
endfunction
function GetUnitCollision takes unit u returns real
local integer i = GetUnitTypeId(u)
if (uc.real.has(i)) then
return uc.real[i]
endif
return C(u, GetUnitX(u), GetUnitY(u), i)
endfunction
private struct init extends array
private static method onInit takes nothing returns nothing
set uc = Table.create()
endmethod
endstruct
endlibrary
library DummyRecycler /*
// DummyRecycler v1.25
// by Flux
//
// A system that recycles dummy units while considering their facing angle.
// It can be used as attachment dummies for visual effects or as dummy caster.
//
// Why is recycling a unit important?
// Because creating a unit is is one of the slowest function in the game
// and there are reports that will always leave a permanent tiny bit of
// memory (0.04 KB).
// On average, retrieving a pending Dummy is approximately 4x faster compared
// to creating a new one and recycling a Dummy compared to removing it is
// approximately 1.3x faster.
// Furthermore, if you're using a lot of "Unit has entered map" events,
// using this system will even result to even more better performance
// because retrieving Dummy units does not cause that event to run.
*/ requires /*
nothing
*/ optional Table/*
if not found, this system will use a hashtable. Hashtables are limited to
255 per map.
*/ optional WorldBounds /*
if not found, this system will initialize its own Map Boundaries.
//
//
// Features:
//
// -- Dummy Sharing
// When a Dummy List gets low on unit count, it will borrow Dummy Units
// from the Dummy List with the highest unit count. The transfer is not
// instant because the shared Dummy Unit has to turn to the appropriate
// angle of its new Dummy List before it can be recycled.
// See BORROW_REQUEST.
//
// -- Self-balancing recycling algorithm
// Recycled Dummy Units will be thrown to the List having the least number
// of Dummy Units.
//
// -- Recycling least used
// Allows recycling a Dummy from the Dummy List with the highest
// unit count. It is useful when the facing angle of the Dummy Unit
// does not matter.
// See GetRecycledDummyAnyAngle.
//
// -- Self-adaptation
// When there are no free Dummy Units from a Dummy List, it will end up creating
// a new unit instead but that unit will be permanently added as a Dummy
// Unit to be recycled increasing the overall total Dummy Unit count.
//
// -- Count control
// Allows limiting the overall number of Dummy Units.
// See MAX_DUMMY_COUNT.
//
// -- Delayed Recycle
// Allows recycling Dummy Units after some delay to allocate time for the
// death animation of Special Effects to be seen.
// See DummyAddRecycleTimer.
//
// ******************************************************************
// ***************************** API: *******************************
// ******************************************************************
//
// function GetRecycledDummy takes real x, real y, real z, real facing returns unit
// - Retrieve an unused Dummy Unit from the List.
// - The equivalent of CreateUnit.
// - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
// function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
// - Use this function if the facing angle of the Dummy doesn't matter to you.
// - It will return a unit from the list having the highest number of unused Dummy Units.
// - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
// function RecycleDummy takes unit u returns nothing
// - Recycle the Dummy unit for it to be used again later.
// - The equivalent of RemoveUnit.
//
// function DummyAddRecycleTimer takes unit u, real time returns nothing
// - Recycle the Dummy unit after a certain time.
// - Use this to allocate time for the the death animation of an effect attached to the
// Dummy Unit to finish..
// - The equivalent of UnitApplyTimedLife.
//
// function ShowDummy takes unit u, boolean flag returns nothing
// - Shows/hides Dummy Unit without conflicting with the Locust ability.
//
//--------------------
// CREDITS
//--------------------
// Bribe - for the MissileRecycler (vJASS) where I got this concept from
// http://www.hiveworkshop.com/forums/jass-resources-412/system-missilerecycler-206086/
// - for the optional Table
// http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
// Vexorian - for the Attachable and Pitch Animation Model (dummy.mdx)
// http://www.wc3c.net/showthread.php?t=101150
// Maker and IcemanBo - for the unit permanent 0.04 KB memory leak of units.
// http://www.hiveworkshop.com/forums/trigger-gui-editor-tutorials-279/memory-leaks-263410/
// Nestharus - for the data structure
// http://www.hiveworkshop.com/forums/2809461-post7.html
// - for the optional WorldBounds
// http://githubusercontent.com/nestharus/JASS/master/jass/Systems/WorldBounds/script.j
// =============================================================== //
// ====================== CONFIGURATION ========================== //
// =============================================================== */
globals
//The rawcode of the Dummy Unit
private constant integer DUMMY_ID = 'dumi'
//The owner of the Dummy Unit
private constant player OWNER = Player(14)
//The number of indexed angle. The higher the value the:
// - Lesser the turning time for the Dummy Units.
// - Higher the total number of Dummy Units created at Map Initialization.
// Recommended Value: 10 (Max difference of 18 degrees)
private constant integer ANGLES_COUNT = 10
//The number of Dummy units per ANGLES_COUNT. The higher the value the:
// - Higher the number of units that can be recycled per angle, when
// no more units are in queue, the system will resort to use CreateUnit.
// - Higher the total number of Dummy Units created at Map Initialization.
// Recommended Value: 3 to 5 (for less overhead in Map Loading Screen)
private constant integer STORED_UNIT_COUNT = 3
//The maximum number of Dummy units that can exist. When the system resort
//to using CreateUnit, the unit will be permanently added to the Dummy
//List. To avoid spamming Dummy Units and having too much free Dummy
//Units to allocate, the maximum number of Dummy Units is capped.
// Recommended Value: 80 to 120
private constant integer MAX_DUMMY_COUNT = 100
//When a certain angle have less than BORROW_REQUEST units in its list,
//it will start to borrow Dummy Units from the list with the highest
//Dummy Unit count.
// Recommended Value: Half of maximum STORED_UNIT_COUNT
private constant integer BORROW_REQUEST = 5
//It will only return a Dummy if the current dummy is close
//to it's appropriate facing angle. This is to avoid returning
//a Dummy which is still turning to face it's list angle.
private constant real ANGLE_TOLERANCE = 10.0
//An additional option to automatically hide recycled dummy units in the
//corner of the map camera bounds
private constant boolean HIDE_ON_MAP_CORNER = true
endglobals
//Every time a new dummy unit is retrieved, it will apply this resets
//If it is redundant/you dont need it, remove it.
//! textmacro DUMMY_UNIT_RESET
call SetUnitScale(bj_lastCreatedUnit, 1, 0, 0)
call SetUnitVertexColor(bj_lastCreatedUnit, 255, 255, 255, 255)
call SetUnitAnimationByIndex(bj_lastCreatedUnit, 90)
call ShowDummy(bj_lastCreatedUnit, true)
//! endtextmacro
// =============================================================== //
// ==================== END CONFIGURATION ======================== //
// =============================================================== //
globals
private integer dummyCount = ANGLES_COUNT*STORED_UNIT_COUNT
private real array angle
private integer array count
private integer array countHead
private integer array countNext
private integer array countPrev
private integer array next
private integer array prev
private unit array dummy
private integer upper
private integer lower
private integer lastInstance
private constant real FACING_OFFSET = 180.0/ANGLES_COUNT
endglobals
static if HIDE_ON_MAP_CORNER and not LIBRARY_WorldBounds then
private module BoundsInit
readonly static real x
readonly static real y
private static method onInit takes nothing returns nothing
local rect map = GetWorldBounds()
set thistype.x = GetRectMaxX(map)
set thistype.y = GetRectMaxY(map)
call RemoveRect(map)
set map = null
endmethod
endmodule
private struct Bounds extends array
implement BoundsInit
endstruct
endif
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable hash = InitHashtable()
endif
private static method onInit takes nothing returns nothing
local real add = 360.0/ANGLES_COUNT
local real a = 0
local integer this = ANGLES_COUNT
local integer head = 0
local integer cHead = JASS_MAX_ARRAY_SIZE - 1 //avoid allocation collision
local integer i = R2I(MAX_DUMMY_COUNT/ANGLES_COUNT + 0.5)
set upper = STORED_UNIT_COUNT
set lower = STORED_UNIT_COUNT
static if LIBRARY_Table then
set tb = Table.create()
endif
//Initialize countHeads
loop
exitwhen i < 0
set countNext[cHead] = cHead
set countPrev[cHead] = cHead
set countHead[i] = cHead
set cHead = cHead - 1
set i = i - 1
endloop
set cHead = countHead[STORED_UNIT_COUNT] //All heads will be inserted here initially
//Create the Dummy units
loop
exitwhen a >= 360
//Initialize head
set next[head] = head
set prev[head] = head
set count[head] = STORED_UNIT_COUNT
set angle[head] = a
//Insert head in the Count List
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
set i = 0
loop
exitwhen i >= STORED_UNIT_COUNT
//Queued Linked List
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
static if HIDE_ON_MAP_CORNER then
static if LIBRARY_WorldBounds then
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, a)
else
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, Bounds.x, Bounds.y, a)
endif
else
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, 0, 0, a)
endif
call PauseUnit(dummy[this], true)
static if LIBRARY_Table then
set tb[GetHandleId(dummy[this])] = this
else
call SaveInteger(hash, GetHandleId(dummy[this]), 0, this)
endif
set this = this + 1
set i = i + 1
endloop
set head = head + 1
set a = a + add
endloop
set lastInstance = this
endmethod
endmodule
private struct S extends array
implement M
endstruct
private function GetHead takes integer facing returns integer
if facing < 0 or facing >= 360 then
set facing = facing - (facing/360)*360
if facing < 0 then
set facing = facing + 360
endif
endif
return R2I((facing*ANGLES_COUNT/360.0))
endfunction
function ShowDummy takes unit u, boolean flag returns nothing
if IsUnitHidden(u) == flag then
call ShowUnit(u, flag)
if flag and GetUnitTypeId(u) == DUMMY_ID then
call UnitRemoveAbility(u, 'Aloc')
call UnitAddAbility(u, 'Aloc')
endif
endif
endfunction
function GetRecycledDummy takes real x, real y, real z, real facing returns unit
local integer head = GetHead(R2I(facing + FACING_OFFSET))
local integer this = next[head]
local integer cHead
//If there are Dummy Units in the Queue List already facing close to the appropriate angle
if this != head and RAbsBJ(GetUnitFacing(dummy[this]) - angle[head]) <= ANGLE_TOLERANCE then
//Remove from the Queue List
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
//For double free protection
set next[this] = -1
//Unit Properties
set bj_lastCreatedUnit = dummy[this]
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitFacing(bj_lastCreatedUnit, facing)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
//! runtextmacro DUMMY_UNIT_RESET()
//Update Count and Bounds
set count[head] = count[head] - 1
//------------------------------------------------
// Unit Sharing
//------------------------------------------------
if count[head] < BORROW_REQUEST and count[countNext[countHead[upper]]] > count[head] then
set count[head] = count[head] + 1
set this = next[countNext[countHead[upper]]]
call SetUnitFacing(dummy[this], angle[head])
//Remove
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
//Add to the Current List
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
set head = countNext[countHead[upper]]
set count[head] = count[head] - 1
endif
//---------------------------
//Update Count Lists
//---------------------------
//Remove from the current Count List
set countNext[countPrev[head]] = countNext[head]
set countPrev[countNext[head]] = countPrev[head]
//Add to the new Count List
set cHead = countHead[count[head]]
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
//---------------------------
// Update Bounds
//---------------------------
set cHead = countHead[upper]
if countNext[cHead] == cHead then
set upper = upper - 1
endif
if count[head] < lower then
set lower = count[head]
endif
else
set bj_lastCreatedUnit = CreateUnit(OWNER, DUMMY_ID, x, y, facing)
call PauseUnit(bj_lastCreatedUnit, true)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
if dummyCount < MAX_DUMMY_COUNT then
set this = lastInstance
//For double free protection
set next[this] = -1
set dummy[this] = bj_lastCreatedUnit
static if LIBRARY_Table then
set S.tb[GetHandleId(bj_lastCreatedUnit)] = this
else
call SaveInteger(S.hash, GetHandleId(bj_lastCreatedUnit), 0, this)
endif
set lastInstance = lastInstance + 1
endif
set dummyCount = dummyCount + 1
endif
return bj_lastCreatedUnit
endfunction
function RecycleDummy takes unit u returns nothing
static if LIBRARY_Table then
local integer this = S.tb[GetHandleId(u)]
else
local integer this = LoadInteger(S.hash, GetHandleId(u), 0)
endif
local integer head
local integer cHead
//If the unit is a legit Dummy Unit
if this > 0 and next[this] == -1 then
//Find where to insert based on the list having the least number of units
set head = countNext[countHead[lower]]
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
//Update Status
call SetUnitFacing(u, angle[head])
call PauseUnit(u, true)
call SetUnitOwner(u, OWNER, false)
static if HIDE_ON_MAP_CORNER then
static if LIBRARY_WorldBounds then
call SetUnitX(u, WorldBounds.maxX)
call SetUnitY(u, WorldBounds.maxY)
else
call SetUnitX(u, Bounds.x)
call SetUnitY(u, Bounds.y)
endif
else
call SetUnitScale(u, 0, 0, 0)
call SetUnitVertexColor(u, 0, 0, 0, 0)
endif
set count[head] = count[head] + 1
//---------------------------
// Update Count Lists
//---------------------------
//Remove
set countNext[countPrev[head]] = countNext[head]
set countPrev[countNext[head]] = countPrev[head]
//Add to the new Count List
set cHead = countHead[count[head]]
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
//---------------------------
// Update Bounds
//---------------------------
set cHead = countHead[lower]
if countNext[cHead] == cHead then
set lower = lower + 1
endif
if count[head] > upper then
set upper = count[head]
endif
elseif this == 0 then
call RemoveUnit(u)
debug elseif next[this] != -1 then
debug call BJDebugMsg("|cffffcc00[DummyRecycler]:|r Attempted to recycle a pending/free Dummy Unit.")
endif
endfunction
private function Expires takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
static if LIBRARY_Table then
call RecycleDummy(S.tb.unit[id])
call S.tb.unit.remove(id)
else
call RecycleDummy(LoadUnitHandle(S.hash, id, 0))
call FlushChildHashtable(S.hash, id)
endif
call DestroyTimer(t)
set t = null
endfunction
function DummyAddRecycleTimer takes unit u, real time returns nothing
local timer t = CreateTimer()
static if LIBRARY_Table then
set S.tb.unit[GetHandleId(t)] = u
else
call SaveUnitHandle(S.hash, GetHandleId(t), 0, u)
endif
call TimerStart(t, time, false, function Expires)
set t = null
endfunction
function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
return GetRecycledDummy(x, y, z, angle[countNext[countHead[upper]]])
endfunction
// runtextmacro DUMMY_DEBUG_TOOLS()
endlibrary
library WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
*
* Fields
* -------------------------
*
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
*
* readonly static integer centerX
* readonly static integer centerY
*
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX = R2I(GetRectMaxX(world))
set maxY = R2I(GetRectMaxY(world))
set minX = R2I(GetRectMinX(world))
set minY = R2I(GetRectMinY(world))
set centerX = R2I((maxX + minX)/2)
set centerY = R2I((minY + maxY)/2)
set worldRegion = CreateRegion()
call RegionAddRect(worldRegion, world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
function Trig_GetStructIndex_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetUnitUserData(u)
if BL_UsesBurstLaser[id] then
call BJDebugMsg("Struct Index: " + I2S(BLAssignWeapon[u]))
call BJDebugMsg( BLAssignWeapon(BLAssignWeapon[u]).LaserLaunchFX[1] )
call BJDebugMsg( I2S(BLAssignWeapon(BLAssignWeapon[u]).LaserDamageType[1]) )
endif
set u = null
endfunction
//===========================================================================
function InitTrig_GetStructIndex takes nothing returns nothing
set gg_trg_GetStructIndex = CreateTrigger( )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_GetStructIndex, Player(0), true )
call TriggerAddAction( gg_trg_GetStructIndex, function Trig_GetStructIndex_Actions )
endfunction
////////////////////////////
// //
// ID Allocator by Flux //
// //
////////////////////////////
library IdAlloc initializer OnInit
globals
private integer array recycler
endglobals
function IndexDeallocate takes integer id returns nothing
set recycler[id] = recycler[0]
set recycler[0] = id
endfunction
function IndexAllocate takes nothing returns integer
local integer id = recycler[0]
if (recycler[id] == 0) then
set recycler[0] = id + 1
else
set recycler[0] = recycler[id]
endif
return id
endfunction
private function OnInit takes nothing returns nothing
set recycler[0] = 1
endfunction
endlibrary
function Trig_Stun_on_ESC_Func001A takes nothing returns nothing
call IssueImmediateOrderById( GetEnumUnit(), 851973 )
endfunction
function Trig_Stun_on_ESC_Actions takes nothing returns nothing
call ForGroupBJ( GetUnitsSelectedAll(Player(0)), function Trig_Stun_on_ESC_Func001A )
endfunction
//===========================================================================
function InitTrig_Stun_on_ESC takes nothing returns nothing
set gg_trg_Stun_on_ESC = CreateTrigger( )
call TriggerRegisterPlayerEventEndCinematic( gg_trg_Stun_on_ESC, Player(0) )
call TriggerAddAction( gg_trg_Stun_on_ESC, function Trig_Stun_on_ESC_Actions )
endfunction
scope SentryCreator
globals
//private trigger SentryTrigger = CreateTrigger()
private unit array SentryUnit
private unit array SentrySource
private real array SentryAngle
private real array SentryAngleInc
private real array SentryDistance
private real array SentryCollisionFix
endglobals
function SentryTimer takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer tID = GetTimerData(t)
local real x = GetUnitX(SentrySource[tID]) + Cos(SentryAngle[tID]) * SentryDistance[tID]
local real y = GetUnitY(SentrySource[tID]) + Sin(SentryAngle[tID]) * SentryDistance[tID]
local real z = GetUnitFlyHeight(SentrySource[tID]) + 60.
if not UnitAlive(SentryUnit[tID]) then
call UnitApplyTimedLife(SentryUnit[tID], 'BTLF', .01)
call IndexDeallocate(tID)
call ReleaseTimer(t)
else
call SetUnitX(SentryUnit[tID], x + SentryCollisionFix[tID])
call SetUnitY(SentryUnit[tID], y + SentryCollisionFix[tID])
call SetUnitFlyHeight(SentryUnit[tID], z + SentryCollisionFix[tID], 0.)
endif
set SentryAngle[tID] = SentryAngle[tID] + SentryAngleInc[tID] * bj_DEGTORAD
endfunction
public function Sentry takes unit Source, integer ID, real angle, real angleINC, real distance, string effectstring, real collisionfix returns nothing
local integer tID = IndexAllocate()
local timer t = NewTimerEx(tID)
set BL_LaserSentry[ID] = CreateUnit(Player(14), 'dumi', 0., 0., 0.)
call AddSpecialEffectTarget(effectstring, BL_LaserSentry[ID], "origin")
set SentryUnit[tID] = BL_LaserSentry[ID]
set SentrySource[tID] = Source
set SentryAngle[tID] = angle
set SentryAngleInc[tID] = angleINC
set SentryDistance[tID] = distance
set SentryCollisionFix[tID] = collisionfix
call TimerStart(t, .03125, true, function SentryTimer)
set t = null
endfunction
endscope
function Trig_SentryCreate_onIndex_Actions takes nothing returns boolean
local unit Source = udg_UDexUnits[udg_UDex]
if GetUnitTypeId(Source) == 'hspt' then
call SentryCreator_Sentry(Source, udg_UDex, GetRandomReal(0., 6.28319), 7., 60., "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl", -16.)
endif
set Source = null
return false
endfunction
//===========================================================================
function InitTrig_SentryCreate_onIndex takes nothing returns nothing
set gg_trg_SentryCreate_onIndex = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_SentryCreate_onIndex, "udg_UnitIndexEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_SentryCreate_onIndex, function Trig_SentryCreate_onIndex_Actions )
endfunction
scope ArcaneSpells initializer init
globals
//private constant string SENTRY_FX = "Abilities\\Spells\\Human\\Invisibility\\InvisibilityTarget.mdl"
endglobals
private function Actions takes nothing returns boolean
local location spellLoc = GetSpellTargetLoc()
local unit source = GetTriggerUnit()
local unit dummy
local real x = GetLocationX(spellLoc)
local real y = GetLocationY(spellLoc)
set dummy = GetRecycledDummyAnyAngle(x, y, 0.)
call BurstLaser.create(source, dummy, null, BLAssignWeapon[source], 2, 50.)
call RecycleDummy(dummy)
set dummy = null
call RemoveLocation(spellLoc)
set source = null
return false
endfunction
//===========================================================================
private function init takes nothing returns nothing
call RegisterSpellEffectEvent('Aarw', function Actions)
endfunction
endscope
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
//============================================================================
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable ht = InitHashtable()
endif
static method onCast takes nothing returns nothing
static if LIBRARY_Table then
call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
else
call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
endif
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set .tb = Table.create()
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
static if LIBRARY_Table then
if not S.tb.handle.has(abil) then
set S.tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
else
if not HaveSavedHandle(S.ht, 0, abil) then
call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
endif
endfunction
endlibrary
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.1.0.1
* By Magtheridon96
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must either
* return a boolean (false) or nothing. (Which is a Pro)
*
* Warning:
* --------
*
* - Don't use TriggerSleepAction inside registered code.
* - Don't destroy a trigger unless you really know what you're doing.
*
* API:
* ----
*
* - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
* - Registers code that will execute when an event fires.
* - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
* - Registers code that will execute when an event fires for a certain player.
* - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = 15
if t[i] == null then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen k == 0
set k = k - 1
endloop
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
local integer i = 16 * GetHandleId(p) + GetPlayerId(pl)
if t[i] == null then
set t[i] = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
return t[GetHandleId(p)]
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AllocFast /* v1.3.1.0
*************************************************************************************
*
* */ uses /*
*
* */ optional ErrorMessage /* github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage
* */ optional MemoryAnalysis /*
*
*************************************************************************************
*
* Maximizes speed by reducing local variable declarations and removing
* if-statement.
*
* set alloc = recycler[0]
* set recycler[0] = recycler[alloc]
*
************************************************************************************
*
* module AllocFast
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
* The Following Require Error Message To Be In The Map
* --------------------------------------------------------
*
* debug readonly boolean allocated
*
* The Following Require Memory Analysis To Be In The Map
* --------------------------------------------------------
*
* debug readonly integer monitorCount
* - the amount of global memory being monitored by this
* debug readonly integer monitorString
* - gets a string representation of all global memory being monitored by this
* debug readonly integer address
* - global memory address for debugging
* - used with monitor and stopMonitor
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
* debug method monitor takes string label, integer address returns nothing
* - monitor a global memory address with a label
* - used to identify memory leaks
* - should be memory that ought to be destroyed by the time this is destroyed
* debug method stopMonitor takes integer address returns nothing
* - stops monitoring global memory
* debug method stopMonitorValue takes handle monitoredHandle returns nothing
* - stops monitoring handle values
*
* The Following Are Used To Monitor Handle Values
*
* debug method monitor_widget takes string label, widget handleToTrack returns nothing
* debug method monitor_destructable takes string label, destructable handleToTrack returns nothing
* debug method monitor_item takes string label, item handleToTrack returns nothing
* debug method monitor_unit takes string label, unit handleToTrack returns nothing
* debug method monitor_timer takes string label, timer handleToTrack returns nothing
* debug method monitor_trigger takes string label, trigger handleToTrack returns nothing
* debug method monitor_triggercondition takes string label, triggercondition handleToTrack returns nothing
* debug method monitor_triggeraction takes string label, triggeraction handleToTrack returns nothing
* debug method monitor_force takes string label, force handleToTrack returns nothing
* debug method monitor_group takes string label, group handleToTrack returns nothing
* debug method monitor_location takes string label, location handleToTrack returns nothing
* debug method monitor_rect takes string label, rect handleToTrack returns nothing
* debug method monitor_boolexpr takes string label, boolexpr handleToTrack returns nothing
* debug method monitor_effect takes string label, effect handleToTrack returns nothing
* debug method monitor_unitpool takes string label, unitpool handleToTrack returns nothing
* debug method monitor_itempool takes string label, itempool handleToTrack returns nothing
* debug method monitor_quest takes string label, quest handleToTrack returns nothing
* debug method monitor_defeatcondition takes string label, defeatcondition handleToTrack returns nothing
* debug method monitor_timerdialog takes string label, timerdialog handleToTrack returns nothing
* debug method monitor_leaderboard takes string label, leaderboard handleToTrack returns nothing
* debug method monitor_multiboard takes string label, multiboard handleToTrack returns nothing
* debug method monitor_multiboarditem takes string label, multiboarditem handleToTrack returns nothing
* debug method monitor_dialog takes string label, dialog handleToTrack returns nothing
* debug method monitor_button takes string label, button handleToTrack returns nothing
* debug method monitor_texttag takes string label, texttag handleToTrack returns nothing
* debug method monitor_lightning takes string label, lightning handleToTrack returns nothing
* debug method monitor_image takes string label, image handleToTrack returns nothing
* debug method monitor_ubersplat takes string label, ubersplat handleToTrack returns nothing
* debug method monitor_region takes string label, region handleToTrack returns nothing
* debug method monitor_fogmodifier takes string label, fogmodifier handleToTrack returns nothing
* debug method monitor_hashtable takes string label, hashtable handleToTrack returns nothing
*
************************************************************************************/
module AllocFast
/*
* stack
*/
private static integer array recycler
private static integer alloc
static if LIBRARY_MemoryAnalysis then
debug private MemoryMonitor globalAddress
debug method operator address takes nothing returns integer
debug call ThrowError(recycler[this] != -1, "Alloc", "address", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress
debug endmethod
endif
/*
* allocation
*/
static method allocate takes nothing returns thistype
set alloc = recycler[0]
static if LIBRARY_ErrorMessage then
debug call ThrowError(alloc == 0, "AllocFast", "allocate", "thistype", 0, "Overflow.")
endif
set recycler[0] = recycler[alloc]
static if LIBRARY_ErrorMessage then
debug set recycler[alloc] = -1
endif
static if LIBRARY_MemoryAnalysis then
debug set thistype(alloc).globalAddress = MemoryMonitor.allocate("thistype")
endif
return alloc
endmethod
method deallocate takes nothing returns nothing
static if LIBRARY_ErrorMessage then
debug call ThrowError(recycler[this] != -1, "AllocFast", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
endif
static if LIBRARY_MemoryAnalysis then
debug call globalAddress.deallocate()
debug set globalAddress = 0
endif
set recycler[this] = recycler[0]
set recycler[0] = this
endmethod
static if LIBRARY_MemoryAnalysis then
debug method monitor takes string label, integer address returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor(label, address)
debug endmethod
debug method stopMonitor takes integer address returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "stopMonitor", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.stopMonitor(address)
debug endmethod
debug method stopMonitorValue takes handle monitoredHandle returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "stopMonitorValue", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.stopMonitorValue(monitoredHandle)
debug endmethod
debug method operator monitorCount takes nothing returns integer
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitorCount", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress.monitorCount
debug endmethod
debug method operator monitorString takes nothing returns string
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitorString", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress.monitorString
debug endmethod
debug method monitor_widget takes string label, widget handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_widget", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_widget(label, handleToTrack)
debug endmethod
debug method monitor_destructable takes string label, destructable handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_destructable", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_destructable(label, handleToTrack)
debug endmethod
debug method monitor_item takes string label, item handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_item", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_item(label, handleToTrack)
debug endmethod
debug method monitor_unit takes string label, unit handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_unit", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_unit(label, handleToTrack)
debug endmethod
debug method monitor_timer takes string label, timer handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_timer", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_timer(label, handleToTrack)
debug endmethod
debug method monitor_trigger takes string label, trigger handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_trigger", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_trigger(label, handleToTrack)
debug endmethod
debug method monitor_triggercondition takes string label, triggercondition handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_triggercondition", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_triggercondition(label, handleToTrack)
debug endmethod
debug method monitor_triggeraction takes string label, triggeraction handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_triggeraction", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_triggeraction(label, handleToTrack)
debug endmethod
debug method monitor_force takes string label, force handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_force", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_force(label, handleToTrack)
debug endmethod
debug method monitor_group takes string label, group handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_group", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_group(label, handleToTrack)
debug endmethod
debug method monitor_location takes string label, location handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_location", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_location(label, handleToTrack)
debug endmethod
debug method monitor_rect takes string label, rect handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_rect", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_rect(label, handleToTrack)
debug endmethod
debug method monitor_boolexpr takes string label, boolexpr handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_boolexpr", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_boolexpr(label, handleToTrack)
debug endmethod
debug method monitor_effect takes string label, effect handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_effect", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_effect(label, handleToTrack)
debug endmethod
debug method monitor_unitpool takes string label, unitpool handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_unitpool", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_unitpool(label, handleToTrack)
debug endmethod
debug method monitor_itempool takes string label, itempool handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_itempool", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_itempool(label, handleToTrack)
debug endmethod
debug method monitor_quest takes string label, quest handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_quest", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_quest(label, handleToTrack)
debug endmethod
debug method monitor_defeatcondition takes string label, defeatcondition handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_defeatcondition", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_defeatcondition(label, handleToTrack)
debug endmethod
debug method monitor_timerdialog takes string label, timerdialog handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_timerdialog", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_timerdialog(label, handleToTrack)
debug endmethod
debug method monitor_leaderboard takes string label, leaderboard handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_leaderboard", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_leaderboard(label, handleToTrack)
debug endmethod
debug method monitor_multiboard takes string label, multiboard handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_multiboard", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_multiboard(label, handleToTrack)
debug endmethod
debug method monitor_multiboarditem takes string label, multiboarditem handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_multiboarditem", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_multiboarditem(label, handleToTrack)
debug endmethod
debug method monitor_dialog takes string label, dialog handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_dialog", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_dialog(label, handleToTrack)
debug endmethod
debug method monitor_button takes string label, button handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_button", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_button(label, handleToTrack)
debug endmethod
debug method monitor_texttag takes string label, texttag handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_texttag", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_texttag(label, handleToTrack)
debug endmethod
debug method monitor_lightning takes string label, lightning handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_lightning", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_lightning(label, handleToTrack)
debug endmethod
debug method monitor_image takes string label, image handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_image", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_image(label, handleToTrack)
debug endmethod
debug method monitor_ubersplat takes string label, ubersplat handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_ubersplat", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_ubersplat(label, handleToTrack)
debug endmethod
debug method monitor_region takes string label, region handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_region", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_region(label, handleToTrack)
debug endmethod
debug method monitor_fogmodifier takes string label, fogmodifier handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_fogmodifier", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_fogmodifier(label, handleToTrack)
debug endmethod
debug method monitor_hashtable takes string label, hashtable handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "AllocFast", "monitor_hashtable", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_hashtable(label, handleToTrack)
debug endmethod
static if DEBUG_MODE then
//! runtextmacro optional MEMORY_ANALYSIS_STATIC_FIELD_FAST("recycler")
static method calculateMemoryUsage takes nothing returns integer
return calculateAllocatedMemory__recycler()
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
return allocatedMemoryString__recycler()
endmethod
endif
endif
/*
* analysis
*/
static if LIBRARY_ErrorMessage then
debug method operator allocated takes nothing returns boolean
debug return recycler[this] == -1
debug endmethod
endif
/*
* initialization
*/
private static method onInit takes nothing returns nothing
local integer i = 0
set recycler[8191] = 0 //so that the array doesn't reallocate over and over again
loop
set recycler[i] = i + 1
exitwhen i == 8190
set i = i + 1
endloop
endmethod
endmodule
endlibrary
//TESH.scrollpos=61
//TESH.alwaysfold=0
//static method create takes unit unit_source, unit unit_target, unit unit_sentry, integer id, real damage, string laser_string, real red, real blue, real green, real alpha, /*
//*/ string launch_string, string impact_string, string area_string, integer no_of_lasers, integer duration, integer fade_time, real interval, real aoe, boolean grounded, /*
//*/ real offset, real height, real angle, real spread_xy, real spread_z, boolean follow_target, boolean lightnin_lock, boolean range_lock, real range_start, real range_per_laser, /*
//*/ real directional_tilt, attacktype attack_type, integer damage_type, boolean uninterruptible, boolean hit_all, boolean friendly_fire returns thistype
//Launch
if this.launch_string != null then
set b = true
call DestroyEffect(AddSpecialEffectZ(this.launch_string, launch_x, launch_y, 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
//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
static method Interruption_Event takes nothing returns nothing
local integer id = GetHandleId(GetTriggerUnit())
local integer counter = LoadInteger(hash, id, COUNTER_KEY)
local thistype this
loop
exitwhen counter < 1
set this = LoadInteger(hash, id, counter)
if not this.uninterruptible and this.interval > 0. then
if GetOrderTargetUnit() == null then
if /*
[Move] */ GetUnitCurrentOrder(this.source) == 851986 or /*
[Stunned] */ GetUnitCurrentOrder(this.source) == 851973 or /*
[Stop] */ GetUnitCurrentOrder(this.source) == 851972 or /*
[Patrol] */ GetUnitCurrentOrder(this.source) == 851990 or /*
[Hold Poz] */ GetUnitCurrentOrder(this.source) == 851993 or /*
[Attack] */ GetUnitCurrentOrder(this.source) == 851983 or /*
[Smart] */ GetUnitCurrentOrder(this.source) == 851971 /*
*/ then
call PauseTimer(this.tmr_volley)
call SaveInteger(hash, id, COUNTER_KEY, counter) // reset counter
set this.laser_num = this.laser_index //This is set in case of interruption
call BJDebugMsg("Interrupt")
endif
else
if /*
[Move] */ GetUnitCurrentOrder(this.source) == 851986 or /*
[Patrol] */ GetUnitCurrentOrder(this.source) == 851990 or /*
[Attack] */ GetUnitCurrentOrder(this.source) == 851983 or /*
[Smart] */ GetUnitCurrentOrder(this.source) == 851971 /*
*/ then
call PauseTimer(this.tmr_volley)
call SaveInteger(hash, id, COUNTER_KEY, counter) // reset counter
set this.laser_num = this.laser_index //This is set in case of interruption
call BJDebugMsg("Interrupt")
endif
endif
endif
set counter = counter - 1
endloop
endmethod
//TESH.scrollpos=537
//TESH.alwaysfold=0
library BurstLaser requires BL, GetUnitCollision, ZLibrary, IdAlloc, TimerUtils, ArmorUtils, SpecialEffectZ
globals
private group DamageGroup = CreateGroup()
private constant real MAX_COLLISION_SIZE = 196.
private real array Damage
private real array LaserRED
private real array LaserBLUE
private real array LaserGREEN
private real array LaserALPHA
private real array FadeAmount
private unit array LaserSource
private unit array LaserTarget
private unit array LaserSentry
private unit array LaserDummyImpact
private unit array LaserDummyLaunch
private unit array LaserDummyArea
private integer array LaserDummyType
private integer array LaserDuration
private integer array LaserCount
private boolean array IsLaserLockedToTarget
private real array LaserLockAngle
private real array LaserLockDistance
private real array LaserLockHeight
private lightning array Laser
private boolean array IsLaserFading
private boolean array IsLaserGrounded
private boolean array LaserHitAll
private boolean array LaserFriendlyFire
private real array LaserLaunchOffset
private real array LaserLaunchHeight
private real array LaserLaunchAngle
private real array LaserSpreadXY
private real array LaserSpreadZ
private real array LaserLaunchX
private real array LaserLaunchY
private real array LaserLaunchZ
private real array LaserImpactX
private real array LaserImpactY
private real array LaserImpactZ
private real array LaserAngle
private boolean array LaserTargetLock //If false, Lasers in a set will strike the same point instead of updating their impact location to follow a moving target.
private boolean array LaserRangeLock //If true will set LaserRangeStart's starting point to the attacker (source of the laser) instead of the taret
private real array LaserRangeStart //Adds or subtracts a certain amount of distance from it's starting point.
private real array LaserRangePerLaser //Adds or substracts distance per Laser in a set.
private string array LaserString
private string array LaserLaunchFX
private string array LaserImpactFX
private string array LaserAreaFX
private real array LaserDamage
private real array LaserAOE
private attacktype array LaserAttackType
private integer array LaserDamageType
private real array InitialX
private real array InitialY
endglobals
function IndividualLaser_Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer NewTimerID = GetTimerData(t)
local real TargetColl = GetUnitCollision(LaserTarget[NewTimerID])
local real SOURCE_X = GetUnitX(LaserSource[NewTimerID])
local real SOURCE_Y = GetUnitY(LaserSource[NewTimerID])
local real TARGET_X = GetUnitX(LaserTarget[NewTimerID])
local real TARGET_Y = GetUnitY(LaserTarget[NewTimerID])
local real Angle = Atan2(TARGET_Y - SOURCE_Y, TARGET_X - SOURCE_X) + LaserLaunchAngle[NewTimerID]
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.
if LaserSentry[NewTimerID] == null then
set LAUNCH_X = SOURCE_X + Cos(Angle) * LaserLaunchOffset[NewTimerID]
set LAUNCH_Y = SOURCE_Y + Sin(Angle) * LaserLaunchOffset[NewTimerID]
set LAUNCH_Z = GetUnitZ(LaserSource[NewTimerID]) + LaserLaunchHeight[NewTimerID]
else
set LAUNCH_X = GetUnitX(LaserSentry[NewTimerID]) + Cos(Angle) * LaserLaunchOffset[NewTimerID]
set LAUNCH_Y = GetUnitY(LaserSentry[NewTimerID]) + Sin(Angle) * LaserLaunchOffset[NewTimerID]
set LAUNCH_Z = GetUnitZ(LaserSentry[NewTimerID]) + LaserLaunchHeight[NewTimerID]
endif
if IsLaserLockedToTarget[NewTimerID] then
set IMPACT_X = TARGET_X + Cos(LaserLockAngle[NewTimerID]) * LaserLockDistance[NewTimerID]
set IMPACT_Y = TARGET_Y + Sin(LaserLockAngle[NewTimerID]) * LaserLockDistance[NewTimerID]
set IMPACT_Z = GetUnitZ(LaserTarget[NewTimerID]) + LaserLockHeight[NewTimerID]
if Laser[NewTimerID] != null then //I set this if.then.else here because I want the IMPACTS to be set for the EVENTS below.
call MoveLightningEx(Laser[NewTimerID], true, LAUNCH_X, LAUNCH_Y, LAUNCH_Z, IMPACT_X, IMPACT_Y, IMPACT_Z)
endif
else
set IMPACT_X = LaserImpactX[NewTimerID]
set IMPACT_Y = LaserImpactY[NewTimerID]
set IMPACT_Z = LaserImpactZ[NewTimerID]
if Laser[NewTimerID] != null then
call MoveLightningEx(Laser[NewTimerID], true, LAUNCH_X, LAUNCH_Y, LAUNCH_Z, LaserImpactX[NewTimerID], LaserImpactY[NewTimerID], LaserImpactZ[NewTimerID])
endif
endif
if IsLaserFading[NewTimerID] then
set LaserALPHA[NewTimerID] = LaserALPHA[NewTimerID] - FadeAmount[NewTimerID]
if Laser[NewTimerID] != null then
call SetLightningColor(Laser[NewTimerID], LaserRED[NewTimerID], LaserBLUE[NewTimerID], LaserGREEN[NewTimerID], LaserALPHA[NewTimerID])
endif
if LaserALPHA[NewTimerID] <= 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 LaserSource[NewTimerID] = null
set LaserTarget[NewTimerID] = null
set LaserSentry[NewTimerID] = null
set LaserLaunchOffset[NewTimerID] = 0.
set LaserLaunchHeight[NewTimerID] = 0.
set LaserLaunchAngle[NewTimerID] = 0.
set LaserImpactX[NewTimerID] = 0.
set LaserImpactY[NewTimerID] = 0.
set LaserImpactZ[NewTimerID] = 0.
set IsLaserLockedToTarget[NewTimerID] = false
set LaserLockAngle[NewTimerID] = 0.
set LaserLockDistance[NewTimerID] = 0.
set LaserLockHeight[NewTimerID] = 0.
set LaserRED[NewTimerID] = 1.
set LaserBLUE[NewTimerID] = 1.
set LaserGREEN[NewTimerID] = 1.
set LaserALPHA[NewTimerID] = 1.
set IsLaserFading[NewTimerID] = false
set LaserALPHA[NewTimerID] = 1.
if Laser[NewTimerID] != null then
call DestroyLightning(Laser[NewTimerID])
set Laser[NewTimerID] = null
endif
call IndexDeallocate(NewTimerID)
call ReleaseTimer(t)
endif
else
set LaserDuration[NewTimerID] = LaserDuration[NewTimerID] - 1
if LaserDuration[NewTimerID] <= 0 then
set IsLaserFading[NewTimerID] = true
endif
endif
endfunction
function BurstLaser_Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer tID = GetTimerData(t)
local timer New_t = null
local integer NewTimerID = 0
local player SourcePlayer = GetOwningPlayer(LaserSource[tID])
local integer Source_ID = GetUnitUserData(LaserSource[tID])
local boolean b = false
local real SOURCE_X = GetUnitX(LaserSource[tID])
local real SOURCE_Y = GetUnitY(LaserSource[tID])
local real TARGET_X = GetUnitX(LaserTarget[tID])
local real TARGET_Y = GetUnitY(LaserTarget[tID])
local real Angle = Atan2(TARGET_Y - SOURCE_Y, TARGET_X - SOURCE_X)
local unit u = null
local real TargetColl = GetUnitCollision(LaserTarget[tID])
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.
if LaserSentry[tID] == null then
set LAUNCH_X = SOURCE_X + Cos(Angle + LaserLaunchAngle[tID]) * LaserLaunchOffset[tID]
set LAUNCH_Y = SOURCE_Y + Sin(Angle + LaserLaunchAngle[tID]) * LaserLaunchOffset[tID]
set LAUNCH_Z = GetUnitZ(LaserSource[tID]) + LaserLaunchHeight[tID]
else
set LAUNCH_X = GetUnitX(LaserSentry[tID]) + Cos(Angle + LaserLaunchAngle[tID]) * LaserLaunchOffset[tID]
set LAUNCH_Y = GetUnitY(LaserSentry[tID]) + Sin(Angle + LaserLaunchAngle[tID]) * LaserLaunchOffset[tID]
set LAUNCH_Z = GetUnitZ(LaserSentry[tID]) + LaserLaunchHeight[tID]
endif
if LaserRangeLock[tID] then //if true, start from the source's point
if LaserTargetLock[tID] then
set Angle = Atan2(TARGET_Y - InitialY[tID], TARGET_X - InitialX[tID])
set LaserImpactX[tID] = LaserImpactX[tID] + Cos(Angle) * LaserRangePerLaser[tID]
set LaserImpactY[tID] = LaserImpactY[tID] + Sin(Angle) * LaserRangePerLaser[tID]
set IMPACT_X = LaserImpactX[tID] + GetRandomReal(LaserSpreadXY[tID] * -1, LaserSpreadXY[tID])
set IMPACT_Y = LaserImpactY[tID] + GetRandomReal(LaserSpreadXY[tID] * -1, LaserSpreadXY[tID])
if IsLaserGrounded[tID] then
set LaserImpactZ[tID] = 0.
set IMPACT_Z = 0.
else
set LaserImpactZ[tID] = GetUnitZ(LaserTarget[tID])
set IMPACT_Z = LaserImpactZ[tID] + GetRandomReal(LaserSpreadZ[tID] * -1, LaserSpreadZ[tID]) + TargetColl * .8
endif
else
set LaserImpactX[tID] = LaserImpactX[tID] + Cos(LaserAngle[tID]) * LaserRangePerLaser[tID]
set LaserImpactY[tID] = LaserImpactY[tID] + Sin(LaserAngle[tID]) * LaserRangePerLaser[tID]
set IMPACT_X = LaserImpactX[tID] + GetRandomReal(LaserSpreadXY[tID] * -1, LaserSpreadXY[tID])
set IMPACT_Y = LaserImpactY[tID] + GetRandomReal(LaserSpreadXY[tID] * -1, LaserSpreadXY[tID])
if IsLaserGrounded[tID] then
set LaserImpactZ[tID] = 0.
set IMPACT_Z = 0.
else
set IMPACT_Z = LaserImpactZ[tID] + GetRandomReal(LaserSpreadZ[tID] * -1, LaserSpreadZ[tID]) + TargetColl * .8
endif
endif
else
if LaserTargetLock[tID] then
set Angle = Atan2(TARGET_Y - InitialY[tID], TARGET_X - InitialX[tID])
set LaserImpactX[tID] = LaserImpactX[tID] + Cos(Angle) * LaserRangePerLaser[tID]
set LaserImpactY[tID] = LaserImpactY[tID] + Sin(Angle) * LaserRangePerLaser[tID]
set IMPACT_X = LaserImpactX[tID] + GetRandomReal(LaserSpreadXY[tID] * -1, LaserSpreadXY[tID])
set IMPACT_Y = LaserImpactY[tID] + GetRandomReal(LaserSpreadXY[tID] * -1, LaserSpreadXY[tID])
if IsLaserGrounded[tID] then
set LaserImpactZ[tID] = 0.
set IMPACT_Z = 0.
else
set LaserImpactZ[tID] = GetUnitZ(LaserTarget[tID])
set IMPACT_Z = LaserImpactZ[tID] + GetRandomReal(LaserSpreadZ[tID] * -1, LaserSpreadZ[tID]) + TargetColl * .8
endif
else
set LaserImpactX[tID] = LaserImpactX[tID] + Cos(LaserAngle[tID]) * LaserRangePerLaser[tID]
set LaserImpactY[tID] = LaserImpactY[tID] + Sin(LaserAngle[tID]) * LaserRangePerLaser[tID]
set IMPACT_X = LaserImpactX[tID] + GetRandomReal(LaserSpreadXY[tID] * -1, LaserSpreadXY[tID])
set IMPACT_Y = LaserImpactY[tID] + GetRandomReal(LaserSpreadXY[tID] * -1, LaserSpreadXY[tID])
if IsLaserGrounded[tID] then
set LaserImpactZ[tID] = 0.
set IMPACT_Z = 0.
else
set IMPACT_Z = LaserImpactZ[tID] + GetRandomReal(LaserSpreadZ[tID] * -1, LaserSpreadZ[tID]) + TargetColl * .8
endif
endif
endif
set LaserCount[tID] = LaserCount[tID] - 1
set NewTimerID = IndexAllocate()
//Launch
if LaserLaunchFX[tID] != null then
set b = true
call DestroyEffect(AddSpecialEffectZ(LaserLaunchFX[tID], LAUNCH_X, LAUNCH_Y, LAUNCH_Z))
endif
//Impact (Not Grounded)
if LaserImpactFX[tID] != null then
set b = true
if IsLaserGrounded[tID] then
call DestroyEffect(AddSpecialEffect(LaserImpactFX[tID], IMPACT_X, IMPACT_Y))
else
call DestroyEffect(AddSpecialEffectZ(LaserImpactFX[tID], IMPACT_X, IMPACT_Y, IMPACT_Z))
endif
endif
//Area
if LaserAreaFX[tID] != null then
set b = true
if IsLaserGrounded[tID] then
call DestroyEffect(AddSpecialEffect(LaserAreaFX[tID], IMPACT_X, IMPACT_Y))
else
call DestroyEffect(AddSpecialEffectZ(LaserAreaFX[tID], IMPACT_X, IMPACT_Y, IMPACT_Z))
endif
endif
//Laser
if LaserString[tID] != null then
set b = true
set LaserSource[NewTimerID] = LaserSource[tID]
set LaserTarget[NewTimerID] = LaserTarget[tID]
set LaserSentry[NewTimerID] = LaserSentry[tID]
set LaserLaunchOffset[NewTimerID] = LaserLaunchOffset[tID]
set LaserLaunchHeight[NewTimerID] = LaserLaunchHeight[tID]
set LaserLaunchAngle[NewTimerID] = LaserLaunchAngle[tID]
set LaserImpactX[NewTimerID] = IMPACT_X
set LaserImpactY[NewTimerID] = IMPACT_Y
set LaserImpactZ[NewTimerID] = IMPACT_Z
set IsLaserLockedToTarget[NewTimerID] = IsLaserLockedToTarget[tID]
if IsLaserLockedToTarget[NewTimerID] then
set LaserLockAngle[NewTimerID] = Atan2(IMPACT_Y - TARGET_Y, IMPACT_X - TARGET_X)
set LaserLockDistance[NewTimerID] = SquareRoot( (IMPACT_X-TARGET_X)*(IMPACT_X-TARGET_X) + (IMPACT_Y-TARGET_Y)*(IMPACT_Y-TARGET_Y) )
set LaserLockHeight[NewTimerID] = IMPACT_Z - GetUnitZ(LaserTarget[tID])
endif
set LaserRED[NewTimerID] = LaserRED[tID]
set LaserBLUE[NewTimerID] = LaserBLUE[tID]
set LaserGREEN[NewTimerID] = LaserGREEN[tID]
set LaserALPHA[NewTimerID] = LaserALPHA[tID]
set Laser[NewTimerID] = AddLightningEx(LaserString[tID], true, LAUNCH_X, LAUNCH_Y, LAUNCH_Z, IMPACT_X, IMPACT_Y, IMPACT_Z)
call SetLightningColor(Laser[NewTimerID], LaserRED[NewTimerID], LaserBLUE[NewTimerID], LaserGREEN[NewTimerID], LaserALPHA[NewTimerID])
set FadeAmount[NewTimerID] = LaserALPHA[NewTimerID] / FadeAmount[tID]
endif
//Damage
if LaserAOE[tID] > 0. then
call GroupEnumUnitsInRange(DamageGroup, IMPACT_X, IMPACT_Y, LaserAOE[tID] + MAX_COLLISION_SIZE, null)
loop
set u = FirstOfGroup(DamageGroup)
call GroupRemoveUnit(DamageGroup, u)
exitwhen u == null
if IsUnitInRangeXY(u, IMPACT_X, IMPACT_Y, LaserAOE[tID]) and UnitAlive(u) and /*
[Friendly Fire] */( (LaserFriendlyFire[tID] and (IsUnitEnemy(u, SourcePlayer) or IsUnitAlly(u, SourcePlayer))) or /*
[Enemy] */ ( (not LaserFriendlyFire[tID] and IsUnitEnemy(u, SourcePlayer)) or /*
[Friendly] */ (not LaserFriendlyFire[tID] and IsUnitAlly(u, SourcePlayer) and u == LaserTarget[tID]) ) ) and /*
[Magic Immune] */( (LaserAttackType[tID] == ATTACK_TYPE_MAGIC and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) or /*
[Ethereal] */ (LaserAttackType[tID] != ATTACK_TYPE_MAGIC and not IsUnitType(u, UNIT_TYPE_ETHEREAL)) ) then
if not LaserHitAll[tID] and /*
[Ground] */ ( (not IsUnitType(u, UNIT_TYPE_FLYING) and not IsUnitType(LaserTarget[tID], UNIT_TYPE_FLYING)) or /*
[Flying] */ (IsUnitType(u, UNIT_TYPE_FLYING) and IsUnitType(LaserTarget[tID], UNIT_TYPE_FLYING)) ) then
set udg_NextDamageType = LaserDamageType[tID]
call UnitDamageTarget(LaserSource[tID], u, LaserDamage[tID], true, true, LaserAttackType[tID], DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
elseif LaserHitAll[tID] then
set udg_NextDamageType = LaserDamageType[tID]
call UnitDamageTarget(LaserSource[tID], u, LaserDamage[tID], true, true, LaserAttackType[tID], DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
endif
endif
endloop
else
set udg_NextDamageType = LaserDamageType[tID]
call UnitDamageTarget(LaserSource[tID], LaserTarget[tID], LaserDamage[tID], true, true, LaserAttackType[tID], DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
endif
//Timer
if b then
set LaserDuration[NewTimerID] = LaserDuration[tID]
set IsLaserFading[NewTimerID] = false
set New_t = NewTimerEx(NewTimerID)
call TimerStart(New_t, .03125, true, function IndividualLaser_Timer)
set New_t = null
set b = false
else
call IndexDeallocate(NewTimerID)
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
if LaserCount[tID] <= 0 or not UnitAlive(LaserSource[tID]) or /*
[Move] */ GetUnitCurrentOrder(LaserSource[tID]) == 851986 or /*
[Stunned] */ GetUnitCurrentOrder(LaserSource[tID]) == 851973 or /*
[Stop] */ GetUnitCurrentOrder(LaserSource[tID]) == 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
set LaserSource[tID] = null
set LaserTarget[tID] = null
call IndexDeallocate(tID)
call ReleaseTimer(t)
endif
endfunction
public function FireLaser takes unit Source, integer Source_ID, unit Target, unit Sentry, real Damage returns nothing
local timer t = null
local integer tID = 0
local integer NewTimerID = 0
local unit u = null
local real TargetColl = GetUnitCollision(Target)
local real SOURCE_X = GetUnitX(Source)
local real SOURCE_Y = GetUnitY(Source)
local real TARGET_X = GetUnitX(Target)
local real TARGET_Y = GetUnitY(Target)
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 real Angle = Atan2(TARGET_Y - SOURCE_Y, TARGET_X - SOURCE_X)
local real RangeOffset = 0.
local boolean b = false
local player SourcePlayer = GetOwningPlayer(Source)
if Sentry == null then
if BL_LaserLaunchOffset[Source_ID] > 0. then
set LAUNCH_X = SOURCE_X + Cos(Angle + BL_LaserLaunchAngle[Source_ID]) * BL_LaserLaunchOffset[Source_ID]
set LAUNCH_Y = SOURCE_Y + Sin(Angle + BL_LaserLaunchAngle[Source_ID]) * BL_LaserLaunchOffset[Source_ID]
else
set LAUNCH_X = SOURCE_X
set LAUNCH_Y = SOURCE_Y
endif
set LAUNCH_Z = GetUnitZ(Source) + BL_LaserLaunchHeight[Source_ID]
else
if BL_LaserLaunchOffset[Source_ID] > 0. then
set LAUNCH_X = GetUnitX(Sentry) + Cos(Angle + BL_LaserLaunchAngle[Source_ID]) * BL_LaserLaunchOffset[Source_ID]
set LAUNCH_Y = GetUnitY(Sentry) + Sin(Angle + BL_LaserLaunchAngle[Source_ID]) * BL_LaserLaunchOffset[Source_ID]
else
set LAUNCH_X = GetUnitX(Sentry)
set LAUNCH_Y = GetUnitY(Sentry)
endif
set LAUNCH_Z = GetUnitZ(Sentry) + BL_LaserLaunchHeight[Source_ID]
endif
set RangeOffset = ((BL_NumberOfLasers[Source_ID]-1) * BL_LaserRangePerLaser[Source_ID] + BL_LaserRangeStart[Source_ID]) * .5
if BL_LaserRangeLock[Source_ID] then //if true, start from the source's point
set LaserImpactX[Source_ID] = SOURCE_X + Cos(Angle) * (RangeOffset + BL_LaserRangeStart[Source_ID])
set LaserImpactY[Source_ID] = SOURCE_Y + Sin(Angle) * (RangeOffset + BL_LaserRangeStart[Source_ID])
set Angle = Angle + BL_LaserDirectionalTilt[Source_ID]
set LaserImpactX[Source_ID] = LaserImpactX[Source_ID] + Cos(Angle) * (RangeOffset)
set LaserImpactY[Source_ID] = LaserImpactY[Source_ID] + Sin(Angle) * (RangeOffset)
set IMPACT_X = LaserImpactX[Source_ID] + GetRandomReal(BL_LaserSpreadXY[Source_ID]*-1, BL_LaserSpreadXY[Source_ID])
set IMPACT_Y = LaserImpactY[Source_ID] + GetRandomReal(BL_LaserSpreadXY[Source_ID]*-1, BL_LaserSpreadXY[Source_ID])
if BL_IsLaserGrounded[Source_ID] then
set LaserImpactZ[Source_ID] = 0.
set IMPACT_Z = 0.
else
set LaserImpactZ[Source_ID] = GetUnitZ(Target)
set IMPACT_Z = LaserImpactZ[Source_ID] + GetRandomReal(BL_LaserSpreadZ[Source_ID] * -1, BL_LaserSpreadZ[Source_ID]) + TargetColl * .8
endif
else
set Angle = Angle + BL_LaserDirectionalTilt[Source_ID] + 3.14159
if BL_LaserRangePerLaser[Source_ID] != 0. then
set LaserImpactX[Source_ID] = TARGET_X + Cos(Angle) * (RangeOffset + BL_LaserRangeStart[Source_ID])
set LaserImpactY[Source_ID] = TARGET_Y + Sin(Angle) * (RangeOffset + BL_LaserRangeStart[Source_ID])
else
set LaserImpactX[Source_ID] = TARGET_X + Cos(Angle) * (TargetColl*.8)
set LaserImpactY[Source_ID] = TARGET_Y + Sin(Angle) * (TargetColl*.8)
endif
set IMPACT_X = LaserImpactX[Source_ID] + GetRandomReal(BL_LaserSpreadXY[Source_ID] * -1, BL_LaserSpreadXY[Source_ID])
set IMPACT_Y = LaserImpactY[Source_ID] + GetRandomReal(BL_LaserSpreadXY[Source_ID] * -1, BL_LaserSpreadXY[Source_ID])
if BL_IsLaserGrounded[Source_ID] then
set LaserImpactZ[Source_ID] = 0.
set IMPACT_Z = 0.
else
set LaserImpactZ[Source_ID] = GetUnitZ(Target)
set IMPACT_Z = LaserImpactZ[Source_ID] + GetRandomReal(BL_LaserSpreadZ[Source_ID] * -1, BL_LaserSpreadZ[Source_ID]) + TargetColl * .8
endif
endif
set NewTimerID = IndexAllocate()
//Launch
if BL_LaserLaunchFX[Source_ID] != null then
set b = true
call DestroyEffect(AddSpecialEffectZ(BL_LaserLaunchFX[Source_ID], LAUNCH_X, LAUNCH_Y, LAUNCH_Z))
endif
//Impact
if BL_LaserImpactFX[Source_ID] != null then
set b = true
if BL_IsLaserGrounded[Source_ID] then
call DestroyEffect(AddSpecialEffect(BL_LaserImpactFX[Source_ID], IMPACT_X, IMPACT_Y))
else
call DestroyEffect(AddSpecialEffectZ(BL_LaserImpactFX[Source_ID], IMPACT_X, IMPACT_Y, IMPACT_Z))
endif
endif
//Area
if BL_LaserAreaFX[Source_ID] != null then
set b = true
if BL_IsLaserGrounded[Source_ID] then
call DestroyEffect(AddSpecialEffect(BL_LaserAreaFX[Source_ID], IMPACT_X, IMPACT_Y))
else
call DestroyEffect(AddSpecialEffectZ(BL_LaserAreaFX[Source_ID], IMPACT_X, IMPACT_Y, IMPACT_Z))
endif
endif
//Laser
if BL_LaserString[Source_ID] != null then
set b = true
set LaserSource[NewTimerID] = Source
set LaserTarget[NewTimerID] = Target
set LaserSentry[NewTimerID] = Sentry
set LaserLaunchOffset[NewTimerID] = BL_LaserLaunchOffset[Source_ID]
set LaserLaunchHeight[NewTimerID] = BL_LaserLaunchHeight[Source_ID]
set LaserLaunchAngle[NewTimerID] = BL_LaserLaunchAngle[Source_ID]
set IsLaserLockedToTarget[NewTimerID] = BL_LaserLightningLock[Source_ID]
set LaserImpactX[NewTimerID] = IMPACT_X
set LaserImpactY[NewTimerID] = IMPACT_Y
set LaserImpactZ[NewTimerID] = IMPACT_Z
set LaserRED[NewTimerID] = BL_RED[Source_ID]
set LaserBLUE[NewTimerID] = BL_BLUE[Source_ID]
set LaserGREEN[NewTimerID] = BL_GREEN[Source_ID]
set LaserALPHA[NewTimerID] = BL_ALPHA[Source_ID]
set Laser[NewTimerID] = AddLightningEx(LaserString[Source_ID], true, LAUNCH_X, LAUNCH_Y, LAUNCH_Z, IMPACT_X, IMPACT_Y, IMPACT_Z)
call SetLightningColor(Laser[NewTimerID], LaserRED[NewTimerID], LaserBLUE[NewTimerID], LaserGREEN[NewTimerID], LaserALPHA[NewTimerID])
set FadeAmount[NewTimerID] = LaserALPHA[NewTimerID] / BL_LaserFadeTime[Source_ID]
endif
//Damage
if BL_LaserAOE[Source_ID] > 0. then
call GroupEnumUnitsInRange(DamageGroup, IMPACT_X, IMPACT_Y, BL_LaserAOE[Source_ID] + MAX_COLLISION_SIZE, null)
loop
set u = FirstOfGroup(DamageGroup)
call GroupRemoveUnit(DamageGroup, u)
exitwhen u == null
if IsUnitInRangeXY(u, IMPACT_X, IMPACT_Y, BL_LaserAOE[Source_ID]) and UnitAlive(u) and /*
[Friendly Fire] */( (BL_LaserFriendlyFire[Source_ID] and (IsUnitEnemy(u, SourcePlayer) or IsUnitAlly(u, SourcePlayer))) or /*
[Enemy] */ ( (not LaserFriendlyFire[Source_ID] and IsUnitEnemy(u, SourcePlayer)) or /*
[Friendly] */ (not LaserFriendlyFire[Source_ID] and IsUnitAlly(u, SourcePlayer) and u == udg_DamageEventTarget) ) ) and /*
[Magic Immune] */( (BL_LaserAttackType[Source_ID] == ATTACK_TYPE_MAGIC and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) or /*
[Ethereal] */ (BL_LaserAttackType[Source_ID] != ATTACK_TYPE_MAGIC and not IsUnitType(u, UNIT_TYPE_ETHEREAL)) ) then
if not BL_LaserHitAll[Source_ID] and /*
[Ground] */ ( (not IsUnitType(u, UNIT_TYPE_FLYING) and not IsUnitType(Target, UNIT_TYPE_FLYING)) or /*
[Flying] */ (IsUnitType(u, UNIT_TYPE_FLYING) and IsUnitType(udg_DamageEventTarget, UNIT_TYPE_FLYING)) ) then
set udg_NextDamageType = BL_LaserDamageType[Source_ID]
call UnitDamageTarget(Source, u, Damage, true, true, BL_LaserAttackType[Source_ID], DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
elseif BL_LaserHitAll[Source_ID] then
set udg_NextDamageType = LaserDamageType[Source_ID]
call UnitDamageTarget(Source, u, Damage, true, true, BL_LaserAttackType[Source_ID], DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
endif
endif
endloop
else
set udg_NextDamageType = BL_LaserDamageType[Source_ID]
call UnitDamageTarget(Source, Target, Damage, true, true, BL_LaserAttackType[Source_ID], DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call TriggerEvaluate(udg_ClearDamageEvent)
endif
//EVENT
set BL_EVENT_Source = Source
set BL_EVENT_Target = Target
set BL_EVENT_Sentry = BL_LaserSentry[Source_ID]
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 = 1.
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
if BL_NumberOfLasers[Source_ID] > 1 then
set tID = IndexAllocate()
set t = NewTimerEx(tID)
set LaserSource[tID] = Source
set LaserTarget[tID] = Target
set LaserSentry[tID] = Sentry
set LaserDamage[tID] = Damage
set LaserAOE[tID] = BL_LaserAOE[Source_ID]
set LaserAttackType[tID] = BL_LaserAttackType[Source_ID]
set LaserDamageType[tID] = BL_LaserDamageType[Source_ID]
set LaserHitAll[tID] = BL_LaserHitAll[Source_ID]
set LaserFriendlyFire[tID] = BL_LaserFriendlyFire[Source_ID]
set LaserLaunchFX[tID] = BL_LaserLaunchFX[Source_ID]
set LaserImpactFX[tID] = BL_LaserImpactFX[Source_ID]
set LaserAreaFX[tID] = BL_LaserAreaFX[Source_ID]
set LaserDuration[tID] = BL_LaserDuration[Source_ID]
set LaserCount[tID] = BL_NumberOfLasers[Source_ID] - 1
set LaserLaunchOffset[tID] = BL_LaserLaunchOffset[Source_ID]
set LaserLaunchHeight[tID] = BL_LaserLaunchHeight[Source_ID]
set LaserLaunchAngle[tID] = BL_LaserLaunchAngle[Source_ID] * bj_DEGTORAD
set LaserSpreadXY[tID] = BL_LaserSpreadXY[Source_ID]
set LaserSpreadZ[tID] = BL_LaserSpreadZ[Source_ID]
set LaserLaunchFX[tID] = BL_LaserLaunchFX[Source_ID]
set LaserImpactFX[tID] = BL_LaserImpactFX[Source_ID]
set LaserAreaFX[tID] = BL_LaserAreaFX[Source_ID]
set LaserTargetLock[tID] = BL_LaserTargetLock[Source_ID]
set LaserRangeLock[tID] = BL_LaserRangeLock[Source_ID]
set LaserRangeStart[tID] = BL_LaserRangeStart[Source_ID]
set LaserRangePerLaser[tID] = BL_LaserRangePerLaser[Source_ID]
set IsLaserLockedToTarget[tID] = BL_LaserLightningLock[Source_ID]
set IsLaserGrounded[tID] = BL_IsLaserGrounded[Source_ID]
set LaserImpactX[tID] = LaserImpactX[Source_ID]
set LaserImpactY[tID] = LaserImpactY[Source_ID]
set LaserImpactZ[tID] = LaserImpactZ[Source_ID]
set LaserAngle[tID] = Angle + 3.14159
set LaserString[tID] = BL_LaserString[Source_ID]
set LaserRED[tID] = BL_RED[Source_ID]
set LaserBLUE[tID] = BL_BLUE[Source_ID]
set LaserGREEN[tID] = BL_GREEN[Source_ID]
set LaserALPHA[tID] = BL_ALPHA[Source_ID]
set IsLaserFading[tID] = false
set FadeAmount[tID] = BL_LaserFadeTime[Source_ID]
set InitialX[tID] = LaserImpactX[Source_ID]
set InitialY[tID] = LaserImpactY[Source_ID]
call TimerStart(t, BL_LaserInterval[Source_ID], true, function BurstLaser_Timer)
set t = null
endif
//Timer
if b then
set LaserDuration[NewTimerID] = BL_LaserDuration[Source_ID]
set IsLaserFading[NewTimerID] = false
set t = NewTimerEx(NewTimerID)
call TimerStart(t, .03125, true, function IndividualLaser_Timer)
set t = null
set b = false
else
call IndexDeallocate(NewTimerID)
endif
endfunction
endlibrary
/*
This is NOT an efficient way of making such a spell, but it is meant solely as a means to show you
that Burst Laser can be used for more than just custom attacks. For instance, if you want a line spell
that behave like the Gryphon's line attack, then it can be done. I'm not sure why this spell lags like
a b*tch, but again, not an example to follow, just a demonstration that it's possible to make a spell
fire a Laser set just like an attack.
*/
scope ArcaneSpells initializer ArcaneSpells_Init
globals
private trigger ArcaneSpells_Trigger = CreateTrigger()
private integer array TimerCount
private unit array TimerSource
//private unit array TimerTarget
private unit array TimerSentry
private real array TimerDamage
private real array TimerX
private real array TimerY
private real array TimerAngle
private real array TimerDistance
private integer array TimerSpellInstance
private unit TARGET_DUMMY = null
private constant string SENTRY_FX = "Abilities\\Spells\\Human\\Invisibility\\InvisibilityTarget.mdl"
endglobals
function AW_Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer tID = GetTimerData(t)
local integer TI_tID = TimerSpellInstance[tID]
set TimerCount[tID] = TimerCount[tID] - 1
if TimerCount[tID] <= 0 then
set BL_LaserString[TI_tID] = null
set BL_RED[TI_tID] = 1.
set BL_BLUE[TI_tID] = 1.
set BL_GREEN[TI_tID] = 1.
set BL_ALPHA[TI_tID] = 1.
set BL_LaserLaunchFX[TI_tID] = null
set BL_LaserImpactFX[TI_tID] = null
set BL_LaserAreaFX[TI_tID] = null
set BL_NumberOfLasers[TI_tID] = 1
set BL_LaserDuration[TI_tID] = 1
set BL_LaserFadeTime[TI_tID] = 1
set BL_LaserInterval[TI_tID] = 0.
set BL_LaserAOE[TI_tID] = 0.
set BL_IsLaserGrounded[TI_tID] = false
set BL_LaserLaunchOffset[TI_tID] = 0.
set BL_LaserLaunchHeight[TI_tID] = 0.
set BL_LaserLaunchAngle[TI_tID] = 0.
set BL_LaserLaunchScatterX[TI_tID] = 0.
set BL_LaserLaunchScatterY[TI_tID] = 0.
set BL_LaserLaunchScatterZ[TI_tID] = 0.
set BL_LaserImpactScatterX[TI_tID] = 0.
set BL_LaserImpactScatterY[TI_tID] = 0.
set BL_LaserImpactScatterZ[TI_tID] = 0.
set BL_FollowTarget[TI_tID] = false
set BL_FloatingLaunch[TI_tID] = false
set BL_LaserImpactLock[TI_tID] = false
set BL_LaserRangeLock[TI_tID] = false
set BL_LaserRangeStart[TI_tID] = 0.
set BL_LaserRangePerLaser[TI_tID] = 0.
set BL_LaserDirectionalTilt[TI_tID]= 0.
set BL_LaserAttackType[TI_tID] = null
set BL_LaserDamageType[TI_tID] = 0
set BL_LaserDivideDamage[TI_tID] = false
set BL_Uninterruptible[TI_tID] = false
set BL_LaserHitAll[TI_tID] = false
set BL_LaserFriendlyFire[TI_tID] = false
set TimerSource[tID] = null
//set TimerTarget[tID] = null
call UnitApplyTimedLife(TimerSentry[tID], 'BTLF', 2.)
set TimerSentry[tID] = null
set TimerDamage[tID] = 0.
set TimerAngle[tID] = 0.
set TimerDistance[tID] = 0.
call IndexDeallocate(TimerSpellInstance[tID])
set TimerSpellInstance[tID] = 0
call ReleaseTimer(t)
call IndexDeallocate(tID)
endif
set TimerX[tID] = TimerX[tID] + Cos(TimerAngle[tID]) * TimerDistance[tID]
set TimerY[tID] = TimerY[tID] + Sin(TimerAngle[tID]) * TimerDistance[tID]
call SetUnitX(TARGET_DUMMY, TimerX[tID])
call SetUnitY(TARGET_DUMMY, TimerY[tID])
call DestroyEffect(AddSpecialEffectTarget(SENTRY_FX, TimerSentry[tID], "origin"))
call BurstLaser.create(TimerSource[tID], TARGET_DUMMY, TimerSentry[tID], TI_tID, TimerDamage[tID])
endfunction
function ArcaneSpells_Actions takes nothing returns boolean
local integer SpellInstance = 0
local integer TimerInstance = 0
local unit Source = null
local real x = 0.
local real y = 0.
local real x2 = 0.
local real y2 = 0.
local timer t = null
if TARGET_DUMMY == null then
set TARGET_DUMMY = CreateUnit(Player(14), 'dumi', 0., 0., 0.)
endif
//Arcane Wall
if GetSpellAbilityId() == 'Aarw' then
set SpellInstance = IndexAllocate()
set TimerInstance = IndexAllocate()
set Source = GetTriggerUnit()
set x = GetUnitX(Source)
set y = GetUnitY(Source)
set x2 = GetLocationX(GetSpellTargetLoc())
set y2 = GetLocationY(GetSpellTargetLoc())
set TimerAngle[TimerInstance] = Atan2(y2 - y, x2 - x)
set TimerDistance[TimerInstance] = 90.
set TimerX[TimerInstance] = x + Cos(TimerAngle[TimerInstance]) * TimerDistance[TimerInstance]
set TimerY[TimerInstance] = y + Sin(TimerAngle[TimerInstance]) * TimerDistance[TimerInstance]
set BL_LaserString[SpellInstance] = "ARBM"
set BL_RED[SpellInstance] = 1.
set BL_BLUE[SpellInstance] = 1.
set BL_GREEN[SpellInstance] = 1.
set BL_ALPHA[SpellInstance] = 1.
set BL_LaserLaunchFX[SpellInstance] = "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
set BL_LaserImpactFX[SpellInstance] = "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
set BL_LaserAreaFX[SpellInstance] = null//"Abilities\\Spells\\Undead\\OrbOfDeath\\OrbOfDeathMissile.mdl"
set BL_NumberOfLasers[SpellInstance] = 13
set BL_LaserDuration[SpellInstance] = 7
set BL_LaserFadeTime[SpellInstance] = 5
set BL_LaserInterval[SpellInstance] = 0.
set BL_LaserAOE[SpellInstance] = 110.
set BL_IsLaserGrounded[SpellInstance] = false
set BL_LaserLaunchOffset[SpellInstance] = 40.
set BL_LaserLaunchHeight[SpellInstance] = 20.
set BL_LaserLaunchAngle[SpellInstance] = 0.
set BL_LaserLaunchScatterX[SpellInstance] = 0.
set BL_LaserLaunchScatterY[SpellInstance] = 0.
set BL_LaserLaunchScatterZ[SpellInstance] = 0.
set BL_LaserImpactScatterX[SpellInstance] = 50.
set BL_LaserImpactScatterY[SpellInstance] = 50.
set BL_LaserImpactScatterZ[SpellInstance] = 0.
set BL_FollowTarget[SpellInstance] = false
set BL_FloatingLaunch[SpellInstance] = false
set BL_LaserImpactLock[SpellInstance] = false
set BL_LaserRangeLock[SpellInstance] = false
set BL_LaserRangeStart[SpellInstance] = 0.
set BL_LaserRangePerLaser[SpellInstance] = 50.
set BL_LaserDirectionalTilt[SpellInstance]= 1.5708
set BL_LaserAttackType[SpellInstance] = ATTACK_TYPE_PIERCE
set BL_LaserDamageType[SpellInstance] = udg_DamageTypeCode
set BL_LaserDivideDamage[SpellInstance] = false
set BL_Uninterruptible[SpellInstance] = true
set BL_LaserHitAll[SpellInstance] = false
set BL_LaserFriendlyFire[SpellInstance] = false
set TimerSource[TimerInstance] = GetTriggerUnit()
//set TimerTarget[SpellInstance] = null
call SetUnitX(TARGET_DUMMY, TimerX[TimerInstance])
call SetUnitY(TARGET_DUMMY, TimerY[TimerInstance])
set TimerSentry[TimerInstance] = CreateUnit(Player(14), 'dumi', x, y, 0.)
call SetUnitZ(TimerSentry[TimerInstance], 300.)
set TimerDamage[TimerInstance] = 30.
set TimerCount[TimerInstance] = 9
set TimerSpellInstance[TimerInstance] = SpellInstance
call BurstLaser.create(Source, TARGET_DUMMY, TimerSentry[TimerInstance], SpellInstance, TimerDamage[TimerInstance])
set t = NewTimerEx(TimerInstance)
call TimerStart(t, .25, true, function AW_Timer)
set t = null
//Arcane Barrage
//elseif GetSpellAbilityId() == 'Aaba' then
//I got lazy, sorry
endif
return false
endfunction
//===========================================================================
function ArcaneSpells_Init takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ( ArcaneSpells_Trigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( ArcaneSpells_Trigger, function ArcaneSpells_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SpecialEffectZ /* v1.0.0.0
*******************************************************************
*
* Allows you to add a special effect with a Z value.
*
*******************************************************************
*
* function AddSpecialEffectZ takes string model, real x, real y, real z returns effect
*
*******************************************************************/
globals
private destructable platform
private effect zEffect
endglobals
function AddSpecialEffectZ takes string model, real x, real y, real z returns effect
set platform = CreateDestructableZ('OTip', x, y, z, 0, 1, 0)
set zEffect = AddSpecialEffect(model, x, y)
call RemoveDestructable(platform)
return zEffect
endfunction
endlibrary
//TESH.scrollpos=262
//TESH.alwaysfold=0
library BL initializer BurstLaser_PreloadWeapons
/*** 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 BurstLaserPreloadTrigger = CreateTrigger()
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 integer array LaserLingerInterval//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.
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 LaserLaunchScatterX //How much your laser's launch will scatter along the X axis.
public real array LaserLaunchScatterY //How much your laser's launch will scatter along the Y axis.
public real array LaserLaunchScatterZ //How much your laser's launch will scatter along the Z axis.
public real array LaserLaunchScale //The size of your launch special effects. 1. is 100%.
public real array LaserImpactScatterX //How much your laser will spread out along the X axis.
public real array LaserImpactScatterY //How much your laser will spread out along the Y axis.
public real array LaserImpactScatterZ //How much your laser will spread out along the Z axis.
public real array LaserImpactScale //The size of your impact special effects. 1. is 100%.
public real array LaserAreaScale //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.
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 FloatingLaunch //If true, lasers will not follow source if it moves away.
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 boolean array ReduceLaunchOverhead //If true, only 1 dummywill 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.
public boolean array ReduceImpactOverhead //Same as above, but for impacts and area special effects.
endglobals
function BurstLaser_onPreload takes nothing returns boolean
local integer WPN_ID = 0
//0
//Rifleman - Heat Spears
set LaserString[WPN_ID] = "YLLN" //This is the lightning effect that will be used. Can be null.
set RED[WPN_ID] = 1. //This is the red tint of your lightning effect. 1.0 is 100% and 0.0 is 0%.
set BLUE[WPN_ID] = 1. //This is the blue tint of your lightning effect. 1.0 is 100% and 0.0 is 0%.
set GREEN[WPN_ID] = 1. //This is the green tint of your lightning effect. 1.0 is 100% and 0.0 is 0%.
set ALPHA[WPN_ID] = .85 //This is the opacity of your lightning effect. 1.0 is fully visible and 0.0 is completely invisible.
set LaserLaunchFX[WPN_ID] = "war3mapImported\\FaerieDragonMissile_Lesser_NoMS.mdx" //The special effect that plays at the launch coordinates.
set LaserImpactFX[WPN_ID] = "war3mapImported\\FaerieDragonMissile_Lesser_NoMS.mdx" //The special effect that plays at the impact coordinates.
set LaserAreaFX[WPN_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 LaserLaunchScale[WPN_ID] = 1. //The size of your launch special effects. 1. is 100%.
set LaserImpactScale[WPN_ID] = 1. //The size of your impact AND area special effects*. 1. is 100%.
set LaserAreaScale[WPN_ID] = 1. //*If this is different from LaserImpactScale[WPN_ID], it will generate more overhead. Keep the same value as above unless absolutely necessary.
set NumberOfLasers[WPN_ID] = 3 //Number of lasers that get fired. CANNOT BE LOWER THATN 1.
set LaserDuration[WPN_ID] = 5 //This is the duration before the lightning effect begins to fade. 32 == 1 second. 5 == .15625 seconds.
set LaserFadeTime[WPN_ID] = 5 /*** CANNOT LESS THAN 1 OR IT WILL CRASH THE WHOLE THING ***/ //This is how long it will take for the lightning effect to fade completely.
set LaserInterval[WPN_ID] = 0.075 //This is the interval, in seconds, between shots.
set LaserLingerInterval[WPN_ID] = 0 //Number of intervals that will pass before the sfx and damage are repeated PER LASER. Leave <= 0 to ignore.
set LaserAOE[WPN_ID] = 0. //If greater that 0., will deal damage in an area.
set IsLaserGrounded[WPN_ID] = false //If true, all your lasers will impact the terrain, regardless of what you're attacking
set LaserLaunchOffset[WPN_ID] = 70. //This moves your launch coordinate towards or away from your target.
set LaserLaunchHeight[WPN_ID] = 45. //This raises or lowers your launch coordinate.
set LaserLaunchAngle[WPN_ID] = 0. //This pivots your launch coordinates to align with off-center weapons on your unit model, for example. USES RADIANS.
set LaserLaunchScatterX[WPN_ID] = 0. //This scatters your lasers' launch along the X axis.
set LaserLaunchScatterY[WPN_ID] = 0. //This scatters your lasers' launch along the Y axis.
set LaserLaunchScatterZ[WPN_ID] = 0. //This scatters your lasers' launch along the Z axis.
set LaserImpactScatterX[WPN_ID] = 20. //This scatters your lasers' impact along the X axis.
set LaserImpactScatterY[WPN_ID] = 20. //This scatters your lasers' impact along the Y axis.
set LaserImpactScatterZ[WPN_ID] = 20. //This scatters your lasers' impact along the Z axis.
set LaserRangeStart[WPN_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[WPN_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[WPN_ID]= 0. //This pivots the beam so that it can travel in a different direction. USES RADIANS.
set FollowTarget[WPN_ID] = true //If false, consequent lasers for a set will continue along the same angle the initial beam was fired.
set FloatingLaunch[WPN_ID] = false //If true, lasers will not follow the source if it moves away.
set LaserImpactLock[WPN_ID] = false //If true, the laser will maintain a lock on their impact location, moving along with their target.
set LaserRangeLock[WPN_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[WPN_ID] = ATTACK_TYPE_PIERCE //Your attack type.
set LaserDamageType[WPN_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[WPN_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[WPN_ID] = false //If false, a laser set will end prematurely if the attacker moves or dies or is ordered to stop.
set LaserHitAll[WPN_ID] = false //If true, and LaserAOE[WPN_ID] is > 0., then the area damage will apply to both ground and flying units.
set LaserFriendlyFire[WPN_ID] = false //If true, and LaserAOE[WPN_ID] is > 0., area damage attacks will affect friendly units and allies as well.
set ReduceLaunchOverhead[WPN_ID]= true //Reduces lag by limited the number of dummies for the launch to 1. May cause some special effects to skip all over the place.
set ReduceImpactOverhead[WPN_ID]= true //Same as above, but for your impacts and area special effects
set WPN_ID = WPN_ID + 1
// 1
//Gryphon Rider - Lightning Barrage
/*
This example shows how you can make lasers strike in a line. It's worth noting that this method is particularly heavy in performance because:
A) It has 8 lasers per set, but the reason this is a problem, per se, is that ReduceImpactOverhead is false, which means it will create an impact dummy PER laser.
B) The LaserImpactScale and LaserAreaScale both have effects and are of different values, which means that instead of tacking on the Area special effects onto the
the Impact dummies, it will create its own Area dummies. So already that's 16 dummes + 1 for launch for ONE gruphon rider. It's excessive, and should only
be reserved for something like boss battles and/or if your PC is an absolute beast.
*/
set LaserString[WPN_ID] = "SLSB"
set RED[WPN_ID] = 1.
set BLUE[WPN_ID] = 1.
set GREEN[WPN_ID] = 1.
set ALPHA[WPN_ID] = 1.
set LaserLaunchFX[WPN_ID] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
set LaserImpactFX[WPN_ID] = "Abilities\\Weapons\\GryphonRiderMissile\\GryphonRiderMissile.mdl"
set LaserAreaFX[WPN_ID] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
set LaserLaunchScale[WPN_ID] = 1.
set LaserImpactScale[WPN_ID] = .75
set LaserAreaScale[WPN_ID] = 1.5
set NumberOfLasers[WPN_ID] = 8
set LaserDuration[WPN_ID] = 10
set LaserFadeTime[WPN_ID] = 4
set LaserInterval[WPN_ID] = .0624
set LaserLingerInterval[WPN_ID] = 0
set LaserAOE[WPN_ID] = 100.
set IsLaserGrounded[WPN_ID] = true
set LaserLaunchOffset[WPN_ID] = 80.
set LaserLaunchHeight[WPN_ID] = 80.
set LaserLaunchAngle[WPN_ID] = 0.
set LaserLaunchScatterX[WPN_ID] = 0.
set LaserLaunchScatterY[WPN_ID] = 0.
set LaserLaunchScatterZ[WPN_ID] = 0.
set LaserImpactScatterX[WPN_ID] = 50.
set LaserImpactScatterY[WPN_ID] = 50.
set LaserImpactScatterZ[WPN_ID] = 0.
set FollowTarget[WPN_ID] = false
set FloatingLaunch[WPN_ID] = false
set LaserImpactLock[WPN_ID] = false
set LaserRangeLock[WPN_ID] = true
set LaserRangeStart[WPN_ID] = 80.
set LaserRangePerLaser[WPN_ID] = 80.
set LaserDirectionalTilt[WPN_ID]= 3.14159
set LaserAttackType[WPN_ID] = ATTACK_TYPE_PIERCE
set LaserDamageType[WPN_ID] = udg_DamageTypeCode
set LaserDivideDamage[WPN_ID] = false
set Uninterruptible[WPN_ID] = false
set LaserHitAll[WPN_ID] = false
set LaserFriendlyFire[WPN_ID] = false
set ReduceLaunchOverhead[WPN_ID]= true
set ReduceImpactOverhead[WPN_ID]= false
set WPN_ID = WPN_ID + 1
// 2
//Gargoyle - Necroshear
/*
This is a variation on the gryphon's line attack, but strikes in a perpendicular line instead, similar to the Colossus from Starcraft II.
This is achieved by setting LaserDirectionalTilt to 1.5708 radians (90°). Note that all lasers fire simultaneously because LaserInterval is set to 0.
*/
set LaserString[WPN_ID] = "GRLN"
set RED[WPN_ID] = 1.
set BLUE[WPN_ID] = 1.
set GREEN[WPN_ID] = 1.
set ALPHA[WPN_ID] = 1.
set LaserLaunchFX[WPN_ID] = "Abilities\\Weapons\\KeeperGroveMissile\\KeeperGroveMissile.mdl"
set LaserImpactFX[WPN_ID] = "Abilities\\Weapons\\KeeperGroveMissile\\KeeperGroveMissile.mdl"
set LaserAreaFX[WPN_ID] = null
set LaserLaunchScale[WPN_ID] = 1.
set LaserImpactScale[WPN_ID] = 1.
set LaserAreaScale[WPN_ID] = 1.
set NumberOfLasers[WPN_ID] = 13
set LaserDuration[WPN_ID] = 7
set LaserFadeTime[WPN_ID] = 5
set LaserInterval[WPN_ID] = 0.
set LaserLingerInterval[WPN_ID] = 0
set LaserAOE[WPN_ID] = 70.
set IsLaserGrounded[WPN_ID] = false
set LaserLaunchOffset[WPN_ID] = 40.
set LaserLaunchHeight[WPN_ID] = 20.
set LaserLaunchAngle[WPN_ID] = 0.
set LaserLaunchScatterX[WPN_ID] = 0.
set LaserLaunchScatterY[WPN_ID] = 0.
set LaserLaunchScatterZ[WPN_ID] = 0.
set LaserImpactScatterX[WPN_ID] = 50.
set LaserImpactScatterY[WPN_ID] = 50.
set LaserImpactScatterZ[WPN_ID] = 50.
set FollowTarget[WPN_ID] = false
set FloatingLaunch[WPN_ID] = false
set LaserImpactLock[WPN_ID] = false
set LaserRangeLock[WPN_ID] = false
set LaserRangeStart[WPN_ID] = 0.
set LaserRangePerLaser[WPN_ID] = 35.
set LaserDirectionalTilt[WPN_ID]= 1.5708
set LaserAttackType[WPN_ID] = ATTACK_TYPE_PIERCE
set LaserDamageType[WPN_ID] = udg_DamageTypeCode
set LaserDivideDamage[WPN_ID] = false
set Uninterruptible[WPN_ID] = false
set LaserHitAll[WPN_ID] = false
set LaserFriendlyFire[WPN_ID] = false
set ReduceLaunchOverhead[WPN_ID]= true
set ReduceImpactOverhead[WPN_ID]= false
set WPN_ID = WPN_ID + 1
// 3
//Spellbreaker - Shock Assault
/*
While not visible in this trigger, it's possible to bind a Sentry to a unit, causing the lasers to fire from that dummy unit instead.
Refer to SentryCreate onIndex and SentryOrbit. Essentially, BL_LaserSentry[WPN_ID] must be set to a unit for this to work.
*/
set LaserString[WPN_ID] = "SLSB"
set RED[WPN_ID] = 1.
set BLUE[WPN_ID] = 1.
set GREEN[WPN_ID] = 1.
set ALPHA[WPN_ID] = 1.
set LaserLaunchFX[WPN_ID] = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
set LaserImpactFX[WPN_ID] = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
set LaserAreaFX[WPN_ID] = null
set LaserLaunchScale[WPN_ID] = 1.
set LaserImpactScale[WPN_ID] = 1.
set LaserAreaScale[WPN_ID] = 1.
set NumberOfLasers[WPN_ID] = 5
set LaserDuration[WPN_ID] = 15
set LaserFadeTime[WPN_ID] = 5
set LaserInterval[WPN_ID] = 0.12
set LaserLingerInterval[WPN_ID] = 0
set LaserAOE[WPN_ID] = 0.
set IsLaserGrounded[WPN_ID] = false
set LaserLaunchOffset[WPN_ID] = 0.
set LaserLaunchHeight[WPN_ID] = 0.
set LaserLaunchAngle[WPN_ID] = 0.
set LaserLaunchScatterX[WPN_ID] = 0.
set LaserLaunchScatterY[WPN_ID] = 0.
set LaserLaunchScatterZ[WPN_ID] = 0.
set LaserImpactScatterX[WPN_ID] = 30.
set LaserImpactScatterY[WPN_ID] = 30.
set LaserImpactScatterZ[WPN_ID] = 30.
set FollowTarget[WPN_ID] = true
set FloatingLaunch[WPN_ID] = false
set LaserImpactLock[WPN_ID] = true
set LaserRangeLock[WPN_ID] = false
set LaserRangeStart[WPN_ID] = 0.
set LaserRangePerLaser[WPN_ID] = 0.
set LaserDirectionalTilt[WPN_ID]= 0.
set LaserAttackType[WPN_ID] = ATTACK_TYPE_PIERCE
set LaserDamageType[WPN_ID] = udg_DamageTypeCode
set LaserDivideDamage[WPN_ID] = true
set Uninterruptible[WPN_ID] = true
set LaserHitAll[WPN_ID] = false
set LaserFriendlyFire[WPN_ID] = false
set ReduceLaunchOverhead[WPN_ID]= true
set ReduceImpactOverhead[WPN_ID]= true
set WPN_ID = WPN_ID + 1
// 4
//Archmage - Mystic Laser
/*
The Archmage is an example of scattering your launch coordinates.
*/
set LaserString[WPN_ID] = "ARBM"
set RED[WPN_ID] = 1.
set BLUE[WPN_ID] = 1.
set GREEN[WPN_ID] = 1.
set ALPHA[WPN_ID] = 1.
set LaserLaunchFX[WPN_ID] = "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
set LaserImpactFX[WPN_ID] = "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
set LaserAreaFX[WPN_ID] = null
set LaserLaunchScale[WPN_ID] = 1.
set LaserImpactScale[WPN_ID] = 1.
set LaserAreaScale[WPN_ID] = 1.
set NumberOfLasers[WPN_ID] = 5
set LaserDuration[WPN_ID] = 30
set LaserFadeTime[WPN_ID] = 8
set LaserInterval[WPN_ID] = 0.3
set LaserLingerInterval[WPN_ID] = 4
set LaserAOE[WPN_ID] = 0.
set IsLaserGrounded[WPN_ID] = false
set LaserLaunchOffset[WPN_ID] = 0.
set LaserLaunchHeight[WPN_ID] = 120.
set LaserLaunchAngle[WPN_ID] = 0.
set LaserLaunchScatterX[WPN_ID] = 90.
set LaserLaunchScatterY[WPN_ID] = 90.
set LaserLaunchScatterZ[WPN_ID] = 50.
set LaserImpactScatterX[WPN_ID] = 10.
set LaserImpactScatterY[WPN_ID] = 10.
set LaserImpactScatterZ[WPN_ID] = 10.
set FollowTarget[WPN_ID] = true
set FloatingLaunch[WPN_ID] = false
set LaserImpactLock[WPN_ID] = true
set LaserRangeLock[WPN_ID] = false
set LaserRangeStart[WPN_ID] = 0.
set LaserRangePerLaser[WPN_ID] = 0.
set LaserDirectionalTilt[WPN_ID]= 0.
set LaserAttackType[WPN_ID] = ATTACK_TYPE_PIERCE
set LaserDamageType[WPN_ID] = udg_DamageTypeCode
set LaserDivideDamage[WPN_ID] = true
set Uninterruptible[WPN_ID] = false
set LaserHitAll[WPN_ID] = false
set LaserFriendlyFire[WPN_ID] = false
set ReduceLaunchOverhead[WPN_ID]= true
set ReduceImpactOverhead[WPN_ID]= true
return false
endfunction
function BurstLaser_PreloadWeapons takes nothing returns nothing
call TriggerAddCondition( BurstLaserPreloadTrigger, function BurstLaser_onPreload)
endfunction
endlibrary
//TESH.scrollpos=155
//TESH.alwaysfold=0
library BL initializer BurstLaser_Create
/*** 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 BurstLaserIndexTrigger = CreateTrigger()
public integer array StructIndex
public boolean array UsesBurstLaser
public unit array LaserSentry
private constant integer MAX_WEAPONS = 5
endglobals
struct BLAssignWeapon
boolean UsesBurstLaser //Must always be true or the system won't work.
boolean array Uninterruptible[MAX_WEAPONS] //If true, lasers will keep firing even if the target 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 LaserImpactLock[MAX_WEAPONS] //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.
integer array NumberOfLasers[MAX_WEAPONS] //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
integer array LaserDuration[MAX_WEAPONS] //How long an individual laser will last before it starts to fade. 32 == 1 second.
integer 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.
integer array LaserLingerInterval[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 divide amoung the number of lasers.
boolean array FollowTarget[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 FloatingLaunch[MAX_WEAPONS] //If true, lasers will not follow source if it moves away.
boolean array LaserRangeLock[MAX_WEAPONS] //If true will set LaserRangeStart's starting point to the attacker (source of the laser) instead of the taret
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
call this.deallocate()
set this.LaserString[LASER_ID] = null
set this.RED[LASER_ID] = 1.
set this.BLUE[LASER_ID] = 1.
set this.GREEN[LASER_ID] = 1.
set this.ALPHA[LASER_ID] = 1.
set this.LaserLaunchFX[LASER_ID] = null
set this.LaserImpactFX[LASER_ID] = null
set this.LaserAreaFX[LASER_ID] = null
set this.LaserLaunchScale[LASER_ID] = 1.
set this.LaserImpactScale[LASER_ID] = 1.
set this.LaserAreaScale[LASER_ID] = 1.
set this.NumberOfLasers[LASER_ID] = 1
set this.LaserDuration[LASER_ID] = 0
set this.LaserFadeTime[LASER_ID] = 0
set this.LaserInterval[LASER_ID] = 0.
set this.LaserLingerInterval[LASER_ID] = 0
set this.LaserAOE[LASER_ID] = 0.
set this.IsLaserGrounded[LASER_ID] = false
set this.LaserLaunchOffset[LASER_ID] = 0.
set this.LaserLaunchHeight[LASER_ID] = 0.
set this.LaserLaunchAngle[LASER_ID] = 0.
set this.LaserLaunchScatterX[LASER_ID] = 0.
set this.LaserLaunchScatterY[LASER_ID] = 0.
set this.LaserLaunchScatterZ[LASER_ID] = 0
set this.LaserImpactScatterX[LASER_ID] = 0.
set this.LaserImpactScatterY[LASER_ID] = 0.
set this.LaserImpactScatterZ[LASER_ID] = 0.
set this.FollowTarget[LASER_ID] = false
set this.FloatingLaunch[LASER_ID] = false
set this.LaserImpactLock[LASER_ID] = false
set this.LaserRangeLock[LASER_ID] = false
set this.LaserRangeStart[LASER_ID] = 0.
set this.LaserRangePerLaser[LASER_ID] = 0.
set this.LaserDirectionalTilt[LASER_ID] = 0.
set this.LaserAttackType[LASER_ID] = null
set this.LaserDamageType[LASER_ID] = 0
set this.LaserDivideDamage[LASER_ID] = false
set this.Uninterruptible[LASER_ID] = false
set this.LaserHitAll[LASER_ID] = false
set this.LaserFriendlyFire[LASER_ID] = false
set this.ReduceLaunchOverhead[LASER_ID] = true
set this.ReduceImpactOverhead[LASER_ID] = true
endmethod
static method terminateweapon takes integer STRUCT_ID returns nothing
local thistype this = STRUCT_ID
call this.destroy()
endmethod
//static method create takes integer UNIT_ID, integer LASER_ID, /*
//*/ string LaserString, real RED, real BLUE, real GREEN, real ALPHA, string LaserLaunchFX, string LaserImpactFX, string LaserAreaFX, real LaserLaunchScale, /*
//*/ real LaserImpactScale, real LaserAreaScale, integer NumberOfLasers, integer LaserDuration, integer LaserFadeTime, real LaserInterval, integer LaserLingerInterval, /*
//*/ real LaserAOE, boolean IsLaserGrounded, real LaserLaunchOffset, real LaserLaunchHeight, real LaserLaunchAngle, real LaserLaunchScatterX, real LaserLaunchScatterY, /*
//*/ real LaserLaunchScatterZ, real LaserImpactScatterX, real LaserImpactScatterY, real LaserImpactScatterZ, boolean FollowTarget, boolean FloatingLaunch, boolean LaserImpactLock, /*
//*/ boolean LaserRangeLock, real LaserRangeStart, real LaserRangePerLaser, real LaserDirectionalTilt, attacktype LaserAttackType, integer LaserDamageType, boolean LaserDivideDamage, /*
//*/ boolean Uninterruptible, boolean LaserHitAll, boolean LaserFriendlyFire, boolean ReduceLaunchOverhead, boolean ReduceImpactOverhead /*
//*/ returns BLAssignWeapon
static method create takes unit u returns thistype
local thistype this = allocate()
set thistype(GetUnitId(u)).instance = this
return this
/*set StructIndex[UNIT_ID] = this
set UsesBurstLaser[UNIT_ID] = true
set this.LaserString[LASER_ID] = LaserString
set this.RED[LASER_ID] = RED
set this.BLUE[LASER_ID] = BLUE
set this.GREEN[LASER_ID] = GREEN
set this.ALPHA[LASER_ID] = ALPHA
set this.LaserLaunchFX[LASER_ID] = LaserLaunchFX
set this.LaserImpactFX[LASER_ID] = LaserImpactFX
set this.LaserAreaFX[LASER_ID] = LaserAreaFX
set this.LaserLaunchScale[LASER_ID] = LaserLaunchScale
set this.LaserImpactScale[LASER_ID] = LaserImpactScale
set this.LaserAreaScale[LASER_ID] = LaserAreaScale
set this.NumberOfLasers[LASER_ID] = NumberOfLasers
set this.LaserDuration[LASER_ID] = LaserDuration
set this.LaserFadeTime[LASER_ID] = LaserFadeTime
set this.LaserInterval[LASER_ID] = LaserInterval
set this.LaserLingerInterval[LASER_ID] = LaserLingerInterval
set this.LaserAOE[LASER_ID] = LaserAOE
set this.IsLaserGrounded[LASER_ID] = IsLaserGrounded
set this.LaserLaunchOffset[LASER_ID] = LaserLaunchOffset
set this.LaserLaunchHeight[LASER_ID] = LaserLaunchHeight
set this.LaserLaunchAngle[LASER_ID] = LaserLaunchAngle
set this.LaserLaunchScatterX[LASER_ID] = LaserLaunchScatterX
set this.LaserLaunchScatterY[LASER_ID] = LaserLaunchScatterY
set this.LaserLaunchScatterZ[LASER_ID] = LaserLaunchScatterZ
set this.LaserImpactScatterX[LASER_ID] = LaserImpactScatterX
set this.LaserImpactScatterY[LASER_ID] = LaserImpactScatterY
set this.LaserImpactScatterZ[LASER_ID] = LaserImpactScatterZ
set this.FollowTarget[LASER_ID] = FollowTarget
set this.FloatingLaunch[LASER_ID] = FloatingLaunch
set this.LaserImpactLock[LASER_ID] = LaserImpactLock
set this.LaserRangeLock[LASER_ID] = LaserRangeLock
set this.LaserRangeStart[LASER_ID] = LaserRangeStart
set this.LaserRangePerLaser[LASER_ID] = LaserRangePerLaser
set this.LaserDirectionalTilt[LASER_ID] = LaserDirectionalTilt
set this.LaserAttackType[LASER_ID] = LaserAttackType
set this.LaserDamageType[LASER_ID] = LaserDamageType
set this.LaserDivideDamage[LASER_ID] = LaserDivideDamage
set this.Uninterruptible[LASER_ID] = Uninterruptible
set this.LaserHitAll[LASER_ID] = LaserHitAll
set this.LaserFriendlyFire[LASER_ID] = LaserFriendlyFire
set this.ReduceLaunchOverhead[LASER_ID] = ReduceLaunchOverhead
set this.ReduceImpactOverhead[LASER_ID] = ReduceImpactOverhead*/
endmethod
endstruct
function BurstLaser_onIndex takes nothing returns boolean
local unit Source = udg_UDexUnits[udg_UDex]
local integer Source_ID = udg_UDex
if udg_UnitIndexEvent == 1. then
//Rifleman
if GetUnitTypeId(Source) == 'hrif' then
call BLAssignWeapon.create(/*
Unit ID */ ID, /*
Weapon ID */ 1, /* This is the index of that particular laser weapon. If you wish to overwrite it with call BLAssignWeapon.create, reference this integer.
Laser String */ "YLLN", /*
RED */ 1., /*
BLUE */ 1., /*
GREEN */ 1., /*
ALPHA */ .5, /*
Launch FX String */ "war3mapImported\\FaerieDragonMissile_Lesser_NoMS.mdx", /*
Impact Fx String */ "war3mapImported\\FaerieDragonMissile_Lesser_NoMS.mdx", /*
Area FX String */ null, /*
Launch FX Scale */ 1., /*
Impact FX Scale */ 1., /*
Area FX Scale */ 1., /*
Number of Lasers */ 3, /*
Laser Duration */ 5, /*
Laser Fade Time */ 5, /*
Interval between lasers */ 0.075, /*
FX repeat interval */ 0, /* repeats your FX and damage until the laser is destroyed
Damage Area of Effect */ 0., /*
Is laser grounded? */ false, /*
Launch Offset */ 70., /*
Launch Height */ 45., /*
Launch Angle */ 0., /*
Launch Scatter X */ 0., /*
Launch Scatter Y */ 0., /*
Launch Scatter Z */ 0., /*
Impact Scatter X */ 20., /*
Impact Scatter Y */ 20., /*
Impact Scatter Z */ 20., /*
Follow Target */ true, /* If TRUE, the angle between the attacker and the target will update for every new laser in a set. Eg: A target moving sideways.
Floating Launch */ false, /* If TRUE, then the Launch coordinates will not update to the attacker's new position if they move.
Impact Lock */ false, /* If TRUE, the laser will maintain a lock on their impact location realtive to the target, moving along with it.
Range Lock */ false, /* If true, the lasers will originate relative to the attacker's location instead of the target's. Works with forwards line attacks.
Range Start */ 0., /* This offsets the IMPACT of your lasers by a certain amount. Leave at 0 if your lasers are not striking a symmetrical pattern.
Range per laser */ 0., /*
Directional Tilt */ 0., /* This pivots the beam so that it can travel in a different direction. USES RADIANS.
Attack Type */ ATTACK_TYPE_PIERCE, /*
Damage Type */ udg_DamageTypeCode, /* This uses Damage Engine's internal damage type mechanic. Refer to it for more information.
Split damage? */ true, /* set this to FALSE if you want one laser in a set to inflict the full damage of a single attack, effectively multiplying the attacker's damage.
Uniterruptible */ false, /* if TRUE, then a laser set will always fire all its lasers regardless of the attacker's state. Otherwise, it can be stopped (eg: death, stunned, etc)
Hit All */ false, /* if TRUE, lasers will splash both to ground and flying units. Generally best left as FALSE as is can produce weird results.
Friendly Fire? */ false, /* if TRUE, aoe lasers will damage friendly units within their aoe.
Reduce Launch Overhead */ true, /* Reduces lag by limited the number of dummies for the launch to 1. May cause some special effects to skip all over the place.
Reduce Impact Overhead */ true /* Same as above, but for your impacts and area special effects
*/)
//Gryphon Rider
/*
This example shows how you can make lasers strike in a line. It's worth noting that this method is particularly heavy in performance because:
A) It has 8 lasers per set, but the reason this is a problem, per se, is that ReduceImpactOverhead is false, which means it will create an impact dummy PER laser.
B) The LaserImpactScale and LaserAreaScale both have effects and are of different values, which means that instead of tacking on the Area special effects onto the
the Impact dummies, it will create its own Area dummies. So already that's 16 dummes + 1 for launch for ONE gruphon rider. It's excessive, and should only
be reserved for something like boss battles and/or if your PC is an absolute beast.
*/
elseif GetUnitTypeId(Source) == 'hgry' then
call BLAssignWeapon.create(/*
Unit ID */ ID, /*
Weapon ID */ 1, /* This is the index of that particular laser weapon. If you wish to overwrite it with call BLAssignWeapon.create, reference this integer.
Laser String */ "SLSB", /*
RED */ 1., /*
BLUE */ 1., /*
GREEN */ 1., /*
ALPHA */ .5, /*
Launch FX String */ "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl", /*
Impact Fx String */ "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl", /*
Area FX String */ "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl", /*
Launch FX Scale */ 1., /*
Impact FX Scale */ .75, /*
Area FX Scale */ 1.5, /*
Number of Lasers */ 8, /*
Laser Duration */ 10, /*
Laser Fade Time */ 4, /*
Interval between lasers */ 0.0624, /*
FX repeat interval */ 0, /* repeats your FX and damage until the laser is destroyed
Damage Area of Effect */ 100., /*
Is laser grounded? */ true, /*
Launch Offset */ 80., /*
Launch Height */ 80., /*
Launch Angle */ 0., /*
Launch Scatter X */ 0., /*
Launch Scatter Y */ 0., /*
Launch Scatter Z */ 0., /*
Impact Scatter X */ 50., /*
Impact Scatter Y */ 50., /*
Impact Scatter Z */ 0., /*
Follow Target */ false, /* If TRUE, the angle between the attacker and the target will update for every new laser in a set. Eg: A target moving sideways.
Floating Launch */ false, /* If TRUE, then the Launch coordinates will not update to the attacker's new position if they move.
Impact Lock */ false, /* If TRUE, the laser will maintain a lock on their impact location realtive to the target, moving along with it.
Range Lock */ true, /* If true, the lasers will originate relative to the attacker's location instead of the target's. Works with forwards line attacks.
Range Start */ 80., /* This offsets the IMPACT of your lasers by a certain amount. Leave at 0 if your lasers are not striking a symmetrical pattern.
Range per laser */ 80., /*
Directional Tilt */ 3.14159, /* This pivots the beam so that it can travel in a different direction. USES RADIANS.
Attack Type */ ATTACK_TYPE_PIERCE, /*
Damage Type */ udg_DamageTypeCode, /* This uses Damage Engine's internal damage type mechanic. Refer to it for more information.
Split damage? */ false, /* set this to FALSE if you want one laser in a set to inflict the full damage of a single attack, effectively multiplying the attacker's damage.
Uniterruptible */ false, /* if TRUE, then a laser set will always fire all its lasers regardless of the attacker's state. Otherwise, it can be stopped (eg: death, stunned, etc)
Hit All */ false, /* if TRUE, lasers will splash both to ground and flying units. Generally best left as FALSE as is can produce weird results.
Friendly Fire? */ false, /* if TRUE, aoe lasers will damage friendly units within their aoe.
Reduce Launch Overhead */ true, /* Reduces lag by limited the number of dummies for the launch to 1. May cause some special effects to skip all over the place.
Reduce Impact Overhead */ false /* Same as above, but for your impacts and area special effects
*/)
//Gargoyle
/*
This is a variation on the gryphon's line attack, but strikes in a perpendicular line instead, similar to the Colossus from Starcraft II.
This is achieved by setting LaserDirectionalTilt to 1.5708 radians (90°). Note that all lasers fire simultaneously because LaserInterval is set to 0.
*/
elseif GetUnitTypeId(Source) == 'ugar' then
call BLAssignWeapon.create(/*
Unit ID */ ID, /*
Weapon ID */ 1, /* This is the index of that particular laser weapon. If you wish to overwrite it with call BLAssignWeapon.create, reference this integer.
Laser String */ "GRLN", /*
RED */ 1., /*
BLUE */ 1., /*
GREEN */ 1., /*
ALPHA */ 1., /*
Launch FX String */ "Abilities\\Weapons\\KeeperGroveMissile\\KeeperGroveMissile.mdl", /*
Impact Fx String */ "Abilities\\Weapons\\KeeperGroveMissile\\KeeperGroveMissile.mdl", /*
Area FX String */ null, /*
Launch FX Scale */ 1., /*
Impact FX Scale */ 1., /*
Area FX Scale */ 1., /*
Number of Lasers */ 13, /*
Laser Duration */ 7, /*
Laser Fade Time */ 5, /*
Interval between lasers */ 0., /*
FX repeat interval */ 0, /* repeats your FX and damage until the laser is destroyed
Damage Area of Effect */ 70., /*
Is laser grounded? */ false, /*
Launch Offset */ 40., /*
Launch Height */ 20., /*
Launch Angle */ 0., /*
Launch Scatter X */ 0., /*
Launch Scatter Y */ 0., /*
Launch Scatter Z */ 0., /*
Impact Scatter X */ 50., /*
Impact Scatter Y */ 50., /*
Impact Scatter Z */ 50., /*
Follow Target */ false, /* If TRUE, the angle between the attacker and the target will update for every new laser in a set. Eg: A target moving sideways.
Floating Launch */ false, /* If TRUE, then the Launch coordinates will not update to the attacker's new position if they move.
Impact Lock */ false, /* If TRUE, the laser will maintain a lock on their impact location realtive to the target, moving along with it.
Range Lock */ false, /* If true, the lasers will originate relative to the attacker's location instead of the target's. Works with forwards line attacks.
Range Start */ 0., /* This offsets the IMPACT of your lasers by a certain amount. Leave at 0 if your lasers are not striking a symmetrical pattern.
Range per laser */ 35., /*
Directional Tilt */ 1.5708, /* This pivots the beam so that it can travel in a different direction. USES RADIANS.
Attack Type */ ATTACK_TYPE_PIERCE, /*
Damage Type */ udg_DamageTypeCode, /* This uses Damage Engine's internal damage type mechanic. Refer to it for more information.
Split damage? */ false, /* set this to FALSE if you want one laser in a set to inflict the full damage of a single attack, effectively multiplying the attacker's damage.
Uniterruptible */ false, /* if TRUE, then a laser set will always fire all its lasers regardless of the attacker's state. Otherwise, it can be stopped (eg: death, stunned, etc)
Hit All */ false, /* if TRUE, lasers will splash both to ground and flying units. Generally best left as FALSE as is can produce weird results.
Friendly Fire? */ false, /* if TRUE, aoe lasers will damage friendly units within their aoe.
Reduce Launch Overhead */ true, /* Reduces lag by limited the number of dummies for the launch to 1. May cause some special effects to skip all over the place.
Reduce Impact Overhead */ false /* Same as above, but for your impacts and area special effects
*/)
//Spellbreaker
/*
While not visible in this trigger, it's possible to bind a Sentry to a unit, causing the lasers to fire from that dummy unit instead.
Refer to SentryCreate onIndex and SentryOrbit. Essentially, LaserSentry[id] must be set to a unit for this to work.
*/
elseif GetUnitTypeId(Source) == 'hspt' then
call BLAssignWeapon.create(/*
Unit ID */ ID, /*
Weapon ID */ 1, /* This is the index of that particular laser weapon. If you wish to overwrite it with call BLAssignWeapon.create, reference this integer.
Laser String */ "SLSB", /*
RED */ 1., /*
BLUE */ 1., /*
GREEN */ 1., /*
ALPHA */ 1., /*
Launch FX String */ "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl", /*
Impact Fx String */ "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl", /*
Area FX String */ null, /*
Launch FX Scale */ 1., /*
Impact FX Scale */ 1., /*
Area FX Scale */ 1., /*
Number of Lasers */ 5, /*
Laser Duration */ 13, /*
Laser Fade Time */ 5, /*
Interval between lasers */ 0.12, /*
FX repeat interval */ 0, /* repeats your FX and damage until the laser is destroyed
Damage Area of Effect */ 0., /*
Is laser grounded? */ false, /*
Launch Offset */ 40., /*
Launch Height */ 20., /*
Launch Angle */ 0., /*
Launch Scatter X */ 0., /*
Launch Scatter Y */ 0., /*
Launch Scatter Z */ 0., /*
Impact Scatter X */ 30., /*
Impact Scatter Y */ 30., /*
Impact Scatter Z */ 30., /*
Follow Target */ true, /* If TRUE, the angle between the attacker and the target will update for every new laser in a set. Eg: A target moving sideways.
Floating Launch */ false, /* If TRUE, then the Launch coordinates will not update to the attacker's new position if they move.
Impact Lock */ true, /* If TRUE, the laser will maintain a lock on their impact location realtive to the target, moving along with it.
Range Lock */ false, /* If true, the lasers will originate relative to the attacker's location instead of the target's. Works with forwards line attacks.
Range Start */ 0., /* This offsets the IMPACT of your lasers by a certain amount. Leave at 0 if your lasers are not striking a symmetrical pattern.
Range per laser */ 0., /*
Directional Tilt */ 0., /* This pivots the beam so that it can travel in a different direction. USES RADIANS.
Attack Type */ ATTACK_TYPE_PIERCE, /*
Damage Type */ udg_DamageTypeCode, /* This uses Damage Engine's internal damage type mechanic. Refer to it for more information.
Split damage? */ true, /* set this to FALSE if you want one laser in a set to inflict the full damage of a single attack, effectively multiplying the attacker's damage.
Uniterruptible */ true, /* if TRUE, then a laser set will always fire all its lasers regardless of the attacker's state. Otherwise, it can be stopped (eg: death, stunned, etc)
Hit All */ false, /* if TRUE, lasers will splash both to ground and flying units. Generally best left as FALSE as is can produce weird results.
Friendly Fire? */ false, /* if TRUE, aoe lasers will damage friendly units within their aoe.
Reduce Launch Overhead */ true, /* Reduces lag by limited the number of dummies for the launch to 1. May cause some special effects to skip all over the place.
Reduce Impact Overhead */ true /* Same as above, but for your impacts and area special effects
*/)
//Archmage
/*
The Archmage is an example of scattering your launch coordinates.
*/
elseif GetUnitTypeId(Source) == 'Hamg' then
call BLAssignWeapon.create(/*
Unit ID */ ID, /*
Weapon ID */ 1, /* This is the index of that particular laser weapon. If you wish to overwrite it with call BLAssignWeapon.create, reference this integer.
Laser String */ "ARBM", /*
RED */ 1., /*
BLUE */ 1., /*
GREEN */ 1., /*
ALPHA */ 1., /*
Launch FX String */ "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl", /*
Impact Fx String */ "Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl", /*
Area FX String */ null, /*
Launch FX Scale */ 1., /*
Impact FX Scale */ 1., /*
Area FX Scale */ 1., /*
Number of Lasers */ 5, /*
Laser Duration */ 30, /*
Laser Fade Time */ 8, /*
Interval between lasers */ 0.3, /*
FX repeat interval */ 4, /* repeats your FX and damage until the laser is destroyed
Damage Area of Effect */ 0., /*
Is laser grounded? */ false, /*
Launch Offset */ 0., /*
Launch Height */ 120., /*
Launch Angle */ 0., /*
Launch Scatter X */ 90., /*
Launch Scatter Y */ 90., /*
Launch Scatter Z */ 50., /*
Impact Scatter X */ 10., /*
Impact Scatter Y */ 10., /*
Impact Scatter Z */ 10., /*
Follow Target */ true, /* If TRUE, the angle between the attacker and the target will update for every new laser in a set. Eg: A target moving sideways.
Floating Launch */ false, /* If TRUE, then the Launch coordinates will not update to the attacker's new position if they move.
Impact Lock */ true, /* If TRUE, the laser will maintain a lock on their impact location realtive to the target, moving along with it.
Range Lock */ false, /* If true, the lasers will originate relative to the attacker's location instead of the target's. Works with forwards line attacks.
Range Start */ 0., /* This offsets the IMPACT of your lasers by a certain amount. Leave at 0 if your lasers are not striking a symmetrical pattern.
Range per laser */ 0., /*
Directional Tilt */ 0., /* This pivots the beam so that it can travel in a different direction. USES RADIANS.
Attack Type */ ATTACK_TYPE_HERO, /*
Damage Type */ udg_DamageTypeCode, /* This uses Damage Engine's internal damage type mechanic. Refer to it for more information.
Split damage? */ true, /* set this to FALSE if you want one laser in a set to inflict the full damage of a single attack, effectively multiplying the attacker's damage.
Uniterruptible */ false, /* if TRUE, then a laser set will always fire all its lasers regardless of the attacker's state. Otherwise, it can be stopped (eg: death, stunned, etc)
Hit All */ false, /* if TRUE, lasers will splash both to ground and flying units. Generally best left as FALSE as is can produce weird results.
Friendly Fire? */ false, /* if TRUE, aoe lasers will damage friendly units within their aoe.
Reduce Launch Overhead */ true, /* Reduces lag by limited the number of dummies for the launch to 1. May cause some special effects to skip all over the place.
Reduce Impact Overhead */ true /* Same as above, but for your impacts and area special effects
*/)
endif
else
call BLAssignWeapon.terminateweapon(StructIndex[Source_ID])
set StructIndex[Source_ID] = 0
set UsesBurstLaser[Source_ID] = false
endif
set Source = null
return false
endfunction
function BurstLaser_Create takes nothing returns nothing
//call TriggerRegisterVariableEvent( BurstLaserCreateTrigger, "udg_UnitIndexEvent", EQUAL, 1.00 )
//call TriggerRegisterVariableEvent( BurstLaserCreateTrigger, "udg_UnitIndexEvent", EQUAL, 2.00 )
call TriggerAddCondition( BurstLaserCreateTrigger, function BurstLaser_onCreate)
endfunction
endlibrary