1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. We have recently started the 16th edition of the Mini Mapping Contest. The theme is mini RPG. Do check it out and have fun.
    Dismiss Notice
  5. Choose your ride to damnation in the 5th Special Effect Contest Poll.
    Dismiss Notice
  6. The winners of the 13th Techtree Contest have been announced!
    Dismiss Notice
  7. The 13th Music Contest Poll has begun! Vote for the best tracks in this symphony of frost and flame.
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Trigger Viewer

Damage Engine v5.5.0.0.w3x
Variables
Variables
Damage Engine
Vars
Armor Types
Attack Types
Damage Types
Defense Types
Weapon Types
Demo Triggers
Opening Text
Set Damage
Untitled Trigger 001
Prevent Lethal
On AOE
On Death
On Zero
Untitled Trigger 002
Damage Report
AfterDamageEvent
Report On Off
Trigger Damage
Demo Requirement
Unit Moving
Vars
Damage Engine Config
Damage Engine
Unit Indexer
Is Unit Moving
Unit Moving Index
Unit Indexer
Vars
Text Tags
Arcing TT by Maker
Damage Tag
Lotsa Damage

		
Name Type Is Array Initial Value
AfterDamageEvent real No
AOEDamageEvent real No
AOEDamageSource unit No
AOEString string No
ARMOR_TYPE_ETHEREAL integer No
ARMOR_TYPE_FLESH integer No
ARMOR_TYPE_METAL integer No
ARMOR_TYPE_NONE integer No
ARMOR_TYPE_STONE integer No
ARMOR_TYPE_WOOD integer No
ArmorTypeDebugStr string Yes
ATTACK_TYPE_CHAOS integer No
ATTACK_TYPE_HERO integer No
ATTACK_TYPE_MAGIC integer No
ATTACK_TYPE_NORMAL integer No
ATTACK_TYPE_PIERCE integer No
ATTACK_TYPE_SIEGE integer No
ATTACK_TYPE_SPELLS integer No
AttackTypeDebugStr string Yes
CONVERTED_ATTACK_TYPE attacktype Yes
CONVERTED_DAMAGE_TYPE damagetype Yes
DAMAGE_TYPE_ACID integer No
DAMAGE_TYPE_COLD integer No
DAMAGE_TYPE_DEATH integer No
DAMAGE_TYPE_DEFENSIVE integer No
DAMAGE_TYPE_DEMOLITION integer No
DAMAGE_TYPE_DISEASE integer No
DAMAGE_TYPE_DIVINE integer No
DAMAGE_TYPE_ENHANCED integer No
DAMAGE_TYPE_FIRE integer No
DAMAGE_TYPE_FORCE integer No
DAMAGE_TYPE_LIGHTNING integer No
DAMAGE_TYPE_MAGIC integer No
DAMAGE_TYPE_MIND integer No
DAMAGE_TYPE_NORMAL integer No
DAMAGE_TYPE_PLANT integer No
DAMAGE_TYPE_POISON integer No
DAMAGE_TYPE_SHADOW_STRIKE integer No
DAMAGE_TYPE_SLOW_POISON integer No
DAMAGE_TYPE_SONIC integer No
DAMAGE_TYPE_SPIRIT_LINK integer No
DAMAGE_TYPE_UNIVERSAL integer No
DAMAGE_TYPE_UNKNOWN integer No
DamageEvent real No
DamageEventAmount real No
DamageEventAOE integer No
DamageEventAOEGroup group No
DamageEventArmorPierced real No
DamageEventArmorT integer No
DamageEventAttackT integer No
DamageEventDamageT integer No
DamageEventDefenseT integer No
DamageEventLevel integer No
DamageEventOverride boolean No
DamageEventPrevAmt real No
DamageEventSource unit No
DamageEventTarget unit No
DamageEventTrigger trigger No
DamageEventType integer No
DamageEventWeaponT integer No
DamageModifierEvent real No
DamageScalingUser real No
DamageScalingWC3 real No
DamageTypeBlocked integer No
DamageTypeCode integer No
DamageTypeCriticalStrike integer No
DamageTypeDebugStr string Yes
DamageTypeExplosive integer No
DamageTypeHeal integer No
DamageTypePure integer No
DamageTypePureExplosive integer No
DamageTypeReduced integer No
DEFENSE_TYPE_DIVINE integer No
DEFENSE_TYPE_FORTIFIED integer No
DEFENSE_TYPE_HEAVY integer No
DEFENSE_TYPE_HERO integer No
DEFENSE_TYPE_LIGHT integer No
DEFENSE_TYPE_MEDIUM integer No
DEFENSE_TYPE_NORMAL integer No
DEFENSE_TYPE_UNARMORED integer No
DefenseTypeDebugStr string Yes
DmgStr string No
EnhancedDamageTarget unit No
IsDamageAttack boolean No
IsDamageCode boolean No
IsDamageMelee boolean No
IsDamageRanged boolean No
IsDamageSpell boolean No
LethalDamageEvent real No
LethalDamageHP real No
NextDamageType integer No
Reporting boolean No
ReportLife real No
TempLoc location No
TempX real No
TempY real No
Timestamp timer No
UDex integer No
UDexGen integer No
UDexNext integer Yes
UDexPrev integer Yes
UDexRecycle integer No
UDexUnits unit Yes
UDexWasted integer No
UMovNext integer Yes
UMovPrev integer Yes
UnitIndexerEnabled boolean No
UnitIndexEvent real No
UnitMoving boolean Yes
UnitMovingEvent real No
UnitMovingInList boolean Yes
UnitMovingX real Yes
UnitMovingY real Yes
WEAPON_TYPE_AM_CHOP integer No
WEAPON_TYPE_CH_SLICE integer No
WEAPON_TYPE_CL_SLICE integer No
WEAPON_TYPE_CM_SLICE integer No
WEAPON_TYPE_MH_BASH integer No
WEAPON_TYPE_MH_CHOP integer No
WEAPON_TYPE_MH_SLICE integer No
WEAPON_TYPE_MH_STAB integer No
WEAPON_TYPE_ML_CHOP integer No
WEAPON_TYPE_ML_SLICE integer No
WEAPON_TYPE_MM_BASH integer No
WEAPON_TYPE_MM_CHOP integer No
WEAPON_TYPE_MM_SLICE integer No
WEAPON_TYPE_MM_STAB integer No
WEAPON_TYPE_NONE integer No
WEAPON_TYPE_RH_BASH integer No
WEAPON_TYPE_WH_BASH integer No
WEAPON_TYPE_WH_SLICE integer No
WEAPON_TYPE_WL_BASH integer No
WEAPON_TYPE_WL_SLICE integer No
WEAPON_TYPE_WL_STAB integer No
WEAPON_TYPE_WM_BASH integer No
WEAPON_TYPE_WM_SLICE integer No
WEAPON_TYPE_WM_STAB integer No
WeaponTypeDebugStr string Yes
Opening Text
  Events
    Time - Elapsed game time is 0.00 seconds
  Conditions
  Actions
    Game - Display to (All players) for 30.00 seconds the text: Ranged attacks deal 50% damage to moving targets, but are armor piercing when the target is still.Summoned units take 200% damage, but retaliate with the damage back at the attacker.The Archmage is healed when attacked by a water elemental.The Knight has a 50% chance to deal a 4x critical strike that pierces 50 armor.The Peasant's attacks are always dodged.The Mutant's health cannot be reduced below 1.Archimonde's attacks will normally kill the target, but instead heal for that amount.Type |cffff0000report|r in order to toggle in-depth damage analysis.Type |cffff0000damage|r in order to damage selected units
    Countdown Timer - Start Timestamp as a One-shot timer that will expire in 604800.00 seconds
This trigger sets the damage based on certain conditions of the attack.
Set Damage
  Events
    Game - DamageModifierEvent becomes Equal to 1.00
  Conditions
  Actions
    Custom script: set DamageEngine_inception = true
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing 1.00 damage of attack type Spells and damage type Magic
    Game - Display to (All players) the text: (String((Mana of DamageEventTarget)))
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Unit-type of DamageEventSource) Equal to Peasant
      Then - Actions
        Set VariableSet DamageEventAmount = 0.00
        Set VariableSet DamageEventArmorT = ARMOR_TYPE_NONE
        Set VariableSet DamageEventWeaponT = WEAPON_TYPE_NONE
      Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            IsDamageSpell Equal to False
            (Unit-type of DamageEventSource) Equal to Warlock
            DamageEventTarget Equal to EnhancedDamageTarget
          Then - Actions
            Set VariableSet DamageEventAmount = (0.00 - DamageEventAmount)
          Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                (DamageEventTarget is A Hero) Equal to True
                (DamageEventSource is Summoned) Equal to True
              Then - Actions
                Set VariableSet DamageEventAmount = (0.00 - DamageEventAmount)
              Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  If - Conditions
                    (Unit-type of DamageEventSource) Equal to Knight
                    (Random integer number between 1 and 10) Less than 6
                    IsDamageSpell Equal to False
                  Then - Actions
                    -------- --------
                    -------- Set DamageEventType to Critical Strike so we can show a critical strike text tag using the trigger "Critical Strike" --------
                    -------- --------
                    Set VariableSet DamageEventType = DamageTypeCriticalStrike
                    Set VariableSet DamageEventAmount = (DamageEventAmount x 4.00)
                    Set VariableSet DamageEventArmorPierced = 50.00
                  Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  If - Conditions
                    (DamageEventTarget is Summoned) Equal to True
                  Then - Actions
                    -------- --------
                    -------- Summoned units take 200% damage --------
                    -------- They also retaliate with the damage amount when attacked. --------
                    -------- --------
                    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type CONVERTED_ATTACK_TYPE[DamageEventAttackT] and damage type CONVERTED_DAMAGE_TYPE[DamageEventDamageT]
                    Set VariableSet DamageEventAmount = (DamageEventAmount x 2.00)
                  Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  If - Conditions
                    IsDamageRanged Equal to True
                  Then - Actions
                    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      If - Conditions
                        UnitMoving[(Custom value of DamageEventTarget)] Equal to True
                      Then - Actions
                        -------- --------
                        -------- Units that are moving take 50% damage from ranged attacks --------
                        -------- --------
                        Set VariableSet DamageEventAmount = (DamageEventAmount x 0.50)
                      Else - Actions
                        Set VariableSet DamageEventDefenseT = DEFENSE_TYPE_UNARMORED
                        Set VariableSet DamageEventArmorPierced = (Armor of DamageEventTarget)
                  Else - Actions
    Set VariableSet ReportLife = (Life of DamageEventTarget)
Untitled Trigger 001
  Events
    Game - DamageModifierEvent becomes Equal to 2.00
    Game - DamageModifierEvent becomes Equal to 3.00
  Conditions
  Actions
    Game - Display to (All players) the text: secondary
Prevent Lethal
  Events
    Game - LethalDamageEvent becomes Equal to 1.00
  Conditions
    (Unit-type of DamageEventTarget) Equal to Dalaran Mutant
  Actions
    Set VariableSet LethalDamageHP = 1.00
On AOE
  Events
    Game - AOEDamageEvent becomes Equal to 1.00
  Conditions
  Actions
    If (Reporting Equal to False) then do (Skip remaining actions) else do (Do nothing)
    Set VariableSet AOEString = ((Name of AOEDamageSource) + has dealt AOE damage to )
    Unit Group - Pick every unit in DamageEventAOEGroup and do (Actions)
      Loop - Actions
        Set VariableSet AOEString = (AOEString + ((Name of (Picked unit)) + , ))
    Game - Display to (All players) the text: ((Substring(AOEString, 1, ((Length of AOEString) - 2))) + .)
This trigger is important to show that the killer is really getting the kill
On Death
  Events
    Unit - A unit owned by Player 1 (Red).Dies
  Conditions
    (Killing unit) Not equal to No unit
    Reporting Equal to True
  Actions
    Game - Display to (All players) the text: ((Name of (Killing unit)) + ( killed a + (Name of (Triggering unit))))
On Zero
  Events
    Game - DamageEvent becomes Equal to 2.00
  Conditions
  Actions
    Set VariableSet ReportLife = (Life of DamageEventTarget)
    Trigger - Run Damage_Report <gen> (ignoring conditions)
Untitled Trigger 002
  Events
    Unit - A unit Is issued an order targeting an object
  Conditions
  Actions
    Custom script: set bj_wantDestroyGroup = true
    Set VariableSet TempLoc = (Position of (Target unit of issued order))
    Unit Group - Pick every unit in (Units within 512 of TempLoc.) and do (Actions)
      Loop - Actions
        Unit - Cause (Triggering unit) to damage (Picked unit), dealing 1.00 damage of attack type Spells and damage type Universal
    Custom script: call RemoveLocation(udg_TempLoc)
Damage Report
  Events
  Conditions
  Actions
    If (Reporting Equal to False) then do (Skip remaining actions) else do (Do nothing)
    Game - Display to (All players) the text: (============== + ((String((Elapsed time for Timestamp))) + ==============))
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        IsDamageCode Equal to True
      Then - Actions
        Set VariableSet DmgStr = ( User damage of type: + (String(DamageEventType)))
      Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            IsDamageAttack Equal to True
          Then - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                IsDamageRanged Equal to True
              Then - Actions
                Set VariableSet DmgStr = Ranged damage.
              Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  If - Conditions
                    IsDamageMelee Equal to True
                  Then - Actions
                    Set VariableSet DmgStr = Melee damage.
                  Else - Actions
                    Set VariableSet DmgStr = Spell attack damage.
          Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                IsDamageSpell Equal to True
              Then - Actions
                Set VariableSet DmgStr = Spell damage.
              Else - Actions
    -------- Set the above condition to True Equal to False to disable the in-game damage analysis --------
    Game - Display to (All players) the text: (REPORT: + ((Name of DamageEventSource) + ( damaged + ((Name of DamageEventTarget) + ( for + ((String(DamageEventPrevAmt)) + ( => + ((String(DamageEventAmount)) + DmgStr))))))))
    Game - Display to (All players) the text: (Attack Type + (AttackTypeDebugStr[DamageEventAttackT] + ( Damage Type + (DamageTypeDebugStr[DamageEventDamageT] + ( Weapon Type + WeaponTypeDebugStr[DamageEventWeaponT])))))
    Game - Display to (All players) the text: (Armor Type + (ArmorTypeDebugStr[DamageEventArmorT] + ( Defense Type + DefenseTypeDebugStr[DamageEventDefenseT])))
    Game - Display to (All players) the text: (Life chanaged from + ((String(ReportLife)) + ( to + (String((Life of DamageEventTarget))))))
    Game - Display to (All players) the text: (WarCraft 3 increased the damage by + ((String((100.00 x (DamageScalingWC3 - 1.00)))) + (% and the user increased it by + ((String((100.00 x (DamageScalingUser - 1.00)))) + %.))))
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        DamageEventLevel Greater than 1
      Then - Actions
        Game - Display to (All players) the text: Source applied an enhanced effect with this damage.
      Else - Actions
AfterDamageEvent
  Events
    Game - AfterDamageEvent becomes Equal to 1.00
  Conditions
  Actions
    Trigger - Run Damage_Report <gen> (ignoring conditions)
Report On Off
  Events
    Player - Player 1 (Red) types a chat message containing report (stringnoformat) as An exact match
  Conditions
  Actions
    Custom script: set udg_Reporting = not udg_Reporting
Trigger Damage
  Events
    Player - Player 1 (Red) types a chat message containing damage (stringnoformat) as An exact match
  Conditions
  Actions
    Custom script: set bj_wantDestroyGroup = true
    Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
      Loop - Actions
        Set VariableSet NextDamageType = DamageTypeCode
        Unit - Cause (Picked unit) to damage (Picked unit), dealing 1.00 damage of attack type Spells and damage type Universal
Damage Engine Config
  Events
    Map initialization
    Game - DamageModifierEvent becomes Equal to 0
    Game - LethalDamageEvent becomes Equal to 0
    Game - DamageEvent becomes Equal to 0
    Game - AfterDamageEvent becomes Equal to 0
    Game - AOEDamageEvent becomes Equal to 0
  Conditions
  Actions
    -------- - --------
    -------- 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 --------
    -------- - --------
    -------- The pre-defined type Code might be set by Damage Engine if Unit - Damage Target is detected and the user didn't define a type of their own. --------
    -------- "Pure" is especially important because it overrides both the Damage Engine as well as WarCraft 3 damage modification. --------
    -------- I therefore gave the user "Explosive Pure" in case one wants to combine the functionality of the two. --------
    -------- - --------
    Set VariableSet DamageTypePureExplosive = -2
    Set VariableSet DamageTypeExplosive = -1
    Set VariableSet DamageTypeCode = 1
    Set VariableSet DamageTypePure = 2
    -------- - --------
    Set VariableSet DamageTypeHeal = 3
    Set VariableSet DamageTypeBlocked = 4
    Set VariableSet DamageTypeReduced = 5
    -------- - --------
    Set VariableSet DamageTypeCriticalStrike = 6
    -------- - --------
    -------- Added 25 July 2017 to allow detection of things like Bash or Pulverize or AOE spread --------
    -------- - --------
    Set VariableSet DamageEventAOE = 1
    Set VariableSet DamageEventLevel = 1
    -------- - --------
    -------- In-game World Editor doesn't allow Attack Type and Damage Type comparisons. Therefore I need to code them as integers into GUI --------
    -------- - --------
    Set VariableSet ATTACK_TYPE_SPELLS = 0
    Set VariableSet ATTACK_TYPE_NORMAL = 1
    Set VariableSet ATTACK_TYPE_PIERCE = 2
    Set VariableSet ATTACK_TYPE_SIEGE = 3
    Set VariableSet ATTACK_TYPE_MAGIC = 4
    Set VariableSet ATTACK_TYPE_CHAOS = 5
    Set VariableSet ATTACK_TYPE_HERO = 6
    -------- - --------
    Set VariableSet DAMAGE_TYPE_UNKNOWN = 0
    Set VariableSet DAMAGE_TYPE_NORMAL = 4
    Set VariableSet DAMAGE_TYPE_ENHANCED = 5
    Set VariableSet DAMAGE_TYPE_FIRE = 8
    Set VariableSet DAMAGE_TYPE_COLD = 9
    Set VariableSet DAMAGE_TYPE_LIGHTNING = 10
    Set VariableSet DAMAGE_TYPE_POISON = 11
    Set VariableSet DAMAGE_TYPE_DISEASE = 12
    Set VariableSet DAMAGE_TYPE_DIVINE = 13
    Set VariableSet DAMAGE_TYPE_MAGIC = 14
    Set VariableSet DAMAGE_TYPE_SONIC = 15
    Set VariableSet DAMAGE_TYPE_ACID = 16
    Set VariableSet DAMAGE_TYPE_FORCE = 17
    Set VariableSet DAMAGE_TYPE_DEATH = 18
    Set VariableSet DAMAGE_TYPE_MIND = 19
    Set VariableSet DAMAGE_TYPE_PLANT = 20
    Set VariableSet DAMAGE_TYPE_DEFENSIVE = 21
    Set VariableSet DAMAGE_TYPE_DEMOLITION = 22
    Set VariableSet DAMAGE_TYPE_SLOW_POISON = 23
    Set VariableSet DAMAGE_TYPE_SPIRIT_LINK = 24
    Set VariableSet DAMAGE_TYPE_SHADOW_STRIKE = 25
    Set VariableSet DAMAGE_TYPE_UNIVERSAL = 26
    -------- - --------
    -------- The below variables don't affect damage amount, but do affect the sound played --------
    -------- They also give important information about the type of attack used. --------
    -------- They can differentiate between ranged and melee for units who are both --------
    -------- - --------
    Set VariableSet WEAPON_TYPE_NONE = 0
    -------- Metal Light/Medium/Heavy --------
    Set VariableSet WEAPON_TYPE_ML_CHOP = 1
    Set VariableSet WEAPON_TYPE_MM_CHOP = 2
    Set VariableSet WEAPON_TYPE_MH_CHOP = 3
    Set VariableSet WEAPON_TYPE_ML_SLICE = 4
    Set VariableSet WEAPON_TYPE_MM_SLICE = 5
    Set VariableSet WEAPON_TYPE_MH_SLICE = 6
    Set VariableSet WEAPON_TYPE_MM_BASH = 7
    Set VariableSet WEAPON_TYPE_MH_BASH = 8
    Set VariableSet WEAPON_TYPE_MM_STAB = 9
    Set VariableSet WEAPON_TYPE_MH_STAB = 10
    -------- Wood Light/Medium/Heavy --------
    Set VariableSet WEAPON_TYPE_WL_SLICE = 11
    Set VariableSet WEAPON_TYPE_WM_SLICE = 12
    Set VariableSet WEAPON_TYPE_WH_SLICE = 13
    Set VariableSet WEAPON_TYPE_WL_BASH = 14
    Set VariableSet WEAPON_TYPE_WM_BASH = 15
    Set VariableSet WEAPON_TYPE_WH_BASH = 16
    Set VariableSet WEAPON_TYPE_WL_STAB = 17
    Set VariableSet WEAPON_TYPE_WM_STAB = 18
    -------- Claw Light/Medium/Heavy --------
    Set VariableSet WEAPON_TYPE_CL_SLICE = 19
    Set VariableSet WEAPON_TYPE_CM_SLICE = 20
    Set VariableSet WEAPON_TYPE_CH_SLICE = 21
    -------- Axe Medium --------
    Set VariableSet WEAPON_TYPE_AM_CHOP = 22
    -------- Rock Heavy --------
    Set VariableSet WEAPON_TYPE_RH_BASH = 23
    -------- - --------
    -------- Since GUI still doesn't provide Defense Type and Armor Types, I needed to include the below --------
    -------- - --------
    Set VariableSet ARMOR_TYPE_NONE = 0
    Set VariableSet ARMOR_TYPE_FLESH = 1
    Set VariableSet ARMOR_TYPE_METAL = 2
    Set VariableSet ARMOR_TYPE_WOOD = 3
    Set VariableSet ARMOR_TYPE_ETHEREAL = 4
    Set VariableSet ARMOR_TYPE_STONE = 5
    -------- - --------
    Set VariableSet DEFENSE_TYPE_LIGHT = 0
    Set VariableSet DEFENSE_TYPE_MEDIUM = 1
    Set VariableSet DEFENSE_TYPE_HEAVY = 2
    Set VariableSet DEFENSE_TYPE_FORTIFIED = 3
    Set VariableSet DEFENSE_TYPE_NORMAL = 4
    Set VariableSet DEFENSE_TYPE_HERO = 5
    Set VariableSet DEFENSE_TYPE_DIVINE = 6
    Set VariableSet DEFENSE_TYPE_UNARMORED = 7
    -------- - --------
    Custom script: call DamageEngine_DebugStr()
//===========================================================================
//  
//  Damage Engine 5.5.0.0 - update requires copying of the Damage Engine folder.
//  
//===========================================================================
library DamageEngine initializer Init
   
globals
    private timer   alarm       = CreateTimer()
    private boolean alarmSet    = false
   
    //Values to track the original pre-spirit Link/defensive damage values
    private boolean canKick         = true
    private boolean totem           = false
    private real lastAmount         = 0.00
    private real lastPrevAmt        = 0.00
    private integer lastType        = 0  
    private boolean lastCode        = false
    private real lastPierced        = 0.00
    private integer armorType       = 0
    private integer lastArmor       = 0
    private boolean lastAttack      = false
    private integer lastPrevArmor   = 0
    private integer defenseType     = 0
    private integer lastDefense     = 0
    private integer lastPrevDefense = 0
   
    //Stuff to track recursive UnitDamageTarget calls.
    private boolean eventsRun       = false
    private boolean kicking         = false
    private integer damageStack     = 0
    private unit array sourceStack
    private unit array targetStack
    private real array amountStack
    private attacktype array attackTStack
    private damagetype array damageTStack
    private weapontype array weaponTStack
    private integer array userTrigStack
    private integer array typeStack
   
    //Added in 5.4 to silently eliminate infinite recursion.
    private integer userTrigs = 9
    private integer eventTrig = 0
    private integer array nextTrig
    private trigger array userTrig
    private boolean array trigFrozen
       
    //Added/re-tooled in 5.4.1 to allow forced recursion (for advanced users only).
    private constant integer    LIMBO           = 16    //Recursion will never go deeper than LIMBO.
    private integer array       levelsDeep              //How deep the user recursion currently is.
    public boolean              inception       = false //You must set DamageEngine_inception = true before dealing damage to utlize this.
                                                        //When true, it allows your trigger to potentially go recursive up to LIMBO.
    private boolean             dreaming        = false
    private boolean array       inceptionTrig           //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
    private integer             sleepLevel      = 0
    private group               proclusGlobal   = CreateGroup() //track sources of recursion
    private group               fischerMorrow   = CreateGroup() //track targets of recursion
   
    //Improves readability in the code to have these as named constants.
    private constant integer    MOD_EVENT       = 1
    private constant integer    SHIELD_EVENT    = 4
    private constant integer    DAMAGE_EVENT    = 5
    private constant integer    ZERO_EVENT      = 6
    private constant integer    AFTER_EVENT     = 7
    private constant integer    LETHAL_EVENT    = 8
    private constant integer    AOE_EVENT       = 9
   
    //private string crashStr = ""
endglobals
   
//GUI Vars:
/*
    Retained from 3.8 and prior:
    ----------------------------
    unit            udg_DamageEventSource
    unit            udg_DamageEventTarget
    unit            udg_EnhancedDamageTarget
    group           udg_DamageEventAOEGroup
    integer         udg_DamageEventAOE
    integer         udg_DamageEventLevel
    real            udg_DamageModifierEvent
    real            udg_DamageEvent
    real            udg_AfterDamageEvent
    real            udg_DamageEventAmount
    real            udg_DamageEventPrevAmt
    real            udg_AOEDamageEvent
    boolean         udg_DamageEventOverride
    boolean         udg_NextDamageType
    boolean         udg_DamageEventType
    boolean         udg_IsDamageSpell
   
    //Added in 5.0:
    boolean          udg_IsDamageMelee    
    boolean          udg_IsDamageRanged    
    unit             udg_AOEDamageSource  
    real             udg_LethalDamageEvent
    real             udg_LethalDamageHP    
    real             udg_DamageScalingWC3
    integer          udg_DamageEventAttackT
    integer          udg_DamageEventDamageT
    integer          udg_DamageEventWeaponT
   
    //Added in 5.1:
    boolean          udg_IsDamageCode    
   
    //Added in 5.2:
    integer          udg_DamageEventArmorT  
    integer          udg_DamageEventDefenseT
   
    //Addded in 5.3:
    real             DamageEventArmorPierced
    real             udg_DamageScalingUser  
   
    //Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
    attacktype array udg_CONVERTED_ATTACK_TYPE
    damagetype array udg_CONVERTED_DAMAGE_TYPE
   
    //Added after Reforged introduced the new native BlzGetDamageIsAttack
    boolean         udg_IsDamageAttack
*/

   
    private function RunTrigs takes integer i returns nothing
        local integer cat = i
        if dreaming then
            //call BJDebugMsg("Tried to run triggers while triggers were already running.")
            return
        endif
        set dreaming = true
        //call BJDebugMsg("Start of event running")
        loop
            set i = nextTrig[i]
            exitwhen i == 0
            exitwhen cat == MOD_EVENT and (udg_DamageEventOverride or udg_DamageEventType*udg_DamageEventType == 4)
            exitwhen cat == SHIELD_EVENT and udg_DamageEventAmount <= 0.00
            exitwhen cat == LETHAL_EVENT and udg_LethalDamageHP > 0.405
            //set crashStr = "Bout to inspect " + I2S(i)
            if not trigFrozen[i] and IsTriggerEnabled(userTrig[i]) then
                set eventTrig = i
                //set crashStr = "Bout to evaluate " + I2S(i)
                if TriggerEvaluate(userTrig[i]) then
                    //set crashStr = "Bout to execute " + I2S(i)
                    call TriggerExecute(userTrig[i])
                endif
                //set crashStr = "Ran " + I2S(i)
                //call BJDebugMsg("Ran " + I2S(i))
                //if not (udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 or udg_DamageEventAmount == 0.00) then
                //    if cat == MOD_EVENT then
                //        set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
                //    elseif cat == SHIELD_EVENT then
                //        set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
                //    endif
                //elseif udg_DamageEventPrevAmt == 0.00 then
                //    call BJDebugMsg("Prev amount 0.00 and User Amount " + R2S(udg_DamageEventAmount))
                //elseif udg_DamageEventAmount == 0.00 then
                //    call BJDebugMsg("User amount 0.00 and Prev Amount " + R2S(udg_DamageEventPrevAmt))
                //elseif udg_DamageScalingWC3 == 0.00 then
                //    call BJDebugMsg("WC3 amount somehow 0.00")
                //endif
                //set crashStr = "Filtered " + I2S(i)
            //elseif i > 9 then
            //    if trigFrozen[i] then
            //        call BJDebugMsg("User Trigger is frozen")
            //    else
            //        call BJDebugMsg("User Trigger is off")
            //    endif
            endif
        endloop
        //call BJDebugMsg("End of event running")
        set dreaming = false
    endfunction
   
    private function OnAOEEnd takes nothing returns nothing
        if udg_DamageEventAOE > 1 then
            call RunTrigs(AOE_EVENT)
            set udg_DamageEventAOE      = 1
        endif
        set udg_DamageEventLevel        = 1
        set udg_EnhancedDamageTarget    = null
        set udg_AOEDamageSource         = null
        call GroupClear(udg_DamageEventAOEGroup)
    endfunction
   
    private function AfterDamage takes nothing returns nothing
        if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
            call RunTrigs(AFTER_EVENT)
        endif
    endfunction
   
    private function Finish takes nothing returns nothing
        local integer i = 0
        local integer exit
        if eventsRun then
            //call BJDebugMsg("events ran")
            set eventsRun = false
            call AfterDamage()
        endif
        if canKick and not kicking then
            //call BJDebugMsg("can kick")
            if damageStack > 0 then
                set kicking = true
                //call BJDebugMsg("Clearing queued damage instances: " + I2S(damageStack))
                loop
                    set exit = damageStack
                    set sleepLevel = sleepLevel + 1
                    loop
                        set udg_NextDamageType = typeStack[i]
                        //call BJDebugMsg("Stacking on " + R2S(amountStack[i]))
                        call UnitDamageTarget(sourceStack[i], targetStack[i], amountStack[i], true, false, attackTStack[i], damageTStack[i], weaponTStack[i])
                        call AfterDamage()
                        set i = i + 1 //Need to loop bottom to top to make sure damage order is preserved.
                        exitwhen i == exit
                    endloop
                    //call BJDebugMsg("Exit at: " + I2S(i))
                    exitwhen i == damageStack
                endloop
                //call BJDebugMsg("Terminate at at: " + I2S(i))
                set sleepLevel = 0
                loop
                    set i = i - 1
                    set trigFrozen[userTrigStack[i]] = false //Only re-enable recursive triggers AFTER all damage is dealt.
                    set levelsDeep[userTrigStack[i]] = 0 //Reset this stuff if the user tried some nonsense
                    exitwhen i == 0
                endloop
                //call BJDebugMsg("Cleared queued damage instances: " + I2S(damageStack))
                set damageStack = 0 //Can only be set after all the damage has successfully ended.
                set kicking = false
            endif
            call GroupClear(proclusGlobal)
            call GroupClear(fischerMorrow)
        //elseif kicking then
        //    call BJDebugMsg("Somehow still kicking")
        //else
        //    call BJDebugMsg("Cannot kick")
        endif
    endfunction
   
    private function ResetArmor takes nothing returns nothing
        if udg_DamageEventArmorPierced != 0.00 then
            call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + udg_DamageEventArmorPierced)
        endif
        if armorType != udg_DamageEventArmorT then
            call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, armorType) //revert changes made to the damage instance
        endif
        if defenseType != udg_DamageEventDefenseT then
            call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, defenseType)
        endif
    endfunction
   
    private function FailsafeClear takes nothing returns nothing
        //call BJDebugMsg("Damage from " + GetUnitName(udg_DamageEventSource) + " to " + GetUnitName(udg_DamageEventTarget) + " has been messing up Damage Engine.")
        //call BJDebugMsg(R2S(udg_DamageEventAmount) + " " + " " + R2S(udg_DamageEventPrevAmt) + " " + udg_AttackTypeDebugStr[udg_DamageEventAttackT] + " " + udg_DamageTypeDebugStr[udg_DamageEventDamageT])
        call ResetArmor()
        set canKick = true
        set totem = false
        set udg_DamageEventAmount = 0.00
        set udg_DamageScalingWC3  = 0.00
        if udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
            call RunTrigs(DAMAGE_EVENT) //Run the normal on-damage event based on this failure.
            set eventsRun = true //Run the normal after-damage event based on this failure.
        endif
        call Finish()
    endfunction
   
    private function WakeUp takes nothing returns nothing
        set alarmSet    = false //The timer has expired. Flag off to allow it to be restarted when needed.
        //if dreaming then
        //    set dreaming= false
        //    call BJDebugMsg("Timer set dreaming to False")
        //    call BJDebugMsg(crashStr)
        //endif
        if totem then
            //Something went wrong somewhere; the WarCraft 3 engine didn't run the DAMAGED event despite running the DAMAGING event.
            call FailsafeClear()
        else
            if not canKick and damageStack > 0 then
                //call BJDebugMsg("Damage Engine recursion deployment was failing with application of: " + R2S(udg_DamageEventAmount))
                set canKick = true
            endif
            call Finish() //Wrap up any outstanding damage instance
        endif
        call OnAOEEnd() //Reset things so they don't perpetuate for AoE/Level target detection
        set udg_DamageEventPrevAmt = 0.00 //Added in 5.4.2.1 to try to squash the Cold Arrows glitch (failed to do it)
    endfunction
   
    private function CalibrateMR takes nothing returns nothing
        set udg_IsDamageMelee           = false
        set udg_IsDamageRanged          = false
        set udg_IsDamageSpell           = udg_DamageEventAttackT == 0 and not udg_IsDamageAttack
        if udg_DamageEventDamageT == udg_DAMAGE_TYPE_NORMAL and not udg_IsDamageSpell then //This damage type is the only one that can get reduced by armor.
            set udg_IsDamageMelee       = IsUnitType(udg_DamageEventSource, UNIT_TYPE_MELEE_ATTACKER)
            set udg_IsDamageRanged      = IsUnitType(udg_DamageEventSource, UNIT_TYPE_RANGED_ATTACKER)
            if udg_IsDamageMelee and udg_IsDamageRanged then
                set udg_IsDamageMelee   = udg_DamageEventWeaponT > 0// Melee units play a sound when damaging
                set udg_IsDamageRanged  = not udg_IsDamageMelee     // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
            endif                                                   // The Huntress has a melee sound for her ranged projectile, however it is only an issue
        endif                                                       //if she also had a melee attack, because by default she is only UNIT_TYPE_RANGED_ATTACKER.
    endfunction
   
    private function OnPreDamage takes nothing returns boolean
        local unit src      = GetEventDamageSource()
        local unit tgt      = GetTriggerUnit()
        local real amt      = GetEventDamage()
        local attacktype at = BlzGetEventAttackType()
        local damagetype dt = BlzGetEventDamageType()
        local weapontype wt = BlzGetEventWeaponType()
       
        //call BJDebugMsg("First damage event running")
       
        if dreaming then
            //call BJDebugMsg("Dreaming")
            if amt != 0.00 then
                //Store recursive damage into a queue from index "damageStack" (0-15)
                //This damage will be fired after the current damage instance has wrapped up its events.
                //This damage can only be caused by triggers.
                set amountStack[damageStack]   = amt
                set sourceStack[damageStack]   = src
                set targetStack[damageStack]   = tgt
                set attackTStack[damageStack]  = at
                set damageTStack[damageStack]  = dt
                set weaponTStack[damageStack]  = wt
                set userTrigStack[damageStack] = eventTrig
                if udg_NextDamageType == 0 then
                    set typeStack[damageStack] = udg_DamageTypeCode
                else
                    set typeStack[damageStack] = udg_NextDamageType
                endif
                //Next block added in 5.4.1 to allow *some* control over whether recursion should kick
                //in. Also it's important to track whether the source and target were both involved at
                //some earlier point, so this is a more accurate and lenient method than before.
                set inception = inception or inceptionTrig[eventTrig]
                call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
                call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
                if kicking and IsUnitInGroup(src, proclusGlobal) and IsUnitInGroup(tgt, fischerMorrow) then
                    if inception and not trigFrozen[eventTrig] then
                        set inceptionTrig[eventTrig] = true
                        if levelsDeep[eventTrig] < sleepLevel then
                            set levelsDeep[eventTrig] = levelsDeep[eventTrig] + 1
                            if levelsDeep[eventTrig] >= LIMBO then
                                set trigFrozen[eventTrig] = true
                            endif
                        endif
                    else
                        set trigFrozen[eventTrig] = true
                    endif
                endif
                set damageStack = damageStack + 1
                //call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(levelsDeep[eventTrig]) + " sleepLevel: " + I2S(sleepLevel))
                call BlzSetEventDamage(0.00) //queue the damage instance instead of letting it run recursively
            endif
        else
            if not kicking then
                //Added 25 July 2017 to detect AOE damage or multiple single-target damage
                if alarmSet then
                    if totem then
                        if dt != DAMAGE_TYPE_SPIRIT_LINK and dt != DAMAGE_TYPE_DEFENSIVE and dt != DAMAGE_TYPE_PLANT then
                            //if 'totem' is still set and it's not due to spirit link distribution or defense retaliation,
                            //the next function must be called as a debug. This reverts an issue I created in patch 5.1.3.
                            call FailsafeClear()
                        else
                            set totem           = false
                            set lastAmount      = udg_DamageEventAmount
                            set lastPrevAmt     = udg_DamageEventPrevAmt    //Store the actual pre-armor value.
                            set lastType        = udg_DamageEventType       //also store the damage type.
                            set lastCode        = udg_IsDamageCode          //store this as well.
                            set lastAttack      = udg_IsDamageAttack        //Added after this new Reforged native.
                            set lastArmor       = udg_DamageEventArmorT
                            set lastPrevArmor   = armorType
                            set lastDefense     = udg_DamageEventDefenseT
                            set lastPrevDefense = defenseType
                            set lastPierced     = udg_DamageEventArmorPierced
                            set canKick         = false
                        endif
                    else
                        call Finish()
                    endif
                    if src != udg_AOEDamageSource then //Source has damaged more than once
                        call OnAOEEnd() //New damage source - unflag everything
                        set udg_AOEDamageSource = src
                    elseif tgt == udg_EnhancedDamageTarget then
                        set udg_DamageEventLevel= udg_DamageEventLevel + 1  //The number of times the same unit was hit.
                    elseif not IsUnitInGroup(tgt, udg_DamageEventAOEGroup) then
                        set udg_DamageEventAOE  = udg_DamageEventAOE + 1    //Multiple targets hit by this source - flag as AOE
                    endif
                else
                    call TimerStart(alarm, 0.00, false, function WakeUp)
                    set alarmSet                = true
                    set udg_AOEDamageSource     = src
                    set udg_EnhancedDamageTarget= tgt
                endif
                call GroupAddUnit(udg_DamageEventAOEGroup, tgt)
            endif
            set udg_DamageEventType             = udg_NextDamageType
            set udg_IsDamageCode                = udg_NextDamageType != 0
            set udg_IsDamageAttack              = BlzGetEventIsAttack()
            set udg_DamageEventOverride         = dt == null //Got rid of NextDamageOverride in 5.1 for simplicity
            set udg_DamageEventPrevAmt          = amt
            set udg_DamageEventSource           = src
            set udg_DamageEventTarget           = tgt
            set udg_DamageEventAmount           = amt
            set udg_DamageEventAttackT          = GetHandleId(at)
            set udg_DamageEventDamageT          = GetHandleId(dt)
            set udg_DamageEventWeaponT          = GetHandleId(wt)
           
            call CalibrateMR() //Set Melee and Ranged settings.
           
            set udg_DamageEventArmorT           = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE) //Introduced in Damage Engine 5.2.0.0
            set udg_DamageEventDefenseT         = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE)
            set armorType                       = udg_DamageEventArmorT
            set defenseType                     = udg_DamageEventDefenseT
            set udg_DamageEventArmorPierced     = 0.00
            set udg_DamageScalingUser           = 1.00
            set udg_DamageScalingWC3            = 1.00
           
            if amt != 0.00 then
                if not udg_DamageEventOverride then
                    call RunTrigs(MOD_EVENT)
               
                    //All events have run and the pre-damage amount is finalized.
                    call BlzSetEventAttackType(ConvertAttackType(udg_DamageEventAttackT))
                    call BlzSetEventDamageType(ConvertDamageType(udg_DamageEventDamageT))
                    call BlzSetEventWeaponType(ConvertWeaponType(udg_DamageEventWeaponT))
                    if udg_DamageEventArmorPierced != 0.00 then
                        call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) - udg_DamageEventArmorPierced)
                    endif
                    if armorType != udg_DamageEventArmorT then
                        call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, udg_DamageEventArmorT) //Introduced in Damage Engine 5.2.0.0
                    endif
                    if defenseType != udg_DamageEventDefenseT then
                        call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, udg_DamageEventDefenseT) //Introduced in Damage Engine 5.2.0.0
                    endif
                    call BlzSetEventDamage(udg_DamageEventAmount)
                endif
                //call BJDebugMsg("Ready to deal " + R2S(udg_DamageEventAmount))
                set totem = true
            else
                call RunTrigs(ZERO_EVENT)
                set canKick = true
                call Finish()
            endif
        endif
        set src = null
        set tgt = null
        set inception = false
        set udg_NextDamageType = 0
        return false
    endfunction
   
    //The traditional on-damage response, where armor reduction has already been factored in.
    private function OnDamage takes nothing returns boolean
        local real r = GetEventDamage()
        //call BJDebugMsg("Second damage event running")
        if dreaming or udg_DamageEventPrevAmt == 0.00 then
            //if dreaming then
            //    call BJDebugMsg("Dreaming")
            //else
            //    call BJDebugMsg("Prev amount is zero")
            //endif
            return false
        endif
        if totem then
            set totem = false   //This should be the case in almost all circumstances
        else
            call AfterDamage() //Wrap up the outstanding damage instance
            set canKick                     = true
            //Unfortunately, Spirit Link and Thorns Aura/Spiked Carapace fire the DAMAGED event out of sequence with the DAMAGING event,
            //so I have to re-generate a buncha stuff here.
            set udg_DamageEventSource       = GetEventDamageSource()
            set udg_DamageEventTarget       = GetTriggerUnit()
            set udg_DamageEventAmount       = lastAmount
            set udg_DamageEventPrevAmt      = lastPrevAmt
            set udg_DamageEventAttackT      = GetHandleId(BlzGetEventAttackType())
            set udg_DamageEventDamageT      = GetHandleId(BlzGetEventDamageType())
            set udg_DamageEventWeaponT      = GetHandleId(BlzGetEventWeaponType())
            set udg_DamageEventType         = lastType
            set udg_IsDamageAttack          = lastAttack
            set udg_IsDamageCode            = lastCode
            set udg_DamageEventArmorT       = lastArmor
            set udg_DamageEventDefenseT     = lastDefense
            set udg_DamageEventArmorPierced = lastPierced
            set armorType                   = lastPrevArmor
            set defenseType                 = lastPrevDefense
            call CalibrateMR() //Apply melee/ranged settings once again.
        endif
        call ResetArmor()
        if udg_DamageEventAmount != 0.00 and r != 0.00 then
            set udg_DamageScalingWC3 = r / udg_DamageEventAmount
        elseif udg_DamageEventAmount > 0.00 then
            set udg_DamageScalingWC3 = 0.00
        else
            set udg_DamageScalingWC3 = 1.00
            set udg_DamageScalingUser = udg_DamageEventAmount / udg_DamageEventPrevAmt
        endif
        set udg_DamageEventAmount = udg_DamageEventAmount*udg_DamageScalingWC3
       
        if udg_DamageEventAmount > 0.00 then
            //This event is used for custom shields which have a limited hit point value
            //The shield here kicks in after armor, so it acts like extra hit points.
            call RunTrigs(SHIELD_EVENT)
            set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
            if udg_LethalDamageHP <= 0.405 then
                call RunTrigs(LETHAL_EVENT) //Added 10 May 2019 to detect and potentially prevent lethal damage. Instead of
                //modifying the damage, you need to modify LethalDamageHP instead (the final HP of the unit).
               
                set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
                if udg_DamageEventType < 0 and udg_LethalDamageHP <= 0.405 then
                    call SetUnitExploded(udg_DamageEventTarget, true)   //Explosive damage types should blow up the target.
                endif
            endif
            set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
        endif
        call BlzSetEventDamage(udg_DamageEventAmount)   //Apply the final damage amount.
        if udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
            call RunTrigs(DAMAGE_EVENT)
        endif
        set eventsRun = true
        if udg_DamageEventAmount == 0.00 then
            call Finish()
        endif
        return false
    endfunction
   
    //===========================================================================
    private function Init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DAMAGED) //Thanks to this I no longer have to create an event for every unit in the map.
        call TriggerAddCondition(trig, Filter(function OnDamage))
        set trig = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DAMAGING) //The new 1.31 event which fires before damage.
        call TriggerAddCondition(trig, Filter(function OnPreDamage))
        set trig = null
    endfunction
   
    public function DebugStr takes nothing returns nothing
        local integer i = 0
        loop
            set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
            exitwhen i == 6
            set i = i + 1
        endloop
        set i = 0
        loop
            set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
            exitwhen i == 26
            set i = i + 1
        endloop
        set udg_AttackTypeDebugStr[0] = "SPELLS"    //ATTACK_TYPE_NORMAL in JASS
        set udg_AttackTypeDebugStr[1] = "NORMAL"    //ATTACK_TYPE_MELEE in JASS
        set udg_AttackTypeDebugStr[2] = "PIERCE"
        set udg_AttackTypeDebugStr[3] = "SIEGE"
        set udg_AttackTypeDebugStr[4] = "MAGIC"
        set udg_AttackTypeDebugStr[5] = "CHAOS"
        set udg_AttackTypeDebugStr[6] = "HERO"
       
        set udg_DamageTypeDebugStr[0]  = "UNKNOWN"
        set udg_DamageTypeDebugStr[4]  = "NORMAL"
        set udg_DamageTypeDebugStr[5]  = "ENHANCED"
        set udg_DamageTypeDebugStr[8]  = "FIRE"
        set udg_DamageTypeDebugStr[9]  = "COLD"
        set udg_DamageTypeDebugStr[10] = "LIGHTNING"
        set udg_DamageTypeDebugStr[11] = "POISON"
        set udg_DamageTypeDebugStr[12] = "DISEASE"
        set udg_DamageTypeDebugStr[13] = "DIVINE"
        set udg_DamageTypeDebugStr[14] = "MAGIC"
        set udg_DamageTypeDebugStr[15] = "SONIC"
        set udg_DamageTypeDebugStr[16] = "ACID"
        set udg_DamageTypeDebugStr[17] = "FORCE"
        set udg_DamageTypeDebugStr[18] = "DEATH"
        set udg_DamageTypeDebugStr[19] = "MIND"
        set udg_DamageTypeDebugStr[20] = "PLANT"
        set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
        set udg_DamageTypeDebugStr[22] = "DEMOLITION"
        set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
        set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
        set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
        set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
        set udg_WeaponTypeDebugStr[0]  = "NONE"     //WEAPON_TYPE_WHOKNOWS in JASS
        set udg_WeaponTypeDebugStr[1]  = "METAL_LIGHT_CHOP"
        set udg_WeaponTypeDebugStr[2]  = "METAL_MEDIUM_CHOP"
        set udg_WeaponTypeDebugStr[3]  = "METAL_HEAVY_CHOP"
        set udg_WeaponTypeDebugStr[4]  = "METAL_LIGHT_SLICE"
        set udg_WeaponTypeDebugStr[5]  = "METAL_MEDIUM_SLICE"
        set udg_WeaponTypeDebugStr[6]  = "METAL_HEAVY_SLICE"
        set udg_WeaponTypeDebugStr[7]  = "METAL_MEDIUM_BASH"
        set udg_WeaponTypeDebugStr[8]  = "METAL_HEAVY_BASH"
        set udg_WeaponTypeDebugStr[9]  = "METAL_MEDIUM_STAB"
        set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
        set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
        set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
        set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
        set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
        set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
        set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
        set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
        set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
        set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
        set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
        set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
        set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
        set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
        set udg_DefenseTypeDebugStr[0] = "LIGHT"
        set udg_DefenseTypeDebugStr[1] = "MEDIUM"
        set udg_DefenseTypeDebugStr[2] = "HEAVY"
        set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
        set udg_DefenseTypeDebugStr[4] = "NORMAL"   //Typically deals flat damage to all armor types
        set udg_DefenseTypeDebugStr[5] = "HERO"
        set udg_DefenseTypeDebugStr[6] = "DIVINE"
        set udg_DefenseTypeDebugStr[7] = "UNARMORED"
       
        set udg_ArmorTypeDebugStr[0] = "NONE"       //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
        set udg_ArmorTypeDebugStr[1] = "FLESH"
        set udg_ArmorTypeDebugStr[2] = "METAL"
        set udg_ArmorTypeDebugStr[3] = "WOOD"
        set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
        set udg_ArmorTypeDebugStr[5] = "STONE"
    endfunction
   
    //This function exists mainly to make it easier to switch from another DDS, like PDD.
    function UnitDamageTargetEx takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns boolean
        if udg_NextDamageType == 0 then
           set udg_NextDamageType = udg_DamageTypeCode
        endif
        call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
        return dreaming
    endfunction
   
    public function SetupEvent takes trigger whichTrig, string var, integer index returns nothing
        local integer max = 1
        local integer off = 0
        local integer exit = 0
        local integer i
        if var == "udg_DamageModifierEvent" then //MOD_EVENT 1-4 -> Events 1-4
            if index < 3 then
                set exit = index + 1
            endif
            if nextTrig[1] == 0 then
                set nextTrig[1] = 2
                set nextTrig[2] = 3
                set trigFrozen[2] = true
                set trigFrozen[3] = true
            endif
            set max = 4
        elseif var == "udg_DamageEvent" then //DAMAGE_EVENT 1,2 -> Events 5,6
            set max = 2
            set off = 4
        elseif var == "udg_AfterDamageEvent" then //AFTER_EVENT -> Event 7
            set off = 6
        elseif var == "udg_LethalDamageEvent" then //LETHAL_EVENT -> Event 8
            set off = 7
        elseif var == "udg_AOEDamageEvent" then //AOE_EVENT -> Event 9
            set off = 8
        else
            return
        endif
        set i = IMaxBJ(IMinBJ(index, max), 1) + off
        //call BJDebugMsg("Root index: " + I2S(i))
        loop
            set index = i
            set i = nextTrig[i]
            exitwhen i == exit
        endloop
        set userTrigs = userTrigs + 1   //User list runs from index 10 and up
        set nextTrig[index] = userTrigs
        set nextTrig[userTrigs] = exit
        set userTrig[userTrigs] = whichTrig
        //call BJDebugMsg("Registered " + I2S(userTrigs) + " to " + I2S(index))
    endfunction
   
    private function PreSetup takes trigger whichTrig, string var, limitop op, real value returns nothing
        call SetupEvent(whichTrig, var, R2I(value))
    endfunction
   
    hook TriggerRegisterVariableEvent PreSetup
   
endlibrary
Use "UnitMoving[(Custom value of Unit)] Equal to true" to check if a unit is moving.

Use the event "UnitMovingEvent Equal to 1.00" to detect when a unit starts moving. Use the event "UnitMovingEvent Equal to 2.00" to detect when one stops moving.

In either event, the unit that has started moving is "UDexUnits[UDex]".
Is Unit Moving
  Events
    Time - Every 0.05 seconds of game time
  Conditions
  Actions
    Set VariableSet UDex = UMovNext[0]
    Custom script: loop
    Custom script: exitwhen udg_UDex == 0
    Custom script: set udg_TempX = GetUnitX(udg_UDexUnits[udg_UDex])
    Custom script: set udg_TempY = GetUnitY(udg_UDexUnits[udg_UDex])
    Custom script: if udg_TempX != udg_UnitMovingX[udg_UDex] or udg_TempY != udg_UnitMovingY[udg_UDex] then
    Set VariableSet UnitMovingX[UDex] = TempX
    Set VariableSet UnitMovingY[UDex] = TempY
    Custom script: if not udg_UnitMoving[udg_UDex] then
    Custom script: if GetUnitTypeId(udg_UDexUnits[udg_UDex]) != 0 then
    Set VariableSet UnitMoving[UDex] = True
    Set VariableSet UnitMovingEvent = 1.00
    Set VariableSet UnitMovingEvent = 0.00
    Custom script: elseif udg_UnitMovingInList[udg_UDex] then
    Set VariableSet UnitMovingInList[UDex] = False
    Set VariableSet UnitMoving[UDex] = False
    Set VariableSet UMovNext[UMovPrev[UDex]] = UMovNext[UDex]
    Set VariableSet UMovPrev[UMovNext[UDex]] = UMovPrev[UDex]
    Set VariableSet UMovPrev[UDex] = 0
    Custom script: endif
    Custom script: endif
    Custom script: elseif udg_UnitMoving[udg_UDex] then
    Set VariableSet UnitMoving[UDex] = False
    Set VariableSet UnitMovingEvent = 2.00
    Set VariableSet UnitMovingEvent = 0.00
    Custom script: endif
    Set VariableSet UDex = UMovNext[UDex]
    Custom script: endloop
Unit Moving Index
  Events
    Game - UnitIndexEvent becomes Equal to 1.00
  Conditions
  Actions
    -------- - --------
    -------- The next conditions let you filter out unwanted units --------
    -------- - --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Default movement speed of UDexUnits[UDex]) Not equal to 0.00
      Then - Actions
        Set VariableSet UnitMovingInList[UDex] = True
        Set VariableSet UMovPrev[UMovNext[0]] = UDex
        Set VariableSet UMovNext[UDex] = UMovNext[0]
        Set VariableSet UMovNext[0] = UDex
        Custom script: set udg_UnitMovingX[udg_UDex] = GetUnitX(udg_UDexUnits[udg_UDex])
        Custom script: set udg_UnitMovingY[udg_UDex] = GetUnitY(udg_UDexUnits[udg_UDex])
      Else - Actions
Unit Indexer gives you an array-safe (1-8190) custom value for units, eliminating the need for hashtables to store unit-specific data.
Just use "Set MyArrayData[(Custom value of Unit)] = (Some data)".
--------
If you want to get the unit assigned to an index (reverse lookup) use "UDexUnits[(Index)]".
--------
If you want to detect when an index is created or when it is released, use "UnitIndexEvent Equal to 1.00" (created) or "UnitIndexEvent Equal to 2.00" (released). The index being created/released is called "UDex".
--------
You can enable/disable Unit Indexer to protect some of your undesirable units from being indexed like this:

Trigger - Turn off Unit Indexer <gen>
Unit - Create 1 Dummy for (Triggering player) at TempPoint facing 0.00 degrees
Trigger - Turn on Unit Indexer <gen>
--------
If you want to use a Map Initialization trigger that uses custom value of units, to make sure that UnitIndexer initializes first, use the event "UnitIndexEvent Equal to 3.00". Otherwise the custom value of units may be zero.
--------
Advanced:
--------
If you want to lock the index of a unit, use "Set UnitIndexLock[(Index)] = (UnitIndexLock[(Index)] + 1)". This will prevent the index from being recycled. If you want to unlock it and allow it to be recycled, run the Unit Indexer <gen> trigger.

Note: Make sure if you add a lock that you will eventually remove the lock, otherwise the index will never be recycled.
Unit Indexer
  Events
    Map initialization
  Conditions
  Actions
    Custom script: call ExecuteFunc("InitializeUnitIndexer")
    Custom script: endfunction
    Custom script:
    Custom script: function ClearUnitIndex takes nothing returns nothing
    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
        Set VariableSet UDexNext[UDexPrev[UDex]] = UDexNext[UDex]
        Set VariableSet UDexPrev[UDexNext[UDex]] = UDexPrev[UDex]
        Set VariableSet UDexPrev[UDex] = 0
        Set VariableSet UnitIndexEvent = 0.00
        Set VariableSet UnitIndexEvent = 2.00
        Set VariableSet UDexUnits[UDex] = No unit
        Set VariableSet UDexNext[UDex] = UDexRecycle
        Set VariableSet UDexRecycle = UDex
      Else - Actions
    Custom script: endfunction
    Custom script:
    Custom script: function IndexUnit takes nothing returns boolean
    Custom script: local integer pdex = udg_UDex
    Custom script: local integer ndex
    -------- - --------
    -------- You can 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
        (Custom value of (Matching unit)) Equal to 0
      Then - Actions
        Set VariableSet UDexWasted = (UDexWasted + 1)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            UDexWasted Equal to 32
          Then - Actions
            Set VariableSet UDexWasted = 0
            Set VariableSet UDex = UDexNext[0]
            Custom script: loop
            Custom script: exitwhen udg_UDex == 0
            Custom script: set ndex = udg_UDexNext[udg_UDex]
            Custom script: call ClearUnitIndex()
            Custom script: set udg_UDex = ndex
            Custom script: endloop
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            UDexRecycle Equal to 0
          Then - Actions
            Set VariableSet UDex = (UDexGen + 1)
            Set VariableSet UDexGen = UDex
          Else - Actions
            Set VariableSet UDex = UDexRecycle
            Set VariableSet UDexRecycle = UDexNext[UDex]
        Set VariableSet UDexUnits[UDex] = (Matching unit)
        Unit - Set the custom value of UDexUnits[UDex] to UDex
        Set VariableSet UDexPrev[UDexNext[0]] = UDex
        Set VariableSet UDexNext[UDex] = UDexNext[0]
        Set VariableSet UDexNext[0] = UDex
        Set VariableSet UnitIndexEvent = 0.00
        Set VariableSet UnitIndexEvent = 1.00
        Custom script: set udg_UDex = pdex
      Else - Actions
    Custom script: return false
    Custom script: endfunction
    Custom script:
    Custom script: function InitializeUnitIndexer takes nothing returns nothing
    Custom script: local integer i = bj_MAX_PLAYER_SLOTS
    Custom script: local boolexpr b = Filter(function IndexUnit)
    Custom script: local region re = CreateRegion()
    Custom script: local trigger t = GetTriggeringTrigger()
    Custom script: local rect r = GetWorldBounds()
    Custom script: call RegionAddRect(re, r)
    Custom script: call TriggerRegisterEnterRegion(t, re, b)
    Custom script: call TriggerClearActions(t)
    Custom script: call TriggerAddAction(t, function ClearUnitIndex)
    Set VariableSet UnitIndexerEnabled = True
    Custom script: loop
    Custom script: set i = i - 1
    Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), b)
    Custom script: exitwhen i == 0
    Custom script: endloop
    Custom script: call RemoveRect(r)
    Custom script: set re = null
    Custom script: set r = null
    Custom script: set t = null
    Custom script: set b = null
    Set VariableSet UnitIndexEvent = 3.00

// Arcing Text Tag v1.0.0.3 by Maker

library FloatingTextArc
    globals
        private constant    real    SIZE_MIN        = 0.018         // Minimum size of text
        private constant    real    SIZE_BONUS      = 0.012         // Text size increase
        private constant    real    TIME_LIFE       = 1.0           // How long the text lasts
        private constant    real    TIME_FADE       = 0.8           // When does the text start to fade
        private constant    real    Z_OFFSET        = 50            // Height above unit
        private constant    real    Z_OFFSET_BON    = 50            // How much extra height the text gains
        private constant    real    VELOCITY        = 2             // How fast the text move in x/y plane
        private constant    real    ANGLE           = bj_PI/2       // Movement angle of the text. Does not apply if
                                                                    // ANGLE_RND is true
        private constant    boolean ANGLE_RND       = true          // Is the angle random or fixed
        private             timer   TMR             = CreateTimer()
    endglobals
   
    struct ArcingTextTag extends array
        private texttag tt
        private real as         // angle, sin component
        private real ac         // angle, cos component
        private real ah         // arc height
        private real t          // time
        private real x          // origin x
        private real y          // origin y
        private string s        // text
        private static integer array next
        private static integer array prev
        private static integer array rn
        private static integer ic           = 0       // Instance count  
       
        private static method update takes nothing returns nothing
            local thistype this=next[0]
            local real p
            loop
                set p = Sin(bj_PI*.t)
                set .t = .t - 0.03125
                set .x = .x + .ac
                set .y = .y + .as
                call SetTextTagPos(.tt, .x, .y, Z_OFFSET + Z_OFFSET_BON * p)
                call SetTextTagText(.tt, .s, SIZE_MIN + SIZE_BONUS * p)
                if .t <= 0 then
                    set .tt = null
                    set next[prev[this]] = next[this]
                    set prev[next[this]] = prev[this]
                    set rn[this] = rn[0]
                    set rn[0] = this
                    if next[0]==0 then
                        call PauseTimer(TMR)
                    endif
                endif
                set this = next[this]
                exitwhen this == 0
            endloop
        endmethod
       
        public static method create takes string s, unit u returns thistype
            local thistype this = rn[0]
            static if ANGLE_RND then
                local real a = GetRandomReal(0, 2*bj_PI)
            else
                local real a = ANGLE
            endif
            if this == 0 then
                set ic = ic + 1
                set this = ic
            else
                set rn[0] = rn[this]
            endif
           
            set next[this] = 0
            set prev[this] = prev[0]
            set next[prev[0]] = this
            set prev[0] = this
           
            set .s = s
            set .x = GetUnitX(u)
            set .y = GetUnitY(u)
            set .t = TIME_LIFE
            set .as = Sin(a)*VELOCITY
            set .ac = Cos(a)*VELOCITY
            set .ah = 0.
           
            if IsUnitVisible(u, GetLocalPlayer()) then
                set .tt = CreateTextTag()
                call SetTextTagPermanent(.tt, false)
                call SetTextTagLifespan(.tt, TIME_LIFE)
                call SetTextTagFadepoint(.tt, TIME_FADE)
                call SetTextTagText(.tt, s, SIZE_MIN)
                call SetTextTagPos(.tt, .x, .y, Z_OFFSET)
            endif
           
            if prev[this] == 0 then
                call TimerStart(TMR, 0.03125, true, function thistype.update)
            endif
           
            return this
        endmethod
    endstruct
endlibrary
Damage Tag
  Events
    Game - DamageEvent becomes Equal to 1.00
  Conditions
  Actions
    Game - Display to (All players) the text: (String((Mana of DamageEventTarget)))
    Set VariableSet DmgStr = |cffffffff
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        DamageEventAmount Equal to 0.00
      Then - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Unit-type of DamageEventSource) Equal to Peasant
          Then - Actions
            Set VariableSet DmgStr = |c00AAAAAADODGED!|r
          Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                DamageScalingWC3 Equal to 0.00
              Then - Actions
                Set VariableSet DmgStr = (|c00AAAAAABlocked + ((String((Integer((DamageEventPrevAmt x DamageScalingUser))))) + !|r))
              Else - Actions
                Set VariableSet DmgStr = (|c00AAAAAABlocked + ((String((Integer((DamageEventPrevAmt x DamageScalingWC3))))) + !|r))
        Custom script: call ArcingTextTag.create(udg_DmgStr, udg_DamageEventTarget)
      Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            DamageEventAmount Less than -0.99
          Then - Actions
            Set VariableSet DmgStr = |cff00ff00+
            Custom script: call ArcingTextTag.create(udg_DmgStr + I2S(R2I(-udg_DamageEventAmount)) + "|r", udg_DamageEventTarget)
          Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                DamageScalingUser Greater than or equal to 1.50
              Then - Actions
                Set VariableSet DmgStr = (|cffff0000 + ((String((Integer(DamageEventAmount)))) + !|r))
                Custom script: call ArcingTextTag.create(udg_DmgStr, udg_DamageEventTarget)
              Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  If - Conditions
                    DamageEventAmount Greater than 0.99
                  Then - Actions
                    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      If - Conditions
                        DamageScalingUser Less than 0.60
                      Then - Actions
                        Set VariableSet DmgStr = |cff808000
                      Else - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                          If - Conditions
                            IsDamageSpell Equal to True
                          Then - Actions
                            Set VariableSet DmgStr = |cff3264c8
                          Else - Actions
                            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                              If - Conditions
                                IsDamageRanged Equal to True
                              Then - Actions
                                Set VariableSet DmgStr = |cffffff00
                              Else - Actions
                    Custom script: call ArcingTextTag.create(udg_DmgStr + I2S(R2I(udg_DamageEventAmount)) + "|r", udg_DamageEventTarget)
                  Else - Actions
    Set VariableSet ReportLife = (Life of DamageEventTarget)
Lotsa Damage
  Events
    Game - DamageEvent becomes Equal to 1.00
  Conditions
  Actions
    Custom script: set DamageEngine_inception = true
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type Spells and damage type Magic
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type Spells and damage type Magic
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type Spells and damage type Magic
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type Spells and damage type Magic
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type Spells and damage type Magic
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type Spells and damage type Magic
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type Spells and damage type Magic
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type Spells and damage type Magic