1. Are you planning to upload your awesome map to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  5. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  6. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  7. The results are out! Check them out.
    Dismiss Notice
  8. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  9. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  10. 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

Shadows of the Past v0.9.3.0.w3x
Variables
Systems
Core Systems
SotP Core
---------------
CTL
Table
Event
WorldBounds
CombatState
Math
RegisterPlayerUnitEvent
SpellEffectEvent
BinaryHeap
PriorityEvent
UnitIndexer
AVL Tree
DamageEvent
Stun
AdvancedTextTag
DamageSystem
UnitRegeneration
MoveSpeedX
Bonus
Status
ItemBonus
SaveLoad
TimedLightnings
Systems
DisplaySpellName
HeroAvatarHotkeys
WeatherSystem
CameraSystem
ProjectileSystem
BuildingInOutSystem
Book System
TeleportSystem
ResourceGenerateSystem
CreepSystem
PetSystem
HeroRespawn
HeroPickSystem
HeroStatsMultiboard
Hero Items and Abilities Lib
CustomInterface
HeroFormSwap
HeroVisionSystem
Cinematics
CinemaSystems
Intro
Need Improvement
Interact
ItemGenerateLib
Transition Camp 1
Transition Camp 2
Transition Swamps
Transition Hills of Arnor
Spells
Spells
Basic
Rest
Test Spells
Hero
Mortal Blow
Defend
Fire Ball
Lightning Strike
Heal
Pet Spells
Dragon Turtle
FireBrathSpell
RavageSpell
BlazingCarapaceSpell
FlammingLasoSpell
Frozen Wolf
Spirit
BrillianceAuraSpell
PowerAuraSpell
DevotionAuraSpell
SpiritualBondSpell
SpiritualEnlightenmentSpell
Wildkin
LightningMasterySpell
LightningStrikeSpell
Dark Seer
Quests
Quests
QuestPingSystem
QuestMessageSystem
SotPQuests
Main Quests
Quest 1
Quest 2
Quest 3
Optional Quests
Quest 501
Quest 502
Quest 503
Quest 504
Quest 505
Quest 506
//TESH.scrollpos=0
//TESH.alwaysfold=0
Name Type Is Array Initial Value
//TESH.scrollpos=27
//TESH.alwaysfold=0
globals
    //Player Colors
    string   array TXTC
   
    //Hero Systems
    unit     HERO                   = null
    unit     HERO_F3                = null
    unit     PET                    = null
    integer  HERO_CLASS             = 0
    integer  HERO_CLASS_ID          = 0
    integer  HERO_ID                = 0
    integer  HERO_UD                = 0
    integer  PET_ID                 = 0
    integer  PET_UD                 = 0
    string   HERO_NAME              = ""
   
    //Expirience rate
    real     EXP                    = 1.00
   
    //General dummy unit
    integer DUMMY_ID                = 'e006'
   
    //AntiFileHeader
    boolean CUSTOM_CAMERA_ENABLED   = false
       
    integer ABILITIES_UNIT_INDEXER  = 'A!!!'
    integer UNITS_UNIT_EVENT        = 'n!!!'
   
    boolean IS_IN_BUILDING          = false
    boolean IS_IN_CI                = false
    boolean IS_PET_ALIVE            = false
    boolean IS_DAY                  = false
    boolean IS_CINEMA_ON            = false
    timer   BUILDING_CAMERA_TIMER   = null
endglobals

library BaseSystems initializer Init uses RegisterPlayerUnitEvent

    globals
        string MUSIC_INTRO = "war3mapImported\\mp3 Intro Music SotP.mp3"
        string MUSIC_QUEST1 = "war3mapImported\\mp3 Quest1 Music SotP.mp3"
        string MUSIC_QUEST2 = "Sound\\Music\\mp3Music\\Undead3.mp3"
        string MUSIC_WORLD1 = "war3mapImported\\Explore.mp3"
        string MUSIC_WORLD2 = "war3mapImported\\ExploreAct2.mp3"
       
        location RevivePos
    endglobals

    function MsgDisp takes string text returns nothing
        call ClearTextMessages()
        call DisplayTimedTextToPlayer(Player(0), 0.8, 0.1, 3,"|cffccccff" + text)
    endfunction
   
    function StartLoopingSound takes string filepath returns nothing
        call StopMusic(false)
        call ClearMapMusic()
        call PlayMusic(filepath)
    endfunction
   
    struct setBBxy extends array
        private static method run takes nothing returns nothing
            call SetUnitX(HERO_F3, GetUnitX(HERO))
            call SetUnitY(HERO_F3, GetUnitY(HERO))
            if HERO != null then
                if GetUnitX(HERO) > -250.00 and GetUnitX(HERO) < 250.00 and GetUnitY(HERO) > -250.00 and GetUnitY(HERO) < 250.00 then
                    call SetUnitX(HERO, GetLocationX(RevivePos))
                    call SetUnitY(HERO, GetLocationY(RevivePos))
                    call BJDebugMsg("debug: Invalid hero loc detected.")
                endif
            endif
        endmethod
       
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), 0.03, true, function thistype.run)
        endmethod
    endstruct
   
    private function AttackStop takes nothing returns nothing
        if IsPlayerAlly(GetOwningPlayer(GetAttacker()), GetOwningPlayer(GetTriggerUnit())) then
            call IssueImmediateOrder(GetAttacker(), "stop")
        endif
    endfunction

    function Init takes nothing returns nothing
        local integer i = 0

        set TXTC[0] = "|CFFFF0303"
        set TXTC[1] = "|c000042FF"
        set TXTC[2] = "|C0000FFFF"
        set TXTC[3] = "|c00540081"
        set TXTC[4] = "|c00FFFC01"
        set TXTC[5] = "|c00FEBA0E"
        set TXTC[6] = "|c0020C000"
        set TXTC[7] = "|c00E55BB0"
        set TXTC[8] = "|c00959697"
        set TXTC[9] = "|CFF7EBFF1"
        set TXTC[10] = "|CFF106246"
        set TXTC[11] = "|CFF4E2A04"

        call FogModifierStart( CreateFogModifierRect( Player(0) , FOG_OF_WAR_VISIBLE , gg_rct_CI1 , true , false ) )
        call FogModifierStart( CreateFogModifierRect( Player(0) , FOG_OF_WAR_VISIBLE , gg_rct_CI2 , true , false ) )
       
           
        loop
            exitwhen i > 14
            call SetPlayerName(Player(i), TXTC[i] + GetPlayerName(Player(i)))
            set i = i + 1
        endloop
       
        call SetPlayerState(Player(0), PLAYER_STATE_RESOURCE_FOOD_USED, 0)

        call SetPlayerHandicapXP(Player(0), 0.00)
        set RevivePos = GetUnitLoc(gg_unit_ncop_0108)
        call SetWaterBaseColor(0,0,0,100)
       
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function AttackStop)
    endfunction
endlibrary
//TESH.scrollpos=75
//TESH.alwaysfold=0
library CTL /* v1.2.0.0
    *************************************************************************************
    *
    *    CTL or Constant Timer Loop provides a loop for constant merged timers of timeout .03125
    *
    *    Similar to T32 but pauses timer when no structs have instances and removes structs
    *    from timer trigger when those structs have no instances.
    *
    *    This can also create new timers after destroying a previous timer and generates less
    *    code in the module. It also generates no triggers so long as the module is implemented
    *    at the top of the struct.
    *
    ************************************************************************************
    *
    *    module CTL
    *
    *       Allows creation/destruction of timers in a struct. Provides instancing of those timers.
    *
    *       -   static method create takes nothing returns thistype
    *       -   method destroy takes nothing returns nothing
    *
    *       CTL (optional)
    *           local variables, code before running any timers
    *       CTLExpire (not optional)
    *           timer code
    *       CTLNull (optional)
    *           null any locals, runs after all timers
    *       CTLEnd (not optional)
    *
    *   module CT32
    *
    *       Converts struct into a timer group. Allows the timer group to be started and stopped.
    *       Instancing and looping through active timers is up to the user.
    *
    *       -   static method start takes nothing returns nothing
    *       -   static method stop takes nothing returns nothing
    *
    *       CT32 (not optional)
    *           timer code
    *       CT32End (not optional)
    *
    *   struct TimerGroup32 extends array
    *
    *       Allows for the creation of timer groups. Timer instancing and looping is entirely up
    *       to the user.
    *
    *       -   static method create takes code func returns thistype
    *       -   method destroy takes nothing returns nothing
    *       -   method start takes nothing returns nothing
    *       -   method stop takes nothing returns nothing
    *
    ************************************************************************************/

    globals
        private integer tgc = 0          //timer group count
        private integer array tgr        //timer group recycler
       
        private integer ic=0                    //instance count
        private integer tc=0                    //timer count
        private integer array rf                //root first
        private integer array n                 //next
        private integer array p                 //previous
        private integer array th                //timer head
        private integer array ns                //next stack
        private trigger t=CreateTrigger()
        private timer m=CreateTimer()
        private triggercondition array ct
        private conditionfunc array rc
       
        private boolean array e32               //enabled
        private integer array i32r              //ct32 recycler
        private integer i32cr = 0               //ct32 count recycler
        private timer t32r = CreateTimer()      //t32 recycler
        private boolean array ir32              //is recycling
        private boolean array id32              //is destroying
    endglobals
    private function E takes nothing returns nothing
        local integer i=ns[0]
        set ns[0]=0
        loop
            exitwhen 0==i
            if (0==p[i]) then
                if (0==n[i]) then
                    call TriggerRemoveCondition(t,ct[th[i]])
                    set ct[th[i]]=null
                    set tc=tc-1
                    set rf[th[i]]=0
                else
                    set rf[th[i]]=n[i]
                    set p[n[i]]=0
                endif
            else
                set p[n[i]]=p[i]
                set n[p[i]]=n[i]
            endif
            set n[i]=n[0]
            set n[0]=i
            set i=ns[i]
        endloop
        loop
            exitwhen 0 == i32cr
            set i32cr = i32cr - 1
            set i = i32r[i32cr]
            if (not e32[i]) then
                call TriggerRemoveCondition(t,ct[i])
                set ct[i] = null
               
                if (id32[i]) then
                    set tgr[i] = tgr[0]
                    set tgr[0] = i
                    set id32[i] = false
                    set e32[i] = false
                    set ir32[i] = false
                endif
            endif
        endloop
        if (0==tc) then
            call PauseTimer(m)
        else
            call TriggerEvaluate(t)
        endif
    endfunction
    private function CT takes integer r returns integer
        local integer i
        local integer f
        if (0==n[0]) then
            set i=ic+1
            set ic=i
        else
            set i=n[0]
            set n[0]=n[i]
        endif
        set th[i]=r
        set ns[i]=-1
        set f=rf[r]
        if (0==f) then
            set n[i]=0
            set p[i]=0
            set rf[r]=i
            set ct[r]=TriggerAddCondition(t,rc[r])
            set ct[r] = null
            if (0==tc) then
                call TimerStart(m,.031250000,true,function E)
            endif
            set tc=tc+1
        else
            set n[i]=f
            set p[i]=0
            set p[f]=i
            set rf[r]=i
        endif
        return i
    endfunction
    private function DT takes integer t returns nothing
        debug if (0>ns[t]) then
            set ns[t]=ns[0]
            set ns[0]=t
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"TIMER LOOP ERROR: ATTEMPT TO DESTROY NULL TIMER")
        debug endif
    endfunction
    private function A takes code c returns integer
        local integer i = tgr[0]
        if (0 == i) then
            set i = tgc + 1
            set tgc = i
        else
            set tgr[0] = tgr[i]
        endif
        set rc[i]=Condition(c)
        return i
    endfunction
    private function A32 takes integer i returns nothing
        if (not e32[i]) then
            if (not ir32[i] and not id32[i]) then
                set ct[i] = TriggerAddCondition(t, rc[i])
            endif
            if (0 == tc) then
                call TimerStart(m,.031250000,true,function E)
            endif
            set tc = tc + 1
            set e32[i] = true
        endif
    endfunction
    private function SR32 takes integer i returns nothing
        if (e32[i]) then
            if (not ir32[i] and not id32[i]) then
                set i32r[i32cr] = i
                set i32cr = i32cr + 1
                set ir32[i] = true
            endif
            set e32[i] = false
            set tc = tc - 1
        endif
    endfunction
    private function DT32 takes integer i returns nothing
        if (not id32[i]) then
            if (not ir32[i]) then
                set ir32[i] = true
                set tc = tc - 1
                set i32r[i32cr] = i
                set i32cr = i32cr + 1
                set e32[i] = false
            endif
            set id32[i] = true
        endif
    endfunction
    private keyword r
    private keyword e
    module CTL
        static integer rctl32
        static method create takes nothing returns thistype
            return CT(rctl32)
        endmethod
        method destroy takes nothing returns nothing
            call DT(this)
        endmethod
        static method ectl32 takes nothing returns boolean
            local thistype this=rf[rctl32]
    endmodule
    module CTLExpire
            implement CTL
            loop
                exitwhen 0==this
    endmodule
    module CTLNull
                set this=n[this]
            endloop
    endmodule
    module CTLEnd
            implement CTLNull
            return false
        endmethod
        private static method onInit takes nothing returns nothing
            set rctl32 = A(function thistype.ectl32)
        endmethod
    endmodule
    module CT32
        static integer rctl32
        static method ectl32 takes nothing returns boolean
    endmodule
    module CT32End
            return false
        endmethod
        static method start takes nothing returns nothing
            call A32(rctl32)
        endmethod
        static method stop takes nothing returns nothing
            call SR32(rctl32)
        endmethod
        private static method onInit takes nothing returns nothing
            set rctl32 = A(function thistype.ectl32)
        endmethod
    endmodule
   
    struct TimerGroup32 extends array
        static method create takes code c returns thistype
            return A(c)
        endmethod
        method destroy takes nothing returns nothing
            call DT32(this)
        endmethod
        method start takes nothing returns nothing
            call A32(this)
        endmethod
        method stop takes nothing returns nothing
            call SR32(this)
        endmethod
    endstruct
endlibrary
//TESH.scrollpos=0
//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
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Event
//2.0.0.1
/////////////////////////////////////////////////////////////////////////
    //function CreateEvent takes nothing returns integer
    //function TriggerRegisterEvent takes trigger t, integer ev returns nothing
    //function RegisterEvent takes boolexpr c, integer ev returns nothing
    //function FireEvent takes integer ev returns nothing
   
    //struct Event extends array
        //static method create takes nothing returns thistype
        //method registerTrigger takes trigger t returns nothing
        //method register takes boolexpr c returns nothing
        //method fire takes nothing returns nothing
/////////////////////////////////////////////////////////////////////////
    globals
        private real q=0
    endglobals
    struct Event extends array
        private static integer w=0
        private static trigger array e
        static method create takes nothing returns thistype
            set w=w+1
            set e[w]=CreateTrigger()
            return w
        endmethod
        method registerTrigger takes trigger t returns nothing
            call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)
        endmethod
        method register takes boolexpr c returns nothing
            call TriggerAddCondition(e[this],c)
        endmethod
        method fire takes nothing returns nothing
            set q=0
            set q=this
            call TriggerEvaluate(e[this])
        endmethod
    endstruct
    function CreateEvent takes nothing returns Event
        return Event.create()
    endfunction
    function TriggerRegisterEvent takes trigger t,Event ev returns nothing
        call ev.registerTrigger(t)
    endfunction
    function RegisterEvent takes boolexpr c,Event ev returns nothing
        call ev.register(c)
    endfunction
    function FireEvent takes Event ev returns nothing
        call ev.fire()
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library WorldBounds
    //struct WorldBounds extends array

    //static readonly rect world
    //  same as GetWorldBounds()
   
    //static readonly region worldRegion
    //  contains world for triggers
   
    //static readonly real maxX
    //static readonly real maxY
    //static readonly real minX
    //static readonly real minY
    //static readonly real centerX
    //static readonly real centerY
   
    private module WorldBoundInit
        private static method onInit takes nothing returns nothing
            set world=GetWorldBounds()
            set maxX=GetRectMaxX(world)
            set maxY=GetRectMaxY(world)
            set minX=GetRectMinX(world)
            set minY=GetRectMinY(world)
            set centerX=(maxX+minX)/2
            set centerY=(minY+maxY)/2
            set worldRegion=CreateRegion()
            call RegionAddRect(worldRegion,world)
        endmethod
    endmodule
    struct WorldBounds extends array
        readonly static real maxX
        readonly static real maxY
        readonly static real minX
        readonly static real minY
        readonly static real centerX
        readonly static real centerY
        readonly static rect world
        readonly static region worldRegion
        implement WorldBoundInit
    endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CombatState requires UnitIndexer, Event, optional TimerUtils
    //******** COMBAT STATE ******************************************//
    //  - This library registers whether or not some unit is in combat.
    //  - To be registered as in combat, the unit must attack or have been attacked by an enemy unit.
    //  - Any spell that is cast by an opposing player onto the unit will flag them as in combat.
    //  - Being in combat only lasts a specific duration, in this case 5 seconds, before the unit leaves combat.
    //  - Once a unit dies, the dying unit will be taken out of combat.
   
    //  Requirements:
    //    -- UnitIndexer by Nestharus
    //    -- Event by Nestharus
    //       - This will allow you to register when a unit enters or leaves combat.
    //    -- *OPTIONAL* TimerUtils by Vexorian
    //       - This will recycle timers instead of creating/destroying them, so it is a bit more optimal. As far as speed goes,
    //         it is pretty negligible. Without TimerUtils, it will use a hashtable.
   
    //  API:
    //    Configurables:
    //       - COMBAT_DURATION: This determines the time before a unit is considered to be out of combat, default 5 seconds.
    //         The unit must remain unattacked and attack no one for COMBAT_DURATION to leave combat.
   
    //    Data Modify/Retrieve:
    //        CombatState[whichUnit].inCombat -> returns boolean
    //        set CombatState[whichUnit].inCombat = flag
   
    //    Function Wrappers:
    //        function GetUnitCombatState takes unit whichUnit returns boolean
    //           - This returns the combat state of a unit. If it returns true, the unit is in combat. If it returns false, then the unit
    //             is not in combat.
    //        function SetUnitCombatState takes unit whichUnit, boolean flag returns nothing
    //           - This allows you to force a unit in or out of combat, and it will register the corresponding events.
   
    //    If you are using Event:
    //        call CombatState.EnterCombat.register(trigger)
    //           - Registers when some unit enters combat after being out of combat.
    //        call CombatState.LeaveCombat.register(trigger)
    //           - Registers when some unit leaves combat after having been just in combat.
    //        function GetTriggerCombatUnit takes nothing returns unit
    //           - When using registering an event, this will basically return the unit who entered or left combat. GetTriggerCombatUnit()
   
    //    Credits:
    //       - Nestharus for UnitIndexer, Event, and optimizations
    //       - Darthfett for the original combat library
    //       - Vexorian for TimerUtils
    //****************************************************************//

    globals
        private constant real COMBAT_DURATION = 5
    //**************DO NOT EDIT PAST THIS POINT***********************//
        private unit combatUnit = null
        private hashtable Hash
    endglobals
   
    function GetTriggerCombatUnit takes nothing returns unit
        return combatUnit
    endfunction
   
    private module Init
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            static if not LIBRARY_TimerUtils then
                set Hash = InitHashtable()
            endif
            set thistype.ENTER = Event.create()
            set thistype.LEAVE = Event.create()
            call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ATTACKED)
            call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
            call UnitIndexer.DEINDEX.register(Condition(function thistype.deindex))
            call TriggerAddCondition(t,Condition(function thistype.CombatEnter))
        endmethod
    endmodule
   
    struct CombatState extends array
        private timer combatTimer
        private boolean inCombatV
       
        readonly static Event LEAVE = 0
        readonly static Event ENTER = 0
       
        static method operator [] takes unit u returns thistype
            return GetUnitUserData(u)
        endmethod
       
        private static method CombatLeave takes nothing returns nothing
            local timer t   = GetExpiredTimer()
            local unit prev = combatUnit
            static if LIBRARY_TimerUtils then
                local integer id  = GetTimerData(t)
                call ReleaseTimer(t)
            else
                local integer id  = LoadInteger(Hash,GetHandleId(t),0)
                call PauseTimer(t)
                call DestroyTimer(t)
                set t             = null
            endif
            set combatUnit               = GetUnitById(id)
            set thistype(id).inCombatV   = false
            set thistype(id).combatTimer = null
            call thistype.LEAVE.fire()
            set combatUnit               = prev
            set prev                     = null
        endmethod
       
        method operator inCombat takes nothing returns boolean
            return this.inCombatV
        endmethod
       
        method operator inCombat= takes boolean flag returns nothing
            local unit prev    = combatUnit
            set combatUnit     = GetUnitById(this)
            if flag then
                if this.combatTimer == null then
                    set this.inCombatV = true
                    call thistype.ENTER.fire()
                    static if LIBRARY_TimerUtils then
                        set this.combatTimer = NewTimer()
                        call SetTimerData(this.combatTimer,this)
                    else
                        set this.combatTimer = CreateTimer()
                        call SaveInteger(Hash,GetHandleId(this.combatTimer),0,this)
                    endif
                endif
                call TimerStart(this.combatTimer,COMBAT_DURATION,false,function thistype.CombatLeave)
            elseif (this.inCombatV) then
                set this.inCombatV = false
                static if LIBRARY_TimerUtils then
                    call ReleaseTimer(this.combatTimer)
                else
                    call PauseTimer(this.combatTimer)
                    call DestroyTimer(this.combatTimer)
                endif
                set this.combatTimer = null
                call thistype.LEAVE.fire()
            endif
            set combatUnit    = prev
            set prev          = null
        endmethod
       
        private static method CombatEnter takes nothing returns boolean
            local unit u = GetAttacker()
            if GetTriggerEventId()==EVENT_PLAYER_UNIT_DEATH then
                set thistype[GetTriggerUnit()].inCombat=false
                return false
            elseif u == null then
                set u = GetSpellTargetUnit()
            endif
            if u != null then
                if IsUnitEnemy(u,GetTriggerPlayer()) then
                    set thistype[GetTriggerUnit()].inCombat=true
                    set thistype[u].inCombat=true
                elseif CombatState[u].inCombat then
                    set thistype[GetTriggerUnit()].inCombat=true
                endif
            endif
            set u = null
            return false
        endmethod
       
        private static method deindex takes nothing returns boolean
            set thistype(GetIndexedUnitId()).inCombat=false
            return false
        endmethod
       
        implement Init
    endstruct
   
    function GetUnitCombatState takes unit whichUnit returns boolean
        return CombatState[whichUnit].inCombat
    endfunction
    function SetUnitCombatState takes unit whichUnit, boolean flag returns nothing
        set CombatState[whichUnit].inCombat = flag
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/**************************
*
*   Math
*   v1.0.0.0
*   By Magtheridon96
*
*   - The BJs suck, so I made this.
*
*
*
**************************/

library Math

    function RMin takes real a, real b returns real
        if a > b then
            return b
        endif
        return a
    endfunction
   
    function RMax takes real a, real b returns real
        if a > b then
            return a
        endif
        return b
    endfunction
   
    function IMin takes integer a, integer b returns integer
        if a > b then
            return b
        endif
        return a
    endfunction
   
    function IMax takes integer a, integer b returns integer
        if a > b then
            return a
        endif
        return b
    endfunction
   
    function IAbs takes integer a returns integer
        if a > 0 then
            return a
        endif
        return -a
    endfunction
   
    function RAbs takes real a returns real
        if a > 0 then
            return a
        endif
        return -a
    endfunction
   
    function GetDistanceBetween takes real x1, real y1, real x2, real y2 returns real
        local real x = x1 - x2
        local real y = y1 - y2
        return SquareRoot(x*x + y*y)
    endfunction
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
/**************************************************************
*
*      RegisterPlayerUnitEvent
*      v4.1.1.0
*      By Magtheridon96
*
*      This library was made to replace that GTrigger
*      monster by Jesus4Lyf at TheHelper. I would like
*      to give a special thanks to Bribe, azlier and BBQ
*      for improving this library. For modularity, it only
*      supports player unit events.
*
*      Functions passed to RegisterPlayerUnitEvent must
*      return false. They can return nothing as well.
*
*      API:
*      ----
*
*      function RegisterPlayerUnitEvent
*          takes
*              playerunitevent whichEvent          :   The event that will be registered.
*              code            whichFunction       :   The function that will fire when the event occurs.
*          returns
*              nothing
*
**************************************************************/

library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
    globals
        private trigger array t
    endglobals
    function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
        local integer i = GetHandleId(p)
        local integer k = 15
        if t[i] == null then
            set t[i] = CreateTrigger()
            loop
                call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
                exitwhen k == 0
                set k = k - 1
            endloop
        endif
        call TriggerAddCondition(t[i], Filter(c))
    endfunction
endlibrary
//TESH.scrollpos=12
//TESH.alwaysfold=0
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
//     RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
//     RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
//     Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
 
//============================================================================
private module M
   
    static if LIBRARY_Table then
        static Table tb
    else
        static hashtable ht = InitHashtable()
    endif
   
    static method onCast takes nothing returns nothing
        static if LIBRARY_Table then
            call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
        else
            call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
        endif
    endmethod
 
    private static method onInit takes nothing returns nothing
        static if LIBRARY_Table then
            set .tb = Table.create()
        endif
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
    endmethod
endmodule
 
//============================================================================
private struct S extends array
    implement M
endstruct
 
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
    static if LIBRARY_Table then
        if not S.tb.handle.has(abil) then
            set S.tb.trigger[abil] = CreateTrigger()
        endif
        call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
    else
        if not HaveSavedHandle(S.ht, 0, abil) then
            call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
        endif
        call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
    endif
endfunction
 
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library BinaryHeap /* v4.0.0.0
*************************************************************************************
*
*   Binary Heap
*
************************************************************************************
*
*   Interface:
*       private static method compare takes thistype value1, thistype value2 returns boolean
*           -   < for minimum heap
*           -   > for maximum heap
*
*   static readonly thistype root
*       -   The node with the smallest/biggest value
*   readonly thistype node
*       -   Node stored within heap position (array[heapPosition] = node)
*   readonly thistype heap
*       -   Heap position of node (array[heapPosition] = node)
*   static readonly integer size
*       -   Size of binary heap
*   readonly integer value
*       -   Sorted value (the value of the node)
*
*   method modify takes integer sortValue returns nothing
*       -   Modifies the value of the node
*
*   static method insert takes integer sortValue returns thistype
*       -   Inserts a new node into the heap and returns it
*       -   Assigns that node the passed in value
*   method delete takes nothing returns nothing
*       -   Deletes node from heap
*
*   static method clear takes nothing returns nothing
*       -   Clears the heap
*
************************************************************************************/

    module BinaryHeap
        readonly static integer size = 0
        readonly thistype node                      //node
        private static thistype instanceCount = 0   //node instance count
        private static thistype array recycler      //node recycler
        readonly thistype value
        readonly thistype heap
       
        static method operator root takes nothing returns thistype
            return thistype(1).node
        endmethod
       
        static method allocate takes thistype value returns thistype
            local thistype this = recycler[0]
           
            if (0 == this) then
                set this = instanceCount + 1
                set instanceCount = this
            else
                set recycler[0] = recycler[this]
            endif
           
            set this.value = value
            set node.heap = 0
           
            return this
        endmethod
        method deallocate takes nothing returns nothing
            set recycler[this]=recycler[0]
            set recycler[0]=this
        endmethod
       
        private method link takes thistype heapPosition returns nothing
            set heapPosition.node = this
            set heap = heapPosition
        endmethod
       
        private method bubbleUp takes nothing returns nothing
            local thistype value = this.value
            local thistype heapPosition = heap
           
            local thistype parent
           
            /*
            *   Bubble node up
            */

            loop
                set parent = heapPosition/2
               
                exitwhen (0 == parent or compare(parent.node.value, value))
               
                set heapPosition.node = parent.node
                set heapPosition.node.heap = heapPosition
               
                set heapPosition = parent
            endloop
           
            /*
            *   Update pointers
            */

            call link(heapPosition)
        endmethod
        private method bubbleDown takes nothing returns nothing
            local thistype value = this.value
            local thistype heapPosition = heap
           
            local thistype left
            local thistype right
           
            /*
            *   Bubble node down
            */

            loop
                set left = heapPosition*2
                set right = left + 1
               
                exitwhen (0 == left.node or compare(value, left.node.value)) and (0 == right.node or compare(value, right.node.value))
               
                if (0 == right.node.value or (0 != left.node and compare(left.node.value, right.node.value))) then
                    /*
                    *   Go left
                    */

                    set heapPosition.node = left.node
                    set heapPosition.node.heap = heapPosition
                    set heapPosition = left
                else
                    /*
                    *   Go right
                    */

                    set heapPosition.node = right.node
                    set heapPosition.node.heap = heapPosition
                    set heapPosition = right
                endif
            endloop
           
            /*
            *   Update pointers
            */

            call link(heapPosition)
        endmethod
       
        method modify takes integer value returns nothing
            set this.value = value
           
            /*
            *   Bubble node into correct position
            */

            call bubbleUp()
            call bubbleDown()
        endmethod
       
        static method insert takes thistype value returns thistype
            local thistype heapPosition
            local thistype this
           
            /*
            *   Allocate new node
            */

            set this = allocate(value)
           
            /*
            *   Increase heap size
            */

            set heapPosition = size + 1
            set size = heapPosition
           
            /*
            *   Store node in last heap position
            */

            call link(heapPosition)
           
            /*
            *   Bubble node into correct position
            */

            call bubbleUp()
           
            return this
        endmethod
        method delete takes nothing returns nothing
            local thistype lastNode
           
            debug if (0 == size) then
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Attempted To Delete Node From Empty Heap")
                debug set this = 1/0
            debug endif

            /*
            *   Deallocate node
            */

            call deallocate()
           
            /*
            *   Remove last node from last position
            */

            set lastNode = thistype(size).node
            set thistype(size).node = 0
            set size = size - 1
           
            if (lastNode != node) then
                /*
                *   Put last node in deallocated node's position
                */

                call lastNode.link(heap)
               
                /*
                *   Bubble into correct spot
                */

                call lastNode.bubbleUp()
                call lastNode.bubbleDown()
            endif
        endmethod
        static method clear takes nothing returns nothing
            set size = 0
            set recycler[0] = 0
            set instanceCount = 0
            set thistype(1).node = 0
        endmethod
    endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library PriorityEvent /* v2.0.0.1
*************************************************************************************
*
*   Creates events that fire given a priority. A higher priority means that those
*   events will fire first. A priority of 0 means that those events will fire last.
*
*   Priority events can only be created at map init
*   Code can only be registered to priority events at map init
*
*************************************************************************************
*
*   */
uses/*
*
*       */
AVL          /*          hiveworkshop.com/forums/jass-resources-412/snippet-avl-tree-203168/
*
************************************************************************************
*
*   struct PriorityEvent extends array
*
*       static method create takes nothing returns thistype
*       method register takes boolexpr func, integer priority returns nothing
*       method fire takes nothing returns nothing
*
************************************************************************************/

    private struct PriorityEventTree extends array
        method lessThan takes thistype value returns boolean
            return integer(this) < integer(value)
        endmethod
       
        method greaterThan takes thistype value returns boolean
            return integer(this) > integer(value)
        endmethod
       
        implement AVL
    endstruct

    private module PriorityEventMod
        private static integer instanceCount = 0
       
        /*
        *   A queue of code registered with the same priority
        */

        private thistype next_p
        private thistype last_p
        private thistype first_p
       
        /*
        *   The priorities are stored in the tree list
        */

       
        /*
        *   Iterate from 0 to count to go over all created events
        */

        private static PriorityEventTree count = 0
        private static PriorityEventTree array tree
       
        /*
        *   This is a temporary trigger to store all code of the same priority
        *   Once the game has started, all code will be merged on to one trigger
        */

        private trigger event
       
        /*
        *   Need to store the code in order to merge all it all on to one trigger
        */

        private boolexpr code
       
        /*
        *   All code is merged on this
        */

        private trigger allEvent
       
        /*
        *   Has the code all been merged?
        */

        private static boolean merged = false
       
        static method create takes nothing returns thistype
            local thistype this
           
            debug if (merged) then
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Priority Event Error: Can Only Create Events On Game Init")
                debug set this = 1/0
            debug endif
           
            /*
            *   Allocate new event
            */

            set this = PriorityEventTree.create()
           
            /*
            *   Add to array for merging later
            */

            set tree[count] = this
            set count = count + 1
           
            /*
            *   Create the merging trigger
            */

            set thistype(count).allEvent = CreateTrigger()
           
            return count
        endmethod
   
        method register takes boolexpr func, integer priority returns nothing
            local thistype node
           
            debug if (merged) then
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Priority Event Error: Can Only Register Code On Game Init")
                debug set node = 1/0
            debug endif
           
            /*
            *   Allocate a new node to store the function
            */

            set node = instanceCount + 1
            set instanceCount = node
           
            set node.code = func
           
            /*
            *   Retrieve the priority. This will act as the pointer to
            *   the queue that the node will be added to.
            */

            set this = PriorityEventTree(this).add(priority)
           
            if (null == event) then
                /*
                *   If the queue hasn't been created yet, create it
                */

                set event = CreateTrigger()
               
                set first_p = node
                set last_p = node
            else
                /*
                *   Add node to queue
                */

                set last_p.next_p = node
                set last_p = node
            endif
           
            call TriggerAddCondition(event, func)
        endmethod
       
        method fire takes nothing returns nothing
            if (merged) then
                /*
                *   If the code has all been merged (game started), evaluate the trigger that contains all code
                */

                call TriggerEvaluate(allEvent)
            else
                /*
                *   If the code hasn't been merged yet, evaluate all of the triggers along the priority queue
                */

                loop
                    set this = PriorityEventTree(this).prev
                    exitwhen PriorityEventTree(this).head
                    call TriggerEvaluate(event)
                endloop
            endif
        endmethod
       
        /*
        *   This is called when the game starts. It merges all of the registered code
        *   for each event on to single triggers to improve performance
        */

        private static method merge takes nothing returns nothing
            local thistype this
            local integer current = count
            local PriorityEventTree priority
            local thistype node
           
            set merged = true
           
            /*
            *   Iterate over all events
            */

            loop
                exitwhen 0 == current
                set current = current - 1
                set this = tree[current]
               
                /*
                *   Iterate over all priorities
                */

                set priority = this
                loop
                    set priority = priority.prev
                    exitwhen priority.head
                   
                    /*
                    *   Clean up temporary priority event trigger
                    */

                    call TriggerClearConditions(thistype(priority).event)
                    call DestroyTrigger(thistype(priority).event)
                    set thistype(priority).event = null
                   
                    /*
                    *   Iterate over all registered code on the priority trigger
                    */

                    set node = thistype(priority).first_p
                    loop
                        exitwhen 0 == node
                       
                        /*
                        *   Add to main trigger
                        */

                        call TriggerAddCondition(allEvent, node.code)
                       
                        set node = node.next_p
                    endloop
                endloop
            endloop
       
            call DestroyTimer(GetExpiredTimer())
        endmethod
       
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), 0, false, function thistype.merge)
        endmethod
    endmodule
    struct PriorityEvent extends array
        implement PriorityEventMod
    endstruct
endlibrary
//TESH.scrollpos=149
//TESH.alwaysfold=0
library UnitIndexer /* v4.0.2.6
*************************************************************************************
*
*   Assigns unique indexes to units via unit user data.
*
*************************************************************************************
*
*   */
uses/*
*
*       */
WorldBounds  /*      hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
*       */
Event        /*      hiveworkshop.com/forums/submissions-414/snippet-event-186555/
*
************************************************************************************
*
*    Functions
*
*       function RegisterUnitIndexEvent takes boolexpr codeToRegister, Event unitIndexEvent returns nothing
*       function TriggerRegisterUnitIndexEvent takes trigger triggerToRegister, Event unitIndexEvent returns nothing
*
*       function GetUnitById takes integer index returns unit
*           -   Returns unit given a unit index
*       function GetUnitId takes unit u returns integer
*           -   Returns unit index given a unit
*
*       function IsUnitIndexed takes unit u returns boolean
*       function IsUnitDeindexing takes unit u returns boolean
*
*       function GetIndexedUnitId takes nothing returns integer
*       function GetIndexedUnit takes nothing returns unit
*
************************************************************************************
*
*   module UnitIndexStructMethods
*       static method operator [] takes unit u returns thistype
*           -   Return GetUnitUserData(u)
*
*       readonly unit unit
*           -   The indexed unit of the struct
*
************************************************************************************
*
*   module UnitIndexStruct extends UnitIndexStructMethods
*
*       -   A pseudo module interface that runs a set of methods if they exist and provides
*       -   a few fields and operators. Runs on static ifs to minimize code.
*
*       readonly boolean allocated
*           -   Is unit allocated for the struct
*
*       Interface:
*
*           -   These methods don't have to exist. If they don't exist, the code
*           -   that calls them won't even be in the module.
*
*           private method index takes nothing returns nothing
*               -   called when a unit is indexed and passes the filter.
*               -
*               -   thistype this:              Unit's index
*           private method deindex takes nothing returns nothing
*               -   called when a unit is deindexed and is allocated for struct
*               -
*               -   thistype this:              Unit's index
*           private static method filter takes unit unitToIndex returns boolean
*               -   Determines whether or not to allocate struct for unit
*               -
*               -   unit unitToIndex:           Unit being filtered
*
************************************************************************************
*
*   struct UnitIndexer extends array
*
*        -    Controls the unit indexer system.
*
*       static constant Event UnitIndexer.INDEX
*       static constant Event UnitIndexer.DEINDEX
*           -   Don't register functions and triggers directly to the events. Register them via
*           -   RegisterUnitIndexEvent and TriggerRegisterUnitIndexEvent.
*
*       static boolean enabled
*           -   Enables and disables unit indexing. Useful for filtering out dummy units.
*
************************************************************************************
*
*   struct UnitIndex extends UnitIndexStructMethods
*
*       -    Constrols specific unit indexes.
*
*       method lock takes nothing returns nothing
*           -   Locks an index. When an index is locked, it will not be recycled
*           -   when the unit is deindexed until all locks are removed. Deindex
*           -   events still fire at the appropriate times, the index just doesn't
*           -   get thrown into the recycler.
*       method unlock takes nothing returns nothing
*           -   Unlocks an index.
*
************************************************************************************/

    globals
        private constant integer ABILITIES_UNIT_INDEXER = 'A!!!'
        private trigger q=CreateTrigger()
        private trigger l=CreateTrigger()
        private unit array e
        private integer r=0
        private integer y=0
        private integer o=0
        private boolean a=false
        private integer array n
        private integer array p
        private integer array lc
    endglobals
    function GetIndexedUnitId takes nothing returns integer
        return o
    endfunction
    function GetIndexedUnit takes nothing returns unit
        return e[o]
    endfunction
    //! runtextmacro optional UNIT_LIST_LIB()
    private struct PreLoader extends array
        public static method run takes nothing returns nothing
            call DestroyTimer(GetExpiredTimer())
            set a=true
        endmethod
        public static method eval takes trigger t returns nothing
            local integer f=n[0]
            local integer d=o
            loop
                exitwhen 0==f
                if (IsTriggerEnabled(t)) then
                    set o=f
                    if (TriggerEvaluate(t)) then
                        call TriggerExecute(t)
                    endif
                else
                    exitwhen true
                endif
                set f=n[f]
            endloop
            set o=d
        endmethod
        public static method evalb takes boolexpr c returns nothing
            local trigger t=CreateTrigger()
            local thistype f=n[0]
            local integer d=o
            call TriggerAddCondition(t,c)
            loop
                exitwhen 0==f
                set o=f
                call TriggerEvaluate(t)
                set f=n[f]
            endloop
            call DestroyTrigger(t)
            set t=null
            set o=d
        endmethod
    endstruct
    //! runtextmacro optional UNIT_EVENT_MACRO()
    private module UnitIndexerInit
        private static method onInit takes nothing returns nothing
            local integer i=15
            local boolexpr bc=Condition(function thistype.onLeave)
            local boolexpr bc2=Condition(function thistype.onEnter)
            local group g=CreateGroup()
            local player p
            set INDEX=CreateEvent()
            set DEINDEX=CreateEvent()
            call TriggerRegisterEnterRegion(q,WorldBounds.worldRegion,bc2)
            loop
                set p=Player(i)
                call TriggerRegisterPlayerUnitEvent(l,p,EVENT_PLAYER_UNIT_ISSUED_ORDER,bc)
                call SetPlayerAbilityAvailable(p,ABILITIES_UNIT_INDEXER,false)
                call GroupEnumUnitsOfPlayer(g,p,bc2)
                exitwhen 0==i
                set i=i-1
            endloop
            call DestroyGroup(g)
            set bc=null
            set g=null
            set bc2=null
            set p=null
            call TimerStart(CreateTimer(),0,false,function PreLoader.run)
        endmethod
    endmodule
    struct UnitIndex extends array
        method lock takes nothing returns nothing
            debug if (null!=e[this]) then
                set lc[this]=lc[this]+1
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO LOCK NULL INDEX")
            debug endif
        endmethod
        method unlock takes nothing returns nothing
            debug if (0<lc[this]) then
                set lc[this]=lc[this]-1
                if (0==lc[this] and null==e[this]) then
                    set n[this]=y
                    set y=this
                endif
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO UNLOCK UNLOCKED INDEX")
            debug endif
        endmethod
        method operator unit takes nothing returns unit
            return e[this]
        endmethod
        static method operator [] takes unit whichUnit returns thistype
            return GetUnitUserData(whichUnit)
        endmethod
    endstruct
    struct UnitIndexer extends array
        readonly static Event INDEX
        readonly static Event DEINDEX
        static boolean enabled=true
        private static method onEnter takes nothing returns boolean
            local unit Q=GetFilterUnit()
            local integer i
            local integer d=o
            if (enabled and Q!=e[GetUnitUserData(Q)]) then
                if (0==y) then
                    set r=r+1
                    set i=r
                else
                    set i=y
                    set y=n[y]
                endif
                call UnitAddAbility(Q,ABILITIES_UNIT_INDEXER)
                call UnitMakeAbilityPermanent(Q,true,ABILITIES_UNIT_INDEXER)
                call SetUnitUserData(Q,i)
                set e[i]=Q
                static if not LIBRARY_UnitList then
                    if (not a)then
                        set p[i]=p[0]
                        set n[p[0]]=i
                        set n[i]=0
                        set p[0]=i
                    endif
                else
                    set p[i]=p[0]
                    set n[p[0]]=i
                    set n[i]=0
                    set p[0]=i
                    call GroupAddUnit(g,e[i])
                endif
                set o=i
                call FireEvent(INDEX)
                set o=d
            endif
            set Q=null
            return false
        endmethod
        private static method onLeave takes nothing returns boolean
            static if LIBRARY_UnitEvent then
                implement optional UnitEventModule
            else
                local unit u=GetFilterUnit()
                local integer i=GetUnitUserData(u)
                local integer d=o
                if (0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER) and u==e[i]) then
                    static if not LIBRARY_UnitList then
                        if (not a)then
                            set n[p[i]]=n[i]
                            set p[n[i]]=p[i]
                        endif
                    else
                        set n[p[i]]=n[i]
                        set p[n[i]]=p[i]
                        call GroupRemoveUnit(g,e[i])
                    endif
                    set o=i
                    call FireEvent(DEINDEX)
                    set o=d
                    if (0==lc[i]) then
                        set n[i]=y
                        set y=i
                    endif
                    set e[i]=null
                endif
                set u=null
            endif
            return false
        endmethod
        implement UnitIndexerInit
    endstruct
    //! runtextmacro optional UNIT_EVENT_MACRO_2()
    function RegisterUnitIndexEvent takes boolexpr c,integer ev returns nothing
        call RegisterEvent(c, ev)
        if (not a and ev==UnitIndexer.INDEX and 0!=n[0]) then
            call PreLoader.evalb(c)
        endif
    endfunction
    function TriggerRegisterUnitIndexEvent takes trigger t,integer ev returns nothing
        call TriggerRegisterEvent(t,ev)
        if (not a and ev == UnitIndexer.INDEX and 0!=n[0]) then
            call PreLoader.eval(t)
        endif
    endfunction
    function GetUnitById takes integer W returns unit
        return e[W]
    endfunction
    function GetUnitId takes unit u returns integer
        return GetUnitUserData(u)
    endfunction
    function IsUnitIndexed takes unit u returns boolean
        return u==e[GetUnitUserData(u)]
    endfunction
    function IsUnitDeindexing takes unit u returns boolean
        return IsUnitIndexed(u) and 0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER)
    endfunction
    module UnitIndexStructMethods
        static method operator [] takes unit u returns thistype
            return GetUnitUserData(u)
        endmethod
        method operator unit takes nothing returns unit
            return e[this]
        endmethod
    endmodule
    module UnitIndexStruct
        implement UnitIndexStructMethods
       
        static if thistype.filter.exists then
            static if thistype.index.exists then
                static if thistype.deindex.exists then
                    readonly boolean allocated
                else
                    method operator allocated takes nothing returns boolean
                        return filter(e[this])
                    endmethod
                endif
            else
                method operator allocated takes nothing returns boolean
                    return filter(e[this])
                endmethod
            endif
        elseif (thistype.index.exists) then
            static if thistype.deindex.exists then
                readonly boolean allocated
            else
                method operator allocated takes nothing returns boolean
                    return this==GetUnitUserData(e[this])
                endmethod
            endif
        else
            method operator allocated takes nothing returns boolean
                return this==GetUnitUserData(e[this])
            endmethod
        endif
        static if thistype.index.exists then
            private static method onIndexEvent takes nothing returns boolean
                static if thistype.filter.exists then
                    if (filter(e[o])) then
                        static if thistype.deindex.exists then
                            set thistype(o).allocated=true
                        endif
                        call thistype(o).index()
                    endif
                else
                    static if thistype.deindex.exists then
                        set thistype(o).allocated=true
                    endif
                    call thistype(o).index()
                endif
                return false
            endmethod
        endif
        static if thistype.deindex.exists then
            private static method onDeindexEvent takes nothing returns boolean
                static if thistype.filter.exists then
                    static if thistype.index.exists then
                        if (thistype(o).allocated) then
                            set thistype(o).allocated=false
                            call thistype(o).deindex()
                        endif
                    else
                        if (filter(e[o])) then
                            call thistype(o).deindex()
                        endif
                    endif
                else
                    static if thistype.index.exists then
                        set thistype(o).allocated=false
                    endif
                    call thistype(o).deindex()
                endif
                return false
            endmethod
        endif
        static if thistype.index.exists then
            static if thistype.deindex.exists then
                private static method onInit takes nothing returns nothing
                    call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
                    call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
                endmethod
            else
                private static method onInit takes nothing returns nothing
                    call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
                endmethod
            endif
        elseif thistype.deindex.exists then
            private static method onInit takes nothing returns nothing
                call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
            endmethod
        endif
    endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AVL /* v1.1.0.6
*************************************************************************************
*
*   An AVL Tree where all nodes are connected by an AVL tree, a linked list, and
*   are referenced by a hashtable.
*
*************************************************************************************
*
*   */
uses/*
*  
*       */
Table /*         hiveworkshop.com/forums/jass-functions-413/snippet-new-table-188084/
*
************************************************************************************
*
*   module AVLTree
*
*       Interface:
*           method lessThan takes thistype value returns boolean
*           method greaterThan takes thistype value returns boolean
*
*       readonly thistype tree
*           -   Tree pointer. Accessible from any node on the tree.
*       readonly thistype root
*           -   Root of two children (if root is 0, it's the tree's root)
*       readonly thistype left
*       readonly thistype right
*       readonly thistype down (tree pointer only)
*           -   The tree has only 1 child, the root
*
*       readonly thistype next
*       readonly thistype prev
*       readonly boolean head
*
*       readonly thistype value
*           -   Value stored in node
*
*       static method create takes nothing returns thistype
*       method destroy takes nothing returns nothing
*
*       method search takes thistype value returns thistype
*           -   Returns the node containing the value
*           -   If the value didn't exist, it will return 0
*       method searchClose takes thistype value, boolean low returns thistype
*           -   Searches for the best match to the value.
*           -
*           -   Low = True
*           -       Search for the closest value <= to the target value
*           -
*           -   Low = False
*           -       Search for the closest value >= to the target value
*
*       method has takes thistype value returns boolean
*           -   Returns true if a node contains the value
*
*       method add takes thistype value returns thistype
*           -   Returns new node containing added value. If the value
*           -   was already in the tree, it returns the node that already
*           -   contained that value.
*       method delete takes nothing returns nothing
*           -   Deletes node
*
*           ->  Delete the value 15 from the tree if it exists
*           ->  call search(15).delete()
*
*       method clear takes nothing returns thistype
*           -   Clears the tree of all nodes
*           -   Returns tree pointer (just in case some node in the tree was passed in rather than the tree)
*
************************************************************************************/

    module AVL
        private static Table array table    //for O(1) searches on specific values
        private static thistype c=0         //instance count
        private static thistype array b     //root
        private static thistype array l     //left
        private static thistype array r     //right
        private static integer array h      //height
        private static thistype array p     //parent
        private static thistype array v     //value
        private static integer array nn     //next node
        private static integer array pn     //prev node
        private static integer array ro     //root
        method operator tree takes nothing returns thistype
            return ro[this]
        endmethod
        method operator root takes nothing returns thistype
            return p[this]
        endmethod
        method operator down takes nothing returns thistype
            return b[this]
        endmethod
        method operator left takes nothing returns thistype
            return l[this]
        endmethod
        method operator right takes nothing returns thistype
            return r[this]
        endmethod
        method operator value takes nothing returns thistype
            return v[this]
        endmethod
        method operator next takes nothing returns thistype
            return nn[this]
        endmethod
        method operator prev takes nothing returns thistype
            return pn[this]
        endmethod
        method operator head takes nothing returns boolean
            return 0==p[this]
        endmethod
        private method getHeight takes nothing returns integer
            //return the bigger leaf height
            if (h[l[this]]>h[r[this]]) then
                return h[l[this]]+1
            endif
            return h[r[this]]+1
        endmethod
        private method updateParent takes integer n returns nothing
            //only update the parent of a target leaf if that leaf isn't the original leaf
            if (n!=this) then
                //update the parent point to
                //first leaf
                if (0==p[p[this]]) then
                    set b[p[this]]=n
                //left
                elseif (l[p[this]]==this) then
                    set l[p[this]]=n
                //right
                else
                    set r[p[this]]=n
                endif
               
                //update the leaf point back
                //if the leaf isn't null, update the leaf's parent
                if (0!=n) then
                    set p[n]=p[this]
                endif
            endif
        endmethod
        private method finishRotate takes thistype n returns nothing
            //this code is identical in rotateLeft and rotateRight, so it has
            //been abstracted to a method
            call updateParent(n)
            set p[this]=n
            set h[this]=getHeight()
            set h[n]=n.getHeight()
        endmethod
        private method rotateLeft takes nothing returns thistype
            local thistype n=r[this]
            set r[this]=l[n]
            set p[l[n]]=this
            set l[n]=this
            call finishRotate(n)
            return n
        endmethod
        private method rotateRight takes nothing returns thistype
            local thistype n=l[this]
            set l[this]=r[n]
            set p[r[n]]=this
            set r[n]=this
            call finishRotate(n)
            return n
        endmethod
        //return the difference between the left and right leaf heights
        private method getBalanceFactor takes nothing returns integer
            return h[l[this]]-h[r[this]]
        endmethod
        private static method allocate takes nothing returns thistype
            local integer n
            if (0==nn[0]) then
                set n=c+1
                set c=n
            else
                set n=nn[0]     //notice that the recycler uses the next pointer
                                //the reason it is used is for fast clear/destroy and to save
                                //a variable
                set nn[0]=nn[n]
            endif
            set l[n]=0          //left leaf
            set r[n]=0          //right leaf
            set b[n]=0          //down leaf (first node of tree)
            set h[n]=1          //height (a node will always have at least a height of 1 for itself)
            return n
        endmethod
        static method create takes nothing returns thistype
            local integer n=allocate()
            set p[n]=0      //the parent of the tree node is 0
           
            //initialize tree next and prev
            set nn[n]=n
            set pn[n]=n
           
            //tree value table for O(1) searches on specific values
            set table[n]=Table.create()
           
            //tree root is itself (allows one to pass any node from the tree into the methods)
            set ro[n]=n
           
            return n
        endmethod
        //balance from the current node up to the root O(log n)
        //balancing is rotations wherever rotations need to be done
        private method balance takes nothing returns nothing
            local integer f
            loop
                exitwhen 0==p[this]
                set h[this]=getHeight()
                set f=getBalanceFactor()
                if (2==f) then
                    if (-1==l[this].getBalanceFactor()) then
                        call l[this].rotateLeft()
                    endif
                    set this=rotateRight()
                    return
                elseif (-2==f) then
                    if (1==r[this].getBalanceFactor()) then
                        call r[this].rotateRight()
                    endif
                    set this=rotateLeft()
                    return
                endif
                set this=p[this]
            endloop
        endmethod
        //goes to the very bottom of a node (for deletion)
        private method getBottom takes nothing returns thistype
            if (0!=r[this]) then
                if (0!=l[this]) then
                    set this=r[this]
                    loop
                        exitwhen 0==l[this]
                        set this=l[this]
                    endloop
                    return this
                else
                    return r[this]
                endif
            elseif (0!=l[this]) then
                return l[this]
            endif
            return this
        endmethod
        method search takes thistype val returns thistype
            return table[ro[this]][val]
        endmethod
        method has takes thistype val returns boolean
            return table[ro[this]].has(val)
        endmethod
        method searchClose takes thistype val, boolean low returns thistype
            local thistype n
           
            //retrieve tree
            set this=ro[this]
           
            //if tree is empty, return 0
            if (0==b[this]) then
                return 0
            endif
           
            //check to see if the node exists in the tree and return it if it does
            set n=table[this][val]
            if (0!=n) then
                return n
            endif
           
            //perform a standard tree search for the value to the bottom of the tree
            //will always be at most 1 off from the best match
            set this=b[this]
            loop
                if (val.lessThan(v[this])) then
                    exitwhen 0==l[this]
                    set this=l[this]
                else
                    exitwhen 0==r[this]
                    set this=r[this]
                endif
            endloop
           
            //look at the found value's neighbors on the linked list
            if (low) then
                //shift down if greater than
                if (v[this].greaterThan(val)) then
                    set this=prev
                endif
                //return 0 if node wasn't found
                if (0==p[this] or v[this].greaterThan(val)) then
                    return 0
                endif
            else
                //shift up if less than
                if (v[this].lessThan(val)) then
                    set this=next
                endif
                //return 0 if node wasn't found
                if (0==p[this] or v[this].lessThan(val)) then
                    return 0
                endif
            endif
           
            return this
        endmethod
        method add takes thistype val returns thistype
            local thistype n
           
            //check if the tree already has the value in it
            set this=ro[this]
            set n=table[this][val]
           
            //if the tree doesn't have the value in it, add the value
            if (0==n) then
                set n=this
           
                set this=allocate()
                set ro[this]=n              //store tree into leaf
                set table[n][val]=this      //store leaf into value table
                set v[this]=val             //store value into leaf
               
                //if the tree is empty
                if (0==b[n]) then
                    set b[n]=this           //place as first node
                    set p[this]=n           //parent of first node is tree
                   
                    //add to list
                    set nn[this]=n
                    set pn[this]=n
                    set nn[n]=this
                    set pn[n]=this
                else
                    //go to the first node in the tree
                    set n=b[n]
                   
                    //go to the bottom of the tree with search algorithm
                    loop
                        if (val.lessThan(v[n])) then
                            exitwhen 0==l[n]
                            set n=l[n]
                        else
                            exitwhen 0==r[n]
                            set n=r[n]
                        endif
                    endloop
                   
                    //add leaf to tree
                    set p[this]=n
                    if (val.lessThan(v[n])) then
                        set l[n]=this
                    else
                        set r[n]=this
                    endif
                   
                    //update the height of the parent
                    set h[n]=n.getHeight()
                   
                    //balance from the parent upwards
                    call p[n].balance()
                   
                    //add leaf to list
                    if (v[n].greaterThan(v[this])) then
                        set n=pn[n]
                    endif
                    set nn[this]=nn[n]
                    set pn[this]=n
                    set pn[nn[n]]=this
                    set nn[n]=this
                endif
                return this
            endif
            return n
        endmethod
        method delete takes nothing returns nothing
            local thistype n
            local thistype y
           
            //if the leaf to be deleted isn't 0 and the leaf isn't the tree
            if (0 != this and 0 != p[this]) then
                //remove the leaf from the value table
                call table[ro[this]].remove(v[this])
               
                set n=getBottom()       //retrieve the bottom leaf
                set y=p[n]              //store the parent here for balancing later
               
                //move the found leaf into the deleted leaf's position
                call n.updateParent(0)
                call updateParent(n)
                if (this!=n) then
                    set l[n]=l[this]
                    set p[l[n]]=n
                    set r[n]=r[this]
                    set p[r[n]]=n
                    set p[n]=p[this]
                    set h[n]=h[this]
                endif
               
                //balance from the found leaf's old parent upwards
                call y.balance()
               
                //remove deleted leaf from list
                set nn[pn[this]]=nn[this]
                set pn[nn[this]]=pn[this]
                set nn[this]=nn[0]
                set nn[0]=this
            endif
        endmethod
        method clear takes nothing returns thistype
            //quick clear
            set this=ro[this]
            if (nn[this] != this) then
                set nn[pn[this]]=nn[0]
                set nn[0]=nn[this]
                set nn[this]=this
                set pn[this]=this
                set b[this] = 0
                call table[this].flush()
            endif
            return this
        endmethod
        method destroy takes nothing returns nothing
            //quick destroy
            set this=ro[this]
            set nn[pn[this]]=nn[0]
            set nn[0]=this
            call table[this].destroy()
        endmethod
    endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DamageEvent /* v3.1.1.3
*************************************************************************************
*
*   Simple light damage detection. Will not run 0 damage events as only invalid attacks and spells can cause these.
*   Can instance spells and attacks with fireSpell and fireAttack methods.
*
*************************************************************************************
*
*   */
uses/*
*
*       */
UnitIndexer      /*      hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*       */
PriorityEvent    /*      hiveworkshop.com/forums/submissions-414/snippet-priority-event-213573/
*       */
BinaryHeap       /*      hiveworkshop.com/forums/jass-resources-412/snippet-binary-heap-199353/
*
************************************************************************************
*
*   SETTINGS
*/

globals
    /*************************************************************************************
    *
    *   How many units can refresh at a given moment (when a trigger is rebuilt).
    *   larger size means less triggers but harder refreshes.
    *
    *************************************************************************************/

    private constant integer TRIGGER_SIZE = 80
endglobals
/*
*************************************************************************************
*
*   struct DamageEvent extends array
*
*       Fields
*       ------------------
*       static constant PriorityEvent ANY
*
*       readonly static UnitIndex targetId
*       readonly static UnitIndex sourceId
*       readonly static unit target
*       readonly static unit source
*       readonly static real amount
*       readonly static integer depth
*           -   if depth == 1, then current damage is the original attack, not a modifier
*
*       static boolean enabled
*
*       readonly static integer damageType
*           -   useful for custom attack types (spell, hero, chaos, etc)
*       readonly static integer damageId
*           -   useful for things like ability ids
*       readonly static integer instance
*           -   useful for passing in a struct
*
*       Methods
*       ------------------
*       static method unitDamageTarget takes unit attacker, widget target, real amount, integer damageType, integer damageId, integer instance returns boolean
*
*************************************************************************************
*
*   module ExtendDamageEvent extends DamageEvent, AdvDamageEvent (if exists)
*
*   module DamageEvent extends DamageEvent, AdvDamageEvent (if exists)
*
*       Interface
*       ------------------
*           private static constant method PRIORITY takes nothing returns integer       (optional)
*               -   without this declared, the priority will be set to 0 (no priority)
*           private static method onDamage takes nothing returns nothing                (optional)
*           private static method filter takes nothing returns boolean                  (optional)
*
*************************************************************************************/

    private struct DamageEventProperties extends array
        static method operator target takes nothing returns unit
            return GetUnitById(DamageEvent.targetId)
        endmethod
        static method operator source takes nothing returns unit
            return GetUnitById(DamageEvent.sourceId)
        endmethod
    endstruct

    //! runtextmacro optional ADV_DAMAGE_EVENT_EXT_CODE()
   
    globals
        private boolexpr damageCondition
    endglobals
   
    private struct DamageTrigger extends array
        private static integer instanceCount = 0
   
        private thistype first
        private thistype next
        private thistype prev
        readonly thistype parent
       
        private integer inactiveUnits
        readonly integer activeUnits
       
        private trigger damageTrigger
       
        private method registerUnit takes UnitIndex whichUnit returns boolean
            if (activeUnits < TRIGGER_SIZE) then
                call TriggerRegisterUnitEvent(damageTrigger, GetUnitById(whichUnit), EVENT_UNIT_DAMAGED)
                set activeUnits = activeUnits + 1
               
                return true
            endif
           
            return false
        endmethod
        private method unregisterUnit takes UnitIndex whichUnit returns nothing
            set inactiveUnits = inactiveUnits + 1
            set activeUnits = activeUnits - 1
        endmethod
       
        private method createTrigger takes nothing returns nothing
            set damageTrigger = CreateTrigger()
            call TriggerAddCondition(damageTrigger, damageCondition)
        endmethod
        private method remakeTrigger takes nothing returns nothing
            call DestroyTrigger(damageTrigger)
            call createTrigger()
        endmethod
        private method rebuildTrigger takes nothing returns nothing
            local thistype current = first
           
            call remakeTrigger()
           
            /*
            *   Iterate over all units registered to the trigger and reregister them
            */

            set current.prev.next = 0
            loop
                exitwhen 0 == current
                call TriggerRegisterUnitEvent(damageTrigger, GetUnitById(current), EVENT_UNIT_DAMAGED)
                set current = current.next
            endloop
            set first.prev.next = current
        endmethod
       
        private method remake takes nothing returns nothing
            if (inactiveUnits == TRIGGER_SIZE) then
                set inactiveUnits = 0
                call rebuildTrigger()
            endif
        endmethod
       
        private method addToList takes thistype whichUnit returns nothing
            set whichUnit.parent = this
       
            if (0 == first) then
                set first = whichUnit
                set whichUnit.next = whichUnit
                set whichUnit.prev = whichUnit
            else
                set this = first
               
                set whichUnit.prev = prev
                set whichUnit.next = this
                set prev.next = whichUnit
                set prev = whichUnit
            endif
        endmethod
        method add takes thistype whichUnit returns boolean
            if (0 == this) then
                return false
            endif
       
            if (registerUnit(whichUnit)) then
                call addToList(whichUnit)
               
                return true
            endif
           
            return false
        endmethod
       
        private method removeFromList takes thistype whichUnit returns nothing
            set whichUnit.parent = 0
       
            set whichUnit.prev.next = whichUnit.next
            set whichUnit.next.prev = whichUnit.prev
           
            if (first == whichUnit) then
                set first = whichUnit.next
                if (first == whichUnit) then
                    set first = 0
                endif
            endif
        endmethod
        static method remove takes thistype whichUnit returns nothing
            local thistype this = whichUnit.parent
       
            call removeFromList(whichUnit)
            call unregisterUnit(whichUnit)
            call remake()
        endmethod
       
        private static method allocate takes nothing returns thistype
            set instanceCount = instanceCount + 1
            return instanceCount
        endmethod
        static method create takes nothing returns thistype
            local thistype this = allocate()
           
            call createTrigger()
           
            return this
        endmethod
    endstruct
   
    private struct DamageTriggerHeapInner extends array
        private static method compare takes DamageTrigger trig1, DamageTrigger trig2 returns boolean
            return trig1.activeUnits <= trig2.activeUnits
        endmethod
        implement BinaryHeap
    endstruct
   
    private struct DamageTriggerHeap extends array
        private static DamageTriggerHeapInner array parent
       
        static method add takes UnitIndex whichUnit returns nothing
            local DamageTrigger damageTrigger = DamageTriggerHeapInner.root.value
           
            if (not damageTrigger.add(whichUnit)) then
                set damageTrigger = DamageTrigger.create()
                call damageTrigger.add(whichUnit)
                set parent[damageTrigger] = DamageTriggerHeapInner.insert(damageTrigger)
            else
                call parent[damageTrigger].modify(damageTrigger)
            endif
        endmethod
        static method remove takes UnitIndex whichUnit returns nothing
            local DamageTrigger damageTrigger = DamageTrigger(whichUnit).parent
            call DamageTrigger.remove(whichUnit)
            call parent[damageTrigger].modify(damageTrigger)
        endmethod
    endstruct
   
    private module DamageEventMod
        readonly static PriorityEvent ANY
        readonly static UnitIndex targetId
        readonly static UnitIndex sourceId
        static real amount
        static boolean enabled
       
        private static integer array damageType_p
        private static integer array damageId_p
        private static integer array instance_p
        private static integer runInstanceCount_p
        private static integer runAttackCount_p
       
        private static method allocateAttack takes integer damageType, integer damageId, integer instance returns nothing
            set runInstanceCount_p = runInstanceCount_p + 1
            set damageType_p[runInstanceCount_p] = damageType
            set damageId_p[runInstanceCount_p] = damageId
            set instance_p[runInstanceCount_p] = instance
        endmethod
        static method unitDamageTarget takes unit attacker, widget target, real amount, integer damageType, integer damageId, integer instance returns boolean
            if (enabled) then
                call allocateAttack(damageType, damageId, instance)
                return UnitDamageTarget(attacker, target, amount, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
            endif
            return false
        endmethod
       
        static method operator damageType takes nothing returns integer
            return damageType_p[runInstanceCount_p]
        endmethod
        static method operator damageId takes nothing returns integer
            return damageId_p[runInstanceCount_p]
        endmethod
        static method operator instance takes nothing returns integer
            return instance_p[runInstanceCount_p]
        endmethod
        static method operator depth takes nothing returns integer
            return runAttackCount_p
        endmethod
       
        private static delegate DamageEventProperties damageEventProperties = 0
       
        private static method damage takes nothing returns boolean
            local integer previousTargetId
            local integer previousSourceId
            local real previousAmount
            //! runtextmacro optional ADV_DAMAGE_EVENT_LOC_BEFORE()
           
            if (enabled and 0 != GetEventDamage()) then
                /*
                *   Setup spell
                */

                set runAttackCount_p = runAttackCount_p + 1
                if (runAttackCount_p != runInstanceCount_p) then
                    set runInstanceCount_p = runInstanceCount_p + 1
                endif
           
                /*
                *   Store previous amounts
                */

                set previousTargetId = targetId
                set previousSourceId = sourceId
                set previousAmount = amount
               
                /*
                *   Update amounts to new amounts
                */

                set targetId = GetUnitUserData(GetTriggerUnit())
                set sourceId = GetUnitUserData(GetEventDamageSource())
                set amount = GetEventDamage()
               
                /*
                *   Fire event
                */

                //! runtextmacro optional ADV_DAMAGE_EVENT_EXT()
                call ANY.fire()
               
                /*
                *   Restore previous amounts
                */

                set targetId = previousTargetId
                set sourceId = previousSourceId
                set amount = previousAmount
                //! runtextmacro optional ADV_DAMAGE_EVENT_LOC_AFTER()
               
                /*
                *   Remove spell
                */

                set damageType_p[runInstanceCount_p] = 0
                set damageId_p[runInstanceCount_p] = 0
                set instance_p[runInstanceCount_p] = 0
                set runInstanceCount_p = runInstanceCount_p - 1
                set runAttackCount_p = runAttackCount_p - 1
            endif
           
            return false
        endmethod
        private static method index takes nothing returns boolean
            call UnitIndex(GetIndexedUnitId()).lock()
            call DamageTriggerHeap.add(GetIndexedUnitId())
            return false
        endmethod
        private static method deindex takes nothing returns boolean
            call DamageTriggerHeap.remove(GetIndexedUnitId())
            call UnitIndex(GetIndexedUnitId()).unlock()
            return false
        endmethod
       
        private static method onInit takes nothing returns nothing
            set enabled = true
            set runInstanceCount_p = 0
            set runAttackCount_p = 0
           
            set damageCondition = Condition(function thistype.damage)

            set ANY = PriorityEvent.create()
           
            call RegisterUnitIndexEvent(Condition(function thistype.index), UnitIndexer.INDEX)
            call RegisterUnitIndexEvent(Condition(function thistype.deindex), UnitIndexer.DEINDEX)
           
            set targetId = 0
            set sourceId = 0
            set amount = 0
        endmethod
    endmodule
   
    struct DamageEvent extends array
        implement DamageEventMod
    endstruct
   
    module ExtendDamageEvent
        static if AdvDamageEvent_p.onDamage_p_core.exists then
            private static delegate AdvDamageEvent advDamageEvent = 0
        else
            private static delegate DamageEvent damageEvent = 0
        endif
    endmodule
   
    module DamageEvent
        implement ExtendDamageEvent
       
        static if thistype.onDamage.exists then
            private static method onDamage_p takes nothing returns boolean
                static if thistype.filter.exists then
                    if (filter()) then
                        call onDamage()
                    endif
                else
                    call onDamage()
                endif
                return false
            endmethod
           
            private static method onInit takes nothing returns nothing
                static if thistype.PRIORITY.exists then
                    call DamageEvent.ANY.register(Condition(function thistype.onDamage_p), PRIORITY())
                else
                    call DamageEvent.ANY.register(Condition(function thistype.onDamage_p), 0)
                endif
            endmethod
        endif
    endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library StunSystem uses Table

//********************************************************************************
//              Stun - Version 1.2.0.0 - By iAyanami aka Ayanami
//********************************************************************************
//
//    Stun:
//         - An easy to use system that stuns units
//         - Able to keep track of the remaining stun duration
//
//    Requirements:
//         - JASS NewGen
//         - Table
//
//    Functions:
//         - Stun.apply takes unit whichUnit, real duration, boolean stack returns nothing
//           * whichUnit is the target to be stunned
//           * duration is the duration of the stun
//           * stack is to determine if the stun should be a stacking one or not
//           * true - the stun will stack, the duration of the stun will add up with the previous duration
//           * false - the stun will not stack, the unit will be stunned for the longer stun duration
//
//         - Stun.getDuration takes unit whichUnit returns real
//           * whichUnit is the target to check
//           * returns the remaining stun duration
//
//         - Stun.stop takes unit whichUnit returns nothing
//           * removes stun from the target
//
//    How to import:
//         - Copy the whole "Stun" Trigger Folder into your map
//         - Save the map. Close and re-opem the map.
//         - You should have a new unit (Stun Dummy), ability (Stun (System)) and buff (Stun (System)) created
//         - Read through the Configuration part of the code
//
//    Credits:
//         - Bribe for Table
//
//********************************************************************************
//                                CONFIGURABLES
//********************************************************************************

    globals
        private constant real PERIOD = 0.03125
        private constant integer ABILID = 'ASTN'
        private constant integer BUFFID = 'BSTN'
        private constant integer STUNID = 'sTUN'
    endglobals
   
    //********************************************************************************
    //                                     CODE
    //********************************************************************************
   
    module Init
        private static method onInit takes nothing returns nothing
            set table = Table.create()
            set caster = CreateUnit(Player(13), STUNID, 0, 0, 0)
            call UnitAddAbility(caster, ABILID)
        endmethod
    endmodule
   
    struct Stun extends array
        private unit u
        private real dur

        private thistype next
        private thistype prev
       
        private static Table table
        private static timer t = CreateTimer()
        private static unit caster
        private static integer count = 0
       
        // remove the stun and deallocate
        private method destroy takes nothing returns nothing
            call UnitRemoveAbility(this.u, BUFFID)
           
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
           
            set this.prev.next = this.next
            set this.dur = 0
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
           
            if thistype(0).next == 0 then
                call PauseTimer(t)
            endif
           
            call table.remove(GetHandleId(this.u))
        endmethod
       
        // iterating through all instances every PERIOD
        private static method iterate takes nothing returns nothing
            local thistype this = thistype(0)
           
            loop
                set this = this.next
                exitwhen this == 0
                if this.dur <= 0 or IsUnitType(this.u, UNIT_TYPE_DEAD) or GetUnitTypeId(this.u) == 0 then
                    call this.destroy()
                else
                    set this.dur = this.dur - PERIOD
                endif
            endloop
        endmethod
       
        // immediately removes stun for the specified unit
        // ex: call Stun.stop(whichTarget)
        static method stop takes unit u returns nothing
            local integer id = GetHandleId(u)
           
            if table.has(id) then
                call thistype(table[id]).destroy()
            endif
        endmethod
       
        // gets the duration left for stun, not stunned units always return 0
        // ex: local real r = Stun.getDuration(whichTarget)
        static method getDuration takes unit u returns real
            return thistype(table[GetHandleId(u)]).dur
        endmethod
       
        // stunning specified target and to see if the stun is a stacking one or not
        // ex: call Stun.apply(whichTarget, 5.0, false)
        static method apply takes unit u, real dur, boolean b returns nothing
            local thistype this
            local integer id = GetHandleId(u)
           
            if table.has(id) then
                set this = table[id]
            else    
                if thistype(0).prev == 0 then
                    set count = count + 1
                    set this = count
                else
                    set this = thistype(0).prev
                    set thistype(0).prev = thistype(0).prev.prev
                endif
               
                if thistype(0).next == 0 then
                    call TimerStart(t, PERIOD, true, function thistype.iterate)
                else
                    set thistype(0).next.prev = this
                endif
               
                set this.next = thistype(0).next
                set thistype(0).next = this
                set this.prev = thistype(0)
                set table[id] = this
                set this.u = u
                set this.dur = 0
               
                call IssueTargetOrder(caster, "firebolt", this.u)
            endif
           
            if b and dur > 0 then
                set this.dur = this.dur + dur
            else
                if this.dur < dur then
                    set this.dur = dur
                endif
            endif
        endmethod
       
        implement Init
    endstruct

endlibrary
//TESH.scrollpos=176
//TESH.alwaysfold=0
library AdvancedTextTag /* ver 2.1 - vuongkkk */

    globals
        public constant real    PERIOD = 0.025

        constant integer TT_NORMAL   = 0
        constant integer TT_CRITICAL = 1
        constant integer TT_CURVED   = 2
        constant integer TT_WHIRL    = 3
        constant integer TT_SPELL    = 4
    endglobals
   
    function SetTextTagVelocityEx takes texttag tag, real speed, real angle returns nothing
        call SetTextTagVelocity(tag, speed*Cos(angle* bj_DEGTORAD)*.071/128, speed*Sin(angle* bj_DEGTORAD)*.071/128)
    endfunction
   
    private function Parabol takes real h, real d, real x returns real
        return (4 * h / d) * (d - x) * (x / d)
    endfunction
       
    struct DTexttag extends array
        private static integer timerInstanceCount = 0
        private static thistype instanceCount = 0
        private static integer array recycler
        private static timer T = CreateTimer()
        private static trigger trig=CreateTrigger()
        private triggercondition la
        readonly texttag tag
        real age
        real fadepoint
        real lifespan
        string text
        real size
       
        method setupText takes string text, real size returns nothing
            set .text = text
            set .size = size
            call SetTextTagText(tag, text, size * .0023)
        endmethod
       
        real angle
        real speed
       
        method setupVelocity takes real speed, real angle returns nothing
            set .angle = angle
            set .speed = speed
            call SetTextTagVelocity(tag, speed*Cos(angle* bj_DEGTORAD)*.071/128, speed*Sin(angle* bj_DEGTORAD)*.071/128)
        endmethod
       
        real posX
        real posY
        real posZ
       
        method setupPosition takes real x, real y, real z returns nothing
            call SetTextTagPos(tag, x , y, z)
        endmethod
       
        static integer Al
        static real    A
        static real    Spd
        static thistype current
       
        readonly thistype next
        private thistype prev
       
        private method remove takes nothing returns nothing
            call DestroyTextTag(tag)
            call TriggerRemoveCondition(trig, la)
            set prev.next = next
            set next.prev = prev
        endmethod
       
        private static method update takes nothing returns nothing
            local thistype this = thistype(0).next
            loop
                exitwhen 0 == this
                if age < lifespan-PERIOD then
                    set age = age + PERIOD
                    set this = next
                else
                    call remove()
                    set recycler[this] = recycler[0]
                    set recycler[0] = this
                    set this = next
                    set timerInstanceCount = timerInstanceCount - 1
                endif
            endloop
            set current=thistype(0).next
            if (0 == timerInstanceCount) then
                call PauseTimer(T)
            else
                call TriggerEvaluate(trig)
            endif
        endmethod
       
        static method allocate takes boolexpr func returns thistype
            local thistype this = recycler[0]
            local texttag tt=CreateTextTag()
            if GetHandleId(tt)==0 then
                set this = thistype(0).next
                call remove()
                set tt=CreateTextTag()
            endif
            if (0 == this) then
                set this = instanceCount + 1
                set instanceCount = this
            else
                set recycler[0] = recycler[this]
            endif
            set next = 0
            set prev = thistype(0).prev
            set thistype(0).prev.next = this
            set thistype(0).prev = this
            set tag=tt
            set age=0
            set fadepoint = 0
            call SetTextTagVisibility(tt, true)
            call SetTextTagPermanent(tag,false)
            set la=TriggerAddCondition(trig, func)
            if (0 == timerInstanceCount) then
                call TimerStart(T, PERIOD, true, function thistype.update)
            endif
            set timerInstanceCount = timerInstanceCount + 1
            return this
        endmethod
    endstruct

    private struct CriticalStyle extends array
        static boolexpr cons
        static method onLoop takes nothing returns boolean
            local DTexttag dtt=DTexttag.current
            local real period=dtt.lifespan/6
            if dtt.age < period then
                call SetTextTagVelocityEx(dtt.tag,dtt.speed+Parabol(36.0,period*2, dtt.age),dtt.angle)
                call SetTextTagText(dtt.tag,dtt.text, (dtt.size+Parabol(9.0,period, dtt.age))*.0023)
            endif
            set DTexttag.current=dtt.next
            return false
        endmethod
       
        private static method onInit takes nothing returns nothing
            set thistype.cons=Condition(function thistype.onLoop)
        endmethod
    endstruct

    private struct CurvedStyle extends array
        static boolexpr cons
        static method onLoop takes nothing returns boolean
            local DTexttag dtt=DTexttag.current
            if dtt.age < dtt.lifespan/2 then
                set DTexttag.Spd=dtt.speed+Parabol(46.0,dtt.lifespan, dtt.age)
            else
                set DTexttag.Spd=(dtt.speed+36.0)*(1+0.05*(dtt.age-dtt.lifespan/2)/PERIOD)
            endif
            call SetTextTagVelocityEx(dtt.tag,DTexttag.Spd, dtt.angle+Parabol(18.0,dtt.lifespan, dtt.age))
            call SetTextTagText(dtt.tag,dtt.text,(dtt.size+Parabol(10.0,dtt.lifespan, dtt.age))*.0023)
            set DTexttag.current=dtt.next
            return false
        endmethod
       
        private static method onInit takes nothing returns nothing
            set thistype.cons=Condition(function thistype.onLoop)
        endmethod
    endstruct

    private struct WhirlStyle extends array
        static boolexpr cons
        static method onLoop takes nothing returns boolean
            local DTexttag dtt=DTexttag.current
            call SetTextTagVelocityEx(dtt.tag,dtt.speed+Parabol(42.0,dtt.lifespan, dtt.age)+dtt.age*1.01, dtt.angle+Parabol(460.0,dtt.lifespan, dtt.age))
            call SetTextTagText(dtt.tag,dtt.text,(dtt.size+Parabol(9.0,dtt.lifespan, dtt.age))*.0023)
            set DTexttag.current=dtt.next
            return false
        endmethod
       
        private static method onInit takes nothing returns nothing
            set thistype.cons=Condition(function thistype.onLoop)
        endmethod
    endstruct

    function CreateAdvancedTextTag takes integer wtype, string mes, real x, real y returns nothing
        local DTexttag dtt
        if wtype == TT_NORMAL then
            set bj_lastCreatedTextTag = CreateTextTag()
            call SetTextTagText(bj_lastCreatedTextTag, mes, 12*.0023)
            call SetTextTagPos(bj_lastCreatedTextTag, x, y, 0.)
            call SetTextTagVelocityEx(bj_lastCreatedTextTag,110,90)
            call SetTextTagLifespan(bj_lastCreatedTextTag,2.)
            call SetTextTagFadepoint(bj_lastCreatedTextTag,1.)
            call SetTextTagPermanent(bj_lastCreatedTextTag,false)
            call SetTextTagVisibility(bj_lastCreatedTextTag,true)
        elseif wtype == TT_CRITICAL then
            set dtt=DTexttag.allocate(CriticalStyle.cons)
            set dtt.lifespan= 2.2
            call dtt.setupVelocity(46.00, 90)
            call dtt.setupText(mes, 13.0)
            call dtt.setupPosition(x, y, 0.)
        elseif wtype == TT_CURVED then
            set dtt=DTexttag.allocate(CurvedStyle.cons)
            set dtt.fadepoint= 0.9
            set dtt.lifespan= 1.8
            call dtt.setupText(mes, 7.0)
            call dtt.setupVelocity(49.00, 90)
            call dtt.setupPosition(x, y, 0.)
        elseif wtype == TT_WHIRL then
            set dtt=DTexttag.allocate(WhirlStyle.cons)
            set dtt.fadepoint= 0.01
            set dtt.lifespan= 1.9
            call dtt.setupText(mes, 7.0)
            call dtt.setupVelocity(29.00, 0)
            call dtt.setupPosition(x, y, 0.)
        elseif wtype == TT_SPELL then
            set dtt=DTexttag.allocate(CurvedStyle.cons)
            set dtt.fadepoint= 0.9
            set dtt.lifespan= 1.8
            call dtt.setupText(mes, 6.0)
            call dtt.setupVelocity(49.00, 90)
            call dtt.setupPosition(x, y+50, 0.)
        endif
    endfunction
endlibrary
//TESH.scrollpos=196
//TESH.alwaysfold=0
/*********************************************
*
*   DamageSystem
*   v1.0.0.0
*   By Magtheridon96 // Edited by -Kobas- (Replaced GetRandomReal(0,1) with GetRandomReal(0,100)), added Math lib
*
*   API:
*   ----
*      
*       struct Unit extends array
*
*           real criticalChance
*           real criticalMultiplier
*          
*           real spellCriticalChance
*           real spellCriticalMultiplier
*          
*           real spellPower
*          
*           real fireResistance
*           real coldResistance
*           real poisonResistance
*           real lightningResistance
*          
*           real fireDamage
*           real coldDamage
*           real poisonDamage
*           real lightningDamage
*          
*           real bashChance
*           real bashDuration
*          
*           real evasion
*          
*           real reflectChance
*           real reflectPercent
*          
*           static method operator [] takes unit u returns thistype
*               - Pass in the unit and get the struct instance
*          
*           method setResistance takes real fire, real cold, real poison, real lightnin returns nothing
*           method setDamage takes real fire, real cold, real poison, real lightnin returns nothing
*           method setBash takes real chance, real dur returns nothing
*           method setCritical takes real critChan, real critMult returns nothing
*           method setSpellCritical takes real critChan, real critMult returns nothing
*           method setReflect takes real chance, real percent returns nothing
*           method setEvasion takes real evas returns nothing
*           method setSpellPower takes real pow returns nothing
*               - These functions allow you to modify unit stat values
*          
*           method damageTarget takes unit target, real amount, integer damageType returns nothing
*               - This function will deal spell damage
*              
*       function IsReflectedDamage takes nothing returns boolean
*           - Calling this on damage events will determine whether the damage is reflected or not
*       function IsPoisonDPS takes nothing returns boolean
*           - Calling this on damage events will determine whether the damage is poison damage per second or not
*       function IsFireSplashDamage takes nothing returns boolean
*           - Calling this on damage events will determine whether the damage is fire splash damage per second or not
*       function IsAttackDamage takes nothing returns boolean
*           - Calling this on damage events will determine whether the damage is from an attack or not
*
*********************************************/

library DamageSystem requires UnitIndexer, DamageEvent, AdvancedTextTag, Math

    globals
        /*
        *   DamageType Declarations
        */

        private constant integer DAMAGE_NORMAL    = 1
        private constant integer DAMAGE_FIRE      = 2
        private constant integer DAMAGE_COLD      = 3
        private constant integer DAMAGE_POISON    = 4
        private constant integer DAMAGE_LIGHTNING = 5
        /*
        *   Damage Configuration
        */

        private constant real    FIRE_AOE            = 150.
        private constant real    POISON_INTERVAL     = 1.
        private constant integer POISON_DAMAGE_COUNT = 5
        /*
        *   Ability Raw Codes
        */

        private constant integer SLOW_ABIL  = 'A00O'
        /*
        *   What are the symbols for Critical/Bash/Reflection?
        */

        private constant string CRIT_CHAR    = "!"
        private constant string BASH_CHAR    = "?"
        private constant string REFLECT_CHAR = "#"
        /*
        *   Color configuration
        */

        private constant string CRIT_COLOR    = "|cffff0000"
        private constant string BASH_COLOR    = "|cffc3dbff"
        private constant string REFLECT_COLOR = "|cffffffff"
        private constant string HEAL_COLOR    = "|cff33ff33"
        private constant string ENEMY_COLOR   = "|cffff0000"
    endglobals
   
    globals
        private boolean poisonEvent       = false
        private boolean reflectEvent      = false
        private boolean fireSplashEvent   = false
        private boolean damageTargetEvent = false
    endglobals
   
    globals
        private constant integer ANTI_DEATH_ABIL = 'A002'
    endglobals
   
    function GiveAntiDeath takes unit whichUnit returns nothing
        call UnitAddAbility(whichUnit, ANTI_DEATH_ABIL)
    endfunction
   
    function RemoveAntiDeath takes unit whichUnit returns nothing
        call UnitRemoveAbility(whichUnit, ANTI_DEATH_ABIL)
    endfunction
   
    private struct PoisonDPS extends array
        private static timer tmr = CreateTimer()
        private static integer stack = 0
       
        private static thistype array next
        private static thistype array prev
       
        private static unit array source
        private static real array amount
       
        private static integer array count
        private static boolean array active
       
        private method destroy takes nothing returns nothing
            set source[this] = null
            set active[this] = false
            set next[prev[this]] = next[this]
            set prev[next[this]] = prev[this]
            set stack = stack - 1
            if stack == 0 then
                call PauseTimer(tmr)
            endif
        endmethod
       
        private static method iterate takes nothing returns nothing
            local thistype this = next[0]
           
            loop
                exitwhen this == 0
               
                if not IsUnitType(GetUnitById(this), UNIT_TYPE_DEAD) then
                    set poisonEvent = true
                    call UnitDamageTarget(source[this], GetUnitById(this), amount[this], false, false, null, DAMAGE_TYPE_NORMAL, null)
                    set poisonEvent = false
                else
                    call this.destroy()
                endif
               
                set count[this] = count[this] - 1
                if count[this] == 0 then
                    call this.destroy()
                endif
               
                set this = next[this]
            endloop
        endmethod
       
        static method push takes unit src, unit trg, real amn returns nothing
            local thistype this = GetUnitUserData(trg)
           
            if not active[this] then
               
                set next[this] = 0
                set prev[this] = prev[0]
                set next[prev[0]] = this
                set prev[0] = this
               
                set source[this] = src
                set amount[this] = amn
               
                set active[this] = true
               
                set stack = stack + 1
                if stack == 1 then
                    call TimerStart(tmr, POISON_INTERVAL, true, function thistype.iterate)
                endif
            endif
            set count[this] = POISON_DAMAGE_COUNT
        endmethod
    endstruct
   
    struct Unit extends array
        private static string array colors
        private static unit damageDummy
       
        real criticalChance
        real criticalMultiplier
       
        real spellCriticalChance
        real spellCriticalMultiplier
       
        real spellPower
       
        real fireResistance
        real coldResistance
        real poisonResistance
        real lightningResistance
       
        real fireDamage
        real coldDamage
        real poisonDamage
        real lightningDamage
       
        real bashChance
        real bashDuration
       
        real evasion
       
        real reflectChance
        real reflectPercent
       
        static method operator [] takes unit u returns thistype
            return GetUnitUserData(u)
        endmethod
       
        method setResistance takes real fire, real cold, real poison, real lightnin returns nothing
            set this.fireResistance = fire/100
            set this.coldResistance = cold/100
            set this.poisonResistance = poison/100
            set this.lightningResistance = lightnin/100//RMin(1, lightnin)
        endmethod
       
        method setDamage takes real fire, real cold, real poison, real lightnin returns nothing
            set this.fireDamage = fire
            set this.coldDamage = cold
            set this.poisonDamage = poison
            set this.lightningDamage = lightnin
        endmethod
       
        method setBash takes real chance, real dur returns nothing
            set this.bashChance = chance
            set this.bashDuration = dur
        endmethod
       
        method setCritical takes real critChan, real critMult returns nothing
            set this.criticalChance = critChan
            set this.criticalMultiplier = critMult
        endmethod
       
        method setSpellCritical takes real critChan, real critMult returns nothing
            set this.spellCriticalChance = critChan
            set this.spellCriticalMultiplier = critMult
        endmethod
       
        method setReflect takes real chance, real percent returns nothing
            set this.reflectChance = chance
            set this.reflectPercent = percent
        endmethod
       
        method setEvasion takes real evas returns nothing
            set this.evasion = evas
        endmethod
       
        method setSpellPower takes real pow returns nothing
            set this.spellPower = pow
        endmethod
       
        /*
        *   Recursion safe data manager
        */

        private static integer array v
        private static integer cc = 0
        private static method new takes nothing returns nothing
            set cc=cc+1
        endmethod
        private static method push takes integer value returns nothing
            set v[cc]=v[cc]+value
        endmethod
        private static method pop takes nothing returns integer
            return v[cc]
        endmethod
        private static method clear takes nothing returns nothing
            set v[cc]=0
        endmethod
        private static method remove takes nothing returns nothing
            set cc=cc+1
        endmethod
       
        method damageTarget takes unit target, real amount, integer damageType returns nothing
            local unit source = GetUnitById(this)
            local thistype targetId = GetUnitUserData(target)
            local player sourceOwner = GetOwningPlayer(source)
            local real a = amount
            local unit u
            local real x
            local real y
           
            set damageTargetEvent = true
           
            if amount < 0 then
                set amount = -amount
                call SetWidgetLife(target, GetWidgetLife(target) + amount)
                call CreateAdvancedTextTag(TT_CURVED,HEAL_COLOR + "+" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
            else
                if damageType == DAMAGE_NORMAL then
                    /*
                    *   Check to see if spell critical should be applied
                    */

                    if GetRandomReal(0, 100) < this.spellCriticalChance then
                        set amount = amount * this.spellCriticalMultiplier
                        call UnitDamageTarget(source, target, amount, false, false, null, DAMAGE_TYPE_NORMAL, null)
                        if target == HERO or target == PET then
                            call CreateAdvancedTextTag(TT_CRITICAL, ENEMY_COLOR + "-" + I2S(R2I(amount)) + CRIT_CHAR, GetUnitX(target),GetUnitY(target))
                        elseif source == HERO or source == PET then
                            call CreateAdvancedTextTag(TT_CRITICAL, CRIT_COLOR + "-" + I2S(R2I(amount)) + CRIT_CHAR, GetUnitX(target),GetUnitY(target))
                        endif
                    else
                        call UnitDamageTarget(source, target, amount, false, false, null, DAMAGE_TYPE_NORMAL, null)
                        if target == HERO or target == PET then
                            call CreateAdvancedTextTag(TT_NORMAL, ENEMY_COLOR + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                        elseif source == HERO or source == PET then
                            call CreateAdvancedTextTag(TT_NORMAL, "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                        endif
                    endif
                elseif damageType == DAMAGE_POISON then
                    /*
                    *   Set amount depending on resistance and deal damage
                    */

                    set amount = 0.5 + amount - amount * targetId.poisonResistance
                    call UnitDamageTarget(source, target, amount, false, false, null, DAMAGE_TYPE_NORMAL, null)
                    if target == HERO or target == PET then
                        call CreateAdvancedTextTag(TT_CURVED, ENEMY_COLOR + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    elseif source == HERO or source == PET then
                        call CreateAdvancedTextTag(TT_CURVED, colors[DAMAGE_POISON] + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    endif
                elseif damageType == DAMAGE_FIRE then
                    /*
                    *   Set amount depending on resistance and deal damage
                    */

                    set amount = 0.5 + amount - amount * targetId.fireResistance
                    call UnitDamageTarget(source, target, amount, false, false, null, DAMAGE_TYPE_NORMAL, null)
                    if target == HERO or target == PET then
                        call CreateAdvancedTextTag(TT_CURVED, ENEMY_COLOR + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    elseif source == HERO or source == PET then
                        call CreateAdvancedTextTag(TT_CURVED, colors[DAMAGE_FIRE] + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    endif
                    /*
                    *   Let the damage detection function run for this system
                    *   and flag the damage events as fire AoE splash damage
                    */

                    set fireSplashEvent = true
                    set damageTargetEvent = false
                    /*
                    *   Pick units in a small range and deal half the damage to them
                    */

                    set x = GetUnitX(target)
                    set y = GetUnitY(target)
                    call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, FIRE_AOE + 197., null)
                    loop
                        set u = FirstOfGroup(bj_lastCreatedGroup)
                        exitwhen u == null
                        call GroupRemoveUnit(bj_lastCreatedGroup, u)
                        if u != target and IsUnitEnemy(u, sourceOwner) and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitInRangeXY(u, x, y, FIRE_AOE) then
                            call UnitDamageTarget(source, u, a/2+.5, false, false, null, DAMAGE_TYPE_NORMAL, null)
                        endif
                    endloop
                    set damageTargetEvent = true
                    set fireSplashEvent = false
                elseif damageType == DAMAGE_COLD then
                    /*
                    *   Set amount depending on resistance and deal damage
                    */

                    set amount = 0.5 + amount - amount * targetId.coldResistance
                    call UnitDamageTarget(source, target, amount, false, false, null, DAMAGE_TYPE_NORMAL, null)
                    if target == HERO or target == PET then
                        call CreateAdvancedTextTag(TT_CURVED, ENEMY_COLOR + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    elseif source == HERO or source == PET then
                        call CreateAdvancedTextTag(TT_CURVED, colors[DAMAGE_COLD] + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    endif
                    /*
                    *   Order dummy to slow target
                    */

                    call IssueTargetOrder(damageDummy, "frostnova", target)
                elseif damageType == DAMAGE_LIGHTNING then
                    /*
                    *   Set amount depending on resistance and deal damage
                    */

                    set amount = 0.5 + amount - amount * targetId.lightningResistance
                    call UnitDamageTarget(source, target, amount, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
                    if target == HERO or target == PET then
                        call CreateAdvancedTextTag(TT_CURVED, ENEMY_COLOR + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    elseif source == HERO or source == PET then
                        call CreateAdvancedTextTag(TT_CURVED, colors[DAMAGE_LIGHTNING] + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    endif
                endif
            endif
           
            set damageTargetEvent = false
           
            set source = null
            set sourceOwner = null
        endmethod
       
        private static method onDamage takes nothing returns boolean
            local string textTarget = ""
            local string s = ""
            local real a = 0
            local real x
            local real y
            local unit u
            /*
            *   Only for readability
            */

            local real amount = DamageEvent.amount
            local unit source = DamageEvent.source
            local unit target = DamageEvent.target
            local player sourceOwner = GetOwningPlayer(source)
            local thistype targetId = DamageEvent.targetId
            local thistype this = DamageEvent.sourceId
           
            if not damageTargetEvent then
                if poisonEvent then
                    if target == HERO or target == PET then
                        call CreateAdvancedTextTag(TT_CURVED, "|cffff0000-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    elseif source == HERO or source == PET then
                        call CreateAdvancedTextTag(TT_CURVED, colors[DAMAGE_POISON] + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                    endif
                else
                    if reflectEvent then
                        if target == HERO or target == PET then
                            call CreateAdvancedTextTag(TT_CURVED, "|cffff0000-" + I2S(R2I(amount)) + REFLECT_CHAR, GetUnitX(target),GetUnitY(target))
                        elseif source == HERO or source == PET then
                            call CreateAdvancedTextTag(TT_CURVED, REFLECT_COLOR + "-" + I2S(R2I(amount)) + REFLECT_CHAR, GetUnitX(target),GetUnitY(target))
                        endif
                    else
                        if fireSplashEvent then
                            if target == HERO or target == PET then
                                call CreateAdvancedTextTag(TT_CURVED, "|cffff0000-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                            elseif source == HERO or source == PET then
                                call CreateAdvancedTextTag(TT_CURVED, colors[DAMAGE_FIRE] + "-" + I2S(R2I(amount)), GetUnitX(target),GetUnitY(target))
                            endif
                        else
                            set DamageEvent.enabled = false
                           
                            if GetRandomReal(0, 100) < targetId.evasion then
                                call GiveAntiDeath(target)
                                call SetWidgetLife(target, GetWidgetLife(target) + amount)
                                call RemoveAntiDeath(target)
                                call CreateAdvancedTextTag(TT_CURVED, ENEMY_COLOR + "miss", GetUnitX(source),GetUnitY(source))
                                set DamageEvent.amount = 0
                            else
                                call new()
                               
                                if GetRandomReal(0, 100) < this.criticalChance then
                                    set a = amount * this.criticalMultiplier
                                    call UnitDamageTarget(source, target, a - amount, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
                                   
                                    if target == HERO or target == PET then
                                        set textTarget = textTarget + "-" + I2S(R2I(a)) + CRIT_CHAR
                                    elseif source == HERO or source == PET then
                                        set s = "-" + I2S(R2I(a)) + CRIT_CHAR
                                        set textTarget = textTarget + CRIT_COLOR + s + "|r"
                                        call push(StringLength(s))
                                    endif
                                   
                                    set DamageEvent.amount = DamageEvent.amount + a - amount
                                else
                                    set textTarget = textTarget + "-" + I2S(R2I(amount))
                                endif
                                /*
                                *   Start dealing elemental damage
                                */

                                if this.fireDamage > 0 then
                                    set a = this.fireDamage - this.fireDamage * targetId.fireResistance
                                    if target == HERO or target == PET then
                                        set textTarget = textTarget + " -" + I2S(R2I(a))
                                    elseif source == HERO or source == PET then
                                        set s = " -" + I2S(R2I(a))
                                        set textTarget = textTarget + colors[DAMAGE_FIRE] + s + "|r"
                                        call push(StringLength(s))
                                    endif
                                    call UnitDamageTarget(source, target, a, false, false, null, DAMAGE_TYPE_NORMAL, null)
                                    set DamageEvent.amount = DamageEvent.amount + a
                                   
                                    set fireSplashEvent = true
                                    set DamageEvent.enabled = true
                                    /*
                                    *   Cache target coordinates
                                    */

                                    set x = GetUnitX(target)
                                    set y = GetUnitY(target)
                                    /*
                                    *   Pick units in a small range and deal half the damage to them
                                    */

                                    call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, FIRE_AOE + 197., null)
                                    loop
                                        set u = FirstOfGroup(bj_lastCreatedGroup)
                                        exitwhen u == null
                                        call GroupRemoveUnit(bj_lastCreatedGroup, u)
                                        if u != target and IsUnitEnemy(u, sourceOwner) and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitInRangeXY(u, x, y, FIRE_AOE) then
                                            call UnitDamageTarget(source, u, this.fireDamage - this.fireDamage * thistype(GetUnitUserData(u)).fireResistance, false, false, null, DAMAGE_TYPE_NORMAL, null)
                                        endif
                                    endloop
                                    set DamageEvent.enabled = false
                                    set fireSplashEvent = false
                                endif
                                if this.coldDamage > 0 then
                                    set a = this.coldDamage - this.coldDamage * targetId.coldResistance
                                    if target == HERO or target == PET then
                                        set textTarget = textTarget + " -" + I2S(R2I(a))
                                    elseif source == HERO or source == PET then
                                        set s = " -" + I2S(R2I(a))
                                        set textTarget = textTarget + colors[DAMAGE_COLD] + s + "|r"
                                        call push(StringLength(s))
                                    endif
                                    call UnitDamageTarget(source, target, a, false, false, null, DAMAGE_TYPE_NORMAL, null)
                                    set DamageEvent.amount = DamageEvent.amount + a
                                    /*
                                    *   Apply the cold slow effect on the target
                                    */

                                    call SetUnitX(damageDummy, GetUnitX(target))
                                    call SetUnitY(damageDummy, GetUnitY(target))
                                    call IssueTargetOrder(damageDummy, "frostnova", target)
                                endif
                                if this.poisonDamage > 0 then
                                    set a = this.poisonDamage - this.poisonDamage * targetId.poisonResistance
                                    if target == HERO or target == PET then
                                        set textTarget = textTarget + " -" + I2S(R2I(a))
                                    elseif source == HERO or source == PET then
                                        set s = " -" + I2S(R2I(a))
                                        set textTarget = textTarget + colors[DAMAGE_POISON] + s + "|r"
                                        call push(StringLength(s))
                                    endif
                                    call UnitDamageTarget(source, target, a, false, false, null, DAMAGE_TYPE_NORMAL, null)
                                    set DamageEvent.amount = DamageEvent.amount + a
                                    /*
                                    *   Add the target to the Poison DPS struct
                                    */

                                    call PoisonDPS.push(source, target, a)
                                endif
                                if this.lightningDamage > 0 then
                                    set a = this.lightningDamage - this.lightningDamage * targetId.lightningResistance
                                    if target == HERO or target == PET then
                                        set textTarget = textTarget + " -" + I2S(R2I(a))
                                    elseif source == HERO or source == PET then
                                        set s = " -" + I2S(R2I(a))
                                        set textTarget = textTarget + colors[DAMAGE_LIGHTNING] + s + "|r"
                                        call push(StringLength(s))
                                    endif
                                    call UnitDamageTarget(source, target, a, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
                                    set DamageEvent.amount = DamageEvent.amount + a
                                endif
                               
                                if GetRandomReal(0, 100) < targetId.reflectChance then
                                    set a = DamageEvent.amount * targetId.reflectPercent
                                   
                                    /*
                                    *   Flag the reflecting event boolean to tell this system that the next
                                    *   damage event to execute will be the one caused by the reflected damage,
                                    *   and then we enable DamageEvent so the next event can actually run (for all
                                    *   other systems but this one.
                                    */

                                    set reflectEvent = true
                                    set DamageEvent.enabled = true
                                    call UnitDamageTarget(target, source, a, false, false, null, DAMAGE_TYPE_NORMAL, null)
                                    set DamageEvent.enabled = false
                                    set reflectEvent = false
                                endif
                               
                                /*
                                *   This will handle bash chance and stunning.
                                */

                                if GetRandomReal(0, 100) < this.bashChance then
                                    call Stun.apply(target, this.bashDuration, false)
                                    if target == HERO or target == PET then
                                        set textTarget = textTarget + "\n" + R2SW(this.bashDuration, 3, 1) + BASH_CHAR
                                    elseif source == HERO or source == PET then
                                        set textTarget = textTarget + "\n" + BASH_COLOR + R2SW(this.bashDuration, 3, 1) + BASH_CHAR + "|r"
                                    endif
                                endif
                               
                                if textTarget != "" then
                                    if target == HERO or target == PET then
                                        call CreateAdvancedTextTag(TT_CURVED, "|cffff0000" + textTarget, GetUnitX(target),GetUnitY(target))
                                    elseif source == HERO or source == PET then
                                        call CreateAdvancedTextTag(TT_CURVED, textTarget, GetUnitX(target),GetUnitY(target))
                                    endif
                                endif
                               
                                call clear()
                                call remove()
                            endif
                           
                            set DamageEvent.enabled = true
                        endif
                    endif
                endif
            endif
           
            set source = null
            set target = null
            set sourceOwner = null
            return false
        endmethod
       
        private static method onInit takes nothing returns nothing
            call DamageEvent.ANY.register(Condition(function thistype.onDamage), 0x7FFFFFFF)
           
            set damageDummy = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), DUMMY_ID, 0, 0, 0)
            call UnitAddAbility(damageDummy, SLOW_ABIL)
           
            set colors[DAMAGE_NORMAL] = "|cffffffff"
            set colors[DAMAGE_FIRE] = "|cffff9900"
            set colors[DAMAGE_COLD] = "|cff3333ff"
            set colors[DAMAGE_POISON] = "|cffa0ff00"
            set colors[DAMAGE_LIGHTNING] = "|cffffff33"
        endmethod
    endstruct
   
    function IsReflectedDamage takes nothing returns boolean
        return reflectEvent
    endfunction
   
    function IsPoisonDPS takes nothing returns boolean
        return poisonEvent
    endfunction
   
    function IsFireSlashDamage takes nothing returns boolean
        return fireSplashEvent
    endfunction
   
    function IsAttackDamage takes nothing returns boolean
        return not reflectEvent and not poisonEvent and not fireSplashEvent and not damageTargetEvent
    endfunction
   
endlibrary
//TESH.scrollpos=9
//TESH.alwaysfold=0
/************************************
*
*   UnitRegeneration
*   v1.0.0.0
*   By Magtheridon96
*
*   API:
*   ----
*
*       struct UnitRegeneration extends array
*          
*           static boolean enabled
*          
*           method enable takes nothing returns nothing
*           method disable takes nothing returns nothing
*          
*           method operator life takes nothing returns real
*           method operator life= takes real r returns nothing
*          
*           method operator mana takes nothing returns real
*           method operator mana= takes real r returns nothing
*
************************************/

library UnitRegeneration requires UnitIndexer, CTL

    function GetUnitMaxMana takes unit u returns real
        return GetUnitState(u, UNIT_STATE_MAX_MANA)
    endfunction
   
    function GetUnitMaxLife takes unit u returns real
        return GetUnitState(u, UNIT_STATE_MAX_LIFE)
    endfunction
   
    function SetUnitMaxLife takes unit u, real r returns nothing
        call SetUnitState(u, UNIT_STATE_MAX_LIFE, r)
    endfunction
   
    function SetUnitMaxMana takes unit u, real r returns nothing
        call SetUnitState(u, UNIT_STATE_MAX_MANA, r)
    endfunction
   
    function GetUnitMana takes unit u returns real
        return GetUnitState(u, UNIT_STATE_MANA)
    endfunction
   
    function SetUnitMana takes unit u, real r returns nothing
        call SetUnitState(u, UNIT_STATE_MANA, r)
    endfunction
   
    struct UnitRegeneration extends array
   
        private static thistype array next
        private static thistype array prev
        private static boolean array running
        private static real array hpRegen
        private static real array mpRegen
        private static real array hpRegenPercent
        private static real array mpRegenPercent
       
        static boolean enabled = true
       
        method enable takes nothing returns nothing
            set running[this] = true
        endmethod
        method disable takes nothing returns nothing
            set running[this] = false
        endmethod
       
        method operator life takes nothing returns real
            return hpRegen[this]*32
        endmethod
        method operator life= takes real r returns nothing
            set hpRegen[this]=r/32
        endmethod
       
        method operator lifePercent takes nothing returns real
            return hpRegenPercent[this]*32
        endmethod
        method operator lifePercent= takes real r returns nothing
            set hpRegenPercent[this]=r/32
        endmethod
       
        method operator mana takes nothing returns real
            return mpRegen[this]*32
        endmethod
        method operator mana= takes real r returns nothing
            set mpRegen[this]=r/32
        endmethod
       
        method operator manaPercent takes nothing returns real
            return mpRegenPercent[this]*32
        endmethod
        method operator manaPercent= takes real r returns nothing
            set mpRegenPercent[this]=r/32
        endmethod
       
        implement CT32
            local thistype this = next[0]
            local real current
            local real max
            if enabled then
                loop
                    exitwhen this == 0
                    if not IsUnitType(this.unit, UNIT_TYPE_DEAD) then
                        set current = GetWidgetLife(this.unit)
                        set max = GetUnitMaxLife(this.unit)
                        if max != current then
                            call SetWidgetLife(this.unit, current + hpRegen[this] + max * hpRegenPercent[this])
                        endif
                        set current = GetUnitMana(this.unit)
                        if GetUnitMaxMana(this.unit) != current then
                            call SetUnitMana(this.unit, current + mpRegen[this] + mpRegen[this] * mpRegenPercent[this])
                        endif
                    endif
                    set this = next[this]
                endloop
            endif
        implement CT32End
       
        private static method deindex takes nothing returns nothing
            set next[prev[GetIndexedUnitId()]] = next[GetIndexedUnitId()]
            set prev[next[GetIndexedUnitId()]] = prev[GetIndexedUnitId()]
        endmethod
       
        private static method index takes nothing returns nothing
            set next[GetIndexedUnitId()] = 0
            set prev[GetIndexedUnitId()] = prev[0]
            set next[prev[0]] = GetIndexedUnitId()
            set prev[0] = GetIndexedUnitId()
        endmethod
       
        implement UnitIndexStruct
    endstruct
   
endlibrary
//TESH.scrollpos=144
//TESH.alwaysfold=0
library MoveSpeedX /* v1.0.0.1
*************************************************************************************
*
*   This library allows you to set unit movement speeds beyond 522 without bugs.
*   This is an extension of the library MoveSpeedX, but is formatted for GUI use.
*
************************************************************************************
*
*   SETTINGS
*/

globals
    private constant real PERIOD = 0.03125
        //  This is the period on which all units will be run.
        // If you lower this value, movement bonuses will be smoother,
        // but will require more processing power (lag more).
        //  Also, the lower this is, the higher the move speed can be
        // before it starts bugging on waypoints. The lowest valid
        // period is 0.00125. A period of 0.00625 is very robust.
    private constant real MARGIN = 0.01
        // This is the margin of approximation when comparing reals.
        // You will most likely not need to change this.
endglobals
/*
************************************************************************************
*
*    Functions
*
*        function GetUnitMoveSpeedX takes unit whichUnit returns real
*           - Returns a unit movement speed. The GUI function will
*           - not return the correct value. This function will always
*           - return the correct value regardless of whether the unit
*           - has a movement speed beyond 522.
*
************************************************************************************
*
*   REQUIREMENTS
*
*       1.  JassNewGen Pack v5d
*       2.  JassHelper 0.A.2.B
*
*   HOW TO IMPLEMENT
*  
*       1.  Copy the trigger MoveSpeedXGUI.
*       2.  Paste it into your map.
*       3.  Open "Advanced -> Gameplay Constants".
*       4.  Checkmark "Use Custom Gameplay Constants".
*       5.  Find the field, "Movement - Unit Speed - Maximum", change
*           that to 522.
*       6.  Find the field, "Movement - Unit Speed - Minimum", hold
*           shift and click, and change it to 0.
*       7.  Read HOW TO USE.
*
************************************************************************************
*
*   HOW TO USE
*
*       This system will automatically work by itself. You can use the
*       normal GUI function for modifying unit movement speeds. Simply
*       use "Unit - Set Movement Speed", input whatever value you want,
*       and you are good to go! It will handle values beyond 522 by itself.
*
*       HOWEVER, the GUI function will not return correct values if a unit
*       has a movement speed greater than 522. To fix this, use the function
*       GetUnitMoveSpeedX to return the correct value. A sample is given in
*       the trigger "Speed Change" in the test map.
*
************************************************************************************
*
*   NOTES
*
*       The unit may move randomly about one point before finally stopping. If
*       this occurs, try changing PERIOD or reduce the unit movement speed.
*
*       This also will not factor in bonuses.
*
************************************************************************************/


    private function ApproxEqual takes real A, real B returns boolean
        return (A >= (B - MARGIN)) and (A <= (B + MARGIN))
    endfunction
   
    private module M
        private static integer ic = 0
        private static integer ir = 0
   
        static hashtable hash = InitHashtable()
       
        thistype next
        thistype prev
       
        unit curr
        real speed
        real x
        real y
       
        method destroy takes nothing returns nothing
            set this.next.prev = this.prev
            set this.prev.next = this.next
            set .prev = ir
            set ir    = this
            call RemoveSavedInteger(hash, 0, GetHandleId(.curr))
        endmethod
           
        private static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next // first instance in list
            local real nx = 0 // the x-coordinate after tick
            local real ny = 0 // the y-coordinate after tick
            local real dx = 0 // distance between new-x and old-x
            local real dy = 0 // distance between new-y and old-y
            local real d  = 0 // distance between new point and old point
            local unit u // unit being affected
            loop
                exitwhen this == 0
                set u  = .curr
                set nx = GetUnitX(u)
                set ny = GetUnitY(u)
                if (not IsUnitPaused(u)) and GetUnitAbilityLevel(u, 'BSTN') == 0 and GetUnitAbilityLevel(u, 'BPSE') == 0 then
                    if not ApproxEqual(nx, .x) or not ApproxEqual(ny, .y) then
                        set dx = nx - .x
                        set dy = ny - .y
                        set d  = SquareRoot(dx * dx + dy * dy)
                        set .x = nx + dx / d * .speed
                        set .y = ny + dy / d * .speed
                        call SetUnitX(u, .x)
                        call SetUnitY(u, .y)
                    endif
                endif
                set this = this.next
            endloop
            set u = null
        endmethod
       
        static method create takes unit whichUnit, real newSpeed returns thistype
            local thistype this = ir
            if this == 0 then
                set ic   = ic + 1
                set this = ic
            else
                set ir   = .prev
            endif
            set this.next = thistype(0).next
            set thistype(0).next.prev = this
            set thistype(0).next = this
            set this.prev  = 0
            set this.curr  = whichUnit
            set this.speed = (newSpeed - 522) * PERIOD
            set this.x     = GetUnitX(whichUnit)
            set this.y     = GetUnitY(whichUnit)
            call SaveInteger(hash, 0, GetHandleId(whichUnit), this)
            return this
        endmethod
       
        static method update takes unit whichUnit, real newSpeed returns nothing
            local thistype this = 0
            if HaveSavedInteger(hash, 0, GetHandleId(whichUnit)) then
                set this = LoadInteger(hash, 0, GetHandleId(whichUnit))
                if newSpeed > 522 then
                    set this.speed = (newSpeed-522)*PERIOD
                else
                    call this.destroy()
                endif
            elseif newSpeed > 522 then
                call thistype.create(whichUnit, newSpeed)
            endif
        endmethod
   
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), PERIOD, true, function thistype.periodic)
        endmethod
    endmodule
   
    private struct MoveSpeedStruct extends array
        implement M
    endstruct
   
    function GetUnitMoveSpeedX takes unit whichUnit returns real
        if HaveSavedInteger(MoveSpeedStruct.hash, 0, GetHandleId(whichUnit)) then
            return (MoveSpeedStruct(LoadInteger(MoveSpeedStruct.hash, 0, GetHandleId(whichUnit))).speed/PERIOD)+522
        endif
        return GetUnitMoveSpeed(whichUnit)
    endfunction
   
    function SetUnitMoveSpeedX takes unit whichUnit, real newSpeed returns nothing
        call MoveSpeedStruct.update(whichUnit, newSpeed)
    endfunction

    hook SetUnitMoveSpeed SetUnitMoveSpeedX
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
library Bonus uses UnitIndexer
   
    globals
        constant integer BONUS_TYPE_STR          = 1
        constant integer BONUS_TYPE_AGI          = 2
        constant integer BONUS_TYPE_INT          = 3
        constant integer BONUS_TYPE_ARMOR        = 4
        constant integer BONUS_TYPE_DAMAGE       = 5
        constant integer BONUS_TYPE_ATTACK_SPEED = 6
        constant integer BONUS_TYPE_LIFE         = 7
        constant integer BONUS_TYPE_MANA         = 8
    endglobals
   
    private module Init
        private static method onInit takes nothing returns nothing
            local integer int = 1
            local integer i = 0
            local integer b = 1
            local unit dummy = CreateUnit(Player(15), 'e006', 0, 0, 0)
           
            loop
                set twoPow[i] = int
                exitwhen i == 30
                set i = i + 1
                set int = int * 2
            endloop
           
            set ABIL[BONUS_TYPE_STR]            = 'A5A@'
            set ABIL[BONUS_TYPE_ARMOR]          = 'A5B@'
            set ABIL[BONUS_TYPE_AGI]            = 'A5D@'
            set ABIL[BONUS_TYPE_INT]            = 'A5E@'
            set ABIL[BONUS_TYPE_DAMAGE]         = 'A5C@'
            set ABIL[BONUS_TYPE_ATTACK_SPEED]   = 'A5F@'
            set ABIL[BONUS_TYPE_LIFE]           = 'A5G@'
            set ABIL[BONUS_TYPE_MANA]           = 'A5H@'
           
            set LEVEL[BONUS_TYPE_ARMOR]         = 10
            set LEVEL[BONUS_TYPE_DAMAGE]        = 15
            set LEVEL[BONUS_TYPE_STR]           = 10
            set LEVEL[BONUS_TYPE_AGI]           = 10
            set LEVEL[BONUS_TYPE_INT]           = 10
            set LEVEL[BONUS_TYPE_ATTACK_SPEED]  = 9
            set LEVEL[BONUS_TYPE_LIFE]          = 15
            set LEVEL[BONUS_TYPE_MANA]          = 20
           
            loop
                exitwhen ABIL[b] == 0
                set int = ABIL[b] + LEVEL[i]
                loop
                    call UnitAddAbility(dummy,int)
                    exitwhen int == ABIL[b]
                    set int = int - 1
                endloop
                set b = b + 1
            endloop
            call RemoveUnit(dummy)
            set dummy = null
                   
            call RegisterUnitIndexEvent(Condition(function thistype.index), UnitIndexer.INDEX)
            call RegisterUnitIndexEvent(Condition(function thistype.deindex), UnitIndexer.DEINDEX)
        endmethod
    endmodule
   
    struct Bonus extends array
        private static integer array ABIL
        private static integer array LEVEL
        private static integer array twoPow
        private static Table array bonus
       
        static method operator [] takes unit u returns thistype
            return GetUnitUserData(u)
        endmethod
       
        method operator unit takes nothing returns unit
            return GetUnitById(this)
        endmethod
       
        private static method index takes nothing returns boolean
            if bonus[GetIndexedUnitId()] == 0 then
                set bonus[GetIndexedUnitId()] = Table.create()
            endif
            return false
        endmethod
       
        private static method deindex takes nothing returns boolean
            call bonus[GetIndexedUnitId()].flush()
            return false
        endmethod
       
        private static method compute takes unit u, integer abil, integer levels, integer amount returns nothing
            local boolean n = amount < 0
            if n then
                set amount = amount + twoPow[levels]
            else
                call UnitMakeAbilityPermanent(u, false, abil)
                call UnitRemoveAbility(u, abil)
            endif
            set abil = abil + levels
            set levels = twoPow[levels]
            loop
                set levels = levels / 2
                if amount >= levels then
                    call UnitAddAbility(u, abil)
                    call UnitMakeAbilityPermanent(u, true, abil)
                    set amount = amount - levels
                else
                    call UnitMakeAbilityPermanent(u, false, abil)
                    call UnitRemoveAbility(u, abil)
                endif
                set abil = abil - 1
                exitwhen levels == 1
            endloop
            if n then
                call UnitAddAbility(u, abil)
                call UnitMakeAbilityPermanent(u, true, abil)
            endif
        endmethod
       
        method getBonus takes integer b returns integer
            return bonus[this][b]
        endmethod
       
        method setBonus takes integer b, integer v returns nothing
            set bonus[this][b]=v
            call compute(this.unit,ABIL[b],LEVEL[b],v)
        endmethod
       
        method removeBonus takes integer b returns nothing
            call this.setBonus(b,0)
        endmethod
       
        method addBonus takes integer b, integer v returns nothing
            call this.setBonus(b,this.getBonus(b)+v)
        endmethod
       
        implement Init
    endstruct
   
endlibrary
//TESH.scrollpos=39
//TESH.alwaysfold=0
library Status uses UnitIndexer, CTL

    globals
        private constant integer ABIL_SILENCE='A501'
        private constant integer ABIL_DISARM='A502'
        private constant integer ABIL_IMMOBOLISE='A505'
        private constant integer ABIL_INVISIBLE='A507'
        private constant integer ABIL_GHOST='A508'
        private constant integer ABIL_DOOM='A509'
        private constant integer ABIL_IMMUNITY='A50B'
        private constant integer ABIL_HEX='A50C'
        private constant integer ABIL_NEVER_MISS='A50F'
        private constant integer ABIL_ALWAYS_MISS='A50H'
        private constant integer ABIL_UNTOUCHABLE='A50J'
        private constant integer ABIL_BANISH='A50K'
        private constant integer ABIL_PHASE='A50L'
        private constant integer ABIL_RESISTANT_SKIN='A50Q'
        private constant integer ABIL_REFLECT_PIERCING='A50S'
        private constant integer ABIL_DISABLE='A50T'
       
        private constant integer BUFF_SILENCE='B501'
        private constant integer BUFF_DOOM='B509'
        private constant integer BUFF_DISARM='B502'
        private constant integer BUFF_IMMOBOLISE_GROUND='B505'
        private constant integer BUFF_IMMOBOLISE_AIR='B506'
        private constant integer BUFF_HEX='B50C'
        private constant integer BUFF_BANISH='B50K'
        private constant integer BUFF_PHASE='B50L'
        private constant integer BUFF_DISABLE='B50T'
       
        private constant integer OID_STOP=851972 //stop
        private constant integer OID_SILENCE=852668 //soulburn
        private constant integer OID_DISARM=852585 //drunkenhaze
        private constant integer OID_IMMOBOLISE=852106 //ensnare
        private constant integer OID_DOOM=852583 //doom
        private constant integer OID_HEX=852502 //hex
        private constant integer OID_BANISH=852486 //banish
        private constant integer OID_PHASE=852129 //windwalk
        private constant integer OID_DISABLE=852252 //creepthunderbolt (hurlboulder)
       
        private unit CASTER_DISARM = null
    endglobals
   
    private module Init
        private static method onInit takes nothing returns nothing
            local integer i = 0
            local unit dummy = CreateUnit(Player(15), 'e006', 0, 0, 0)
            set thistype.dummyCaster = CreateUnit(Player(15), 'e006', 0, 0, 0)
            call UnitAddAbility(thistype.dummyCaster,ABIL_DISABLE)
            call UnitAddAbility(thistype.dummyCaster,ABIL_SILENCE)
            call UnitAddAbility(thistype.dummyCaster,ABIL_DISARM)
            call UnitAddAbility(thistype.dummyCaster,ABIL_IMMOBOLISE)
            call UnitAddAbility(thistype.dummyCaster,ABIL_DOOM)
            call UnitAddAbility(thistype.dummyCaster,ABIL_HEX)
            call UnitAddAbility(thistype.dummyCaster,ABIL_BANISH)
            loop
                call SetPlayerAbilityAvailable(Player(i),ABIL_IMMUNITY,false)
                call SetPlayerAbilityAvailable(Player(i),ABIL_NEVER_MISS,false)
                call SetPlayerAbilityAvailable(Player(i),ABIL_ALWAYS_MISS,false)
                call SetPlayerAbilityAvailable(Player(i),ABIL_UNTOUCHABLE,false)
                call SetPlayerAbilityAvailable(Player(i),ABIL_RESISTANT_SKIN,false)
                call SetPlayerAbilityAvailable(Player(i),ABIL_REFLECT_PIERCING,false)
                exitwhen i == 9
                set i = i + 1
            endloop
            call UnitAddAbility(dummy,ABIL_INVISIBLE)
            call UnitAddAbility(dummy,ABIL_GHOST)
            call UnitAddAbility(dummy,ABIL_IMMUNITY)
            call UnitAddAbility(dummy,ABIL_NEVER_MISS)
            call UnitAddAbility(dummy,ABIL_ALWAYS_MISS)
            call UnitAddAbility(dummy,ABIL_UNTOUCHABLE)
            call UnitAddAbility(dummy,ABIL_PHASE)
            call UnitAddAbility(dummy,ABIL_RESISTANT_SKIN)
            call UnitAddAbility(dummy,ABIL_REFLECT_PIERCING)
            call RemoveUnit(dummy)
            set dummy = null
        endmethod
    endmodule
   
    struct Status extends array
        private static method index takes nothing returns nothing
            local thistype this = GetIndexedUnitId()
            call UnitShareVision(this.unit, Player(15), true)
           
            set this.disableLevel = 0
            set this.silenceLevel = 0
            set this.doomLevel = 0
            set this.disarmLevel = 0
            set this.immoboliseLevel = 0
            set this.invisibleLevel = 0
            set this.ghostLevel = 0
            set this.immunityLevel = 0
            set this.hexLevel = 0
            set this.neverMissLevel = 0
            set this.alwaysMissLevel = 0
            set this.untouchableLevel = 0
            set this.banishLevel = 0
            set this.phaseLevel = 0
            set this.resistantSkinLevel = 0
            set this.reflectPiercingLevel = 0
        endmethod
       
        implement UnitIndexStruct
       
        private static unit dummyCaster=null
       
        implement Init
       
        // Disable
        private integer disableLevel
        method addDisable takes nothing returns nothing
            set this.disableLevel=this.disableLevel+1
            if this.disableLevel>0 then
                call IssueTargetOrderById(thistype.dummyCaster,OID_DISABLE,this.unit)
            endif
        endmethod
        method removeDisable takes nothing returns nothing
            set this.disableLevel=this.disableLevel-1
            if this.disableLevel==0 then
                call UnitRemoveAbility(this.unit,BUFF_DISABLE)
            endif
        endmethod
        method isDisabled takes nothing returns boolean
            return this.disableLevel>0
        endmethod
       
        // Silence
        private integer silenceLevel
        method addSilence takes nothing returns nothing
            set this.silenceLevel=this.silenceLevel+1
            if this.silenceLevel>0 then
                call IssueTargetOrderById(thistype.dummyCaster,OID_SILENCE,this.unit)
            endif
        endmethod
        method removeSilence takes nothing returns nothing
            set this.silenceLevel=this.silenceLevel-1
            if this.silenceLevel==0 then
                call UnitRemoveAbility(this.unit,BUFF_SILENCE)
            endif
        endmethod
        method isSilenced takes nothing returns boolean
            return this.silenceLevel>0
        endmethod
       
        private integer doomLevel
        method addDoom takes nothing returns nothing
            set this.doomLevel=this.doomLevel+1
            if this.doomLevel>0 then
                call IssueTargetOrderById(thistype.dummyCaster,OID_DOOM,this.unit)
            endif
        endmethod
        method removeDoom takes nothing returns nothing
            set this.doomLevel=this.doomLevel-1
            if this.doomLevel==0 then
                call UnitRemoveAbility(this.unit,BUFF_DOOM)
            endif
        endmethod
        method isDoomed takes nothing returns boolean
            return this.doomLevel>0
        endmethod
       
        private integer disarmLevel
        method addDisarm takes nothing returns nothing
            set this.disarmLevel=this.disarmLevel+1
            if this.disarmLevel>0 then
                call IssueTargetOrderById(thistype.dummyCaster,OID_DISARM,this.unit)
            endif
        endmethod
        method removeDisarm takes nothing returns nothing
            set this.disarmLevel=this.disarmLevel-1
            if this.disarmLevel==0 then
                call UnitRemoveAbility(this.unit,BUFF_DISARM)
            endif
        endmethod
        method isDisarmed takes nothing returns boolean
            return this.disarmLevel>0
        endmethod
       
        // Immobolise
        private integer immoboliseLevel
        method addImmobolise takes nothing returns nothing
            set this.immoboliseLevel=this.immoboliseLevel+1
            if this.immoboliseLevel>0 then
                call IssueTargetOrderById(thistype.dummyCaster,OID_IMMOBOLISE,this.unit)
            endif
        endmethod
        method removeImmobolise takes nothing returns nothing
            set this.immoboliseLevel=this.immoboliseLevel-1
            if this.immoboliseLevel==0 then
                call UnitRemoveAbility(this.unit,BUFF_IMMOBOLISE_GROUND)
                call UnitRemoveAbility(this.unit,BUFF_IMMOBOLISE_AIR)
            endif
        endmethod
        method isImmobolised takes nothing returns boolean
            return this.immoboliseLevel>0
        endmethod
       
        // Invisibility
        private integer invisibleLevel
        method addInvisible takes nothing returns nothing
            set this.invisibleLevel=this.invisibleLevel+1
            if this.invisibleLevel>0 then
                call UnitAddAbility(this.unit,ABIL_INVISIBLE)
                call UnitMakeAbilityPermanent(this.unit,true,ABIL_INVISIBLE)
            endif
        endmethod
        method removeInvisible takes nothing returns nothing
            set this.invisibleLevel=this.invisibleLevel-1
            if this.invisibleLevel==0 then
                call UnitMakeAbilityPermanent(this.unit,false,ABIL_INVISIBLE)
                call UnitRemoveAbility(this.unit,ABIL_INVISIBLE)
            endif
        endmethod
        method isInvisible takes nothing returns boolean
            return this.invisibleLevel>0
        endmethod
       
        // Ghost
        private integer ghostLevel
        method addGhost takes nothing returns nothing
            set this.ghostLevel=this.ghostLevel+1
            if this.ghostLevel>0 then
                call UnitAddAbility(this.unit,ABIL_GHOST)
                call UnitMakeAbilityPermanent(this.unit,true,ABIL_GHOST)
            endif
        endmethod
        method removeGhost takes nothing returns nothing
            set this.ghostLevel=this.ghostLevel-1
            if this.ghostLevel==0 then
                call UnitMakeAbilityPermanent(this.unit,false,ABIL_GHOST)
                call UnitRemoveAbility(this.unit,ABIL_GHOST)
            endif
        endmethod
        method isGhost takes nothing returns boolean
            return this.ghostLevel>0
        endmethod
       
        // Spell Immunity
        private integer immunityLevel
        method addImmunity takes nothing returns nothing
            set this.immunityLevel=this.immunityLevel+1
            if this.immunityLevel>0 then
                call UnitAddAbility(this.unit,ABIL_IMMUNITY)
                call UnitMakeAbilityPermanent(this.unit,true,ABIL_IMMUNITY)
            endif
        endmethod
        method removeImmunity takes nothing returns nothing
            set this.immunityLevel=this.immunityLevel-1
            if this.immunityLevel==0 then
                call UnitMakeAbilityPermanent(this.unit,false,ABIL_IMMUNITY)
                call UnitRemoveAbility(this.unit,ABIL_IMMUNITY)
            endif
        endmethod
        method isImmune takes nothing returns boolean
            return this.immunityLevel>0
        endmethod
       
        // Hex
        private integer hexLevel
        method addHex takes nothing returns nothing
            set this.hexLevel=this.hexLevel+1
            if this.hexLevel>0 then
                call IssueTargetOrderById(thistype.dummyCaster,OID_HEX,this.unit)
            endif
        endmethod
        method removeHex takes nothing returns nothing
            set this.hexLevel=this.hexLevel-1
            if this.hexLevel==0 then
                call UnitRemoveAbility(this.unit,BUFF_HEX)
            endif
        endmethod
        method isHexed takes nothing returns boolean
            return this.hexLevel>0
        endmethod
       
        // Never Miss
        private integer neverMissLevel
        method addNeverMiss takes nothing returns nothing
            set this.neverMissLevel=this.neverMissLevel+1
            if this.neverMissLevel>0 then
                call UnitAddAbility(this.unit,ABIL_NEVER_MISS)
                call UnitMakeAbilityPermanent(this.unit,true,ABIL_NEVER_MISS)
            endif
        endmethod
        method removeNeverMiss takes nothing returns nothing
            set this.neverMissLevel=this.neverMissLevel-1
            if this.neverMissLevel==0 then
                call UnitMakeAbilityPermanent(this.unit,false,ABIL_NEVER_MISS)
                call UnitRemoveAbility(this.unit,ABIL_NEVER_MISS)
            endif
        endmethod
        method isNeverMiss takes nothing returns boolean
            return this.neverMissLevel>0
        endmethod
       
        // Always Miss
        private integer alwaysMissLevel
        method addAlwaysMiss takes nothing returns nothing
            set this.alwaysMissLevel=this.alwaysMissLevel+1
            if this.alwaysMissLevel>0 then
                call UnitAddAbility(this.unit,ABIL_ALWAYS_MISS)
                call UnitMakeAbilityPermanent(this.unit,true,ABIL_ALWAYS_MISS)
            endif
        endmethod
        method removeAlwaysMiss takes nothing returns nothing
            set this.alwaysMissLevel=this.alwaysMissLevel-1
            if this.alwaysMissLevel==0 then
                call UnitMakeAbilityPermanent(this.unit,false,ABIL_ALWAYS_MISS)
                call UnitRemoveAbility(this.unit,ABIL_ALWAYS_MISS)
            endif
        endmethod
        method isAlwaysMiss takes nothing returns boolean
            return this.alwaysMissLevel>0
        endmethod
       
        // Untouchable
        private integer untouchableLevel
        method addUntouchable takes nothing returns nothing
            set this.untouchableLevel=this.untouchableLevel+1
            if this.untouchableLevel>0 then
                call UnitAddAbility(this.unit,ABIL_UNTOUCHABLE)
                call UnitMakeAbilityPermanent(this.unit,true,ABIL_UNTOUCHABLE)
            endif
        endmethod
        method removeUntouchable takes nothing returns nothing
            set this.untouchableLevel=this.untouchableLevel-1
            if this.untouchableLevel==0 then
                call UnitMakeAbilityPermanent(this.unit,false,ABIL_UNTOUCHABLE)
                call UnitRemoveAbility(this.unit,ABIL_UNTOUCHABLE)
            endif
        endmethod
        method isUntouchable takes nothing returns boolean
            return this.untouchableLevel>0
        endmethod
       
        // Banish
        private integer banishLevel
        method addBanish takes nothing returns nothing
            set this.banishLevel=this.banishLevel+1
            if this.banishLevel>0 then
                call IssueTargetOrderById(thistype.dummyCaster,OID_BANISH,this.unit)
            endif
        endmethod
        method removeBanish takes nothing returns nothing
            set this.banishLevel=this.banishLevel-1
            if this.banishLevel==0 then
                call UnitRemoveAbility(this.unit,BUFF_BANISH)
            endif
        endmethod
        method isBanished takes nothing returns boolean
            return this.banishLevel>0
        endmethod
       
        // Phase
        private integer phaseLevel
        method addPhase takes nothing returns nothing
            set this.phaseLevel=this.phaseLevel+1
            if this.phaseLevel>0 then
                call SetPlayerAbilityAvailable(GetOwningPlayer(this.unit),ABIL_PHASE,true)
                if UnitAddAbility(this.unit,ABIL_PHASE) then
                    call UnitMakeAbilityPermanent(this.unit,true,ABIL_PHASE)
                endif
                call IssueImmediateOrderById(this.unit,OID_PHASE)
                call SetPlayerAbilityAvailable(GetOwningPlayer(this.unit),ABIL_PHASE,false)
            endif
        endmethod
        method removePhase takes nothing returns nothing
            set this.phaseLevel=this.phaseLevel-1
            if this.phaseLevel==0 then
                call UnitRemoveAbility(this.unit,BUFF_PHASE)
            endif
        endmethod
        method isPhased takes nothing returns boolean
            return this.phaseLevel>0
        endmethod
       
        // Resistant Skin
        private integer resistantSkinLevel
        method addResistantSkin takes nothing returns nothing
            set this.resistantSkinLevel=this.resistantSkinLevel+1
            if this.resistantSkinLevel>0 then
                call UnitAddAbility(this.unit,ABIL_RESISTANT_SKIN)
                call UnitMakeAbilityPermanent(this.unit,true,ABIL_RESISTANT_SKIN)
            endif
        endmethod
        method removeResistantSkin takes nothing returns nothing
            set this.resistantSkinLevel=this.resistantSkinLevel-1
            if this.resistantSkinLevel==0 then
                call UnitMakeAbilityPermanent(this.unit,false,ABIL_RESISTANT_SKIN)
                call UnitRemoveAbility(this.unit,ABIL_RESISTANT_SKIN)
            endif
        endmethod
        method isResistantSkin takes nothing returns boolean
            return this.resistantSkinLevel>0
        endmethod
       
        // Reflect Piercing
        private integer reflectPiercingLevel
        method addReflectPiercing takes nothing returns nothing
            set this.reflectPiercingLevel=this.reflectPiercingLevel+1
            if this.reflectPiercingLevel>0 then
                call UnitAddAbility(this.unit,ABIL_REFLECT_PIERCING)
                call UnitMakeAbilityPermanent(this.unit,true,ABIL_REFLECT_PIERCING)
            endif
        endmethod
        method removeReflectPiercing takes nothing returns nothing
            set this.reflectPiercingLevel=this.reflectPiercingLevel-1
            if this.reflectPiercingLevel==0 then
                call UnitMakeAbilityPermanent(this.unit,false,ABIL_REFLECT_PIERCING)
                call UnitRemoveAbility(this.unit,ABIL_REFLECT_PIERCING)
            endif
        endmethod
        method isReflectPiercing takes nothing returns boolean
            return this.reflectPiercingLevel>0
        endmethod
    endstruct
endlibrary
//TESH.scrollpos=226
//TESH.alwaysfold=0
library ItemBonus initializer Init requires DamageSystem, MoveSpeedX
    globals
        private unit DUMMY_HERO = null
    endglobals
   
    private function Init takes nothing returns nothing
        set DUMMY_HERO = gg_unit_H02A_0342
    endfunction
   
    struct ItemBonus extends array
   
        integer strength
        integer intelligence
        integer agility
       
        integer damage
        integer armor
       
        integer life
        integer mana
       
        real attackSpeed
        real movementSpeed
       
        real manaRegeneration
        real lifeRegeneration
        real manaRegenerationPercent
        real lifeRegenerationPercent
       
        real criticalChance
        real criticalMultiplier
       
        real spellCriticalChance
        real spellCriticalMultiplier
       
        real spellPower
       
        real fireResistance
        real coldResistance
        real poisonResistance
        real lightningResistance
       
        real fireDamage
        real coldDamage
        real poisonDamage
        real lightningDamage
       
        real bashChance
        real bashDuration
       
        real evasion
       
        real reflectChance
        real reflectPercent
       
        string effectPath
        string attachmentPoint
       
        integer AddedAbility

        effect dummySFX
        effect heroSFX
       
        static method operator [] takes integer itemId returns thistype
            return itemId - 'I000'
        endmethod
       
        method saveStats takes integer strengthB, integer intelligenceB, integer agilityB, integer damageB, integer armorB, integer lifeB, integer manaB, real attackSpeedB, real movementSpeedB, real manaRegenerationB, real lifeRegenerationB, real lifeRegenerationPercentB, real manaRegenerationPercentB returns nothing
            set this.strength                   = strengthB
            set this.intelligence               = intelligenceB
            set this.agility                    = agilityB
            set this.damage                     = damageB
            set this.armor                      = armorB
            set this.life                       = lifeB
            set this.mana                       = manaB
            set this.attackSpeed                = attackSpeedB
            set this.movementSpeed              = movementSpeedB
            set this.manaRegeneration           = manaRegenerationB
            set this.lifeRegeneration           = lifeRegenerationB
            set this.manaRegenerationPercent    = manaRegenerationPercentB
            set this.lifeRegenerationPercent    = lifeRegenerationPercentB
        endmethod
       
        method saveStatsPet takes integer damageB, integer armorB, integer lifeB, integer manaB, real attackSpeedB, real movementSpeedB, real manaRegenerationB, real lifeRegenerationB, real lifeRegenerationPercentB, real manaRegenerationPercentB returns nothing
            set this.damage                     = damageB
            set this.armor                      = armorB
            set this.life                       = lifeB
            set this.mana                       = manaB
            set this.attackSpeed                = attackSpeedB
            set this.movementSpeed              = movementSpeedB
            set this.manaRegeneration           = manaRegenerationB
            set this.lifeRegeneration           = lifeRegenerationB
            set this.manaRegenerationPercent    = manaRegenerationPercentB
            set this.lifeRegenerationPercent    = lifeRegenerationPercentB
        endmethod
       
        method saveDamageStats takes real criticalChanceB, real criticalMultiplierB, real spellCriticalChanceB, real spellCriticalMultiplierB, real spellPowerB, real fireResistanceB, real coldResistanceB, real poisonResistanceB, real lightningResistanceB, real fireDamageB, real coldDamageB, real lightningDamageB, real poisonDamageB, real bashChanceB, real bashDurationB, real evasionB, real reflectChanceB, real reflectPercentB returns nothing
            set this.criticalChance             = criticalChanceB
            set this.criticalMultiplier         = criticalMultiplierB
            set this.spellCriticalChance        = spellCriticalChanceB
            set this.spellCriticalMultiplier    = spellCriticalMultiplierB
            set this.spellPower                 = spellPowerB
            set this.fireResistance             = fireResistanceB
            set this.coldResistance             = coldResistanceB
            set this.poisonResistance           = poisonResistanceB
            set this.lightningResistance        = lightningResistanceB
            set this.fireDamage                 = fireDamageB
            set this.coldDamage                 = coldDamageB
            set this.poisonDamage               = poisonDamageB
            set this.lightningDamage            = lightningDamageB
            set this.bashChance                 = bashChanceB
            set this.bashDuration               = bashDurationB
            set this.evasion                    = evasionB
            set this.reflectChance              = reflectChanceB
            set this.reflectPercent             = reflectPercentB
        endmethod
       
        method saveEffect takes integer a, string effectPathB, string attachmentPointB returns nothing
            set this.effectPath = effectPathB
            set this.attachmentPoint = attachmentPointB
            set this.AddedAbility = a
        endmethod
       
        static method load takes integer id returns nothing
            local thistype this = id - 'I000'
            set Unit(HERO_UD).criticalChance             = Unit(HERO_UD).criticalChance           + this.criticalChance
            set Unit(HERO_UD).criticalMultiplier         = Unit(HERO_UD).criticalMultiplier       + this.criticalMultiplier
            set Unit(HERO_UD).spellCriticalChance        = Unit(HERO_UD).spellCriticalChance      + this.spellCriticalChance
            set Unit(HERO_UD).spellCriticalMultiplier    = Unit(HERO_UD).spellCriticalMultiplier  + this.spellCriticalMultiplier
            set Unit(HERO_UD).spellPower                 = Unit(HERO_UD).spellPower               + this.spellPower
            set Unit(HERO_UD).fireResistance             = Unit(HERO_UD).fireResistance           + this.fireResistance/100
            set Unit(HERO_UD).coldResistance             = Unit(HERO_UD).coldResistance           + this.coldResistance/100
            set Unit(HERO_UD).poisonResistance           = Unit(HERO_UD).poisonResistance         + this.poisonResistance/100
            set Unit(HERO_UD).lightningResistance        = Unit(HERO_UD).lightningResistance      + this.lightningResistance/100
            set Unit(HERO_UD).bashChance                 = Unit(HERO_UD).bashChance               + this.bashChance
            set Unit(HERO_UD).bashDuration               = Unit(HERO_UD).bashDuration             + this.bashDuration
            set Unit(HERO_UD).evasion                    = Unit(HERO_UD).evasion                  + this.evasion
            set Unit(HERO_UD).reflectChance              = Unit(HERO_UD).reflectChance            + this.reflectChance
            set Unit(HERO_UD).reflectPercent             = Unit(HERO_UD).reflectPercent           + this.reflectPercent
            set Unit(HERO_UD).fireDamage                 = Unit(HERO_UD).fireDamage               + this.fireDamage
            set Unit(HERO_UD).coldDamage                 = Unit(HERO_UD).coldDamage               + this.coldDamage
            set Unit(HERO_UD).poisonDamage               = Unit(HERO_UD).poisonDamage             + this.poisonDamage
            set Unit(HERO_UD).lightningDamage            = Unit(HERO_UD).lightningDamage          + this.lightningDamage
            call Bonus(HERO_UD).addBonus(BONUS_TYPE_STR,             this.strength)
            call Bonus(HERO_UD).addBonus(BONUS_TYPE_AGI,             this.agility