• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Triggers

Knockback 2_5D.w3x
Variables
Knockback 2D
Requirement
Unit Indexer
---------------------------
Knockback 2D Config
Knockback 2D Destroy
Knockback 2D
Knockback 2D System
K2D OnLoop Template
Demo Requirement
Damage Engine
Demo Related
On Damage
On Impact
On Spell Cast
On Spell Stop
Stop time of day
Test
Name Type is_array initial_value
AfterDamageEvent real No
CenterPoint location No
ClearDamageEvent trigger 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
DamageTypeCriticalStrike integer No
DamageTypeExplosive integer No
DamageTypeHeal integer No
DamageTypeReduced integer No
DmgEvLife real No
DmgEvPrevLife real No
DmgEvRecursionLevel integer No
DmgEvRecursionN integer No
DmgEvRunning boolean No
DmgEvStarted boolean No
DmgEvTimer timer No
DmgEvTrig trigger No
DmgEvUnit unit No
IsDamageSpell boolean No
IsUnitBeingKnockedBack boolean Yes
K2DAmphibious boolean Yes
K2DAngle real Yes
K2DBounce boolean Yes
K2DCollision real Yes
K2DCos real Yes
K2DCosD1 real Yes
K2DCosD2 real Yes
K2DCosH real Yes
K2DDebrisKiller unit No
K2DDestRadius real Yes
K2DDistanceLeft real Yes
K2DFlying boolean Yes
K2DFreeze boolean Yes
K2DFriction real Yes
K2DFXModel string Yes
K2DFXRate real Yes
K2DFXTimeLeft real Yes
K2DHeight real Yes
K2DHeightThreshold real Yes
K2DImpact trigger Yes
K2DItem item No
K2DItemOffset boolean No
K2DItemsFound boolean No
K2DKillTrees boolean Yes
K2DLastX real Yes
K2DLastY real Yes
K2DMaxDestRadius real No
K2DMaxX real No
K2DMaxY real No
K2DMinX real No
K2DMinY real No
K2DNext integer Yes
K2DOverride boolean Yes
K2DPause boolean Yes
K2DPrev integer Yes
K2DRadius integer Yes
K2DRegion rect No
K2DSimple boolean Yes
K2DSin real Yes
K2DSinD1 real Yes
K2DSinD2 real Yes
K2DSinH real Yes
K2DSource unit Yes
K2DTimeLeft real Yes
K2DTimeout real No
K2DTimer timer No
K2DUnbiasedCollision boolean Yes
K2DVelocity real Yes
K2DX real No
K2DY real No
Knockback2DAmphibious boolean No
Knockback2DAngle real No
Knockback2DBounces boolean No
Knockback2DCollision real No
Knockback2DDefaultBounce boolean No
Knockback2DDefaultDestRadius real No
Knockback2DDefaultFriction real No
Knockback2DDefaultFX string No
Knockback2DDefaultFXRate real No
Knockback2DDefaultGravity real No
Knockback2DDefaultKillTrees boolean No
Knockback2DDefaultPause boolean No
Knockback2DDestRadius real No
Knockback2DDistance real No
Knockback2DFriction real No
Knockback2DFXRate real No
Knockback2DGravity real No
Knockback2DHeight real No
Knockback2DKillTrees boolean No
Knockback2DLoopFX string No
Knockback2DOnImpact trigger No
Knockback2DOverride boolean No
Knockback2DPause boolean No
Knockback2DRobustPathing integer No
Knockback2DSimple boolean No
Knockback2DSource unit No
Knockback2DTime real No
Knockback2DTreeOrDebris string No
Knockback2DUnbiasedCollision boolean No
Knockback2DUnit unit No
LastDamageHP real No
LastDmgPrevAmount real Yes
LastDmgPrevType integer Yes
LastDmgSource unit Yes
LastDmgTarget unit Yes
LastDmgValue real Yes
LastDmgWasSpell boolean Yes
LeaklessGroup group No
LoopInt integer No
NextDamageOverride boolean No
NextDamageType integer No
Radians_QuarterPi real No
Radians_QuarterTurn real No
Radians_Turn real No
SpellDamageAbility abilcode No
TargetPoint location No
Tauren_Shockwave boolean Yes
Tauren_WarStomp boolean Yes
TempReal real No
UDex integer No
UDexGen integer No
UDexNext integer Yes
UDexPrev integer Yes
UDexRecycle integer No
UDexUnits unit Yes
UDexWasted integer No
UnitDamageRegistered boolean Yes
UnitIndexerEnabled boolean No
UnitIndexEvent real No
Delete the Unit Indexer trigger below if you already have Unit Indexer in your map.
This trigger works in two key phases:

1) During map initialization, enumerate all units of all players to give them an index.
2) Adds a second event to itself to index new units as they enter the map.

As a unit enters the map, check for any old units that may have been removed at some point in order to free their index.
Unit Indexer
Events
Map initialization
Conditions
Actions
Custom script: call ExecuteFunc("InitializeUnitIndexer")
Custom script: endfunction
-------- --------
-------- This is the most important function - it provides an index for units as they enter the map --------
-------- --------
Custom script: function IndexUnit takes nothing returns boolean
Custom script: local integer pdex = udg_UDex
-------- --------
-------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
-------- - Example: --------
-------- -- Set UnitIndexerEnabled = False --------
-------- -- Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
-------- -- Set UnitIndexerEnabled = True --------
-------- --------
-------- You can also customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
-------- --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UnitIndexerEnabled Equal to True
Then - Actions
-------- --------
-------- Generate a unique integer index for this unit --------
-------- --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UDexRecycle Equal to 0
Then - Actions
Set Variable Set UDex = (UDexGen + 1)
Set Variable Set UDexGen = UDex
Else - Actions
Set Variable Set UDex = UDexRecycle
Set Variable Set UDexRecycle = UDexNext[UDex]
-------- --------
-------- Link index to unit, unit to index --------
-------- --------
Set Variable Set UDexUnits[UDex] = (Matching unit)
Unit - Set the custom value of UDexUnits[UDex] to UDex
-------- --------
-------- Use a doubly-linked list to store all active indexes --------
-------- --------
Set Variable Set UDexPrev[UDexNext[0]] = UDex
Set Variable Set UDexNext[UDex] = UDexNext[0]
Set Variable Set UDexNext[0] = UDex
-------- --------
-------- Fire index event for UDex --------
-------- --------
Set Variable Set UnitIndexEvent = "0.00"
Set Variable Set UnitIndexEvent = "1.00"
Set Variable Set UnitIndexEvent = "0.00"
Custom script: set udg_UDex = pdex
Else - Actions
Custom script: return false
Custom script: endfunction
-------- --------
-------- The next function is called each time a unit enters the map --------
-------- --------
Custom script: function IndexNewUnit takes nothing returns boolean
Custom script: local integer pdex = udg_UDex
Custom script: local integer ndex
-------- --------
-------- Recycle indices of units no longer in-play every (15) units created --------
-------- --------
Set Variable Set UDexWasted = (UDexWasted + 1)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UDexWasted Equal to 15
Then - Actions
Set Variable Set UDexWasted = "0"
Set Variable Set UDex = UDexNext[0]
Custom script: loop
Custom script: exitwhen udg_UDex == 0
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Custom value of UDexUnits[UDex]) Equal to 0
Then - Actions
-------- --------
-------- Remove index from linked list --------
-------- --------
Custom script: set ndex = udg_UDexNext[udg_UDex]
Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
Set Variable Set UDexPrev[UDex] = "0"
-------- --------
-------- Fire deindex event for UDex --------
-------- --------
Set Variable Set UnitIndexEvent = "2.00"
Set Variable Set UnitIndexEvent = "0.00"
-------- --------
-------- Recycle the index for later use --------
-------- --------
Set Variable Set UDexUnits[UDex] = No unit
Set Variable Set UDexNext[UDex] = UDexRecycle
Set Variable Set UDexRecycle = UDex
Custom script: set udg_UDex = ndex
Else - Actions
Set Variable Set UDex = UDexNext[UDex]
Custom script: endloop
Custom script: set udg_UDex = pdex
Else - Actions
-------- --------
-------- Handle the entering unit (Matching unit) --------
-------- --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Custom value of (Matching unit)) Equal to 0
Then - Actions
Custom script: call IndexUnit()
Else - Actions
Custom script: return false
Custom script: endfunction
-------- --------
-------- The next function initializes the core of the system --------
-------- --------
Custom script: function InitializeUnitIndexer takes nothing returns nothing
Custom script: local integer i = 0
Custom script: local region re = CreateRegion()
Custom script: local rect r = GetWorldBounds()
Set Variable Set UnitIndexerEnabled = "true"
Custom script: call RegionAddRect(re, r)
Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, Filter(function IndexNewUnit))
Custom script: call RemoveRect(r)
Custom script: set re = null
Custom script: set r = null
Custom script: loop
Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), Filter(function IndexUnit))
Custom script: set i = i + 1
Custom script: exitwhen i == 16
Custom script: endloop
-------- --------
-------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
-------- --------
Set Variable Set UnitIndexEvent = "3.00"
Set Variable Set UnitIndexEvent = "0.00"
Knockback 2D version 4.2.3.1

Flying units now display special effect art attached to their "origin". Simplified the pathing check for flying units to only check for air unit pathability.

For the full list of changes, please review the Knockback 2D Spell resource on HiveWorkshop.com
Knockback 2D Config
Events
Game - UnitIndexEvent becomes Equal to 3.00
Conditions
Actions
-------- --------
-------- Configure things below --------
-------- --------
-------- Set the timeout to be used throughout the system --------
-------- --------
Set Variable Set K2DTimeout = (1.00 / 60.00)
-------- --------
-------- Robust Pathing at 0 is only safe for collision sizes 16 and lower, but requires only one SetItemPosition check per timeout. --------
-------- -------- 1 checks collision vertically and horizontally to momentum. Uses an extra 4 SetItemPosition checks pet timeout. --------
-------- -------- 2 checks collision diagonally with momentum. Uses a total of 9 SetItemPosition checks per timeout. --------
-------- In any case, if the unit only has size 16 or lower collision, only one SetItemPosition check will be used for it. --------
-------- If RobustPathing is set to 2 and the unit has 36 or less collision, it will only use the normal check of 5 SetItemPosition calls --------
-------- The only reason to use robustness above 1 is for visual continuity - it features potentially-less glitchy movement. --------
-------- --------
Set Variable Set Knockback2DRobustPathing = "2"
-------- --------
-------- Keep the friction between 0.00 and 1.00, At 0.00, friction keeps the unit at the same speed for the knockback --------
-------- 1.00 friction will be an evenly-distributed deceleration which sees the unit slow to a complete stop --------
-------- Friction outside of these bounds gives the knockback a boomerang-effect, so you are welcome to experiment. --------
-------- --------
Set Variable Set Knockback2DDefaultFriction = "1.00"
Set Variable Set Knockback2DFriction = Knockback2DDefaultFriction
-------- --------
-------- Determine the default bouncing behavior of units. You can set this before knocking a unit back. --------
-------- --------
Set Variable Set Knockback2DDefaultBounce = "true"
Set Variable Set Knockback2DBounces = Knockback2DDefaultBounce
-------- --------
-------- Determine the default mechanics of whether a unit should be unable to move while knocked back --------
-------- --------
Set Variable Set Knockback2DDefaultPause = "false"
Set Variable Set Knockback2DPause = Knockback2DDefaultPause
-------- --------
-------- Determine if surrounding trees should be killed by default or not --------
-------- --------
Set Variable Set Knockback2DDefaultKillTrees = "true"
Set Variable Set Knockback2DKillTrees = Knockback2DDefaultKillTrees
-------- --------
-------- If so, how wide should the radius be? 128.00 should be the minimum if you use pathing robustness greater than 0. --------
-------- The minimum should be 64 if you use a robustness of 0. --------
-------- --------
Set Variable Set Knockback2DDefaultDestRadius = "128.00"
Set Variable Set Knockback2DDestRadius = Knockback2DDefaultDestRadius
-------- --------
-------- The "attack" option below will destroy any valid debris, from trees to barrels to creep homes. --------
-------- If you just want to destroy trees, change the string to: harvest --------
-------- --------
Set Variable Set Knockback2DTreeOrDebris = "attack"
-------- --------
-------- 0.50 gravity will have equal ascend and decline rate, 1.00 is instant descend, 0.67 is twice as fast, 0.75 is three times as fast. --------
-------- --------
Set Variable Set Knockback2DDefaultGravity = "0.71"
Set Variable Set Knockback2DGravity = Knockback2DDefaultGravity
-------- --------
-------- Change the following to the default type of looping FX you want to have if you use Knockback Effects --------
-------- --------
Set Variable Set Knockback2DDefaultFX = "Abilities\Weapons\AncientProtectorMissile\AncientProtectorMissile.mdl"
Set Variable Set Knockback2DLoopFX = Knockback2DDefaultFX
-------- --------
-------- How frequently should the effects appear per unit? This can also be customized per-knockback --------
-------- --------
Set Variable Set Knockback2DDefaultFXRate = "0.10"
Set Variable Set Knockback2DFXRate = Knockback2DDefaultFXRate
-------- --------
-------- Create an item to help verify pathing throughout the game --------
-------- --------
Set Variable Set CenterPoint = (Point(K2DX, K2DY))
Item - Create Slippers of Agility +3 at CenterPoint
Set Variable Set K2DItem = (Last created item)
-------- --------
-------- Create a harvest-capable unit to check if debris can be killed --------
-------- --------
Set Variable Set UnitIndexerEnabled = "false"
Unit - Create 1 . Ghoul for Neutral Passive at CenterPoint facing 0.00 degrees
Set Variable Set K2DDebrisKiller = (Last created unit)
-------- --------
-------- End Configuration --------
-------- --------
Set Variable Set UnitIndexerEnabled = "true"
Custom script: call RemoveLocation(udg_CenterPoint)
Game - Preload Knockback2DDefaultFX
Item - Hide K2DItem
Unit - Hide K2DDebrisKiller
Unit - Pause K2DDebrisKiller
Custom script: call UnitAddAbility(udg_K2DDebrisKiller, 'Aloc')
Set Variable Set Radians_Turn = (Radians(360.00))
Set Variable Set Radians_QuarterTurn = (Radians(90.00))
Set Variable Set Radians_QuarterPi = (Radians(45.00))
Set Variable Set K2DRegion = (Entire map)
Set Variable Set K2DMaxX = (Max X of K2DRegion)
Set Variable Set K2DMaxY = (Max Y of K2DRegion)
Set Variable Set K2DMinX = (Min X of K2DRegion)
Set Variable Set K2DMinY = (Min Y of K2DRegion)
Set Variable Set K2DMaxDestRadius = (Knockback2DDefaultDestRadius x 2.00)
Custom script: call SetRect(udg_K2DRegion, 0.00, 0.00, udg_K2DMaxDestRadius, udg_K2DMaxDestRadius)
Set Variable Set K2DItemsFound = "false"
Set Variable Set K2DItemOffset = "false"
Knockback 2D Destroy
Events
Game - UnitIndexEvent becomes Equal to 2.00
Conditions
IsUnitBeingKnockedBack[UDex] Equal to True
Actions
-------- --------
-------- This trigger destroys any knockback; you can execute it yourself by first setting UDex to the custom value --------
-------- --------
Set Variable Set IsUnitBeingKnockedBack[UDex] = "false"
Set Variable Set K2DNext[K2DPrev[UDex]] = K2DNext[UDex]
Set Variable Set K2DPrev[K2DNext[UDex]] = K2DPrev[UDex]
Set Variable Set K2DPrev[UDex] = "0"
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
K2DNext[0] Equal to 0
Then - Actions
Countdown Timer - Pause K2DTimer
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
K2DHeight[UDex] Not equal to 0.00
Then - Actions
Animation - Change Knockback2DUnit flying height to (Default flying height of Knockback2DUnit) at 0.00
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
K2DFreeze[UDex] Not equal to True
(K2DImpact[UDex] is on) Equal to True
Then - Actions
Trigger - Run K2DImpact[UDex] (checking conditions)
Else - Actions
Set Variable Set K2DOverride[UDex] = "false"
Set Variable Set K2DSource[UDex] = No unit
You can run this trigger, checking conditions if you want to play it safe.
Knockback 2D
Events
Conditions
(Default movement speed of Knockback2DUnit) Not equal to 0.00
K2DOverride[(Custom value of Knockback2DUnit)] Equal to False
Actions
Custom script: local integer pdex = udg_UDex
Set Variable Set UDex = (Custom value of Knockback2DUnit)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
IsUnitBeingKnockedBack[UDex] Equal to True
Then - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Knockback2DOverride Equal to False
Then - Actions
Set Variable Set K2DAngle[UDex] = (Degrees(K2DAngle[UDex]))
Set Variable Set Knockback2DAngle = ((Knockback2DAngle + K2DAngle[UDex]) x 0.50)
Set Variable Set Knockback2DDistance = ((K2DDistanceLeft[UDex] + Knockback2DDistance) x 0.50)
Set Variable Set Knockback2DTime = ((K2DTimeLeft[UDex] + Knockback2DTime) x 0.50)
Else - Actions
Trigger - Run Knockback_2D_Destroy <gen> (ignoring conditions)
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
K2DNext[0] Equal to 0
Then - Actions
Custom script: call ExecuteFunc("StartKnockback2DTimer")
Else - Actions
Set Variable Set IsUnitBeingKnockedBack[UDex] = "true"
Set Variable Set K2DPrev[K2DNext[0]] = UDex
Set Variable Set K2DNext[UDex] = K2DNext[0]
Set Variable Set K2DNext[0] = UDex
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Knockback2DHeight Not equal to 0.00
Then - Actions
Set Variable Set K2DHeight[UDex] = Knockback2DHeight
Custom script: if UnitAddAbility(udg_Knockback2DUnit, 'Amrf') then
Custom script: call UnitRemoveAbility(udg_Knockback2DUnit, 'Amrf')
Custom script: endif
Animation - Change Knockback2DUnit flying height to ((Default flying height of Knockback2DUnit) + Knockback2DHeight) at ((Knockback2DHeight - (Default flying height of Knockback2DUnit)) / (Knockback2DGravity x Knockback2DTime))
Set Variable Set K2DHeightThreshold[UDex] = ((1 - Knockback2DGravity) x Knockback2DTime)
Set Variable Set Knockback2DHeight = "0.00"
Else - Actions
Set Variable Set K2DHeight[UDex] = "0.00"
Custom script: set udg_K2DX = GetUnitX(udg_Knockback2DUnit)
Custom script: set udg_K2DY = GetUnitY(udg_Knockback2DUnit)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Knockback2DPause Equal to True
Then - Actions
Set Variable Set K2DLastX[UDex] = K2DX
Set Variable Set K2DLastY[UDex] = K2DY
Else - Actions
Set Variable Set K2DAngle[UDex] = (Radians(Knockback2DAngle))
Set Variable Set K2DCos[UDex] = (Cos(Knockback2DAngle))
Set Variable Set K2DSin[UDex] = (Sin(Knockback2DAngle))
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Knockback2DUnit is A flying unit) Equal to True
Then - Actions
Set Variable Set K2DFlying[UDex] = "true"
Else - Actions
Set Variable Set K2DFlying[UDex] = "false"
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Knockback2DRobustPathing Greater than 0
Then - Actions
-------- --------
-------- Handle the pathing checker based on the unit's collision size --------
-------- --------
Custom script: if not IsUnitInRangeXY(udg_Knockback2DUnit, udg_K2DX + 17, udg_K2DY, 0) then
Set Variable Set K2DRadius[UDex] = "0"
Custom script: else
Custom script: if not IsUnitInRangeXY(udg_Knockback2DUnit, udg_K2DX + 25, udg_K2DY, 0) then
Set Variable Set K2DRadius[UDex] = "8"
Custom script: elseif not IsUnitInRangeXY(udg_Knockback2DUnit, udg_K2DX + 33, udg_K2DY, 0) then
Set Variable Set K2DRadius[UDex] = "16"
Custom script: elseif not IsUnitInRangeXY(udg_Knockback2DUnit, udg_K2DX + 49, udg_K2DY, 0) then
Set Variable Set K2DRadius[UDex] = "32"
Custom script: else
Set Variable Set K2DRadius[UDex] = "48"
Custom script: endif
Set Variable Set Knockback2DAngle = ((Knockback2DAngle + 90.00) mod 360.00)
Set Variable Set K2DCosH[UDex] = (Cos(Knockback2DAngle))
Set Variable Set K2DSinH[UDex] = (Sin(Knockback2DAngle))
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Knockback2DRobustPathing Equal to 2
K2DRadius[UDex] Greater than 16
Then - Actions
Set Variable Set Knockback2DAngle = ((Knockback2DAngle + 45.00) mod 360.00)
Set Variable Set K2DCosD1[UDex] = (Cos(Knockback2DAngle))
Set Variable Set K2DSinD1[UDex] = (Sin(Knockback2DAngle))
Set Variable Set Knockback2DAngle = ((Knockback2DAngle + 90.00) mod 360.00)
Set Variable Set K2DCosD2[UDex] = (Cos(Knockback2DAngle))
Set Variable Set K2DSinD2[UDex] = (Sin(Knockback2DAngle))
Else - Actions
Custom script: endif
Else - Actions
Set Variable Set K2DDistanceLeft[UDex] = Knockback2DDistance
Set Variable Set Knockback2DDistance = (((1.00 + Knockback2DFriction) x Knockback2DDistance) / Knockback2DTime)
Set Variable Set K2DFriction[UDex] = ((Knockback2DDistance / Knockback2DTime) x ((1.00 - (1 - Knockback2DFriction)) x (K2DTimeout x K2DTimeout)))
Set Variable Set K2DVelocity[UDex] = (Knockback2DDistance x K2DTimeout)
-------- --------
Set Variable Set K2DKillTrees[UDex] = Knockback2DKillTrees
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Knockback2DKillTrees Equal to True
Then - Actions
-------- Square the radius so we don't have to use SquareRoot when comparing distance. --------
Set Variable Set K2DDestRadius[UDex] = (Knockback2DDestRadius x Knockback2DDestRadius)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Knockback2DDestRadius x 2.00) Greater than K2DMaxDestRadius
Then - Actions
-------- Update the size of the enumerating rect to compensate for the desired extra radius. --------
Set Variable Set K2DMaxDestRadius = (Knockback2DDestRadius x 2.00)
Custom script: call SetRect(udg_K2DRegion, 0.00, 0.00, udg_K2DMaxDestRadius, udg_K2DMaxDestRadius)
Else - Actions
Set Variable Set Knockback2DDestRadius = Knockback2DDefaultDestRadius
Else - Actions
-------- --------
Set Variable Set K2DAmphibious[UDex] = Knockback2DAmphibious
Set Variable Set K2DBounce[UDex] = Knockback2DBounces
Set Variable Set K2DCollision[UDex] = Knockback2DCollision
Set Variable Set K2DFreeze[UDex] = "false"
Set Variable Set K2DFXModel[UDex] = Knockback2DLoopFX
Set Variable Set K2DFXRate[UDex] = Knockback2DFXRate
Set Variable Set K2DFXTimeLeft[UDex] = Knockback2DFXRate
Set Variable Set K2DImpact[UDex] = Knockback2DOnImpact
Set Variable Set K2DOverride[UDex] = Knockback2DOverride
Set Variable Set K2DPause[UDex] = Knockback2DPause
Set Variable Set K2DSimple[UDex] = Knockback2DSimple
Set Variable Set K2DSource[UDex] = Knockback2DSource
Set Variable Set K2DTimeLeft[UDex] = Knockback2DTime
Set Variable Set K2DUnbiasedCollision[UDex] = Knockback2DUnbiasedCollision
Set Variable Set Knockback2DAmphibious = "false"
Set Variable Set Knockback2DBounces = Knockback2DDefaultBounce
Set Variable Set Knockback2DCollision = "0.00"
Set Variable Set Knockback2DFriction = Knockback2DDefaultFriction
Set Variable Set Knockback2DFXRate = Knockback2DDefaultFXRate
Set Variable Set Knockback2DGravity = Knockback2DDefaultGravity
Set Variable Set Knockback2DKillTrees = Knockback2DDefaultKillTrees
Set Variable Set Knockback2DLoopFX = Knockback2DDefaultFX
Custom script: set udg_Knockback2DOnImpact = null
Set Variable Set Knockback2DOverride = "false"
Set Variable Set Knockback2DPause = Knockback2DDefaultPause
Set Variable Set Knockback2DSimple = "false"
Set Variable Set Knockback2DSource = No unit
Set Variable Set Knockback2DUnbiasedCollision = "false"
Custom script: set udg_UDex = pdex
//TESH.scrollpos=205
//TESH.alwaysfold=0
function K2DItemCheckXY takes real x, real y returns boolean
    call SetItemPosition(udg_K2DItem, x, y)
    return GetWidgetX(udg_K2DItem) == x and GetWidgetY(udg_K2DItem) == y
endfunction

function K2DItemCheckAxis takes real x, real y returns boolean
    local real x2 = x*udg_K2DRadius[udg_UDex]
    local real y2 = y*udg_K2DRadius[udg_UDex]
    set x = udg_K2DX + x2
    set y = udg_K2DY + y2
    if K2DItemCheckXY(x, y) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) then
        set x = udg_K2DX - x2
        set y = udg_K2DY - y2
        return K2DItemCheckXY(x, y) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
    endif
    return false
endfunction

function K2DItemCheck takes nothing returns boolean
    local boolean result = K2DItemCheckXY(udg_K2DX, udg_K2DY)
    
    //Only perform additional pathing checks if the unit has a larger collision.
    if result and udg_Knockback2DRobustPathing > 0 and udg_K2DRadius[udg_UDex] > 0 then

        //Check horizontal axis of unit to make sure nothing is going to collide
        set result = K2DItemCheckAxis(udg_K2DCosH[udg_UDex], udg_K2DSinH[udg_UDex])
        
        //Check vertical axis of unit to ensure nothing will collide
        set result = result and K2DItemCheckAxis(udg_K2DCos[udg_UDex], udg_K2DSin[udg_UDex])
        
        if result and udg_Knockback2DRobustPathing == 2 and udg_K2DRadius[udg_UDex] > 16 then

            //Check diagonal axis of unit if more thorough pathing is desired
            set result = K2DItemCheckAxis(udg_K2DCosD1[udg_UDex], udg_K2DSinD1[udg_UDex])
            set result = result and K2DItemCheckAxis(udg_K2DCosD2[udg_UDex], udg_K2DSinD2[udg_UDex])
        endif
    endif
    
    //Reset item so it won't interfere with the map
    call SetItemPosition(udg_K2DItem, udg_K2DMaxX, udg_K2DMaxY)
    call SetItemVisible(udg_K2DItem, false)
    
    return result
endfunction

function K2DItemFilter takes nothing returns boolean
    //Check for visible items, temporarily hide them and add them to the filter.
    if IsItemVisible(GetFilterItem()) then
        call SetItemVisible(GetFilterItem(), false)
        return true
    endif
    return false
endfunction
function K2DItemCode takes nothing returns nothing
    //Perform the item-pathing check only once, then unhide those filtered items
    if not udg_K2DItemsFound then
        set udg_K2DItemsFound = true
        set udg_K2DItemOffset = K2DItemCheck()
    endif
    call SetItemVisible(GetEnumItem(), true)
endfunction

function K2DKillDest takes nothing returns nothing
    local real x
    local real y
    //Handle destruction of debris
    set bj_destRandomCurrentPick = GetEnumDestructable()
    if GetWidgetLife(bj_destRandomCurrentPick) > 0.405 and IssueTargetOrder(udg_K2DDebrisKiller, udg_Knockback2DTreeOrDebris, bj_destRandomCurrentPick) then
        set x = GetWidgetX(bj_destRandomCurrentPick) - udg_K2DX
        set y = GetWidgetY(bj_destRandomCurrentPick) - udg_K2DY
        if x*x + y*y <= udg_K2DDestRadius[udg_UDex] then
            call KillDestructable(bj_destRandomCurrentPick)
        endif
    endif
endfunction

function K2DEnumDests takes nothing returns nothing
    call MoveRectTo(udg_K2DRegion, udg_K2DX, udg_K2DY)
    if udg_K2DKillTrees[udg_UDex] then
        call SetUnitX(udg_K2DDebrisKiller, udg_K2DX)
        call SetUnitY(udg_K2DDebrisKiller, udg_K2DY)
        call EnumDestructablesInRect(udg_K2DRegion, null, function K2DKillDest)
    endif
endfunction

function Knockback2DCheckXY takes real x, real y returns boolean
    set udg_K2DX = x + udg_K2DVelocity[udg_UDex]*udg_K2DCos[udg_UDex]
    set udg_K2DY = y + udg_K2DVelocity[udg_UDex]*udg_K2DSin[udg_UDex]
    if udg_K2DSimple[udg_UDex] then
        //A "pull" effect or a missile system does not require complex pathing.
        if udg_K2DX <= udg_K2DMaxX and udg_K2DX >= udg_K2DMinX and udg_K2DY <= udg_K2DMaxY and udg_K2DY >= udg_K2DMinY then
            call K2DEnumDests()
            return true
        endif
        return false
    elseif udg_K2DFlying[udg_UDex] then
        return not IsTerrainPathable(udg_K2DX, udg_K2DY, PATHING_TYPE_FLYABILITY)
    elseif not IsTerrainPathable(udg_K2DX, udg_K2DY, PATHING_TYPE_WALKABILITY) then
        call K2DEnumDests()
        set udg_K2DItemOffset = false
        call EnumItemsInRect(udg_K2DRegion, Filter(function K2DItemFilter), function K2DItemCode)
        if udg_K2DItemsFound then
            //If items were found, the check was already performed.
            set udg_K2DItemsFound = false
        else
            //Otherwise, perform the check right now.
            set udg_K2DItemOffset = K2DItemCheck()
        endif
        return udg_K2DItemOffset
    endif
    return udg_K2DAmphibious[udg_UDex] and not IsTerrainPathable(udg_K2DX, udg_K2DY, PATHING_TYPE_FLOATABILITY)
endfunction

function Knockback2DApplyAngle takes real angle returns nothing
    set angle = ModuloReal(angle, udg_Radians_Turn)
    set udg_K2DCos[udg_UDex] = Cos(angle)
    set udg_K2DSin[udg_UDex] = Sin(angle)
    set udg_K2DAngle[udg_UDex] = angle
    if udg_Knockback2DRobustPathing > 0 then
        set angle = ModuloReal(angle + udg_Radians_QuarterTurn, udg_Radians_Turn)
        set udg_K2DCosH[udg_UDex] = Cos(angle)
        set udg_K2DSinH[udg_UDex] = Sin(angle)
        if udg_Knockback2DRobustPathing == 2 and udg_K2DRadius[udg_UDex] > 16 then
            set angle = ModuloReal(angle + udg_Radians_QuarterPi, udg_Radians_Turn)
            set udg_K2DCosD1[udg_UDex] = Cos(angle)
            set udg_K2DSinD1[udg_UDex] = Sin(angle)
            set angle = ModuloReal(angle + udg_Radians_QuarterTurn, udg_Radians_Turn)
            set udg_K2DCosD2[udg_UDex] = Cos(angle)
            set udg_K2DSinD2[udg_UDex] = Sin(angle)
        endif
    endif
endfunction

function Knockback2DLooper takes nothing returns nothing
    local integer i = 0
    local unit u
    local real x
    local real y
    
    call PauseUnit(udg_K2DDebrisKiller, false)
    
    loop
        set i = udg_K2DNext[i]
        exitwhen i == 0
        set udg_UDex = i
        set udg_K2DTimeLeft[i] = udg_K2DTimeLeft[i] - udg_K2DTimeout
        set udg_K2DDistanceLeft[i] = udg_K2DDistanceLeft[i] - udg_K2DVelocity[i]
        set u = udg_UDexUnits[i]
        
        if udg_K2DTimeLeft[i] > 0.00 then
            if udg_K2DTimeLeft[i] < udg_K2DHeightThreshold[i] and udg_K2DHeightThreshold[i] != 0.00 then
                call SetUnitFlyHeight(u, GetUnitDefaultFlyHeight(u), GetUnitFlyHeight(u) - GetUnitDefaultFlyHeight(u)/udg_K2DHeightThreshold[i])
                set udg_K2DHeightThreshold[i] = 0.00
            endif
            if udg_K2DPause[i] then
                set x = udg_K2DLastX[i]
                set y = udg_K2DLastY[i]
            else
                set x = GetUnitX(u)
                set y = GetUnitY(u)
            endif
            
            if not Knockback2DCheckXY(x, y) then
                if not udg_K2DFreeze[i] and IsTriggerEnabled(udg_K2DImpact[i]) and TriggerEvaluate(udg_K2DImpact[i]) then
                    call TriggerExecute(udg_K2DImpact[i])
                endif
                if udg_K2DBounce[i] then
                    call Knockback2DApplyAngle(udg_Radians_Turn - udg_K2DAngle[i])
                    if not Knockback2DCheckXY(x, y) then
                        call Knockback2DApplyAngle(udg_K2DAngle[i] + bj_PI)
                        if not Knockback2DCheckXY(x, y) then
                            call Knockback2DApplyAngle(udg_Radians_Turn - udg_K2DAngle[i])
                            set udg_K2DX = x
                            set udg_K2DY = y
                        endif
                    endif
                else
                    set udg_K2DX = x
                    set udg_K2DY = y
                    set udg_K2DFreeze[i] = true
                endif
            endif
            call SetUnitX(u, udg_K2DX)
            call SetUnitY(u, udg_K2DY)
            set udg_K2DLastX[i] = udg_K2DX
            set udg_K2DLastY[i] = udg_K2DY
            if udg_K2DFXModel[i] != "" then
                set udg_K2DFXTimeLeft[i] = udg_K2DFXTimeLeft[i] - udg_K2DTimeout
                if udg_K2DFXTimeLeft[i] <= 0.00 then
                    set udg_K2DFXTimeLeft[i] = udg_K2DFXRate[i]
                    if udg_K2DFlying[i] then
                        call DestroyEffect(AddSpecialEffectTarget(udg_K2DFXModel[i], u, "origin"))
                    else
                        call DestroyEffect(AddSpecialEffect(udg_K2DFXModel[i], udg_K2DX, udg_K2DY))
                    endif
                endif
            endif
            if udg_K2DCollision[i] >= 0.00 then
                set udg_Knockback2DSource = u
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, udg_K2DX, udg_K2DY, 200.00, null)
                call GroupRemoveUnit(bj_lastCreatedGroup, u)
                loop
                    set udg_Knockback2DUnit = FirstOfGroup(bj_lastCreatedGroup)
                    exitwhen udg_Knockback2DUnit == null
                    call GroupRemoveUnit(bj_lastCreatedGroup, udg_Knockback2DUnit)
                    
                    if IsUnitInRange(udg_Knockback2DUnit, u, udg_K2DCollision[i]) and udg_K2DFlying[i] == IsUnitType(udg_Knockback2DUnit, UNIT_TYPE_FLYING) and (not IsUnitType(udg_Knockback2DUnit, UNIT_TYPE_STRUCTURE)) and not IsUnitType(udg_Knockback2DUnit, UNIT_TYPE_DEAD) and (udg_K2DUnbiasedCollision[i] or IsUnitAlly(udg_Knockback2DUnit, GetOwningPlayer(u))) and TriggerEvaluate(gg_trg_Knockback_2D) then
                        set udg_Knockback2DAngle = bj_RADTODEG * Atan2(GetUnitY(udg_Knockback2DUnit) - udg_K2DY, GetUnitX(udg_Knockback2DUnit) - udg_K2DX)
                        set udg_Knockback2DDistance = udg_K2DDistanceLeft[i]
                        set udg_Knockback2DBounces = udg_K2DBounce[i]
                        set udg_Knockback2DCollision = udg_K2DCollision[i]
                        if udg_K2DHeight[i] != 0.00 then
                            set udg_Knockback2DHeight = GetUnitFlyHeight(u) - GetUnitDefaultFlyHeight(u)
                        endif
                        set udg_Knockback2DLoopFX = udg_K2DFXModel[i]
                        set udg_Knockback2DTime = udg_K2DTimeLeft[i]
                        set udg_Knockback2DUnbiasedCollision = udg_K2DUnbiasedCollision[i]
                        call TriggerExecute(gg_trg_Knockback_2D)
                        set udg_Knockback2DSource = u //in case of a recursive knockback
                    endif
                endloop
            endif
            set udg_K2DVelocity[i] = udg_K2DVelocity[i] - udg_K2DFriction[i]
        else
            call TriggerExecute(gg_trg_Knockback_2D_Destroy)
        endif
    endloop
    set u = null
    
    //Disable dummy after the loop finishes so it doesn't interfere with the map
    call PauseUnit(udg_K2DDebrisKiller, true)
endfunction

//===========================================================================
function StartKnockback2DTimer takes nothing returns nothing
    call TimerStart(udg_K2DTimer, udg_K2DTimeout, true, function Knockback2DLooper)
endfunction
function InitTrig_Knockback_2D_System takes nothing returns nothing
endfunction
Using the event K2DTimer expires ensures your onLoop triggers only run when a knockback is running.
K2D OnLoop Template
Events
Time - K2DTimer expires
Conditions
Actions
Set Variable Set LoopInt = K2DNext[0]
Custom script: loop
Custom script: exitwhen udg_LoopInt == 0
-------- --------
-------- Put your stuff that you want to happen every K2DTimeout seconds here. To reference the knocked back unit, use UDexUnits[LoopInt] --------
-------- --------
Set Variable Set LoopInt = K2DNext[LoopInt]
Custom script: endloop
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".
Damage Engine
Events
Game - UnitIndexEvent becomes Equal to 1.00
Game - UnitIndexEvent becomes Equal to 2.00
Conditions
Actions
-------- Copy the Cheat Death Ability from Object Editor into your map and set the following variable respectively: --------
Set Variable Set DamageBlockingAbility = "A003"
-------- Copy the Detect Spell Damage Ability from Object Editor into your map and set the following variable respectively: --------
Set Variable Set SpellDamageAbility = "A002"
-------- - --------
-------- You can add extra classifications here if you want to differentiate between your triggered damage --------
-------- Use DamageTypeExplosive (or any negative value damage type) if you want a unit killed by that damage to explode --------
Set Variable Set DamageTypeExplosive = "-1"
Set Variable Set DamageTypeCriticalStrike = "1"
Set Variable Set DamageTypeHeal = "2"
Set Variable Set DamageTypeReduced = "3"
Set Variable Set DamageTypeBlocked = "4"
-------- - --------
Custom script: call ExecuteFunc("InitDamageEvent")
Custom script: endfunction
Custom script: function DmgEvAmplifyCheck takes nothing returns nothing
-------- The next if/else blocks handles magic damage modification --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(DamageEventTarget is Ethereal) Equal to True
(DamageEventTarget is A Hero) Equal to False
Then - Actions
Set Variable Set DamageEventAmount = (DamageEventAmount x 1.67)
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Level of Elune's Grace for DamageEventTarget) Greater than 0
Then - Actions
Set Variable Set DamageEventAmount = (DamageEventAmount x 0.80)
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(DamageEventTarget is A Hero) Equal to True
(DamageEventTarget has an item of type Runed Bracers) Equal to True
Then - Actions
Set Variable Set DamageEventAmount = (DamageEventAmount x 0.67)
Else - Actions
Custom script: endfunction
-------- - --------
-------- The next conditions let you filter out units you don't want detection for. By default, units with Locust will not pass the check. --------
-------- - --------
Custom script: function DmgEvFilter takes nothing returns boolean
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(DmgEvUnit is A structure) Equal to False
Then - Actions
Custom script: return GetUnitAbilityLevel(udg_DmgEvUnit, 'Aloc') == 0
Else - Actions
Custom script: return false
Custom script: endfunction
Custom script: function DmgEvResetVars takes nothing returns nothing
Set Variable Set DmgEvRecursionN = (DmgEvRecursionN - 1)
Set Variable Set DamageEventPrevAmt = LastDmgPrevAmount[DmgEvRecursionN]
Set Variable Set DamageEventAmount = LastDmgValue[DmgEvRecursionN]
Set Variable Set DamageEventSource = LastDmgSource[DmgEvRecursionN]
Set Variable Set DamageEventTarget = LastDmgTarget[DmgEvRecursionN]
Set Variable Set IsDamageSpell = LastDmgWasSpell[DmgEvRecursionN]
Set Variable Set DamageEventType = LastDmgPrevType[DmgEvRecursionN]
Custom script: endfunction
Custom script: function CheckDamagedLifeEvent takes nothing returns nothing
Set Variable Set NextDamageOverride = "false"
Set Variable Set NextDamageType = "0"
Custom script: if udg_DmgEvTrig != null then
Custom script: call DestroyTrigger(udg_DmgEvTrig)
Custom script: set udg_DmgEvTrig = null
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
IsDamageSpell Equal to True
Then - Actions
Unit - Set life of DamageEventTarget to (Max(LastDamageHP, 0.41))
Custom script: if udg_LastDamageHP <= 0.405 then
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventType Less than 0
Then - Actions
Unit - Make DamageEventTarget Explode on death
Else - Actions
Trigger - Turn off DamageEventTrigger
-------- Kill the unit --------
Custom script: call UnitDamageTarget(udg_DamageEventSource, udg_DamageEventTarget, -999, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
Trigger - Turn on DamageEventTrigger
Custom script: endif
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Level of DamageBlockingAbility for DamageEventTarget) Greater than 0
Then - Actions
Unit - Remove DamageBlockingAbility from DamageEventTarget
Unit - Set life of DamageEventTarget to LastDamageHP
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventAmount Not equal to 0.00
Then - Actions
Set Variable Set AfterDamageEvent = "0.00"
Set Variable Set AfterDamageEvent = "1.00"
Set Variable Set AfterDamageEvent = "0.00"
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DmgEvRecursionN Greater than 0
Then - Actions
Custom script: call DmgEvResetVars()
Else - Actions
Custom script: endif
Custom script: endfunction
Custom script: function DmgEvOnExpire takes nothing returns nothing
Set Variable Set DmgEvStarted = "false"
Custom script: call CheckDamagedLifeEvent()
Custom script: endfunction
Custom script: function OnDmgEv takes nothing returns nothing
Custom script: local boolean clear = false
Custom script: local boolean override = udg_DamageEventOverride
Custom script: local code c = function CheckDamagedLifeEvent
Custom script: call CheckDamagedLifeEvent() //in case the unit state event failed and the 0.00 second timer hasn't yet expired
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DmgEvRunning Equal to True
Then - Actions
Set Variable Set DmgEvRecursionLevel = (DmgEvRecursionLevel + 1)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DmgEvRecursionLevel Less than 16
Then - Actions
Set Variable Set LastDmgPrevAmount[DmgEvRecursionN] = DamageEventPrevAmt
Set Variable Set LastDmgValue[DmgEvRecursionN] = DamageEventAmount
Set Variable Set LastDmgSource[DmgEvRecursionN] = DamageEventSource
Set Variable Set LastDmgTarget[DmgEvRecursionN] = DamageEventTarget
Set Variable Set LastDmgWasSpell[DmgEvRecursionN] = IsDamageSpell
Set Variable Set LastDmgPrevType[DmgEvRecursionN] = DamageEventType
Set Variable Set DmgEvRecursionN = (DmgEvRecursionN + 1)
Else - Actions
-------- Delete the next couple of lines to disable the in-game recursion crash warnings --------
Cinematic - Clear the screen of text messages for (All players) .
Game - Display to (All players) for 999.00 seconds the text: WARNING: Recursion error when dealing damage! Make sure when you deal damage from within a DamageEvent trigger, do it like this: Trigger - Turn off (This Trigger) Unit - Cause... Trigger - Turn on (This Trigger)
Skip remaining actions
Else - Actions
Set Variable Set DmgEvRunning = "true"
Custom script: set clear = true
Set Variable Set DamageEventAmount = (Damage taken)
Set Variable Set DamageEventSource = (Damage source)
Set Variable Set DamageEventTarget = (Triggering unit)
Set Variable Set DamageEventPrevAmt = (Abs(DamageEventAmount))
Set Variable Set DamageEventType = NextDamageType
Set Variable Set NextDamageType = "0"
Set Variable Set DamageEventOverride = NextDamageOverride
Set Variable Set NextDamageOverride = "false"
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventAmount Equal to 0.00
Then - Actions
Set Variable Set DamageEvent = "0.00"
Set Variable Set DamageEvent = "2.00"
Set Variable Set DamageEvent = "0.00"
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DmgEvStarted Equal to False
Then - Actions
Set Variable Set DmgEvStarted = "true"
Custom script: call TimerStart(udg_DmgEvTimer, 0.00, false, function DmgEvOnExpire)
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventAmount Less than 0.00
Then - Actions
Set Variable Set DamageEventAmount = (0.00 - DamageEventAmount)
Set Variable Set IsDamageSpell = "true"
Custom script: call DmgEvAmplifyCheck()
Else - Actions
Set Variable Set IsDamageSpell = "false"
Set Variable Set DamageModifierEvent = "0.00"
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventOverride Equal to False
Then - Actions
Set Variable Set DamageModifierEvent = "1.00"
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventOverride Equal to False
Then - Actions
Set Variable Set DamageModifierEvent = "2.00"
Set Variable Set DamageModifierEvent = "3.00"
Else - Actions
Custom script: set udg_DamageEventOverride = override
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventAmount Greater than 0.01
Then - Actions
Set Variable Set DamageModifierEvent = "4.00"
Else - Actions
Set Variable Set DamageModifierEvent = "0.00"
Set Variable Set DamageEvent = "0.00"
Set Variable Set DamageEvent = "1.00"
Set Variable Set DamageEvent = "0.00"
Custom script: call CheckDamagedLifeEvent() //in case the unit state event failed from a recursive damage event
-------- Process damage modification --------
Set Variable Set DmgEvLife = (Life of DamageEventTarget)
Custom script: set udg_DmgEvTrig = CreateTrigger()
Custom script: call TriggerAddCondition(udg_DmgEvTrig, Filter(c))
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
IsDamageSpell Equal to False
Then - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventAmount Not equal to DamageEventPrevAmt
Then - Actions
Set Variable Set DmgEvLife = ((DmgEvLife + DamageEventPrevAmt) - DamageEventAmount)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Max life of DamageEventTarget) Less than DmgEvLife
Then - Actions
Set Variable Set LastDamageHP = (DmgEvLife - DamageEventPrevAmt)
Unit - Add DamageBlockingAbility to DamageEventTarget
Else - Actions
Unit - Set life of DamageEventTarget to (Max(DmgEvLife, 0.42))
Else - Actions
Trigger - Add to DmgEvTrig the event (DamageEventTarget's life becomes Less than (Max(0.41, (DmgEvLife - (DamageEventPrevAmt / 2.00)))))
Else - Actions
Set Variable Set LastDamageHP = (Max life of DamageEventTarget)
Set Variable Set DmgEvPrevLife = DmgEvLife
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(DmgEvLife + (DamageEventPrevAmt x 0.75)) Greater than LastDamageHP
Then - Actions
Set Variable Set DmgEvLife = (Max((LastDamageHP - (DamageEventPrevAmt / 2.00)), 1.00))
Unit - Set life of DamageEventTarget to DmgEvLife
Set Variable Set DmgEvLife = ((DmgEvLife + LastDamageHP) / 2.00)
Else - Actions
Set Variable Set DmgEvLife = (DmgEvLife + (DamageEventPrevAmt x 0.50))
Set Variable Set LastDamageHP = (DmgEvPrevLife - (DamageEventPrevAmt - (DamageEventPrevAmt - DamageEventAmount)))
Trigger - Add to DmgEvTrig the event (DamageEventTarget's life becomes Greater than DmgEvLife)
Custom script: if clear then
Set Variable Set DmgEvRunning = "false"
Set Variable Set DmgEvRecursionLevel = "0"
Custom script: elseif udg_DamageEventPrevAmt == 0.00 then
Custom script: call DmgEvResetVars()
Custom script: endif
Custom script: endfunction
Custom script: function CreateDmgEv takes nothing returns nothing
Custom script: local code c = function OnDmgEv
Custom script: set udg_DamageEventTrigger = CreateTrigger()
Custom script: call TriggerAddCondition(udg_DamageEventTrigger, Filter(c))
Custom script: endfunction
Custom script: function SetupDmgEv takes nothing returns nothing
Custom script: local integer pdex = udg_UDex
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UnitIndexEvent Equal to 1.00
Then - Actions
Set Variable Set DmgEvUnit = UDexUnits[UDex]
Custom script: if DmgEvFilter() then
Set Variable Set UnitDamageRegistered[UDex] = "true"
Trigger - Add to DamageEventTrigger the event (DmgEvUnit Takes damage)
Unit - Add SpellDamageAbility to DmgEvUnit
Custom script: call UnitMakeAbilityPermanent(udg_DmgEvUnit, true, udg_SpellDamageAbility)
Custom script: endif
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UnitDamageRegistered[UDex] Equal to True
Then - Actions
Set Variable Set UnitDamageRegistered[UDex] = "false"
Set Variable Set DamageEventsWasted = (DamageEventsWasted + 1)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
DamageEventsWasted Equal to 32
Then - Actions
Set Variable Set DamageEventsWasted = "0"
Custom script: call DestroyTrigger(udg_DamageEventTrigger)
Custom script: call CreateDmgEv()
Set Variable Set UDex = UDexNext[0]
Custom script: loop
Custom script: exitwhen udg_UDex == 0
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UnitDamageRegistered[UDex] Equal to True
Then - Actions
Trigger - Add to DamageEventTrigger the event (UDexUnits[UDex] Takes damage)
Else - Actions
Set Variable Set UDex = UDexNext[UDex]
Custom script: endloop
Custom script: set udg_UDex = pdex
Else - Actions
Else - Actions
Custom script: endfunction
Custom script: function InitDamageEvent takes nothing returns nothing
Custom script: local code c = function CheckDamagedLifeEvent
Custom script: set udg_ClearDamageEvent = CreateTrigger()
Custom script: call TriggerAddCondition(udg_ClearDamageEvent, Filter(c))
For each (Integer A) from 1 to 16 , do (Actions)
Loop - Actions
Player - Disable SpellDamageAbility for (Player((Integer A)))
Custom script: call CreateDmgEv()
Custom script: set c = function SetupDmgEv
Set Variable Set UnitIndexerEnabled = "false"
Custom script: set udg_DmgEvUnit = CreateUnit(Player(15), 'uloc', 0, 0, 0)
Set Variable Set UnitIndexerEnabled = "true"
Unit - Add DamageBlockingAbility to DmgEvUnit
Unit - Add SpellDamageAbility to DmgEvUnit
Unit - Remove DmgEvUnit from the game
Custom script: call TriggerAddCondition(GetTriggeringTrigger(), Filter(c))
Trigger - Run (This trigger) (checking conditions)
Countdown Timer - Start DmgEvTimer as a One-shot timer that will expire in 0.00 seconds
Trigger - Turn off ClearDamageEvent
For this demo, I want units to never take damage. There doesn't need to be any damage taken, anyway, since it's only about the knockback.
On Damage
Events
Game - DamageModifierEvent becomes Equal to 1.00
Conditions
Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
IsDamageSpell Equal to False
(Owner of DamageEventSource) Equal to Player 1 (Red)
Then - Actions
-------- --------
-------- There are four required variables when issuing a knockback --------
-------- --------
-------- 1. Knockback2DAngle -------- this is the direction angle the unit is knocked back (in degrees) --------
-------- 2. Knockback2DTime -------- this is how long the unit will be knocked back (in seconds) --------
-------- 3. Knockback2DDistance -------- this is how far the unit will be knocked back --------
-------- 4. Knockback2DUnit -------- this is the unit being knocked back --------
-------- --------
-------- When all four variables are set, you can run the Knockback 2D trigger, ignoring conditions --------
-------- --------
Set Variable Set CenterPoint = (Position of DamageEventSource)
Set Variable Set TargetPoint = (Position of DamageEventTarget)
Set Variable Set Knockback2DAngle = (Angle from CenterPoint to TargetPoint)
Custom script: call RemoveLocation(udg_CenterPoint)
Custom script: call RemoveLocation(udg_TargetPoint)
Set Variable Set Knockback2DTime = "0.90"
Set Variable Set Knockback2DDistance = "500.00"
Set Variable Set Knockback2DUnit = DamageEventTarget
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Owner of DamageEventSource) Not equal to (Owner of DamageEventTarget)
Then - Actions
-------- --------
-------- There are optional variables you can consider when issuing a knockback --------
-------- If they are not set, "0.00, false, null" or their default states assigned in the Knockback 2D Config trigger will be used --------
-------- --------
-------- Knockback2DAmphibious -------- Allows the unit to pass over deep water, but it is more performance-intensive --------
-------- -------- If you aren't ToolOrDie from TheHiveWorkshop, you probably won't use this --------
-------- Knockback2DBounces -------- if the unit will bounce off of walls or remain stunned there. --------
-------- --------
-------- Knockback2DCollision -------- You can specify the collision radius of units to be adjacently knocked back if you want --------
-------- -------- A value of 0 will require the units' collision sizes to overlap to knock back --------
-------- -------- A value greater than 0 will allow that much space between the units to still permit the knockback --------
-------- -------- A value less than 0 will disable collision checking altogether. --------
-------- --------
-------- Knockback2DDestRadius -------- If debris is to be killed, how far away must it be? --------
-------- Knockback2DFriction -------- How quickly the unit will slow down from its initial speed. --------
-------- Knockback2DFX -------- What kind of special effect will occasionally be played on the ground of the unit --------
-------- Knockback2DFXRate -------- How often should the effect appear? --------
-------- Knockback2DGravity -------- If you want to specify a custom gravity for each knockback, you can --------
-------- Knockback2DHeight -------- How high you want the unit to go during the knockback --------
-------- Knockback2DKillTrees -------- If you want surrounding trees to die, this is for you --------
-------- Knockback2DOnImpact -------- this trigger is run when the unit hits a wall or structure. --------
-------- -------- If it is bouncing, it can hit multiple walls and fire this trigger multiple times --------
-------- -------- The trigger will not run if it is off, so you can use this if you only want it to run on the first bounce --------
-------- Knockback2DOverride -------- Set this to true to prevent future knockbacks from interrupting this one --------
-------- Knockback2DPause -------- confines the unit to its knockback velocity (no running to change course) --------
-------- Knockback2DSimple -------- Only checks to make sure unit movement is within the map bounds --------
-------- Knockback2DSource -------- If you need to store this unit to deal damage on-impact or within the timer loop --------
-------- Knockback2DUnbiasedCollision -------- Should adjacent knockbacks consider alliances or be neutral? --------
-------- --------
Set Variable Set Knockback2DAmphibious = "true"
Set Variable Set Knockback2DBounces = "false"
Set Variable Set Knockback2DCollision = "16.00"
Set Variable Set Knockback2DDestRadius = "128.00"
Set Variable Set Knockback2DGravity = "0.67"
Set Variable Set Knockback2DHeight = "137.00"
Set Variable Set Knockback2DKillTrees = "false"
Set Variable Set Knockback2DOnImpact = On_Impact <gen>
Set Variable Set Knockback2DOverride = "true"
Set Variable Set Knockback2DPause = "true"
Set Variable Set Knockback2DSimple = "true"
Set Variable Set Knockback2DSource = DamageEventSource
Set Variable Set Knockback2DUnbiasedCollision = "false"
Else - Actions
-------- Allied units shouldn't allow collision with each other, but for the sake of the demo let's make it interesting --------
Set Variable Set Knockback2DCollision = "32.00"
-------- Also make it so that enemies will bounce with these experiments --------
Set Variable Set Knockback2DUnbiasedCollision = "true"
Set Variable Set Knockback2DLoopFX = "Abilities\Weapons\FaerieDragonMissile\FaerieDragonMissile.mdl"
Set Variable Set Knockback2DFXRate = "0.20"
-------- --------
-------- When all variables are set, run the Knockback 2D trigger, checking conditions if you want to be safe --------
-------- --------
Trigger - Run Knockback_2D <gen> (checking conditions)
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Or - Any (Conditions) are true
Conditions
Tauren_Shockwave[(Custom value of DamageEventSource)] Equal to True
Tauren_WarStomp[(Custom value of DamageEventSource)] Equal to True
Then - Actions
Set Variable Set CenterPoint = (Position of DamageEventSource)
Set Variable Set TargetPoint = (Position of DamageEventTarget)
Set Variable Set Knockback2DAngle = (Angle from CenterPoint to TargetPoint)
Custom script: call RemoveLocation(udg_CenterPoint)
Custom script: call RemoveLocation(udg_TargetPoint)
Set Variable Set Knockback2DTime = "0.50"
Set Variable Set Knockback2DDistance = "75.00"
Set Variable Set Knockback2DUnit = DamageEventTarget
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Tauren_WarStomp[(Custom value of DamageEventSource)] Equal to True
Then - Actions
-------- For War Stomp, add a height factor --------
Set Variable Set Knockback2DHeight = "250.00"
Set Variable Set Knockback2DDistance = "100.00"
Else - Actions
Set Variable Set Knockback2DDistance = "300.00"
Trigger - Run Knockback_2D <gen> (ignoring conditions)
Else - Actions
-------- Deleting the next line will re-enable damage in the map --------
Set Variable Set DamageEventAmount = "0.00"
On Impact
Events
Conditions
Actions
Special Effect - Create a special effect attached to the origin (Unexpected type: 'attachpoint') of UDexUnits[UDex] using Objects\Spawnmodels\Undead\ImpaleTargetDust\ImpaleTargetDust.mdl
Special Effect - Destroy (Last created special effect)
On Spell Cast
Events
Unit - A unit owned by Player 1 (Red) . Starts the effect of an ability
Conditions
Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Ability being cast) Equal to Shockwave
Then - Actions
Set Variable Set Tauren_Shockwave[(Custom value of (Triggering unit))] = "true"
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Ability being cast) Equal to War Stomp
Then - Actions
Set Variable Set Tauren_WarStomp[(Custom value of (Triggering unit))] = "true"
Else - Actions
On Spell Stop
Events
Unit - A unit owned by Player 1 (Red) . Stops casting an ability
Conditions
Actions
Unit - Reset ability cooldowns for (Triggering unit) .
Unit - Set mana of (Triggering unit) to 100 %
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Ability being cast) Equal to Shockwave
Then - Actions
-------- In case the unit had other damaging spells, we don't want those spells to trigger an unwanted knockback --------
Set Variable Set Tauren_Shockwave[(Custom value of (Triggering unit))] = "false"
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Ability being cast) Equal to War Stomp
Then - Actions
-------- Same goes for here --------
Set Variable Set Tauren_WarStomp[(Custom value of (Triggering unit))] = "false"
Else - Actions
Stop time of day
Events
Map initialization
Conditions
Actions
Game - Turn the day/night cycle Off
Test
Events
Unit - A unit owned by Player 1 (Red) . Is issued an order targeting a point
Unit - A unit owned by Player 1 (Red) . Is issued an order targeting an object
Conditions
Actions
Unit - Add Ghost (Visible) to (Triggering unit)
Custom script: call UnitAddAbility(GetTriggerUnit(), 'Aloc')
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Target unit of issued order) Not equal to No unit
Then - Actions
Set Variable Set TargetPoint = (Position of (Target unit of issued order))
Else - Actions
Set Variable Set TargetPoint = (Target point of issued order)
Custom script: call GroupEnumUnitsInRangeOfLoc(udg_LeaklessGroup, udg_TargetPoint, 128.00, null)
Unit Group - Pick every unit in LeaklessGroup and do (Actions)
Loop - Actions
Unit - Add Ghost (Visible) to (Picked unit)
Unit - Hide (Picked unit)
Unit - Move (Triggering unit) instantly to TargetPoint
Unit - Remove Ghost (Visible) from (Triggering unit)
Custom script: call RemoveLocation(udg_TargetPoint)
Set Variable Set TargetPoint = (Position of (Triggering unit))
Special Effect - Create a special effect at TargetPoint using Abilities\Spells\NightElf\Blink\BlinkTarget.mdl
Special Effect - Destroy (Last created special effect)
Custom script: call RemoveLocation(udg_TargetPoint)
Wait 0.00 seconds
Unit Group - Pick every unit in LeaklessGroup and do (Actions)
Loop - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Picked unit) Not equal to (Triggering unit)
Then - Actions
Unit - Remove Ghost (Visible) from (Picked unit)
Else - Actions
Unit - Unhide (Picked unit)
Top