• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Triggers

Battle of Flags v2.0b.w3x
Variables
Demo
Demo
onEscape
Setup
Globals
Credits
Ability Settings
Heroes
Spawn Settings
Team Settings
User Settings
Gameplay
Music Injection
GameHandler
Create Slider
Leave
GameEnd
Fight System
KD System
Respawn
Kill
Flag system
Flag
Sliding System
Sliding System
Terrain Settings
Terrain Types
Abilities
Missle
---------------------------
Engery Ball
Sniper Arrow
Rocket
---------------------------
Invisiblity
---------------------------
Jump
---------------------------
Holy Ra
---------------------------
Roots
Display Range On Off
---------------------------
Flag Indicator
---------------------------
Explosive Egg
---------------------------
Cam Lock
Walls System
Walls
Magic Walls
Weather System
Weather
Weapons
Weapon PickUp
WeaponLists
TextTags
TextHandler
Dialogs
Dialog System
Catapults
Catapult
Teleport
Teleport
Multiboard
Board CurrentStats
Board LocalStats
Board Switching
SaveLoad
SaveLoad
-----------
Libraries
-----------
Libraries Used
AbilityPreload
Player Tools
Multiboard
AllocT
List
Rapid Sound
Weather Lib
MaxState
RecycleDummy
CTL
Table
World Bounds
RegisterPlayerUnitEvent
TimerUtils
Unit Indexer
SpellEffectEvent
IsGameOnline
Init
File IO
Sync
Savecode
Libraries Required
Trigger
IsTerrainWalkable
BigNum
GetUnitCollision
Event
ErrorMessage
SyncInteger
ListT
BooleanExpression
TableField
UniqueNxListT
NxListT
My libs
Colors
Zoom
Clear
TileDefinition
PauseUnit
Print
QuickSort
Gametime
LineIntersect
Parabola
Name Type is_array initial_value
s string No
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Demo initializer Init
  
    private function Start takes nothing returns nothing
        call NewSlider(Player(6), CATCHER)
    endfunction
    
    private function testAction takes nothing returns nothing
    endfunction
        
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerAddAction(t, function testAction)
        
        call TimerStart(CreateTimer(), 1, false, function Start)
    endfunction
endscope
onEscape
Events
Player - Player 1 (Red) skips a cinematic sequence
Conditions
Actions
Custom script: call BJDebugMsg(I2S(PlayerTools.user_Amount) + " users")
Custom script: call BJDebugMsg(I2S(Team.BLUE.count) + " Blue users")
Custom script: call BJDebugMsg(I2S(Team.RED.count) + " Red users")
//TESH.scrollpos=146
//TESH.alwaysfold=0
library Default uses Print, CTL, TimerUtils, Table, UnitIndexer, SuspendUnit
globals
    constant integer ALIEN       = 'H003'
    constant integer CATCHER     = 'H004'
    constant integer JUMPER      = 'H002'
    constant integer SAVER       = 'H00D'
    constant integer SNIPER      = 'H009'
    constant integer SPY         = 'H007'
    constant integer STEAMROLLER = 'H001'
    constant integer TANK        = 'H00C'
    
    constant rect RECT_LEFT  = Rect(-16000, 3800, -9400, 11400)
    constant rect RECT_RIGHT = Rect(1050, 5270, 7800, 12400)
    
    constant integer ROCKET_EFFECT = 'rEff'
    constant integer NET_EFFECT = 'cEff'
    
    constant string MISSLE_BLUE_MODELPATH   = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
    constant string MISSLE_RED_MODELPATH    = "Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl"
    constant string MISSLE_SNIPER_MODELPATH = "Abilities\\Weapons\\ColdArrow\\ColdArrowMissile.mdl"
    constant string MISSLE_ROCKET_MODELPATH = "Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl"
    constant string SECRET_ITEM_MODELPATH   = "Objects\\InventoryItems\\BundleofGifts\\BundleofGifts.mdl"
    
    constant real SCALE_ROCKET       = 2.2
    constant real SCALE_ENERGY_BALL  = 2.8
    constant real SCALE_SNIPER_ARROW = 1.4
    constant real SCALE_SECRET_ITEM  = 2.0
    
    constant integer MISSLE_BLUE   = 'h000'
    constant integer MISSLE_RED    = 'h00F'
    constant integer MISSLE_SNIPER = 'h006'
    constant integer MISSLE_ROCKET = 'h00E'
    constant integer MISSLE_HOLYRA = 'holy'
    
    constant integer FLAG_BLUE = 'blue'
    constant integer FLAG_RED  = 'redf'
    
    constant integer ENERGY_BALL   = 'ENER'
    constant integer SNIPER_ARROW  = 'ARRO'
    constant integer JUMP          = 'JUMP'
    constant integer ROCKET        = 'ROCK'
    constant integer FLAG_DROP     = 'drop'
    constant integer INVISIBILITY  = 'INVI'
    constant integer HOLYRA        = 'HOLY'
    constant integer NET           = 'NET1'
    constant integer RANGE_ON      = 'RANG'
    constant integer RANGE_OFF     = 'ROFF'
    constant integer EXPLOSIVE_EGG = 'EGGa'
    constant integer EXPLOSION     = 'EGGb'
    constant integer CAM_LOCK      = 'CAM0'
    constant integer CAM_UNLOCK    = 'CAM1'
    
    integer ORDER_ENERGY_BALL  
    integer ORDER_SNIPER_ARROW 
    integer ORDER_ROCKET     
    integer ORDER_INVISIBILITY
    integer ORDER_JUMP
    
    
    constant integer SMART  = 851971
    constant integer STOP   = 851972
    constant integer PATROL = 851990
    constant integer MOVE   = 851986
    
    constant real INTERVAL  = 0.031250000             
    constant real TPS       = 1/INTERVAL
    
    constant integer SLIDE_FAST     = 'Iice'
    constant integer SLIDE_SNOW     = 'cIc1'
    constant integer SLIDE_NORMAL   = 'Nice'
    constant integer SLIDE_DARK     = 'Idki'
    
    constant integer SAVE_CIRCLE    = 'save'
    
     //constant integer SLIDE_SNOW     = 'Nsnw' oldsnow
    // MIRROR       = 'Glav'
    // MIRROW_SLOW  = 'Glvc'
    
    constant real CENTER_X = -4230
    constant real CENTER_Y = 8050
    
    constant real DEFAULT_SPEED = 580.
    
    constant hashtable HASH = InitHashtable()
    group G = CreateGroup()
    
    RSound array Sound[30]
    constant integer FIRSTBLOOD = 14
    constant integer HEADHUNTER = 15
    constant integer HATTRICK   = 16
    constant integer PLAY       = 17
    constant integer PREPARE    = 18
    constant integer ERROR      = 19
    
    constant integer LAUNCH_SNIPERARROW     = 20
    constant integer LAUNCH_ROCKET          = 21
    constant integer LAUNCH_ENERGYBALL      = 22
    
    
    constant integer RESCUE      = 23
    constant integer WARNING     = 24
    constant integer STARTROUND  = 25
    constant integer TICK        = 26
    constant integer GOODJOB     = 27
    
    constant integer ROOTSOUND   = 28
    
    constant integer LAUNCH_HOLYRA          = 29
    
    player LOCAL_PLAYER
    
endglobals

struct Init extends array

    private static method preload takes nothing returns nothing
    
        call AbilityPreload(ENERGY_BALL)
        call AbilityPreload(SNIPER_ARROW)
        call AbilityPreload(JUMP)
        call AbilityPreload(ROCKET)
        call AbilityPreload(FLAG_DROP)
        call AbilityPreload(INVISIBILITY)
        call AbilityPreload(HOLYRA)
        call AbilityPreload(NET)
        call AbilityPreload(RANGE_ON)
        call AbilityPreload(RANGE_OFF)
        call AbilityPreload(EXPLOSIVE_EGG)
        call AbilityPreload(EXPLOSION)
        call AbilityPreload(CAM_LOCK)
        call AbilityPreload(CAM_UNLOCK)
        
        call AbilityPreload('ZxLa')
        call AbilityPreload('ZxLb')
        call AbilityPreload('ZxLc')
        call AbilityPreload('ZxLd')
        call AbilityPreload('ZxLe')
        call AbilityPreload('ZxLf')
        
        call AbilityPreload('ZxMa')
        call AbilityPreload('ZxMb')
        call AbilityPreload('ZxMc')
        call AbilityPreload('ZxMd')
        call AbilityPreload('ZxMe')
        call AbilityPreload('ZxMf')
    
        call ReleaseTimer(GetExpiredTimer())
    endmethod

   private static method init takes nothing returns nothing
        set LOCAL_PLAYER = GetLocalPlayer()
        
        call TimerStart(NewTimer(), 0, false, function thistype.preload)
        
        set Sound[1] = RSound.create("war3mapImported\\doublekill.mp3", false, false, 0, 0)
        set Sound[2] = RSound.create("war3mapImported\\triplekill.mp3", false, false, 0, 0)
        set Sound[3] = RSound.create("war3mapImported\\multikill.mp3", false, false, 0, 0)
        set Sound[4] = RSound.create("war3mapImported\\rampage.mp3", false, false, 0, 0)
        set Sound[5] = RSound.create("war3mapImported\\megakill.mp3", false, false, 0, 0)
        set Sound[6] = RSound.create("war3mapImported\\dominating.mp3", false, false, 0, 0)
        set Sound[7] = RSound.create("war3mapImported\\monsterkill.mp3", false, false, 0, 0)
        set Sound[8] = RSound.create("war3mapImported\\holyshit.mp3", false, false, 0, 0)
        set Sound[9] = RSound.create("war3mapImported\\ultrakill.mp3", false, false, 0, 0)
        set Sound[10] = RSound.create("war3mapImported\\unstoppable.mp3", false, false, 0, 0)
        set Sound[11] = RSound.create("war3mapImported\\ludicrouskill.mp3", false, false, 0, 0)
        set Sound[12] = RSound.create("war3mapImported\\wickedsick.mp3", false, false, 0, 0)
        set Sound[13] = RSound.create("war3mapImported\\godlike.mp3", false, false, 0, 0)
        set Sound[FIRSTBLOOD] = RSound.create("war3mapImported\\firstblood.mp3", false, false, 0, 0)
        set Sound[HEADHUNTER] = RSound.create("war3mapImported\\headhunter.mp3", false, false, 0, 0)
        set Sound[HATTRICK] = RSound.create("war3mapImported\\hattrick.wav", false, false, 0, 0)
        set Sound[PLAY] = RSound.create("war3mapImported\\play.wav", false, false, 0, 0)
        set Sound[PREPARE] = RSound.create("war3mapImported\\Prepare.mp3", false, false, 0, 0)
        set Sound[ERROR] = RSound.create("Sound\\Interface\\Error.wav", false, false, 0, 0)
        set Sound[LAUNCH_SNIPERARROW] = RSound.create("Abilities\\Weapons\\BristleBackMissile\\BristleBackMissileLaunch3.wav", false, false, 0, 0)
        set Sound[LAUNCH_ENERGYBALL] = RSound.create("Abilities\\Weapons\\FarseerMissile\\FarseerMissileLaunch.wav", true, false, 0, 0) 
        set Sound[LAUNCH_ROCKET] = RSound.create("Abilities\\Weapons\\CannonTowerMissile\\CannonTowerMissileLaunch2.wav", true, false, 0, 0)
        set Sound[LAUNCH_HOLYRA] = RSound.create("Units\\Human\\Phoenix\\PhoenixYes1.wav", true, false, 0, 0)
        set Sound[RESCUE] = RSound.create("Sound\\Interface\\Rescue.wav", false, false, 0, 0)
        set Sound[WARNING] = RSound.create("Sound\\Interface\\Warning.wav", false, false, 0, 0)
        set Sound[STARTROUND] = RSound.create("Sound\\Interface\\ArrangedTeamInvitation.wav", false, false, 0, 0)
        set Sound[TICK] = RSound.create("Sound\\Interface\\BattleNetTick.wav", false, false, 0, 0)
        set Sound[GOODJOB] = RSound.create("Sound\\Interface\\GoodJob.wav", false, false, 0, 0)
        set Sound[ROOTSOUND] = RSound.create("Abilities\\Spells\\NightElf\\EntanglingRoots\\EntanglingRootsTarget1.wav", false, false, 0, 0)
       
        set ORDER_ENERGY_BALL  = OrderId("berserk")
        set ORDER_SNIPER_ARROW = OrderId("berserk")
        set ORDER_ROCKET       = OrderId("berserk")
        set ORDER_INVISIBILITY = OrderId("divineshield")
        set ORDER_JUMP         = OrderId("divineshield")
    endmethod
    implement InitTimer
endstruct
    
endlibrary
Credits
Events
Time - Elapsed game time is 0.00 seconds
Conditions
Actions
Set Variable Set s = "|c00ffcc00Thanks for playing!|r|n|n"
Player Group - Pick every player in (All players) and do (Actions)
Loop - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
((Picked player) controller) Equal to User
Then - Actions
Set Variable Set s = (s + ((Name of (Picked player)) + |n))
Else - Actions
Quest - Create a Required quest titled Codes with the description Bribe - TableBribe - TimerUtilsDioD - isGameOnlineEarth-Fury - Max StateFlux - RecycldeDummygrim001 - AbilityPrelloadIcemanBo - PauseUnitIcemanBo - QuickSortIcemanBo - TildeDefinitionMagtheridon96 RPUENestharus - AllocNestharus - CTLNestharus - File IONestharus - InitNestharus - ListNestharus - MultiboardNestharus - Unit IndexerNestharus - WorldBoundsTriggerHappy - SyncQuilnez - RapidSound , using icon path ReplaceableTextures\CommandButtons\BTNEngineeringUpgrade.blp
Quest - Create a Required quest titled Icons, Models, Skins with the description General Frank - IceRoots modelKILLCIDE - IceRoots iconKILLCIDE - TalkToMe modelClan KMNOK - Acolyte CarClan KMNOK - Death Knight CarSA Dashie - Selection Circle , using icon path ReplaceableTextures\CommandButtons\BTNAdvStruct.blp
Quest - Create a Optional quest titled Sounds with the description KillSounds takes from QuakeOpening Track is "The Pure and the Tainted" , using icon path ReplaceableTextures\CommandButtons\BTNReplay-Play.blp
Quest - Create a Optional quest titled Others with the description Leandrop - CommandFunc.txtSin'dorei300 - Human UIWaterKnight - Testing , using icon path ReplaceableTextures\CommandButtons\BTNAuraOfDarkness.blp
Quest - Create a Optional quest titled Community with the description s , using icon path ReplaceableTextures\WorldEditUI\Editor-MultipleUnits.blp
Quest - Flash the quest dialog button
Visibility - Disable black mask
Visibility - Disable fog of war
Game - Set Visibility - Always Visible to On
Game - Set the time of day to 22.00
Game - Turn the day/night cycle Off
//TESH.scrollpos=0
//TESH.alwaysfold=0

    
// Set and Get the default shoot ability of a unit
struct DefaultShootAbility extends array
    private static key k
    static Table table = k
    public static method apply takes integer unitType, integer abilityId returns nothing
        set thistype.table[unitType] = abilityId
    endmethod
    public static method operator [] takes unit u returns integer
        return thistype.table[GetUnitTypeId(u)]
    endmethod
endstruct

// Set and Get the current shoot ability of a unit
struct CurrentShootAbility extends array
    private static key k
    static Table table = k
    public static method apply takes unit who, integer abilityId returns nothing
        call UnitRemoveAbility(who, thistype.table[GetHandleId(who)])
        call UnitAddAbility(who, abilityId)
        set thistype.table[GetHandleId(who)] = abilityId
    endmethod
    public static method operator [] takes unit who returns integer
        return thistype.table[GetHandleId(who)]
    endmethod
    
    private static method init takes nothing returns nothing
        call DefaultShootAbility.apply(ALIEN, ENERGY_BALL)
        call DefaultShootAbility.apply(CATCHER, ENERGY_BALL)
        call DefaultShootAbility.apply(JUMPER, ENERGY_BALL)
        call DefaultShootAbility.apply(SAVER, ENERGY_BALL)
        call DefaultShootAbility.apply(SNIPER, SNIPER_ARROW)
        call DefaultShootAbility.apply(SPY, ENERGY_BALL)
        call DefaultShootAbility.apply(STEAMROLLER, ENERGY_BALL)
        call DefaultShootAbility.apply(TANK, ENERGY_BALL)
    endmethod
    
    implement InitTimer
endstruct
//TESH.scrollpos=19
//TESH.alwaysfold=0
struct Hero extends array
    static key k
    static Table table = k
    integer unittypeId
    static integer counter = 0
    
    public static method operator [] takes integer who returns thistype
        return thistype(who).unittypeId
    endmethod
    
    private static method onInit takes nothing returns nothing
        local thistype this
        
        set counter = counter + 1
        set this = counter
        set this.unittypeId = ALIEN
        set table.string[ALIEN] = "ReplaceableTextures\\CommandButtons\\BTNAcolyte.blp"
        
        set counter = counter + 1
        set this = counter
        set this.unittypeId = CATCHER
        set table.string[CATCHER] = "ReplaceableTextures\\CommandButtons\\BTNCagedIllidan.blp"
        
        set counter = counter + 1
        set this = counter
        set this.unittypeId = JUMPER
        set table.string[JUMPER] = "ReplaceableTextures\\CommandButtons\\BTNHeroDeathKnight.blp"
        
        set counter = counter + 1
        set this = counter
        set this.unittypeId = SAVER
        set table.string[SAVER] = "ReplaceableTextures\\CommandButtons\\BTNFlyingMachine.blp"
        
        set counter = counter + 1
        set this = counter
        set this.unittypeId = SNIPER
        set table.string[SNIPER] = "ReplaceableTextures\\CommandButtons\\BTNClockWerkGoblin.blp"
        
        set counter = counter + 1
        set this = counter
        set this.unittypeId = TANK
        set table.string[TANK] = "ReplaceableTextures\\CommandButtons\\BTNDwarfCar.blp"
        
        /*
        set counter = counter + 1
        set this = counter
        set this.unittypeId = SPY
        
        set counter = counter + 1
        set this = counter
        set this.unittypeId = STEAMROLLER
        */
        
    endmethod
    
endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0

// Define spawn (rects)
struct Spawn extends array
    readonly static constant integer LEFT  = 1
    readonly static constant integer RIGHT = 2
    real xMax
    real yMax
    real xMin
    real yMin
    real xCenter
    real yCenter
    public static method operator [] takes integer who returns thistype
        return thistype(who)
    endmethod
    private static method init takes nothing returns nothing
        set thistype[LEFT].xCenter = -11472
        set thistype[LEFT].yCenter = 8064
        set thistype[LEFT].xMax = -11155
        set thistype[LEFT].xMin = -11808
        set thistype[LEFT].yMax = 8615
        set thistype[LEFT].yMin = 7500
        
        set thistype[RIGHT].xCenter = 3104
        set thistype[RIGHT].yCenter = 8064
        set thistype[RIGHT].xMax = 3456
        set thistype[RIGHT].xMin = 2752
        set thistype[RIGHT].yMax = 8615
        set thistype[RIGHT].yMin = 7500
    endmethod
    implement Init
    method GetRandomX takes nothing returns real
        return GetRandomReal(.xMin, .xMax)
    endmethod
    method GetRandomY takes nothing returns real
        return GetRandomReal(.yMin, .yMax)
    endmethod
endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0

// Define teams with individual spawns
struct Team
    readonly static thistype BLUE
    readonly static thistype RED
    Spawn spawn
    string color
    playercolor unitcolor
    integer r
    integer g
    integer b
    integer score
    string name
  
    readonly integer count
    player array user[11]
    
    public static method operator [] takes integer who returns thistype
        return thistype(who)
    endmethod
    
    method add takes player p returns nothing
        set this.count =  this.count + 1
        set  this.user[this.count] = p
    endmethod
    
    method remove takes player p returns nothing
        local integer i = 0
        local integer j
        local player temp
        loop
            exitwhen i > .count
            
            if(.user[i] == p) then
                
                loop
                    set j = i + 1
                    exitwhen j > .count
                    set .user[i] = .user[j]
                    set i = i + 1
                endloop
                
                set .count = .count - 1
                exitwhen true
            endif
            
            set i = i + 1
        endloop
    endmethod
    
    method sort takes nothing returns nothing
        local integer i
        local integer offset
        
        if(.count < 1)then
            return
        endif
        
        set i = 0
        loop
            exitwhen i > .count
            set QuickSortValue[i] = KD[.user[i]].kills
            set QuickSortIndex[i] = GetPlayerId(.user[i])
            set i = i + 1
        endloop
        
        call QuickSort(0, .count)
        
        if this == BLUE then
            set offset = 1
        else
            set offset = Team.BLUE.count + 3
        endif
        
        set i = 0
        loop
            exitwhen i > .count
            set offset = offset + 1
            set user[i] = Player(QuickSortIndex[i])
            set Board.playerRow[QuickSortIndex[i]] = offset
            call Board.update(.user[i])
            set i = i + 1
        endloop
        
    endmethod
    
    static method onLeave takes nothing returns nothing
        call User[GetTriggerPlayer()].team.remove(GetTriggerPlayer())
    endmethod
    
    private static method init takes nothing returns nothing
        local integer i = 0
        local trigger t = CreateTrigger()
        local thistype this
        call TriggerAddAction(t, function thistype.onLeave)
        loop
            exitwhen i > 11
            call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_LEAVE)
            call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_DEFEAT)
            set i = i + 1
        endloop
        
        set BLUE = allocate()
        set this = BLUE
        set this.spawn = Spawn.LEFT
        set this.color = Color[1]
        set this.r = 85
        set this.g = 85
        set this.b = 255
        set this.unitcolor = PLAYER_COLOR_BLUE
        set this.name = this.color  + "Blue Team|r"
        set this.count = -1
        
        set RED = allocate()
        set this = RED
        set this.spawn  = Spawn.RIGHT
        set this.color = Color[0]
        set this.r = 255
        set this.g = 85
        set this.b = 85
        set this.unitcolor = PLAYER_COLOR_RED
        set this.name = this.color  + "Red Team|r"
        set this.count = -1
        
    endmethod
    implement Init
endstruct
//TESH.scrollpos=2
//TESH.alwaysfold=0

// each user belongs to a team
// each user owns a slider

struct User
    Team team
    Slider slider
   
    public static method operator [] takes player who returns thistype
        return thistype(GetPlayerId(who)+1)
    endmethod
    
    private static method init takes nothing returns nothing
        local integer i = 0
        local player p
        
        loop
            exitwhen i > 5
            set p = Player(i)
            if PlayerTools.isPlayerUser(p) then
                set thistype[p].team = Team.BLUE
                call Team[Team.BLUE].add(p)
            endif
            set i = i + 1
        endloop
        loop
            exitwhen i > 11
            set p = Player(i)
            
            if PlayerTools.isPlayerUser(p) then
                call Team[Team.RED].add(p)
                set thistype[p].team = Team.RED
            endif
            set i = i + 1
        endloop
        
    endmethod
    implement Init
endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0
//! inject config
    
    // Wow this shit needs to be takes from .j file.
    
    call SetMapName("TRIGSTR_010")
    call SetMapDescription("TRIGSTR_300")
    call SetPlayers(12)
    call SetTeams(12)
    call SetGamePlacement(MAP_PLACEMENT_TEAMS_TOGETHER)
    
    call PlayMusic("war3mapImported\\PureAndTheTainted.mp3")
    
    call DefineStartLocation(0, - 13952.0, 8192.0)
    call DefineStartLocation(1, - 13952.0, 8192.0)
    call DefineStartLocation(2, - 13952.0, 8192.0)
    call DefineStartLocation(3, - 13952.0, 8192.0)
    call DefineStartLocation(4, - 13952.0, 8192.0)
    call DefineStartLocation(5, - 13952.0, 8192.0)
    call DefineStartLocation(6, 5760.0, 8128.0)
    call DefineStartLocation(7, 5760.0, 8128.0)
    call DefineStartLocation(8, 5760.0, 8128.0)
    call DefineStartLocation(9, 5760.0, 8128.0)
    call DefineStartLocation(10, 5760.0, 8128.0)
    call DefineStartLocation(11, 5760.0, 8128.0)

    // Player setup
    call InitCustomPlayerSlots()
    call InitCustomTeams()
    call InitAllyPriorities()

//! endinject
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GameHandler initializer Init uses Default
    
    globals
        integer SCORE_BLUE
        integer SCORE_RED
        integer SCORE_MAX
        string PICKMODE
        boolean Firstblood
        integer startcounter
    endglobals
    
    function ShowDialog_car takes player p returns nothing
        call DialogDisplay(p, dialog_car, true)
    endfunction
    
    function ShowDialog_score takes player p returns nothing
        call DialogDisplay(p, dialog_score, true)
    endfunction
    
    function ShowDialog_pickmode takes player p returns nothing
        call DialogDisplay(p, dialog_pickmode, true)
    endfunction
    
    function ScoreDisplayRefresh takes nothing returns nothing
        local integer j = 0
        loop
            exitwhen j > 11
            call SetPlayerState(Player(j), PLAYER_STATE_RESOURCE_FOOD_USED, SCORE_MAX)
            call SetPlayerState(Player(j), PLAYER_STATE_RESOURCE_GOLD, Team(Team.BLUE).score)
            call SetPlayerState(Player(j), PLAYER_STATE_RESOURCE_LUMBER, Team(Team.RED).score)
            set j = j + 1
        endloop
    endfunction
    
    function IsPlayerActive takes player p returns boolean
        return GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING
    endfunction
   
    
    function SetMaxScore takes integer i returns nothing
        set SCORE_MAX = i
        call Print(Color[5] + "Game-Mode: |r" + I2S(SCORE_MAX) + " score to win.", 8)
        call ScoreDisplayRefresh()
    endfunction
    
    function SliderRemoveAll takes nothing returns nothing
        local Slider s
        set s = Slider.first
        loop
            exitwhen s == 0
                call KillUnit(s.slider)
                call s.destroy()
            set s = s.next
        endloop
    endfunction
    
    function PickModeDialog_Start takes nothing returns nothing
        local integer i = 0
        set KD.firstblood = false
        loop
            if IsPlayerActive(Player(i))then
                call ShowDialog_pickmode(Player(i))
                 call Sound[PREPARE].play(0, 0, 0, 200)
                call ReleaseTimer(GetExpiredTimer())
                return
            endif
            set i = i + 1
            exitwhen i > 11
        endloop
        call ReleaseTimer(GetExpiredTimer())
       
    endfunction
    
    function ScoreCarDialog_Start takes nothing returns nothing
        local integer i = 0
        loop
            if IsPlayerActive(Player(i))then
                call ShowDialog_car(Player(i))
            endif
            set i = i + 1
            exitwhen i > 11
        endloop
        call ReleaseTimer(GetExpiredTimer())
    endfunction

    function SliderScores takes Slider s returns nothing
        local integer j = 0
        local string scoreString
        
        local User user = User[s.owner]
        
        set user.team.score = user.team.score + 1
        set scoreString = "[" + Team(Team.BLUE).color + I2S(Team(Team.BLUE).score) + "|r]" + " : " + "[" + Team(Team.RED).color + I2S(Team(Team.RED).score) + "|r]"
        call Print(User[s.owner].team.color + GetPlayerName(s.owner) + "|r scores! " + scoreString, 8)
        set KD[s.owner].score = KD[s.owner].score + 1
        if ModuloInteger(KD[s.owner].score, 3) == 0 then
            call Sound[HATTRICK].play(0, 0, 0, 200)
        endif
        call Sound[GOODJOB].play(GetUnitX(s.slider), GetUnitY(s.slider), 0, 200)
        set KD.enabled = false
        call SliderRemoveAll()
        set KD.enabled = true
        call ScoreDisplayRefresh()
        
        if( user.team.score >= SCORE_MAX)then
            call Print(User[s.owner].team.name + " has won!", 9)
            call StopMusic( false )
            call PlayMusic(gg_snd_War2IntroMusic)
            call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_MUSIC, 2)
            call GameEnd()
        else
            call TimerStart(NewTimer(), 2, false, function PickModeDialog_Start)
        endif
        
    endfunction
    
    function Cars_AllRandom takes nothing returns nothing
        local integer i = 0
        loop
            if IsPlayerActive(Player(i))then
                call NewRandomSlider(Player(i))
            endif
            set i = i + 1
            exitwhen i > 11
        endloop
        call ReleaseTimer(GetExpiredTimer())
    endfunction
    
    function StartPlaySound takes nothing returns nothing
        
        set startcounter = startcounter + 1
        if startcounter > 3 then
            if PICKMODE == "Pick" then
                call TimerStart(GetExpiredTimer(), 0.1, false, function ScoreCarDialog_Start)
            elseif PICKMODE == "Random" then
                call TimerStart(GetExpiredTimer(), 0.1, false, function Cars_AllRandom)
            endif
            call Sound[PLAY].play(0, 0, 0, 200)
            call Print(" ", 0)
            call Print(Color[7] + " ~ Play! ~|r", 4.5)
           
        else
            call Sound[TICK].play(0, 0, 0, 200)
            call Print(Color[12] + I2S(startcounter) + "|r", 1.2)
        endif
    endfunction
    
    function PlayerToSpawn takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i > 11
                if User[LOCAL_PLAYER].team == Team.RED then
                    call PanCameraToTimed(Spawn[Team.RED].xCenter, Spawn[Team.RED].yCenter, 1)
                elseif User[LOCAL_PLAYER].team == Team.BLUE then
                    call PanCameraToTimed(Spawn[Team.BLUE].xCenter, Spawn[Team.BLUE].yCenter, 1)
                endif
            set i = i + 1
        endloop
    endfunction
    
    function SetPickMode takes string s returns nothing
        
        set PICKMODE = s
        call ClearTextMessages()
        
        call PlayerToSpawn()
        
        call Print(Color[5] + "Game-Mode: |r" + I2S(SCORE_MAX) + " score to win.", 9)
        call Print(Color[5] + "Game-Mode: |rAll " + s, 9)
        call Print(" ", 0)
        set startcounter = 0
        call TimerStart(NewTimer(), 1, true, function StartPlaySound)
    endfunction
    
    function PickModeDialog_End takes nothing returns nothing
        //
    endfunction
    
    function ScoreModeDialog_End takes nothing returns nothing
        call TimerStart(NewTimer(), 0.5, false, function PickModeDialog_Start)
    endfunction
    
    function ScoreModeDialog_Start takes nothing returns nothing
        local integer i = 0
        loop
            if IsPlayerActive(Player(i))then
                call ShowDialog_score(Player(i))
                call Sound[STARTROUND].play(0, 0, 0, 200)
                call ReleaseTimer(GetExpiredTimer())
                return
            endif
            
            set i = i + 1
            exitwhen i > 11
        endloop
        call ReleaseTimer(GetExpiredTimer())
        
    endfunction
    
    function SomeMusicRandomLoliloOaSettings takes nothing returns nothing
        call PlayMusic(gg_snd_PH1)
        call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_MUSIC, 2)
        call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_AMBIENTSOUNDS, 2)
        call ReleaseTimer(GetExpiredTimer())
    endfunction
    
    function MusicStop takes nothing returns nothing
        call StopMusic( false )
        call ReleaseTimer(GetExpiredTimer())
    endfunction
    
    private function Init takes nothing returns nothing
        
        call TimerStart(NewTimer(), 0., false, function MusicStop)
        call TimerStart(NewTimer(), 0.5, false, function SomeMusicRandomLoliloOaSettings)
        call TimerStart(NewTimer(), 2., false, function ScoreModeDialog_Start)
        call CinematicFadeBJ( bj_CINEFADETYPE_FADEOUT, 0, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 0, 0, 0, 0 )
        call CinematicFadeBJ( bj_CINEFADETYPE_FADEIN, 3.00, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 0, 0, 0, 0 )
    endfunction

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CreateSlider uses Default

function NewSlider takes player who, integer unitId returns nothing
    local real x = User[who].team.spawn.GetRandomX()
    local real y = User[who].team.spawn.GetRandomY()
    local unit u
    set User[who].slider = Slider.create(CreateUnit(who, unitId, x, y, GetRandomReal(0, 360)))
    
    call Board.update(who)
    
    set u = User[who].slider.slider
    call SetUnitVertexColor(u, User[who].team.r, User[who].team.g, User[who].team.b, 255)
    call SetUnitColor(u, User[who].team.unitcolor)
    
    call CurrentShootAbility.apply(u, DefaultShootAbility[u])
    
    if (LOCAL_PLAYER == who) then
        call SetCameraTargetController(u, 0, 0, false)
        call SelectUnit(u, true)
    endif
    
    set u = null
endfunction

function NewRandomSlider takes player who returns nothing
    local real x = User[who].team.spawn.GetRandomX()
    local real y = User[who].team.spawn.GetRandomY()
    local unit u
    set User[who].slider = Slider.create(CreateUnit(who, Hero[GetRandomInt(1, Hero.counter)], x, y, GetRandomReal(0, 360)))
    
    call Board.update(who)
    
    set u = User[who].slider.slider
    call SetUnitVertexColor(u, User[who].team.r, User[who].team.g, User[who].team.b, 255)
    call SetUnitColor(u, User[who].team.unitcolor)
    
    call CurrentShootAbility.apply(u, DefaultShootAbility[u])
    
    if (LOCAL_PLAYER == who) then
        call SetCameraTargetController(u, 0, 0, false)
        call SelectUnit(u, true)
    endif
    set u = null
endfunction
    
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope LeaveSystem initializer Init

    private function onLeave takes nothing returns nothing
        local player p = GetTriggerPlayer()
        
        if (User[p].slider.slider != null) then
            call User[p].slider.destroy()
        endif
        call Print(User[p].team.color + GetPlayerName(p) + "|r has left the game.", 8)
        call TimerStart(NewTimer(),0.1,false,function Board.NewBoard)
    endfunction

    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        loop
            exitwhen i > 11
            call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_LEAVE)
            call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_DEFEAT)
            
            set i = i + 1
        endloop
        call TriggerAddAction(t, function onLeave)
    endfunction

endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GameEnd uses Default

    function KickPlayers takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i > 11
            call CustomVictoryBJ( Player(i), false, false )
            set i = i + 1
        endloop
        call ReleaseTimer(GetExpiredTimer())
    endfunction

    function GameEnd takes nothing returns nothing
        call CinematicFadeBJ( bj_CINEFADETYPE_FADEOUT, 6.00, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 0, 0, 0, 0 )
        call TimerStart(NewTimer(), 6, false, function KickPlayers)
    endfunction


endlibrary
//TESH.scrollpos=31
//TESH.alwaysfold=0
struct KD

    public static boolean enabled = true
    public static boolean firstblood

    integer streak_current
    integer streak_max
    integer deaths
    integer kills
    real kd
    integer score
    
     
    integer score_loaded
    integer streak_loaded
    integer kills_loaded
    integer deaths_loaded
    integer kd_loaded
    
    public static method operator [] takes player who returns thistype
        return thistype(GetPlayerId(who)+1)
    endmethod
    
    public static method apply takes player killer, player victim returns nothing
        
        if null != killer then
            set KD[killer].kills = KD[killer].kills + 1
            set KD[killer].streak_current = KD[killer].streak_current + 1
            if (KD[killer].streak_current > KD[killer].streak_max) then
                 set KD[killer].streak_max = KD[killer].streak_current
            endif
             call ApplyPendingTextTag(User[killer].slider, User[killer].team.color + "Kills +1|r", 8, 1.5, 3, 0, 85, GetRandomReal(90-15, 90+15))
            if not firstblood then
                call Sound[FIRSTBLOOD].play(GetUnitX(User[killer].slider.slider), GetUnitY(User[killer].slider.slider), 0, 200)
                set firstblood = true
            endif
            
            if(KD[killer].streak_current > 2) then
                if (KD[killer].streak_current > 12) then
                    call Sound[13].play(GetUnitX(User[killer].slider.slider), GetUnitY(User[killer].slider.slider), 0, 200)
                else
                    call Sound[KD[killer].streak_current].play(GetUnitX(User[killer].slider.slider), GetUnitY(User[killer].slider.slider), 0, 200)
                endif
            endif
            
            if(KD[killer].deaths > 0) then
                set KD[killer].kd = R2I(KD[killer].kills)/R2I(KD[killer].deaths)
            else
                set KD[killer].kd = KD[killer].kills
            endif
            
            call Board.update(killer)
            
            call Print(User[killer].team.color + GetPlayerName(killer) + " |r(" + I2S(KD[killer].streak_current) + ") killed " +  User[victim].team.color + GetPlayerName(victim) + " |r(" + I2S(KD[victim].streak_current) + ")" , 7)
        else
            call Print(User[killer].team.color + GetPlayerName(victim) + " (" + I2S(KD[victim].streak_current) + ") " + "|r died.", 5)
        endif
        
        call Team.BLUE.sort()
        call Team.RED.sort()
        
        set KD[victim].streak_current = 0
        set KD[victim].deaths = KD[victim].deaths + 1
        set KD[victim].kd = R2I(KD[victim].kills)/R2I(KD[victim].deaths)
        call Board.update(victim)
    endmethod
    
endstruct
//TESH.scrollpos=86
//TESH.alwaysfold=0
struct Respawn

    public static integer counter_max = 6
    public static constant real COLLISION = 100.
    
    texttag tt
    integer counter
    timer clock
    timer circle_clock
    unit circle
    boolean enabled
    real x
    real y
    unit reviver
    
    public static method operator [] takes player who returns thistype
        return thistype(GetPlayerId(who)+1)
    endmethod
    
    method revive takes unit reviver returns nothing
        local real x
        local real y
        if(null == reviver) then
            set x = User(this).team.spawn.GetRandomX()
            set y = User(this).team.spawn.GetRandomY()
        else
            set x = GetUnitX(reviver)
            set y = GetUnitY(reviver)
        endif
        set .enabled = false
        call ReviveHero(User(this).slider.slider, x, y, true)
        if(User(this).slider.owner == LOCAL_PLAYER)then
            call SelectUnit(User(this).slider.slider, true)
        endif
        call PauseTimer(.clock)
        call PauseTimer(.circle_clock)
        call SetTextTagVisibility(.tt, false)
        call ShowUnit(.circle, false)
    endmethod
    
    private static method circleCheck takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        local Slider s = Slider.first
        
        loop
            exitwhen s == 0
            
            if UnitAlive(s.slider) and User[s.owner].team == User(this).team and /*
            */SquareRoot((GetUnitX(s.slider)-.x) * (GetUnitX(s.slider)-.x) + (GetUnitY(s.slider)-.y) * (GetUnitY(s.slider)-.y)) < .COLLISION then
                
                call .revive(s.slider)
                
            endif
    
            set s = s.next
        endloop
    endmethod
    
    private static method callback takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        
        if(.counter <= 1) then
            call .revive(null)
        else
            set .counter = .counter - 1
            call SetTextTagText(.tt, User(this).team.color + I2S(.counter), 0.023)
        endif
        
    endmethod
    
    public static method apply takes player p returns nothing
        local thistype this = Respawn[p]
        set this.counter = counter_max
        
        call TimerStart(.clock, 1, true, function thistype.callback)
        call TimerStart(.circle_clock, 0.075, true, function thistype.circleCheck)
        
        call SetTextTagVisibility(.tt, true)
        call SetTextTagText(.tt, User(this).team.color + I2S(.counter), 0.023)
        call SetTextTagPosUnit(tt, User(this).slider.slider, 50)
        
        set .x = GetUnitX(User(this).slider.slider)
        set .y = GetUnitY(User(this).slider.slider)
        set .enabled = true
        
        call SetUnitX(.circle, x)
        call SetUnitY(.circle, y)
        call ShowUnit(.circle, true)
        
        call UnitRemoveAbility(.circle, 'Aloc')
        call UnitAddAbility(.circle, 'Aloc')
        
    endmethod
    
    private static method setup takes nothing returns nothing
        local integer i = 1
        local thistype this
        call ReleaseTimer(GetExpiredTimer())
        loop
            set this = Respawn(i)
            set .tt = CreateTextTag()
            call SetTextTagPermanent(.tt, true)
            call SetTextTagVisibility(.tt, false)
            call SetTextTagColor(.tt, 255, 255, 255, 255)
            set .clock = NewTimerEx(Respawn(i))
            set .circle_clock = NewTimerEx(Respawn(i))
            set .circle = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), SAVE_CIRCLE, 0, 0, 0)
            if User(i).team == Team.BLUE then
                call SetUnitVertexColor(.circle, 0, 0, 200, 255)
            else
                call SetUnitVertexColor(.circle, 200, 0, 0, 255)
            endif
            call ShowUnit(.circle, false)
            set i = i + 1
            exitwhen i > 12
        endloop
    endmethod
    
    private static method onInit takes nothing returns nothing
        call TimerStart(NewTimer(), 0, false, function thistype.setup)
    endmethod
    
endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0
struct Kill

    private static method onDeath takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local player killerOwner
        local player victimOwner
        local RangeData rangeElement
        if KD.enabled and Slider.isUnitSlider(u) then
        
            call SetHeroLevel(u, 1, false)
            
            if IsUnitType(GetKillingUnit(), UNIT_TYPE_HERO) then
                set killerOwner = GetOwningPlayer(GetKillingUnit())
            else
                set killerOwner = null
            endif
            
            set victimOwner = GetOwningPlayer(u)
            
            call KD.apply(killerOwner, victimOwner)
            call Respawn.apply(victimOwner)
            
            call CurrentShootAbility.apply(u, DefaultShootAbility[u])
            call SetUnitMaxState(u, UNIT_STATE_MAX_MANA, 0)
            
            if GetUnitAbilityLevel(u, RANGE_OFF) != 0 then
                set rangeElement = Slider[u].RangeList.first
                loop
                    exitwhen 0 == rangeElement
                    call KillUnit(rangeElement.u)
                    set rangeElement.u = null
                    set rangeElement = rangeElement.next
                endloop
                
                set Slider[u].showRange = false
                call Slider[u].RangeList.clear()
                call UnitRemoveAbility(u, RANGE_OFF)
                call UnitAddAbility(u, RANGE_ON)
            endif

        endif
        set u = null
    endmethod
    
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH )
        call TriggerAddAction(t, function thistype.onDeath)
    endmethod
    

endstruct
//TESH.scrollpos=244
//TESH.alwaysfold=0
struct Flag extends array
    readonly static constant integer BLUE = 1
    readonly static constant integer RED  = 2
    private static key k
    private static Table table = k
    
    static constant real COLLISION = 120
    static constant real INTERVAL = 0.075
    
    real x
    real y
    real x_goal
    real y_goal
    real angle
    unit flag
    Slider holder
    timer clock
    boolean captured
    boolean saveable
    real scale_captured
    real scale_default
    string name
    boolean enabled
    real zOffset
    
    Team team
    
    // call SetUnitVertexColor(.flagPointer_blue, 20, 150, 255, 255)
    // call SetUnitVertexColor(.flagPointer_red, 255, 55, 55, 255)
    
    public static method operator [] takes unit who returns thistype
        return thistype.table[GetHandleId(who)]
    endmethod
    
    private method save takes Slider s returns nothing
        
        local Slider sl = Slider.first
        loop
            exitwhen sl == 0
            
            if this == Flag.BLUE then
                call SetUnitVertexColor(sl.flagPointer_blue, 255, 240, 0, 150)
            else
                call SetUnitVertexColor(sl.flagPointer_red, 255, 240, 0, 150)
            endif
            
            set sl = sl.next
        endloop
        
        if(s == 0)then
        
            call Print(.name + " has returned to base", 6)
            set table[GetHandleId(.holder.slider)] = 0
            call UnitRemoveAbility(.holder.slider, FLAG_DROP)
            set .holder.flag = 0
            set .holder = 0
            call SetUnitScale(.flag, .scale_default, 0, 0)
            set .captured = false
        else
        
            call Print(.name + "saved by " + GetPlayerName(s.owner), 6)
            set .saveable = false
        endif
        call Sound[RESCUE].play(GetUnitX(.flag), GetUnitY(.flag), 50, 200)
        call SetUnitX(.flag, .x)
        call SetUnitY(.flag, .y)
        call SetUnitFacing(.flag, .angle)
        call Sound[RESCUE].play(0, 0, 0, 150)

    endmethod
    
    private method capture takes Slider s returns nothing
    
        local Slider sl = Slider.first
        loop
            exitwhen sl == 0
            
            if this == Flag.BLUE then
                call SetUnitVertexColor(sl.flagPointer_blue, 20, 20, 255, 150)
            else
                call SetUnitVertexColor(sl.flagPointer_red, 255, 20, 20, 150)
            endif
            
            set sl = sl.next
        endloop
    
        set .captured = true
        set .saveable = false
        set s.flag = this
        set .holder = s
        call SetUnitScale(.flag, .scale_captured, 0, 0)
        call UnitAddAbility(.holder.slider, FLAG_DROP)
        set table[GetHandleId(s.slider)] = this
        call Print(.name + "captured by " + GetPlayerName(s.owner), 7)
        call Sound[WARNING].play(0, 0, 0, 100)
    endmethod
    
    
    // is called from slider system
    method updatePosition takes nothing returns nothing
        local real x = GetUnitX(.holder.slider)
        local real y = GetUnitY(.holder.slider)
        local real z = GetUnitFlyHeight(.holder.slider)
        call SetUnitX(.flag, x)
        call SetUnitY(.flag, y)
        call SetUnitFlyHeight(.flag, z + .zOffset, 0)
        call SetUnitFacingTimed(.flag, GetUnitFacing(.holder.slider), 0.3)
    endmethod
    
    method isDropable takes nothing returns boolean
        local integer i = Teleport.counter
        local Teleport tp
        loop
            exitwhen i < 1
            set tp = Teleport(i)
            if tp.isUnitInRange(.flag)then
                return false
            endif
            set i = i - 1
        endloop
        
        return  (GetTerrainType(GetUnitX(.flag), GetUnitY(.flag)) != SLIDE_SNOW)
    endmethod
    
    private static method removeAbility takes nothing returns nothing
         call UnitRemoveAbility(Slider(GetTimerData(GetExpiredTimer())).slider, FLAG_DROP)
         call ReleaseTimer(GetExpiredTimer())
    endmethod
    
    method drop takes nothing returns nothing
        if .isDropable() then
            set table[GetHandleId(.holder.slider)] = 0
            call TimerStart(NewTimerEx(.holder), 0, false, function thistype.removeAbility)
            set .holder.flag = 0
             call Print(.name + " dropped by " + GetPlayerName(.holder.owner), 7)
            set .holder = 0
            call SetUnitScale(.flag, .scale_default, 0, 0)
            set .captured = false
            set .saveable = true
        else
            call .save(0)
        endif
    endmethod
    
    private static method onDeath takes nothing returns nothing
        
        local thistype this = thistype[GetTriggerUnit()]
        if (this != 0 and KD.enabled)then
            call .drop()
        endif
        
    endmethod
    
    method reset takes nothing returns nothing
        set table[GetHandleId(.holder.slider)] = 0
        set .holder.flag = 0
        set .holder = 0
        call SetUnitScale(.flag, .scale_default, 0, 0)
        set .captured = false
        set .saveable = false
        call SetUnitX(.flag, .x)
        call SetUnitY(.flag, .y)
        call SetUnitFacing(.flag, .angle)
    endmethod
    
    private method score takes nothing returns nothing
        call SliderScores(.holder)
        call TimerStart(NewTimerEx(.holder), 0, false, function thistype.removeAbility)
        call Flag(BLUE).reset()
        call Flag(RED).reset()
    endmethod
    
    private method filter_capture takes Slider s returns boolean
        return IsUnitInRange(s.slider, .flag, thistype.COLLISION) and User[s.owner].team != .team /*
        */  and UnitAlive(s.slider)/*
        */  and not s.jump/*
        */  and not s.cata
    endmethod
    
    private method filter_save takes Slider s returns boolean
        return IsUnitInRange(s.slider, .flag, thistype.COLLISION) and User[s.owner].team == .team /*
        */  and UnitAlive(s.slider)/*
        */  and not s.jump/*
        */  and not s.cata
    endmethod
    
    private static method callback takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        local Slider s
        if (.enabled)then
        
            if(.captured)then
                if IsUnitInRangeXY(.flag, x_goal, y_goal, thistype.COLLISION)then
                    call .score()
                endif
                return
            endif
        
            set s = Slider.first
            loop
                exitwhen s == 0
                    if .filter_capture(s) then
                        call .capture(s)
                        return
                    elseif .saveable and .filter_save(s) then
                        call .save(s)
                        return
                    endif
                set s = s.next
            endloop
        endif
    endmethod
    
    private static method onCast takes nothing returns nothing
        local thistype this = thistype[GetTriggerUnit()]
        local real x
        local real y
        local real angle
        if (this != 0)then
            
            if GetSpellAbilityId() == FLAG_DROP then
                set x = GetUnitX(.holder.slider)
                set y = GetUnitY(.holder.slider)
                set angle = GetUnitFacing(.holder.slider)*bj_DEGTORAD
                call SetUnitX(.flag, x - 150 *Cos(angle))
                call SetUnitY(.flag, y - 150 *Sin(angle))
                
                if .isDropable() then
                    call .drop()
                else
                    call SetUnitX(.flag, x)
                    call SetUnitY(.flag, y)
                    call ApplyErrorTextTag(.holder)
                endif
            endif
        endif
    endmethod
    
    private static method onInit takes nothing returns nothing
        local thistype this
        
        local trigger t = CreateTrigger()
        call TriggerAddAction(t, function thistype.onDeath)
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
        
        call RegisterSpellEffectEvent(FLAG_DROP, function thistype.onCast)
        
        set this = Flag.BLUE
        set .clock = NewTimerEx(this)
        set .x = -13963
        set .y = 8194
        set .x_goal = 5758
        set .y_goal = 8190
        set .angle = 270
        set .scale_captured = 1.5
        set .scale_default = 2.0
        set .name = Color[1] + "Blue Flag |r"
        set .team = Team[BLUE]
        set .zOffset = .55
        set .flag = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), FLAG_BLUE, .x, .y, .angle)
        set .enabled = true
        call TimerStart(.clock, Flag.INTERVAL, true, function thistype.callback)
        
        set this = Flag.RED
        set .clock = NewTimerEx(this)
        set .x = 5758
        set .y = 8190
        set .x_goal = -13962
        set .y_goal = 8190
        set .angle = 270
        set .scale_captured = 1
        set .scale_default = 1.4
        set .name = Color[0] + "Red Flag |r"
        set .team = Team[RED]
        set .zOffset = .10
        set .enabled = true
        set .flag = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), FLAG_RED, .x, .y, .angle)
        call TimerStart(.clock, Flag.INTERVAL, true, function thistype.callback)
    endmethod
    
endstruct
//TESH.scrollpos=559
//TESH.alwaysfold=0
library SlidingSystem/* v3.4    By IcemanBo -- much specified for Battle of Flags

 */ requires /*

        */ UnitIndexer    /* The one in test map. (by Nestharus v4.0.2.6)
        */ TimerUtils     /* http://www.wc3c.net/showthread.php?t=101322
        */ Table          /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
        */ WorldBounds    /* https://github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
        */ Event          /* The one in test map.
        */ TextHandler  /*


**                          Info
**                        ¯¯¯¯¯¯¯¯
**
**  Sliders can have a special sliding behaviour on different terrain types.
**  Each slider also can have it's own movement speed while sliding,
**  seperated and indepentand from the terrain type.
**
**  This library provides various possibilities
**  to create an individual behaviour for each terrain type. (Config - Part)
**    
**
**  Struct Terrain:
**
**
**      static method create takes integer terainType, real terrainSpeed returns thistype
**
**          Furthermore you can define and read these public members:
**          (by default all values are "0" or "false".
**
**          pullSpeed      = Unit will be constantly pulled with this speed. (real)
**          pullDirection  = Direction for pulling, in degrees. (real)
**          angle          = Angle that will be added, when steering. (real)
**          lifeAddition   = Life that will be added each second. Negagtive values are also possible. (real)
**          allowSteer     = If unit can steer on the tarrainType or not. (boolean)
**          allowCast      = If unit can cast on the terrainType or not. (boolean)
**          kill           = Kill the unit on the terrainType or not. (boolean)
**           
**
**    You can have a look into folder TestMap -> "Terrain Settings" for a better understanding and examples.
**
**
**  Struct Slider:
**
**
**      static methods:
**     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
**
**          static method create takes unit u returns thistype
**
**          static method getSliderId takes unit u returns thistype
**
**          static method isUnitSlider takes unit u returns boolean
**
**
**
**      methods:
**     ¯¯¯¯¯¯¯¯¯¯
**
**          method destroy takes nothing returns nothing
**
**          method enable takes boolean b returns nothing   (disabled instance can't slide)
**              
**          method isEnabled takes nothing returns boolean
**
**          method getDefaultSpeed takes nothing returns real
**
**          method getTempSpeed takes nothing returns real
**
**          method setDefaultSpeed takes real s returns nothing
**  
**          method addDefaultSpeed takes real s returns nothing
**
**          method addTempSpeed takes real speed, real duration returns nothing
**
**
**
**    Deindexed units will be automatically removed from system.
**    You can have a look into folder TestMap -> "Create Slider" for a better understanding and examples.
**
***************************************************************************
**
**  Credits to guys named in brackets.
**
**  Requires:
**      - Table (Bribe)
**      - TimerUtils (Vexorian)
**      - UnitIndexer (Nestharus)
**          • WorldBounds (Nestharus)
**          • Event (Nestharus)
**
**
**************************************************************************
*
*
************************  Configuration - Start ***************************/

    globals
    
        private constant boolean SLIDER_UNCLICKABLE    = true    // Make Slider unclickable.
        private constant boolean SLIDER_NO_PATHING     = true    // Disable pathing for Slider.
        private constant boolean CHECK_PATHING         = true   // Check for pathability while sliding.
        
        
/************************ Configuration - End *****************************/

        private trigger steerTrigger       = CreateTrigger()
        private trigger moveTrigger        = CreateTrigger()  // Sliding looks smoother with trigger instead of a timer.
        
        constant real STUN_TIMEOUT  = 1.5
                                        
    endglobals
    
    /*
    *   Terrain struct, to define sliding behaviour.
    */
    native UnitAlive takes unit u returns boolean
    struct Terrain
        private static key k
        static Table table = k
        
        readonly integer terrainType
        
        real factor
        real speed
        real pullSpeed = 0
        real pullDirection = 0
        real angle = 0
        real lifeAddition = 0
        boolean allowSteer = false
        boolean allowCast = false
        boolean kill = false
        boolean stun
        
        static method create takes integer whichTerrain returns thistype
            local thistype this = thistype.allocate()
            set thistype.table[whichTerrain] = this
            set this.terrainType = whichTerrain
            set this.speed = DEFAULT_SPEED
            return this
        endmethod
        static method operator [] takes integer i returns thistype
            return thistype.table[i]
        endmethod
    endstruct

    /*
    *   Acceleration struct, to manipulate Slider's temporary speed
    */
    
    private struct Acceleration
        public timer tim
        public real speedChange
        public Slider instance
        
        static method create takes Slider slider, real speed returns thistype
            local thistype this = thistype.allocate()
            set this.instance = slider
            set this.speedChange = speed
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call this.deallocate()
            call ReleaseTimer(tim)
        endmethod
    endstruct
    
    struct RangeData extends array
        static constant real OFFSET = 500.
        implement List
        unit u
        real angle
        real change
    endstruct
    
    struct TextData extends array
        implement List
        texttag t
        real x
        real z
    endstruct

    struct Slider extends array
        
        static thistype array sliderlist
        static boolean  array is    // Is unit a slider
        
        unit slider
        public real defaultSpeed  //  Permanent speed
        public real bonusSpeed    //  Temporary speed
        boolean steer
        boolean stunned
        real stunnedTime
        effect stunEffect
        integer snowCount
        boolean snowImmune
        boolean jump
        boolean cata
        player owner
        boolean invisible
        boolean roots
        
        boolean showRange
        
        RangeData RangeList
        real rangeTime
        boolean rangeChangePositive
        real rangeChange
        TextData TextList
        Flag flag
        boolean pointToFlag
        
        unit flagPointer_blue
        unit flagPointer_red
        
        real propWindow
        real turnSpeed
        
        boolean enabled   // If slider is currently enabled.
        
        thistype prev
        thistype next
        static thistype first = 0
        
        static method operator [] takes unit u returns thistype
            return thistype(GetUnitUserData(u))
        endmethod
        
        static method isUnitSlider takes unit u returns boolean
            return is[GetUnitUserData(u)]
        endmethod
        
        static method create takes unit u returns thistype
            local thistype this = GetUnitUserData(u)
            
            set this.TextList = TextData.create()
            set this.RangeList = RangeData.create()
            
            set is[this] = true
            
            set .owner = GetOwningPlayer(u)
            set .snowImmune = false
            set .slider = u
            set .enabled = true
            set .steer = true
            set .stunned = false
            set .snowCount = 0
            set .cata = false
            set .stunnedTime = 0
            set .snowCount = 0
            set .snowImmune = false
            set .jump = false
            
            set this.propWindow = GetUnitDefaultPropWindow(slider)*bj_RADTODEG
            set this.turnSpeed  = GetUnitDefaultTurnSpeed(slider)
            
            if UnitAddAbility(u,'Amrf') and  UnitRemoveAbility(u,'Amrf')then
            endif
            
            call UnitAddAbility(u,'Aloc')
            call ShowUnit(u,false)
            call ShowUnit(u,true)
            call UnitRemoveAbility(u,'Aloc')
            
            call SetUnitPathing( u, false )
            
            if (thistype.first == 0) then
                call EnableTrigger(moveTrigger)
            endif
            
            call UnitAddAbility(u, CAM_UNLOCK)
            
            set .pointToFlag = true
            
            set showRange = false
            
            set .flagPointer_blue = CreateUnit(.owner, 'fPoi', 0, 0, 270)
            set .flagPointer_red = CreateUnit(.owner, 'fPoi', 0, 0, 270)
            
            call SetUnitVertexColor(.flagPointer_blue, 255, 240, 0, 150)
            call SetUnitVertexColor(.flagPointer_red, 255, 240, 0, 150)
            
            
            if LOCAL_PLAYER != .owner then
                call ShowUnit(.flagPointer_blue, false)
                call ShowUnit(.flagPointer_red, false)
            endif
            
            call UnitAddAbility(.slider, FLAG_INDICATOR_OFF)
            
            set .next = thistype.first
            set thistype.first.prev = this
            set thistype.first = this
            set .prev = 0
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            
            call .TextList.destroy()
            call .RangeList.destroy()
            
            set is[this] = false
            
            call RemoveUnit(.flagPointer_blue)
            call RemoveUnit(.flagPointer_red)
            
            call RemoveUnit(.slider)
            set .slider = null
            
            set .flagPointer_blue = null
            set .flagPointer_red = null
            
            call DestroyEffect(.stunEffect)
            set .stunEffect = null
            
            if (this == thistype.first) then
                set thistype.first = this.next
            endif
            set this.next.prev = this.prev
            set this.prev.next = this.next
            if (thistype.first == 0) then
                call DisableTrigger(moveTrigger)
            endif
        endmethod
        
        private method stunMove takes nothing returns nothing
            
            local real x1
            local real y1
            local real x2
            local real y2
            local real x3
            local real y3
            local real angle
            
            
            if this.snowCount > 3 then
            
                call ApplyPendingTextTag(this, Color[8] + "Too long in snow!|r", 16, 1.5, 2.5, 0, 100, GetRandomReal(90-15, 90+15))
                
                call KillUnit(slider)
                set this.snowCount = 0
                return
            endif
            set this.snowCount = this.snowCount + 1
            
            // Go forward -- if there's snow then go backward
            set angle = GetUnitFacing(this.slider)*bj_DEGTORAD
            set x1 = GetUnitX(this.slider) - 160*Cos(angle)
            set y1 = GetUnitY(this.slider) - 160*Sin(angle)
            if Terrain[GetTerrainType(x1, y1)].stun then
                set x1 = GetUnitX(this.slider) + 160*Cos(angle)
                set y1 = GetUnitY(this.slider) + 160*Sin(angle)
            endif
            
            // Go left and right from point from above
            set x2 = x1 + 150*Cos(angle+bj_PI/2)
            set y2 = y1 + 150*Sin(angle+bj_PI/2)
            set x3 = x1 + 150*Cos(angle-bj_PI/2)
            set y3 = y1 + 150*Sin(angle-bj_PI/2)
            
            // If both are snow or both are not snow then move to first point above
            if  (Terrain[GetTerrainType(x2, y2)].stun and Terrain[GetTerrainType(x3, y3)].stun)/*
            */or not (Terrain[GetTerrainType(x2, y2)].stun or Terrain[GetTerrainType(x3, y3)].stun) then
                // To interrupt current order so unit doesnt run in snow again
                call SetUnitPosition(this.slider, x1, y1)
            else
            
                // go to the one that is not snow
                if (Terrain[GetTerrainType(x2, y2)].stun) then
                    call SetUnitPosition(this.slider, x3, y3)
                else
                    call SetUnitPosition(this.slider, x2, y2)
                endif
            endif
            
               
            set stunEffect =  AddSpecialEffectTarget("Abilities\\Spells\\Orc\\LightningShield\\LightningShieldTarget.mdl", this.slider, "chest large")
            // Make slider moveable.
            call SetUnitPropWindow(slider,  propWindow )
            call SetUnitTurnSpeed(slider, turnSpeed)
            call SetUnitMoveSpeed(slider, 0)
        endmethod
        
        /*
        *   Sliding - Movement  (periodic call)
        */
        
        private static method onMove takes nothing returns nothing
            local real angle
            local real offset
            local real x
            local real y
            local real x2
            local real y2
            local real z
            local integer terrainType
            local thistype this = thistype.first
            local TextData element
            local TextData temp
            local RangeData rangeElement
            local integer i = 0
            
            loop
                
                exitwhen this == 0
                
                if enabled and UnitAlive(this.slider) and not .cata and not .roots then
                    
                    set x = GetUnitX(slider)
                    set y = GetUnitY(slider)
                    
                    set terrainType = GetTerrainType(x, y)
                    
                    if this.stunned then
                        set this.stunnedTime = this.stunnedTime - INTERVAL
                        set this.stunned = this.stunnedTime > 0
                        if not (this.stunned) then
                            call DestroyEffect(this.stunEffect)
                            call SetUnitMoveSpeed(slider, GetUnitDefaultMoveSpeed(slider))
                        endif
                        
                    // Check if slider is on a registered terrain type.
                    elseif (Terrain[terrainType] != 0) or jump then
                        
                        if (Terrain[terrainType].kill) then
                            call KillUnit(slider)
            
                        else
                                
                            if Terrain[terrainType].stun and not this.snowImmune then
                                set this.stunned = true
                                set this.stunnedTime = STUN_TIMEOUT
                                call this.stunMove()
                            else
                                set this.snowCount = 0
                                set angle = (GetUnitFacing(slider)*bj_DEGTORAD)
                                
                                if((Terrain[terrainType] == 0) and jump) then
                                    set offset = (defaultSpeed + bonusSpeed + DEFAULT_SPEED/TPS)
                                else
                                    set offset = (defaultSpeed + bonusSpeed + Terrain[terrainType].speed/TPS)*Terrain[terrainType].factor
                                endif
                                
                                
                                //  Heal/damage the slider.
                                call SetWidgetLife(slider,GetWidgetLife(slider) + Terrain[terrainType].lifeAddition/TPS)
                                
                                set x = x + offset * Cos(angle)
                                set y = y + offset * Sin(angle)
                                
                                //  Sliding
                                static if (CHECK_PATHING) then
                                    call SetUnitPosition(slider, x, y)
                                else
                                    call SetUnitX(slider, x)
                                    call SetUnitY(slider, y)
                                endif
                                
                                //  Check if terrain type is pulling.
                                if (Terrain[terrainType].pullSpeed != 0) then
                                    static if (CHECK_PATHING) then
                                        call SetUnitPosition(slider, x + (Terrain[terrainType].pullSpeed/TPS) * Cos(Terrain[terrainType].pullDirection*bj_DEGTORAD), y + (Terrain[terrainType].pullSpeed/TPS) * Sin(Terrain[terrainType].pullDirection*bj_DEGTORAD))
                                    else
                                        call SetUnitX(slider, x + (Terrain[terrainType].pullSpeed/TPS) * Cos(Terrain[terrainType].pullDirection*bj_DEGTORAD))
                                        call SetUnitY(slider, y + (Terrain[terrainType].pullSpeed/TPS) * Sin(Terrain[terrainType].pullDirection*bj_DEGTORAD))
                                    endif
                                endif
                                
                                // Make slider unmoveable while sliding.
                                call SetUnitPropWindow(slider, 0)
                                call SetUnitTurnSpeed(slider, 0.00)
                                
                            endif
    
                        endif
                    else
                        // Make slider moveable.
                        call SetUnitPropWindow(slider,  propWindow )
                        call SetUnitTurnSpeed(slider, turnSpeed)
                    endif
                    
                    if(.flag != 0)then
                        call .flag.updatePosition()
                    endif
                    
                     if MagicWall.isInWallRange(.slider, 80) then
                        call KillUnit(.slider)
                        call ApplyPendingTextTag(this, Color[0] + "Arghh!|r", 6, 1.25, 2.25, 0, 100, GetRandomReal(90-15, 90+15))
                        call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Undead\\UDeathSmall\\UDeathSmall.mdl", .slider, "origin"))
                    endif
                    
                    
                
                endif
                
                if not .cata then
                    set x = GetUnitX(.slider)
                    set y = GetUnitY(.slider)
                    set z = GetUnitFlyHeight(.slider)
                    set element = .TextList.first
                    set i = 1
                    loop
                        // fuck you, List, for this shit
                        exitwhen 0 == element
                        set temp = element.next
                
                        if(element.t != null)then
                            call SetTextTagPos(element.t, x-element.x, y, element.z + z)
                        else
                            call element.remove()
                        endif
                        
                        set element = temp
                    endloop
                endif
                
                if .pointToFlag then
                    set x = GetUnitX(.slider)
                    set y = GetUnitY(.slider)
                    set z = GetUnitFlyHeight(.slider)
                    
                    if this == Flag(Flag.BLUE).holder then
                        set angle = GetUnitFacing(.slider)*bj_DEGTORAD
                        call SetUnitX(.flagPointer_blue, x + 70*Cos(angle))
                        call SetUnitY(.flagPointer_blue, y + 70*Sin(angle))
                        call SetUnitFlyHeight(.flagPointer_blue, z+150, 0)
                    else
                        set angle = Atan2(GetUnitY(Flag(Flag.BLUE).flag) - y , GetUnitX(Flag(Flag.BLUE).flag) - x)
                        call SetUnitX(.flagPointer_blue, x + 300*Cos(angle))
                        call SetUnitY(.flagPointer_blue, y + 300*Sin(angle))
                        call SetUnitFlyHeight(.flagPointer_blue, z, 0)
                    endif
                    
                    if this == Flag(Flag.RED).holder then
                        set angle = GetUnitFacing(.slider)*bj_DEGTORAD
                        call SetUnitX(.flagPointer_red, x + 70*Cos(angle))
                        call SetUnitY(.flagPointer_red, y + 70*Sin(angle))
                        call SetUnitFlyHeight(.flagPointer_red, z+150, 0)
                    else
                        set angle = Atan2(GetUnitY(Flag(Flag.RED).flag) - y , GetUnitX(Flag(Flag.RED).flag) - x)
                        call SetUnitX(.flagPointer_red, x + 300*Cos(angle))
                        call SetUnitY(.flagPointer_red, y + 300*Sin(angle))
                        call SetUnitFlyHeight(.flagPointer_red, z, 0)
                    endif
                    
                    
                endif
                
               
                
                if (.showRange) then
                
                    if UnitAlive(.slider) then
                
                        set x = GetUnitX(.slider)
                        set y = GetUnitY(.slider)
                        set rangeElement = .RangeList.first
                        set .rangeTime = rangeTime + INTERVAL
                        if rangeTime > 4 then
                            
                            if .rangeChange != 0 then
                                set .rangeChange = 0
                                set .rangeTime = 0
                            elseif .rangeChangePositive then
                                set .rangeChange = bj_PI/100
                                set .rangeChangePositive = not .rangeChangePositive
                                set .rangeTime = 0
                            else
                                set .rangeChange = -bj_PI/100
                                set .rangeChangePositive = not .rangeChangePositive
                                set .rangeTime = 0
                            endif
                        
                        endif
                        loop
                            exitwhen 0 == rangeElement
                            set x2 = x + RangeData.OFFSET * Cos(rangeElement.angle)
                            set y2 = y + RangeData.OFFSET * Sin(rangeElement.angle)
                            if IsInBounds(x2, y2) then
                                call SetUnitX(rangeElement.u, x2)
                                call SetUnitY(rangeElement.u, y2)
                            endif
                            
                            set rangeElement.angle = rangeElement.angle - .rangeChange
                            
                            set rangeElement = rangeElement.next
                        endloop
                    else
                        set rangeElement = .RangeList.first
                        loop
                            exitwhen 0 == rangeElement
                            call KillUnit(rangeElement.u)
                            set rangeElement.u = null
                            set rangeElement = rangeElement.next
                        endloop
                        call .RangeList.destroy()
                        call UnitRemoveAbility(.slider, RANGE_OFF)
                        call UnitAddAbility(.slider, RANGE_ON)
                        set .showRange = false
                    endif
                endif
                
                set this = next
            endloop
        endmethod
        
        /*
        *   Sliding - Steering
        */
        
        private static method onTurn takes nothing returns boolean
            local unit u = GetTriggerUnit()
            local real x
            local real y
            local integer terrainType
            local integer order = GetIssuedOrderId()
            local boolean b = true
            local thistype slider = thistype[u]

            if (is[GetUnitUserData(u)] and slider.enabled) and not slider.cata then
                set x = GetUnitX(u)
                set y = GetUnitY(u)
                
                
                set terrainType = GetTerrainType(x, y)
                
                // Check if slider is on a registered terrain type.
                if (Terrain[terrainType] != 0 and slider.steer) or slider.jump then
                    
                    if( (order == SMART) and (Terrain[terrainType].allowSteer) or slider.stunned or slider.jump) then
                        // Let the slider turn.
                        call SetUnitFacing( u, (Atan2(GetOrderPointY() - y , GetOrderPointX() - x) * bj_RADTODEG) + Terrain[terrainType].angle)
                        
                    elseif ((order != SMART) and (order != MOVE) and (order != PATROL) and (Terrain[terrainType].allowCast)) then
                        // The slider is casting an ability. Let him face wanted position, if allowed.
                        call SetUnitFacing( u, Atan2(GetOrderPointY() - y , GetOrderPointX() - x) * bj_RADTODEG)
                        set b = false
                    endif
                    
                    if ((order == SMART) or (order == MOVE) or (order == PATROL) or (b)) then
                        call DisableTrigger( steerTrigger )
                        call PauseUnit (u,true)
                        call IssueImmediateOrderById(u, STOP)   // That will abbort unit's order if unit is not casting.
                        call PauseUnit (u,false)
                        call EnableTrigger( steerTrigger )
                    endif
                endif
            endif
            
            set u = null
            return false
        endmethod
        
        
        method newText takes texttag text, real z returns TextData
            local TextData element
            set element = .TextList.enqueue()
            set element.t = text
            set element.z = z
            return element
        endmethod
        
       // API - Start
        
        method enable takes boolean b returns nothing
            set enabled = b
        endmethod
        
        method isEnabled takes nothing returns boolean
            return enabled
        endmethod
        
        method getDefaultSpeed takes nothing returns real
            return defaultSpeed*TPS
        endmethod
        
        method getTempSpeed takes nothing returns real
            return bonusSpeed*TPS
        endmethod
        
        /*   Permanent Boost   */
        
        method setDefaultSpeed takes real s returns nothing
            set defaultSpeed = s/TPS
        endmethod
        
        method addDefaultSpeed takes real s returns nothing
            set defaultSpeed = defaultSpeed + s/TPS
        endmethod
        
        /*  Temporary Boost  */
        
        private static method callback takes nothing returns nothing
            local Acceleration this = GetTimerData(GetExpiredTimer())
            set this.instance.bonusSpeed = this.instance.bonusSpeed - this.speedChange
            call this.destroy()
        endmethod
        
        method addTempSpeed takes real speed, real duration returns nothing
            local integer handleId
            local Acceleration newData
            
            if duration > 0 then
                set speed = speed/TPS
                set bonusSpeed = bonusSpeed + speed
                set newData = Acceleration.create(this, speed)
                set newData.tim = NewTimerEx(newData)
                call TimerStart(newData.tim, duration, false, function thistype.callback)
            else
                debug call BJDebugMsg("Error -  Sliding System - AddTempSpeed:  Duration must be greater 0.")
            endif
            
        endmethod
        
        // API - End
        
        private static method onDeindex takes nothing returns boolean
            if is[GetUnitUserData(GetIndexedUnit())] then
                call thistype[GetIndexedUnit()].destroy()
            endif
            return false
        endmethod

        private static method onInit takes nothing returns nothing
            call TriggerRegisterAnyUnitEventBJ( steerTrigger, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
            call TriggerAddCondition(steerTrigger, Condition(function thistype.onTurn))
            call TriggerRegisterTimerEvent(moveTrigger, INTERVAL, true)
            call TriggerAddAction(moveTrigger, function thistype.onMove)
            call DisableTrigger(moveTrigger)
            call RegisterUnitIndexEvent(Condition(function thistype.onDeindex), UnitIndexer.DEINDEX)
        endmethod
    endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
struct TerrainSettings extends array
    private static method onInit takes nothing returns nothing
        local integer TerrainType
        
        set TerrainType = SLIDE_NORMAL
        call Terrain.create(TerrainType)
        set Terrain[TerrainType].allowSteer = true
        set Terrain[TerrainType].factor = 1
        
        set TerrainType = SLIDE_FAST
        call Terrain.create(SLIDE_FAST)
        set Terrain[TerrainType].allowSteer = true
        set Terrain[TerrainType].factor = 2
        
        set TerrainType = SLIDE_DARK
        call Terrain.create(TerrainType)
        set Terrain[TerrainType].factor = 1
        
        set TerrainType = SLIDE_SNOW
        call Terrain.create(TerrainType)
        set Terrain[TerrainType].stun = true
        set Terrain[TerrainType].allowSteer = true
        set Terrain[TerrainType].factor = 1
    endmethod
endstruct
//TESH.scrollpos=220
//TESH.alwaysfold=0
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//-=-=-= Terrain Type Constants by Darthfett =-=-=-=-=-
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//-=-=-=-= Thanks to Romek for the Raw Codes  -=-=-=-=-
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

scope LORDAERONSUMMER
// Lordaeron Summer
globals
    public constant integer DIRT = 'Ldrt'
    public constant integer ROUGH_DIRT = 'Ldro'
    public constant integer GRASSY_DIRT = 'Ldrg'
    public constant integer ROCK = 'Lrok'
    public constant integer GRASS = 'Lgrs'
    public constant integer DARK_GRASS = 'Lgrd'
    public constant integer DIRT_CLIFF = 'cLc2'
    public constant integer GRASS_CLIFF = 'cLc1'
endglobals

endscope

scope LORDAERONFALL
// Lordaeron Fall
globals
    public constant integer DIRT = 'Fdrt'
    public constant integer ROUGH_DIRT = 'Fdro'
    public constant integer GRASSY_DIRT = 'Fdrg'
    public constant integer ROCK = 'Frok'
    public constant integer GRASS = 'Fgrs'
    public constant integer DARK_GRASS = 'Fgrd'
    public constant integer DIRT_CLIFF = 'cFc2'
    public constant integer GRASS_CLIFF = 'cFc1'
endglobals

endscope

scope LORDAERONWINTER
// Lordaeron Winter
globals
    public constant integer DIRT = 'Wdrt'
    public constant integer ROUGH_DIRT = 'Wdro'
    public constant integer GRASSY_SNOW = 'Wsng'
    public constant integer ROCK = 'Wrok'
    public constant integer GRASS = 'Wgrs'
    public constant integer SNOW = 'Wsnw'
    public constant integer GRASS_CLIFF = 'cWc2'
    public constant integer SNOW_CLIFF = 'cWc1'
endglobals

endscope

scope BARRENS
// Barrens
globals
    public constant integer DIRT = 'Bdrt'
    public constant integer ROUGH_DIRT = 'Bdrh'
    public constant integer PEBBLES = 'Bdrr'
    public constant integer GRASSY_DIRT = 'Bdrg'
    public constant integer DESERT = 'Bdsr'
    public constant integer DARK_DESERT = 'Bdsd'
    public constant integer ROCK = 'Bflr'
    public constant integer GRASS = 'Bgrr'
    public constant integer DESERT_CLIFF = 'cBc2'
    public constant integer GRASS_CLIFF = 'cBc1'
endglobals

endscope

scope ASHENVALE
// Ashenvale
globals
    public constant integer DIRT = 'Adrt'
    public constant integer ROUGH_DIRT = 'Adrd'
    public constant integer GRASS = 'Agrs'
    public constant integer ROCK = 'Arck'
    public constant integer LUMPY_GRASS = 'Agrd'
    public constant integer VINES = 'Avin'
    public constant integer GRASSY_DIRT = 'Adrg'
    public constant integer LEAVES = 'Alvd'
    public constant integer DIRT_CLIFF = 'cAc2'
    public constant integer GRASS_CLIFF = 'cAc1'
endglobals

endscope

scope FELWOOD
// Felwood
globals
    public constant integer DIRT = 'Cdrt'
    public constant integer ROUGH_DIRT = 'Cdrd'
    public constant integer POISON = 'Cpos'
    public constant integer ROCK = 'Crck'
    public constant integer VINES = 'Cvin'
    public constant integer GRASS = 'Cgrs'
    public constant integer LEAVES = 'Clvg'
    public constant integer DIRT_CLIFF = 'cCc2'
    public constant integer GRASS_CLIFF = 'cCc1'
endglobals

endscope

scope NORTHREND
// Northrend
globals
    public constant integer DIRT = 'Ndrt'
    public constant integer DARK_DIRT = 'Ndrd'
    public constant integer ROCK = 'Nrck'
    public constant integer GRASS = 'Ngrs'
    public constant integer ICE = 'Nice'
    public constant integer SNOW = 'Nsnw'
    public constant integer ROCKY_SNOW = 'Nsnr'
    public constant integer DIRT_CLIFF = 'cNc2'
    public constant integer SNOW_CLIFF = 'cNc1'
endglobals

endscope

scope CITYSCAPE
// Cityscape
globals
    public constant integer DIRT = 'Ydrt'
    public constant integer ROUGH_DIRT = 'Ydtr'
    public constant integer BLACK_MARBLE = 'Yblm'
    public constant integer BRICK = 'Ybtl'
    public constant integer SQUARE_TILES = 'Ysqd'
    public constant integer ROUND_TILES = 'Yrtl'
    public constant integer GRASS = 'Ygsb'
    public constant integer GRASS_TRIM = 'Yhdg'
    public constant integer WHITE_MARBLE = 'Ywmb'
    public constant integer DIRT_CLIFF = 'cYc2'
    public constant integer SQUARE_TILES_CLIFF = 'cYc1'
endglobals

endscope

scope VILLAGE
// Village
globals
    public constant integer DIRT = 'Vdrt'
    public constant integer ROUGH_DIRT = 'Vdrr'
    public constant integer CROPS = 'Vcrp'
    public constant integer COBBLE_PATH = 'Vcbp'
    public constant integer STONE_PATH = 'Vstp'
    public constant integer SHORT_GRASS = 'Vgrs'
    public constant integer ROCKS = 'Vrck'
    public constant integer THICK_GRASS = 'Vgrt'
    public constant integer DIRT_CLIFF = 'cVc2'
    public constant integer GRASS_THICK_CLIFF = 'cVc1'
endglobals

endscope

scope VILLAGEFALL
// Village Fall
globals
    public constant integer DIRT = 'Qdrt'
    public constant integer ROUGH_DIRT = 'Qdrr'
    public constant integer CROPS = 'Qcrp'
    public constant integer COBBLE_PATH = 'Qcbp'
    public constant integer STONE_PATH = 'Qstp'
    public constant integer SHORT_GRASS = 'Qgrs'
    public constant integer ROCKS = 'Qrck'
    public constant integer THICK_GRASS = 'Qgrt'
    public constant integer DIRT_CLIFF = 'cQc2'
    public constant integer GRASS_THICK_CLIFF = 'cQc1'
endglobals

endscope

scope DALARAN
// Dalaran
globals
    public constant integer DIRT = 'Xdrt'
    public constant integer ROUGH_DIRT = 'Xdtr'
    public constant integer BLACK_MARBLE = 'Xblm'
    public constant integer BRICK_TILES = 'Xbtl'
    public constant integer SQUARE_TILES = 'Xsqd'
    public constant integer ROUND_TILES = 'Xrtl'
    public constant integer GRASS = 'Xgsb'
    public constant integer TRIM_GRASS = 'Xhdg'
    public constant integer WHITE_MARBLE = 'Xwmb'
    public constant integer DIRT_CLIFF = 'cXc2'
    public constant integer SQUARE_TILES_CLIFF = 'cXc1'
endglobals

endscope

scope DUNGEON
// Dungeon
globals
    public constant integer DIRT = 'Ddrt'
    public constant integer BRICK = 'Dbrk'
    public constant integer RED_STONES = 'Drds'
    public constant integer LAVA_CRACKS = 'Dlvc'
    public constant integer LAVA = 'Dlav'
    public constant integer DARK_ROCKS = 'Ddkr'
    public constant integer GREY_STONES = 'Dgrs'
    public constant integer SQUARE_TILES = 'Dsqd'
    public constant integer DIRT_CLIFF = 'cDc2'
    public constant integer SQUARE_TILES_CLIFF = 'cDc1'
endglobals

endscope

scope UNDERGROUND
// Underground
globals
    public constant integer DIRT = 'Gdrt'
    public constant integer BRICK = 'Gbrk'
    public constant integer RED_STONES = 'Grds'
    public constant integer LAVA_CRACKS = 'Glvc'
    public constant integer LAVA = 'Glav'
    public constant integer DARK_ROCKS = 'Gdkr'
    public constant integer GREY_STONES = 'Ggrs'
    public constant integer SQUARE_TILES = 'Gsqd'
    public constant integer DIRT_CLIFF = 'cGc2'
    public constant integer SQUARE_TILES_CLIFF = 'cGc1'
endglobals

endscope

scope SUNKENRUINS
// Sunken Ruins
globals
    public constant integer DIRT = 'Zdrt'
    public constant integer ROUGH_DIRT = 'Zdtr'
    public constant integer GRASSY_DIRT = 'Zdrg'
    public constant integer SMALL_BRICKS = 'Zbks'
    public constant integer SAND = 'Zsan'
    public constant integer LARGE_BRICKS = 'Zbkl'
    public constant integer ROUND_TILES = 'Ztil'
    public constant integer GRASS = 'Zgrs'
    public constant integer DARK_GRASS = 'Zvin'
    public constant integer DIRT_CLIFF = 'cZc2'
    public constant integer LARGE_BRICKS_CLIFF = 'cZc1'
endglobals

endscope

scope ICECROWNGLACIER
// Icecrown Glacier
globals
    public constant integer DIRT = 'Idrt'
    public constant integer ROUGH_DIRT = 'Idtr'
    public constant integer DARK_ICE = 'Idki'
    public constant integer BLACK_BRICKS = 'Ibkb'
    public constant integer RUNE_BRICKS = 'Irbk'
    public constant integer TILED_BRICKS = 'Itbk'
    public constant integer ICE = 'Iice'
    public constant integer BLACK_SQUARES = 'Ibsq'
    public constant integer SNOW = 'Isnw'
    public constant integer RUNE_BRICKS_CLIFF = 'cIc2'
    public constant integer SNOW_CLIFF = 'cIc1'
endglobals

endscope

scope OUTLAND
// Outland
globals
    public constant integer DIRT = 'Odrt'
    public constant integer LIGHT_DIRT = 'Odtr'
    public constant integer ROUGH_DIRT = 'Osmb'
    public constant integer CRACKED_DIRT = 'Ofst'
    public constant integer FLAT_STONES = 'Olgb'
    public constant integer ROCK = 'Orok'
    public constant integer LIGHT_FLAT_STONES = 'Ofsl'
    public constant integer ABYSS = 'Oaby'
    public constant integer ABYSS_CLIFF = 'cOc1'
    public constant integer ROUGH_DIRT_CLIFF = 'cOc2'
endglobals

endscope

scope BLACKCITADEL
// Black Citadel
globals
    public constant integer DIRT = 'Kdrt'
    public constant integer LIGHT_DIRT = 'Kfsl'
    public constant integer ROUGH_DIRT = 'Kdtr'
    public constant integer FLAT_STONES = 'Kfst'
    public constant integer SMALL_BRICKS = 'Ksmb'
    public constant integer LARGE_BRICKS = 'Klgb'
    public constant integer SQUARE_TILES = 'Ksqt'
    public constant integer DARK_TILES = 'Kdkt'
    public constant integer DIRT_CLIFF = 'cKc1'
    public constant integer DARK_TILES_CLIFF = 'cKc2'
endglobals

endscope

scope DALARANRUINS
// Dalaran Ruins
globals
    public constant integer DIRT = 'Jdrt'
    public constant integer ROUGH_DIRT = 'Jdtr'
    public constant integer BLACK_MARBLE =  'Jblm'
    public constant integer BRICK_TILES = 'Jbtl'
    public constant integer SQUARE_TILES = 'Jsqd'
    public constant integer ROUND_TILES = 'Jrtl'
    public constant integer GRASS = 'Jgsb'
    public constant integer TRIM_GRASS = 'Jhdg'
    public constant integer WHITE_MARBLE = 'Jwmb'
    public constant integer DIRT_CLIFF = 'cJc2'
    public constant integer SQUARE_TILES_CLIFF = 'cJc1'
endglobals

endscope
//TESH.scrollpos=99
//TESH.alwaysfold=0
library Missle requires WorldBounds

    struct Missle extends array
        
        static group g = CreateGroup()
        static constant attacktype ATTACK_TYPE = ATTACK_TYPE_CHAOS
        static constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_COLD
        
        real cos
        real sin
        real speed
        unit missle
        effect effect
        unit caster
        player owner
        real time_current
        real time_max
        real distance_current
        real distance_max
        real damage
        real collision
        real aoe
        integer aoeEffect
        integer killCount
        
        RSound sound_launch
        RSound sound_explosion
        
        private method unitFilter takes unit u returns boolean
            return IsUnitType(u, UNIT_TYPE_HERO) and UnitAlive(u) and User[GetOwningPlayer(u)].team != User[.owner].team/*
                */ and not Slider[u].jump/*
                */ and not Slider[u].cata
        endmethod
        
        method onExplosion takes unit u returns nothing
            local unit fog
            local real x = GetUnitX(u)
            local real y = GetUnitY(u)
            
            if (u != null) then
                
                call KillUnit(CreateUnit(.owner, 'blod', x,  y, 0))
                call UnitDamageTarget(.caster, u, .damage, true, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                if(GetWidgetLife(u) <= .damage)then
                    set .killCount = .killCount + 1
                    if(.killCount == 2)then
                        call Sound[1].play(x, y, 0, 200)
                    elseif .killCount > 2 then
                        call Sound[2].play(x, y, 0, 200)
                    endif
                endif
                
            endif
            
            if(.aoe > 0) then
                
                if (u == null) then
                    call KillUnit(CreateUnit(.owner, .aoeEffect, GetUnitX(.missle),  GetUnitY(.missle), 0))
                else
                    call KillUnit(CreateUnit(.owner, .aoeEffect, GetUnitX(u),  GetUnitY(u), 0))
                endif
                call GroupEnumUnitsInRange(g, x, y, .aoe, null)
                loop
                    set fog = FirstOfGroup(g)
                    exitwhen fog == null
                    
                    if (.unitFilter(fog) and u != fog) then
                        call UnitDamageTarget(.caster, fog, .damage, true, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                    endif
                    
                    call GroupRemoveUnit(g, fog)
                endloop
                
            endif
            
            call KillUnit(.missle)
            set .aoeEffect = 0
            set .caster = null
            set .missle = null
            call .destroy()
            
        endmethod
        
        implement CTL
            // Loop locals
            local real x_origin
            local real y_origin
            local real x
            local real y
            local integer terrainType
            local unit fog
            local Slider s
            
        implement CTLExpire
        
            // Loop body
            set .time_current = .time_current + INTERVAL
            if(.time_current >= .time_max or not UnitAlive(.missle)) then
                call .onExplosion(null)
            else
                set x_origin = GetUnitX(.missle)
                set y_origin = GetUnitY(.missle)
                set terrainType = GetTerrainType(x_origin, y_origin)
                if Terrain.table.has(terrainType)then
                    set x = x_origin + (.speed/TPS)* Terrain[terrainType].factor * .cos
                    set y = y_origin + (.speed/TPS)* Terrain[terrainType].factor * .sin
                else
                    set x = x_origin + (.speed/TPS) * .cos
                    set y = y_origin + (.speed/TPS) * .sin
                endif
                
                if IsInBounds(x, y) then
                    
                    if(Wall.isInWall(x_origin, y_origin, x, y) or not IsInBounds(x, y)) then
                        call .onExplosion(null)
                    else
                    
                        call SetUnitX(.missle, x)
                        call SetUnitY(.missle, y)
                        
                        call GroupEnumUnitsInRange(g, x, y, .collision, null)
                        loop
                            set fog = FirstOfGroup(g)
                            exitwhen fog == null
                            
                            if .unitFilter(fog) then
                                call .onExplosion(fog)
                                exitwhen true
                            endif
                            
                            call GroupRemoveUnit(g, fog)
                        endloop
                        
                        set s = Slider.first
                        loop
                            exitwhen s == 0
                            
                            if ExplosiveEgg[s.slider].egg != null and IsUnitInRange(.missle, ExplosiveEgg[s.slider].egg, ExplosiveEgg.COLLISION) then
                                call ExplosiveEgg[s.slider].explode()
                                call .onExplosion(null)
                                exitwhen true
                            endif
                            
                            set s = s.next
                        endloop
                        
                    endif
                    
                else
                    call .onExplosion(null)
                endif
            endif 
            
        implement CTLEnd
        
        public static method apply takes unit u, integer who returns thistype
            local thistype this = create()
            local real angle = GetUnitFacing(u)
            set .caster = u
            set .killCount = 0
            set .owner = GetOwningPlayer(u)
            set .cos = Cos(angle*bj_DEGTORAD)
            set .sin = Sin(angle*bj_DEGTORAD)
            set .missle = CreateUnit(.owner, who , GetUnitX(u)+40*.cos, GetUnitY(u)+40*.sin, angle)
            call UnitAddAbility(.missle, 'Aloc')
            call SetUnitPathing(.missle, false)
            set .speed = 0
            set .time_current = 0
            set .time_max = 0
            set .distance_current = 0
            set .distance_max = 0
            set .damage = 0
            set .collision = 0
            set .aoe = 0
            return this
        endmethod
    endstruct
endlibrary
//TESH.scrollpos=30
//TESH.alwaysfold=0

// Normal missles for blue and red team
scope EnergyBall
    globals
        private constant real SPEED              = 2.4*DEFAULT_SPEED
        private constant real COLLISION          = 80.
        private constant real DURATION           = 1.2
        private constant real DAMAGE             = 100.
        private constant real SCALE              = 2.8
    endglobals
    private struct EnegeryBall extends array
        
        private static method orderFilter takes unit u, integer orderId returns boolean
            return orderId == ORDER_ENERGY_BALL and GetUnitAbilityLevel(u, ENERGY_BALL) > 0
        endmethod
        
        private static method filter takes Slider s returns boolean
            return not(Terrain.table.has(GetTerrainType(GetUnitX(s.slider), GetUnitY(s.slider))))/*
                */ or s.jump/*
                */ or s.roots/*
                */ or s.stunned
        endmethod
    
        private static method onCast takes nothing returns nothing
            local Missle this
            
            set Slider[GetTriggerUnit()].invisible = false
            if (GetPlayerId(GetTriggerPlayer()) < 6) then
                set this = Missle.apply(GetTriggerUnit(), MISSLE_BLUE)
            else
                set this = Missle.apply(GetTriggerUnit(), MISSLE_RED)
            endif
            call Sound[LAUNCH_ENERGYBALL].play(GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), 0, 200)
            set this.speed = SPEED
            set this.collision = COLLISION
            set this.time_max = DURATION
            set this.damage = DAMAGE
        endmethod
        
        private static method callback takes nothing returns nothing
            call UnitAddAbility(Slider(GetTimerData(GetExpiredTimer())).slider, ENERGY_BALL)
            call ReleaseTimer(GetExpiredTimer())
        endmethod
        
        private static method onOrder takes nothing returns nothing
            local unit u = GetTriggerUnit()
            
            if orderFilter(u, GetIssuedOrderId())then
                
                if filter(Slider[u]) then
                    call ApplyErrorTextTag(Slider[u])
                    call UnitRemoveAbility(u, ENERGY_BALL)
                    call TimerStart(NewTimerEx(Slider[u]), 0, false, function thistype.callback)
                endif
                
            endif
            set u = null
        endmethod
        
        private static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(ENERGY_BALL, function thistype.onCast)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
        endmethod
    endstruct
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0

// Fast sniper missles
scope SniperArrow
    globals
        private constant real SPEED              = 3*DEFAULT_SPEED
        private constant real COLLISION          = 80.
        private constant real DURATION           = 1.2
        private constant real DAMAGE             = 200.
        private constant real SCALE              = 1.4
    endglobals
    private struct EnegeryBall extends array
    
        private static method orderFilter takes unit u, integer orderId returns boolean
            return orderId == ORDER_SNIPER_ARROW and GetUnitAbilityLevel(u, SNIPER_ARROW) > 0
        endmethod
        
        private static method filter takes Slider s returns boolean
            return not(Terrain.table.has(GetTerrainType(GetUnitX(s.slider), GetUnitY(s.slider))))/*
                */ or s.jump/*
                */ or s.roots/*
                */ or s.stunned
        endmethod
        
        private static method callback takes nothing returns nothing
            call UnitAddAbility(Slider(GetTimerData(GetExpiredTimer())).slider, SNIPER_ARROW)
            call ReleaseTimer(GetExpiredTimer())
        endmethod
    
        private static method onCast takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local Missle this = Missle.apply(u, MISSLE_SNIPER)
            set Slider[u].invisible = false
            call Sound[LAUNCH_SNIPERARROW].play(GetUnitX(u), GetUnitY(u), 0, 200)
            set this.speed = SPEED
            set this.collision = COLLISION
            set this.time_max = DURATION
            set this.damage = DAMAGE
            set u = null
        endmethod
        
        private static method onOrder takes nothing returns nothing
            local unit u = GetTriggerUnit()
            if orderFilter(u, GetIssuedOrderId()) and filter(Slider[u])then
                call ApplyErrorTextTag(Slider[u])
                call UnitRemoveAbility(u, SNIPER_ARROW)
                call TimerStart(NewTimerEx(Slider[u]), 0, false, function thistype.callback)
            endif
            set u = null
        endmethod
        
        private static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(SNIPER_ARROW, function thistype.onCast)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
        endmethod
    endstruct
endscope
//TESH.scrollpos=36
//TESH.alwaysfold=0

// Fast and strong sniper missle with aoe
scope Rocket
    globals
        private constant real SPEED              = 2.8*DEFAULT_SPEED
        private constant real COLLISION          = 105.
        private constant real DURATION           = 1
        private constant real DAMAGE             = 200.
        private constant real AOE                = 260
        private constant real SCALE              = 2.2
        private constant integer AOE_EFFECT      = ROCKET_EFFECT//"Objects\\Spawnmodels\\Human\\FragmentationShards\\FragBoomSpawn.mdl"
    endglobals
    private struct EnegeryBall extends array
    
        private static method orderFilter takes unit u, integer orderId returns boolean
            return orderId == ORDER_ROCKET and GetUnitAbilityLevel(u, ROCKET) > 0
        endmethod
        
        private static method filter takes Slider s returns boolean
            return not(Terrain.table.has(GetTerrainType(GetUnitX(s.slider), GetUnitY(s.slider))))/*
                */ or s.jump/*
                */ or s.roots/*
                */ or s.stunned
        endmethod
    
        private static method onCast takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local Missle this = Missle.apply(u, MISSLE_ROCKET)
            set Slider[u].invisible = false
            call Sound[LAUNCH_ROCKET].play(GetUnitX(u), GetUnitY(u), 0, 200)
            set this.speed = SPEED
            set this.collision = COLLISION
            set this.time_max = DURATION
            set this.damage = DAMAGE
            set this.aoe = AOE
            set this.aoeEffect = AOE_EFFECT
            set u = null
        endmethod
        
        private static method onFinish takes nothing returns nothing
            if (GetSpellAbilityId() == ROCKET and GetUnitState(GetTriggerUnit(), UNIT_STATE_MANA) < 1) then
                call CurrentShootAbility.apply(GetTriggerUnit(), DefaultShootAbility[GetTriggerUnit()])
                call SetUnitMaxState(GetTriggerUnit(), UNIT_STATE_MAX_MANA, 0)
            endif
        endmethod
        
        private static method callback takes nothing returns nothing
            call UnitAddAbility(Slider(GetTimerData(GetExpiredTimer())).slider, ROCKET)
            call ReleaseTimer(GetExpiredTimer())
        endmethod
        
        private static method onOrder takes nothing returns nothing
            local unit u = GetTriggerUnit()
            if orderFilter(u, GetIssuedOrderId()) and filter(Slider[u])then
                call ApplyErrorTextTag(Slider[u])
                call UnitRemoveAbility(u, ROCKET)
                call TimerStart(NewTimerEx(Slider[u]), 0, false, function thistype.callback)
            endif
            set u = null
        endmethod
        
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call RegisterSpellEffectEvent(ROCKET, function thistype.onCast)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
            call TriggerAddAction(t, function thistype.onFinish)
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_FINISH )
        endmethod
    endstruct
endscope
//TESH.scrollpos=30
//TESH.alwaysfold=0
scope Invisibility
    struct Invisibility extends array
        private static constant real    DURATION    = 4
        
        real time
        Slider slider
        
        implement CTL
            local Team t = User[.slider.owner].team
        implement CTLExpire
            
            // Loop body
            set this.time = this.time + INTERVAL
            if this.time >= DURATION  or (not UnitAlive(this.slider.slider)) or not .slider.invisible then
                call this.destroy()
                call SetUnitVertexColor(.slider.slider, t.r, t.g, t.b, 255)
                set slider.invisible = false
            endif
        implement CTLEnd
        
        private static method orderFilter takes unit u, integer orderId returns boolean
            return orderId == ORDER_INVISIBILITY and GetUnitAbilityLevel(u, INVISIBILITY) > 0
        endmethod
        
        private static method filter takes Slider s returns boolean
            return /*
                */ s.stunned/*
                */ or s.roots
        endmethod
        
        private static method onCast takes nothing returns nothing
            local thistype this = create()
            local Team t = User[GetTriggerPlayer()].team
            set .slider = Slider[GetTriggerUnit()]
            set .slider.invisible = true
            set .time = 0
            if User[GetTriggerPlayer()].team != User[LOCAL_PLAYER].team then
                call SetUnitVertexColor(.slider.slider, t.r, t.g, t.b, 0)
            else
                call SetUnitVertexColor(.slider.slider, t.r, t.g, t.b, 125)
            endif
        endmethod
        
        private static method callback takes nothing returns nothing
            call UnitAddAbility(Slider(GetTimerData(GetExpiredTimer())).slider, INVISIBILITY)
            call ReleaseTimer(GetExpiredTimer())
        endmethod
        
        private static method onOrder takes nothing returns nothing
            local unit u = GetTriggerUnit()
            if orderFilter(u, GetIssuedOrderId()) and filter(Slider[u])then
                call ApplyErrorTextTag(Slider[u])
                call UnitRemoveAbility(u, INVISIBILITY)
                call TimerStart(NewTimerEx(Slider[u]), 0, false, function thistype.callback)
            endif
            set u = null
        endmethod
            
        private static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(INVISIBILITY, function thistype.onCast)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
        endmethod
        
    endstruct
endscope
//TESH.scrollpos=38
//TESH.alwaysfold=0
scope Jump
    struct Jump extends array
        private static constant real    DURATION    = 0.6
        private static constant real    SPEED_BOOST = DEFAULT_SPEED*0.8
        private static constant real    MAX_HEIGHT  = 250
        
        real time
        real height
        Slider slider
        
        implement CTL
            // Loop locals
        implement CTLExpire
            
            // Loop body
            set this.time = this.time + INTERVAL
            call SetUnitFlyHeight(this.slider.slider, ParabolaZ(MAX_HEIGHT, DURATION, time), 0)
            if(this.time >= DURATION  or not UnitAlive(this.slider.slider)) then
                call this.destroy()
                call SetUnitFlyHeight(this.slider.slider, 0, 0)
                call this.slider.addDefaultSpeed(-SPEED_BOOST)
                set this.slider.snowImmune = false
                set this.slider.jump = false
            endif
        implement CTLEnd
        
        private static method orderFilter takes unit u, integer orderId returns boolean
            return orderId == ORDER_JUMP and GetUnitAbilityLevel(u, JUMP) > 0
        endmethod
        
        private static method filter takes Slider s returns boolean
            return s.stunned or s.roots
        endmethod
        
        private static method onCast takes nothing returns nothing
            local thistype this = create()
            set .slider = Slider[GetTriggerUnit()]
            set .time = 0
            set .height = 0
            call .slider.addDefaultSpeed(SPEED_BOOST)
            set .slider.snowImmune = true
            set .slider.jump = true
        endmethod
        
        private static method callback takes nothing returns nothing
            call UnitAddAbility(Slider(GetTimerData(GetExpiredTimer())).slider, JUMP)
            call ReleaseTimer(GetExpiredTimer())
        endmethod
        
        private static method onOrder takes nothing returns nothing
            local unit u = GetTriggerUnit()
            if orderFilter(u, GetIssuedOrderId()) then
                if filter(Slider[u])then
                    call ApplyErrorTextTag(Slider[u])
                    call UnitRemoveAbility(u, JUMP)
                    call TimerStart(NewTimerEx(Slider[u]), 0, false, function thistype.callback)
                    
                elseif MagicWall.isInWallRange(u, 800) then
                    call ApplyPendingTextTag(Slider[u], Color[0] + "Wall Blocks|r", 10, 1.5, 2.5, 0, 100, GetRandomReal(90-15, 90+15))
                    call Sound[ERROR].play(GetUnitX(u), GetUnitY(u), 0, 200)
                    call UnitRemoveAbility(u, JUMP)
                    call TimerStart(NewTimerEx(Slider[u]), 0, false, function thistype.callback)
                endif
            endif
            set u = null
        endmethod
            
        private static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(JUMP, function thistype.onCast)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
        endmethod
    endstruct
endscope
//TESH.scrollpos=66
//TESH.alwaysfold=0
struct HolyRa extends array

    private static constant real DURATION = 2.6
    private static constant real SPEED =  2.5*DEFAULT_SPEED

    unit u
    real time
    Team team
    
    implement CTL
       local Slider s
       local real minimumRange
       local unit aimUnit = null
       local real x
       local real y
       local real angle
       local real distance
       local integer terrainType
       local real offset
    implement CTLExpire
        
        // Loop body
        set this.time = this.time + INTERVAL
        if this.time >= DURATION  or not UnitAlive(this.u) then
            call this.destroy()
            call KillUnit(this.u)
            set this.u = null
        else
            
            set x = GetUnitX(.u)
            set y = GetUnitY(.u)
            
            // Get clostest dead slider
            set s = Slider.first
            loop
                exitwhen s == 0
                
                if User[s.owner].team == .team and not UnitAlive(s.slider) then
                    
                    set distance = SquareRoot(((GetUnitX(s.slider) - x) * (GetUnitX(s.slider) - x)) + ((GetUnitY(s.slider) - y) * (GetUnitY(s.slider) - y)))
                    if null == aimUnit or minimumRange > distance then
                        set aimUnit = s.slider
                        set minimumRange = distance
                    endif
                
                endif
                
                set s = s.next
            endloop
            
            if(aimUnit != null) then
                call SetUnitFacing(.u, Atan2(GetUnitY(aimUnit) - y, GetUnitX(aimUnit) - x)*bj_RADTODEG)
            endif
            
            set angle = GetUnitFacing(.u)*bj_DEGTORAD
            
            set terrainType = GetTerrainType(x, y)
            if Terrain[terrainType] == 0 then
                set offset = SPEED/TPS
            else
                set offset = (SPEED + Terrain[terrainType].speed)/TPS*Terrain[terrainType].factor
            endif
            
            set x = x + offset*Cos(angle)
            set y = y + offset*Sin(angle)
            
            if IsInBounds(x, y) then
                call SetUnitX(.u, x)
                call SetUnitY(.u, y)
                
                // Save all dead heroes in range
                set s = Slider.first
                loop
                    exitwhen s == 0
                    
                    if User[s.owner].team == .team and not UnitAlive(s.slider) then
                        
                        set distance = SquareRoot(((GetUnitX(s.slider) - x) * (GetUnitX(s.slider) - x)) + ((GetUnitY(s.slider) - y) * (GetUnitY(s.slider) - y)))
                        if  Respawn.COLLISION > distance then
                            call Respawn[s.owner].revive(.u)
                        endif
                    
                    endif
                    
                    set s = s.next
                endloop
            else
                call this.destroy()
                call KillUnit(this.u)
                set this.u = null
                set aimUnit = null
            endif
        
        endif
        set aimUnit = null
    implement CTLEnd
    
    private static method onCast takes nothing returns nothing
        local thistype this = create()
        local unit u = GetTriggerUnit()
        local real angle = GetUnitFacing(u)
        local real x = GetUnitX(u) + 50*Cos(angle)*bj_DEGTORAD
        local real y = GetUnitY(u) + 50*Sin(angle)*bj_DEGTORAD
        call Sound[LAUNCH_HOLYRA].play(GetUnitX(u), GetUnitY(u), 0, 200)
        set .u = CreateUnit(GetTriggerPlayer(), MISSLE_HOLYRA, x, y, angle)
        set .team = User[GetTriggerPlayer()].team
        set .time = 0
    endmethod
        
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(HOLYRA, function thistype.onCast)
    endmethod

endstruct
//TESH.scrollpos=37
//TESH.alwaysfold=0
struct Roots extends array

    private static constant real DURATION = 1.5
    private static constant real RANGE    = 500.

    Slider slider
    unit u
    real time
    effect sfx
    unit eff
    
    implement CTL
      
    implement CTLExpire
        
        // Loop body
        set this.time = this.time + INTERVAL
        if this.time >= DURATION  or not UnitAlive(u) then
            call this.destroy()
            set .slider.roots = false
            call SetUnitMoveSpeed(u, GetUnitDefaultMoveSpeed(.u))
            call KillUnit(.eff)
            set u = null
            set .eff = null
        endif
      
    implement CTLEnd
    
    private static method onCast takes nothing returns nothing
        local thistype this = 0
        local Slider s = Slider.first
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local Team team = User[GetTriggerPlayer()].team
        
        loop
            exitwhen s == 0
            
            if IsUnitInRange(s.slider, u, RANGE) and team !=  User[s.owner].team and UnitAlive(s.slider) then
                set this = create()
                set u = s.slider
                set x = GetUnitX(u)
                set y = GetUnitY(u)
                call Sound[ROOTSOUND].play(x, y, 0, 200)
                
                call SetUnitMoveSpeed(u, 0)
                set .eff = CreateUnit(GetTriggerPlayer(), NET_EFFECT, x, y, GetUnitFacing(u))
                
                set .u = u
                set s.roots = true
                set .slider = s
                set .time = 0
                exitwhen true
            endif
            
            set s = s.next
        endloop
        
        if this == 0 then
            call Sound[ERROR].play(x, y, 0, 200)
            call ApplyPendingTextTag(Slider[u], Color[12] + "No found|r", 8, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
        endif
        
        set u = null
    endmethod
        
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(NET, function thistype.onCast)
    endmethod

endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DisplayRange initializer Init
    
    globals
        private constant integer AMOUNT = 8
        private constant integer EFFECT = 'rang'
    endglobals

    private function onCast_on takes nothing returns nothing
        local real angle = 0
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local RangeData element = Slider[u].RangeList
        local player p = GetTriggerPlayer()
        local integer i = 1
        
        loop
            exitwhen i > AMOUNT
            
            set element = Slider[u].RangeList.enqueue()
            set element.angle = angle
            
            set element.u = CreateUnit(p, EFFECT, x + RangeData.OFFSET*Cos(angle), y + RangeData.OFFSET*Sin(angle), 0)
            
            if(LOCAL_PLAYER != p)then
                call ShowUnit(element.u, false)
            endif
            
            set angle = angle + bj_PI*2/AMOUNT
            set i = i + 1
        endloop
        call UnitRemoveAbility(u, RANGE_ON)
        call UnitAddAbility(u, RANGE_OFF)
        
        set Slider[u].showRange = true
        
        call ApplyPendingTextTag(Slider[u], Color[12] + "Range on|r", 8, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
        set u = null
    
    endfunction
    
    private function onCast_off takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local RangeData rangeElement = Slider[u].RangeList.first
        loop
            exitwhen 0 == rangeElement
            call KillUnit(rangeElement.u)
            set rangeElement.u = null
            set rangeElement = rangeElement.next
        endloop
        
        set Slider[u].showRange = false
        
        call Slider[u].RangeList.clear()
        call UnitRemoveAbility(u, RANGE_OFF)
        call UnitAddAbility(u, RANGE_ON)
        call ApplyPendingTextTag(Slider[u], Color[12] + "Range off|r", 9, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
        set u = null
    endfunction

    private function Init takes nothing returns nothing
        call RegisterSpellEffectEvent(RANGE_ON, function onCast_on)
        call RegisterSpellEffectEvent(RANGE_OFF, function onCast_off)
    endfunction
    
endscope
//TESH.scrollpos=18
//TESH.alwaysfold=0
scope FlagIndicator initializer Init
    
    globals
        constant integer FLAG_INDICATOR_ON  = 'FLAG'
        constant integer FLAG_INDICATOR_OFF = 'pOff'
    endglobals

    private function onCast_on takes nothing returns nothing
        
        local unit u = GetTriggerUnit()
        local player p = GetTriggerPlayer()
        
        if(LOCAL_PLAYER == p)then
            
            call ShowUnit(Slider[u].flagPointer_blue, true)
            call ShowUnit(Slider[u].flagPointer_red, true)
        endif
        
        set Slider[u].pointToFlag = true
        
        call UnitRemoveAbility(Slider[u].flagPointer_blue, 'Aloc')
        call UnitRemoveAbility(Slider[u].flagPointer_red, 'Aloc')
        call UnitAddAbility(Slider[u].flagPointer_blue, 'Aloc')
        call UnitAddAbility(Slider[u].flagPointer_red, 'Aloc')
        
        call UnitRemoveAbility(u, FLAG_INDICATOR_ON)
        call UnitAddAbility(u, FLAG_INDICATOR_OFF)
        call ApplyPendingTextTag(Slider[u], Color[12] + "Flags on|r", 8, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
        set u = null
    
    endfunction
    
    private function onCast_off takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local player p = GetTriggerPlayer()
        
        if(LOCAL_PLAYER == p)then
            call ShowUnit(Slider[u].flagPointer_blue, false)
            call ShowUnit(Slider[u].flagPointer_red, false)
        endif
        
        set Slider[u].pointToFlag = false
        
        call UnitRemoveAbility(u, FLAG_INDICATOR_OFF)
        call UnitAddAbility(u, FLAG_INDICATOR_ON)
        call ApplyPendingTextTag(Slider[u], Color[12] + "Flags off|r", 9, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
        set u = null
    endfunction

    private function Init takes nothing returns nothing
        call RegisterSpellEffectEvent(FLAG_INDICATOR_ON, function onCast_on)
        call RegisterSpellEffectEvent(FLAG_INDICATOR_OFF, function onCast_off)
    endfunction
    
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
struct ExplosiveEgg extends array
    
    private static constant real    DURATION    = 3.
    private static constant real    INTERVAL    = 0.05
    static constant real    COLLISION   = 70.
    private static constant real AOE = 260
    private static constant real DAMAGE = 150
    
    real time
    unit egg
    player owner
    
    method destroy takes nothing returns nothing
        set .egg = null
    endmethod
    
    private method unitFilter takes unit u returns boolean
        return IsUnitType(u, UNIT_TYPE_HERO) and UnitAlive(u) and User[GetOwningPlayer(u)].team != User[.owner].team/*
            */ and not Slider[u].jump/*
            */ and not Slider[u].cata
    endmethod
    
    
    method explode takes nothing returns nothing
        
        local real x = GetUnitX(.egg)
        local real y = GetUnitY(.egg)
        local unit fog
        call KillUnit(CreateUnit(.owner, ROCKET_EFFECT, x,  y, 0))

        call GroupEnumUnitsInRange(G, x, y, AOE, null)
        loop
            set fog = FirstOfGroup(G)
            exitwhen fog == null
            
            if (.unitFilter(fog) and .egg != fog) then
                call UnitDamageTarget(User[.owner].slider.slider, fog, DAMAGE, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_COLD, null)
            endif
            
            call GroupRemoveUnit(G, fog)
        endloop
    
        call KillUnit(.egg)
        call .destroy()
    endmethod
    
    private static method callback takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        
        local Slider s
        local real range
        set this.time = this.time + INTERVAL
        if(this.time >= DURATION  or not UnitAlive(this.egg)) then
            call this.explode()
            call ReleaseTimer(GetExpiredTimer())
        else
        
            set s = Slider.first
            loop
                exitwhen s == 0
                
                set range = SquareRoot((GetUnitX(s.slider) - GetUnitX(.egg))*(GetUnitX(s.slider) - GetUnitX(.egg)) + (GetUnitY(s.slider) - GetUnitY(.egg))*(GetUnitY(s.slider) - GetUnitY(.egg)))
                if range < COLLISION and unitFilter(s.slider) then
                    call ReleaseTimer(GetExpiredTimer())
                    call this.explode()
                    exitwhen true
                endif
                set s = s.next
            endloop
        endif
    endmethod
    
    static method operator [] takes unit u returns thistype
        return thistype(GetUnitUserData(u))
    endmethod
    
    private static method onCast_egg takes nothing returns nothing
       local thistype this = ExplosiveEgg[GetTriggerUnit()]
       local unit u = GetTriggerUnit()
       set .owner = GetTriggerPlayer()
       set .egg = CreateUnit(.owner, 'eggU', GetUnitX(u), GetUnitY(u), GetUnitFacing(u))
       set .time = 0
       call SetUnitVertexColor(.egg, User[.owner].team.r, User[.owner].team.g, User[.owner].team.b, 255)
       call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
       set u = null
    endmethod
    
    private static method onCast_explosion takes nothing returns nothing
        call thistype[GetTriggerUnit()].explode()
    endmethod
        
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(EXPLOSIVE_EGG, function thistype.onCast_egg)
        call RegisterSpellEffectEvent(EXPLOSION, function thistype.onCast_explosion)
    endmethod
endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0
struct CamLock extends array
    
    private static method onLock takes nothing returns nothing
       local unit u = GetTriggerUnit()
        call UnitRemoveAbility(u, CAM_LOCK)
        call UnitAddAbility(u, CAM_UNLOCK)
        if(LOCAL_PLAYER == GetTriggerPlayer())then
            call SetCameraTargetController(u, 0, 0, false)
        endif
        call ApplyPendingTextTag(Slider[u], Color[12] + "Lock|r", 4, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
        set u = null
    endmethod
    
    private static method onUnlock takes nothing returns nothing
        local unit u = GetTriggerUnit()
        call UnitRemoveAbility(u, CAM_UNLOCK)
        call UnitAddAbility(u, CAM_LOCK)
        if(LOCAL_PLAYER == GetTriggerPlayer())then
            call PanCameraTo(GetUnitX(u), GetUnitY(u))
        endif
         call ApplyPendingTextTag(Slider[u], Color[12] + "Unlock|r", 6, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
        set u = null
    endmethod
        
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(CAM_LOCK, function thistype.onLock)
        call RegisterSpellEffectEvent(CAM_UNLOCK, function thistype.onUnlock)
    endmethod
    
endstruct
//TESH.scrollpos=2
//TESH.alwaysfold=0
struct Wall extends array
    static constant real WALL_WIDTH = 50.
    private static integer counter = 0

    real xMin
    real yMin
    real xMax
    real yMax
    
    // sometimes missles can be very fast so a simple check if x/y is inside rect is not enough
    // since the rect is not very big. missle could just skip it within one tickrate
    
    // so we take original x/y and x/y to move to, and check if this line crosses the rect
    
    static method isInWall takes real x1, real y1, real x2, real y2 returns boolean
        local thistype this = counter
        local real xMin
        local real xMax
        local real yMin
        local real yMax
        
        if (x1 < x2)then
            set xMin = x1
            set xMax = x2
        else
            set xMin = x2
            set xMax = x1
        endif
        
        if (y1 < y2)then
            set yMin = y1
            set yMax = y2
        else
            set yMin = y2
            set yMax = y1
        endif
        
        loop
            exitwhen this == 0
                if (xMax > .xMin) and (xMin < .xMax) and (yMax > .yMin) and (yMin < .yMax) then
                    return true
                endif
            set this = this - 1
        endloop
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        local thistype this
        
        // always define the length of the wall of the bottom or the left side
        
        
        // Left base - start from bottom left
        set counter = counter + 1
        set this = counter
        set .xMin = -11445
        set .xMax = -11082
        set .yMin = 7300
        set .yMax = 7300 + WALL_WIDTH
        
        set counter = counter + 1
        set this = counter
        set .xMin = -11082 - WALL_WIDTH
        set .xMax = -11082
        set .yMin = 7300
        set .yMax = 7809
        
        set counter = counter + 1
        set this = counter
        set .xMin = -11082 - WALL_WIDTH
        set .xMax = -11082
        set .yMin = 8258
        set .yMax = 8760
        
        set counter = counter + 1
        set this = counter
        set .xMin = -11454
        set .xMax = -11082
        set .yMin = 8786 - WALL_WIDTH
        set .yMax = 8760
        
        // Middle
        set counter = counter + 1
        set this = counter
        set .xMin = -4849// -65
        set .xMax = -4849 + WALL_WIDTH// + 65
        set .yMin = 7816
        set .yMax = 8325
        
        set counter = counter + 1
        set this = counter
        set .xMin = -3634// - 65
        set .xMax = -3634 + WALL_WIDTH// + 65
        set .yMin = 7823
        set .yMax = 8340
        
        // Right base - start from bottom right
        set counter = counter + 1
        set this = counter
        set .xMin = 2631
        set .xMax = 3005
        set .yMin = 7305
        set .yMax = 7300 + WALL_WIDTH
        
        set counter = counter + 1
        set this = counter
        set .xMin = 2631
        set .xMax = 2631 + WALL_WIDTH
        set .yMin = 7305
        set .yMax = 7805
        
        set counter = counter + 1
        set this = counter
        set .xMin = 2631
        set .xMax = 2631 + WALL_WIDTH
        set .yMin = 8259
        set .yMax = 8761
        
        set counter = counter + 1
        set this = counter
        set .xMin = 2631
        set .xMax = 3005
        set .yMin = 8761 - WALL_WIDTH
        set .yMax = 8761
        
        set counter = counter + 1
        set this = counter
        set .xMin = -12319
        set .xMax = -12261
        set .yMin = 7037
        set .yMax = 9213
        
        set counter = counter + 1
        set this = counter
        set .xMin = 3940
        set .xMax = 3993
        set .yMin = 7104
        set .yMax = 9131
    
    endmethod
endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0
struct MagicWall extends array
    private static integer counter = 0

    real x1
    real y1
    real x2
    real y2
    
    static method isInWallRange takes unit u, real distance returns boolean
        local thistype this = counter
        
        local real x1 = GetUnitX(u)
        local real y1 = GetUnitY(u)
        local real angle = GetUnitFacing(u)*bj_DEGTORAD
        local real x2 = x1 + distance*Cos(angle)
        local real y2 = y1 + distance*Sin(angle)
        
        loop
            exitwhen this == 0
            
            if DoLinesIntersect(x1, y1, x2, y2, .x1, .y1, .x2, .y2) then
                return true
            endif
            
            set this = this - 1
        endloop
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        local thistype this
    
        set counter = counter + 1
        set this = counter
        set .x1 = -12290
        set .y1 = 6930
        set .x2 = -12291
        set .y2 = 9250
        
         set counter = counter + 1
        set this = counter
        set .x1 = 3960
        set .y1 = 6930
        set .x2 = 3961
        set .y2 = 9250
        
    endmethod
endstruct
//TESH.scrollpos=1
//TESH.alwaysfold=0
scope WeatherTest initializer Init
    globals
        private WeatherEffect WE
        private timer clock
    endglobals
    private function SwitchWeather takes nothing returns nothing
        local integer rand = GetRandomInt(0, 5)
        
        if(rand == 0)then
            set WE.style = WeatherStyle.NorthrendBlizzard
        elseif rand == 1 then
            set WE.style = WeatherStyle.NorthrendSnowHeavy
        elseif rand == 2 then
            set WE.style = WeatherStyle.NorthrendSnowLight
        elseif rand == 3 then
            set WE.style = WeatherStyle.RaysOfLight
        elseif rand == 4 then
            set WE.style = WeatherStyle.RaysOfMoonlight
        elseif rand == 5 then
            set WE.style = WeatherStyle.LordaeronRainHeavy
        endif

        call TimerStart(clock, GetRandomReal(80, 150), false, function SwitchWeather)
    endfunction
    
    private function foo takes nothing returns nothing
        set WE = WeatherEffect.create(bj_mapInitialPlayableArea, WeatherStyle.NorthrendBlizzard)
        call WE.enable()
        call TimerStart(clock, GetRandomReal(80, 150), false, function SwitchWeather)
    endfunction

    private function Init takes nothing returns nothing
        set clock = NewTimer()
        call TimerStart(clock, 0, false, function foo)
    endfunction
endscope
//TESH.scrollpos=33
//TESH.alwaysfold=0
scope WeaponPickUp
    
    // Config onInit

    struct WeaponPickUp extends array
        private static constant real INTERVAL = 0.075
        real x
        real y
        unit dummy
        real collision
        real mana
        real timeout
        Weapon weaponlist
        
        private method filter takes Slider s returns boolean
            return SquareRoot((GetUnitX(s.slider)-.x) * (GetUnitX(s.slider)-.x) + (GetUnitY(s.slider)-.y) * (GetUnitY(s.slider)-.y)) < .collision/*
                */ and not s.jump/*
                */ and not s.cata
        endmethod
        
        private static method timeoutFinish takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local thistype this = GetTimerData(t)
            call ShowUnit(.dummy, true)
            call UnitRemoveAbility(.dummy, 'Aloc')
            call UnitAddAbility(.dummy, 'Aloc')
            call SetUnitPathing(.dummy, false)
            call TimerStart(t, .INTERVAL, true, function thistype.callback)
        endmethod
        
        private static method callback takes nothing returns nothing
            local Slider s = Slider.first
            local timer t = GetExpiredTimer()
            local thistype this = GetTimerData(t)
    
            local Weapon weapon
            
            loop
                exitwhen null == s
                if(.filter(s))then
                
                    set weapon = .weaponlist.getRandomWeapon()
                
                    call ApplyStaticTextTag(s, Color[12] + "Weapon: |r" + GetObjectName(weapon.whichability), (7+StringLength(GetObjectName(weapon.whichability))), 3, 4, 120)
                    
                    call SetUnitMaxState(s.slider, UNIT_STATE_MAX_MANA, weapon.mana)
                    call CurrentShootAbility.apply(s.slider, weapon.whichability)
                    call SetUnitState(s.slider, UNIT_STATE_MANA, weapon.mana)
                    call ShowUnit(.dummy, false)
                    call TimerStart(t, .timeout, false, function thistype.timeoutFinish)
                    
                endif
                set s = s.next
            endloop
                
        endmethod
        
        implement AllocT
        static method create takes string modelpath, real scale, real x, real y, Weapon weaponlist, real collision, real mana, real timeout returns thistype
            local thistype this = allocate()
            set .x = x
            set .y = y
            set .collision = collision
            set .mana = mana
            set .timeout = timeout
            set .weaponlist = weaponlist
            set .dummy = GetRecycledDummy(x, y, 0, 90)
            call UnitAddAbility(.dummy, 'Aloc')
            call SetUnitPathing(.dummy, false)
            call AddSpecialEffectTarget(modelpath, .dummy, "origin")
            call SetUnitScale(.dummy, scale, 1, 1)
            call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
            return this
        endmethod
        
        // CONFIG
        private static method init takes nothing returns nothing
           
            // Rocket in center
            call create(SECRET_ITEM_MODELPATH, SCALE_SECRET_ITEM, CENTER_X, CENTER_Y, Weapon.WEAPON_LIST_1, 105, 10, 45)
            
        endmethod
        
        implement InitTimer
    endstruct
endscope
//TESH.scrollpos=69
//TESH.alwaysfold=0
struct Weapon extends array
    
    implement List
    integer whichability
    real whichChance
    integer mana
    
    // weapon lists
    // each list can have multiple weapons (abilities)
    static thistype WEAPON_LIST_1
    static thistype WEAPON_LIST_2
    static thistype WEAPON_LIST_3
    static thistype WEAPON_LIST_4
    static thistype WEAPON_LIST_5
    
    method getRandomWeapon takes nothing returns thistype
    
        local thistype node
        local real rand = GetRandomReal(0, 100)
    
        local real currentLowestChance
        local thistype array currentWeapon
        local integer index = -1
         
        set node = .first
        set currentLowestChance = 101
        
        loop
             
            exitwhen node == 0
            
            if (rand <= node.whichChance) then
                
                if(node.whichChance < currentLowestChance and node.whichChance > 0)then
                    
                    // A weapon with new lowest chance has qualified, empty array
                    set index = 0
                    set currentWeapon[index] = node
                    set currentLowestChance = node.whichChance
                    
                elseif (node.whichChance == currentLowestChance) then
                
                    // A weapon with same chance has qualified, add to array
                    set index = index + 1
                    set currentWeapon[index] = node
                    set currentLowestChance = node.whichChance
                    
                endif
                
            endif
            set node = node.next
        endloop
        
        // no weapon had qualified, just take the one now with highest chance
        
        if(index == -1)then
    
            set node = .first
            set currentLowestChance = 0
            loop
                exitwhen node == 0
                    
                if(node.whichChance > currentLowestChance)then
                    
                    set index = 0
                    set currentWeapon[index] = node
                    set currentLowestChance = node.whichChance
                elseif (node.whichChance == currentLowestChance and currentLowestChance > 0) then
                
                    // A weapon with same chance has qualified, add to array
                    set index = index + 1
                    set currentWeapon[index] = node
                    set currentLowestChance = node.whichChance
                endif
                    
                set node = node.next
            endloop
        
        endif
        
        if (index > -1) and (currentLowestChance > 0) then
            set index = GetRandomInt(0, index)
            return currentWeapon[index]
        endif
        
        return 0
    endmethod

    private static method init takes nothing returns nothing
        local thistype this
        local thistype node
        
        // All weapons from a list must give together 100 (%) for correct result.
        set WEAPON_LIST_1 = create()
        set this = WEAPON_LIST_1
        set node = .push()
        set node.whichability = ROCKET
        set node.whichChance = 100.
        set node.mana = 10
    endmethod
    
    implement Init

endstruct
//TESH.scrollpos=22
//TESH.alwaysfold=0
library TextHandler uses Default
    
    // for charCount
    globals
        private real xRate = 100/13
    endglobals
            
    // if .t is set to null it means for sliding system the node can be removed
    private function callback takes nothing returns nothing
        local TextData element = GetTimerData(GetExpiredTimer())
        set element.t = null
        call ReleaseTimer(GetExpiredTimer())
    endfunction
    
    //Pending means it has x/y velocity.
    
    // charCount is used so textags are a bit fixed to appear in middle above car, and not next to
    
    function ApplyPendingTextTag takes Slider s, string text, integer charCount, real fp, real lt, real z, real speed, real angle returns texttag
        local texttag t =  CreateTextTag()
        local real offset = speed*0.071/128
        local real xVel   = offset * Cos(angle*bj_DEGTORAD)
        local real yVel   = offset * Sin(angle*bj_DEGTORAD)
        
        local TextData td
        call SetTextTagText(t, text, .023)
        call SetTextTagColor(t, 255, 255, 255, 255)
        call SetTextTagVelocity(t,xVel, yVel)
        call SetTextTagPermanent(t, false)
        call SetTextTagFadepoint(t, fp)
        call SetTextTagLifespan(t, lt)
        set td = s.newText(t,z)
        set td.x = charCount*xRate
        call TimerStart(NewTimerEx(td), lt, false, function callback)
        return t
    endfunction
    
    function ApplyStaticTextTag takes Slider s, string text, integer charCount, real fp, real lt, real z returns texttag
        local texttag t =  CreateTextTag()
        local TextData td
        call SetTextTagText(t, text, .023)
        call SetTextTagColor(t, 255, 255, 255, 255)
        call SetTextTagPermanent(t, false)
        call SetTextTagFadepoint(t, fp)
        call SetTextTagLifespan(t, lt)
        set td = s.newText(t,z)
        set td.x = charCount*xRate
        call TimerStart(NewTimerEx(td), lt, false, function callback)
        return t
    endfunction
    
    function ApplyErrorTextTag takes Slider s returns nothing
        call ApplyPendingTextTag(s, Color[12] + "Error|r", 5, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
        call Sound[ERROR].play(GetUnitX(s.slider), GetUnitY(s.slider), 0, 200)
    endfunction

endlibrary
//TESH.scrollpos=48
//TESH.alwaysfold=0
library DialogSystem initializer Init uses GameHandler
    globals
        dialog dialog_car
        dialog dialog_score
        dialog dialog_pickmode
        // 8 for cars
        // 3 for score
        // 2 for pick mode
        private button array b[12]
        
        private trigger trigger_car = CreateTrigger()
        private trigger trigger_score = CreateTrigger()
        private trigger trigger_pickmode = CreateTrigger()
    endglobals
    
    private function onClick_car takes nothing returns nothing
        local integer i =  LoadInteger(HASH, GetHandleId(GetClickedButton()), 0)
        if i != 0 then
            call NewSlider(GetTriggerPlayer(), i)
        else
            call NewRandomSlider(GetTriggerPlayer())
        endif
    endfunction
    
    private function NewButton_car takes dialog d, integer unitType returns nothing
        local integer counter = LoadInteger(HASH, GetHandleId(d), 0)
        call SaveInteger(HASH, GetHandleId(d), 0, counter + 1)
        set b[counter] = DialogAddButton(d, GetObjectName(unitType), 0)
        call SaveInteger(HASH, GetHandleId(b[counter]), 0, unitType)
    endfunction
    
    
    private function onClick_score takes nothing returns nothing
        call SetMaxScore(LoadInteger(HASH, GetHandleId(GetClickedButton()), 0))
        call ScoreModeDialog_End()
    endfunction
    
    private function NewButton_score takes dialog d, string s returns nothing
        local integer counter = LoadInteger(HASH, GetHandleId(d), 0)
        call SaveInteger(HASH, GetHandleId(d), 0, counter + 1)
        set b[counter] = DialogAddButton(d, s, 0)
        call SaveInteger(HASH, GetHandleId(b[counter]), 0, S2I(s))
    endfunction
    
    private function onClick_pickmode takes nothing returns nothing
        call SetPickMode(LoadStr(HASH, GetHandleId(GetClickedButton()), 0))
        call PickModeDialog_End()
    endfunction
    
    private function NewButton_pickmode takes dialog d, string s returns nothing
        local integer counter = LoadInteger(HASH, GetHandleId(d), 0)
        call SaveInteger(HASH, GetHandleId(d), 0, counter + 1)
        set b[counter] = DialogAddButton(d, s, 0)
        call SaveStr(HASH, GetHandleId(b[counter]), 0, s)
    endfunction
    
    private function Setup takes nothing returns nothing
        
        local integer i = 1
    
        set dialog_car = DialogCreate()
        call TriggerRegisterDialogEvent(trigger_car, dialog_car)
        call TriggerAddAction(trigger_car, function onClick_car)
        call DialogSetMessage(dialog_car, "Choose a vehicle")
        loop
            exitwhen i > Hero.counter
            call NewButton_car(dialog_car, Hero(i).unittypeId)
            set i = i + 1
        endloop
        call DialogAddButton(dialog_car, "<Random>", 0)
        
        set dialog_score = DialogCreate()
        call TriggerRegisterDialogEvent(trigger_score, dialog_score)
        call TriggerAddAction(trigger_score, function onClick_score)
        call DialogSetMessage(dialog_score, "Score Limit")
        call NewButton_score(dialog_score, "1")
        call NewButton_score(dialog_score, "3")
        call NewButton_score(dialog_score, "5")
        
        set dialog_pickmode = DialogCreate()
        call TriggerRegisterDialogEvent(trigger_pickmode, dialog_pickmode)
        call TriggerAddAction(trigger_pickmode, function onClick_pickmode)
        call DialogSetMessage(dialog_pickmode, "Pick Mode")
        call NewButton_pickmode(dialog_pickmode, "Pick")
        call NewButton_pickmode(dialog_pickmode, "Random")
        
        
        call ReleaseTimer(GetExpiredTimer())
    endfunction
        
    private function Init takes nothing returns nothing
        call TimerStart(NewTimer(), 0, false, function Setup)
    endfunction
endlibrary
//TESH.scrollpos=198
//TESH.alwaysfold=0
scope Catapult

    // Config onInit

    globals
        private constant integer CATA_ID         = 'cata'
        private constant integer AIM_ID          = 'n000'
        private constant real    SPEED           = DEFAULT_SPEED*2.4
        private constant real    HEIGHT_MINIMUM  = 400
        private constant real    RANGE           = 130  // collision with cata
        private constant real    TIMEOUT         = 0.1  // interval for collision checl
    endglobals

    struct CatapultShot extends array
        
        static constant real TURN_TIME_MAX = 0.3
        
        Catapult cata
        Slider slider
        real travel_current
        real height
        integer stage
        real time
        
        implement CTL
            // Loop locals
            
            local real x
            local real y
            local real z
        implement CTLExpire
            
            // Loop body
            if (.stage == 1) then
                set .time = .time + INTERVAL
                call SetUnitFacing(slider.slider, cata.angle)
                if .time >= TURN_TIME_MAX then
                    set .stage = 2
                    set this.cata.enabled = true
                    call SetUnitAnimation( this.cata.cata, "attack" )
                endif
                
            elseif (.stage == 2) then
                set x = GetUnitX(this.slider.slider)
                set y = GetUnitY(this.slider.slider)
                set this.travel_current = this.travel_current + SPEED/TPS
                call SetUnitFlyHeight(this.slider.slider, ParabolaZ(this.cata.height_max, this.cata.travel_max, this.travel_current), 0)
                call SetUnitX(this.slider.slider, x + (SPEED/TPS) * .cata.cos)
                call SetUnitY(this.slider.slider, y + (SPEED/TPS) * .cata.sin)
                if(this.travel_current >= this.cata.travel_max  or not UnitAlive(this.slider.slider)) then
                    call this.destroy()
                    call SetUnitFlyHeight(this.slider.slider, 0, 0)
                    set this.slider.cata = false
                    call SuspendUnit(this.slider.slider, false)
                endif
            
            endif
                
            if(.slider.flag != 0)then
                call .slider.flag.updatePosition()
            endif
            
        implement CTLEnd
        
        
        static method apply takes Catapult c, Slider s returns nothing
            local thistype this = create()
            call SetUnitPosition(s.slider, c.x1, c.y1)
            call SuspendUnit(s.slider, true)
            set .cata = c
            set .slider = s
            set .travel_current = 0
            set .time = 0
            set .height = 0
            set .stage = 1
            set c.enabled = false
            set s.cata    = true
        endmethod
    
    endstruct

    struct Catapult extends array
        
        private static timer clock = CreateTimer()
        private static trigger t = CreateTrigger()
        
        real travel_max
        boolean enabled
        real height_max
        real x1
        real y1
        real x2
        real y2
        real angle
        real cos
        real sin
        unit cata
        unit aim
        
        private static method callback takes nothing returns nothing
            local thistype this = GetTimerData(GetExpiredTimer())
            local Slider slider = Slider.first
            local real x
            local real y
            loop
                exitwhen slider == 0
                set x = GetUnitX(slider.slider)
                set y = GetUnitY(slider.slider)
                if this.enabled and slider.enabled and not slider.jump and not slider.cata and /*
                */  SquareRoot((x-x1)*(x-x1) + (y-y1)*(y-y1)) < RANGE then
    
                    call CatapultShot.apply(this, slider)
                    return
                endif
                set slider = slider.next
            endloop
        endmethod
        
        implement AllocT
        private static method create takes real x1, real y1, real x2, real y2 returns thistype
            local thistype this = allocate()
            set .angle = Atan2(y2 - y1, x2 - x1)*bj_RADTODEG
            set .cos = Cos(.angle*bj_DEGTORAD)
            set .sin = Sin(.angle*bj_DEGTORAD)
            set .cata = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), CATA_ID, x1, y1, .angle)
            call SetUnitPathing(.cata, false)
            set .aim = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), AIM_ID, x2, y2, 0)
            call SetUnitPathing(.aim, false)
            set .x1 = x1
            set .y1 = y1
            set .x2 = x2
            set .y2 = y2
            set .travel_max = SquareRoot((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
            set .height_max = RMaxBJ(HEIGHT_MINIMUM, HEIGHT_MINIMUM + (.travel_max-1000)/150*10)
            set .enabled = true
            call TimerStart(NewTimerEx(this), TIMEOUT, true, function thistype.callback)
            return this
        endmethod
        
        // x1 for cata
        // y1 for cata
        
        // x2 for aim
        // y2 for aim
        private static method onInit takes nothing returns nothing
            local real x1
            local real y1
            local real x2
            local real y2
            
            // ==== Left Catas ====
            
            
            // Base to top-left
            set x1 = -11725
            set y1 = 9040
            set x2 = -14661
            set y2 = 13635
            call create(x1, y1, x2, y2)
            
            // Base to bottom
            set x1 = -11725
            set y1 = 7125
            set x2 = -10314
            set y2 = 2073
            call create(x1, y1, x2, y2)
            
            // Top - down/right
            set x1 = -13060
            set y1 = 14611
            set x2 = -8628
            set y2 = 11867
            call create(x1, y1, x2, y2)
            
            
            // ==== Middle Catas ====
            
            
            // Top Left to Top middle
            set x1 = -6619
            set y1 = 13044
            set x2 = -5635
            set y2 = 13046
            call create(x1, y1, x2, y2)
            
            // Top - to bottom
            set x1 = -4420
            set y1 = 11150
            set x2 = -3000
            set y2 = 4220
            call create(x1, y1, x2, y2)
            
            // Bottom - to top
            set x1 = -4420
            set y1 = 4900
            set x2 = -5720
            set y2 = 11890
            call create(x1, y1, x2, y2)
            
            // Right Bottom - to Middle Bottom
            set x1 = -2025
            set y1 = 2950
            set x2 = -3085
            set y2 = 2935
            call create(x1, y1, x2, y2)
            
            
            // ==== Right Catas ====
            
            
            // Base to bottom
            set x1 = 3160
            set y1 = 7120
            set x2 = 6590
            set y2 = 2900
            call create(x1, y1, x2, y2)
            
            // bottom - middle/left
            set x1 = 5243
            set y1 = 1950
            set x2 = 229
            set y2 = 4700
            call create(x1, y1, x2, y2)
            
            // bottom - middle/left
            set x1 = 3160
            set y1 = 9040
            set x2 = 1770
            set y2 = 14335
            call create(x1, y1, x2, y2)
        endmethod
    endstruct
endscope
//TESH.scrollpos=63
//TESH.alwaysfold=0
struct Teleport

    real x_enter
    real y_enter
    
    real x_leave
    real y_leave
    
    unit e_unit
    
    real angle
    
    real range
    
    integer block
    boolean array blocked[11]
    
    private static constant real INTERVAL  = 0.075
    private static constant real INTERVAL_TURN = 6
    boolean turn_right
    readonly static integer counter = 0
    
    private static method enableMessage takes nothing returns nothing
        local timer clock = GetExpiredTimer()
        set thistype(LoadInteger(HASH, GetHandleId(clock), 0)).blocked[LoadInteger(HASH, GetHandleId(clock), 1)] = false
        call ReleaseTimer(clock)
    endmethod
    
    method isUnitInRange takes unit u returns boolean
        return IsUnitInRangeXY(u, .x_enter, .y_enter, .range) /*
            */ and not Slider[u].jump/*
            */ and not Slider[u].cata
    endmethod
    
    private static method callback takes nothing returns nothing
        local Slider s = Slider.first
        local timer t
        local thistype this = GetTimerData(GetExpiredTimer())
        loop
            exitwhen s == null
            if .isUnitInRange(s.slider)then
                if User[s.owner].team != .block then
                    if(s.flag == 0)then
                        call SetUnitPosition(s.slider, x_leave, y_leave)
                        call SetUnitFacing(s.slider, .angle)
                        if GetUnitAbilityLevel(s.slider, CAM_LOCK) > 0 and s.owner == LOCAL_PLAYER then
                            call PanCameraToTimed(x_leave, y_leave, 0)
                        endif
                    elseif not .blocked[GetPlayerId(s.owner)] then 
                        set t = NewTimer()
                        //call PrintTo(s.owner, Color[9] + "Not allowed to enter with flag.", 5)
                        call ApplyPendingTextTag(s, Color[0] + "Not allowed with flag|r", 20, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
                        call Sound[ERROR].play(GetUnitX(s.slider), GetUnitY(s.slider), 0, 200)
                        call SaveInteger(HASH, GetHandleId(t), 0, this)
                        call SaveInteger(HASH, GetHandleId(t), 1, GetPlayerId(s.owner))
                        set .blocked[GetPlayerId(s.owner)] = true
                        call TimerStart(t, 3, false, function thistype.enableMessage)
                    endif
                elseif not .blocked[GetPlayerId(s.owner)] then
                    set t = NewTimer()
                    //call PrintTo(s.owner, Color[9] + "Not allowed to enter.", 5)
                    call ApplyPendingTextTag(s, Color[0] + "Not allowed|r", 11, 1, 2, 0, 100, GetRandomReal(90-15, 90+15))
                    call Sound[ERROR].play(GetUnitX(s.slider), GetUnitY(s.slider), 0, 200)
                    call SaveInteger(HASH, GetHandleId(t), 0, this)
                    call SaveInteger(HASH, GetHandleId(t), 1, GetPlayerId(s.owner))
                    set .blocked[GetPlayerId(s.owner)] = true
                    call TimerStart(t, 3, false, function thistype.enableMessage)
                endif
            endif
            set s = s.next
        endloop
    endmethod
    
    private static method callback_turn takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        if .turn_right then
            call SetUnitFacingTimed(.e_unit, GetUnitFacing(.e_unit)+179, 2)
        else
            call SetUnitFacingTimed(.e_unit, GetUnitFacing(.e_unit)+181, 2)
        endif
        set .turn_right = not .turn_right
    endmethod
    
    private static method onInit takes nothing returns nothing
        local thistype this
        /*
            LEFT SIDE
        */
        
        // Spawn - Flag
        set counter = counter + 1
        set this = counter
        set .x_enter = -12100
        set .y_enter = 8150
        set .x_leave = -15970+240
        set .y_leave = 8230
        set .angle = 0
        set .range = 140
        set .block = Team.RED
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
        
        
        // Flag - Spawn
        set counter = counter + 1
        set this = counter
        set .x_enter = -15970
        set .y_enter = 8230
        set .x_leave = -12100+240
        set .y_leave = 8150
        set .angle = 0
        set .range = 140
        set .block = Team.RED
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
        // Spawn - Bottom
        set counter = counter + 1
        set this = counter
        set .x_enter = -9973
        set .y_enter = 7086
        set .x_leave = -4547
        set .y_leave = 1783
        set .angle = 90
        set .range = 110
        set .block = 0
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
         // Spawn - Top
        set counter = counter + 1
        set this = counter
        set .x_enter = -9973
        set .y_enter = 9054
        set .x_leave = -4301
        set .y_leave = 14242
        set .angle = 270
        set .range = 110
        set .block = 0
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
         // Left - Right
        set counter = counter + 1
        set this = counter
        set .x_enter = -11526
        set .y_enter = 4874
        set .x_leave = 4370
        set .y_leave = 13730
        set .angle = 90
        set .range = 110
        set .block = 0
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
        
        /*
            RIGHT SIDE
        */
        
        // Spawn - Flag
        set counter = counter + 1
        set this = counter
        set .x_enter = 3765
        set .y_enter = 8145
        set .x_leave = 7636
        set .y_leave = 8304
        set .angle = 180
        set .range = 160
        set .block = Team.BLUE
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
        // Flag - Spawn
        set counter = counter + 1
        set this = counter
        set .x_enter = 7636+240
        set .y_enter = 8230
        set .x_leave = 3765-240
        set .y_leave = 8145
        set .angle = 180
        set .range = 160
        set .block = Team.BLUE
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
        // Spawn - Bottom
        set counter = counter + 1
        set this = counter
        set .x_enter = 1480
        set .y_enter = 7200
        set .x_leave = -4547
        set .y_leave = 1783
        set .angle = 90
        set .range = 110
        set .block = 0
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
         // Spawn - Top
        set counter = counter + 1
        set this = counter
        set .x_enter = 1480
        set .y_enter = 9170
        set .x_leave = -4301
        set .y_leave = 14242
        set .angle = 270
        set .range = 110
        set .block = 0
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
         // Right - Left
        set counter = counter + 1
        set this = counter
        set .x_enter = 3193
        set .y_enter = 11276
        set .x_leave = -12787
        set .y_leave = 2372
        set .angle = 270
        set .range = 110
        set .block = 0
        set .e_unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'tele', x_enter, y_enter, 0)
        call TimerStart(NewTimerEx(this), INTERVAL, true, function thistype.callback)
        call TimerStart(NewTimerEx(this), INTERVAL_TURN, true, function thistype.callback_turn)
        
    endmethod

endstruct
//TESH.scrollpos=62
//TESH.alwaysfold=0
struct Board extends array

    static Multiboard Board
    static integer array playerRow
    
    static method update takes player p returns nothing
        local integer row = playerRow[GetPlayerId(p)]
        set Board[row][0].text = GetPlayerName(p) + "|r (" + I2S(KD[p].streak_current) + ")"
        set Board[row][1].text = I2S(KD[p].kills)
        set Board[row][2].text = I2S(KD[p].deaths)
        set Board[row][3].text = R2S(KD[p].kd)
        if User[p].slider != 0 then
            set Board[row][0].icon = Hero.table.string[GetUnitTypeId(User[p].slider.slider)]
        else
            set Board[row][0].icon = "UI\\Minimap\\MinimapIconCreepLoc2.blp"
        endif
    endmethod

    static method NewBoard takes nothing returns nothing
    
        local integer i = 0
        local integer currentRow
        local player p
        
        if Board != 0 then
            call Board.destroy()
        endif
        
        set Board = Multiboard.create(PlayerTools.user_Amount + 6, 4)
        set Board.title = "Stats Board"
        
        call Board.setStyle(true, false)
        call Board.column[0].setStyle(true, true)
        call Board[0][0].setStyle(true, false)
        call Board[1][0].setStyle(true, false)
        call Board[Team.BLUE.count + 3][0].setStyle(true, false)
        call Board[PlayerTools.user_Amount + 4][0].setStyle(true, false)
        call Board[PlayerTools.user_Amount + 5][0].setStyle(true, false)
        
        set Board.Board[PlayerTools.user_Amount + 5][0].text = "|cffffffccGametime:|r " + Gametime.toString()
        set Board.Board[PlayerTools.user_Amount + 5][1].text = "|cffffffccESC to switch Boards|r"
        
        
        set Board.column[0].width = 0.132
        set Board.column[1].width = 0.03
        set Board.column[2].width = 0.04
        set Board.column[3].width = 0.035
        
        set Board[PlayerTools.user_Amount + 5][0].width = 0.11
        set Board[PlayerTools.user_Amount + 5][1].width = 0. //0.12
        set Board[PlayerTools.user_Amount + 5][2].width = 0
        set Board[PlayerTools.user_Amount + 5][3].width = 0
        
        set Board[0][0].text = Color[13] + "Player (streak)"
        set Board[0][1].text = Color[13] + "Kills"
        set Board[0][2].text = Color[13] + "Deaths"
        set Board[0][3].text = Color[13] + "KD"
        
        set Board[1][0].text = Color[1] + "Blue Team"
        call Board[1][0].setStyle(true, false)
        set Board[Team.BLUE.count + 3][0].text = Color[0] + "Red Team"
        
        set currentRow = 1
        set i = 0
    
        loop
            exitwhen i > Team.BLUE.count
            set currentRow = currentRow + 1
            set p = Team.BLUE.user[i]
            set playerRow[GetPlayerId(p)] = currentRow
            call update(p)
          
            set i = i + 1
        endloop
        
        set currentRow = Team[Team.BLUE].count + 3
        set i = 0
        
        loop
            exitwhen i > Team.RED.count
            set currentRow = currentRow + 1
            set p = Team.RED.user[i]
            set playerRow[GetPlayerId(p)] = currentRow
            call update(p)
            set i = i + 1
        endloop
        
        set Board.display = true
        set Board.minimize = false
        
        //set BoardSwitch.switch = true
        
        call ReleaseTimer(GetExpiredTimer())
    endmethod
    private static method onInit takes nothing returns nothing
        set Board = 0
        call TimerStart(NewTimer(),1.8 ,false,function thistype.NewBoard)
    endmethod
endstruct
//TESH.scrollpos=14
//TESH.alwaysfold=0
struct BoardLocal extends array

    static Multiboard Board
    static integer array playerRow
    
    private static method load takes player p returns nothing
        local integer kills
        local integer deaths
        local real kd
        local integer streak
        local integer scores
        local integer row = playerRow[GetPlayerId(p)]
      
        set kills = KD[p].kills_loaded
        set deaths = KD[p].deaths_loaded
        set streak = KD[p].streak_loaded
        set scores = KD[p].score_loaded
        
        if deaths > 0 then
            set kd = I2R(kills/deaths)
        else
            set kd = I2R(kills)
        endif
        
        set Board[row][0].text = GetPlayerName(p)
        set Board[row][1].text = I2S(scores)
        set Board[row][2].text = I2S(streak)
        set Board[row][3].text = I2S(kills)
        set Board[row][4].text = I2S(deaths)
        set Board[row][5].text = R2S(kd)
    
    endmethod

    static method NewBoard takes nothing returns nothing
    
        local integer i = 0
        local integer currentRow
        local player p
        
        set Board = Multiboard.create(PlayerTools.user_Amount + 4, 6)
        set Board.title = "Stats Board (loaded)"
        
        call Board.setStyle(true, false)
        
        set Board.column[0].width = 0.11
        
        set Board.column[1].width = 0.04
        set Board.column[2].width = 0.04
        set Board.column[3].width = 0.03
        set Board.column[4].width = 0.04
        set Board.column[5].width = 0.035
        
        set Board[0][0].text = Color[13] + "Player"
        set Board[0][1].text = Color[13] + "Scores"
        set Board[0][2].text = Color[13] + "Streak"
        set Board[0][3].text = Color[13] + "Kills"
        set Board[0][4].text = Color[13] + "Deaths"
        set Board[0][5].text = Color[13] + "KD"
        
        set currentRow = 1
        set i = 0
        loop
            exitwhen i > PlayerTools.user_Amount
            set currentRow = currentRow + 1
            set p = PlayerTools.user[i]
            set playerRow[GetPlayerId(p)] = currentRow
            call load(p)
            
            if LOCAL_PLAYER == PlayerTools.user[i] then
            
                if File.enabled and IS_GAME_ONLINE then
                    set Board.row.count = Board.row.count + 1
                    set Board[Board.row.count-1][0].width = 0.3
                    set Board[Board.row.count-1][0].text = "Status: |r" + Color[6] + "enabled"
                else
                    if File.enabled then
                        set Board.row.count = Board.row.count + 2
                        set Board[Board.row.count-2][0].width = 0.3
                        set Board[Board.row.count-1][0].width = 0.3
                        set Board[Board.row.count-2][0].text = "Status: |r" + Color[6] + "enabled"
                        set Board[Board.row.count-1][0].text = Color[4] + "Warning: |r Saving data is not allowed in SinglePlayer mode."
                    else
                        set Board.row.count = Board.row.count + 4
                        set Board[Board.row.count-1][0].width = 0.3
                        set Board[Board.row.count-2][0].width = 0.3
                        set Board[Board.row.count-3][0].width = 0.3
                        set Board[Board.row.count-4][0].width = 0.3
                        set Board[Board.row.count-4][0].text = "Status: |r" + Color[0] + "disabled"
                        set Board[Board.row.count-3][0].text = Color[4] + "Warning: |r You need to enable LocalFiles to use Save/Load."
                        set Board[Board.row.count-2][0].text = "You can use following map to enable LocalFiles:"
                        set Board[Board.row.count-1][0].text = Color[13] + "www.epicwar.com/maps/263738"
                    endif
                endif
            
            endif
            
            set i = i + 1
        endloop
        
        set Board.display = false
        call ReleaseTimer(GetExpiredTimer())
    endmethod
    
    private static method onInit takes nothing returns nothing
        call TimerStart(NewTimer(),3,false,function thistype.NewBoard)
    endmethod
    
endstruct
//TESH.scrollpos=2
//TESH.alwaysfold=0
struct BoardSwitch extends array

    static integer state = 0
    static boolean switch = false
    
    private static method onSwitch takes nothing returns nothing
        
        /*
        if switch and LOCAL_PLAYER == GetTriggerPlayer() then
        
            set state = state + 1
            
            if state == 1 then
                set Board.Board.display = false
                set BoardLocal.Board.display = true
            elseif state == 2 then
                set BoardLocal.Board.display = false
                set Board.Board.display = true
                set state = 0
            endif
            
        endif
        */
    endmethod
    
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        loop
            exitwhen i > 11
            call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_END_CINEMATIC)
            set i = i + 1
        endloop
        call TriggerAddAction(t, function thistype.onSwitch)
    endmethod

endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0
struct BoFData extends array

    static constant string MAP_NAME = "Battle of Flags v2.0"
    static constant string FILE_NAME = "Statistics"
    static constant integer MAX_VALUE = 100000
    
    static method LoadFinish takes nothing returns nothing
        local SyncData data = GetSyncedData()
        local player p = data.from
        local string s = ""
        local integer i = 0
        local Savecode loadcode
        
        set s = data.readString(0)
        call data.destroy()
        
        set loadcode = Savecode.create()
        if not loadcode.Load(p, s, 1) then
            if (s != "") then
                call DisplayTextToPlayer(p, 0 , 0, "Your stats code is invalid: " + s)
            endif
            return
        endif
        
        // data needs to be decoded
        // note that if you decode multiple bits of data, the given order will be reversed.
        // the first encoded data will be the last data to decode
        
        set KD[p].deaths_loaded = loadcode.Decode(MAX_VALUE)
        set KD[p].kills_loaded = loadcode.Decode(MAX_VALUE)
        set KD[p].streak_loaded = loadcode.Decode(MAX_VALUE)
        set KD[p].score_loaded = loadcode.Decode(MAX_VALUE)
        
    endmethod

    static method Load takes player p returns boolean
    
        local File f
        local string line = ""
        local string s = ""
        local integer i = 0
        local SyncData data
    
        if (GetLocalPlayer() == p) then
            
            set f = File.open(MAP_NAME, FILE_NAME, File.Flag.READ)
            set s = f.read()
                
            if (s == null or StringLength(s) <= 0) then
                //call DisplayTextToPlayer(p, 0, 0, "File is empty or was not found.")
                call f.close()
                return false
            else
                // Loop and get all lines from file
                loop
                    set line = f.read()
                    exitwhen null == line
                    set s = s + line
                    set i = i + 1
                endloop
                call f.close()
            endif
        endif
        
        // Local data exists, so it must be synced now
        set data = SyncData.create(p)
        call data.addString(s, 64)
        call data.addEventListener(function thistype.LoadFinish)
        call data.start()
        
        return true
        
    endmethod
    
    static method Save takes player p returns nothing
        
        local File f
        local string s
        local Savecode savecode
        local integer i = 0
        
        // Open local file
        if (GetLocalPlayer() == p) then
             set f = File.open(MAP_NAME, FILE_NAME, File.Flag.WRITE)
        endif
        
        // encode all values
        set savecode = Savecode.create()
        
        call savecode.Encode(KD[p].score + KD[p].score_loaded, MAX_VALUE)
        set i = IMaxBJ(KD[p].streak_max, KD[p].streak_loaded)
        call savecode.Encode(i, MAX_VALUE)
        call savecode.Encode(KD[p].kills + KD[p].kills_loaded, MAX_VALUE)
        call savecode.Encode(KD[p].deaths + KD[p].deaths_loaded, MAX_VALUE)
        
        // Give s the encoded data
        set s = savecode.Save(p, 1)
        
        // Insert s to local file
        if (GetLocalPlayer() == p) then
            call f.write(s)
            call f.close()
        endif
        
    endmethod
    
    // File.enabled can't be used onInit
    private static method init takes nothing returns nothing
        local integer i = 0
        loop
            call Load(Player(i))
            set i = i + 1
            exitwhen i > 11
        endloop
        call ReleaseTimer(GetExpiredTimer())
    endmethod
    
    private static method onInit takes nothing returns nothing
        call TimerStart(NewTimer(), 0., false, function thistype.init)
    endmethod

endstruct
//TESH.scrollpos=51
//TESH.alwaysfold=0
library AbilityPreload
//===========================================================================
// Information:
//==============
//
//      Preloading removes the noticeable delay the first time an ability
//  is loaded in a game. If an ability was not already on a pre-placed unit
//  or a unit that was created during initialization, preloading is needed
//  to prevent a delay.
//
//===========================================================================
// AbilityPreload API:
//=====================
//
//  AbilityPreload(abilityid) :
//        Call this before any time has elapsed to preload a specific
//     ability. If debug mode is enabled, you will see an error message
//     if you call this after initialization, or if you try to preload
//     an ability that does not exist. Will inline to a UnitAddAbility
//     call if debug mode is disabled.
//
//  AbilityRangePreload(start, end) :
//        Same as AbilityPreload, but preloads a range of abilities.
//      It will iterates between the two rawcode values and preload
//      every ability along the way. It will not show an error message
//      for non-existent abilities.
// 
//===========================================================================
// Configuration:
//================

globals
    private constant integer PreloadUnitRawcode = 'zsmc'
    //This is the rawcode for "Sammy!". It is never used and has no model,
    //which makes an ideal preloading unit. Change it if you want to.
endglobals

//===========================================================================

globals
    private unit PreloadUnit
endglobals

function AbilityPreload takes integer abilityid returns nothing
    static if DEBUG_MODE then
        if GetUnitTypeId(PreloadUnit) == 0 then
            call BJDebugMsg("AbilityPreload error: Can't preload an ability after initialization")
            return
        endif
    endif
    call UnitAddAbility(PreloadUnit, abilityid)
    static if DEBUG_MODE then
        if GetUnitAbilityLevel(PreloadUnit, abilityid) == 0 then
            call BJDebugMsg("AbilityPreload error: Attempted to preload a non-existent ability")
        endif
    endif
endfunction

function AbilityRangePreload takes integer start, integer end returns nothing
    local integer i = 1
        static if DEBUG_MODE then
            if GetUnitTypeId(PreloadUnit) == 0 then
                call BJDebugMsg("AbilityPreload error: Can't preload an ability after initialization")
                return
            endif
        endif
        if start > end then
            set i = -1
        endif
        loop
            exitwhen start > end
            call UnitAddAbility(PreloadUnit, start)
            set start = start + i
        endloop
endfunction

//===========================================================================

private struct Init extends array
    private static method onInit takes nothing returns nothing
        set PreloadUnit = CreateUnit(Player(15), PreloadUnitRawcode, 0., 0., 0.)
        call UnitApplyTimedLife(PreloadUnit, 0, .001)
        call ShowUnit(PreloadUnit, false)
        call UnitAddAbility(PreloadUnit, 'Aloc')
    endmethod
endstruct

endlibrary
//TESH.scrollpos=22
//TESH.alwaysfold=0
struct PlayerTools
    static force user_Force
    static integer user_Amount
    static player array user

    static method isPlayerUser takes player p returns boolean
        return (GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING)
    endmethod
    
    static method user_update takes nothing returns nothing
        local player p
        local integer i = 0
        local trigger t = CreateTrigger()
        
        set user_Amount = -1
        loop
            exitwhen i > 11
            set p = Player(i)
            
            if isPlayerUser(p)then
                set user_Amount = user_Amount + 1
                set user[user_Amount] = p
            endif
            
            set i = i + 1
        endloop
    endmethod
    
    static method onLeave takes nothing returns nothing
        call ForceRemovePlayer(user_Force, GetTriggerPlayer())
        call thistype.user_update()
    endmethod
    
    static method onInit takes nothing returns nothing
        local player p
        local integer i = 0
        local trigger t = CreateTrigger()
        call TriggerAddAction(t, function thistype.onLeave)
        
        set user_Force = CreateForce()
        loop
            exitwhen i > 11
            set p = Player(i)
            
            if isPlayerUser(p) then
                call ForceAddPlayer(user_Force, p)
                call TriggerRegisterPlayerEvent(t, p, EVENT_PLAYER_LEAVE)
                call TriggerRegisterPlayerEvent(t, p, EVENT_PLAYER_DEFEAT)
            endif
            
            set i = i + 1
        endloop
        call user_update()

    endmethod
    implement Init
endstruct
//TESH.scrollpos=177
//TESH.alwaysfold=0
library Multiboard /* v2.0.0.1
*************************************************************************************
*
*   Multiboard Struct API that actually works and is actually easy to use.
*
*************************************************************************************
*
*   */uses/*
*
*       */ Table /*         hiveworkshop.com/forums/jass-functions-413/snippet-new-table-188084/
*
************************************************************************************
*
*   struct Multiboard
*
*       string title
*       boolean display
*       boolean minimize
*       boolean suppress
*
*       real width=  (set only)
*       string icon= (set only)
*       string text= (set only)
*
*       readonly MultiboardRow row
*       readonly MultiboardColumn column
*
*       this[row][column] -> MultiboardItem
*
*       static method create takes integer rowCount, integer columnCount returns Multiboard
*       method destroy takes nothing returns nothing
*
*       method clear takes nothing returns nothing
*
*       method setTitleColor takes integer red, integer green, integer blue, integer alpha returns nothing
*       method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
*       method setStyle takes boolean showValues, boolean showIcons returns nothing
*
************************************************************************************
*
*   struct MultiboardRow extends array
*   struct MultiboardColumn extends array
*
*       integer count
*           -   row.count
*
*       string text
*       string icon=
*       real width=
*           -   row[0].width
*
*       method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
*       method setStyle takes boolean showValue, boolean showIcon returns nothing
*           -   row[0].setStyle
*
************************************************************************************
*
*   struct MultiboardItem extends array
*
*       string text= (set only)
*       string icon= (set only)
*       real width=  (set only)
*
*       method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
*       method setStyle takes boolean showValue, boolean showIcon returns nothing
*
************************************************************************************/
    globals
        private Table table
        private Table table2
        private integer array r
        private integer ic = 0
        private multiboard array boardp
        private integer array rc
        private integer array cc
        private boolean array suppressed
    endglobals
    
    private module Init
        private static method onInit takes nothing returns nothing
            set table = Table.create()
            set table2 = Table.create()
        endmethod
    endmodule
    
    struct MultiboardItem extends array
        method operator text= takes string value returns nothing
            call MultiboardSetItemValue(table.multiboarditem[this], value)
        endmethod
        method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
            call MultiboardSetItemValueColor(table.multiboarditem[this], red, green, blue, alpha)
        endmethod
        method setStyle takes boolean showValue, boolean showIcon returns nothing
            call MultiboardSetItemStyle(table.multiboarditem[this], showValue, showIcon)
        endmethod
        method operator icon= takes string str returns nothing
            call MultiboardSetItemIcon(table.multiboarditem[this], str)
        endmethod
        method operator width= takes real percent returns nothing
            call MultiboardSetItemWidth(table.multiboarditem[this], percent)
        endmethod
    
        implement Init
    endstruct
    
    //! textmacro MULTIBOARD_LOOPER takes ROW, TABLE, CODE
        local multiboarditem mb
        loop
            exitwhen 0 == $ROW$
            set mb = $TABLE$.multiboarditem[this]
            call $CODE$
            set this = this + 1
            set $ROW$ = $ROW$ - 1
        endloop
        
        set mb = null
    //! endtextmacro
    
    private keyword Multiboard2D
    private keyword getItems
    private keyword clearItems
    struct Multiboard extends array
        method getItems takes nothing returns nothing
            local integer row = rc[this]
            local integer column
            local multiboarditem mb
            loop
                set column = cc[this]
                loop
                    set mb = MultiboardGetItem(boardp[this], row, column)
                    set table.multiboarditem[(this*500+row)*500+column] = mb
                    set table2.multiboarditem[(this*500+column)*500+row] = mb
                    exitwhen 0 == column
                    set column = column - 1
                endloop
                exitwhen 0 == row
                set row = row - 1
            endloop
            set mb = null
        endmethod
        method clearItems takes nothing returns nothing
            local integer row = rc[this]
            local integer column
            loop
                set column = cc[this]
                loop
                    call MultiboardReleaseItem(table.multiboarditem[(this*500+row)*500+column])
                    call table.handle.remove((this*500+row)*500+column)
                    call table2.handle.remove((this*500+column)*500+row)
                    exitwhen 0 == column
                    set column = column - 1
                endloop
                exitwhen 0 == row
                set row = row - 1
            endloop
        endmethod
        
        static method create takes integer rowCount, integer columnCount returns thistype
            local thistype this = r[0]
            
            if (0 == this) then
                set this = ic + 1
                set ic = this
            else
                set suppressed[this] = false
                set r[0] = r[this]
            endif
            
            set boardp[this] = CreateMultiboard()
            call MultiboardSetColumnCount(boardp[this], columnCount)
            call MultiboardSetRowCount(boardp[this], rowCount)
            
            set rc[this] = rowCount
            set cc[this] = columnCount
            
            call getItems()
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            set r[this] = r[0]
            set r[0] = this
            
            call clearItems()
            
            call DestroyMultiboard(boardp[this])
            set boardp[this] = null
        endmethod
        
        method clear takes nothing returns nothing
            call MultiboardClear(boardp[this])
        endmethod
        
        method operator display takes nothing returns boolean
            return IsMultiboardDisplayed(boardp[this])
        endmethod
        method operator display= takes boolean b returns nothing
            call MultiboardDisplay(boardp[this], b)
        endmethod
        method operator minimize takes nothing returns boolean
            return IsMultiboardMinimized(boardp[this])
        endmethod
        method operator minimize= takes boolean b returns nothing
            call MultiboardMinimize(boardp[this], b)
        endmethod
        method operator title takes nothing returns string
            return MultiboardGetTitleText(boardp[this])
        endmethod
        method operator title= takes string txt returns nothing
            call MultiboardSetTitleText(boardp[this], txt)
        endmethod
        method setTitleColor takes integer red, integer green, integer blue, integer alpha returns nothing
            call MultiboardSetTitleTextColor(boardp[this], red, green, blue, alpha)
        endmethod
        method operator suppress takes nothing returns boolean
            return suppressed[this]
        endmethod
        method operator suppress= takes boolean b returns nothing
            set suppressed[this] = b
            call MultiboardSuppressDisplay(b)
        endmethod
        method operator width= takes real percent returns nothing
            call MultiboardSetItemsWidth(boardp[this], percent)
        endmethod
        method operator row takes nothing returns MultiboardRow
            return this
        endmethod
        method operator column takes nothing returns MultiboardColumn
            return this
        endmethod
        method operator [] takes integer row returns Multiboard2D
            return this*500+row
        endmethod
        method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
            call MultiboardSetItemsValueColor(boardp[this], red, green, blue, alpha)
        endmethod
        method setStyle takes boolean showValues, boolean showIcons returns nothing
            call MultiboardSetItemsStyle(boardp[this], showValues, showIcons)
        endmethod
        method operator icon= takes string txt returns nothing
            call MultiboardSetItemsIcon(boardp[this], txt)
        endmethod
        method operator text= takes string txt returns nothing
            call MultiboardSetItemsValue(boardp[this], txt)
        endmethod
    endstruct
    
    private struct MultiboardSet extends array
        method text takes string v, integer c, Table t returns nothing
            //! runtextmacro MULTIBOARD_LOOPER("c", "t", "MultiboardSetItemValue(mb, v)")
        endmethod
        method color takes integer red, integer green, integer blue, integer alpha, integer c, Table t returns nothing
            //! runtextmacro MULTIBOARD_LOOPER("c", "t", "MultiboardSetItemValueColor(mb, red, green, blue, alpha)")
        endmethod
        method style takes boolean v, boolean i, integer c, Table t returns nothing
            //! runtextmacro MULTIBOARD_LOOPER("c", "t", "MultiboardSetItemStyle(mb, v, i)")
        endmethod
        method icon takes string s, integer c, Table t returns nothing
            //! runtextmacro MULTIBOARD_LOOPER("c", "t", "MultiboardSetItemIcon(mb, s)")
        endmethod
        method width takes real p, integer c, Table t returns nothing
            //! runtextmacro MULTIBOARD_LOOPER("c", "t", "MultiboardSetItemWidth(mb, p)")
        endmethod
    endstruct
    struct MultiboardColumn extends array
        method operator count takes nothing returns integer
            return MultiboardGetColumnCount(boardp[this])
        endmethod
        method operator count= takes integer columns returns nothing
            call Multiboard(this).clearItems()
            call MultiboardSetColumnCount(boardp[this], columns)
            set cc[this] = columns
            call Multiboard(this).getItems()
        endmethod
        method operator text= takes string value returns nothing
            call MultiboardSet(this).text(value, rc[this/250000], table2)
        endmethod
        method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
            call MultiboardSet(this).color(red, green, blue, alpha, rc[this/250000], table2)
        endmethod
        method setStyle takes boolean showValue, boolean showIcon returns nothing
            call MultiboardSet(this).style(showValue, showIcon, rc[this/250000], table2)
        endmethod
        method operator icon= takes string str returns nothing
            call MultiboardSet(this).icon(str, rc[this/250000], table2)
        endmethod
        method operator width= takes real percent returns nothing
            call MultiboardSet(this).width(percent, rc[this/250000], table2)
        endmethod
        method operator [] takes integer column returns thistype
            return (this*500+column)*500
        endmethod
    endstruct
    struct MultiboardRow extends array
        method operator count takes nothing returns integer
            return MultiboardGetRowCount(boardp[this])
        endmethod
        method operator count= takes integer rows returns nothing
            call Multiboard(this).clearItems()
            call MultiboardSetRowCount(boardp[this], rows)
            set rc[this] = rows
            call Multiboard(this).getItems()
        endmethod
        method operator text= takes string value returns nothing
            call MultiboardSet(this).text(value, cc[this/250000], table)
        endmethod
        method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
            call MultiboardSet(this).color(red, green, blue, alpha, cc[this/250000], table)
        endmethod
        method setStyle takes boolean showValue, boolean showIcon returns nothing
            call MultiboardSet(this).style(showValue, showIcon, cc[this/250000], table)
        endmethod
        method operator icon= takes string str returns nothing
            call MultiboardSet(this).icon(str, cc[this/250000], table)
        endmethod
        method operator width= takes real percent returns nothing
            call MultiboardSet(this).width(percent,cc[this/250000], table)
        endmethod
        method operator [] takes integer row returns thistype
            return (this*500+row)*500
        endmethod
    endstruct
    private struct Multiboard2D extends array
        method operator [] takes integer column returns MultiboardItem
            return this*500+column
        endmethod
    endstruct
endlibrary
//TESH.scrollpos=4
//TESH.alwaysfold=0
library AllocT /* v1.0.2.0
*************************************************************************************
*
*	*/uses/*
*
*		*/ ErrorMessage /*      https://github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage
*		*/ Table		/*      http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
*************************************************************************************
*
*	Minimizes code generation and global variables while maintaining
*   excellent performance.
*
*   Uses hashtable instead of array, which drastically reduces performance
*   but uncaps the instance limit. Should use with table fields instead of
*   array fields.
*
*       local thistype this = recycler[0]
*
*       if (recycler[this] == 0) then
*           set recycler[0] = this + 1
*       else
*           set recycler[0] = recycler[this]
*       endif
*
************************************************************************************
*
*	module AllocT
*
*		static method allocate takes nothing returns thistype
*		method deallocate takes nothing returns nothing
*
*		readonly boolean isAllocated
*
*		debug static method calculateMemoryUsage takes nothing returns integer
*		debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
	module AllocT
        /*
        *   stack
        */
		private static Table recycler
        
        /*
        *   list of allocated memory
        */
        debug private static Table allocatedNext
        debug private static Table allocatedPrev
        
        /*
        *   free memory counter
        */
        debug private static integer usedMemory = 0
		
        /*
        *   allocation
        */
		static method allocate takes nothing returns thistype
			local thistype this = recycler[0]
			
			debug call ThrowError(this < 0, "AllocT", "allocate", "thistype", 0, "Overflow.")
            
            if (recycler[this] == 0) then
                set recycler[0] = this + 1
            else
                set recycler[0] = recycler[this]
            endif
            
            set recycler[this] = -1
            
            debug set usedMemory = usedMemory + 1
            
            debug set allocatedNext[this] = 0
            debug set allocatedPrev[this] = allocatedPrev[0]
            debug set allocatedNext[allocatedPrev[0]] = this
            debug set allocatedPrev[0] = this
			
			return this
		endmethod
		
		method deallocate takes nothing returns nothing
			debug call ThrowError(recycler[this] != -1, "AllocT", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
			
			set recycler[this] = recycler[0]
			set recycler[0] = this
            
            debug set usedMemory = usedMemory - 1
            
            debug set allocatedNext[allocatedPrev[this]] = allocatedNext[this]
            debug set allocatedPrev[allocatedNext[this]] = allocatedPrev[this]
		endmethod
		
        /*
        *   analysis
        */
        method operator isAllocated takes nothing returns boolean
			return recycler[this] == -1
		endmethod
        
		static if DEBUG_MODE then
			static method calculateMemoryUsage takes nothing returns integer
				return usedMemory
			endmethod
			
			static method getAllocatedMemoryAsString takes nothing returns string
				local integer memoryCell = allocatedNext[0]
				local string memoryRepresentation = null
				
				loop
					exitwhen memoryCell == 0
                    
                    if (memoryRepresentation == null) then
                        set memoryRepresentation = I2S(memoryCell)
                    else
                        set memoryRepresentation = memoryRepresentation + ", " + I2S(memoryCell)
                    endif
                    
                    set memoryCell = allocatedNext[memoryCell]
                endloop
                    
				return memoryRepresentation
			endmethod
		endif
        
        /*
        *   initialization
        */
		private static method onInit takes nothing returns nothing
            set recycler = Table.create()
            debug set allocatedNext = Table.create()
            debug set allocatedPrev = Table.create()
            
			set recycler[0] = 1
		endmethod
	endmodule
endlibrary
Bribe - Table[n
Bribe - TimerUtils[n

Earth-Fury - Max State[n

Flux - RecycldeDummy[n

IcemanBo - TildeDefinition[n
IcemanBo - PauseUnit[n

Magtheridon96 RPUE[n

Nestharus - List[n
Nestharus - CTL[n
Nestharus - WorldBounds[n
Nestharus - Unit Indexer[n
Nestharus - Alloc[n

Spinnaker - Weather Lib

Quilnez -SoundTools
//TESH.scrollpos=258
//TESH.alwaysfold=0
library List /* v1.0.0.3
************************************************************************************
*
*   */uses/*
*   
*       */ ErrorMessage /*         hiveworkshop.com/forums/submissions-414/snippet-error-message-239210/
*
************************************************************************************
*
*   module List
*
*       Description
*       -------------------------
*
*           NA
*
*       Fields
*       -------------------------
*
*           readonly static integer sentinel
*
*           readonly thistype list
*
*           readonly thistype first
*           readonly thistype last
*
*           readonly thistype next
*           readonly thistype prev
*
*       Methods
*       -------------------------
*
*           static method create takes nothing returns thistype
*           method destroy takes nothing returns nothing
*               - May only destroy lists
*
*           method push takes nothing returns thistype
*           method enqueue takes nothing returns thistype
*
*           method pop takes nothing returns nothing
*           method dequeue takes nothing returns nothing
*
*           method remove takes nothing returns nothing
*
*           method clear takes nothing returns nothing
*
*           debug static method calculateMemoryUsage takes nothing returns integer
*           debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
    module List
        private static thistype collectionCount = 0
        private static thistype nodeCount = 0
        debug private boolean isNode
        debug private boolean isCollection
        
        private thistype _list
        method operator list takes nothing returns thistype
            debug call ThrowError(this == 0,    "List", "list", "thistype", this, "Attempted To Read Null Node.")
            debug call ThrowError(not isNode,   "List", "list", "thistype", this, "Attempted To Read Invalid Node.")
            return _list
        endmethod
        
        private thistype _next
        method operator next takes nothing returns thistype
            debug call ThrowError(this == 0,    "List", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
            debug call ThrowError(not isNode,   "List", "next", "thistype", this, "Attempted To Read Invalid Node.")
            return _next
        endmethod
        
        private thistype _prev
        method operator prev takes nothing returns thistype
            debug call ThrowError(this == 0,    "List", "prev", "thistype", this, "Attempted To Go Out Of Bounds.")
            debug call ThrowError(not isNode,   "List", "prev", "thistype", this, "Attempted To Read Invalid Node.")
            return _prev
        endmethod
        
        private thistype _first
        method operator first takes nothing returns thistype
            debug call ThrowError(this == 0,        "List", "first", "thistype", this, "Attempted To Read Null List.")
            debug call ThrowError(not isCollection, "List", "first", "thistype", this, "Attempted To Read Invalid List.")
            return _first
        endmethod
        
        private thistype _last
        method operator last takes nothing returns thistype
            debug call ThrowError(this == 0,        "List", "last", "thistype", this, "Attempted To Read Null List.")
            debug call ThrowError(not isCollection, "List", "last", "thistype", this, "Attempted To Read Invalid List.")
            return _last
        endmethod
        
        static method operator sentinel takes nothing returns integer
            return 0
        endmethod
        
        private static method allocateCollection takes nothing returns thistype
            local thistype this = thistype(0)._first
            
            if (0 == this) then
                debug call ThrowError(collectionCount == 8191, "List", "allocateCollection", "thistype", 0, "Overflow.")
                
                set this = collectionCount + 1
                set collectionCount = this
            else
                set thistype(0)._first = _first
            endif
            
            return this
        endmethod
        
        private static method allocateNode takes nothing returns thistype
            local thistype this = thistype(0)._next
            
            if (0 == this) then
                debug call ThrowError(nodeCount == 8191, "List", "allocateNode", "thistype", 0, "Overflow.")
                
                set this = nodeCount + 1
                set nodeCount = this
            else
                set thistype(0)._next = _next
            endif
            
            return this
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this = allocateCollection()
            
            debug set isCollection = true
            
            set _first = 0
            
            return this
        endmethod
        method push takes nothing returns thistype
            local thistype node = allocateNode()
            
            debug call ThrowError(this == 0,        "List", "push", "thistype", this, "Attempted To Push On To Null List.")
            debug call ThrowError(not isCollection, "List", "push", "thistype", this, "Attempted To Push On To Invalid List.")
            
            debug set node.isNode = true
            
            set node._list = this
        
            if (_first == 0) then
                set _first = node
                set _last = node
                set node._next = 0
            else
                set _first._prev = node
                set node._next = _first
                set _first = node
            endif
            
            set node._prev = 0
            
            return node
        endmethod
        method enqueue takes nothing returns thistype
            local thistype node = allocateNode()
            
            debug call ThrowError(this == 0,        "List", "enqueue", "thistype", this, "Attempted To Enqueue On To Null List.")
            debug call ThrowError(not isCollection, "List", "enqueue", "thistype", this, "Attempted To Enqueue On To Invalid List.")
            
            debug set node.isNode = true
            
            set node._list = this
        
            if (_first == 0) then
                set _first = node
                set _last = node
                set node._prev = 0
            else
                set _last._next = node
                set node._prev = _last
                set _last = node
            endif
            
            set node._next = 0
            
            return node
        endmethod
        method pop takes nothing returns nothing
            local thistype node = _first
            
            debug call ThrowError(this == 0,        "List", "pop", "thistype", this, "Attempted To Pop Null List.")
            debug call ThrowError(not isCollection, "List", "pop", "thistype", this, "Attempted To Pop Invalid List.")
            debug call ThrowError(node == 0,        "List", "pop", "thistype", this, "Attempted To Pop Empty List.")
            
            debug set node.isNode = false
            
            set _first._list = 0
            
            set _first = _first._next
            if (_first == 0) then
                set _last = 0
            else
                set _first._prev = 0
            endif
            
            set node._next = thistype(0)._next
            set thistype(0)._next = node
        endmethod
        method dequeue takes nothing returns nothing
            local thistype node = _last
            
            debug call ThrowError(this == 0,        "List", "dequeue", "thistype", this, "Attempted To Dequeue Null List.")
            debug call ThrowError(not isCollection, "List", "dequeue", "thistype", this, "Attempted To Dequeue Invalid List.")
            debug call ThrowError(node == 0,        "List", "dequeue", "thistype", this, "Attempted To Dequeue Empty List.")
            
            debug set node.isNode = false
            
            set _last._list = 0
        
            set _last = _last._prev
            if (_last == 0) then
                set _first = 0
            else
                set _last._next = 0
            endif
            
            set node._next = thistype(0)._next
            set thistype(0)._next = node
        endmethod
        method remove takes nothing returns nothing
            local thistype node = this
            set this = node._list
            
            debug call ThrowError(node == 0,        "List", "remove", "thistype", this, "Attempted To Remove Null Node.")
            debug call ThrowError(not node.isNode,  "List", "remove", "thistype", this, "Attempted To Remove Invalid Node (" + I2S(node) + ").")
            
            debug set node.isNode = false
            
            set node._list = 0
        
            if (0 == node._prev) then
                set _first = node._next
            else
                set node._prev._next = node._next
            endif
            if (0 == node._next) then
                set _last = node._prev
            else
                set node._next._prev = node._prev
            endif
            
            set node._next = thistype(0)._next
            set thistype(0)._next = node
        endmethod
        method clear takes nothing returns nothing
            debug local thistype node = _first
        
            debug call ThrowError(this == 0,            "List", "clear", "thistype", this, "Attempted To Clear Null List.")
            debug call ThrowError(not isCollection,     "List", "clear", "thistype", this, "Attempted To Clear Invalid List.")
            
            static if DEBUG_MODE then
                loop
                    exitwhen node == 0
                    set node.isNode = false
                    set node = node._next
                endloop
            endif
            
            if (_first == 0) then
                return
            endif
            
            set _last._next = thistype(0)._next
            set thistype(0)._next = _first
            
            set _first = 0
            set _last = 0
        endmethod
        method destroy takes nothing returns nothing
            debug call ThrowError(this == 0,            "List", "destroy", "thistype", this, "Attempted To Destroy Null List.")
            debug call ThrowError(not isCollection,     "List", "destroy", "thistype", this, "Attempted To Destroy Invalid List.")
            
            static if DEBUG_MODE then
                debug call clear()
                
                debug set isCollection = false
            else
                if (_first != 0) then
                    set _last._next = thistype(0)._next
                    set thistype(0)._next = _first
                    
                    set _last = 0
                endif
            endif
            
            set _first = thistype(0)._first
            set thistype(0)._first = this
        endmethod
        
        static if DEBUG_MODE then
            static method calculateMemoryUsage takes nothing returns integer
                local thistype start = 1
                local thistype end = 8191
                local integer count = 0
                
                loop
                    exitwhen integer(start) > integer(end)
                    if (integer(start) + 500 > integer(end)) then
                        return count + checkRegion(start, end)
                    else
                        set count = count + checkRegion(start, start + 500)
                        set start = start + 501
                    endif
                endloop
                
                return count
            endmethod
              
            private static method checkRegion takes thistype start, thistype end returns integer
                local integer count = 0
            
                loop
                    exitwhen integer(start) > integer(end)
                    if (start.isNode) then
                        set count = count + 1
                    endif
                    if (start.isCollection) then
                        set count = count + 1
                    endif
                    set start = start + 1
                endloop
                
                return count
            endmethod
            
            static method getAllocatedMemoryAsString takes nothing returns string
                local thistype start = 1
                local thistype end = 8191
                local string memory = null
                
                loop
                    exitwhen integer(start) > integer(end)
                    if (integer(start) + 500 > integer(end)) then
                        if (memory != null) then
                            set memory = memory + ", "
                        endif
                        set memory = memory + checkRegion2(start, end)
                        set start = end + 1
                    else
                        if (memory != null) then
                            set memory = memory + ", "
                        endif
                        set memory = memory + checkRegion2(start, start + 500)
                        set start = start + 501
                    endif
                endloop
                
                return memory
            endmethod
              
            private static method checkRegion2 takes thistype start, thistype end returns string
                local string memory = null
            
                loop
                    exitwhen integer(start) > integer(end)
                    if (start.isNode) then
                        if (memory == null) then
                            set memory = I2S(start)
                        else
                            set memory = memory + ", " + I2S(start) + "N"
                        endif
                    endif
                    if (start.isCollection) then
                        if (memory == null) then
                            set memory = I2S(start)
                        else
                            set memory = memory + ", " + I2S(start) + "C"
                        endif
                    endif
                    set start = start + 1
                endloop
                
                return memory
            endmethod
        endif
    endmodule
endlibrary

//TESH.scrollpos=0
//TESH.alwaysfold=0
library RapidSound requires optional TimerUtils

    globals
        // Actually, just leave this value
        private constant real MIN_DELAY_FACTOR = 4.0
    endglobals

    /* v1.6

        Description
        ¯¯¯¯¯¯¯¯¯¯¯
            Allows you to play sounds rapidly and flawlessly without limit.
            Remember one sound file can only have one RSound instance.
        
        
        External Dependencies
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            (Optional)
            TimerUtils by Vexorian
                wc3c.net/showthread.php?t=101322
    
    
        User API
        ¯¯¯¯¯¯¯¯
            struct RSound
        
                Instantiate an RapidSound instance
                    | static method create takes string fileName, boolean is3D, boolean autoStop, integer inRate, integer outRate returns thistype
                        autoStop => stop when sound is out of range
                        inRate   => fade in rate
                        outRate  => fade out rate
                
                Play the sound at given coordinate
                    | method play takes real x, real y, real z, integer volume returns nothing
                
                Stop sound
                    | method stop takes boolean fadeOut returns nothing
            
                Destroy RapidSound instance
                    | method kill takes nothing returns nothing
            
                Sound file duration (in second)
                    | method operator duration takes nothing returns real
    
    
        Resource Link
        ¯¯¯¯¯¯¯¯¯¯¯¯¯
            hiveworkshop.com/threads/snippet-rapidsound.258991/
    */

    struct RSound

        private static constant integer MAX_COUNT = 4
        private static integer  Counter = -1
        private static string   array StrLib
        private static thistype array StrDex
    
        private integer ct
        private integer lib
        private integer dex
        private real    dur
    
        private sound array snd[thistype.MAX_COUNT]
        private timer array tmr[thistype.MAX_COUNT]
    
        method operator duration takes nothing returns real
            return .dur*MIN_DELAY_FACTOR
        endmethod
    
        method kill takes nothing returns nothing
    
            local integer i
        
            set .ct = .ct - 1
            if .ct == 0 then
                set i = 0
                loop
                    exitwhen i == MAX_COUNT
                    call StopSound(.snd[i], true, false)
                    static if LIBRARY_TimerUtils then
                        call ReleaseTimer(.tmr[i])
                    else
                        call DestroyTimer(.tmr[i])
                    endif
                    set .snd[i] = null
                    set .tmr[i] = null
                    set i = i + 1
                endloop
                set StrLib[.lib] = StrLib[Counter]
                set StrDex[.lib] = StrDex[Counter]
                set Counter = Counter - 1
                call deallocate()
            endif
        
        endmethod
    
        method stop takes boolean fadeOut returns nothing
    
            local integer i = 0
        
            loop
                exitwhen i == MAX_COUNT
                call StopSound(.snd[i], false, fadeOut)
                set i = i + 1
            endloop
        
        endmethod
    
        method play takes real x, real y, real z, integer volume returns nothing
        
            set .dex = .dex + 1
            if .dex == MAX_COUNT then
                set .dex = 0
            endif
            if TimerGetRemaining(.tmr[.dex]) == 0 then
                call StopSound(.snd[.dex], false, false)
                call SetSoundPosition(.snd[.dex], x, y, z)
                call SetSoundVolume(.snd[.dex], volume)
                call StartSound(.snd[.dex])
                call TimerStart(.tmr[.dex], .dur, false, null)
            endif
        
        endmethod
    
        static method create takes string fileName, boolean is3D, boolean autoStop, integer inRate, integer outRate returns thistype
    
            local thistype this
            local integer  i = 0
            local boolean  b = true
        
            loop
                exitwhen i > Counter
                if fileName == StrLib[i] then
                    set b = false
                    exitwhen true
                endif
                set i = i + 1
            endloop
        
            if b then
                set this = allocate()
                set Counter = Counter + 1
                set StrLib[Counter] = fileName
                set StrDex[Counter] = this
            
                set .ct  = 1
                set .dex = -1
                set .lib = Counter
                set .dur = I2R(GetSoundFileDuration(fileName))/(1000.*MIN_DELAY_FACTOR)
                set i = 0
                loop
                    exitwhen i == MAX_COUNT
                    set .snd[i] = CreateSound(fileName, false, is3D, autoStop, inRate, outRate, "")
                    static if LIBRARY_TimerUtils then
                        set .tmr[i] = NewTimer()
                        call TimerStart(.tmr[i], 0, false, null)
                        call PauseTimer(.tmr[i])
                    else
                        set .tmr[i] = CreateTimer()
                    endif
                    set i = i + 1
                endloop
            else
                set this = StrDex[i]
                set .ct  = .ct + 1
            endif
        
            return this
        endmethod
    
    endstruct

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*****************************************************************************
*
*    Weather v1.1.0.0
*       by Bannar aka Spinnaker
*
*    Defines Weather struct family, for better weathereffect management.
*
******************************************************************************
*
*    Optional requirements:
*
*       Table by Bribe
*          hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
*       Alloc - choose whatever you like
*
******************************************************************************
*
*    Function:
*
*       function GetRectWeather takes rect r, WeatherType wt returns WeatherEffect
*          returns WeatherEffect instance (if exists) associated with rect r of type wt
*
******************************************************************************
*
*    struct WeatherType:
*
*       constant type    Rain
*       constant type    Shield
*       constant type    DungeonFog
*       constant type    Snow
*       constant type    Wind
*       constant type    Ray
*
******************************************************************************
*
*    struct WeatherStyle:
*
*       Fields:
*
*        | readonly integer effectId
*        |    static id of weathereffect style
*        |
*        | readonly WeatherType type
*        |    generic type of weathereffect
*
*       constant style    AshenvaleRainHeavy
*       constant style    AshenvaleRainLight
*       constant style    DalaranShield
*       constant style    DungeonBlueFogHeavy
*       constant style    DungeonBlueFogLight
*       constant style    DungeonGreenFogHeavy
*       constant style    DungeonGreenFogLight
*       constant style    DungeonRedFogHeavy
*       constant style    DungeonRedFogLight
*       constant style    DungeonWhiteFogHeavy
*       constant style    DungeonWhiteFogLight
*       constant style    LordaeronRainHeavy
*       constant style    LordaeronRainLight
*       constant style    NorthrendBlizzard
*       constant style    NorthrendSnowHeavy
*       constant style    NorthrendSnowLight
*       constant style    OutlandWindHeavy
*       constant style    OutlandWindLight
*       constant style    RaysOfLight
*       constant style    RaysOfMoonlight
*       constant style    WindHeavy
*
******************************************************************************
*
*    struct WeatherEffect:
*
*       Fields:
*
*        | readonly weathereffect weather
*        |    actual weathereffect handle
*        |
*        | readonly rect where
*        |    area which weathereffect is associated with
*        |
*        | readonly boolean enabled
*        |    indicates whether weathereffect is visible or not
*        |
*        | method operator style takes nothing returns WeatherStyle
*        | method operator style= takes WeatherStyle ws returns nothing
*        |    generic style of weathereffect
*
*       Methods:
*
*        | static method create takes rect r, WeatherStyle ws returns thistype
*        |    default ctor, creates new WeatherEffect given the rect and WeatherStyle
*        |
*        | method destroy takes nothing returns nothing
*        |    default dctor
*        |
*        | method enable takes nothing returns nothing
*        |    enables this weathereffect on associated rect
*        |
*        | method disable takes nothing returns nothing
*        |    disables this weathereffect on associated rect
*
*****************************************************************************/
library WeatherEffect uses optional Table, optional Alloc

struct WeatherType extends array
    readonly static thistype    Rain          = 1
    readonly static thistype    Shield        = 2
    readonly static thistype    DungeonFog    = 3
    readonly static thistype    Snow          = 4
    readonly static thistype    Wind          = 5
    readonly static thistype    Ray           = 6
endstruct

private module WeatherStyleInit
    private static method onInit takes nothing returns nothing
        set AshenvaleRainHeavy      = create('RAhr', WeatherType.Rain)
        set AshenvaleRainLight      = create('RAlr', WeatherType.Rain)
        set DalaranShield           = create('MEds', WeatherType.Shield)
        set DungeonBlueFogHeavy     = create('FDbh', WeatherType.DungeonFog)
        set DungeonBlueFogLight     = create('FDbl', WeatherType.DungeonFog)
        set DungeonGreenFogHeavy    = create('FDgh', WeatherType.DungeonFog)
        set DungeonGreenFogLight    = create('FDgl', WeatherType.DungeonFog)
        set DungeonRedFogHeavy      = create('FDrh', WeatherType.DungeonFog)
        set DungeonRedFogLight      = create('FDrl', WeatherType.DungeonFog)
        set DungeonWhiteFogHeavy    = create('FDwh', WeatherType.DungeonFog)
        set DungeonWhiteFogLight    = create('FDwl', WeatherType.DungeonFog)
        set LordaeronRainHeavy      = create('RLhr', WeatherType.Rain)
        set LordaeronRainLight      = create('RLlr', WeatherType.Rain)
        set NorthrendBlizzard       = create('SNbs', WeatherType.Snow)
        set NorthrendSnowHeavy      = create('SNhs', WeatherType.Snow)
        set NorthrendSnowLight      = create('SNls', WeatherType.Snow)
        set OutlandWindHeavy        = create('WOcw', WeatherType.Wind)
        set OutlandWindLight        = create('WOlw', WeatherType.Wind)
        set RaysOfLight             = create('LRaa', WeatherType.Ray)
        set RaysOfMoonlight         = create('LRma', WeatherType.Ray)
        set WindHeavy               = create('WNcw', WeatherType.Wind)
    endmethod
endmodule

struct WeatherStyle extends array
    private static integer count = 1 // up to 21
    readonly integer effectId
    readonly WeatherType type

    readonly static thistype    AshenvaleRainHeavy
    readonly static thistype    AshenvaleRainLight
    readonly static thistype    DalaranShield
    readonly static thistype    DungeonBlueFogHeavy
    readonly static thistype    DungeonBlueFogLight
    readonly static thistype    DungeonGreenFogHeavy
    readonly static thistype    DungeonGreenFogLight
    readonly static thistype    DungeonRedFogHeavy
    readonly static thistype    DungeonRedFogLight
    readonly static thistype    DungeonWhiteFogHeavy
    readonly static thistype    DungeonWhiteFogLight
    readonly static thistype    LordaeronRainHeavy
    readonly static thistype    LordaeronRainLight
    readonly static thistype    NorthrendBlizzard
    readonly static thistype    NorthrendSnowHeavy
    readonly static thistype    NorthrendSnowLight
    readonly static thistype    OutlandWindHeavy
    readonly static thistype    OutlandWindLight
    readonly static thistype    RaysOfLight
    readonly static thistype    RaysOfMoonlight
    readonly static thistype    WindHeavy

    private static method create takes integer id, WeatherType t returns thistype
        local thistype this = count
        set effectId = id
        set type = t

        set count = count + 1

        return this
    endmethod

    implement WeatherStyleInit
endstruct

static if LIBRARY_Table then
    private module WeatherBaseInit
        private static method onInit takes nothing returns nothing
            set table = TableArray[7]
        endmethod
    endmodule
endif

private struct WeatherBase extends array
    static if LIBRARY_Table then
        static TableArray table
        implement WeatherBaseInit
    else
        static hashtable table = InitHashtable()
    endif
endstruct

function GetRectWeather takes rect r, WeatherType wt returns WeatherEffect
    static if LIBRARY_Table then
        return WeatherBase.table[wt][GetHandleId(r)]
    else
        return LoadInteger(WeatherBase.table, wt, GetHandleId(r))
    endif
endfunction

struct WeatherEffect extends array
    readonly weathereffect weather
    readonly rect where
    readonly boolean enabled
    private WeatherStyle wstyle

    private method init takes WeatherStyle ws returns nothing // assumes all the checks already happened
        if ( wstyle != 0 ) then
            call RemoveWeatherEffect(weather)
        endif

        set weather = AddWeatherEffect(where, ws.effectId)
        call EnableWeatherEffect(weather, enabled)

        if ( ws.type != wstyle.type ) then
            static if LIBRARY_Table then
                call WeatherBase.table[wstyle.type].remove(GetHandleId(where))
                set WeatherBase.table[ws.type][GetHandleId(where)] = this
            else
                call RemoveSavedInteger(WeatherBase.table, wstyle.type, GetHandleId(where))
                call SaveInteger(WeatherBase.table, ws.type, GetHandleId(where), this)
            endif

            set wstyle = ws
        endif
    endmethod

    method operator style takes nothing returns WeatherStyle
        return wstyle
    endmethod

    method operator style= takes WeatherStyle ws returns nothing
        local WeatherEffect we

        if ( ws != wstyle ) then
            set we = GetRectWeather(where, wstyle.type)
            if ( we == 0 or we == this ) then            
                call init(ws) // initializes actual weathereffect
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "WeatherEffect::operator style= failed assigning new style. Area is already connected with WeatherEffect instance of type: " + I2S(ws.type) + ".")
            endif
        endif
    endmethod

    implement optional Alloc

    static if not thistype.allocate.exists then
        private static integer instances = 0
        private thistype recycle

        static method allocate takes nothing returns thistype
            local thistype this = thistype(0).recycle

            if (this == 0) then
                set instances = instances + 1
                set this = instances
            else
                set thistype(0).recycle = this.recycle
            endif

            return this
        endmethod

        method deallocate takes nothing returns nothing
            set this.recycle = thistype(0).recycle
            set thistype(0).recycle = this
        endmethod
    endif

    static method create takes rect r, WeatherStyle ws returns thistype
        local thistype this = GetRectWeather(r, ws.type)

        if ( this == 0 ) then
            set this = allocate()
            set where = r
            set enabled = false
            call init(ws) // initializes actual weathereffect
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "WeatherEffect::create failed allocating new instance. Area is already connected with WeatherEffect instance of type: " + I2S(ws.type) + ".")
        endif

        return this
    endmethod

    method destroy takes nothing returns nothing
        static if LIBRARY_Table then
            call WeatherBase.table[wstyle.type].remove(GetHandleId(where))
        else
            call RemoveSavedInteger(WeatherBase.table, wstyle.type, GetHandleId(where))
        endif

        call RemoveWeatherEffect(weather)
        set weather = null
        set where = null
        set wstyle = 0

        call deallocate()
    endmethod

    method enable takes nothing returns nothing
        set enabled = true
        call EnableWeatherEffect(weather, enabled)
    endmethod

    method disable takes nothing returns nothing
        set enabled = false
        call EnableWeatherEffect(weather, enabled)
    endmethod
endstruct

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitMaxState initializer Initialize requires optional AbilityPreload, optional xepreload
//==============================================================================
// UnitMaxState v2.1
//==============================================================================
// Credits:
//------------------------------------------------------------------------------
// Written By:
//     Earth-Fury
// 
// Original System By:
//     Blade.dk
// 
// Intermittent Version By:
//     Deaod
//
// With Thanks To:
//     - weaaddar for BonusMod and thus inspiration
//     - PitzerMike for the ObjectMerger
//     - Vexorian for vJass and Jass Helper
//     - PipeDream for Grimoire
//     - SFilip for TESH
//     - MindWorX for maintaining NewGen
//------------------------------------------------------------------------------
// If you use this library in your map, please at least give credit to Blade.dk.
// Without him, this library would not exist.
//==============================================================================
// Introduction:
//------------------------------------------------------------------------------
// UnitMaxState is a library which allows you to modify a unit's maximum life,
// or maximum mana. To achieve this, the library abuses a bug with the AIlf and
// AImz abilities, which is too complex to explain here.
// 
// I do believe it was indeed Blade.dk who initially found this bug. If not,
// it's still his system I stole and rewrote. Further, let me thank Deaod for
// writing up his version of this system, which inspired both the reality of
// this rewrite, and the method abilities are handled within it.
// 
//==============================================================================
// Requirements:
//------------------------------------------------------------------------------
// UnitMaxState is written in vJass and requires the NewGen editor, or
// Jass Helper with PitzerMike's Object Merger configured for it.
// 
// UnitMaxState requires the latest version of Jass Helper.
// 
// Preloading of abilities requires either AbilityPreload or xepreload. Neither
// are required for the library to function; however, having one or the other
// will remove the slight delay the first time a unit's max state is changed.
// 
//==============================================================================
// Using UnitMaxState:
//------------------------------------------------------------------------------
// UnitMaxState comes with two useful functions:
// 
// nothing SetUnitMaxState(unit <target>, unitstate <state>, real <value>)
//     Changes <target>'s unitstate <state> to be equal to <value>.
//
// nothing AddUnitMaxState(unit <target>, unitstate <state>, real <value>)
//     Adds <value> to <target>'s <state> unitstate. Note that you can use
//     negative values with this function.
//
// Both of these functions accept unitstate's other than UNIT_STATE_MAX_LIFE and
// UNIT_STATE_MAX_MANA. There is a small performance penalty in using these over
// direct usage of SetUnitState.
// 
// You must not use life/mana boosting upgrades in combination with this system.
// 
// Attempting to set a unit's maximum life below 1, or mana below 0 will do
// nothing. A debug message will be output if the script is compiled in
// debug mode.
//==============================================================================



//==============================================================================
// Configuration:
//------------------------------------------------------------------------------
// The below textmacro call is an all-in-one configuration line.
//------------------------------------------------------------------------------
// The first parameter is a boolean.
// 
// If true, the abilities used by this system will be created on save. This adds
// a slight delay to saving your map. You only ever have to create the abilities
// the first time this library is added to your map, or if you modify any of
// the other configuration options.
// 
// Note that to make the ability creation permanent, you must save with ability
// creation enabled, close your map, and reopen it in the editor. You can then
// disable ability creation, as the abilities will be permanently in your map.
//------------------------------------------------------------------------------
// The second parameter is an integer.
// 
// This is the number of abilities this system will use for adding/removing
// life/mana. Note that this system uses four sets of abilities, so the actual
// number of abilities generated and used will be the value you pass here,
// multiplied by 4.
// 
// The higher this number, the faster large bonuses will be added. This number
// should never have to go above 13. Between 3 and 5 will work fine for most
// maps.
//------------------------------------------------------------------------------
// The fourth and fifth parameters are 3 character prefixes for rawcodes.
//
// The first one is for the life-modifying abilities, while the second is for
// the mana-modifying abilities.
// 
// Please, make sure your map has no abilities whose rawcodes begin with either
// of these prefixes before saving! Otherwise, those abilities will be
// overwritten. You can change these to any 3 character combination, if your
// map does already contain abilities whose rawcodes begin with these prefixes.
//------------------------------------------------------------------------------

///! runtextmacro UnitMaxState_Configuration("true", "3", "ZxL", "ZxM")
//! runtextmacro UnitMaxState_Globals("true", "3", "ZxL", "ZxM")

//------------------------------------------------------------------------------
// End of configuration
//------------------------------------------------------------------------------

//! textmacro UnitMaxState_Configuration takes LOAD_ABILITIES, ABILITY_COUNT, LIFE_PREFIX, MANA_PREFIX
    //*
    //! externalblock extension=lua ObjectMerger $FILENAME$
    //! i function CreateAbilities(baseAbility, rawcodePrefix, field, name, icon)
    //! i     k = 0
    //! i     for sign = -1, 1, 2 do
    //! i         signStr = "+"
    //! i         if sign < 0 then
    //! i             signStr = "-"
    //! i         end
    //! i         j = 0
    //! i         for i = 0, (abilityCount - 1) * 3, 3 do
    //! i             j = j + 1
    //! i             createobject(baseAbility, rawcodePrefix .. string.sub(Chars, k + 1, k + 1))
    //! i             makechange(current, "anam", "UnitMaxState - " .. name)
    //! i             makechange(current, "ansf", "(" .. signStr .. tostring(j) .. ")")
    //! i             makechange(current, "aart", "ReplaceableTextures\\CommandButtons\\" .. icon)
    //! i             makechange(current, "aite", 0)
    //! i             makechange(current, "alev", 4)
    //! i             makechange(current, field, 1, 0)
    //! i             makechange(current, field, 2, 2^(i + 0) * sign)
    //! i             makechange(current, field, 3, 2^(i + 1) * sign)
    //! i             makechange(current, field, 4, 2^(i + 2) * sign)
    //! i             k = k + 1
    //! i         end
    //! i     end
    //! i end
    //! i if $LOAD_ABILITIES$ then
    //! i     setobjecttype("abilities")
    //! i     abilityCount = $ABILITY_COUNT$
    //! i     Chars = "abcdefghijklmnopqrstuvwxyz"
    //! i     CreateAbilities("AIlf", "$LIFE_PREFIX$", "Ilif", "Life", "BTNHealthStone.blp")
    //! i     CreateAbilities("AImz", "$MANA_PREFIX$", "Iman", "Mana", "BTNManaStone.blp")
    //! i end
    //! endexternalblock
    // */
//! endtextmacro

//! textmacro UnitMaxState_Globals takes LOAD_ABILITIES, ABILITY_COUNT, LIFE_PREFIX, MANA_PREFIX
    globals
        private constant integer RAWCODE_LIFE = '$LIFE_PREFIX$a'
        private constant integer RAWCODE_MANA = '$MANA_PREFIX$a'
        
        public constant integer ABILITY_COUNT = $ABILITY_COUNT$
    endglobals
//! endtextmacro
globals
    private constant boolean PRELOAD_ABILITIES = false
    
    private integer array POWERS_OF_2
endglobals

private function ErrorMsg takes string s returns nothing
    debug call BJDebugMsg("SetUnitMaxState: " + s)
endfunction

function SetUnitMaxState takes unit target, unitstate state, real targetValue returns nothing
    local integer difference
    local integer rawcode
    
    local integer abilityId
    local integer abilityLevel
    
    local integer currentAbility
    
    if state == UNIT_STATE_MAX_LIFE then
        set rawcode = RAWCODE_LIFE
        
        if targetValue < 1 then
            call ErrorMsg("You can not set a unit's max life to below 1")
            return
        endif
    elseif state == UNIT_STATE_MAX_MANA then
        set rawcode = RAWCODE_MANA
        
        if targetValue < 0 then
            call ErrorMsg("You can not set a unit's max mana to below 0")
            return
        endif
    else
        call SetUnitState(target, state, targetValue)
        return
    endif
    
    set difference = R2I(targetValue) - R2I(GetUnitState(target, state))
    
    if difference < 0 then
        set difference = -difference
        set rawcode = rawcode + ABILITY_COUNT
    endif
    
    set abilityId = ABILITY_COUNT - 1
    set abilityLevel = 4
    set currentAbility = rawcode + abilityId
    loop
        exitwhen difference == 0
        
        if difference >= POWERS_OF_2[abilityId * 3 + (abilityLevel - 2)] then
            call UnitAddAbility(target, currentAbility)
            call SetUnitAbilityLevel(target, currentAbility, abilityLevel)
            call UnitRemoveAbility(target, currentAbility)
            
            set difference = difference - POWERS_OF_2[abilityId * 3 + (abilityLevel - 2)]
        else
            set abilityLevel = abilityLevel - 1
            if abilityLevel <= 1 then
                set abilityId = abilityId - 1
                set abilityLevel = 4
                set currentAbility = rawcode + abilityId
            endif
        endif
    endloop
endfunction

function AddUnitMaxState takes unit target, unitstate state, real additionalValue returns nothing
    call SetUnitMaxState(target, state, GetUnitState(target, state) + additionalValue)
endfunction

//! textmacro UnitMaxState_Preload takes RAWCODE
    set i = 0
    loop
        exitwhen i == ABILITY_COUNT * 2 - 1
        
        static if LIBRARY_AbilityPreload then
            call AbilityPreload($RAWCODE$ + i)
        elseif LIBRARY_xepreload then
            call XE_PreloadAbility($RAWCODE$ + i)
        endif
        
        set i = i + 1
    endloop
//! endtextmacro

private function Initialize takes nothing returns nothing
    local integer i
    local integer k
    
    set i = 1
    set POWERS_OF_2[0] = 1
    loop
        exitwhen i == ABILITY_COUNT * 2 * 2 * 3 + 1
        
        set POWERS_OF_2[i] = POWERS_OF_2[i - 1] * 2
        set i = i + 1
    endloop
    
    static if DEBUG_MODE and PRELOAD_ABILITIES and not LIBRARY_AbilityPreload and not LIBRARY_xepreload then
        call ErrorMsg("Ability preloading was enabled, but neither of the supported preload libraries are present")
    elseif PRELOAD_ABILITIES then
        //! runtextmacro UnitMaxState_Preload("RAWCODE_LIFE")
        //! runtextmacro UnitMaxState_Preload("RAWCODE_MANA")
    endif
endfunction
endlibrary
//TESH.scrollpos=124
//TESH.alwaysfold=0
library DummyRecycler
   
//                      DummyRecycler v1.22
//                          by Flux
//  
//  A system that recycles dummy units while considering their facing angle.
//  It can be used as attachment units or as dummy caster.
//
//  Why is recycling a unit important?
//      Because creating a unit is is one of the slowest function in the game
//      and it will always leave a permanent tiny bit of memory (0.04 KB).
//
//  Features:
//
//    -- Dummy Sharing
//        When a Dummy List gets low on unit count, it will borrow Dummy Units 
//        from the Dummy List with the highest unit count. The transfer is not
//        instant because the shared Dummy Unit has to turn to the appropriate 
//        angle of its new Dummy List before it can be recycled. 
//        See BORROW_REQUEST.
//
//    -- Self-balancing recycling algorithm
//        Recycled Dummy Units will be thrown to the List having the least number
//        of Dummy Units.
//
//    -- Recycling least used
//        Allows recycling a Dummy from the Dummy List with the highest
//        unit count. It is useful when the facing angle of the Dummy Unit
//        does not matter. 
//        See GetRecycledDummyAnyAngle.
//
//    -- Self-adaptation
//        When there are no free Dummy Units from a Dummy List, it will end up creating
//        a new unit instead but that unit will be permanently added as a Dummy
//        Unit to be recycled increasing the overall total Dummy Unit count.
//
//    -- Count control
//        Allows limiting the overall number of Dummy Units. 
//        See MAX_DUMMY_COUNT.
//
//    -- Delayed Recycle
//        Allows recycling Dummy Units after some delay to allocate time for the 
//        death animation of Special Effects to be seen. 
//        See DummyAddRecycleTimer.
//
//
//--------------------
//      CREDITS
//--------------------
//  Bribe - for the MissileRecycler (vJASS) where I got this concept from
//       http://www.hiveworkshop.com/forums/jass-resources-412/system-missilerecycler-206086/
//        - for the optional Table
//       http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
//  Vexorian - for the Attachable and Pitch Animation Model (dummy.mdx)
//       http://www.wc3c.net/showthread.php?t=101150
//  Maker and IcemanBo - for the unit permanent 0.04 KB memory leak of units.
//       http://www.hiveworkshop.com/forums/trigger-gui-editor-tutorials-279/memory-leaks-263410/
//  Nestharus - for the data structure
//       http://www.hiveworkshop.com/forums/2809461-post7.html
//            - for the optional WorldBounds
//       http://githubusercontent.com/nestharus/JASS/master/jass/Systems/WorldBounds/script.j
//
// ******************************************************************
// ***************************** API: *******************************
// ******************************************************************
//
//  function GetRecycledDummy takes real x, real y, real z, real facing returns unit
//      - Retrieve an unused Dummy Unit from the List.
//      - The equivalent of CreateUnit
//      - To use as a Dummy Caster, follow it with PauseUnit(dummy, false)
//
//  function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
//      - Use this function if the facing angle of the Dummy doesn't matter to you.
//      - It will return a unit from the list having the highest number of unused Dummy Units.
//      - To use as a Dummy Caster, follow it with PauseUnit(dummy, false)
//
//  function RecycleDummy takes unit u returns nothing
//      - Recycle the Dummy unit for it to be used again later.
//      - The equivalent of RemoveUnit.
//
//  function DummyAddRecycleTimer takes unit u, real time returns nothing
//      - Recycle the Dummy unit after a certain time. 
//      - Use this to allocate time for the the death animation of an effect attached to the 
//        Dummy Unit to finish..
//      - The equivalent of UnitApplyTimedLife.

// =============================================================== //
// ====================== CONFIGURATION ========================== //
// =============================================================== //

    globals
        //The rawcode of the Dummy Unit
        private constant integer DUMMY_ID = 'dumy'
       
        //The owner of the Dummy Unit
        private constant player OWNER = Player(14)
       
        //The number of indexed angle. The higher the value the:
        // - Lesser the turning time for the Dummy Units.
        // - Higher the total number of Dummy Units created at Map Initialization.
        //          Recommended Value: 10 (Max difference of 18 degrees)
        private constant integer ANGLES_COUNT = 10
       
        //The number of Dummy units per ANGLES_COUNT. The higher the value the:
        // - Higher the number of units that can be recycled per angle, when 
        //   no more units are in queue, the system will resort to use CreateUnit.
        // - Higher the total number of Dummy Units created at Map Initialization.
        //    Recommended Value: 3 to 5 (for less overhead in Map Loading Screen)
        private constant integer STORED_UNIT_COUNT = 3
       
        //The maximum number of Dummy units that can exist. When the system resort
        //to using CreateUnit, the unit will be permanently added to the Dummy
        //List. To avoid spamming Dummy Units and having too much free Dummy
        //Units to allocate, the maximum number of Dummy Units is capped.
        //               Recommended Value: 80 to 120
        private constant integer MAX_DUMMY_COUNT = 100
       
        //When a certain angle have less than BORROW_REQUEST units in its list,
        //it will start to borrow Dummy Units from the list with the highest
        //Dummy Unit count.
        //      Recommended Value: Half of maximum STORED_UNIT_COUNT
        private constant integer BORROW_REQUEST = 5
       
        //It will only return a Dummy if the current dummy is close
        //to it's appropriate facing angle. This is to avoid returning
        //a Dummy which is still turning to face it's list angle.
        private constant real ANGLE_TOLERANCE = 10.0
       
        //An additional option to automatically hide recycled dummy units in the
        //corner of the map camera bounds
        private constant boolean HIDE_ON_MAP_CORNER = true
    endglobals
   
    //Every time a new dummy unit is retrieved, it will apply this resets
    //If it is redundant/you dont need it, remove it.
    //! textmacro DUMMY_UNIT_RESET
        //call SetUnitScale(bj_lastCreatedUnit, 1, 0, 0)
        //call SetUnitAnimationByIndex(bj_lastCreatedUnit, 90)
    //! endtextmacro
// =============================================================== //
// ==================== END CONFIGURATION ======================== //
// =============================================================== //
   
   
    globals
        private integer dummyCount = ANGLES_COUNT*STORED_UNIT_COUNT
        private real array angle 
        private integer array count 
        private integer array countHead
        private integer array countNext
        private integer array countPrev
        private integer array next
        private integer array prev
        private unit array dummy
        private integer upper
        private integer lower
        private integer lastInstance
        private constant real FACING_OFFSET = 180.0/ANGLES_COUNT
    endglobals
   
    static if HIDE_ON_MAP_CORNER and not LIBRARY_WorldBounds then
        private struct Bounds extends array
            readonly static real x
            readonly static real y
           
            private static method onInit takes nothing returns nothing
                local rect map = GetWorldBounds()
                set thistype.x = GetRectMaxX(map)
                set thistype.y = GetRectMaxY(map)
                call RemoveRect(map)
                set map = null
            endmethod
            
        endstruct
    endif
   
    private struct S extends array
        static if LIBRARY_Table then
            static Table tb
        else
            static hashtable hash = InitHashtable()
        endif
       
        private static method onInit takes nothing returns nothing
            local real add = 360.0/ANGLES_COUNT
            local real a = 0
            local integer this = ANGLES_COUNT
            local integer head = 0
            local integer cHead = JASS_MAX_ARRAY_SIZE - 1   //avoid allocation collision
            local integer i = R2I(MAX_DUMMY_COUNT/ANGLES_COUNT + 0.5)
            set upper = STORED_UNIT_COUNT
            set lower = STORED_UNIT_COUNT
            static if LIBRARY_Table then
                set tb = Table.create()
            endif
            //Initialize countHeads
            loop
                exitwhen i < 0
                set countNext[cHead] = cHead
                set countPrev[cHead] = cHead
                set countHead[i] = cHead
                set cHead = cHead - 1
                set i = i - 1
            endloop
            set cHead = countHead[STORED_UNIT_COUNT]  //All heads will be inserted here initially
            //Create the Dummy units
            loop
                exitwhen a >= 360
                //Initialize head
                set next[head] = head
                set prev[head] = head
                set count[head] = STORED_UNIT_COUNT
                set angle[head] = a
                //Insert head in the Count List 
                set countNext[head] = cHead
                set countPrev[head] = countPrev[cHead]
                set countNext[countPrev[head]] = head
                set countPrev[countNext[head]] = head
                set i = 0
                loop
                    exitwhen i >= STORED_UNIT_COUNT
                    //Queued Linked List
                    set next[this] = head
                    set prev[this] = prev[head]
                    set next[prev[this]] = this
                    set prev[next[this]] = this
                    static if HIDE_ON_MAP_CORNER then
                        static if LIBRARY_WorldBounds then
                            set dummy[this] = CreateUnit(OWNER, DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, a)
                        else
                            set dummy[this] = CreateUnit(OWNER, DUMMY_ID, Bounds.x, Bounds.y, a)
                        endif
                    else
                        set dummy[this] = CreateUnit(OWNER, DUMMY_ID, 0, 0, a)
                    endif
                    call PauseUnit(dummy[this], true)
                    static if LIBRARY_Table then
                        set tb[GetHandleId(dummy[this])] = this
                    else
                        call SaveInteger(hash, GetHandleId(dummy[this]), 0, this)
                    endif
                    set this = this + 1
                    set i = i + 1
                endloop
                set head = head + 1
                set a = a + add
            endloop
            set lastInstance = this
        endmethod
    endstruct
   
    private function GetHead takes integer facing returns integer
        if facing < 0 or facing >= 360 then
            set facing = facing - (facing/360)*360
            if facing < 0 then
                set facing = facing + 360
            endif
        endif
        return R2I((facing*ANGLES_COUNT/360.0))
    endfunction
   
    function GetRecycledDummy takes real x, real y, real z, real facing returns unit
        local integer head = GetHead(R2I(facing + FACING_OFFSET))
        local integer this = next[head]
        local integer cHead
       
        //If there are Dummy Units in the Queue List already facing close to the appropriate angle
        if this != head and RAbsBJ(GetUnitFacing(dummy[this]) - angle[head]) <= ANGLE_TOLERANCE then
            //Remove from the Queue List
            set next[prev[this]] = next[this]
            set prev[next[this]] = prev[this]
            //For double free protection
            set next[this] = -1
            //Unit Properties
            set bj_lastCreatedUnit = dummy[this]
            call PauseUnit(bj_lastCreatedUnit, true)
            call SetUnitX(bj_lastCreatedUnit, x)
            call SetUnitY(bj_lastCreatedUnit, y)
            call SetUnitFacing(bj_lastCreatedUnit, facing)
            call SetUnitVertexColor(bj_lastCreatedUnit, 255, 255, 255, 255)
            call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
            //! runtextmacro DUMMY_UNIT_RESET()
            //Update Count and Bounds
            set count[head] = count[head] - 1
           
            //------------------------------------------------
            //                 Unit Sharing
            //------------------------------------------------
            if count[head] < BORROW_REQUEST and count[countNext[countHead[upper]]] > count[head] then
                set count[head] = count[head] + 1
                set this = next[countNext[countHead[upper]]]
                call SetUnitFacing(dummy[this], angle[head])
                //Remove
                set next[prev[this]] = next[this]
                set prev[next[this]] = prev[this]
                //Add to the Current List
                set next[this] = head
                set prev[this] = prev[head]
                set next[prev[this]] = this
                set prev[next[this]] = this
                set head = countNext[countHead[upper]]
                set count[head] = count[head] - 1
            endif
           
            //---------------------------
            //Update Count Lists
            //---------------------------
            //Remove from the current Count List
            set countNext[countPrev[head]] = countNext[head]
            set countPrev[countNext[head]] = countPrev[head]
            //Add to the new Count List
            set cHead = countHead[count[head]]
            set countNext[head] = cHead
            set countPrev[head] = countPrev[cHead]
            set countNext[countPrev[head]] = head
            set countPrev[countNext[head]] = head
           
            //---------------------------
            //  Update Bounds
            //---------------------------
            set cHead = countHead[upper]
            if countNext[cHead] == cHead then
                set upper = upper - 1
            endif
            if count[head] < lower then
                set lower = count[head]
            endif
        else
            set bj_lastCreatedUnit = CreateUnit(OWNER, DUMMY_ID, x, y, facing)
            call PauseUnit(bj_lastCreatedUnit, true)
            call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
            if dummyCount < MAX_DUMMY_COUNT then
                set this = lastInstance
                //For double free protection
                set next[this] = -1
                set dummy[this] = bj_lastCreatedUnit
                static if LIBRARY_Table then
                    set S.tb[GetHandleId(bj_lastCreatedUnit)] = this
                else
                    call SaveInteger(S.hash, GetHandleId(bj_lastCreatedUnit), 0, this)
                endif
                set lastInstance = lastInstance + 1
            endif
            set dummyCount = dummyCount + 1
        endif

        return bj_lastCreatedUnit
    endfunction
   
    function RecycleDummy takes unit u returns nothing
        static if LIBRARY_Table then
            local integer this = S.tb[GetHandleId(u)]
        else
            local integer this = LoadInteger(S.hash, GetHandleId(u), 0)
        endif
        local integer head
        local integer cHead
       
        //If the unit is a legit Dummy Unit
        if this > 0 and next[this] == -1 then
            //Find where to insert based on the list having the least number of units
            set head = countNext[countHead[lower]]
            set next[this] = head
            set prev[this] = prev[head]
            set next[prev[this]] = this
            set prev[next[this]] = this
            //Update Status
            call SetUnitFacing(u, angle[head])
            call PauseUnit(u, true)
            call SetUnitOwner(u, OWNER, false)
            static if HIDE_ON_MAP_CORNER then
                static if LIBRARY_WorldBounds then
                    call SetUnitX(u, WorldBounds.maxX)
                    call SetUnitY(u, WorldBounds.maxY)
                else
                    call SetUnitX(u, Bounds.x)
                    call SetUnitY(u, Bounds.y)
                endif
            else
                call SetUnitVertexColor(u, 0, 0, 0, 0)
            endif
            set count[head] = count[head] + 1
           
            //---------------------------
            //    Update Count Lists
            //---------------------------
            //Remove
            set countNext[countPrev[head]] = countNext[head]
            set countPrev[countNext[head]] = countPrev[head]
            //Add to the new Count List
            set cHead = countHead[count[head]]
            set countNext[head] = cHead
            set countPrev[head] = countPrev[cHead]
            set countNext[countPrev[head]] = head
            set countPrev[countNext[head]] = head
           
            //---------------------------
            //  Update Bounds
            //---------------------------
            set cHead = countHead[lower]
            if countNext[cHead] == cHead then
                set lower = lower + 1
            endif
            if count[head] > upper then
                set upper = count[head]
            endif
        elseif this == 0 then
            call RemoveUnit(u)
        debug elseif next[this] != -1 then
            debug call BJDebugMsg("|cffffcc00[DummyRecycler]:|r Attempted to recycle a pending/free Dummy Unit.")
        endif
       
    endfunction
   
    private function Expires takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer id = GetHandleId(t)
        static if LIBRARY_Table then
            call RecycleDummy(S.tb.unit[id])
            call S.tb.remove(id)
        else
            call RecycleDummy(LoadUnitHandle(S.hash, id, 0))
            call FlushChildHashtable(S.hash, id)
        endif
        call DestroyTimer(t)
        set t = null
    endfunction

    function DummyAddRecycleTimer takes unit u, real time returns nothing
        local timer t = CreateTimer()
        static if LIBRARY_Table then
            set S.tb.unit[GetHandleId(t)] = u
        else
            call SaveUnitHandle(S.hash, GetHandleId(t), 0, u)
        endif
        call TimerStart(t, time, false, function Expires)
        set t = null
    endfunction
   
    function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
        return GetRecycledDummy(x, y, z, angle[countNext[countHead[upper]]])
    endfunction
   
    // runtextmacro DUMMY_DEBUG_TOOLS()
   
endlibrary
//TESH.scrollpos=132
//TESH.alwaysfold=0
library CTL /* v1.2.0.1
    *************************************************************************************
    *
    *    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 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=9
//TESH.alwaysfold=0
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.1.0
   
    One map, one hashtable. Welcome to NewTable 3.1
   
    This library was originally called NewTable so it didn't conflict with
    the API of Table by Vexorian. However, the damage is done and it's too
    late to change the library name now. To help with damage control, I
    have provided an extension library called TableBC, which bridges all
    the functionality of Vexorian's Table except for 2-D string arrays &
    the ".flush(integer)" method. I use ".flush()" to flush a child hash-
    table, because I wanted the API in NewTable to reflect the API of real
    hashtables (I thought this would be more intuitive).
   
    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 integer less = 0    //Index generation for TableArrays (below 0).
    private integer more = 8190 //Index generation for Tables.
    //Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
   
    private hashtable ht = InitHashtable()
    private key sizeK
    private key listK
endglobals
   
private struct dex extends array
    static method operator size takes nothing returns Table
        return sizeK
    endmethod
    static method operator list takes nothing returns Table
        return listK
    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
    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 module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
   
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
   
//! 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 syntax (tb.handle; tb.unit; etc.)
    implement realm
    implement integerm
    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 = tb[GetSpellAbilityId()]
    method operator [] takes integer key returns Table
        return LoadInteger(ht, this, key) //return this.integer[key]
    endmethod
   
    //set tb[389034] = 8192
    method operator []= takes integer key, Table tb returns nothing
        call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
    endmethod
   
    //set b = tb.has(2493223)
    method has takes integer key returns boolean
        return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
    endmethod
   
    //call tb.remove(294080)
    method remove takes integer key returns nothing
        call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
    endmethod
   
    //Remove all data from a Table instance
    method flush takes nothing returns nothing
        call FlushChildHashtable(ht, this)
    endmethod
   
    //local Table tb = Table.create()
    static method create takes nothing returns Table
        local Table this = dex.list[0]
       
        if this == 0 then
            set this = more + 1
            set more = this
        else
            set dex.list[0] = dex.list[this]
            call dex.list.remove(this) //Clear hashed memory
        endif
       
        debug set dex.list[this] = -1
        return this
    endmethod
   
    // Removes all data from a Table instance and recycles its index.
    //
    //     call tb.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
   
    //! runtextmacro optional TABLE_BC_METHODS()
endstruct
   
//! runtextmacro optional TABLE_BC_STRUCTS()
   
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 tb = dex.size[array_size] //Get the unique recycle list for this array size
        local TableArray this = tb[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 this = less - array_size
            set less = this
        else
            set tb[0] = tb[this]  //Set the last destroyed to the last-last destroyed
            call tb.remove(this)  //Clear hashed 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
   
    //This magic method enables two-dimensional[array][syntax] for Tables,
    //similar to the two-dimensional utility provided by hashtables them-
    //selves.
    //
    //ta[integer a].unit[integer b] = unit u
    //ta[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; I assume you call .flush()
    //if you want it flushed too. This is a public method so that you don't
    //have to loop through all TableArray indices to flush them if you don't
    //need to (ie. if you were flushing all child-keys as you used them).
    //
    method destroy takes nothing returns nothing
        local Table tb = 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 tb == 0 then
            //Create a Table to index recycled instances with their array size
            set tb = Table.create()
            set dex.size[this.size] = tb
        endif
       
        call dex.size.remove(this) //Clear the array size from hash memory
       
        set tb[this] = tb[0]
        set tb[0] = this
    endmethod
   
    private static Table tempTable
    private static integer tempEnd
   
    //Avoids hitting the op limit
    private static method clean takes nothing returns nothing
        local Table tb = .tempTable
        local integer end = tb + 0x1000
        if end < .tempEnd then
            set .tempTable = end
            call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
        else
            set end = .tempEnd
        endif
        loop
            call tb.flush()
            set tb = tb + 1
            exitwhen tb == 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
        debug if this.size == 0 then
            debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
            debug return
        debug endif
        set .tempTable = this
        set .tempEnd = this + this.size
        call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
        call this.destroy()
    endmethod
   
endstruct
   
endlibrary
//TESH.scrollpos=9
//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
    
    function IsInBounds takes real x, real y returns boolean
        return x < WorldBounds.maxX and x > WorldBounds.minX and y < WorldBounds.maxY and y > WorldBounds.minY
    endfunction
    
endlibrary
//TESH.scrollpos=18
//TESH.alwaysfold=0
/**************************************************************
*
*   RegisterPlayerUnitEvent
*   v5.1.0.1
*   By Magtheridon96
*
*   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 either
*   return a boolean (false) or nothing. (Which is a Pro)
*
*   Warning:
*   --------
*
*       - Don't use TriggerSleepAction inside registered code.
*       - Don't destroy a trigger unless you really know what you're doing.
*
*   API:
*   ----
*
*       - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
*           - Registers code that will execute when an event fires.
*       - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
*           - Registers code that will execute when an event fires for a certain player.
*       - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
*           - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
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
   
    function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
        local integer i = 16 * GetHandleId(p) + GetPlayerId(pl)
        if t[i] == null then
            set t[i] = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
        endif
        call TriggerAddCondition(t[i], Filter(c))
    endfunction
   
    function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
        return t[GetHandleId(p)]
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x)   : Get a timer (alternative to CreateTimer), call
//*                            Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Multi-flavor:
//*    Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************

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

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

    endglobals

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

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

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

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

    //==========================================================================================
    // I needed to decide between duplicating code ignoring the "Once and only once" rule
    // and using the ugly textmacros. I guess textmacros won.
    //
    //! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
    // On second thought, no.
    //! endtextmacro

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


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

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

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

    endfunction

endlibrary
//TESH.scrollpos=0
//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 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,'Adef',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,'Adef')
                call UnitMakeAbilityPermanent(Q,true,'Adef')
                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,'Adef') 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,'Adef')
    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=36
//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 isGameOnline initializer INIT

globals

    boolean IS_GAME_ONLINE = false
    //TRUE  = Game is online, no cheats possible.
    //FALSE = Game is offline, cheats possible.
    //If your map have some sort of secrets, you can cover them in offline games
endglobals

private function INIT takes nothing returns nothing
    if GetExpiredTimer() != null then
        set IS_GAME_ONLINE = not IsNoDefeatCheat()
        call Cheat("StrengthAndHonor")
        call DestroyTimer(GetExpiredTimer())
        call ClearTextMessages()
        return
    endif

    call Cheat("StrengthAndHonor")
    call TimerStart(CreateTimer(),1.0,false,function INIT)
endfunction

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Init /* v1.0.0.0
************************************************************************************
*
*	module Init
*
*		interface private static method init takes nothing returns nothing
*			-	Runs at map init
*
*************************************************************************************
*
*	module InitTimer
*
*		interface private static method init takes nothing returns nothing
*			-	Runs after a one-shot timer with a period of 0
*
************************************************************************************/
	module Init
		static if thistype.init.exists then
			private static method onInit takes nothing returns nothing
				call init()
			endmethod
		endif
	endmodule
	
	module InitTimer
		static if thistype.init.exists then
			private static method initex takes nothing returns nothing
				call DestroyTimer(GetExpiredTimer())
				call init()
			endmethod
			private static method onInit takes nothing returns nothing
				call TimerStart(CreateTimer(), 0, false, function thistype.initex)
			endmethod
		endif
	endmodule
endlibrary
//TESH.scrollpos=24
//TESH.alwaysfold=0
// modified to create the .bat file inside the warcraft folder

library FileIO /* v2.0.0.1
*************************************************************************************
*
*   Used read/write data to/from files
*
************************************************************************************
*
*   struct File extends array
*
*       Description
*       -----------------------
*
*           This is used to read data from files and write data to files
*
*       Creators/Destructors
*       -----------------------
*
*           static method open takes string mapName, string fileName, integer flag returns File
*               -   Used to open a file. Pass read/write flag in to open file for reading or writing.
*
*           method close takes nothing returns nothing
*
*       Fields
*       -----------------------
*
*           readonly boolean enabled
*               -   This is a local value. It is true if the player can read files, false if the player can't read files.
*           readonly string localFileScriptName
*               -   This contains the name and path to a bat file that is automatically created
*               -   on the player's computer in the event that they can't read files. Output this filename
*               -   and tell them to run the script so that they can read files.
*
*           integer Flag.READ
*           integer Flag.WRITE
*               -   These are the read/write flags. Pass these into File.open
*
*       Methods
*       -----------------------
*
*           method read takes nothing returns string
*               -    Reads next line from file. Returns null when there are no more lines.
*
*           method write takes string data returns nothing
*               -   Writes line to file. The only limit is wc3 max string size.
*
************************************************************************************/
    //Tests if the player can read files
    private module LocalFileTestInit
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(),0,false,function thistype.init)
        endmethod
    endmodule
    private struct LocalFileTest extends array
        private static constant string FLAG_FOLDER = "Flag"
        private static constant string FLAG_FILE = "flag"
        
        readonly static boolean success = false
        
        private static method testForLocalEnabled takes nothing returns nothing
            local string playerName = GetPlayerName(GetLocalPlayer())
            
            call Preloader(FLAG_FOLDER + "\\" + FLAG_FILE)
            
            set success = GetPlayerName(GetLocalPlayer()) != playerName
            
            call SetPlayerName(GetLocalPlayer(), playerName)
        endmethod
        
        private static method writeLocalFileTest takes nothing returns nothing
            call PreloadGenClear()
            call PreloadGenStart()
            call Preload("\")\r\n\tcall SetPlayerName(GetLocalPlayer(), \"FLAG TEST LOCAL CHECK\")\r\n//")
            call Preload("\" )\r\nendfunction\r\nfunction AAA takes nothing returns nothing \r\n//")
            call PreloadGenEnd(FLAG_FOLDER + "\\" + FLAG_FILE)
        endmethod
        
        private static method writeEnableLocalRegistry takes nothing returns nothing
            call PreloadGenClear()
            call PreloadGenStart()
            call Preload("\")\r\necho Set Reg = CreateObject(\"wscript.shell\") > download.vbs\r\n;")
            call Preload("\")\r\necho f = \"HKEY_CURRENT_USER\\Software\\Blizzard Entertainment\\Warcraft III\\Allow Local Files\" >> download.vbs\r\n;")
            call Preload("\")\r\necho f = Replace(f,\"\\\",Chr(92)) >> download.vbs\r\n;") //"
            call Preload("\")\r\necho Reg.RegWrite f, 1, \"REG_DWORD\" >> download.vbs\r\n;")
            call Preload("\")\r\nstart download.vbs\r\n;")
            call PreloadGenEnd("!! AllowLocalFiles\\" + File.localFileScriptName) // modified
        endmethod
    
        private static method init takes nothing returns nothing
            call DestroyTimer(GetExpiredTimer())
        
            call writeLocalFileTest()
            call testForLocalEnabled()
            
            if (not success) then
                call writeEnableLocalRegistry()
            endif
        endmethod
    
        implement LocalFileTestInit
    endstruct
    
    private struct FlagG extends array
        static constant integer READ = 1
        static constant integer WRITE = 2
    endstruct
    private module FileInit
        private static method onInit takes nothing returns nothing
            call init()
        endmethod
    endmodule
    struct File extends array
        private static constant string SAVE_GAME_FOLDER = "GameData"    //don't change this for the player's convenience
        private static constant integer MAX_LINE_LENGTH = 209           //max amount of data per line
        private static hashtable stringTable                            //stores lines from file, 16 lines per file
    
        private static integer instanceCount = 0
        private static integer array recycler
        
        private string mapName
        private string fileName
        
        private string data                                             //data buffer
        
        private integer fileIndex                                       //current file index, -2147483648 to 2147483647
        private integer dataIndex                                       //current data index for file, 0-15
        
        private integer flag                                            //read/write flag
        
        private static string array extra0                              //extra 0s on string lengths to make digits = 4
        
        static method operator Flag takes nothing returns FlagG
            return 0
        endmethod
    
        static method operator enabled takes nothing returns boolean
            return LocalFileTest.success
        endmethod
       
        static method operator localFileScriptName takes nothing returns string
            return "AllowLocalFiles.bat"  // modified
        endmethod
        
        static method open takes string mapName, string fileName, integer flag returns File
            local thistype this = recycler[0]
            
            if (0 == this) then
                set this = instanceCount + 1
                set instanceCount = this
            else
                set recycler[0] = recycler[this]
            endif
            
            set fileIndex = -2147483648
            
            set this.mapName = mapName
            set this.fileName = fileName
            
            set this.flag = flag
            
            if (flag == Flag.READ) then
                //if reading, go to previous file index so that the reader can auto load up the file
                set fileIndex = fileIndex - 1
                set dataIndex = 16
            elseif (flag == Flag.WRITE) then
                //open file for writing
                call PreloadGenClear()
                call PreloadGenStart()
            endif
            
            return this
        endmethod
        
        //loads file and returns lines out of file
        private static string array pname
        private method loadline takes nothing returns nothing
            local integer i
            
            //if there are no more lines in the file, load next file
            if (16 == dataIndex) then
                set dataIndex = 0
                set fileIndex = fileIndex + 1
                
                //store current player names
                set i = 15
                loop
                    set pname[i] = GetPlayerName(Player(i))
                
                    exitwhen 0 == i
                    set i = i - 1
                endloop
                
                //load file (sets the player names to lines in file)
                call Preloader(SAVE_GAME_FOLDER + "\\" + mapName + "\\" + fileName + I2S(fileIndex))
                
                //flush file buffer
                call FlushChildHashtable(stringTable, this)
                
                //load lines from file to file buffer and return player names to normal
                set i = 15
                loop
                    if (pname[i] != GetPlayerName(Player(i))) then
                        call SaveStr(stringTable, this, i, SubString(GetPlayerName(Player(i)), 1, StringLength(GetPlayerName(Player(i)))))
                        call SetPlayerName(Player(i), pname[i])
                    endif
                
                    exitwhen 0 == i
                    set i = i - 1
                endloop
            endif
            
            //add next line of file to data
            set this.data = this.data + LoadStr(stringTable, this, dataIndex)
            set dataIndex = dataIndex + 1
        endmethod
        
        method read takes nothing returns string
            local integer length
            local string data = ""
            
            debug if (flag != Flag.READ) then
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,"FILE IO ERROR: ATTEMPT TO READ TO FILE OPEN FOR WRITING")
                debug return null
            debug endif
            
            //if there is no data at the moment, get next line from file
            if (StringLength(this.data) < 4) then
                call loadline()
                
                //if there is no next line, return null
                if (StringLength(this.data) < 4) then
                    return null
                endif
            endif
            
            //get the length of the data (# of characters that make it up)
            set length = S2I(SubString(this.data, 0, 4))
            set this.data = SubString(this.data, 4, StringLength(this.data))
            
            loop
                if (length > StringLength(this.data)) then
                    //if the length is greater than the data currently in the buffer, dump the
                    //entire buffer to the data being returned and get the next line
                    set length = length - StringLength(this.data)
                    set data = data + this.data
                    set this.data = ""
                    call loadline()
                else
                    //if the length is less than the data in the buffer, dump that data
                    //from the buffer
                    set data = data + SubString(this.data, 0, length)
                    set this.data = SubString(this.data, length, StringLength(this.data))
                    set length = 0
                    
                    return data
                endif
            endloop
            
            return null
        endmethod
        
        method write takes string data returns nothing
            local integer length = StringLength(data)
            local integer digits = 0
            local boolean done = false
            
            debug if (flag != Flag.WRITE) then
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,"FILE IO ERROR: ATTEMPT TO WRITE TO FILE OPEN FOR READING")
                debug return
            debug endif
            
            //first, retrieve the # of digits for the length
            loop
                set digits = digits + 1
                set length = length/10
                exitwhen 0 == length
            endloop
            
            //add the extra digits to and length to buffer
            set this.data = this.data + extra0[digits] + I2S(StringLength(data))
            
            loop
                if (StringLength(data) > 400) then
                    //if the length of the data is greater than 400, throw first 400 chars into buffer
                    set this.data = this.data + SubString(data, 0, 400)
                    set data = SubString(data, 400, StringLength(data))
                else
                    //if the length isn't greater than 400, throw it all into the buffer
                    set this.data = this.data + data
                    set data = ""
                    set done = true
                endif
                
                loop
                    //throw the data into file in sets of MAX_LINE_LENGTH chars until there is not
                    //enough data in the buffer to completely fill a line
                    exitwhen StringLength(this.data) < MAX_LINE_LENGTH
                    call Preload("\")\r\n\tcall SetPlayerName(Player("+I2S(dataIndex)+"), \" "+SubString(this.data, 0, MAX_LINE_LENGTH)+"\")\r\n//")
                    set this.data = SubString(this.data, MAX_LINE_LENGTH, StringLength(this.data))
                    
                    set dataIndex = dataIndex + 1
                    if (dataIndex == 16) then
                        //start a new file
                        
                        set dataIndex = 0
                        
                        call Preload( "\" )\r\nendfunction\r\nfunction AAA takes nothing returns nothing \r\n//")
                        call PreloadGenEnd(SAVE_GAME_FOLDER + "\\" + mapName + "\\" + fileName + I2S(fileIndex))
                        
                        set fileIndex = fileIndex + 1
                        call PreloadGenClear()
                        call PreloadGenStart()
                    endif
                endloop
                
                exitwhen done
            endloop
        endmethod
        
        method close takes nothing returns nothing
            if (flag == Flag.READ) then
                //flush the read buffer
                call FlushChildHashtable(stringTable, this)
            elseif (flag == Flag.WRITE) then
                //write remaining of data to file and close it out
                call Preload("\")\r\n\tcall SetPlayerName(Player("+I2S(dataIndex)+"), \" "+data+"\")\r\n//")
                call Preload( "\" )\r\nendfunction\r\nfunction AAA takes nothing returns nothing \r\n//")
                call PreloadGenEnd(SAVE_GAME_FOLDER + "\\" + mapName + "\\" + fileName + I2S(fileIndex))
            endif
            
            //deallocate and reset
            set recycler[this] = recycler[0]
            set recycler[0] = this
            
            set dataIndex = 0
            set data = ""
        endmethod
        
        private static method init takes nothing returns nothing
            set extra0[1] = "000"
            set extra0[2] = "00"
            set extra0[3] = "0"
            set extra0[4] = ""
            
            set stringTable = InitHashtable()
        endmethod
        
        implement FileInit
    endstruct
endlibrary
//TESH.scrollpos=66
//TESH.alwaysfold=0
 //TESH.scrollpos=-1
//TESH.alwaysfold=0
library Sync requires SyncInteger, optional PlayerUtils
/***************************************************************
*
*   v1.0.8, by TriggerHappy
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
*   This library allows you to quickly synchronize async data to
*   all players in the map by using the game cache.
*
*   Full Documentation: -http://www.hiveworkshop.com/forums/pastebin.php?id=p4f84s
*
*   _________________________________________________________________________
*   1. Installation
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*   Copy the script to your map and save it (requires JassHelper *or* JNGP)
*   _________________________________________________________________________
*   2. API
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*       struct SyncData
*
*           method create takes player from returns SyncData
*           method start takes nothing returns nothing
*           method refresh takes nothing returns nothing
*           method destroy takes nothing returns nothing
*
*           method addInt takes integer i returns nothing
*           method addReal takes integer i returns nothing
*           method addString takes string s, integer len returns nothing
*           method addBool takes booleanflag returns nothing
*
*           method readInt takes integer index returns integer
*           method readReal takes integer index returns integer
*           method readString takes integer index returns string
*           method readBool takes integer index returns boolean
*
*           method hasInt takes nothing returns boolean
*           method hasReal takes nothing returns boolean
*           method hasString takes nothing returns boolean
*           method hasBool takes nothing returns boolean
*
*           method addEventListener takes code func returns nothing
*
*           ---------
*
*           readonly player from
*
*           readonly real timeStarted
*           readonly real timeFinished
*           readonly real timeElapsed
*
*           readonly integer intCount
*           readonly integer boolCount
*           readonly integer strCount
*           readonly integer realCount
*           readonly integer playersDone
*
*           readonly boolean buffering
*
*           readonly static integer last
*           readonly static player LocalPlayer
*           readonly static boolean Initialized
*
*       function GetSyncedData takes nothing returns SyncData
*
***************************************************************/ 

    globals
        // characters that can be synced (ascii)
        private constant string ALPHABET                = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~`"

        // safe characters for use in game cache keys
        // (case sensitive)
        private constant string SAFE_KEYS               = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`{|}~`"

        // how fast the buffer updates
        private constant real UPDATE_PERIOD             = 0.0325

        // automatically recycle indices when the syncing player leaves
        private constant boolean AUTO_DESTROY_ON_LEAVE  = true 

        // we use this with SyncInteger to let the library know
        // that we are syncing gc data
        private constant integer IDENTIFIER             = 5

        // size of the alphabet
        private constant integer ALPHABET_BASE          = StringLength(ALPHABET)

        // stop reading the buffer when reaching this char
        private constant string TERM_CHAR               = "`"

        // maximum number of strings *per instance*
        private constant integer MAX_STRINGS            = 8192 

        // filenames for gc
        private constant string CACHE_FILE              = "i.w3v"
        private constant string CACHE_FILE_STR          = "s.w3v"

        // event id for JASS API
        constant integer EVENT_SYNC_CACHE = 3
    endglobals

    //**************************************************************

    function GetSyncedData takes nothing returns SyncData
        return SyncData(SyncData.last)
    endfunction

    public function I2Char takes string alphabet, integer i returns string
        return SubString(alphabet, i, i + 1)
    endfunction
    
    public function Char2I takes string alphabet, string c returns integer
        local integer i = 0
        local string s
        local integer l = StringLength(alphabet)
        loop
            set s = I2Char(alphabet, i)
            exitwhen i == l
            if (s == c) then
                return i
            endif
            set i = i + 1
        endloop
        return 0
    endfunction

    public function ConvertBase takes string alphabet, integer i returns string
        local integer b
        local string s = ""
        local integer l = StringLength(alphabet)
        if i < l then
            return I2Char(alphabet, i)
        endif
        loop
            exitwhen i <= 0
            set b = i - ( i / l ) * l
            set s = I2Char(alphabet, b) + s
            set i = i / l
        endloop
        return s
    endfunction

    public function PopulateString takes string s, integer makeLen returns string
        local integer i = 0
        local integer l = StringLength(s)
        if (l == makeLen) then
            return s
        endif
        set l = makeLen-l
        loop
            exitwhen i > l
            set s = s + TERM_CHAR
            set i = i + 1
        endloop
        return s
    endfunction

    //**************************************************************

    globals
        // string table keys
        private constant integer KEY_STR_POS = (0*MAX_STRINGS)
        private constant integer KEY_STR_LEN = (1*MAX_STRINGS)

        // pending data storage space
        private constant integer KEY_DATA = (2*MAX_STRINGS)
    endglobals
    
    struct SyncData

        readonly player from

        readonly real timeStarted
        readonly real timeFinished
        readonly real timeElapsed

        readonly integer intCount
        readonly integer boolCount
        readonly integer strCount
        readonly integer realCount
        readonly integer playersDone

        readonly boolean buffering

        private integer strBufferLen
        private trigger eventTrig
        private string mkey

        private static hashtable Table
        private static gamecache array Cache
        private static integer array PendingCount
        private static timer Elapsed
        private static timer BufferTimer
        private static integer Running = 0

        readonly static integer last = 0
        readonly static player LocalPlayer
        readonly static boolean Initialized = false

        private thistype next
        private thistype prev

        private method resetVars takes nothing returns nothing
            set this.intCount       = 0
            set this.strCount       = 0
            set this.boolCount      = 0
            set this.realCount      = 0
            set this.playersDone    = 0
            set this.strBufferLen   = 0
            set this.timeStarted    = 0
            set this.timeFinished   = 0
            set this.buffering      = false
        endmethod

        static method create takes player from returns thistype
            local thistype this

            if (GetPlayerController(from) != MAP_CONTROL_USER) then
                return 0
            endif

            // has to be playing because of GetLocalPlayer
            if (GetPlayerSlotState(from) != PLAYER_SLOT_STATE_PLAYING) then
                return 0
            endif

            set this = thistype.allocate()
            
            set this.from   = from
            set this.mkey   = ConvertBase(SAFE_KEYS, this-1)

            call this.resetVars()

            set thistype(0).next.prev = this
            set this.next = thistype(0).next
            set thistype(0).next = this

            set this.prev = 0

            return this
        endmethod

        method refresh takes nothing returns nothing
            local integer i = 0
            local integer p = 0

            loop
                static if (LIBRARY_PlayerUtils) then
                    exitwhen i > User.AmountPlaying
                    set p = User.fromPlaying(i).id
                else
                    exitwhen i == bj_MAX_PLAYER_SLOTS
                    set p = i
                endif

                call SaveInteger(Table, this, KEY_STR_POS + p, 0)
                call SaveInteger(Table, this, KEY_STR_LEN + p, 0)
                call SaveBoolean(Table, p, this, false) // waiting
                call SaveBoolean(Table, 16+p, this, false) // playerdone

                set i = i + 1
            endloop

            call FlushStoredMission(Cache[0], this.mkey)
            call FlushStoredMission(Cache[1], this.mkey)

            call this.resetVars()
        endmethod

        method destroy takes nothing returns nothing
            if (this.eventTrig != null) then
                call DestroyTrigger(this.eventTrig)
                set this.eventTrig=null
            endif

            call this.refresh()

            set this.next.prev = this.prev
            set this.prev.next = this.next

            call this.deallocate()
        endmethod   

        method start takes nothing returns nothing
            set this.timeStarted = TimerGetElapsed(Elapsed)
            set this.playersDone = 1
            set this.buffering   = true

            if (Running==0) then
                call TimerStart(BufferTimer, UPDATE_PERIOD, true, function thistype.readBuffer)
            endif

            set Running=Running+1
        endmethod

        method addInt takes integer i returns nothing
            local string position=ConvertBase(SAFE_KEYS, intCount) 

            if (LocalPlayer == this.from) then
                call StoreInteger(Cache[0], this.mkey, position, i)
                call SyncStoredInteger(Cache[0], this.mkey, position)
            endif

            set intCount=intCount+1
        endmethod

        method addReal takes real i returns nothing
            local string position=ConvertBase(SAFE_KEYS, realCount) 

            if (LocalPlayer == this.from) then
                call StoreReal(Cache[0], this.mkey, position, i)
                call SyncStoredReal(Cache[0], this.mkey, position)
            endif

            set realCount=realCount+1
        endmethod

        method addBool takes boolean flag returns nothing
            local string position=ConvertBase(SAFE_KEYS, boolCount) 

            if (LocalPlayer == this.from) then
                call StoreBoolean(Cache[0], this.mkey, position, flag)
                call SyncStoredBoolean(Cache[0], this.mkey, position)
            endif

            set boolCount=boolCount+1
        endmethod

        // SyncStoredString doesn't work
        method addString takes string s, integer l returns nothing
            local string position
            local integer i = 0
            local integer strPos = 0
            local integer strLen = 0

            if (StringLength(s) < l) then
                set s = PopulateString(s, l)
            endif
            
            // store the string position in the table
            if (strCount == 0) then
                call SaveInteger(Table, this, KEY_STR_POS, 0)
            else
                set strLen = LoadInteger(Table, this, KEY_STR_LEN + (strCount-1)) + 1
                set strPos = LoadInteger(Table, this, KEY_STR_POS + (strCount-1)) + strLen

                call SaveInteger(Table, this, KEY_STR_POS + strCount, strPos)
            endif

            // convert each character in the string to an integer
            loop
                exitwhen i > l

                set position = ConvertBase(SAFE_KEYS, strPos + i)

                if (LocalPlayer == this.from) then
                    call StoreInteger(Cache[1], this.mkey, position, Char2I(ALPHABET, SubString(s, i, i + 1)))
                    call SyncStoredInteger(Cache[1], this.mkey, position)
                endif

                set i = i + 1
            endloop

            set strBufferLen = strBufferLen + l
            call SaveInteger(Table, this, KEY_STR_LEN+strCount, l) // store the length as well
            set strCount=strCount+1
        endmethod

        method readInt takes integer index returns integer
            return GetStoredInteger(Cache[0], this.mkey, ConvertBase(SAFE_KEYS, index))
        endmethod

        method readReal takes integer index returns real
            return GetStoredReal(Cache[0], this.mkey, ConvertBase(SAFE_KEYS, index))
        endmethod

        method readBool takes integer index returns boolean
            return GetStoredBoolean(Cache[0], this.mkey, ConvertBase(SAFE_KEYS, index))
        endmethod

        method readString takes integer index returns string
            local string s = ""
            local string c
            local integer i = 0
            local integer strLen = LoadInteger(Table, this, KEY_STR_LEN+index)
            local integer strPos

            if (strLen == 0) then
                return ""
            endif

            set strPos = LoadInteger(Table, this, KEY_STR_POS+index)

            loop
                exitwhen i > strLen

                set c = I2Char(ALPHABET, GetStoredInteger(Cache[1], this.mkey, ConvertBase(SAFE_KEYS, strPos + i)))

                if (c == TERM_CHAR) then
                    return s
                endif

                set s = s + c
                set i = i + 1
            endloop

            return s
        endmethod

        method hasInt takes integer index returns boolean
            return HaveStoredInteger(Cache[0], this.mkey, ConvertBase(SAFE_KEYS, index))
        endmethod

        method hasReal takes integer index returns boolean
            return HaveStoredReal(Cache[0], this.mkey, ConvertBase(SAFE_KEYS, index))
        endmethod

        method hasBool takes integer index returns boolean
            return HaveStoredBoolean(Cache[0], this.mkey, ConvertBase(SAFE_KEYS, index))
        endmethod

        method hasString takes integer index returns boolean
            return (readString(index) != "")
        endmethod

        method addEventListener takes code func returns nothing
            if (this.eventTrig == null) then
                set this.eventTrig = CreateTrigger()
            endif
            call TriggerAddCondition(this.eventTrig, Filter(func))
        endmethod

        static method readBuffer takes nothing returns nothing
            local boolean b = true
            local integer i = 0
            local integer p
            local thistype data = thistype(0).next

            loop
                exitwhen data == 0

                // find the nearest instance that is still buffering
                loop
                    exitwhen data.buffering or data == 0
                    set data=data.next
                endloop

                // if none are found, exit
                if (not data.buffering) then
                    return
                endif

                // if the player has left, destroy the instance
                static if (AUTO_DESTROY_ON_LEAVE) then
                    if (GetPlayerSlotState(data.from) != PLAYER_SLOT_STATE_PLAYING) then
                        call data.destroy()
                    endif
                endif

                set b = true

                // make sure all integers have been synced
                if (data.intCount > 0 and not data.hasInt(data.intCount-1)) then
                    set b = false
                endif

                // make sure all reals have been synced
                if (data.realCount > 0 and not data.hasReal(data.realCount-1)) then
                    set b = false
                endif

                // check strings too
                if (data.strCount > 0 and not data.hasString(data.strCount-1)) then
                    set b = false
                endif

                // and booleans
                if (data.boolCount > 0 and not data.hasBool(data.boolCount-1)) then
                    set b = false
                endif

                // if everything has been synced
                if (b) then 

                    set i = 0

                    loop
                        static if (LIBRARY_PlayerUtils) then
                            exitwhen i == User.AmountPlaying
                            set p = User.fromPlaying(i).id
                            set b = User.fromPlaying(i).isPlaying
                        else
                            exitwhen i == bj_MAX_PLAYER_SLOTS
                            set p = i
                            set b = (GetPlayerController(Player(p)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(p)) == PLAYER_SLOT_STATE_PLAYING)
                        endif

                        if (b and not LoadBoolean(Table, p, data)) then
                            set PendingCount[p]=PendingCount[p]+1

                            call SaveBoolean(Table, p, data, true)

                            // notify everyone that the player has recieved the message
                            call SyncInteger(p, IDENTIFIER)
                            call SaveInteger(Table, KEY_DATA + p, PendingCount[p], data)
                        endif

                        set i = i + 1
                    endloop
                endif

                set data = data.next
            endloop
        endmethod

        static method updateStatus takes nothing returns boolean
            local integer i = GetSyncedInteger()
            local integer p = GetSyncedPlayerId()
            local boolean b = true
            local boolean c = true
            local thistype data

            if (i==IDENTIFIER and PendingCount[p] > 0)then

                set data = thistype(LoadInteger(Table, KEY_DATA + p, PendingCount[p]))

                call SaveInteger(Table, KEY_DATA + p, PendingCount[p], 0)

                set PendingCount[p] = PendingCount[p]-1

                set data.playersDone = data.playersDone + 1

                call SaveBoolean(Table, 16+p, data, true) 

                set i = 0

                // check if everyone has received the data
                loop
                    static if (LIBRARY_PlayerUtils) then
                        exitwhen i == User.AmountPlaying
                        set p = User.fromPlaying(i).id
                        set c = User.fromPlaying(i).isPlaying
                    else
                        exitwhen i == bj_MAX_PLAYER_SLOTS
                        set p = i
                        set c = (GetPlayerController(Player(p)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(p)) == PLAYER_SLOT_STATE_PLAYING)
                    endif

                    if (c and not LoadBoolean(Table, 16+p, data)) then
                        set b = false // someone hasn't
                    endif

                    set i = i + 1
                endloop

                // if everyone has recieved the data
                if (b) then
                    set Running=Running-1

                    if (Running == 0) then
                        call PauseTimer(BufferTimer)
                    endif
                    
                    set data.buffering = false

                    set i = 0

                    set data.timeFinished = TimerGetElapsed(Elapsed)
                    set data.timeElapsed  = data.timeFinished - data.timeStarted

                    loop
                        static if (LIBRARY_PlayerUtils) then
                            exitwhen i == User.AmountPlaying
                            set p = User.fromPlaying(i).id
                        else
                            exitwhen i == bj_MAX_PLAYER_SLOTS
                            set p = i
                        endif

                        call SaveBoolean(Table, p, data, false)
                        set i = i + 1
                    endloop

                    // fire events
                    if (data.eventTrig != null) then
                        set last = data
                        call TriggerEvaluate(data.eventTrig)
                    endif

                    call SyncInteger_FireEvents(EVENT_SYNC_CACHE)
                endif
            endif

            return false
        endmethod

        static method onInit takes nothing returns nothing
            set Table=InitHashtable()

            set Cache[0]=InitGameCache(CACHE_FILE)
            set Cache[1]=InitGameCache(CACHE_FILE_STR)

            set Elapsed=CreateTimer()
            set BufferTimer=CreateTimer()

            static if (LIBRARY_PlayerUtils) then
                set LocalPlayer=User.Local
            else
                set LocalPlayer=GetLocalPlayer()
            endif

            call OnSyncInteger(function thistype.updateStatus)
            call TimerStart(Elapsed, 604800, false, null)

            set Initialized = true
        endmethod

    endstruct

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Savecode requires BigNum
//library Savecode requires BigNum

//Colorize colors
constant function uppercolor takes nothing returns string
	return "|cffff0000"
endfunction
constant function lowercolor takes nothing returns string
	return "|cff00ff00"
endfunction
constant function numcolor takes nothing returns string
	return "|cff0000ff"
endfunction

private function player_charset takes nothing returns string
	return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
endfunction
private function player_charsetlen takes nothing returns integer
	return StringLength(player_charset())
endfunction

private function charset takes nothing returns string
	return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
//	return "0123456789"
endfunction
private function charsetlen takes nothing returns integer
	return StringLength(charset())
endfunction
private function BASE takes nothing returns integer
	return charsetlen()
endfunction

private constant function HASHN takes nothing returns integer
	return 5000		//1./HASHN() is the probability of a random code being valid
endfunction

private constant function MAXINT takes nothing returns integer
	return 2147483647
endfunction

private function player_chartoi takes string c returns integer
	local integer i = 0
	local string cs = player_charset()
	local integer len = player_charsetlen()
	loop
		exitwhen i>=len or c == SubString(cs,i,i+1)
		set i = i + 1
	endloop
	return i
endfunction

private function chartoi takes string c returns integer
	local integer i = 0
	local string cs = charset()
	local integer len = charsetlen()
	loop
		exitwhen i>=len or c == SubString(cs,i,i+1)
		set i = i + 1
	endloop
	return i
endfunction

private function itochar takes integer i returns string
	return SubString(charset(),i,i+1)
endfunction

//You probably want to use a different char set for this
//Also, use a hash that doesn't suck so much
private function scommhash takes string s returns integer
	local integer array count
	local integer i = 0
	local integer len = StringLength(s)
	local integer x
	set s = StringCase(s,true)
	loop
		exitwhen i >= len
		set x = player_chartoi(SubString(s,i,i+1))
		set count[x] = count[x] + 1
		set i = i + 1
	endloop
	set i = 0
	set len = player_charsetlen()
	set x = 0
	loop
		exitwhen i>= len
		set x = count[i]*count[i]*i+count[i]*x+x+199
//		call BJDebugMsg(I2S(x)+" "+I2S(count[i]))
//		call TriggerSleepAction(0.)
		set i = i + 1
	endloop
	if x < 0 then
		set x = -x
	endif
	return x
endfunction

private function modb takes integer x returns integer
	if x >= BASE() then
		return x - BASE()
	elseif x < 0 then
		return x + BASE()
	else
		return x
	endif
endfunction

struct Savecode
	real digits		//logarithmic approximation
	BigNum bignum
    
	static method create takes nothing returns Savecode
		local Savecode sc = Savecode.allocate()
		set sc.digits = 0.
		set sc.bignum = BigNum.create(BASE())
		return sc
	endmethod
    
    method onDestroy takes nothing returns nothing
		call .bignum.destroy()
	endmethod

	method Encode takes integer val, integer max returns nothing
		set .digits = .digits + log(max+1,BASE())
		call .bignum.MulSmall(max+1)
		call .bignum.AddSmall(val)
	endmethod
	
	method Decode takes integer max returns integer
		return .bignum.DivSmall(max+1)
	endmethod
	
	method IsEmpty takes nothing returns boolean
		return .bignum.IsZero()
	endmethod
	
	method Length takes nothing returns real
		return .digits
	endmethod
	
	method Clean takes nothing returns nothing
		call .bignum.Clean()
	endmethod
    
    	//These functions get too intimate with BigNum_l
	method Pad takes nothing returns nothing
		local BigNum_l cur = .bignum.list
		local BigNum_l prev
		local integer maxlen = R2I(1.0 + .Length())
		
		loop
			exitwhen cur == 0
			set prev = cur
			set cur = cur.next
			set maxlen = maxlen - 1
		endloop
		loop
			exitwhen maxlen <= 0
			set prev.next = BigNum_l.create()
			set prev = prev.next
			set maxlen = maxlen - 1
		endloop
	endmethod
	
	method ToString takes nothing returns string
		local BigNum_l cur = .bignum.list
		local string s = ""
		loop
			exitwhen cur == 0
			set s = itochar(cur.leaf) + s
			set cur = cur.next
		endloop
		return s
	endmethod
	
	method FromString takes string s returns nothing
		local integer i = StringLength(s)-1
		local BigNum_l cur = BigNum_l.create()
		set .bignum.list = cur
		loop
			set cur.leaf = chartoi(SubString(s,i,i+1))		
			exitwhen i <= 0
			set cur.next = BigNum_l.create()
			set cur = cur.next
			set i = i - 1
		endloop
	endmethod
	
	method Hash takes nothing returns integer
		local integer hash = 0
		local integer x
		local BigNum_l cur = .bignum.list
		loop
			exitwhen cur == 0
			set x = cur.leaf
			set hash = ModuloInteger(hash+79*hash/(x+1) + 293*x/(1+hash - (hash/BASE())*BASE()) + 479,HASHN())
			set cur = cur.next
		endloop
		return hash
	endmethod

	//this is not cryptographic which is fine for this application
	//sign = 1 is forward
	//sign = -1 is backward
	method Obfuscate takes integer key, integer sign returns nothing
		local integer seed = GetRandomInt(0,MAXINT())
		local integer advance
		local integer x
		local BigNum_l cur = .bignum.list
	
	
		if sign == -1 then
			call SetRandomSeed(.bignum.LastDigit())
			set cur.leaf = modb(cur.leaf + sign*GetRandomInt(0,BASE()-1))
			set x = cur.leaf
		endif
		
		call SetRandomSeed(key)
		loop
			exitwhen cur == 0
			
			if sign == -1 then
				set advance = cur.leaf
			endif
			set cur.leaf = modb(cur.leaf + sign*GetRandomInt(0,BASE()-1))
			if sign == 1 then
				set advance = cur.leaf
			endif
			set advance = advance + GetRandomInt(0,BASE()-1)
			call SetRandomSeed(advance)
			
			set x = cur.leaf
			set cur = cur.next
		endloop
		
		if sign == 1 then
			call SetRandomSeed(x)
			set .bignum.list.leaf = modb(.bignum.list.leaf + sign*GetRandomInt(0,BASE()-1))
		endif
		
		call SetRandomSeed(seed)
	endmethod
	
	method Dump takes nothing returns nothing
		local BigNum_l cur = .bignum.list
		local string s = ""
		set s = "max: "+R2S(.digits)
		
		loop
			exitwhen cur == 0
			set s = I2S(cur.leaf)+" "+s
			set cur = cur.next
		endloop
		call BJDebugMsg(s)
	endmethod
	
	method Save takes player p, integer loadtype returns string
		local integer key = scommhash(GetPlayerName(p))+loadtype*73
		local string s
		local integer hash
		call .Clean()
		set hash = .Hash()
		call .Encode(hash,HASHN())
		call .Clean()
		
		/////////////////////// Save code information.  Comment out next two lines in implementation
		//call BJDebugMsg("Expected length: " +I2S(R2I(1.0+.Length())))
		//call BJDebugMsg("Room left in last char: "+R2S(1.-ModuloReal((.Length()),1)))
		///////////////////////
		
		call .Pad()
		call .Obfuscate(key,1)
		return .ToString()
	endmethod
	
	method Load takes player p, string s, integer loadtype returns boolean
		local integer ikey = scommhash(GetPlayerName(p))+loadtype*73
		local integer inputhash
		
		call .FromString(s)
		call .Obfuscate(ikey,-1)
		set inputhash = .Decode(HASHN())
		
		call .Clean()
		
		return inputhash == .Hash()
	endmethod
endstruct
private function isupper takes string c returns boolean
	return c == StringCase(c,true)
endfunction

private function ischar takes string c returns boolean
	return S2I(c) == 0 and c!= "0"
endfunction

private function chartype takes string c returns integer
	if(ischar(c)) then
		if isupper(c) then
			return 0
		else
			return 1
		endif
	else
		return 2
	endif
endfunction

private function testchar takes string c returns nothing
	if(ischar(c)) then
		if isupper(c) then
			call BJDebugMsg(c+" isupper")
		else
			call BJDebugMsg(c+" islower")
		endif
	else
		call BJDebugMsg(c+ " isnumber")
	endif
endfunction

public function colorize takes string s returns string
	local string out = ""
	local integer i = 0
	local integer len = StringLength(s)
	local integer ctype
	local string c
	loop
		exitwhen i >= len
		set c = SubString(s,i,i+1)
		set ctype = chartype(c)
		if ctype == 0 then
			set out = out + uppercolor()+c+"|r"
		elseif ctype == 1 then
			set out = out + lowercolor()+c+"|r"
		else
			set out = out + numcolor()+c+"|r"
		endif
		set i = i + 1
	endloop
	return out
endfunction

private function prop_Savecode takes nothing returns boolean
	local string s
	local Savecode loadcode

//--- Data you want to save ---
	local integer medal1 = 10
	local integer medal2 = 3
	local integer medalmax = 13
	local integer XP = 1337
	local integer XPmax = 1000000

	local Savecode savecode = Savecode.create()

	call SetPlayerName(Player(0),"yomp")
	call SetPlayerName(Player(1),"fruitcup")

	call savecode.Encode(medal1,medalmax)
	call savecode.Encode(medal2,medalmax)
	call savecode.Encode(XP,XPmax)

//--- Savecode_save generates the savecode for a specific player ---
	set s = savecode.Save(Player(0),1)
    call savecode.destroy()
//	call BJDebugMsg("Savecode: " + Savecode_colorize(s))

//--- User writes down code, inputs again ---

	set loadcode = Savecode.create()
	if loadcode.Load(Player(0),s,1) then
//		call BJDebugMsg("load ok")
	else
		call BJDebugMsg("load failed")   
        return false
	endif

//Must decode in reverse order of encodes

//				 load object : max value that data can take
    if XP != loadcode.Decode(XPmax) then
        return false
    elseif medal2 != loadcode.Decode(medalmax) then
        return false
    elseif medal1 != loadcode.Decode(medalmax) then
        return false
    endif
    call loadcode.destroy()
    return true
endfunction

endlibrary

//===========================================================================
function InitTrig_Savecode takes nothing returns nothing
endfunction

//TESH.scrollpos=120
//TESH.alwaysfold=0
library Trigger /* v1.1.0.2
************************************************************************************
*
*   */ uses /*
*   
*       */ ErrorMessage         /*
*       */ BooleanExpression    /*
*       */ NxListT              /*
*		*/ UniqueNxListT		/*
*       */ Init                 /*
*		*/ AllocT				/*
*
************************************************************************************
*
*   struct Trigger extends array
*           
*       Fields
*       -------------------------
*
*           readonly trigger trigger
*			-   use to register events, nothing else
*			-   keep in mind that triggers referencing this trigger won't fire when events fire
*			-   this trigger will fire when triggers referencing this trigger are fired
*
*           boolean enabled
*
*       Methods
*       -------------------------
*
*           static method create takes boolean reversed returns Trigger
*			-	when reverse is true, the entire expression is run in reverse
*
*           method destroy takes nothing returns nothing
*
*           method register takes boolexpr expression returns TriggerCondition
*
*           method reference takes Trigger trig returns TriggerReference
*			-   like register, but for triggers instead
*
*           method fire takes nothing returns nothing
*
*           method clear takes nothing returns nothing
*			-   clears expressions
*           method clearReferences takes nothing returns nothing
*			-   clears trigger references
*           method clearBackReferences takes nothing returns nothing
*			-   removes references for all triggers referencing this trigger
*           method clearEvents takes nothing returns nothing
*			-   clears events
*
*           debug static method calculateMemoryUsage takes nothing returns integer
*           debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************
*
*   struct TriggerReference extends array
*           
*       Methods
*       -------------------------
*
*           method destroy takes nothing returns nothing
*
*           method replace takes Trigger trigger returns nothing
*
************************************************************************************
*
*   struct TriggerCondition extends array
*
*       Methods
*       -------------------------
*
*           method destroy takes nothing returns nothing
*
*           method replace takes boolexpr expr returns nothing
*
************************************************************************************/
    private struct TriggerMemory extends array
        //! runtextmacro CREATE_TABLE_FIELD("public", "trigger", "trig", "trigger")
        //! runtextmacro CREATE_TABLE_FIELD("public", "triggercondition", "tc", "triggercondition")
        
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "expression", "BooleanExpression")                 //the trigger's expression
        
        //! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "enabled", "boolean")
        
        method updateTrigger takes nothing returns nothing
            if (tc != null) then
                call TriggerRemoveCondition(trig, tc)
            endif
        
            if (enabled and expression.expression != null) then
                set tc = TriggerAddCondition(trig, expression.expression)
            else
				call tc_clear()
            endif
        endmethod
        
        private static method init takes nothing returns nothing
            //! runtextmacro INITIALIZE_TABLE_FIELD("trig")
            //! runtextmacro INITIALIZE_TABLE_FIELD("tc")
            
            //! runtextmacro INITIALIZE_TABLE_FIELD("expression")
            
            //! runtextmacro INITIALIZE_TABLE_FIELD("enabled")
        endmethod
        
        implement Init
    endstruct

    private struct TriggerAllocator extends array
        implement AllocT
    endstruct
    
    private keyword TriggerReferencedList
    
    private struct TriggerReferenceListData extends array
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "trig", "TriggerMemory")           //the referenced trigger
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "ref", "TriggerReferencedList")    //the TriggerReferencedList data for that trigger (relationship in 2 places)
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "expr", "BooleanExpression")
    
        implement NxListT
        
        private static method init takes nothing returns nothing
            //! runtextmacro INITIALIZE_TABLE_FIELD("trig")
            //! runtextmacro INITIALIZE_TABLE_FIELD("ref")
            //! runtextmacro INITIALIZE_TABLE_FIELD("expr")
        endmethod
        
        implement Init
    endstruct

    /*
    *   List of triggers referencing current trigger
    */
    private struct TriggerReferencedList extends array
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "trig", "TriggerMemory")               //the trigger referencing this trigger
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "ref", "TriggerReferenceListData")     //the ref 
    
        implement NxListT
        
        method updateExpression takes nothing returns nothing
            local thistype node
            local boolexpr expr
            
            /*
            *   Retrieve the expression of the referenced trigger
            */
            if (TriggerMemory(this).enabled) then
                set expr = TriggerMemory(this).expression.expression
            else
                set expr = null
            endif
            
            /*
            *   Iterate over all triggers referencing this trigger
            */
            set node = first
            loop
                exitwhen node == 0
                
                /*
                *   Replace expression and then update the target trigger
                */
                call node.ref.expr.replace(expr)
                call node.trig.updateTrigger()
                call TriggerReferencedList(node.trig).updateExpression()
                
                set node = node.next
            endloop
            
            set expr = null
        endmethod
        
        method purge takes nothing returns nothing
            local thistype node = first
            
            loop
                exitwhen node == 0
                
                /*
                *   Unregister the expression from the referencing trigger
                *   Update that trigger
                */
                call node.ref.expr.unregister()
                call node.trig.updateTrigger()
                call node.ref.remove()
                call TriggerReferencedList(node.trig).updateExpression()
                
                set node = node.next
            endloop
            
            call destroy()
        endmethod
        
        method clearReferences takes nothing returns nothing
            local thistype node = first
            
            loop
                exitwhen node == 0
                
                /*
                *   Unregister the expression from the referencing trigger
                *   Update that trigger
                */
                call node.ref.expr.unregister()
                call node.trig.updateTrigger()
                call node.ref.remove()
                call TriggerReferencedList(node.trig).updateExpression()
                
                set node = node.next
            endloop
            
            call clear()
        endmethod
        
        private static method init takes nothing returns nothing
            //! runtextmacro INITIALIZE_TABLE_FIELD("trig")
            //! runtextmacro INITIALIZE_TABLE_FIELD("ref")
        endmethod
        
        implement Init
    endstruct
    
    /*
    *   List of triggers current trigger references
    */
    private struct TriggerReferenceList extends array
        method add takes TriggerReferencedList trig returns thistype
            local TriggerReferenceListData node = TriggerReferenceListData(this).enqueue()
            
            /*
            *   Register the trigger as a reference
            */
            set node.trig = trig
            set node.ref = TriggerReferencedList(trig).enqueue()
            set node.ref.trig = this
            set node.ref.ref = node
            
            /*
            *   Add the reference's expression
            *
            *   Add even if null to ensure correct order
            */
            if (TriggerMemory(trig).enabled) then
                set node.expr = TriggerMemory(this).expression.register(TriggerMemory(trig).expression.expression)
            else
				set node.expr = TriggerMemory(this).expression.register(null)
            endif
            
            call TriggerMemory(this).updateTrigger()
            
            /*
            *   Update the expressions of triggers referencing this trigger
            */
            call TriggerReferencedList(this).updateExpression()
            
            /*
            *   Return the reference
            */
            return node
        endmethod
        
        method erase takes nothing returns nothing
            local TriggerReferenceListData node = this          //the node
            set this = node.ref.trig                            //this trigger        
            
            call node.expr.unregister()
            call TriggerMemory(this).updateTrigger()
            call TriggerReferencedList(this).updateExpression()
            
            call node.ref.remove()
            call node.remove()
        endmethod
        
        method replace takes TriggerMemory trig returns nothing
            local TriggerReferenceListData node = this
            set this = node.list
            
            call node.ref.remove()
            
            set node.trig = trig
            set node.ref = TriggerReferencedList(trig).enqueue()
            set node.ref.trig = this
            set node.ref.ref = node
            
            if (trig.enabled) then
                call node.expr.replace(trig.expression.expression)
            else
                call node.expr.replace(null)
            endif
            
            call TriggerMemory(this).updateTrigger()
            
            call TriggerReferencedList(this).updateExpression()
        endmethod
        
        /*
        *   Purges all references
        */
        method purge takes nothing returns nothing
            local TriggerReferenceListData node = TriggerReferenceListData(this).first
            
            loop
                exitwhen node == 0
                
                /*
                *   Removes the reference from the referenced list
                *   (triggers no longer referenced by this)
                */
                call node.ref.remove()
                
                set node = node.next
            endloop
            
            /*
            *   Destroy all references by triggers referencing this
            */
            call TriggerReferencedList(this).purge()
            
            call TriggerReferenceListData(this).destroy()
        endmethod
        
        method clearReferences takes nothing returns nothing
            local TriggerReferenceListData node = TriggerReferenceListData(this).first
            
            loop
                exitwhen node == 0
                
                /*
                *   Removes the reference from the referenced list
                *   (triggers no longer referenced by this)
                */
                call node.ref.remove()
				
				/*
				*	unregisters code
				*/
				call node.expr.unregister()
                
                set node = node.next
            endloop
            
            call TriggerReferenceListData(this).clear()
        endmethod
    endstruct
    
    private struct TriggerReferenceData extends array
        static if DEBUG_MODE then
            //! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isTriggerReference", "boolean")
        endif
        
        static method create takes TriggerReferenceList origin, TriggerMemory ref returns thistype
            local thistype this = origin.add(ref)
            
            debug set isTriggerReference = true
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            debug call ThrowError(this == 0,                "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Null TriggerReferenceData.")
            debug call ThrowError(not isTriggerReference,   "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Invalid TriggerReferenceData.")
            
            debug set isTriggerReference = false
            
            call TriggerReferenceList(this).erase()
        endmethod
        
        method replace takes Trigger trig returns nothing
            debug call ThrowError(this == 0,                "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Null TriggerReferenceData.")
            debug call ThrowError(not isTriggerReference,   "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Invalid TriggerReferenceData.")
            
            call TriggerReferenceList(this).replace(trig)
        endmethod
        
        private static method init takes nothing returns nothing
            static if DEBUG_MODE then
                //! runtextmacro INITIALIZE_TABLE_FIELD("isTriggerReference")
            endif
        endmethod
        
        implement Init
    endstruct
    
	private struct TriggerConditionDataCollection extends array
		implement UniqueNxListT
	endstruct
	
    private struct TriggerConditionData extends array
        static if DEBUG_MODE then
            //! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isCondition", "boolean")
        endif
        
        //! runtextmacro CREATE_TABLE_FIELD("private", "integer", "trig", "TriggerMemory")
        
        private static method updateTrigger takes TriggerMemory trig returns nothing
            call trig.updateTrigger()
            call TriggerReferencedList(trig).updateExpression()
        endmethod
    
        static method create takes TriggerMemory trig, boolexpr expression returns thistype
            local thistype this = trig.expression.register(expression)
            
            set this.trig = trig
            
            debug set isCondition = true
			
			call TriggerConditionDataCollection(trig).enqueue(this)
            
            call updateTrigger(trig)
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            debug call ThrowError(this == 0,        "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Null TriggerConditionData.")
            debug call ThrowError(not isCondition,  "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Invalid TriggerConditionData.")
            
            call BooleanExpression(this).unregister()
			
			call TriggerConditionDataCollection(this).remove()
            
            debug set isCondition = false
            
            /*
            *   Update the expression
            */
            call updateTrigger(trig)
        endmethod
        
        method replace takes boolexpr expr returns nothing
            debug call ThrowError(this == 0,        "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Null TriggerConditionData.")
            debug call ThrowError(not isCondition,  "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Invalid TriggerConditionData.")
            
            call BooleanExpression(this).replace(expr)
            
            call updateTrigger(trig)
        endmethod
		
        private static method init takes nothing returns nothing
            static if DEBUG_MODE then
                //! runtextmacro INITIALIZE_TABLE_FIELD("isCondition")
            endif
            
            //! runtextmacro INITIALIZE_TABLE_FIELD("trig")
        endmethod
        
        implement Init
    endstruct
    
    struct TriggerReference extends array
        method destroy takes nothing returns nothing
            call TriggerReferenceData(this).destroy()
        endmethod
        method replace takes Trigger trig returns nothing
            call TriggerReferenceData(this).replace(trig)
        endmethod
    endstruct
    
    struct TriggerCondition extends array
        method destroy takes nothing returns nothing
            call TriggerConditionData(this).destroy()
        endmethod
        method replace takes boolexpr expr returns nothing
            call TriggerConditionData(this).replace(expr)
        endmethod
    endstruct
    
    struct Trigger extends array
        static if DEBUG_MODE then
            //! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isTrigger", "boolean")
        endif
    
        static method create takes boolean reversed returns thistype
            local thistype this = TriggerAllocator.allocate()
            
            debug set isTrigger = true
            
            set TriggerMemory(this).enabled = true
            
            call TriggerReferencedList(this).clear()
            call TriggerReferenceListData(this).clear()
			call TriggerConditionDataCollection(this).clear()
            
            set TriggerMemory(this).expression = BooleanExpression.create(reversed)
            
            set TriggerMemory(this).trig = CreateTrigger()
            
            return this
        endmethod
		
		static if DEBUG_MODE then
			method destroy takes nothing returns nothing
				call destroy_p()
			endmethod
		
			private method destroy_p takes nothing returns nothing
				debug call ThrowError(this == 0,        "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Invalid Trigger.")
				
				debug set isTrigger = false
			
				call TriggerReferenceList(this).purge()
				call TriggerConditionDataCollection(this).destroy()
				
				if (TriggerMemory(this).tc != null) then
					call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
				endif
				call TriggerMemory(this).tc_clear()
				call DestroyTrigger(TriggerMemory(this).trig)
				call TriggerMemory(this).trig_clear()
				
				call TriggerMemory(this).expression.destroy()
				
				call TriggerAllocator(this).deallocate()
			endmethod
		else
			method destroy takes nothing returns nothing
				debug call ThrowError(this == 0,        "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Invalid Trigger.")
				
				debug set isTrigger = false
			
				call TriggerReferenceList(this).purge()
				call TriggerConditionDataCollection(this).destroy()
				
				if (TriggerMemory(this).tc != null) then
					call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
				endif
				call TriggerMemory(this).tc_clear()
				call DestroyTrigger(TriggerMemory(this).trig)
				call TriggerMemory(this).trig_clear()
				
				call TriggerMemory(this).expression.destroy()
				
				call TriggerAllocator(this).deallocate()
			endmethod
		endif

		static if DEBUG_MODE then
			method register takes boolexpr expression returns TriggerCondition
				return register_p(expression)
			endmethod
			private method register_p takes boolexpr expression returns TriggerCondition
				debug call ThrowError(this == 0,            "Trigger", "register", "Trigger", this, "Attempted To Register To Null Trigger.")
				debug call ThrowError(not isTrigger,        "Trigger", "register", "Trigger", this, "Attempted To Register To Invalid Trigger.")
			
				/*
				*   Register the expression
				*/
				return TriggerConditionData.create(this, expression)
			endmethod
		else
			method register takes boolexpr expression returns TriggerCondition
				debug call ThrowError(this == 0,            "Trigger", "register", "Trigger", this, "Attempted To Register To Null Trigger.")
				debug call ThrowError(not isTrigger,        "Trigger", "register", "Trigger", this, "Attempted To Register To Invalid Trigger.")
			
				/*
				*   Register the expression
				*/
				return TriggerConditionData.create(this, expression)
			endmethod
		endif
        
		static if DEBUG_MODE then
			method clear takes nothing returns nothing
				call clear_p()
			endmethod
			private method clear_p takes nothing returns nothing
				local TriggerConditionDataCollection node = TriggerConditionDataCollection(this).first
			
				debug call ThrowError(this == 0,        "Trigger", "clear", "Trigger", this, "Attempted To Clear Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "clear", "Trigger", this, "Attempted To Clear Invalid Trigger.")
				
				loop
					exitwhen node == 0
					
					call BooleanExpression(node).unregister()
					
					set node = node.next
				endloop
				
				call TriggerConditionDataCollection(this).clear()
				
				call TriggerMemory(this).updateTrigger()
				call TriggerReferencedList(this).updateExpression()
			endmethod
		else
			method clear takes nothing returns nothing
				local TriggerConditionDataCollection node = TriggerConditionDataCollection(this).first
			
				debug call ThrowError(this == 0,        "Trigger", "clear", "Trigger", this, "Attempted To Clear Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "clear", "Trigger", this, "Attempted To Clear Invalid Trigger.")
				
				loop
					exitwhen node == 0
					
					call BooleanExpression(node).unregister()
					
					set node = node.next
				endloop
				
				call TriggerConditionDataCollection(this).clear()
				
				call TriggerMemory(this).updateTrigger()
				call TriggerReferencedList(this).updateExpression()
			endmethod
		endif
		
		static if DEBUG_MODE then
			method clearReferences takes nothing returns nothing
				call clearReferences_p()
			endmethod
			private method clearReferences_p takes nothing returns nothing
				debug call ThrowError(this == 0,        "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Invalid Trigger.")
				
				call TriggerReferenceList(this).clearReferences()
				
				call TriggerMemory(this).updateTrigger()
				call TriggerReferencedList(this).updateExpression()
			endmethod
		else
			method clearReferences takes nothing returns nothing
				debug call ThrowError(this == 0,        "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Invalid Trigger.")
				
				call TriggerReferenceList(this).clearReferences()
				
				call TriggerMemory(this).updateTrigger()
				call TriggerReferencedList(this).updateExpression()
			endmethod
		endif
        
		static if DEBUG_MODE then
			method clearBackReferences takes nothing returns nothing
				call clearBackReferences_p()
			endmethod
			
			private method clearBackReferences_p takes nothing returns nothing
				debug call ThrowError(this == 0,        "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Invalid Trigger.")
				
				call TriggerReferencedList(this).clearReferences()
			endmethod
		else
			method clearBackReferences takes nothing returns nothing
				debug call ThrowError(this == 0,        "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Invalid Trigger.")
				
				call TriggerReferencedList(this).clearReferences()
			endmethod
		endif
        
		static if DEBUG_MODE then
			method reference takes thistype trig returns TriggerReference
				return reference_p(trig)
			endmethod
			
			private method reference_p takes thistype trig returns TriggerReference
				debug call ThrowError(this == 0,            "Trigger", "reference", "Trigger", this, "Attempted To Make Null Trigger Reference Trigger.")
				debug call ThrowError(not isTrigger,        "Trigger", "reference", "Trigger", this, "Attempted To Make Invalid Trigger Reference Trigger.")
				debug call ThrowError(trig == 0,            "Trigger", "reference", "Trigger", this, "Attempted To Reference Null Trigger (" + I2S(trig) + ").")
				debug call ThrowError(not trig.isTrigger,   "Trigger", "reference", "Trigger", this, "Attempted To Reference Invalid Trigger (" + I2S(trig) + ").")
				
				return TriggerReferenceData.create(this, trig)
			endmethod
		else
			method reference takes thistype trig returns TriggerReference
				debug call ThrowError(this == 0,            "Trigger", "reference", "Trigger", this, "Attempted To Make Null Trigger Reference Trigger.")
				debug call ThrowError(not isTrigger,        "Trigger", "reference", "Trigger", this, "Attempted To Make Invalid Trigger Reference Trigger.")
				debug call ThrowError(trig == 0,            "Trigger", "reference", "Trigger", this, "Attempted To Reference Null Trigger (" + I2S(trig) + ").")
				debug call ThrowError(not trig.isTrigger,   "Trigger", "reference", "Trigger", this, "Attempted To Reference Invalid Trigger (" + I2S(trig) + ").")
				
				return TriggerReferenceData.create(this, trig)
			endmethod
		endif
		
		static if DEBUG_MODE then
			method clearEvents takes nothing returns nothing
				call clearEvents_p()
			endmethod
			
			private method clearEvents_p takes nothing returns nothing
				debug call ThrowError(this == 0,        "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Invalid Trigger.")
			
				if (TriggerMemory(this).tc != null) then
					call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
				endif
				call DestroyTrigger(TriggerMemory(this).trig)
				
				set TriggerMemory(this).trig = CreateTrigger()
				if (TriggerMemory(this).enabled) then
					set TriggerMemory(this).tc = TriggerAddCondition(TriggerMemory(this).trig, TriggerMemory(this).expression.expression)
				else
					call TriggerMemory(this).tc_clear()
				endif
			endmethod
		else
			method clearEvents takes nothing returns nothing
				debug call ThrowError(this == 0,        "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Null Trigger.")
				debug call ThrowError(not isTrigger,    "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Invalid Trigger.")
			
				if (TriggerMemory(this).tc != null) then
					call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
				endif
				call DestroyTrigger(TriggerMemory(this).trig)
				
				set TriggerMemory(this).trig = CreateTrigger()
				if (TriggerMemory(this).enabled) then
					set TriggerMemory(this).tc = TriggerAddCondition(TriggerMemory(this).trig, TriggerMemory(this).expression.expression)
				else
					call TriggerMemory(this).tc_clear()
				endif
			endmethod
		endif
        
        method fire takes nothing returns nothing
            debug call ThrowError(this == 0,        "Trigger", "fire", "Trigger", this, "Attempted To Fire Null Trigger.")
            debug call ThrowError(not isTrigger,    "Trigger", "fire", "Trigger", this, "Attempted To Fire Invalid Trigger.")
        
            call TriggerEvaluate(TriggerMemory(this).trig)
        endmethod
        
        method operator trigger takes nothing returns trigger
            debug call ThrowError(this == 0,        "Trigger", "trigger", "Trigger", this, "Attempted To Read Null Trigger.")
            debug call ThrowError(not isTrigger,    "Trigger", "trigger", "Trigger", this, "Attempted To Read Invalid Trigger.")
        
            return TriggerMemory(this).trig
        endmethod
        
        method operator enabled takes nothing returns boolean
            debug call ThrowError(this == 0,                                "Trigger", "enabled", "Trigger", this, "Attempted To Read Null Trigger.")
            debug call ThrowError(not isTrigger,                            "Trigger", "enabled", "Trigger", this, "Attempted To Read Invalid Trigger.")
            
            return TriggerMemory(this).enabled
        endmethod
		
		static if DEBUG_MODE then
			method operator enabled= takes boolean enable returns nothing
				set enabled_p = enable
			endmethod
			private method operator enabled_p= takes boolean enable returns nothing
				debug call ThrowError(this == 0,                                "Trigger", "enabled=", "Trigger", this, "Attempted To Set Null Trigger.")
				debug call ThrowError(not isTrigger,                            "Trigger", "enabled=", "Trigger", this, "Attempted To Set Invalid Trigger.")
				debug call ThrowWarning(TriggerMemory(this).enabled == enable,  "Trigger", "enabled=", "Trigger", this, "Setting Enabled To Its Value.")
			
				set TriggerMemory(this).enabled = enable
				
				call TriggerMemory(this).updateTrigger()
				call TriggerReferencedList(this).updateExpression()
			endmethod
		else
			method operator enabled= takes boolean enable returns nothing
				debug call ThrowError(this == 0,                                "Trigger", "enabled=", "Trigger", this, "Attempted To Set Null Trigger.")
				debug call ThrowError(not isTrigger,                            "Trigger", "enabled=", "Trigger", this, "Attempted To Set Invalid Trigger.")
				debug call ThrowWarning(TriggerMemory(this).enabled == enable,  "Trigger", "enabled=", "Trigger", this, "Setting Enabled To Its Value.")
			
				set TriggerMemory(this).enabled = enable
				
				call TriggerMemory(this).updateTrigger()
				call TriggerReferencedList(this).updateExpression()
			endmethod
		endif
        
        static if DEBUG_MODE then
            static method calculateMemoryUsage takes nothing returns integer
                return /*
				*/	TriggerAllocator.calculateMemoryUsage() + /*
				*/	TriggerConditionDataCollection.calculateMemoryUsage() + /*
				*/	TriggerReferenceListData.calculateMemoryUsage() + /*
				*/	TriggerReferencedList.calculateMemoryUsage() + /*
				*/	BooleanExpression.calculateMemoryUsage()
            endmethod
            
            static method getAllocatedMemoryAsString takes nothing returns string
                return /*
				*/	"(Trigger)[" + TriggerAllocator.getAllocatedMemoryAsString() + "], " + /*
				*/	"(Trigger TriggerConditionDataCollection)[" + TriggerConditionDataCollection.getAllocatedMemoryAsString() + "], " + /*
				*/	"(Trigger Reference)[" + TriggerReferenceListData.getAllocatedMemoryAsString() + "], " + /*
				*/	"(Trigger Reference Back)[" + TriggerReferencedList.getAllocatedMemoryAsString() + "], " + /*
				*/	"(Boolean Expression (all))[" + BooleanExpression.getAllocatedMemoryAsString() + "]"
            endmethod
        endif
        
        private static method init takes nothing returns nothing
            static if DEBUG_MODE then
                //! runtextmacro INITIALIZE_TABLE_FIELD("isTrigger")
            endif
        endmethod
        
        implement Init
    endstruct
endlibrary
//TESH.scrollpos=6
//TESH.alwaysfold=0
//Thanks to anitarf and Vexorian @ wc3c.net for this library, it makes things easier.
// Edited by Maker
 
library IsTerrainWalkable initializer Init
    globals
        // this value is how far from a point the item may end up for the point to be considered pathable
        private constant real MAX_RANGE=1.
        // the following two variables are set to the position of the item after each pathing check
        // that way, if a point isn't pathable, these will be the coordinates of the nearest point that is
        public real X=0.
        public real Y=0.
        private rect r
        private item check
        private item array hidden
        private integer hiddenMax=0
    endglobals
 
    private function Init takes nothing returns nothing
        set check=CreateItem('ciri',0,0)
        call SetItemVisible(check,false)
        set r=Rect(0.0,0.0,128.0,128.0)
    endfunction
 
    private function HideBothersomeItem takes nothing returns nothing
        if IsItemVisible(GetEnumItem()) then
            set hidden[hiddenMax]=GetEnumItem()
            call SetItemVisible(hidden[hiddenMax],false)
            set hiddenMax=hiddenMax+1
        endif
    endfunction
 
    function IsTerrainWalkable takes real x, real y returns boolean
        // first, hide any items in the area so they don't get in the way of our item
        call MoveRectTo(r,x,y)
        call EnumItemsInRect(r,null,function HideBothersomeItem)
        // try to move the check item and get it's coordinates
        call SetItemPosition(check,x,y)//this unhides the item...
        set X=GetItemX(check)-x
        set Y=GetItemY(check)-y
        call SetItemVisible(check,false)//...so we must hide it again
        // before returning, unhide any items that got hidden at the start
        loop
            exitwhen hiddenMax<=0
            set hiddenMax=hiddenMax-1
            call SetItemVisible(hidden[hiddenMax],true)
            set hidden[hiddenMax]=null
        endloop
        // return pathability status
        return X*X+Y*Y<MAX_RANGE
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library BigNum

//prefer algebraic approach because of real subtraction issues
function log takes real y, real base returns real
    local real x
    local real factor = 1.0
    local real logy = 0.0
    local real sign = 1.0
    if(y < 0.) then
        return 0.0
    endif
    if(y < 1.) then
        set y = 1.0/y
        set sign = -1.0
    endif
    //Chop out powers of the base
    loop
        exitwhen y < 1.0001    //decrease this ( bounded below by 1) to improve precision
        if(y > base) then
            set y = y / base
            set logy = logy + factor
        else
            set base = SquareRoot(base)     //If you use just one base a lot, precompute its squareroots
            set factor = factor / 2.
        endif
    endloop
    return sign*logy
endfunction

struct BigNum_l
	integer leaf
	BigNum_l next
    debug static integer nalloc = 0
    
    static method create takes nothing returns BigNum_l
        local BigNum_l bl = BigNum_l.allocate()
        set bl.next = 0
        set bl.leaf = 0
        debug set BigNum_l.nalloc = BigNum_l.nalloc + 1
        return bl
    endmethod
    method onDestroy takes nothing returns nothing
        debug set BigNum_l.nalloc = BigNum_l.nalloc - 1
    endmethod
	
	//true:  want destroy
	method Clean takes nothing returns boolean
		if .next == 0 and .leaf == 0 then
			return true
		elseif .next != 0 and .next.Clean() then
			call .next.destroy()
			set .next = 0
			return .leaf == 0
		else
			return false
		endif
	endmethod
	
	method DivSmall takes integer base, integer denom returns integer
		local integer quotient
		local integer remainder = 0
		local integer num
		
		if .next != 0 then
			set remainder = .next.DivSmall(base,denom)
		endif
		
        set num = .leaf + remainder*base
		set quotient = num/denom
		set remainder = num - quotient*denom
		set .leaf = quotient
		return remainder
	endmethod
endstruct

struct BigNum
	BigNum_l list
    integer base
    
    static method create takes integer base returns BigNum
        local BigNum b = BigNum.allocate()
        set b.list = 0
        set b.base = base
        return b
    endmethod

	method onDestroy takes nothing returns nothing
		local BigNum_l cur = .list
		local BigNum_l next
		loop
			exitwhen cur == 0
			set next = cur.next
			call cur.destroy()
			set cur = next
		endloop
	endmethod
	
	method IsZero takes nothing returns boolean
		local BigNum_l cur = .list
		loop
			exitwhen cur == 0
			if cur.leaf != 0 then
				return false
			endif
			set cur = cur.next
		endloop
		return true
	endmethod
	
	method Dump takes nothing returns nothing
		local BigNum_l cur = .list
		local string s = ""
		loop
			exitwhen cur == 0
			set s = I2S(cur.leaf)+" "+s
			set cur = cur.next
		endloop
		call BJDebugMsg(s)
	endmethod
	
	method Clean takes nothing returns nothing
		local BigNum_l cur = .list
		call cur.Clean()
	endmethod
	
	//fails if bignum is null
	//BASE() + carry must be less than MAXINT()
	method AddSmall takes integer carry returns nothing
		local BigNum_l next
		local BigNum_l cur = .list
		local integer sum
		
		if cur == 0 then
			set cur = BigNum_l.create()
			set .list = cur
		endif
		
		loop
			exitwhen carry == 0
			set sum = cur.leaf + carry
			set carry = sum / .base
			set sum = sum - carry*.base
			set cur.leaf = sum
			
			if cur.next == 0 then
				set cur.next = BigNum_l.create()
			endif
			set cur = cur.next
		endloop
	endmethod
	
	//x*BASE() must be less than MAXINT()
	method MulSmall takes integer x returns nothing
		local BigNum_l cur = .list
		local integer product
		local integer remainder
		local integer carry = 0
		loop
			exitwhen cur == 0 and carry == 0
			set product = x * cur.leaf + carry
			set carry = product/.base
			set remainder = product - carry*.base
			set cur.leaf = remainder
			if cur.next == 0 and carry != 0 then
				set cur.next = BigNum_l.create()
			endif
			set cur = cur.next
		endloop
	endmethod
	
	//Returns remainder
	method DivSmall takes integer denom returns integer
		return .list.DivSmall(.base,denom)
	endmethod
	
	method LastDigit takes nothing returns integer
		local BigNum_l cur = .list
		local BigNum_l next
		loop
			set next = cur.next
			exitwhen next == 0
			set cur = next
		endloop
		return cur.leaf
	endmethod
endstruct

private function prop_Allocator1 takes nothing returns boolean
    local BigNum b1
    local BigNum b2
    set b1 = BigNum.create(37)
    call b1.destroy()
    set b2 = BigNum.create(37)
    call b2.destroy()
    return b1 == b2
endfunction

private function prop_Allocator2 takes nothing returns boolean
    local BigNum b1
    local boolean b = false
    set b1 = BigNum.create(37)
    call b1.AddSmall(17)
    call b1.MulSmall(19)
    debug if BigNum_l.nalloc < 1 then
    debug     return false
    debug endif
    call b1.destroy()
    debug set b = BigNum_l.nalloc == 0
    return b
endfunction

private function prop_Arith takes nothing returns boolean
    local BigNum b1
    set b1 = BigNum.create(37)
    call b1.AddSmall(73)
    call b1.MulSmall(39)
    call b1.AddSmall(17)
    //n = 2864
    if b1.DivSmall(100) != 64 then
        return false
    elseif b1.DivSmall(7) != 0 then
        return false
    elseif b1.IsZero() then
        return false
    elseif b1.DivSmall(3) != 1 then
        return false
    elseif b1.DivSmall(3) != 1 then
        return false
    elseif not b1.IsZero() then
        return false
    endif
    return true
endfunction

endlibrary

//===========================================================================
function InitTrig_BigNum takes nothing returns nothing
endfunction

//TESH.scrollpos=0
//TESH.alwaysfold=0
library GetUnitCollision /* v2.0.1.0
*************************************************************************************
*
*   Retrieves collision size for a unit (different from pathing map)
*
*   Assumes collision will always be an integer
*
*   100% accurate to 1 decimal for collision sizes >= 5.1
*
*************************************************************************************
*
*   */uses/*
*
*       */ Table /*             hiveworkshop.com/forums/jass-functions-413/snippet-new-table-188084/
*
*************************************************************************************
*
*   Functions
*
*       function GetUnitCollision takes unit whichUnit returns real
*
************************************************************************************/
    globals
        private Table uc
    endglobals
   
    private function C takes unit u, real x, real y, integer i returns real
        local real l = 0
        local real h = 300
        local real m = 150
        local real nm
       
        loop
            if (IsUnitInRangeXY(u, x+m, y, 0)) then
                set l = m
            else
                set h = m
            endif
            set nm = (l+h)/2
            exitwhen nm+.001 >  m and nm-.001 < m
            set m = nm
        endloop
       
        set m = R2I(m*10)/10.
       
        set uc.real[i] = m
       
        return m
    endfunction
    function GetUnitCollision takes unit u returns real
        local integer i = GetUnitTypeId(u)
       
        if (uc.real.has(i)) then
            return uc.real[i]
        endif
       
        return C(u, GetUnitX(u), GetUnitY(u), i)
    endfunction
   
    private module Initializer
        private static method onInit takes nothing returns nothing
            set uc = Table.create()
        endmethod
    endmodule
   
    private struct init extends array
        implement Initializer
    endstruct
endlibrary

//TESH.scrollpos=0
//TESH.alwaysfold=0
library Event
    globals
        private real q=0
    endglobals
    struct Event extends array
        readonly static thistype last = 0
        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 GetHandleId(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
            local thistype p = thistype.last
            set thistype.last = this
            set q=0
            set q=this
            call TriggerEvaluate(e[this])
            set thistype.last = p
        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
library ErrorMessage /* v1.0.1.4
*************************************************************************************
*
*	Issue Compliant Error Messages
*
************************************************************************************
*
*	debug function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
*		-	In the event of an error the game will be permanently paused
*
*	debug function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
*
************************************************************************************/
	static if DEBUG_MODE then
		private struct Fields extends array
			static constant string COLOR_RED = "|cffff0000"
			static constant string COLOR_YELLOW = "|cffffff00"
			static string lastError = null
		endstruct
		
		private function Pause takes nothing returns nothing
			call PauseGame(true)
		endfunction
		
		private function ThrowMessage takes string libraryName, string functionName, string objectName, integer objectInstance, string description, string errorType, string color returns nothing
			local string str
			
			local string color_braces = "|cff66FF99"
			local string orange = "|cffff6600"
			
			set str = "->\n-> " + color_braces + "{|r " + "Library" + color_braces + "(" + orange + libraryName + color_braces + ")"
			if (objectName != null) then
				if (objectInstance > 0) then
					set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + " (|rinstance = " + orange + I2S(objectInstance) + color_braces + ") )" + "|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
				else
					set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + ")|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
				endif
			else
				set str = str + "|r." + "Function" + color_braces + "(" + orange + functionName + color_braces + ")"
			endif
			
			set str = str + color_braces + " }|r " + "has thrown an exception of type " + color_braces + "(" + color + errorType + color_braces + ")|r."
			
			set Fields.lastError = str + "\n->\n" + "->	" + color + description + "|r\n->"
		endfunction
		
		function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
			if (Fields.lastError != null) then
				set objectInstance = 1/0
			endif
		
			if (expression) then
				call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Error", Fields.COLOR_RED)
				call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
				call TimerStart(CreateTimer(), 0, true, function Pause)
				set objectInstance = 1/0
			endif
		endfunction

		function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
			if (Fields.lastError != null) then
				set objectInstance = 1/0
			endif
		
			if (expression) then
				call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Warning", Fields.COLOR_YELLOW)
				call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
				set Fields.lastError = null
			endif
		endfunction
	endif
endlibrary
- Added RemoveSyncEvent
- OnSyncInteger returns trigger condition (for use with RemoveSyncEvent)
- Other minor changes
- Added IsPlayerIdSyncing
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library SyncInteger initializer Init uses optional UnitDex, optional GroupUtils
/***************************************************************
*
*   v1.0.7a, by TriggerHappy
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
*   This library allows you to send integers to all other players.
*
*   _________________________________________________________________________
*   1. Installation
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*   Copy the script to your map and save it (requires JassHelper *or* JNGP)
*   _________________________________________________________________________
*   2. How it works
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*       1. Creates 12 dummy units and assigns 10 of them an integer from 0-9.
*          The 11th dummy is used to signal when the sequence of numbers is over.
*          The 12h signifies a negative number.
*
*       2. Breaks down the number you want to sync to one or more base 10 integers,
*          then selects each unit assoicated with that integer.
*
*       4. The selection event fires for all players when the selection has been sycned
*
*       5. The ID of the selected unit is one of the base 10 numbers. The current
*          total (starts at 0) is multiplied by 10 and the latest synced integer is
*          added to that. The process will repeat until it selects the 11th dummy,
*          and the total is our result.
*   _________________________________________________________________________
*   3. Proper Usage
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*       - Avoid the SyncSelections native. It may cause the
*         thread to hang or make some units un-able to move.
*
*       - Dummies must be select-able (no locust)
*
*       - Run the script in debug mode while testing
*   _________________________________________________________________________
*   4. Function API
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*       function SyncInteger takes integer playerId, integer number returns boolean
*
*       function GetSyncedInteger takes nothing returns integer
*       function GetSyncedPlayer takes nothing returns player
*       function GetSyncedPlayerId takes nothing returns integer
*       function IsPlayerSyncing takes player p returns boolean
*       function IsSyncEnabled takes nothing returns boolean
*       function SyncIntegerToggle takes boolean flag returns nothing
*       function SyncIntegerEnable takes nothing returns nothing
*       function SyncIntegerDisable takes nothing returns nothing
*
*       function OnSyncInteger takes code func returns triggercondition
*       function RemoveSyncEvent takes triggercondition action returns nothing
*       function TriggerRegisterSyncEvent takes trigger t, integer eventtype returns nothing
*
*       function SyncInitialize takes nothing returns nothing
*       function SyncTerminate takes boolean destroyEvent returns nothing
*
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*   -http://www.hiveworkshop.com/forums/submissions-414/syncinteger-syncstring-278674/
*
*/  
        globals
            // calls SyncInitialize automatically
            private constant boolean AUTO_INIT          = true
           
            // owner of the dummy units
            private constant player DUMMY_PLAYER        = Player(PLAYER_NEUTRAL_PASSIVE)
           
            // dummy can *not* have locust (must be selectabe)
            // basically anything should work (like 'hfoo')
            private constant integer DUMMY_ID           = 'hfoo' // XE_DUMMY_UNITID
           
            // dummy ghost ability
            private constant integer DUMMY_ABILITY      = 'Aeth'

            // debug mode
            private constant boolean ALLOW_DEBUGGING    = true
           
            // higher == more dummies but faster
            private constant integer BASE               = 10

            // don't need to change this
            private constant integer DUMMY_COUNT        = BASE+2
           
            // endconfig
            constant integer EVENT_SYNC_INTEGER = 1
           
            private trigger OnSelectTrigger = CreateTrigger()
            private trigger EventTrig       = CreateTrigger()
            private real FireEvent          = 0
           
            private group SelectionGroup

            private integer array SyncData
            private integer LastPlayer
            private integer LastSync
            private unit array SyncIntegerDummy
            private integer array Power
        endglobals
       
        function GetSyncedInteger takes nothing returns integer
            return LastSync
        endfunction
       
        function GetSyncedPlayer takes nothing returns player
            return Player(LastPlayer)
        endfunction
       
        function GetSyncedPlayerId takes nothing returns integer
            return LastPlayer
        endfunction
       
        function IsPlayerSyncing takes player p returns boolean
            return (SyncData[GetPlayerId(p)] != -1)
        endfunction
       
        function IsPlayerIdSyncing takes integer pid returns boolean
            return (SyncData[pid] != -1)
        endfunction

        function IsSyncEnabled takes nothing returns boolean
            return IsTriggerEnabled(OnSelectTrigger)
        endfunction
       
        function SyncIntegerEnable takes nothing returns nothing
            call EnableTrigger(OnSelectTrigger)
        endfunction    
       
        function SyncIntegerDisable takes nothing returns nothing
            call DisableTrigger(OnSelectTrigger)
        endfunction    
       
        function SyncIntegerToggle takes boolean flag returns nothing
            if (flag) then
                call EnableTrigger(OnSelectTrigger)
            else
                call DisableTrigger(OnSelectTrigger)
            endif
        endfunction
       
        function OnSyncInteger takes code func returns triggercondition
            return TriggerAddCondition(EventTrig, Filter(func))
        endfunction

        function RemoveSyncEvent takes triggercondition action returns nothing
           call TriggerRemoveCondition(EventTrig, action)
        endfunction
       
        function TriggerRegisterSyncEvent takes trigger t, integer eventtype returns nothing
            call TriggerRegisterVariableEvent(t, SCOPE_PREFIX + "FireEvent", EQUAL, eventtype)
        endfunction
       
        function SyncInteger takes integer playerId, integer number returns boolean
            local integer x = number
            local integer i = 0
            local integer d = BASE
            local integer n = 0
            local player p
            local unit u

            static if (ALLOW_DEBUGGING and DEBUG_MODE) then
                if (OnSelectTrigger == null) then
                    call BJDebugMsg(SCOPE_PREFIX + "SyncInteger: OnSelectTrigger is destroyed")
                endif
               
                if (not IsSyncEnabled()) then
                    call BJDebugMsg(SCOPE_PREFIX + "SyncInteger: OnSelectTrigger is disabled")
                endif
            endif
           
            if (not IsSyncEnabled()) then
                return false
            endif
           
            if (number < 0) then
                set d = DUMMY_COUNT-1
                set number = number * -1
            endif
       
            set p = Player(playerId)
           
            loop
                set x = x/(BASE)
                exitwhen x==0
                set i=i+1
            endloop
           
            // de-select one unit in case the players selection is full
            call GroupEnumUnitsSelected(SelectionGroup, p, null)
            set u = FirstOfGroup(SelectionGroup)

            if (GetLocalPlayer() == p) then
                call SelectUnit(u, false)
            endif

            loop
                set n = Power[i]
                set x = number/n
               
                if (GetLocalPlayer() == p) then
                    call SelectUnit(SyncIntegerDummy[x], true)
                    call SelectUnit(SyncIntegerDummy[x], false)
                endif
               
                set number = number-x*n

                exitwhen i == 0
               
                set i = i - 1
            endloop
       
            if (GetLocalPlayer() == p) then
                call SelectUnit(SyncIntegerDummy[d], true)
                call SelectUnit(SyncIntegerDummy[d], false)
                call SelectUnit(u, true)
            endif

            set u = null

            return true
        endfunction
       
        //this cleans up all dummies and triggers created by the system
        function SyncTerminate takes boolean destroyEvents returns nothing
            local integer i = 0
           
            if (destroyEvents) then
                call DestroyTrigger(OnSelectTrigger)
                call DestroyTrigger(EventTrig)
                static if (LIBRARY_SyncString) then
                    call DestroyTrigger(SyncString_EventTrig)
                endif
            else
                call SyncIntegerDisable()
            endif
           
            static if (LIBRARY_UnitDex) then
                set UnitDex.Enabled = false
            endif
           
            loop
                exitwhen i >= DUMMY_COUNT
                call RemoveUnit(SyncIntegerDummy[i])
                set SyncIntegerDummy[i] = null
                set i = i + 1
            endloop
           
            static if (LIBRARY_UnitDex) then
                set UnitDex.Enabled = true
            endif
        endfunction
       
        function SyncInitialize takes nothing returns nothing
            local integer i = 0
           
            static if (ALLOW_DEBUGGING and DEBUG_MODE) then
                if (OnSelectTrigger == null) then
                    call BJDebugMsg(SCOPE_PREFIX + "SyncInitialize: OnSelectTrigger is null and has no events attached to it")
                endif
            endif
           
            static if (LIBRARY_UnitDex) then
                set UnitDex.Enabled = false
            endif
           
            loop
                exitwhen i >= DUMMY_COUNT
                set SyncIntegerDummy[i]=CreateUnit(DUMMY_PLAYER, DUMMY_ID, 1000000, 1000000, i)
               
                static if (ALLOW_DEBUGGING and DEBUG_MODE) then
                    if (i == 0) then // display once
                        if (SyncIntegerDummy[i] == null) then
                            call BJDebugMsg(SCOPE_PREFIX + "SyncInitialize: Dummy unit is null (check DUMMY_ID)")
                        endif
                   
                        if (GetUnitAbilityLevel(SyncIntegerDummy[i], 'Aloc') > 0) then
                            call BJDebugMsg(SCOPE_PREFIX + "SyncInitialize: Dummy units must be selectable (detected locust)")
                            call UnitRemoveAbility(SyncIntegerDummy[i], 'Aloc')
                        endif
                    endif
                endif
               
                call SetUnitUserData(SyncIntegerDummy[i], i)
                call UnitAddAbility(SyncIntegerDummy[i], DUMMY_ABILITY)
                call PauseUnit(SyncIntegerDummy[i], true)
                set i = i + 1
            endloop
           
            static if (LIBRARY_UnitDex) then
                set UnitDex.Enabled = true
            endif
           
            if (GetExpiredTimer() != null) then
                call DestroyTimer(GetExpiredTimer())
            endif
        endfunction
       
        private function OnSelect takes nothing returns boolean
            local unit u        = GetTriggerUnit()
            local player p      = GetTriggerPlayer()
            local integer id    = GetPlayerId(p)
            local integer index = GetUnitUserData(u)
            local boolean isNeg = (SyncIntegerDummy[DUMMY_COUNT-1] == u)

            if (SyncIntegerDummy[index] != u) then
                set u = null
                return false
            endif

            static if (ALLOW_DEBUGGING and DEBUG_MODE) then
                if (OnSelectTrigger == null) then
                    call BJDebugMsg(SCOPE_PREFIX + "SyncInteger: OnSelectTrigger is null")
                endif
            endif
           
            if (isNeg) then
                set SyncData[id] = SyncData[id]*-1
            endif

            if (isNeg or SyncIntegerDummy[DUMMY_COUNT-2] == u) then
                set LastPlayer   = id
                set LastSync     = SyncData[id]
                set SyncData[id] = -1

                // run "events"
                set FireEvent = EVENT_SYNC_INTEGER
                call TriggerEvaluate(EventTrig)
                set FireEvent = 0
            else
                if (SyncData[id]==-1)then
                    set SyncData[id]=0
                endif
                set SyncData[id] = SyncData[id] * BASE + index
            endif
           
            set u = null
           
            return false
        endfunction
       
        public function FireEvents takes real eventtype returns nothing
            set FireEvent = eventtype
            set FireEvent = 0
        endfunction
   
        //===========================================================================
        private function Init takes nothing returns nothing
            local integer i = 0
            local integer j
           
            loop
                call TriggerRegisterPlayerUnitEvent(OnSelectTrigger, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
               
                set SyncData[i] = -1
               
                set i = i + 1
                exitwhen i==bj_MAX_PLAYER_SLOTS
            endloop

            call TriggerAddCondition(OnSelectTrigger, Filter(function OnSelect))
           
            static if (AUTO_INIT) then
                call TimerStart(CreateTimer(), 0, false, function SyncInitialize)
            endif
           
            static if (LIBRARY_GroupUtils) then
                set SelectionGroup=ENUM_GROUP
            else
                set SelectionGroup=CreateGroup()
            endif
            
            // fix for innacuracy of real numbers
            set i=0
            set j=1
            
            loop
                exitwhen i==32
                
                set Power[i]=j
                set j = j * BASE
                
                set i=i+1
            endloop
        endfunction
       
        static if (ALLOW_DEBUGGING and DEBUG_MODE) then
            private function SyncSelectionsHook takes nothing returns nothing
                call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, SCOPE_PREFIX + "SyncSelectionsHook: Detected SyncSelections (can cause issues)")
            endfunction
           
            hook SyncSelections SyncSelectionsHook
        endif

endlibrary
//TESH.scrollpos=48
//TESH.alwaysfold=0
library ListT /* v1.0.1.0
************************************************************************************
*
*	*/ uses /*
*
*		*/ ErrorMessage	/*
*
************************************************************************************
*
*	module ListT
*
*		Description
*		-------------------------
*
*			NA
*
*		Fields
*		-------------------------
*
*			debug readonly boolean isList
*			debug readonly boolean isElement
*
*			readonly static integer sentinel
*
*			readonly thistype list
*
*			readonly thistype first
*			readonly thistype last
*
*			readonly thistype next
*			readonly thistype prev
*
*		Methods
*		-------------------------
*
*			static method create takes nothing returns thistype
*			method destroy takes nothing returns nothing
*				-	May only destroy lists
*
*			method push takes nothing returns thistype
*			method enqueue takes nothing returns thistype
*
*			method pop takes nothing returns nothing
*			method dequeue takes nothing returns nothing
*
*			method remove takes nothing returns nothing
*
*			method clear takes nothing returns nothing
*
*			debug static method calculateMemoryUsage takes nothing returns integer
*			debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
	private keyword isNode
	private keyword isCollection
	private keyword pp_list
	private keyword pp_next
	private keyword pp_prev
	private keyword pp_first
	private keyword pp_last

	module ListT
		private static thistype collectionCount = 0
		private static thistype nodeCount = 0
		
		debug private static Table p_isNode
		debug method operator isNode takes nothing returns boolean
			debug return p_isNode.boolean[this]
		debug endmethod
		debug method operator isNode= takes boolean value returns nothing
			debug set p_isNode.boolean[this] = value
		debug endmethod
		
		debug private static Table p_isCollection
		debug method operator isCollection takes nothing returns boolean
			debug return p_isCollection.boolean[this]
		debug endmethod
		debug method operator isCollection= takes boolean value returns nothing
			debug set p_isCollection.boolean[this] = value
		debug endmethod
		
		debug method operator isList takes nothing returns boolean
			debug return isCollection
		debug endmethod
		
		debug method operator isElement takes nothing returns boolean
			debug return isNode
		debug endmethod
		
		private static Table p_list
		method operator pp_list takes nothing returns thistype
			return p_list[this]
		endmethod
		method operator pp_list= takes thistype value returns nothing
			set p_list[this] = value
		endmethod
		method operator list takes nothing returns thistype
			debug call ThrowError(this == 0,	"List", "list", "thistype", this, "Attempted To Read Null Node.")
			debug call ThrowError(not isNode,	"List", "list", "thistype", this, "Attempted To Read Invalid Node.")
			return pp_list
		endmethod
		
		private static Table p_next
		method operator pp_next takes nothing returns thistype
			return p_next[this]
		endmethod
		method operator pp_next= takes thistype value returns nothing
			set p_next[this] = value
		endmethod
		method operator next takes nothing returns thistype
			debug call ThrowError(this == 0,	"List", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
			debug call ThrowError(not isNode,	"List", "next", "thistype", this, "Attempted To Read Invalid Node.")
			return pp_next
		endmethod
		
		private static Table p_prev
		method operator pp_prev takes nothing returns thistype
			return p_prev[this]
		endmethod
		method operator pp_prev= takes thistype value returns nothing
			set p_prev[this] = value
		endmethod
		method operator prev takes nothing returns thistype
			debug call ThrowError(this == 0,	"List", "prev", "thistype", this, "Attempted To Go Out Of Bounds.")
			debug call ThrowError(not isNode,	"List", "prev", "thistype", this, "Attempted To Read Invalid Node.")
			return pp_prev
		endmethod
		
		private static Table p_first
		method operator pp_first takes nothing returns thistype
			return p_first[this]
		endmethod
		method operator pp_first= takes thistype value returns nothing
			set p_first[this] = value
		endmethod
		method operator first takes nothing returns thistype
			debug call ThrowError(this == 0,		"List", "first", "thistype", this, "Attempted To Read Null List.")
			debug call ThrowError(not isCollection,	"List", "first", "thistype", this, "Attempted To Read Invalid List.")
			return pp_first
		endmethod
		
		private static Table p_last
		method operator pp_last takes nothing returns thistype
			return p_last[this]
		endmethod
		method operator pp_last= takes thistype value returns nothing
			set p_last[this] = value
		endmethod
		method operator last takes nothing returns thistype
			debug call ThrowError(this == 0,		"List", "last", "thistype", this, "Attempted To Read Null List.")
			debug call ThrowError(not isCollection,	"List", "last", "thistype", this, "Attempted To Read Invalid List.")
			return pp_last
		endmethod
		
		static method operator sentinel takes nothing returns integer
			return 0
		endmethod
		
		private static method allocateCollection takes nothing returns thistype
			local thistype this = thistype(0).pp_first
			
			if (0 == this) then
				debug call ThrowError(collectionCount == 8191, "List", "allocateCollection", "thistype", 0, "Overflow.")
				
				set this = collectionCount + 1
				set collectionCount = this
			else
				set thistype(0).pp_first = pp_first
			endif
			
			return this
		endmethod
		
		private static method allocateNode takes nothing returns thistype
			local thistype this = thistype(0).pp_next
			
			if (0 == this) then
				debug call ThrowError(nodeCount == 8191, "List", "allocateNode", "thistype", 0, "Overflow.")
				
				set this = nodeCount + 1
				set nodeCount = this
			else
				set thistype(0).pp_next = pp_next
			endif
			
			return this
		endmethod
		
		static method create takes nothing returns thistype
			local thistype this = allocateCollection()
			
			debug set isCollection = true
			
			set pp_first = 0
			
			return this
		endmethod
		method push takes nothing returns thistype
			local thistype node = allocateNode()
			
			debug call ThrowError(this == 0,		"List", "push", "thistype", this, "Attempted To Push On To Null List.")
			debug call ThrowError(not isCollection,	"List", "push", "thistype", this, "Attempted To Push On To Invalid List.")
			
			debug set node.isNode = true
			
			set node.pp_list = this
		
			if (pp_first == 0) then
				set pp_first = node
				set pp_last = node
				set node.pp_next = 0
			else
				set pp_first.pp_prev = node
				set node.pp_next = pp_first
				set pp_first = node
			endif
			
			set node.pp_prev = 0
			
			return node
		endmethod
		method enqueue takes nothing returns thistype
			local thistype node = allocateNode()
			
			debug call ThrowError(this == 0,		"List", "enqueue", "thistype", this, "Attempted To Enqueue On To Null List.")
			debug call ThrowError(not isCollection,	"List", "enqueue", "thistype", this, "Attempted To Enqueue On To Invalid List.")
			
			debug set node.isNode = true
			
			set node.pp_list = this
		
			if (pp_first == 0) then
				set pp_first = node
				set pp_last = node
				set node.pp_prev = 0
			else
				set pp_last.pp_next = node
				set node.pp_prev = pp_last
				set pp_last = node
			endif
			
			set node.pp_next = 0
			
			return node
		endmethod
		method pop takes nothing returns nothing
			local thistype node = pp_first
			
			debug call ThrowError(this == 0,		"List", "pop", "thistype", this, "Attempted To Pop Null List.")
			debug call ThrowError(not isCollection,	"List", "pop", "thistype", this, "Attempted To Pop Invalid List.")
			debug call ThrowError(node == 0,		"List", "pop", "thistype", this, "Attempted To Pop Empty List.")
			
			debug set node.isNode = false
			
			set pp_first.pp_list = 0
			
			set pp_first = pp_first.pp_next
			if (pp_first == 0) then
				set pp_last = 0
			else
				set pp_first.pp_prev = 0
			endif
			
			set node.pp_next = thistype(0).pp_next
			set thistype(0).pp_next = node
		endmethod
		method dequeue takes nothing returns nothing
			local thistype node = pp_last
			
			debug call ThrowError(this == 0,		"List", "dequeue", "thistype", this, "Attempted To Dequeue Null List.")
			debug call ThrowError(not isCollection,	"List", "dequeue", "thistype", this, "Attempted To Dequeue Invalid List.")
			debug call ThrowError(node == 0,		"List", "dequeue", "thistype", this, "Attempted To Dequeue Empty List.")
			
			debug set node.isNode = false
			
			set pp_last.pp_list = 0
		
			set pp_last = pp_last.pp_prev
			if (pp_last == 0) then
				set pp_first = 0
			else
				set pp_last.pp_next = 0
			endif
			
			set node.pp_next = thistype(0).pp_next
			set thistype(0).pp_next = node
		endmethod
		method remove takes nothing returns nothing
			local thistype node = this
			set this = node.pp_list
			
			debug call ThrowError(node == 0,		"List", "remove", "thistype", this, "Attempted To Remove Null Node.")
			debug call ThrowError(not node.isNode,	"List", "remove", "thistype", this, "Attempted To Remove Invalid Node (" + I2S(node) + ").")
			
			debug set node.isNode = false
			
			set node.pp_list = 0
		
			if (0 == node.pp_prev) then
				set pp_first = node.pp_next
			else
				set node.pp_prev.pp_next = node.pp_next
			endif
			if (0 == node.pp_next) then
				set pp_last = node.pp_prev
			else
				set node.pp_next.pp_prev = node.pp_prev
			endif
			
			set node.pp_next = thistype(0).pp_next
			set thistype(0).pp_next = node
		endmethod
		method clear takes nothing returns nothing
			debug local thistype node = pp_first
		
			debug call ThrowError(this == 0,		"List", "clear", "thistype", this, "Attempted To Clear Null List.")
			debug call ThrowError(not isCollection,	"List", "clear", "thistype", this, "Attempted To Clear Invalid List.")
			
			static if DEBUG_MODE then
				loop
					exitwhen node == 0
					set node.isNode = false
					set node = node.pp_next
				endloop
			endif
			
			if (pp_first == 0) then
				return
			endif
			
			set pp_last.pp_next = thistype(0).pp_next
			set thistype(0).pp_next = pp_first
			
			set pp_first = 0
			set pp_last = 0
		endmethod
		method destroy takes nothing returns nothing
			debug call ThrowError(this == 0,		"List", "destroy", "thistype", this, "Attempted To Destroy Null List.")
			debug call ThrowError(not isCollection,	"List", "destroy", "thistype", this, "Attempted To Destroy Invalid List.")
			
			static if DEBUG_MODE then
				debug call clear()
				
				debug set isCollection = false
			else
				if (pp_first != 0) then
					set pp_last.pp_next = thistype(0).pp_next
					set thistype(0).pp_next = pp_first
					
					set pp_last = 0
				endif
			endif
			
			set pp_first = thistype(0).pp_first
			set thistype(0).pp_first = this
		endmethod
		
		private static method onInit takes nothing returns nothing
			static if DEBUG_MODE then
				set p_isNode = Table.create()
				set p_isCollection = Table.create()
			endif
			set p_list = Table.create()
			set p_next = Table.create()
			set p_prev = Table.create()
			set p_first = Table.create()
			set p_last = Table.create()
		endmethod
		
		static if DEBUG_MODE then
			static method calculateMemoryUsage takes nothing returns integer
				local thistype start = 1
				local thistype end = 8191
				local integer count = 0
				
				loop
					exitwhen integer(start) > integer(end)
					if (integer(start) + 500 > integer(end)) then
						return count + checkRegion(start, end)
					else
						set count = count + checkRegion(start, start + 500)
						set start = start + 501
					endif
				endloop
				
				return count
			endmethod
			
			private static method checkRegion takes thistype start, thistype end returns integer
				local integer count = 0
			
				loop
					exitwhen integer(start) > integer(end)
					if (start.isNode) then
						set count = count + 1
					endif
					if (start.isCollection) then
						set count = count + 1
					endif
					set start = start + 1
				endloop
				
				return count
			endmethod
			
			static method getAllocatedMemoryAsString takes nothing returns string
				local thistype start = 1
				local thistype end = 8191
				local string memory = null
				
				loop
					exitwhen integer(start) > integer(end)
					if (integer(start) + 500 > integer(end)) then
						if (memory != null) then
							set memory = memory + ", "
						endif
						set memory = memory + checkRegion2(start, end)
						set start = end + 1
					else
						if (memory != null) then
							set memory = memory + ", "
						endif
						set memory = memory + checkRegion2(start, start + 500)
						set start = start + 501
					endif
				endloop
				
				return memory
			endmethod
			
			private static method checkRegion2 takes thistype start, thistype end returns string
				local string memory = null
			
				loop
					exitwhen integer(start) > integer(end)
					if (start.isNode) then
						if (memory == null) then
							set memory = I2S(start)
						else
							set memory = memory + ", " + I2S(start) + "N"
						endif
					endif
					if (start.isCollection) then
						if (memory == null) then
							set memory = I2S(start)
						else
							set memory = memory + ", " + I2S(start) + "C"
						endif
					endif
					set start = start + 1
				endloop
				
				return memory
			endmethod
		endif
	endmodule
endlibrary
//TESH.scrollpos=397
//TESH.alwaysfold=0
library BooleanExpression /* v1.2.0.0
************************************************************************************
*
*	*/ uses /*
*
*		*/ ErrorMessage	/*
*		*/ ListT		/*
*		*/ Table		/*
*		*/ Init			/*
*		*/ TableField	/*
*
************************************************************************************
*
*	struct BooleanExpression extends array
*
*		Description
*		-------------------------
*
*			Creates a single boolean expression via Or's
*
*			Provides a slight speed boost
*
*			Allows the for the safe usage of TriggerRemoveCondition given that the only boolexpr on the trigger
*			is the one from this struct
*
*			To put multiple boolean expressions on to one trigger, combine them with Or. Be sure to destroy later.
*
*			Alternatively, they can be wrapped with another BooleanExpression, but this will add overhead. Only use
*			if more than three are planned to be on one trigger.
*
*		Fields
*		-------------------------
*
*			readonly boolexpr expression
*
*				Examples:	call booleanExpression.register(myCode)
*							call TriggerRemoveCondition(thisTrigger, theOneCondition)
*							set theOneCondition = TriggerAddCondition(thisTrigger, booleanExpression.expression)
*
*			boolean reversed
*			-	if this is true, the expression will run in reverse
*
*		Methods
*		-------------------------
*
*			static method create takes boolean reversed returns BooleanExpression
*			-	if reversed is true, the expression will run in reverse
*
*			method destroy takes nothing returns nothing
*			-	only use .destroy with BooleanExpression from .create, not .register
* 
*			method register takes boolexpr expression returns BooleanExpression
*			-	the returned BooleanExpression is a subtype to be used with
*			-	.unregister and .replace
*			method unregister takes nothing returns nothing
*			-	unregisters a BooleanExpression
*			-	only use BooleanExpression from .register, not .create
*
*			method replace takes boolexpr expression returns nothing
*			-	replaces the boolexpr inside of the registered expression
*			-	useful for updating expressions without breaking order
*			-	null expressions take no space and have no overhead, so use them
*			-	only use BooleanExpression from .register, not .create
*
*			method clear takes nothing returns nothing
*			-	only use .clear with BooleanExpression from .create, not .register
*
*			debug static method calculateMemoryUsage takes nothing returns integer
*			-	calculates how many instances are currently active
*			debug static method getAllocatedMemoryAsString takes nothing returns string
*			-	returns a list of all active instances as a string
*
************************************************************************************/
	private struct List extends array
		//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "reversed", "boolean")
		
		implement ListT
		
		private static method init takes nothing returns nothing
			//! runtextmacro INITIALIZE_TABLE_FIELD("reversed")
		endmethod
		
		implement Init
	endstruct

	private struct TreeNode extends array
		/*
		*	Tree Fields
		*/
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "root", "thistype")
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "left", "thistype")
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "right", "thistype")
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "height", "integer")
		
		/*
		*	Standard Fields
		*/
		//! runtextmacro CREATE_TABLE_FIELD("public", "boolexpr", "expression", "boolexpr")
		//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "canDestroy", "boolean")
		
		///! runtextmacro CREATE_TABLE_FIELD("public", "integer", "list", "ListExpression")
		
		public method operator isData takes nothing returns boolean
			return height == 1
		endmethod
		
		public method operator isNode takes nothing returns boolean
			return height != 1
		endmethod
		
		public method join takes nothing returns nothing
			if (canDestroy) then
				call DestroyBoolExpr(expression)
			endif
			
			if (left.expression == null) then
				set canDestroy = false
				
				if (right.expression == null) then
					call expression_clear()
				else
					set expression = right.expression
				endif
			elseif (right.expression == null) then
				set canDestroy = false
				
				set expression = left.expression
			elseif (List(this).list.reversed) then
				set canDestroy = true
				
				set expression = Or(right.expression, left.expression)
			else
				set canDestroy = true
				
				set expression = Or(left.expression, right.expression)
			endif
		endmethod
		
		public method rebuild takes nothing returns nothing
			if (isNode) then
				call left.rebuild()
				call right.rebuild()
				
				call join()
			endif
		endmethod
		
		public method replace takes boolexpr expression returns nothing
			if (this.expression == expression) then
				return
			endif
		
			if (expression == null) then
				call this.expression_clear()
			else
				set this.expression = expression
			endif
			
			loop
				set this = root
				exitwhen this == 0
				
				call join()
			endloop
		endmethod
		
		public static method create takes List parent returns thistype
			local thistype this = parent.enqueue()
			
			set canDestroy = false
			set height = 1
			
			return this
		endmethod
		
		public static method createData takes List parent returns thistype
			local thistype this = parent.push()
			
			set canDestroy = false
			
			return this
		endmethod
		
		method clean takes nothing returns nothing
			if (canDestroy) then
				call DestroyBoolExpr(expression)
			endif
			
			call expression_clear()
		endmethod
		
		method destroy takes nothing returns nothing
			call clean()
			
			call List(this).remove()
		endmethod
		
		public method operator sibling takes nothing returns thistype
			if (root != 0) then
				if (root.left == this) then
					return root.right
				else
					return root.left
				endif
			endif
			
			return 0
		endmethod
		
		method updateHeight takes nothing returns nothing
			if (left.height > right.height) then
				set height = left.height + 1
			else
				set height = right.height + 1
			endif
		endmethod
		
		method operator factor takes nothing returns integer
			return left.height - right.height
		endmethod
		
		method setRoot takes thistype newNode returns nothing
			local thistype root = this.root
		
			if (root != 0) then
				if (this == root.left) then
					set root.left = newNode
				else
					set root.right = newNode
				endif
			endif
			
			set newNode.root = root
		endmethod
	
		method rotateRight takes nothing returns thistype
			local thistype newRoot = left
			
			call setRoot(newRoot)
			set root = newRoot
			
			set left = newRoot.right
			set left.root = this
			set newRoot.right = this
			
			call updateHeight()
			call newRoot.updateHeight()
			
			call join()
			call newRoot.join()
			
			return newRoot
		endmethod
		
		method rotateLeft takes nothing returns thistype
			local thistype newRoot = right
			
			call setRoot(newRoot)
			set root = newRoot
			
			set right = newRoot.left
			set right.root = this
			set newRoot.left = this
			
			call updateHeight()
			call newRoot.updateHeight()
			
			call join()
			call newRoot.join()
			
			return newRoot
		endmethod
		
		method balance takes nothing returns thistype
			local integer factor
			local thistype node
			
			loop
				call updateHeight()
				
				set factor = this.factor
				
				if (factor > 1) then
					if (left.factor < 0) then
						call left.rotateLeft()
					endif

					set this = rotateRight()

					exitwhen true
				elseif (factor < -1) then
					if (right.factor > 0) then
						call right.rotateRight()
					endif

					set this = rotateLeft()

					exitwhen true
				else
					call join()
				endif
			
				set this = root
				exitwhen this == 0
			endloop
			
			if (this != 0) then
				set node = root
				
				loop
					exitwhen node == 0
					
					call node.updateHeight()
					call node.join()
					set node = node.root
				endloop
			endif
		
			return this
		endmethod
		
		private static method init takes nothing returns nothing
			//! runtextmacro INITIALIZE_TABLE_FIELD("root")
			//! runtextmacro INITIALIZE_TABLE_FIELD("left")
			//! runtextmacro INITIALIZE_TABLE_FIELD("right")
			//! runtextmacro INITIALIZE_TABLE_FIELD("height")
			//! runtextmacro INITIALIZE_TABLE_FIELD("expression")
			//! runtextmacro INITIALIZE_TABLE_FIELD("canDestroy")
		endmethod
		
		implement Init
	endstruct
	
	private struct Tree extends array
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "root", "TreeNode")
		
		public static method create takes boolean reversed returns thistype
			local thistype this = List.create()
			
			set List(this).reversed = reversed
			
			return this
		endmethod
		
		method clear takes nothing returns nothing
			local List node = List(this).first
			
			loop
				exitwhen node == 0
				
				call TreeNode(node).clean()
				
				set node = node.next
			endloop
			
			call List(this).clear()
			
			call root_clear()
		endmethod
		
		method destroy takes nothing returns nothing
			call clear()
			
			call List(this).destroy()
		endmethod
		
		method operator reversed takes nothing returns boolean
			return List(this).reversed
		endmethod
		
		method operator reversed= takes boolean b returns nothing
			if (b == reversed) then
				return
			endif
			
			set List(this).reversed = b
			
			if (root != 0) then
				call root.rebuild()
			endif
		endmethod
		
		method updateRoot takes TreeNode node returns nothing
			if (node != 0 and node.root == 0) then
				set this.root = node
			endif
		endmethod
		
		method insert takes boolexpr expression returns TreeNode
			local TreeNode sibling = List(this).last
			local TreeNode node = TreeNode.create(this)
			local TreeNode root = 0
			local TreeNode grandroot = 0
			
			if (expression != null) then
				set node.expression = expression
			endif
			
			if (sibling != 0) then
				set root = TreeNode.createData(this)
				set grandroot = sibling.root
				
				set root.left = sibling
				set root.right = node
				set node.root = root
				set sibling.root = root
				set root.height = 2
				set root.root = grandroot
				
				call root.join()
				
				if (grandroot != 0) then
					set grandroot.right = root
					
					call updateRoot(grandroot.balance())
				else
					set this.root = root
				endif
			else
				set this.root = node
				call node.root_clear()
			endif
			
			call node.left_clear()
			call node.right_clear()
			
			return node
		endmethod
		
		method delete takes TreeNode node returns nothing
			local TreeNode sibling = node.sibling
			local TreeNode root = node.root
			local TreeNode grandroot
			
			if (root != 0) then
				set grandroot = root.root
			endif
			
			if (sibling != 0) then
				if (sibling.isData) then
					set sibling.root = grandroot
					
					if (grandroot != 0) then
						if (grandroot.left == root) then
							set grandroot.left = sibling
						else
							set grandroot.right = sibling
						endif
						
						call updateRoot(grandroot.balance())
					else
						set this.root = sibling
					endif
					
					call root.destroy()
				else
					set root.left = sibling.left
					set root.right = sibling.right
					call root.updateHeight()
					call root.join()
					
					if (sibling.left != 0) then
						set sibling.left.root = root
					endif
					if (sibling.right != 0) then
						set sibling.right.root = root
					endif
					
					call sibling.destroy()
					
					if (grandroot != 0) then
						call updateRoot(grandroot.balance())
					endif
				endif
			else
				set this.root = 0
			endif
			
			call node.destroy()
		endmethod
		
		private static method init takes nothing returns nothing
			//! runtextmacro INITIALIZE_TABLE_FIELD("root")
		endmethod
		
		implement Init
	endstruct
	
	struct BooleanExpression extends array
		method operator expression takes nothing returns boolexpr
			debug call ThrowError(not List(this).isList,	"BooleanExpression", "expression", "BooleanExpression", this, "Attempted To Read Null Boolean Expression.")
			
			if (Tree(this).root != 0) then
				return Tree(this).root.expression
			endif
			
			return null
		endmethod
		
		method operator reversed takes nothing returns boolean
			debug call ThrowError(not List(this).isList,	"BooleanExpression", "reversed", "BooleanExpression", this, "Attempted To Read Null Boolean Expression.")
			
			return Tree(this).reversed
		endmethod
		
		method operator reversed= takes boolean b returns nothing
			debug call ThrowError(not List(this).isList,	"BooleanExpression", "reversed", "BooleanExpression", this, "Attempted To Set Null Boolean Expression.")
			
			set Tree(this).reversed = b
		endmethod
		
		static method create takes boolean reversed returns thistype
			return Tree.create(reversed)
		endmethod
		
		method destroy takes nothing returns nothing
			debug call ThrowError(not List(this).isList,	"BooleanExpression", "reversed", "BooleanExpression", this, "Attempted To Destroy Null Boolean Expression.")
			call Tree(this).destroy()
		endmethod
		
		method register takes boolexpr expression returns BooleanExpression
			return Tree(this).insert(expression)
		endmethod
		
		method unregister takes nothing returns nothing
			debug call ThrowError(not TreeNode(this).isData,	"BooleanExpression", "unregister", "BooleanExpression", this, "Attempted To Unregister Null Boolean Expression.")
			call Tree(List(this).list).delete(this)
		endmethod
		
		method replace takes boolexpr expression returns nothing
			debug call ThrowError(not TreeNode(this).isData,	"BooleanExpression", "replace", "BooleanExpression", this, "Attempted To Replace Null Boolean Expression.")
			call TreeNode(this).replace(expression)
		endmethod
		
		method clear takes nothing returns nothing
			debug call ThrowError(not List(this).isList,	"BooleanExpression", "clear", "BooleanExpression", this, "Attempted To Clear Null Boolean Expression.")
			call Tree(this).clear()
		endmethod
		
		private static string indentation = "            "

		static method printEx takes TreeNode node, string indent, boolean height returns nothing
			if (node != 0) then
				call printEx(node.right, indent + indentation, height)
				
				if (height) then
					call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, indent + I2S(node.height))
				else
					call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, indent + I2S(node))
				endif
				
				call printEx(node.left, indent + indentation, height)
			endif
		endmethod
		
		method print takes boolean height returns nothing
			call printEx(Tree(this).root, "", height)
			call DisplayTimedTextFromPlayer(GetLocalPlayer(), 0, 0, 60000, "------------------------------------")
		endmethod
		
		debug static method calculateMemoryUsage takes nothing returns integer
			debug return List.calculateMemoryUsage()
		debug endmethod
		
		debug static method getAllocatedMemoryAsString takes nothing returns string
			debug return List.getAllocatedMemoryAsString()
		debug endmethod
	endstruct
endlibrary
//! runtextmacro CREATE_TABLE_FIELD("ACCESS_MODIFIER", "TYPE", "NAME", "RETURN_TYPE")
//! runtextmacro CREATE_TABLE_FIELD_ARRAY("TYPE", "NAME", "RETURN_TYPE")
//! runtextmacro USE_TABLE_FIELD_ARRAY("ACCESS_MODIFIER", "NAME")
//! runtextmacro INITIALIZE_TABLE_FIELD("NAME")
//TESH.scrollpos=36
//TESH.alwaysfold=0
library TableField /* v1.0.0.1
************************************************************************************
*
*	*/ uses /*
*
*		*/ Table	/*
*		*/ Init		/*
*
************************************************************************************
*
*	//! textmacro CREATE_TABLE_FIELD takes ACCESS_MODIFIER, TYPE, NAME, RETURN_TYPE
*		-	creates a table field surrounded by method operators
*
*	//! textmacro INITIALIZE_TABLE_FIELD takes NAME
*		-	initializes table field
*		-	used in onInit
*
*	//! textmacro CREATE_TABLE_FIELD_ARRAY takes TYPE, NAME, RETURN_TYPE
*		-	creates a struct that acts as an array
*		-	not used in a struct
*
*	//! textmacro USE_TABLE_FIELD_ARRAY takes ACCESS_MODIFIER, NAME
*		-	creates a field of a struct array
*		-	used in a struct
*
************************************************************************************/
	//! textmacro CREATE_TABLE_FIELD takes ACCESS_MODIFIER, TYPE, NAME, RETURN_TYPE
		private static Table t$NAME$
			
		$ACCESS_MODIFIER$ method operator $NAME$ takes nothing returns $RETURN_TYPE$
			return t$NAME$.$TYPE$[this]
		endmethod
		$ACCESS_MODIFIER$ method operator $NAME$= takes $RETURN_TYPE$ value returns nothing
			set t$NAME$.$TYPE$[this] = value
		endmethod
		$ACCESS_MODIFIER$ method $NAME$_clear takes nothing returns nothing
			call t$NAME$.$TYPE$.remove(this)
		endmethod
	//! endtextmacro
	
	//! textmacro CREATE_TABLE_FIELD_ARRAY takes TYPE, NAME, RETURN_TYPE
		private struct T$NAME$ extends array
			private static Table table
			
			method operator [] takes integer index returns $RETURN_TYPE$
				return table.$TYPE$[index]
			endmethod
			method operator []= takes integer index, $RETURN_TYPE$ value returns nothing
				set table.$TYPE$[index] = value
			endmethod
			static method remove takes integer index returns nothing
				call table.$TYPE$.remove(index)
			endmethod
			static method clear takes nothing returns nothing
				call table.flush()
			endmethod
			
			private static method init takes nothing returns nothing
				set table = Table.create()
			endmethod
			
			implement Init
		endstruct
	//! endtextmacro
	
	//! textmacro USE_TABLE_FIELD_ARRAY takes ACCESS_MODIFIER, NAME
		$ACCESS_MODIFIER$ static T$NAME$ $NAME$ = 0
	//! endtextmacro
	
	//! textmacro INITIALIZE_TABLE_FIELD takes NAME
		set t$NAME$ = Table.create()
	//! endtextmacro
endlibrary
library UniqueNxListT /* v1.0.0.1
************************************************************************************
*
*	*/ uses /*
*
*		*/ ErrorMessage /*
*		*/ TableField	/*
*
************************************************************************************
*
*	module UniqueNxListT
*
*		Description
*		-------------------------
*
*			Node Properties:
*
*				Unique
*				Allocated
*				Not 0
*
*		Fields
*		-------------------------
*
*			readonly static integer sentinel
*
*			readonly thistype list
*
*			readonly thistype first
*			readonly thistype last
*
*			readonly thistype next
*			readonly thistype prev
*
*		Methods
*		-------------------------
*
*			method destroy takes nothing returns nothing
*				-	May only destroy lists
*
*			method push takes thistype node returns nothing
*			method enqueue takes thistype node returns nothing
*
*			method pop takes nothing returns nothing
*			method dequeue takes nothing returns nothing
*
*			method remove takes nothing returns nothing
*
*			method clear takes nothing returns nothing
*				-	Initializes list, use instead of create
*
*			debug static method calculateMemoryUsage takes nothing returns integer
*			debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
	private keyword isNode
	private keyword isCollection
	private keyword p_list
	private keyword p_next
	private keyword p_prev
	private keyword p_first
	private keyword p_last

	module UniqueNxListT
		static if DEBUG_MODE then
			//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "isNode", "boolean")
			//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "isCollection", "boolean")
		endif
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_list", "thistype")
		method operator list takes nothing returns thistype
			debug call ThrowError(this == 0,	"UniqueNxListT", "list", "thistype", this, "Attempted To Read Null Node.")
			debug call ThrowError(not isNode,	"UniqueNxListT", "list", "thistype", this, "Attempted To Read Invalid Node.")
			return p_list
		endmethod
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_next", "thistype")
		method operator next takes nothing returns thistype
			debug call ThrowError(this == 0,	"UniqueNxListT", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
			debug call ThrowError(not isNode,	"UniqueNxListT", "next", "thistype", this, "Attempted To Read Invalid Node.")
			return p_next
		endmethod
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_prev", "thistype")
		method operator prev takes nothing returns thistype
			debug call ThrowError(this == 0,	"UniqueNxListT", "prev", "thistype", this, "Attempted To Go Out Of Bounds.")
			debug call ThrowError(not isNode,	"UniqueNxListT", "prev", "thistype", this, "Attempted To Read Invalid Node.")
			return p_prev
		endmethod
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_first", "thistype")
		method operator first takes nothing returns thistype
			debug call ThrowError(this == 0,		"UniqueNxListT", "first", "thistype", this, "Attempted To Read Null List.")
			debug call ThrowError(not isCollection,	"UniqueNxListT", "first", "thistype", this, "Attempted To Read Invalid List.")
			return p_first
		endmethod
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_last", "thistype")
		method operator last takes nothing returns thistype
			debug call ThrowError(this == 0,		"UniqueNxListT", "last", "thistype", this, "Attempted To Read Null List.")
			debug call ThrowError(not isCollection,	"UniqueNxListT", "last", "thistype", this, "Attempted To Read Invalid List.")
			return p_last
		endmethod
		
		static method operator sentinel takes nothing returns integer
			return 0
		endmethod
		
		method push takes thistype node returns nothing
			debug call ThrowError(this == 0,		"UniqueNxListT", "push", "thistype", this, "Attempted To Push (" + I2S(node) + ") On To Null List.")
			debug call ThrowError(not isCollection,	"UniqueNxListT", "push", "thistype", this, "Attempted To Push (" + I2S(node) + ") On To Invalid List.")
			debug call ThrowError(node == 0,		"UniqueNxListT", "push", "thistype", this, "Attempted To Push Null Node.")
			debug call ThrowError(node.isNode,		"UniqueNxListT", "push", "thistype", this, "Attempted To Push Owned Node (" + I2S(node) + ").")
			
			debug set node.isNode = true
			
			set node.p_list = this
		
			if (p_first == 0) then
				set p_first = node
				set p_last = node
				set node.p_next = 0
			else
				set p_first.p_prev = node
				set node.p_next = p_first
				set p_first = node
			endif
			
			set node.p_prev = 0
		endmethod
		method enqueue takes thistype node returns nothing
			debug call ThrowError(this == 0,		"UniqueNxListT", "enqueue", "thistype", this, "Attempted To Enqueue (" + I2S(node) + ") On To Null List.")
			debug call ThrowError(not isCollection,	"UniqueNxListT", "enqueue", "thistype", this, "Attempted To Enqueue (" + I2S(node) + ") On To Invalid List.")
			debug call ThrowError(node == 0,		"UniqueNxListT", "enqueue", "thistype", this, "Attempted To Enqueue Null Node.")
			debug call ThrowError(node.isNode,		"UniqueNxListT", "enqueue", "thistype", this, "Attempted To Enqueue Owned Node (" + I2S(node) + ").")
			
			debug set node.isNode = true
			
			set node.p_list = this
		
			if (p_first == 0) then
				set p_first = node
				set p_last = node
				set node.p_prev = 0
			else
				set p_last.p_next = node
				set node.p_prev = p_last
				set p_last = node
			endif
			
			set node.p_next = 0
		endmethod
		method pop takes nothing returns nothing
			debug call ThrowError(this == 0,		"UniqueNxListT", "pop", "thistype", this, "Attempted To Pop Null List.")
			debug call ThrowError(not isCollection,	"UniqueNxListT", "pop", "thistype", this, "Attempted To Pop Invalid List.")
			debug call ThrowError(p_first == 0,		"UniqueNxListT", "pop", "thistype", this, "Attempted To Pop Empty List.")
			
			debug set p_first.isNode = false
			
			set p_first.p_list = 0
			
			set p_first = p_first.p_next
			if (p_first == 0) then
				set p_last = 0
			else
				set p_first.p_prev = 0
			endif
		endmethod
		method dequeue takes nothing returns nothing
			debug call ThrowError(this == 0,		"UniqueNxListT", "dequeue", "thistype", this, "Attempted To Dequeue Null List.")
			debug call ThrowError(not isCollection,	"UniqueNxListT", "dequeue", "thistype", this, "Attempted To Dequeue Invalid List.")
			debug call ThrowError(p_last == 0,		"UniqueNxListT", "dequeue", "thistype", this, "Attempted To Dequeue Empty List.")
			
			debug set p_last.isNode = false
			
			set p_last.p_list = 0
		
			set p_last = p_last.p_prev
			if (p_last == 0) then
				set p_first = 0
			else
				set p_last.p_next = 0
			endif
		endmethod
		method remove takes nothing returns nothing
			local thistype node = this
			set this = node.p_list
			
			debug call ThrowError(node == 0,		"UniqueNxListT", "remove", "thistype", this, "Attempted To Remove Null Node.")
			debug call ThrowError(not node.isNode,	"UniqueNxListT", "remove", "thistype", this, "Attempted To Remove Invalid Node (" + I2S(node) + ").")
			
			debug set node.isNode = false
			
			set node.p_list = 0
		
			if (0 == node.p_prev) then
				set p_first = node.p_next
			else
				set node.p_prev.p_next = node.p_next
			endif
			if (0 == node.p_next) then
				set p_last = node.p_prev
			else
				set node.p_next.p_prev = node.p_prev
			endif
		endmethod
		method clear takes nothing returns nothing
			debug local thistype node = p_first
		
			debug call ThrowError(this == 0,		"UniqueNxListT", "clear", "thistype", this, "Attempted To Clear Null List.")
			
			debug if (not isCollection) then
				debug set isCollection = true
				
				debug set p_first = 0
				debug set p_last = 0
				
				debug return
			debug endif
			
			static if DEBUG_MODE then
				loop
					exitwhen node == 0
					set node.isNode = false
					set node = node.p_next
				endloop
			endif
			
			if (p_first == 0) then
				return
			endif
			
			set p_first = 0
			set p_last = 0
		endmethod
		method destroy takes nothing returns nothing
			debug call ThrowError(this == 0,		"UniqueNxListT", "destroy", "thistype", this, "Attempted To Destroy Null List.")
			debug call ThrowError(not isCollection,	"UniqueNxListT", "destroy", "thistype", this, "Attempted To Destroy Invalid List.")
			
			call clear()
			
			debug set isCollection = false
		endmethod
		
		private static method onInit takes nothing returns nothing
			static if DEBUG_MODE then
				//! runtextmacro INITIALIZE_TABLE_FIELD("isNode")
				//! runtextmacro INITIALIZE_TABLE_FIELD("isCollection")
			endif
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_list")
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_next")
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_prev")
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_first")
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_last")
		endmethod
		
		static if DEBUG_MODE then
			static method calculateMemoryUsage takes nothing returns integer
				local thistype start = 1
				local thistype end = 8191
				local integer count = 0
				
				loop
					exitwhen integer(start) > integer(end)
					if (integer(start) + 500 > integer(end)) then
						return count + checkRegion(start, end)
					else
						set count = count + checkRegion(start, start + 500)
						set start = start + 501
					endif
				endloop
				
				return count
			endmethod
			
			private static method checkRegion takes thistype start, thistype end returns integer
				local integer count = 0
			
				loop
					exitwhen integer(start) > integer(end)
					if (start.isNode) then
						set count = count + 1
					endif
					if (start.isCollection) then
						set count = count + 1
					endif
					set start = start + 1
				endloop
				
				return count
			endmethod
			
			static method getAllocatedMemoryAsString takes nothing returns string
				local thistype start = 1
				local thistype end = 8191
				local string memory = null
				
				loop
					exitwhen integer(start) > integer(end)
					if (integer(start) + 500 > integer(end)) then
						set memory = memory + checkRegion2(start, end)
						set start = end + 1
					else
						set memory = memory + checkRegion2(start, start + 500)
						set start = start + 501
					endif
				endloop
				
				return memory
			endmethod
			
			private static method checkRegion2 takes thistype start, thistype end returns string
				local string memory = null
			
				loop
					exitwhen integer(start) > integer(end)
					if (start.isNode) then
						if (memory == null) then
							set memory = I2S(start)
						else
							set memory = memory + ", " + I2S(start) + "N"
						endif
					endif
					if (start.isCollection) then
						if (memory == null) then
							set memory = I2S(start)
						else
							set memory = memory + ", " + I2S(start) + "C"
						endif
					endif
					set start = start + 1
				endloop
				
				return memory
			endmethod
		endif
	endmodule
endlibrary
library NxListT /* v1.0.0.1
************************************************************************************
*
*	*/ uses /*
*
*		*/ ErrorMessage	/*
*		*/ TableField	/*
*
************************************************************************************
*
*	module NxListT
*
*		Description
*		-------------------------
*
*			NA
*
*		Fields
*		-------------------------
*
*			readonly static integer sentinel
*
*			readonly thistype list
*
*			readonly thistype first
*			readonly thistype last
*
*			readonly thistype next
*		readonly thistype prev
*
*		Methods
*		-------------------------
*
*			method destroy takes nothing returns nothing
*				-	May only destroy lists
*
*			method push takes nothing returns thistype
*			method enqueue takes nothing returns thistype
*
*			method pop takes nothing returns nothing
*			method dequeue takes nothing returns nothing
*
*			method remove takes nothing returns nothing
*
*			method clear takes nothing returns nothing
*				-	Initializes list, use instead of create
*
*			debug static method calculateMemoryUsage takes nothing returns integer
*			debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
	private keyword isNode
	private keyword isCollection
	private keyword p_list
	private keyword p_next
	private keyword p_prev
	private keyword p_first
	private keyword p_last
	
	module NxListT
		private static thistype nodeCount = 0
		
		static if DEBUG_MODE then
			//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "isNode", "boolean")
			//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "isCollection", "boolean")
		endif
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_list", "thistype")
		method operator list takes nothing returns thistype
			debug call ThrowError(this == 0,	"NxList", "list", "thistype", this, "Attempted To Read Null Node.")
			debug call ThrowError(not isNode,	"NxList", "list", "thistype", this, "Attempted To Read Invalid Node.")
			return p_list
		endmethod
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_next", "thistype")
		method operator next takes nothing returns thistype
			debug call ThrowError(this == 0,	"NxList", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
			debug call ThrowError(not isNode,	"NxList", "next", "thistype", this, "Attempted To Read Invalid Node.")
			return p_next
		endmethod
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_prev", "thistype")
		method operator prev takes nothing returns thistype
			debug call ThrowError(this == 0,	"NxList", "prev", "thistype", this, "Attempted To Go Out Of Bounds.")
			debug call ThrowError(not isNode,	"NxList", "prev", "thistype", this, "Attempted To Read Invalid Node.")
			return p_prev
		endmethod
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_first", "thistype") 
		method operator first takes nothing returns thistype
			debug call ThrowError(this == 0,		"NxList", "first", "thistype", this, "Attempted To Read Null List.")
			debug call ThrowError(not isCollection,	"NxList", "first", "thistype", this, "Attempted To Read Invalid List.")
			return p_first
		endmethod
		
		//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_last", "thistype")
		method operator last takes nothing returns thistype
			debug call ThrowError(this == 0,		"NxList", "last", "thistype", this, "Attempted To Read Null List.")
			debug call ThrowError(not isCollection,	"NxList", "last", "thistype", this, "Attempted To Read Invalid List.")
			return p_last
		endmethod
		
		static method operator sentinel takes nothing returns integer
			return 0
		endmethod
		
		private static method allocateNode takes nothing returns thistype
			local thistype this = thistype(0).p_next
			
			if (0 == this) then
				set this = nodeCount + 1
				set nodeCount = this
			else
				set thistype(0).p_next = p_next
			endif
			
			return this
		endmethod
		
		method push takes nothing returns thistype
			local thistype node = allocateNode()
			
			debug call ThrowError(this == 0,		"NxList", "push", "thistype", this, "Attempted To Push On To Null List.")
			debug call ThrowError(not isCollection,	"NxList", "push", "thistype", this, "Attempted To Push On To Invalid List.")
			
			debug set node.isNode = true
			
			set node.p_list = this
		
			if (p_first == 0) then
				set p_first = node
				set p_last = node
				set node.p_next = 0
			else
				set p_first.p_prev = node
				set node.p_next = p_first
				set p_first = node
			endif
			
			set node.p_prev = 0
			
			return node
		endmethod
		method enqueue takes nothing returns thistype
			local thistype node = allocateNode()
			
			debug call ThrowError(this == 0,		"NxList", "enqueue", "thistype", this, "Attempted To Enqueue On To Null List.")
			debug call ThrowError(not isCollection,	"NxList", "enqueue", "thistype", this, "Attempted To Enqueue On To Invalid List.")
			
			debug set node.isNode = true
			
			set node.p_list = this
		
			if (p_first == 0) then
				set p_first = node
				set p_last = node
				set node.p_prev = 0
			else
				set p_last.p_next = node
				set node.p_prev = p_last
				set p_last = node
			endif
			
			set node.p_next = 0
			
			return node
		endmethod
		method pop takes nothing returns nothing
			local thistype node = p_first
			
			debug call ThrowError(this == 0,		"NxList", "pop", "thistype", this, "Attempted To Pop Null List.")
			debug call ThrowError(not isCollection,	"NxList", "pop", "thistype", this, "Attempted To Pop Invalid List.")
			debug call ThrowError(node == 0,		"NxList", "pop", "thistype", this, "Attempted To Pop Empty List.")
			
			debug set node.isNode = false
			
			set p_first.p_list = 0
			
			set p_first = p_first.p_next
			if (p_first == 0) then
				set p_last = 0
			else
				set p_first.p_prev = 0
			endif
			
			set node.p_next = thistype(0).p_next
			set thistype(0).p_next = node
		endmethod
		method dequeue takes nothing returns nothing
			local thistype node = p_last
			
			debug call ThrowError(this == 0,		"NxList", "dequeue", "thistype", this, "Attempted To Dequeue Null List.")
			debug call ThrowError(not isCollection,	"NxList", "dequeue", "thistype", this, "Attempted To Dequeue Invalid List.")
			debug call ThrowError(node == 0,		"NxList", "dequeue", "thistype", this, "Attempted To Dequeue Empty List.")
			
			debug set node.isNode = false
			
			set p_last.p_list = 0
		
			set p_last = p_last.p_prev
			if (p_last == 0) then
				set p_first = 0
			else
				set p_last.p_next = 0
			endif
			
			set node.p_next = thistype(0).p_next
			set thistype(0).p_next = node
		endmethod
		method remove takes nothing returns nothing
			local thistype node = this
			set this = node.p_list
			
			debug call ThrowError(node == 0,		"NxList", "remove", "thistype", this, "Attempted To Remove Null Node.")
			debug call ThrowError(not node.isNode,	"NxList", "remove", "thistype", this, "Attempted To Remove Invalid Node (" + I2S(node) + ").")
			
			debug set node.isNode = false
			
			set node.p_list = 0
		
			if (0 == node.p_prev) then
				set p_first = node.p_next
			else
				set node.p_prev.p_next = node.p_next
			endif
			if (0 == node.p_next) then
				set p_last = node.p_prev
			else
				set node.p_next.p_prev = node.p_prev
			endif
			
			set node.p_next = thistype(0).p_next
			set thistype(0).p_next = node
		endmethod
		method clear takes nothing returns nothing
			debug local thistype node = p_first
		
			debug call ThrowError(this == 0,		"NxList", "clear", "thistype", this, "Attempted To Clear Null List.")
			
			debug if (not isCollection) then
				debug set isCollection = true
				
				debug set p_first = 0
				debug set p_last = 0
				
				debug return
			debug endif
			
			static if DEBUG_MODE then
				loop
					exitwhen node == 0
					set node.isNode = false
					set node = node.p_next
				endloop
			endif
			
			if (p_first == 0) then
				return
			endif
			
			set p_last.p_next = thistype(0).p_next
			set thistype(0).p_next = p_first
			
			set p_first = 0
			set p_last = 0
		endmethod
		method destroy takes nothing returns nothing
			debug call ThrowError(this == 0,		"NxList", "destroy", "thistype", this, "Attempted To Destroy Null List.")
			debug call ThrowError(not isCollection,	"NxList", "destroy", "thistype", this, "Attempted To Destroy Invalid List.")
			
			call clear()
			
			debug set isCollection = false
		endmethod
		
		private static method onInit takes nothing returns nothing
			static if DEBUG_MODE then
				//! runtextmacro INITIALIZE_TABLE_FIELD("isNode")
				//! runtextmacro INITIALIZE_TABLE_FIELD("isCollection")
			endif
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_list")
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_next")
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_prev")
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_first")
			//! runtextmacro INITIALIZE_TABLE_FIELD("p_last")
		endmethod
		
		static if DEBUG_MODE then
			static method calculateMemoryUsage takes nothing returns integer
				local thistype start = 1
				local thistype end = 8191
				local integer count = 0
				
				loop
					exitwhen integer(start) > integer(end)
					if (integer(start) + 500 > integer(end)) then
						return count + checkRegion(start, end)
					else
						set count = count + checkRegion(start, start + 500)
						set start = start + 501
					endif
				endloop
				
				return count
			endmethod
			
			private static method checkRegion takes thistype start, thistype end returns integer
				local integer count = 0
			
				loop
					exitwhen integer(start) > integer(end)
					if (start.isNode) then
						set count = count + 1
					endif
					if (start.isCollection) then
						set count = count + 1
					endif
					set start = start + 1
				endloop
				
				return count
			endmethod
			
			static method getAllocatedMemoryAsString takes nothing returns string
				local thistype start = 1
				local thistype end = 8191
				local string memory = null
				
				loop
					exitwhen integer(start) > integer(end)
					if (integer(start) + 500 > integer(end)) then
						set memory = memory + checkRegion2(start, end)
						set start = end + 1
					else
						set memory = memory + checkRegion2(start, start + 500)
						set start = start + 501
					endif
				endloop
				
				return memory
			endmethod
			
			private static method checkRegion2 takes thistype start, thistype end returns string
				local string memory = null
			
				loop
					exitwhen integer(start) > integer(end)
					if (start.isNode) then
						if (memory == null) then
							set memory = I2S(start)
						else
							set memory = memory + ", " + I2S(start) + "N"
						endif
					endif
					if (start.isCollection) then
						if (memory == null) then
							set memory = I2S(start)
						else
							set memory = memory + ", " + I2S(start) + "C"
						endif
					endif
					set start = start + 1
				endloop
				
				return memory
			endmethod
		endif
	endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Colors
globals
    string array Color
endglobals
private struct color extends array

    private static method init takes nothing returns nothing
        set Color[0] = "|CFFFF0303"
        set Color[1] = "|CFF0042FF"
        set Color[2] = "|c001CE6B9"            /***********  Colors  **********/
        set Color[3] = "|CFF540081"            /**                            **/
        set Color[4] = "|CFFFFFF01"            /**   Color 0-11 = player     **/
        set Color[5] = "|CFFFE8A0E"            /**                            **/
        set Color[6] = "|CFF20C000"            /**   [12] = gold              **/
        set Color[7] = "|CFFE55BB0"            /**                            **/
        set Color[8] = "|c00959697"            /**   [13] = white             **/
        set Color[9] = "|CFF7EBFF1"            /**                            **/         
        set Color[10] = "|CFF106246"           /********************************/
        set Color[11] = "|CFF4E2A04"
        set Color[12] = "|c00ffcc00" 
        set Color[13] = "|cffffffcc" 
    endmethod
    implement Init
endstruct

endlibrary
//TESH.scrollpos=33
//TESH.alwaysfold=0
library Cam initializer CamInit uses Print
globals
    constant real ZOOM_START   = 2950.
    constant real ZOOM_MIN     = 500.
    constant real ZOOM_MAX     = 4500.
    constant real ZOOM_TIMEOUT = 0.1
    constant real ZOOM_TIME    = 0.1
    constant integer MAX_PLAYERS = 11
    real array zoom
endglobals

function SetDistance takes nothing returns nothing
    local integer i = 0
    local player p
    loop
        set p = Player(i)
        if GetLocalPlayer() == p then
            call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, zoom[i], ZOOM_TIME)
        endif
        set i = i + 1
        exitwhen i > MAX_PLAYERS
    endloop
endfunction

function Zoom takes nothing returns boolean
    local string chat = GetEventPlayerChatString()
    local player p = GetTriggerPlayer()
    local real r = S2R(SubString(chat, 6, StringLength(chat)))
    local string s = null
    
    if r == 0 and chat != "-zoom 0"  and chat != "zoom0" then
        call PrintTo(p, "|c00ffcc00Current Zoom: |r" + R2S(zoom[GetPlayerId(p)]), 8)
    else
        if r < ZOOM_MIN or r == 0 then
            set r = ZOOM_MIN
            set s = "|c00ffcc00Min-"
        elseif r > ZOOM_MAX then
            set r = ZOOM_MAX
            set s = "|c00ffcc00Max-"
        endif
        set zoom[GetPlayerId(p)] = r
        if GetLocalPlayer() == p then
            call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, r, ZOOM_TIME)
        endif
        set s = s + "|c00ffcc00Zoom: |r" + R2S(r)
        call PrintTo(p, s, 8)
    endif
   
   return false
endfunction

function CamInit takes nothing returns nothing
    local integer i = 0
    local trigger t = CreateTrigger()
    local timer tim = CreateTimer()
    
    call TriggerAddCondition( t, Filter(function Zoom ))
    call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, ZOOM_START, 0.00)
    call TimerStart(tim, ZOOM_TIMEOUT, true, function SetDistance)
    
    loop
        set zoom[i] = ZOOM_START
        call TriggerRegisterPlayerChatEvent( t, Player(i), "-zoom", false )
        set i = i + 1
        exitwhen i > MAX_PLAYERS
    endloop

    set tim = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Clear initializer ClearInit
    function ClearScreen takes nothing returns nothing
        if GetLocalPlayer() == GetTriggerPlayer() then
            call ClearTextMessages()
        endif
    endfunction
    function ClearInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        loop
            call TriggerRegisterPlayerChatEvent(t, Player(i), "-clear", true )
            call TriggerRegisterPlayerChatEvent(t, Player(i), "-c", true )
            set i = i + 1
            exitwhen i > 11
        endloop
        call TriggerAddAction( t, function ClearScreen )
    endfunction
endscope
//TESH.scrollpos=54
//TESH.alwaysfold=0
library TileDefinition

/*              TileDefinition v1.1a
              -----------------------
               
Link:
   
    [url]http://www.hiveworkshop.com/forums/submissions-414/snippet-tiledefinition-259347/[/url]          
               
**
**
**                          Information
**                         _____________
**
**  TileDefinition gives geographical information about the location of a terrain tile.
**            
**      
**                             API
**                           _______
**
**                
**   Functions:
**  -----------
**
**      function AreCoordinatesInSameTile takes real a, real b returns boolean
**          Checks if two coordinates share the same terrain tile.
**          
**          Attention: Only makes sense if both coordinates are of same type. Or x- or y coordinates.
**                     May bring wrong result, if you compare x with y coordinates.
**
**      function ArePointsInSameTile takes real x1, real y1, real x2, real y2 returns boolean
**          Checks if two points share the same terrain tile.
**
**
**      function GetTileRect takes real x, real y returns rect
**          Returns a rect, that covers the terrain tile of given coorinates.
**
**      function GetTileCenterLoc takes real x, real y returns location
**          Returns the centre of the terrain tile of given coorinates.
**
**      function GetTileCenterCoordinate takes real a returns real
**          Returns the cooridnate for the center of the tile.
**          Works for x- and y coordiantes.
**
**
**      function GetTileMax takes real a returns real
**          Returns the max value, that is still in same terrain tile.
**          Works for x- and y coordiantes.
**                  
**      function GetTileMin takes real a returns real
**          Returns the min value, that is still in same terrain tile.
**          Works for x- and y coordiantes.
**                  
**
***********************************************************************************************************/
   
    /*
    *   GetTileDistance evaluates how many tiles the given
    *   cooridnate is away from reference tile. (located at 0/0)
    */
   
    private function GetTileDistance takes real a returns integer
        if (a >= 0) then
            return R2I((a + 64)/128)  
        else
            return R2I((a - 64)/128)
        endif
    endfunction
   
    function GetTileMax takes real a returns real
        local integer aCount = GetTileDistance(a)
        if (aCount == 0) then
            return 64.
        elseif (aCount > 0) then
            return (aCount + 1.)*128. - 64.
        else
            return (aCount)* 128. + 64.
        endif
    endfunction
   
    function GetTileMin takes real a returns real
        local integer aCount = GetTileDistance(a)
        if (aCount == 0) then
            return -64.
        elseif (aCount > 0) then
            return (aCount)*128. - 64.
        else
            return (aCount - 1.)* 128. + 64.
        endif
    endfunction
   
    function AreCoordinatesInSameTile takes real a, real b returns boolean
        return (GetTileMin(a) == GetTileMin(b))
    endfunction
   
    function ArePointsInSameTile takes real x1, real y1, real x2, real y2 returns boolean
        return ((GetTileDistance(x1) == (GetTileDistance(x2)) and (GetTileDistance(y1) == (GetTileDistance(y2)))))
    endfunction
     
    function GetTileRect takes real x, real y returns rect
        return Rect(GetTileMin(x), GetTileMin(y), GetTileMax(x), GetTileMax(y))
    endfunction
   
    function GetTileCenterCooridnate takes real a returns real
        if (a >= 0) then
            return GetTileMin(a) + 64.
        else
            return GetTileMin(a) - 64.
        endif
    endfunction
   
    function GetTileCenterLoc takes real x, real y returns location
        return Location(GetTileCenterCooridnate(x), GetTileCenterCooridnate(y))
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SuspendUnit /* v1.1    By IcemanBo (credits to Maker for this method)

    Alternative for the PauseUnit() function without known side effects.
    A paused unit will be completly unuseable until unpaused.
    Unit's current order will be forgetten.
    
            API
          ¯¯¯¯¯¯
    function SuspendUnit(unit, boolean) returns nothing
    
    function IsUnitSuspended(unit) returns boolean
    
        
    Instructions:
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯

    After copying the library save the map and restart the editor.
    When done, then comment out the next line:*/
    
    ///! external ObjectMerger w3a ANcl paus Ncl6 1 "defend" anam "Channel Pause" acat "" atat "" aher 0 alev 1 Ncl1 1 10000 aani "stand" aeat "" |

    globals
        private constant integer PAUSE = 'paus'
        private constant integer DEFEND = 852055
    endglobals
    function SuspendUnit takes unit u, boolean b returns nothing
        if (b) then
           call UnitAddAbility(u, PAUSE)
           call IssueImmediateOrderById(u, DEFEND)
        else
            call UnitRemoveAbility(u, PAUSE)
        endif
    endfunction
    function IsUnitSuspended takes unit u returns boolean
        return (GetUnitAbilityLevel(u, PAUSE) > 0)
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Print
    function Print takes string text, real duration returns nothing
        local integer i = 0
        loop
            call DisplayTimedTextToPlayer(Player(i), 0, 0, duration, text)
            set i = i + 1
            exitwhen i > 11
        endloop
    endfunction
    function PrintTo takes player p, string text, real duration returns nothing
        call DisplayTimedTextToPlayer(p, 0, 0, duration, text)
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library QuickSort

/*
    Allows to sort an array of integer/real.
    Binds an extra integer (index)
    to the filled value to allow keeping track of it.
    
    Complexity:
        Best: O(n*log (n))
        Average: O(n log n) .
        Worst: O(n^2)
        
    // For bigger unsorted arrays it gets unlikely to get the worst case.
    // In tests it could sort arrays with size of ~650 until OP limit was hit.
    

   Usage
  ¯¯¯¯¯¯¯
*/
//! novjass
    // Fill these arrays:
            real    array QuickSortValue[]
            integer array QuickSortIndex[]  // Requierement, not optional.
    
    // Ascending:
            boolean QuickSortAscending
                    // just set it to true or false
    
    // Start:
            function QuickSort takes integer left, integer right returns nothing
                    // left is index where it starts
                    // right is index where it ends
            
//==============================================================//
//! endnovjass
    globals
        real array QuickSortValue
        integer array QuickSortIndex
        boolean QuickSortAscending = false
    endglobals
    
/*
    Get median of three values.

     if (i < j)then
        if(j<k) then
            return j
        elseif (k<pivot) then
            return = k
        else
            return i
        endif
    elseif (k<j) then
        return j
    elseif (k<i) then
        return k
    else
        return i
    endif
*/
    private function Partition takes integer left, integer right returns integer
        local real pivot = QuickSortValue[left]
        local integer l = left
        local integer r = right
        local real tempR
        local integer tempI
        loop
            exitwhen l > r
            if (QuickSortAscending and QuickSortValue[l] > pivot) or (not QuickSortAscending and QuickSortValue[l] < pivot) then
                set tempR = QuickSortValue[l]
                set QuickSortValue[l] = QuickSortValue[r]
                set QuickSortValue[r] = tempR
                set tempI = QuickSortIndex[l]
                set QuickSortIndex[l] = QuickSortIndex[r]
                set QuickSortIndex[r] = tempI
                set r = r - 1
            else
                set l = l + 1
            endif
        endloop
        set tempR = QuickSortValue[left]
        set QuickSortValue[left] = QuickSortValue[r]
        set QuickSortValue[r] = tempR
        set tempI = QuickSortIndex[left]
        set QuickSortIndex[left] = QuickSortIndex[r]
        set QuickSortIndex[r] = tempI
        return r
    endfunction
    
    function QuickSort takes integer left, integer right returns nothing
        local integer i
        if (left < right) then
            set i = Partition(left, right)
            call QuickSort(left, i - 1)
            call QuickSort(i + 1, right)
        endif
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
struct Gametime extends array
    readonly static integer seconds
    readonly static integer minutes
    
    private static method callback takes nothing returns nothing
        set seconds = seconds + 1
        if ModuloInteger(seconds, 60) == 0 then
            set minutes = minutes + 1
        endif
        set Board.Board[PlayerTools.user_Amount + 5][0].text = "|cffffffccGametime:|r " + Gametime.toString()
    endmethod
    
    static method toString takes nothing returns string
        local string s = ""
        set s = I2S(minutes) + ": "
        if ModuloInteger(seconds, 60) < 10 then
             set s = s + "0" +  I2S(ModuloInteger(seconds, 60))
        else
            set s = s+ I2S(ModuloInteger(seconds, 60))
        endif
        return s
    endmethod
    
    private static method onInit takes nothing returns nothing
        call TimerStart(NewTimer(), 1, true, function thistype.callback)
        set seconds = 0
        set minutes = 0
    endmethod
endstruct
//TESH.scrollpos=0
//TESH.alwaysfold=0
library LineIntersect
    // if points are oredered counterclockwise
    function ccw takes real x1, real y1, real x2, real y2, real x3, real y3 returns boolean
        return (y3 - y1)*(x2 - x1) > (y2 - y1)*(x3 - x1)
    endfunction

    // if ACD xor BCD is ccw we have intersection
    function DoLinesIntersect takes real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4 returns boolean
        return ccw(x1, y1, x3, y3, x4, y4) != ccw(x2, y2, x3, y3, x4, y4) and ccw(x1, y1, x2, y2, x3, y3) != ccw(x1, y1, x2, y2, x4, y4)
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ParabolicMovement

function ParabolaZ takes real h, real d, real x returns real
  return (4 * h / d) * (d - x) * (x / d)
endfunction

endlibrary
Top