1. Are you planning to upload your awesome map to Hive? Please review the rules here.
    Dismiss Notice
  2. Head to the 33rd Modeling Contest Poll and drink to your heart's desire.
    Dismiss Notice
  3. Choose your means of doom in the 17th Mini Mapping Contest Poll.
    Dismiss Notice
  4. A slave to two rhythms, the 22nd Terraining Contest is here.
    Dismiss Notice
  5. The heavens smile on the old faithful. The 16th Techtree Contest has begun.
    Dismiss Notice
  6. The die is cast - the 6th Melee Mapping Contest results have been announced. Onward to the Hive Cup!
    Dismiss Notice
  7. The glory of the 20th Icon Contest is yours for the taking!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Trigger Viewer

THW.TC14.Last Revolt.w3x
Variables
Core Code
TechtreeMechanics
ProtocolCenterLimit
ProtocolCenterBuildLimit
MainstayConstruction
Replace
LRTier2
LRTier3
Melee Game
UnitAbilities
FrostMine
FrostMineTrigger
Pressure
PressureConfig
PressureEffect
ChromiumBlossom
BlossomDepletion
BlossomDrainConfig
BlossomDrain
OutOfMana
SuppressionAura
SuppressionAuraConfig
SuppressioonAuraRegister
NaniteAura
HealAuraConfig
HealAuraRegister
DragonAura
DragonAuraConfig
DragonAuraRegister
PteneradonAura
PteneradonAuraConfig
PteneradonAuraRegister
Reprocessor
ReprocessorConfig
ReprocessorKillBlow
Revolution
RevolutionConfig
RevolutionDamage
Judgment
JudgmentConfig
Judgment
RepairGun
LAG SOURCE 1
RepairGunConfig
RepairGunRegister
RepairGunLoop
CrushingFist
CrushingFistConfig
CrushingFist
JudasShield
JudasShieldConfig
JudasShield
ChromiumMainGun
ChromiumBeamConfig
ChromiumBeam
StrikerField
StrikerFieldRegister
StrikerFieldRegister2
StrikerFieldLoop
HeroAbilities
ManaburnSpawn
ManaburnAppear
CherryCrush
VoltyCrush
BombPower
BombPowerSpellbookLearn
SupportPowers
BlossomBurst
BlossomBurstConfig
BlossomBurstEffect
StrikerRush
StrikerRushConfig
StrikerRushEffect
PhoenixStorm
Purification
GenesisShield
Melee Initialization
FactionChoice
FactionRevolt
BombardmentPosition
DefenseSignal
AssaultSignal
TO DO
AssaultSignalConfig
AssaultSignalCast
AssaultSignalLoop
BountyHunter
IN GAME AS BOUNTY HUNTER
ReusableMaterialsConfig
ReusableMaterialsKillBlow
TestUnits
level
teststart
ReplaceTest
StrikerTest
GunnerTest
DroneTest
SkystrikerTest
ChromiumTest
BlossomTest
BlademageTest
BlightcleanerTest
GBTest
JATest
Playable
VisionTest
Damage Engine
Damage Engine Config
Damage Engine
Vars
Armor Types
Attack Types
Damage Types
Defense Types
Weapon Types
TimerUtils
TimerUtils
Table
Table
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.
//TESH.scrollpos=84
//TESH.alwaysfold=0

function AAdd takes integer i1, integer i2, integer i3, unit u returns nothing
	if i1 == i2 then
    	    call UnitAddAbilityBJ( i3, u )
    	endif
endfunction

//===========================================================================
// Counts key structures owned by a player and his or her allies, including
// structures currently upgrading or under construction.
//
// Key structures: Town Hall, Great Hall, Tree of Life, Necropolis
//

function LivingPlayerHallsFilter takes nothing returns boolean
    return (IsUnitAliveBJ(GetFilterUnit()) and IsUnitType(GetFilterUnit(),UNIT_TYPE_TOWNHALL))
endfunction

function CountLivingPlayerTownHalls takes player whichPlayer returns integer
    local group g
    local integer matchedCount
    local boolexpr b=Filter(function LivingPlayerHallsFilter)

    set g = CreateGroup()
    call GroupEnumUnitsOfPlayer(g, whichPlayer, b)
    set matchedCount = CountUnitsInGroup(g)
    call DestroyGroup(g)
    call DestroyBoolExpr(b)
    set b=null
    set g=null

    return matchedCount
endfunction

function Custom_MeleeGetAllyKeyStructureCount takes player whichPlayer returns integer
    local integer    playerIndex
    local player     indexPlayer
    local integer    keyStructs

    // Count the number of buildings controlled by all not-yet-defeated co-allies.
    set keyStructs = 0
    set playerIndex = 0
    loop
        set indexPlayer = Player(playerIndex)
        if (PlayersAreCoAllied(whichPlayer, indexPlayer)) then
            set keyStructs = keyStructs + CountLivingPlayerTownHalls(indexPlayer)
        //    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "townhall", true, true)
        //    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "greathall", true, true)
        //    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "treeoflife", true, true)
        //    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "necropolis", true, true)
        //    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h030", true, true)
        //    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h01C", true, true)
        //    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h012", true, true)
        //    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h013", true, true)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h013',indexPlayer)//Never use group functions for this, just count living units for player. Much better idea.
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h014',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h015',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01C',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01E',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01F',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h012',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h02F',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h02J',indexPlayer)
        //    set keyStructs = keySructs + CountLivingPlayerUnitsOfTypeId('h030',indexPlayer)
			
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h000',indexPlayer)//Non-modded human custom ids
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h00D',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h00E',indexPlayer)
			
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00C',indexPlayer)//Non-modded orc custom ids
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00D',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00E',indexPlayer)
			
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00M',indexPlayer)//Non-modded night elf custom ids
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00N',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00O',indexPlayer)
			
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00C',indexPlayer)//Non-modded undead custom ids
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00D',indexPlayer)
        //    set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00E',indexPlayer)
        endif
            
        set playerIndex = playerIndex + 1
        exitwhen playerIndex == bj_MAX_PLAYERS
    endloop

    return keyStructs
endfunction







//===========================================================================
function Custom_MeleePlayerIsCrippled takes player whichPlayer returns boolean
    local integer allyStructures    = MeleeGetAllyStructureCount(whichPlayer)
    local integer allyKeyStructures = Custom_MeleeGetAllyKeyStructureCount(whichPlayer)

    // Dead teams are not considered to be crippled.
    return (allyStructures > 0) and (allyKeyStructures <= 0)
endfunction



//===========================================================================
// Test each player to determine if anyone has become crippled.
//
function Custom_MeleeCheckForCrippledPlayers takes nothing returns nothing
    local integer    playerIndex
    local player     indexPlayer
    local force      crippledPlayers = CreateForce()
    local boolean    isNowCrippled
    local race       indexRace

    // The "finish soon" exposure of all players overrides any "crippled" exposure
    if bj_finishSoonAllExposed then
        return
    endif

    // Check each player to see if he or she has been crippled or uncrippled.
    set playerIndex = 0
    loop
        set indexPlayer = Player(playerIndex)
        set isNowCrippled = Custom_MeleePlayerIsCrippled(indexPlayer)

        if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then

            // Player became crippled; start their cripple timer.
            set bj_playerIsCrippled[playerIndex] = true
            call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeout)

            if (GetLocalPlayer() == indexPlayer) then
                // Use only local code (no net traffic) within this block to avoid desyncs.

                // Show the timer window.
                call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)

                // Display a warning message.
                call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, "|cffffcc00"+udg_RevealWarning+"|r")
            endif

        elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then

            // Player became uncrippled; stop their cripple timer.
            set bj_playerIsCrippled[playerIndex] = false
            call PauseTimer(bj_crippledTimer[playerIndex])

            if (GetLocalPlayer() == indexPlayer) then
                // Use only local code (no net traffic) within this block to avoid desyncs.

                // Hide the timer window for this player.
                call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)

                // Display a confirmation message if the player's team is still alive.
                if (MeleeGetAllyStructureCount(indexPlayer) > 0) then
                    if (bj_playerIsExposed[playerIndex]) then
                        call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
                    else
                        call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
                    endif
                endif
            endif

            // If the player granted shared vision, deny that vision now.
            call MeleeExposePlayer(indexPlayer, false)

        endif
            
        set playerIndex = playerIndex + 1
        exitwhen playerIndex == bj_MAX_PLAYERS
    endloop
endfunction

//===========================================================================
// Determine if the lost unit should result in any defeats or victories.
//
function Custom_MeleeCheckLostUnit takes unit lostUnit returns nothing
    local player lostUnitOwner = GetOwningPlayer(lostUnit)

    // We only need to check for mortality if this was the last building.
    if (GetPlayerStructureCount(lostUnitOwner, true) <= 0) then
        call MeleeCheckForLosersAndVictors()
    endif

    // Check if the lost unit has crippled or uncrippled the player.
    // (A team with 0 units is dead, and thus considered uncrippled.)
    call Custom_MeleeCheckForCrippledPlayers()
endfunction

//===========================================================================
// Determine if the gained unit should result in any defeats, victories,
// or cripple-status changes.
//
function Custom_MeleeCheckAddedUnit takes unit addedUnit returns nothing
    local player addedUnitOwner = GetOwningPlayer(addedUnit)

    // If the player was crippled, this unit may have uncrippled him/her.
    if (bj_playerIsCrippled[GetPlayerId(addedUnitOwner)]) then
        call Custom_MeleeCheckForCrippledPlayers()
    endif
endfunction

//===========================================================================
function Custom_MeleeTriggerActionConstructCancel takes nothing returns nothing
    call Custom_MeleeCheckLostUnit(GetCancelledStructure())
endfunction

//===========================================================================
function Custom_MeleeTriggerActionUnitDeath takes nothing returns nothing
    if (IsUnitType(GetDyingUnit(), UNIT_TYPE_STRUCTURE)) then
        call Custom_MeleeCheckLostUnit(GetDyingUnit())
    endif
endfunction

//===========================================================================
function Custom_MeleeTriggerActionUnitConstructionStart takes nothing returns nothing
    call Custom_MeleeCheckAddedUnit(GetConstructingStructure())
endfunction

//===========================================================================
function Custom_MeleeTriggerActionAllianceChange takes nothing returns nothing
    call MeleeCheckForLosersAndVictors()
    call Custom_MeleeCheckForCrippledPlayers()
endfunction

//===========================================================================
function MeleeInitVictoryDefeatCustomized takes nothing returns nothing
    local trigger trig
    local integer index
    local player indexPlayer

    // Create a timer window for the "finish soon" timeout period, it has no timer
    // because it is driven by real time (outside of the game state to avoid desyncs)
    set bj_finishSoonTimerDialog = CreateTimerDialog(null)

    // Set a trigger to fire when we receive a "finish soon" game event
    set trig = CreateTrigger()
    call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_SOON)
    call TriggerAddAction(trig , function MeleeTriggerTournamentFinishSoon)

    // Set a trigger to fire when we receive a "finish now" game event
    set trig = CreateTrigger()
    call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_NOW)
    call TriggerAddAction(trig , function MeleeTriggerTournamentFinishNow)

    // Set up each player's mortality code.
    set index = 0
    loop
        set indexPlayer = Player(index)

        // Make sure this player slot is playing.
        if ( GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING ) then
            set bj_meleeDefeated[index]=false
            set bj_meleeVictoried[index]=false

            // Create a timer and timer window in case the player is crippled.
            set bj_playerIsCrippled[index]=false
            set bj_playerIsExposed[index]=false
            set bj_crippledTimer[index]=CreateTimer()
            set bj_crippledTimerWindows[index]=CreateTimerDialog(bj_crippledTimer[index])
            call TimerDialogSetTitle(bj_crippledTimerWindows[index] , MeleeGetCrippledTimerMessage(indexPlayer))

            // Set a trigger to fire whenever a building is cancelled for this player.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL , null)
            call TriggerAddAction(trig , function Custom_MeleeTriggerActionConstructCancel)

            // Set a trigger to fire whenever a unit dies for this player.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_DEATH , null)
            call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitDeath)

            // Set a trigger to fire whenever a unit begins construction for this player
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_START , null)
            call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitConstructionStart)

            // Set a trigger to fire whenever this player defeats-out
            set trig = CreateTrigger()
            call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_DEFEAT)
            call TriggerAddAction(trig , function MeleeTriggerActionPlayerDefeated)

            // Set a trigger to fire whenever this player leaves
            set trig = CreateTrigger()
            call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
            call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)

            // Set a trigger to fire whenever this player changes his/her alliances.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerAllianceChange(trig , indexPlayer , ALLIANCE_PASSIVE)
            call TriggerRegisterPlayerStateEvent(trig , indexPlayer , PLAYER_STATE_ALLIED_VICTORY , EQUAL , 1)
            call TriggerAddAction(trig , function Custom_MeleeTriggerActionAllianceChange)
        else
            set bj_meleeDefeated[index]=true
            set bj_meleeVictoried[index]=false

            // Handle leave events for observers
            if ( IsPlayerObserver(indexPlayer) ) then
                // Set a trigger to fire whenever this player leaves
                set trig = CreateTrigger()
                call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
                call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)
            endif
        endif

        set index = index + 1
        exitwhen index == bj_MAX_PLAYERS
    endloop

    // Test for victory / defeat at startup, in case the user has already won / lost.
    // Allow for a short time to pass first, so that the map can finish loading.
    call TimerStart(CreateTimer() , 2.0 , false , function Custom_MeleeTriggerActionAllianceChange)
endfunction

Name Type Is Array Initial Value
AfterDamageEvent real No
AOEDamageEvent real No
AOEDamageSource unit 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
AssaultSignalArmorReduction integer No
AssaultSignalDuration real No
AssaultSignalSFX string No
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
BlossomBurstAbil abilcode No
BlossomBurstPoint location No
BlossomBurstUnit unitcode No
BlossomDrainAmount real No
BlossomGlobalGroup group No
BuildingCount group No
ChromiumBeamPoint location No
ChromiumBeamSFX string No
CONVERTED_ATTACK_TYPE attacktype Yes
CONVERTED_DAMAGE_TYPE damagetype Yes
CrushingFistAbility abilcode No
CrushingFistSFX string No
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
DragonAuraActualAbility abilcode No
DragonAuraBlossomGroup group No
DragonAuraToggleAbility abilcode No
EnhancedDamageTarget unit No
IsDamageCode boolean No
IsDamageMelee boolean No
IsDamageRanged boolean No
IsDamageSpell boolean No
JudasShieldBuff buffcode No
JudgmentAbility abilcode No
JudgmentDamage real No
JudgmentRange real No
JudgmentTempLoc location No
LethalDamageEvent real No
LethalDamageHP real No
MainstayPlayer player No
ManaburnSpawnPoint location No
ManufactoryGroup group Yes
NaniteAuraActualAbility abilcode No
NaniteAuraBlossomGroup group No
NaniteAuraToggleAbility abilcode No
NextDamageType integer No
PlayerRaceDialog dialog Yes
PlayerRaceDialogButton button Yes
ProtocolGroup group Yes
PteneradonAuraActualAbility abilcode No
PteneradonAuraBlossomGroup group No
PteneradonAuraToggleAbility abilcode No
RepairGunActiveGroup group No
RepairGunHeal real No
RepairGunHealArea real No
RepairGunRefreshTime real Yes
RepairGunSFX string No
RepairGunTempLoc location No
RepairGunTempTarget unit No
RepairGunTempUnit unit No
ReprocessorBonusGold integer No
ReprocessorBonusLumber integer No
ReusableBonusGoldRate integer No
ReusableBonusLumberRate integer No
ReusableEarnedResources integer No
ReusableMaterialsBuff buffcode No
ReusablePlayerGroup force No
RevealWarning string No You will be revealed to your opponents unless you build a town hall type building.
RevolutionBuff buffcode No
RevolutionCritChance real No
RevolutionCritMulti real No
SanitariumGroup group Yes
StrikerCount integer No
StrikerGroup group No
StrikerPoint location No
StrikerRushAbil abilcode No
StrikerRushNewUnit unitcode No
StrikerRushPoint location No
StrikerRushSFX string No
SuppressionAuraActualAbility abilcode No
SuppressionAuraToggleAbility abilcode No
SuppressionBlossomGroup group No
SuppressionBuff buffcode No
SuppressionRate real No
TierThreeUnit unit Yes
TierTwoUnit unit 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
ProtocolCenterBuildLimit
  Events
    Map initialization
  Conditions
  Actions
    Player Group - Pick every player in (All players) and do (Actions)
      Loop - Actions
        Player - Limit training of Extreme Protocols Center [Last Revolt] to 1 for (Picked player)
Replace
  Events
    Unit - A unit Finishes construction
  Conditions
    (Unit-type of (Triggering unit)) Equal to Mainstay [Last Revolt - Under Construction]
  Actions
    Unit - Replace (Triggering unit) with a Mainstay [Last Revolt - Ready] using The old unit's relative life and mana
LRTier2
  Events
    Unit - A unit Finishes construction
    Unit - A unit Dies
  Conditions
    Or - Any (Conditions) are true
      Conditions
        (Unit-type of (Triggering unit)) Equal to Manufactory [Last Revolt]
        (Unit-type of (Triggering unit)) Equal to Magi Sanitarium [Last Revolt]
  Actions
    Set VariableSet MainstayPlayer = (Owner of (Triggering unit))
    Set VariableSet ManufactoryGroup[(Player number of MainstayPlayer)] = (Units owned by MainstayPlayer of type Manufactory [Last Revolt])
    Set VariableSet SanitariumGroup[(Player number of MainstayPlayer)] = (Units owned by MainstayPlayer of type Magi Sanitarium [Last Revolt])
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Number of living Manufactory [Last Revolt] units owned by MainstayPlayer) Greater than 0
        (Number of living Magi Sanitarium [Last Revolt] units owned by MainstayPlayer) Greater than 0
        (Number of units in ManufactoryGroup[(Player number of MainstayPlayer)]) Greater than or equal to 1
        (Number of units in SanitariumGroup[(Player number of MainstayPlayer)]) Greater than or equal to 1
      Then - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Number of units in (Units owned by MainstayPlayer of type Tier 2 - Last Revolt)) Equal to 0
          Then - Actions
            Unit - Create 1.Tier 2 - Last Revolt for MainstayPlayer at (Center of (Playable map area)) facing Default building facing degrees
            Set VariableSet TierTwoUnit[(Player number of MainstayPlayer)] = (Last created unit)
          Else - Actions
      Else - Actions
        Unit - Kill TierTwoUnit[(Player number of MainstayPlayer)]
    Custom script: call DestroyGroup(udg_ManufactoryGroup[GetConvertedPlayerId(udg_MainstayPlayer)])
    Custom script: call DestroyGroup(udg_SanitariumGroup[GetConvertedPlayerId(udg_MainstayPlayer)])
LRTier3
  Events
    Unit - A unit Finishes construction
    Unit - A unit Dies
  Conditions
    Or - Any (Conditions) are true
      Conditions
        (Unit-type of (Triggering unit)) Equal to Extreme Protocols Center [Last Revolt]
  Actions
    Set VariableSet MainstayPlayer = (Owner of (Triggering unit))
    Set VariableSet ProtocolGroup[(Player number of MainstayPlayer)] = (Units owned by MainstayPlayer of type Extreme Protocols Center [Last Revolt])
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Number of units in ProtocolGroup[(Player number of MainstayPlayer)]) Greater than or equal to 1
      Then - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Number of units in (Units owned by MainstayPlayer of type Tier 3 - Last Revolt)) Equal to 0
          Then - Actions
            Unit - Create 1.Tier 3 - Last Revolt for MainstayPlayer at (Center of (Playable map area)) facing Default building facing degrees
            Set VariableSet TierThreeUnit[(Player number of MainstayPlayer)] = (Last created unit)
          Else - Actions
      Else - Actions
        Unit - Kill TierThreeUnit[(Player number of MainstayPlayer)]
    Custom script: call DestroyGroup(udg_ProtocolGroup[GetConvertedPlayerId(udg_MainstayPlayer)])
FrostMineTrigger
  Events
    Unit - A unit enters (Entire map)
  Conditions
    (Unit-type of (Triggering unit)) Equal to Frost Mine Dummy
  Actions
    Unit - Order (Triggering unit) to Undead Lich - Frost Nova.(Triggering unit)
PressureConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet SuppressionBuff = Poison (Non-stacking)
    Set VariableSet SuppressionRate = 0.75
PressureEffect
  Events
    Game - DamageModifierEvent becomes Equal to 1.00
  Conditions
    (DamageEventSource has buff SuppressionBuff) Equal to True
  Actions
    Set VariableSet DamageEventAmount = (DamageEventAmount x SuppressionRate)
BlossomDrainConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet BlossomDrainAmount = 2.00
BlossomDrain
  Events
    Time - Every 0.50 seconds of game time
  Conditions
  Actions
    Set VariableSet BlossomGlobalGroup = (Units of type Chromium Blossom [Last Revolt])
    Unit Group - Pick every unit in BlossomGlobalGroup and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            Or - Any (Conditions) are true
              Conditions
                ((Picked unit) is in DragonAuraBlossomGroup.) Equal to True
                ((Picked unit) is in NaniteAuraBlossomGroup.) Equal to True
                ((Picked unit) is in PteneradonAuraBlossomGroup.) Equal to True
                ((Picked unit) is in SuppressionBlossomGroup.) Equal to True
          Then - Actions
            Unit - Set mana of (Picked unit) to ((Mana of (Picked unit)) - BlossomDrainAmount)
          Else - Actions
    Custom script: call DestroyGroup(udg_BlossomGlobalGroup)
OutOfMana
  Events
    Time - Every 0.50 seconds of game time
  Conditions
  Actions
    Set VariableSet BlossomGlobalGroup = (Units of type Chromium Blossom [Last Revolt])
    Unit Group - Pick every unit in BlossomGlobalGroup and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Mana of (Picked unit)) Less than or equal to 0.00
          Then - Actions
            Unit - Remove SuppressionAuraActualAbility from (Picked unit)
            Unit - Remove NaniteAuraActualAbility from (Picked unit)
            Unit - Remove DragonAuraActualAbility from (Picked unit)
            Unit - Remove PteneradonAuraActualAbility from (Picked unit)
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                ((Triggering unit) is in SuppressionBlossomGroup.) Equal to True
              Then - Actions
                Unit Group - Remove (Picked unit) from SuppressionBlossomGroup.
              Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                ((Triggering unit) is in NaniteAuraBlossomGroup.) Equal to True
              Then - Actions
                Unit Group - Remove (Picked unit) from NaniteAuraBlossomGroup.
              Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                ((Triggering unit) is in DragonAuraBlossomGroup.) Equal to True
              Then - Actions
                Unit Group - Remove (Picked unit) from DragonAuraBlossomGroup.
              Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                ((Triggering unit) is in PteneradonAuraBlossomGroup.) Equal to True
              Then - Actions
                Unit Group - Remove (Picked unit) from DragonAuraBlossomGroup.
              Else - Actions
          Else - Actions
    Custom script: call DestroyGroup(udg_BlossomGlobalGroup)
SuppressionAuraConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet SuppressionAuraActualAbility = Suppression Aura [On] [Chromium Blossom]
    Set VariableSet SuppressionAuraToggleAbility = Suppression Aura [Toggle] [Chromium Blossom]
SuppressioonAuraRegister
  Events
    Unit - A unit Begins casting an ability
  Conditions
    (Ability being cast) Equal to SuppressionAuraToggleAbility
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        ((Triggering unit) is in SuppressionBlossomGroup.) Not equal to True
      Then - Actions
        Unit Group - Add (Triggering unit) to SuppressionBlossomGroup
        Unit - Add SuppressionAuraActualAbility to (Triggering unit)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in DragonAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove DragonAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from DragonAuraBlossomGroup.
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in NaniteAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove NaniteAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from NaniteAuraBlossomGroup.
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in PteneradonAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove PteneradonAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from PteneradonAuraBlossomGroup.
          Else - Actions
      Else - Actions
        Unit - Remove SuppressionAuraActualAbility from (Triggering unit)
        Unit Group - Remove (Triggering unit) from SuppressionBlossomGroup.
HealAuraConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet NaniteAuraActualAbility = Nanite Aura [On] [Chromium Blossom]
    Set VariableSet NaniteAuraToggleAbility = Nanite Aura [Toggle] [Chromium Blossom]
HealAuraRegister
  Events
    Unit - A unit Begins casting an ability
  Conditions
    (Ability being cast) Equal to NaniteAuraToggleAbility
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        ((Triggering unit) is in NaniteAuraBlossomGroup.) Not equal to True
      Then - Actions
        Unit Group - Add (Triggering unit) to NaniteAuraBlossomGroup
        Unit - Add NaniteAuraActualAbility to (Triggering unit)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in SuppressionBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove SuppressionAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from SuppressionBlossomGroup.
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in PteneradonAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove PteneradonAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from PteneradonAuraBlossomGroup.
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in DragonAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove DragonAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from DragonAuraBlossomGroup.
          Else - Actions
      Else - Actions
        Unit - Remove NaniteAuraActualAbility from (Triggering unit)
        Unit Group - Remove (Triggering unit) from NaniteAuraBlossomGroup.
DragonAuraConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet DragonAuraActualAbility = Dragon Aura [On] [Chromium Blossom]
    Set VariableSet DragonAuraToggleAbility = Dragon Aura [Toggle] [Chromium Blossom]
DragonAuraRegister
  Events
    Unit - A unit Begins casting an ability
  Conditions
    (Ability being cast) Equal to DragonAuraToggleAbility
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        ((Triggering unit) is in DragonAuraBlossomGroup.) Not equal to True
      Then - Actions
        Unit Group - Add (Triggering unit) to DragonAuraBlossomGroup
        Unit - Add DragonAuraActualAbility to (Triggering unit)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in SuppressionBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove SuppressionAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from SuppressionBlossomGroup.
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in NaniteAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove NaniteAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from NaniteAuraBlossomGroup.
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in PteneradonAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove PteneradonAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from PteneradonAuraBlossomGroup.
          Else - Actions
      Else - Actions
        Unit - Remove DragonAuraActualAbility from (Triggering unit)
        Unit Group - Remove (Triggering unit) from DragonAuraBlossomGroup.
PteneradonAuraConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet PteneradonAuraActualAbility = Pteranodon Aura [On] [Chromium Blossom]
    Set VariableSet PteneradonAuraToggleAbility = Pteranodon Aura [Toggle] [Chromium Blossom]
PteneradonAuraRegister
  Events
    Unit - A unit Begins casting an ability
  Conditions
    (Ability being cast) Equal to PteneradonAuraToggleAbility
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        ((Triggering unit) is in PteneradonAuraBlossomGroup.) Not equal to True
      Then - Actions
        Unit Group - Add (Triggering unit) to PteneradonAuraBlossomGroup
        Unit - Add PteneradonAuraActualAbility to (Triggering unit)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in SuppressionBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove SuppressionAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from SuppressionBlossomGroup.
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in NaniteAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove NaniteAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from NaniteAuraBlossomGroup.
          Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Triggering unit) is in DragonAuraBlossomGroup.) Equal to True
          Then - Actions
            Unit - Remove DragonAuraActualAbility from (Triggering unit)
            Unit Group - Remove (Triggering unit) from DragonAuraBlossomGroup.
          Else - Actions
      Else - Actions
        Unit - Remove PteneradonAuraActualAbility from (Triggering unit)
        Unit Group - Remove (Triggering unit) from PteneradonAuraBlossomGroup.
ReprocessorConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet ReprocessorBonusGold = 15
    Set VariableSet ReprocessorBonusLumber = 5
ReprocessorKillBlow
  Events
    Unit - A unit Dies
  Conditions
    ((Triggering unit) is A structure) Equal to False
    ((Killing unit) belongs to an enemy of (Triggering player).) Equal to True
    (Number of living Reprocessing Center [Last Revolt] units owned by (Owner of (Killing unit))) Greater than 0
  Actions
    Set VariableSet ReusablePlayerGroup = (All allies of (Owner of (Killing unit)).)
    -------- Add Gold --------
    Set VariableSet ReusableEarnedResources = ReprocessorBonusGold
    Player - Add ReusableEarnedResources to (Owner of (Killing unit)).Current gold
    Floating Text - Create floating text that reads (+ + (String(ReusableEarnedResources))) above (Triggering unit) with Z offset 32.00, using font size 10, color (100.00%, 84.30%, 0.00%), and 0% transparency
    Floating Text - Show (Last created floating text) for ReusablePlayerGroup
    Floating Text - Set the velocity of (Last created floating text) to 64 towards 90 degrees
    Floating Text - Change (Last created floating text): Disable permanence
    Floating Text - Change the lifespan of (Last created floating text) to 6.00 seconds
    Floating Text - Change the fading age of (Last created floating text) to 4 seconds
    -------- Add Lumber --------
    Set VariableSet ReusableEarnedResources = ReprocessorBonusLumber
    Player - Add ReusableEarnedResources to (Owner of (Killing unit)).Current lumber
    Floating Text - Create floating text that reads (+ + (String(ReusableEarnedResources))) above (Triggering unit) with Z offset 0, using font size 10, color (13.30%, 54.50%, 13.30%), and 0% transparency
    Floating Text - Show (Last created floating text) for ReusablePlayerGroup
    Floating Text - Set the velocity of (Last created floating text) to 64 towards 90 degrees
    Floating Text - Change (Last created floating text): Disable permanence
    Floating Text - Change the lifespan of (Last created floating text) to 6.00 seconds
    Floating Text - Change the fading age of (Last created floating text) to 4 seconds
    Custom script: call DestroyForce(udg_ReusablePlayerGroup)
RevolutionConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet RevolutionBuff = Revolution
    Set VariableSet RevolutionCritChance = 20.00
    Set VariableSet RevolutionCritMulti = 2.50
RevolutionDamage
  Events
    Game - DamageModifierEvent becomes Equal to 1.00
  Conditions
    (DamageEventSource has buff RevolutionBuff) Equal to True
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Random real number between 0 and 100.00) Less than or equal to RevolutionCritChance
      Then - Actions
        Set VariableSet DamageEventAmount = (DamageEventAmount x RevolutionCritMulti)
        Floating Text - Create floating text that reads ((String(DamageEventAmount)) + !) above DamageEventSource with Z offset 0, using font size 12.00, color (100%, 0.00%, 0.00%), and 0% transparency
        Floating Text - Show (Last created floating text) for (All players)
        Floating Text - Set the velocity of (Last created floating text) to 64 towards 90 degrees
        Floating Text - Change (Last created floating text): Disable permanence
        Floating Text - Change the fading age of (Last created floating text) to 4 seconds
        Floating Text - Change the lifespan of (Last created floating text) to 5.00 seconds
      Else - Actions
JudgmentConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet JudgmentAbility = Judgment [Last Revolt]
    Set VariableSet JudgmentRange = 300.00
    Set VariableSet JudgmentDamage = 250.00
Judgment
  Events
    Unit - A unit Starts the effect of an ability
  Conditions
    (Ability being cast) Equal to JudgmentAbility
  Actions
    Set VariableSet JudgmentTempLoc = (Target point of ability being cast)
    Custom script: set bj_wantDestroyGroup = true
    Unit Group - Pick every unit in (Units within JudgmentRange of JudgmentTempLoc.) and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Picked unit) is alive) Equal to True
          Then - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                ((Picked unit) belongs to an enemy of (Owner of (Triggering unit)).) Equal to True
              Then - Actions
                Special Effect - Create a special effect attached to the origin (attachpoint) of (Picked unit) using Abilities\Spells\Human\HolyBolt\HolyBoltSpecialArt.mdl
                Unit - Cause (Triggering unit) to damage (Picked unit), dealing JudgmentDamage damage of attack type Spells and damage type Normal
              Else - Actions
                Special Effect - Create a special effect attached to the origin (attachpoint) of (Picked unit) using Abilities\Spells\Orc\HealingWave\HealingWaveTarget.mdl
                Unit - Set life of (Picked unit) to ((Life of (Picked unit)) + (JudgmentDamage / 2.00))
          Else - Actions
        Special Effect - Destroy (Last created special effect)
    Custom script: call RemoveLocation(udg_JudgmentTempLoc)
RepairGunConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet RepairGunHeal = 12.00
    Set VariableSet RepairGunHealArea = 500.00
    Set VariableSet RepairGunSFX = Abilities\Weapons\Bolt\BoltImpact.mdl
RepairGunRegister
  Events
    Unit - A unit enters (Playable map area)
  Conditions
    (Unit-type of (Triggering unit)) Equal to
  Actions
    Unit Group - Add (Triggering unit) to RepairGunActiveGroup
RepairGunLoop
  Events
    Time - Every 1.00 seconds of game time
  Conditions
  Actions
    Unit Group - Pick every unit in RepairGunActiveGroup and do (Actions)
      Loop - Actions
        Custom script: set bj_wantDestroyGroup = true
        Set VariableSet RepairGunTempUnit = (Picked unit)
        Set VariableSet RepairGunTempLoc = (Position of RepairGunTempUnit)
        Set VariableSet RepairGunTempTarget = No unit
        Unit Group - Pick every unit in (Units within RepairGunHealArea of RepairGunTempLoc.) and do (Actions)
          Loop - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                (Picked unit) Not equal to RepairGunTempUnit
                ((Picked unit) is A structure) Equal to False
                ((Picked unit) is Mechanical) Equal to True
                (Life of (Picked unit)) Less than (Max life of (Picked unit))
              Then - Actions
                Set VariableSet RepairGunTempTarget = (Picked unit)
              Else - Actions
        Unit - Set life of RepairGunTempTarget to ((Life of RepairGunTempTarget) + RepairGunHeal)
        Special Effect - Create a special effect attached to the origin (attachpoint) of RepairGunTempTarget using RepairGunSFX
        Special Effect - Destroy (Last created special effect)
CrushingFistConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet CrushingFistAbility = Crushing Fist [Thundergunner]
    Set VariableSet CrushingFistSFX = Abilities\Weapons\Bolt\BoltImpact.mdl
CrushingFist
  Events
    Unit - A unit Starts the effect of an ability
  Conditions
    (Ability being cast) Equal to CrushingFistAbility
  Actions
    Unit - Set Armor of (Target unit of ability being cast) to 0.00
    Special Effect - Create a special effect attached to the origin (attachpoint) of (Target unit of ability being cast) using CrushingFistSFX
    Special Effect - Destroy (Last created special effect)
    Unit - Remove CrushingFistAbility from (Triggering unit)
JudasShieldConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet JudasShieldBuff = Divine Shield
JudasShield
  Events
    Game - DamageModifierEvent becomes Equal to 1.00
  Conditions
    (DamageEventTarget has buff JudasShieldBuff) Equal to True
  Actions
    Set VariableSet DamageEventAmount = 0.00
ChromiumBeamConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet ChromiumBeamSFX = Abilities\Spells\Human\MassTeleport\MassTeleportTarget.mdl
ChromiumBeam
  Events
    Unit - A unit Dies
  Conditions
    (Unit-type of (Killing unit)) Equal to Chromium Suppressor Tank [Last Revolt] [Deprecated]
  Actions
    Set VariableSet ChromiumBeamPoint = (Position of (Triggering unit))
    Special Effect - Create a special effect at ChromiumBeamPoint using ChromiumBeamSFX
    Special Effect - Destroy (Last created special effect)
    Unit - Remove (Triggering unit) from the game
    Custom script: call RemoveLocation(udg_ChromiumBeamPoint)
StrikerFieldRegister
  Events
    Unit - A unit enters (Playable map area)
  Conditions
    (Unit-type of (Triggering unit)) Equal to Striker [Last Revolt]
  Actions
    Unit Group - Add (Triggering unit) to StrikerGroup
StrikerFieldRegister2
  Events
    Time - Elapsed game time is 0.03 seconds
  Conditions
  Actions
    Unit Group - Pick every unit in (Units in (Entire map)) and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Unit-type of (Picked unit)) Equal to Striker [Last Revolt]
          Then - Actions
            Unit Group - Add (Triggering unit) to StrikerGroup
          Else - Actions
StrikerFieldLoop
  Events
    Time - Every 1.00 seconds of game time
  Conditions
  Actions
    Unit Group - Pick every unit in StrikerGroup and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Picked unit) is alive) Equal to True
          Then - Actions
            Set VariableSet StrikerCount = 0
            Set VariableSet StrikerPoint = (Position of (Picked unit))
            Custom script: set bj_wantDestroyGroup = true
            Unit Group - Pick every unit in (Units within 400.00 of StrikerPoint.) and do (Actions)
              Loop - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  If - Conditions
                    ((Picked unit) is alive) Equal to True
                  Then - Actions
                    Set VariableSet StrikerCount = (StrikerCount + 1)
                  Else - Actions
            Custom script: call RemoveLocation(udg_StrikerPoint)
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                StrikerCount Greater than 30
              Then - Actions
                Set VariableSet StrikerCount = 30
              Else - Actions
            Unit - Set level of Striker Field [Striker] for (Picked unit) to StrikerCount
          Else - Actions
            Unit Group - Remove (Picked unit) from StrikerGroup.
ManaburnAppear
  Events
    Unit - A unit Begins casting an ability
  Conditions
    (Ability being cast) Equal to Manaburn Core
  Actions
    Set VariableSet ManaburnSpawnPoint = (Target point of ability being cast)
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Level of Manaburn Core for (Triggering unit)) Equal to 1
      Then - Actions
        Unit - Create 1.Manaburn Core [Level 1] for (Owner of (Triggering unit)) at ManaburnSpawnPoint facing Default building facing degrees
      Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Level of Manaburn Core for (Triggering unit)) Equal to 2
          Then - Actions
            Unit - Create 1.Manaburn Core [Level 2] for (Owner of (Triggering unit)) at ManaburnSpawnPoint facing Default building facing degrees
          Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                (Level of Manaburn Core for (Triggering unit)) Equal to 3
              Then - Actions
                Unit - Create 1.Manaburn Core [Level 3] for (Owner of (Triggering unit)) at ManaburnSpawnPoint facing Default building facing degrees
              Else - Actions
    Custom script: call RemoveLocation(udg_ManaburnSpawnPoint)
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
-------------Volty Crush 1.3 by Adiktuz---------------------------------

 What is Volty Crush?
    -By default its an ability which inflicts the target with a magical curse which explodes after a set time
     damaging the target, and any unit near it. Also deals damage to the target during the duration
 
 Requirements
     -Warcraft 3 - TFT (1.24e and up)
     -NewGenWE (comes with the JNGP)
     -Jass Helper (0.A.2.A or 0.A.2.B)
     -Basic editor knowledge
     
 How to import
    -Open your map in NewGenWE
    -Create a new trigger and convert it to custom script
    -Copy this library and paste it into the new trigger, replacing anything inside that trigger
    -Modify the modifiable globals and functions to fit the new map or settings that you would like
    -You can copy the ability or just make a new one
    -Copy the buff ability and the buff and modify the rawcodes here (if you would create a new buff, Use slow aura as a base for the buff ability)
   
 How to use
    -Once you have done the steps on importing, you're good to go.
   
 Credits:
    -Vexorian For TimerUtils
    -Bribe for Table
*/

library VoltyCrush requires TimerUtils, Table

    globals
        //Rawcode of the spell
        private constant integer SPELL_ID = 'AFvc'
       
        //Rawcode of the buff ability
        private constant integer BUFF_SPELL_ID = 'Abvc'
       
        //Rawcode of the buff itself
        private constant integer BUFF_ID = 'Bbvc'
       
        //The path to the special effect which is shown on the unit every tick
        private constant string TICK_FX = "Abilities\\Weapons\\PrismaticSakura\\PrismaticSakura.mdl"
       
        //The path to the special effect when the ability explodes
        private constant string EXPLODE_FX = "Abilities\\Spells\\LastRevolt\\ArcaneExplosion\\ArcaneExplosion.mdl"
       
        //The path to the special effect shown on the units that will get hit by the explosion
        private constant string TARGET_FX = "Abilities\\Spells\\Undead\\DeathPact\\DeathPactTarget.mdl"
       
        //The attachment point of TICK_FX
        private constant string TICK_AP = "chest"
       
        //The attachment point of EXPLODE_FX
        private constant string EXPLODE_AP = "origin"
       
        //The attachment point of TARGET_FX
        private constant string TARGET_AP = "chest"
       
        //this is the timer interval in which duration damage takes place
        private constant real TICK = 0.50
       
        //The attack type of the spell
        private constant attacktype AT = ATTACK_TYPE_MAGIC
       
        //The damage type of the spell
        private constant damagetype DT = DAMAGE_TYPE_MAGIC
       
        //Checks whether the curses will explode upon death of target or just fade away
        private constant boolean ExUponDeath = true
       
        private Table VoltyTab
    endglobals
   
    //Use this function to calculate the duration of the curse before it explodes
    private function GetTime takes integer level returns real
        return level + 2.00 + 1.00
    endfunction
   
    //Use this function to get the explosion radius - default 100.00 + level*(25)
    private function GetRadius takes integer level returns real
        return 160.00
    endfunction
   
    //Use this function to calculate the damage per tick
    private function GetTickDamage takes integer level returns real
        return 20*TICK
    endfunction
   
    //Use this function to calculate the explosion damage to the target
    private function GetExploTargetDamage takes integer level returns real
        return level*100.00
    endfunction
   
    //Use this function to calculate the explosion damage to the units around the target
    private function GetExploAoeDamage takes integer level returns real
        return level*70.00
    endfunction
   
    //The initialization module... I used a module for init because Nestharus said that its better
    private module init
   
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            local integer i = 0
            loop
                exitwhen i > 15
                call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
                set i = i + 1
            endloop
            call TriggerAddCondition(t, Condition(function thistype.FilterFunction))
            set VoltyTab = Table.create()
            set t = null
        endmethod
   
    endmodule
   
    //The struct for the spell
    private struct VoltyStruct
       
        //We implement the module here
        implement init
       
        //The struct data holders
        static thistype data
        static thistype datum
        static thistype datab
        static group dgroup = CreateGroup()
        static unit triggerunit = null
        unit target
        unit caster
        player owner
        integer level
        real time
       
        //This method runs when a curse finishes and checks if the unit has other instances of the spell, if none it removes the buff
        method RemoveBuff takes nothing returns nothing
            if VoltyTab[GetHandleId(this.target)] == 0 then
                /*I remove both the ability and the buff since if only the ability is removed,
                  the buff will stay for about 2 seconds...
                */

                call UnitRemoveAbility(this.target, BUFF_SPELL_ID)
                call UnitRemoveAbility(this.target, BUFF_ID)
            endif
        endmethod
       
        //This method is for dealing the damage into the unit
        method OnHit takes unit fu returns nothing
            if fu != this.target then
                call DestroyEffect(AddSpecialEffectTarget(TARGET_FX, fu, TARGET_AP))
                call UnitDamageTarget(this.caster, fu, GetExploAoeDamage(this.level), false, false, AT, DT, null)
            else
                call UnitDamageTarget(this.caster, fu, GetExploTargetDamage(this.level), false, false, AT, DT, null)
            endif
        endmethod
       
        //The filter for the group pick, I merged the actions to the group filter for better performance
        static method OnHitFilter takes nothing returns boolean
            local unit fu = GetFilterUnit()
            if IsUnitEnemy(fu, datab.owner) and /*
            */
GetWidgetLife(fu) > .405 and /*
            just for double checking...
            */
(not IsUnitType(fu, UNIT_TYPE_DEAD)) and /*
            */
not IsUnitType(fu, UNIT_TYPE_STRUCTURE) then
                call datab.OnHit(fu)
            endif
            set fu = null
            return false
        endmethod
       
        //the method run when the timer reaches 0.00 or when the target dies
        method OnExplode takes boolean dead returns nothing
            //This checks if the unit is dead and whether death is registered as a cause of explosion
            if not (dead and not ExUponDeath) then
                call GroupEnumUnitsInRange(thistype.dgroup, GetUnitX(this.target), GetUnitY(this.target), GetRadius(this.level), Condition(function thistype.OnHitFilter) )
                call DestroyEffect(AddSpecialEffectTarget(EXPLODE_FX, this.target, EXPLODE_AP))
            endif
        endmethod
       
        //The method which is run after each interval
        private static method Refresh takes nothing returns nothing
            local boolean dead = false
            set datab = GetTimerData(GetExpiredTimer())
            set datab.time = datab.time - TICK
            set dead = GetWidgetLife(datab.target) < .405
            call DestroyEffect(AddSpecialEffectTarget(TICK_FX, datab.target, TICK_AP))
            call UnitDamageTarget(datab.caster, datab.target, GetTickDamage(datab.level), false, false, AT, DT, null)
            if datab.time <= 0.00 or dead then
                set VoltyTab[GetHandleId(datab.target)] = VoltyTab[GetHandleId(datab.target)] - 1
                call datab.OnExplode(dead)
                call datab.RemoveBuff()
                call datab.destroy()
                call ReleaseTimer(GetExpiredTimer())
            endif
        endmethod
       
        //The method run when the spell VoltyCrush is used
        private static method create takes unit caster, unit target, integer level , player owner returns thistype
            local timer t = NewTimer()
            set data = thistype.allocate()
            set data.target = target
            set data.level = level
            set data.owner = owner
            set data.caster = caster
            set data.time = GetTime(level)
            call UnitAddAbility(target, BUFF_SPELL_ID)
            call SetTimerData(t, data)
            call TimerStart(t, TICK, true, function thistype.Refresh)
            set VoltyTab[GetHandleId(target)] = VoltyTab[GetHandleId(target)] + 1
            set t = null
            return data
        endmethod
       
        //The filter function used by the trigger, this also contains the actions for the spell
        private static method FilterFunction takes nothing returns boolean
            set thistype.triggerunit = GetTriggerUnit()
            if GetSpellAbilityId() == SPELL_ID then
                call thistype.create( thistype.triggerunit, GetSpellTargetUnit(), GetUnitAbilityLevel(thistype.triggerunit, SPELL_ID), GetOwningPlayer(thistype.triggerunit))
            endif
            return false
        endmethod
       
    endstruct
   
endlibrary
BombPowerSpellbookLearn
  Events
    Unit - A unit Learns a skill
  Conditions
    (Learned Hero Skill) Equal to Bomb Power [New]
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Level of Bomb Power [New] for (Triggering unit)) Equal to 1
      Then - Actions
        Unit - Add Bomb Power Cherrymite Bonus [Cherrybomber] to (Triggering unit)
      Else - Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Level of Bomb Power [New] for (Triggering unit)) Equal to 2
      Then - Actions
        Unit - Remove Bomb Power Cherrymite Bonus [Cherrybomber] from (Triggering unit)
        Unit - Add Bomb Power Cherrymite Bonus 2 [Cherrybomber] to (Triggering unit)
      Else - Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Level of Bomb Power [New] for (Triggering unit)) Equal to 3
      Then - Actions
        Unit - Remove Bomb Power Cherrymite Bonus 2 [Cherrybomber] from (Triggering unit)
        Unit - Add Bomb Power Cherrymite Bonus 3 [Cherrybomber] to (Triggering unit)
      Else - Actions
BlossomBurstConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet BlossomBurstAbil = Blossom Burst [Support Power]
    Set VariableSet BlossomBurstUnit = Chromium Blossom [Last Revolt]
BlossomBurstEffect
  Events
    Unit - A unit Starts the effect of an ability
  Conditions
    (Ability being cast) Equal to BlossomBurstAbil
  Actions
    Custom script: set bj_wantDestroyGroup = true
    Unit Group - Pick every unit in (Units of type Chromium Blossom [Last Revolt]) and do (Actions)
      Loop - Actions
        Set VariableSet BlossomBurstPoint = (Position of (Picked unit))
        Unit - Cause (Picked unit) to damage circular area after 0 seconds of radius 512.00 at BlossomBurstPoint, dealing 50.00 damage of attack type Spells and damage type Normal
        Special Effect - Create a special effect attached to the origin (attachpoint) of (Picked unit) using Objects\Spawnmodels\NightElf\NECancelDeath\NECancelDeath.mdl
        Special Effect - Destroy (Last created special effect)
        Custom script: call RemoveLocation(udg_BlossomBurstPoint)
StrikerRushConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet StrikerRushAbil = Striker Rush [Support Power]
    Set VariableSet StrikerRushNewUnit = Elite Striker [Last Revolt]
    Set VariableSet StrikerRushSFX = Abilities\Spells\Undead\DarkRitual\DarkRitualTarget.mdl
StrikerRushEffect
  Events
    Unit - A unit Starts the effect of an ability
  Conditions
    (Ability being cast) Equal to StrikerRushAbil
  Actions
    Set VariableSet StrikerRushPoint = (Target point of ability being cast)
    Custom script: set bj_wantDestroyGroup = true
    Unit Group - Pick every unit in (Units within 512.00 of StrikerRushPoint.) and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Unit-type of (Picked unit)) Equal to Striker [Last Revolt]
          Then - Actions
            Special Effect - Create a special effect attached to the origin (attachpoint) of (Picked unit) using StrikerRushSFX
            Special Effect - Destroy (Last created special effect)
            Unit - Replace (Picked unit) with a StrikerRushNewUnit using The new unit's max life and mana
          Else - Actions
    Custom script: call RemoveLocation(udg_StrikerRushPoint)
Default melee game initialization for all players
Melee Initialization
  Events
    Map initialization
  Conditions
  Actions
    Melee Game - Use melee time of day (for all players)
    Melee Game - Limit Heroes to 1 per Hero-type (for all players)
    Melee Game - Give trained Heroes a Scroll of Town Portal (for all players)
    Melee Game - Set starting resources (for all players)
    Melee Game - Remove creeps and critters from used start locations (for all players)
    Melee Game - Create starting units (for all players)
    Melee Game - Run melee AI scripts (for computer players)
    Custom script: call MeleeInitVictoryDefeatCustomized()
    -------- For the Last Revolt --------
    Player Group - Pick every player in (All players) and do (Actions)
      Loop - Actions
        Player - Limit training of Lurking Phantom [Unused For Now] to 1 for (Picked player)
        Player - Limit training of Artificer to 1 for (Picked player)
        Player - Limit training of Cherrybomber to 1 for (Picked player)
FactionChoice
  Events
    Time - Elapsed game time is 0.20 seconds
  Conditions
  Actions
    For each (Integer A) from 1 to 24, do (Actions)
      Loop - Actions
        Dialog - Change the title of PlayerRaceDialog[(Integer A)] to Play as the Last Revolt?
        Dialog - Create a dialog button for PlayerRaceDialog[(Integer A)] labelled |cff7ebff1Human Alliance|r
        Set VariableSet PlayerRaceDialogButton[((((Integer A) - 1) x 2) + 0)] = (Last created dialog Button)
        Dialog - Create a dialog button for PlayerRaceDialog[(Integer A)] labelled |cff98fb98Last Revolt|r
        Set VariableSet PlayerRaceDialogButton[((((Integer A) - 1) x 2) + 1)] = (Last created dialog Button)
    Player Group - Pick every player in (All players matching (((Matching player) slot status) Equal to Is playing).) and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            And - All (Conditions) are true
              Conditions
                ((Picked player) Food used) Less than or equal to 5
                (Race of (Picked player)) Equal to Human
                ((Picked player) controller) Equal to User
          Then - Actions
            Dialog - Show PlayerRaceDialog[(Player number of (Picked player))] for (Picked player)
          Else - Actions
FactionRevolt
  Events
    Dialog - A dialog button is clicked for PlayerRaceDialog[1]
    Dialog - A dialog button is clicked for PlayerRaceDialog[2]
    Dialog - A dialog button is clicked for PlayerRaceDialog[3]
    Dialog - A dialog button is clicked for PlayerRaceDialog[4]
    Dialog - A dialog button is clicked for PlayerRaceDialog[5]
    Dialog - A dialog button is clicked for PlayerRaceDialog[6]
    Dialog - A dialog button is clicked for PlayerRaceDialog[7]
    Dialog - A dialog button is clicked for PlayerRaceDialog[8]
    Dialog - A dialog button is clicked for PlayerRaceDialog[9]
    Dialog - A dialog button is clicked for PlayerRaceDialog[10]
    Dialog - A dialog button is clicked for PlayerRaceDialog[11]
    Dialog - A dialog button is clicked for PlayerRaceDialog[12]
    Dialog - A dialog button is clicked for PlayerRaceDialog[13]
    Dialog - A dialog button is clicked for PlayerRaceDialog[14]
    Dialog - A dialog button is clicked for PlayerRaceDialog[15]
    Dialog - A dialog button is clicked for PlayerRaceDialog[16]
    Dialog - A dialog button is clicked for PlayerRaceDialog[17]
    Dialog - A dialog button is clicked for PlayerRaceDialog[18]
    Dialog - A dialog button is clicked for PlayerRaceDialog[19]
    Dialog - A dialog button is clicked for PlayerRaceDialog[20]
    Dialog - A dialog button is clicked for PlayerRaceDialog[21]
    Dialog - A dialog button is clicked for PlayerRaceDialog[22]
    Dialog - A dialog button is clicked for PlayerRaceDialog[23]
    Dialog - A dialog button is clicked for PlayerRaceDialog[24]
  Conditions
  Actions
    For each (Integer A) from 1 to 24, do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            (Clicked dialog button) Equal to PlayerRaceDialogButton[((((Integer A) - 1) x 2) + 1)]
          Then - Actions
            Custom script: set bj_wantDestroyGroup=true
            Unit Group - Pick every unit in (Units owned by (Triggering player).) and do (Actions)
              Loop - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  If - Conditions
                    (Unit-type of (Picked unit)) Equal to Peasant
                  Then - Actions
                    Unit - Replace (Picked unit) with a Craftsdrone [Last Revolt] using The new unit's default life and mana
                  Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  If - Conditions
                    (Unit-type of (Picked unit)) Equal to Town Hall
                  Then - Actions
                    Unit - Replace (Picked unit) with a Mainstay [Last Revolt - Ready] using The new unit's default life and mana
                  Else - Actions
          Else - Actions
AssaultSignalConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet AssaultSignalArmorReduction = 10
    Set VariableSet AssaultSignalDuration = 15.00
    Set VariableSet AssaultSignalSFX =
AssaultSignalCast
  Events
  Conditions
  Actions
AssaultSignalLoop
  Events
  Conditions
  Actions
ReusableMaterialsConfig
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet ReusableMaterialsBuff = Bounty Hunter
    Set VariableSet ReusableBonusGoldRate = 80
    Set VariableSet ReusableBonusGoldRate = 30
ReusableMaterialsKillBlow
  Events
    Unit - A unit Dies
  Conditions
    ((Triggering unit) has buff ReusableMaterialsBuff) Equal to True
    ((Killing unit) belongs to an enemy of (Triggering player).) Equal to True
  Actions
    Set VariableSet ReusablePlayerGroup = (All allies of (Owner of (Killing unit)).)
    -------- Add Gold --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        ((Triggering unit) is A Hero) Equal to True
      Then - Actions
        Set VariableSet ReusableEarnedResources = ((Hero level of (Triggering unit)) x ReusableBonusGoldRate)
      Else - Actions
        Set VariableSet ReusableEarnedResources = ((Level of (Triggering unit)) x ReusableBonusGoldRate)
    Player - Add ReusableEarnedResources to (Owner of (Killing unit)).Current gold
    Floating Text - Create floating text that reads (+ + (String(ReusableEarnedResources))) above (Triggering unit) with Z offset 32.00, using font size 10, color (100.00%, 84.30%, 0.00%), and 0% transparency
    Floating Text - Show (Last created floating text) for ReusablePlayerGroup
    Floating Text - Set the velocity of (Last created floating text) to 64 towards 90 degrees
    Floating Text - Change (Last created floating text): Disable permanence
    Floating Text - Change the lifespan of (Last created floating text) to 6.00 seconds
    Floating Text - Change the fading age of (Last created floating text) to 4 seconds
    -------- Add Lumber --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        ((Triggering unit) is A Hero) Equal to True
      Then - Actions
        Set VariableSet ReusableEarnedResources = ((Hero level of (Triggering unit)) x ReusableBonusLumberRate)
      Else - Actions
        Set VariableSet ReusableEarnedResources = ((Level of (Triggering unit)) x ReusableBonusLumberRate)
    Player - Add ReusableEarnedResources to (Owner of (Killing unit)).Current lumber
    Floating Text - Create floating text that reads (+ + (String(ReusableEarnedResources))) above (Triggering unit) with Z offset 0, using font size 10, color (13.30%, 54.50%, 13.30%), and 0% transparency
    Floating Text - Show (Last created floating text) for ReusablePlayerGroup
    Floating Text - Set the velocity of (Last created floating text) to 64 towards 90 degrees
    Floating Text - Change (Last created floating text): Disable permanence
    Floating Text - Change the lifespan of (Last created floating text) to 6.00 seconds
    Floating Text - Change the fading age of (Last created floating text) to 4 seconds
    Custom script: call DestroyForce(udg_ReusablePlayerGroup)
level
  Events
    Player - Player 1 (Red) types a chat message containing level (stringnoformat) as An exact match
  Conditions
  Actions
    Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
      Loop - Actions
        Hero - Set (Picked unit) Hero-level to ((Hero level of (Picked unit)) + 1), Show level-up graphics
        Custom script: set bj_wantDestroyGroup = true
teststart
  Events
    Time - Elapsed game time is 0.00 seconds
  Conditions
  Actions
    Camera - .Apply. gg_cam_Camera_002 for Player 1 (Red) over 0 seconds
ReplaceTest
  Events
    Time - Elapsed game time is 0.05 seconds
  Conditions
  Actions
    Unit Group - Pick every unit in (Units owned by Player 1 (Red) of type Town Hall) and do (Actions)
      Loop - Actions
        Unit - Replace (Picked unit) with a Mainstay [Last Revolt - Ready] using The old unit's relative life and mana
    Unit Group - Pick every unit in (Units owned by Player 1 (Red) of type Peasant) and do (Actions)
      Loop - Actions
        Unit - Replace (Picked unit) with a Craftsdrone [Last Revolt] using The old unit's relative life and mana
StrikerTest
  Events
    Player - Player 1 (Red) types a chat message containing -t1 (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 3.Striker [Last Revolt] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
GunnerTest
  Events
    Player - Player 1 (Red) types a chat message containing -t1r (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 3.Thundergunner [Last Revolt] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
DroneTest
  Events
    Player - Player 1 (Red) types a chat message containing -w (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 1. for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
    Unit - Set life of (Last created unit) to 1.00%
SkystrikerTest
  Events
    Player - Player 1 (Red) types a chat message containing -ss (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 1.Phoenix Skystriker [Last Revolt] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
ChromiumTest
  Events
    Player - Player 1 (Red) types a chat message containing -ch (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 1.Chromium Suppressor Tank [Last Revolt] [Deprecated] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
BlossomTest
  Events
    Player - Player 1 (Red) types a chat message containing -chn (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 1.Chromium Blossom [Last Revolt] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
BlademageTest
  Events
    Player - Player 1 (Red) types a chat message containing -bm (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 3.Blademage [Last Revolt] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
    Player - Set the current research level of R002 (techcode) to 2 for Player 1 (Red)
BlightcleanerTest
  Events
    Player - Player 1 (Red) types a chat message containing -bc (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 3.Blightcleaner [Last Revolt] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
    Player - Set the current research level of Rfbt (techcode) to 2 for Player 1 (Red)
GBTest
  Events
    Player - Player 1 (Red) types a chat message containing -gb (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 1.Genesis Blade [Last Revolt] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
JATest
  Events
    Player - Player 1 (Red) types a chat message containing -ja (stringnoformat) as An exact match
  Conditions
  Actions
    Unit - Create 1.Judas Artillery [Last Revolt] for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
Playable
  Events
    Unit - A unit enters (Playable map area)
  Conditions
  Actions
    Game - Display to (All players) the text: (Name of (Triggering unit))
VisionTest
  Events
    Map initialization
  Conditions
  Actions
    Visibility - Disable fog of war
    Visibility - Disable black mask
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
    -------- - --------
    Custom script: call DamageEngine_DebugStr()
//===========================================================================
//  
//  Damage Engine 5.4.2.3 - update requires copying of the JASS script
//  
//===========================================================================
library DamageEngine initializer Init
   
globals
    private timer   alarm       = CreateTimer()
    private boolean alarmSet    = false
   
    //Values to track the original pre-spirit Link/defensive damage values
    private boolean canKick         = true
    private boolean totem           = false
    private real lastAmount         = 0.00
    private real lastPrevAmt        = 0.00
    private integer lastType        = 0  
    private boolean lastCode        = false
    private real lastPierced        = 0.00
    private integer armorType       = 0
    private integer lastArmor       = 0
    private integer lastPrevArmor   = 0
    private integer defenseType     = 0
    private integer lastDefense     = 0
    private integer lastPrevDefense = 0
   
    //Stuff to track recursive UnitDamageTarget calls.
    private boolean eventsRun       = false
    private boolean kicking         = false
    private integer damageStack     = 0
    private unit array sourceStack
    private unit array targetStack
    private real array amountStack
    private attacktype array attackTStack
    private damagetype array damageTStack
    private weapontype array weaponTStack
    private integer array userTrigStack
    private integer array typeStack
   
    //Added in 5.4 to silently eliminate infinite recursion.
    private integer userTrigs = 9
    private integer eventTrig = 0
    private integer array nextTrig
    private trigger array userTrig
    private boolean array trigFrozen
       
    //Added/re-tooled in 5.4.1 to allow forced recursion (for advanced users only).
    private constant integer    LIMBO           = 16    //Recursion will never go deeper than LIMBO.
    private integer array       levelsDeep              //How deep the user recursion currently is.
    public boolean              inception       = false //You must set DamageEngine_inception = true before dealing damage to utlize this.
                                                        //When true, it allows your trigger to potentially go recursive up to LIMBO.
    private boolean             dreaming        = false
    private boolean array       inceptionTrig           //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
    private integer             sleepLevel      = 0
    private group               proclusGlobal   = CreateGroup() //track sources of recursion
    private group               fischerMorrow   = CreateGroup() //track targets of recursion
   
    //Improves readability in the code to have these as named constants.
    private constant integer    MOD_EVENT       = 1
    private constant integer    SHIELD_EVENT    = 4
    private constant integer    DAMAGE_EVENT    = 5
    private constant integer    ZERO_EVENT      = 6
    private constant integer    AFTER_EVENT     = 7
    private constant integer    LETHAL_EVENT    = 8
    private constant integer    AOE_EVENT       = 9
   
    //private string crashStr = ""
endglobals
   
//GUI Vars:
/*
    Retained from 3.8 and prior:
    ----------------------------
    unit            udg_DamageEventSource
    unit            udg_DamageEventTarget
    unit            udg_EnhancedDamageTarget
    group           udg_DamageEventAOEGroup
    integer         udg_DamageEventAOE
    integer         udg_DamageEventLevel
    real            udg_DamageModifierEvent
    real            udg_DamageEvent
    real            udg_AfterDamageEvent
    real            udg_DamageEventAmount
    real            udg_DamageEventPrevAmt
    real            udg_AOEDamageEvent
    boolean         udg_DamageEventOverride
    boolean         udg_NextDamageType
    boolean         udg_DamageEventType
    boolean         udg_IsDamageSpell
   
    //Added in 5.0:
    boolean          udg_IsDamageMelee    
    boolean          udg_IsDamageRanged    
    unit             udg_AOEDamageSource  
    real             udg_LethalDamageEvent
    real             udg_LethalDamageHP    
    real             udg_DamageScalingWC3
    integer          udg_DamageEventAttackT
    integer          udg_DamageEventDamageT
    integer          udg_DamageEventWeaponT
   
    //Added in 5.1:
    boolean          udg_IsDamageCode    
   
    //Added in 5.2:
    integer          udg_DamageEventArmorT  
    integer          udg_DamageEventDefenseT
   
    //Addded in 5.3:
    real             DamageEventArmorPierced
    real             udg_DamageScalingUser  
   
    //Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
    attacktype array udg_CONVERTED_ATTACK_TYPE
    damagetype array udg_CONVERTED_DAMAGE_TYPE
*/

   
    private function RunTrigs takes integer i returns nothing
        local integer cat = i
        if dreaming then
            //call BJDebugMsg("Tried to run triggers while triggers were already running.")
            return
        endif
        set dreaming = true
        //call BJDebugMsg("Start of event running")
        loop
            set i = nextTrig[i]
            exitwhen i == 0
            exitwhen cat == MOD_EVENT and (udg_DamageEventOverride or udg_DamageEventType*udg_DamageEventType == 4)
            exitwhen cat == SHIELD_EVENT and udg_DamageEventAmount <= 0.00
            exitwhen cat == LETHAL_EVENT and udg_LethalDamageHP > 0.405
            //set crashStr = "Bout to inspect " + I2S(i)
            if not trigFrozen[i] and IsTriggerEnabled(userTrig[i]) then
                set eventTrig = i
                //set crashStr = "Bout to evaluate " + I2S(i)
                if TriggerEvaluate(userTrig[i]) then
                    //set crashStr = "Bout to execute " + I2S(i)
                    call TriggerExecute(userTrig[i])
                endif
                //set crashStr = "Ran " + I2S(i)
                //call BJDebugMsg("Ran " + I2S(i))
                //if not (udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 or udg_DamageEventAmount == 0.00) then
                //    if cat == MOD_EVENT then
                //        set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
                //    elseif cat == SHIELD_EVENT then
                //        set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
                //    endif
                //elseif udg_DamageEventPrevAmt == 0.00 then
                //    call BJDebugMsg("Prev amount 0.00 and User Amount " + R2S(udg_DamageEventAmount))
                //elseif udg_DamageEventAmount == 0.00 then
                //    call BJDebugMsg("User amount 0.00 and Prev Amount " + R2S(udg_DamageEventPrevAmt))
                //elseif udg_DamageScalingWC3 == 0.00 then
                //    call BJDebugMsg("WC3 amount somehow 0.00")
                //endif
                //set crashStr = "Filtered " + I2S(i)
            //elseif i > 9 then
            //    if trigFrozen[i] then
            //        call BJDebugMsg("User Trigger is frozen")
            //    else
            //        call BJDebugMsg("User Trigger is off")
            //    endif
            endif
        endloop
        //call BJDebugMsg("End of event running")
        set dreaming = false
    endfunction
   
    private function OnAOEEnd takes nothing returns nothing
        if udg_DamageEventAOE > 1 then
            call RunTrigs(AOE_EVENT)
            set udg_DamageEventAOE      = 1
        endif
        set udg_DamageEventLevel        = 1
        set udg_EnhancedDamageTarget    = null
        set udg_AOEDamageSource         = null
        call GroupClear(udg_DamageEventAOEGroup)
    endfunction
   
    private function AfterDamage takes nothing returns nothing
        if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
            call RunTrigs(AFTER_EVENT)
        endif
    endfunction
   
    private function Finish takes nothing returns nothing
        local integer i = 0
        local integer exit
        if eventsRun then
            //call BJDebugMsg("events ran")
            set eventsRun = false
            call AfterDamage()
        endif
        if canKick and not kicking then
            //call BJDebugMsg("can kick")
            if damageStack > 0 then
                set kicking = true
                //call BJDebugMsg("Clearing queued damage instances: " + I2S(damageStack))
                loop
                    set exit = damageStack
                    set sleepLevel = sleepLevel + 1
                    loop
                        set udg_NextDamageType = typeStack[i]
                        //call BJDebugMsg("Stacking on " + R2S(amountStack[i]))
                        call UnitDamageTarget(sourceStack[i], targetStack[i], amountStack[i], true, false, attackTStack[i], damageTStack[i], weaponTStack[i])
                        call AfterDamage()
                        set i = i + 1 //Need to loop bottom to top to make sure damage order is preserved.
                        exitwhen i == exit
                    endloop
                    //call BJDebugMsg("Exit at: " + I2S(i))
                    exitwhen i == damageStack
                endloop
                //call BJDebugMsg("Terminate at at: " + I2S(i))
                set sleepLevel = 0
                loop
                    set i = i - 1
                    set trigFrozen[userTrigStack[i]] = false //Only re-enable recursive triggers AFTER all damage is dealt.
                    set levelsDeep[userTrigStack[i]] = 0 //Reset this stuff if the user tried some nonsense
                    exitwhen i == 0
                endloop
                //call BJDebugMsg("Cleared queued damage instances: " + I2S(damageStack))
                set damageStack = 0 //Can only be set after all the damage has successfully ended.
                set kicking = false
            endif
            call GroupClear(proclusGlobal)
            call GroupClear(fischerMorrow)
        //elseif kicking then
        //    call BJDebugMsg("Somehow still kicking")
        //else
        //    call BJDebugMsg("Cannot kick")
        endif
    endfunction
   
    private function ResetArmor takes nothing returns nothing
        if udg_DamageEventArmorPierced != 0.00 then
            call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + udg_DamageEventArmorPierced)
        endif
        if armorType != udg_DamageEventArmorT then
            call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, armorType) //revert changes made to the damage instance
        endif
        if defenseType != udg_DamageEventDefenseT then
            call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, defenseType)
        endif
    endfunction
   
    private function FailsafeClear takes nothing returns nothing
        //call BJDebugMsg("Damage from " + GetUnitName(udg_DamageEventSource) + " to " + GetUnitName(udg_DamageEventTarget) + " has been messing up Damage Engine.")
        //call BJDebugMsg(R2S(udg_DamageEventAmount) + " " + " " + R2S(udg_DamageEventPrevAmt) + " " + udg_AttackTypeDebugStr[udg_DamageEventAttackT] + " " + udg_DamageTypeDebugStr[udg_DamageEventDamageT])
        call ResetArmor()
        set canKick = true
        set totem = false
        set udg_DamageEventAmount = 0.00
        set udg_DamageScalingWC3  = 0.00
        if udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
            call RunTrigs(DAMAGE_EVENT) //Run the normal on-damage event based on this failure.
            set eventsRun = true //Run the normal after-damage event based on this failure.
        endif
        call Finish()
    endfunction
   
    private function WakeUp takes nothing returns nothing
        set alarmSet    = false //The timer has expired. Flag off to allow it to be restarted when needed.
        //if dreaming then
        //    set dreaming= false
        //    call BJDebugMsg("Timer set dreaming to False")
        //    call BJDebugMsg(crashStr)
        //endif
        if totem then
            //Something went wrong somewhere; the WarCraft 3 engine didn't run the DAMAGED event despite running the DAMAGING event.
            call FailsafeClear()
        else
            if not canKick and damageStack > 0 then
                //call BJDebugMsg("Damage Engine recursion deployment was failing with application of: " + R2S(udg_DamageEventAmount))
                set canKick = true
            endif
            call Finish() //Wrap up any outstanding damage instance
        endif
        call OnAOEEnd() //Reset things so they don't perpetuate for AoE/Level target detection
        set udg_DamageEventPrevAmt = 0.00 //Added in 5.4.2.1 to try to squash the Cold Arrows glitch (failed to do it)
    endfunction
   
    private function CalibrateMR takes nothing returns nothing
        set udg_IsDamageMelee           = false
        set udg_IsDamageRanged          = false
        set udg_IsDamageSpell           = udg_DamageEventAttackT == 0 //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.
            set udg_IsDamageMelee       = IsUnitType(udg_DamageEventSource, UNIT_TYPE_MELEE_ATTACKER)
            set udg_IsDamageRanged      = IsUnitType(udg_DamageEventSource, UNIT_TYPE_RANGED_ATTACKER)
            if udg_IsDamageMelee and udg_IsDamageRanged then
                set udg_IsDamageMelee   = udg_DamageEventWeaponT > 0// Melee units play a sound when damaging
                set udg_IsDamageRanged  = not udg_IsDamageMelee     // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
            endif                                                   // The Huntress has a melee sound for her ranged projectile, however it is only an issue
        endif                                                       //if she also had a melee attack, because by default she is only UNIT_TYPE_RANGED_ATTACKER.
    endfunction
   
    private function OnPreDamage takes nothing returns boolean
        local unit src      = GetEventDamageSource()
        local unit tgt      = GetTriggerUnit()
        local real amt      = GetEventDamage()
        local attacktype at = BlzGetEventAttackType()
        local damagetype dt = BlzGetEventDamageType()
        local weapontype wt = BlzGetEventWeaponType()
       
        //call BJDebugMsg("First damage event running")
       
        if dreaming then
            //call BJDebugMsg("Dreaming")
            if amt != 0.00 then
                //Store recursive damage into a queue from index "damageStack" (0-15)
                //This damage will be fired after the current damage instance has wrapped up its events.
                //This damage can only be caused by triggers.
                set amountStack[damageStack]   = amt
                set sourceStack[damageStack]   = src
                set targetStack[damageStack]   = tgt
                set attackTStack[damageStack]  = at
                set damageTStack[damageStack]  = dt
                set weaponTStack[damageStack]  = wt
                set userTrigStack[damageStack] = eventTrig
                if udg_NextDamageType == 0 then
                    set typeStack[damageStack] = udg_DamageTypeCode
                else
                    set typeStack[damageStack] = udg_NextDamageType
                endif
                //Next block added in 5.4.1 to allow *some* control over whether recursion should kick
                //in. Also it's important to track whether the source and target were both involved at
                //some earlier point, so this is a more accurate and lenient method than before.
                set inception = inception or inceptionTrig[eventTrig]
                call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
                call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
                if kicking and IsUnitInGroup(src, proclusGlobal) and IsUnitInGroup(tgt, fischerMorrow) then
                    if inception and not trigFrozen[eventTrig] then
                        set inceptionTrig[eventTrig] = true
                        if levelsDeep[eventTrig] < sleepLevel then
                            set levelsDeep[eventTrig] = levelsDeep[eventTrig] + 1
                            if levelsDeep[eventTrig] >= LIMBO then
                                set trigFrozen[eventTrig] = true
                            endif
                        endif
                    else
                        set trigFrozen[eventTrig] = true
                    endif
                endif
                set damageStack = damageStack + 1
                //call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(levelsDeep[eventTrig]) + " sleepLevel: " + I2S(sleepLevel))
                call BlzSetEventDamage(0.00) //queue the damage instance instead of letting it run recursively
            endif
        else
            if not kicking then
                //Added 25 July 2017 to detect AOE damage or multiple single-target damage
                if alarmSet then
                    if totem then
                        if dt != DAMAGE_TYPE_SPIRIT_LINK and dt != DAMAGE_TYPE_DEFENSIVE and dt != DAMAGE_TYPE_PLANT then
                            //if 'totem' is still set and it's not due to spirit link distribution or defense retaliation,
                            //the next function must be called as a debug. This reverts an issue I created in patch 5.1.3.
                            call FailsafeClear()
                        else
                            set totem           = false
                            set lastAmount      = udg_DamageEventAmount
                            set lastPrevAmt     = udg_DamageEventPrevAmt    //Store the actual pre-armor value.
                            set lastType        = udg_DamageEventType       //also store the damage type.
                            set lastCode        = udg_IsDamageCode          //store this as well.
                            set lastArmor       = udg_DamageEventArmorT
                            set lastPrevArmor   = armorType
                            set lastDefense     = udg_DamageEventDefenseT
                            set lastPrevDefense = defenseType
                            set lastPierced     = udg_DamageEventArmorPierced
                            set canKick         = false
                        endif
                    else
                        call Finish()
                    endif
                    if src != udg_AOEDamageSource then //Source has damaged more than once
                        call OnAOEEnd() //New damage source - unflag everything
                        set udg_AOEDamageSource = src
                    elseif tgt == udg_EnhancedDamageTarget then
                        set udg_DamageEventLevel= udg_DamageEventLevel + 1  //The number of times the same unit was hit.
                    elseif not IsUnitInGroup(tgt, udg_DamageEventAOEGroup) then
                        set udg_DamageEventAOE  = udg_DamageEventAOE + 1    //Multiple targets hit by this source - flag as AOE
                    endif
                else
                    call TimerStart(alarm, 0.00, false, function WakeUp)
                    set alarmSet                = true
                    set udg_AOEDamageSource     = src
                    set udg_EnhancedDamageTarget= tgt
                endif
                call GroupAddUnit(udg_DamageEventAOEGroup, tgt)
            endif
            set udg_DamageEventType             = udg_NextDamageType
            set udg_IsDamageCode                = udg_NextDamageType != 0
            set udg_DamageEventOverride         = dt == null //Got rid of NextDamageOverride in 5.1 for simplicity
            set udg_DamageEventPrevAmt          = amt
            set udg_DamageEventSource           = src
            set udg_DamageEventTarget           = tgt
            set udg_DamageEventAmount           = amt
            set udg_DamageEventAttackT          = GetHandleId(at)
            set udg_DamageEventDamageT          = GetHandleId(dt)
            set udg_DamageEventWeaponT          = GetHandleId(wt)
           
            call CalibrateMR() //Set Melee and Ranged settings.
           
            set udg_DamageEventArmorT           = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE) //Introduced in Damage Engine 5.2.0.0
            set udg_DamageEventDefenseT         = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE)
            set armorType                       = udg_DamageEventArmorT
            set defenseType                     = udg_DamageEventDefenseT
            set udg_DamageEventArmorPierced     = 0.00
            set udg_DamageScalingUser           = 1.00
            set udg_DamageScalingWC3            = 1.00
           
            if amt != 0.00 then
                if not udg_DamageEventOverride then
                    call RunTrigs(MOD_EVENT)
               
                    //All events have run and the pre-damage amount is finalized.
                    call BlzSetEventAttackType(ConvertAttackType(udg_DamageEventAttackT))
                    call BlzSetEventDamageType(ConvertDamageType(udg_DamageEventDamageT))
                    call BlzSetEventWeaponType(ConvertWeaponType(udg_DamageEventWeaponT))
                    if udg_DamageEventArmorPierced != 0.00 then
                        call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) - udg_DamageEventArmorPierced)
                    endif
                    if armorType != udg_DamageEventArmorT then
                        call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, udg_DamageEventArmorT) //Introduced in Damage Engine 5.2.0.0
                    endif
                    if defenseType != udg_DamageEventDefenseT then
                        call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, udg_DamageEventDefenseT) //Introduced in Damage Engine 5.2.0.0
                    endif
                    call BlzSetEventDamage(udg_DamageEventAmount)
                endif
                //call BJDebugMsg("Ready to deal " + R2S(udg_DamageEventAmount))
                set totem = true
            else
                call RunTrigs(ZERO_EVENT)
                set canKick = true
                call Finish()
            endif
        endif
        set src = null
        set tgt = null
        set inception = false
        set udg_NextDamageType = 0
        return false
    endfunction
   
    //The traditional on-damage response, where armor reduction has already been factored in.
    private function OnDamage takes nothing returns boolean
        local real r = GetEventDamage()
        //call BJDebugMsg("Second damage event running")
        if dreaming or udg_DamageEventPrevAmt == 0.00 then
            //if dreaming then
            //    call BJDebugMsg("Dreaming")
            //else
            //    call BJDebugMsg("Prev amount is zero")
            //endif
            return false
        endif
        if totem then
            set totem = false   //This should be the case in almost all circumstances
        else
            call AfterDamage() //Wrap up the outstanding damage instance
            set canKick                     = true
            //Unfortunately, Spirit Link and Thorns Aura/Spiked Carapace fire the DAMAGED event out of sequence with the DAMAGING event,
            //so I have to re-generate a buncha stuff here.
            set udg_DamageEventSource       = GetEventDamageSource()
            set udg_DamageEventTarget       = GetTriggerUnit()
            set udg_DamageEventAmount       = lastAmount
            set udg_DamageEventPrevAmt      = lastPrevAmt
            set udg_DamageEventAttackT      = GetHandleId(BlzGetEventAttackType())
            set udg_DamageEventDamageT      = GetHandleId(BlzGetEventDamageType())
            set udg_DamageEventWeaponT      = GetHandleId(BlzGetEventWeaponType())
            set udg_DamageEventType         = lastType
            set udg_IsDamageCode            = lastCode
            set udg_DamageEventArmorT       = lastArmor
            set udg_DamageEventDefenseT     = lastDefense
            set udg_DamageEventArmorPierced = lastPierced
            set armorType                   = lastPrevArmor
            set defenseType                 = lastPrevDefense
            call CalibrateMR() //Apply melee/ranged settings once again.
        endif
        call ResetArmor()
        if udg_DamageEventAmount != 0.00 and r != 0.00 then
            set udg_DamageScalingWC3 = r / udg_DamageEventAmount
        elseif udg_DamageEventAmount > 0.00 then
            set udg_DamageScalingWC3 = 0.00
        else
            set udg_DamageScalingWC3 = 1.00
            set udg_DamageScalingUser = udg_DamageEventAmount / udg_DamageEventPrevAmt
        endif
        set udg_DamageEventAmount = udg_DamageEventAmount*udg_DamageScalingWC3
       
        if udg_DamageEventAmount > 0.00 then
            //This event is used for custom shields which have a limited hit point value
            //The shield here kicks in after armor, so it acts like extra hit points.
            call RunTrigs(SHIELD_EVENT)
            set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
            if udg_LethalDamageHP <= 0.405 then
                call RunTrigs(LETHAL_EVENT) //Added 10 May 2019 to detect and potentially prevent lethal damage. Instead of
                //modifying the damage, you need to modify LethalDamageHP instead (the final HP of the unit).
               
                set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
                if udg_DamageEventType < 0 and udg_LethalDamageHP <= 0.405 then
                    call SetUnitExploded(udg_DamageEventTarget, true)   //Explosive damage types should blow up the target.
                endif
            endif
            set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
        endif
        call BlzSetEventDamage(udg_DamageEventAmount)   //Apply the final damage amount.
        if udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
            call RunTrigs(DAMAGE_EVENT)
        endif
        set eventsRun = true
        if udg_DamageEventAmount == 0.00 then
            call Finish()
        endif
        return false
    endfunction
   
    //===========================================================================
    private function Init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DAMAGED) //Thanks to this I no longer have to create an event for every unit in the map.
        call TriggerAddCondition(trig, Filter(function OnDamage))

        set trig = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DAMAGING) //The new 1.31 event which fires before damage.
        call TriggerAddCondition(trig, Filter(function OnPreDamage))
        set trig = null
    endfunction
   
    public function DebugStr takes nothing returns nothing
        local integer i = 0
        loop
            set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
            exitwhen i == 6
            set i = i + 1
        endloop
        set i = 0
        loop
            set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
            exitwhen i == 26
            set i = i + 1
        endloop
        set udg_AttackTypeDebugStr[0] = "SPELLS"    //ATTACK_TYPE_NORMAL in JASS
        set udg_AttackTypeDebugStr[1] = "NORMAL"    //ATTACK_TYPE_MELEE in JASS
        set udg_AttackTypeDebugStr[2] = "PIERCE"
        set udg_AttackTypeDebugStr[3] = "SIEGE"
        set udg_AttackTypeDebugStr[4] = "MAGIC"
        set udg_AttackTypeDebugStr[5] = "CHAOS"
        set udg_AttackTypeDebugStr[6] = "HERO"
       
        set udg_DamageTypeDebugStr[0]  = "UNKNOWN"
        set udg_DamageTypeDebugStr[4]  = "NORMAL"
        set udg_DamageTypeDebugStr[5]  = "ENHANCED"
        set udg_DamageTypeDebugStr[8]  = "FIRE"
        set udg_DamageTypeDebugStr[9]  = "COLD"
        set udg_DamageTypeDebugStr[10] = "LIGHTNING"
        set udg_DamageTypeDebugStr[11] = "POISON"
        set udg_DamageTypeDebugStr[12] = "DISEASE"
        set udg_DamageTypeDebugStr[13] = "DIVINE"
        set udg_DamageTypeDebugStr[14] = "MAGIC"
        set udg_DamageTypeDebugStr[15] = "SONIC"
        set udg_DamageTypeDebugStr[16] = "ACID"
        set udg_DamageTypeDebugStr[17] = "FORCE"
        set udg_DamageTypeDebugStr[18] = "DEATH"
        set udg_DamageTypeDebugStr[19] = "MIND"
        set udg_DamageTypeDebugStr[20] = "PLANT"
        set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
        set udg_DamageTypeDebugStr[22] = "DEMOLITION"
        set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
        set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
        set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
        set udg_DamageTypeDebugStr[26] = "UNIVERSAL"

        set udg_WeaponTypeDebugStr[0]  = "NONE"     //WEAPON_TYPE_WHOKNOWS in JASS
        set udg_WeaponTypeDebugStr[1]  = "METAL_LIGHT_CHOP"
        set udg_WeaponTypeDebugStr[2]  = "METAL_MEDIUM_CHOP"
        set udg_WeaponTypeDebugStr[3]  = "METAL_HEAVY_CHOP"
        set udg_WeaponTypeDebugStr[4]  = "METAL_LIGHT_SLICE"
        set udg_WeaponTypeDebugStr[5]  = "METAL_MEDIUM_SLICE"
        set udg_WeaponTypeDebugStr[6]  = "METAL_HEAVY_SLICE"
        set udg_WeaponTypeDebugStr[7]  = "METAL_MEDIUM_BASH"
        set udg_WeaponTypeDebugStr[8]  = "METAL_HEAVY_BASH"
        set udg_WeaponTypeDebugStr[9]  = "METAL_MEDIUM_STAB"
        set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
        set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
        set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
        set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
        set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
        set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
        set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
        set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
        set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
        set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
        set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
        set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
        set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
        set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"

        set udg_DefenseTypeDebugStr[0] = "LIGHT"
        set udg_DefenseTypeDebugStr[1] = "MEDIUM"
        set udg_DefenseTypeDebugStr[2] = "HEAVY"
        set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
        set udg_DefenseTypeDebugStr[4] = "NORMAL"   //Typically deals flat damage to all armor types
        set udg_DefenseTypeDebugStr[5] = "HERO"
        set udg_DefenseTypeDebugStr[6] = "DIVINE"
        set udg_DefenseTypeDebugStr[7] = "UNARMORED"
       
        set udg_ArmorTypeDebugStr[0] = "NONE"       //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
        set udg_ArmorTypeDebugStr[1] = "FLESH"
        set udg_ArmorTypeDebugStr[2] = "METAL"
        set udg_ArmorTypeDebugStr[3] = "WOOD"
        set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
        set udg_ArmorTypeDebugStr[5] = "STONE"
    endfunction
   
    //This function exists mainly to make it easier to switch from another DDS, like PDD.
    function UnitDamageTargetEx takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns boolean
        if udg_NextDamageType == 0 then
           set udg_NextDamageType = udg_DamageTypeCode
        endif
        call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
        return dreaming
    endfunction
   
    public function SetupEvent takes trigger whichTrig, string var, integer index returns nothing
        local integer max = 1
        local integer off = 0
        local integer exit = 0
        local integer i
        if var == "udg_DamageModifierEvent" then //MOD_EVENT 1-4 -> Events 1-4
            if index < 3 then
                set exit = index + 1
            endif
            if nextTrig[1] == 0 then
                set nextTrig[1] = 2
                set nextTrig[2] = 3
                set trigFrozen[2] = true
                set trigFrozen[3] = true
            endif
            set max = 4
        elseif var == "udg_DamageEvent" then //DAMAGE_EVENT 1,2 -> Events 5,6
            set max = 2
            set off = 4
        elseif var == "udg_AfterDamageEvent" then //AFTER_EVENT -> Event 7
            set off = 6
        elseif var == "udg_LethalDamageEvent" then //LETHAL_EVENT -> Event 8
            set off = 7
        elseif var == "udg_AOEDamageEvent" then //AOE_EVENT -> Event 9
            set off = 8
        else
            return
        endif
        set i = IMaxBJ(IMinBJ(index, max), 1) + off
        //call BJDebugMsg("Root index: " + I2S(i))
        loop
            set index = i
            set i = nextTrig[i]
            exitwhen i == exit
        endloop
        set userTrigs = userTrigs + 1   //User list runs from index 10 and up
        set nextTrig[index] = userTrigs
        set nextTrig[userTrigs] = exit
        set userTrig[userTrigs] = whichTrig
        //call BJDebugMsg("Registered " + I2S(userTrigs) + " to " + I2S(index))
    endfunction
   
    private function PreSetup takes trigger whichTrig, string var, limitop op, real value returns nothing
        call SetupEvent(whichTrig, var, R2I(value))
    endfunction
   
    hook TriggerRegisterVariableEvent PreSetup
   
endlibrary
//TESH.scrollpos=9
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Multi-flavor:
//*    Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************

//================================================================
    globals
        //How to tweak timer utils:
        // USE_HASH_TABLE = true  (new blue)
        //  * SAFEST
        //  * SLOWEST (though hash tables are kind of fast)
        //
        // USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true  (orange)
        //  * kinda safe (except there is a limit in the number of timers)
        //  * ALMOST FAST
        //
        // USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
        //  * THE FASTEST (though is only  faster than the previous method
        //                  after using the optimizer on the map)
        //  * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
        //                     work)
        //
        private constant boolean USE_HASH_TABLE      = true
        private constant boolean USE_FLEXIBLE_OFFSET = false

        private constant integer OFFSET     = 0x100000
        private          integer VOFFSET    = OFFSET
             
        //Timers to preload at map init:
        private constant integer QUANTITY   = 256
       
        //Changing this  to something big will allow you to keep recycling
        // timers even when there are already AN INCREDIBLE AMOUNT of timers in
        // the stack. But it will make things far slower so that's probably a bad idea...
        private constant integer ARRAY_SIZE = 8190

    endglobals

    //==================================================================================================
    globals
        private integer array data[ARRAY_SIZE]
        private hashtable     ht
    endglobals

    //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
    function SetTimerData takes timer t, integer value returns nothing
        static if(USE_HASH_TABLE) then
            // new blue
            call SaveInteger(ht,0,GetHandleId(t), value)
           
        elseif (USE_FLEXIBLE_OFFSET) then
            // orange
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-VOFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            set data[GetHandleId(t)-VOFFSET]=value
        else
            // new red
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-OFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            set data[GetHandleId(t)-OFFSET]=value
        endif        
    endfunction

    function GetTimerData takes timer t returns integer
        static if(USE_HASH_TABLE) then
            // new blue
            return LoadInteger(ht,0,GetHandleId(t) )
           
        elseif (USE_FLEXIBLE_OFFSET) then
            // orange
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-VOFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            return data[GetHandleId(t)-VOFFSET]
        else
            // new red
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-OFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            return data[GetHandleId(t)-OFFSET]
        endif        
    endfunction

    //==========================================================================================
    globals
        private timer array tT[ARRAY_SIZE]
        private integer tN = 0
        private constant integer HELD=0x28829022
        //use a totally random number here, the more improbable someone uses it, the better.
    endglobals

    //==========================================================================================
    function NewTimer takes nothing returns timer
        if (tN==0) then
            //If this happens then the QUANTITY rule has already been broken, try to fix the
            // issue, else fail.
            debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
            static if( not USE_HASH_TABLE) then
                debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
                set tT[0]=CreateTimer()
                static if( USE_FLEXIBLE_OFFSET) then
                    if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
                        //all right, couldn't fix it
                        call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
                        return null
                    endif
                else
                    if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
                        //all right, couldn't fix it
                        call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
                        return null
                    endif
                endif
            endif
        else
            set tN=tN-1
        endif
        call SetTimerData(tT[tN],0)
     return tT[tN]
    endfunction

    //==========================================================================================
    function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==ARRAY_SIZE) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction

    private function init takes nothing returns nothing
     local integer i=0
     local integer o=-1
     local boolean oops = false
     
        static if( USE_HASH_TABLE ) then
            set ht = InitHashtable()
            loop
                exitwhen(i==QUANTITY)
                set tT[i]=CreateTimer()
                call SetTimerData(tT[i], HELD)
                set i=i+1
            endloop
            set tN = QUANTITY
        else
            loop
                set i=0
                loop
                    exitwhen (i==QUANTITY)
                    set tT[i] = CreateTimer()
                    if(i==0) then
                        set VOFFSET = GetHandleId(tT[i])
                        static if(USE_FLEXIBLE_OFFSET) then
                            set o=VOFFSET
                        else
                            set o=OFFSET
                        endif
                    endif
                    if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
                        exitwhen true
                    endif
                    if (GetHandleId(tT[i])-o>=0)  then
                        set i=i+1
                    endif
                endloop
                set tN = i
                exitwhen(tN == QUANTITY)
                set oops = true
                exitwhen not USE_FLEXIBLE_OFFSET
                debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")              
            endloop
           
            if(oops) then
                static if ( USE_FLEXIBLE_OFFSET) then
                    debug call BJDebugMsg("The problem has been fixed.")
                    //If this message doesn't appear then there is so much
                    //handle id fragmentation that it was impossible to preload
                    //so many timers and the thread crashed! Therefore this
                    //debug message is useful.
                elseif(DEBUG_MODE) then
                    call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
                    call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
                    call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
                    call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
                endif
            endif
        endif

    endfunction

endlibrary
 
//TESH.scrollpos=9
//TESH.alwaysfold=0
library Table // made by Bribe, special thanks to Nestharus, version 3.0.0.0
/*
    API
   
    ------------
    struct Table
    | static method create takes nothing returns Table
    |     create a new Table
    |    
    | method destroy takes nothing returns nothing
    |     destroy it
    |    
    | method flush takes nothing returns nothing
    |     flush all stored values inside of it
    |    
    | method remove takes integer key returns nothing
    |     remove the value at index "key"
    |    
    | method operator []= takes integer key, $TYPE$ value returns nothing
    |     assign "value" to index "key"
    |    
    | method operator [] takes integer key returns $TYPE$
    |     load the value at index "key"
    |    
    | method has takes integer key returns boolean
    |     whether or not the key was assigned
    |
    ----------------
    struct TableArray
    | static method operator [] takes integer array_size returns TableArray
    |     create a new array of Tables of size "array_size"
    |
    | method destroy takes nothing returns nothing
    |     destroy it
    |
    | method flush takes nothing returns nothing
    |     flush and destroy it
    |
    | method operator size takes nothing returns integer
    |     returns the size of the TableArray
    |
    | method operator [] takes integer key returns Table
    |     returns a Table accessible exclusively to index "key"
*/

   
globals
    private hashtable ht = InitHashtable() //The last hashtable you need
    private integer more = 2 //Index generation for Tables (above 2)
    private integer less = 0 //Index generation for TableArrays (below 0)
endglobals
   
private struct dex extends array
    static method operator size takes nothing returns Table
        return 1
    endmethod
    static method operator list takes nothing returns Table
        return 2
    endmethod
endstruct
   
private struct handles extends array
    method has takes integer key returns boolean
        return HaveSavedHandle(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSavedHandle(ht, this, key)
    endmethod
endstruct
   
private struct agents extends array
    method operator []= takes integer key, agent value returns nothing
        call SaveAgentHandle(ht, this, key, value)
    endmethod
endstruct
   
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
    method operator [] takes integer key returns $TYPE$
        return Load$FUNC$(ht, this, key)
    endmethod
    method operator []= takes integer key, $TYPE$ value returns nothing
        call Save$FUNC$(ht, this, key, value)
    endmethod
    method has takes integer key returns boolean
        return HaveSaved$SUPER$(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSaved$SUPER$(ht, this, key)
    endmethod
endstruct
private module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
   
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
    method operator [] takes integer key returns $TYPE$
        return Load$FUNC$Handle(ht, this, key)
    endmethod
    method operator []= takes integer key, $TYPE$ value returns nothing
        call Save$FUNC$Handle(ht, this, key, value)
    endmethod
endstruct
private module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
   
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
   
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
   
struct Table extends array
   
    // Implement modules for intuitive type-syntax
    implement realm
    implement booleanm
    implement stringm
    implement playerm
    implement widgetm
    implement destructablem
    implement itemm
    implement unitm
    implement abilitym
    implement timerm
    implement triggerm
    implement triggerconditionm
    implement triggeractionm
    implement eventm
    implement forcem
    implement groupm
    implement locationm
    implement rectm
    implement boolexprm
    implement soundm
    implement effectm
    implement unitpoolm
    implement itempoolm
    implement questm
    implement questitemm
    implement defeatconditionm
    implement timerdialogm
    implement leaderboardm
    implement multiboardm
    implement multiboarditemm
    implement trackablem
    implement dialogm
    implement buttonm
    implement texttagm
    implement lightningm
    implement imagem
    implement ubersplatm
    implement regionm
    implement fogstatem
    implement fogmodifierm
    implement hashtablem
   
    method operator handle takes nothing returns handles
        return this
    endmethod
   
    method operator agent takes nothing returns agents
        return this
    endmethod
   
    // set this = a[GetSpellAbilityId()]
    method operator [] takes integer key returns Table
        return LoadInteger(ht, this, key)
    endmethod
   
    // set a[389034] = 8192
    method operator []= takes integer key, Table a returns nothing
        call SaveInteger(ht, this, key, a)
    endmethod
   
    // set b = a.has(2493223)
    method has takes integer key returns boolean
        return HaveSavedInteger(ht, this, key)
    endmethod
   
    // call a.remove(294080)
    method remove takes integer key returns nothing
        call RemoveSavedInteger(ht, this, key)
    endmethod
   
    // Remove all data from a Table instance
    method flush takes nothing returns nothing
        call FlushChildHashtable(ht, this)
    endmethod
   
    // local Table a = Table.create()
    static method create takes nothing returns Table
        local Table this = dex.list[0]
       
        if this == 0 then
            set more = more + 1
            set this = more
        else
            set dex.list[0] = dex.list[this]
            call dex.list.remove(this)
        endif
       
        debug set dex.list[this] = -1
        return this
    endmethod
   
    // Removes all data from a Table instance and recycles its index.
    //
    //     call a.destroy()
    //
    method destroy takes nothing returns nothing
        debug if dex.list[this] != -1 then
            debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
            debug return
        debug endif
       
        call this.flush()
       
        set dex.list[this] = dex.list[0]
        set dex.list[0] = this
    endmethod
   
endstruct
   
struct TableArray extends array
   
    //Returns a new TableArray to do your bidding. Simply use:
    //
    //    local TableArray ta = TableArray[array_size]
    //
    static method operator [] takes integer array_size returns TableArray
        local Table a = dex.size[array_size] //Get the unique recycle list for this array size
        local TableArray this = a[0]         //The last-destroyed TableArray that had this array size
       
        debug if array_size <= 0 then
            debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
            debug return 0
        debug endif
       
        if this == 0 then
            set less = less - array_size
            set this = less
        else
            set a[0] = a[this]  //Set the last destroyed to the last-last destroyed
            call a.remove(this) //Clear hash memory
        endif
       
        set dex.size[this] = array_size //This remembers the array size
        return this
    endmethod
   
    //Returns the size of the TableArray
    method operator size takes nothing returns integer
        return dex.size[this]
    endmethod
   
    //da[integer a].unit[integer b] = unit u
    //da[integer a][integer c] = integer d
    //
    //Inline-friendly when not running in debug mode
    //
    method operator [] takes integer key returns Table
        static if DEBUG_MODE then
            local integer i = this.size
            if i == 0 then
                call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
                return 0
            elseif key < 0 or key >= i then
                call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
                return 0
            endif
        endif
        return this + key
    endmethod
   
    //Destroys a TableArray without flushing it; assumed you'd call .flush()
    //if you want it flushed too. This is public so that if you are flushing
    //instances the whole time you don't waste efficiency when disposing the
    //TableArray.
    //
    method destroy takes nothing returns nothing
        local Table a = dex.size[this.size]
       
        debug if this.size <= 0 then
            debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
            debug return
        debug endif
       
        if a == 0 then
            //Create an array to index recycled instances with their array size
            set a = Table.create()
            set dex.size[this.size] = a
        endif
       
        call dex.size.remove(this) //Clear the array size from hash memory
       
        set a[this] = a[0]
        set a[0] = this
    endmethod
   
    //All you need to know about this one is that it won't hit the op limit.
    private static method clean takes Table a, integer end returns nothing
        local integer i = a + 5000
        if i < end then
            call clean.evaluate(i, end)
            set end = i
        endif
        loop
            call a.flush()
            set a = a + 1
            exitwhen a == end
        endloop
    endmethod
   
    //Flushes the TableArray and also destroys it. Doesn't get any more
    //similar to the FlushParentHashtable native than this.
    //
    method flush takes nothing returns nothing
        local integer end = this.size + this
        debug if this == end then
            debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
            debug return
        debug endif
        call clean.evaluate(this, end)
        call this.destroy()
    endmethod
   
endstruct
   
endlibrary