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 haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Let your favorite entries duke it out in the 15th Techtree Contest Poll.
    Dismiss Notice
  5. Weave light to take you to your highest hopes - the 6th Special Effect Contest is here!
    Dismiss Notice
  6. 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

Shadow_over_Blackwood.w3x
Variables
External Systems
TimerUtils
GroupUtils
Math
Table
ErrorMessage
Alloc
Pool
PathingType
ProgressBar
ReverseAnimation
StructuredDD
IntuitiveDamageSystem
Shield System
MoCo Systems
HandleTable
SpellUtils
EffectUtils
IsUnitInSight
CastBar
IsSomethingInBetween
SaveInventory
Map Basics
Globals
Initialization
InitStrings
BasicFunctions
TempVisMod
Camera
GameStart
Daybreak
Villagers & Guards
VillagerSystem
WaypointSystem
HomeSystem
-- Initial Creation --
CreateCivilians
CreateGuardsStayput
CreateGuardsPatrol
-- Reinforcements --
Vampires & Hunters
-- Vampires --
VampireSystem
VampireSpellSystem
VampireLearnAbilities
RegisterVampiresOnMap
-- Vampire Spells --
SuckBlood
Transformation
Fear
CallSpawns
-- Hunters --
HunterSystem
-- Hunter Spells --
Vampire Trap
Mage
Assassin
Sentinal
Gunslinger
Various
Quest Log
AnimalSystem
CreateAnimals
CityRats
XP System
WeatherSystem
Gates
Spawns
GhostMerchant
Baron
Zombies
Items & Ingredients
ItemFunctions
ItemPickup
Cauldrons
Recipes
CreateForestItems
Items
Crates
Wine
ItemStack
------- Potions ---------
Potions
Commands
Debugging
DisplayStructData
DisplayStructDataVampire
DisplayVillagerData
GetOrders
GetCliffLevel
Set XP
GiveGold
GiveVision
GiveIngredients
ShowIngredients
Set Level
Killme
Healme
Debugging
DebugStuff
KillDebugUnits
CreateTestHunters
VisionTester
Pathability
PerformanceTester
HeavyCalcTester

		
Name Type Is Array Initial Value
//TESH.scrollpos=46
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0 + FIX
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x)   : Get a timer (alternative to CreateTimer), call
//*                            Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Multi-flavor:
//*    Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************

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

        private constant integer OFFSET     = 0x100000
        private          integer VOFFSET    = OFFSET
             
        //Timers to preload at map init:
        private constant integer QUANTITY   = 512
       
        //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)
     //   debug call BJDebugMsg( "|cff76CAFF"+I2S(tN)+"|r") // MoCo
     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    
   //     debug call BJDebugMsg( "|cff76CAFF"+I2S(tN)+"|r") // MoCo
    endfunction
   
    // MoCo    
    private function ShowTimerActions takes nothing returns nothing
        debug call BJDebugMsg( "|cff76CAFFTimer N:|r "+I2S(tN)) // MoCo
    endfunction
   
    private function init takes nothing returns nothing
     local integer i=0
     local integer o=-1
     local boolean oops = false
     local trigger trg = CreateTrigger(  )
     
     // MoCo
     call TriggerRegisterPlayerChatEvent( trg, Player(0), "res", true )
     call TriggerAddAction( trg, function ShowTimerActions )
     set trg = null
     
     
        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=99
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//*     [group]    ENUM_GROUP      As you might expect, this group is good for
//*                                when you need a group just for enumeration.
//*     [boolexpr] BOOLEXPR_TRUE   This is a true boolexpr, which is important
//*                                because a 'null' boolexpr in enumeration
//*                                calls results in a leak. Use this instead.
//*     [boolexpr] BOOLEXPR_FALSE  This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//*     local group MyGroup = NewGroup()
//*     call GroupRefresh(MyGroup)
//*     call ReleaseGroup(MyGroup)
//*     call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//*     call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
    //If you don't have xebasic in your map, this value will be used instead.
    //This value corresponds to the max collision size of a unit in your map.
    private constant real    MAX_COLLISION_SIZE = 197.
    //If you are insane and don't care about any of the protection involved in
    //this library, but want this script to be really fast, set this to true.
    private constant boolean LESS_SAFETY        = false
endglobals

globals
    //* Constants that are available to the user
    group    ENUM_GROUP     = CreateGroup()
    boolexpr BOOLEXPR_TRUE  = null
    boolexpr BOOLEXPR_FALSE = null
endglobals

globals
    //* Hashtable for debug purposes
    private hashtable     ht     = InitHashtable()
    //* Temporary references for GroupRefresh
    private boolean       Flag   = false
    private group         Refr   = null
    //* Arrays and counter for the group stack
    private group   array Groups
    private integer       Count  = 0
    //* Variables for use with the GroupUnitsInArea function
    private real          X      = 0.
    private real          Y      = 0.
    private real          R      = 0.
    private hashtable     H      = InitHashtable()
endglobals

private function HookDestroyGroup takes group g returns nothing
    if g == ENUM_GROUP then
        call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
    endif
endfunction

debug hook DestroyGroup HookDestroyGroup

private function AddEx takes nothing returns nothing
    if Flag then
        call GroupClear(Refr)
        set Flag = false
    endif
    call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
    set Flag = true
    set Refr = g
    call ForGroup(Refr, function AddEx)
    if Flag then
        call GroupClear(g)
    endif
endfunction

function NewGroup takes nothing returns group
    if Count == 0 then
        set Groups[0] = CreateGroup()
    else
        set Count = Count - 1
    endif
    static if not LESS_SAFETY then
        call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
    endif
    return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
    local integer id = GetHandleId(g)
    static if LESS_SAFETY then
        if g == null then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
            return false
        elseif Count == 8191 then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
            call DestroyGroup(g)
            return false
        endif
    else
        if g == null then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
            return false
        elseif not HaveSavedInteger(ht, 0, id) then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
            return false
        elseif LoadInteger(ht, 0, id) == 2 then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
            return false
        elseif Count == 8191 then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
            call DestroyGroup(g)
            return false
        endif
        call SaveInteger(ht, 0, id, 2)
    endif
    call GroupClear(g)
    set Groups[Count] = g
    set Count         = Count + 1
    return true
endfunction

private function Filter takes nothing returns boolean
    return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction

private function HookDestroyBoolExpr takes boolexpr b returns nothing
    local integer bid = GetHandleId(b)
    if HaveSavedHandle(H, 0, bid) then
        //Clear the saved boolexpr
        call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
        call RemoveSavedHandle(H, 0, bid)
    endif
endfunction

hook DestroyBoolExpr HookDestroyBoolExpr

private constant function GetRadius takes real radius returns real
    static if LIBRARY_xebasic then
        return radius+XE_MAX_COLLISION_SIZE
    else
        return radius+MAX_COLLISION_SIZE
    endif
endfunction

function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
    local real    prevX = X
    local real    prevY = Y
    local real    prevR = R
    local integer bid   = 0
   
    //Set variables to new values
    set X = x
    set Y = y
    set R = radius
    if filter == null then
        //Adjusts for null boolexprs passed to the function
        set filter = Condition(function Filter)
    else
        //Check for a saved boolexpr
        set bid = GetHandleId(filter)
        if HaveSavedHandle(H, 0, bid) then
            //Set the filter to use to the saved one
            set filter = LoadBooleanExprHandle(H, 0, bid)
        else
            //Create a new And() boolexpr for this filter
            set filter = And(Condition(function Filter), filter)
            call SaveBooleanExprHandle(H, 0, bid, filter)
        endif
    endif
    //Enumerate, if they want to use the boolexpr, this lets them
    call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
    //Give back original settings so nested enumerations work
    set X = prevX
    set Y = prevY
    set R = prevR
endfunction

function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
    local real prevX = X
    local real prevY = Y
    local real prevR = R
   
    //Set variables to new values
    set X = x
    set Y = y
    set R = radius
    //Enumerate
    call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
    //Give back original settings so nested enumerations work
    set X = prevX
    set Y = prevY
    set R = prevR
endfunction

private function True takes nothing returns boolean
    return true
endfunction
private function False takes nothing returns boolean
    return false
endfunction
private function Init takes nothing returns nothing
    set BOOLEXPR_TRUE  = Condition(function True)
    set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
// **************************************************************************
// ** **
// ** Mathematical Functions **
// ** ————————————— **
// ** **
// ** Functions used instead of BJs to calculate some values **
// ** **
// ** By: Majin **
// **
// ** **
// **************************************************************************

library Math
    function GetDistance takes real ax, real ay, real bx, real by returns real
        return SquareRoot((bx-ax)*(bx-ax)+(by-ay)*(by-ay))
    endfunction
   
    function PolarProjectionx takes real ax, real dist, real angle returns real
        return ax + dist * Cos(angle)
    endfunction
   
    function PolarProjectiony takes real ay, real dist, real angle returns real
        return ay + dist * Sin(angle)
    endfunction

    function GetAngle takes real ax, real ay, real bx, real by returns real
        return Atan2(by-ay, bx-ax)
    endfunction    
   
    function IAbs takes integer a returns integer
        if (a >= 0) then
            return a
        else
            return -a
        endif
    endfunction
   
    function RAbs takes real a returns real
        if (a >= 0) then
            return a
        else
            return -a
        endif
    endfunction
   
    function IMin takes integer a, integer b returns integer
        if (a < b) then
            return a
        else
            return b
        endif
    endfunction
   
    function AntiLeak takes nothing returns boolean
        return true
    endfunction

endlibrary
//TESH.scrollpos=7
//TESH.alwaysfold=0
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=21
//TESH.alwaysfold=0
library ErrorMessage /* v1.0.1.4
*************************************************************************************
*
* Issue Compliant Error Messages
*
************************************************************************************
*
* debug function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
* - In the event of an error the game will be permanently paused
*
* debug function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
*
************************************************************************************/

static if DEBUG_MODE then
private struct Fields extends array
static constant string COLOR_RED = "|cffff0000"
static constant string COLOR_YELLOW = "|cffffff00"
static string lastError = null
endstruct
private function Pause takes nothing returns nothing
call PauseGame(true)
endfunction
private function ThrowMessage takes string libraryName, string functionName, string objectName, integer objectInstance, string description, string errorType, string color returns nothing
local string str
local string color_braces = "|cff66FF99"
local string orange = "|cffff6600"
set str = "->\n-> " + color_braces + "{|r " + "Library" + color_braces + "(" + orange + libraryName + color_braces + ")"
if (objectName != null) then
if (objectInstance > 0) then
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + " (|rinstance = " + orange + I2S(objectInstance) + color_braces + ") )" + "|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
else
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + ")|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
else
set str = str + "|r." + "Function" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
set str = str + color_braces + " }|r " + "has thrown an exception of type " + color_braces + "(" + color + errorType + color_braces + ")|r."
set Fields.lastError = str + "\n->\n" + "-> " + color + description + "|r\n->"
endfunction
function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Error", Fields.COLOR_RED)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
call TimerStart(CreateTimer(), 0, true, function Pause)
set objectInstance = 1/0
endif
endfunction
function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Warning", Fields.COLOR_YELLOW)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
set Fields.lastError = null
endif
endfunction
endif
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Alloc /* v1.1.2.0
*************************************************************************************
*
*   */
uses/*
*
*       */
ErrorMessage /*      https://github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage
*
*************************************************************************************
*
*   Minimizes code generation and global variables while maintaining
*   excellent performance.
*
*       local thistype this = recycler[0]
*
*       if (recycler[this] == 0) then
*           set recycler[0] = this + 1
*       else
*           set recycler[0] = recycler[this]
*       endif
*
************************************************************************************
*
*   module Alloc
*
*       static method allocate takes nothing returns thistype
*       method deallocate takes nothing returns nothing
*
*       readonly boolean isAllocated
*
*       debug static method calculateMemoryUsage takes nothing returns integer
*       debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/

    module Alloc
        /*
        *   stack
        */

        private static integer array recycler
       
        /*
        *   list of allocated memory
        */

        debug private static integer array allocatedNext
        debug private static integer array allocatedPrev
       
        /*
        *   free memory counter
        */

        debug private static integer usedMemory = 0
       
        /*
        *   allocation
        */

        static method allocate takes nothing returns thistype
            local thistype this = recycler[0]
           
            debug call ThrowError(this == 8192, "Alloc", "allocate", "thistype", 0, "Overflow.")
           
            if (recycler[this] == 0) then
                set recycler[0] = this + 1
            else
                set recycler[0] = recycler[this]
            endif
           
            set recycler[this] = -1
           
            debug set usedMemory = usedMemory + 1
           
            debug set allocatedNext[this] = 0
            debug set allocatedPrev[this] = allocatedPrev[0]
            debug set allocatedNext[allocatedPrev[0]] = this
            debug set allocatedPrev[0] = this
           
            return this
        endmethod
       
        method deallocate takes nothing returns nothing
            debug call ThrowError(recycler[this] != -1, "Alloc", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
           
            set recycler[this] = recycler[0]
            set recycler[0] = this
           
            debug set usedMemory = usedMemory - 1
           
            debug set allocatedNext[allocatedPrev[this]] = allocatedNext[this]
            debug set allocatedPrev[allocatedNext[this]] = allocatedPrev[this]
        endmethod
       
        /*
        *   analysis
        */

        method operator isAllocated takes nothing returns boolean
            return recycler[this] == -1
        endmethod
       
        static if DEBUG_MODE then
            static method calculateMemoryUsage takes nothing returns integer
                return usedMemory
            endmethod
           
            static method getAllocatedMemoryAsString takes nothing returns string
                local integer memoryCell = allocatedNext[0]
                local string memoryRepresentation = null
               
                loop
                    exitwhen memoryCell == 0
                   
                    if (memoryRepresentation == null) then
                        set memoryRepresentation = I2S(memoryCell)
                    else
                        set memoryRepresentation = memoryRepresentation + ", " + I2S(memoryCell)
                    endif
                   
                    set memoryCell = allocatedNext[memoryCell]
                endloop
                   
                return memoryRepresentation
            endmethod
        endif
       
        /*
        *   initialization
        */

        private static method onInit takes nothing returns nothing
            set recycler[0] = 1
        endmethod
    endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Pool
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script gives the user access to general integer pools. A pool is a data
//* structure that allows you to give entries to it a weight. This weight
//* essentially scales how likely certain random accesses to the pool will be
//* returned by the internal .getRandomInt method. Pools can be useful in any
//* number of ways, such as item drops, randomizing enemy encounters, randomly
//* selecting rects weighted by area, and so forth.
//*
//* Modified by Moco [2013-04-12]:
//*   - Fixed a critical issue with the RemoveInt function not properly updating the hashtable
//*   - Added a flush method to clear the whole pool
//*
//******************************************************************************
//*
//* Example usage:
//*    local intpool ip = intpool.create()
//*    call ip.addInt(1, 1.0)
//*    call ip.addInt(2, 0.5)
//*    call ip.getRandomInt()
//*    call ip.getChance(2)
//*    call ip.getWeight(2)
//*    call ip.removeInt(1)
//*
//* You will first need to create an intpool as shown above. Once you've done
//* that, you may use the .addInt method to add an entry to the pool with a
//* specific weight. The example above adds 2 integers, one twice as likely to
//* be randomly selected as the other. That means for the above example, the
//* .getRandomInt method will 66% of the time return 1 and 33% of the time
//* return 2. If you want to remove an entry from an intpool, the .removeInt
//* method is what you will want to use. If you would like to update an entry's
//* weight after already adding it, simply use .addInt again with the new
//* weight.
//*
//* The .getChance and .getWeight methods are there for convenience. If you are
//* interested in the exact chance of the intpool returning a specific entry,
//* then you should use .getChance to obtain the decimal chance out of 1. If you
//* want to know the weight input for a specific entry, .getWeight will return
//* that for you.
//*
//* When adding an entry to the intpool with .addInt, the actual magnitude of
//* the weight doesn't matter. What matters is its magnitude relative to the
//* magnitudes of all other entries in the intpool. This means that it is ok to
//* use very large or very small weights and is done at the user's discretion.
//*
//* It is worth noting that if you use .getRandomInt on an intpool with no
//* entries, the function will return INTPOOL_NO_ENTRIES, which is about as
//* random an integer as possible so as to avoid people accidentally using it.
//*
globals
    //These constants can be changed
    private constant integer MAX_INSTANCES         = 8191
    private constant integer MAX_ENTRIES           = 256
            constant integer INTPOOL_NO_ENTRIES    = 0x672819
           
    //Don't change the following global declaration
    private hashtable ht = InitHashtable()
endglobals

struct intpool[MAX_INSTANCES]
    private integer Cnt         = 0
    private real    WeightTotal = 0.
    private integer array Entries[MAX_ENTRIES]
    private real    array Weights[MAX_ENTRIES]
    private string name = " " // pool name for debug
   
    method getWeight takes integer entry returns real
        return Weights[LoadInteger(ht, integer(this), entry)]
    endmethod
   
    method getChance takes integer entry returns real
        if WeightTotal > 0. then
            return Weights[LoadInteger(ht, integer(this), entry)]/WeightTotal
        endif
        return 0.
    endmethod
   
    method addInt takes integer entry, real weight returns nothing
        local integer in = 0
        if .Cnt == MAX_ENTRIES then
            //Can't hold any more entries
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: .addEntry has reached MAX_ENTRIES")
            return
        elseif weight <= 0. then
            //Zero or negative weights make no sense
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: .addEntry can't take zero or negative weights (" +.name+")")
            return
        endif
        set in = LoadInteger(ht, integer(this), entry)
        if in > 0 then
            //Update old entry
            set .WeightTotal = .WeightTotal - .Weights[in] + weight
            set .Weights[in] = weight
        //    debug call BJDebugMsg(SCOPE_PREFIX+"Pool updated existing entry: "+I2S(entry))
        else
            //Make a new entry
            set .Cnt           = .Cnt + 1
            call SaveInteger(ht, integer(this), entry, .Cnt)
            set .Entries[.Cnt] = entry
            set .Weights[.Cnt] = weight
            set .WeightTotal   = .WeightTotal + weight
         //   debug call BJDebugMsg(SCOPE_PREFIX+"Pool New Entry: "+I2S(entry))
        endif
       // debug call BJDebugMsg("Pool added value: "+I2S(entry)+" with weight: "+R2S(weight))
    endmethod
   
    method flush takes nothing returns nothing
        local integer c = 0
        call FlushChildHashtable(ht, integer(this))
        loop
            exitwhen c > Cnt
            set .Entries[.Cnt] = 0
            set .Weights[.Cnt] = 0
            set c = c + 1
        endloop
        set .WeightTotal = 0
        set .Cnt         = 0
    endmethod
   
    method showEntries takes nothing returns nothing
        local integer c = 1
        call BJDebugMsg(" Pool count: "+I2S(Cnt))
        loop
            exitwhen c > Cnt
            call BJDebugMsg("Pool entry #"+I2S(c)+ ": "+I2S(.Entries[c]))
            set c = c + 1
        endloop
    endmethod
   
    method removeInt takes integer entry returns nothing
        local integer in = LoadInteger(ht, integer(this), entry)
        if in > 0 then
            call RemoveSavedInteger(ht, integer(this), entry)
           
            //Remove its entry in the arrays
            set .WeightTotal = .WeightTotal - .Weights[in]
           
            if in != .Cnt then          
                set .Entries[in] = .Entries[.Cnt]
                set .Weights[in] = .Weights[.Cnt]
                call SaveInteger(ht, integer(this), .Entries[in], in)
            endif
            set .Entries[.Cnt] = 0
            set .Weights[.Cnt] = 0
            set .Cnt         = .Cnt - 1
           
            if .Cnt == 0 then
                call this.flush()
            endif
        debug else
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: .removeEntry entry doesn't exist")
        endif
    endmethod
   
    method getRandomInt takes nothing returns integer
        local real    r = GetRandomReal(0, .WeightTotal)
        local integer c = 0
        if .WeightTotal <= 0. then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: intpool has no entries (" +.name+")")
            return INTPOOL_NO_ENTRIES
        endif
        set r = GetRandomReal(0, .WeightTotal) // Double Random
        loop
            set r = r - .Weights[c]
            exitwhen r <= 0
            set c = c + 1
        endloop
        return .Entries[c]
    endmethod
   
    method setName takes string name returns nothing
        set this.name = name
    endmethod
   
endstruct
endlibrary
//TESH.scrollpos=112
//TESH.alwaysfold=0
library PathingType initializer onInit
   
    // Configuration
   
        globals
       
            private constant integer PATH_CHECKER  = 'h00C'
            private constant integer FLY_CHECKER   = 'h00E'
            private constant integer WALK_CHECKER  = 'h00D'
            private constant integer BUILD_CHECKER = 'h00F'
           
            private constant player  UNUSED_PLAYER = Player(15)
           
        endglobals
   
    /*
   
                PathingType v1.3
                ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
                        by: Dalvengyr
       
       
        Description
        ¯¯¯¯¯¯¯¯¯¯¯
            This library allows you to detect all pathability types:
            walkablility, flyability, and buildability. As well as allowing
            you to determine the pathing color of given coordinates.
           
            Here is the pathing color specifications:
       
       
                Color   Buildable   Walkable    Flyable     Red     Green   Blue
            ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
                White       x           x           x       255      255    255
                Magenta     x           x           o       255       0     255
                Cyan        x           o           x        0       255    255
                Blue        x           o           o        0        0     255
                Yellow      o           x           x       255      255     0
                Red         o           x           o       255       0      0
                Green       o           o           x        0       255     0
                Black       o           o           o        0        0      0
               
               
            (You can check your pathing map by pressing 'p' at terrain editor.)
           
           
        API
        ¯¯¯
            1. Used for checking certain point's flyability
           
                | function IsTerrainFlyable takes real x, real y returns boolean
               
               
            2. Used for checking certain point's walkability.
           
                | function IsTerrainWalkable takes real x, real y returns boolean
               
               
            3. Used for checking certain point's buildability.
           
                | function IsTerrainBuildable takes real x, real y returns boolean
               
               
            4. (Bonus) Used for checking certain point's pathability color.
           
                | function GetTerrainPathingColor takes real x, real y returns integer
               
                Returned values (pathing colors):
                    | PATHING_COLOR_WHITE
                    | PATHING_COLOR_MAGENTA
                    | PATHING_COLOR_CYAN
                    | PATHING_COLOR_BLUE
                    | PATHING_COLOR_YELLOW
                    | PATHING_COLOR_RED
                    | PATHING_COLOR_GREEN
                    | PATHING_COLOR_BLACK
                   
                   
        How to import
        ¯¯¯¯¯¯¯¯¯¯¯¯¯
            - Copy Fly, Walk, Build, and Path Checker (units) at object editor.
            - Make sure Path Checker is able to build Fly, Walk, and Build Checker.
            - Configure this system (available above).
                   
                   
        Credits
        ¯¯¯¯¯¯¯
            - PurgeandFire for pathability checking method.
            - TheHelper.net for complete pathing types tutorial.
                   
                   
        Link
        ¯¯¯¯
            hiveworkshop.com/forums/spells-569/pathing-type-v1-2-a-263230/
   
    */

   
    globals
       
        private unit PathChecker
       
        constant integer PATHING_COLOR_WHITE   = 0
        constant integer PATHING_COLOR_MAGENTA = 1
        constant integer PATHING_COLOR_CYAN    = 2
        constant integer PATHING_COLOR_BLUE    = 3
        constant integer PATHING_COLOR_YELLOW  = 4
        constant integer PATHING_COLOR_RED     = 5
        constant integer PATHING_COLOR_GREEN   = 6
        constant integer PATHING_COLOR_BLACK   = 7
       
    endglobals
   
    function IsTerrainFlyable takes real x, real y returns boolean
        return IssueBuildOrderById(PathChecker, FLY_CHECKER, x, y)
    endfunction
   
    function IsTerrainWalkable takes real x, real y returns boolean
        return IssueBuildOrderById(PathChecker, WALK_CHECKER, x, y)
    endfunction
   
    function IsTerrainBuildable takes real x, real y returns boolean
        return IssueBuildOrderById(PathChecker, BUILD_CHECKER, x, y)
    endfunction
   
    function GetTerrainPathingColor takes real x, real y returns integer
       
        local integer color = 0
       
        if IsTerrainFlyable(x, y) then
            set color = color + 1
        endif
       
        if IsTerrainWalkable(x, y) then
            set color = color + 2
        endif
       
        if IsTerrainBuildable(x, y) then
            set color = color + 4
        endif
       
        return color
    endfunction
   
    private function onInit takes nothing returns nothing
   
        set PathChecker = CreateUnit(UNUSED_PLAYER, PATH_CHECKER, 0, 0, 0)
        call UnitRemoveAbility(PathChecker, 'Amov')
        call ShowUnit(PathChecker, false)
       
        if GetLocalPlayer() == UNUSED_PLAYER then
            call FogEnable(false)
            call FogMaskEnable(false)
           
            set bj_lastCreatedFogModifier = CreateFogModifierRect(UNUSED_PLAYER, FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea, true, false)
            call FogModifierStart(bj_lastCreatedFogModifier)  
           
        endif
   
    endfunction
   
endlibrary
//TESH.scrollpos=106
//TESH.alwaysfold=0
library ProgressBars requires TimerUtils optional BoundSentinel
/**************************************************************
*
*   ProgressBars v2.0.1 by TriggerHappy
*
*   This library allows you to easily create and modify progress bars.
*   It works by creating a dummy unit with a special model and changing
*   the animation speed to increase or reduce the bar speed. It is more than
*   just a wrapper as it recycles each progress bar, meaning it will avoid
*   costly CreateUnit calls whenever possible which also leak.
*
*   Options:
*       x            - set X coordinate
*       y            - set Y coordinate
*       xOffset      - offset of the target unit, if any.
*       yOffset      - offset of the target unit, if any.
*       zOffset      - how high the bar is from the ground.
*       color        - allows you to tint the bar or add transparency
*       targetUnit   - pick which unit the bar should hover over
*       size         - set model scale
*
*   Usage:
*       local ProgressBar bar = ProgressBar.create()
*       set bar.zOffset       = 150
*       set bar.color         = PLAYER_COLOR_RED
*       set bar.targetUnit    = CreateUnit(Player(0), 'hfoo', 0, 0, 0)
*       call bar.setPercentage(30)
*
*   Installation:
*       1. Copy the dummy unit over to your map
*       2. Change the DUMMY constant to fit the Raw code of the dummy.
*       3. Copy this and all required libraries over to your map.
*
*   Thanks to JesusHipster for the Progress Bar models
*   and to Vexorian for TimerUtils & BoundSentinel
*
**************************************************************/


    globals
        private constant integer PROGRESS_BAR_DUMMY     = 'e001' // the default one
        private constant player  PROGRESS_BAR_OWNER     = Player(PLAYER_NEUTRAL_PASSIVE) // owner of the dummy
        private constant real    UPDATE_POSITION_PERIOD = 0.03 // the timer period used with .targetUnit
        private integer DUMMY_COUNT = 0
    endglobals
   
    struct ProgressBar
   
        unit bar
        unit target
       
        real xOffset = 0
        real yOffset = 0
       
        timer timer
        timer timer2
       
        private boolean t_enabled = false
        private real endVal
        private real curVal=0
        private real pspeed=0
        private boolean reverse
        private boolean done
        private boolean recycle
       
        readonly static unit array dummy
        readonly static integer lastDummyIndex = -1

        method operator x= takes real x returns nothing
            call SetUnitX(this.bar, x)
        endmethod
       
        method operator x takes nothing returns real
            return GetUnitX(this.bar)
        endmethod
       
        method operator y= takes real y returns nothing
            call SetUnitY(this.bar, y)
        endmethod
       
        method operator y takes nothing returns real
            return GetUnitY(this.bar)
        endmethod
       
        method operator zOffset= takes real offset returns nothing
            call SetUnitFlyHeight(this.bar, offset, 0)
        endmethod
       
        method operator zOffset takes nothing returns real
            return GetUnitFlyHeight(this.bar)
        endmethod
       
        method operator size= takes real size returns nothing
            call SetUnitScale(this.bar, size, size, size)
        endmethod
       
        method operator color= takes playercolor color returns nothing
            call SetUnitColor(this.bar, color)
        endmethod
       
        method show takes boolean flag returns nothing
            call UnitRemoveAbility(this.bar, 'Aloc')
            call ShowUnit(this.bar, flag)
            call UnitAddAbility(this.bar, 'Aloc')
        endmethod
       
        method reset takes nothing returns nothing
            call SetUnitAnimationByIndex(this.bar, 1)
        endmethod

        method RGB takes integer red, integer green, integer blue, integer alpha returns nothing
            call SetUnitVertexColor(this.bar, red, green, blue, alpha)
        endmethod
       
        method destroy takes nothing returns nothing
            if (recycle) then
                set lastDummyIndex = lastDummyIndex + 1
                set dummy[lastDummyIndex] = this.bar
                call SetUnitAnimationByIndex(this.bar, 0)
                call SetUnitTimeScale(this.bar, 1)
            endif
           
            set this.bar        = null
            set this.target     = null
            set this.t_enabled  = false
            set this.endVal     = 0
            set this.curVal     = 0
           
            if (this.timer != null) then
                call ReleaseTimer(this.timer)
                set this.timer = null
            endif
           
            if (this.timer2 != null) then
                call ReleaseTimer(this.timer2)
                set this.timer2 = null
            endif
        endmethod
       
        private static method updatePercentage takes nothing returns nothing
            local timer expired = GetExpiredTimer()
            local thistype this = GetTimerData(expired)
           
            if (this.reverse) then
           
                if (this.curVal > this.endVal) then
                    call SetUnitTimeScale(this.bar, -this.pspeed)
                    set this.curVal = (this.curVal - (this.pspeed))
                elseif (this.curVal <= this.endVal) then
                    call PauseTimer(this.timer2)
                    call SetUnitTimeScale(this.bar, 0)
                    set this.curVal = this.endVal
                    set this.done   = true
                endif
               
            else
           
                if (this.curVal < this.endVal) then
                    call SetUnitTimeScale(this.bar, this.pspeed)
                    set this.curVal = (this.curVal + (this.pspeed))
                elseif (this.curVal >= this.endVal) then
                    call PauseTimer(this.timer2)
                    call SetUnitTimeScale(this.bar, 0)
                    set this.curVal = this.endVal
                    set this.done   = true
                endif
            endif
            set expired = null
        endmethod
       
        private static method updatePosition takes nothing returns nothing
            local thistype this = GetTimerData(GetExpiredTimer())
            if (this.target != null) then
                call SetUnitX(this.bar, GetUnitX(this.target) + xOffset)
                call SetUnitY(this.bar, GetUnitY(this.target) + yOffset)
            else
                call ReleaseTimer(GetExpiredTimer())
            endif
        endmethod
       
        private static method getDummy takes nothing returns unit
            if (lastDummyIndex <= -1) then
                set bj_lastCreatedUnit = CreateUnit(PROGRESS_BAR_OWNER, PROGRESS_BAR_DUMMY, 0, 0, 270)
                call PauseUnit(bj_lastCreatedUnit, true)
                return bj_lastCreatedUnit
            endif
            call SetUnitAnimationByIndex(dummy[lastDummyIndex], 1)
            set lastDummyIndex = lastDummyIndex - 1
            return dummy[lastDummyIndex + 1]
        endmethod
       
        static method release takes integer count returns nothing
            if (count > thistype.lastDummyIndex) then
                set count = thistype.lastDummyIndex
            endif
           
            debug call BJDebugMsg("release method of progress bar")
               
            loop
                exitwhen count <= 0
                call RemoveUnit(dummy[count])
                set DUMMY_COUNT = DUMMY_COUNT - 1
                set dummy[count] = null
                set count = count - 1
            endloop
               
            set thistype.lastDummyIndex = -1
        endmethod
       
        static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
           
            set this.bar        = thistype.getDummy()
            set this.done       = true
            set this.recycle    = true
           
            set DUMMY_COUNT = DUMMY_COUNT + 1
            call SetUnitAnimationByIndex(this.bar, 1)
            call SetUnitTimeScale(this.bar, 0)
           
            debug call BJDebugMsg("progress bar dummy count: "+I2S(DUMMY_COUNT))
            return this
        endmethod
       
        static method createEx takes integer unitId returns thistype
            local thistype this = thistype.allocate()
           
            set this.bar        = CreateUnit(PROGRESS_BAR_OWNER, unitId, 0, 0, 0)
            set this.done       = true
            set this.recycle    = false
           
            call SetUnitAnimationByIndex(this.bar, 1)
            call SetUnitTimeScale(this.bar, 0)
           
            return this
        endmethod
       
        method setPercentage takes real percent, real speed returns nothing
            set this.endVal = R2I(percent)
            set this.pspeed = speed
           
            set this.reverse = (curVal > endVal)
               
            if (this.done) then
               
                if (this.timer2 == null) then
                    set this.timer2 = NewTimerEx(this)
                endif
           
                call TimerStart(this.timer2, 0.01, true, function thistype.updatePercentage)
                set this.done=false
            endif
        endmethod
       
        method operator targetUnit= takes unit u returns nothing
            set this.target = u
           
            if (u != null) then
                if (this.timer == null) then
                    set this.timer = NewTimerEx(this)
                endif
                call TimerStart(this.timer, UPDATE_POSITION_PERIOD, true, function thistype.updatePosition)
                call SetUnitX(this.bar, GetUnitX(this.target) - xOffset)
                call SetUnitY(this.bar, GetUnitY(this.target) - yOffset)
                set this.t_enabled = true
            else
                if (this.timer != null) then
                    call ReleaseTimer(this.timer)
                endif
                set this.t_enabled = false
            endif
        endmethod
       
    endstruct
   
endlibrary
//TESH.scrollpos=78
//TESH.alwaysfold=0
library ReverseAnimation requires TimerUtils

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //  ReverseAnimation
    //====================================================================================================================
    //  Firstly, this script requires TimerUtils (by Vexorian @ [url]www.wc3campaigns.net):[/url]
    //          [url]http://wc3campaigns.net/showthread.php?t=101322[/url]
    //
    //  Background Info:
    //   [url]http://www.wc3campaigns.net/showpost.php?p=1017121&postcount=88[/url]
    //
    //  function SetUnitAnimationReverse takes:
    //
    //      unit u - animation of which reverse animation is played;
    //      integer index - animation index of the animation to be played;
    //      real animTime - the natural duration of the animation to be played. This can be referred to in the preview
    //                      window in the bottom-left part of the World Editor interface (it is the real value enclosed
    //                      in parenthesis);
    //      real runSpeed - the speed at which the animation to be played in reverse will be ran.
    //      boolean resetAnim - indicates to the system if it should set the unit's animation to "stand" after playing the
    //                          reverse animation.
    //
    //  function SetUnitAnimationReverseFollowed takes all of the above and:
    //      FollowUpFunc func - function to be ran after the animation is played. Expressed as a function interface
    //                          (see below). Takes an data object arguement pertaining to relevant stuff that must be
    //                          passed.
    //      integer data - a struct that is the above data object.
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//  -- Configuration --

    globals
        private constant real PREP_INTERVAL_DURATION = 0.03
    endglobals

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//  -- User Functions --

    private keyword ReverseAnimation

    function SetUnitAnimationReverse takes unit u, integer index, real animTime, real runSpeed, boolean resetAnim returns boolean
        return ReverseAnimation.Prepare(u, index, animTime, runSpeed, resetAnim, 0, 0)
    endfunction

    function SetUnitAnimationReverseFollowed takes unit u, integer index, real animTime, real runSpeed, boolean resetAnim, FollowUpFunc func, integer data returns boolean
        return ReverseAnimation.Prepare(u, index, animTime, runSpeed, resetAnim, func, data)
    endfunction

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//  -- Script Operation Functions --

    function interface FollowUpFunc takes integer data returns nothing

    private struct ReverseAnimation

        private unit u
        private integer intAnimIndex
        private real rAnimTime
        private real rRunSpeed
        private boolean boolResetAnim
        private FollowUpFunc func
        private integer data

        public static method Prepare takes unit u, integer index, real animTime, real runSpeed, boolean resetAnim, FollowUpFunc func, integer data returns boolean
            local ReverseAnimation new = 0
            local timer TIM = null

            if u != null and runSpeed > 0.00 then // MoCo
                set new = .allocate()
                set new.u = u
                set new.intAnimIndex = index
                set new.rAnimTime = animTime
                set new.rRunSpeed = -runSpeed
                set new.boolResetAnim = resetAnim
                set new.func = func
                set new.data = data

                call SetUnitTimeScale(u, animTime/PREP_INTERVAL_DURATION)
                call SetUnitAnimationByIndex(u, index)
                set TIM = NewTimer()
                call SetTimerData(TIM, integer(new))
                call TimerStart(TIM, PREP_INTERVAL_DURATION, false, function ReverseAnimation.Play)

                set TIM = null
                return true
            endif

            return false
        endmethod

        public static method Play takes nothing returns nothing
            local timer TIM = GetExpiredTimer()
            local ReverseAnimation INST = GetTimerData(TIM)

            call SetUnitTimeScale(INST.u, INST.rRunSpeed)
            call TimerStart(TIM, INST.rAnimTime/-INST.rRunSpeed, false, function ReverseAnimation.End)

            set TIM = null
        endmethod

        public static method End takes nothing returns nothing
            local timer TIM = GetExpiredTimer()
            local ReverseAnimation INST = GetTimerData(TIM)

            call SetUnitTimeScale(INST.u, 1.00)
            if INST.boolResetAnim then
                call SetUnitAnimation(INST.u, "stand")
            endif
            if INST.func != 0 then
                call INST.func.execute(INST.data)
            endif

            set INST.u = null
            call INST.destroy()
            call ReleaseTimer(TIM)
            set TIM = null
        endmethod

    endstruct

endlibrary
//TESH.scrollpos=95
//TESH.alwaysfold=0

//*     API:
//* boolean ADD_ALL_UNITS: If enabled, a trigger turns on which automatically
//*     registers all units in the map.
//* integer BUCKET_SIZE: How many units to add to each 'bucket' - a larger
//*     bucket will have their trigger refresh less frequently but will be
//*     more computationally expensive. A good starting value is about 20.
//* real PER_CLEANUP_TIMEOUT: How many seconds to wait in between each
//*     scan for empty buckets. This value should be lower if units die often
//*     in your map. A good starting value is about 60.
//* static method addHandler: Registers a callback function to the generic
//*     unit damage event. Example: call StructuredDD.addHandler(function h)
//* static method add: Adds a unit to a bucket. If ADD_ALL_UNITS is enabled,
//*     this method need not be used.
library StructuredDD
    globals
   
        //<< BEGIN SETTINGS SECTION
       
        //* Set this to true if you want all units in your map to be
        //* automatically added to StructuredDD. Otherwise you will have to
        //* manually add them with StructuredDD.add(u).
        private constant boolean ADD_ALL_UNITS=false
       
        //* This is the amount of units that exist in each trigger bucket.
        //* This number should be something between 5 and 30. A good starting
        //* value will be an estimate of your map's average count of units,
        //* divided by 10. When in doubt, just use 20.
        private constant integer BUCKET_SIZE=10
       
        //* This is how often StructuredDD will search for empty buckets. If
        //* your map has units being created and dying often, a lower value
        //* is better. Anything between 10 and 180 is good. When in doubt,
        //* just use 60.
        private constant real PER_CLEANUP_TIMEOUT= 120.
       
        //>> END SETTINGS SECTION
       
    endglobals

    //* Our bucket struct which contains a trigger and its associated contents.
    private struct bucket
        integer bucketIndex=0
        trigger trig=CreateTrigger()
        unit array members[BUCKET_SIZE]
    endstruct
   
    //* Our wrapper struct. We never intend to actually instanciate "a
    //* StructuredDD", we just use this for a pretty, java-like API :3
    struct StructuredDD extends array
        private static boolexpr array conditions
        private static bucket array bucketDB
        private static integer conditionsIndex=-1
        private static integer dbIndex=-1
        private static integer maxDBIndex=-1
       
        //* This method gets a readily available bucket for a unit to be added.
        //* If the "current" bucket is full, it returns a new one, otherwise
        //* it just returns the current bucket.
        private static method getBucket takes nothing returns integer
            local integer index=0
            local integer returner=-1
            local bucket tempDat
            if thistype.dbIndex!=-1 and thistype.bucketDB[thistype.dbIndex].bucketIndex<BUCKET_SIZE then
                return thistype.dbIndex
            else
                set thistype.maxDBIndex=thistype.maxDBIndex+1
                set thistype.dbIndex=thistype.maxDBIndex
                set tempDat=bucket.create()
                set thistype.bucketDB[.maxDBIndex]=tempDat
                loop
                    exitwhen index>thistype.conditionsIndex
                    call TriggerAddCondition(tempDat.trig,thistype.conditions[index])
                    set index=index+1
                endloop
                return thistype.dbIndex
            endif
            return -1
        endmethod
       
        //* This method is for adding a handler to the system. Whenever a
        //* handler is added, damage detection will immediately trigger that
        //* handler. There is no way to deallocate a handler, so don't try to
        //* do this dynamically (!) Support for handler deallocation is
        //* feasible (please contact me)
        public static method addHandler takes code func returns nothing
            local bucket tempDat
            local integer index=0
            set thistype.conditionsIndex=thistype.conditionsIndex+1
            set thistype.conditions[thistype.conditionsIndex]=Condition(func)
            loop
                exitwhen index>thistype.maxDBIndex
                set tempDat=thistype.bucketDB[index]
                call TriggerAddCondition(tempDat.trig,thistype.conditions[thistype.conditionsIndex])
                set index=index+1
            endloop
        endmethod
       
        //* This method adds a unit to the damage detection system. If
        //* ADD_ALL_UNITS is enabled, this method need not be used.
        public static method add takes unit member returns nothing
            local bucket tempDat
            local integer whichBucket=thistype.getBucket()
            set tempDat=thistype.bucketDB[whichBucket]
            set tempDat.bucketIndex=tempDat.bucketIndex+1
            set tempDat.members[tempDat.bucketIndex]=member
            call TriggerRegisterUnitEvent(tempDat.trig,member,EVENT_UNIT_DAMAGED)
        endmethod
       
        //* This is just an auxillary function for ADD_ALL_UNITS' implementation
        static if ADD_ALL_UNITS then
            private static method autoAddC takes nothing returns boolean
                call thistype.add(GetTriggerUnit())
                return false
            endmethod
        endif
       
        //* This method is used to check if a given bucket is empty (and thus
        //* can be deallocated) - this is an auxillary reoutine for the
        //* periodic cleanup system.
        private static method bucketIsEmpty takes integer which returns boolean
            local bucket tempDat=thistype.bucketDB[which]
            local integer index=0
            loop
                exitwhen index==BUCKET_SIZE
                //GetUnitTypeId(unit)==0 means that the unit has been removed.
                if GetUnitTypeId(tempDat.members[index])!=0 then
                    return false
                endif
                set index=index+1
            endloop
            return true
        endmethod
       
        //* This method cleans up any empty buckets periodically by checking
        //* if it has been fully allocated and then checking if all its
        //* members no longer exist.
        private static method perCleanup takes nothing returns nothing
            local integer index=0
            loop
                exitwhen index>thistype.maxDBIndex
                if index!=thistype.dbIndex and thistype.bucketIsEmpty(index) then
                    call DestroyTrigger(thistype.bucketDB[index].trig)
                    call thistype.bucketDB[index].destroy()
                    set thistype.bucketDB[index]=thistype.bucketDB[thistype.maxDBIndex]
                    set thistype.maxDBIndex=thistype.maxDBIndex-1
                    if thistype.maxDBIndex==thistype.dbIndex then
                        set thistype.dbIndex=index
                    endif
                    set index=index-1
                endif
                set index=index+1
            endloop
        endmethod
       
        //* This is a initialization function necessary for the setup of
        //* StructuredDD.
        private static method onInit takes nothing returns nothing
            local group grp
            local region reg
            local trigger autoAddUnits
            local timer perCleanup
            local unit FoG
            static if ADD_ALL_UNITS then
                //Add starting units
                set grp=CreateGroup()
                call GroupEnumUnitsInRect(grp,bj_mapInitialPlayableArea,null)
                loop
                    set FoG=FirstOfGroup(grp)
                    exitwhen FoG==null
                    call thistype.add(FoG)
                    call GroupRemoveUnit(grp,FoG)
                endloop
                //Add entering units
                set autoAddUnits=CreateTrigger()
                set reg=CreateRegion()
                call RegionAddRect(reg,bj_mapInitialPlayableArea)
                call TriggerRegisterEnterRegion(autoAddUnits,reg,null)
                call TriggerAddCondition(autoAddUnits,Condition(function thistype.autoAddC))
                set autoAddUnits=null
                set reg=null
            endif
            //enable periodic cleanup:
            set perCleanup=CreateTimer()
            call TimerStart(perCleanup,PER_CLEANUP_TIMEOUT,true,function thistype.perCleanup)
            set perCleanup=null
        endmethod
    endstruct
endlibrary
//TESH.scrollpos=238
//TESH.alwaysfold=0
library IntuitiveDamageSystem initializer Init requires Table, HeroSystem
//******************************************************************************
//* BY: Rising_Dusk
//*     (Intuitive) Damage Detection System 1.14
//*
//* This library is the core for what has come to be known as the Intuitive
//* Damage Detection System, or IDDS for short. Simply by copying this library
//* into your map somewhere, you will have access to all of its features and
//* options. Below this documentation are some global variables that can be
//* edited to make the system more useful for your map, whatever it might be.
//* Please note that you should only change those globals listed under
//* configuration constants and damage type constants.
//*
//* An important note for the system is that all non-attack damage in your map
//* MUST BE TRIGGERED using the special function call included in this system,
//* UnitDamageTargetEx. This is how the system works to detect attacks, because
//* if the only non-triggered damage in your map originates from attacks, you
//* clearly know which damage packets are attacks. This allows users to use
//* orb abilities in their maps for whatever they want.
//*
//*     function UnitDamageTargetEx takes unit source, unit target, real damage, ...
//*     ...attacktype attackType, integer damageType, boolean ConsiderArmor returns boolean
//*
//* This is the function with which you will deal all triggered damage in your
//* map. The damageType argument is one of the predefined integer constants that
//* you can edit or add below. Default values for this with the system are
//* DAMAGE_TYPE_ATTACK, DAMAGE_TYPE_SPELL, and DAMAGE_TYPE_EXTRA. You can
//* trigger the system to treat triggered damage like it is an attack if you
//* want to by using DAMAGE_TYPE_ATTACK. It is very easy to make new damage
//* types in the system, just follow the instructions in the configuration
//* constants area. In addition, be sure that the constants you define do not
//* conflict with the predefined Blizzard constants. (ie. DAMAGE_TYPE_FIRE) If
//* these conflicts do exist, you will encounter multiply defined syntax errors.
//* The AttackType argument is the same as in the regular UnitDamageTarget
//* native. Also, the system allows you to consider armor when dealing damage or
//* not. Set the ConsiderArmor boolean argument to false if you want to ignore
//* armor for that damage, or true if you want to factor it in.
//*
//*     function TriggerUnregisterDamageEvent takes trigger trg returns boolean
//*     function TriggerRegisterDamageEvent takes trigger trg, integer priority returns boolean
//*
//* The TriggerRegisterDamageEvent function is used when initializing a damage
//* detection response trigger. By using this, it allows you to use a syntax
//* structure nigh-identical to the standard JASS2. It returns a boolean for
//* your convenience that is false if you pass it a null trigger. The system
//* also allows you to pass a positive, zero-inclusive integer to it as that
//* trigger's priority. The higher the number you pass, the later on in the
//* trigger executions it will fire. This is useful if you want shield
//* abilities, as you will want their priorities low so that they can block the
//* damage before it gets to other things. You are also allowed to unregister
//* a trigger from the system at any time if you want; this will likely never
//* have to be done for most maps.
//*
//*     function SetDamage takes real dmg returns nothing
//*     function SetDamageType takes integer dmgtype returns boolean
//*
//* With this function, you can modify the damage the system interprets for its
//* triggers. This function DOES NOT ACTUALLY CHANGE THE DAMAGE BEING DEALT, it
//* is merely a tool for users to use to change the internal variables. The user
//* will need to modify the damage himself by some other means. Similarly, the
//* SetDamageType function internally changes the damage type of a given packet
//* of damage. This can be useful if you want to convert DAMAGE_TYPE_ATTACK into
//* something else or if you want dynamic damagetypes in-game.
//*
//*     function SetTriggerPriority takes trigger trg, integer priority returns boolean
//*     function GetTriggerPriority takes trigger trg returns integer
//*
//* These functions let you set or get a given trigger's priority at will. These
//* functions both require that the trigger being passed to it is registered to
//* the IDDS system. If you pass an unregistered trigger to GetTriggerPriority,
//* it will return -1. If you pass a similar trigger to SetTriggerPriority, it
//* will return false.
//*
//*     function IgnoreHigherPriority takes nothing returns boolean
//*
//* This function is one of the most important reasons for priorities to exist.
//* With it, you can tell the system to ignore higher priority triggers. This
//* is useful, for instance, if you have a triggered evasion ability and don't
//* want anything else to be done with that damage because it was dodged. Other,
//* similar damage-preventing routines will also find this function useful.
//*
//*     function RegisterDamageType takes nothing returns integer
//*
//* This function is useful for declaring your own DAMAGE_TYPE_ETC constants
//* external to the system. By declaring your global variable and then calling
//* this on it as follows, you can register new damage types on the fly. This
//* is very useful if you want other systems or spells to introduce new damage
//* types that are either ignored or do special things for that application.
//*
//*     function GetTriggerDamageType takes nothing returns integer
//*     function GetTriggerDamageSource takes nothing returns unit
//*     function GetTriggerDamageTarget takes nothing returns unit
//*     function GetTriggerDamageBase takes nothing returns real
//*     function GetTriggerDamage takes nothing returns real
//*
//* Like normal WC3 damage detection, the system has event responses for the
//* damage source, the target of the damage, the amount of damage dealt, and
//* other things. It also permits the detection of damage type, which is
//* something standard WC3 does not have. This lets you create on-attack spells
//* very easily whereas without the system it would be very difficult and
//* computationally costly. GetTriggerDamageBase returns the amount of damage
//* the unit was dealt at the beginning of a given trigger series, whereas
//* GetTriggerDamage returns whatever damage the unit has left to receive, if
//* it has been modified in any way with the SetDamage function mentioned
//* earlier.
//*
//* Once you understand all of the aforementioned aspects of the system, you're
//* ready to put it to use. I know it can be tricky to require all spells be
//* triggered, but this is the way of many great maps anyways, so such a
//* requirement is not so unreasonable. If you have any questions regarding the
//* system, please go to [url]www.wc3c.net[/url] and send a private message to the account
//* Rising_Dusk and I will respond as soon as I can. This system may only be
//* released at [url]www.wc3c.net[/url] and its existence on any other website is against
//* the author's will.
//*
//* Enjoy!
//*
globals
    //* Configuration constants
    private          integer       DamageTypeCount     = 4
   
    //* These are the damagetype constant globals for ease of use
            constant integer       DAMAGE_TYPE_ATTACK  = 0
            constant integer       DAMAGE_TYPE_SPELL   = 1
            constant integer       DAMAGE_TYPE_EXTRA   = 2
            constant integer       DAMAGE_TYPE_IGNORED = 3
            constant integer       DAMAGE_TYPE_HEALING = 4
           
        //    constant integer       DAMAGE_TYPE_ATTACK  = 0
        //    constant integer       DAMAGE_TYPE_IGNORED = 1
        //    constant integer       DAMAGE_TYPE_SPELL   = 2
        //    constant integer       DAMAGE_TYPE_EXTRA   = 3
           
   
    //* To add new constants, simply follow the naming convention and increment
    //* the number. You shouldn't change or remove DAMAGE_TYPE_ATTACK or
    //* DAMAGE_TYPE_IGNORED, though, since they have special properties in the
    //* system.
   
    //* These are static constants used by the system and shouldn't be changed
    private          trigger       RunTrigger          = CreateTrigger()
    private          trigger       AddTrigger          = CreateTrigger()
    private          integer       Count               = 0
    private          Table         TrigTable           = 0
    private          Table         RegiTable           = 0
    private          boolean       IgnPrior            = false
    private          integer array NewDamageType
    private          real    array NewDamage
    private          trigger array Trg
    private          integer array Priority
   
    //* Temporary variables used by the system
    private          unit          DamageSource        = null
    private          unit          DamageTarget        = null
    private          integer       DamageType          = 0
    private          integer       DamageId            = 0
    private          real          DamageBase          = 0.
    private          real          Damage              = 0.
endglobals

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

//* Use an insertion sort algorithm to sort the trigger stack based on priority
private function TriggerSort takes nothing returns boolean
    local integer i = 1
    local integer j = 0
    local integer p = 0
    local trigger t = null
   
    loop
        exitwhen i >= Count
        set t = Trg[i]
        set p = Priority[i]
        set j = i-1
        loop
            exitwhen j < 0 or Priority[j] <= p
            set Priority[j+1]                  = Priority[j]
            set Trg[j+1]                       = Trg[j]
            set TrigTable[GetHandleId(Trg[j])] = j+1
            set j = j - 1
        endloop
        set Priority[j+1]             = p
        set Trg[j+1]                  = t
        set TrigTable[GetHandleId(t)] = j+1
        set i = i + 1
    endloop
   
    set t = null
    return true
endfunction

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

//* The function to call when you want to end a damage's trigger series
function IgnoreHigherPriority takes nothing returns boolean
    if DamageSource != null then
        //Make sure it was called in the right place
        set IgnPrior = true
    endif
    return IgnPrior
endfunction

//* Changes the base damage for a trigger series on the fly
function SetDamage takes real dmg returns boolean
    if DamageSource != null and dmg >= 0 then
        //Make sure it was called in the right place
        set NewDamage[DamageId] = dmg
        set Damage              = dmg
        return true
    endif
    return false
endfunction

//* Changes the base damage type of the series
function SetDamageType takes integer dmgtype returns boolean
    if DamageSource != null and dmgtype >= 0 then
        //Make sure it was called in the right place
        set NewDamageType[DamageId] = dmgtype
        set DamageType              = dmgtype
        return true
    endif
    return false
endfunction

//* Returns the given trigger's priority if it's loaded to the system
function GetTriggerPriority takes trigger trg returns integer
    if RegiTable[GetHandleId(trg)] == 0 then
        return -1
    endif
    return Priority[TrigTable[GetHandleId(trg)]]
endfunction

//* Sets the given trigger's priority if it's loaded to the system
function SetTriggerPriority takes trigger trg, integer priority returns boolean
    if RegiTable[GetHandleId(trg)] == 0 or priority < 0 then
        return false
    endif
    set Priority[TrigTable[GetHandleId(trg)]] = priority
    return TriggerSort()
endfunction

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

//* The new damage function used by the system
function UnitDamageTargetEx takes unit source, unit target, real damage, attacktype attackType, integer damageType, boolean ConsiderArmor, boolean isCrit returns boolean
    local boolean b  = false
    set DamageType   = damageType
    set DamageSource = source
   
    set CritDeath[GetHandleId(target)] = 0
    if isCrit then
        set CritDeath[GetHandleId(target)] = 1
    endif
    if ConsiderArmor then
        set b = UnitDamageTarget(source, target, damage, false, false, attackType, DAMAGE_TYPE_NORMAL, null)
    else
        set b = UnitDamageTarget(source, target, damage, false, false, attackType, DAMAGE_TYPE_UNIVERSAL, null)
    endif
    if not b or damageType == DAMAGE_TYPE_IGNORED then
        set DamageType   = DAMAGE_TYPE_ATTACK
        set DamageSource = null
    endif
    return b
endfunction

//* The method by which one registers a trigger with the system
function TriggerRegisterDamageEvent takes trigger trg, integer priority returns boolean
    if trg == null or priority < 0 then
        return false
    endif
    if RegiTable[GetHandleId(trg)] == 0 then
        set RegiTable[GetHandleId(trg)] = 1
    endif
    set Trg[Count]                  = trg
    set Priority[Count]             = priority
    set TrigTable[GetHandleId(trg)] = Count
    set Count                       = Count + 1
    return TriggerSort()
endfunction

//* The method by which one unregisters a trigger from the system
function TriggerUnregisterDamageEvent takes trigger trg returns boolean
    local integer i = 0
    if trg == null then
        return false
    endif
    set i = TrigTable[GetHandleId(trg)]
    if trg != Trg[i] then
        return false
    endif
    set Trg[i]                         = Trg[Count]
    set Priority[i]                    = Priority[Count]
    set TrigTable[GetHandleId(Trg[i])] = i
    set RegiTable[GetHandleId(trg)]    = 0
    set Count                          = Count - 1
    return TriggerSort()
endfunction

//* Initialization shorthand to register a new damage type externally
function RegisterDamageType takes nothing returns integer
    local integer i = DamageTypeCount
    set DamageTypeCount = DamageTypeCount + 1
    return i
endfunction

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

//* Wrappers for the system that can get inlined anyways
function GetTriggerDamageType takes nothing returns integer
    return DamageType
endfunction
function GetTriggerDamageSource takes nothing returns unit
    return DamageSource
endfunction
function GetTriggerDamageTarget takes nothing returns unit
    return DamageTarget
endfunction
function GetTriggerDamageBase takes nothing returns real
    return DamageBase
endfunction
function GetTriggerDamage takes nothing returns real
    return Damage
endfunction

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

private function RunConditions takes nothing returns boolean
    //* The conditions for what must be true for damage detection to run
    return GetEventDamage() >= 0.0001 and DamageType != DAMAGE_TYPE_IGNORED
endfunction

private function AddConditions takes nothing returns boolean
    //* The conditions for registering a unit with the damage system
    return true
endfunction

private function PreloadConditions takes unit u returns boolean
    //* The conditions for preloading a unit to the damage system
    return true
endfunction

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

globals
    private integer array IDStack
    private integer       IDC     = 0
    private integer       IDN     = 0
endglobals

private function Run takes nothing returns nothing
    local unit    u  = GetEventDamageSource()
    local unit    s  = DamageSource
    local unit    t  = GetTriggerUnit()
    local integer i  = 0
    local integer id = 0
    local integer d  = DamageType
    local real    r  = GetEventDamage()
    local real    b  = r
   
    //Allocate an id for this damage packet
    if IDN > 0 then
        set id  = IDStack[IDN]
        set IDN = IDN - 1
    else
        set id  = IDC
        set IDC = IDC + 1
    endif
   
    if DamageSource == null then
        //Damage is of type attack
        set d = DAMAGE_TYPE_ATTACK
        set s = u
    endif
    loop
        exitwhen i > Count or IgnPrior
        //Ensure all variables are correct for nesting
        set Damage            = r
        set DamageBase        = b
        set DamageTarget      = t
        set DamageSource      = s
        set DamageType        = d
        set DamageId          = id
        set NewDamage[id]     = 0.
        set NewDamageType[id] = -1
        if IsTriggerEnabled(Trg[i]) and TriggerEvaluate(Trg[i]) then
            call TriggerExecute(Trg[i])
        endif
        if NewDamage[id] > 0. then
            //Update damage if it was changed
            set r = NewDamage[id]
        endif
        if NewDamageType[id] >= 0 then
            //Update damagetype if it was changed
            set d = NewDamageType[id]
        endif
        set i = i + 1
    endloop
    set Damage        = 0.
    set DamageBase    = 0.
    set DamageTarget  = null
    set DamageSource  = null
    set DamageType    = DAMAGE_TYPE_ATTACK
    set DamageId      = 0
    set IgnPrior      = false
    set NewDamage[id] = 0.
   
    //Return id to the stack
    set IDN          = IDN + 1
    set IDStack[IDN] = id
   
    set u = null
    set s = null
    set t = null
endfunction

private function Load takes nothing returns nothing
    call TriggerRegisterUnitEvent(RunTrigger, GetEnteringUnit(), EVENT_UNIT_DAMAGED)
endfunction

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

private function PreloadUnits takes nothing returns boolean
    if PreloadConditions(GetFilterUnit()) then
        call TriggerRegisterUnitEvent(RunTrigger, GetFilterUnit(), EVENT_UNIT_DAMAGED)
    endif
    return false
endfunction

private function Init takes nothing returns nothing
    local rect     r  = GetWorldBounds()
    local region   re = CreateRegion()
    local boolexpr b  = Condition(function PreloadUnits)
    local group    g  = CreateGroup()
   
    //* Create the tables for use with the system
    set TrigTable = Table.create()
    set RegiTable = Table.create()
   
    call TriggerAddAction(RunTrigger, function Run)
    call TriggerAddCondition(RunTrigger, Condition(function RunConditions))
    call GroupEnumUnitsInRect(g, r, b)
   
    call RegionAddRect(re, r)
    call TriggerRegisterEnterRegion(AddTrigger, re, null)
    call TriggerAddAction(AddTrigger, function Load)
    call TriggerAddCondition(AddTrigger, Condition(function AddConditions))
   
    call RemoveRect(r)
    call DestroyGroup(g)
    call DestroyBoolExpr(b)
    set re = null
    set g  = null
    set b  = null
    set r  = null
endfunction
endlibrary
//TESH.scrollpos=102
//TESH.alwaysfold=0
library ShieldSystem initializer Init requires IntuitiveBuffSystem

// The_Witcher's Shield System
//
// This is an easy to use shield system.
// it allows you to add shield points to a unit
// the shield works like in the game halo:
// the attacked unit doesn't receive any dmg, the shield gets it
// when the shield is down the unit is damaged
// the shield can reload constantly or after some seconds of not beeing attacked
//
// to give a unit a shield just use (if duration is 0 the shield will stay without a time limit)
//
//  call AddShield( towhichunit, hitpoints, RegPerSec, TimeTillReg,  damage factor, colorcode, destroy when shieldhp = 0, show the bar, Duration  )
//                    unit         real       real        real         real           string       boolean                  boolean       real
//                                                                                                                  
// you can check whether a unit has already a shield with (it will return a boolean)
//  UnitHasShield( yourunit)
//                  unit
//
// to implement this system, just copy this trigger in your map
// it requires jngp to be edited/saved
//
// To get rid of a shield just use
//   call DestroyShield( which unit's)
//                         unit
//
// to show or hide the shield bar use
//   call ShowShield( WhichUnits, Show? )
//                      unit     boolean
//
// to get information about an existing shield use:
//    HP:           GetShieldHp(  unit  )
//    maxHP:        GetShieldMaxHp(  unit  )
//    percentHP:    GetShieldHpPercent(  unit  )
//    regeneration: GetShieldReg(  unit  )
//    TimeTillReg:  GetShieldTimeTillReg(  unit  )
//    DamageFactor: GetShieldDamageFactor(  unit  )
//
// to change the values of an existing shield use:
//    HP:           SetShieldHp(  unit, NewValue  )
//    maxHP:        SetShieldMaxHp(  unit, NewValue  )
//    percentHP:    SetShieldHpPercent(  unit, NewValue  )
//    regeneration: SetShieldReg(  unit, NewValue  )
//    TimeTillReg:  SetShieldTimeTillReg(  unit, NewValue  )
//    DamageFactor: SetShieldDamageFactor(  unit, NewValue  )
//
// have fun^^
// The (very small^^) Setup part
globals
    // the shieldbar's size (should be (7.5 * 0.023 / 10 - 0.00625) or 0.01(which isn't working for everyone) for a good result)
    private constant real size = 7.5 * 0.023 / 10 - 0.00625  
   
    // A ability which gives a high instant life bonus
    private constant integer lifeabi = 'A001'  
   
    // the timer interval (should be 0.01 but if laggy then just change it)
    private constant real interval = 0.01  
   
    //the path of the special effect for untis with a shield
    //another good effect: "Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl"
    // private constant string sfx = "Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl"
   
    //the attachement point for sfx
    private constant string AtPoint = "chest"
endglobals
// end of Setup!!
private struct shield
unit u
real hp
real fullhp
real reg
real f
string code
texttag t
real r
effect fx
real remain
timer time
boolean kill
integer i
real damage = 0
boolean show
endstruct

globals
    private trigger trg = CreateTrigger()
    private group g = CreateGroup()
    private hashtable h = InitHashtable()
    private integer total = 0
    private unit array units
    private timer tim = CreateTimer()
endglobals

function UnitHasShield takes unit u returns boolean
    return LoadInteger(h,GetHandleId(u),0) != 0
endfunction

function DestroyShield takes unit whichunits returns nothing
    local shield dat = LoadInteger(h,GetHandleId(whichunits),0)
    local shield dat2 = LoadInteger(h,GetHandleId(units[total-1]),0)
   
    call Debug_Message("Destroy Shield")
   
    if dat != 0 then
       
        call DestroyTextTag(dat.t)
        // add by Moco
        set dat.t = null
       
        call DestroyTimer(dat.time)
        call DestroyEffect(dat.fx)
        call FlushChildHashtable(h,GetHandleId(whichunits))
        set total = total - 1
        set units[dat.i] = units[total]
        set dat2.i = dat.i
        call dat.destroy()
       
        // If unit already has old buff, remove it
    //    if UnitHasBuff(whichunits, BUFF_TYPE_ICE_BARRIER) then
    //        call UnitRemoveBuff(whichunits, BUFF_TYPE_ICE_BARRIER)
    //    endif
       
     //   if UnitHasBuff(whichunits, BUFF_TYPE_SHIELD) then
     //       call UnitRemoveBuff(whichunits, BUFF_TYPE_SHIELD)
     //   endif
       
        if UnitHasBuff(whichunits, BUFF_TYPE_SOUL_SHIELD) then
            call UnitRemoveBuff(whichunits, BUFF_TYPE_SOUL_SHIELD)
        endif
       
    endif
    if total == 0 then
        call PauseTimer(tim)
    endif
endfunction

private function regeneration takes nothing returns nothing
    local shield dat
    local string s = "''''''''''''''''''''''''''''''''''''''''''''''''''"
    local integer k
    local integer i = 0
    loop
        exitwhen i >= total
        set dat = LoadInteger(h,GetHandleId(units[i]),0)
        if TimerGetRemaining(dat.time) == 0 then
            if dat.hp < dat.fullhp then
                set dat.hp = dat.hp + dat.reg
            else
                set dat.hp = dat.fullhp
            endif
        endif
        if dat.remain > 0 then
            set dat.remain = dat.remain - interval
        elseif dat.remain != -100 then
            call DestroyShield(dat.u)
        endif
        set k = R2I(50 * (dat.hp / dat.fullhp))
        call SetTextTagText(dat.t, dat.code + SubString(s,0, k ) + "|r"  + SubString(s,k + 1,StringLength(s)) , size)
        call SetTextTagPos(dat.t,GetUnitX(dat.u) -40, GetUnitY(dat.u),-100)
       // changed by MoCo for healin
            if dat.damage > 0 then
       //  if dat.damage != 0 then
       
            if dat.hp > (dat.damage * dat.f) then
                set dat.hp = dat.hp - (dat.damage * dat.f)
                call SetWidgetLife( dat.u,GetWidgetLife(dat.u) + dat.damage)
            else
                call SetWidgetLife( dat.u,GetWidgetLife(dat.u) + dat.hp)
                set dat.hp = 0
            endif
            set dat.damage = 0
        endif
        call UnitRemoveAbility(dat.u,lifeabi)
        if dat.hp <= 0 and dat.kill == true then
            call DestroyShield(dat.u)
            set i = i - 1
        endif
        set i = i + 1
    endloop
    set s = null
endfunction

private function attack takes nothing returns nothing
    local shield dat = LoadInteger(h,GetHandleId(GetTriggerUnit()),0)
    local timer t
    if dat != 0 then
        if dat.hp > 0 then
            if GetEventDamage() > 0 then// add by MoCo
                set dat.damage = dat.damage + GetEventDamage()
            endif
        endif    
        call TimerStart(dat.time,dat.r,false,null)
    endif
endfunction

function AddShield takes unit towhich, real hp, real RegPerSec, real TimeTillReg, real dmgfactor, string colorcode, boolean destroy, boolean ShowBar, real Duration, string sfx returns nothing
    local shield dat
    if LoadInteger(h,GetHandleId(towhich),0) != 0 then
        call DestroyShield(towhich)
    endif
    set dat = shield.create()
    set dat.u = towhich
    set dat.fullhp = hp
    set dat.hp = hp
    set dat.reg = RegPerSec / 100
    set dat.f = dmgfactor
    set dat.code = colorcode
    set dat.r = TimeTillReg
    set dat.kill = destroy
    set dat.time = CreateTimer()
    set dat.t = CreateTextTag()
    set dat.show = ShowBar
    set dat.fx = AddSpecialEffectTarget(sfx, dat.u, AtPoint)      
    set dat.remain = Duration
    if dat.remain == 0 then
        set dat.remain = -100
    endif
    call SetTextTagVisibility(dat.t,ShowBar)
    set dat.i = total
    if not IsUnitInGroup(dat.u,g) then
        call GroupAddUnit(g,dat.u)
        call TriggerRegisterUnitEvent( trg, towhich, EVENT_UNIT_DAMAGED )
    endif
    set units[total] = dat.u
    set total = total + 1
    call SaveInteger(h,GetHandleId(dat.u),0,dat)
    if total == 1 then
        call TimerStart(tim,interval,true,function regeneration)
    endif
endfunction

private function kill takes nothing returns nothing
    call DestroyShield(GetTriggerUnit())
endfunction

function ShowShield takes unit u, boolean flag returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.show = flag
        call SetTextTagVisibility(dat.t,flag)
    endif
endfunction

function GetShieldHpPercent takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.hp / dat.fullhp * 100.0
    endif
    return .0
endfunction

function GetShieldHp takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.hp
    endif
    return .0
endfunction

function GetShieldMaxHp takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.fullhp
    endif
    return .0
endfunction

function GetShieldReg takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.reg*100
    endif
    return .0
endfunction

function GetShieldTimeTillReg takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.r
    endif
    return .0
endfunction

function GetShieldDamageFactor takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.f
    endif
    return .0
endfunction

function SetShieldHpPercent takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.hp = dat.fullhp * new
        if dat.fullhp < dat.hp then
            set dat.hp = dat.fullhp
        endif
    endif
endfunction

function SetShieldHp takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.hp = new
        if dat.fullhp < dat.hp then
            set dat.hp = dat.fullhp
        endif
    endif
endfunction

function SetShieldMaxHp takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.fullhp = new
        if dat.fullhp < dat.hp then
            set dat.hp = dat.fullhp
        endif
    endif
endfunction

function SetShieldReg takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.reg = new/100
    endif
endfunction
                                                                           
function SetShieldTimeTillReg takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.r = new
        call TimerStart(dat.time,dat.r,false,null)
    endif
endfunction

function SetShieldDamageFactor takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.f = new
    endif
endfunction

private function Init takes nothing returns nothing
 //   local trigger tt = CreateTrigger()
//    call TriggerAddAction(tt, function kill)
 //   call TriggerRegisterAnyUnitEventBJ( tt, EVENT_PLAYER_UNIT_DEATH )    
   
    call TriggerAddAction(trg, function attack)    
endfunction

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library HandleTable initializer Init requires Table
// ====================================================================
//
//  HandleTable by MoCo   v1.0
//
//  A simple toolset for storing an integer data field for handles
//
// ====================================================================

// Saves an integer for a handle
function SetHandleData takes handle h, integer data returns nothing
    set HandleIdTable[ GetHandleId(h) ] = data
endfunction

// Retrieves integer for handle
function GetHandleData takes handle h returns integer
    return HandleIdTable[ GetHandleId(h) ]
endfunction

// Releases the data
function ReleaseHandleData takes handle h returns nothing
    call HandleIdTable.remove( GetHandleId( h ) )
endfunction

private function Init takes nothing returns nothing
    set HandleIdTable = Table.create()
endfunction

endlibrary

 
//TESH.scrollpos=87
//TESH.alwaysfold=0
library SpellUtils initializer Init requires TimerUtils, EffectUtils, Table
// ====================================================================
//
//  SpellUtils by MoCo   v0.8
//
//  A simple and easy to use toolset for spell structs handling.
//
// ====================================================================

globals
    private constant integer SPELL_WARNING = 48
    private constant integer SPELL_MAX = 128
    Spell array spells[1]
   
    private integer spell_count = 0
endglobals

struct Spell

    unit caster = null
    unit target = null
    timer t = null
   
    real x = 0
    real y = 0
    real damage = 0.0
    boolean isCrit = false
    real health = 0.0
    real mana = 0.0
    real armor = 0.0
    real speed = 0.0
    integer ticks = 0
    integer effect_id = 0
    trigger trg = null
    integer name_id = 0
    integer playerId = 0
   
    method destroy takes nothing returns nothing
        set this.caster = null
        set this.target = null
       
        if this.t != null then
            call ReleaseTimer(this.t)
            set this.t = null
        endif
       
        if this.trg != null then
            call DestroyTrigger(this.trg)
            set this.trg = null
        endif
 
        call this.deallocate()
    endmethod
   
endstruct

function GetSpellCaster takes integer id returns unit
    return spells[id].caster
endfunction
function GetSpellTarget takes integer id returns unit
    return spells[id].target
endfunction
function GetSpellDamage takes integer id returns real
    return spells[id].damage
endfunction
function GetSpellX takes integer id returns real
    return spells[id].x
endfunction
function GetSpellY takes integer id returns real
    return spells[id].y
endfunction
function GetSpellCrit takes integer id returns boolean
    return spells[id].isCrit
endfunction
function GetSpellTicks takes integer id returns integer
    return spells[id].ticks
endfunction
function GetSpellEffectId takes integer id returns integer
    return spells[id].effect_id
endfunction
function GetSpell takes integer id returns Spell
    return spells[id]
endfunction
function IncSpellTicks takes integer id returns nothing  
    set spells[id].ticks = spells[id].ticks + 1
endfunction

function SetSpellTicks takes integer id, integer ticks returns nothing
    set spells[id].ticks = ticks
endfunction

function SetSpellEffectId takes integer id, integer effect_id returns nothing
    set spells[id].effect_id = effect_id
endfunction


function ReleaseSpell takes integer spell_id returns nothing  
    local Spell spell = spell_id
    if spell_id == 0 then
        debug call BJDebugMsg("Error: Trying to release a NULL spell!")
    else
        call spell.destroy()
        set spell_count = spell_count - 1
    endif
endfunction


function RegisterSpell takes unit caster, unit target, real x, real y, real damage, boolean crit, real health, real mana, real armor, real speed, integer ticks, integer effect_id, integer name_id returns integer
    local Spell thisSpell = Spell.create()
    local integer spell_id = thisSpell
   
    set spell_count = spell_count + 1
   
    set thisSpell.caster = caster
    set thisSpell.target = target
    set thisSpell.x = x
    set thisSpell.y = y
    set thisSpell.damage = damage
    set thisSpell.isCrit = crit
    set thisSpell.health = health
    set thisSpell.mana = mana
    set thisSpell.armor = armor
    set thisSpell.speed = speed
    set thisSpell.ticks = ticks
    set thisSpell.effect_id = effect_id
    set thisSpell.name_id = name_id
   
    // debug call BJDebugMsg("|cffBD57DFSpell|r reg. ID#"+I2S(spell_id))
   
    set spells[spell_id] = thisSpell
   
    if spell_id > SPELL_WARNING then
        debug call BJDebugMsg("Warning: |cffBD57DFspells count|r higher than "+I2S(SPELL_WARNING)+" there might be unrecycled spells!")
    endif
   
    return spell_id
endfunction

private function TestConditions takes nothing returns boolean
    return DEBUG_MODE
endfunction

private function TestReleaseActions takes nothing returns nothing
    local integer id = GetPlayerId(GetTriggerPlayer())
    local integer i = S2I(SubString( GetEventPlayerChatString(), 2, 1 ))
    call ReleaseSpell(i)
endfunction

private function TestRegisterActions takes nothing returns nothing
    call RegisterSpell(null, null, 0, 0, 30, false, 0,0,0,0,0,1,0)
endfunction

private function ShowArray takes nothing returns nothing
    local integer i = 0
    local integer count = 0
    debug call BJDebugMsg("|cffBD57DFSpell|r array:")
    loop
        exitwhen i > 8 // SPELL_WARNING
        debug call BJDebugMsg("spells["+I2S(i)+"] = "+I2S(spells[i]) + " " + I2S(spells[i].name_id))
        if spells[i] > 0 then
            set count = count + 1
        endif
        set i = i + 1
    endloop
    debug call BJDebugMsg("|cffBD57DFSpells:|r "+I2S(count))
endfunction

private function ShowSpellCount takes nothing returns nothing
    local integer i = 0
    local integer count = 0
    loop
        exitwhen i > SPELL_WARNING // spells[i] == 0
        if spells[i] > 0 then
            set count = count + 1
        endif
        set i = i + 1
    endloop
    debug call BJDebugMsg("|cffBD57DFSpells:|r "+I2S(count))
endfunction

private function Init takes nothing returns nothing
    local trigger trg
           
//    set SpellTab = Table.create()
   
    set trg = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( trg, Player(0), "cs", false )
    call TriggerAddCondition( trg, Condition( function TestConditions ) )
    call TriggerAddAction( trg, function TestRegisterActions )
   
    set trg = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( trg, Player(0), "rs", false )
    call TriggerAddCondition( trg, Condition( function TestConditions ) )
    call TriggerAddAction( trg, function TestReleaseActions )
   
    set trg = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( trg, Player(0), "res", false )
    call TriggerAddCondition( trg, Condition( function TestConditions ) )
    call TriggerAddAction( trg, function ShowArray )
   
    set trg = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( trg, Player(0), "ss", false )
    call TriggerAddCondition( trg, Condition( function TestConditions ) )
    call TriggerAddAction( trg, function ShowSpellCount )
   
    set trg = null
endfunction

endlibrary

 
//TESH.scrollpos=6
//TESH.alwaysfold=0
library EffectUtils initializer Init requires TimerUtils
// ====================================================================
//
//  EffectUtils by MoCo
//
//  A simple and easy to use toolset for timed effects.
//
//  use RegisterEffect(yourEffect, lifeTime)
//   - After the lifeTime runs out, the effect is automatically destroyed and recycled.
//   - The RegisterEffect functions returns a unique effect id so you can access the effect during its lifeTime.
//   - A Lifetime of 0 makes the effect permanent, so you should manually recycle it via ReleaseEffect(effect_id) later.
//
//  use ReleaseEffect(effect id) to destroy and recycle a registered effect
//   - You should always use this function to recycle permanent effects when you do not need them anymore.
//   - You can as well use the function for timed effects to destroy them before the end of their lifeTime.
//
//  use EFFECT_MAX to define the limit of simultanously active effects allowed
//   - Effects are  getting automatically recycled if the limit is exceeded.
//   - A lower value means faster auto-recycling of permanent effects.
//
// ====================================================================
//  Examples:
//  
//  (1)
//
//  local effect e = AddSpecialEffect("myEffect", x, y)
//  call RegisterEffect(e, lifeTime)
//
//  (2)
//
//  local integer effectId
//  local effect e = AddSpecialEffectTarget("myEffect", u, "origin")
//  set effectId = RegisterEffect(e, 0)
//     ...
//  call ReleaseEffect(effectId)
//
// ====================================================================

globals
    private constant integer EFFECT_MAX = 256
    private integer e_pointer = 0
    private effect array effects[1]
endglobals

function ReleaseEffect takes integer id returns nothing
    if effects[id] != null then
        call DestroyEffect(effects[id])
        set effects[id] = null
    endif
endfunction

private function TimedEffectFinished takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetTimerData(t)
    call ReleaseTimer(t)
    set t = null
    call ReleaseEffect(id)
endfunction

// Effects with timed life are automatically destroyed
function RegisterEffect takes effect e, real lifespan returns integer
    local timer t
    local integer id = e_pointer
   
    // If an old effect hasn't cleaned up -> destroy
    if effects[id] != null then
        call DestroyEffect(effects[id])
        debug call BJDebugMsg("An effect hasn't been properly released!")
    endif
   
    // Store Effect and inc ID
    set effects[id] = e
    if e_pointer < EFFECT_MAX - 1 then
        set e_pointer = e_pointer + 1
    else
        set e_pointer = 0
    endif
   
    // Timed life?
    if lifespan > 0 then
        set t = NewTimer()
        call SetTimerData(t, id)
        call TimerStart(t, lifespan, false, function TimedEffectFinished)
    endif
   
    set t = null
    return id
endfunction

private function Init takes nothing returns nothing
    local integer i = 0
    loop
        exitwhen i > (EFFECT_MAX-1)
        set effects[i] = null
        set i = i + 1
    endloop
endfunction

endlibrary

 
//TESH.scrollpos=11
//TESH.alwaysfold=0
library IsUnitInSight requires Math

function IsUnitBehind takes unit attacker, unit target returns boolean
    local real face = GetUnitFacing(target)
    local real rangle = bj_RADTODEG*Atan2(GetUnitY(attacker)-GetUnitY(target),GetUnitX(attacker)-GetUnitX(target))
   // debug call BJDebugMsg( "T Facing: " + R2S(face) + " Rangle: " + R2S(rangle) + " Rabs(face-rangle)+ " + R2S(RAbs(face-rangle)) + " Rabs(face-angle-360): "+R2S(RAbs(face-rangle-360))  )
    return RAbs(face-rangle) > BACKSTAB_ANGLE and RAbs(face-rangle-360) > BACKSTAB_ANGLE
endfunction

function IsUnitInSightOfUnit takes unit observer, unit target, real fov returns boolean
    local real face = GetUnitFacing(observer)
    local real angle = bj_RADTODEG*Atan2(GetUnitY(observer)-GetUnitY(target), GetUnitX(observer)-GetUnitX(target))
    local real r1 = face-angle
    local real r2 = r1-360
   
    // we do not want to use the RabsBJ function so we do a manual conversion here
    if r1 < 0 then  
        set r1 = -r1
    endif
    if r2 < 0 then
        set r2 = -r2
    endif
   
    return r1 > FIELD_OF_VIEW and r2 > FIELD_OF_VIEW
endfunction

function IsUnitInSight takes unit observer, unit target returns boolean
    local real face = GetUnitFacing(observer)
    local real angle = bj_RADTODEG*Atan2(GetUnitY(observer)-GetUnitY(target), GetUnitX(observer)-GetUnitX(target))
    local real r1 = face-angle
    local real r2 = r1-360
   
    if r1 < 0 then
        set r1 = -r1
    endif
    if r2 < 0 then
        set r2 = -r2
    endif
   
    return r1 > FIELD_OF_VIEW and r2 > FIELD_OF_VIEW
endfunction

endlibrary
//TESH.scrollpos=93
//TESH.alwaysfold=0
library CastBar requires TimerUtils
/**************************************************************
*
*   CastBar v1.0.0    A a simplified version of TriggerHappy's ProgressBar by MoCo
*
*   This library allows you to easily use cast bars.
*   Technically, it works by creating a dummy unit with a special model and changing
*   the animation speed to increase or reduce the bar speed.
*
*   Just create a new CastBar struct, set it up as you like and assign the target unit once (the bar is displayed over this unit).
*   Then just start the cast bar by calling bar.startCastBar(real duration) and the bar fills over the duration.
*   After the bar has done it's job, it's automatically hidden.
*
*
*   Options:
*       x            - set X coordinate
*       y            - set Y coordinate
*       xOffset      - offset of the target unit, if any.
*       yOffset      - offset of the target unit, if any.
*       zOffset      - how high the bar is from the ground.
*       color        - allows you to tint the bar or add transparency
*       target       - pick which unit the bar should hover over
*       size         - set model scale
*
*   Usage:
*       local CastBar bar     = CastBar.create()
*       set bar.zOffset       = 150
*       set bar.color         = PLAYER_COLOR_RED
*       set bar.targetUnit    = CreateUnit(Player(0), 'hfoo', 0, 0, 0)
*
*       call bar.startCastBar(real duration)
*
*   Installation:
*       1. Copy the dummy unit over to your map
*       2. Change the DUMMY constant to fit the Raw code of the dummy.
*       3. Copy this and all required libraries over to your map.
*
*   Thanks to JesusHipster for the Progress Bar models
*   and to Vexorian for TimerUtils
*
**************************************************************/


    globals
        private constant integer PROGRESS_BAR_DUMMY     = 'e001' // the default one
        private constant player  PROGRESS_BAR_OWNER     = Player(PLAYER_NEUTRAL_PASSIVE) // owner of the dummy
    endglobals
   
    struct CastBar
   
        unit bar
        unit target
       
        real xOffset = 0
        real yOffset = 0
        boolean active = false
       
        timer t = null
       
        method operator x= takes real x returns nothing
            call SetUnitX(this.bar, x)
        endmethod
       
        method operator x takes nothing returns real
            return GetUnitX(this.bar)
        endmethod
       
        method operator y= takes real y returns nothing
            call SetUnitY(this.bar, y)
        endmethod
       
        method operator y takes nothing returns real
            return GetUnitY(this.bar)
        endmethod
       
        method operator zOffset= takes real offset returns nothing
            call SetUnitFlyHeight(this.bar, offset, 0)
        endmethod
       
        method operator zOffset takes nothing returns real
            return GetUnitFlyHeight(this.bar)
        endmethod
       
        method operator size= takes real size returns nothing
            call SetUnitScale(this.bar, size, size, size)
        endmethod
       
        method operator color= takes playercolor color returns nothing
            call SetUnitColor(this.bar, color)
        endmethod
       
        method show takes boolean flag returns nothing
            call UnitRemoveAbility(this.bar, 'Aloc')
            call ShowUnit(this.bar, flag)
            call UnitAddAbility(this.bar, 'Aloc')
        endmethod
       
        method RGB takes integer red, integer green, integer blue, integer alpha returns nothing
            call SetUnitVertexColor(this.bar, red, green, blue, alpha)
        endmethod
       
        method destroy takes nothing returns nothing
           
            if this.bar != null then
                call RemoveUnit(this.bar)
            endif
           
            set this.bar        = null
            set this.target     = null
           
            set this.xOffset = 0
            set this.yOffset = 0
            set this.active = false
           
            if (this.t != null) then
                call ReleaseTimer(this.t)
                set this.t = null
            endif
           
     //       call this.deallocate() // the line of code that you NEED for any deconstructor
           
        endmethod
       
        static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
           
            set this.bar        = CreateUnit(PROGRESS_BAR_OWNER, PROGRESS_BAR_DUMMY, 0, 0, 0)
           
            call SetUnitAnimationByIndex(this.bar, 1)
            call SetUnitTimeScale(this.bar, 0)
            return this
        endmethod
       
        private static method releaseBar takes nothing returns nothing
            local thistype this = GetTimerData(GetExpiredTimer())
            call ReleaseTimer(GetExpiredTimer())
            set this.t = null
            set this.active = false
            call this.show(false)
        endmethod
       
        method startCastBar takes real duration returns nothing
            local real timeScale = 1.0 / duration
           
            if (this.target != null) and not this.active then
               
                set this.active = true
               
                set this.t = NewTimer()
                call SetTimerData(this.t, this)
                call TimerStart(this.t, duration, false, function thistype.releaseBar)
               
                call SetUnitX(this.bar, GetUnitX(this.target) - xOffset)
                call SetUnitY(this.bar, GetUnitY(this.target) - yOffset)
           
                call this.show(true)
           
                call SetUnitAnimationByIndex(this.bar, 1)
                call SetUnitTimeScale(this.bar, timeScale)
           
            endif
           
        endmethod
       
    endstruct
   
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library IsSomethingInBetween requires PathingType

globals
    private constant integer STEPS = 12      // A lower value means better performance but lower accuracy
                                             // Should be set depending on the distances needed
endglobals

function WallInBetween takes real uX, real uY, real tX, real tY returns boolean
    local real IncX = (tX-uX)/STEPS
    local real IncY = (tY-uY)/STEPS
    local real x = uX
    local real y = uY
    local integer i = 0
    local boolean wallCheck = false
   
    loop
        exitwhen i > STEPS or wallCheck
        if IsTerrainWalkable(x,y) == false then
            set wallCheck = true
        endif
        set x = x + IncX
        set y = y + IncY
        set i = i + 1
    endloop

    return wallCheck
endfunction

endlibrary
//TESH.scrollpos=36
//TESH.alwaysfold=0
library SaveInventory initializer Init

globals
    constant integer SAFE_SYSTEM_SAFE = 'h007'
    private constant real SAFE_SPOT_X = -7360
    private constant real SAFE_SPOT_Y = -7647
    private unit array Safes[1]
    private boolean array SafesFilled[1]
endglobals


function SaveInventory takes unit hero returns nothing
    local integer slot = 0
    local item thisItem
    local integer playerId = GetPlayerId(GetOwningPlayer(hero))
   
    if SafesFilled[playerId] then
        debug call BJDebugMsg("SaveInventory System Error: two inventories saved for one player at a time!")
    else
        set SafesFilled[playerId] = true
   
        // save items in hero inventory
        loop
            exitwhen slot > 5
            set thisItem = UnitItemInSlot(hero, slot)
            if thisItem != null then
                call UnitRemoveItem(hero, thisItem)
                call UnitAddItem(Safes[playerId], thisItem)
            endif
            set slot = slot + 1
        endloop
   
    endif
    set thisItem = null
endfunction

function LoadInventory takes unit hero returns nothing
    local integer slot = 0
    local item thisItem
    local integer playerId = GetPlayerId(GetOwningPlayer(hero))
   
    if SafesFilled[playerId] then

        loop
            exitwhen slot > 5
            set thisItem = UnitItemInSlot(Safes[playerId], slot)
            if thisItem != null then
                call UnitRemoveItem(Safes[playerId], thisItem)
                call UnitAddItem(hero, thisItem)
            endif
            set slot = slot + 1
        endloop
       
        set SafesFilled[playerId] = false
    else
         debug call BJDebugMsg("SaveInventory System Error: Unable to load saved inventory!")
    endif

    set thisItem = null
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local integer i = 0
   
    loop
        exitwhen i > 11
        set Safes[i] = CreateUnit(Player(i), SAFE_SYSTEM_SAFE, SAFE_SPOT_X, SAFE_SPOT_Y, bj_UNIT_FACING)
        set SafesFilled[i] = false
        set i = i + 1
    endloop
   
    // debug call BJDebugMsg("SaveInventory System initialized!")
   
endfunction

endlibrary
 
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals

    // Map information
    constant string TITLE               = "|cff9577F8THE SHADOW OVER BLACKWOOD"
    constant string VERSION             = "1.01"
    constant string VERSION_TEXT        = "|cffFFB06Av"+VERSION+" (BETA)|r"
    constant string AUTHOR              = "|cff616161by MoCo|r"
    constant string SCORE_TITLE         = "|c009999ffS|c009693ffh|c00938effa|c009189ffd|c008e84ffo|c008c7fffw |c008775ffo|c008470ffv|c00826bffe|c007f66ffr |c007a5bffB|c007756ffl|c007551ffa|c00724cffc|c007047ffk|c006d42ffw|c006b3dffo|c006838ffo|c006633ffd|r "+VERSION_TEXT
    constant boolean SCREENSHOT_MODE    = false      // only affects DEBUG
   
    // Debugging options
    constant boolean FULL_VISION        = false   // default: false
    constant boolean NO_SHOUTS          = false   // default: false
    constant boolean STATE_TESTER       = false   // default: false
    constant boolean SHOW_WAYPOINTS     = false   // default: false
    constant boolean MAX_GUARDS         = false   // default: false  |  If set to true, the map uses all available guards (default: false)
    constant boolean FORCE_TEST_SPAWN   = false   // default: false
    constant integer TEST_SPAWN         = 2
    constant integer START_SKILL_POINTS = 1
   
    // Time scale
    constant real TIME_SCALE            = 0.10      // 1 game hour is 20 real time seconds by default;
                                                    // a game goes from 21:00 til 6:00 = 9 game hours = 180 real time seconds (3 minutes).
                                                    // We want about 30 minutes, so let's use a scale of 0.10
   
    // Game preferences    
    constant real CAMERA_ZOFFSET = 200 // Z offset of game camera   (TDMS: -130)
    constant real CAMERA_ANGLE_OF_ATTACK = 290  // normal game cam: 304   (TDMS: 296)
 
     // Tags
    constant string DEBUG     = "|cffEA34DFDebug-Info:|r "
    constant string INFO      = "|cffFFC786Info:|r "
    constant string EVENT     = "|cffF7A647Game Info:|r "
    constant string HINT      = "|cff34A3EAHint:|r "
    constant string GET_READY = "|cffFE2A2AGet Ready!|r "
    constant string ERROR     = "|cffF63B3BError:|r "
    constant string SHADOW_C1 = "|cff726BB1Voice from the Shadows:|r"
    constant string SOUL_STRING = "|cffC2A0F6+1 soul|r"
    constant string RELOAD_STRING = "|cffFFE2AAreloading..|r"
    constant string BAR_COLOR_DARK = "2B2B2B"
    constant string BAR_COLOR_BLUE = "3091FF"
    constant string PROBLEM_COLOR = "D45151"
    constant string WARNING_COLOR = "FFD98F"
    constant real TAG_SIZE         = 0.02 // // 0.0184
    constant real CRIT_TAG_SIZE    = 0.03
    constant integer HOLD_POSITION = 851993
   
    constant integer PLAYER_VAMPIRES_START_ID = 0       // First vampire player slot
    constant integer PLAYER_VAMPIRES_END_ID   = 5       // Last vampire player slot
    constant integer PLAYER_HUNTERS_START_ID  = 6       // First hunter player slot
    constant integer PLAYER_HUNTERS_END_ID    = 8       // Last hunter player slot
   
  //  constant integer VAMPIRE_BOUNTY = 150
   
    constant real VAMPIRE_RESPAWN_TIME = 20     // Vampires spawn pretty fast
    constant real HUNTER_RESPAWN_TIME  = 20     // Hunters as well
   
    constant real FAST_TRANSFORM_FACTOR = 0.65  // Time factor for fast transform ability
   
    constant integer VAMPIRE_OVERLORD_LEVEL = 8     // Level at which overlord form is given
   
    constant real VAMPIRE_LEVEL_SIZE_SCALE_INC = 0.04     // Vampires grow slightly bigger in size with higher levels
 
    // Vampire UnitType IDs
    constant integer VAMPIRE  = 'U000'                  
    constant integer RAT      = 'U002'
    constant integer WOLF     = 'U001'
    constant integer BAT      = 'U003'
    constant integer GHOST    = 'U005'
    constant integer OVERLORD = 'U006'
    constant integer VAMPIRE_VILLAGER = 'U005'
   
    constant integer SPAWN    = 'u004'
    constant integer ZOMBIE   = 'n00I'
   
    constant integer GHOST_MERCHANT = 'u008'
   
    // Townsfolk and hunters
    constant integer VILLAGER1    = 'n00J'
    constant integer VILLAGER2    = 'n00K'
    constant integer VILLAGER3    = 'n00L'
   
    constant integer GUARD        = 'n000'
    constant integer ARCHER       = 'e000'
    constant integer ARCHER_TOWER = 'e002'
    constant integer PRIEST       = 'n001'
    constant integer INQUISITOR   = 'h000'
   
    constant integer GUNSLINGER   = 'H002'
    constant integer ASSASSIN     = 'H003'
    constant integer MAGE         = 'H004'
    constant integer FIRE_MAGE    = 'H008'
    constant integer FROST_MAGE   = 'H009'
   
    constant integer CITY_RAT = 'n002'
   
   
    // Animals
    constant integer RABBIT     = 'necr'
    constant integer CHICKEN    = 'nech'
    constant integer RACOON     = 'nrac'
    constant integer PIG        = 'npig'
    constant integer SHEEP      = 'nshe'
    constant integer DEER       = 'nder'
    constant integer WILD_WOLF  = 'n008'
    constant integer GIANT_WOLF = 'n00G'
    constant integer BEAR       = 'n007'
   
    // Animal spawn chances
    constant real RABBIT_WEIGHT = 1.00
    constant real RACOON_WEIGHT = 1.00
    constant real DEER_WEIGHT   = 0.30
    constant real WOLF_WEIGHT   = 0.25
    constant real BEAR_WEIGHT   = 0.05
   
    constant real BOUNTY_AREA = 250
    constant integer BOUNTY_VAMPIRE = 500       // Base bounty given for vampire kill
    constant integer BOUNTY_VAMPIRE_LEVEL_BONUS = 25        // Level bonus
    constant integer BOUNTY_SPAWN   = 100
    constant integer BOUNTY_ZOMBIE  =  30
    constant integer CRATE_GOLD     = 100
    constant integer HUNTER_START_GOLD = 150
   
    constant real FIELD_OF_VIEW              = 115.00  // Real FoV is: 180 - 2x (FIELD_OF_VIEW-90)
    constant real BACKSTAB_ANGLE             = 120.00
    constant real VILLAGER_SIGHT_RANGE       = 480.00  // 420
    constant real START_TALKING_RANGE        = 110.00
    constant real GUARD_GIVEUP_CHASING_RANGE = 600.00
    constant real GUARD_ALERT_RANGE          = 512.00
    constant real GUARD_RAT_SMASH_RANGE      = 100.00

    constant real BAR_Z_OFFSET               = 150
    constant real BAR_TAG_Z_OFFSET           = 170
   
    constant integer MAX_BLOOD               = 100
    constant integer MAX_BLOOD_VILLAGER      = 100
   
    constant integer MAX_BLOOD_DEER          = 100
    constant integer MAX_BLOOD_RABBIT        = 30
    constant integer MAX_BLOOD_CHICKEN       = 30
    constant integer MAX_BLOOD_RACOON        = 40
    constant integer MAX_BLOOD_PIG           = 60
    constant integer MAX_BLOOD_SHEEP         = 50
   
    constant integer BLOOD_SUCK_DRAIN_AMOUNT = 5
    constant integer SUCK_BLOOD_XP_GAIN      = 10
    constant real BLOOD_SUCK_LIFE_FACTOR     = 0.048
    constant integer SUCKED_TO_DEATH_BLOOD   = 15
       
    constant integer MAX_SHOTS_GUNSLINGER    = 12
    constant integer MAX_SHOTS_ASSASSIN      = 1
   
    constant real BASE_RELOAD_TIME_GUNSLINGER = 2.5
    constant real FAST_RELOAD_1_GUNSLINGER    = 2.0
    constant real FAST_RELOAD_2_GUNSLINGER    = 1.5
    constant real FAST_RELOAD_3_GUNSLINGER    = 1.0
    constant real FAST_RELOAD_4_GUNSLINGER    = 0.5
   
    constant real BASE_RELOAD_TIME_ASSASSIN   = 1.25
   
    constant real INVESTIGATION_AREA     = 64  
    constant integer INVESTIGATION_TICKS = 5
   
    constant integer MAX_CIVILIANS   = 30
    constant integer START_CIVILIANS = 30   // How many villagers to spawn at game start
   
    constant real GUARD_STAYPUT_COUNT_FACTOR = 0.6  // Percentage of all pre-placed guards to use in the game
   
    constant integer MAX_PATROL_GUARDS_COUNT = 30     // Number of guards patrolling on the streets
    constant real    ESCORT_CHANCE       = 25     // chance that a patrolling guard is escorted by another guard
   
    constant real PARK_VISIT_CHANCE      = 20  //
    constant real TORCH_CHANCE           = 30  // Generic chance that a WP user has a torch
    constant real CITY_VILLAGER_USES_WP_CHANCE = 40 // Chance that a city spawned villager uses Waypoints instead of just wandering
   
    constant real SPAWN_WEIGHT_CITY         = 0.70
    constant real SPAWN_WEIGHT_FOREST_NORTH = 0.30
    constant real SPAWN_WEIGHT_FOREST_SOUTH = 0.20
    constant real SPAWN_WEIGHT_FOREST_WEST  = 0.25
   
    constant real CRATE_USE_FACTOR = 0.5
    constant real WINE_USE_FACTOR = 0.5
   
    constant real ANIMAL_AREA_1_WEIGHT      = 1.05
    constant real ANIMAL_AREA_2_WEIGHT      = 0.90
    constant real ANIMAL_AREA_3_WEIGHT      = 1.00
    constant real ANIMAL_AREA_4_WEIGHT      = 1.00
    constant real ANIMAL_AREA_5_WEIGHT      = 0.20
   
    constant real ANIMAL_MAX_COUNT = 30
    constant real SPIDER_COUNT = 30
   
    constant real VAMPIRE_TRACKER_INTERVAL = 5.0
    constant real VAMPIRE_TRACKER_DISTANCE = 3200. // 4096.
   
    constant real SIXTH_SENSE_INTERVAL = 3.0
    constant real SIXTH_SENSE_DISTANCE = 1500
   
    constant integer LOOKOUT_START_TICKS_MIN = 15   // Min. ticks elapsed in state before starting wondering
    constant integer LOOKOUT_START_TICKS_MAX = 50   // Max. ticks elapsed in state before starting wondering
   
    constant integer LOOKOUT_TICKS_MIN = 4           // End of lookout state min ticks
    constant integer LOOKOUT_TICKS_MAX = 12          // End of lookout state max ticks
   
    constant integer LOOKOUT_INVESTIGATE_TICKS_MIN = 8   // End of lookout state (investigation) min ticks
    constant integer LOOKOUT_INVESTIGATE_TICKS_MAX = 14  // End of lookout state (investigation) max ticks
   
    constant integer LOOKOUT_TIME_TICKS_MIN = 4      // 1 sec   Min. ticks after a new lookout action is performed
    constant integer LOOKOUT_TIME_TICKS_MAX = 8      // 2.5 sec Max. ticks after a new lookout action is performed
   

    constant real WONDERING_REFRESH = 1.5
   
    constant integer INVESTIGATION_TICKS_MIN = 5
    constant integer INVESTIGATION_TICKS_MAX = 10
   
    constant integer TRANSFORMATION_TICKS_MIN = 15
    constant integer TRANSFORMATION_TICKS_MAX = 60
   

    constant real AI_REFRESH_INTERVAL         = 0.5
    constant real STATE_TESTER_REFRESH        = 1.0
    constant real SHOUT_PERIOD                = 1.2
    constant real TALKING_PERIOD              = 1.2
    constant real TALKING_CHANCE              = 50
    constant integer TALKING_COUNT_MIN        = 7
    constant integer TALKING_COUNT_MAX        = 15
    constant integer CALMING_DOWN_TICKS       = 14  // After villagers were set in panic
    constant integer CALMING_DOWN_TICKS_GUARD = 10  // After a guard was chasing a monster
    constant integer MAX_CHASING_TICKS        = 50
   
    constant integer SHADOW_PLAYER_ID         = 9
   
   
    constant real CIVILIAN_MOVE_SPEED_NORMAL  = 50
    constant real CIVILIAN_MOVE_SPEED_PANIC   = 290
    constant real GUARD_MOVE_SPEED_PATROL     = 70
    constant real GUARD_MOVE_SPEED_NORMAL     = 240
    constant real VILLAGER_MOVE_SPEED_FEAR    = 250
   
    constant real INQUISITOR_MOVE_SPEED       = 350  
   
    // AI states
    constant integer VILLAGER_STATE_UNDEFINED         = 0
    constant integer VILLAGER_STATE_DEFAULT           = 1
    constant integer VILLAGER_STATE_STAND             = 2
    constant integer VILLAGER_STATE_WANDERING         = 3
    constant integer VILLAGER_STATE_TALKING           = 4
    constant integer VILLAGER_STATE_PANIC             = 5
    constant integer VILLAGER_STATE_LOOKOUT           = 6
    constant integer VILLAGER_STATE_ON_WAYPOINTS      = 7
    constant integer VILLAGER_STATE_PARALYZED         = 8
    constant integer VILLAGER_STATE_TRANSFORMING      = 9
    constant integer VILLAGER_STATE_SLEEP             = 10
    constant integer VILLAGER_STATE_FEAR              = 11
    constant integer VILLAGER_STATE_WORK              = 12
    constant integer VILLAGER_STATE_DEAD              = 13

    // Guard state
    constant integer VILLAGER_STATE_GUARD_HOLDGROUND  = 14
    constant integer VILLAGER_STATE_GUARD_PATROL      = 15
    constant integer VILLAGER_STATE_GUARD_ESCORT      = 16
    constant integer VILLAGER_STATE_GUARD_INVESTIGATE = 17
    constant integer VILLAGER_STATE_GUARD_ATTACK      = 18
   
    constant real GENERIC_AOE_RANGE = 400.00
    constant real GENERIC_DOT_INTERVAL = 1.0
   
    constant integer ODER_STOP = 851972
   
    constant real HOME_PUFFER = 32
    constant real SEEN_PUFFER = 32
    constant real FACING_BUFFER = 1.
   
    constant integer ORDER_ATTACK = 851983

    intpool AnimalAreaPool
    rect array AnimalAreas[1]
   
    integer array IngredientInfoAbilities[1]
   
    // Strings
    // ==================================================================================
   
    // String arrays
    string array SPELL_NAMES[1]
    string array StateNames[1]
   
    // Villager colors (for comments etc)
    string array VillagerColors[1]
    integer VillagerColorCount = 0
   
    // PlayerColors
    string array PlayerColors[1]
    string array PlayerNames[1]
   
    // Civilian panic souhts (vampire)
    string array PanicShouts[1]
    integer PanicShoutsCount = 0
   
    // Civilian panic shouts (wolf)
    string array PanicShoutsWolf[1]
    integer PanicShoutsWolfCount = 0
   
    // Civilian Lookout comments
    string array LookoutComments[1]
    integer LookoutCommentsCount = 0
   
    // Guard reach Investigation area comments
    string array InvestigationAreaComments[1]
    integer InvestigationAreaCommentsCount = 0
   
    // Guard lookout comments
    string array LookoutCommentsGuards[1]
    integer LookoutCommentsGuardsCount = 0
   
    // Guard stop chasing comments
    string array StopChasingComments[1]
    integer StopChasingCommentsCount = 0
   
    // WTF shouts
    string array WTFShouts[1]
    integer WTFShoutsCount = 0
   
        string array RatShouts[1]
    integer RatShoutsCount = 0
   
    // Guard attack comments
    string array AttackShouts[1]
    integer AttackShoutsCount = 0
   
    // Guard kills comments
    string array GuardKillsComments[1]
    integer GuardKillsCommentsCount = 0
   
    // Vampire escapes comments
    string array EscapeComments[1]
    integer EscapeCommentsCount = 0
   
    // Death Messages (Shadow)
    string array ShadowDeathMessages[1]
    integer ShadowDeathMessageCount = 0

    // Revive Messages (Shadow)
    string array ShadowReviveMessages[1]
    integer ShadowReviveMessageCount = 0
   
    Table HandleIdTable
    integer array Waypoints[1]
   
    rect array Homes[1]
    integer HOME_COUNT = 0
   
   
    unit BehindTesterAttacker
   
    // Counters
    integer VillagerCount = 0
    integer CivilianCount = 0
    integer GuardCount = 0
    integer GuardCountPatrol = 0
    integer GuardCountStayput = 0
   
    integer AnimalCount = 0
   
    // Debugging stuff
    integer HEAVY_CALC_COUNT = 0
    unit testUnit = null
    unit TEST_VAMPIRE = null
   
    // Used for core function (villager notices threat)
    group targetGroup = null
   
   
    force ForceHunters = null
    force ForceVampires = null
       
    integer array HeroStructIdByPlayer[1]
    unit array HeroByPlayer[1]
   
    // Score System
    multiboard Score_Table = null // Don't use "= CreateMultiboard()"! here else the game will crash
    integer array ScoreBoard_Positions[1]
    timer GameTime
    integer GameTime_Minutes
    integer GameTime_Seconds
    integer array Score_Kills[1]
    integer array Score_PvP[1]
    integer array Score_Deaths[1]
    integer array Score_Levels[1]
    real array Score_Damage[1]
    real array Score_Healing[1]
    integer ClockRow
   
    integer VampirePlayerCount = 0
    integer HunterPlayerCount = 0
    integer PlayerCount = 0
   
    timer array ReviveTimers[1]
    timerdialog array ReviveTimerWindows[1]
    boolean OverlordOnMap = false
   
    integer OverlordPlayer = 0
   
endglobals
 
//TESH.scrollpos=100
//TESH.alwaysfold=0
library MapInitialization initializer Init requires TimerUtils

globals

endglobals


public function Init_Game takes nothing returns nothing
   
    if DEBUG_MODE and FULL_VISION then
        set bj_lastCreatedFogModifier = CreateFogModifierRect(Player(0), FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea, true, false)
        call FogModifierStart(bj_lastCreatedFogModifier)
    endif
   
    set targetGroup = CreateGroup()
   
    call EnablePreSelect( true, false )
    call SetFloatGameState(GAME_STATE_TIME_OF_DAY, 21.00 )
    call SetTimeOfDayScale(TIME_SCALE)
  //  call SuspendTimeOfDay(true)
   
    // Computer must see all in order for AI scripts to work properly!
    set bj_lastCreatedFogModifier = CreateFogModifierRect(Player(11), FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea, true, false)
    call FogModifierStart(bj_lastCreatedFogModifier)  

    // Lock Minimap
    call EnableMinimapFilterButtons( false, false )
    call SetAllyColorFilterState( 0 )
    call SetCreepCampFilterState( false )
   
    // Vampire spawn player
    call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(0), bj_ALLIANCE_ALLIED )
    call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(1), bj_ALLIANCE_ALLIED )
    call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(2), bj_ALLIANCE_ALLIED )
    call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(3), bj_ALLIANCE_ALLIED )
    call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(4), bj_ALLIANCE_ALLIED )
    call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(5), bj_ALLIANCE_ALLIED )
   
    call SetPlayerAllianceStateBJ( Player(0), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
    call SetPlayerAllianceStateBJ( Player(1), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
    call SetPlayerAllianceStateBJ( Player(2), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
    call SetPlayerAllianceStateBJ( Player(3), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
    call SetPlayerAllianceStateBJ( Player(4), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
    call SetPlayerAllianceStateBJ( Player(5), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
   
    set AnimalAreas[0] = null
    set AnimalAreas[1] = gg_rct_AnimalArea1
    set AnimalAreas[2] = gg_rct_AnimalArea2
    set AnimalAreas[3] = gg_rct_AnimalArea3
    set AnimalAreas[4] = gg_rct_AnimalArea4
    set AnimalAreas[5] = gg_rct_AnimalArea5
   
    set AnimalAreaPool = intpool.create()
    call AnimalAreaPool.addInt(1, ANIMAL_AREA_1_WEIGHT)  // Animal area 1
    call AnimalAreaPool.addInt(2, ANIMAL_AREA_2_WEIGHT)  // Animal area 2
    call AnimalAreaPool.addInt(3, ANIMAL_AREA_3_WEIGHT)  // Animal area 3
    call AnimalAreaPool.addInt(4, ANIMAL_AREA_4_WEIGHT)  // Animal area 4
    call AnimalAreaPool.addInt(5, ANIMAL_AREA_5_WEIGHT)  // Animal area 5
   
 //   call RemoveAllGuardPositions( Player(11) )
 
endfunction

private function InitVillagerColors takes nothing returns nothing

        // Villager colors
    set VillagerColors[0] = "CCB9A7"
    set VillagerColors[1] = "8F8880"
    set VillagerColors[2] = "857361"
    set VillagerColors[3] = "76706B"
    set VillagerColors[4] = "928E8A"
    set VillagerColors[5] = "CFBAA6"
    set VillagerColors[6] = "625950"
    set VillagerColors[7] = "87817B"
    set VillagerColors[8] = "B79B80"
    set VillagerColors[9] = "5C5853"
    set VillagerColors[10] = "7A6856"
    set VillagerColors[11] = "998068"
    set VillagerColors[12] = "BFAF9F"
    set VillagerColors[13] = "C8C1BA"
    set VillagerColors[14] = "AD8F72"
    set VillagerColors[15] = "E4C8AD"
    set VillagerColors[16] = "DAC1A9"
    set VillagerColors[17] = "969491"
    set VillagerColors[18] = "C4B19F"
    set VillagerColors[19] = "7D6B5A"
    set VillagerColors[20] = "595550"
    set VillagerColorCount = 21
   
    // Init Colors
    set PlayerColors[0] = "FF0202"
    set PlayerColors[1] = "0041FF"
    set PlayerColors[2] = "1BE5B8"
    set PlayerColors[3] = "530080"
    set PlayerColors[4] = "FFFC00"
    set PlayerColors[5] = "FE890D"
    set PlayerColors[6] = "1FBF00"
    set PlayerColors[7] = "E45AAF"
    set PlayerColors[8] = "949596"
    set PlayerColors[9] = "7DBEF1"
    set PlayerColors[10] = "0F6145"
    set PlayerColors[11] = "4D2903"
    set PlayerColors[GetPlayerId(Player(PLAYER_NEUTRAL_AGGRESSIVE))] = "DA4949"
    set PlayerColors[GetPlayerId(Player(bj_PLAYER_NEUTRAL_VICTIM))] = "B6B6B6"
    set PlayerColors[GetPlayerId(Player(bj_PLAYER_NEUTRAL_EXTRA))] = "B6B6B6"
    set PlayerColors[GetPlayerId(Player(PLAYER_NEUTRAL_PASSIVE))] = "94D598"
   
    // Player Names
    set PlayerNames[0] = "|cff" + PlayerColors[0] + GetPlayerName(Player(0)) + "|r"
    set PlayerNames[1] = "|cff" + PlayerColors[1] + GetPlayerName(Player(1)) + "|r"
    set PlayerNames[2] = "|cff" + PlayerColors[2] + GetPlayerName(Player(2)) + "|r"
    set PlayerNames[3] = "|cff" + PlayerColors[3] + GetPlayerName(Player(3)) + "|r"
    set PlayerNames[4] = "|cff" + PlayerColors[4] + GetPlayerName(Player(4)) + "|r"
    set PlayerNames[5] = "|cff" + PlayerColors[5] + GetPlayerName(Player(5)) + "|r"
    set PlayerNames[6] = "|cff" + PlayerColors[6] + GetPlayerName(Player(6)) + "|r"
    set PlayerNames[7] = "|cff" + PlayerColors[7] + GetPlayerName(Player(7)) + "|r"
    set PlayerNames[8] = "|cff" + PlayerColors[8] + GetPlayerName(Player(8)) + "|r"
    set PlayerNames[9] = "|cff" + PlayerColors[9] + GetPlayerName(Player(9)) + "|r"
    set PlayerNames[10] = "|cff" + PlayerColors[10] + GetPlayerName(Player(10)) + "|r"
    set PlayerNames[11] = "|cff" + PlayerColors[11] + GetPlayerName(Player(11)) + "|r"
   
    set PlayerNames[GetPlayerId(Player(PLAYER_NEUTRAL_AGGRESSIVE))] = "|cff" + PlayerColors[10] + "NEUTRAL HOSTILE|r"
    set PlayerNames[GetPlayerId(Player(PLAYER_NEUTRAL_PASSIVE))] = "|cff" + PlayerColors[11] + "NEUTRAL PASSIVE|r"
   
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trg = CreateTrigger(  )
    call TriggerAddAction( trg, function Init_Game )
    call TriggerExecute(trg)
   
    set trg = CreateTrigger(  )
    call TriggerAddAction( trg, function InitVillagerColors )
    call TriggerExecute(trg)
    set trg = null
endfunction

endlibrary
 
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope InitStrings initializer Init

private function InitSomeStrings takes nothing returns nothing

    // State names
    set StateNames[VILLAGER_STATE_UNDEFINED] = "undef."
    set StateNames[VILLAGER_STATE_STAND] = "stand"
    set StateNames[VILLAGER_STATE_WANDERING] ="wander"
    set StateNames[VILLAGER_STATE_TALKING] = "talking"
    set StateNames[VILLAGER_STATE_PANIC] = "panic"
    set StateNames[VILLAGER_STATE_LOOKOUT] = "lookout"
    set StateNames[VILLAGER_STATE_ON_WAYPOINTS] = "waypoint"
    set StateNames[VILLAGER_STATE_PARALYZED] = "paralyzed"
    set StateNames[VILLAGER_STATE_TRANSFORMING] = "transforming"
    set StateNames[VILLAGER_STATE_WORK] = "working"
    set StateNames[VILLAGER_STATE_GUARD_HOLDGROUND] = "holdground"
    set StateNames[VILLAGER_STATE_GUARD_PATROL] = "patrol"
    set StateNames[VILLAGER_STATE_GUARD_ESCORT] = "escort"
    set StateNames[VILLAGER_STATE_GUARD_ATTACK] = "attack"
    set StateNames[VILLAGER_STATE_GUARD_INVESTIGATE] = "investigate"

    // Lookout comments
    set LookoutComments[0] = "Did I hear something?"
    set LookoutComments[1] = "This feels strange"
    set LookoutComments[2] = "Something moving in the shadows?"
    set LookoutComments[3] = "Someone moving?"
    set LookoutComments[4] = "Hello? Is there somebody?"
    set LookoutComments[5] = "This night gives me the creeps!"
    set LookoutComments[6] = "Could swear I've seen someone.."
    set LookoutComments[7] = "Is someone there?"  
    set LookoutComments[8] = "Night lasts forever.."
    set LookoutComments[9] = "Is it true what they say about those vampires?"
    set LookoutComments[10] = "What a frosty night!"
    set LookoutComments[11] = "I'm not feeling well.."
    set LookoutComments[12] = "This place scares me"
    set LookoutComments[13] = "Can't get any sleep tonight"
    set LookoutComments[14] = "What a dark night.."
    set LookoutComments[15] = "So much guards in the city.."
    set LookoutCommentsCount = 16
   
    // Guard Lookout comments
    set LookoutCommentsGuards[0] = "Did I hear something?"
    set LookoutCommentsGuards[1] = "They don't pay me enough for this!"
    set LookoutCommentsGuards[2] = "Something moving in the shadows?"
    set LookoutCommentsGuards[3] = "Someone moving?"
    set LookoutCommentsGuards[4] = "Hello? Is there anybody?"
    set LookoutCommentsGuards[5] = "This night gives me the creeps!"
    set LookoutCommentsGuards[6] = "Could swear I've seen something.."
    set LookoutCommentsGuards[7] = "Is someone there?"  
    set LookoutCommentsGuards[8] = "Night lasts forever.."
    set LookoutCommentsGuards[9] = "I don't believe in any vampires!"
    set LookoutCommentsGuards[10] = "What a frosty night"
    set LookoutCommentsGuards[11] = "I think I'm getting a cold out here"
    set LookoutCommentsGuards[12] = "What I'd give for coffee right now"
    set LookoutCommentsGuards[13] = "I think I'm gettin' rusty"
    set LookoutCommentsGuards[14] = "What a dark night"
    set LookoutCommentsGuards[15] = "I'm not afraid of any vampires!"
    set LookoutCommentsGuards[16] = "Better stay away from me!"
    set LookoutCommentsGuards[17] = "This job is damn boring!"
    set LookoutCommentsGuards[18] = "Wish I hadn't come here at all.."
    set LookoutCommentsGuards[19] = "Don't mess with me!"
    set LookoutCommentsGuardsCount = 20
   
    // Reach Investigation area comments
    set InvestigationAreaComments[0] = "So.. where it is?"
    set InvestigationAreaComments[1] = "Hmm.."
    set InvestigationAreaComments[2] = "Anyone here?"
    set InvestigationAreaComments[3] = "Something's wrong here?"
    set InvestigationAreaComments[4] = "Hello? Is there anybody?"
    set InvestigationAreaComments[5] = "Someone's here?!"
    set InvestigationAreaComments[6] = "So where is this monster?!"
    set InvestigationAreaComments[7] = "I cannot see anything.."
    set InvestigationAreaComments[8] = "Must be false alarm.."
    set InvestigationAreaComments[9] = "Must have some kind of hallucination.."
    set InvestigationAreaComments[10] = "Nothing's here"
    set InvestigationAreaComments[11] = "All clear over here"
    set InvestigationAreaCommentsCount = 12
   
    // Panic shouts
    set PanicShouts[0] = "HELP!"
    set PanicShouts[1] = "VAMPIRES!"
    set PanicShouts[2] = "HELP ME!"
    set PanicShouts[3] = "IT'S HUNTING ME!"
    set PanicShouts[4] = "A VAMPIRE!"
    set PanicShouts[5] = "I DON'T WANNA DIE!"
    set PanicShouts[6] = "OH NOOO!"
    set PanicShouts[7] = "GUARDS!"
    set PanicShouts[8] = "I'M BEING HUNTED!"
    set PanicShouts[9] = "THE VAMPIRES ARE COMING!"
    set PanicShouts[10] = "OH GOD NO!"
    set PanicShoutsCount = 11
   
    // Panic shouts wolf
    set PanicShoutsWolf[0] = "HELP!"
    set PanicShoutsWolf[1] = "A WOLF!"
    set PanicShoutsWolf[2] = "HELP ME!"
    set PanicShoutsWolf[3] = "IT'S HUNTING ME!"
    set PanicShoutsWolf[4] = "GET THE BEAST!"
    set PanicShoutsWolf[5] = "I DON'T WANNA DIE!"
    set PanicShoutsWolf[6] = "OH NOOO!"
    set PanicShoutsWolf[7] = "GUARDS!"
    set PanicShoutsWolf[8] = "I'M BEING HUNTED!"
    set PanicShoutsWolf[9] = "THE WOLVES ARE COMING!"
    set PanicShoutsWolf[10] = "OH GOD NO!"
    set PanicShoutsWolfCount = 11
   
    // WTF shouts
    set WTFShouts[0] = "What the.. ?!"
    set WTFShouts[1] = "What?!"
    set WTFShouts[2] = "WTF?!"
    set WTFShouts[3] = "Damn you!"
    set WTFShouts[4] = "Huh?!"
    set WTFShouts[5] = "...?!"
    set WTFShouts[6] = "!!!"
    set WTFShouts[7] = "Oh no!"
    set WTFShouts[8] = "Oh my.."
    set WTFShoutsCount = 9
   
    // Rat shouts
    set RatShouts[0] = "Damn rat!"
    set RatShouts[1] = "A rat!"
    set RatShouts[2] = "Hate those rats!"
    set RatShouts[3] = "Hate those beast !"
    set RatShouts[4] = "Die you dirty rat!"
    set RatShouts[5] = "Those damn rats are everywhere"
    set RatShouts[6] = "I squish you!"
    set RatShouts[7] = "I smash you!"
    set RatShoutsCount = 8
   
    // Attack shouts
    set AttackShouts[0] = "I WILL GET YOU!"
    set AttackShouts[1] = "HOLD ON YOU BASTARD!"
    set AttackShouts[2] = "YOU ARE DEAD!"
    set AttackShouts[3] = "I WILL KILL YOU!"
    set AttackShouts[4] = "IN THE NAME OF THE LORD!"
    set AttackShouts[5] = "EVIL FACE MY WEAPON EVIL!"
    set AttackShouts[6] = "YOU CAN RUN BUT YOU CAN'T HIDE!"
    set AttackShouts[7] = "YOU ARE NO MATCH FOR ME!"
    set AttackShoutsCount = 8
   
    // Stop chasing comments
    set StopChasingComments[0] = "Can't keep up any longer.."
    set StopChasingComments[1] = "Seems to be gone now"
    set StopChasingComments[2] = "Whatever it was - it's gone now"
    set StopChasingComments[3] = "Not worth my time"
    set StopChasingComments[4] = "Enough for me"
    set StopChasingComments[5] = "Yeah, run away!"
    set StopChasingComments[6] = "Stay away from now!"
    set StopChasingComments[7] = "And don't come back!"
    set StopChasingComments[8] = "I'm too old for this!"
    set StopChasingCommentsCount = 9
   
    // Stop chasing comments
    set GuardKillsComments[0] = "Got ya!"
    set GuardKillsComments[1] = "And stay down!"
    set GuardKillsComments[2] = "Face the dirt!"
    set GuardKillsComments[3] = "Got one!"
    set GuardKillsComments[4] = "Terminated!"
    set GuardKillsComments[5] = "One more!"
    set GuardKillsComments[6] = "Die!"
    set GuardKillsComments[7] = "Who's next?"
    set GuardKillsComments[8] = "Don't mess with me!"
    set GuardKillsComments[9] = "Die you bastard!"
    set GuardKillsComments[10] = "Die monster!"
    set GuardKillsCommentsCount = 11
   
    // Vampire escapes comments
    set EscapeComments[0] = "Damn! It escaped me!"
    set EscapeComments[1] = "And gone.."
    set EscapeComments[2] = "Damn! It get's away!"
    set EscapeComments[3] = "Yeah, fly away you coward!"
    set EscapeComments[4] = "I'll get you later!"
    set EscapeCommentsCount = 5
   
    // Shadow death messages
    set ShadowDeathMessages[0] = "Be more careful next time!"
    set ShadowDeathMessages[1] = "Revenge will be ours!"
    set ShadowDeathMessages[2] = "Do not be that risky next time!"
    set ShadowDeathMessages[3] = "You'll be back soon enough."
    set ShadowDeathMessages[4] = "Bad luck my friend.."
    set ShadowDeathMessages[5] = "While you regenerate, our enemies grow stronger!"
    set ShadowDeathMessages[6] = "Bad move."
    set ShadowDeathMessageCount = 7
   
    // Shadow revive messages
    set ShadowReviveMessages[0] = "You live again!"
    set ShadowReviveMessages[1] = "Go and smash our enemies!"
    set ShadowReviveMessages[2] = "Time for more blood my friend!"
    set ShadowReviveMessages[3] = "Do not dissapoint me again!"
    set ShadowReviveMessages[4] = "Time to fulfill our mission!"
    set ShadowReviveMessages[5] = "Time to bring darkness!"
    set ShadowReviveMessages[6] = "Our enemies fear your return!"
    set ShadowReviveMessageCount = 7
   
    call Debug_Message("Strings successfully initialized!")

endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trg = CreateTrigger(  )
    call TriggerAddAction( trg, function InitSomeStrings )
    call TriggerExecute(trg)
    set trg = null
endfunction

endscope

 
//TESH.scrollpos=267
//TESH.alwaysfold=0
library BasicFunctions requires TimerUtils, Math

globals
    private location TempLocation = null
endglobals

function Chance takes integer i returns boolean
    if GetRandomInt(0,100) <= i then
        return true
    endif
    return false
endfunction

function GameVictory takes integer startId, integer endId returns nothing
    local integer i
    set i = startId
    loop
        exitwhen i > endId
        call CustomVictoryBJ( Player(i), true, true )
        set i = i + 1
    endloop
endfunction

function GameDefeat takes integer startId, integer endId returns nothing
    local integer i
    set i = startId
    loop
        exitwhen i > endId
        call CustomDefeatBJ( Player(i), "TRIGSTR_2123" )
        set i = i + 1
    endloop
endfunction

function Blank_Message takes string text returns nothing
    call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, text )
endfunction

function Game_Message takes string text returns nothing
    call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, INFO + text )
endfunction

function Game_Message_Player takes integer player_id, string text returns nothing
    call DisplayTimedTextToPlayer( Player(player_id), 0, 0, 15.00, INFO + text )
endfunction

function Hint_Message takes string text returns nothing
    call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 10.00, HINT + text )
endfunction

function Error_Message takes integer player_id, string text returns nothing
    call DisplayTimedTextToPlayer( Player(player_id), 0, 0, 15.00, ERROR + text )
endfunction

function Problem_Message takes integer playerId, string text returns nothing
    call DisplayTimedTextToPlayer( Player(playerId), 0, 0, 15.00, "|cff"+PROBLEM_COLOR+text+"|r" )
endfunction

function Warning_Message takes integer playerId, string text returns nothing
    call DisplayTimedTextToPlayer( Player(playerId), 0, 0, 15.00, "|cff"+WARNING_COLOR+text+"|r" )
endfunction

function Debug_Message takes string text returns nothing
    if DEBUG_MODE and not SCREENSHOT_MODE then
        call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, DEBUG + text )
    endif
endfunction    

function Info_Message takes string text returns nothing
    call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, DEBUG + text )
endfunction  

function Vampire_Message takes player pl, string text returns nothing
    call DisplayTimedTextToPlayer( pl, 0, 0, 10.00, text )
endfunction

function IsVampire takes unit u returns boolean
    return GetUnitTypeId(u) == VAMPIRE
endfunction

function CanPickupIngredients takes unit u returns boolean
    return GetUnitTypeId(u) == VAMPIRE or GetUnitTypeId(u) == VAMPIRE_VILLAGER or GetUnitTypeId(u) == OVERLORD
endfunction

function IsWolf takes unit u returns boolean
    return GetUnitTypeId(u) == WOLF
endfunction

function IsHuman takes unit u returns boolean
    return GetPlayerRace( GetOwningPlayer(u) ) == RACE_HUMAN
endfunction

function IsCivilian takes unit u returns boolean
    return GetUnitTypeId(u) == VILLAGER1 or GetUnitTypeId(u) == VILLAGER2 or GetUnitTypeId(u) == VILLAGER3
endfunction

function IsGuard takes unit u returns boolean
    return GetUnitTypeId(u) == GUARD or GetUnitTypeId(u) == ARCHER or GetUnitTypeId(u) == PRIEST or GetUnitTypeId(u) == ARCHER_TOWER or GetUnitTypeId(u) == INQUISITOR
endfunction

function IsVillager takes unit u returns boolean
    return ( IsGuard(u) or IsCivilian(u) )
endfunction

function IsHunter takes unit u returns boolean
    return GetUnitTypeId(u) == GUNSLINGER or GetUnitTypeId(u) == ASSASSIN or GetUnitTypeId(u) == MAGE or GetUnitTypeId(u) == FROST_MAGE or GetUnitTypeId(u) == FIRE_MAGE// Frost mage etc.
endfunction

function IsUndead takes unit u returns boolean
    return IsUnitType(u, UNIT_TYPE_UNDEAD)
endfunction

function IsVampiricThreat takes unit u returns boolean
    return GetUnitTypeId(u) == VAMPIRE or GetUnitTypeId(u) == SPAWN or GetUnitTypeId(u) == OVERLORD
endfunction

function IsVampireAnimalForm takes unit u returns boolean
    return GetUnitTypeId(u) == RAT or GetUnitTypeId(u) == WOLF or GetUnitTypeId(u) == BAT
endfunction

function IsPlayerVampiric takes unit u returns boolean
    return GetUnitTypeId(u) == VAMPIRE or GetUnitTypeId(u) == RAT or GetUnitTypeId(u) == WOLF or GetUnitTypeId(u) == BAT or GetUnitTypeId(u) == OVERLORD or GetUnitTypeId(u) == VAMPIRE_VILLAGER
endfunction

function IsVampirePlayer takes unit u returns boolean
    return GetPlayerRace( GetOwningPlayer(u) ) == RACE_UNDEAD
endfunction

function IsBeast takes unit u returns boolean
    return GetUnitTypeId(u) == WOLF or GetUnitTypeId(u) == WILD_WOLF or GetUnitTypeId(u) == GIANT_WOLF or GetUnitTypeId(u) == BEAR
endfunction

function IsVampiricTypeId takes integer id returns boolean
    return id == VAMPIRE or id == SPAWN or id == OVERLORD
endfunction

function IsBeastTypeId takes integer id returns boolean
    return id == WOLF or id == WILD_WOLF or id == GIANT_WOLF or id == BEAR
endfunction

function IsThreat takes unit u returns boolean
    return IsUnitType(u, UNIT_TYPE_ANCIENT)
endfunction

function ShareVision takes unit u, integer idRangeBegin, integer idRangeEnd, boolean flag returns nothing
    local integer i = 0
    set i = idRangeBegin
    loop
        exitwhen i > idRangeEnd
        if i != GetPlayerId(GetOwningPlayer(u)) then
            call UnitShareVision(u, Player(i), flag)
        endif
        set i = i + 1
    endloop
endfunction

function Shadow_Message takes integer playerId, string text, boolean showAll returns nothing
    if showAll then
        call DisplayTimedTextToPlayer( Player(0), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
        call DisplayTimedTextToPlayer( Player(1), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
        call DisplayTimedTextToPlayer( Player(2), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
        call DisplayTimedTextToPlayer( Player(3), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
        call DisplayTimedTextToPlayer( Player(4), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
        call DisplayTimedTextToPlayer( Player(5), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
    else
        call DisplayTimedTextToPlayer( Player(playerId), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
    endif
endfunction

function CreateTagOnUnit takes unit TargetUnit, string Text returns nothing
  local integer id = GetPlayerId(GetOwningPlayer(TargetUnit))
  local texttag t = CreateTextTag()
 
  call SetTextTagText(t, Text, 0.0184)
  call SetTextTagPos(t, GetUnitX(TargetUnit), GetUnitY(TargetUnit), 0.00)
  call SetTextTagVelocity(t, 0, 0.03)
  call SetTextTagVisibility(t, true)
  call SetTextTagFadepoint(t, 3)
  call SetTextTagLifespan(t, 4)
  call SetTextTagPermanent(t, false)  
  set t = null
endfunction

function CreateDamageTag takes unit source, unit target, string s returns nothing
    local texttag t = CreateTextTag()
 
    call SetTextTagText(t, s, 0.0184)
    call SetTextTagColor(t, 200, 0, 30, 255)
    call SetTextTagPos(t, GetUnitX(target), GetUnitY(target), 0.00)
    call SetTextTagVelocity(t, 0, 0.03)
    call SetTextTagVisibility(t, false)
    call SetTextTagFadepoint(t, 3)
    call SetTextTagLifespan(t, 4)
    call SetTextTagPermanent(t, false)  
   
    if GetOwningPlayer(source) == GetLocalPlayer() then
        call SetTextTagVisibility(t, true)
    endif
   
    set t = null
endfunction

function UnitHasItemOfType takes unit whichUnit, integer itemId returns boolean
    local integer index
    local item indexItem = null
    local boolean found = false
    set index = 0
    loop
        set indexItem = UnitItemInSlot(whichUnit, index)
        if (indexItem != null) and (GetItemTypeId(indexItem) == itemId) then
            set found = true
        endif
        set index = index + 1
        exitwhen index >= bj_MAX_INVENTORY
    endloop
    set indexItem = null
    return found
endfunction

function UpdateScoreBoard takes integer playerId returns nothing
    local multiboarditem field
    local integer row
   
   // call Debug_Message("Update Scoreboard")
   
    if playerId <= 8 then
   
        set row = ScoreBoard_Positions[playerId]
       
        // Name
        set field = MultiboardGetItem(Score_Table, row, 0)
        call MultiboardSetItemValue( field, "  " + PlayerNames[playerId] )
       
        // Kills
        set field = MultiboardGetItem(Score_Table, row, 1)
        call MultiboardSetItemValue( field, " " + I2S(Score_Kills[playerId]) )
       
        // PvP
        set field = MultiboardGetItem(Score_Table, row, 2)
        call MultiboardSetItemValue( field, " " + I2S(Score_PvP[playerId]) )
       
        // Level
        set field = MultiboardGetItem(Score_Table, row, 3)
        call MultiboardSetItemValue( field, " " + I2S(GetHeroLevel(HeroByPlayer[playerId])) )

        // Deaths
        set field = MultiboardGetItem(Score_Table, row, 4)
        call MultiboardSetItemValue( field, " " + I2S(Score_Deaths[playerId]) )
       
    endif
   
    set field = null
   
endfunction

private function InitVillagerCountFields takes nothing returns nothing
    local multiboarditem field = null

    set field =  MultiboardGetItem(Score_Table, ClockRow, 2)
    call MultiboardSetItemStyle( field, true, false )
    call MultiboardSetItemValueColor( field, 100, 100, 100, 255 )
    call MultiboardSetItemValue( field, "0" )
   
    set field =  MultiboardGetItem(Score_Table, ClockRow, 3)
    call MultiboardSetItemStyle( field, true, false )
    call MultiboardSetItemValueColor( field, 100, 100, 100, 255 )
    call MultiboardSetItemValue( field, "0" )
endfunction

function UpdateVillagerCount takes nothing returns nothing
    local multiboarditem field = null
    call Debug_Message("BLUB 1")
   
    if (Score_Table != null) then
        set field =  MultiboardGetItem(Score_Table, ClockRow, 2)
        call MultiboardSetItemValue( field, I2S(CivilianCount) )
       
        set field =  MultiboardGetItem(Score_Table, ClockRow, 3)
        call MultiboardSetItemValue( field, I2S(GuardCount) )
    endif
   
    call Debug_Message("BLUB 2")
endfunction

private function Set_Clock takes nothing returns nothing
    local multiboarditem clockfield = null
   
    set clockfield = MultiboardGetItem(Score_Table, ClockRow, 1)
   
    set GameTime_Minutes = ( R2I(TimerGetElapsed(GameTime)) / 60 )
    set GameTime_Seconds = ModuloInteger(R2I(TimerGetElapsed(GameTime)), 60)
   
    if GameTime_Seconds >= 10 then
        call MultiboardSetItemValue( clockfield, I2S(GameTime_Minutes) + ":" + I2S(GameTime_Seconds) )
    else
        call MultiboardSetItemValue( clockfield, I2S(GameTime_Minutes) + ":0" + I2S(GameTime_Seconds) )
    endif
   
    set clockfield = null
endfunction

function Init_Score_Board takes nothing returns nothing
    local integer i // rows
    local integer j // columns
    local multiboarditem field = null
    local trigger trg
    local timer t = GetExpiredTimer()
    local integer row
   
    call ReleaseTimer(t)
    set t = null
   
    call Debug_Message("Init Score Board..")
   
    // Start game timeer
    set GameTime = NewTimer()
    call TimerStart( GameTime, 999999.00, false, null )
       
    // Now create the Multiboard
    set Score_Table = CreateMultiboard()
   
    // Set row count
    call MultiboardSetRowCount(Score_Table, 5+PlayerCount)
   
    // Set number of columns
    call MultiboardSetColumnCount(Score_Table, 5)
   
    // Set title
    call MultiboardSetTitleText(Score_Table, SCORE_TITLE)
   
    // Display
    call MultiboardDisplay(Score_Table, true)

    //  Adjust color and display style for all fields
    set i = 0
    loop
        exitwhen ( i > MultiboardGetRowCount(Score_Table)-1 )
        set j = 0
        loop
            exitwhen ( j > MultiboardGetColumnCount(Score_Table)-1 )
            set field = MultiboardGetItem(Score_Table, i, j)
            call MultiboardSetItemStyle( field, true, false )
            call MultiboardSetItemValueColor( field, 220, 220, 220, 255 )
            set j = j + 1
        endloop
        set i = i + 1
    endloop
       
    // Adjust column width
    set i = 0
    loop
        exitwhen ( i > MultiboardGetRowCount(Score_Table)-1 )
       
        // Player names
        set field = MultiboardGetItem(Score_Table, i, 0)
        call MultiboardSetItemWidth(field, 0.070)          
       
        // Kills
        set field = MultiboardGetItem(Score_Table, i, 1)
        call MultiboardSetItemWidth(field, 0.025)
       
        // PvP
        set field = MultiboardGetItem(Score_Table, i, 2)
        call MultiboardSetItemWidth(field, 0.025)
       
        // Level
        set field = MultiboardGetItem(Score_Table, i, 3)
        call MultiboardSetItemWidth(field, 0.02)

        // Deaths
        set field = MultiboardGetItem(Score_Table, i, 4)
        call MultiboardSetItemWidth(field, 0.01)
       
        set i = i + 1
    endloop
   
    // Vampire Headline
    // ================
    set field = MultiboardGetItem(Score_Table, 0, 0)
    call MultiboardSetItemValue( field, "|cffB292DAVampires:|r" )
    call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
   
    set field = MultiboardGetItem(Score_Table, 0, 1)    // Kills
    call MultiboardSetItemValue( field, "|cffD60505Kills|r" )
    call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
   
    set field = MultiboardGetItem(Score_Table, 0, 2)    // PvP
    call MultiboardSetItemValue( field, "|cffFD986CPvP|r" )
    call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
   
    set field = MultiboardGetItem(Score_Table, 0, 3)    // Level
    call MultiboardSetItemValue( field, "|cffFFDD8DLv|r" )
    call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
   
    set field = MultiboardGetItem(Score_Table, 0, 4)    // Death
    call MultiboardSetItemStyle( field, true, true )
    call MultiboardSetItemIcon(field, "ReplaceableTextures\\CommandButtons\\BTNPunisher.blp")

    // Hunter Headline
    // ================
    set row = VampirePlayerCount+2
    set field = MultiboardGetItem(Score_Table, row, 0)
    call MultiboardSetItemValue( field, "|cffD7B894Hunters:|r" )
    call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
   
    set field = MultiboardGetItem(Score_Table, row, 1)    // Kills
    call MultiboardSetItemValue( field, "|cffD60505Kills|r" )
    call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
   
    set field = MultiboardGetItem(Score_Table, row, 2)    // PvP
    call MultiboardSetItemValue( field, "|cffFD986CPvP|r" )
    call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
   
    set field = MultiboardGetItem(Score_Table, row, 3)    // Level
    call MultiboardSetItemValue( field, "|cffFFDD8DLv|r" )
    call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
   
    set field = MultiboardGetItem(Score_Table, row, 4)    // Death
    call MultiboardSetItemStyle( field, true, true )
    call MultiboardSetItemIcon(field, "ReplaceableTextures\\CommandButtons\\BTNPunisher.blp")
   
    // Game Time
    set ClockRow = ( PlayerCount + 4 )
    set field = MultiboardGetItem(Score_Table, ClockRow, 0)
    call MultiboardSetItemValueColor( field, 100, 100, 100, 255 )
    call MultiboardSetItemValue( field, "Game Time:" )
    set field = MultiboardGetItem(Score_Table, ClockRow, 1)
    call MultiboardSetItemValueColor( field, 180, 180, 180, 255 )
    call MultiboardSetItemValue( field, "0:00" )
 
    call MultiboardDisplay( Score_Table, true )
   
    // Update Clock
    set trg = CreateTrigger()
    call TriggerRegisterTimerEvent(trg, 1, true)
    call TriggerAddAction(trg, function Set_Clock)
   
    // Update for Vampire players
    set i = 0
    loop
        exitwhen i > 5
        if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
            call UpdateScoreBoard(i)
        endif
        set i = i + 1
    endloop
   
    // Update for Hunter players
    set i = 6
    loop
        exitwhen i > 8
        if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
            call UpdateScoreBoard(i)
        endif
        set i = i + 1
    endloop
   
    call InitVillagerCountFields()
    call UpdateVillagerCount()
   
  //  call UpdateScoreBoard()
   
  //  set MultiBoardSetUp = true
   
    set field = null
    set trg = null
   
endfunction

function IncScoreKills takes integer playerId returns nothing
    set Score_Kills[playerId] = Score_Kills[playerId] + 1
    call UpdateScoreBoard(playerId)
endfunction

function IncScorePvP takes integer playerId returns nothing
    set Score_PvP[playerId] = Score_PvP[playerId] + 1
    call UpdateScoreBoard(playerId)
endfunction

function IncScoreDeaths takes integer playerId returns nothing
    set Score_Deaths[playerId] = Score_Deaths[playerId] + 1
    call UpdateScoreBoard(playerId)
endfunction


endlibrary

 
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TemporaryVisibilityMod initializer Init requires TimerUtils

globals
endglobals

private function VisModFinished takes nothing returns nothing
    local VisMod vis = GetTimerData(GetExpiredTimer())
    call vis.destroy()
endfunction

struct VisMod
    fogmodifier fogMod = null
    timer t = null
   
    static method create takes integer playerId, real x, real y, real radius, real duration returns thistype
        local thistype this = thistype.allocate()
        set this.fogMod = CreateFogModifierRadius(Player(playerId), FOG_OF_WAR_VISIBLE, x, y, radius, true, true)
        set this.t = NewTimer()
        call SetTimerData(t, this)
        call TimerStart(this.t, duration, false, function VisModFinished)
        return this
    endmethod
   
    public method destroy takes nothing returns nothing
        call DestroyFogModifier(this.fogMod)
        set this.fogMod = null
        call ReleaseTimer(this.t)
        set this.t = null
        call this.deallocate() // the line of code that you NEED for any deconstructor
    endmethod
endstruct

function CreateTimedVisibility takes integer playerId, real x, real y, real radius, real duration returns nothing
    local VisMod vis = VisMod.create(playerId,x,y,radius,duration)
    call Debug_Message("Temporary vision")
endfunction

//===========================================================================
private function Init takes nothing returns nothing

endfunction

endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Camera initializer Init

private function Game_Camera_Conditions takes nothing returns boolean
    return true // CutScene == false and SceneCamera == null
endfunction

private function Scene_Camera_Conditions takes nothing returns boolean
    return false // CutScene and SceneCamera != null
endfunction

private function Game_Camera takes nothing returns nothing
    call  SetCameraField(CAMERA_FIELD_ZOFFSET, CAMERA_ZOFFSET, 0)
    call  SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, CAMERA_ANGLE_OF_ATTACK, 0)
   // call Debug_Message("Cam?")
endfunction

private function Scene_Camera takes nothing returns nothing
   // call CameraSetupApplyForceDuration(SceneCamera, true, 0.00)
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trg
   
    set trg = CreateTrigger(  )
    call TriggerRegisterTimerEvent(trg, 0.025, true)
    call TriggerAddCondition(trg, function Game_Camera_Conditions )
    call TriggerAddAction( trg, function Game_Camera )
   
    set trg = CreateTrigger(  )
    call TriggerRegisterTimerEvent(trg, 0.025, true)
    call TriggerAddCondition(trg, function Scene_Camera_Conditions )
    call TriggerAddAction( trg, function Scene_Camera )
   
    set trg = null
endfunction

endscope

 
//TESH.scrollpos=104
//TESH.alwaysfold=0
scope GameStart initializer Init

globals
    private constant integer VAMPIRE_PLAYER_COUNT = 6
    private unit array HeroSelectors[1]
    private unit CAMP_FIRE
    private boolean array PlayerSelected[1]
endglobals

private function SpawnVampireForPlayers takes integer playerId returns nothing
    local integer i = CheckOutVampireRespawn()
    local real x = GetRectCenterX(VampireSpawns[i])
    local real y = GetRectCenterY(VampireSpawns[i])
    local unit u = CreateUnit(Player(playerId), VAMPIRE, x, y, bj_UNIT_FACING)
    local effect e
    call RegisterVampire(u)
   
    set e = AddSpecialEffectTarget("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl", u, "origin")
    call DestroyEffect(e)
    set e = null
    if (GetLocalPlayer() == Player(playerId)) then
        // Use only local code (no net traffic) within this block to avoid desyncs.
        call ClearSelection()
        call SelectUnit(u, true)
        call PanCameraToTimed(x, y, 0.5)
    endif
   
    call Shadow_Message( playerId, "You are alive, good.. now drink some blood to grow stronger.", false)
   
    set u = null
endfunction

private function Actions takes nothing returns nothing
    local integer i = 0
    local real x
    local real y
    local timer t
    local integer scorePosition = 0
   
    set ForceHunters = CreateForce()
    set ForceVampires = CreateForce()

    // loop vammpire players
    set scorePosition = 1
    set i = PLAYER_VAMPIRES_START_ID
    loop
        exitwhen i > PLAYER_VAMPIRES_END_ID
       
        set HeroByPlayer[i] = null
       
        if GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
            call ForceAddPlayer(ForceVampires, Player(i))
            set VampirePlayerCount = VampirePlayerCount + 1
            set ScoreBoard_Positions[i] = scorePosition
            set scorePosition = scorePosition + 1
            call SpawnVampireForPlayers(i)
        endif
        set i = i + 1
    endloop
   
    // loop hunter players
    set scorePosition = scorePosition + 2
    set i = PLAYER_HUNTERS_START_ID
    loop
        exitwhen i > PLAYER_HUNTERS_END_ID
        set PlayerSelected[i] = false
        set HeroByPlayer[i] = null
       
        if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
            call ForceAddPlayer(ForceHunters, Player(i))
           
            set HunterPlayerCount = HunterPlayerCount + 1
            set ScoreBoard_Positions[i] = scorePosition
            set scorePosition = scorePosition + 1
           
            call Debug_Message("Init Hunter Player: "+I2S(i))
            if GetPlayerController(Player(i)) == MAP_CONTROL_USER then
                set x = GetUnitX(CAMP_FIRE) - 64
                set y = GetUnitY(CAMP_FIRE) + 64
                call PanCameraToTimedForPlayer(Player(i), x, y, 0.5)
                set HeroSelectors[i] = CreateUnit(Player(i), 'e003', x, y, bj_UNIT_FACING)
                call SelectUnitForPlayerSingle(CAMP_FIRE, Player(i))
            else
           
            endif
           
        endif
        set i = i + 1
    endloop
   
    set PlayerCount = VampirePlayerCount + HunterPlayerCount
   
    set t = NewTimer()
    call TimerStart(t, 1.0, false, function Init_Score_Board )
    set t = null
   
endfunction

private function HunterChoosenConditions takes nothing returns boolean
    return IsHunter(GetTriggerUnit()) and not PlayerSelected[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))]
endfunction

private function HunterChoosen takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local integer playerId = GetPlayerId(GetOwningPlayer(u))
    local item i
   
    set PlayerSelected[playerId] = true
   
    call UnitAddType(u, UNIT_TYPE_PEON)
    call RemoveUnit(HeroSelectors[playerId])
    call SelectUnitForPlayerSingle(u, Player(playerId))
   
    set i = CreateItem('I017', GetUnitX(u), GetUnitY(u))
    call UnitAddItem(u, i)
    set i = CreateItem('I017', GetUnitX(u), GetUnitY(u))
    call UnitAddItem(u, i)

    call Game_Message(PlayerNames[playerId] + "has picked a hero: " + GetUnitName(u))
    call RegisterHunter(u)
   
    set u = null
    set i = null
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trg
    set CAMP_FIRE = gg_unit_n006_0001
  //  call Actions(  )
   
    set trg = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( trg, bj_mapInitialPlayableArea )
    call TriggerAddCondition( trg, Condition( function HunterChoosenConditions ) )
    call TriggerAddAction( trg, function HunterChoosen )
   
    set trg = CreateTrigger()
    call TriggerAddAction( trg, function Actions )
    call TriggerExecute(trg)
   
    set trg = null
endfunction

endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Daybreak initializer Init

globals
    private boolean Daybreak = false
endglobals

private function Actions takes nothing returns nothing
   
    if not Daybreak then
        set Daybreak = true
        call Game_Message("The new day has come - The vampires lose the game!")
    endif
   
    call GameDefeat(PLAYER_VAMPIRES_START_ID, PLAYER_VAMPIRES_END_ID)
    call GameVictory(PLAYER_HUNTERS_START_ID, PLAYER_HUNTERS_END_ID)

endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trg
    set trg = CreateTrigger(  )
    call TriggerRegisterGameStateEventTimeOfDay( trg, EQUAL, 6.00 )
    call TriggerAddAction( trg, function Actions )
    set trg = null
endfunction

endscope
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library VillagerSystem initializer Init requires HandleTable, BasicFunctions, Alloc, ItemFunctions, StructuredDD, IsUnitInSight

globals  
    rect VillageArea1
    rect VillageArea2
   
    integer array VillagerTypes[1]
   
    private unit ThreatUnit = null
endglobals

function GetVillagerState takes unit u returns integer
    local Villager v = GetHandleData(u)
    return v.state
endfunction

private function UnitIsWandering takes unit u returns boolean
    return GetVillagerState(u) == VILLAGER_STATE_WANDERING
endfunction

private function UnitIsTalking takes unit u returns boolean
    return GetVillagerState(u) == VILLAGER_STATE_TALKING
endfunction

private function UnitHasPanic takes unit u returns boolean
    return GetVillagerState(u) == VILLAGER_STATE_PANIC
endfunction

private function UnitHasBlood takes unit u returns boolean
    local Villager v = GetHandleData(u)
    return v.blood > 0
endfunction

private function StartTalkingConditions takes nothing returns boolean
    return ( IsCivilian(GetTriggerUnit()) and UnitIsWandering(GetTriggerUnit()) and UnitHasBlood(GetTriggerUnit()) and GetRandomReal(0,100) <= TALKING_CHANCE )
endfunction

private function BackAttackConditions takes nothing returns boolean
    return GetVillagerState(GetTriggerUnit()) == VILLAGER_STATE_GUARD_HOLDGROUND
endfunction

private function GuardSmashRatConditions takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == RAT or GetUnitTypeId(GetTriggerUnit()) == CITY_RAT
endfunction

function RegisterSpawn takes unit u returns integer
    local Vampire vamp
   
    // Throw double registration warning
    if GetHandleData(u) != 0 then
        call Debug_Message("|cffFF0000Error:|r Double registration of vampire spawn!")
    endif
   
    // Create struct data
    set vamp = Vampire.create(u)
   
    // Adjust color
    call SetUnitColor( u, ConvertPlayerColor(12) )
   
    // Share vision with vampire players
    call UnitShareVision(u, Player(0), true)
    call UnitShareVision(u, Player(1), true)
    call UnitShareVision(u, Player(2), true)
    call UnitShareVision(u, Player(3), true)
    call UnitShareVision(u, Player(4), true)
    call UnitShareVision(u, Player(5), true)
   
    // Register for damage detection
    call StructuredDD.add(u)
   
    return vamp
endfunction

function DisableGuardRatSmash takes integer id returns nothing
    local Villager v = id
    if v.rat_trigger != null then
        call DisableTrigger(v.rat_trigger)
    endif
endfunction

function EnableGuardRatSmash takes integer id returns nothing
    local Villager v = id
    if v.rat_trigger != null then
        call EnableTrigger(v.rat_trigger)
    endif
endfunction

function DisableTalking takes integer id returns nothing
    local Villager v = id
    if v.talk_trigger != null then
        call DisableTrigger(v.talk_trigger)
    endif
endfunction

function EnableTalking takes integer id returns nothing
    local Villager v = id
    if v.talk_trigger != null then
        call EnableTrigger(v.talk_trigger)
    endif
endfunction

function GoNextWaypoint takes integer id returns nothing
    local Villager v = id
    local Waypoint wp = Waypoints[v.wpNext]
    call IssuePointOrder(v.u, "move", wp.x, wp.y)
endfunction

private function MoveAroundMap takes integer id returns nothing
    local Villager v = id
    local real x
    local real y
    set x = GetRandomReal(GetRectMinX(bj_mapInitialPlayableArea), GetRectMaxX(bj_mapInitialPlayableArea))
    set y = GetRandomReal(GetRectMinY(bj_mapInitialPlayableArea), GetRectMaxY(bj_mapInitialPlayableArea))
    call IssuePointOrder(v.u, "move", x, y)
endfunction

private function MoveAroundTown takes integer id returns nothing
    local Villager v = id
    local real r = GetRandomReal(0, 100)
    local real x
    local real y
   
    if r <= PARK_VISIT_CHANCE then
        set x = GetRandomReal(GetRectMinX(VillageArea2), GetRectMaxX(VillageArea2))
        set y = GetRandomReal(GetRectMinY(VillageArea2), GetRectMaxY(VillageArea2))
    else
        set x = GetRandomReal(GetRectMinX(VillageArea1), GetRectMaxX(VillageArea1))
        set y = GetRandomReal(GetRectMinY(VillageArea1), GetRectMaxY(VillageArea1))
    endif
    call IssuePointOrder(v.u, "move", x, y)
endfunction

function CreateTalkingTag takes integer id, string text returns nothing
    local Villager v = id
    local texttag t = null

    // We do not need to create a tag if the villager is not visible
    if IsUnitVisible(v.u, Player(SHADOW_PLAYER_ID)) then
   
        set t = CreateTextTag()
        set text = "|c00" + v.colorString + text + "|r"
       
        call SetTextTagText(t, text, 0.0184)
        call SetTextTagPos(t, GetUnitX(v.u), GetUnitY(v.u), 0.00)
        call SetTextTagVelocity(t, 0, 0.02)
        call SetTextTagVisibility(t, false)
        if IsUnitVisible(v.u, GetLocalPlayer()) then
            call SetTextTagVisibility(t, true)
        endif
     
        call SetTextTagFadepoint(t, 1)
        call SetTextTagLifespan(t, 2)
        call SetTextTagPermanent(t, false)  
        set t = null
   
    endif
endfunction

private function CreateGuardAlertTag takes unit u returns nothing
    local integer id = GetPlayerId(GetOwningPlayer(u))
    local texttag t = null
 
    if IsUnitVisible(u, Player(SHADOW_PLAYER_ID)) then

        set t = CreateTextTag()
        call SetTextTagColor(t, 66, 200, 255, 255)  
        call SetTextTagText(t, "!", 0.05)
        call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
        // call SetTextTagVelocity(t, 0, 0.02)
        call SetTextTagVisibility(t, true)
        call SetTextTagFadepoint(t, 1)
        call SetTextTagLifespan(t, 2)
        call SetTextTagPermanent(t, false)  
        set t = null
       
    endif
   
endfunction

function CreateShoutTag takes integer vil, string text returns nothing
    local Villager v = vil
    local texttag t = null
    local integer i
   
    if (NO_SHOUTS == false) and IsUnitVisible(v.u, Player(SHADOW_PLAYER_ID)) then
       
        set t = CreateTextTag()
        set i  = GetRandomInt(1,8)
       
        if v.isGuard then
            set text = "|c00" + v.colorString + text + "|r"
        else
            call SetTextTagColor(t, 200, 0, 30, 255)
        endif
        call SetTextTagText(t, text, 0.0184)
        call SetTextTagPos(t, GetUnitX(v.u), GetUnitY(v.u), 0.00)
        call SetTextTagVelocity(t, 0, 0.04)
        call SetTextTagVisibility(t, false)
        if IsUnitVisible(v.u, GetLocalPlayer()) then
            call SetTextTagVisibility(t, true)
        endif
        call SetTextTagFadepoint(t, 0)
        call SetTextTagLifespan(t, 1)
        call SetTextTagPermanent(t, false