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

Trigger Viewer

Scourge_Darkfang New.w3x
Variables
Credits List
Code
Libraries
Global Alloc
Table
List T
Dummy Recycler
Timer Utils
Selection Circle
Timed Effect
Bezier Ease
Self Written Libraries
Animation Manager
Missile
Linked List
Missile
Spells
Overmind
Overmind Spell Three
Debug
Toxic Illusion
Command
Set Unit Animation
Loop Unit Animation
Toxic Illusion Config
Toxic Illusion
Fel Magic Synthesis
Fel Magic Synthesis Config
Fel Magic Synthesis
Saccular Genesis
Saccular Genesis Config
Saccular Genesis
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code.
function RegionMoveRect takes region reg, rect rec, real newX, real newY returns nothing
    call RegionClearRect(reg, rec)
    
    call MoveRectTo(rec, newX, newY)
    
    call RegionAddRect(reg, rec)
endfunction
Name Type Is Array Initial Value
//! novjass
    As much as I would like to make my own libraries for this contest, I would have to stick with the already approved
    ones...
   
        Flux - DummyRecycler, DamagePackage
        Bribe - Table, TimerUtilsEx
        Magtheridon96, Vexorian - TimerUtilsEx
    AGD - Global Alloc
       
//! endnovjass
library Alloc /* v1.1.0 https://www.hiveworkshop.com/threads/324937/


    */
uses /*

    */
Table                 /*  https://www.hiveworkshop.com/threads/188084/

    */
optional ErrorMessage /*  https://github.com/nestharus/JASS/blob/master/jass/Systems/ErrorMessage/main.j


    */
//! novjass

    /*
        Written by AGD, based on MyPad's allocation algorithm

            A allocator module using a single global indexed stack. Allocated values are
            within the JASS_MAX_ARRAY_SIZE. No more need to worry about code bloats behind
            the module implementation as it generates the least code possible (6 lines of
            code in non-DEBUG_MODE), nor does it use an initialization function. This system
            also only uses ONE variable (for the whole map) for the hashtable.
    */

    |-----|
    | API |
    |-----|
    /*
      */
module GlobalAlloc/*
            - Uses a single stack globally
      */
module Alloc/*
            - Uses a unique stack per struct

          */
debug readonly boolean allocated/* Is node allocated?

          */
static method allocate takes nothing returns thistype/*
          */
method deallocate takes nothing returns nothing/*

    */
//! endnovjass

    /*===========================================================================*/

    globals
        private key stack
    endglobals

    static if DEBUG_MODE then
        private function AssertError takes boolean condition, string methodName, string structName, integer node, string message returns nothing
            static if LIBRARY_ErrorMessage then
                call ThrowError(condition, SCOPE_PREFIX, methodName, structName, node, message)
            else
                if condition then
                    call BJDebugMsg("[Library: " + SCOPE_PREFIX + "] [Struct: " + structName + "] [Method: " + methodName + "] [Instance: " + I2S(node) + "] : |cffff0000" + message + "|r")
                endif
            endif
        endfunction

        public function IsAllocated takes integer typeId, integer node returns boolean
            return node > 0 and Table(stack)[typeId*JASS_MAX_ARRAY_SIZE + node] == 0
        endfunction
    endif

    public function Allocate takes integer typeId returns integer
        local integer offset = typeId*JASS_MAX_ARRAY_SIZE
        local integer node = Table(stack)[offset]
        local integer stackNext = Table(stack)[offset + node]
        debug call AssertError(typeId < 0, "allocate()", Table(stack).string[-typeId], 0, "Invalid struct ID (" + I2S(typeId) + ")")
        if stackNext == 0 then
            debug call AssertError(node == (JASS_MAX_ARRAY_SIZE - 1), "allocate()", Table(stack).string[-typeId], node, "Overflow")
            set node = node + 1
            set Table(stack)[offset] = node
        else
            set Table(stack)[offset] = stackNext
            set Table(stack)[offset + node] = 0
        endif
        return node
    endfunction
    public function Deallocate takes integer typeId, integer node returns nothing
        local integer offset = typeId*JASS_MAX_ARRAY_SIZE
        debug call AssertError(node == 0, "deallocate()", Table(stack).string[-typeId], 0, "Null node")
        debug call AssertError(Table(stack)[offset + node] > 0, "deallocate()", Table(stack).string[-typeId], node, "Double-free")
        set Table(stack)[offset + node] = Table(stack)[offset]
        set Table(stack)[offset] = node
    endfunction

    module Alloc
        debug method operator allocated takes nothing returns boolean
            debug return IsAllocated(thistype.typeid, this)
        debug endmethod
        static method allocate takes nothing returns thistype
            return Allocate(thistype.typeid)
        endmethod
        method deallocate takes nothing returns nothing
            call Deallocate(thistype.typeid, this)
        endmethod
        debug private static method onInit takes nothing returns nothing
            debug set Table(stack).string[-thistype.typeid] = "thistype"
        debug endmethod
    endmodule

    module GlobalAlloc
        debug method operator allocated takes nothing returns boolean
            debug return IsAllocated(0, this)
        debug endmethod
        static method allocate takes nothing returns thistype
            debug call AssertError(Table(stack)[0] == (JASS_MAX_ARRAY_SIZE - 1), "allocate()", "thistype", JASS_MAX_ARRAY_SIZE - 1, "Overflow")
            return Allocate(0)
        endmethod
        method deallocate takes nothing returns nothing
            debug call AssertError(this == 0, "deallocate()", "thistype", 0, "Null node")
            debug call AssertError(Table(stack)[this] > 0, "deallocate()", "thistype", this, "Double-free")
            call Deallocate(0, this)
        endmethod
    endmodule


endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
   
    One map, one hashtable. Welcome to NewTable 4.1.0.1
   
    This newest iteration of Table introduces the new HashTable struct.
    You can now instantiate HashTables which enables the use of large
    parent and large child keys, just like a standard hashtable. Previously,
    the user would have to instantiate a Table to do this on their own which -
    while doable - is something the user should not have to do if I can add it
    to this resource myself (especially if they are inexperienced).
   
    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
   
    function GetHash takes nothing returns hashtable
        return ht
    endfunction
   
    private struct dex extends array
        static method operator size takes nothing returns Table
            return sizeK
        endmethod
        static method operator list takes nothing returns Table
            return listK
        endmethod
    endstruct
       
    private struct handles extends array
        method has takes integer key returns boolean
            return HaveSavedHandle(ht, this, key)
        endmethod
        method remove takes integer key returns nothing
            call RemoveSavedHandle(ht, this, key)
        endmethod
    endstruct
       
    private struct agents extends array
        method operator []= takes integer key, agent value returns nothing
            call SaveAgentHandle(ht, this, key, value)
        endmethod
    endstruct
       
    //! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
    private struct $TYPE$s extends array
        method operator [] takes integer key returns $TYPE$
            return Load$FUNC$(ht, this, key)
        endmethod
        method operator []= takes integer key, $TYPE$ value returns nothing
            call Save$FUNC$(ht, this, key, value)
        endmethod
        method has takes integer key returns boolean
            return HaveSaved$SUPER$(ht, this, key)
        endmethod
        method remove takes integer key returns nothing
            call RemoveSaved$SUPER$(ht, this, key)
        endmethod
    endstruct
    private module $TYPE$m
        method operator $TYPE$ takes nothing returns $TYPE$s
            return this
        endmethod
    endmodule
    //! endtextmacro
       
    //! textmacro NEW_ARRAY takes FUNC, TYPE
    private struct $TYPE$s extends array
        method operator [] takes integer key returns $TYPE$
            return Load$FUNC$Handle(ht, this, key)
        endmethod
        method operator []= takes integer key, $TYPE$ value returns nothing
            call Save$FUNC$Handle(ht, this, key, value)
        endmethod
        method has takes integer key returns boolean
            return HaveSavedHandle(ht, this, key)
        endmethod
        method remove takes integer key returns nothing
            call RemoveSavedHandle(ht, this, key)
        endmethod
    endstruct
    private module $TYPE$m
        method operator $TYPE$ takes nothing returns $TYPE$s
            return this
        endmethod
    endmodule
    //! endtextmacro
   
    //Run these textmacros to include the entire hashtable API as wrappers.
    //Don't be intimidated by the number of macros - Vexorian's map optimizer is
    //supposed to kill functions which inline (all of these functions inline).
    //! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
    //! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
    //! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
    //New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
    //! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
   
    //! runtextmacro NEW_ARRAY("Player", "player")
    //! runtextmacro NEW_ARRAY("Widget", "widget")
    //! runtextmacro NEW_ARRAY("Destructable", "destructable")
    //! runtextmacro NEW_ARRAY("Item", "item")
    //! runtextmacro NEW_ARRAY("Unit", "unit")
    //! runtextmacro NEW_ARRAY("Ability", "ability")
    //! runtextmacro NEW_ARRAY("Timer", "timer")
    //! runtextmacro NEW_ARRAY("Trigger", "trigger")
    //! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
    //! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
    //! runtextmacro NEW_ARRAY("TriggerEvent", "event")
    //! runtextmacro NEW_ARRAY("Force", "force")
    //! runtextmacro NEW_ARRAY("Group", "group")
    //! runtextmacro NEW_ARRAY("Location", "location")
    //! runtextmacro NEW_ARRAY("Rect", "rect")
    //! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
    //! runtextmacro NEW_ARRAY("Sound", "sound")
    //! runtextmacro NEW_ARRAY("Effect", "effect")
    //! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
    //! runtextmacro NEW_ARRAY("ItemPool", "itempool")
    //! runtextmacro NEW_ARRAY("Quest", "quest")
    //! runtextmacro NEW_ARRAY("QuestItem", "questitem")
    //! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
    //! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
    //! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
    //! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
    //! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
    //! runtextmacro NEW_ARRAY("Trackable", "trackable")
    //! runtextmacro NEW_ARRAY("Dialog", "dialog")
    //! runtextmacro NEW_ARRAY("Button", "button")
    //! runtextmacro NEW_ARRAY("TextTag", "texttag")
    //! runtextmacro NEW_ARRAY("Lightning", "lightning")
    //! runtextmacro NEW_ARRAY("Image", "image")
    //! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
    //! runtextmacro NEW_ARRAY("Region", "region")
    //! runtextmacro NEW_ARRAY("FogState", "fogstate")
    //! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
    //! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
       
    struct Table extends array
       
        // Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
        implement realm
        implement integerm
        implement booleanm
        implement stringm
        implement playerm
        implement widgetm
        implement destructablem
        implement itemm
        implement unitm
        implement abilitym
        implement timerm
        implement triggerm
        implement triggerconditionm
        implement triggeractionm
        implement eventm
        implement forcem
        implement groupm
        implement locationm
        implement rectm
        implement boolexprm
        implement soundm
        implement effectm
        implement unitpoolm
        implement itempoolm
        implement questm
        implement questitemm
        implement defeatconditionm
        implement timerdialogm
        implement leaderboardm
        implement multiboardm
        implement multiboarditemm
        implement trackablem
        implement dialogm
        implement buttonm
        implement texttagm
        implement lightningm
        implement imagem
        implement ubersplatm
        implement regionm
        implement fogstatem
        implement fogmodifierm
        implement hashtablem
       
        method operator handle takes nothing returns handles
            return this
        endmethod
       
        method operator agent takes nothing returns agents
            return this
        endmethod
       
        //set this = tb[GetSpellAbilityId()]
        method operator [] takes integer key returns Table
            return LoadInteger(ht, this, key) //return this.integer[key]
        endmethod
       
        //set tb[389034] = 8192
        method operator []= takes integer key, Table tb returns nothing
            call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
        endmethod
       
        //set b = tb.has(2493223)
        method has takes integer key returns boolean
            return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
        endmethod
       
        //call tb.remove(294080)
        method remove takes integer key returns nothing
            call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
        endmethod
       
        //Remove all data from a Table instance
        method flush takes nothing returns nothing
            call FlushChildHashtable(ht, this)
        endmethod
       
        //local Table tb = Table.create()
        static method create takes nothing returns Table
            local Table this = dex.list[0]
           
            if this == 0 then
                set this = more + 1
                set more = this
            else
                set dex.list[0] = dex.list[this]
                call dex.list.remove(this) //Clear hashed memory
            endif
           
            debug set dex.list[this] = -1
            return this
        endmethod
       
        // Removes all data from a Table instance and recycles its index.
        //
        //     call tb.destroy()
        //
        method destroy takes nothing returns nothing
            debug if dex.list[this] != -1 then
                debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
                debug return
            debug endif
           
            call this.flush()
           
            set dex.list[this] = dex.list[0]
            set dex.list[0] = this
        endmethod
       
        //! runtextmacro optional TABLE_BC_METHODS()
    endstruct
   
    //! runtextmacro optional TABLE_BC_STRUCTS()
   
    struct TableArray extends array
       
        //Returns a new TableArray to do your bidding. Simply use:
        //
        //    local TableArray ta = TableArray[array_size]
        //
        static method operator [] takes integer array_size returns TableArray
            local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
            local TableArray this = tb[0]         //The last-destroyed TableArray that had this array size
           
            debug if array_size <= 0 then
                debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
                debug return 0
            debug endif
           
            if this == 0 then
                set this = less - array_size
                set less = this
            else
                set tb[0] = tb[this]  //Set the last destroyed to the last-last destroyed
                call tb.remove(this)  //Clear hashed memory
            endif
           
            set dex.size[this] = array_size //This remembers the array size
            return this
        endmethod
       
        //Returns the size of the TableArray
        method operator size takes nothing returns integer
            return dex.size[this]
        endmethod
       
        //This magic method enables two-dimensional[array][syntax] for Tables,
        //similar to the two-dimensional utility provided by hashtables them-
        //selves.
        //
        //ta[integer a].unit[integer b] = unit u
        //ta[integer a][integer c] = integer d
        //
        //Inline-friendly when not running in debug mode
        //
        method operator [] takes integer key returns Table
            static if DEBUG_MODE then
                local integer i = this.size
                if i == 0 then
                    call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
                    return 0
                elseif key < 0 or key >= i then
                    call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
                    return 0
                endif
            endif
            return this + key
        endmethod
       
        //Destroys a TableArray without flushing it; I assume you call .flush()
        //if you want it flushed too. This is a public method so that you don't
        //have to loop through all TableArray indices to flush them if you don't
        //need to (ie. if you were flushing all child-keys as you used them).
        //
        method destroy takes nothing returns nothing
            local Table tb = dex.size[this.size]
           
            debug if this.size == 0 then
                debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
                debug return
            debug endif
           
            if tb == 0 then
                //Create a Table to index recycled instances with their array size
                set tb = Table.create()
                set dex.size[this.size] = tb
            endif
           
            call dex.size.remove(this) //Clear the array size from hash memory
           
            set tb[this] = tb[0]
            set tb[0] = this
        endmethod
       
        private static Table tempTable
        private static integer tempEnd
       
        //Avoids hitting the op limit
        private static method clean takes nothing returns nothing
            local Table tb = .tempTable
            local integer end = tb + 0x1000
            if end < .tempEnd then
                set .tempTable = end
                call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
            else
                set end = .tempEnd
            endif
            loop
                call tb.flush()
                set tb = tb + 1
                exitwhen tb == end
            endloop
        endmethod
       
        //Flushes the TableArray and also destroys it. Doesn't get any more
        //similar to the FlushParentHashtable native than this.
        //
        method flush takes nothing returns nothing
            debug if this.size == 0 then
                debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
                debug return
            debug endif
            set .tempTable = this
            set .tempEnd = this + this.size
            call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
            call this.destroy()
        endmethod
       
    endstruct
   
    //NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
    //than that which was previously possible.
    struct HashTable extends array

        //Enables myHash[parentKey][childKey] syntax.
        //Basically, it creates a Table in the place of the parent key if
        //it didn't already get created earlier.
        method operator [] takes integer index returns Table
            local Table t = Table(this)[index]
            if t == 0 then
                set t = Table.create()
                set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
            endif
            return t
        endmethod

        //You need to call this on each parent key that you used if you
        //intend to destroy the HashTable or simply no longer need that key.
        method remove takes integer index returns nothing
            local Table t = Table(this)[index]
            if t != 0 then
                call t.destroy()
                call Table(this).remove(index)
            endif
        endmethod
       
        //Added in version 4.1
        method has takes integer index returns boolean
            return Table(this).has(index)
        endmethod
       
        //HashTables are just fancy Table indices.
        method destroy takes nothing returns nothing
            call Table(this).destroy()
        endmethod
       
        //Like I said above...
        static method create takes nothing returns thistype
            return Table.create()
        endmethod

    endstruct

endlibrary
/*****************************************************************************
*
*    List<T> v2.1.2.3
*       by Bannar
*
*    Doubly-linked list.
*
******************************************************************************
*
*    Requirements:
*
*       Table by Bribe
*          hiveworkshop.com/threads/snippet-new-table.188084/
*
*       Alloc - choose whatever you like
*          e.g.: by Sevion hiveworkshop.com/threads/snippet-alloc.192348/
*
******************************************************************************
*
*    Implementation:
*
*       macro DEFINE_LIST takes ACCESS, NAME, TYPE
*
*       macro DEFINE_STRUCT_LIST takes ACCESS, NAME, TYPE
*
*          ACCESS - encapsulation, choose restriction access
*            NAME - name of list type
*            TYPE - type of values stored
*
*     Implementation notes:
*
*       - DEFINE_STRUCT_LIST macro purpose is to provide natural typecasting syntax for struct types.
*       - <NAME>Item structs inline directly into hashtable operations thus generate basically no code.
*       - Lists defined with DEFINE_STRUCT_LIST are inlined nicely into single create method and single integer array.
*
******************************************************************************
*
*    struct API:
*
*       struct <NAME>Item:
*
*        | <TYPE> data
*        | <NAME>Item next
*        | <NAME>Item prev
*
*
*       General:
*
*        | static method create takes nothing returns thistype
*        |    Default ctor.
*        |
*        | static method operator [] takes thistype other returns thistype
*        |    Copy ctor.
*        |
*        | method destroy takes nothing returns nothing
*        |    Default dctor.
*        |
*        | method empty takes nothing returns boolean
*        |    Checks whether the list is empty.
*        |
*        | method size takes nothing returns integer
*        |    Returns size of a list.
*
*
*       Access:
*
*        | readonly <NAME>Item first
*        | readonly <NAME>Item last
*        |
*        | method front takes nothing returns $TYPE$
*        |    Retrieves first element.
*        |
*        | method back takes nothing returns $TYPE$
*        |    Retrieves last element.
*
*
*       Modifiers:
*
*        | method clear takes nothing returns nothing
*        |    Flushes list and recycles its nodes.
*        |
*        | method push takes $TYPE$ value returns thistype
*        |    Adds elements to the end.
*        |
*        | method unshift takes $TYPE$ value returns thistype
*        |    Adds elements to the front.
*        |
*        | method pop takes nothing returns thistype
*        |    Removes the last element.
*        |
*        | method shift takes nothing returns thistype
*        |    Removes the first element.
*        |
*        | method find takes $TYPE$ value returns $NAME$Item
*        |    Returns the first node which data equals value.
*        |
*        | method erase takes $NAME$Item node returns boolean
*        |    Removes node from the list, returns true on success.
*        |
*        | method removeElem takes $TYPE$ value returns thistype
*        |    Removes first element that equals value from the list.
*
*
*****************************************************************************/

library ListT requires Table, Alloc

//! runtextmacro DEFINE_LIST("", "IntegerList", "integer")
// Run here any global list types you want to be defined.

//! textmacro_once DEFINE_LIST takes ACCESS, NAME, TYPE
$ACCESS$ struct $NAME$Item extends array
    // No default ctor and dctor due to limited array size

    method operator data takes nothing returns $TYPE$
        return Table(this).$TYPE$[-1] // hashtable[ node, -1 ] = data
    endmethod
    method operator data= takes $TYPE$ value returns nothing
        set Table(this).$TYPE$[-1] = value
    endmethod

    method operator next takes nothing returns thistype
        return Table(this)[-2] // hashtable[ node, -2 ] = next
    endmethod
    method operator next= takes thistype value returns nothing
        set Table(this)[-2] = value
    endmethod

    method operator prev takes nothing returns thistype
        return Table(this)[-3] // hashtable[ node, -3 ] = prev
    endmethod
    method operator prev= takes thistype value returns nothing
        set Table(this)[-3] = value
    endmethod
endstruct

$ACCESS$ struct $NAME$ extends array
    readonly $NAME$Item first
    readonly $NAME$Item last
    private integer count

    implement Alloc

    private static method setNodeOwner takes $NAME$Item node, $NAME$ owner returns nothing
        set Table(node)[-4] = owner
    endmethod

    private static method getNodeOwner takes $NAME$Item node returns thistype
        return Table(node)[-4]
    endmethod

    private method createNode takes $TYPE$ value returns $NAME$Item
        local $NAME$Item node = Table.create()
        set node.data = value
        call setNodeOwner(node, this) // ownership
        return node
    endmethod

    private method deleteNode takes $NAME$Item node returns nothing
        call Table(node).destroy() // also removes ownership
    endmethod

    static method create takes nothing returns thistype
        local thistype this = allocate()
        set count = 0
        return this
    endmethod

    method clear takes nothing returns nothing
        local $NAME$Item node = first
        local $NAME$Item temp

        loop // recycle all Table indexes
            exitwhen 0 == node
            set temp = node.next
            call deleteNode(node)
            set node = temp
        endloop

        set first = 0
        set last = 0
        set count = 0
    endmethod

    method destroy takes nothing returns nothing
        call clear()
        call deallocate()
    endmethod

    method front takes nothing returns $TYPE$
        return first.data
    endmethod

    method back takes nothing returns $TYPE$
        return last.data
    endmethod

    method empty takes nothing returns boolean
        return count == 0
    endmethod

    method size takes nothing returns integer
        return count
    endmethod

    method push takes $TYPE$ value returns thistype
        local $NAME$Item node = createNode(value)

        if not empty() then
            set last.next = node
            set node.prev = last
        else
            set first = node
            set node.prev = 0
        endif

        set last = node
        set node.next = 0
        set count = count + 1
        return this
    endmethod

    method unshift takes $TYPE$ value returns thistype
        local $NAME$Item node = createNode(value)

        if not empty() then
            set first.prev = node
            set node.next = first
        else
            set last = node
            set node.next = 0
        endif

        set first = node
        set node.prev = 0
        set count = count + 1
        return this
    endmethod

    method pop takes nothing returns thistype
        local $NAME$Item node

        if not empty() then
            set node = last
            set last = last.prev

            if last == 0 then
                set first = 0
            else
                set last.next = 0
            endif

            call deleteNode(node)
            set count = count - 1
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::pop failed for instance "+I2S(this)+". List is empty.")
        endif
        return this
    endmethod

    method shift takes nothing returns thistype
        local $NAME$Item node

        if not empty() then
            set node = first
            set first = first.next

            if first == 0 then
                set last = 0
            else
                set first.prev = 0
            endif

            call deleteNode(node)
            set count = count - 1
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::shift failed for instance "+I2S(this)+". List is empty.")
        endif
        return this
    endmethod

    static method operator [] takes thistype other returns thistype
        local thistype instance = create()
        local $NAME$Item node = other.first

        loop
            exitwhen node == 0
            call instance.push(node.data)
            set node = node.next
        endloop

        return instance
    endmethod

    method find takes $TYPE$ value returns $NAME$Item
        local $NAME$Item node = first
        loop
            exitwhen node == 0 or node.data == value
            set node = node.next
        endloop
        return node
    endmethod

    method erase takes $NAME$Item node returns boolean
        if getNodeOwner(node) == this then // match ownership
            if node == first then
                call shift()
            elseif node == last then
                call pop()
            else
                set node.prev.next = node.next
                set node.next.prev = node.prev
                call deleteNode(node)
                set count = count - 1
            endif
            return true
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::erase failed for instance "+I2S(this)+". Attempted to remove invalid node "+I2S(node)+".")
        endif
        return false
    endmethod

    method remove takes $NAME$Item node returns boolean
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Method $NAME$::remove is obsolete, use $NAME$::erase instead.")
        return erase(node)
    endmethod

    method removeElem takes $TYPE$ value returns thistype
        local $NAME$Item node = find(value)
        if node != 0 then
            call erase(node)
        endif
        return this
    endmethod
endstruct
//! endtextmacro

//! textmacro_once DEFINE_STRUCT_LIST takes ACCESS, NAME, TYPE
$ACCESS$ struct $NAME$Item extends array
    // Cannot inherit methods via delegate due to limited array size
    method operator data takes nothing returns $TYPE$
        return IntegerListItem(this).data
    endmethod
    method operator data= takes $TYPE$ value returns nothing
        set IntegerListItem(this).data = value
    endmethod

    method operator next takes nothing returns thistype
        return IntegerListItem(this).next
    endmethod
    method operator next= takes thistype value returns nothing
        set IntegerListItem(this).next = value
    endmethod

    method operator prev takes nothing returns thistype
        return IntegerListItem(this).prev
    endmethod
    method operator prev= takes thistype value returns nothing
        set IntegerListItem(this).prev = value
    endmethod
endstruct

$ACCESS$ struct $NAME$ extends array
    private delegate IntegerList parent

    static method create takes nothing returns thistype
        local thistype this = IntegerList.create()
        set parent = this
        return this
    endmethod

    method front takes nothing returns $TYPE$
        return parent.front()
    endmethod

    method back takes nothing returns $TYPE$
        return parent.back()
    endmethod
endstruct
//! endtextmacro

endlibrary
library DummyRecycler /*
 
//                      DummyRecycler v1.25
//                          by Flux
//
//  A system that recycles dummy units while considering their facing angle.
//  It can be used as attachment dummies for visual effects or as dummy caster.
//
//  Why is recycling a unit important?
//      Because creating a unit is is one of the slowest function in the game
//      and there are reports that will always leave a permanent tiny bit of
//      memory (0.04 KB).
//      On average, retrieving a pending Dummy is approximately 4x faster compared
//      to creating a new one and recycling a Dummy compared to removing it is
//      approximately 1.3x faster.
//      Furthermore, if you're using a lot of "Unit has entered map" events,
//      using this system will even result to even more better performance
//      because retrieving Dummy units does not cause that event to run.


    */
requires /*
       nothing
     
    */
optional Table/*
        if not found, this system will use a hashtable. Hashtables are limited to
        255 per map.
     
    */
optional WorldBounds /*
        if not found, this system will initialize its own Map Boundaries.
//
//
//  Features:
//
//    -- Dummy Sharing
//        When a Dummy List gets low on unit count, it will borrow Dummy Units
//        from the Dummy List with the highest unit count. The transfer is not
//        instant because the shared Dummy Unit has to turn to the appropriate
//        angle of its new Dummy List before it can be recycled.
//        See BORROW_REQUEST.
//
//    -- Self-balancing recycling algorithm
//        Recycled Dummy Units will be thrown to the List having the least number
//        of Dummy Units.
//
//    -- Recycling least used
//        Allows recycling a Dummy from the Dummy List with the highest
//        unit count. It is useful when the facing angle of the Dummy Unit
//        does not matter.
//        See GetRecycledDummyAnyAngle.
//
//    -- Self-adaptation
//        When there are no free Dummy Units from a Dummy List, it will end up creating
//        a new unit instead but that unit will be permanently added as a Dummy
//        Unit to be recycled increasing the overall total Dummy Unit count.
//
//    -- Count control
//        Allows limiting the overall number of Dummy Units.
//        See MAX_DUMMY_COUNT.
//
//    -- Delayed Recycle
//        Allows recycling Dummy Units after some delay to allocate time for the
//        death animation of Special Effects to be seen.
//        See DummyAddRecycleTimer.
//
// ******************************************************************
// ***************************** API: *******************************
// ******************************************************************
//
//  function GetRecycledDummy takes real x, real y, real z, real facing returns unit
//      - Retrieve an unused Dummy Unit from the List.
//      - The equivalent of CreateUnit.
//      - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
//  function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
//      - Use this function if the facing angle of the Dummy doesn't matter to you.
//      - It will return a unit from the list having the highest number of unused Dummy Units.
//      - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
//  function RecycleDummy takes unit u returns nothing
//      - Recycle the Dummy unit for it to be used again later.
//      - The equivalent of RemoveUnit.
//
//  function DummyAddRecycleTimer takes unit u, real time returns nothing
//      - Recycle the Dummy unit after a certain time.
//      - Use this to allocate time for the the death animation of an effect attached to the
//        Dummy Unit to finish..
//      - The equivalent of UnitApplyTimedLife.
//
//  function ShowDummy takes unit u, boolean flag returns nothing
//      - Shows/hides Dummy Unit without conflicting with the Locust ability.
//
//--------------------
//      CREDITS
//--------------------
//  Bribe - for the MissileRecycler (vJASS) where I got this concept from
//       http://www.hiveworkshop.com/forums/jass-resources-412/system-missilerecycler-206086/
//        - for the optional Table
//       http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
//  Vexorian - for the Attachable and Pitch Animation Model (dummy.mdx)
//       http://www.wc3c.net/showthread.php?t=101150
//  Maker and IcemanBo - for the unit permanent 0.04 KB memory leak of units.
//       http://www.hiveworkshop.com/forums/trigger-gui-editor-tutorials-279/memory-leaks-263410/
//  Nestharus - for the data structure
//       http://www.hiveworkshop.com/forums/2809461-post7.html
//            - for the optional WorldBounds
//       http://githubusercontent.com/nestharus/JASS/master/jass/Systems/WorldBounds/script.j

// =============================================================== //
// ====================== CONFIGURATION ========================== //
// =============================================================== */


    /*
    //! externalblock extension=lua ObjectMerger $FILENAME$
        //! i function dummy()
            //! i setobjecttype("units")
           
            //! i createobject("uloc", "dumi")
            //! i makechange(current, "umdl", "dummy.mdx")
        //! i end
       
        //! i dummy()
    //! endexternalblock
    */

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

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

    function DummyAddRecycleTimer takes unit u, real time returns nothing
        local timer t = CreateTimer()
        static if LIBRARY_Table then
            set S.tb.unit[GetHandleId(t)] = u
        else
            call SaveUnitHandle(S.hash, GetHandleId(t), 0, u)
        endif
        call TimerStart(t, time, false, function Expires)
        set t = null
    endfunction
 
    function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
        return GetRecycledDummy(x, y, z, angle[countNext[countHead[upper]]])
    endfunction
 
    // runtextmacro DUMMY_DEBUG_TOOLS()
 
endlibrary
library TimerUtilsEx requires optional Table
/*************************************************
*
*   TimerUtilsEx
*   v2.1.0.2
*   By Vexorian, Bribe & Magtheridon96
*
*   Original version by Vexorian.
*
*   Flavors:
*       Hashtable:
*           - RAM:              Minimal
*           - TimerData:        Slow
*
*       Array:
*           - RAM:              Maximal
*           - TimerData:        Fast
*
*   All the functions have O(1) complexity.
*   The Array version is the fastest, but the hashtable
*   version is the safest. The Array version is still
*   quite safe though, and I would recommend using it.
*   The system is much slower in debug mode.
*
*   Optional Requirement:
*       - Table by Bribe
*           - hiveworkshop.com/forums/showthread.php?t=188084
*
*   API:
*   ----
*       - function NewTimer takes nothing returns timer
*           - Returns a new timer from the stack.
*       - function NewTimerEx takes integer i returns timer
*           - Returns a new timer from the stack and attaches a value to it.
*       - function ReleaseTimer takes timer t returns integer
*           - Throws a timer back into the stack. Also returns timer data.
*       - function SetTimerData takes timer t, integer value returns nothing
*           - Attaches a value to a timer.
*       - function GetTimerData takes timer t returns integer
*           - Returns the attached value.
*
*************************************************/

    // Configuration
    globals
        // Use hashtable, or fast array?
        private constant boolean USE_HASH = true
        // Max Number of Timers Held in Stack
        private constant integer QUANTITY = 256
    endglobals
   
    globals
        private timer array tT
        private integer tN = 0
    endglobals
   
    private module Init
        private static method onInit takes nothing returns nothing
            static if not USE_HASH then
                local integer i = QUANTITY
                loop
                    set i = i - 1
                    set tT[i] = CreateTimer()
                    exitwhen i == 0
                endloop
               
                set tN = QUANTITY
            elseif LIBRARY_Table then
                set tb = Table.create()
            endif
        endmethod
    endmodule
   
    // JassHelper doesn't support static ifs for globals.
    private struct Data extends array
        static if not USE_HASH then
            static integer array data
        endif
        static if LIBRARY_Table then
            static Table tb = 0
        else
            static hashtable ht = InitHashtable()
        endif
        implement Init
    endstruct
   
    // Double free protection
    private function ValidTimer takes integer i returns boolean
        static if LIBRARY_Table then
            return Data.tb.boolean[-i]
        else
            return LoadBoolean(Data.ht, i, 1)
        endif
    endfunction
   
    private function Get takes integer id returns integer
        debug if not ValidTimer(id) then
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to get data from invalid timer.")
        debug endif
        static if USE_HASH then
            static if LIBRARY_Table then
                return Data.tb[id]
            else
                return LoadInteger(Data.ht, id, 0)
            endif
        else
            return Data.data[id - 0x100000]
        endif
    endfunction
   
    private function Set takes integer id, integer data returns nothing
        debug if not ValidTimer(id) then
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to attach data to invalid timer.")
        debug endif
        static if USE_HASH then
            static if LIBRARY_Table then
                set Data.tb[id] = data
            else
                call SaveInteger(Data.ht, id, 0, data)
            endif
        else
            set Data.data[id - 0x100000] = data
        endif
    endfunction
   
    function SetTimerData takes timer t, integer data returns nothing
        call Set(GetHandleId(t), data)
    endfunction
   
    function GetTimerData takes timer t returns integer
        return Get(GetHandleId(t))
    endfunction
   
    function NewTimerEx takes integer data returns timer
        local integer id
        if tN == 0 then
            static if USE_HASH then
                set tT[0] = CreateTimer()
            else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: No Timers In The Stack! You must increase 'QUANTITY'")
                return null
            endif
        else
            set tN = tN - 1
        endif
        set id = GetHandleId(tT[tN])
        static if LIBRARY_Table then
            set Data.tb.boolean[-id] = true
        else
            call SaveBoolean(Data.ht, id, 1, true)
        endif
        call Set(id, data)
        return tT[tN]
    endfunction
   
    function NewTimer takes nothing returns timer
        return NewTimerEx(0)
    endfunction
   
    function ReleaseTimer takes timer t returns integer
        local integer id = GetHandleId(t)
        local integer data = 0
       
        // Pause the timer just in case.
        call PauseTimer(t)
       
        // Make sure the timer is valid.
        if ValidTimer(id) then
            // Get the timer's data.
            set data = Get(id)
           
            // Unmark handle id as a valid timer.
            static if LIBRARY_Table then
                call Data.tb.boolean.remove(-id)
            else
                call RemoveSavedBoolean(Data.ht, id, 1)
            endif
           
            //If it's not run in USE_HASH mode, this next block is useless.
            static if USE_HASH then
           
                //At least clear hash memory while it's in the recycle stack.
                static if LIBRARY_Table then
                    call Data.tb.remove(id)
                else
                    call RemoveSavedInteger(Data.ht, id, 0)
                endif
               
                // If the recycle limit is reached
                if tN == QUANTITY then
                    // then we destroy the timer.
                    call DestroyTimer(t)
                    return data
                endif
            endif
           
            //Recycle the timer.
            set tT[tN] = t
            set tN = tN + 1
           
        //Tried to pass a bad timer.
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to release non-active timer!")
        endif
       
        //Return Timer Data.
        return data
    endfunction

endlibrary

library TimerUtils requires TimerUtilsEx
endlibrary
library SelectionCircle initializer init
   
    /*  SelectionCircle
    *       -   By Aniki
    *       -   Documentation added out of good will.
    *      
    *   Link:   https://www.hiveworkshop.com/threads/show-me-the-ranges.299681/#post-3201943
    *
    *   ________
    *
    *     API
    *   ________
    *
    *       function get_rgba(integer i)
    *           Sets the globals R, G, B, A to their respective values. Integer i is a hex parameter.
    *
    *   struct SelectionCircle
    *           boolean once = true
    *           string file_name
    *           image img
    *           real radius
    *           integer color
    *      
    *           real x
    *           real y
    *
    *           unit target
    *           integer ul_pos = 0
    *
    *           static SelectionCircle array update_list
    *           static integer update_list_len
    *           static code update_cb
    *           static timer ticker = CreateTimer()
    *
    *       method set_radius(real radius)
    *           - Sets the radius of the circle.
    *
    *       static method create(real x, real y, real radius, integer color) returns SelectionCircle
    *           - Constructs a SelectionCircle instance.
    *
    *       static method create_xy(real x, real y, real radius, integer color) returns SelectionCircle
    *           - A wrapper for the constructor above.
    *
    *       static method attach_to_unit(unit u, real radius, integer color) returns SelectionCircle
    *           - Internally calls create_xy and binds it to a list, of which will be iterated over.
    *
    *       method destroy()
    *           - Destroys a SelectionCircle instance.
    *
    *       method set_pos(real x, real y)
    *           - Sets the position of a circular object of a SelectionCircle instance.
    *
    *       method set_dotted(boolean flag)
    *           - Modifies the external properties of the circular object.
    *
    *       Added: (Did not originally exist)
    *           private trigger exec_trig
    *           private triggercondition exec
    *           private integer data
    *           private boolean visible
    *
    *           static SelectionCircle current
    *
    *       method set_listener_event(code exe)
    *           - Removes a previous set of instructions and adds a new set of instructions
    *             to the listening trigger instance.
    *
    *       method set_show(boolean flag)
    *           - Shows or hides a SelectionCircle (untested).
    *
    *       End API description.
    */


    globals
        // SelectionCircle(s) attached to units are updated this frequently
        private constant real Update_Delay = 1.0 / 32.0
    endglobals

    globals
        private integer R
        private integer G
        private integer B
        private integer A
    endglobals
   
    private function get_rgba takes integer i returns nothing
        local boolean is_neg = false

        if i < 0 then
            set is_neg = true
            set i = i + 0x80000000
        endif

        set A = i - i / 0x100 * 0x100
        set i = i / 0x100
        set B = i - i / 0x100 * 0x100
        set i = i / 0x100
        set G = i - i / 0x100 * 0x100
        set i = i / 0x100
        set R = i

        if is_neg then
            set R = R + 0x80
        endif
    endfunction

    struct SelectionCircle
        //  Added for event listening.
        trigger exec_trig
        triggercondition exec
        boolean visible
        integer data
       
        boolean once = true
        string file_name
        image img
        real radius
        integer color

        real x
        real y

        unit target
        integer ul_pos = 0

        method set_radius takes real radius returns nothing
            local SelectionCircle sc = this

            set sc.radius = radius

            // we can't use the check
            //     if sc.img != null
            // because the first image's handle-id is 0 (gj blizzard...)
            // and 0 == null :/
            if sc.once then
                set sc.once = false
            else
                call DestroyImage(sc.img)
            endif

            set sc.img = CreateImage(sc.file_name, /*
                image-width, image-height:*/
2.0*radius, 2.0*radius, 0.0, /*
                image-position: */
sc.x, sc.y, 0.0, /*
                origin: */
radius, radius, 0.0, /*
                image-type: */
1 /*
            */
)

            call SetImageRenderAlways(sc.img, true)
            call get_rgba(sc.color)
            call SetImageColor(sc.img, R, G, B, A)
        endmethod
       
        static method create takes real x, real y, real radius, integer color returns SelectionCircle
            local SelectionCircle sc = SelectionCircle.allocate()

            set sc.file_name = "ReplaceableTextures\\Selection\\SelectionCircleLarge.blp"
            set sc.x = x
            set sc.y = y
            set sc.color = color
            set sc.data = 0
           
            call sc.set_radius(radius)

            return sc
        endmethod

        static method create_xy takes real x, real y, real radius, integer color returns SelectionCircle
            return create(x, y, radius, color)
        endmethod

        static SelectionCircle array update_list
        static SelectionCircle current = 0
       
        static integer update_list_len = 0
        static code update_cb
        static timer ticker = CreateTimer()
       
        //  Modified to accomodate the event listener
        static method attach_to_unit takes unit u, real radius, integer color returns SelectionCircle
            local SelectionCircle sc = create_xy(GetUnitX(u), GetUnitY(u), radius, color)

            set sc.target = u
            set sc.exec_trig = CreateTrigger()
           
            set update_list_len = update_list_len + 1
            set update_list[update_list_len] = sc
            set sc.ul_pos = update_list_len

            if update_list_len == 1 then
                call TimerStart(ticker, Update_Delay, true, update_cb)
            endif

            return sc
        endmethod

        method destroy takes nothing returns nothing
            local SelectionCircle sc = this
            local SelectionCircle last

            call DestroyImage(sc.img)

            if sc.ul_pos != 0 then
                call DestroyTrigger(exec_trig)
               
                set sc.target = null
               
                set last = update_list[update_list_len]
                set last.ul_pos = sc.ul_pos
                set update_list[last.ul_pos] = last
                set update_list_len = update_list_len - 1

                if update_list_len == 0 then
                    call PauseTimer(ticker)
                endif
            endif
           
            set exec = null
           
            call sc.deallocate()
        endmethod

        static method update takes nothing returns nothing
            local integer i
            local SelectionCircle sc

            set i = 1
            loop
                exitwhen i > update_list_len
               
                set SelectionCircle.current = update_list[i]
                set sc = SelectionCircle.current
                set sc.x = GetUnitX(sc.target)
                set sc.y = GetUnitY(sc.target)
                call SetImagePosition(sc.img, sc.x, sc.y, 0.0)
               
                call TriggerEvaluate(sc.exec_trig)
                set i = i + 1
            endloop
        endmethod

        method set_color takes integer color returns nothing
            local SelectionCircle sc = this
            set sc.color = color
            call get_rgba(color)
            call SetImageColor(sc.img, R, G, B, A)
        endmethod

        method set_pos takes real x, real y returns nothing
            local SelectionCircle sc = this
            set sc.x = x
            set sc.y = y
            call SetImagePosition(sc.img, x, y, 0.0)
        endmethod

        method set_dotted takes boolean flag returns nothing
            local SelectionCircle sc = this
            if flag then
                set sc.file_name = "ReplaceableTextures\\Selection\\SelectionCircleLargeDotted.blp"
            else
                set sc.file_name = "ReplaceableTextures\\Selection\\SelectionCircleLarge.blp"
            endif
            call sc.set_radius(sc.radius)
        endmethod
       
        method set_listener_event takes code exe returns nothing
            local SelectionCircle sc = this
            if sc.ul_pos != 0 then
                call TriggerRemoveCondition(sc.exec_trig, sc.exec)
                set exec = TriggerAddCondition(sc.exec_trig, Condition(exe))
            endif
        endmethod
       
        method set_show takes boolean flag returns nothing
            local SelectionCircle sc = this
            call SetImageRenderAlways(sc.img, flag)
        endmethod
       
        method set_show_player takes player p, boolean flag returns nothing
            local SelectionCircle sc = this
            if GetLocalPlayer() == p then
                call SetImageRenderAlways(sc.img, flag)
            endif
        endmethod
    endstruct
   
    private function init takes nothing returns nothing
        set SelectionCircle.update_cb = function SelectionCircle.update
    endfunction

endlibrary
library TimedEffect requires TimerUtils, Table

globals
    private Table destFlagMap   = 0
endglobals

private module Init
    private static method onInit takes nothing returns nothing
        set destFlagMap = Table.create()
    endmethod
endmodule
private struct S extends array
    implement Init
endstruct

private function OnDestroyEffect takes nothing returns nothing
    local integer id            = ReleaseTimer(GetExpiredTimer())
    local effect whichEffect    = destFlagMap.effect[id]
    call destFlagMap.effect.remove(id)
    call DestroyEffect(whichEffect)
    set whichEffect = null
endfunction

function DestroyEffectTimed takes effect whichEffect, real duration returns nothing
    local integer id = GetHandleId(whichEffect)
    if duration <= 0 then
        call DestroyEffect(whichEffect)
        return
    elseif destFlagMap.effect.has(id) then
        return
    endif
    set destFlagMap.effect[id] = whichEffect
    call TimerStart(NewTimerEx(id), duration, false, function OnDestroyEffect)
endfunction

endlibrary
library BezierEasing /* 1.0.0
*************************************************************************************
*
*   Build Cubic Bezier-based Easing functions
*
*   Instead of solving for the point on the cubic bezier curve, BezierEasing
*   solves for output Y where X is the input.
*
*   Useful for adjusting animation rate smoothness
*
*************************************************************************************
*
*   struct BezierEasing extends array
*
*       static method create takes real ax, real ay, real bx, real by returns thistype
*       - points (ax, ay) and (bx, by) are cubic bezier control points on 2D plane.
*       - cx = cubic(0, ax, bx, 1)
*       - cy = cubic(0, ay, by, 1)
*       method operator [] takes real t returns real
*       - real "t" is the given time progression whose value in [0..1] range
*
*************************************************************************************/

globals
    /*
    *   Adjust precision of epsilon's value
    *   higher precision = lower performance
    *
    *   May cause infinite loop if the
    *   precision is too high.
    */

    private constant real EPSILON = 0.00001
endglobals

private function Abs takes real a returns real
    if(a < 0) then
        return -a
    endif
    return a
endfunction

private function Max takes real a, real b returns real
    if(a < b) then
        return b
    endif
    return a
endfunction

/*
*   Float Equality Approximation
*   Accuracy is influenced by EPSILON's value
*/

private function Equals  takes real a, real b returns boolean
    return Abs(a - b) <= EPSILON*Max(1., Max(Abs(a), Abs(b)))
endfunction

private function Bezier3 takes real a, real b, real c, real d, real t returns real
    local real x = 1. - t
    return x*x*x*a + 3*x*x*t*b + 3*x*t*t*c + t*t*t*d
endfunction

private module Init
    private static method onInit takes nothing returns nothing
        call init()
    endmethod
endmodule

struct BezierEasing extends array
    private static thistype array r
   
    private real x1
    private real y1
    private real x2
    private real y2
   
    static method create takes real ax, real ay, real bx, real by returns thistype
        local thistype this = r[0]
        if(r[this] == 0) then
            set r[0] = this + 1
        else
            set r[0] = r[this]
        endif
        set r[this] = -1
       
        set x1 = ax
        set y1 = ay
        set x2 = bx
        set y2 = by
        return this
    endmethod
   
    method operator [] takes real t returns real
        /*
        *   Perform binary search for the equivalent points on curve
        *   by using the t factor of cubic beziers, where the input
        *   is equal to the bezier point's x, and the output is the
        *   point's y, respectively.
        */

        local real lo = 0.
        local real hi = 1.
        local real mid
        local real tx
        local real ty
       
        local real ax = x1
        local real ay = y1
        local real bx = x2
        local real by = y2
       
        /*
        *   Since bezier points lies within
        *   the [0, 1] bracket, just return
        *   the bound values.
        */

        if(Equals(t, 0.)) or (t < 0.) then
            return 0.
        elseif(Equals(t, 1.)) or (t > 1.) then
            return 1.
        endif
       
        /*
        *   Binary Search
        */

        loop
            set mid = (lo + hi)*0.5
            set tx = Bezier3(0, ax, bx, 1, mid)
            set ty = Bezier3(0, ay, by, 1, mid)
           
            if(Equals(t, tx))then
                return ty
            elseif(t < tx) then
                set hi = mid
            else
                set lo = mid
            endif
        endloop
        return 0.
    endmethod
   
    method destroy takes nothing returns nothing
        if(r[this] == -1) then
            set r[this] = r[0]
            set r[0] = this
           
            set x1 = 0.
            set y1 = 0.
            set x2 = 0.
            set y2 = 0.
        endif
    endmethod
   
    private static method init takes nothing returns nothing
        set r[0] = 1
    endmethod
    implement Init
endstruct

struct BezierEase extends array
    readonly static BezierEasing inQuad
    readonly static BezierEasing outQuad
    readonly static BezierEasing inOutQuad
    readonly static BezierEasing inCubic
    readonly static BezierEasing outCubic
    readonly static BezierEasing inOutCubic
    readonly static BezierEasing inQuart
    readonly static BezierEasing outQuart
    readonly static BezierEasing inOutQuart
    readonly static BezierEasing inQuint
    readonly static BezierEasing outQuint
    readonly static BezierEasing inOutQuint
    readonly static BezierEasing inSine
    readonly static BezierEasing outSine
    readonly static BezierEasing inOutSine
    readonly static BezierEasing inBack
    readonly static BezierEasing outBack
    readonly static BezierEasing inOutBack
    readonly static BezierEasing inCirc
    readonly static BezierEasing outCirc
    readonly static BezierEasing inOutCirc
    readonly static BezierEasing inExpo
    readonly static BezierEasing outExpo
    readonly static BezierEasing inOutExpo
   
    private static method init takes nothing returns nothing
        set inSine = BezierEasing.create(0.47, 0, 0.745, 0.715)
        set outSine = BezierEasing.create(0.39, 0.575, 0.565, 1)
        set inOutSine = BezierEasing.create(0.445, 0.05, 0.55, 0.95)
        set inQuad = BezierEasing.create(0.55, 0.085, 0.68, 0.53)
        set outQuad = BezierEasing.create(0.25, 0.46, 0.45, 0.94)
        set inOutQuad = BezierEasing.create(0.455, 0.03, 0.515, 0.955)
        set inCubic = BezierEasing.create(0.55, 0.055, 0.675, 0.19)
        set outCubic = BezierEasing.create(0.215, 0.61, 0.355, 1)
        set inOutCubic = BezierEasing.create(0.645, 0.045, 0.355, 1)
        set inQuart = BezierEasing.create(0.895, 0.03, 0.685, 0.22)
        set outQuart = BezierEasing.create(0.165, 0.84, 0.44, 1)
        set inOutQuart = BezierEasing.create(0.77, 0, 0.175, 1)
        set inQuint = BezierEasing.create(0.755, 0.05, 0.855, 0.06)
        set outQuint = BezierEasing.create(0.23, 1, 0.32, 1)
        set inOutQuint = BezierEasing.create(0.86, 0, 0.07, 1)
        set inExpo = BezierEasing.create(0.95, 0.05, 0.795, 0.035)
        set outExpo = BezierEasing.create(0.19, 1, 0.22, 1)
        set inOutExpo = BezierEasing.create(1, 0, 0, 1)
        set inCirc = BezierEasing.create(0.6, 0.04, 0.98, 0.335)
        set outCirc = BezierEasing.create(0.075, 0.82, 0.165, 1)
        set inOutCirc = BezierEasing.create(0.785, 0.135, 0.15, 0.86)
        set inBack = BezierEasing.create(0.6, -0.28, 0.735, 0.045)
        set outBack = BezierEasing.create(0.175, 0.885, 0.32, 1.275)
        set inOutBack = BezierEasing.create(0.68, -0.55, 0.265, 1.55)
    endmethod
   
    implement Init
endstruct

endlibrary
library AnimationManager requires Table, TimerUtils

/*
    Internal notes: Only 1 AnimationManager can be active
    for a unit at a given time.

    AnimationManager automatically stops when a unit is
    dead. This can be changed in the globals section
*/

globals
    private constant boolean ANIM_DEATH_PERSIST     = false
endglobals

native UnitAlive takes unit id returns boolean

private module AnimationManagerInit
    private static thistype         current             = 0
    private static unit             currentUnit         = null

    private static TableArray       table               = 0
    private static constant integer ANIM_TYPE_MAP       = 0
    private static constant integer ANIM_STRING         = 1
    private static constant integer ANIM_INDEX          = 2
    private static constant integer ANIM_DURATION       = 3
    private static constant integer ANIM_TIMER          = 4
    private static constant integer ANIM_UNIT           = 5

    private static constant integer ANIM_TYPE_STRING    = 0
    private static constant integer ANIM_TYPE_INDEX     = 1

    static method operator [] takes unit whichunit returns thistype
        if currentUnit != whichunit then
            set current     = GetHandleId(whichunit)
            set currentUnit = whichunit
        endif
        return current
    endmethod

    private static method setAnimByIndex takes unit whichunit, integer index, boolean queueStand returns nothing
        call SetUnitAnimationByIndex(whichunit, index)
        if queueStand then
            call QueueUnitAnimation(whichunit, "stand")
        endif
    endmethod

    private static method setAnim takes unit whichunit, string anim, boolean queueStand returns nothing
        call SetUnitAnimation(whichunit, anim)
        if queueStand then
            call QueueUnitAnimation(whichunit, "stand")
        endif
    endmethod

    private method setAnimLoopCore takes nothing returns nothing
        if not table[ANIM_UNIT].unit.has(this) then
            set table[ANIM_UNIT].unit[this]     = currentUnit
        endif
        if not table[ANIM_TIMER].timer.has(this) then
            set table[ANIM_TIMER].timer[this]   = NewTimerEx(this)
        else
            call PauseTimer(table[ANIM_TIMER].timer[this])
        endif
    endmethod

    private method release takes nothing returns nothing
        if table[ANIM_TIMER].timer.has(this) then
            call PauseTimer(table[ANIM_TIMER].timer[this])
            call ReleaseTimer(table[ANIM_TIMER].timer[this])
            if UnitAlive(table[ANIM_UNIT].unit[this]) then
                call setAnim(table[ANIM_UNIT].unit[this], "stand", true)
            endif
        endif
        call table[ANIM_UNIT].unit.remove(this)
        call table[ANIM_TIMER].timer.remove(this)
        call table[ANIM_DURATION].real.remove(this)
        call table[ANIM_INDEX].integer.remove(this)
        call table[ANIM_STRING].string.remove(this)
        call table[ANIM_TYPE_MAP].integer.remove(this)
    endmethod

    private static method onAnimStringLoop takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        if GetUnitTypeId(table[ANIM_UNIT].unit[this]) == 0 then
            call this.release()
            return
        endif
        static if not ANIM_DEATH_PERSIST then
            if not UnitAlive(table[ANIM_UNIT].unit[this]) then
                call this.release()
                return
            endif
        endif
        call setAnim(table[ANIM_UNIT].unit[this], table[ANIM_STRING].string[this], false)
    endmethod

    private static method onAnimIndexLoop takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        if GetUnitTypeId(table[ANIM_UNIT].unit[this]) == 0 then
            call this.release()
            return
        endif
        static if not ANIM_DEATH_PERSIST then
            if not UnitAlive(table[ANIM_UNIT].unit[this]) then
                call this.release()
                return
            endif
        endif
        call setAnimByIndex(table[ANIM_UNIT].unit[this], table[ANIM_INDEX].integer[this], false)
    endmethod

    method setAnimLoop takes string anim, real interval returns nothing
        //  setting anim to null or "" will release the timer handle.
        if anim == null or anim == "" then
            call this.release()
            return
        endif
        call this.setAnimLoopCore()

        if table[ANIM_TYPE_MAP].integer[this] == ANIM_TYPE_INDEX then
            call table[ANIM_INDEX].integer.remove(this)
        endif
        set table[ANIM_TYPE_MAP].integer[this]  = ANIM_TYPE_STRING
        set table[ANIM_STRING].string[this]     = anim
        set table[ANIM_DURATION].real[this]     = interval

        call setAnim(table[ANIM_UNIT].unit[this], anim, false)
        call TimerStart(table[ANIM_TIMER].timer[this], interval, true, function thistype.onAnimStringLoop)
    endmethod

    method setAnimLoopByIndex takes integer index, real interval returns nothing
        //  setting anim to null or "" will release the timer handle.
        if index < 0 then
            call this.release()
            return
        endif
        call this.setAnimLoopCore()

        if table[ANIM_TYPE_MAP].integer[this] == ANIM_TYPE_STRING then
            call table[ANIM_STRING].string.remove(this)
        endif
        set table[ANIM_TYPE_MAP].integer[this]  = ANIM_TYPE_STRING
        set table[ANIM_INDEX].integer[this]     = index
        set table[ANIM_DURATION].real[this]     = interval

        call setAnimByIndex(table[ANIM_UNIT].unit[this], index, false)
        call TimerStart(table[ANIM_TIMER].timer[this], interval, true, function thistype.onAnimIndexLoop)
    endmethod

    private static method onInit takes nothing returns nothing
        set table   = TableArray[6]
    endmethod
endmodule

struct AnimationManager extends array
    implement AnimationManagerInit
endstruct

function UnitAddAnimationLoop takes unit whichunit, string whichanim, real interval returns nothing
    call AnimationManager[whichunit].setAnimLoop(whichanim, interval)
endfunction
function UnitRemoveAnimationLoop takes unit whichunit returns nothing
    call AnimationManager[whichunit].setAnimLoop("", 1)
endfunction

endlibrary
library LinkedList /* v1.3.0 https://www.hiveworkshop.com/threads/linkedlist-modules.325635/


    */
uses /*

    */
optional ErrorMessage /*  https://github.com/nestharus/JASS/blob/master/jass/Systems/ErrorMessage/main.j


    */
//! novjass

    /*
        Author:
            - AGD
        Credits:
            - Nestharus, Dirac, Bribe
                > For their scripts and discussions which I used as reference

        Pros:
            - Feature-rich (Can be)
            - Modular
            - Safety-oriented (On DEBUG_MODE, but not 100% fool-proof ofcourse)
            - Flexible (Does not enforce a built-in allocator - allows user to choose between a custom Alloc
              or the default vjass allocator, or neither)
            - Extensible (Provides interfaces)

        Note:
            If you are using using Dirac's 'LinkedListModule' library, you need to replace its contents with
            the compatibility lib provided alongside this library for all to work seamlessly.

    */

    |-----|
    | API |
    |-----|
    /*
    Note: All the fields except from 'prev' and 'next' are actually operators, so you might want to
          avoid using them from the interface methods that would be declared above them.
    =====================================================================================================
    List Fields Modules (For those who want to write or inline the core linked-list operations themselves)

      */
module LinkedListFields/*

          */
readonly thistype prev/*
          */
readonly thistype next/*


      */
module StaticListFields extends LinkedListFields/*

          */
readonly static constant thistype sentinel/*
          */
readonly static thistype front/*
          */
readonly static thistype back/*
          */
readonly static boolean empty/*


      */
module ListFields extends LinkedListFields/*

          */
readonly thistype front/*
          */
readonly thistype back/*
          */
readonly boolean empty/*

    =====================================================================================================
    Lite List Modules (Should be enough for most cases)

      */
module LinkedListLite extends LinkedListFields/*

          */
optional interface static method onInsert takes thistype node returns nothing/*
          */
optional interface static method onRemove takes thistype node returns nothing/*
          */
optional interface method onTraverse takes thistype node returns boolean/*

          */
static method insert takes thistype prev, thistype node returns nothing/*
          */
static method remove takes thistype node returns nothing/*

          */
method traverseForwards takes nothing returns nothing/*
          */
method traverseBackwards takes nothing returns nothing/*
                - Only present if onTraverse() is also present


      */
module StaticListLite extends StaticListFields, LinkedListLite/*

          */
static method pushFront takes thistype node returns nothing/*
          */
static method popFront takes nothing returns thistype/*

          */
static method pushBack takes thistype node returns nothing/*
          */
static method popBack takes nothing returns thistype/*


      */
module ListLite extends ListFields, LinkedListLite/*

          */
method pushFront takes thistype node returns nothing/*
          */
method popFront takes nothing returns thistype/*

          */
method pushBack takes thistype node returns nothing/*
          */
method popBack takes nothing returns thistype/*


      */
module InstantiatedListLite extends ListLite/*

          */
interface static method allocate takes nothing returns thistype/*
          */
interface method deallocate takes nothing returns nothing/*
          */
optional interface method onConstruct takes nothing returns nothing/*
          */
optional interface method onDestruct takes nothing returns nothing/*

          */
static method create takes nothing returns thistype/*
          */
method destroy takes nothing returns nothing/*

    =====================================================================================================
    Standard List Modules

      */
module LinkedList extends LinkedListLite/*

          */
static method isLinked takes thistype node returns boolean/*


      */
module StaticList extends StaticListLite, LinkedList/*

          */
static method clear takes nothing returns nothing/*
          */
static method flush takes nothing returns nothing/*


      */
module List extends ListLite, LinkedList/*

          */
static method makeHead takes thistype node returns nothing/*
          */
method clear takes nothing returns nothing/*
          */
method flush takes nothing returns nothing/*


      */
module InstantiatedList extends InstantiatedListLite, List/*
 
    =====================================================================================================
    Feature-rich List Modules (For those who somehow need exotic linked-list operations)

      */
module LinkedListEx extends LinkedList/*

          */
static method move takes thistype prev, thistype node returns nothing/*
          */
static method swap takes thistype nodeA, thistype nodeB returns nothing/*


      */
module StaticListEx extends StaticList, LinkedListEx/*

          */
static method contains takes thistype node returns boolean/*
          */
static method getSize takes nothing returns integer/*
          */
static method rotateLeft takes nothing returns nothing/*
          */
static method rotateRight takes nothing returns nothing/*


      */
module ListEx extends List, LinkedListEx/*

          */
method contains takes thistype node returns boolean/*
          */
method getSize takes nothing returns integer/*
          */
method rotateLeft takes nothing returns nothing/*
          */
method rotateRight takes nothing returns nothing/*


      */
module InstantiatedListEx extends InstantiatedList, ListEx/*


    */
//! endnovjass

    /*========================================= CONFIGURATION ===========================================
    *   Only affects DEBUG_MODE
    *   If false, throws warnings instead (Errors pauses the game (Or stops the thread) while warnings do not)
    */

    globals
        private constant boolean THROW_ERRORS = true
    endglobals
    /*====================================== END OF CONFIGURATION =====================================*/

    static if DEBUG_MODE then
        public function AssertError takes boolean condition, string methodName, string structName, integer node, string message returns nothing
            static if LIBRARY_ErrorMessage then
                static if THROW_ERRORS then
                    call ThrowError(condition, SCOPE_PREFIX, methodName, structName, node, message)
                else
                    call ThrowWarning(condition, SCOPE_PREFIX, methodName, structName, node, message)
                endif
            else
                if condition then
                    static if THROW_ERRORS then
                        call BJDebugMsg("|cffff0000[ERROR]|r [Library: " + SCOPE_PREFIX + "] [Struct: " + structName + "] [Method: " + methodName + "] [Instance: " + I2S(node) + "] : |cffff0000" + message + "|r")
                        call PauseGame(true)
                    else
                        call BJDebugMsg("|cffffcc00[WARNING]|r [Library: " + SCOPE_PREFIX + "] [Struct: " + structName + "] [Method: " + methodName + "] [Instance: " + I2S(node) + "] : |cffffcc00" + message + "|r")
                    endif
                endif
            endif
        endfunction
    endif

    private module LinkedListUtils
        method p_clear takes nothing returns nothing
            set this.next.prev = 0
            set this.prev.next = 0
            set this.prev = this
            set this.next = this
        endmethod
        method p_flush takes nothing returns nothing
            local thistype node = this.prev
            loop
                exitwhen node == this
                call remove(node)
                set node = node.prev
            endloop
        endmethod
    endmodule
    private module LinkedListUtilsEx
        implement LinkedListUtils
        method p_contains takes thistype toFind returns boolean
            local thistype node = this.next
            loop
                exitwhen node == this
                if node == toFind then
                    return true
                endif
                set node = node.next
            endloop
            return false
        endmethod
        method p_getSize takes nothing returns integer
            local integer count = 0
            local thistype node = this.next
            loop
                exitwhen node == this
                set count = count + 1
                set node = node.next
            endloop
            return count
        endmethod
    endmodule

    private module LinkedListLiteBase
        implement LinkedListFields
        debug method p_isEmptyHead takes nothing returns boolean
            debug return this == this.next and this == this.prev
        debug endmethod
        static method p_insert takes thistype this, thistype node returns nothing
            local thistype next = this.next
            set node.prev = this
            set node.next = next
            set next.prev = node
            set this.next = node
        endmethod
        static method p_remove takes thistype node returns nothing
            set node.next.prev = node.prev
            set node.prev.next = node.next
        endmethod
        static method insert takes thistype this, thistype node returns nothing
            debug call AssertError(node == 0, "insert()", "thistype", 0, "Cannot insert null node")
            debug call AssertError(not node.p_isEmptyHead() and (node.next.prev == node or node.prev.next == node), "insert()", "thistype", 0, "Already linked node [" + I2S(node) + "]: prev = " + I2S(node.prev) + " ; next = " + I2S(node.next))
            call p_insert(this, node)
            static if thistype.onInsert.exists then
                call onInsert(node)
            endif
        endmethod
        static method remove takes thistype node returns nothing
            debug call AssertError(node == 0, "remove()", "thistype", 0, "Cannot remove null node")
            debug call AssertError(node.next.prev != node and node.prev.next != node, "remove()", "thistype", 0, "Invalid node [" + I2S(node) + "]")
            static if thistype.onRemove.exists then
                call onRemove(node)
            endif
            call p_remove(node)
        endmethod
        static if thistype.onTraverse.exists then
            method p_traverse takes boolean forward returns nothing
                local thistype node
                local thistype next
                debug local thistype prev
                debug local boolean array traversed
                if forward then
                    set node = this.next
                    loop
                        exitwhen node == this or node.prev.next != node
                        debug call AssertError(traversed[node], "traverseForwards()", "thistype", this, "A node was traversed twice in a single traversal")
                        debug set traversed[node] = true
                        debug set prev = node.prev
                        set next = node.next
                        if this.onTraverse(node) then
                            call remove(node)
                            debug set traversed[node] = false
                        debug elseif next.prev == prev then
                            debug set traversed[node] = false
                        endif
                        set node = next
                    endloop
                else
                    set node = this.prev
                    loop
                        exitwhen node == this or node.next.prev != node
                        debug call AssertError(traversed[node], "traverseBackwards()", "thistype", this, "A node was traversed twice in a single traversal")
                        debug set traversed[node] = true
                        debug set prev = node.next
                        set next = node.prev
                        if this.onTraverse(node) then
                            call remove(node)
                            debug set traversed[node] = false
                        debug elseif next.prev == prev then
                            debug set traversed[node] = false
                        endif
                        set node = next
                    endloop
                endif
            endmethod
            method traverseForwards takes nothing returns nothing
                call this.p_traverse(true)
            endmethod
            method traverseBackwards takes nothing returns nothing
                call this.p_traverse(false)
            endmethod
        endif
    endmodule
    private module LinkedListBase
        implement LinkedListLiteBase
        static method isLinked takes thistype node returns boolean
            return node.next.prev == node or node.prev.next == node
        endmethod
    endmodule

    module LinkedListFields
        readonly thistype prev
        readonly thistype next
    endmodule
    module LinkedListLite
        implement LinkedListLiteBase
        implement optional LinkedListLiteModuleCompatibility // For API compatibility with Dirac's 'LinkedListModule' library
    endmodule
    module LinkedList
        implement LinkedListBase
        implement optional LinkedListModuleCompatibility // For API compatibility with Dirac's 'LinkedListModule' library
    endmodule
    module LinkedListEx
        implement LinkedListBase
        static method p_move takes thistype prev, thistype node returns nothing
            call p_remove(node)
            call p_insert(prev, node)
        endmethod
        static method move takes thistype prev, thistype node returns nothing
            debug call AssertError(not isLinked(node), "move()", "thistype", 0, "Cannot use unlinked node [" + I2S(node) + "]")
            call p_move(prev, node)
        endmethod
        static method swap takes thistype this, thistype node returns nothing
            local thistype thisPrev = this.prev
            local thistype thisNext = this.next
            debug call AssertError(this == 0, "swap()", "thistype", 0, "Cannot swap null node")
            debug call AssertError(node == 0, "swap()", "thistype", 0, "Cannot swap null node")
            debug call AssertError(not isLinked(this), "swap()", "thistype", 0, "Cannot use unlinked node [" + I2S(this) + "]")
            debug call AssertError(not isLinked(node), "swap()", "thistype", 0, "Cannot use unlinked node [" + I2S(node) + "]")
            call p_move(node, this)
            if thisNext != node then
                call p_move(thisPrev, node)
            endif
        endmethod
    endmodule

    module StaticListFields
        implement LinkedListFields
        static constant method operator head takes nothing returns thistype
            return 0
        endmethod
        static method operator back takes nothing returns thistype
            return head.prev
        endmethod
        static method operator front takes nothing returns thistype
            return head.next
        endmethod
        static method operator empty takes nothing returns boolean
            return front == head
        endmethod
    endmodule
    module StaticListLite
        implement StaticListFields
        implement LinkedListLiteBase
        static method pushFront takes thistype node returns nothing
            debug call AssertError(node == 0, "pushFront()", "thistype", 0, "Cannot use null node")
            debug call AssertError(not node.p_isEmptyHead() and (node.next.prev == node or node.prev.next == node), "pushFront()", "thistype", 0, "Already linked node [" + I2S(node) + "]: prev = " + I2S(node.prev) + " ; next = " + I2S(node.next))
            call insert(head, node)
        endmethod
        static method popFront takes nothing returns thistype
            local thistype node = front
            debug call AssertError(node.prev != head, "popFront()", "thistype", 0, "Invalid list")
            call remove(node)
            return node
        endmethod
        static method pushBack takes thistype node returns nothing
            debug call AssertError(node == 0, "pushBack()", "thistype", 0, "Cannot use null node")
            debug call AssertError(not node.p_isEmptyHead() and (node.next.prev == node or node.prev.next == node), "pushBack()", "thistype", 0, "Already linked node [" + I2S(node) + "]: prev = " + I2S(node.prev) + " ; next = " + I2S(node.next))
            call insert(back, node)
        endmethod
        static method popBack takes nothing returns thistype
            local thistype node = back
            debug call AssertError(node.next != head, "popBack()", "thistype", 0, "Invalid list")
            call remove(node)
            return node
        endmethod
    endmodule
    module StaticList
        implement StaticListLite
        implement LinkedListBase
        implement LinkedListUtils
        static method clear takes nothing returns nothing
            call head.p_clear()
        endmethod
        static method flush takes nothing returns nothing
            call head.p_flush()
        endmethod
    endmodule
    module StaticListEx
        implement StaticList
        implement LinkedListEx
        implement LinkedListUtilsEx
        static method contains takes thistype node returns boolean
            return head.p_contains(node)
        endmethod
        static method getSize takes nothing returns integer
            return head.p_getSize()
        endmethod
        static method rotateLeft takes nothing returns nothing
            call p_move(back, front)
        endmethod
        static method rotateRight takes nothing returns nothing
            call p_move(head, back)
        endmethod
    endmodule

    module ListFields
        implement LinkedListFields
        method operator back takes nothing returns thistype
            return this.prev
        endmethod
        method operator front takes nothing returns thistype
            return this.next
        endmethod
        method operator empty takes nothing returns boolean
            return this.next == this
        endmethod
    endmodule
    module ListLite
        implement ListFields
        implement LinkedListLiteBase
        method pushFront takes thistype node returns nothing
            debug call AssertError(this == 0, "pushFront()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev != this, "pushFront()", "thistype", this, "Invalid list")
            debug call AssertError(node == 0, "pushFront()", "thistype", this, "Cannot insert null node")
            debug call AssertError(not node.p_isEmptyHead() and (node.next.prev == node or node.prev.next == node), "pushFront()", "thistype", this, "Already linked node [" + I2S(node) + "]: prev = " + I2S(node.prev) + " ; next = " + I2S(node.next))
            call insert(this, node)
        endmethod
        method popFront takes nothing returns thistype
            local thistype node = this.next
            debug call AssertError(this == 0, "popFront()", "thistype", 0, "Null list")
            debug call AssertError(node.prev != this, "popFront()", "thistype", this, "Invalid list")
            call remove(node)
            return node
        endmethod
        method pushBack takes thistype node returns nothing
            debug call AssertError(this == 0, "pushBack()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev != this, "pushBack()", "thistype", this, "Invalid list")
            debug call AssertError(node == 0, "pushBack()", "thistype", this, "Cannot insert null node")
            debug call AssertError(not node.p_isEmptyHead() and (node.next.prev == node or node.prev.next == node), "pushBack()", "thistype", this, "Already linked node [" + I2S(node) + "]: prev = " + I2S(node.prev) + " ; next = " + I2S(node.next))
            call insert(this.prev, node)
        endmethod
        method popBack takes nothing returns thistype
            local thistype node = this.prev
            debug call AssertError(this == 0, "popBack()", "thistype", 0, "Null list")
            debug call AssertError(node.next != this, "pushFront()", "thistype", this, "Invalid list")
            call remove(node)
            return node
        endmethod
    endmodule
    module List
        implement ListLite
        implement LinkedListBase
        implement LinkedListUtils
        static method makeHead takes thistype node returns nothing
            set node.prev = node
            set node.next = node
        endmethod
        method clear takes nothing returns nothing
            debug call AssertError(this == 0, "clear()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev != this, "clear()", "thistype", this, "Invalid list")
            call this.p_clear()
        endmethod
        method flush takes nothing returns nothing
            debug call AssertError(this == 0, "flush()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev != this, "flush()", "thistype", this, "Invalid list")
            call this.p_flush()
        endmethod
    endmodule
    module ListEx
        implement List
        implement LinkedListEx
        implement LinkedListUtilsEx
        method contains takes thistype node returns boolean
            debug call AssertError(this == 0, "contains()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev != this, "contains()", "thistype", this, "Invalid list")
            return this.p_contains(node)
        endmethod
        method getSize takes nothing returns integer
            debug call AssertError(this == 0, "getSize()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev != this, "getSize()", "thistype", this, "Invalid list")
            return this.p_getSize()
        endmethod
        method rotateLeft takes nothing returns nothing
            debug call AssertError(this == 0, "rotateLeft()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev != this, "rotateLeft()", "thistype", this, "Invalid list")
            call p_move(this.back, this.front)
        endmethod
        method rotateRight takes nothing returns nothing
            debug call AssertError(this == 0, "rotateRight()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev == this, "rotateRight()", "thistype", this, "Invalid list")
            call p_move(this, this.back)
        endmethod
    endmodule

    module InstantiatedListLite
        implement ListLite
        debug private boolean valid
        static method create takes nothing returns thistype
            local thistype node = allocate()
            set node.prev = node
            set node.next = node
            debug set node.valid = true
            static if thistype.onConstruct.exists then
                call node.onConstruct()
            endif
            return node
        endmethod
        method destroy takes nothing returns nothing
            debug call AssertError(this == 0, "destroy()", "thistype", 0, "Null list")
            debug call AssertError(this.next.prev != this, "destroy()", "thistype", this, "Invalid list")
            debug call AssertError(not this.valid, "destroy()", "thistype", this, "Double-free")
            debug set this.valid = false
            static if thistype.flush.exists then
                call this.flush()
            endif
            static if thistype.onDestruct.exists then
                call this.onDestruct()
            endif
            debug set this.prev = 0
            debug set this.next = 0
            call this.deallocate()
        endmethod
    endmodule
    module InstantiatedList
        implement List
        implement InstantiatedListLite
    endmodule
    module InstantiatedListEx
        implement ListEx
        implement InstantiatedList
    endmodule

endlibrary
library Missile /* version 3.0.2 (Unofficial Update for patches 1.30+)
Unofficial updates link: https://www.hiveworkshop.com/threads/missile.265370/page-13#post-3429957
*************************************************************************************
*
*   Creating custom projectiles in Warcraft III.
*
*   Major goal:
*       No unessary external requirements.
*       Implements code optional.
*
*   Philosophy:
*       I want that feature --> Compiler writes that code into your map script.
*       I don't want that   --> Compiler ignores that code completely.
*
*   Important:
*       Take yourself 2 minutes time to setup Missile correctly.
*       Otherwise I can't guarantee, that Missile works the way you want.
*       Once the setup is done, you can check out some examples and Missile will be easy
*       to use for everyone. I promise it.
*
*       Do the setup at:
*
*           1.) Import instruction
*           2.) Global configuration
*           3.) Function configuration    
*
*   Credits to Dirac, emjlr3, AceHart, Bribe, Wietlol,
*              Nestharus, Maghteridon96, Vexorian and Zwiebelchen.
*
*************************************************************************************
*
*   */
requires /*
*
*       */
Table                    /*  https://www.hiveworkshop.com/threads/188084/
*
*       */
LinkedList               /*  https://www.hiveworkshop.com/threads/325635/
*           - Make the vJass code shorter and more readable
*
*************************************************************************************
*
*   Optional requirements listed can reduce overall code generation,
*   add safety mechanisms, decrease overhead and optimize handle management.
*   For a better overview I put them into blocks.
*
*   I recommend to use at least one per block in your map.
*
*   a) For best debug results: ( Useful )
*       */
optional ErrorMessage    /*  https://github.com/nestharus/JASS/blob/master/jass/Systems/ErrorMessage/main.j
*
*   b) Fatal error protection: ( Case: unit out moves of world bounds )
*           - WorldBounds is safer than BoundSentinel.
*           - WorldBounds adds more overhead than BoundSentinel.
*           - Using none of these two forces Missile to switch from SetUnitX/Y to the SetUnitPosition native.
*       */
optional WorldBounds     /*  https://github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
*       */
optional BoundSentinel   /*  wc3c.net/showthread.php?t=102576
*
*   c) Unit indexing: ( Avoid an onIndex event )
*           - not required for Missile. Only if you use one already.
*       */
optional UnitIndexer     /*  github.com/nestharus/JASS/tree/master/jass/Systems/Unit%20Indexer
*
*   d) Allocator:
*           - Reduces generated codes and variables
*           - Takes advantage of the new JASS_MAX_ARRAY_SIZE value for patches 1.29+
*       */
optional Alloc           /*  https://www.hiveworkshop.com/threads/324937/
*
*   e) Game version detection:
*           - Helps fix bugs introduced in 1.30.x related to new SFX natives
*       */
optional GameVersion     /*  https://www.hiveworkshop.com/threads/308204/
*
************************************************************************************
*
*   1. Import instruction
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*       • Copy Missile into to your map.
*       • You need a dummy unit, using Vexorians "dummy.mdx".
*         This unit must use the locust and crow form ability. ( Aloc & Amrf )
*                   ¯¯¯¯
*
*   2. Global configuration
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*       Seven constants to setup!
*/

    globals

        /**
        *   Missiles are moved periodically. An interval of 1./32. is recommended.
        *       • Too short timeout intervals may cause performance issues.
        *       • Too large timeout intervals may look fishy.
        */

        public constant real TIMER_TIMEOUT                          = 1./32.

        /**
        *   Owner of all Missile dummies. Should be a neutral player in your map.
        *
        *   (Depreciated in version 3.0.0)
        */

        public constant player NEUTRAL_PASSIVE                      = Player(PLAYER_NEUTRAL_PASSIVE)

        /**
        *   Raw code of the dummy unit. Object Editor ( F6 )
        *       • Must be correct, otherwise missile dummies can neither be recycled nor destroyed.
        *       • Units of other type ids will not be thrown into the recycler bin.
        *
        *   (Depreciated in version 3.0.0)
        */

        public constant integer DUMMY_UNIT_ID                       = 'dumi'

        /**
        *   The maximum collision size used in your map. If unsure use 197. ( Town hall collision )
        *       • Applies for all types of widgets.
        *       • A precise value can improve Missile's performance,
        *         since smaller values enumerate less widgtes per loop per missile.
        */

        public constant real MAXIMUM_COLLISION_SIZE                 = 197.

        /**
        *   Collision types for missiles. ( Documentation only )
        *   Missile decides internally each loop which type of collision is required.
        *       • Uses circular collision dectection for speed < collision. ( Good accuracy, best performance )
        *       • Uses rectangle collision for speed >= collision. ( Best accuracy, normal performance )
        */

        public constant integer COLLISION_TYPE_CIRCLE               = 0
        public constant integer COLLISION_TYPE_RECTANGLE            = 1

        /**
        *   Determine when rectangle collision is required to detect nearby widgets.
        *       • The smaller the factor the earlier rectangle collision is used. ( by default 1. )
        *       • Formula: speed >= collision*Missile_COLLISION_ACCURACY_FACTOR
        */

        public constant real    COLLISION_ACCURACY_FACTOR           = 1.

// Optional toogles:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      Set booleans listed below to "true" and the compiler will write
//      the feature into your map. Otherwise this code is completly ignored.                                      
//          • Yay, I want that           --> "true"
//          • Naah that's useless for me --> "false"

        /**
        *   USE_COLLISION_Z_FILTER enables z axis checks for widget collision. ( Adds minimal overhead )
        *   Use it when you need:
        *       • Missiles flying over or under widgets.
        *       • Determine between flying and walking units.
        */

        public constant boolean USE_COLLISION_Z_FILTER              = true

        /**
        *   WRITE_DELAYED_MISSILE_RECYCLING enables a delayed dummy recycling system. ( Very recommended )
        *   Use it if:
        *       • You use a dummy recycling library like MissileRecycler, Dummy or xedummy.
        *       • You want to properly display death animations of effects added to missiles.
        *
        *   (Depreciated in version 3.0.0)
        */

        public constant boolean WRITE_DELAYED_MISSILE_RECYCLING     = true

        /**
        *   DELAYED_MISSILE_DEATH_ANIMATION_TIME is the delay in seconds
        *   Missile holds back a dummy, before recycling it.
        *       • The time value does not have to be precise.
        *       • Requires WRITE_DELAYED_MISSILE_RECYCLING = true
        *
        *   (Depreciated in version 3.0.0)
        */

        private constant real DELAYED_MISSILE_DEATH_ANIMATION_TIME  = 2.

        /**
        *   USE_DESTRUCTABLE_FILTER and USE_ITEM_FILTER are redundant constants from previous Missile versions.
        *   They do nothing, but remain for backwards compatibilty.
        *   From Missile version 1.5 on all widget collisions are always enabled.
        */

        public constant boolean USE_DESTRUCTABLE_FILTER             = true
        public constant boolean USE_ITEM_FILTER                     = true
    endglobals
/*  
*  3. Function configuration
*  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*       Four functions to setup!
*/

    /**
    *   GetUnitBodySize(unit) returns a fictional value for z - axis collision.
    *   You have two options:
    *       • One constant value shared over all units.
    *       • Dynamic values based on handle id, type id, unit user data, scaling or other parameters.
    */

    function GetUnitBodySize takes unit whichUnit returns real
        return 100.// Other example: return LoadReal(hash, GetHandleId(whichUnit), KEY_UNIT_BODY_SIZE)
    endfunction

    /**
    *   Same as GetUnitBodySize, but for destructables.
    *   Using occluder height is an idea of mine. Of course you can use your own values.
    */

    function GetDestructableHeight takes destructable d returns real
        return GetDestructableOccluderHeight(d)// Other example: return 100.
    endfunction

    /**
    *   Same as GetUnitBodySize, but for items.
    *   Again it's up to you to figure out a fictional item height.
    */

    function GetItemHeight takes item i returns real
        return 16.
    endfunction
   
    /**
    *   Unit indexers and missiles ( Only if you don't use a dummy recycling library )
    *   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    *   It is most likely intended that projectiles don't run through a unit indexing process.
    *   ToogleUnitIndexer runs:
    *       • Directly before a dummy is created.
    *       • Directly after dummy unit creation.
    *
    *   Please return the previous setup of your indexing tool ( enabled, disabled ),
    *   so Missile can properly reset it to the original state.
    */

    private function ToogleUnitIndexer takes boolean enable returns boolean
        local boolean prev = true//UnitIndexer.enabled
        // set UnitIndexer.enabled = enable
        return prev
    endfunction

/**
*   4. API
*   ¯¯¯¯¯¯
*/

//! novjass ( Disables the compiler until the next endnovjass )

        // Custom type Missile for your projectile needs.
        struct Missile extends array

        // Constants:
        // ==========
            //
            readonly static constant string ORIGIN = "origin"
            //  • Attach point name for fxs on dummies.

            readonly static constant real   HIT_BOX = (2./3.)
            //  • Fictional hit box for homing missiles.
            //    while 0 would be the toe and 1 the head of a unit.

        // Available creators:
        // ===================
            //
            static method createEx takes unit missileDummy, real impactX, real impactY, real impactZ returns Missile
            //  • Core creator method.
            //  • May launches any unit.
            //  • Units of type Missile_DUMMY_UNIT_ID get recycled in the end.

            static method create takes real x, real y, real z, real angleInRadians, real distanceToTravel, real endZ returns Missile
            //  • Converts arguments to fit into createEx, then calls createEx.

            static method createXYZ takes real x, real y, real z, real impactX, real impactY, real impactZ returns Missile
            //  • Converts arguments to fit into createEx, then calls createEx.

        // Available destructors:
        // ======================
            //
            return true
            //  • Core destructor.
            //  • Returning true in any of the interface methods of the MissileStruct module
            //    will destroy that instance instantly.

            method destroy   takes nothing returns nothing
            //  • Destroys the missile during the next timer callback.

            method terminate takes nothing returns nothing
            //  • Destroys the missile instantly.

        // Fields you can set and read directly:
        // =====================================
            //
            unit       source
            unit       target      // For homing missiles.
            real       distance    // Distance traveled.
            player     owner       // Pseudo owner for faster onCollide evaluation. The proper dummy owner remains PLAYER_NEUTRAL_PASSIVE.
            real       speed       // Vector lenght for missile movement in plane x / y. ( DOES NOT TAKE THE TIMER TIMEOUT IN ACCOUNT )
            real       acceleration
            real       damage
            real       turn        // Set a turn rate for missiles.
            integer    data        // For data transfer set and read data.
            boolean    recycle     // Is automatically set to true, when a Missile reaches it's destination.
            boolean    wantDestroy // Set wantDestroy to true, to destroy a missile during the next timer callback.

            // Neither collision nor collisionZ accept values below zero.
            real       collision   // Collision size in plane x / y.
            real       collisionZ  // Collision size in z - axis. ( deprecated )

        // Fields you can only read:
        // =========================    
            //
            readonly boolean         allocated      
            readonly unit            dummy// The dummy unit of this missile.

            // Position members for you needs.
            readonly MissilePosition origin// Grants access to readonly members of MissilePosition,
            readonly MissilePosition impact// which are "x", "y", "z", "angle", "distance", "slope" and the pitch angle "alpha".
                                           // Furthermore method origin.move(x, y, z) and impact.move(x, y, z).
            readonly real            terrainZ
            readonly real            x
            readonly real            y
            readonly real            z
            readonly real            angle// Current angle in radians.

        // Method operators for set and read:
        // ==================================
            //
            method operator model= takes string modelFile returns nothing
            method operator model  takes nothing returns string
            //  • Adds an effect handle on a missile dummy to it's "origin".
            //  • You can read the file path.
            //  • For multiple effects access "this.dummy" in your struct.

            method operator scale= takes real value returns nothing
            method operator scale  takes nothing returns real
            //  • Set and read the scaling of the dummy unit.

            method operator curve= takes real value returns nothing
            method operator curve  takes nothing returns real
            //  • Enables curved movement for your missile. ( Pass in radians, NOT degrees )
            //  • Do not pass in PI/2.

            method operator arc=   takes real value returns nothing
            method operator arc    takes nothing returns real
            //  • Enables arcing movement for your missile. ( Pass in radians, NOT degrees )
            //  • Do not pass in PI/2.

        // Methods for missile movement:
        // =============================
            //
            method bounce           takes nothing returns nothing
            //  • Moves the MissilePosition "origin" to the current missile coordinates.
            //  • Resets the distance traveled to 0.

            method deflect          takes real tx, real ty returns nothing
            //  • Deflect the missile towards tx, ty. Then calls bounce.      

            method deflectEx        takes real tx, real ty, real tz returns nothing
            //  • Deflect the missile towards tx, ty, tz. Then calls bounce.

            method flightTime2Speed takes real duration returns nothing
            //  • Converts a fly time to a vector lenght for member "speed".
            //  • Does not take acceleration into account. ( Disclaimer )

            method setMovementSpeed takes real value returns nothing
            //  • Converts Warcraft III movement speed to a vector lenght for member "speed".

        // Methods for missile collision: ( all are hashtable entries )
        // ==============================
            // By default a widget can only be hit once per missile.
            //
            method hitWidget        takes widget w returns nothing
            //  • Saves a widget in the memory as hit by this instance.

            method hasHitWidget     takes widget w returns boolean
            //  • Returns true, if "w" has been hit by this instance.

            method removeHitWidget  takes widget w returns nothing
            //  • Removes a widget from this missile's memory for widget collision. ( Can hit "w" again )

            method flushHitWidgets  takes nothing returns nothing
            //  • Flushes a missile's memory for widget collision. ( All widgets can be hit again )

            method enableHitAfter   takes widget w, real seconds returns nothing
            //  • Automatically calls removeHitWidget(w) after "seconds" time. ( Can hit "w" again after given time )

        // UPDATE 3.0.0 ADDITIONAL FEATURES:
        // ============================

            method effect.addModel      takes string model  returns effect
            method effect.removeModel   takes string model  returns nothing
            method effect.clearModels   takes nothing       returns nothing
            //  • Adds/removes/clears Missile sfx models

            method effect.getHandle     takes string model  returns effect
            //  • For Missiles with multiple sfx models, allows you to access those individual <effect> handles
            //  • Useful for example if one wants some <effect> to have a certain offset from the Missile's origin

        // Module MissileStruct:
        // =====================
            //
            module MissileLaunch // ( optional )
            module MissileStruct
            //  • Enables the entire missile interface for that struct.

        // Interface in structs: ( Must implement module MissileStruct )
        // =====================
            //
            //  • Write one, many or all of the static method below into your struct.
            //  • Missiles launched in this struct will run those methods, when their events fire.
            //
            //  • All of those static methods must return a boolean.
            //      a) return true  --> destroys the missile instance instantly.
            //      b) return false --> keep on flying.

        // Available static method:
        // ========================
            //
            static method onCollide            takes Missile missile, unit hit returns boolean
            //  • Runs for units in collision range of a missile.

            static method onDestructable       takes Missile missile, destructable hit returns boolean
            //  • Runs for destructables in collision range of a missile.

            static method onItem               takes Missile missile, item hit returns boolean
            //  • Runs for items in collision range of a missile.

            static method onTerrain takes Missile missile returns boolean
            //  • Runs when a missile collides with the terrain. ( Ground and cliffs )

            static method onFinish  takes Missile missile returns boolean
            //  • Runs only when a missile reaches it's destination.
            //  • However does not run, if a Missile is destroyed in another method.

            static method onPeriod  takes Missile missile returns boolean
            //  • Runs every Missile_TIMER_TIMEOUT seconds.

            static method onRemove takes Missile missile returns boolean
            //  • Runs when a missile is destroyed.
            //  • Unlike onFinish, onRemove will runs ALWAYS when a missile is destroyed!!!
            //
            //  For onRemove the returned boolean has a unique meaning:
            //  • Return true will recycle this missile delayed. ( Only if WRITE_DELAYED_MISSILE_RECYCLING = true )
            //  • Return false will recycle this missile right away.

            static method launch takes Missile toLaunch returns nothing
            //  • Well ... Launches this Missile.
            //  • Missile "toLaunch" will behave as declared in the struct. ( static methods from above )

    // Misc: ( From the global setup )
    // =====
        //
        // Constants:
        // ==========
            //
            public constant real    TIMER_TIMEOUT              
            public constant player  NEUTRAL_PASSIVE          
            public constant integer DUMMY_UNIT_ID              
            public constant real    MAXIMUM_COLLISION_SIZE        
            public constant boolean USE_COLLISION_Z_FILTER          
            public constant boolean WRITE_DELAYED_MISSILE_RECYCLING  
            public constant boolean USE_DESTRUCTABLE_FILTER          
            public constant boolean USE_ITEM_FILTER

            readonly static constant string ORIGIN
            readonly static constant real   HIT_BOX

        // Functions:
        // ==========
            //
            public function GetLocZ               takes real x, real y returns real
                   function GetUnitBodySize       takes unit whichUnit returns real
                   function GetDestructableHeight takes destructable d returns real
                   function GetItemHeight         takes item i returns real

//========================================================================
// Missile system. Make changes carefully.
//========================================================================

//! endnovjass ( Enables the compiler )

// Hello and welcome to Missile.
// I wrote a guideline for every piece of code inside Missile, so you
// can easily understand how the it gets compiled and evaluated.
//
// Let's go!
    private keyword Init

    globals
        // Core constant handle variables of Missile.
        private constant trigger   CORE  = CreateTrigger()
        private constant trigger   MOVE  = CreateTrigger()
        private constant timer     TMR   = CreateTimer()
        private constant location  LOC   = Location(0., 0.)
        private constant rect      RECT  = Rect(0., 0., 0., 0.)
        private constant group     GROUP = CreateGroup()
        // For starting and stopping the timer.
        private integer active = 0
        // Arrays for data structure.
        private integer          array   instances
        private Missile          array   missileList
        private boolexpr         array   expression
        private triggercondition array   condition
        private integer          array   removed
        private boolean          array   destroying
        private boolean          array   recycling
        // Internal widget filter functions.
        private boolexpr destFilter
        private boolexpr itemFilter
        private boolexpr unitFilter

        private TableArray table
        private boolean fixedRotationAxes
    endglobals
   
    public function GetLocZ takes real x, real y returns real
        call MoveLocation(LOC, x, y)
        return GetLocationZ(LOC)
    endfunction

    /*
    *   Detects game version - Credits to TriggerHappy
    *   https://www.hiveworkshop.com/threads/308204/
    */

    private function IsRotationAxesFixed takes nothing returns boolean
        static if LIBRARY_GameVersion then
            return GetPatchLevel() == PATCH_LEVEL_131
        else
            local image img = CreateImage("ReplaceableTextures\\WorldEditUI\\Editor-Toolbar-MapValidation.blp", 64, 64, 0, 0,0,0,64,64,0, 1)
            local string tmp = GetLocalizedString("ERROR_ID_CDKEY_INUSE")

            if (GetHandleId(img) == -1) then
                return false
            endif
            call DestroyImage(img)

            return not ((JASS_MAX_ARRAY_SIZE <= 8192) or (GetLocalizedString("DOWNLOADING_MAP") == "DOWNLOADING_MAP") or (SubString(tmp, StringLength(tmp)-1, StringLength(tmp)) == ")") or (GetLocalizedString("WINDOW_MODE_WINDOWED") == "WINDOW_MODE_WINDOWED"))
        endif
    endfunction

    /*===============================================================================================*/

    /*
    *   One allocator for the whole library
    */

    private struct Node extends array
        static if LIBRARY_Alloc then
            implement optional Alloc
        else
            /*
            *   Credits to MyPad for the allocation algorithm
            */

            private static thistype array stack
            static method allocate takes nothing returns thistype
                local thistype node = stack[0]
                if stack[node] == 0 then
                    static if LIBRARY_ErrorMessage then
                        debug call ThrowError(node == (JASS_MAX_ARRAY_SIZE - 1), "Missile", "allocate()", "thistype", node, "Overflow")
                    endif
                    set node = node + 1
                    set stack[0] = node
                else
                    set stack[0] = stack[node]
                    set stack[node] = 0
                endif
                return node
            endmethod
            method deallocate takes nothing returns nothing
                static if LIBRARY_ErrorMessage then
                    debug call ThrowError(this == 0, "Missile", "deallocate()", "thistype", 0, "Null node")
                    debug call ThrowError(stack[this] > 0, "Missile", "deallocate()", "thistype", this, "Double-free")
                endif
                set stack[this] = stack[0]
                set stack[0] = this
            endmethod
        endif
    endstruct

    /*
    *   For calculating <effect> orientation
    */

    private struct EulerAngles extends array
        private static constant integer XY_STEPS    = 420
        private static constant integer Z_STEPS     = 270

        private static TableArray angleTable
        private static real xyDelta                 = (2.00*bj_PI)/XY_STEPS
        private static real zDelta                  = (2.00*bj_PI)/Z_STEPS
        private static integer zSteps               = 0

        readonly static real yaw                    = 0.00
        readonly static real pitch                  = 0.00
        readonly static real roll                   = 0.00

        static method from takes real xyAngle, real zAngle returns nothing
            local integer key
            set xyAngle     = ModuloReal(xyAngle, 2.00*bj_PI)
            set zAngle      = ModuloReal(zAngle, 2.00*bj_PI)
            set key         = R2I(zAngle/zDelta)*XY_STEPS + R2I(xyAngle/xyDelta)
            set yaw         = angleTable[0].real[key]
            set pitch       = angleTable[1].real[key]
            set roll        = angleTable[2].real[key]
        endmethod

        /*
        *   Based on Cyclotrutan's algorithm
        *   https://www.hiveworkshop.com/threads/orienteffect.313410/
        */

        private static method initAngles takes integer key, real dx, real dy, real dz returns nothing
            local real N = dx*dx + dy*dy
            local real norm = N + dz*dz
            local real cp
            local real pitch

            if norm == 0 then
                return
            endif

            set norm = 1.00001*SquareRoot(norm)

            set dx = dx/norm
            set dy = dy/norm
            set dz = dz/norm

            if N == 0 then
                set angleTable[0].real[key] = 0.00
                set angleTable[2].real[key] = 0.00

                if dz > 0 then
                    set angleTable[1].real[key] = -bj_PI*0.5
                else
                    set angleTable[1].real[key] = bj_PI*0.5
                endif

                return
            endif

            set N = SquareRoot(N)

            if dy < 0 then
                set pitch = Asin(dx*dz/N) + bj_PI
                set cp = Cos(pitch)

                if fixedRotationAxes then
                    set angleTable[0].real[key] = Acos(dx/cp)
                    set angleTable[2].real[key] = -Asin(dy*dz/(N*cp)) + bj_PI
                else
                    set angleTable[0].real[key] = -Asin(dy*dz/(N*cp)) + bj_PI
                    set angleTable[2].real[key] = Acos(dx/cp)
                endif
            else
                set pitch = -Asin(dx*dz/N)
                set cp = Cos(pitch)

                if fixedRotationAxes then
                    set angleTable[0].real[key] = Acos(dx/cp)
                    set angleTable[2].real[key] = Asin(dy*dz/(N*cp))
                else
                    set angleTable[0].real[key] = Asin(dy*dz/(N*cp))
                    set angleTable[2].real[key] = Acos(dx/cp)
                endif
            endif
            set angleTable[1].real[key] = pitch
        endmethod

        private static method initOrientationTables takes integer zStep returns nothing
            local real xy = Cos(zStep*zDelta)
            local real z = Sin(zStep*zDelta)
            local integer xySteps = 0
            loop
                exitwhen xySteps == XY_STEPS
                call initAngles(zStep*XY_STEPS + xySteps, xy*Cos(xySteps*xyDelta), xy*Sin(xySteps*xyDelta), z)
                set xySteps = xySteps + 1
            endloop
        endmethod

        private static method initTables takes nothing returns nothing
            call initOrientationTables(zSteps)
            call initOrientationTables(zSteps + Z_STEPS/2)
        endmethod

        static method onScopeInit takes nothing returns nothing
            set angleTable = TableArray[3]
            set fixedRotationAxes = IsRotationAxesFixed()
            loop
                exitwhen zSteps == Z_STEPS/2
                call ForForce(bj_FORCE_PLAYER[0], function thistype.initTables)
                set zSteps = zSteps + 1
            endloop
        endmethod
    endstruct

    /*
    *   List of <effect>s
    */

    private struct EffectHandle extends array
        effect effect

        private static method onRemove takes thistype node returns nothing
            call DestroyEffect(node.effect)
            set node.effect = null
            call Node(node).deallocate()
        endmethod

        private static method allocate takes nothing returns thistype
            return Node.allocate()
        endmethod
        private method deallocate takes nothing returns nothing
            call Node(this).deallocate()
        endmethod

        implement InstantiatedList
    endstruct

    /*
    *   Effect is a cluster of <effect>s that can easily be controlled as a single object
    */

    private struct Effect extends array
        private static TableArray lookupTable

        private method operator handle takes nothing returns EffectHandle
            return this
        endmethod

        method operator missile takes nothing returns Missile
            return this
        endmethod

        method addModel takes string model returns effect
            local EffectHandle node = Node.allocate()
            set lookupTable[this][StringHash(model)] = node
            set node.effect = AddSpecialEffect(model, this.missile.x, this.missile.y)
            call BlzSetSpecialEffectZ(node.effect, this.missile.z)
            call BlzSetSpecialEffectScale(node.effect, this.missile.scale)
            call this.handle.pushBack(node)
            return node.effect
        endmethod
        method removeModel takes string model returns nothing
            local integer stringId = StringHash(model)
            call EffectHandle.remove(lookupTable[this][stringId])
            call lookupTable[this].remove(stringId)
        endmethod
        method clearModels takes nothing returns nothing
            call this.handle.flush()
            call lookupTable[this].flush()
        endmethod

        method getHandle takes string model returns effect
            return EffectHandle(lookupTable[this][StringHash(model)]).effect
        endmethod

        method scale takes real value returns nothing
            local EffectHandle node = this.handle.next
            loop
                exitwhen node == this.handle
                call BlzSetSpecialEffectScale(node.effect, value)
                set node = node.next
            endloop
        endmethod

        method move takes real x, real y, real z returns nothing
            local EffectHandle node = this.handle.next
            local real dx = x - this.missile.x
            local real dy = y - this.missile.y
            local real dz = z - this.missile.z
            static if not LIBRARY_BoundSentinel and not LIBRARY_WorldBounds then
                if not RectContainsCoords(bj_mapInitialPlayableArea, x, y) then
                    return
                endif
            elseif LIBRARY_WorldBounds then
                if not (x < WorldBounds.maxX and x > WorldBounds.minX and y < WorldBounds.maxY and y > WorldBounds.minY) then
                    return
                endif
            endif
            loop
                exitwhen node == this.handle
                call BlzSetSpecialEffectPosition(node.effect, BlzGetLocalSpecialEffectX(node.effect) + dx, BlzGetLocalSpecialEffectY(node.effect) + dy, BlzGetLocalSpecialEffectZ(node.effect) + dz)
                set node = node.next
            endloop
        endmethod

        method orient takes real xyAngle, real pitch returns nothing
            local EffectHandle node = this.handle.next
            call EulerAngles.from(xyAngle, pitch)
            loop
                exitwhen node == this.handle
                call BlzSetSpecialEffectOrientation(node.effect, EulerAngles.yaw, EulerAngles.pitch, EulerAngles.roll)
                set node = node.next
            endloop
        endmethod

        static method create takes nothing returns thistype
            return EffectHandle.create()
        endmethod
        method destroy takes nothing returns nothing
            call lookupTable[this].flush()
            call this.handle.destroy()
        endmethod

        static method onScopeInit takes nothing returns nothing
            set lookupTable = TableArray[JASS_MAX_ARRAY_SIZE]
        endmethod
    endstruct

    // Simple trigonometry.
    struct MissilePosition extends array
        readonly real x
        readonly real y
        readonly real z
        readonly real angle
        readonly real distance
        readonly real square
        readonly real slope
        readonly real alpha

        // Creates an origin - impact link.
        private thistype ref

        private static method math takes thistype a, thistype b returns nothing
            local real dx
            local real dy
            loop
                set dx = b.x - a.x
                set dy = b.y - a.y
                set dx = dx*dx + dy*dy
                set dy = SquareRoot(dx)
                exitwhen dx != 0. and dy != 0.
                set b.x = b.x + .01
                set b.z = b.z - Missile_GetLocZ(b.x -.01, b.y) + Missile_GetLocZ(b.x, b.y)
            endloop

            set a.square   = dx
            set a.distance = dy
            set a.angle    = Atan2(b.y - a.y, b.x - a.x)
            set a.slope    = (b.z - a.z)/dy
            set a.alpha    = Atan(a.slope)*bj_RADTODEG
            // Set b.
            if b.ref == a then
                set b.angle     = a.angle + bj_PI
                set b.distance  = dy
                set b.slope     = -a.slope
                set b.alpha     = -a.alpha
                set b.square    = dx
            endif
        endmethod

        static method link takes thistype a, thistype b returns nothing
            set a.ref = b
            set b.ref = a
            call math(a, b)
        endmethod

        method move takes real toX, real toY, real toZ returns nothing
            set x = toX
            set y = toY
            set z = toZ + Missile_GetLocZ(toX, toY)
            if ref != this then
                call math(this, ref)
            endif
        endmethod

        static method create takes real x, real y, real z returns MissilePosition
            local thistype this = Node.allocate()
            set ref = this
            call move(x, y, z)
            return this
        endmethod
        method destroy takes nothing returns nothing
            call Node(this).deallocate()
        endmethod

    endstruct

    struct MissileList extends array
        method operator missile takes nothing returns Missile
            return this
        endmethod
        implement StaticList
    endstruct

    struct Missile extends array

        // Attach point name for effects created by model=.
        readonly static constant string ORIGIN = "origin"

        // Set a ficitional hit box in range of 0 to 1,
        // while 0 is the toe and 1 the head of a unit.
        readonly static constant real HIT_BOX  = (2./3.)

        // Checks for double launching. Throws an error message.
        debug boolean launched

        // The position of a missile using curve= does not
        // match the position used by Missile's trigonometry.
        // Therefore we need this member two times.
        // Readable x / y / z for your needs and posX / posY for cool mathematics.
        private real posX
        private real posY
        private real dist// distance

        // Readonly members:
        // =================
        //
        // Prevents a double free case.
        readonly boolean allocated

        // The dummy unit.
        readonly unit    dummy

        // Position members for your needs.
        readonly MissilePosition origin// Grants access to readonly members of MissilePosition,
        readonly MissilePosition impact// which are "x", "y", "z", "angle", "distance", "slope" and "alpha".
        readonly real            terrainZ
        readonly real            x
        readonly real            y
        readonly real            z
        readonly real            angle// Current angle
        readonly real            prevX
        readonly real            prevY
        readonly real            prevZ

        // Collision detection type. ( Evaluated new in each loop )
        readonly integer         collisionType// Current collision type ( circular or rectangle )

        unit       source
        unit       target      // For homing missiles.
        real       distance    // Distance traveled.
        player     owner       // Pseudo owner for faster onCollide evaluation. The proper dummy owner is PLAYER_NEUTRAL_PASSIVE.
        real       speed       // Vector lenght for missile movement in plane x / y.
        real       acceleration
        real       damage
        integer    data        // For data transfer set and read data.
        boolean    recycle     // Is set to true, when a Missile reaches it's destination.
        real       turn        // Sets a turn rate for a missile.
        real       collision   // Collision size in plane x / y.

        private static method onInsert takes thistype node returns nothing
            call MissileList.pushBack(node)
        endmethod
        private static method onRemove takes thistype node returns nothing
            call MissileList.remove(node)
        endmethod
        implement List

        static method p_makeHead takes thistype node returns nothing
            set node.prev = node
            set node.next = node
        endmethod

        method operator effect takes nothing returns Effect
            return this
        endmethod

        // Setting collision z is deprecated since Missile v2.5.
        method operator collisionZ= takes real value returns nothing
        endmethod
        method operator collisionZ takes nothing returns real
            return collision
        endmethod

        method operator sfx takes nothing returns effect
            return null
        endmethod

        private string path
        method operator model= takes string file returns nothing
            call effect.clearModels()
            // null and ""
            if StringLength(file) > 0 then
                call effect.addModel(file)
                set path = file
            else
                set path = null
            endif
        endmethod
        method operator model takes nothing returns string
            return path
        endmethod

        real open
        // Enables curved movement for your missile.
        // Remember that the result of Tan(PI/2) is infinity.
        method operator curve= takes real value returns nothing
            set open = Tan(value)*origin.distance
        endmethod
        method operator curve takes nothing returns real
            return Atan(open/origin.distance)
        endmethod

        private real height
        // Enables arcing movement for your missile.
        method operator arc= takes real value returns nothing
            set height = Tan(value)*origin.distance/4
        endmethod
        method operator arc takes nothing returns real
            return Atan(4*height/origin.distance)
        endmethod

        private real scaling
        method operator scale= takes real value returns nothing
            call SetUnitScale(dummy, value, 0., 0.)
            call effect.scale(value)
            set scaling = value
        endmethod
        method operator scale takes nothing returns real
            return scaling
        endmethod

        method bounce takes nothing returns nothing
            call origin.move(x, y, z)
            set dist = 0.
        endmethod

        method deflect takes real tx, real ty returns nothing
            local real a = 2.*Atan2(ty - y, tx - x) + bj_PI - angle
            call impact.move(x + (origin.distance - dist)*Cos(a), y + (origin.distance - dist)*Sin(a), impact.z)
            call bounce()
        endmethod

        method deflectEx takes real tx, real ty, real tz returns nothing
            call impact.move(impact.x, impact.y, tz)
            call deflect(tx, ty)
        endmethod

        method flightTime2Speed takes real duration returns nothing
            set speed = RMaxBJ(0.00000001, (origin.distance - dist)*Missile_TIMER_TIMEOUT/RMaxBJ(0.00000001, duration))
        endmethod

        method setMovementSpeed takes real value returns nothing
            set speed = value*Missile_TIMER_TIMEOUT
        endmethod

        boolean wantDestroy// For "true" a missile is destroyed on the next timer callback. 100% safe.
        method destroy takes nothing returns nothing
            set wantDestroy = true
        endmethod

        // Instantly destroys a missile.
        method terminate takes nothing returns nothing
            if allocated then
                set allocated = false
                call impact.destroy()
                call origin.destroy()

                call table[this].flush()
                set source = null
                set target = null
                set dummy = null
                set owner = null

                call this.effect.destroy()
                call remove(this)
            endif
        endmethod

        // Runs in createEx.
        private method resetMembers takes nothing returns nothing
            set path = null
            set speed = 0.
            set acceleration = 0.
            set distance = 0.
            set dist = 0.
            set height = 0.
            set turn = 0.
            set open = 0.
            set collision = 0.
            set collisionType = 0
            set stackSize = 0
            set scaling = 1.
            set wantDestroy = false
            set recycle = false
        endmethod

        // Launches a dummy of your choice.
        static method createEx takes unit missileDummy, real impactX, real impactY, real impactZ returns thistype
            local real originX  = GetUnitX(missileDummy)
            local real originY  = GetUnitY(missileDummy)
            local real originZ  = GetUnitFlyHeight(missileDummy)
            local thistype this = Effect.create()

            call resetMembers()

            set origin = MissilePosition.create(originX, originY, originZ)
            set impact = MissilePosition.create(impactX, impactY, impactZ)
            call MissilePosition.link(origin, impact)

            set posX      = originX
            set posY      = originY
            set x         = originX
            set y         = originY
            set z         = originZ
            set angle     = origin.angle
            set dummy     = missileDummy
            set allocated = true

            if UnitAddAbility(missileDummy, 'Arav') then
                call UnitRemoveAbility(missileDummy, 'Arav')
            endif

            call SetUnitFlyHeight(missileDummy, originZ, 0.)
            set table[this].unit[GetHandleId(missileDummy)] = missileDummy

            static if LIBRARY_ErrorMessage then
                debug call ThrowWarning(GetUnitTypeId(missileDummy) == 0, "Missile", "createEx", "missileDummy", this, "Invalid missile dummy unit ( null )!")
            endif
            debug set launched = false
            return this
        endmethod

        // Wrapper to createEx.
        static method create takes real x, real y, real z, real angle, real distance, real impactZ returns thistype
            local real impactX = x + distance*Cos(angle)
            local real impactY = y + distance*Sin(angle)
            local thistype this = Effect.create()

            call resetMembers()

            set origin = MissilePosition.create(x, y, z)
            set impact = MissilePosition.create(impactX, impactY, impactZ)
            call MissilePosition.link(origin, impact)

            set .posX       = x
            set .posY       = y
            set .x          = x
            set .y          = y
            set .z          = z
            set angle       = origin.angle
            set dummy       = null
            set allocated   = true

            debug set launched = false
            return this
        endmethod

        static method createXYZ takes real x, real y, real z, real impactX, real impactY, real impactZ returns thistype
            local real dx = impactX - x
            local real dy = impactY - y
            local real dz = impactZ - z

            return create(x, y, z, Atan2(dy, dx), SquareRoot(dx*dx + dy*dy), impactZ)
        endmethod

        // Missile motion takes place every Missile_TIMER_TIMEOUT
        // before accessing each active struct.
        static Missile temp = 0
        static method move takes nothing returns boolean
            local integer loops = 0   // Current iteration.
            local integer limit = 150 // Set iteration border per trigger evaluation to avoid hitting the operation limit.
            local thistype this = thistype.temp

            local MissilePosition p
            local real a
            local real d
            local unit u
            local real newX
            local real newY
            local real newZ
            local real vel
            local real point
            loop
                exitwhen this == MissileList.head or loops == limit
                set p = origin

                // Save previous, respectively current missile position.
                set prevX = x
                set prevY = y
                set prevZ = z

                // Evaluate the collision type.
                set vel = speed
                set speed = vel + acceleration
                if vel < collision*Missile_COLLISION_ACCURACY_FACTOR then
                    set collisionType = Missile_COLLISION_TYPE_CIRCLE
                else
                    set collisionType = Missile_COLLISION_TYPE_RECTANGLE
                endif

                // Update missile guidance to its intended target.
                set u = target
                if u != null then
                    if 0 == GetUnitTypeId(u) then
                        set target = null
                    else
                        call origin.move(x, y, z)
                        call impact.move(GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u) + GetUnitBodySize(u)*Missile.HIT_BOX)
                        set dist = 0
                        set height = 0
                        set curve = 0
                    endif
                endif
                set a = p.angle

                // Update the missile facing angle depending on the turn ratio.
                if 0. != turn and Cos(angle - a) < Cos(turn) then
                    if 0. > Sin(a - angle) then
                        set angle = angle - turn
                    else
                        set angle = angle + turn
                    endif
                else
                    set angle = a
                endif

                // Update the missile position on the parabola.
                set d = p.distance// origin - impact distance.

                set recycle = dist + vel >= d
                if recycle then
                    set point = d
                    set distance = distance + d - dist
                else
                    set distance = distance + vel
                    set point = dist + vel
                endif
                set dist = point

                set newX = posX + vel*Cos(angle)
                set newY = posY + vel*Sin(angle)
                set posX = newX
                set posY = newY

                // Update point(x/y) if a curving trajectory is defined.
                set u = dummy
                if 0. != open and target == null then
                    set vel = 4*open*point*(d - point)/p.square
                    set a = angle + bj_PI/2
                    set newX = newX + vel*Cos(a)
                    set newY = newY + vel*Sin(a)
                    set a = angle + Atan(-((4*open)*(2*point - d))/p.square)
                else
                    set a = angle
                endif

                // Update pos z if an arc or height is set.
                call MoveLocation(LOC, newX, newY)
                set terrainZ = GetLocationZ(LOC)
                if 0. == height and 0. == p.alpha then
                    set newZ = p.z - terrainZ
                else
                    set newZ = p.z - terrainZ + p.slope*point
                    if 0. != height and target == null then
                        set newZ = newZ + (4*height*point*(d - point)/p.square)
                    endif
                endif

                // Set missile position and orientation
                call .effect.move(newX, newY, newZ)
                call .effect.orient(a, Atan2(newZ - prevZ, vel))

                if u != null then
                    call SetUnitFlyHeight(u, newZ, 0.)
                    call SetUnitFacing(u, a*bj_RADTODEG)
                    call SetUnitLookAt(u, "bone_head", u, 2.*newX - prevX, 2.*newY - prevY, 2.*newZ - prevZ)

                    // WorldBounds > BoundSentinel.
                    static if not LIBRARY_BoundSentinel and not LIBRARY_WorldBounds then
                        if RectContainsCoords(bj_mapInitialPlayableArea, newX, newY) then
                            call SetUnitX(u, newX)
                            call SetUnitY(u, newY)
                        endif
                    elseif LIBRARY_WorldBounds then
                        if newX < WorldBounds.maxX and newX > WorldBounds.minX and newY < WorldBounds.maxY and newY > WorldBounds.minY then
                            call SetUnitX(u, newX)
                            call SetUnitY(u, newY)
                        endif
                    else
                        call SetUnitX(u, newX)
                        call SetUnitY(u, newY)
                    endif
                endif

                set .x = newX
                set .y = newY
                set .z = newZ

                set loops = loops + 1
                set this = MissileList(this).next
            endloop

            set u = null
            set thistype.temp = this
            return this == MissileList.head
        endmethod
           
        // Widget collision API:
        // =====================
        //
        // Runs automatically on widget collision.
        method hitWidget takes widget w returns nothing
            if w != null then
                set table[this].widget[GetHandleId(w)] = w
            endif
        endmethod

        // All widget which have been hit return true.
        method hasHitWidget takes widget w returns boolean
            return table[this].handle.has(GetHandleId(w))
        endmethod

        // Removes a widget from the missile's memory of hit widgets. ( This widget can be hit again )
        method removeHitWidget takes widget w returns nothing
            if w != null then
                call table[this].handle.remove(GetHandleId(w))
            endif
        endmethod

        // Flushes a missile's memory for collision. ( All widgets can be hit again )
        method flushHitWidgets takes nothing returns nothing
            call table[this].flush()
            call hitWidget(dummy)
        endmethod

        // Tells missile to call removeHitWidget(w) after "seconds" time.
        // Does not apply to widgets, which are already hit by this missile.
        readonly integer stackSize
        method enableHitAfter takes widget w, real seconds returns nothing
            local integer id = GetHandleId(w)
            local Table t
            if w != null then
                set t = table[this]
                if not t.has(id) then
                    set t[id] = stackSize
                    set t[stackSize] = id
                    set stackSize = stackSize + 1
                endif
                set t.real[id] = seconds
            endif
        endmethod

        method updateStack takes nothing returns nothing
            local integer dex = 0
            local integer id
            local real time
            local Table t
            loop
                exitwhen dex == stackSize
                set t = table[this]
                set id = t[dex]
                set time = t.real[id] - Missile_TIMER_TIMEOUT
                if time <= 0. or not t.handle.has(id) then
                    set stackSize = stackSize - 1
                    set id = t[stackSize]
                    set t[dex] = id
                    set t[id] = dex
                    // Enables hit.
                    call t.handle.remove(id)
                    // Remove data from stack.
                    call t.real.remove(id)
                    call t.remove(id)
                    call t.remove(stackSize)
                else
                    set t.real[id] = time
                    set dex = dex + 1
                endif
            endloop
        endmethod

        // Widget collision code:
        // ======================
        //
        private static boolean circle = true
        //
        // 1.) Rectangle collision for fast moving missiles with small collision radius.
        //
        // Runs for destructables and items in a rectangle.
        // Checks if widget w is in collision range of a missile.
        // Is not precise in z - axis collision.
        private method isWidgetInRectangle takes widget w, real wz, real distance returns boolean
            local real wx = GetWidgetX(w)
            local real wy = GetWidgetY(w)
            local real dz = Missile_GetLocZ(wx, wy) - terrainZ
            local real dx = x - prevX
            local real dy = y - prevY
            local real s  = (dx*(wx - prevX) + dy*(wy - prevY))/(dx*dx + dy*dy)

            if s < 0. then
                set s = 0.
            elseif s > 1 then
                set s = 1.
            endif
            set dx = (prevX + s*dx) - wx
            set dy = (prevY + s*dy) - wy

            return dx*dx + dy*dy <= distance*distance and dz + wz >= z - distance and dz <= z + distance
        endmethod
        //
        // 2.) Circular collision detection for all other missiles.
        //
        // Returns true for widgets in a xyz collision range.
        private method isWidgetInRange takes widget w, real wz, real distance returns boolean
            local real wx = GetWidgetX(w)
            local real wy = GetWidgetY(w)
            local real dz = Missile_GetLocZ(wx, wy) - terrainZ
            //     collision in plane x and y,            collision in z axis.
            return IsUnitInRangeXY(dummy, wx, wy, distance) and dz + wz >= z - distance and dz <= z + distance
        endmethod
        //
        //  3.) Action functions inside the widget enumeration thread.
        //
        // Runs for every enumerated destructable.
        //  • Directly filters out already hit destructables.
        //  • Distance formula based on the Pythagorean theorem.
        //                      
        private static method filterDests takes nothing returns boolean
            local destructable d = GetFilterDestructable()
            local boolean b = false
            if not table[temp].handle.has(GetHandleId(d)) then
                if circle then
                    set b = temp.isWidgetInRange(d, GetDestructableHeight(d), temp.collision)
                else
                    set b = temp.isWidgetInRectangle(d, GetDestructableHeight(d), temp.collision)
                endif
            endif
            set d = null
            return b
        endmethod
        //
        // Runs for every enumerated item.
        //  • Directly filters out already hit items.
        //  • Distance formula based on the Pythagorean theorem.
        //  • Items have a fix collision size of 16.
        //
        private static method filterItems takes nothing returns boolean
            local item i = GetFilterItem()
            local boolean b = false
            if not table[temp].handle.has(GetHandleId(i)) then
                if circle then                                        // Item in missile collision size or item pathing in missile range.
                    set b = temp.isWidgetInRange(i, GetItemHeight(i), RMaxBJ(temp.collision, 16.))
                else
                    set b = temp.isWidgetInRectangle(i, GetItemHeight(i), RMaxBJ(temp.collision, 16.))
                endif
            endif
            set i = null
            return b
        endmethod
        //
        //  4.) Filter function for rectangle unit collision.
        //
        // Runs for every enumerated units.
        //  • Filters out units which are not in collision range in plane x / y.
        //  • Inlined and therefore a bit faster than item and destructable collision.
        //
        private static method filterUnits takes nothing returns boolean
            local thistype this = thistype.temp
            local unit u = GetFilterUnit()
            local real dx
            local real dy
            local real s
            local boolean is = false

            if not table[this].handle.has(GetHandleId(u)) then
                set dx = x - prevX
                set dy = y - prevY
                set s = (dx*(GetUnitX(u) - prevX) + dy*(GetUnitY(u)- prevY))/(dx*dx + dy*dy)
                if s < 0. then
                    set s = 0.
                elseif s > 1. then
                    set s = 1.
                endif
                set is = IsUnitInRangeXY(u, prevX + s*dx, prevY + s*dy, collision)
            endif
           
            set u = null
            return is
        endmethod
        //
        // 5.) Proper rect preparation.
        //
        // For rectangle.
        private method prepareRectRectangle takes nothing returns nothing
            local real x1 = prevX
            local real y1 = prevY
            local real x2 = x
            local real y2 = y
            local real d = collision + Missile_MAXIMUM_COLLISION_SIZE
            // What is min, what is max ...
            if x1 < x2 then
                if y1 < y2 then
                    call SetRect(RECT, x1 - d, y1 - d, x2 + d, y2 + d)
                else
                    call SetRect(RECT, x1 - d, y2 - d, x2 + d, y1 + d)
                endif
            elseif y1 < y2 then
                call SetRect(RECT, x2 - d, y1 - d, x1 + d, y2 + d)
            else
                call SetRect(RECT, x2 - d, y2 - d, x1 + d, y1 + d)
            endif
        endmethod
        //
        // For circular.
        private method prepareRectCircle takes nothing returns nothing
            local real d = collision + Missile_MAXIMUM_COLLISION_SIZE
            call SetRect(RECT, x - d, y - d, x + d, y + d)
        endmethod
        //
        // 5.) API for the MissileStruct iteration.
        //
        method groupEnumUnitsRectangle takes nothing returns nothing
            call prepareRectRectangle()
            set thistype.temp = this
            call GroupEnumUnitsInRect(GROUP, RECT, unitFilter)
        endmethod
        //
        // Prepares destructable enumeration, then runs enumDests.
        method checkDestCollision takes code func returns nothing
            set circle = collisionType == Missile_COLLISION_TYPE_CIRCLE
            if circle then
                call prepareRectCircle()
            else
                call prepareRectRectangle()
            endif

            set thistype.temp = this
            call EnumDestructablesInRect(RECT, destFilter, func)
        endmethod
        //
        // Prepares item enumeration, then runs enumItems.
        method checkItemCollision takes code func returns nothing
            set circle = collisionType == Missile_COLLISION_TYPE_CIRCLE
            if circle then
                call prepareRectCircle()
            else
                call prepareRectRectangle()
            endif

            set thistype.temp = this
            call EnumItemsInRect(RECT, itemFilter, func)
        endmethod

static if Missile_WRITE_DELAYED_MISSILE_RECYCLING then
    method nullBefore takes nothing returns nothing
    endmethod
endif

// Does not check for 'Aloc' and 'Amrf' as they could be customized.
        private static method onScopeInit takes nothing returns nothing
            static if LIBRARY_ErrorMessage then
                debug call ThrowError((Missile_MAXIMUM_COLLISION_SIZE < 0), "Missile", "DEBUG_MISSILE", "collision",  0, "Global setup for public real MAXIMUM_COLLISION_SIZE is incorrect, below zero! This map currently can't use Missile!")
            endif

            set unitFilter = Filter(function thistype.filterUnits)
            set destFilter = Filter(function thistype.filterDests)
            set itemFilter = Filter(function thistype.filterItems)
            call TriggerAddCondition(MOVE, Condition(function thistype.move))

            set table = TableArray[JASS_MAX_ARRAY_SIZE]
        endmethod
        implement Init
    endstruct

    // Boolean expressions per struct:
    // ===============================
    //
    // Condition function for the core trigger evaluation. ( Runs for all struct using module MissileStruct )
    private function MissileCreateExpression takes integer structId, code func returns nothing
        set expression[structId] = Condition(func)
    endfunction

    // Creates a collection for a struct. ( Runs for all struct using module MissileStruct )
    private function MissileCreateCollection takes integer structId returns nothing
        local Missile node = Node.allocate()
        call Missile.p_makeHead(node) // Make a circular list
        set missileList[structId] = node
    endfunction

    // Core:
    // =====
    //
    // Fires every Missile_TIMER_TIMEOUT.
    private function Fire takes nothing returns nothing
        local integer i = removed[0]
        set removed[0] = 0
        loop
            exitwhen 0 == i
            if recycling[i] then
                call TriggerRemoveCondition(CORE, condition[i])
                set condition[i] = null
                set active = active - 1
            endif
            set destroying[i] = false
            set recycling[i] = false
            set i = removed[i]
        endloop

        if 0 == active then
            call PauseTimer(TMR)
        else
            // Move all launched missiles.
            //set Missile.temp = nextNode[0]
            set Missile.temp = MissileList.front
            set i = 0
            loop
                exitwhen TriggerEvaluate(MOVE)
                exitwhen i == 60// Moved over 8910 missiles, something buggy happened.
                set i = i + 1   // This case is impossible, hence never happens. But if I'm wrong, which also never happens
            endloop             // then the map 100% crashes. i == 66 will prevent the game crash and Missile will start to
                                // to debug itself over the next iterations.

            // Access all structs using module MissileStruct.
            static if DEBUG_MODE and LIBRARY_ErrorMesssage then
                if not TriggerEvaluate(CORE) then
                    call ThrowWarning(true, "Missile", "Fire", "op limit", 0, /*
*/
"You just ran into a op limit!
The op limit protection of Missile is insufficient for your map.
The code of the missile module can't run in one thread and must be splitted.
If unsure make a post in the official 'The Hive Workshop' forum thread of Missile!"
)
                endif
            else
                call TriggerEvaluate(CORE)
            endif
        endif
    endfunction

    // Conditionally starts the timer.
    private function StartPeriodic takes integer structId returns nothing
        if 0 == instances[structId] or destroying[structId] then          
            if destroying[structId] then
                set recycling[structId] = false
            else
                if 0 == active then
                    call TimerStart(TMR, Missile_TIMER_TIMEOUT, true, function Fire)
                endif
                set active = active + 1
                set condition[structId] = TriggerAddCondition(CORE, expression[structId])
            endif
        endif
        set instances[structId] = instances[structId] + 1
    endfunction
   
    // Conditionally stops the timer in the next callback.
    private function StopPeriodic takes integer structId returns nothing
        set instances[structId] = instances[structId] - 1
        if 0 == instances[structId] and condition[structId] != null then
            if not destroying[structId] and not recycling[structId] then
                set destroying[structId] = true
                set recycling[structId] = true
                set removed[structId] = removed[0]
                set removed[0] = structId
            endif
        endif
    endfunction

    // Modules:
    // ========
    //
    // You want to place module MissileLaunch at the very top of your struct.
    module MissileLaunch
        static method launch takes Missile missile returns nothing
            static if LIBRARY_ErrorMessage then
                debug call ThrowError(missile.launched, "thistype", "launch", "missile.launched", missile, "This missile was already launched before!")
            endif
            debug set missile.launched = true

            call missileList[thistype.typeid].pushBack(missile)
            call StartPeriodic(thistype.typeid)
        endmethod
    endmodule

    module MissileTerminate
        // Called from missileIterate. "P" to avoid code collision.
        static method missileTerminateP takes Missile node returns nothing
            if node.allocated then
                static if thistype.onRemove.exists then
                    call thistype.onRemove(node)
                endif

                call node.terminate()
                call StopPeriodic(thistype.typeid)
            endif
        endmethod
    endmodule

    // Allows you to inject missile in certain stages of the motion process.
    module MissileAction

static if DEBUG_MODE then
    // Runs check during compile time.
    static if thistype.onMissile.exists then
        Error Message from library Missile in struct thistype !
        thistype.onMissile is a reserved name for Missile, once you implemented MissileStruct.
        thistype.onMissile is currently not supported by library Missile.
        Please delete or re-name that method.
    endif
endif

    static if thistype.onItem.exists then
        private static method missileActionItem takes nothing returns nothing
            local item i = GetEnumItem()
            local Missile this = Missile.temp
            if this.allocated then
                set table[this].item[GetHandleId(i)] = i
                if thistype.onItem(this, i) then
                    call missileTerminateP(this)
                endif
            endif
            set i = null
        endmethod
    endif
       
    static if thistype.onDestructable.exists then
        private static method missileActionDest takes nothing returns nothing
            local destructable d = GetEnumDestructable()
            local Missile this = Missile.temp
            if this.allocated then
                set table[this].destructable[GetHandleId(d)] = d
                if thistype.onDestructable(this, d) then
                    call missileTerminateP(this)
                endif
            endif
            set d = null
        endmethod
    endif

        // Runs every Missile_TIMER_TIMEOUT for this struct.
        static method missileIterateP takes nothing returns boolean
            local Missile this = missileList[thistype.typeid].front
            local Missile node
            local real collideZ
            local boolean b
            local unit u

            loop
                exitwhen this == missileList[thistype.typeid]
                set node = this.next// The linked list should not lose the next node.

                if this.wantDestroy then
                    call thistype.missileTerminateP(this)
                else
                    if this.stackSize > 0 then
                        call this.updateStack()
                    endif

                    // Runs unit collision.
                    static if thistype.onCollide.exists then
                        if this.allocated and 0. < this.collision then
                            set b = this.collisionType == Missile_COLLISION_TYPE_RECTANGLE
                            if b then
                                call this.groupEnumUnitsRectangle()
                            else
                                call GroupEnumUnitsInRange(GROUP, this.x, this.y, this.collision + Missile_MAXIMUM_COLLISION_SIZE, null)
                            endif
                            loop
                                set u = FirstOfGroup(GROUP)
                                exitwhen u == null
                                call GroupRemoveUnit(GROUP, u)
                                if not table[this].handle.has(GetHandleId(u)) then
                                    if b or (this.dummy == null and IsUnitInRangeXY(u, this.x, this.y, this.collision)) or IsUnitInRange(u, this.dummy, this.collision) then
                                        // Eventually run z collision checks.
                                        static if Missile_USE_COLLISION_Z_FILTER then
                                            set collideZ = Missile_GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u) - this.terrainZ
                                            if (collideZ + GetUnitBodySize(u) >= this.z - this.collisionZ) and (collideZ <= this.z + this.collisionZ) then
                                                // Mark as hit.
                                                set table[this].unit[GetHandleId(u)] = u
                                                if thistype.onCollide(this, u) then
                                                    call thistype.missileTerminateP(this)
                                                    exitwhen true
                                                endif
                                            endif
                                        else
                                            // Runs unit collision without z collision checks.
                                            set table[this].unit[GetHandleId(u)] = u
                                            if thistype.onCollide(this, u) then
                                                call thistype.missileTerminateP(this)
                                                exitwhen true
                                            endif
                                        endif
                                    endif
                                endif
                            endloop
                        endif
                    endif

                    // Runs destructable collision.
                    static if thistype.onDestructable.exists then
                        // Check if the missile is not terminated.
                        if this.allocated and 0. < this.collision then
                            call this.checkDestCollision(function thistype.missileActionDest)
                        endif
                    endif

                    // Runs item collision.
                    static if thistype.onItem.exists then
                        //  Check if the missile is not terminated.
                        if this.allocated and 0. < this.collision then
                            call this.checkItemCollision(function thistype.missileActionItem)
                        endif
                    endif

                    // Runs when the destination is reached.
                    if this.recycle and this.allocated then
                        static if thistype.onFinish.exists then
                            if thistype.onFinish(this) then
                                call thistype.missileTerminateP(this)
                            endif
                        else
                            call thistype.missileTerminateP(this)
                        endif
                    endif

                    // Runs on terrian collision.
                    static if thistype.onTerrain.exists then
                        if this.allocated and 0. > this.z and thistype.onTerrain(this) then
                            call missileTerminateP(this)
                        endif
                    endif

                    // Runs every Missile_TIMER_TIMEOUT.
                    static if thistype.onPeriod.exists then
                        if this.allocated and thistype.onPeriod(this) then
                            call missileTerminateP(this)
                        endif
                    endif
                endif
                set this = node
            endloop

            set u = null
            static if DEBUG_MODE and LIBRARY_ErrorMessage then
                return true
            else
                return false
            endif
        endmethod
    endmodule

    module MissileStruct
        implement MissileLaunch
        implement MissileTerminate
        implement MissileAction

        private static method onInit takes nothing returns nothing
            call MissileCreateCollection(thistype.typeid)
            call MissileCreateExpression(thistype.typeid, function thistype.missileIterateP)
        endmethod
    endmodule

    private module Init
        private static method onInit takes nothing returns nothing
            call EulerAngles.onScopeInit()
            call Effect.onScopeInit()
            call Missile.onScopeInit()
        endmethod
    endmodule

// The end!
endlibrary
library OvermindSpells requires /*

    */
Table    /*
    *
    */
AllocationAndLinks /*
    *
    */
TimerUtils /*
    *
    */
GenericGroup /*
    *
    */
SelectionCircle /*
    *
    */
PathChecker     /*
    *
    */

   
    native UnitAlive takes unit id returns boolean
   
    globals
        private constant group ENUM_GROUP = CreateGroup()
        private unit enum_unit            = null
    endglobals
   
    //! runtextmacro GroupT("Int", "", "8", "integer", "Integer", "integer", "0")
    //! runtextmacro GroupT("FX", "", "10", "effect", "EffectHandle", "effect", "null")
    //! runtextmacro GroupT("Image", "", "8", "image", "ImageHandle", "image", "null")
   
    private function FXGroup_onDestroy takes nothing returns nothing
        call DestroyEffect(FXGroup.getRemovedNode().effect)
    endfunction
   
    private function CreateFXGroup takes nothing returns FXGroup
        local FXGroup new = FXGroup.create()
        call new.setOnDestroy(function FXGroup_onDestroy)
        return new
    endfunction
   
    scope SpellOne
       
        /*
        *    Toxic Illusion
        *        -   Hides the caster for a period of time, rendering the caster invulnerable.
        *            The caster can actually gain experience due to the caster having its
        *            position updated every tick.
        *
        *        -   Upon death of illusion, the caster spawns at the target location when the
        *            spell was cast.
        */

       
        private struct Spell extends array
            //  Basic modules
            implement AllocLink
           
            //  Member variables and configurables
            //  The timer which will be ran when there are any active instances.
            //  The order cast by dummy
            private static constant integer ILLUSION_ORDER = 852274
            //  The spell id to trigger creation
            private static constant integer SPELL_ID = 'A000'
            //  The buff id to act as an identifier
            private static constant integer BUFF_ID = 'B000'
            //  The ability cast by dummy
            private static constant integer ILLUSION_ABILITY = '0000'
            //  The set timer interval for TIMER_CHECK
            private static constant real INTERVAL = 1/32.
            //  The set timer interval for the venom
            private static constant real VENOM_INTERVAL = 1.
           
            private static timer TIMER_CHECK = null
            private static unit DUMMY_CASTER = null
           
            //  Global parameters
            private static real array parameters
            private static thistype current         = 0
           
            //  Main information
            //  Casting unit
            private unit unit
            //  Illusion
            private unit illu
            //  target
            private unit target
           
            //  Level of ability
            private integer level
            //  Additional data
            private IntGroup metaData
            private RealGroup metaDataR
           
            //  Cannot be explained properly yet.
            private real tickReal
            //  
            private timer time
           
            /*  Meta-data information                                                    *
            /  Generates a method operator index abstracting a call to variable Num01    *
            /  which will return the struct Spell, requiring a reference to the          *
            /  hashtable Table through a submethod integer. The method operator is       *
            /  then treated privately, which does not allow any other script to          *
            /  refer to it. The null type is defined as 0.                              */

           
            //! runtextmacro op_set("index", "Num01", "thistype", "integer", "private", "0")
           
            //  Read methods
            //  FADE_DURATION returns the amount of time needed to make
            private static method FADE_DURATION takes integer lev returns real
                return 2.5
            endmethod
           
            //  Returns the default vertex color of the unit.
            //  0 - Red, 1 - Green, 2 - Blue, 3 - Alpha
            private static method COLOR takes integer req returns integer
                if req == 0 then
                    return 255
                elseif req == 1 then
                    return 255
                elseif req == 2 then
                    return 255
                elseif req == 3 then
                    return 255
                endif
                return 0
            endmethod
           
            private static method FINAL_COLOR takes integer req returns integer
                if req == 0 then
                    return 255
                elseif req == 1 then
                    return 255
                elseif req == 2 then
                    return 255
                elseif req == 3 then
                    return 0
                endif
                return 0
            endmethod
           
            private static method MODEL_FILE takes integer req returns string
                //  The Corrosive breath model for the venomous fountain.
                if req == 0 then
                    return "Abilities\\Weapons\\ChimaeraAcidMissile\\ChimaeraAcidMissile.mdl"
                //  The poison fountain. Unfortunately, a cloud will have to suffice.
                //  This will be updated in the future
                elseif req == 1 then
                    return "Abilities\\Spells\\Human\\CloudOfFog\\CloudOfFog.mdl"
                endif
                return ""
            endmethod
           
            /*  The speed of the venomous projectile */
            private static method VENOM_SPEED takes nothing returns real
                return 900.
            endmethod
           
            /*  The enumeration radius for dealing damage */
            private static method VENOM_RADIUS takes integer level returns real
                if level == 1 then
                    return 200.
                elseif level == 2 then
                    return 225.
                elseif level == 3 then
                    return 250.
                endif
                return 0.
            endmethod
           
            /*  The amount of damage dealt */
            private static method VENOM_DAMAGE takes integer level returns real
                if level == 1 then
                    return 25.
                elseif level == 2 then
                    return 40.
                elseif level == 3 then
                    return 55.
                endif
                return 0.
            endmethod
           
            /*  The duration of the illusion    */
            private static method VENOM_COPY_DURATION takes integer level returns real
                if level == 1 then
                    return 15.
                elseif level == 2 then
                    return 20.
                elseif level == 3 then
                    return 25.
                endif
                return 0.
            endmethod
           
            private static method VENOM_COPY_DAMAGE_RATIO takes integer level returns real
                //  3*Instruction + level
                //  Instruction: 0 (Damage dealt)
                if level == 1 then
                    return 1.0
                elseif level == 2 then
                    return 1.0
                elseif level == 3 then
                    return 1.0
                //  Instruction: 1 (Damage received)
                elseif level == 4 then
                    return 2.0
                elseif level == 5 then
                    return 1.4
                elseif level == 6 then
                    return 0.7
                endif
                return 0.
            endmethod
           
            private static method FOUNTAIN_DAMAGE takes integer level returns real
                if level == 1 then
                    return 100./FADE_DURATION(level)*INTERVAL
                elseif level == 2 then
                    return 140./FADE_DURATION(level)*INTERVAL
                elseif level == 3 then
                    return 180./FADE_DURATION(level)*INTERVAL
                endif
                return 0.
            endmethod
           
            //  Destructor
            private method destroy takes nothing returns nothing
                call SetUnitInvulnerable(this.unit, false)
                call PauseUnit(this.unit, false)
               
                call this.metaDataR.destroy()
                call this.metaData.destroy()
               
                set this.unit = null
                set this.tickReal = 0.
                set this.metaDataR = 0
                set this.metaData = 0
               
                call this.pop()
                call this.deallocate()
            endmethod
           
            //  onFinish methods
            /*      Damage callback
            *       This damages nearby units every 1/50. seconds, dealing about a total of
            *       100/140/180 damage over 2.5 seconds.       */

            private static method onFinish_Damage takes nothing returns nothing
                local player owner = GetOwningPlayer(current.unit)
               
                call GroupEnumUnitsInRange(ENUM_GROUP, GetUnitX(current.unit), GetUnitY(current.unit), VENOM_RADIUS(current.level), null)
                loop
                    set enum_unit = FirstOfGroup(ENUM_GROUP)
                    exitwhen enum_unit == null
                        //  Begin loop
                        if IsUnitEnemy(enum_unit, owner) and UnitAlive(enum_unit) and not IsUnitType(enum_unit, UNIT_TYPE_MECHANICAL) then
                            call UnitDamageTarget(current.unit, enum_unit, FOUNTAIN_DAMAGE(current.level), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
                        endif
                        //  End loop
                    call GroupRemoveUnit(ENUM_GROUP, enum_unit)
                endloop
            endmethod
           
            //  Meta-Data methods
            /*  This updates the color of the Overmind (as a transition method) */
            private method metaData_update takes nothing returns nothing
                local real fade_duration = FADE_DURATION(this.level)
                local real array color_disparity
                local integer i = 1
               
                if this.metaData.integer == 1 then

                    loop
                        exitwhen i > 4
                        set color_disparity[i] = this.metaData[i].integer - (COLOR(i - 1) - FINAL_COLOR(i - 1))/fade_duration*INTERVAL
                        set this.metaData[i].integer = R2I(color_disparity[i])
                       
                        set i = i + 1
                    endloop
               
                elseif this.metaData.integer == 4 then
               
                    loop
                        exitwhen i > 4
                        set color_disparity[i] = this.metaData[i].integer + (COLOR(i - 1) - FINAL_COLOR(i - 1))/fade_duration*INTERVAL
                        set this.metaData[i].integer = R2I(color_disparity[i])
                       
                        set i = i + 1
                    endloop
                   
                endif
            endmethod
           
            /*  This initializes the color data.
            *       - each add call allocates a space for the metaData group.
            *       - Here, we initialize the following: Red, Green, Blue and Alpha
            *       - see COLOR function for more details on initial color.
            */

            private method metaData_init takes nothing returns nothing
                set this.metaData.integer = 1
               
                call this.metaData.add(COLOR(0))
                call this.metaData.add(COLOR(1))
                call this.metaData.add(COLOR(2))
                call this.metaData.add(COLOR(3))
            endmethod
           
            //  Unit methods
            /*
                This hides the unit who cast the spell SPELL_ID, and spawns an identical illusion
            */

            private method unit_createIllu takes nothing returns nothing
                call SetUnitX(DUMMY_CASTER, GetUnitX(this.unit))
                call SetUnitY(DUMMY_CASTER, GetUnitY(this.unit))
                       
                call SetUnitInvulnerable(this.unit, false)
                       
                call SetUnitOwner(DUMMY_CASTER, GetOwningPlayer(this.unit), false)
                call IssueTargetOrderById(DUMMY_CASTER, ILLUSION_ORDER, this.unit)
                call SetUnitOwner(DUMMY_CASTER, Player(PLAYER_NEUTRAL_PASSIVE), false)
               
                call SetUnitInvulnerable(this.unit, true)
               
                call ShowUnit(this.unit, false)
               
                set this.illu = bj_lastCreatedUnit
               
                call UnitApplyTimedLife(this.illu, 'B000', VENOM_COPY_DURATION(this.level))
               
                call SetUnitX(this.illu, GetUnitX(this.unit))
                call SetUnitY(this.illu, GetUnitY(this.unit))
               
                if GetLocalPlayer() == GetOwningPlayer(this.unit) then
                    call SelectUnit(this.illu, true)
                endif
               
                set thistype(GetHandleId(this.illu)).index = this
            endmethod
           
            //  Venom illusion methods
            private method venomCopy_onDeath takes nothing returns nothing
                local FXGroup fx = this.metaData[5].integer
               
                call ReleaseTimer(this.time)
                call fx.destroy()
               
                call this.metaData.node_pop(5)
               
                call ShowUnit(this.unit, true)
                call SetUnitX(this.unit, this.metaDataR[1].real)
                call SetUnitY(this.unit, this.metaDataR[2].real)
               
                set thistype(GetHandleId(this.illu)).index = 0                
               
                set this.time = null
                set this.illu = null
                set this.tickReal = FADE_DURATION(this.level)
                set this.metaData.integer = 4
            endmethod
           
            //  Venom methods
            private static method venom_periodic takes nothing returns nothing
                local player owner
                local timer time = GetExpiredTimer()
                local thistype this = GetTimerData(time)
                local FXGroup fx = this.metaData[5].integer
               
                set owner = GetOwningPlayer(this.unit)
               
                call fx.node_pop(1)
                call fx.add_pos( AddSpecialEffect(MODEL_FILE(0), this.metaDataR[1].real, this.metaDataR[2].real), 1)
               
                call GroupEnumUnitsInRange(ENUM_GROUP, this.metaDataR[1].real, this.metaDataR[2].real, VENOM_RADIUS(this.level), null)
                loop
                    set enum_unit = FirstOfGroup(ENUM_GROUP)
                    exitwhen enum_unit == null
                        //  Begin block
                        if IsUnitEnemy(enum_unit, owner) and UnitAlive(enum_unit) and not IsUnitType(enum_unit, UNIT_TYPE_MECHANICAL) then
                            call UnitDamageTarget(this.illu, enum_unit, VENOM_DAMAGE(this.level), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
                        endif
                        //  End block
                    call GroupRemoveUnit(ENUM_GROUP, enum_unit)
                endloop
               
                set time = null
            endmethod
           
            private static method venom_onHit takes nothing returns nothing
                local thistype this = R2I( Movement.current.metaData[1].real)
                local FXGroup fx = R2I( Movement.current.metaData[2].real)
               
                call this.metaDataR.add(GetUnitX(Movement.current.unit))
                call this.metaDataR.add(GetUnitY(Movement.current.unit))
                call this.metaData.add(fx)
               
                call TimerStart(time, VENOM_INTERVAL, true, function thistype.venom_periodic)
               
                call fx.clear()
                call fx.add( AddSpecialEffect(MODEL_FILE(0), this.metaDataR[1].real, this.metaDataR[2].real))
                call fx.add( AddSpecialEffect(MODEL_FILE(1), this.metaDataR[1].real, this.metaDataR[2].real))
               
                call DummyAddRecycleTimer(Movement.current.unit, 1.0)
                call Movement.current.destroy()
            endmethod
           
            //  Exclusively for the struct!
           
            private static method onTick takes nothing returns nothing
                local thistype this = thistype(0).next
                local Movement miss = 0
                local FXGroup fx = 0
               
                loop
                    exitwhen this == 0
                   
                    if this.metaData.integer == 1 then
                        call this.metaData_update()
                       
                        call DestroyEffect( AddSpecialEffect(MODEL_FILE(0), GetUnitX(this.unit), GetUnitY(this.unit)) )
                        call SetUnitVertexColor(this.unit, this.metaData[1].integer, this.metaData[2].integer, /*
                                             */
this.metaData[3].integer, this.metaData[4].integer)
                       
                        set this.tickReal = this.tickReal - INTERVAL
                        if ModuloReal(this.tickReal, 1.00) == 0.50 then
                            call SetUnitAnimation(this.unit, "spell")
                            call QueueUnitAnimation(this.unit, "stand")
                        endif
                       
                        if this.tickReal <= 0. then
                            set this.tickReal = 0.
                            set this.metaData.integer = 2
                        endif
                   
                    elseif this.metaData.integer == 2 then
                       
                        call this.unit_createIllu()
                       
                        set parameters[0] = GetUnitX(this.unit)
                        set parameters[1] = GetUnitY(this.unit)
                       
                        set parameters[2] = Atan2(GetUnitY(this.target) - parameters[1], GetUnitX(this.target) - parameters[0])*bj_RADTODEG
                       
                        call GetRecycledDummy(parameters[0], parameters[1], 50, parameters[2])
                        call PauseUnit(bj_lastCreatedUnit, true)
                        call DestroyEffect( AddSpecialEffect(MODEL_FILE(0), parameters[0], parameters[1]) )
                       
                        set fx = CreateFXGroup()
                            call fx.add(AddSpecialEffectTarget(MODEL_FILE(0), bj_lastCreatedUnit, "origin"))
                           
                        set miss = Movement.add(bj_lastCreatedUnit)
                            set miss.speed = VENOM_SPEED()
                           
                            call miss.metaData.add(this)
                            call miss.metaData.add(fx)
                            call miss.setExpireListener(function thistype.venom_onHit)
                           
                            call miss.aimUnit(this.target)
                       
                        set this.target = null
                        set this.metaData.integer = 3
                       
                    elseif this.metaData.integer == 3 then
                       
                        call SetUnitX(this.unit, GetUnitX(this.illu))
                        call SetUnitY(this.unit, GetUnitY(this.illu))
                   
                    elseif this.metaData.integer == 4 then
                       
                        call this.metaData_update()
                                               
                        if ModuloReal(this.tickReal, 1.00) == 0.50 then
                            call SetUnitAnimation(this.unit, "spell")
                            call QueueUnitAnimation(this.unit, "stand")
                        endif
                       
                        set this.tickReal = this.tickReal - INTERVAL
                        if this.tickReal <= 0. then
                            call this.destroy()
                        else
                            call DestroyEffect( AddSpecialEffect(MODEL_FILE(0), GetUnitX(this.unit), GetUnitY(this.unit)) )
                            call SetUnitVertexColor(this.unit, this.metaData[1].integer, this.metaData[2].integer, /*
                                                */
this.metaData[3].integer, this.metaData[4].integer)
                           
                            set current = this
                            call ForForce(bj_FORCE_PLAYER[0], function thistype.onFinish_Damage)
                        endif
                       
                    endif
                   
                    set this = this.next
                endloop
            endmethod
           
            private static method create takes nothing returns thistype
                local thistype this = 0
               
                set this = allocate()
                    set this.unit = GetTriggerUnit()
                    set this.level = GetUnitAbilityLevel(this.unit, SPELL_ID)
                    set this.tickReal = FADE_DURATION(this.level)
                    set this.target = GetSpellTargetUnit()
                    set this.metaData = IntGroup.create()
                    set this.metaDataR = RealGroup.create()
                    set this.time = NewTimerEx(this)
                   
                call this.metaData_init()
                call this.push()
               
                call SetUnitAnimation(this.unit, "spell")
                call SetUnitInvulnerable(this.unit, true)
                call PauseUnit(this.unit, true)
               
                if GetTimerData(TIMER_CHECK) == 0 then
                    call TimerStart(TIMER_CHECK, INTERVAL, true, function thistype.onTick)
                endif
                call SetTimerData(TIMER_CHECK, GetTimerData(TIMER_CHECK) + 1)
               
                return this
            endmethod
           
            private static method onSpellCast takes nothing returns nothing
                if GetSpellAbilityId() == SPELL_ID then
                    call create()
                endif
            endmethod
           
            private static method onDummySummon takes nothing  returns nothing
                set bj_lastCreatedUnit = GetSummonedUnit(