1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The contestants were to create water structures for the 20th Terraining Contest. Choose one in the public poll!
    Dismiss Notice
  3. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  4. The Melee Mapping Contest #4: 2v2 - Results are out! Step by to congratulate the winners!
    Dismiss Notice
  5. We're hosting the 15th Mini-Mapping Contest with YouTuber Abelhawk! The contestants are to create a custom map that uses the hidden content within Warcraft 3 or is inspired by any of the many secrets within the game.
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice

Trigger Viewer

Guhun Combat State Manager.w3x
Variables
GUI Combat State Manager
Requirement
Unit Event Config
Unit Event
---------------------------
GCSM Import
GCSM Main
GCSM Register and Cleanup
TestMap Example
Requirements
GTS Import
GTS Main
---------------------------
Damage Engine Config
Damage Engine
---------------------------
TestMap Cast Ability Combat
TestMap Enter Combat Damage
TestMap Enter Combat Support
---------------------------
TestMap Leave Combat On Death
---------------------------
TestMap Combat Timer
TestMap Combat Timer Expired
Damage Engine Spell Fixes
Life Drain Fix
Finger of Death Fix
Anti Magic Shiled Var
Anti Magic Shield Fix
Mana Shield Fix
TestMap
Command Combat
Command Combat Copy
Help Messages
Esc Help
Esc Switch
Esc SingleClick
Esc DoubleClick
//TESH.scrollpos=0
//TESH.alwaysfold=0
Name Type Is Array Initial Value
AfterDamageEvent real No
AMSAmount real Yes
AOEDamageEvent real No
AOEString string No
CargoEvent real No
CargoTransportGroup group Yes
CargoTransportUnit unit Yes
CheckDeathList integer Yes
CheckDeathTimer timer No
ClearDamageEvent trigger No
DAMAGE_FACTOR_BRACERS real No
DAMAGE_FACTOR_ELUNES real No
DAMAGE_FACTOR_ETHEREAL real No
DamageBlockingAbility abilcode No
DamageEvent real No
DamageEventAmount real No
DamageEventAOE integer No
DamageEventAOEGroup group No
DamageEventLevel integer No
DamageEventOverride boolean No
DamageEventPrevAmt real No
DamageEventSource unit No
DamageEventsWasted integer No
DamageEventTarget unit No
DamageEventTrigger trigger No
DamageEventType integer No
DamageModifierEvent real No
DamageTypeBlocked integer No
DamageTypeCriticalStrike integer No
DamageTypeExplosive integer No
DamageTypeHeal integer No
DamageTypeReduced integer No
DeathEvent real No
DetectRemoveAbility abilcode No
DetectTransformAbility abilcode No
DmgEvBracers itemcode No
DmgEvMana real No
DmgEvManaMult real No
DmgEvMSlvl integer No
DmgEvRecursionN integer No
DmgEvRunning boolean No
DmgEvStarted boolean No
DmgEvTimer timer No
DmgEvTrig trigger No
EnhancedDamageTarget unit No
GCSM_CombatEvent real No
GCSM_CombatGroups group Yes
GCSM_Source unit No
GCSM_Target unit No
GCSM_UnitInCombat boolean Yes
GTS_CustomValue integer No
GTS_DestroyTimer boolean No
GTS_ExecutionCounter integer No
GTS_Hashtable hashtable No
GTS_TimeOut real No
GTS_Timer timer No
GTS_Trigger trigger No
HideDamageFrom boolean Yes
IsDamageSpell boolean No
IsUnitAlive boolean Yes
IsUnitBeingUnloaded boolean Yes
IsUnitNew boolean Yes
IsUnitPreplaced boolean Yes
IsUnitReincarnating boolean Yes
IsUnitRemoved boolean Yes
IsUnitTransforming boolean Yes
KillerOfUnit unit Yes
LastDamageHP real No
LastDmgPrevAmount real Yes
LastDmgPrevType integer Yes
LastDmgSource unit Yes
LastDmgTarget unit Yes
LastDmgValue real Yes
LastDmgWasSpell boolean Yes
NextDamageOverride boolean No
NextDamageType integer No
SpellDamageAbility abilcode No
SummonerOfUnit unit Yes
Test_EscTimer timer No
Test_Timers timer Yes
UDex integer No
UDexGen integer No
UDexLastRecycled integer No
UDexMax integer No
UDexNext integer Yes
UDexPrev integer Yes
UDexRecycle integer No
UDexUnits unit Yes
UDexWasted integer No
UnitDamageRegistered boolean Yes
UnitIndexerEnabled boolean No
UnitIndexEvent real No
UnitIndexLock integer Yes
UnitTypeEvent real No
UnitTypeOf unitcode Yes
WorldMaxX real No
WorldMaxY real No
Delete Unit Indexer if you already have it or the latest Unit Event in your map.
GUI Unit Event by Bribe, version 2.4.0.0
Unit Event Config
  Events
    Map initialization
  Conditions
  Actions
    -------- --------
    -------- Copy Unit Event Ability from Object Editor, then set DetectRemoveAbility to it as follows: --------
    -------- --------
    Set DetectRemoveAbility = Unit Event Ability (Removal Detect)
    -------- --------
    -------- Paste it a second time, then set DetectTransformAbility to it as follows: --------
    -------- --------
    Set DetectTransformAbility = Unit Event Ability (Transform Detect)
    -------- --------
    -------- Don't enable the following lines as they exist simply to make copying the system easier --------
    -------- --------
    Set WorldMaxX = WorldMaxY
    Set CargoTransportUnit[0] = (Random unit from CargoTransportGroup[0])
    Set CheckDeathList[UDexMax] = UDexNext[UDexPrev[UDexLastRecycled]]
    Set UDexUnits[UDex] = SummonerOfUnit[0]
    Countdown Timer - Pause CheckDeathTimer
    Set UnitIndexEvent = (CargoEvent + (DeathEvent + UnitTypeEvent))
    Set IsUnitAlive[0] = IsUnitBeingUnloaded[0]
    Set IsUnitNew[0] = IsUnitReincarnating[0]
    Set IsUnitRemoved[0] = UnitIndexerEnabled
    Set KillerOfUnit[0] = No unit
    Set UnitTypeOf[0] = No unit-type
    -------- One additional event to run right before Unit Indexer initializes, added 29 May 2017 for ZiBitheWand3r3r --------
    Set UnitIndexEvent = -1.00
    -------- --------
    -------- Initialize Unit Event now that all the InitTrig_ functions have run --------
    -------- --------
    Set IsUnitPreplaced[0] = True
    Custom script: call ExecuteFunc("UnitEventInit")
    Set UnitIndexEvent = 3.00
    Set IsUnitPreplaced[0] = IsUnitTransforming[0]
//===========================================================================
function UnitEventDestroyGroup takes integer i returns nothing
    if udg_CargoTransportGroup[i] != null then
        call DestroyGroup(udg_CargoTransportGroup[i])
        set udg_CargoTransportGroup[i] = null
    endif
endfunction
function UnitEventCheckAfter takes nothing returns nothing
    local integer i = udg_CheckDeathList[0]
    set udg_CheckDeathList[0] = 0
    loop
        exitwhen i == 0
        if udg_IsUnitNew[i] then
            //The unit was just created.
            set udg_IsUnitNew[i] = false
        elseif udg_IsUnitTransforming[i] then
           //Added 21 July 2017 to fix the issue re-adding this ability in the same instant
           set udg_UDex = i
           set udg_UnitTypeEvent = 0.00
           set udg_UnitTypeEvent = 1.00
           set udg_UnitTypeOf[i] = GetUnitTypeId(udg_UDexUnits[i]) //Set this afterward to give the user extra reference
           set udg_IsUnitTransforming[i] = false
           call UnitAddAbility(udg_UDexUnits[i], udg_DetectTransformAbility)
        elseif udg_IsUnitAlive[i] then
            //The unit has started reincarnating.
            set udg_IsUnitReincarnating[i] = true
            set udg_IsUnitAlive[i] = false
            set udg_UDex = i
            set udg_DeathEvent = 0.50
            set udg_DeathEvent = 0.00
        endif
        set i = udg_CheckDeathList[i]
    endloop
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
    if udg_CheckDeathList[0] == 0 then
        call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
    endif
    set udg_CheckDeathList[i] = udg_CheckDeathList[0]
    set udg_CheckDeathList[0] = i
endfunction

function UnitEventOnUnload takes nothing returns nothing
    local integer i = udg_UDex
    call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
    set udg_IsUnitBeingUnloaded[i] = true
    set udg_CargoEvent = 0.00
    set udg_CargoEvent = 2.00
    set udg_CargoEvent = 0.00
    set udg_IsUnitBeingUnloaded[i] = false
    if not IsUnitLoaded(udg_UDexUnits[i]) or IsUnitType(udg_CargoTransportUnit[i], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CargoTransportUnit[i]) == 0 then
        set udg_CargoTransportUnit[i] = null
    endif
endfunction

function UnitEventOnDeath takes nothing returns boolean
    local integer pdex = udg_UDex
    set udg_UDex = GetUnitUserData(GetTriggerUnit())
    if udg_UDex != 0 then
        set udg_KillerOfUnit[udg_UDex] = GetKillingUnit() //Added 29 May 2017 for GIMLI_2
        set udg_IsUnitAlive[udg_UDex] = false
        set udg_DeathEvent = 0.00
        set udg_DeathEvent = 1.00
        set udg_DeathEvent = 0.00
        set udg_KillerOfUnit[udg_UDex] = null
        if udg_CargoTransportUnit[udg_UDex] != null then
            call UnitEventOnUnload()
        endif
    endif
    set udg_UDex = pdex
    return false
endfunction
 
function UnitEventOnOrder takes nothing returns boolean
    local integer pdex = udg_UDex
    local unit u = GetFilterUnit()
    local integer i = GetUnitUserData(u)
    if i > 0 then
        set udg_UDex = i
        if GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
            if not udg_IsUnitRemoved[i] then
                set udg_IsUnitRemoved[i] = true
                set udg_IsUnitAlive[i] = false
                set udg_SummonerOfUnit[i] = null
               
                //For backwards-compatibility:
                set udg_DeathEvent = 0.00
                set udg_DeathEvent = 3.00
                set udg_DeathEvent = 0.00
               
                //Fire deindex event for UDex:
                set udg_UnitIndexEvent = 0.00
                set udg_UnitIndexEvent = 2.00
                set udg_UnitIndexEvent = 0.00
               
                set udg_UDexNext[udg_UDexPrev[i]] = udg_UDexNext[i]
                set udg_UDexPrev[udg_UDexNext[i]] = udg_UDexPrev[i]
               
                // Recycle the index for later use
                set udg_UDexUnits[i] = null
                set udg_UDexPrev[i] = udg_UDexLastRecycled
                set udg_UDexLastRecycled = i
                call UnitEventDestroyGroup(i)
            endif
        elseif not udg_IsUnitAlive[i] then
            if not IsUnitType(u, UNIT_TYPE_DEAD) then
                set udg_IsUnitAlive[i] = true
                set udg_DeathEvent = 0.00
                set udg_DeathEvent = 2.00
                set udg_DeathEvent = 0.00
                set udg_IsUnitReincarnating[i] = false
            endif
        elseif IsUnitType(u, UNIT_TYPE_DEAD) then
            if udg_IsUnitNew[i] then
                //This unit was created as a corpse.
                set udg_IsUnitAlive[i] = false
                set udg_DeathEvent = 0.00
                set udg_DeathEvent = 1.00
                set udg_DeathEvent = 0.00
            elseif udg_CargoTransportUnit[i] == null or not IsUnitType(u, UNIT_TYPE_HERO) then
                //The unit may have just started reincarnating.
                call UnitEventCheckAfterProxy(i)
            endif
        elseif GetUnitAbilityLevel(u, udg_DetectTransformAbility) == 0 and not udg_IsUnitTransforming[i] then
            set udg_IsUnitTransforming[i] = true
            call UnitEventCheckAfterProxy(i)  //This block has been updated on 21 July 2017
        endif
        if udg_CargoTransportUnit[i] != null and not udg_IsUnitBeingUnloaded[i] and not IsUnitLoaded(u) or IsUnitType(u, UNIT_TYPE_DEAD) then
            call UnitEventOnUnload()
        endif
        set udg_UDex = pdex
    endif
    set u = null
    return false
endfunction
function UnitEventOnSummon takes nothing returns boolean
    local integer pdex = udg_UDex
    set udg_UDex = GetUnitUserData(GetTriggerUnit())
    if udg_IsUnitNew[udg_UDex] then
        set udg_SummonerOfUnit[udg_UDex] = GetSummoningUnit()
        set udg_UnitIndexEvent = 0.00
        set udg_UnitIndexEvent = 0.50
        set udg_UnitIndexEvent = 0.00
    endif
    set udg_UDex = pdex
    return false
endfunction
function UnitEventOnLoad takes nothing returns boolean
    local integer pdex = udg_UDex
    local integer i = GetUnitUserData(GetTriggerUnit())
    local integer index
    if i != 0 then
        set udg_UDex = i
        if udg_CargoTransportUnit[i] != null then
            call UnitEventOnUnload()
        endif
        //Loaded corpses do not issue an order when unloaded, therefore must
        //use the enter-region event method taken from Jesus4Lyf's Transport.
        if not udg_IsUnitAlive[i] then
            call SetUnitX(udg_UDexUnits[i], udg_WorldMaxX)
            call SetUnitY(udg_UDexUnits[i], udg_WorldMaxY)
        endif
       
        set udg_CargoTransportUnit[i] = GetTransportUnit()
        set index = GetUnitUserData(udg_CargoTransportUnit[i])
        if udg_CargoTransportGroup[index] == null then
            set udg_CargoTransportGroup[index] = CreateGroup()
        endif
        call GroupAddUnit(udg_CargoTransportGroup[index], udg_UDexUnits[i])
        set udg_CargoEvent = 0.00
        set udg_CargoEvent = 1.00
        set udg_CargoEvent = 0.00
        set udg_UDex = pdex
    endif
    return false
endfunction
function UnitEventEnter takes nothing returns boolean
    local integer pdex = udg_UDex
    local integer i = udg_UDexLastRecycled
    local unit u = GetFilterUnit()
    if udg_UnitIndexerEnabled and GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
        //Generate a unique integer index for this unit
        if i == 0 then
            set i = udg_UDexMax + 1
            set udg_UDexMax = i
        else
            set udg_UDexLastRecycled = udg_UDexPrev[i]
        endif
        //Link index to unit, unit to index
        set udg_UDexUnits[i] = u
        call SetUnitUserData(u, i)
       
        //For backwards-compatibility, add the unit to a linked list
        set udg_UDexNext[i] = udg_UDexNext[0]
        set udg_UDexPrev[udg_UDexNext[0]] = i
        set udg_UDexNext[0] = i
        set udg_UDexPrev[i] = 0
       
        call UnitAddAbility(u, udg_DetectRemoveAbility)
        call UnitMakeAbilityPermanent(u, true, udg_DetectRemoveAbility)
        call UnitAddAbility(u, udg_DetectTransformAbility)
        set udg_UnitTypeOf[i] = GetUnitTypeId(u)
        set udg_IsUnitNew[i] = true
        set udg_IsUnitAlive[i] = true
        set udg_IsUnitRemoved[i] = false
        set udg_IsUnitReincarnating[i] = false
        set udg_IsUnitPreplaced[i] = udg_IsUnitPreplaced[0] //Added 29 May 2017 for Spellbound
        call UnitEventCheckAfterProxy(i)
       
        //Fire index event for UDex
        set udg_UDex = i
        set udg_UnitIndexEvent = 0.00
        set udg_UnitIndexEvent = 1.00
        set udg_UnitIndexEvent = 0.00
    else
        set udg_UDex = GetUnitUserData(u)
        if udg_CargoTransportUnit[udg_UDex] != null and not IsUnitLoaded(u) then
            //The unit was dead, but has re-entered the map.
            call UnitEventOnUnload()
        endif
    endif
    set udg_UDex = pdex
    set u = null
    return false
endfunction
//===========================================================================
function UnitEventInit takes nothing returns nothing
    local integer i = 16
    local player p
    local trigger t = CreateTrigger()
    local trigger load = CreateTrigger()
    local trigger death = CreateTrigger()
    local trigger summon = CreateTrigger()
    local rect r = GetWorldBounds()
    local region re = CreateRegion()
    local boolexpr enterB = Filter(function UnitEventEnter)
    local boolexpr orderB = Filter(function UnitEventOnOrder)
    set udg_WorldMaxX = GetRectMaxX(r)
    set udg_WorldMaxY = GetRectMaxY(r)
    call RegionAddRect(re, r)
    call RemoveRect(r)
    call UnitEventDestroyGroup(0)
    call UnitEventDestroyGroup(1)
   
    set udg_UnitIndexerEnabled = true
    call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
    call TriggerAddCondition(load, Filter(function UnitEventOnLoad))
    call TriggerAddCondition(death, Filter(function UnitEventOnDeath))
    call TriggerAddCondition(summon, Filter(function UnitEventOnSummon))
    loop
        set i = i - 1
        set p = Player(i)
        call SetPlayerAbilityAvailable(p, udg_DetectRemoveAbility, false)
        call SetPlayerAbilityAvailable(p, udg_DetectTransformAbility, false)
        call TriggerRegisterPlayerUnitEvent(summon, p, EVENT_PLAYER_UNIT_SUMMON, null)
        call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
        call TriggerRegisterPlayerUnitEvent(death, p, EVENT_PLAYER_UNIT_DEATH, null)
        call TriggerRegisterPlayerUnitEvent(load, p, EVENT_PLAYER_UNIT_LOADED, null)
        call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
        exitwhen i == 0
    endloop
    set summon = null
    set death = null
    set load = null
    set re = null
    set enterB = null
    set orderB = null
    set p = null
    set r = null
    set t = null
endfunction
function InitTrig_Unit_Event takes nothing returns nothing
endfunction
GCSM Import
  Events
  Conditions
  Actions
    Set GCSM_CombatEvent = (Y of (Center of (Playable map area)))
    Set GCSM_CombatGroups[0] = (Last created unit group)
    Set GCSM_Source = (Last created unit)
    Set GCSM_Target = (Last created unit)
    Set GCSM_UnitInCombat[0] = False
    Set GCSM_UnitInCombat[0] = False
////////////////////////////////////////////////////////
//Guhun's Combat State Manager v1.0.0
////////////////////////////////////////////////////////

//This function engages both specified units in combat, adding each to the other's combat group
function GCSM_UnitEnterCombat takes unit target, unit source returns nothing
    local integer targetID = GetUnitUserData(target)
    local integer sourceID = GetUnitUserData(source)
   
    set udg_GCSM_UnitInCombat[targetID] = true
    set udg_GCSM_UnitInCombat[sourceID] = true
   
    call GroupAddUnit(udg_GCSM_CombatGroups[targetID], source)
    call GroupAddUnit(udg_GCSM_CombatGroups[sourceID], target)
endfunction

//This is function is for a ForGroup loop (not part of API)
function GCSM_Grp_EngageSupport takes nothing returns nothing
    call GCSM_UnitEnterCombat(udg_GCSM_Target, GetEnumUnit())
endfunction

//This function engages the supporter unit in combat with all units that are in combat with the target unit
function GCSM_UnitAidCombat takes unit target, unit supporter returns boolean
    local integer targetID = GetUnitUserData(target)
    if udg_GCSM_UnitInCombat[targetID] then
        set udg_GCSM_UnitInCombat[GetUnitUserData(supporter)] = true
        set udg_GCSM_Target = supporter
        call ForGroup(udg_GCSM_CombatGroups[targetID], function GCSM_Grp_EngageSupport)
        return true
    endif
    return false
endfunction

//This is function is for a ForGroup loop (not part of API)
function GCSM_Grp_RemoveFromGroup takes nothing returns nothing
    call GroupRemoveUnit(udg_GCSM_CombatGroups[GetUnitUserData(GetEnumUnit())], udg_GCSM_Target)
endfunction

//This function removes a unit from combat, removing it from the combat groups of units in combat with it
//and cleaing its own combat group.
function GCSM_UnitLeaveCombat takes unit target returns nothing
    local integer targetID = GetUnitUserData(target)
    set udg_GCSM_UnitInCombat[targetID] = false
    set udg_GCSM_Target = target
    call ForGroup(udg_GCSM_CombatGroups[targetID], function GCSM_Grp_RemoveFromGroup)
    call GroupClear(udg_GCSM_CombatGroups[targetID])
endfunction

//This function removes the speacified units form eachother's combat groups
function GCSM_UnitLeaveCombatWith takes unit target, unit source returns nothing
    call GroupRemoveUnit(udg_GCSM_CombatGroups[GetUnitUserData(target)], source)
    call GroupRemoveUnit(udg_GCSM_CombatGroups[GetUnitUserData(source)], target)
endfunction


//Returns whether a unit is in combat
function GCSM_UnitInCombat takes unit target returns boolean
    return udg_GCSM_UnitInCombat[GetUnitUserData(target)]
endfunction

//Returns whether the target unit is in the source unit's combat group
function GCSM_UnitInCombatWith takes unit target, unit source returns boolean
    return IsUnitInGroup(target, udg_GCSM_CombatGroups[GetUnitUserData(source)])
endfunction

////////////////////////////////////////////////////////
//End of Combat State Manager
////////////////////////////////////////////////////////


//=======
//Functions for GUI API
//=======

function Trig_GCSM_Main_Actions takes nothing returns nothing
    call GCSM_UnitEnterCombat(udg_GCSM_Target, udg_GCSM_Source)
endfunction

function Trig_GCSM_Main_Conditions takes nothing returns boolean
    if udg_GCSM_Source == null then
        call GCSM_UnitLeaveCombat(udg_GCSM_Target)
    else
        call GCSM_UnitAidCombat(udg_GCSM_Target, udg_GCSM_Source)
    endif
    return false
endfunction



//===========================================================================
function InitTrig_GCSM_Main takes nothing returns nothing
    set gg_trg_GCSM_Main = CreateTrigger(  )
    call TriggerAddAction( gg_trg_GCSM_Main, function Trig_GCSM_Main_Actions )
    call TriggerAddCondition( gg_trg_GCSM_Main, Condition(function Trig_GCSM_Main_Conditions) )
endfunction

 
GCSM Register and Cleanup
  Events
    Game - UnitIndexEvent becomes Equal to 1.00
    Game - UnitIndexEvent becomes Equal to 2.00
  Conditions
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        IsUnitRemoved[UDex] Equal to True
      Then - Actions
        -------- DESTROY GROUP FOR REMOVED UNITS --------
        Set GCSM_Target = UDexUnits[UDex]
        Set GCSM_Source = No unit
        Custom script: call DestroyGroup(udg_GCSM_CombatGroups[udg_UDex])
      Else - Actions
        -------- CREATE GROUP FOR REGISTERED UNITS --------
        Custom script: set udg_GCSM_CombatGroups[udg_UDex] = CreateGroup()
Delete Unit Indexer if you already have it or the latest Unit Event in your map.
Copy this trigger to import variables. You can later delete it.
GTS Import
  Events
  Conditions
  Actions
    Set GTS_CustomValue = 0
    Set GTS_DestroyTimer = False
    Set GTS_ExecutionCounter = 0
    Set GTS_Hashtable = (Last created hashtable)
    Set GTS_TimeOut = 0.00
    Set GTS_Trigger = (This trigger)
    Set GTS_Timer = (Last started timer)
////////////////////////////////////////////////////////
//Guhun's Timer System version 1.0
////////////////////////////////////////////////////////
//Hashtable adresses:
//-3: Trigger
//-2: Execution Counter
//-1: User Data
////////////////////////////////////////////////////////

//This function executes when a timer expires, running the correct trigger while checking conditions and if it is enabled
function GTS_DestroyTimer takes timer t returns nothing
    call PauseTimer(t)
    call DestroyTimer(t)
    call FlushChildHashtable(udg_GTS_Hashtable, GetHandleId(t))
endfunction

function GTS_ExecuteTimer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer tId = GetHandleId(t)
    local integer counter = LoadInteger(udg_GTS_Hashtable, tId, -2) + 1 //Increase counter
    local trigger trig = LoadTriggerHandle(udg_GTS_Hashtable, tId, -3)

    set udg_GTS_CustomValue = LoadInteger(udg_GTS_Hashtable, tId, -1)
    set udg_GTS_ExecutionCounter = counter
   
    if IsTriggerEnabled(trig) and TriggerEvaluate(trig) then
        call TriggerExecute(trig)
    endif

    if udg_GTS_DestroyTimer then
        call PauseTimer(t)
        call DestroyTimer(t)
        call FlushChildHashtable(udg_GTS_Hashtable, tId)
        set udg_GTS_DestroyTimer = false //User must manually specify if timer should be destroyed
    else
        call SaveInteger(udg_GTS_Hashtable, tId, -2, counter)
    endif
    set t = null
    set trig = null
endfunction

function GTS_RestartTimer takes timer t, real timeout returns nothing
    call TimerStart(t, timeout, true, function GTS_ExecuteTimer)
endfunction

//Creates a new timer, starts it and stores relevant data in hashtable
function GTS_StartTimer takes timer t, real timeout, trigger whichTrigger, boolean useHandleId, integer userData returns nothing
    local integer tId = GetHandleId(t)
   
    call TimerStart(t, timeout, true, function GTS_ExecuteTimer)    

    if useHandleId then
        call SaveInteger(udg_GTS_Hashtable, tId, -1, tId)
        set udg_GTS_CustomValue = tId
    else
        call SaveInteger(udg_GTS_Hashtable, tId, -1, userData)
    endif
   
    call SaveTriggerHandle(udg_GTS_Hashtable, tId, -3, whichTrigger)
endfunction

//Creates a new timer and sets GTS_Timer to it, then starts the timer
function GTS_CreateTimer takes real timeout, trigger whichTrigger, boolean useHandleId, integer userData returns nothing
    set udg_GTS_Timer = CreateTimer()
    call GTS_StartTimer(udg_GTS_Timer, timeout, whichTrigger, useHandleId, userData)
endfunction
////////////////////////////////////////////////////////
//End of Guhun's Timer System
////////////////////////////////////////////////////////

function Trig_GTS_Main_Actions takes nothing returns nothing
    if udg_GTS_TimeOut >= 0 then
        call GTS_CreateTimer(udg_GTS_TimeOut, udg_GTS_Trigger, false, udg_GTS_CustomValue)
    else
        call GTS_DestroyTimer(udg_GTS_Timer)
        set udg_GTS_Timer = null
    endif
endfunction

function Trig_GTS_Main_Conditions takes nothing returns boolean
    if udg_GTS_TimeOut >= 0 then
        call GTS_CreateTimer(udg_GTS_TimeOut, udg_GTS_Trigger, true, 0)
    else
        call GTS_RestartTimer(udg_GTS_Timer, -udg_GTS_TimeOut)
    endif
    return false
endfunction


//===========================================================================
function InitTrig_GTS_Main takes nothing returns nothing
    set gg_trg_GTS_Main = CreateTrigger()
    set udg_GTS_Hashtable = InitHashtable()
    call TriggerAddAction( gg_trg_GTS_Main, function Trig_GTS_Main_Actions )
    call TriggerAddCondition(gg_trg_GTS_Main, Condition(function Trig_GTS_Main_Conditions))
endfunction

 
Damage Engine Config
  Events
  Conditions
    (UDexUnits[UDex] is A structure) Equal to False
  Actions
    -------- - --------
    -------- This trigger's conditions let you filter out units you don't want detection for. --------
    -------- NOTE: By default, units with Locust will not pass the check. --------
    -------- TIP: The unit is called UDexUnits[UDex] and its custom value is UDex --------
    -------- - --------
    -------- Copy the Cheat Death Ability from Object Editor into your map and set the following variable respectively: --------
    -------- - --------
    Set DamageBlockingAbility = Cheat Death Ability (+500,000)
    -------- - --------
    -------- Copy the Detect Spell Damage Ability from Object Editor into your map and set the following variable respectively: --------
    -------- - --------
    Set SpellDamageAbility = Detect Spell Damage
    -------- - --------
    -------- You can add extra classifications here if you want to differentiate between your triggered damage --------
    -------- Use DamageTypeExplosive (or any negative value damage type) if you want a unit killed by that damage to explode --------
    -------- - --------
    Set DamageTypeExplosive = -1
    Set DamageTypeCriticalStrike = 1
    Set DamageTypeHeal = 2
    Set DamageTypeReduced = 3
    Set DamageTypeBlocked = 4
    -------- - --------
    -------- Leave the next Set statement disabled if you modified the Spell Damage Reduction item ability to 1.67 reduction --------
    -------- Otherwise, if you removed that ability from Runed Bracers, you'll need to enable this line: --------
    -------- - --------
    Set DmgEvBracers = Runed Bracers
    -------- - --------
    -------- Set the damage multiplication factor (1.00 being unmodified, increasing in damage over 1.00 and at 0 damage with 0.00) --------
    -------- NOTE. With the default values, Runed Bracers is reduces 33%, Elune's Grace reduces 20% and Ethereal increases 67% --------
    -------- - --------
    Set DAMAGE_FACTOR_BRACERS = 0.67
    Set DAMAGE_FACTOR_ELUNES = 0.80
    Set DAMAGE_FACTOR_ETHEREAL = 1.67
    -------- - --------
    -------- Added 25 July 2017 to allow detection of things like Bash or Pulverize or AOE spread --------
    -------- - --------
    Set DamageEventAOE = 1
    Set DamageEventLevel = 1
    -------- - --------
    -------- Do not enable any of the following lines as they are simply variable declarations to make copying easier --------
    -------- - --------
    Set AfterDamageEvent = (DamageEvent + (AOEDamageEvent + DamageModifierEvent))
    Set ClearDamageEvent = (This trigger)
    Set DamageEventAmount = DamageEventPrevAmt
    Set DamageEventOverride = NextDamageOverride
    Set DamageEventSource = DamageEventTarget
    Set DamageEventTrigger = DmgEvTrig
    Set DamageEventType = (LastDmgPrevType[0] + NextDamageType)
    Set DamageEventsWasted = DmgEvRecursionN
    Set DmgEvRunning = DmgEvStarted
    Set IsDamageSpell = LastDmgWasSpell[0]
    Set LastDamageHP = (Elapsed time for DmgEvTimer)
    Set LastDmgPrevAmount[0] = LastDmgValue[0]
    Set LastDmgSource[0] = LastDmgTarget[0]
    Set HideDamageFrom[0] = False
    Set UnitDamageRegistered[0] = False
    Unit Group - Add EnhancedDamageTarget to DamageEventAOEGroup
//===========================================================================
// Damage Engine lets you detect, amplify, block or nullify damage. It even
// lets you detect if the damage was physical or from a spell. Just reference
// DamageEventAmount/Source/Target or the boolean IsDamageSpell, to get the
// necessary damage event data.
//
// - Detect damage: use the event "DamageEvent Equal to 1.00"
// - To change damage before it's dealt: use the event "DamageModifierEvent Equal to 1.00"
// - Detect damage after it was applied, use the event "AfterDamageEvent Equal to 1.00"
// - Detect spell damage: use the condition "IsDamageSpell Equal to True"
// - Detect zero-damage: use the event "DamageEvent Equal to 2.00" (an AfterDamageEvent will not fire for this)
//
// You can specify the DamageEventType before dealing triggered damage. To prevent an already-improbable error, I recommend running the trigger "ClearDamageEvent (Checking Conditions)" after dealing triggered damage from within a damage event:
// - Set NextDamageType = DamageTypeWhatever
// - Unit - Cause...
// - Trigger - Run ClearDamageEvent (Checking Conditions)
//
// You can modify the DamageEventAmount and the DamageEventType from a "DamageModifierEvent Equal to 1.00" trigger.
// - If the amount is modified to negative, it will count as a heal.
// - If the amount is set to 0, no damage will be dealt.
//
// If you need to reference the original in-game damage, use the variable "DamageEventPrevAmt".
//
//===========================================================================
// Programming note about "integer i" and "udg_DmgEvRecursionN": integer i
// ranges from -1 upwards. "udg_DmgEvRecursionN" ranges from 0 upwards.
// "integer i" is always 1 less than "udg_DmgEvRecursionN"
//
function DmgEvResetVars takes nothing returns nothing
    local integer i = udg_DmgEvRecursionN - 2
    set udg_DmgEvRecursionN = i + 1
    if i >= 0 then
        set udg_DamageEventPrevAmt  = udg_LastDmgPrevAmount[i]
        set udg_DamageEventAmount   = udg_LastDmgValue[i]
        set udg_DamageEventSource   = udg_LastDmgSource[i]
        set udg_DamageEventTarget   = udg_LastDmgTarget[i]
        set udg_IsDamageSpell       = udg_LastDmgWasSpell[i]
        set udg_DamageEventType     = udg_LastDmgPrevType[i]
    endif
endfunction

function CheckDamagedLifeEvent takes boolean clear returns nothing
    if clear then
        set udg_NextDamageOverride = false
        set udg_NextDamageType = 0
    endif
    if udg_DmgEvTrig != null then
        call DestroyTrigger(udg_DmgEvTrig)
        set udg_DmgEvTrig = null
        if udg_IsDamageSpell then
            call SetWidgetLife(udg_DamageEventTarget, RMaxBJ(udg_LastDamageHP, 0.41))
            if udg_LastDamageHP <= 0.405 then
                if udg_DamageEventType < 0 then
                    call SetUnitExploded(udg_DamageEventTarget, true)
                endif
                //Kill the unit
                call DisableTrigger(udg_DamageEventTrigger)
                call UnitDamageTarget(udg_DamageEventSource, udg_DamageEventTarget, -999, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
                call EnableTrigger(udg_DamageEventTrigger)
            endif
        elseif GetUnitAbilityLevel(udg_DamageEventTarget, udg_DamageBlockingAbility) > 0 then
            call UnitRemoveAbility(udg_DamageEventTarget, udg_DamageBlockingAbility)
            call SetWidgetLife(udg_DamageEventTarget, udg_LastDamageHP)
        endif
        if udg_DamageEventAmount != 0.00 and not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
            set udg_AfterDamageEvent = 0.00
            set udg_AfterDamageEvent = 1.00
            set udg_AfterDamageEvent = 0.00
        endif
        call DmgEvResetVars()
    endif
endfunction
   
function DmgEvOnAOEEnd takes nothing returns nothing
    if udg_DamageEventAOE > 1 then
        set udg_AOEDamageEvent = 0.00
        set udg_AOEDamageEvent = 1.00
        set udg_AOEDamageEvent = 0.00
        set udg_DamageEventAOE = 1
    endif
    set udg_DamageEventLevel = 1
    set udg_EnhancedDamageTarget = null
    call GroupClear(udg_DamageEventAOEGroup)
endfunction
   
function DmgEvOnExpire takes nothing returns nothing
    set udg_DmgEvStarted = false
    call CheckDamagedLifeEvent(true)
    //Reset things so they don't perpetuate for AoE/Level target detection
    call DmgEvOnAOEEnd()
    set udg_DamageEventTarget = null
    set udg_DamageEventSource = null
endfunction

function PreCheckDamagedLifeEvent takes nothing returns boolean
    call CheckDamagedLifeEvent(true)
    return false
endfunction

function OnUnitDamage takes nothing returns boolean
    local boolean override = udg_DamageEventOverride
    local integer i
    local integer e = udg_DamageEventLevel
    local integer a = udg_DamageEventAOE
    local string s
    local real prevAmount
    local real life
    local real prevLife
    local unit u
    local unit f
    call CheckDamagedLifeEvent(false) //in case the unit state event failed and the 0.00 second timer hasn't yet expired
    set i = udg_DmgEvRecursionN - 1 //Had to be moved here due to false recursion tracking
    if i < 0 then
        //Added 25 July to detect AOE damage or multiple single-target damage
        set u                       = udg_DamageEventTarget
        set f                       = udg_DamageEventSource
    elseif i < 16 then
        set udg_LastDmgPrevAmount[i]= udg_DamageEventPrevAmt
        set udg_LastDmgValue[i]     = udg_DamageEventAmount
        set udg_LastDmgSource[i]    = udg_DamageEventSource
        set udg_LastDmgTarget[i]    = udg_DamageEventTarget
        set udg_LastDmgWasSpell[i]  = udg_IsDamageSpell
        set udg_LastDmgPrevType[i]  = udg_DamageEventType
    else
        set s = "WARNING: Recursion error when dealing damage! Make sure when you deal damage from within a DamageEvent trigger, do it like this:\n\n"
        set s = s + "Trigger - Turn off (This Trigger)\n"
        set s = s + "Unit - Cause...\n"
        set s = s + "Trigger - Turn on (This Trigger)"
       
        //Delete the next couple of lines to disable the in-game recursion crash warnings
        call ClearTextMessages()
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, 999.00, s)
        return false
    endif
    set udg_DmgEvRecursionN     = i + 2
    set prevAmount              = GetEventDamage()
    set udg_DamageEventTarget   = GetTriggerUnit()
    set udg_DamageEventSource   = GetEventDamageSource()
   
    set udg_DamageEventAmount   = prevAmount
   
    set udg_DamageEventType     = udg_NextDamageType
    set udg_NextDamageType      = 0
    set udg_DamageEventOverride = udg_NextDamageOverride
    set udg_NextDamageOverride  = false
   
    if i < 0 then
        //Added 25 July to detect AOE damage or multiple single-target damage
        if udg_DamageEventType == 0 then
            if f == udg_DamageEventSource then
                //Source has damaged more than once
                if IsUnitInGroup(udg_DamageEventTarget, udg_DamageEventAOEGroup) then
                    //Added 5 August to improve tracking of enhanced damage against, say, Pulverize
                    set udg_DamageEventLevel = udg_DamageEventLevel + 1
                    set udg_EnhancedDamageTarget = udg_DamageEventTarget
                else
                    //Multiple targets hit by this source - flag as AOE
                    set udg_DamageEventAOE = udg_DamageEventAOE + 1
                endif
            else
                //New damage source - unflag everything
                set u = udg_DamageEventSource
                set udg_DamageEventSource = f
                call DmgEvOnAOEEnd()
                set udg_DamageEventSource = u
            endif
            call GroupAddUnit(udg_DamageEventAOEGroup, udg_DamageEventTarget)
        endif
        if not udg_DmgEvStarted then
            set udg_DmgEvStarted = true
            call TimerStart(udg_DmgEvTimer, 0.00, false, function DmgEvOnExpire)
        endif
    endif
   
    if prevAmount == 0.00 then
        if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
            set udg_DamageEventPrevAmt = 0.00
            set udg_DamageEvent = 0.00
            set udg_DamageEvent = 2.00
            set udg_DamageEvent = 0.00
        endif
        call DmgEvResetVars()
    else
        set u = udg_DamageEventTarget
        set udg_IsDamageSpell = prevAmount < 0.00
        if udg_IsDamageSpell then
            set prevAmount = -udg_DamageEventAmount
            set life = 1.00
            if IsUnitType(u, UNIT_TYPE_ETHEREAL) and not IsUnitType(u, UNIT_TYPE_HERO) then
                set life = life*udg_DAMAGE_FACTOR_ETHEREAL //1.67
            endif
            if GetUnitAbilityLevel(u, 'Aegr') > 0 then
                set life = life*udg_DAMAGE_FACTOR_ELUNES //0.80
            endif
            if udg_DmgEvBracers != 0 and IsUnitType(u, UNIT_TYPE_HERO) then
                //Inline of UnitHasItemOfTypeBJ without the potential handle ID leak.
                set i = 6
                loop
                    set i = i - 1
                    if GetItemTypeId(UnitItemInSlot(u, i)) == udg_DmgEvBracers then
                        set life = life*udg_DAMAGE_FACTOR_BRACERS //0.67
                        exitwhen true
                    endif
                    exitwhen i == 0
                endloop
            endif
            set udg_DamageEventAmount = prevAmount*life
        endif
        set udg_DamageEventPrevAmt = prevAmount
        set udg_DamageModifierEvent = 0.00
        if not udg_DamageEventOverride then
            set udg_DamageModifierEvent = 1.00
            if not udg_DamageEventOverride then
                set udg_DamageModifierEvent = 2.00
                set udg_DamageModifierEvent = 3.00
            endif
        endif
        set udg_DamageEventOverride = override
        if udg_DamageEventAmount > 0.00 then
            set udg_DamageModifierEvent = 4.00
        endif
        set udg_DamageModifierEvent = 0.00
        if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
            set udg_DamageEvent = 0.00
            set udg_DamageEvent = 1.00
            set udg_DamageEvent = 0.00
        endif
        call CheckDamagedLifeEvent(true) //in case the unit state event failed from a recursive damage event
       
        //All events have run and the damage amount is finalized.
        set life = GetWidgetLife(u)
        set udg_DmgEvTrig = CreateTrigger()
        call TriggerAddCondition(udg_DmgEvTrig, Filter(function PreCheckDamagedLifeEvent))
        if not udg_IsDamageSpell then
            if udg_DamageEventAmount != prevAmount then
                set life = life + prevAmount - udg_DamageEventAmount
                if GetUnitState(u, UNIT_STATE_MAX_LIFE) < life then
                    set udg_LastDamageHP = life - prevAmount
                    call UnitAddAbility(u, udg_DamageBlockingAbility)
                endif
                call SetWidgetLife(u, RMaxBJ(life, 0.42))
            endif
            call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, LESS_THAN, RMaxBJ(0.41, life - prevAmount/2.00))
        else
            set udg_LastDamageHP = GetUnitState(u, UNIT_STATE_MAX_LIFE)
            set prevLife = life
            if life + prevAmount*0.75 > udg_LastDamageHP then
                set life = RMaxBJ(udg_LastDamageHP - prevAmount/2.00, 1.00)
                call SetWidgetLife(u, life)
                set life = (life + udg_LastDamageHP)/2.00
            else
                set life = life + prevAmount*0.50
            endif
            set udg_LastDamageHP = prevLife - (prevAmount - (prevAmount - udg_DamageEventAmount))
            call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, GREATER_THAN, life)
        endif
    endif
    set u = null
    set f = null
    return false
endfunction

function CreateDmgEvTrg takes nothing returns nothing
    set udg_DamageEventTrigger = CreateTrigger()
    call TriggerAddCondition(udg_DamageEventTrigger, Filter(function OnUnitDamage))
endfunction

function SetupDmgEv takes nothing returns boolean
    local integer i = udg_UDex
    local unit u
    if udg_UnitIndexEvent == 1.00 then
        set u = udg_UDexUnits[i]
        if GetUnitAbilityLevel(u, 'Aloc') == 0 and TriggerEvaluate(gg_trg_Damage_Engine_Config) then
            set udg_UnitDamageRegistered[i] = true
            call TriggerRegisterUnitEvent(udg_DamageEventTrigger, u, EVENT_UNIT_DAMAGED)
            call UnitAddAbility(u, udg_SpellDamageAbility)
            call UnitMakeAbilityPermanent(u, true, udg_SpellDamageAbility)
        endif
        set u = null
    else
        set udg_HideDamageFrom[i] = false
        if udg_UnitDamageRegistered[i] then
            set udg_UnitDamageRegistered[i] = false
            set udg_DamageEventsWasted = udg_DamageEventsWasted + 1
            if udg_DamageEventsWasted == 32 then //After 32 registered units have been removed...
                set udg_DamageEventsWasted = 0
               
                //Rebuild the mass EVENT_UNIT_DAMAGED trigger:
                call DestroyTrigger(udg_DamageEventTrigger)
                call CreateDmgEvTrg()
                set i = udg_UDexNext[0]
                loop
                    exitwhen i == 0
                    if udg_UnitDamageRegistered[i] then
                        call TriggerRegisterUnitEvent(udg_DamageEventTrigger, udg_UDexUnits[i], EVENT_UNIT_DAMAGED)
                    endif
                    set i = udg_UDexNext[i]
                endloop
            endif
        endif
    endif
    return false
endfunction
   
//===========================================================================
function InitTrig_Damage_Engine takes nothing returns nothing
    local unit u = CreateUnit(Player(15), 'uloc', 0, 0, 0)
    local integer i = 16
   
    //Create this trigger with UnitIndexEvents in order add and remove units
    //as they are created or removed.
    local trigger t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 1.00)
    call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 2.00)
    call TriggerAddCondition(t, Filter(function SetupDmgEv))
    set t = null
   
    //Run the configuration trigger to set all configurables:
    if gg_trg_Damage_Engine_Config == null then
        //It's possible this InitTrig_ function ran first, in which case use ExecuteFunc.
        call ExecuteFunc("Trig_Damage_Engine_Config_Actions")
    else
        call TriggerExecute(gg_trg_Damage_Engine_Config)
    endif
   
    //Create trigger for storing all EVENT_UNIT_DAMAGED events.
    call CreateDmgEvTrg()
   
    //Create GUI-friendly trigger for cleaning up after UnitDamageTarget.
    set udg_ClearDamageEvent = CreateTrigger()
    call TriggerAddCondition(udg_ClearDamageEvent, Filter(function PreCheckDamagedLifeEvent))
   
    //Disable SpellDamageAbility for every player.
    loop
        set i = i - 1
        call SetPlayerAbilityAvailable(Player(i), udg_SpellDamageAbility, false)
        exitwhen i == 0
    endloop
   
    //Preload abilities.
    call UnitAddAbility(u, udg_DamageBlockingAbility)
    call UnitAddAbility(u, udg_SpellDamageAbility)
    call RemoveUnit(u)
    set u = null
endfunction
This trigger will use Enter Combat Damage and Enter Combat Support to engage units in combat when they cast spells on one another.

The way they engage in combat will depend on if they are allies or enemies.
TestMap Cast Ability Combat
  Events
    Unit - A unit Starts the effect of an ability
  Conditions
    (Target unit of ability being cast) Not equal to No unit
  Actions
    Set DamageEventTarget = (Triggering unit)
    Set DamageEventSource = (Target unit of ability being cast)
    Trigger - Run TestMap_Enter_Combat_Damage <gen> (checking conditions)
    Trigger - Run TestMap_Enter_Combat_Support <gen> (checking conditions)
This trigger engages two units in combat (DamageEventTarget and DamageEventSource) if they are not allies and DamageEventSource is alive.

It uses the Combat Timer trigger to create/refresh the units' combat timers.
TestMap Enter Combat Damage
  Events
    Game - DamageModifierEvent becomes Equal to 1.00
  Conditions
    ((Owner of DamageEventSource) is an ally of (Owner of DamageEventTarget)) Equal to False
    IsUnitAlive[(Custom value of DamageEventSource)] Equal to True
  Actions
    Set GCSM_Target = DamageEventTarget
    Trigger - Run TestMap_Combat_Timer <gen> (ignoring conditions)
    Set GCSM_Target = DamageEventSource
    Trigger - Run TestMap_Combat_Timer <gen> (ignoring conditions)
    -------- ------------------ --------
    -------- FLAG SOURCE AND TARGET FOR COMBAT --------
    -------- ------------------ --------
    Set GCSM_Target = DamageEventSource
    Set GCSM_Source = DamageEventTarget
    Trigger - Run GCSM_Main <gen> (ignoring conditions)
This trigger engages 1 unit (DamageEventTarget) in combat if DamageEventSource in in combat and both units are allies.

The unit will engaged in combat with all units that are in combat with DamageEventSource.

The trigger uses the Combat Timer trigger to create/refresh the units' combat timers.
TestMap Enter Combat Support
  Events
  Conditions
    GCSM_UnitInCombat[(Custom value of DamageEventSource)] Equal to True
    ((Owner of DamageEventSource) is an ally of (Owner of DamageEventTarget)) Equal to True
  Actions
    Set GCSM_Target = DamageEventTarget
    Trigger - Run TestMap_Combat_Timer <gen> (ignoring conditions)
    -------- ------------------ --------
    -------- FLAG THE SUPPORTER (SOURCE) FOR COMBAT --------
    -------- ------------------ --------
    Set GCSM_Target = DamageEventSource
    Set GCSM_Source = DamageEventTarget
    Trigger - Run GCSM_Main <gen> (checking conditions)
This trigger will check the combat group of any unit that dies and will remove from combat any units that were only in combat with the dying unit.

It will also remove the dying unit from combat and destroy its combat timer.
TestMap Leave Combat On Death
  Events
    Unit - A unit Dies
  Conditions
  Actions
    -------- ------------------ --------
    -------- For all units in the dying unit's combat group, check if they are only in combat with 1 unit (the dying unit) --------
    -------- If they are, reduce the duration of their combat timer to 0.5 seconds --------
    -------- ------------------ --------
    Unit Group - Pick every unit in GCSM_CombatGroups[(Custom value of (Triggering unit))] and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Number of units in GCSM_CombatGroups[(Custom value of (Picked unit))]) Equal to 1
          Then - Actions
            Set GTS_Timer = Test_Timers[(Custom value of (Picked unit))]
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                (Remaining time for GTS_Timer) Greater than 0.50
              Then - Actions
                Set GTS_TimeOut = -0.50
                Trigger - Run GTS_Main <gen> (checking conditions)
              Else - Actions
          Else - Actions
    -------- ------------------ --------
    -------- Remove the dying unit from combat --------
    -------- ------------------ --------
    Set GCSM_Source = No unit
    Set GCSM_Target = (Triggering unit)
    Trigger - Run GCSM_Main <gen> (checking conditions)
    -------- ------------------ --------
    -------- Destroy the combat timer and special effect for the dying unit --------
    -------- ------------------ --------
    Set GTS_TimeOut = -0.50
    Set GTS_Timer = Test_Timers[(Custom value of (Triggering unit))]
    -------- Get Handle ID of the timer with a Custom Script, since you can't use variables to get Handle ID --------
    Custom script: set udg_GTS_CustomValue = GetHandleId(udg_GTS_Timer)
    Special Effect - Destroy (Load 1 of GTS_CustomValue in GTS_Hashtable)
    Trigger - Run GTS_Main <gen> (ignoring conditions)
This trigger will create a combat timer for a unit if that unit is not in combat.

If the unit was already in combat, it will reset the combat timer.
TestMap Combat Timer
  Events
  Conditions
  Actions
    -------- ------------------ --------
    -------- If the unit is not in combat, create timer and special effect --------
    -------- If unit is not in combat, restart its timer --------
    -------- ------------------ --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        GCSM_UnitInCombat[(Custom value of GCSM_Target)] Equal to False
      Then - Actions
        -------- Create the combat timer (using Handle ID as custom value of the timer) --------
        Set GTS_TimeOut = 5.00
        Set GTS_Trigger = TestMap_Combat_Timer_Expired <gen>
        Trigger - Run GTS_Main <gen> (checking conditions)
        Set Test_Timers[(Custom value of GCSM_Target)] = GTS_Timer
        -------- ------------------ --------
        -------- Create special effect and save timer data in GTS_Hashtable --------
        Special Effect - Create a special effect attached to the overhead of GCSM_Target using Abilities\Spells\Other\TalkToMe\TalkToMe.mdl
        Hashtable - Save Handle OfGCSM_Target as 0 of GTS_CustomValue in GTS_Hashtable
        Hashtable - Save Handle Of(Last created special effect) as 1 of GTS_CustomValue in GTS_Hashtable
      Else - Actions
        -------- Restart the combat timer --------
        Set GTS_TimeOut = -5.00
        Set GTS_Timer = Test_Timers[(Custom value of GCSM_Target)]
        Trigger - Run GTS_Main <gen> (checking conditions)
This trigger runs when a combat timer expires, removing the unit from combat and removing the created special effect.
TestMap Combat Timer Expired
  Events
  Conditions
  Actions
    -------- ------------------ --------
    -------- Remove the timer unit from combat --------
    -------- ------------------ --------
    Set GCSM_Source = No unit
    Set GCSM_Target = (Load 0 of GTS_CustomValue in GTS_Hashtable)
    Trigger - Run GCSM_Main <gen> (checking conditions)
    -------- ------------------ --------
    -------- Destroy special effect and flag timer for destruction --------
    -------- ------------------ --------
    Special Effect - Destroy (Load 1 of GTS_CustomValue in GTS_Hashtable)
    Set GTS_DestroyTimer = True
Copy this trigger into your map if you want to fix the life drain abilitity. It comes with a potential weird side-effect: if you had already cast a damage over time ability on the damage target from the damage source before life draining, it will heal off of that damage over time ability as well. Without triggering life drain completely on your own, there is no way to prevent this. However, this issue does not affect the Dark Ranger since she only has that one damage-over-time ability.
Life Drain Fix
  Events
    Game - AfterDamageEvent becomes Equal to 1.00
  Conditions
    IsDamageSpell Equal to True
    (DamageEventSource has buff Drain Life (Caster)) Equal to True
    (DamageEventTarget has buff Drain Life (Target)) Equal to True
  Actions
    Unit - Set life of DamageEventSource to ((Life of DamageEventSource) + DamageEventAmount)
This is pretty easy to fix.
Finger of Death Fix
  Events
    Game - DamageModifierEvent becomes Equal to 1.00
  Conditions
    IsDamageSpell Equal to True
    (Current order of DamageEventSource) Equal to (Order(fingerofdeath))
  Actions
    Set DamageEventType = DamageTypeExplosive
Anti Magic Shiled Var
  Events
  Conditions
  Actions
    Set AMSAmount[0] = 0.00
Requires you to copy the ability "Anti-Magic Shell (Fixed)" from Object Editor into your map. AMS cannot be configured to work with a damage detection system as it will always have ambiguous results and the shield will be popped or reduce damage to 0.00 before the damage event runs, so the ability is based off of Frost Armor with its only utility being triggered.
constant function GetAMSBuffId takes nothing returns integer
    return 'Bams'
endfunction

constant function GetAMSAbilId takes nothing returns integer
    return 'A002'
endfunction

constant function GetAMSShieldVal takes nothing returns real
    return 300.00
endfunction

function Trig_Anti_Magic_Shield_Fix_Actions takes nothing returns nothing
    local integer id = GetUnitUserData(udg_DamageEventTarget)
    local real shield = udg_AMSAmount[id]- udg_DamageEventAmount
    if shield <= 0.00 then
        set udg_DamageEventAmount = -shield
        set shield = 0.00
        call UnitRemoveAbility(udg_DamageEventTarget, GetAMSBuffId())
    else
        set udg_DamageEventAmount = 0.00
        if udg_DamageEventType == 0 then
            set udg_DamageEventType = udg_DamageTypeBlocked
        endif
    endif
    set udg_AMSAmount[id] = shield
endfunction

function Trig_Anti_Magic_Shield_Fix_Conditions takes nothing returns boolean
    if udg_IsDamageSpell then
        if GetUnitAbilityLevel(udg_DamageEventTarget, GetAMSBuffId()) > 0 then
            call Trig_Anti_Magic_Shield_Fix_Actions()
        else
            set udg_AMSAmount[GetUnitUserData(udg_DamageEventTarget)] = 0.00
        endif
    endif
    return false
endfunction

function AMS_Refresh_Conditions takes nothing returns boolean
    if GetSpellAbilityId() == GetAMSAbilId() then
        set udg_AMSAmount[GetUnitUserData(GetSpellTargetUnit())] = GetAMSShieldVal()
    endif
    return false
endfunction

function InitTrig_Anti_Magic_Shield_Fix takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_DamageModifierEvent", EQUAL, 4.00)
    call TriggerAddCondition(t, Condition(function Trig_Anti_Magic_Shield_Fix_Conditions))
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Filter(function AMS_Refresh_Conditions))
endfunction
DamageModifierEvent becoming Equal to 4.00 is a new event introduced in DamageEngine 3.5. It is the final phase of damage processing as it is built specifically to handle shields, and only runs if the damage is greater than 0.
Mana Shield Fix
  Events
    Game - DamageModifierEvent becomes Equal to 4.00
  Conditions
    (DamageEventTarget has buff Mana Shield) Equal to True
  Actions
    -------- Mana Shield handling. For it to work, you need to set the mana shield Damage Absorbed % --------
    -------- to 0.00 for Mana Shield (Neutral Hostile) and for all 3 levels of Mana Shield for the Naga Sea Witch. --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
      Then - Actions
        Set DmgEvMana = (Mana of DamageEventTarget)
        -------- Get the shielding mana multiplier from the target unit based on the unit or hero ability ("multiplier" mana per HP) --------
        -------- If you have custom mana shield abilities or have modified the normal ones, add or configure those here. --------
        Set DmgEvMSlvl = (Level of Mana Shield for DamageEventTarget)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            DmgEvMSlvl Equal to 0
          Then - Actions
            Set DmgEvManaMult = 2.00
          Else - Actions
            Set DmgEvManaMult = ((0.50 x (Real(DmgEvMSlvl))) + 0.50)
        Set DmgEvMana = (DmgEvMana x DmgEvManaMult)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            DamageEventAmount Less than (DmgEvMana - 0.01)
          Then - Actions
            Set DmgEvMana = (DmgEvMana - DamageEventAmount)
            Set DamageEventAmount = 0.00
            Set DmgEvMana = (DmgEvMana / DmgEvManaMult)
            -------- You can remove this damage type change if you want, it's mostly for the purpose of the test map. --------
            Set DamageEventType = DamageTypeBlocked
          Else - Actions
            Set DamageEventAmount = (DamageEventAmount - DmgEvMana)
            Set DmgEvMana = 0.00
            Unit - Order DamageEventTarget to Neutral Naga Sea Witch - Deactivate Mana Shield
            -------- You can remove this damage type change if you want, it's mostly for the purpose of the test map. --------
            Set DamageEventType = DamageTypeReduced
        Unit - Set mana of DamageEventTarget to DmgEvMana
      Else - Actions
Command Combat
  Events
    Player - Player 1 (Red) types a chat message containing combat 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
        Unit Group - Pick every unit in GCSM_CombatGroups[(Custom value of (Picked unit))] and do (Actions)
          Loop - Actions
            Game - Display to (All players) the text: (Name of (Picked unit))
        Custom script: set bj_wantDestroyGroup = true
Command Combat Copy
  Events
    Player - Player 1 (Red) types a chat message containing kill 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
        Unit - Kill (Picked unit)
Esc Help
  Events
    Time - Elapsed game time is 0.00 seconds
  Conditions
  Actions
    Game - Display to (All players) the text: Press Esc to view commandsDouble press Esc to clear text messages
Esc Switch
  Events
    Time - Test_EscTimer expires
  Conditions
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Esc_DoubleClick <gen> is on) Equal to True
      Then - Actions
        Trigger - Turn on Esc_SingleClick <gen>
        Trigger - Turn off Esc_DoubleClick <gen>
      Else - Actions
        Trigger - Turn on Esc_DoubleClick <gen>
        Countdown Timer - Start Test_EscTimer as a One-shot timer that will expire in 0.50 seconds
Esc SingleClick
  Events
    Player - Player 1 (Red) skips a cinematic sequence
  Conditions
  Actions
    Game - Display to (All players) the text: kill -> kills your selected unitscombat -> shows which units are in combat with your selected units
    Countdown Timer - Start Test_EscTimer as a One-shot timer that will expire in 0.00 seconds
    Trigger - Turn off Esc_SingleClick <gen>
Esc DoubleClick
  Events
    Player - Player 1 (Red) skips a cinematic sequence
  Conditions
  Actions
    Cinematic - Clear the screen of text messages for (All players)