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. Dismiss Notice
  6. The Highway to Hell has been laid open. Come along and participate in the 5th Special Effect Contest.
    Dismiss Notice
  7. 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

Lua Damage Engine based on 5.4.2.3.w3x
Variables
Damage Engine
Damage Engine Config
DamageEngine
Required Lua
Global Initialization
Variable Event
Vars
Armor Types
Attack Types
Damage Types
Defense Types
Weapon Types
Demo Triggers
Opening Text
Set Damage
Prevent Lethal
On AOE
On Zero
Damage Report
AfterDamageEvent
Report On Off
TimerUtils
FastTriggers
PolledWait
SlowEval
Benchmark
Untitled Trigger 001
Untitled Trigger 003
Untitled Trigger 003 Copy
Untitled Trigger 002
TestTrig
Demo Requirement
Unit Moving
Is Unit Moving
Unit Moving Index
Vars
Unit Indexer
Unit Indexer
Unit Indexer Event
Vars
Text Tags
Arcing TT by Maker
Damage Tag
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code except Custom Script Item. Custom Script Item will merge into map script after globals variables declaration with the list order in trigger view.

		
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
IsDamageCode boolean No
IsDamageMelee boolean No
IsDamageRanged boolean No
IsDamageSpell boolean No
IsUnitPreplaced boolean Yes
LethalDamageEvent real No
LethalDamageHP real No
NextDamageType integer No
Reporting boolean No
ReportLife real No
TempGroup group No
TempX real No
TempY real No
Timestamp timer No
UDex integer No
UDexUnits unit Yes
UMovNext integer Yes
UMovPrev integer Yes
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
Damage Engine Config
  Events
    Map initialization
  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
--[[
===========================================================================
 Lua Version
 
 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 (after it was dealt to the unit): use the event "DamageEvent Equal to 1.00"
 - To change damage before it is dealt: use the event "DamageModifierEvent 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"
   
 You can specify the DamageEventType before dealing triggered damage:
 - Set NextDamageType = DamageTypeWhatever
 - Unit - Cause...
   
 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".
 
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
   
=============================================================================
--]]
 
do
   local alarm       = CreateTimer()
   local alarmSet    = false
   
   --Values to track the original pre-spirit Link/defensive damage values
   local canKick     = true
   local totem       = false
   local armorType   = 0
   local defenseType = 0
   local prev        = {}
   
   --Stuff to track recursive UnitDamageTarget calls.
   local eventsRun   = false
   local kicking     = false
   local stack       = {}
   
   --Added in 5.4 to silently eliminate infinite recursion.
   local userTrigs   = 9
   local eventTrig   = 0
   local nextTrig    = {}
   local userTrig    = {}
   local trigFrozen  = {}
   
   --Added/re-tooled in 5.4.1 to allow forced recursion (for advanced users only).
   local levelsDeep     = {}   --How deep the user recursion currently is.
   local LIMBO          = 16   --Recursion will never go deeper than LIMBO.
   DamageEngine_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.
   local dreaming       = false
   local fischerMorrow  = {} --track targets of recursion
   local inceptionTrig  = {}   --Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
   local proclusGlobal  = {} --track sources of recursion
   local sleepLevel     = 0
   
   --Improves readability in the code to have these as named constants.
   local event = {
      mod      = 1,
      shield   = 4,
      damage   = 5,
      zero     = 6,
      after    = 7,
      lethal   = 8,
      aoe      = 9
   }
   
   local function runTrigs(i)
      local cat = i
      dreaming = true
      --print("Running " .. cat)
      while (true) do
         i = nextTrig[i]
         if (i == 0)
           or (cat == event.mod and (udg_DamageEventOverride or udg_DamageEventType*udg_DamageEventType == 4))
           or (cat == event.shield and udg_DamageEventAmount <= 0.00)
           or (cat == event.lethal and udg_LethalDamageHP > 0.405) then
            break
         end
         if not trigFrozen[i] then
            eventTrig = i
            if RunTrigger then --Added 10 July 2019 to enable FastTriggers mode.
               RunTrigger(userTrig[i])
            elseif IsTriggerEnabled(userTrig[i])
              and TriggerEvaluate(userTrig[i]) then
               TriggerExecute(userTrig[i])
            end
            --print("Ran " .. i)
         end
      end
      --print("Ran")
      dreaming = false
   end
   
   local function onAOEEnd()
      if udg_DamageEventAOE > 1 then
         runTrigs(event.aoe)
         udg_DamageEventAOE   = 1
      end
      udg_DamageEventLevel    = 1
      udg_EnhancedDamageTarget= nil
      udg_AOEDamageSource     = nil
      GroupClear(udg_DamageEventAOEGroup)
   end
   
   local function afterDamage()
      if udg_DamageEventPrevAmt ~= 0.00 and udg_DamageEventDamageT ~= udg_DAMAGE_TYPE_UNKNOWN then
         runTrigs(event.after)
      end
   end
   
   local oldUDT = UnitDamageTarget
   
   local function finish()
      if eventsRun then
         --print "events ran"
         eventsRun = false
         afterDamage()
      end
      if canKick and not kicking then
         local n = #stack
         if n > 0 then
            kicking = true
            --print("Clearing Recursion: " .. n)
            local i = 0
            local open
            repeat
               sleepLevel = sleepLevel + 1
               repeat
                  i = i + 1 --Need to loop bottom to top to make sure damage order is preserved.
                  open = stack[i]
                  udg_NextDamageType = open.type
                  --print("Stacking on " .. open.amount)
                  oldUDT(open.source, open.target, open.amount, true, false, open.attack, open.damage, open.weapon)
                  afterDamage()
               until (i == n)
               --print("Exit at: " .. i)
               n = #stack
            until (i == n)
            --print("Terminate at: " .. i)
            sleepLevel = 0
            repeat
               open = stack[i].trig
               stack[i] = nil
               proclusGlobal[open] = nil
               fischerMorrow[open] = nil
               trigFrozen[open] = false -- Only re-enable recursive triggers AFTER all damage is dealt.
               levelsDeep[open] = 0 --Reset this stuff if the user tried some nonsense
               --print("unfreezing " .. open)
               i = i - 1
            until (i == 0)
            kicking = false
         end
      end
   end
   
   function UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
      if udg_NextDamageType == 0 then
         udg_NextDamageType = udg_DamageTypeCode
      end
      local b = false
      if dreaming then
         if amt ~= 0.00 then
            -- Store triggered, recursive damage into a stack.
            -- This damage will be fired after the current damage instance has wrapped up its events.
            stack[#stack + 1] = {
               type     = udg_NextDamageType,
               source   = src,
               target   = tgt,
               amount   = amt,
               attack   = at,
               damage   = dt,
               weapon   = wt,
               trig     = eventTrig
            }
            --print("increasing damage stack: " .. #stack)
           
            -- 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.
            DamageEngine_inception = DamageEngine_inception or inceptionTrig[eventTrig]
           
            local sg = proclusGlobal[eventTrig]
            if not sg then
               sg = {}
               proclusGlobal[eventTrig] = sg
            end
            sg[udg_DamageEventSource] = true
           
            local tg = fischerMorrow[eventTrig]
            if not tg then
               tg = {}
               fischerMorrow[eventTrig] = tg
            end
            tg[udg_DamageEventTarget] = true
           
            if kicking and sg[src] and tg[tgt] then
               if DamageEngine_inception and not trigFrozen[eventTrig] then
                  inceptionTrig[eventTrig] = true
                  if levelsDeep[eventTrig] < sleepLevel then
                     levelsDeep[eventTrig] = levelsDeep[eventTrig] + 1
                     if levelsDeep[eventTrig] >= LIMBO then
                        --print("freezing inception trig: " .. eventTrig)
                        trigFrozen[eventTrig] = true
                     end
                  end
               else
                  --print("freezing standard trig: " .. eventTrig)
                  trigFrozen[eventTrig] = true
               end
            end
         end
      else
         b = oldUDT(src, tgt, amt, a, r, at, dt, wt)
      end
      --print("setting inception to false")
      DamageEngine_inception = false
      udg_NextDamageType = 0
      if b and not dreaming then
         finish() -- Wrap up the outstanding damage instance right away.
      end
      return b
   end
   
   local function resetArmor()
      if udg_DamageEventArmorPierced ~= 0.00 then
         BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + udg_DamageEventArmorPierced)
      end
      if armorType ~= udg_DamageEventArmorT then
         BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, armorType) --revert changes made to the damage instance
      end
      if defenseType ~= udg_DamageEventDefenseT then
         BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, defenseType)
      end
   end
   
   local function failsafeClear()
      --print("Damage from " .. GetUnitName(udg_DamageEventSource) .. " to " .. GetUnitName(udg_DamageEventTarget) .. " has been messing up Damage Engine.")
      --print(udg_DamageEventAmount .. " " .. " " .. udg_DamageEventPrevAmt .. " " .. udg_AttackTypeDebugStr[udg_DamageEventAttackT] .. " " .. udg_DamageTypeDebugStr[udg_DamageEventDamageT])
      resetArmor()
      canKick = true
      totem = false
      udg_DamageEventAmount = 0.00
      udg_DamageScalingWC3  = 0.00
      if udg_DamageEventDamageT ~= udg_DAMAGE_TYPE_UNKNOWN then
         runTrigs(event.damage) --Run the normal on-damage event based on this failure.
         eventsRun = true --Run the normal after-damage event based on this failure.
      end
      finish()
   end
   
   local function calibrateMR()
      udg_IsDamageMelee         = false
      udg_IsDamageRanged        = false
      udg_IsDamageSpell         = udg_DamageEventAttackT == 0 --In Patch 1.31, one can just check the attack type to find out if it'
s a spell.
      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.
         udg_IsDamageMelee      = IsUnitType(udg_DamageEventSource, UNIT_TYPE_MELEE_ATTACKER)
         udg_IsDamageRanged     = IsUnitType(udg_DamageEventSource, UNIT_TYPE_RANGED_ATTACKER)
         if udg_IsDamageMelee and udg_IsDamageRanged then
            udg_IsDamageMelee   = udg_DamageEventWeaponT > 0-- Melee units play a sound when damaging
            udg_IsDamageRanged  = not udg_IsDamageMelee    -- In the case where a unit is both ranged and melee, the ranged attack plays no sound.
         end                                       -- The Huntress has a melee sound for her ranged projectile, however it is only an issue
      end                                          --if she also had a melee attack, because by default she is only UNIT_TYPE_RANGED_ATTACKER.
   end
   
   local t1 = CreateTrigger()
   TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
   TriggerAddCondition(t1, Filter(function()
      local src = GetEventDamageSource()
      local tgt = BlzGetEventDamageTarget()
      local amt = GetEventDamage()
      local at = BlzGetEventAttackType()
      local dt = BlzGetEventDamageType()
      local wt = BlzGetEventWeaponType()
     
      --print "First damage event running"
     
      if not kicking then
         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.
                  failsafeClear()
               else
                  totem       = false
                  canKick     = false
                  prev.type   = udg_DamageEventType      -- also store the damage type.
                  prev.amount = udg_DamageEventAmount
                  prev.preAmt = udg_DamageEventPrevAmt   -- Store the actual pre-armor value.
                  prev.pierce = udg_DamageEventArmorPierced
                  prev.armor  = udg_DamageEventArmorT
                  prev.preArm = armorType
                  prev.defense= udg_DamageEventDefenseT
                  prev.preDef = defenseType
                  prev.code   = udg_IsDamageCode        -- store this as well.
               end
            end
            if src ~= udg_AOEDamageSource then -- Source has damaged more than once
               onAOEEnd() -- New damage source - unflag everything
               udg_AOEDamageSource = src
            elseif tgt == udg_EnhancedDamageTarget then
               udg_DamageEventLevel= udg_DamageEventLevel + 1  -- The number of times the same unit was hit.
            elseif not IsUnitInGroup(tgt, udg_DamageEventAOEGroup) then
               udg_DamageEventAOE  = udg_DamageEventAOE + 1   -- Multiple targets hit by this source - flag as AOE
            end
         else
            TimerStart(alarm, 0.00, false, function()
               alarmSet = false --The timer has expired. Flag off to allow it to be restarted when needed.
               finish() --Wrap up any outstanding damage instance
               onAOEEnd() --Reset things so they don'
t perpetuate for AoE/Level target detection
            end)
            alarmSet                = true
            udg_AOEDamageSource     = src
            udg_EnhancedDamageTarget= tgt
         end
         GroupAddUnit(udg_DamageEventAOEGroup, tgt)
      end
      udg_DamageEventType           = udg_NextDamageType
      udg_IsDamageCode              = udg_NextDamageType ~= 0
      udg_DamageEventOverride       = dt == nil -- Got rid of NextDamageOverride in 5.1 for simplicity
      udg_DamageEventPrevAmt        = amt
      udg_DamageEventSource         = src
      udg_DamageEventTarget         = tgt
      udg_DamageEventAmount         = amt
      udg_DamageEventAttackT        = GetHandleId(at)
      udg_DamageEventDamageT        = GetHandleId(dt)
      udg_DamageEventWeaponT        = GetHandleId(wt)
     
      calibrateMR() -- Set Melee and Ranged settings.
     
      udg_DamageEventArmorT         = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE) -- Introduced in Damage Engine 5.2.0.0
      udg_DamageEventDefenseT       = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE)
      armorType                     = udg_DamageEventArmorT
      defenseType                   = udg_DamageEventDefenseT
      udg_DamageEventArmorPierced   = 0.00
      udg_DamageScalingUser         = 1.00
      udg_DamageScalingWC3          = 1.00
     
      if amt ~= 0.00 then
         if not udg_DamageEventOverride then
            runTrigs(event.mod)
       
            -- All events have run and the pre-damage amount is finalized.
            BlzSetEventAttackType(ConvertAttackType(udg_DamageEventAttackT))
            BlzSetEventDamageType(ConvertDamageType(udg_DamageEventDamageT))
            BlzSetEventWeaponType(ConvertWeaponType(udg_DamageEventWeaponT))
            if udg_DamageEventArmorPierced ~= 0.00 then
               BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) - udg_DamageEventArmorPierced)
            end
            if armorType ~= udg_DamageEventArmorT then
               BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, udg_DamageEventArmorT) -- Introduced in Damage Engine 5.2.0.0
            end
            if defenseType ~= udg_DamageEventDefenseT then
               BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, udg_DamageEventDefenseT) -- Introduced in Damage Engine 5.2.0.0
            end
            BlzSetEventDamage(udg_DamageEventAmount)
         end
         totem = true
         -- print("Ready to deal " .. udg_DamageEventAmount)
      else
         runTrigs(event.zero)
         canKick = true
         finish()
      end
      return false
   end))
   
   local t2 = CreateTrigger()
   TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DAMAGED)
   TriggerAddCondition(t2, Filter(function()
      if udg_DamageEventPrevAmt == 0.00 then
         return false
      end
      --print "Second event running"
      if totem then
         totem = false   --This should be the case in almost all circumstances
      else
         afterDamage() --Wrap up the outstanding damage instance
         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.
         udg_DamageEventSource      = GetEventDamageSource()
         udg_DamageEventTarget      = GetTriggerUnit()
         udg_DamageEventAmount      = prev.amount
         udg_DamageEventPrevAmt     = prev.preAmt
         udg_DamageEventAttackT     = GetHandleId(BlzGetEventAttackType())
         udg_DamageEventDamageT     = GetHandleId(BlzGetEventDamageType())
         udg_DamageEventWeaponT     = GetHandleId(BlzGetEventWeaponType())
         udg_DamageEventType        = prev.type
         udg_IsDamageCode           = prev.code
         udg_DamageEventArmorT      = prev.armor
         udg_DamageEventDefenseT    = prev.defense
         udg_DamageEventArmorPierced= prev.pierce
         armorType                  = prev.preArm
         defenseType                = prev.preDef
         calibrateMR() --Apply melee/ranged settings once again.
      end
      resetArmor()
      local r = GetEventDamage()
      if udg_DamageEventAmount ~= 0.00 and r ~= 0.00 then
         udg_DamageScalingWC3 = r/udg_DamageEventAmount
      else
         if udg_DamageEventAmount > 0.00 then
            udg_DamageScalingWC3 = 0.00
         else
            udg_DamageScalingWC3 = 1.00
         end
         udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
      end
      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.
         runTrigs(event.shield)
         udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
         if udg_LethalDamageHP <= 0.405 then
            runTrigs(event.lethal) -- 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).
           
            udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
            if udg_DamageEventType < 0 and udg_LethalDamageHP <= 0.405 then
               SetUnitExploded(udg_DamageEventTarget, true)   --Explosive damage types should blow up the target.
            end
         end
         udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
      end
      BlzSetEventDamage(udg_DamageEventAmount)   --Apply the final damage amount.
      if udg_DamageEventDamageT ~= udg_DAMAGE_TYPE_UNKNOWN then
         runTrigs(event.damage)
      end
      eventsRun = true
      --print(canKick)
      if udg_DamageEventAmount == 0.00 then
         finish()
      end
      return false
   end))
   
   onGlobalInit(function()
      local i
      for i = 0, 6 do udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i) end
      for i = 0, 26 do udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i) end
     
      udg_AttackTypeDebugStr[0] = "SPELLS"   -- ATTACK_TYPE_NORMAL in JASS
      udg_AttackTypeDebugStr[1] = "NORMAL"   -- ATTACK_TYPE_MELEE in JASS
      udg_AttackTypeDebugStr[2] = "PIERCE"
      udg_AttackTypeDebugStr[3] = "SIEGE"
      udg_AttackTypeDebugStr[4] = "MAGIC"
      udg_AttackTypeDebugStr[5] = "CHAOS"
      udg_AttackTypeDebugStr[6] = "HERO"
     
      udg_DamageTypeDebugStr[0]  = "UNKNOWN"
      udg_DamageTypeDebugStr[4]  = "NORMAL"
      udg_DamageTypeDebugStr[5]  = "ENHANCED"
      udg_DamageTypeDebugStr[8]  = "FIRE"
      udg_DamageTypeDebugStr[9]  = "COLD"
      udg_DamageTypeDebugStr[10] = "LIGHTNING"
      udg_DamageTypeDebugStr[11] = "POISON"
      udg_DamageTypeDebugStr[12] = "DISEASE"
      udg_DamageTypeDebugStr[13] = "DIVINE"
      udg_DamageTypeDebugStr[14] = "MAGIC"
      udg_DamageTypeDebugStr[15] = "SONIC"
      udg_DamageTypeDebugStr[16] = "ACID"
      udg_DamageTypeDebugStr[17] = "FORCE"
      udg_DamageTypeDebugStr[18] = "DEATH"
      udg_DamageTypeDebugStr[19] = "MIND"
      udg_DamageTypeDebugStr[20] = "PLANT"
      udg_DamageTypeDebugStr[21] = "DEFENSIVE"
      udg_DamageTypeDebugStr[22] = "DEMOLITION"
      udg_DamageTypeDebugStr[23] = "SLOW_POISON"
      udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
      udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
      udg_DamageTypeDebugStr[26] = "UNIVERSAL"
     
      udg_WeaponTypeDebugStr[0]  = "NONE"    -- WEAPON_TYPE_WHOKNOWS in JASS
      udg_WeaponTypeDebugStr[1]  = "METAL_LIGHT_CHOP"
      udg_WeaponTypeDebugStr[2]  = "METAL_MEDIUM_CHOP"
      udg_WeaponTypeDebugStr[3]  = "METAL_HEAVY_CHOP"
      udg_WeaponTypeDebugStr[4]  = "METAL_LIGHT_SLICE"
      udg_WeaponTypeDebugStr[5]  = "METAL_MEDIUM_SLICE"
      udg_WeaponTypeDebugStr[6]  = "METAL_HEAVY_SLICE"
      udg_WeaponTypeDebugStr[7]  = "METAL_MEDIUM_BASH"
      udg_WeaponTypeDebugStr[8]  = "METAL_HEAVY_BASH"
      udg_WeaponTypeDebugStr[9]  = "METAL_MEDIUM_STAB"
      udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
      udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
      udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
      udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
      udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
      udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
      udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
      udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
      udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
      udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
      udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
      udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
      udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
      udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
     
      udg_DefenseTypeDebugStr[0] = "LIGHT"
      udg_DefenseTypeDebugStr[1] = "MEDIUM"
      udg_DefenseTypeDebugStr[2] = "HEAVY"
      udg_DefenseTypeDebugStr[3] = "FORTIFIED"
      udg_DefenseTypeDebugStr[4] = "NORMAL"
      udg_DefenseTypeDebugStr[5] = "HERO"
      udg_DefenseTypeDebugStr[6] = "DIVINE"
      udg_DefenseTypeDebugStr[7] = "UNARMORED"
     
      udg_ArmorTypeDebugStr[0] = "NONE"
      udg_ArmorTypeDebugStr[1] = "FLESH"
      udg_ArmorTypeDebugStr[2] = "METAL"
      udg_ArmorTypeDebugStr[3] = "WOOD"
      udg_ArmorTypeDebugStr[4] = "ETHEREAL"
      udg_ArmorTypeDebugStr[5] = "STONE"
   end)
   
   function DamageEngine_SetupEvent(whichTrig, var, val)
      --print("Setup event: " .. var)
      local mx = 1
      local off = 0
      local ex = 0
      if var == "udg_DamageModifierEvent" then --event.mod 1-4 -> Events 1-4
         if (val < 3) then
            ex = val + 1
         end
         mx = 4
      elseif var == "udg_DamageEvent" then --event.damage 1,2 -> Events 5,6
         mx = 2
         off = 4
      elseif var == "udg_AfterDamageEvent" then --event.after -> Event 7
         off = 6
      elseif var == "udg_LethalDamageEvent" then --event.lethal -> Event 8
         off = 7
      elseif var == "udg_AOEDamageEvent" then --event.aoe -> Event 9
         off = 8
      else
         return false
      end
      local i
      if userTrigs == 9 then
         nextTrig[1] = 2
         nextTrig[2] = 3
         trigFrozen[2] = true
         trigFrozen[3] = true
         for i = 3, 9 do nextTrig[i] = 0 end
      end
      i = math.max(math.min(val, mx), 1) + off
      --print("Root index: " .. i .. " nextTrig: " .. nextTrig[i] .. " exit: " .. ex)
      repeat
         val = i
         i = nextTrig[i]
      until (i == ex)
      userTrigs = userTrigs + 1   --User list runs from index 10 and up
      nextTrig[val] = userTrigs
      nextTrig[userTrigs] = ex
      userTrig[userTrigs] = whichTrig
      levelsDeep[userTrigs] = 0
      trigFrozen[userTrigs] = false
      inceptionTrig[userTrigs] = false
      --print("Registered " .. userTrigs .. " to " .. val)
      return true
   end
   
   onRegisterVar(function(trig, var, val)
      DamageEngine_SetupEvent(trig, var, math.floor(val))
   end)
end
--Global Initialization 1.1 also hooks the InitCustomTriggers and RunInitializationTriggers functions
do
   local iFuncs = {}
   function onInitialization(func) -- Runs once all Map Initialization triggers are executed
      iFuncs[func] = func
   end
   local function runInitialization()
      for k, f in pairs(iFuncs) do f() end
      iFuncs = nil
   end
   
   local tFuncs = {}
   function onTriggerInit(func) -- Runs once all InitTrig_ functions are called
      tFuncs[func] = func
   end
   local function runTriggerInit()
      for k, f in pairs(tFuncs) do f() end
      tFuncs = nil
      local old = RunInitializationTriggers
      if old then
         function RunInitializationTriggers()
            old()
            runInitialization()
         end
      else
         runInitialization()
      end
   end
   
   local gFuncs = {}
   function onGlobalInit(func) --Runs once all udg_ globals are set.
      gFuncs[func] = func --Simplification thanks to TheReviewer and Zed on Hive Discord
   end
   local function runGlobalInit()
      for k, f in pairs(gFuncs) do f() end
      gFuncs = nil
     
      local old = InitCustomTriggers
      if old then
         function InitCustomTriggers()
            old()
            runTriggerInit()
         end
      else
         runTriggerInit()
      end
   end
   
   local oldBliz = InitBlizzard
   function InitBlizzard()
      oldBliz()
      local old = InitGlobals
      if old then
         function InitGlobals()
            old()
            runGlobalInit()
         end
      else
         runGlobalInit()
      end
   end
end
-- TriggerRegisterVariableEvent hook to convert these old school events into something more useful.

do
   events = {}
   function onRegisterVar(func)
      events[func] = func
   end
   
   local oldEvent = TriggerRegisterVariableEvent
   function TriggerRegisterVariableEvent(trig, var, op, val)
      for k, func in pairs(events) do
         if func(trig, var, val) then return end
      end
      oldEvent(trig, var, op, val)
   end
end
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 deals 0 damage and attacks silently.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.
    Countdown Timer - Start Timestamp as a One-shot timer that will expire in 30000.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
    True Equal to True
  Actions
    Game - Display to (All players) the text: (String((Mana of DamageEventTarget)))
    Custom script: DamageEngine_inception = true
    Unit - Cause DamageEventTarget to damage DamageEventSource, dealing DamageEventAmount damage of attack type CONVERTED_ATTACK_TYPE[DamageEventAttackT] and damage type CONVERTED_DAMAGE_TYPE[DamageEventDamageT]
    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
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
    True Equal to True
  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))) + .)
On Zero
  Events
    Game - DamageEvent becomes Equal to 2.00
  Conditions
    True Equal to True
  Actions
    Set VariableSet ReportLife = (Life of DamageEventTarget)
    Trigger - Run Damage_Report <gen> (ignoring conditions)
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
        IsDamageMelee Equal to True
      Then - Actions
        Set VariableSet DmgStr = Melee 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
            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
    -------- 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: udg_Reporting = not udg_Reporting
do
   local data = {}
   function SetTimerData(whichTimer, dat)
      data[whichTimer] = dat
   end

   --GetData functionality doesn't even require an argument.
   function GetTimerData(whichTimer)
      if not whichTimer then whichTimer = GetExpiredTimer() end
      return data[whichTimer]
   end

   --NewTimer functionality includes optional parameter to pass data to timer.
   function NewTimer(dat)
      local t = CreateTimer()
      if dat then data[t] = dat end
      return t
   end

   --Release functionality doesn'
t even need for you to pass the expired timer.
   --as an arg. It also returns the user data passed.
   function ReleaseTimer(whichTimer)
      if not whichTimer then whichTimer = GetExpiredTimer() end
      local dat = data[whichTimer]
      data[whichTimer] = nil
      PauseTimer(whichTimer)
      DestroyTimer(whichTimer)
      return dat
   end
end
do
   local cMap = {}
   local aMap = {}
   local lastCondFunc
   local waitFunc
   
   local oldCond = Condition --If you don't want this Condition-overwrite behavior
   --for any particular resource, use Filter() instead of Condition(). This tool
   --is mainly for GUI users & the GUI->script compiled behavior uses Condition().
   function Condition(func)
      lastCondFunc = func
      return oldCond(func)
   end
   
   local oldTAC = TriggerAddCondition
   function TriggerAddCondition(trig, cond)
      if lastCondFunc then
         cMap[trig] = lastCondFunc --map the condition function to the trigger.
         lastCondFunc = nil
         cond = Filter(function()
            local t = GetTriggeringTrigger()
            if cMap[t]() then --Call the triggerconditions manually.
               waitFunc = aMap[t]
               waitFunc() --If this was caused by an event, call the trigger actions manually.
            end
         end)
      end
      return oldTAC(trig, cond) --use the regular event if a boolexpr or Filter
      --was used instead of Condition()
   end
   
   local oldTAA = TriggerAddAction
   function TriggerAddAction(trig, act)
      aMap[trig] = act
      return oldTAA(trig, function()
         waitFunc = aMap[GetTriggeringTrigger()]
         waitFunc() --If this was caused by an event, call the trigger actions manually.
      end)
   end
   
   local oldEval = TriggerEvaluate
   function TriggerEvaluate(trig)
      local f = cMap[trig]
      if f then return f() end
      return oldEval(trig)
   end
   
   local oldExec = TriggerExecute
   function TriggerExecute(trig)
      waitFunc = aMap[trig]
      waitFunc()
   end
   
   function RunTrigger(trig)
      local conds = cMap[trig]
      if IsTriggerEnabled(trig) and not conds or conds() then
         waitFunc = aMap[trig]
         waitFunc()
      end
   end
   
   local skipNext = false
   function EnableWaits()
      if skipNext then
         skipNext = false
         return false
      end
      skipNext = true
      coroutine.resume(coroutine.create(function()
         waitFunc()
      end))
      return true
   end
end
do
   local oldWait = PolledWait
   function PolledWait(duration)
      local thread = coroutine.running()
      if thread then
         TimerStart(NewTimer(thread), duration, false, function()
            coroutine.resume(ReleaseTimer())
         end)
         coroutine.yield(thread)
      else
         oldWait(duration)
      end
   end
   
   local oldTSA = TriggerSleepAction
   function TriggerSleepAction(duration) PolledWait(duration) end
   
   local thread
   local oldSync = SyncSelections
   function SyncSelectionsHelper()
      local t = thread
      oldSync()
      coroutine.resume(t)
   end
   function SyncSelections()
      thread = coroutine.running()
      if thread then
         ExecuteFunc("SyncSelectionsHelper")
         coroutine.yield(thread)
      else
         oldSync()
      end
   end
   
   if not EnableWaits then --Added this check to ensure compatibilitys with Lua Fast Triggers
      local oldAction = TriggerAddAction
      function TriggerAddAction(whichTrig, userAction)
         oldAction(whichTrig, function()
            coroutine.resume(coroutine.create(function()
               userAction()
            end))
         end)
      end
   end
end
    function RunTrigger(trig)
        if IsTriggerEnabled(trig) and TriggerEvaluate(trig) then
            TriggerExecute(trig)
        end
    end
    function RunTriggerHelper()
        RunTrigger(gg_trg_TestTrig)
    end
function initBenchmark()
    local arr = {}
    local arr_count = 0
   
    function initBench(f)
        arr_count = arr_count + 1
        arr[arr_count] = f
    end
    --[[
    TimerStart(CreateTimer(), 0.00, false, function()
        for i=1,arr_count do
            arr[i]()
        end
    end)]]
   
    local function benchmark_clock(f, count)
        local clock = os.clock
        local start = clock()
        for i=1,count do
            f()
        end
        return clock() - start
    end
   
    function benchmark(f_name, f)
        local t = benchmark_clock(f, 1000)
        print('Benchmark ' .. f_name .. ' takes ' .. t .. ' ms to complete on average')
    end
    function tester()
        benchmark("RunTrigger", poop)
    end
end
Untitled Trigger 001
  Events
    Time - Every 1.00 seconds of game time
  Conditions
    True Equal to True
  Actions
    Custom script: print "first one"
    Custom script: if EnableWaits() then return end
    Custom script: print "second one"
    Custom script: print "poop"
    Custom script: ExecuteFunc("tester")
    Custom script: benchmark("RunTrigger", poop)
    Custom script: print "poop 2"
    Wait 0.50 seconds
    Custom script: SyncSelections()
    Custom script: print "third one"
    Custom script: print("dood")
    Custom script: GroupEnumUnitsSelected(udg_TempGroup, GetLocalPlayer(), nil)
    Set VariableSet TempGroup = (Units currently selected by Player 1 (Red))
    Custom script: print(BlzGroupGetSize(udg_TempGroup))
    Custom script: print(GetUnitName(BlzGroupUnitAt(udg_TempGroup, 0)))
    Custom script: dood = BlzGroupUnitAt(udg_TempGroup, 0)
    Custom script: if not dood then return end
    Custom script: RemoveUnit(dood)
    Custom script: print(IsUnitInGroup(dood, udg_TempGroup))
    Wait 0.01 seconds
    Custom script: print(GetUnitX(dood) .. " " .. GetUnitY(dood))
    Custom script: print(dood)
    Wait 1.00 seconds
    Custom script: print(BlzGroupUnitAt(udg_TempGroup, 1))
    Custom script: print(BlzGroupGetSize(udg_TempGroup))
    Custom script: print (alphabet)
Untitled Trigger 003
  Events
    Unit - A unit Decays
  Conditions
  Actions
    Custom script: print(GetUnitName(GetTriggerUnit()) .. " decayed")
Untitled Trigger 003 Copy
  Events
    Unit - A unit Dies
  Conditions
  Actions
    Custom script: if EnableWaits() then return end
    Custom script: print(GetUnitName(GetTriggerUnit()) .. " died")
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        ((Triggering unit) is in IndexedUnitsGroup.) Equal to True
      Then - Actions
        Custom script: print(GetUnitName(GetTriggerUnit()) .. " is in group")
      Else - Actions
    Custom script: print(BlzGetUnitBooleanField(GetTriggerUnit(), UNIT_BF_RAISABLE))
    Custom script: print(BlzGetUnitBooleanField(GetTriggerUnit(), UNIT_BF_DECAYABLE))
    Custom script: local unit poop = GetTriggerUnit()
    Wait 0.00 seconds
    Custom script: print(GetUnitName(poop) .. " next thread")
    Custom script: if IsUnitInGroup(poop, udg_IndexedUnitsGroup) then print("in group") end
    Custom script: print(GetUnitUserData(poop))
Untitled Trigger 002
  Events
    Map initialization
  Conditions
  Actions
    Custom script: initBenchmark()
    Custom script: poop = RunTriggerHelper
    Custom script: print "poop init"
TestTrig
  Events
  Conditions
    True Equal to True
  Actions
    Do nothing
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: while (udg_UDex ~= 0) do
    Custom script: udg_TempX = GetUnitX(udg_UDexUnits[udg_UDex])
    Custom script: 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]
    Custom script: end
    Custom script: end
    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: end
    Set VariableSet UDex = UMovNext[UDex]
    Custom script: end
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: udg_UnitMovingX[udg_UDex] = GetUnitX(udg_UDexUnits[udg_UDex])
        Custom script: udg_UnitMovingY[udg_UDex] = GetUnitY(udg_UDexUnits[udg_UDex])
      Else - Actions
do
   local MAX_WASTED = 1 --Every MAX_WASTED units created after map initialization, run the "garbage collector"
   
   local sUUD = SetUnitUserData
   function SetUnitUserData(whichUnit, val) end -- disallow user from changing this value.
   
   local function runEvent(dex, val)
      local pdex = udg_UDex
      udg_UDex = dex
      globals.udg_UnitIndexEvent = 0.00
      globals.udg_UnitIndexEvent = val
      udg_UDex = pdex
   end
   
   local iFuncs = {}
   function onUnitIndex(func)
      iFuncs[func] = func
   end
   onUnitIndex(function(dex) runEvent(dex, 1.00) end)
   
   local dFuncs = {}
   function onUnitDeindex(func)
      dFuncs[func] = func
   end
   onUnitDeindex(function(dex) runEvent(dex, 2.00) end)
   
   local wasted = 0
   local gen = 0
   local active = {}
   local inactive = {}
   local preplaced = true
   
   onTriggerInit(function()
      local re = CreateRegion()
      local r = GetWorldBounds()
      RegionAddRect(re, r) RemoveRect(r)
      local b = Filter(function()
         u = GetFilterUnit()
         if GetUnitUserData(u) == 0 then
            local dex
            if not preplaced then -- No need to check for removed units during the beginning of the game sequence
               wasted = wasted + 1
               if wasted > MAX_WASTED then
                  local n = #active
                  for i = n, 1, -1 do
                     if GetUnitUserData(udg_UDexUnits[dex]) == 0 then
                        active[i] = active[n]
                        active[n] = nil
                        n = n - 1
                        inactive[#inactive + 1] = dex
                        for k, f in pairs(dFuncs) do f(dex) end -- Run the deindex event
                        --print("deindexed" .. dex)
                     end
                  end
                  wasted = 0
               end
            end
            local n = #inactive
            if n == 0 then
               dex = gen + 1
               gen = dex
            else
               dex = inactive[n]
               inactive[n] = nil
            end
            active[#active + 1] = dex
           
            udg_UDexUnits[dex] = u
            sUUD(udg_UDexUnits[dex], dex)
           
            udg_IsUnitPreplaced[dex] = preplaced
            for k, f in pairs(iFuncs) do f(dex) end -- Run the index event
            --print("indexed " .. dex)
         end
         return false
      end)
      TriggerRegisterEnterRegion(CreateTrigger(), re, b)
      for i = bj_MAX_PLAYER_SLOTS - 1, 0, -1 do
         GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), b)
      end
      preplaced = false
      globals.udg_UnitIndexEvent = 3.00
   end)
end
Unit Indexer Event
  Events
    Game - UnitIndexEvent becomes Equal to -1.00
  Conditions
  Actions
-- Arcing Text Tag v1.0.0.3 by Maker encoded to Lua

DEFINITION      = 1.0/60.0
SIZE_MIN        = 0.018         -- Minimum size of text
SIZE_BONUS      = 0.012         -- Text size increase
TIME_LIFE       = 1.0           -- How long the text lasts
TIME_FADE       = 0.8           -- When does the text start to fade
Z_OFFSET        = 50            -- Height above unit
Z_OFFSET_BON    = 50            -- How much extra height the text gains
VELOCITY        = 2.0           -- How fast the text move in x/y plane
TMR             = CreateTimer()

ANGLE_RND       = true          -- Is the angle random or fixed
if not ANGLE_RND then
    ANGLE       = bj_PI/2.0     -- If fixed, specify the Movement angle of the text.
end

tt   = {}
as   = {} -- angle, sin component
ac   = {} -- angle, cos component
ah   = {} -- arc height
t    = {} -- time
x    = {} -- origin x
y    = {} -- origin y
str  = {} -- text

ic   = 0  -- Instance count  
rn   = {} ; rn[0] = 0
next = {} ; next[0] = 0
prev = {} ; prev[0] = 0 --Needed due to Lua not initializing them.

function ArcingTextTag(s, u)
    local this = rn[0]
    if this == 0 then
        ic = ic + 1
        this = ic
    else
        rn[0] = rn[this]
    end
   
    next[this] = 0
    prev[this] = prev[0]
    next[prev[0]] = this
    prev[0] = this
   
    str[this] = s
    x[this] = GetUnitX(u)
    y[this] = GetUnitY(u)
    t[this] = TIME_LIFE
   
    local a
    if ANGLE_RND then
        a = GetRandomReal(0, 2*bj_PI)
    else
        a = ANGLE
    end
    as[this] = Sin(a)*VELOCITY
    ac[this] = Cos(a)*VELOCITY
    ah[this] = 0.
   
    if IsUnitVisible(u, GetLocalPlayer()) then
        tt[this] = CreateTextTag()
        SetTextTagPermanent(tt[this], false)
        SetTextTagLifespan(tt[this], TIME_LIFE)
        SetTextTagFadepoint(tt[this], TIME_FADE)
        SetTextTagText(tt[this], s, SIZE_MIN)
        SetTextTagPos(tt[this], x[this], y[this], Z_OFFSET)
    end
   
    if prev[this] == 0 then
        TimerStart(TMR, DEFINITION, true, function()
            local this = next[0]
            local p
            while (this ~= 0) do
                p = Sin(bj_PI*t[this])
                t[this] = t[this] - DEFINITION
                x[this] = x[this] + ac[this]
                y[this] = y[this] + as[this]
                SetTextTagPos(tt[this], x[this], y[this], Z_OFFSET + Z_OFFSET_BON * p)
                SetTextTagText(tt[this], str[this], SIZE_MIN + SIZE_BONUS * p)
                if t[this] <= 0.0 then
                    tt[this] = null
                    next[prev[this]] = next[this]
                    prev[next[this]] = prev[this]
                    rn[this] = rn[0]
                    rn[0] = this
                    if next[0] == 0 then
                        PauseTimer(TMR)
                    end
                end
                this = next[this]
            end
        end)
    end
    return this
end
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 ReportLife = (Life 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: ArcingTextTag(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: ArcingTextTag(udg_DmgStr .. 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: ArcingTextTag(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: ArcingTextTag(udg_DmgStr .. R2I(udg_DamageEventAmount) .. "|r", udg_DamageEventTarget)
                  Else - Actions