1. Are you planning to upload your awesome map to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  5. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  8. The raddest synthwave tracks were chosen - Check out our Music Contest #12 - Results and congratulate the winners!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Trigger Viewer

Banjoball v1.21D [PROT].w3x
Variables
Constants
Constants
Systems
TimerUtils
xebasic
AutoIndex
UnitStatus
Table
TableBC
RegisterPlayerUnitEvent
SpellEffectEvent
TerrainPathability
Multiboard
Event
Dummy
Utilities
Sounds
Camera
AutoFly
GetTerrainZ
UnitZ
Vector
AddSpecialEffectZ
LinkedList
InstanceIterator
UnitCollision
Alpha
ErrorMessage
ARGB
UnitAppearanceTracker
Sure Invisibility
Ascii
Dialog
PlayerColors
HCL
Game
Stats Tracking
UnitProperties
Boundary
ObjectInit
Objects
Taverns
---------------------------
Player and Teams
Teams
Players
Player Utilities
Host
Info
Text Bar
Info
Hint
Commands
Team Commands
Observe
Draft
Franchise
Trade
Switch
Votekick
Repick
Lolz Mode
Apocalypse
Practice Mode
No Goal Mode
Mets Hax Mode
Cheer
Miscellaneous Commands
Game
Initialization
Fields
Pick
Leaving
Goal Block
Game
Referee
Test
Ball
Silence
OuterSpace
Other
AntiCell
Biz Tree
Epic Chickens
Protection
Abilities
Abilities
Angelic Kick
Backflip
Black Hole
Curveshot
Earth Pillar
Hook
Metamorph
Pull
Rift
Shadow
Slam
Smash
Swap
Trickster
Tackle
Possess
Powerdash
Powershot WITHOUT SLOW
Powershot
Powershot with OneTimers
Sprints
Divine Endurance
Sprint
Super Sprint
Ogre Time
Stealth Sprint
Wisp Sprint
Utility
Fake Injury
Jump
Shout
Pass Me
Emotes
Horses
Ride Horse
Horse Dance
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code.

		
Name Type Is Array Initial Value
library Constants

    globals
        constant boolean TEST                                 = false
        constant boolean PROTECTION_ENABLED                   = true
       
        constant string  MAP_NAME                             = "Banjoball"
       
        //Ball
        constant integer BALL_RAWCODE                         = 'h000'
        constant real    BALL_CATCH_RANGE                     = 90.0
        constant real    BALL_KEEP_RANGE                      = 100.0
                 real    BALL_FRICTION_GROUND                 = 0.45
                 real    BALL_FRICTION_AIR                    = 0.07
                 real    BALL_BUMP_SPEED_LOSS                 = 4.00
        constant real    BALL_BUMP_SFX_THRESHOLD              = 250.0
        constant string  BALL_BUMP_SFX_PATH                   = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCasterOverhead.mdl"
        constant integer BALL_SLOW_BUFF_RAWCODE               = 'B002'
       
        //Players
        constant integer DOCTRINAL_CAKE_RAWCODE               = 'h004'
        constant integer KARMA_GREEN_INN_RAWCODE              = 'h00P'
        constant integer KARMIC_LIVID_LION_RAWCODE            = 'h003'
        constant integer NISEI_LINESMAN_RAWCODE               = 'h005'
        constant integer OAK_KING_ZIT_RAWCODE                 = 'h00R'
        constant integer AKARI_SKA_AS_ION_INK_RAWCODE         = 'h00F'
        constant integer SZURA_COH_RAWCODE                    = 'h00Y'
        constant integer PARCH_NINE_TIE_RAWCODE               = 'h010'
        constant integer IDEAL_VIZZD_RAKIA_RAWCODE            = 'h001'
        constant integer DARK_DAWN_OAR_RAWCODE                = 'h012'
        constant integer CLAY_HAND_NIL_RAWCODE                = 'h01I'
        constant integer DEAD_HERO_RAWCODE                    = 'h01N'
        constant integer JIG_PER_ACE_RAWCODE                  = 'h01R'
        constant integer SIR_REAL_PUNTS_RAWCODE               = 'h026'
        constant integer MASTER_AWE_QI_RAWCODE                = 'h028'
        constant integer MANFUL_LOAF_RAWCODE                  = 'h029'
        constant integer MARZIPAN_USA_BRO_RAWCODE             = 'h02C'
        constant integer MR_DOLT_AMIGO_RAWCODE                = 'h027'
        constant real    PARCH_NINE_TIE_SCALE                 = 1.80
        constant real    OAK_KING_ZIT_SCALE                   = 1.34
        constant real    TEMP_SCALE                           = 1.35
                 real    PLAYER_FRICTION_GROUND               = 0.65
        constant real    PLAYER_FRICTION_AIR                  = 0.08
        constant real    PLAYER_BUMP_SPEED_LOSS               = 15.0
        constant real    PLAYER_BUMP_SFX_THRESHOLD            = 30.0
        constant string  PLAYER_BUMP_SFX_PATH                 = "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
        constant string  GOAL_BLOCK_SFX_PATH                  = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCasterOverhead.mdl"
        constant real    PLAYER_COLLISION_SIZE                = 30.0
       
        // Ice Levels
        constant real    BALL_FRICTION_ICE                    = 0.30
        constant real    PLAYER_FRICTION_ICE                  = 0.40
        constant real    PLAYER_SLIDE_SPEED_ICE               = 0.70
        constant real    PLAYER_MAX_SLIDE_SPEED               = 20
        constant real    POSITION_RADIUS                      = 100.0
       
        // Team Franchises
        constant integer LOGO_PLACEHOLDER                     = 'B006'
        constant integer BANNER_PLACEHOLDER_HOME              = 'B00C'
        constant integer BANNER_PLACEHOLDER_AWAY              = 'B00D'
       
        //Hats
        constant integer CHEF_HAT_RAWCODE                     = 'h00A'
        constant integer CRUSADER_HELM_RAWCODE                = 'h00M'
        constant integer MAGE_HAT_RAWCODE                     = 'h008'
        constant integer MILITARY_HAT_RAWCODE                 = 'h009'
        constant integer PIRATE_HAT_RAWCODE                   = 'h006'
        constant integer PUMPKIN_HAT_RAWCODE                  = 'h00N'
        constant integer SAMURAI_HELM_RAWCODE                 = 'h00L'
        constant integer SANTA_HAT_RAWCODE                    = 'h007'
        constant integer SHAMAN_CAP_RAWCODE                   = 'h00K'
        constant integer SPARTAN_HELM_RAWCODE                 = 'h00J'
        constant integer VOODOO_MASK_RAWCODE                  = 'h00I'
        constant integer WITCH_HUNTER_HAT_RAWCODE             = 'h00B'
       
        //Helping units
        constant integer DUMMY_RAWCODE                        = 'h00D'
        constant integer SFX_DUMMY_RAWCODE                    = 'h00X'
        constant integer GOAL_LINE_RAWCODE                    = 'h00H'
        constant integer PICKER_RAWCODE                       = 'h00C'
        constant integer PUDDLE_RAWCODE                       = 'h00O'
        constant integer BLACK_HOLE_APOCALYPSE_RAWCODE        = 'h00U'
        constant integer SUMMER_TREE_UNIT_RAWCODE             = 'h00V'
        constant integer SNOWY_TREE_UNIT_RAWCODE              = 'h00W'
        constant integer UNIT_SYNC_RAWCODE                    = 'h00Z'
        constant integer HORSE_RAWCODE                        = 'hhdl'
        constant integer EPIC_CHICKEN_RAWCODE                 = 'h01H'
        constant integer SILENCED_DUMMY_RAWCODE               = 'h02F'
       
        constant integer SUMMER_TREE_RAWCODE                  = 'LTlt'
        constant integer SNOWY_TREE_RAWCODE                   = 'WTst'
       
        constant integer BIZ_TREE_SUMMER_RAWCODE              = 'h01K'
        constant integer BIZ_TREE_SNOW_RAWCODE                = 'h01L'
       
        constant integer PLAYER_TAVERN_1_RAWCODE              = 'n000'
        constant integer PLAYER_TAVERN_2_RAWCODE              = 'n004'
        constant integer HAT_TAVERN_1_RAWCODE                 = 'n001'
        constant integer HAT_TAVERN_2_RAWCODE                 = 'n002'
        constant integer HAT_TAVERN_3_RAWCODE                 = 'n003'
       
        //Spells                              
            //Black hole
            constant integer BLACK_HOLE_RAWCODE               = 'A002'
            constant integer BLACK_HOLE_QC_RAWCODE            = 'A01K'
            constant integer BLACK_HOLE_DUMMY_RAWCODE         = 'h002'
            constant real    BLACK_HOLE_DURATION              = 3.50
            constant real    BLACK_HOLE_AOE                   = 700.0
                     real    BLACK_HOLE_FORCE                 = 50000.0
                     real    BLACK_HOLE_INITIAL_FORCE         = 0.00
                     real    BLACK_HOLE_LIMIT                 = 60.0
            constant real    BLACK_HOLE_HEIGHT                = 50.0
            constant string  BLACK_HOLE_LIGHTNING_CODE        = "BKHL"
            constant real    BLACK_HOLE_INITIAL_SIZE          = 0.01
            constant real    BLACK_HOLE_GROW_TIME             = 1.10
            constant real    BLACK_HOLE_SIZE                  = 0.50
           
            //Kick
            constant integer KICK_RAWCODE                     = 'A000'
            constant integer KICK_QC_RAWCODE                  = 'A01Q'
            constant real    KICK_SPEED                       = 30.0
            constant real    KICK_Z                           = 7.00
           
            //Powershot
            constant integer POWERSHOT_RAWCODE                = 'A003'
            constant integer POWERSHOT_QC_RAWCODE             = 'A01T'
                     real    POWERSHOT_SPEED                  = 51.0
            constant string  POWERSHOT_SFX_PATH               = "Abilities\\Spells\\Undead\\DarkRitual\\DarkRitualTarget.mdl"
            constant string  POWERSHOT_BLAST_SFX_PATH         = "Abilities\\Spells\\NightElf\\Taunt\\TauntCaster.mdl"
            constant real    POWERSHOT_BLAST_FACTOR           = 0.85
            constant real    POWERSHOT_CHARGE_TIME            = 0.50
            constant string  POWERSHOT_CHARGE_SFX_PATH        = "Abilities\\Spells\\Other\\Drain\\ManaDrainTarget.mdl"
            constant integer POWERSHOT_SLOW_RAWCODE           = 'A00I'
            constant integer POWERSHOT_SLOW_BUFF_RAWCODE      = 'B00A'
            constant integer POWERSHOT_DISABLE_RAWCODE        = 'A016'
            constant string  POWERSHOT_SLOW_ORDER             = "slow"
            constant real    POWERSHOT_SLOW_AOE               = 400.0
            constant integer POWERSHOT_ANIMATION_INDEX        = 6
            constant real    POWERSHOT_SLOW_COOLDOWN          = 5.00
           
            constant integer POWERDASH_RAWCODE                = 'A01E'
            constant string  POWERDASH_SFX_PATH               = "Abilities\\Spells\\NightElf\\Taunt\\TauntCaster.mdl"
                     real    POWERDASH_SPEED                  = 40.00
                     real    POWERDASH_RANGE                  = 300.0
            constant real    POWERDASH_PUSH_FORCE             = 5.0
           
            //Slam
            constant integer SLAM_RAWCODE                     = 'A00C'
            constant real    SLAM_AOE                         = 720.0
            constant real    SLAM_KNOCKBACK_POINT_Z           = -300.0
                     real    SLAM_FORCE                       = 66.50
            constant real    SLAM_DISTANCE_FACTOR             = 1.00/12.00
            constant string  SLAM_SFX_PATH                    = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
            constant integer SLAM_ANIMATION_INDEX             = 6
            constant real    SLAM_DELAY                       = 0.36
           
            //Sprint
            constant integer SPRINT_RAWCODE                   = 'A001'
            constant integer SPRINT_BUFF_RAWCODE              = 'B000'
            constant real    SPRINT_NEW_SPEED                 = 400.0
           
            //Wisp Sprint
            constant integer WISP_SPRINT_RAWCODE              = 'A00A'
            constant integer WISP_SPRINT_BUFF_RAWCODE         = 'B003'
            constant real    WISP_SPRINT_NEW_SPEED            = SPRINT_NEW_SPEED
           
            //Stealth Sprint
            constant integer STEALTH_SPRINT_RAWCODE           = 'A00E'
            constant integer STEALTH_SPRINT_BUFF_RAWCODE      = 'B004'
            constant real    STEALTH_SPRINT_NEW_SPEED         = 400.0
            constant integer STEALTH_SPRINT_INVIS_RAWCODE     = 'A00G'
            constant string  STEALTH_SPRINT_SFX_PATH          = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"
           
            //Super Sprint
            constant integer SUPER_SPRINT_RAWCODE             = 'A004'
            constant integer SUPER_SPRINT_BUFF_RAWCODE        = 'B001'
                     real    SUPER_SPRINT_PROPULSION          = 20.2
                     real    SUPER_SPRINT_ACCELERATION        = 0.72
            constant integer SUPER_SPRINT_SHADOW_RAWCODE      = 'h00Q'
           
            //Divine Endurance
            constant integer DIVINE_ENDURANCE_RAWCODE         = 'A01A'
            constant integer DIVINE_ENDURANCE_BUFF_RAWCODE    = 'B00E'
           
            //Tackle
            constant integer TACKLE_RAWCODE                   = 'A009'
            constant integer TACKLE_QC_RAWCODE                = 'A01S'
                     real    TACKLE_SPEED                     = 44.60
                     real    TACKLE_RANGE                     = 640.0
            constant real    TACKLE_AOE                       = 200.0
            constant integer TACKLE_SLOW_RAWCODE              = 'A00J'
            constant integer TACKLE_SLOW_BUFF_RAWCODE         = 'B005'
            constant integer TACKLE_SHADOW_RAWCODE            = 'h00E'
            constant real    TACKLE_PUSH_FORCE                = 10.0
           
            //Backflip
            constant integer BACKFLIP_RAWCODE                 = 'A00D'
            constant integer BACKFLIP_DUMMY_RAWCODE           = 'h00S'
                     real    BACKFLIP_RANGE                   = 635.0
                     real    BACKFLIP_TIME                    = 1.09
                     
            //Pull
            constant integer PULL_RAWCODE                     = 'A007'
            constant integer PULL_DISABLE_RAWCODE             = 'A00M'
                     real    PULL_FORCE                       = 1.40
            constant real    PULL_DURATION                    = 4.50
            constant string  PULL_LIGHTNING_CODE              = "DRAL"
           
            //Possess
            constant integer POSSESS_RAWCODE                  = 'A00K'
            constant real    POSSESS_SPEED                    = 30.0
            constant real    POSSESS_DURATION                 = 8.00
            constant string  POSSESS_SFX_PATH                 = "war3mapImported\\PossessionMissile.mdx"
            constant string  POSSESS_EJECT_SFX_PATH           = "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl"
                     real    POSSESS_EJECT_MAGNITUDE          = 38.0
            constant integer POSSESS_FLAG_RAWCODE             = 'h01J'
                     real    POSSESS_JUMP_VELOCITY_REDUCTION  = 26.00
                     real    POSSESS_JUMP_SPEED               = 31.0
            constant real    POSSESS_JUMP_ANGLE               = 50.0*bj_DEGTORAD
                     
            //Swap
            constant integer SWAP_RAWCODE                     = 'A00P'
            constant integer SWAP_QC_RAWCODE                  = 'A01R'
            constant integer SWAP_PROJECTILE_RAWCODE          = 'h011'
                     real    SWAP_PROJECTILE_SPEED            = 44.40
                     real    SWAP_PROJECTILE_DURATION         = 1.80
            constant real    SWAP_PROJECTILE_AOE              = 80.0
            constant string  SWAP_CASTER_SFX_PATH             = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
            constant string  SWAP_TARGET_SFX_PATH             = "Abilities\\Spells\\NightElf\\Blink\\BlinkTarget.mdl"
            constant string  SWAP_LIGHTNING_1_CODE            = "LINK"
            constant string  SWAP_LIGHTNING_2_CODE            = "SWAP"
           
            //Curveshot
            constant integer CURVESHOT_RIGHT_RAWCODE          = 'A00Q'
            constant integer CURVESHOT_LEFT_RAWCODE           = 'A00R'
            constant integer CURVESHOT_RIGHT_QC_RAWCODE       = 'A00Q'
            constant integer CURVESHOT_LEFT_QC_RAWCODE        = 'A01M'
                     real    CURVESHOT_RANGE                  = 1450.0 //Values aren't accurate and have weird effect
                     real    CURVESHOT_DURATION               = 1.40 //pls don't change
                     real    CURVESHOT_RADIUS                 = 1500.0
                     real    CURVESHOT_SPEED_FACTOR           = 1.25
            constant string  CURVESHOT_SFX_PATH               = "war3mapImported\\IllidanMissile.mdl"
            constant real    CURVESHOT_MANA_INCREASE          = 100.0
            constant integer CURVESHOT_COOLDOWN_LEFT_RAWCODE  = 'h01F'
            constant integer CURVESHOT_COOLDOWN_RIGHT_RAWCODE = 'h01G'
            constant real    CURVESHOT_COOLDOWN               = 1.00
           
            //Shadow
            constant integer SHADOW_RAWCODE                   = 'A00W'
            constant integer SHADOW_RECALL_RAWCODE            = 'A01F'
                     real    SHADOW_RANGE                     = 400.0
                     real    SHADOW_DELAY                     = 0.50
            constant real    SHADOW_RECALL_DELAY              = 2.00
            constant string  SHADOW_SFX_PATH                  = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageDeathCaster.mdl"
            constant real    SHADOW_RECALL_COOLDOWN           = 32.00
            constant integer SHADOW_SHADOW_RAWCODE            = 'h02B'
           
            //Trickster
            constant integer TRICKSTER_KEEP_RAWCODE           = 'A00F'
            constant integer TRICKSTER_KICK_RAWCODE           = 'A00H'
            constant integer TRICKSTER_COOLDOWN_KEEP_RAWCODE  = 'h01O'
            constant integer TRICKSTER_COOLDOWN_KICK_RAWCODE  = 'h01P'
            constant integer TRICKSTER_FAKE_BALL_SFX_RAWCODE  = 'h01M'
            constant real    TRICKSTER_FAKE_BALL_DEATH        = 10.00
            constant real    TRICKSTER_COOLDOWN               = 14.00
           
            //Hook
            constant integer HOOK_ENEMY_RAWCODE               = 'A00Y'
            constant integer HOOK_ALLY_RAWCODE                = 'A00Z'
            constant integer HOOK_ENEMY_QC_RAWCODE            = 'A01O'
            constant integer HOOK_ALLY_QC_RAWCODE             = 'A01P'
            constant integer HOOK_PROJECTILE_RAWCODE          = 'h01S'
                     real    HOOK_PROJECTILE_SPEED            = 40.0
                     real    HOOK_PROJECTILE_RETURN_SPEED     = 20.0
                     real    HOOK_PROJECTILE_DURATION         = 0.85
            constant real    HOOK_PROJECTILE_AOE              = 100.0
            constant real    HOOK_RETURN_AOE                  = 40.0
            constant string  HOOK_LIGHTNING_CODE              = "ROPE"
            constant integer HOOK_ANCHOR_RAWCODE              = 'A00L'
            constant integer HOOK_SILENCE_RAWCODE             = 'A010'
            constant integer HOOK_SILENCE_VISUAL_RAWCODE      = 'A01J'
            constant integer HOOK_WITHDRAW_ENEMY_RAWCODE      = 'A011'
            constant integer HOOK_WITHDRAW_ALLY_RAWCODE       = 'A013'
            constant integer HOOK_DROP_ENEMY_RAWCODE          = 'A012'
            constant integer HOOK_DROP_ALLY_RAWCODE           = 'A014'
            constant integer HOOK_COOLDOWN_ENEMY_RAWCODE      = 'h024'
            constant integer HOOK_COOLDOWN_ALLY_RAWCODE       = 'h025'
            constant real    HOOK_ENEMY_COOLDOWN              = 26.00
            constant real    HOOK_ALLY_COOLDOWN               = 22.00
            constant string  HOOK_SFX_PATH                    = "war3mapImported\\Hook SFX.mdx"
            constant boolean HOOK_BALL_HOOK_ENABLED           = true
           
            //Ogre Smash
            constant integer SMASH_RAWCODE                    = 'A015'
            constant integer SMASH_SLOW_RAWCODE               = 'A017'
            constant integer SMASH_STUN_RAWCODE               = 'A018'
            constant integer SMASH_OGRE_TIME_RAWCODE          = 'A01B'
            constant integer SMASH_OGRE_SPEED_RAWCODE         = 'A01D'
            constant integer SMASH_SPEED_COOLDOWN_RAWCODE     = 'h02A'
            constant integer SMASH_OGRE_SPEED_BUFF_RAWCODE    = 'B00F'
            constant integer SMASH_OGRE_SLOW_BUFF_RAWCODE     = 'B00D'
            constant integer SMASH_OGRE_STUN_BUFF_RAWCODE     = 'B00G'
            constant real    SMASH_DELAY                      = 0.15
            constant real    SMASH_OGRE_TIME                  = 4.00
                     real    SMASH_RANGE                      = 350.0
            constant real    SMASH_RANGE_BALL                 = 350.0
            constant real    SMASH_WIDTH_INNER                = 200.00
            constant real    SMASH_WIDTH_OUTER                = 200.00
                     real    SMASH_PUSH_FORCE                 = 45.0
                     real    SMASH_BALL_PUSH_FORCE            = 55.0
            constant string  SMASH_SFX_PATH                   = "WarStompCasterNoUberSplat.mdx"
            constant real    SMASH_COOLDOWN                   = 24.00
            constant real    SMASH_OGRE_TIME_COOLDOWN         = 30.00
            constant integer SMASH_ANIMATION_INDEX            = 6
           
            //Metamorph
            constant integer METAMORPH_RAWCODE                = 'A01G'
            constant integer METAMORPH_COOLDOWN_RAWCODE       = 'A01H'
            constant integer METAMORPH_ANIMATION_INDEX        = 8
            constant string  METAMORPH_SFX_PATH               = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageDeathCaster.mdl"
            constant real    METAMORPH_CAST_TIME              = 2.50
            constant real    METAMORPH_ROLL_TIME              = 0.10
            constant real    METAMORPH_COOLDOWN               = 30.00
           
            //Angelic Kick
            constant integer ANGELIC_KICK_RAWCODE             = 'A019'
            constant integer ANGELIC_KICK_QC_RAWCODE          = 'A01J'
            constant real    ANGELIC_KICK_SPEED               = 35.0
            constant string  ANGELIC_KICK_SFX_PATH            = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
           
            // Earth Pillar
            constant integer EARTH_PILLAR_RAWCODE             = 'A01I'
            constant integer EARTH_PILLAR_QC_RAWCODE          = 'A01N'
            constant integer EARTH_PILLAR_DUMMY_RAWCODE       = 'h02D'
            constant string  EARTH_PILLAR_ANIMATION_INDEX     = "attack slam"
            constant real    EARTH_PILLAR_ANIMATION_TIME      = 0.30
            constant real    EARTH_PILLAR_DELAY               = 0.40
            constant real    EARTH_PILLAR_DURATION            = 3.00
            constant real    EARTH_PILLAR_RANGE               = 700.0
            constant real    EARTH_PILLAR_RADIUS              = 60.0
            constant real    EARTH_PILLAR_AOE                 = 380.0
            constant real    EARTH_PILLAR_DEFLECT_DAMPEN      = 0.90
            constant real    EARTH_PILLAR_BALL_DAMPEN         = 3.00
            constant real    EARTH_PILLAR_HEIGHT              = 300.0
                     real    EARTH_PILLAR_KNOCKBACK_FORCE     = 5.0
                     real    EARTH_PILLAR_KNOCKUP_FORCE       = 35.0
            constant real    EARTH_PILLAR_DISTANCE_FACTOR     = 0.1
            constant string  EARTH_PILLAR_SFX_PATH            = "WarStompCasterNoUberSplat.mdx"
            constant string  EARTH_PILLAR_END_SFX_PATH        = "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
            constant integer PILLAR_BIRTH_ANIMATION_INDEX     = 0
            constant integer PILLAR_DEATH_ANIMATION_INDEX     = 2

            // Rift
            constant integer RIFT_RAWCODE                     = 'A01C'
            constant integer RIFT_REFUND_RAWCODE              = 'A01K'
            constant integer RIFT_DUMMY_RAWCODE               = 'h02E'
            constant integer RIFT_PROJECTILE_RAWCODE          = 'h02A'
            constant string  RIFT_LIGHTNING_RAWCODE           = "RIFT"
            constant real    RIFT_COOLDOWN                    = 32.0
            constant real    RIFT_REFUND_COOLDOWN             = 10.0
            constant real    RIFT_GROUND_THRESHOLD            = 25.0
            constant real    RIFT_RADIUS                      = 50.0
            constant real    RIFT_TIMEOUT_DURATION            = 5.00
            constant real    RIFT_DURATION                    = 3.00
            constant real    RIFT_PROJECTILE_START_HEIGHT     = 100.0
                     real    RIFT_PROJECTILE_SPEED            = 1000.0 / 32
                     real    RIFT_MAX_RANGE                   = 750.0
            constant real    RIFT_PROJECTILE_GRAVITY_FORCE    = RIFT_PROJECTILE_START_HEIGHT / 32
                     real    RIFT_BUMP_FORCE                  = 12.5
           
           

            //Misc spells
            constant integer PASS_ME_RAWCODE                  = 'A006'
            constant real    PASS_ME_COOLDOWN                 = 1.00
            constant string  PASS_ME_ORDER_STRING             = "windwalk"
            constant integer TAUNT_RAWCODE                    = 'A005'
            constant real    TAUNT_COOLDOWN                   = 5.00
            constant string  TAUNT_ORDER                      = "berserk"
            constant integer SADFACE_RAWCODE                  = 'A00T'
            constant real    SADFACE_COOLDOWN                 = 5.00
            constant string  SADFACE_ORDER_1                  = "defend"
            constant string  SADFACE_ORDER_2                  = "undefend"
            constant integer SHOUT_RAWCODE                    = 'A00S'
            constant integer SHOUT_ADRENALINE_RAWCODE         = 'A00X'
            constant string  SHOUT_ADRENALINE_ORDER           = "cripple"
            constant integer BALL_SLOW_RAWCODE                = 'A008'
            constant integer HERO_GLOW_RAWCODE                = 'A00B'
            constant integer RIDE_HORSE_RAWCODE               = 'A00N'
            constant integer HORSE_DANCE_RAWCODE              = 'A00O'
            constant real    JUMP_COOLDOWN                    = 2.00
            constant real    JUMP_ANGLE                       = 80.0*bj_DEGTORAD
            constant real    JUMP_INTENSITY                   = 29.00
            constant string  JUMP_SFX_PATH                    = "Abilities\\Spells\\Undead\\ReplenishHealth\\ReplenishHealthCaster.mdl"
           
            constant integer DISABLE_BUFF_RAWCODE             = '&DIS'
           
            //Metamorph Heroes
            constant integer METAMORPH_REMOVE_ABILITY_RAWCODE = 'RAAA'
            constant integer METAMORPH_SLAM_RAWCODE           = 'R000'
            constant integer METAMORPH_BLACKHOLE_RAWCODE      = 'R001'
            constant integer METAMORPH_TACKLE_RAWCODE         = 'R002'
            constant integer METAMORPH_BACKFLIP_RAWCODE       = 'R003'
            constant integer METAMORPH_POWERSHOT_RAWCODE      = 'R004'
            constant integer METAMORPH_PULL_RAWCODE           = 'R005'
            constant integer METAMORPH_SWAP_RAWCODE           = 'R006'
            constant integer METAMORPH_CURVESHOT_RAWCODE      = 'R007'
            constant integer METAMORPH_SHADOW_RAWCODE         = 'R008'
            constant integer METAMORPH_HOOK_RAWCODE           = 'R009'
            constant integer METAMORPH_SMASH_RAWCODE          = 'R00A'
            constant integer METAMORPH_EARTH_PILLAR_RAWCODE   = 'R00B'
       
        //Misc
        constant unittype UNIT_TYPE_VISUAL                    = UNIT_TYPE_TAUREN
        constant unittype UNIT_TYPE_DUMMY                     = UNIT_TYPE_MECHANICAL
        constant unittype UNIT_TYPE_OBJECT                    = UNIT_TYPE_ANCIENT
        constant unittype UNIT_TYPE_PLAYER                    = UNIT_TYPE_GIANT
        constant string  DEFAULT_COLOR_CODE                   = "|c00468BFF"
        constant string  HINT_COLOR_CODE                      = "|c009FFFE4"
        constant string  VALID_COLOR_CODE                     = "|c0004FF04"
        constant string  INVALID_COLOR_CODE                   = "|c00FF0000"
        constant string  REFEREE_COLOR_CODE                   = "|c007AA0E9"
        constant string  EMOTE_COLOR_CODE                     = "|c00A9D5F5"
        constant string  HOTKEY_COLOR_CODE                    = "|cffffcc00"
        constant string  EMPHASIZE_COLOR_CODE                 = "|c008ED6DB"
        constant string  WHITE_COLOR_CODE                     = "|c00ffffff"
        constant real    EMOTE_Z_OFFSET                       = 150.0
        constant real    ASSIST_TIME                          = 6.00
        constant real    GRAVITY_ACCELERATION                 = 1.50
        constant real    EXTENSION_TIME                       = 120.0
        constant integer REFEREE_RAWCODE                      = 'h00T'
        constant player  REFEREE_PLAYER                       = Player(PLAYER_NEUTRAL_PASSIVE)
        constant real    CAMERA_DEFAULT_DISTANCE              = 3000.0
        constant real    CAMERA_ALTERNATE_ANGLE_DIFFERENCE    = 11.50
        constant real    DEFAULT_Z                            = 1024.0
        constant integer WATER_RAWCODE                        = 'B000'
        constant player  DUMMY_OWNER                          = REFEREE_PLAYER
        constant real    GOAL_HEIGHT                          = 300.0
        constant real    BOUNDARY_DEFAULT_Z                   = 32468.0
        constant integer MAX_PLAYERS                          = 12
        constant integer MAX_BALLS                            = 13
        constant real    TOURNAMENT_HALF_TIME                 = 600.0
        constant real    DUMMY_X                              = 1600.0
        constant real    DUMMY_Y                              = 2200.0
        constant real    VOTE_TIME                            = 30.0
        constant real    VOTE_EXTENSION                       = 2.00
        constant string  SWITCH_SFX_PATH                      = "Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl"
        constant real    HALF_DELAY                           = 15.0
        constant real    GOAL_BLOCK_FACTOR                    = 0.50
        constant integer STATS_MIN_PLAYERS                    = 4
        constant real    ATMOSPHERE_HEIGHT                    = 10000.00
        constant real    RECOLOR_ENABLED_DURATION             = 91.0
        constant integer PATHING_BLOCKER_RAWCODE              = 'YTob'
    endglobals
   
endlibrary
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      = false
        private constant boolean USE_FLEXIBLE_OFFSET = true

        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=10
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
//                   use the dummy.mdx model, so remember to import it as
//                   well, just use copy&paste to copy the dummy from the
//                   xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
//                    this rawcode to another spell that morphs into a flier
//                    in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
//                      raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
//                      timer that depends on it, if you put a low value
//                      the movement will look good but it may hurt your
//                      performance, if instead you use a high value it
//                      will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
//                        you got a unit bigger than 197.0 it would be
//                        a good idea to update this constant, since some
//                        enums will not find it. Likewise, if none of
//                        your units can go bellow X and X is much smaller
//                        than 197.0, it would be a good idea to update
//                        as well, since it will improve the performance
//                        those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************

//===========================================================================
globals
   constant integer XE_DUMMY_UNITID       = DUMMY_RAWCODE
   constant integer XE_HEIGHT_ENABLER     = 'Amrf'
   constant integer XE_TREE_RECOGNITION   = 'Aeat'
   constant real    XE_ANIMATION_PERIOD   =  0.025
   constant real    XE_MAX_COLLISION_SIZE =  197.0
endglobals

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AutoIndex
//===========================================================================
// Information:
//==============
//
//     AutoIndex is a very simple script to utilize. Just call GetUnitId(unit)
// to get get the unique value assigned to a particular unit. The GetUnitId
// function is extremely fast because it inlines directly to a GetUnitUserData
// call. AutoIndex automatically assigns an ID to each unit as it enters the
// map, and instantly frees that ID as the unit leaves the map. Detection of
// leaving units is accomplished in constant time without a periodic scan.
//
//     AutoIndex uses UnitUserData by default. If something else in your map
// would conflict with that, you can set the UseUnitUserData configuration
// constant to false, and a hashtable will be used instead. Note that hash-
// tables are about 60% slower.
//
//     If you turn on debug mode, AutoIndex will be able to display several
// helpful error messages. The following issues will be detected:
//   -Passing a removed or decayed unit to GetUnitId
//   -Code outside of AutoIndex has overwritten a unit's UserData value.
//   -GetUnitId was used on a filtered unit (a unit you don't want indexed).
//
//     AutoIndex provides events upon indexing or deindexing units. This
// effectively allows you to notice when units enter or leave the game. Also
// included are the AutoData, AutoCreate, and AutoDestroy modules, which allow
// you to fully utilize AutoIndex's enter/leave detection capabilities in
// conjunction with your structs.
//
//===========================================================================
// How to install AutoIndex:
//===========================
//
// 1.) Copy and paste this script into your map.
// 2.) Save it to allow the ObjectMerger macro to generate the "Leave Detect"
//     ability for you. Close and re-open the map. After that, disable the macro
//     to prevent the delay while saving.
//
//===========================================================================
// How to use AutoIndex:
//=======================
//
//     So you can get a unique integer for each unit, but how do you use that to
// attach data to a unit? GetUnitId will always return a number in the range of
// 1-8190. This means it can be used as an array index, as demonstrated below:
/*
    globals
        integer array IntegerData
        real array RealData
        SomeStruct array SomeStructData
    englobals

    function Example takes nothing returns nothing
        local unit u = CreateUnit(Player(0), 'hpea', 0., 0., 0.)
        local integer id = GetUnitId(u)
            //You now have a unique index for the unit, so you can
            //attach or retrieve data about the unit using arrays.
            set IntegerData[id] = 5
            set RealData[id] = 25.0
            set SomeStructData[id] = SomeStruct.create()
            //If you have access to the same unit in another function, you can
            //retrieve the data by using GetUnitId() and reading the arrays.
    endfunction
*/

//     The UnitFilter function in the configuration section is provided so that
// you can make AutoIndex completely ignore certain unit-types. Ignored units
// won't be indexed or fire indexed/deindexed events. You may want to filter out
// dummy casters or system-private units, especially ones that use UnitUserData
// internally. xe dummy units are automatically filtered.
//
//===========================================================================
// How to use OnUnitIndexed / OnUnitDeindexed:
//=============================================
//
//     AutoIndex will fire the OnUnitIndexed event when a unit enters the map,
// and the OnUnitDeindexed event when a unit leaves the map. Functions used
// as events must take a unit and return nothing. An example is given below:
/*
    function UnitEntersMap takes unit u returns nothing
        call BJDebugMsg(GetUnitName(u)+" with ID "+I2S(GetUnitId(u))+" entered the map.")
    endfunction //Using GetUnitId() during Indexed events works fine...

    function UnitLeavesMap takes unit u returns nothing
        call BJDebugMsg(GetUnitName(u)+" with ID "+I2S(GetUnitId(u))+" left the map.")
    endfunction  //So does using GetUnitId() during Deindexed events.

    function Init takes nothing returns nothing
        call OnUnitIndexed(UnitEntersMap)
        call OnUnitDeindexed(UnitLeavesMap)
    endfunction
*/

//     If you call OnUnitIndexed during map initialization, every existing
// unit will be considered as entering the map. This saves you from the need
// to manually enumerate preplaced units (or units created by initialization
// code that ran before OnUnitIndexed was called).
//
//     OnUnitDeindexed runs while a unit still exists, which means you can
// still do things such as destroy special effects attached to the unit.
// The unit will cease to exist immediately after the event is over.
//
//===========================================================================
// AutoIndex API:
//================
//
// GetUnitId(unit) -> integer
//   This function returns a unique ID in the range of 1-8190 for the
//   specified unit. Returns 0 if a null unit was passed. This function
//   inlines directly to GetUnitUserData or LoadInteger if debug mode
//   is disabled. If debug mode is enabled, this function will print
//   an error message when passed a decayed or filtered unit.
//
// IsUnitIndexed(unit) -> boolean
//   This function returns a boolean indicating whether the specified
//   unit has been indexed. The only time this will return false is
//   for units you have filtered using the UnitFilter function, or
//   for xe dummy units. You can use this function to easily detect
//   dummy units and avoid performing certain actions on them.
//
// OnUnitIndexed(IndexFunc)
//   This function accepts an IndexFunc, which must take a unit and
//   return nothing. The IndexFunc will be fired instantly whenever
//   a unit enters the map. You may use GetUnitId on the unit. When
//   you call this function during map initialization, every existing
//   unit will be considered as entering the map.
//
// OnUnitDeindexed(IndexFunc)
//   Same as above, but runs whenever a unit is leaving the map. When
//   this event runs, the unit still exists, but it will cease to exist
//   as soon as the event ends. You may use GetUnitId on the unit.
//
//===========================================================================
// How to use AutoData:
//======================
//
//     The AutoData module allows you to associate one or more instances
// of the implementing struct with units, as well as iterate through all
// of the instances associated with each unit.
//
//     This association is accomplished through the "me" instance member,
// which the module will place in the implementing struct. Whichever unit
// you assign to "me" becomes the owner of that instance. You may change
// ownership by reassigning "me" to another unit at any time, or you may
// make the instance unowned by assigning "me" to null.
//
//     AutoData implements the static method operator [] in your struct
// to allow you to access instances from their owning units. For example,
// you may type: local StructName s = StructName[u]. If u has been set
// to own an instance of StructName, s will be set to that instance.
//
//     So, what happens if you assign the same owning unit to multiple
// instances? You may use 2D array syntax to access instances assigned to
// the same unit: local StructName s = StructName[u][n], where u is the
// owning unit, and n is the index beginning with 0 for each unit. You
// can access the size of a unit's instance list (i.e. the number of
// instances belonging to the unit) by using the .size instance member.
/*
    struct Example
        implement AutoData
        static method create takes unit u returns Example
            local Example this = allocate()
                set me = u //Assigning the "me" member from AutoData.
            return this
        endmethod
    endstruct
    function Test takes nothing returns nothing
        local unit u = CreateUnit(Player(0), 'hpea', 0., 0., 0.)
        local Example e1 = Example.create(u)
        local Example e2 = Example.create(u)
        local Example e3 = Example.create(u)
        local Example e
            call BJDebugMsg(I2S(Example[u].size)) //Prints 3 because u owns e1, e2, and e3.
            set e = Example[u][GetRandomInt(0, Example[u].size - 1)] //Random instance belonging to u.
            set e = Example[u]  //This is the fastest way to iterate the instances belonging
            loop                //to a specific unit, starting with the first instance.
                exitwhen e == 0 //e will be assigned to 0 when no instances remain.
                call BJDebugMsg(I2S(e)) //Prints the values of e1, e2, e3.
                set e = e[e.index + 1] //"e.index" refers to the e's position in u's instance list.
            endloop                    //Thus, index + 1 is next, and index - 1 is previous.
    endfunction                        //This trick allows you to avoid a local counter.
*/

//   AutoData restrictions:
//   -You may not implement AutoData in any struct which has already
//    declared static or non-static method operator [].
//   -AutoData will conflict with anything named "me", "size", or
//    "index" in the implementing struct.
//   -AutoData may not be implemented in structs that extend array.
//   -You may not declare your own destroy method. (This restriction
//    can be dropped as soon as JassHelper supports module onDestroy).
//
//   AutoData information:
//   -You do not need to null the "me" member when destroying an
//    instance. That is done for you automatically during destroy().
//    (But if you use deallocate(), you must null "me" manually.)
//   -StructName[u] and StructName[u][0] refer to the same instance,
//    which is the first instance that was associated with unit u.
//   -StructName[u][StructName[u].size - 1] refers to the instance that
//    was most recently associated with unit u.
//   -Instances keep their relative order in the list when one is removed.
//
//===========================================================================
// How to use AutoCreate:
//=======================
//
//     The AutoCreate module allows you to automatically create instances
// of the implementing struct for units as they enter the game. AutoCreate
// automatically implements AutoData into your struct. Any time an instance
// is automatically created for a unit, that instance's "me" member will be
// assigned to the entering unit.
//
//   AutoCreate restrictions:
//   -All of the same restrictions as AutoData.
//   -If your struct's allocate() method takes parameters (i.e. the parent
//    type's create method takes parameters), you must declare a create
//    method and pass those extra parameters to allocate yourself.
//
//   AutoCreate information:
//   -You may optionally declare the createFilter method, which specifies
//    which units should recieve an instance as they enter the game. If
//    you do not declare it, all entering units will recieve an instance.
//   -You may optionally declare the onCreate method, which will run when
//    AutoCreate automatically creates an instance. (This is just a stand-
//    in until JassHelper supports the onCreate method.)
//   -You may declare your own create method, but it must take a single
//    unit parameter (the entering unit) if you do so.
/*
    struct Example
        private static method createFilter takes unit u returns boolean
            return GetUnitTypeId(u) == 'hfoo' //Created only for Footmen.
        endmethod
        private method onCreate takes nothing returns nothing
            call BJDebugMsg(GetUnitName(me)+" entered the game!")
        endmethod
        implement AutoCreate
    endstruct
*/

//===========================================================================
// How to use AutoDestroy:
//=========================
//
//     The AutoDestroy module allows you to automatically destroy instances
// of the implementing struct when their "me" unit leaves the game. AutoDestroy
// automatically implements AutoData into your struct. You must assign a unit
// to the "me" member of an instance for this module to have any effect.
//
//   AutoDestroy restrictions:
//   -All of the same restrictions as AutoData.
//
//   AutoDestroy information:
//   -If you also implement AutoCreate in the same struct, remember that it
//    assigns the "me" unit automatically. That means you can have fully
//    automatic creation and destruction.
/*
    struct Example
        static method create takes unit u returns Example
            local Example this = allocate()
                set me = u //You should assign a unit to "me",
            return this    //otherwise AutoDestroy does nothing.
        endmethod          //Not necessary if using AutoCreate.
        private method onDestroy takes nothing returns nothing
            call BJDebugMsg(GetUnitName(me)+" left the game!")
        endmethod
        implement AutoDestroy
    endstruct
*/

//===========================================================================
// Configuration:
//================

// external ObjectMerger w3a Adef lvdt anam "Leave Detect" aart "" arac 0
//Save your map with this Object Merger call enabled, then close and reopen your
//map. Disable it by removing the exclamation to remove the delay while saving.

globals
    private constant integer LeaveDetectAbilityID = 'lvdt'
    //This rawcode must match the parameter after "Adef" in the
    //ObjectMerger macro above. You may change both if you want.
   
    private constant boolean UseUnitUserData = true
    //If this is set to true, UnitUserData will be used. You should only set
    //this to false if something else in your map already uses UnitUserData.
    //A hashtable will be used instead, but it is about 60% slower.
   
    private constant boolean SafeMode = true
    //This is set to true by default so that GetUnitId() will ALWAYS work.
    //If if this is set to false, GetUnitId() may fail to work in a very
    //rare circumstance: creating a unit that has a default-on autocast
    //ability, and using GetUnitId() on that unit as it enters the game,
    //within a trigger that detects any order. Set this to false for a
    //performance boost only if you think you can avoid this issue.
   
    private constant boolean AutoDataFastMode = true
    //If this is set to true, AutoData will utilize one hashtable per time
    //it is implemented. If this is set to false, all AutoDatas will share
    //a single hashtable, but iterating through the instances belonging to
    //a unit will become about 12.5% slower. Your map will break if you
    //use more than 255 hashtables simultaneously. Only set this to false
    //if you suspect you will run out of hashtable instances.
endglobals

private function UnitFilter takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DUMMY)
endfunction
//Make this function return false for any unit-types you want to ignore.
//Ignored units won't be indexed or fire OnUnitIndexed/OnUnitDeindexed
//events. The unit parameter "u" to refers to the unit being filtered.
//Do not filter out xe dummy units; they are automatically filtered.

//===========================================================================
// AutoData / AutoCreate / AutoDestroy modules:
//==============================================

function interface AutoCreator takes unit u returns nothing
function interface AutoDestroyer takes unit u returns nothing

globals                
    hashtable AutoData = null //If AutoDataFastMode is disabled, this hashtable will be
endglobals                    //initialized and shared between all AutoData implementations.

module AutoData
    private static hashtable ht
    private static thistype array data
    private static integer array listsize
    private static key typeid //Good thing keys exist to identify each implementing struct.
    private unit meunit
    private integer id
   
    readonly integer index //The user can avoid using a local counter because this is accessable.
   
    static method operator [] takes unit u returns thistype
        return data[GetUnitId(u)]
    endmethod //This is as fast as retrieving an instance from a unit gets.
   
    method operator [] takes integer index returns thistype
        static if AutoDataFastMode then //If fast mode is enabled...
            return LoadInteger(ht, id, index)
        else //Each instance has its own hashtable to associate unit and index.
            return LoadInteger(AutoData, id, index*8190+typeid)
        endif //Otherwise, simulate a 3D array associating unit, struct-type ID, and index.
    endmethod //Somehow, this version is 12.5% slower just because of the math.
   
    private method setIndex takes integer index, thistype data returns nothing
        static if AutoDataFastMode then //Too bad you can't have a module-private operator []=.
            call SaveInteger(ht, id, index, data)
        else
            call SaveInteger(AutoData, id, index*8190+typeid, data)
        endif
    endmethod
   
    private method remove takes nothing returns nothing
        if meunit == null then //If the struct doesn't have an owner...
            return             //Nothing needs to be done.
        endif
        loop
            exitwhen index == listsize[id]        //The last value gets overwritten by 0.
            call setIndex(index, this[index + 1]) //Shift each element down by one.
            set this[index].index = index         //Update the shifted instance's index.
            set index = index + 1
        endloop
        set listsize[id] = listsize[id] - 1
        set data[id] = this[0] //Ensure thistype[u] returns the same value as thistype[u][0].
        set meunit = null
    endmethod
   
    private method add takes unit u returns nothing
        if meunit != null then     //If the struct has an owner...
            call remove()          //remove it first.
        endif
        set meunit = u
        set id = GetUnitId(u)      //Cache GetUnitId for slight performance boost.
        if data[id] == 0 then      //If this is the first instance for this unit...
            set data[id] = this    //Update the value that thistype[u] returns.
        endif
        set index = listsize[id]   //Remember the index for removal.
        call setIndex(index, this) //Add to the array.
        set listsize[id] = index + 1
    endmethod
   
    method operator me takes nothing returns unit
        return meunit
    endmethod
   
    method operator me= takes unit u returns nothing
        if u != null then //If assigning "me" a non-null value...
            call add(u)   //Add this instance to that unit's array.
        else              //If assigning "me" a null value...
            call remove() //Remove this instance from that unit's array.
        endif
    endmethod
   
    method operator size takes nothing returns integer
        return listsize[id]
    endmethod
   
    method destroy takes nothing returns nothing
        call deallocate()
        call remove() //This makes removal automatic when an instance is destroyed.
    endmethod
   
    private static method onInit takes nothing returns nothing
        static if AutoDataFastMode then        //If fast mode is enabled...
            set ht = InitHashtable()           //Initialize one hashtable per instance.
        else                                   //If fast mode is disabled...
            if AutoData == null then           //If the hashtable hasn't been initialized yet...
                set AutoData = InitHashtable() //Initialize the shared hashtable.
            endif
        endif
    endmethod
endmodule

module AutoCreate
    implement AutoData //AutoData is necessary for AutoCreate.

    private static method creator takes unit u returns nothing
        local thistype this
        local boolean b = true                          //Assume that the instance will be created.
            static if thistype.createFilter.exists then //If createFilter exists...
                set b = createFilter(u)                 //evaluate it and update b.
            endif
            if b then                                   //If the instance should be created...
                static if thistype.create.exists then   //If the create method exists...
                    set this = create(u)                //Create the instance, passing the entering unit.
                else                                    //If the create method doesn't exist...
                    set this = allocate()               //Just allocate the instance.
                endif
                set me = u                              //Assign the instance's owner as the entering unit.
                static if thistype.onCreate.exists then //If onCreate exists...
                    call onCreate()                     //Call it, because JassHelper should do this anyway.
                endif
            endif
    endmethod

    private static method onInit takes nothing returns nothing
        call AutoIndex.addAutoCreate(thistype.creator)
    endmethod //During module initialization, pass the creator function to AutoIndex.
endmodule

module AutoDestroy
    implement AutoData //AutoData is necessary for AutoDestroy.
   
    static method destroyer takes unit u returns nothing
        loop
            exitwhen thistype[u] == 0
            call thistype[u].destroy()
        endloop
    endmethod //Destroy each instance owned by the unit until none are left.

    private static method onInit takes nothing returns nothing
        call AutoIndex.addAutoDestroy(thistype.destroyer)
    endmethod //During module initialization, pass the destroyer function to AutoIndex.
endmodule

//===========================================================================
// AutoIndex struct:
//===================

function interface IndexFunc takes unit u returns nothing

hook RemoveUnit AutoIndex.hook_RemoveUnit
hook ReplaceUnitBJ AutoIndex.hook_ReplaceUnitBJ
debug hook SetUnitUserData AutoIndex.hook_SetUnitUserData

private keyword getIndex
private keyword getIndexDebug
private keyword isUnitIndexed
private keyword onUnitIndexed
private keyword onUnitDeindexed

struct AutoIndex
    private static trigger   enter      = CreateTrigger()
    private static trigger   order      = CreateTrigger()
    private static trigger   creepdeath = CreateTrigger()
    private static group     preplaced  = CreateGroup()
    private static timer     allowdecay = CreateTimer()
    private static hashtable ht

    private static boolean array dead
    private static boolean array summoned
    private static boolean array animated
    private static boolean array nodecay
    private static boolean array removing
   
    private static IndexFunc array indexfuncs
    private static integer indexfuncs_n = -1
    private static IndexFunc array deindexfuncs
    private static integer deindexfuncs_n = -1
    private static IndexFunc indexfunc
   
    private static AutoCreator array creators
    private static integer creators_n = -1
    private static AutoDestroyer array destroyers
    private static integer destroyers_n = -1
   
    private static unit array allowdecayunit
    private static integer allowdecay_n = -1
   
    private static boolean duringinit = true
    private static boolean array altered
    private static unit array idunit
   
    //===========================================================================

    static method getIndex takes unit u returns integer
        static if UseUnitUserData then
            return GetUnitUserData(u)
        else
            return LoadInteger(ht, 0, GetHandleId(u))
        endif
    endmethod //Resolves to an inlinable one-liner after the static if.
   
    static method getIndexDebug takes unit u returns integer
            if u == null then
                return 0
            elseif GetUnitTypeId(u) == 0 then
                call BJDebugMsg("AutoIndex error: Removed or decayed unit passed to GetUnitId.")
            elseif idunit[getIndex(u)] != u and GetIssuedOrderId() != 852056 then
                call BJDebugMsg("AutoIndex error: "+GetUnitName(u)+" is a filtered unit.")
            endif
        return getIndex(u)
    endmethod //If debug mode is enabled, use the getIndex method that shows errors.
   
    private static method setIndex takes unit u, integer index returns nothing
        static if UseUnitUserData then
            call SetUnitUserData(u, index)
        else
            call SaveInteger(ht, 0, GetHandleId(u), index)
        endif
    endmethod //Resolves to an inlinable one-liner after the static if.
   
    static method isUnitIndexed takes unit u returns boolean
        return u != null and idunit[getIndex(u)] == u
    endmethod
   
    static method isUnitAnimateDead takes unit u returns boolean
        return animated[getIndex(u)]
    endmethod //Don't use this; use IsUnitAnimateDead from AutoEvents instead.
   
    //===========================================================================
   
    private static method onUnitIndexed_sub takes nothing returns nothing
        call indexfunc.evaluate(GetEnumUnit())
    endmethod
    static method onUnitIndexed takes IndexFunc func returns nothing
        set indexfuncs_n = indexfuncs_n + 1
        set indexfuncs[indexfuncs_n] = func
        if duringinit then //During initialization, evaluate the indexfunc for every preplaced unit.
            set indexfunc = func
            call ForGroup(preplaced, function AutoIndex.onUnitIndexed_sub)
        endif
    endmethod
   
    static method onUnitDeindexed takes IndexFunc func returns nothing
        set deindexfuncs_n = deindexfuncs_n + 1
        set deindexfuncs[deindexfuncs_n] = func
    endmethod
   
    static method addAutoCreate takes AutoCreator func returns nothing
        set creators_n = creators_n + 1
        set creators[creators_n] = func
    endmethod
   
    static method addAutoDestroy takes AutoDestroyer func returns nothing
        set destroyers_n = destroyers_n + 1
        set destroyers[destroyers_n] = func
    endmethod
   
    //===========================================================================
   
    private static method hook_RemoveUnit takes unit whichUnit returns nothing
        set removing[getIndex(whichUnit)] = true
    endmethod //Intercepts whenever RemoveUnit is called and sets a flag.
    private static method hook_ReplaceUnitBJ takes unit whichUnit, integer newUnitId, integer unitStateMethod returns nothing
        set removing[getIndex(whichUnit)] = true
    endmethod //Intercepts whenever ReplaceUnitBJ is called and sets a flag.
   
    private static method hook_SetUnitUserData takes unit whichUnit, integer data returns nothing
        static if UseUnitUserData then
            if idunit[getIndex(whichUnit)] == whichUnit then
                if getIndex(whichUnit) == data then
                    call BJDebugMsg("AutoIndex error: Code outside AutoIndex attempted to alter "+GetUnitName(whichUnit)+"'s index.")
                else
                    call BJDebugMsg("AutoIndex error: Code outside AutoIndex altered "+GetUnitName(whichUnit)+"'s index.")
                    if idunit[data] != null then
                        call BJDebugMsg("AutoIndex error: "+GetUnitName(whichUnit)+" and "+GetUnitName(idunit[data])+" now have the same index.")
                    endif
                    set altered[data] = true
                endif
            endif
        endif //In debug mode, intercepts whenever SetUnitUserData is used on an indexed unit.
    endmethod //Displays an error message if outside code tries to alter a unit's index.
   
    //===========================================================================
   
    private static method allowDecay takes nothing returns nothing
        local integer n = allowdecay_n
            loop
                exitwhen n < 0
                set nodecay[getIndex(allowdecayunit[n])] = false
                set allowdecayunit[n] = null
                set n = n - 1
            endloop
            set allowdecay_n = -1
    endmethod //Iterate through all the units in the stack and allow them to decay again.
   
    private static method detectStatus takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer index = getIndex(u)
        local integer n
           
            if idunit[index] == u then //Ignore non-indexed units.
                if not IsUnitType(u, UNIT_TYPE_DEAD) then
               
                    if dead[index] then         //The unit was dead, but now it's alive.
                        set dead[index] = false //The unit has been resurrected.
                        //! runtextmacro optional RunAutoEvent("Resurrect")
                        //If AutoEvents is in the map, run the resurrection events.
                       
                        if IsUnitType(u, UNIT_TYPE_SUMMONED) and not summoned[index] then
                            set summoned[index] = true //If the unit gained the summoned flag,
                            set animated[index] = true //it's been raised with Animate Dead.
                            //! runtextmacro optional RunAutoEvent("AnimateDead")
                            //If AutoEvents is in the map, run the Animate Dead events.
                        endif
                    endif
                else
               
                    if not removing[index] and not dead[index] and not animated[index] then
                        set dead[index] = true               //The unit was alive, but now it's dead.
                        set nodecay[index] = true            //A dead unit can't decay for at least 0. seconds.
                        set allowdecay_n = allowdecay_n + 1  //Add the unit to a stack. After the timer
                        set allowdecayunit[allowdecay_n] = u //expires, allow the unit to decay again.
                        call TimerStart(allowdecay, 0., false, function AutoIndex.allowDecay)
                        //! runtextmacro optional RunAutoEvent("Death")
                        //If AutoEvents is in the map, run the Death events.
                       
                    elseif removing[index] or (dead[index] and not nodecay[index]) or (not dead[index] and animated[index]) then
                        //If .nodecay was false and the unit is dead and was previously dead, the unit decayed.
                        //If .animated was true and the unit is dead, the unit died and exploded.
                        //If .removing was true, the unit is being removed or replaced.
                        set n = deindexfuncs_n
                        loop //Run the OnUnitDeindexed events.
                            exitwhen n < 0
                            call deindexfuncs[n].evaluate(u)
                            set n = n - 1
                        endloop
                        set n = destroyers_n
                        loop //Destroy AutoDestroy structs for the leaving unit.
                            exitwhen n < 0
                            call destroyers[n].evaluate(u)
                            set n = n - 1
                        endloop
                        call AutoIndex(index).destroy() //Free the index by destroying the AutoIndex struct.
                        set idunit[index] = null        //Null this unit reference to prevent a leak.
                    endif
                endif
            endif
        set u = null
        return false
    endmethod

    //===========================================================================
   
    private static method unitEntersMap takes unit u returns nothing
        local integer index
        local integer n = 0
            if getIndex(u) != 0 then
                return //Don't index a unit that already has an ID.
            endif
            static if LIBRARY_xebasic then
                if GetUnitTypeId(u) == XE_DUMMY_UNITID then
                    return //Don't index xe dummy units.
                endif
            endif
            if not UnitFilter(u) then
                return //Don't index units that fail the unit filter.
            endif
            set index = create()
            call setIndex(u, index) //Assign an index to the entering unit.
           
            call UnitAddAbility(u, LeaveDetectAbilityID)                 //Add the leave detect ability to the entering unit.
            call UnitMakeAbilityPermanent(u, true, LeaveDetectAbilityID) //Prevent it from disappearing on morph.
            set dead[index] = IsUnitType(u, UNIT_TYPE_DEAD)              //Reset all of the flags for the entering unit.
            set summoned[index] = IsUnitType(u, UNIT_TYPE_SUMMONED)      //Each of these flags are necessary to detect
            set animated[index] = false                                  //when a unit leaves the map.
            set nodecay[index] = false
            set removing[index] = false
            debug set altered[index] = false    //In debug mode, this flag tracks wheter a unit's index was altered.
            set idunit[index] = u               //Attach the unit that is supposed to have this index to the index.
           
            if duringinit then                  //If a unit enters the map during initialization...
                call GroupAddUnit(preplaced, u) //Add the unit to the preplaced units group. This ensures that
            endif                               //all units are noticed by OnUnitIndexed during initialization.
            loop //Create AutoCreate structs for the entering unit.
                exitwhen n > creators_n
                call creators[n].evaluate(u)
                set n = n + 1
            endloop
            set n = 0
            loop //Run the OnUnitIndexed events.
                exitwhen n > indexfuncs_n
                call indexfuncs[n].evaluate(u)
                set n = n + 1
            endloop
    endmethod
   
    private static method onIssuedOrder takes nothing returns boolean
            static if SafeMode then     //If SafeMode is enabled, perform this extra check.
                if getIndex(GetTriggerUnit()) == 0 then  //If the unit doesn't already have
                    call unitEntersMap(GetTriggerUnit()) //an index, then assign it one.
                endif
            endif
        return GetIssuedOrderId() == 852056 //If the order is Undefend, allow detectStatus to run.
    endmethod
   
    private static method initEnteringUnit takes nothing returns boolean
            call unitEntersMap(GetFilterUnit())
        return false
    endmethod
   
    //===========================================================================
   
    private static method afterInit takes nothing returns nothing
        set duringinit = false               //Initialization is over; set a flag.
        call DestroyTimer(GetExpiredTimer()) //Destroy the timer.
        call GroupClear(preplaced)           //The preplaced units group is
        call DestroyGroup(preplaced)         //no longer needed, so clean it.
        set preplaced = null
    endmethod
   
    private static method onInit takes nothing returns nothing
        local region maparea = CreateRegion()
        local rect bounds = GetWorldBounds()
        local group g = CreateGroup()
        local integer i = 15
            static if not UseUnitUserData then
                set ht = InitHashtable() //Only create a hashtable if it will be used.
            endif
            loop
                exitwhen i < 0
                call SetPlayerAbilityAvailable(Player(i), LeaveDetectAbilityID, false)
                //Make the LeaveDetect ability unavailable so that it doesn't show up on the command card of every unit.
                call TriggerRegisterPlayerUnitEvent(order, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
                //Register the "EVENT_PLAYER_UNIT_ISSUED_ORDER" event for each player.
                call GroupEnumUnitsOfPlayer(g, Player(i), function AutoIndex.initEnteringUnit)
                //Enum every non-filtered unit on the map during initialization and assign it a unique
                //index. By using GroupEnumUnitsOfPlayer, even units with Locust can be detected.
                set i = i - 1
            endloop
            call TriggerAddCondition(order, And(function AutoIndex.onIssuedOrder, function AutoIndex.detectStatus))
            //The detectStatus method will fire every time a non-filtered unit recieves an undefend order.
            //And() is used here to avoid using a trigger action, which starts a new thread and is slower.
            call TriggerRegisterPlayerUnitEvent(creepdeath, Player(12), EVENT_PLAYER_UNIT_DEATH, null)
            call TriggerAddCondition(creepdeath, function AutoIndex.detectStatus)
            //The detectStatus method must also fire when a neutral hostile creep dies, in case it was
            //sleeping. Sleeping creeps don't fire undefend orders on non-damaging deaths.
            call RegionAddRect(maparea, bounds) //GetWorldBounds() includes the shaded boundry areas.
            call TriggerRegisterEnterRegion(enter, maparea, function AutoIndex.initEnteringUnit)
            //The filter function of an EnterRegion trigger runs instantly when a unit is created.
            call TimerStart(CreateTimer(), 0., false, function AutoIndex.afterInit)
            //After any time elapses, perform after-initialization actions.
        call GroupClear(g)
        call DestroyGroup(g)
        call RemoveRect(bounds)
        set g = null
        set bounds = null
    endmethod
   
endstruct

//===========================================================================
// User functions:
//=================

function GetUnitId takes unit u returns integer
    static if DEBUG_MODE then             //If debug mode is enabled...
        return AutoIndex.getIndexDebug(u) //call the debug version of GetUnitId.
    else                                  //If debug mode is disabled...
        return AutoIndex.getIndex(u)      //call the normal, inlinable version.
    endif
endfunction

function IsUnitIndexed takes unit u returns boolean
    return AutoIndex.isUnitIndexed(u)
endfunction

function OnUnitIndexed takes IndexFunc func returns nothing
    call AutoIndex.onUnitIndexed(func)
endfunction

function OnUnitDeindexed takes IndexFunc func returns nothing
    call AutoIndex.onUnitDeindexed(func)
endfunction

endlibrary
 
//TESH.scrollpos=108
//TESH.alwaysfold=0
library UnitStatus initializer Init requires TimerUtils, AutoIndex, optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library exists because oftentimes, a mapmaker needs to apply a specific
//* status effect to a unit. If he were to do it on his own, he'd need to find a
//* way to get the status effects to stack properly with one another and with
//* multiple instances of themselves. This script does just that with the five
//* most useful status options in WC3 that cannot be reproduced perfectly with
//* just code and not actual in-game buffs.
//*
//* WARNING: This library uses the following buffs. If you use any of the listed
//*          buffs in your map, they will not stack with this script's buffs and
//*          it may not work. If you need these effects, then only use this
//*          script to achieve them.
//*           - Drunken Haze
//*           - Soul Burn
//*           - Ensnare
//*           - Storm Bolt
//*           - Hurl Boulder
//*
//******************************************************************************
//*
//* The following status effects are supported by this library.
//*
//* -   Silence
//*   This status disables a given unit's ability to cast spells. This works
//*   properly on spell immune and normal units.
//*  
//*     Example Usage:
//*   call SilenceUnit(u, true)     //Silences a unit
//*   call SilenceUnit(u, false)    //Removes silence from a unit
//*   call SilenceUnitTimed(u, 4.0) //Adds a timed silence to a unit
//*  
//* -   Disarm
//*   This status disables a given unit's ability to attack and attack ground.
//*   This will not work properly on spell immune units because of a Blizzard
//*   bug. The function calls will return false when used on units that are
//*   spell immune. This status disables both ranged and melee attacks.
//*  
//*     Example Usage:
//*   call DisarmUnit(u, true)      //Disarms a unit
//*   call DisarmUnit(u, false)     //Removes disarm from a unit
//*   call DisarmUnitTimed(u, 4.0)  //Adds a timed disarm to a unit
//*  
//* -   Ensnare
//*   This status disables a given unit's ability to move. This works properly
//*   on spell immune and normal units. Because of the nature of the ability
//*   this is based upon, it will exhibit strange behavior on flying units. If
//*   this is used on flying units, they will retain their flying height, but
//*   be treated as ground units by the game. There is unfortunately no
//*   workaround for this behavior. It is recommended to not use it on flying
//*   units because for that reason.
//*  
//*     Example Usage:
//*   call EnsnareUnit(u, true)     //Ensnares a unit
//*   call EnsnareUnit(u, false)    //Removes ensnare from a unit
//*   call EnsnareUnitTimed(u, 4.0) //Adds a timed ensnare to a unit
//*  
//* -   Stun
//*   This status is identical in nature to the standard melee stun. A stunned
//*   unit cannot move, attack, or cast spells. Both spell immune and normal
//*   units can be stunned.
//*  
//*     Example Usage:
//*   call StunUnit(u, true)        //Ensnares a unit
//*   call StunUnit(u, false)       //Removes stun from a unit
//*   call StunUnitTimed(u, 4.0)    //Adds a timed stun to a unit
//*  
//* -   Disable
//*   Disable is a unique status meant to be used as a replacement for pausing a
//*   unit using the PauseUnit native. Pausing a unit has the negative side
//*   effects of removing the unit's command card and not preserving queued
//*   orders. Disabling a unit retains both of those sought features. Disable is
//*   a non-graphical stun at its core that is always 'underneath' stun when
//*   both are applied on a unit at once as listed below.
//*  
//*   Disable also interacts with stun in a unique way.
//*    - If stun is used on a disabled unit, the unit becomes stunned instead.
//*    - If stun ends on a disabled unit, the unit is disabled until the disable
//*      ends.
//*    - If disable is used on a stunned unit, the unit remains visibly stunned.
//*  
//*     Example Usage:
//*   call DisableUnit(u, true)     //Disables a unit
//*   call DisableUnit(u, false)    //Removes disable from a unit
//*   call DisableUnitTimed(u, 4.0) //Adds a timed disable to a unit
//*
//* WARNING: These status effects, when used on invulnerable units, will have
//*          absolutely no effect.
//*
//******************************************************************************
//*
//* There is a textmacro call below that runs a series of ObjectMerger calls
//* inside of an embedded .lua script. This sub-script generates all of the
//* abilities and buffs required by this library automatically for you. Enable
//* it by uncommenting the textmacro, saving your map, closing your map,
//* reopening your map, and commenting the macro again.
//*
//* Note that you, as the user, may edit any of the buff icons or tooltips to
//* your liking. It is not recommended to edit the data fields for the spells,
//* though. They are the way they are so that they will work.
//*
//* WARNING: The ObjectMerger call for Disarm's ability seems to be unable to
//*          properly configure the "Data - Attacks Prevented" field. If you
//*          find that the DisarmUnit call isn't functioning as intended, then
//*          set that field to "None", save your map, set the field back to
//*          "Melee, Ranged", and then save your map again. It should now work
//*          properly.
//*
//* You may change the raw ids of any of the generated abilities as needed for
//* your map. (If there are conflicts) If you want to do so, then make sure that
//* you change the raw ids inside all affected ObjectMerger calls and the
//* constants in the globals block below.
//*
//* WARNING: If you choose to change the raw id for the Silence ability, do NOT
//*          let the buff raw id match the ability raw id. If you do, the buff's
//*          special effect fields will not show in-game. (This may or may not
//*          even affect you, but it is worth noting regardless)
//*
//* xebasic is an optional requirement. If you have xebasic in your map, this
//* script will use xebasic's dummy unit id instead of the constant below. If
//* you do not have xebasic in your map, for this to work you will need to make
//* (if you have not already) a dummy unit caster for your map. Put its raw id
//* below in the DUMMY_UNITID constant field.
//*
//* Enjoy!
//*

//* Uncomment the following textmacro to create the abilities.
////! runtextmacro GenerateAbilities()

//! textmacro GenerateAbilities
//! externalblock extension=lua ObjectMerger $FILENAME$
//! i
//! i function set(field, value)
//! i     makechange(current, field, value)
//! i end
//! i function setl(field, level, value)
//! i     makechange(current, field, level, value)
//! i end
//! i
//! i setobjecttype("abilities")
//! i
//! i createobject("AHtb", "stun"); set("anam", "Stun Ability")
//! i set ("aani", "")        ; set ("aart", "")    ; set ("amat", "")     ; set ("amsp", 0)           ; setl("Htb1", 1, 0.0);
//! i setl("aran", 1, 99999.0); setl("acdn", 1, 0.0); setl("ahdu", 1, 0.0) ; setl("adur", 1, 0.0)      ; set ("arlv", 6)     ;
//! i set ("alev", 1)         ; setl("amcs", 1, 0)  ; set ("arac", "other"); setl("atar", 1, "notself");
//! i
//! i createobject("ANso", "&sil"); set("anam", "Silence Ability")
//! i set ("aart", "")       ; setl("Nso1", 1, 0.0); setl("Nso3", 1, 0.0) ; setl("Nso2", 1, 99999.0)  ; setl("aran", 1, 99999.0);
//! i setl("abuf", 1, "&SIL"); setl("acdn", 1, 0.0); setl("ahdu", 1, 0.0) ; setl("adur", 1, 0.0)      ; set ("arlv", 1);
//! i set ("alev", 1)        ; setl("amcs", 1, 0)  ; set ("arac", "other"); setl("atar", 1, "notself");
//! i
//! i createobject("ANdh", "&arm"); set("anam", "Disarm Ability")
//! i set ("aart", "")     ; set ("amat", "")          ; set ("amac", 0.0)   ; set ("amsp", 0)         ; setl("Nsi1", 1, 3)     ;
//! i setl("Nsi2", 1, 0.0) ; setl("Nsi3", 1, 0.0)      ; setl("aare", 1, 0.0); setl("aran", 1, 99999.0); setl("abuf", 1, "&ARM");
//! i setl("acdn", 1, 0.0) ; setl("ahdu", 1, 0.0)      ; setl("adur", 1, 0.0); set ("arlv", 6)         ; set ("alev", 1)        ;
//! i setl("amcs", 1, 0)   ; set ("arac", "other")     ; setl("atar", 1, "notself");
//! i
//! i createobject("ACen", "&ens"); set("anam", "Ensnare Ability")
//! i set ("aart", "")          ; set ("amat", "")            ; set ("amsp", 0)     ; setl("Ens1", 1, -1.0); setl("Ens2", 1, -1.0);
//! i setl("aran", 1, 99999.0)  ; setl("abuf", 1, "&EN1,&EN2"); setl("acdn", 1, 0.0); setl("ahdu", 1, 0.0) ; set ("aher", 1)      ;
//! i setl("adur", 1, 0.0)      ; set ("arlv", 6)             ; set ("alev", 1)     ; setl("amcs", 1, 0)   ; set ("arac", "other");
//! i setl("atar", 1, "notself"); set ("areq", "")            ; set("ansf", "")     ;
//! i
//! i createobject("ACtb", "&dis"); set("anam", "Disable Ability")
//! i set ("aani", "")          ; set ("aart", "")       ; set ("amat", "")    ; set ("amsp", 0)     ; setl("Ctb1", 1, 0.0) ;
//! i setl("aran", 1, 99999.0)  ; setl("abuf", 1, "&DIS"); setl("acdn", 1, 0.0); setl("ahdu", 1, 0.0); setl("adur", 1, 0.0) ;
//! i set ("aher", 1)           ; set ("arlv", 6)        ; set ("alev", 1)     ; setl("amcs", 1, 0)  ; set ("arac", "other");
//! i setl("atar", 1, "notself");
//! i
//! i setobjecttype("buffs")
//! i
//! i createobject("BNso", "&SIL"); set("fnam", "Disabled (Spells)")
//! i set("ftip", "Disabled (Spells)")                                 ; set("fube", "This unit cannot cast spells.");
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "")                             ; set("fta0", "");
//! i
//! i createobject("BNdh", "&ARM"); set("fnam", "Disabled (Attacks)")
//! i set("ftip", "Disabled (Attacks)")                                ; set("fube", "This unit cannot attack.");
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "")                        ; set("fta0", "");
//! i
//! i createobject("Beng", "&EN1"); set("fnam", "Disabled (Movement)")
//! i set("ftip", "Disabled (Movement)")                               ; set("fube", "This unit cannot move." );
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "")                       ; set("frac", "other");
//! i
//! i createobject("Bena", "&EN2"); set("fnam", "Disabled (Movement)")
//! i set("ftip", "Disabled (Movement)")                               ; set("fube", "This unit cannot move.");
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "")                      ; set("fta0", "");
//! i set("frac", "other");
//! i
//! i createobject("BPSE", "&DIS"); set("fnam", "Disabled")
//! i set("ftip", "Disabled")                                          ; set("fube", "This unit cannot do anything.");
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "")                             ; set("fta0", "")
//! i
//! endexternalblock
//! endtextmacro GenerateAbilities

globals
    //General constants
    private constant integer DUMMY_UNITID     = 'e000' //Replace this with your dummy's id
   
    //Stun constants
    private constant integer STUN_ID          = 'stun' //This needs to match the ObjectMerger call above
    private constant integer STUN_ORDER_ID    = 852095 //Order id to stun a unit
    private constant integer STUN_BUFF_ID     = 'BPSE' //Normal storm bolt stun buff
   
    //Silence constants
    private constant integer SILENCE_ID       = '&sil' //This needs to match the ObjectMerger call above
    private constant integer SILENCE_ORDER_ID = 852668 //Order id to soul burn a unit
    private constant integer SILENCE_BUFF_ID  = '&SIL' //Generated soul burn based buff
   
    //Disarm constants
    private constant integer DISARM_ID        = '&arm' //This needs to match the ObjectMerger call above
    private constant integer DISARM_ORDER_ID  = 852585 //Order id to drunken haze a unit
    private constant integer DISARM_BUFF_ID   = '&ARM' //Generated drunken haze based buff
   
    //Ensnare constants
    private constant integer ENSNARE_ID       = '&ens' //This needs to match the ObjectMerger call above
    private constant integer ENSNARE_ORDER_ID = 852106 //Order id to ensnare a unit
    private constant integer ENSNARE_BUFF_ID  = '&EN1' //Generated ensnare based buff (ground)
    private constant integer ENSNARE_BUFF_ID2 = '&EN2' //Generated ensnare based buff (air)
   
    //Disable constants
    private constant integer DISABLE_ID       = '&dis' //This needs to match the ObjectMerger call above
    private constant integer DISABLE_ORDER_ID = 852252 //Order id to hurl boulder at a unit
    private constant integer DISABLE_BUFF_ID  = '&DIS' //Generated hurl boulder based buff
endglobals

globals
    private unit  Caster = null //Dummy caster
    private timer Temp   = null //For callback referencing
endglobals

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

//! textmacro UnitStatus_GenerateBase takes TYPE, CONSTANT, STRUCTNAME, INJECTPOSTBUFF, INJECTCHECK, INJECTPREBUFF
private struct clear$TYPE$
    unit u = null
    //Exists only for clearing on Add/Remove situations
    static method create takes unit t returns thistype
        local thistype c = thistype.allocate()
        set c.u = t
        return c
    endmethod
endstruct

private function TimerRemove$TYPE$ takes nothing returns nothing
    local clear$TYPE$ c         = clear$TYPE$(GetTimerData(GetExpiredTimer()))
    local unit        whichUnit = c.u
    if $TYPE$Counter[GetUnitId(c.u)] == 0 then
        //Make sure we should still remove it
        call UnitRemoveAbility(c.u, $CONSTANT$_BUFF_ID)
        $INJECTPOSTBUFF$
    endif
    call ReleaseTimer(GetExpiredTimer())
    call c.destroy()
    set whichUnit = null
endfunction

function $TYPE$Unit takes unit whichUnit, boolean flag returns boolean
    local integer id = GetUnitId(whichUnit)
    local boolean b  = true
    if whichUnit == null then
        //Target can't be null
        debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null unit given to $TYPE$Unit")
        return false
    endif
    if flag then
        if $TYPE$Counter[id] == 0 $INJECTCHECK$ then
            //Buff the unit
            $INJECTPREBUFF$
            call UnitShareVision(whichUnit, GetOwningPlayer(Caster), true)
            set b = IssueTargetOrderById(Caster, $CONSTANT$_ORDER_ID, whichUnit)
            call UnitShareVision(whichUnit, GetOwningPlayer(Caster), false)
        endif
        if not b then
            //Cast failed somehow
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Unit could not be buffed ($TYPE$Unit)")
            return false
        endif
       set $TYPE$Counter[id] = $TYPE$Counter[id] + 1
    elseif $TYPE$Counter[id] > 0 then //Only run this if unit is buffed at all
        //Decrement Counter
        set $TYPE$Counter[id] = $TYPE$Counter[id] - 1
        if $TYPE$Counter[id] == 0 then
            //Clear the buff
            if GetUnitAbilityLevel(whichUnit, $CONSTANT$_BUFF_ID) == 0 then
                //Remove it in a 0.01s callback because it hasn't been applied yet
                set Temp = NewTimer()
                call SetTimerData(Temp, integer(clear$TYPE$.create(whichUnit)))
                call TimerStart(Temp, 0.01, false, function TimerRemove$TYPE$)
            else
                call UnitRemoveAbility(whichUnit, $CONSTANT$_BUFF_ID)
                $INJECTPOSTBUFF$
            endif
        endif
    else
        //Unit doesn't have the buff we're trying to remove
        return false
    endif
    return true
endfunction

private struct $STRUCTNAME$
    timer t
    unit  tar
    real  dur
   
    private static method end takes nothing returns nothing
        call thistype(GetTimerData(GetExpiredTimer())).destroy()
    endmethod
    static method start takes unit target, real duration returns boolean
        local thistype s
        local boolean  b = $TYPE$Unit(target, true)
        if not b then
            //Failed, return false
            return false
        endif
        set s     = thistype.allocate()
        set s.tar = target
        set s.dur = duration
        set s.t   = NewTimer()
        call SetTimerData(s.t, integer(s))
        call TimerStart(s.t, duration, false, function $STRUCTNAME$.end)
        return true
    endmethod
    private method onDestroy takes nothing returns nothing
        call $TYPE$Unit(.tar, false)
        call ReleaseTimer(.t)
    endmethod
endstruct

function $TYPE$UnitTimed takes unit whichUnit, real duration returns boolean
    if duration <= 0.01 then
        debug call BJDebugMsg(SCOPE_PREFIX+"Error: Less than 0.01 duration given to $TYPE$UnitTimed")
        return false
    endif
    return $STRUCTNAME$.start(whichUnit, duration)
endfunction
//! endtextmacro

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

//Declare all necessary globals first
globals
    private integer array StunCounter
    private integer array SilenceCounter
    private integer array DisarmCounter
    private integer array EnsnareCounter
    private integer array DisableCounter
endglobals

//Special functions for Stun
private function StunLingeringDisable takes unit u returns nothing
    local integer id = GetUnitId(u)
    if DisableCounter[id] > 0 then
        //Add the disabled buff because it lingers on
        call UnitShareVision(u, GetOwningPlayer(Caster), true)
        call IssueTargetOrderById(Caster, DISABLE_ORDER_ID, u)
        call UnitShareVision(u, GetOwningPlayer(Caster), false)
    endif
endfunction
private function StunFinishDisable takes unit u returns nothing
    local integer id = GetUnitId(u)
    if DisableCounter[id] > 0 then
        //Remove the disable buff for first refcount stun
        call UnitRemoveAbility(u, DISABLE_BUFF_ID)
    endif
endfunction

//Generates all of the base code
//! runtextmacro UnitStatus_GenerateBase("Stun"   , "STUN"   , "stun"   , "call StunLingeringDisable(whichUnit)", "", "call StunFinishDisable(whichUnit)")
//! runtextmacro UnitStatus_GenerateBase("Silence", "SILENCE", "silence", "", "", "")
//! runtextmacro UnitStatus_GenerateBase("Disarm" , "DISARM" , "disarm" , "", "", "")
//! runtextmacro UnitStatus_GenerateBase("Ensnare", "ENSNARE", "ensnare", "call UnitRemoveAbility(whichUnit, ENSNARE_BUFF_ID2)", "", "")
//! runtextmacro UnitStatus_GenerateBase("Disable", "DISABLE", "disable", "", "and StunCounter[id] == 0", "")

private function Init takes nothing returns nothing
    static if LIBRARY_xebasic then
        set Caster = CreateUnit(Player(15), XE_DUMMY_UNITID, 0., 0., 0.)
    else
        set Caster = CreateUnit(Player(15), DUMMY_UNITID   , 0., 0., 0.)
    endif
    call UnitRemoveAbility(Caster, 'Amov')
    if GetUnitAbilityLevel(Caster, 'Aloc') == 0 then
        call UnitAddAbility(Caster, 'Aloc') //xe dummies don't have this automatically
    endif
   
    //Add the abilities
    call UnitAddAbility(Caster, STUN_ID)
    call UnitAddAbility(Caster, SILENCE_ID)
    call UnitAddAbility(Caster, DISARM_ID)
    call UnitAddAbility(Caster, ENSNARE_ID)
    call UnitAddAbility(Caster, DISABLE_ID)
endfunction
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.0.1
   
    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
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")
   
//! 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 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)
    endmethod
   
    //set tb[389034] = 8192
    method operator []= takes integer key, Table tb returns nothing
        call SaveInteger(ht, this, key, tb)
    endmethod
   
    //set b = tb.has(2493223)
    method has takes integer key returns boolean
        return HaveSavedInteger(ht, this, key)
    endmethod
   
    //call tb.remove(294080)
    method remove takes integer key returns nothing
        call RemoveSavedInteger(ht, this, key)
    endmethod
   
    //Remove all data from a Table instance
    method flush takes nothing returns nothing
        call FlushChildHashtable(ht, this)
    endmethod
   
    //local Table 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=30
//TESH.alwaysfold=0
library TableBC requires Table
/*
    Backwards-compatibility add-on for scripts employing Vexorian's Table.
   
    Disclaimer:
   
    The following error does not occur with HandleTables & StringTables, only
    with the standard, integer-based Table, so you do not need to make any
    changes to StringTable/HandleTable-employing scripts.
   
    The this.flush(key) method from the original Table cannot be parsed with
    the new Table. For the scripts that use this method, they need to be up-
    dated to use the more fitting this.remove(key) method.
   
    Please don't try using StringTables/HandleTables with features exclusive
    to the new Table as they will cause syntax errors. I do not have any plan
    to endorse these types of Tables because delegation in JassHelper is not
    advanced enough for three types of Tables without copying every single
    method over again (as you can see this already generates plenty of code).
    StringTable & HandleTable are wrappers for StringHash & GetHandleId, so
    just type them out.
*/


//! textmacro TABLE_BC_METHODS
    method reset takes nothing returns nothing
        call this.flush()
    endmethod
    method exists takes integer key returns boolean
        return this.has(key)
    endmethod
//! endtextmacro

//! textmacro TABLE_BC_STRUCTS
struct HandleTable extends array
    method operator [] takes handle key returns integer
        return Table(this)[GetHandleId(key)]
    endmethod
    method operator []= takes handle key, integer value returns nothing
        set Table(this)[GetHandleId(key)] = value
    endmethod
    method flush takes handle key returns nothing
        call Table(this).remove(GetHandleId(key))
    endmethod
    method exists takes handle key returns boolean
        return Table(this).has(GetHandleId(key))
    endmethod
    method reset takes nothing returns nothing
        call Table(this).flush()
    endmethod
    method destroy takes nothing returns nothing
        call Table(this).destroy()
    endmethod
    static method create takes nothing returns thistype
        return Table.create()
    endmethod
endstruct

struct StringTable extends array
    method operator [] takes string key returns integer
        return Table(this)[StringHash(key)]
    endmethod
    method operator []= takes string key, integer value returns nothing
        set Table(this)[StringHash(key)] = value
    endmethod
    method flush takes string key returns nothing
        call Table(this).remove(StringHash(key))
    endmethod
    method exists takes string key returns boolean
        return Table(this).has(StringHash(key))
    endmethod
    method reset takes nothing returns nothing
        call Table(this).flush()
    endmethod
    method destroy takes nothing returns nothing
        call Table(this).destroy()
    endmethod
    static method create takes nothing returns thistype
        return Table.create()
    endmethod
endstruct
//! endtextmacro

endlibrary
/**************************************************************
*
*   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 = 27
        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=27
//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 TerrainPathability initializer Init
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//*    > function IsTerrainDeepWater    takes real x, real y returns boolean
//*    > function IsTerrainShallowWater takes real x, real y returns boolean
//*    > function IsTerrainLand         takes real x, real y returns boolean
//*    > function IsTerrainPlatform     takes real x, real y returns boolean
//*    > function IsTerrainWalkable     takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//*     [real]    TerrainPathability_X
//*     [real]    TerrainPathability_Y
//*
globals
    private constant real    MAX_RANGE     = 10.
    private constant integer DUMMY_ITEM_ID = 'wolg'
endglobals

globals    
    private item       Item   = null
    private rect       Find   = null
    private item array Hid
    private integer    HidMax = 0
    public  real       X      = 0.
    public  real       Y      = 0.
endglobals

function IsTerrainDeepWater takes real x, real y returns boolean
    return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
    return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
    return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
    return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction

private function HideItem takes nothing returns nothing
    if IsItemVisible(GetEnumItem()) then
        set Hid[HidMax] = GetEnumItem()
        call SetItemVisible(Hid[HidMax], false)
        set HidMax = HidMax + 1
    endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
    //Hide any items in the area to avoid conflicts with our item
    call MoveRectTo(Find, x, y)
    call EnumItemsInRect(Find ,null, function HideItem)
    //Try to move the test item and get its coords
    call SetItemPosition(Item, x, y) //Unhides the item
    set X = GetItemX(Item)
    set Y = GetItemY(Item)
    static if LIBRARY_IsTerrainWalkable then
        //This is for compatibility with the IsTerrainWalkable library
        set IsTerrainWalkable_X = X
        set IsTerrainWalkable_Y = Y
    endif
    call SetItemVisible(Item, false)//Hide it again
    //Unhide any items hidden at the start
    loop
        exitwhen HidMax <= 0
        set HidMax = HidMax - 1
        call SetItemVisible(Hid[HidMax], true)
        set Hid[HidMax] = null
    endloop
    //Return walkability
    return (X-x)*(X-x)+(Y-y)*(Y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction

private function Init takes nothing returns nothing
    set Find = Rect(0., 0., 128., 128.)
    set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
    call SetItemVisible(Item, false)
endfunction
endlibrary
//TESH.scrollpos=292
//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=17
//TESH.alwaysfold=0
library Event /* v2.0.0.1
************************************************************************************
*
*   Functions
*
*       function CreateEvent takes nothing returns integer
*       function TriggerRegisterEvent takes trigger t, integer ev returns nothing
*
************************************************************************************
*
*       struct Event extends array
*
*           static method create takes nothing returns thistype
*           method registerTrigger takes trigger t returns nothing
*           method register takes boolexpr c returns nothing
*           method fire takes nothing returns nothing
*
************************************************************************************/

    globals
        private real q=0
    endglobals
    struct Event extends array
        private static integer w=0
        private static trigger array e
        static method create takes nothing returns thistype
            set w=w+1
            set e[w]=CreateTrigger()
            return w
        endmethod
        method registerTrigger takes trigger t returns nothing
            call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)
        endmethod
        method register takes code c returns nothing
            call TriggerAddCondition(e[this],Condition(c))
        endmethod
        method fire takes nothing returns nothing
            set q=0
            set q=this
            call TriggerEvaluate(e[this])
        endmethod
    endstruct
    function CreateEvent takes nothing returns Event
        return Event.create()
    endfunction
    function TriggerRegisterEvent takes trigger t,Event ev returns nothing
        call ev.registerTrigger(t)
    endfunction
    function RegisterEvent takes code c,Event ev returns nothing
        call ev.register(c)
    endfunction
    function FireEvent takes Event ev returns nothing
        call ev.fire()
    endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Dummy initializer init requires Constants

    globals
        private unit dummy
    endglobals

    function dummyCast takes unit u, integer a, string o returns nothing
        call UnitAddAbility(dummy, a)
        call IssueTargetOrder(dummy, o, u)
        call UnitRemoveAbility(dummy, a)
    endfunction
   
    private function init takes nothing returns nothing
        set dummy = CreateUnit(DUMMY_OWNER, DUMMY_RAWCODE, DUMMY_X, DUMMY_Y, 0.00)
        call SetUnitPathing(dummy, false)
        call SetUnitX(dummy, DUMMY_X)
        call SetUnitY(dummy, DUMMY_Y)
    endfunction

endlibrary

 
library Utilities initializer init requires AutoIndex, UnitStatus, Dummy, GetTerrainZ, UnitZ

    globals
        constant group enumGroup = CreateGroup()
    endglobals
   
    //! textmacro TEMP takes type, name
    globals
        $type$ temp$name$
        $type$ temp$name$2
    endglobals
    //! endtextmacro
   
    //! runtextmacro TEMP("unit", "Unit")
    //! runtextmacro TEMP("integer", "Integer")
    //! runtextmacro TEMP("boolean", "Boolean")
    //! runtextmacro TEMP("real", "Real")
    //! runtextmacro TEMP("trigger", "Trigger")
    //! runtextmacro TEMP("widget", "Widget")
    //! runtextmacro TEMP("string", "String")
    //! runtextmacro TEMP("player", "Player")
    //! runtextmacro TEMP("rect", "Rect")
   
    function IsUnitDisabled takes unit u returns boolean
        return GetUnitAbilityLevel(u, DISABLE_BUFF_RAWCODE) > 0
    endfunction
   
    function Seconds2Time takes real r returns string
        local integer h
        local integer m
        local integer s = R2I(r)
        local string t
        set h = s/3600
        set m = (s - h*3600)/60
        set s = s - h*3600 - m*60
        set t = I2S(h)+":"
        if m < 10 then
            set t = t+"0"+I2S(m)+":"
        else
            set t = t+I2S(m)+":"
        endif
        if s < 10 then
            set t = t+"0"+I2S(s)
        else
            set t = t+I2S(s)
        endif
        if h == 0 then
            set t = SubString(t, 2, 7)
        endif
        return t
    endfunction
   
    function Time2Seconds takes string t returns real
        local integer array f
        local integer i = StringLength(t)
        local integer n = 2
        loop
            loop
                exitwhen i == 0 or SubString(t, i - 1, i) == ":"
                set i = i - 1
            endloop
            set f[n] = S2I(SubString(t, i, StringLength(t)))
            exitwhen i == 0
            set i = i - 1
            set t = SubString(t, 0, i)
            set n = n - 1
        endloop
        return f[0]*3600.0 + f[1]*60.0 + f[2]
    endfunction
   
    function Sfx takes string path, real x, real y, real z, real facing, real pitch, real size returns nothing
        local unit d = CreateUnit(DUMMY_OWNER, SFX_DUMMY_RAWCODE, x, y, facing)
        call SetUnitX(d, x)
        call SetUnitY(d, y)
        call SetUnitZ(d, z)
        call SetUnitScale(d, size, size, size)
        call UnitApplyTimedLife(d, 'BTLF', 8.00)
        call SetUnitAnimationByIndex(d, R2I(pitch))
        call DestroyEffect(AddSpecialEffectTarget(path, d, "origin"))
    endfunction
   
    function TestUnit takes real x, real y returns unit
        return CreateUnit(Player(0), 'hfoo', x, y, 0.00)
    endfunction
   
    function Print takes string s returns nothing
        call BJDebugMsg(s)
    endfunction
   
    function PrintInt takes integer i returns nothing
        call BJDebugMsg(I2S(i))
    endfunction
   
    function PrintReal takes real r returns nothing
        call BJDebugMsg(R2S(r))
    endfunction
   
    function DistanceBetweenUnits takes unit u1, unit u2 returns real
        local real x = GetUnitX(u2) - GetUnitX(u1)
        local real y = GetUnitY(u2) - GetUnitY(u1)
        return SquareRoot(x*x + y*y)
    endfunction
   
    globals
        private texttag t
    endglobals
   
    function TextTag takes string text, real size, real x, real y, real z, real ls returns texttag
        set t = CreateTextTag()
        call SetTextTagText(t, text, size)
        call SetTextTagPos(t, x, y, z - GetTerrainZ(x, y))
        call SetTextTagLifespan(t, ls)
        call SetTextTagFadepoint(t, ls - 0.50)
        call SetTextTagPermanent(t, false)
        call SetTextTagVelocity(t, 0.00, 130.0 * 0.071 / 128)
        return t
    endfunction
   
    function sgn takes real r returns integer
        if r < 0 then
            return -1
        elseif r > 0 then
            return 1
        endif
        return 0
    endfunction
   
    function Digits takes integer i returns integer
        local integer d = 1
        set d = d + 1*sgn(i/10)
        set d = d + 1*sgn(i/100)
        return d
    endfunction
   
    function Spaces takes integer i returns string
        local string s = ""
        loop
            exitwhen i == 0
            set s = s + " "
            set i = i - 1
        endloop
        return s
    endfunction
   
    globals
        private unit array units
    endglobals
   
    function GetUnitById takes integer id returns unit
        return units[id]
    endfunction
   
    private function index takes unit u returns nothing
        set units[GetUnitId(u)] = u
    endfunction
   
    private function deindex takes unit u returns nothing
        set units[GetUnitId(u)] = null
    endfunction
   
    private function init takes nothing returns nothing
        call OnUnitIndexed(index)
        call OnUnitDeindexed(deindex)
    endfunction

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Sounds initializer init requires Table
   
    globals
        private TableArray sounds
    endglobals
   
    function Play takes string s returns nothing
        local integer h = StringHash(s)
        call StartSound(sounds[sounds[0][h]].sound[h])
        if sounds[0][h] == 9 then
            set sounds[0][h] = 0
        else
            set sounds[0][h] = sounds[0][h] + 1
        endif
    endfunction
   
    function InitSound takes string s returns nothing
        local integer i = 0
        local integer h = StringHash(s)
    local sound snd = CreateSound(s, false, false, false, 12700, 12700, "")
        loop
            set sounds[i].sound[h] = snd
            set sounds[0][h] = 0
            set i = i + 1
            exitwhen i == 10
        endloop
    endfunction
   
    private function init takes nothing returns nothing
        set sounds = TableArray[10]
    endfunction
   
endlibrary
//TESH.scrollpos=27
//TESH.alwaysfold=0
library Camera initializer init requires Constants, Players

    globals
        private real camDistance = CAMERA_DEFAULT_DISTANCE
        private real camAngleOfAttack = bj_CAMERA_DEFAULT_AOA
        private real camRotation = bj_CAMERA_DEFAULT_ROTATION
        boolean camAdjustment = false
       
        private boolean altCam = false
    endglobals
   
    function camAdjust takes nothing returns nothing
        if camAdjustment and camDistance != 0.00 then
            call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, camDistance, 0.00)
            call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, camAngleOfAttack, 0.00)
            call SetCameraField(CAMERA_FIELD_ROTATION, camRotation, 0.00)
        endif
    endfunction
   
    private function camSet takes nothing returns boolean
        local string s = StringCase(GetEventPlayerChatString(), false)
        local Ball ball = Ball.balls[0]
        local integer n
        local player p = null
       
        if SubString(s, 0, 5) == "-cam " then
            set camDistance = S2R(SubString(s, 5, 9))
            if not camAdjustment and camDistance == 0.00 then
                set camDistance = CAMERA_DEFAULT_DISTANCE
            endif
        elseif SubString(s, 0, 6) == "-zoom " then
            set camDistance = S2R(SubString(s, 6, 10))
            if not camAdjustment and camDistance == 0.00 then
                set camDistance = CAMERA_DEFAULT_DISTANCE
            endif
        endif
       
        if s == "-alt cam" then
            if altCam then
                set camRotation = bj_CAMERA_DEFAULT_ROTATION
                set camAngleOfAttack = bj_CAMERA_DEFAULT_AOA
                set altCam = false
            else
                set camRotation = 180.0*GetPlayerTeam(GetLocalPlayer())
                set camAngleOfAttack = camAngleOfAttack + CAMERA_ALTERNATE_ANGLE_DIFFERENCE
                set altCam = true
            endif
        endif
       
        if camAdjustment then
            if camDistance == 0.00 then
                call CameraSetSourceNoiseEx(10000.00, 1000.00, false)
            else
                call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, camDistance, 0.00)
                call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, camAngleOfAttack, 0.00)
                call SetCameraField(CAMERA_FIELD_ROTATION, camRotation, 0.00)
                call CameraSetSourceNoiseEx(0.00, 0.00, false)
            endif
        endif
       
        return false
    endfunction
   
    private function init takes nothing returns nothing
        local integer i = 0
        local trigger t = CreateTrigger()
        call TriggerRegisterPlayerChatEvent(t, GetLocalPlayer(), "-cam", false)
        call TriggerRegisterPlayerChatEvent(t, GetLocalPlayer(), "-zoom", false)
        call TriggerRegisterPlayerChatEvent(t, GetLocalPlayer(), "-alt cam", false)
        call TriggerRegisterPlayerChatEvent(t, GetLocalPlayer(), "-lock", false)
        call TriggerRegisterPlayerChatEvent(t, GetLocalPlayer(), "-unlock", false)
        call TriggerAddCondition(t, function camSet)
        static if not TEST then
            call TimerStart(CreateTimer(), 0.50, true, function camAdjust)
        endif
        set t = null
    endfunction
   
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AutoFly initializer init requires AutoIndex, xebasic

    private function enableFlight takes unit u returns nothing
        if UnitAddAbility(u, XE_HEIGHT_ENABLER) then
            call UnitRemoveAbility(u, XE_HEIGHT_ENABLER)
        endif
    endfunction

    private function init takes nothing returns nothing
        call OnUnitIndexed(enableFlight)
    endfunction

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GetTerrainZ /* v1.0.0.0
********************************************************************
*
*    function GetTerrainZ takes real x, real y returns real
*
********************************************************************/


    globals
        private constant location L = Location(0, 0)
    endglobals

    function GetTerrainZ takes real x, real y returns real
        call MoveLocation(L, x, y)
        return GetLocationZ(L)
    endfunction

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitZ /* v1.0.0.0
********************************************************************
*
*    */
uses/*
*        */
GetTerrainZ /*
*    */
optional/*
*        */
AutoFly     /*      hiveworkshop.com/forums/jass-resources-412/snippet-autofly-unitindexer-version-195563/
*
*    function GetUnitZ takes unit whichUnit returns real
*    function SetUnitZ takes unit whichUnit, real z returns real
*
********************************************************************/


    function GetUnitZ takes unit u returns real
        return GetTerrainZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
    endfunction
       
    function SetUnitZ takes unit u, real z returns nothing
        call SetUnitFlyHeight(u, z - GetTerrainZ(GetUnitX(u), GetUnitY(u)), 0)
    endfunction
       
endlibrary
library Vector requires GetTerrainZ, UnitZ

    struct Vector
        real x
        real y
        real z
       
        static method create takes real x, real y, real z returns thistype
            local thistype this = thistype.allocate()
            set .x = x
            set .y = y
            set .z = z
            return this
        endmethod
       
        method add takes thistype v returns nothing
            set .x = .x + v.x
            set .y = .y + v.y
            set .z = .z + v.z
        endmethod
       
        static method sum takes thistype a, thistype b returns thistype
            local thistype v = thistype.allocate()
            set v.x = a.x + b.x
            set v.y = a.y + b.y
            set v.z = a.z + b.z
            return v
        endmethod
       
        method scale takes real f returns nothing
            set .x = .x * f
            set .y = .y * f
            set .z = .z * f
        endmethod
       
        method getLength takes nothing returns real
            return SquareRoot(.x*.x + .y*.y + .z*.z)
        endmethod
       
        method setLength takes real l returns nothing
            if .getLength() != 0.00 then
                set l = l / .getLength()
                set .x = .x * l
                set .y = .y * l
                set .z = .z * l
            endif
        endmethod
       
        static method dotProduct takes thistype a, thistype b returns real
            return (a.x*b.x + a.y*b.y + a.z*b.z)
        endmethod
       
        static method createTerrainPoint takes real x, real y returns thistype
            local thistype this = thistype.allocate()
            set .x = x
            set .y = y
            set .z = GetTerrainZ(x, y)
            return this
        endmethod
       
        static method createUnitPoint takes unit u returns thistype
            local thistype this = thistype.allocate()
            set .x = GetUnitX(u)
            set .y = GetUnitY(u)
            set .z = GetUnitZ(u)
            return this
        endmethod
       
        static method projectionVector takes thistype p, thistype d returns thistype
            local thistype v = thistype.allocate()
            local real l = (p.x*d.x + p.y*d.y + p.z*d.z) / (d.x*d.x + d.y*d.y + d.z*d.z)
            set v.x = d.x * l
            set v.y = d.y * l
            set v.z = d.z * l
            return v
        endmethod
       
        method isInSphere takes thistype o, real r returns boolean
            if r*r > ((.x - o.x)*(.x - o.x) + (.y - o.y)*(.y - o.y) + (.z - o.z)*(.z - o.z)) then
                return true
            endif
            return false
        endmethod
   
    endstruct

endlibrary
library AddSpecialEffectZ

    function AddSpecialEffectZ takes string modelName, real x, real y, real z returns effect
        //Creates a invisible platform at the given x/y/z coordinates.
        local destructable d = CreateDestructableZ('OTip', x, y, z, 0., 1, 0)
        //The created special effect will now appear on top of the platform.
        set bj_lastCreatedEffect = AddSpecialEffect(modelName, x, y)
        //Removing platform and null the variable. The effect will still keep its height.
        call RemoveDestructable(d)
        set d = null
        //Return effect.
        return bj_lastCreatedEffect
    endfunction

endlibrary

 
library LinkedList //v1.0.0.0

    private module initNodes
        private static method onInit takes nothing returns nothing
            local integer i = 1
            loop
                set Node[i].n = Node[i + 1]
                set i = i + 1
                exitwhen i == 8190
            endloop
        endmethod
    endmodule

    struct Node extends array
        private static thistype avail = 1
        private thistype n
       
        integer data
        thistype next
        thistype prev

        static method get takes nothing returns thistype
            local thistype this = avail
            set avail = avail.n
            set this.next = 0
            set this.prev = 0
            return this
        endmethod
       
        method free takes nothing returns nothing
            set this.n = avail
            set avail = this
        endmethod
       
        implement initNodes

    endstruct
   
    struct List
        Node head
       
        static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
            set head = Node.get()
            set head.next = head
            set head.prev = head
            return this
        endmethod
       
        method addElement takes integer e returns Node
            local Node node = Node.get()
            set node.data = e
            set node.next = head
            set node.prev = head.prev
            set head.prev.next = node
            set head.prev = node
            return node
        endmethod
       
        static method removeElement takes Node position returns nothing
            set position.prev.next = position.next
            set position.next.prev = position.prev
            call position.free()
        endmethod
       
    endstruct
   
    module ObjectList
        static List list
        private Node position
       
        method listAdd takes nothing returns nothing
            set position = list.addElement(this)
        endmethod
       
        method listRemove takes nothing returns nothing
            call list.removeElement(position)
        endmethod
       
        private static method onInit takes nothing returns nothing
            set list = List.create()
        endmethod
           
    endmodule

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library InstanceIterator requires LinkedList //v2.1.0.0
   
    //! textmacro II takes FREQUENCY, PERIOD
   
    globals
        private trigger trigger$FREQUENCY$ = CreateTrigger()
        private integer globalCount$FREQUENCY$ = 0
        private timer timer$FREQUENCY$ = CreateTimer()
        constant real II$FREQUENCY$period = $PERIOD$
    endglobals
   
    private function eval$FREQUENCY$ takes nothing returns nothing
        call TriggerEvaluate(trigger$FREQUENCY$)
    endfunction

    module II$FREQUENCY$
        private static List list
        private static integer localCount = 0
        private static conditionfunc iterationFunction
        private static triggercondition iterationCondition
       
        private Node position
        boolean enabled$FREQUENCY$ = false
       
        private static method iteration takes nothing returns boolean
            local Node head = list.head
            local Node node = head.next
            loop
                call thistype(node.data).iterate$FREQUENCY$()
                set node = node.next
                exitwhen node == head
            endloop
            return false
        endmethod
       
        implement ObjectList
       
        method start$FREQUENCY$ takes nothing returns boolean
            if not enabled$FREQUENCY$ then
           
                set position = list.addElement(this)
           
                if localCount == 0 then
                    set iterationCondition = TriggerAddCondition(trigger$FREQUENCY$, iterationFunction)
                endif
                set localCount = localCount + 1
                if globalCount$FREQUENCY$ == 0 then
                    call TimerStart(timer$FREQUENCY$, $PERIOD$, true, function eval$FREQUENCY$)
                endif
                set globalCount$FREQUENCY$ = globalCount$FREQUENCY$ + 1
               
                set enabled$FREQUENCY$ = true
                return true
            endif
            return false
        endmethod
       
        method stop$FREQUENCY$ takes nothing returns boolean
            if enabled$FREQUENCY$ then
           
                call list.removeElement(position)
               
                set localCount = localCount - 1
                if localCount == 0 then
                    call TriggerRemoveCondition(trigger$FREQUENCY$, iterationCondition)
                    set iterationCondition = null
                endif
                set globalCount$FREQUENCY$ = globalCount$FREQUENCY$ - 1
                if globalCount$FREQUENCY$ == 0 then
                    call PauseTimer(timer$FREQUENCY$)
                endif
               
                set enabled$FREQUENCY$ = false
                return true
            endif
            return false
        endmethod
       
        private static method onInit takes nothing returns nothing
            set iterationFunction = Condition(function thistype.iteration)
            set list = List.create()
        endmethod
   
    endmodule
   
    //! endtextmacro
   
    //! runtextmacro II("32", "0.031250")
    // runtextmacro II("16", "0.062500")
    //! runtextmacro II("10", "0.100000")
    // runtextmacro II("8", "0.125000")
    // runtextmacro II("5", "0.200000")
    // runtextmacro II("2", "0.500000")
    // runtextmacro II("1", "1.000000")

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitCollision

    function DisableUnitCollision takes unit u returns boolean
        call SetUnitPathing(u, false)
        return UnitAddAbility(u, 'Aeth')
    endfunction
   
    function EnableUnitCollision takes unit u returns boolean
        call SetUnitPathing(u, true)
        return UnitRemoveAbility(u, 'Aeth')
    endfunction

endlibrary
library Alpha requires InstanceIterator //Handles alpha change over time
   
    struct Alpha
        unit u
        integer alpha
        integer delta
        boolean revert
        integer red = 255
        integer green = 255
        integer blue = 255
       
        method iterate32 takes nothing returns nothing
            set .alpha = .alpha + .delta
            if .alpha > 255 or .alpha < 0 then
                if .revert then
                    set .delta = -1*.delta
                    set .revert = false
                else
                    call .stop32()
                    call .destroy()
                endif
                if .alpha > 255 then
                    set .alpha = 255
                else
                    set .alpha = 0
                endif
            endif
            call SetUnitVertexColor(u, red, green, blue, .alpha)
        endmethod
       
        implement II32
       
        static method create takes unit u, integer a, integer d, boolean r returns thistype
            local thistype this = thistype.allocate()
            set .u = u
            set .alpha = a
            set .delta = d
            set .revert = r
            call SetUnitVertexColor(u, 255, 255, 255, a)
            call .start32()
            return this
        endmethod
       
        method setColor takes integer r, integer g, integer b returns nothing
            set .red = r
            set .green = g
            set .blue = b
        endmethod

    endstruct

endlibrary
//TESH.scrollpos=25
//TESH.alwaysfold=0
library ErrorMessage /* v1.0.1.4
*************************************************************************************
*
*   Issue THW 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
//TESH.scrollpos=150
//TESH.alwaysfold=0
library ARGB initializer init
//******************************************************************************
//*
//* ARGB 1.2
//* ====
//*  For your color needs.
//*  
//*  An ARGB object is a by-value struct, this means that assigning copies the
//* contents of the struct and that you don't have to use .destroy(), the
//* downside is that you cannot assign its members (can't do set c.r= 123 )
//*
//*  This library should have plenty of uses, for example, if your spell involves
//* some unit recoloring you can allow users to input the color in the config
//* section as 0xAARRGGBB and you can then use this to decode that stuff.
//*
//* You can also easily merge two colors and make fading effects using ARGB.mix
//*
//* There's ARGB.fromPlayer which gets an ARGB object containing the player's
//* color. Then you can use the previous utilities on it.
//*
//* The .str() instance method can recolor a string, and the recolorUnit method
//* will apply the ARGB on a unit
//*
//* For other uses, you can use the .red, .green, .blue and .alpha members to get
//* an ARGB object's color value (from 0 to 255).
//*
//* structs that have a recolor method that takes red,green,blue and alpha as 0.255
//* integers can implement the ARGBrecolor module to gain an ability to quickly
//* recolor using an ARGB object.
//*
//********************************************************************************

//=================================================================================
globals
    private string array i2cc
endglobals

//this double naming stuff is beginning to make me insane, if only TriggerEvaluate() wasn't so slow...
struct ARGB extends array
    static method create takes integer a, integer r, integer g, integer b returns ARGB
        return ARGB(b + g*0x100 + r*0x10000 + a*0x1000000)
    endmethod
   
    // not really part of the exported stuff, I may remove it in the future, so please don't call this textmacro
    //! textmacro ARGB_PLAYER_COLOR_2_ARGB
        if(pc==PLAYER_COLOR_RED) then
            return 0xFFFF0303
        elseif(pc==PLAYER_COLOR_BLUE) then
            return 0xFF0042FF
        elseif(pc==PLAYER_COLOR_CYAN) then
            return 0xFF1CE6B9
        elseif(pc==PLAYER_COLOR_PURPLE) then
            return 0xFF540081
        elseif(pc==PLAYER_COLOR_YELLOW) then
            return 0xFFFFFC01
        elseif(pc==PLAYER_COLOR_ORANGE) then
            return 0xFFFE8A0E
        elseif(pc==PLAYER_COLOR_GREEN) then
            return 0xFF20C000
        elseif(pc==PLAYER_COLOR_PINK) then
            return 0xFFE55BB0
        elseif(pc==PLAYER_COLOR_LIGHT_GRAY) then
            return 0xFF959697
        elseif(pc==PLAYER_COLOR_LIGHT_BLUE) then
            return 0xFF7EBFF1
        elseif(pc==PLAYER_COLOR_AQUA) then
            return 0xFF106246
        elseif(pc==PLAYER_COLOR_BROWN) then
            return 0xFF4E2A04
        endif
       
      return 0xFF111111
    //! endtextmacro
    static method fromPlayerColor takes playercolor pc returns ARGB
        //! runtextmacro ARGB_PLAYER_COLOR_2_ARGB()
    endmethod

    static method fromPlayer takes player p returns ARGB
     local playercolor pc=GetPlayerColor(p)
        //! runtextmacro ARGB_PLAYER_COLOR_2_ARGB()
    endmethod

    method operator alpha takes nothing returns integer
        if( integer(this) <0) then
            return 0x80+(-(-integer(this)+0x80000000))/0x1000000
        else
            return (integer(this))/0x1000000
        endif
    endmethod
    method operator alpha= takes integer na returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(b + g*0x100 + r*0x10000 + na*0x1000000)
    endmethod




    method operator red takes nothing returns integer
     local integer c=integer(this)*0x100
        if(c<0) then
            return 0x80+(-(-c+0x80000000))/0x1000000
        else
            return c/0x1000000
        endif
    endmethod
    method operator red= takes integer nr returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(b + g*0x100 + nr*0x10000 + a*0x1000000)
    endmethod

    method operator green takes nothing returns integer
     local integer c=integer(this)*0x10000
        if(c<0) then
            return 0x80+(-(-c+0x80000000))/0x1000000
        else
            return c/0x1000000
        endif
    endmethod
    method operator green= takes integer ng returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(b + ng*0x100 + r*0x10000 + a*0x1000000)
    endmethod

    //=======================================================
    //
    //
    method operator blue takes nothing returns integer
     local integer c=integer(this)*0x1000000
        if(c<0) then
            return 0x80+(-(-c+0x80000000))/0x1000000
        else
            return c/0x1000000
        endif
    endmethod
    method operator blue= takes integer nb returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(nb + g*0x100 + r*0x10000 + a*0x1000000)
    endmethod

    //====================================================================
    // Mixes two colors, s would be a number 0<=s<=1 that determines
    // the weight given to color c2.
    //
    //  mix(c1,c2,0)   = c1
    //  mix(c1,c2,1)   = c2
    //  mix(c1,c2,0.5) = Mixing the colors c1 and c2 in equal proportions.
    //
    static method mix takes ARGB c1, ARGB c2, real s returns ARGB
      //widest function ever
      return ARGB( R2I(c2.blue*s+c1.blue*(1-s)+0.5) + R2I(c2.green*s+c1.green*(1-s)+0.5)*0x100 + R2I(c2.red*s+c1.red*(1-s)+0.5)*0x10000 + R2I(c2.alpha*s+c1.alpha*(1-s)+0.5)*0x1000000)
    endmethod

    method str takes string s returns string
       return "|c"+i2cc[.alpha]+i2cc[.red]+i2cc[.green]+i2cc[.blue]+s+"|r"
    endmethod

    method recolorUnit takes unit u returns nothing
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       call SetUnitVertexColor(u,r,g,b,a)
    endmethod

endstruct

module ARGBrecolor
    method ARGBrecolor takes ARGB color returns nothing
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       
       call this.recolor(r, g , b, a)
    endmethod

endmodule

private function init takes nothing returns nothing
 local integer i=0

    // Don't run textmacros you don't own!
    //! textmacro ARGB_CHAR takes int, chr
        set i=0
        loop
            exitwhen i==16
            set i2cc[$int$*16+i]="$chr$"+i2cc[$int$*16+i]
            set i2cc[i*16+$int$]=i2cc[i*16+$int$]+"$chr$"
            set i=i+1
        endloop
    //! endtextmacro
    //! runtextmacro ARGB_CHAR( "0","0")
    //! runtextmacro ARGB_CHAR( "1","1")
    //! runtextmacro ARGB_CHAR( "2","2")
    //! runtextmacro ARGB_CHAR( "3","3")
    //! runtextmacro ARGB_CHAR( "4","4")
    //! runtextmacro ARGB_CHAR( "5","5")
    //! runtextmacro ARGB_CHAR( "6","6")
    //! runtextmacro ARGB_CHAR( "7","7")
    //! runtextmacro ARGB_CHAR( "8","8")
    //! runtextmacro ARGB_CHAR( "9","9")
    //! runtextmacro ARGB_CHAR("10","A")
    //! runtextmacro ARGB_CHAR("11","B")
    //! runtextmacro ARGB_CHAR("12","C")
    //! runtextmacro ARGB_CHAR("13","D")
    //! runtextmacro ARGB_CHAR("14","E")
    //! runtextmacro ARGB_CHAR("15","F")
endfunction

endlibrary
//TESH.scrollpos=74
//TESH.alwaysfold=0
library UnitAppearanceTracker requires ARGB, Table, optional AutoIndex

//*****************************************************************
//*  UNIT APPEARANCE TRACKER
//*
//*  written by: Anitarf
//*  original implementation: Tot
//*  requires: -ARGB
//*            -Table
//*  optional: -AutoIndex
//*
//*  There is no native way to get a unit's current vertex colour
//*  or scale in WC3. This library was written to work around this
//*  limitation. The library tracks changes made to the vertex
//*  colour and scale of individual units so that those values can
//*  be obtained for a specific unit at any time. Vertex color is
//*  described using ARGB. This library now also tracks the
//*  animation speed of units.
//*
//*   local ARGB c = GetUnitVertexColor(u)
//*   local real s = GetUnitScale(u)
//*   local real s = GetUnitTimeScale(u)
//*
//*  If a unit type has a vertex colour or scale defined in the
//*  object editor that is different from the DEFAULT_COLOR/SCALE,
//*  UnitAppearanceTracker must be informed of this using the
//*  following functions in order for it to correctly assume these
//*  values for newly created units:
//*
//*   call SetUnitTypeVertexColor('nzom', 0xFFFF9696) // zombie
//*   call SetUnitTypeScale('hgry', 1.2) // gryphon rider
//*
//*  Finally, to be able to reset a unit's color and scale, the
//*  library provides the following functions that return the
//*  default values for a given unit type:
//*
//*   set c = GetUnitTypeVertexColor(GetUnitTypeId(u))
//*   set s = GetUnitTypeScale(GetUnitTypeId(u))
//*
//*  This library optionally requires AutoIndex. Without AutoIndex,
//*  the library still has full functionality, AutoIndex only makes
//*  it slightly faster, however it will only be able to track the
//*  appearance of indexed units.
//*****************************************************************

    globals
        // Set this to false if you want to track the appearance of units ignored by AutoIndex.
        private constant boolean USE_AUTOINDEX_IF_PRESENT = true
        // Multiplication factor used when converting reals to integers so they can be stored in Table.
        private constant real PRECISION = 1000.0

        // You do not need to call SetUnitTypeVertexColor/SetUnitTypeScale for units that use these default values,
        // so the values should match the most commonly used scale/colour in your map. Speed should always be 1.0.
        private ARGB DEFAULT_COLOR = 0xFFFFFFFF
        private real DEFAULT_SCALE = 1.0
        private real DEFAULT_SPEED = 1.0

// END OF CALIBRATION SECTION    
// ================================================================

        private ARGB array unitsColor
        private real array unitsScale
        private real array unitsSpeed
        private HandleTable unitColor
        private HandleTable unitScale
        private HandleTable unitSpeed
       
        private Table unittypeColor
        private Table unittypeScale
    endglobals

// ================================================================
// Hooks:

    private function SetUnitVertexColor_hook takes unit whichUnit, integer red, integer green, integer blue, integer alpha returns nothing
      static if USE_AUTOINDEX_IF_PRESENT and LIBRARY_AutoIndex then
        if IsUnitIndexed(whichUnit) then
            set unitsColor[GetUnitId(whichUnit)] = ARGB.create(alpha, red, green, blue)
        endif
      else
        set unitColor[whichUnit] = integer(ARGB.create(alpha, red, green, blue))
      endif
    endfunction
    private function SetUnitVertexColorBJ_hook takes unit whichUnit, real red, real green, real blue, real transparency returns nothing
        call SetUnitVertexColor_hook(whichUnit, PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100.0-transparency))
    endfunction
    hook SetUnitVertexColor SetUnitVertexColor_hook
    hook SetUnitVertexColorBJ SetUnitVertexColorBJ_hook
   
    // ----------------------------------------------------------------

    private function SetUnitScale_hook takes unit whichUnit, real scaleX, real scaleY, real scaleZ returns nothing
      static if USE_AUTOINDEX_IF_PRESENT and LIBRARY_AutoIndex then
        if IsUnitIndexed(whichUnit) then
            set unitsScale[GetUnitId(whichUnit)] = scaleX
        endif
      else
        set unitScale[whichUnit] = R2I(scaleX*PRECISION)
      endif
    endfunction
    private function SetUnitScalePercent_hook takes unit whichUnit, real percentScaleX, real percentScaleY, real percentScaleZ returns nothing
        call SetUnitScale_hook(whichUnit, percentScaleX * 0.01, 0.0, 0.0)
    endfunction
    hook SetUnitScale SetUnitScale_hook
    hook SetUnitScalePercent SetUnitScalePercent_hook

    // ----------------------------------------------------------------

    private function SetUnitTimeScale_hook takes unit whichUnit, real timeScale returns nothing
      static if USE_AUTOINDEX_IF_PRESENT and LIBRARY_AutoIndex then
        if IsUnitIndexed(whichUnit) then
            set unitsSpeed[GetUnitId(whichUnit)] = timeScale
        endif
      else
        set unitSpeed[whichUnit] = R2I(timeScale*PRECISION)
      endif
    endfunction
    private function SetUnitTimeScalePercent_hook takes unit whichUnit, real percentScale returns nothing
        call SetUnitTimeScale_hook(whichUnit, percentScale * 0.01)
    endfunction
    hook SetUnitTimeScale SetUnitTimeScale_hook
    hook SetUnitTimeScalePercent SetUnitTimeScalePercent_hook

// ================================================================
// User functions:
   
    function GetUnitVertexColor takes unit u returns ARGB
      static if USE_AUTOINDEX_IF_PRESENT and LIBRARY_AutoIndex then
        if IsUnitIndexed(u) then
            return unitsColor[GetUnitId(u)]
        else
            return DEFAULT_COLOR
        endif
      else
        return ARGB(unitColor[u])
      endif
    endfunction

    function GetUnitScale takes unit u returns real
      static if USE_AUTOINDEX_IF_PRESENT and LIBRARY_AutoIndex then
        if IsUnitIndexed(u) then
            return unitsScale[GetUnitId(u)]
        else
            return DEFAULT_SCALE
        endif
      else
        return unitScale[u]/PRECISION
      endif
    endfunction

    function GetUnitTimeScale takes unit u returns real
      static if USE_AUTOINDEX_IF_PRESENT and LIBRARY_AutoIndex then
        if IsUnitIndexed(u) then
            return unitsSpeed[GetUnitId(u)]
        else
            return DEFAULT_SPEED
        endif
      else
        return unitSpeed[u]/PRECISION
      endif
    endfunction

    // ----------------------------------------------------------------

    function GetUnitTypeVertexColor takes integer unitID returns ARGB
        if unittypeColor.exists(unitID) then
            return ARGB(unittypeColor[unitID])
        endif
        return DEFAULT_COLOR
    endfunction

    function GetUnitTypeScale takes integer unitID returns real
        if unittypeScale.exists(unitID) then
            return unittypeScale[unitID]/PRECISION
        endif
        return DEFAULT_SCALE
    endfunction

    // ----------------------------------------------------------------

    function SetUnitTypeVertexColor takes integer unitID, ARGB c returns nothing
        set unittypeColor[unitID]=integer(c)
    endfunction

    function SetUnitTypeScale takes integer unitID, real s returns nothing
        set unittypeScale[unitID]=R2I(s*PRECISION)
    endfunction

// ================================================================
// Initialization:

    private struct Initializer extends array

    private static method UnitEntersMap takes unit u returns nothing
      static if USE_AUTOINDEX_IF_PRESENT and LIBRARY_AutoIndex then
        set unitsScale[GetUnitId(u)] = GetUnitTypeScale(GetUnitTypeId(u))
        set unitsColor[GetUnitId(u)] = GetUnitTypeVertexColor(GetUnitTypeId(u))
        set unitsSpeed[GetUnitId(u)] = DEFAULT_SPEED
      else
        set unitScale[u] = R2I(GetUnitTypeScale(GetUnitTypeId(u))*PRECISION)
        set unitColor[u] = integer(GetUnitTypeVertexColor(GetUnitTypeId(u)))
        set unitSpeed[u] = R2I(DEFAULT_SPEED*PRECISION)
      endif
    endmethod
    private static method UnitEntersMapTrigger takes nothing returns boolean
        call .UnitEntersMap(GetFilterUnit())
        return false
    endmethod

    // ----------------------------------------------------------------

    private static method onInit takes nothing returns nothing
        local rect rc
        local region rg
        local trigger t
        set unittypeColor=Table.create()
        set unittypeScale=Table.create()

      static if LIBRARY_AutoIndex then
        call OnUnitIndexed(UnitEntersMap)
      static if not USE_AUTOINDEX_IF_PRESENT then
        set unitScale=Table.create()
        set unitColor=Table.create()
        set unitSpeed=Table.create()
      endif
      else
        set unitScale=Table.create()
        set unitColor=Table.create()
        set unitSpeed=Table.create()

        set rc=GetWorldBounds()
        set rg=CreateRegion()
        set t=CreateTrigger()
        call RegionAddRect(rg, rc)
        call RemoveRect(rc)
        call TriggerRegisterEnterRegion( t, rg, Condition(function Initializer.UnitEntersMapTrigger) )
        set rc=null
        set rg=null
      endif
    endmethod

    endstruct

endlibrary
scope SureInvisibility

    private struct SureInvisibility
        boolean invis
       
        method onCreate takes nothing returns nothing
            set .invis = false
            call .start32()
        endmethod
   
        static method createFilter takes unit u returns boolean
            return IsUnitType(u, UNIT_TYPE_PLAYER)
        endmethod
       
        method iterate32 takes nothing returns nothing
            if (not .invis) and (IsUnitInvisible(.me, GetLocalPlayer())) then
                set .invis = true
                call SetUnitVertexColor(.me, GetUnitVertexColor(.me).red, GetUnitVertexColor(.me).green, GetUnitVertexColor(.me).blue, 0)
            elseif (.invis) and (not IsUnitInvisible(.me, GetLocalPlayer())) then
                set .invis = false
                call SetUnitVertexColor(.me, GetUnitVertexColor(.me).red, GetUnitVertexColor(.me).green, GetUnitVertexColor(.me).blue, 255)
            endif
        endmethod
       
        implement AutoCreate
        implement AutoDestroy
        implement II32
       
    endstruct

endscope
 
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Ascii /* v1.1.0.0         Nestharus/Bribe
************************************************************************************
*
*   function Char2Ascii takes string s returns integer
*       integer ascii = Char2Ascii("F")
*
*   function Ascii2Char takes integer a returns string
*       string char = Ascii2Char('F')
*
*   function A2S takes integer a returns string
*       string rawcode = A2S('CODE')
*
*   function S2A takes string s returns integer
*       integer rawcode = S2A("CODE")
*
************************************************************************************/

    globals
        private integer array i //hash
        private integer array h //hash2
        private integer array y //hash3
        private string array c  //char
    endglobals
    function Char2Ascii takes string p returns integer
        local integer z = i[StringHash(p)/0x1F0748+0x40D]
        if (c[z] != p) then
            if (c[z - 32] != p) then
                if (c[h[z]] != p) then
                    if (c[y[z]] != p) then
                        if (c[83] != p) then
                            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII ERROR: INVALID CHARACTER: " + p)
                            return 0
                        endif
                        return 83
                    endif
                    return y[z]
                endif
                return h[z]
            endif
            return z - 32
        endif
        return z
    endfunction
    function Ascii2Char takes integer a returns string
        return c[a]
    endfunction
    function A2S takes integer a returns string
        local string s=""
        loop
            set s=c[a-a/256*256]+s
            set a=a/256
            exitwhen 0==a
        endloop
        return s
    endfunction
    function S2A takes string s returns integer
        local integer a=0
        local integer l=StringLength(s)
        local integer j=0
        local string m
        local integer h
        loop
            exitwhen j==l
            set a = a*256 + Char2Ascii(SubString(s,j,j+1))
            set j=j+1
        endloop
        return a
    endfunction
    private module Init
        private static method onInit takes nothing returns nothing
            set i[966] = 8
            set i[1110] = 9
            set i[1621] = 10
            set i[1375] = 12
            set i[447] = 13
            set i[233] = 32
            set i[2014] = 33
            set i[1348] = 34
            set i[1038] = 35
            set i[1299] = 36
            set i[1018] = 37
            set i[1312] = 38
            set i[341] = 39
            set i[939] = 40
            set i[969] = 41
            set i[952] = 42
            set i[2007] = 43
            set i[1415] = 44
            set i[2020] = 45
            set i[904] = 46
            set i[1941] = 47
            set i[918] = 48
            set i[1593] = 49
            set i[719] = 50
            set i[617] = 51
            set i[703] = 52
            set i[573] = 53
            set i[707] = 54
            set i[1208] = 55
            set i[106] = 56
            set i[312] = 57
            set i[124] = 58
            set i[1176] = 59
            set i[74] = 60
            set i[1206] = 61
            set i[86] = 62
            set i[340] = 63
            set i[35] = 64
            set i[257] = 65
            set i[213] = 66
            set i[271] = 67
            set i[219] = 68
            set i[1330] = 69
            set i[1425] = 70
            set i[1311] = 71
            set i[238] = 72
            set i[1349] = 73
            set i[244] = 74
            set i[1350] = 75
            set i[205] = 76
            set i[1392] = 77
            set i[1378] = 78
            set i[1432] = 79
            set i[1455] = 80
            set i[1454] = 81
            set i[1431] = 82
            set i[1409] = 83
            set i[1442] = 84
            set i[534] = 85
            set i[1500] = 86
            set i[771] = 87
            set i[324] = 88
            set i[1021] = 89
            set i[73] = 90
            set i[1265] = 91
            set i[1941] = 92
            set i[1671] = 93
            set i[1451] = 94
            set i[1952] = 95
            set i[252] = 96
            set i[257] = 97
            set i[213] = 98
            set i[271] = 99
            set i[219] = 100
            set i[1330] = 101
            set i[1425] = 102
            set i[1311] = 103
            set i[238] = 104
            set i[1349] = 105
            set i[244] = 106
            set i[1350] = 107
            set i[205] = 108
            set i[1392] = 109
            set i[1378] = 110
            set i[1432] = 111
            set i[1455] = 112
            set i[1454] = 113
            set i[1431] = 114
            set i[1409] = 115
            set i[1442] = 116
            set i[534] = 117
            set i[1500] = 118
            set i[771] = 119
            set i[324] = 120
            set i[1021] = 121
            set i[73] = 122
            set i[868] = 123
            set i[1254] = 124
            set i[588] = 125
            set i[93] = 126
            set i[316] = 161
            set i[779] = 162
            set i[725] = 163
            set i[287] = 164
            set i[212] = 165
            set i[7] = 166
            set i[29] = 167
            set i[1958] = 168
            set i[1009] = 169
            set i[1580] = 170
            set i[1778] = 171
            set i[103] = 172
            set i[400] = 174
            set i[1904] = 175
            set i[135] = 176
            set i[1283] = 177
            set i[469] = 178
            set i[363] = 179
            set i[550] = 180
            set i[1831] = 181
            set i[1308] = 182
            set i[1234] = 183
            set i[1017] = 184
            set i[1093] = 185
            set i[1577] = 186
            set i[606] = 187
            set i[1585] = 188
            set i[1318] = 189
            set i[980] = 190
            set i[1699] = 191
            set i[1292] = 192
            set i[477] = 193
            set i[709] = 194
            set i[1600] = 195
            set i[2092] = 196
            set i[50] = 197
            set i[546] = 198
            set i[408] = 199
            set i[853] = 200
            set i[205] = 201
            set i[411] = 202
            set i[1311] = 203
            set i[1422] = 204
            set i[1808] = 205
            set i[457] = 206
            set i[1280] = 207
            set i[614] = 208
            set i[1037] = 209
            set i[237] = 210
            set i[1409] = 211
            set i[1023] = 212
            set i[1361] = 213
            set i[695] = 214
            set i[161] = 215
            set i[1645] = 216
            set i[1822] = 217
            set i[644] = 218
            set i[1395] = 219
            set i[677] = 220
            set i[1677] = 221
            set i[881] = 222
            set i[861] = 223
            set i[1408] = 224
            set i[1864] = 225
            set i[1467] = 226
            set i[1819] = 227
            set i[1971] = 228
            set i[949] = 229
            set i[774] = 230
            set i[1828] = 231
            set i[865] = 232
            set i[699] = 233
            set i[786] = 234
            set i[1806] = 235
            set i[1286] = 236
            set i[1128] = 237
            set i[1490] = 238
            set i[1720] = 239
            set i[1817] = 240
            set i[729] = 241
            set i[1191] = 242
            set i[1164] = 243
            set i[413] = 244
            set i[349] = 245
            set i[1409] = 246
            set i[660] = 247
            set i[2016] = 248
            set i[1087] = 249
            set i[1497] = 250
            set i[753] = 251
            set i[1579] = 252
            set i[1456] = 253
            set i[606] = 254
            set i[1625] = 255
            set h[92] = 47
            set h[201] = 108
            set h[201] = 76
            set h[203] = 103
            set h[203] = 71
            set h[246] = 115
            set h[246] = 83
            set h[246] = 211
            set h[254] = 187
            set y[201] = 108
            set y[203] = 103
            set y[246] = 115

            set c[8]="\b"
            set c[9]="\t"
            set c[10]="\n"
            set c[12]="\f"
            set c[13]="\r"
            set c[32]=" "
            set c[33]="!"
            set c[34]="\""
            set c[35]="#"
            set c[36]="$"
            set c[37]="%"
            set c[38]="&"
            set c[39]="'"
            set c[40]="("
            set c[41]=")"
            set c[42]="*"
            set c[43]="+"
            set c[44]=","
            set c[45]="-"
            set c[46]="."
            set c[47]="/"
            set c[48]="0"
            set c[49]="1"
            set c[50]="2"
            set c[51]="3"
            set c[52]="4"
            set c[53]="5"
            set c[54]="6"
            set c[55]="7"
            set c[56]="8"
            set c[57]="9"
            set c[58]=":"
            set c[59]=";"
            set c[60]="<"
            set c[61]="="
            set c[62]=">"
            set c[63]="?"
            set c[64]="@"
            set c[65]="A"
            set c[66]="B"
            set c[67]="C"
            set c[68]="D"
            set c[69]="E"
            set c[70]="F"
            set c[71]="G"
            set c[72]="H"
            set c[73]="I"
            set c[74]="J"
            set c[75]="K"
            set c[76]="L"
            set c[77]="M"
            set c[78]="N"
            set c[79]="O"
            set c[80]="P"
            set c[81]="Q"
            set c[82]="R"
            set c[83]="S"
            set c[84]="T"
            set c[85]="U"
            set c[86]="V"
            set c[87]="W"
            set c[88]="X"
            set c[89]="Y"
            set c[90]="Z"
            set c[91]="["
            set c[92]="\\"
            set c[93]="]"
            set c[94]="^"
            set c[95]="_"
            set c[96]="`"
            set c[97]="a"
            set c[98]="b"
            set c[99]="c"
            set c[100]="d"
            set c[101]="e"
            set c[102]="f"
            set c[103]="g"
            set c[104]="h"
            set c[105]="i"
            set c[106]="j"
            set c[107]="k"
            set c[108]="l"
            set c[109]="m"
            set c[110]="n"
            set c[111]="o"
            set c[112]="p"
            set c[113]="q"
            set c[114]="r"
            set c[115]="s"
            set c[116]="t"
            set c[117]="u"
            set c[118]="v"
            set c[119]="w"
            set c[120]="x"
            set c[121]="y"
            set c[122]="z"
            set c[123]="{"
            set c[124]="|"
            set c[125]="}"
            set c[126]="~"
            set c[128] = "€"
            set c[130] = "‚"
            set c[131] = "ƒ"
            set c[132] = "„"
            set c[133] = "…"
            set c[134] = "†"
            set c[135] = "‡"
            set c[136] = "ˆ"
            set c[137] = "‰"
            set c[138] = "Š"
            set c[139] = "‹"
            set c[140] = "Œ"
            set c[142] = "Ž"
            set c[145] = "‘"
            set c[146] = "’"
            set c[147] = "“"
            set c[148] = "”"
            set c[149] = "•"
            set c[150] = "–"
            set c[151] = "—"
            set c[152] = "˜"
            set c[153] = "™"
            set c[154] = "š"
            set c[155] = "›"
            set c[156] = "œ"
            set c[158] = "ž"
            set c[159] = "Ÿ"
            set c[160] = " "
            set c[161] = "¡"
            set c[162] = "¢"
            set c[163] = "£"
            set c[164] = "¤"
            set c[165] = "¥"
            set c[166] = "¦"
            set c[167] = "§"
            set c[168] = "¨"
            set c[169] = "©"
            set c[170] = "ª"
            set c[171] = "«"
            set c[172] = "¬"
            set c[174] = "®"
            set c[175] = "¯"
            set c[176] = "°"
            set c[177] = "±"
            set c[178] = "²"
            set c[179] = "³"
            set c[180] = "´"
            set c[181] = "µ"
            set c[182] = "¶"
            set c[183] = "·"
            set c[184] = "¸"
            set c[185] = "¹"
            set c[186] = "º"
            set c[187] = "»"
            set c[188] = "¼"
            set c[189] = "½"
            set c[190] = "¾"
            set c[191] = "¿"
            set c[192] = "À"
            set c[193] = "Á"
            set c[194] = "Â"
            set c[195] = "Ã"
            set c[196] = "Ä"
            set c[197] = "Å"
            set c[198] = "Æ"
            set c[199] = "Ç"
            set c[200] = "È"
            set c[201] = "É"
            set c[202] = "Ê"
            set c[203] = "Ë"
            set c[204] = "Ì"
            set c[205] = "Í"
            set c[206] = "Î"
            set c[207] = "Ï"
            set c[208] = "Ð"
            set c[209] = "Ñ"
            set c[210] = "Ò"
            set c[211] = "Ó"
            set c[212] = "Ô"
            set c[213] = "Õ"
            set c[214] = "Ö"
            set c[215] = "×"
            set c[216] = "Ø"
            set c[217] = "Ù"
            set c[218] = "Ú"
            set c[219] = "Û"
            set c[220] = "Ü"
            set c[221] = "Ý"
            set c[222] = "Þ"
            set c[223] = "ß"
            set c[224] = "à"
            set c[225] = "á"
            set c[226] = "â"
            set c[227] = "ã"
            set c[228] = "ä"
            set c[229] = "å"
            set c[230] = "æ"
            set c[231] = "ç"
            set c[232] = "è"
            set c[233] = "é"
            set c[234] = "ê"
            set c[235] = "ë"
            set c[236] = "ì"
            set c[237] = "í"
            set c[238] = "î"
            set c[239] = "ï"
            set c[240] = "ð"
            set c[241] = "ñ"
            set c[242] = "ò"
            set c[243] = "ó"
            set c[244] = "ô"
            set c[245] = "õ"
            set c[246] = "ö"
            set c[247] = "÷"
            set c[248] = "ø"
            set c[249] = "ù"
            set c[250] = "ú"
            set c[251] = "û"
            set c[252] = "ü"
            set c[253] = "ý"
            set c[254] = "þ"
            set c[255] = "ÿ"
        endmethod
    endmodule
    private struct Inits extends array
        implement Init
    endstruct
endlibrary
//TESH.scrollpos=9
//TESH.alwaysfold=0
library Dialog /* v.1.1.0.0
**************************************************
*
*   A struct wrapper for easy dialog creation.
*
**************************************************
*
*/
 requires Table  /* [url]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url]
*
**************************************************
*
*   struct Dialog
*
*       static method create() returns thistype
*          
*           Creates a new dialog and returns its instance.
*
*       method operator title= takes string s
*
*           Sets the title message for the dialog.
*
*       method addButton( string text, integer hotkey ) returns button
*
*           Adds a button to the dialog that reads <text>.
*           The hotkey serves as a shortcut to press a dialog
*           button. Example input: 'a', 'b', 512 (esc).
*
*       method display( player p, boolean flag )
*          
*           Shows/hides a dialog for a particular player.
*
*       method displayAll( boolean flag )
*
*           Shows/hides a dialog for all players.
*
*       method clear()
*  
*           Clears a dialog of its message and buttons.
*
*       method destroy()
*
*           Destroys a dialog and its instance.
*
*   -- Event API --
*
*       method registerClickEvent( boolexpr b )
*
*           Registers when a dialog button is clicked.
*
*       static method getClickedDialog() returns Dialog
*       static method getClickedButton() returns button
*       static method getPlayer() returns player
*
*            Event responses.
*
**************************************************
*
*   Constants - Credits to DysfunctionaI for the list!
*/

    globals
        constant integer KEY_SPACEBAR          = 32
       
        /* Number Pad */
        constant integer KEY_NUMPAD_0          = 257
        constant integer KEY_NUMPAD_1          = 258
        constant integer KEY_NUMPAD_2          = 259
        constant integer KEY_NUMPAD_3          = 260
        constant integer KEY_NUMPAD_4          = 261
        constant integer KEY_NUMPAD_5          = 262
        constant integer KEY_NUMPAD_6          = 263
        constant integer KEY_NUMPAD_7          = 264
        constant integer KEY