Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AllocQ /* v1.0.1.0
*************************************************************************************
*
* */ uses /*
*
* */ ErrorMessage /*
*
*************************************************************************************
*
* Maximizes speed by reducing local variable declarations and removing
* if-statement.
*
* Uses a queue instead of a stack for recycler. Using a queue requires one
* extra variable declaration.
*
* set alloc = recycler[0]
* set recycler[0] = recycler[alloc]
*
************************************************************************************
*
* module AllocQFast
*
* Fields
* -------------------------
*
* readonly boolean isAllocated
*
* Methods
* -------------------------
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
module AllocQ
/*
* stack
*/
private static integer array recycler
private static integer alloc
private static integer last = 8191
/*
* list of allocated memory
*/
debug private static integer array allocatedNext
debug private static integer array allocatedPrev
/*
* free memory counter
*/
debug private static integer usedMemory = 0
/*
* allocation
*/
static method allocate takes nothing returns thistype
set alloc = recycler[0]
debug call ThrowError(alloc == 0, "AllocQ", "allocate", "thistype", 0, "Overflow.")
set recycler[0] = recycler[alloc]
set recycler[alloc] = -1
debug set usedMemory = usedMemory + 1
debug set allocatedNext[alloc] = 0
debug set allocatedPrev[alloc] = allocatedPrev[0]
debug set allocatedNext[allocatedPrev[0]] = alloc
debug set allocatedPrev[0] = alloc
return alloc
endmethod
method deallocate takes nothing returns nothing
debug call ThrowError(recycler[this] != -1, "AllocQ", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
set recycler[last] = this
set recycler[this] = 0
set last = this
debug set usedMemory = usedMemory - 1
debug set allocatedNext[allocatedPrev[this]] = allocatedNext[this]
debug set allocatedPrev[allocatedNext[this]] = allocatedPrev[this]
endmethod
/*
* analysis
*/
method operator isAllocated takes nothing returns boolean
return recycler[this] == -1
endmethod
static if DEBUG_MODE then
static method calculateMemoryUsage takes nothing returns integer
return usedMemory
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
local integer memoryCell = allocatedNext[0]
local string memoryRepresentation = null
loop
exitwhen memoryCell == 0
if (memoryRepresentation == null) then
set memoryRepresentation = I2S(memoryCell)
else
set memoryRepresentation = memoryRepresentation + ", " + I2S(memoryCell)
endif
set memoryCell = allocatedNext[memoryCell]
endloop
return memoryRepresentation
endmethod
endif
/*
* initialization
*/
private static method onInit takes nothing returns nothing
local integer i = 0
set recycler[8191] = 0 //so that the array doesn't reallocate over and over again
loop
set recycler[i] = i + 1
exitwhen i == 8190
set i = i + 1
endloop
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AllocT /* v1.0.2.0
*************************************************************************************
*
* */uses/*
*
* */ ErrorMessage /* https://github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage
* */ Table /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
*************************************************************************************
*
* Minimizes code generation and global variables while maintaining
* excellent performance.
*
* Uses hashtable instead of array, which drastically reduces performance
* but uncaps the instance limit. Should use with table fields instead of
* array fields.
*
* local thistype this = recycler[0]
*
* if (recycler[this] == 0) then
* set recycler[0] = this + 1
* else
* set recycler[0] = recycler[this]
* endif
*
************************************************************************************
*
* module AllocT
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
* readonly boolean isAllocated
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
module AllocT
/*
* stack
*/
private static Table recycler
/*
* list of allocated memory
*/
debug private static Table allocatedNext
debug private static Table allocatedPrev
/*
* free memory counter
*/
debug private static integer usedMemory = 0
/*
* allocation
*/
static method allocate takes nothing returns thistype
local thistype this = recycler[0]
debug call ThrowError(this < 0, "AllocT", "allocate", "thistype", 0, "Overflow.")
if (recycler[this] == 0) then
set recycler[0] = this + 1
else
set recycler[0] = recycler[this]
endif
set recycler[this] = -1
debug set usedMemory = usedMemory + 1
debug set allocatedNext[this] = 0
debug set allocatedPrev[this] = allocatedPrev[0]
debug set allocatedNext[allocatedPrev[0]] = this
debug set allocatedPrev[0] = this
return this
endmethod
method deallocate takes nothing returns nothing
debug call ThrowError(recycler[this] != -1, "AllocT", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
set recycler[this] = recycler[0]
set recycler[0] = this
debug set usedMemory = usedMemory - 1
debug set allocatedNext[allocatedPrev[this]] = allocatedNext[this]
debug set allocatedPrev[allocatedNext[this]] = allocatedPrev[this]
endmethod
/*
* analysis
*/
method operator isAllocated takes nothing returns boolean
return recycler[this] == -1
endmethod
static if DEBUG_MODE then
static method calculateMemoryUsage takes nothing returns integer
return usedMemory
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
local integer memoryCell = allocatedNext[0]
local string memoryRepresentation = null
loop
exitwhen memoryCell == 0
if (memoryRepresentation == null) then
set memoryRepresentation = I2S(memoryCell)
else
set memoryRepresentation = memoryRepresentation + ", " + I2S(memoryCell)
endif
set memoryCell = allocatedNext[memoryCell]
endloop
return memoryRepresentation
endmethod
endif
/*
* initialization
*/
private static method onInit takes nothing returns nothing
set recycler = Table.create()
debug set allocatedNext = Table.create()
debug set allocatedPrev = Table.create()
set recycler[0] = 1
endmethod
endmodule
endlibrary
library StaticUniqueList /* v1.0.0.2
************************************************************************************
*
* */ uses /*
*
* */ ErrorMessage /*
*
************************************************************************************
*
* module StaticUniqueList
*
* Description
* -------------------------
*
* Node Properties:
*
* Unique
* Not 0
*
* Fields
* -------------------------
*
* readonly static integer sentinel
*
* readonly static thistype first
* readonly static thistype last
*
* readonly thistype next
* readonly thistype prev
*
* Methods
* -------------------------
*
* static method push takes thistype node returns nothing
* static method enqueue takes thistype node returns nothing
*
* static method pop takes nothing returns nothing
* static method dequeue takes nothing returns nothing
*
* method remove takes nothing returns nothing
*
* static method clear takes nothing returns nothing
*
************************************************************************************/
module StaticUniqueList
debug private boolean isNode
private thistype _next
method operator next takes nothing returns thistype
debug call ThrowError(this == 0, "StaticUniqueList", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
debug call ThrowError(not isNode, "StaticUniqueList", "next", "thistype", this, "Attempted To Read Invalid Node.")
return _next
endmethod
private thistype _prev
method operator prev takes nothing returns thistype
debug call ThrowError(this == 0, "StaticUniqueList", "prev", "thistype", this, "Attempted To Go Out Of Bounds.")
debug call ThrowError(not isNode, "StaticUniqueList", "prev", "thistype", this, "Attempted To Read Invalid Node.")
return _prev
endmethod
static method operator first takes nothing returns thistype
return thistype(0)._next
endmethod
static method operator last takes nothing returns thistype
return thistype(0)._prev
endmethod
private static method setFirst takes thistype node returns nothing
set thistype(0)._next = node
endmethod
private static method setLast takes thistype node returns nothing
set thistype(0)._prev = node
endmethod
static constant integer sentinel = 0
static method push takes thistype node returns nothing
debug call ThrowError(node == 0, "StaticUniqueList", "push", "thistype", 0, "Attempted To Push Null Node.")
debug call ThrowError(node.isNode, "StaticUniqueList", "push", "thistype", 0, "Attempted To Push Owned Node (" + I2S(node) + ").")
debug set node.isNode = true
set first._prev = node
set node._next = first
call setFirst(node)
set node._prev = 0
endmethod
static method enqueue takes thistype node returns nothing
debug call ThrowError(node == 0, "StaticUniqueList", "enqueue", "thistype", 0, "Attempted To Enqueue Null Node.")
debug call ThrowError(node.isNode, "StaticUniqueList", "enqueue", "thistype", 0, "Attempted To Enqueue Owned Node (" + I2S(node) + ").")
debug set node.isNode = true
set last._next = node
set node._prev = last
call setLast(node)
set node._next = 0
endmethod
static method pop takes nothing returns nothing
debug call ThrowError(first == 0, "StaticUniqueList", "pop", "thistype", 0, "Attempted To Pop Empty List.")
debug set first.isNode = false
call setFirst(first._next)
set first._prev = 0
endmethod
static method dequeue takes nothing returns nothing
debug call ThrowError(last == 0, "StaticUniqueList", "dequeue", "thistype", 0, "Attempted To Dequeue Empty List.")
debug set last.isNode = false
call setLast(last._prev)
set last._next = 0
endmethod
method remove takes nothing returns nothing
debug call ThrowError(this == 0, "StaticUniqueList", "remove", "thistype", 0, "Attempted To Remove Null Node.")
debug call ThrowError(not isNode, "StaticUniqueList", "remove", "thistype", 0, "Attempted To Remove Invalid Node (" + I2S(this) + ").")
debug set isNode = false
set _prev._next = _next
set _next._prev = _prev
endmethod
static method clear takes nothing returns nothing
static if DEBUG_MODE then
local thistype node = first
loop
exitwhen node == 0
set node.isNode = false
set node = node._next
endloop
endif
call setFirst(0)
call setLast(0)
endmethod
endmodule
endlibrary
library ListT /* v1.0.1.0
************************************************************************************
*
* */ uses /*
*
* */ ErrorMessage /*
*
************************************************************************************
*
* module ListT
*
* Description
* -------------------------
*
* NA
*
* Fields
* -------------------------
*
* debug readonly boolean isList
* debug readonly boolean isElement
*
* readonly static integer sentinel
*
* readonly thistype list
*
* readonly thistype first
* readonly thistype last
*
* readonly thistype next
* readonly thistype prev
*
* Methods
* -------------------------
*
* static method create takes nothing returns thistype
* method destroy takes nothing returns nothing
* - May only destroy lists
*
* method push takes nothing returns thistype
* method enqueue takes nothing returns thistype
*
* method pop takes nothing returns nothing
* method dequeue takes nothing returns nothing
*
* method remove takes nothing returns nothing
*
* method clear takes nothing returns nothing
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
private keyword isNode
private keyword isCollection
private keyword pp_list
private keyword pp_next
private keyword pp_prev
private keyword pp_first
private keyword pp_last
module ListT
private static thistype collectionCount = 0
private static thistype nodeCount = 0
debug private static Table p_isNode
debug method operator isNode takes nothing returns boolean
debug return p_isNode.boolean[this]
debug endmethod
debug method operator isNode= takes boolean value returns nothing
debug set p_isNode.boolean[this] = value
debug endmethod
debug private static Table p_isCollection
debug method operator isCollection takes nothing returns boolean
debug return p_isCollection.boolean[this]
debug endmethod
debug method operator isCollection= takes boolean value returns nothing
debug set p_isCollection.boolean[this] = value
debug endmethod
debug method operator isList takes nothing returns boolean
debug return isCollection
debug endmethod
debug method operator isElement takes nothing returns boolean
debug return isNode
debug endmethod
private static Table p_list
method operator pp_list takes nothing returns thistype
return p_list[this]
endmethod
method operator pp_list= takes thistype value returns nothing
set p_list[this] = value
endmethod
method operator list takes nothing returns thistype
debug call ThrowError(this == 0, "List", "list", "thistype", this, "Attempted To Read Null Node.")
debug call ThrowError(not isNode, "List", "list", "thistype", this, "Attempted To Read Invalid Node.")
return pp_list
endmethod
private static Table p_next
method operator pp_next takes nothing returns thistype
return p_next[this]
endmethod
method operator pp_next= takes thistype value returns nothing
set p_next[this] = value
endmethod
method operator next takes nothing returns thistype
debug call ThrowError(this == 0, "List", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
debug call ThrowError(not isNode, "List", "next", "thistype", this, "Attempted To Read Invalid Node.")
return pp_next
endmethod
private static Table p_prev
method operator pp_prev takes nothing returns thistype
return p_prev[this]
endmethod
method operator pp_prev= takes thistype value returns nothing
set p_prev[this] = value
endmethod
method operator prev takes nothing returns thistype
debug call ThrowError(this == 0, "List", "prev", "thistype", this, "Attempted To Go Out Of Bounds.")
debug call ThrowError(not isNode, "List", "prev", "thistype", this, "Attempted To Read Invalid Node.")
return pp_prev
endmethod
private static Table p_first
method operator pp_first takes nothing returns thistype
return p_first[this]
endmethod
method operator pp_first= takes thistype value returns nothing
set p_first[this] = value
endmethod
method operator first takes nothing returns thistype
debug call ThrowError(this == 0, "List", "first", "thistype", this, "Attempted To Read Null List.")
debug call ThrowError(not isCollection, "List", "first", "thistype", this, "Attempted To Read Invalid List.")
return pp_first
endmethod
private static Table p_last
method operator pp_last takes nothing returns thistype
return p_last[this]
endmethod
method operator pp_last= takes thistype value returns nothing
set p_last[this] = value
endmethod
method operator last takes nothing returns thistype
debug call ThrowError(this == 0, "List", "last", "thistype", this, "Attempted To Read Null List.")
debug call ThrowError(not isCollection, "List", "last", "thistype", this, "Attempted To Read Invalid List.")
return pp_last
endmethod
static method operator sentinel takes nothing returns integer
return 0
endmethod
private static method allocateCollection takes nothing returns thistype
local thistype this = thistype(0).pp_first
if (0 == this) then
debug call ThrowError(collectionCount == 8191, "List", "allocateCollection", "thistype", 0, "Overflow.")
set this = collectionCount + 1
set collectionCount = this
else
set thistype(0).pp_first = pp_first
endif
return this
endmethod
private static method allocateNode takes nothing returns thistype
local thistype this = thistype(0).pp_next
if (0 == this) then
debug call ThrowError(nodeCount == 8191, "List", "allocateNode", "thistype", 0, "Overflow.")
set this = nodeCount + 1
set nodeCount = this
else
set thistype(0).pp_next = pp_next
endif
return this
endmethod
static method create takes nothing returns thistype
local thistype this = allocateCollection()
debug set isCollection = true
set pp_first = 0
return this
endmethod
method push takes nothing returns thistype
local thistype node = allocateNode()
debug call ThrowError(this == 0, "List", "push", "thistype", this, "Attempted To Push On To Null List.")
debug call ThrowError(not isCollection, "List", "push", "thistype", this, "Attempted To Push On To Invalid List.")
debug set node.isNode = true
set node.pp_list = this
if (pp_first == 0) then
set pp_first = node
set pp_last = node
set node.pp_next = 0
else
set pp_first.pp_prev = node
set node.pp_next = pp_first
set pp_first = node
endif
set node.pp_prev = 0
return node
endmethod
method enqueue takes nothing returns thistype
local thistype node = allocateNode()
debug call ThrowError(this == 0, "List", "enqueue", "thistype", this, "Attempted To Enqueue On To Null List.")
debug call ThrowError(not isCollection, "List", "enqueue", "thistype", this, "Attempted To Enqueue On To Invalid List.")
debug set node.isNode = true
set node.pp_list = this
if (pp_first == 0) then
set pp_first = node
set pp_last = node
set node.pp_prev = 0
else
set pp_last.pp_next = node
set node.pp_prev = pp_last
set pp_last = node
endif
set node.pp_next = 0
return node
endmethod
method pop takes nothing returns nothing
local thistype node = pp_first
debug call ThrowError(this == 0, "List", "pop", "thistype", this, "Attempted To Pop Null List.")
debug call ThrowError(not isCollection, "List", "pop", "thistype", this, "Attempted To Pop Invalid List.")
debug call ThrowError(node == 0, "List", "pop", "thistype", this, "Attempted To Pop Empty List.")
debug set node.isNode = false
set pp_first.pp_list = 0
set pp_first = pp_first.pp_next
if (pp_first == 0) then
set pp_last = 0
else
set pp_first.pp_prev = 0
endif
set node.pp_next = thistype(0).pp_next
set thistype(0).pp_next = node
endmethod
method dequeue takes nothing returns nothing
local thistype node = pp_last
debug call ThrowError(this == 0, "List", "dequeue", "thistype", this, "Attempted To Dequeue Null List.")
debug call ThrowError(not isCollection, "List", "dequeue", "thistype", this, "Attempted To Dequeue Invalid List.")
debug call ThrowError(node == 0, "List", "dequeue", "thistype", this, "Attempted To Dequeue Empty List.")
debug set node.isNode = false
set pp_last.pp_list = 0
set pp_last = pp_last.pp_prev
if (pp_last == 0) then
set pp_first = 0
else
set pp_last.pp_next = 0
endif
set node.pp_next = thistype(0).pp_next
set thistype(0).pp_next = node
endmethod
method remove takes nothing returns nothing
local thistype node = this
set this = node.pp_list
debug call ThrowError(node == 0, "List", "remove", "thistype", this, "Attempted To Remove Null Node.")
debug call ThrowError(not node.isNode, "List", "remove", "thistype", this, "Attempted To Remove Invalid Node (" + I2S(node) + ").")
debug set node.isNode = false
set node.pp_list = 0
if (0 == node.pp_prev) then
set pp_first = node.pp_next
else
set node.pp_prev.pp_next = node.pp_next
endif
if (0 == node.pp_next) then
set pp_last = node.pp_prev
else
set node.pp_next.pp_prev = node.pp_prev
endif
set node.pp_next = thistype(0).pp_next
set thistype(0).pp_next = node
endmethod
method clear takes nothing returns nothing
debug local thistype node = pp_first
debug call ThrowError(this == 0, "List", "clear", "thistype", this, "Attempted To Clear Null List.")
debug call ThrowError(not isCollection, "List", "clear", "thistype", this, "Attempted To Clear Invalid List.")
static if DEBUG_MODE then
loop
exitwhen node == 0
set node.isNode = false
set node = node.pp_next
endloop
endif
if (pp_first == 0) then
return
endif
set pp_last.pp_next = thistype(0).pp_next
set thistype(0).pp_next = pp_first
set pp_first = 0
set pp_last = 0
endmethod
method destroy takes nothing returns nothing
debug call ThrowError(this == 0, "List", "destroy", "thistype", this, "Attempted To Destroy Null List.")
debug call ThrowError(not isCollection, "List", "destroy", "thistype", this, "Attempted To Destroy Invalid List.")
static if DEBUG_MODE then
debug call clear()
debug set isCollection = false
else
if (pp_first != 0) then
set pp_last.pp_next = thistype(0).pp_next
set thistype(0).pp_next = pp_first
set pp_last = 0
endif
endif
set pp_first = thistype(0).pp_first
set thistype(0).pp_first = this
endmethod
private static method onInit takes nothing returns nothing
static if DEBUG_MODE then
set p_isNode = Table.create()
set p_isCollection = Table.create()
endif
set p_list = Table.create()
set p_next = Table.create()
set p_prev = Table.create()
set p_first = Table.create()
set p_last = Table.create()
endmethod
static if DEBUG_MODE then
static method calculateMemoryUsage takes nothing returns integer
local thistype start = 1
local thistype end = 8191
local integer count = 0
loop
exitwhen integer(start) > integer(end)
if (integer(start) + 500 > integer(end)) then
return count + checkRegion(start, end)
else
set count = count + checkRegion(start, start + 500)
set start = start + 501
endif
endloop
return count
endmethod
private static method checkRegion takes thistype start, thistype end returns integer
local integer count = 0
loop
exitwhen integer(start) > integer(end)
if (start.isNode) then
set count = count + 1
endif
if (start.isCollection) then
set count = count + 1
endif
set start = start + 1
endloop
return count
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
local thistype start = 1
local thistype end = 8191
local string memory = null
loop
exitwhen integer(start) > integer(end)
if (integer(start) + 500 > integer(end)) then
if (memory != null) then
set memory = memory + ", "
endif
set memory = memory + checkRegion2(start, end)
set start = end + 1
else
if (memory != null) then
set memory = memory + ", "
endif
set memory = memory + checkRegion2(start, start + 500)
set start = start + 501
endif
endloop
return memory
endmethod
private static method checkRegion2 takes thistype start, thistype end returns string
local string memory = null
loop
exitwhen integer(start) > integer(end)
if (start.isNode) then
if (memory == null) then
set memory = I2S(start)
else
set memory = memory + ", " + I2S(start) + "N"
endif
endif
if (start.isCollection) then
if (memory == null) then
set memory = I2S(start)
else
set memory = memory + ", " + I2S(start) + "C"
endif
endif
set start = start + 1
endloop
return memory
endmethod
endif
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.0.3
One map, one hashtable. Welcome to NewTable 3.2
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY 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
//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("Real", "Real", "real")
//! runtextmacro NEW_ARRAY("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Handle", "PlayerHandle", "player")
//! runtextmacro NEW_ARRAY("Handle", "WidgetHandle", "widget")
//! runtextmacro NEW_ARRAY("Handle", "DestructableHandle", "destructable")
//! runtextmacro NEW_ARRAY("Handle", "ItemHandle", "item")
//! runtextmacro NEW_ARRAY("Handle", "UnitHandle", "unit")
//! runtextmacro NEW_ARRAY("Handle", "AbilityHandle", "ability")
//! runtextmacro NEW_ARRAY("Handle", "TimerHandle", "timer")
//! runtextmacro NEW_ARRAY("Handle", "TriggerHandle", "trigger")
//! runtextmacro NEW_ARRAY("Handle", "TriggerConditionHandle", "triggercondition")
//! runtextmacro NEW_ARRAY("Handle", "TriggerActionHandle", "triggeraction")
//! runtextmacro NEW_ARRAY("Handle", "TriggerEventHandle", "event")
//! runtextmacro NEW_ARRAY("Handle", "ForceHandle", "force")
//! runtextmacro NEW_ARRAY("Handle", "GroupHandle", "group")
//! runtextmacro NEW_ARRAY("Handle", "LocationHandle", "location")
//! runtextmacro NEW_ARRAY("Handle", "RectHandle", "rect")
//! runtextmacro NEW_ARRAY("Handle", "BooleanExprHandle", "boolexpr")
//! runtextmacro NEW_ARRAY("Handle", "SoundHandle", "sound")
//! runtextmacro NEW_ARRAY("Handle", "EffectHandle", "effect")
//! runtextmacro NEW_ARRAY("Handle", "UnitPoolHandle", "unitpool")
//! runtextmacro NEW_ARRAY("Handle", "ItemPoolHandle", "itempool")
//! runtextmacro NEW_ARRAY("Handle", "QuestHandle", "quest")
//! runtextmacro NEW_ARRAY("Handle", "QuestItemHandle", "questitem")
//! runtextmacro NEW_ARRAY("Handle", "DefeatConditionHandle", "defeatcondition")
//! runtextmacro NEW_ARRAY("Handle", "TimerDialogHandle", "timerdialog")
//! runtextmacro NEW_ARRAY("Handle", "LeaderboardHandle", "leaderboard")
//! runtextmacro NEW_ARRAY("Handle", "MultiboardHandle", "multiboard")
//! runtextmacro NEW_ARRAY("Handle", "MultiboardItemHandle", "multiboarditem")
//! runtextmacro NEW_ARRAY("Handle", "TrackableHandle", "trackable")
//! runtextmacro NEW_ARRAY("Handle", "DialogHandle", "dialog")
//! runtextmacro NEW_ARRAY("Handle", "ButtonHandle", "button")
//! runtextmacro NEW_ARRAY("Handle", "TextTagHandle", "texttag")
//! runtextmacro NEW_ARRAY("Handle", "LightningHandle", "lightning")
//! runtextmacro NEW_ARRAY("Handle", "ImageHandle", "image")
//! runtextmacro NEW_ARRAY("Handle", "UbersplatHandle", "ubersplat")
//! runtextmacro NEW_ARRAY("Handle", "RegionHandle", "region")
//! runtextmacro NEW_ARRAY("Handle", "FogStateHandle", "fogstate")
//! runtextmacro NEW_ARRAY("Handle", "FogModifierHandle", "fogmodifier")
//! runtextmacro NEW_ARRAY("Handle", "HashtableHandle", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
endlibrary
library NxListT /* v1.0.0.1
************************************************************************************
*
* */ uses /*
*
* */ ErrorMessage /*
* */ TableField /*
*
************************************************************************************
*
* module NxListT
*
* Description
* -------------------------
*
* NA
*
* Fields
* -------------------------
*
* readonly static integer sentinel
*
* readonly thistype list
*
* readonly thistype first
* readonly thistype last
*
* readonly thistype next
* readonly thistype prev
*
* Methods
* -------------------------
*
* method destroy takes nothing returns nothing
* - May only destroy lists
*
* method push takes nothing returns thistype
* method enqueue takes nothing returns thistype
*
* method pop takes nothing returns nothing
* method dequeue takes nothing returns nothing
*
* method remove takes nothing returns nothing
*
* method clear takes nothing returns nothing
* - Initializes list, use instead of create
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
private keyword isNode
private keyword isCollection
private keyword p_list
private keyword p_next
private keyword p_prev
private keyword p_first
private keyword p_last
module NxListT
private static thistype nodeCount = 0
static if DEBUG_MODE then
//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "isNode", "boolean")
//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "isCollection", "boolean")
endif
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_list", "thistype")
method operator list takes nothing returns thistype
debug call ThrowError(this == 0, "NxList", "list", "thistype", this, "Attempted To Read Null Node.")
debug call ThrowError(not isNode, "NxList", "list", "thistype", this, "Attempted To Read Invalid Node.")
return p_list
endmethod
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_next", "thistype")
method operator next takes nothing returns thistype
debug call ThrowError(this == 0, "NxList", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
debug call ThrowError(not isNode, "NxList", "next", "thistype", this, "Attempted To Read Invalid Node.")
return p_next
endmethod
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_prev", "thistype")
method operator prev takes nothing returns thistype
debug call ThrowError(this == 0, "NxList", "prev", "thistype", this, "Attempted To Go Out Of Bounds.")
debug call ThrowError(not isNode, "NxList", "prev", "thistype", this, "Attempted To Read Invalid Node.")
return p_prev
endmethod
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_first", "thistype")
method operator first takes nothing returns thistype
debug call ThrowError(this == 0, "NxList", "first", "thistype", this, "Attempted To Read Null List.")
debug call ThrowError(not isCollection, "NxList", "first", "thistype", this, "Attempted To Read Invalid List.")
return p_first
endmethod
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_last", "thistype")
method operator last takes nothing returns thistype
debug call ThrowError(this == 0, "NxList", "last", "thistype", this, "Attempted To Read Null List.")
debug call ThrowError(not isCollection, "NxList", "last", "thistype", this, "Attempted To Read Invalid List.")
return p_last
endmethod
static method operator sentinel takes nothing returns integer
return 0
endmethod
private static method allocateNode takes nothing returns thistype
local thistype this = thistype(0).p_next
if (0 == this) then
set this = nodeCount + 1
set nodeCount = this
else
set thistype(0).p_next = p_next
endif
return this
endmethod
method push takes nothing returns thistype
local thistype node = allocateNode()
debug call ThrowError(this == 0, "NxList", "push", "thistype", this, "Attempted To Push On To Null List.")
debug call ThrowError(not isCollection, "NxList", "push", "thistype", this, "Attempted To Push On To Invalid List.")
debug set node.isNode = true
set node.p_list = this
if (p_first == 0) then
set p_first = node
set p_last = node
set node.p_next = 0
else
set p_first.p_prev = node
set node.p_next = p_first
set p_first = node
endif
set node.p_prev = 0
return node
endmethod
method enqueue takes nothing returns thistype
local thistype node = allocateNode()
debug call ThrowError(this == 0, "NxList", "enqueue", "thistype", this, "Attempted To Enqueue On To Null List.")
debug call ThrowError(not isCollection, "NxList", "enqueue", "thistype", this, "Attempted To Enqueue On To Invalid List.")
debug set node.isNode = true
set node.p_list = this
if (p_first == 0) then
set p_first = node
set p_last = node
set node.p_prev = 0
else
set p_last.p_next = node
set node.p_prev = p_last
set p_last = node
endif
set node.p_next = 0
return node
endmethod
method pop takes nothing returns nothing
local thistype node = p_first
debug call ThrowError(this == 0, "NxList", "pop", "thistype", this, "Attempted To Pop Null List.")
debug call ThrowError(not isCollection, "NxList", "pop", "thistype", this, "Attempted To Pop Invalid List.")
debug call ThrowError(node == 0, "NxList", "pop", "thistype", this, "Attempted To Pop Empty List.")
debug set node.isNode = false
set p_first.p_list = 0
set p_first = p_first.p_next
if (p_first == 0) then
set p_last = 0
else
set p_first.p_prev = 0
endif
set node.p_next = thistype(0).p_next
set thistype(0).p_next = node
endmethod
method dequeue takes nothing returns nothing
local thistype node = p_last
debug call ThrowError(this == 0, "NxList", "dequeue", "thistype", this, "Attempted To Dequeue Null List.")
debug call ThrowError(not isCollection, "NxList", "dequeue", "thistype", this, "Attempted To Dequeue Invalid List.")
debug call ThrowError(node == 0, "NxList", "dequeue", "thistype", this, "Attempted To Dequeue Empty List.")
debug set node.isNode = false
set p_last.p_list = 0
set p_last = p_last.p_prev
if (p_last == 0) then
set p_first = 0
else
set p_last.p_next = 0
endif
set node.p_next = thistype(0).p_next
set thistype(0).p_next = node
endmethod
method remove takes nothing returns nothing
local thistype node = this
set this = node.p_list
debug call ThrowError(node == 0, "NxList", "remove", "thistype", this, "Attempted To Remove Null Node.")
debug call ThrowError(not node.isNode, "NxList", "remove", "thistype", this, "Attempted To Remove Invalid Node (" + I2S(node) + ").")
debug set node.isNode = false
set node.p_list = 0
if (0 == node.p_prev) then
set p_first = node.p_next
else
set node.p_prev.p_next = node.p_next
endif
if (0 == node.p_next) then
set p_last = node.p_prev
else
set node.p_next.p_prev = node.p_prev
endif
set node.p_next = thistype(0).p_next
set thistype(0).p_next = node
endmethod
method clear takes nothing returns nothing
debug local thistype node = p_first
debug call ThrowError(this == 0, "NxList", "clear", "thistype", this, "Attempted To Clear Null List.")
debug if (not isCollection) then
debug set isCollection = true
debug set p_first = 0
debug set p_last = 0
debug return
debug endif
static if DEBUG_MODE then
loop
exitwhen node == 0
set node.isNode = false
set node = node.p_next
endloop
endif
if (p_first == 0) then
return
endif
set p_last.p_next = thistype(0).p_next
set thistype(0).p_next = p_first
set p_first = 0
set p_last = 0
endmethod
method destroy takes nothing returns nothing
debug call ThrowError(this == 0, "NxList", "destroy", "thistype", this, "Attempted To Destroy Null List.")
debug call ThrowError(not isCollection, "NxList", "destroy", "thistype", this, "Attempted To Destroy Invalid List.")
call clear()
debug set isCollection = false
endmethod
private static method onInit takes nothing returns nothing
static if DEBUG_MODE then
//! runtextmacro INITIALIZE_TABLE_FIELD("isNode")
//! runtextmacro INITIALIZE_TABLE_FIELD("isCollection")
endif
//! runtextmacro INITIALIZE_TABLE_FIELD("p_list")
//! runtextmacro INITIALIZE_TABLE_FIELD("p_next")
//! runtextmacro INITIALIZE_TABLE_FIELD("p_prev")
//! runtextmacro INITIALIZE_TABLE_FIELD("p_first")
//! runtextmacro INITIALIZE_TABLE_FIELD("p_last")
endmethod
static if DEBUG_MODE then
static method calculateMemoryUsage takes nothing returns integer
local thistype start = 1
local thistype end = 8191
local integer count = 0
loop
exitwhen integer(start) > integer(end)
if (integer(start) + 500 > integer(end)) then
return count + checkRegion(start, end)
else
set count = count + checkRegion(start, start + 500)
set start = start + 501
endif
endloop
return count
endmethod
private static method checkRegion takes thistype start, thistype end returns integer
local integer count = 0
loop
exitwhen integer(start) > integer(end)
if (start.isNode) then
set count = count + 1
endif
if (start.isCollection) then
set count = count + 1
endif
set start = start + 1
endloop
return count
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
local thistype start = 1
local thistype end = 8191
local string memory = null
loop
exitwhen integer(start) > integer(end)
if (integer(start) + 500 > integer(end)) then
set memory = memory + checkRegion2(start, end)
set start = end + 1
else
set memory = memory + checkRegion2(start, start + 500)
set start = start + 501
endif
endloop
return memory
endmethod
private static method checkRegion2 takes thistype start, thistype end returns string
local string memory = null
loop
exitwhen integer(start) > integer(end)
if (start.isNode) then
if (memory == null) then
set memory = I2S(start)
else
set memory = memory + ", " + I2S(start) + "N"
endif
endif
if (start.isCollection) then
if (memory == null) then
set memory = I2S(start)
else
set memory = memory + ", " + I2S(start) + "C"
endif
endif
set start = start + 1
endloop
return memory
endmethod
endif
endmodule
endlibrary
library UniqueNxListT /* v1.0.0.1
************************************************************************************
*
* */ uses /*
*
* */ ErrorMessage /*
* */ TableField /*
*
************************************************************************************
*
* module UniqueNxListT
*
* Description
* -------------------------
*
* Node Properties:
*
* Unique
* Allocated
* Not 0
*
* Fields
* -------------------------
*
* readonly static integer sentinel
*
* readonly thistype list
*
* readonly thistype first
* readonly thistype last
*
* readonly thistype next
* readonly thistype prev
*
* Methods
* -------------------------
*
* method destroy takes nothing returns nothing
* - May only destroy lists
*
* method push takes thistype node returns nothing
* method enqueue takes thistype node returns nothing
*
* method pop takes nothing returns nothing
* method dequeue takes nothing returns nothing
*
* method remove takes nothing returns nothing
*
* method clear takes nothing returns nothing
* - Initializes list, use instead of create
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
private keyword isNode
private keyword isCollection
private keyword p_list
private keyword p_next
private keyword p_prev
private keyword p_first
private keyword p_last
module UniqueNxListT
static if DEBUG_MODE then
//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "isNode", "boolean")
//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "isCollection", "boolean")
endif
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_list", "thistype")
method operator list takes nothing returns thistype
debug call ThrowError(this == 0, "UniqueNxListT", "list", "thistype", this, "Attempted To Read Null Node.")
debug call ThrowError(not isNode, "UniqueNxListT", "list", "thistype", this, "Attempted To Read Invalid Node.")
return p_list
endmethod
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_next", "thistype")
method operator next takes nothing returns thistype
debug call ThrowError(this == 0, "UniqueNxListT", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
debug call ThrowError(not isNode, "UniqueNxListT", "next", "thistype", this, "Attempted To Read Invalid Node.")
return p_next
endmethod
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_prev", "thistype")
method operator prev takes nothing returns thistype
debug call ThrowError(this == 0, "UniqueNxListT", "prev", "thistype", this, "Attempted To Go Out Of Bounds.")
debug call ThrowError(not isNode, "UniqueNxListT", "prev", "thistype", this, "Attempted To Read Invalid Node.")
return p_prev
endmethod
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_first", "thistype")
method operator first takes nothing returns thistype
debug call ThrowError(this == 0, "UniqueNxListT", "first", "thistype", this, "Attempted To Read Null List.")
debug call ThrowError(not isCollection, "UniqueNxListT", "first", "thistype", this, "Attempted To Read Invalid List.")
return p_first
endmethod
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "p_last", "thistype")
method operator last takes nothing returns thistype
debug call ThrowError(this == 0, "UniqueNxListT", "last", "thistype", this, "Attempted To Read Null List.")
debug call ThrowError(not isCollection, "UniqueNxListT", "last", "thistype", this, "Attempted To Read Invalid List.")
return p_last
endmethod
static method operator sentinel takes nothing returns integer
return 0
endmethod
method push takes thistype node returns nothing
debug call ThrowError(this == 0, "UniqueNxListT", "push", "thistype", this, "Attempted To Push (" + I2S(node) + ") On To Null List.")
debug call ThrowError(not isCollection, "UniqueNxListT", "push", "thistype", this, "Attempted To Push (" + I2S(node) + ") On To Invalid List.")
debug call ThrowError(node == 0, "UniqueNxListT", "push", "thistype", this, "Attempted To Push Null Node.")
debug call ThrowError(node.isNode, "UniqueNxListT", "push", "thistype", this, "Attempted To Push Owned Node (" + I2S(node) + ").")
debug set node.isNode = true
set node.p_list = this
if (p_first == 0) then
set p_first = node
set p_last = node
set node.p_next = 0
else
set p_first.p_prev = node
set node.p_next = p_first
set p_first = node
endif
set node.p_prev = 0
endmethod
method enqueue takes thistype node returns nothing
debug call ThrowError(this == 0, "UniqueNxListT", "enqueue", "thistype", this, "Attempted To Enqueue (" + I2S(node) + ") On To Null List.")
debug call ThrowError(not isCollection, "UniqueNxListT", "enqueue", "thistype", this, "Attempted To Enqueue (" + I2S(node) + ") On To Invalid List.")
debug call ThrowError(node == 0, "UniqueNxListT", "enqueue", "thistype", this, "Attempted To Enqueue Null Node.")
debug call ThrowError(node.isNode, "UniqueNxListT", "enqueue", "thistype", this, "Attempted To Enqueue Owned Node (" + I2S(node) + ").")
debug set node.isNode = true
set node.p_list = this
if (p_first == 0) then
set p_first = node
set p_last = node
set node.p_prev = 0
else
set p_last.p_next = node
set node.p_prev = p_last
set p_last = node
endif
set node.p_next = 0
endmethod
method pop takes nothing returns nothing
debug call ThrowError(this == 0, "UniqueNxListT", "pop", "thistype", this, "Attempted To Pop Null List.")
debug call ThrowError(not isCollection, "UniqueNxListT", "pop", "thistype", this, "Attempted To Pop Invalid List.")
debug call ThrowError(p_first == 0, "UniqueNxListT", "pop", "thistype", this, "Attempted To Pop Empty List.")
debug set p_first.isNode = false
set p_first.p_list = 0
set p_first = p_first.p_next
if (p_first == 0) then
set p_last = 0
else
set p_first.p_prev = 0
endif
endmethod
method dequeue takes nothing returns nothing
debug call ThrowError(this == 0, "UniqueNxListT", "dequeue", "thistype", this, "Attempted To Dequeue Null List.")
debug call ThrowError(not isCollection, "UniqueNxListT", "dequeue", "thistype", this, "Attempted To Dequeue Invalid List.")
debug call ThrowError(p_last == 0, "UniqueNxListT", "dequeue", "thistype", this, "Attempted To Dequeue Empty List.")
debug set p_last.isNode = false
set p_last.p_list = 0
set p_last = p_last.p_prev
if (p_last == 0) then
set p_first = 0
else
set p_last.p_next = 0
endif
endmethod
method remove takes nothing returns nothing
local thistype node = this
set this = node.p_list
debug call ThrowError(node == 0, "UniqueNxListT", "remove", "thistype", this, "Attempted To Remove Null Node.")
debug call ThrowError(not node.isNode, "UniqueNxListT", "remove", "thistype", this, "Attempted To Remove Invalid Node (" + I2S(node) + ").")
debug set node.isNode = false
set node.p_list = 0
if (0 == node.p_prev) then
set p_first = node.p_next
else
set node.p_prev.p_next = node.p_next
endif
if (0 == node.p_next) then
set p_last = node.p_prev
else
set node.p_next.p_prev = node.p_prev
endif
endmethod
method clear takes nothing returns nothing
debug local thistype node = p_first
debug call ThrowError(this == 0, "UniqueNxListT", "clear", "thistype", this, "Attempted To Clear Null List.")
debug if (not isCollection) then
debug set isCollection = true
debug set p_first = 0
debug set p_last = 0
debug return
debug endif
static if DEBUG_MODE then
loop
exitwhen node == 0
set node.isNode = false
set node = node.p_next
endloop
endif
if (p_first == 0) then
return
endif
set p_first = 0
set p_last = 0
endmethod
method destroy takes nothing returns nothing
debug call ThrowError(this == 0, "UniqueNxListT", "destroy", "thistype", this, "Attempted To Destroy Null List.")
debug call ThrowError(not isCollection, "UniqueNxListT", "destroy", "thistype", this, "Attempted To Destroy Invalid List.")
call clear()
debug set isCollection = false
endmethod
private static method onInit takes nothing returns nothing
static if DEBUG_MODE then
//! runtextmacro INITIALIZE_TABLE_FIELD("isNode")
//! runtextmacro INITIALIZE_TABLE_FIELD("isCollection")
endif
//! runtextmacro INITIALIZE_TABLE_FIELD("p_list")
//! runtextmacro INITIALIZE_TABLE_FIELD("p_next")
//! runtextmacro INITIALIZE_TABLE_FIELD("p_prev")
//! runtextmacro INITIALIZE_TABLE_FIELD("p_first")
//! runtextmacro INITIALIZE_TABLE_FIELD("p_last")
endmethod
static if DEBUG_MODE then
static method calculateMemoryUsage takes nothing returns integer
local thistype start = 1
local thistype end = 8191
local integer count = 0
loop
exitwhen integer(start) > integer(end)
if (integer(start) + 500 > integer(end)) then
return count + checkRegion(start, end)
else
set count = count + checkRegion(start, start + 500)
set start = start + 501
endif
endloop
return count
endmethod
private static method checkRegion takes thistype start, thistype end returns integer
local integer count = 0
loop
exitwhen integer(start) > integer(end)
if (start.isNode) then
set count = count + 1
endif
if (start.isCollection) then
set count = count + 1
endif
set start = start + 1
endloop
return count
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
local thistype start = 1
local thistype end = 8191
local string memory = null
loop
exitwhen integer(start) > integer(end)
if (integer(start) + 500 > integer(end)) then
set memory = memory + checkRegion2(start, end)
set start = end + 1
else
set memory = memory + checkRegion2(start, start + 500)
set start = start + 501
endif
endloop
return memory
endmethod
private static method checkRegion2 takes thistype start, thistype end returns string
local string memory = null
loop
exitwhen integer(start) > integer(end)
if (start.isNode) then
if (memory == null) then
set memory = I2S(start)
else
set memory = memory + ", " + I2S(start) + "N"
endif
endif
if (start.isCollection) then
if (memory == null) then
set memory = I2S(start)
else
set memory = memory + ", " + I2S(start) + "C"
endif
endif
set start = start + 1
endloop
return memory
endmethod
endif
endmodule
endlibrary
library WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
*
* Fields
* -------------------------
*
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
*
* readonly static integer centerX
* readonly static integer centerY
*
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX = R2I(GetRectMaxX(world))
set maxY = R2I(GetRectMaxY(world))
set minX = R2I(GetRectMinX(world))
set minY = R2I(GetRectMinY(world))
set centerX = R2I((maxX + minX)/2)
set centerY = R2I((minY + maxY)/2)
set worldRegion = CreateRegion()
call RegionAddRect(worldRegion, world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
library ErrorMessage /* v1.0.1.4
*************************************************************************************
*
* Issue Compliant Error Messages
*
************************************************************************************
*
* debug function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
* - In the event of an error the game will be permanently paused
*
* debug function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
*
************************************************************************************/
static if DEBUG_MODE then
private struct Fields extends array
static constant string COLOR_RED = "|cffff0000"
static constant string COLOR_YELLOW = "|cffffff00"
static string lastError = null
endstruct
private function Pause takes nothing returns nothing
call PauseGame(true)
endfunction
private function ThrowMessage takes string libraryName, string functionName, string objectName, integer objectInstance, string description, string errorType, string color returns nothing
local string str
local string color_braces = "|cff66FF99"
local string orange = "|cffff6600"
set str = "->\n-> " + color_braces + "{|r " + "Library" + color_braces + "(" + orange + libraryName + color_braces + ")"
if (objectName != null) then
if (objectInstance > 0) then
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + " (|rinstance = " + orange + I2S(objectInstance) + color_braces + ") )" + "|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
else
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + ")|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
else
set str = str + "|r." + "Function" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
set str = str + color_braces + " }|r " + "has thrown an exception of type " + color_braces + "(" + color + errorType + color_braces + ")|r."
set Fields.lastError = str + "\n->\n" + "-> " + color + description + "|r\n->"
endfunction
function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Error", Fields.COLOR_RED)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
call TimerStart(CreateTimer(), 0, true, function Pause)
set objectInstance = 1/0
endif
endfunction
function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Warning", Fields.COLOR_YELLOW)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
set Fields.lastError = null
endif
endfunction
endif
endlibrary
library Init /* v1.0.0.0
************************************************************************************
*
* module Init
*
* interface private static method init takes nothing returns nothing
* - Runs at map init
*
*************************************************************************************
*
* module InitTimer
*
* interface private static method init takes nothing returns nothing
* - Runs after a one-shot timer with a period of 0
*
************************************************************************************/
module Init
static if thistype.init.exists then
private static method onInit takes nothing returns nothing
call init()
endmethod
endif
endmodule
module InitTimer
static if thistype.init.exists then
private static method initex takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
call init()
endmethod
private static method onInit takes nothing returns nothing
call TimerStart(CreateTimer(), 0, false, function thistype.initex)
endmethod
endif
endmodule
endlibrary
library TableField /* v1.0.0.1
************************************************************************************
*
* */ uses /*
*
* */ Table /*
* */ Init /*
*
************************************************************************************
*
* //! textmacro CREATE_TABLE_FIELD takes ACCESS_MODIFIER, TYPE, NAME, RETURN_TYPE
* - creates a table field surrounded by method operators
*
* //! textmacro INITIALIZE_TABLE_FIELD takes NAME
* - initializes table field
* - used in onInit
*
* //! textmacro CREATE_TABLE_FIELD_ARRAY takes TYPE, NAME, RETURN_TYPE
* - creates a struct that acts as an array
* - not used in a struct
*
* //! textmacro USE_TABLE_FIELD_ARRAY takes ACCESS_MODIFIER, NAME
* - creates a field of a struct array
* - used in a struct
*
************************************************************************************/
//! textmacro CREATE_TABLE_FIELD takes ACCESS_MODIFIER, TYPE, NAME, RETURN_TYPE
private static Table t$NAME$
$ACCESS_MODIFIER$ method operator $NAME$ takes nothing returns $RETURN_TYPE$
return t$NAME$.$TYPE$[this]
endmethod
$ACCESS_MODIFIER$ method operator $NAME$= takes $RETURN_TYPE$ value returns nothing
set t$NAME$.$TYPE$[this] = value
endmethod
$ACCESS_MODIFIER$ method $NAME$_clear takes nothing returns nothing
call t$NAME$.$TYPE$.remove(this)
endmethod
//! endtextmacro
//! textmacro CREATE_TABLE_FIELD_ARRAY takes TYPE, NAME, RETURN_TYPE
private struct T$NAME$ extends array
private static Table table
method operator [] takes integer index returns $RETURN_TYPE$
return table.$TYPE$[index]
endmethod
method operator []= takes integer index, $RETURN_TYPE$ value returns nothing
set table.$TYPE$[index] = value
endmethod
static method remove takes integer index returns nothing
call table.$TYPE$.remove(index)
endmethod
static method clear takes nothing returns nothing
call table.flush()
endmethod
private static method init takes nothing returns nothing
set table = Table.create()
endmethod
implement Init
endstruct
//! endtextmacro
//! textmacro USE_TABLE_FIELD_ARRAY takes ACCESS_MODIFIER, NAME
$ACCESS_MODIFIER$ static T$NAME$ $NAME$ = 0
//! endtextmacro
//! textmacro INITIALIZE_TABLE_FIELD takes NAME
set t$NAME$ = Table.create()
//! endtextmacro
endlibrary
library BooleanExpression /* v1.2.0.0
************************************************************************************
*
* */ uses /*
*
* */ ErrorMessage /*
* */ ListT /*
* */ Table /*
* */ Init /*
* */ TableField /*
*
************************************************************************************
*
* struct BooleanExpression extends array
*
* Description
* -------------------------
*
* Creates a single boolean expression via Or's
*
* Provides a slight speed boost
*
* Allows the for the safe usage of TriggerRemoveCondition given that the only boolexpr on the trigger
* is the one from this struct
*
* To put multiple boolean expressions on to one trigger, combine them with Or. Be sure to destroy later.
*
* Alternatively, they can be wrapped with another BooleanExpression, but this will add overhead. Only use
* if more than three are planned to be on one trigger.
*
* Fields
* -------------------------
*
* readonly boolexpr expression
*
* Examples: call booleanExpression.register(myCode)
* call TriggerRemoveCondition(thisTrigger, theOneCondition)
* set theOneCondition = TriggerAddCondition(thisTrigger, booleanExpression.expression)
*
* boolean reversed
* - if this is true, the expression will run in reverse
*
* Methods
* -------------------------
*
* static method create takes boolean reversed returns BooleanExpression
* - if reversed is true, the expression will run in reverse
*
* method destroy takes nothing returns nothing
* - only use .destroy with BooleanExpression from .create, not .register
*
* method register takes boolexpr expression returns BooleanExpression
* - the returned BooleanExpression is a subtype to be used with
* - .unregister and .replace
* method unregister takes nothing returns nothing
* - unregisters a BooleanExpression
* - only use BooleanExpression from .register, not .create
*
* method replace takes boolexpr expression returns nothing
* - replaces the boolexpr inside of the registered expression
* - useful for updating expressions without breaking order
* - null expressions take no space and have no overhead, so use them
* - only use BooleanExpression from .register, not .create
*
* method clear takes nothing returns nothing
* - only use .clear with BooleanExpression from .create, not .register
*
* debug static method calculateMemoryUsage takes nothing returns integer
* - calculates how many instances are currently active
* debug static method getAllocatedMemoryAsString takes nothing returns string
* - returns a list of all active instances as a string
*
************************************************************************************/
private struct List extends array
//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "reversed", "boolean")
implement ListT
private static method init takes nothing returns nothing
//! runtextmacro INITIALIZE_TABLE_FIELD("reversed")
endmethod
implement Init
endstruct
private struct TreeNode extends array
/*
* Tree Fields
*/
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "root", "thistype")
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "left", "thistype")
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "right", "thistype")
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "height", "integer")
/*
* Standard Fields
*/
//! runtextmacro CREATE_TABLE_FIELD("public", "boolexpr", "expression", "boolexpr")
//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "canDestroy", "boolean")
///! runtextmacro CREATE_TABLE_FIELD("public", "integer", "list", "ListExpression")
public method operator isData takes nothing returns boolean
return height == 1
endmethod
public method operator isNode takes nothing returns boolean
return height != 1
endmethod
public method join takes nothing returns nothing
if (canDestroy) then
call DestroyBoolExpr(expression)
endif
if (left.expression == null) then
set canDestroy = false
if (right.expression == null) then
call expression_clear()
else
set expression = right.expression
endif
elseif (right.expression == null) then
set canDestroy = false
set expression = left.expression
elseif (List(this).list.reversed) then
set canDestroy = true
set expression = Or(right.expression, left.expression)
else
set canDestroy = true
set expression = Or(left.expression, right.expression)
endif
endmethod
public method rebuild takes nothing returns nothing
if (isNode) then
call left.rebuild()
call right.rebuild()
call join()
endif
endmethod
public method replace takes boolexpr expression returns nothing
if (this.expression == expression) then
return
endif
if (expression == null) then
call this.expression_clear()
else
set this.expression = expression
endif
loop
set this = root
exitwhen this == 0
call join()
endloop
endmethod
public static method create takes List parent returns thistype
local thistype this = parent.enqueue()
set canDestroy = false
set height = 1
return this
endmethod
public static method createData takes List parent returns thistype
local thistype this = parent.push()
set canDestroy = false
return this
endmethod
method clean takes nothing returns nothing
if (canDestroy) then
call DestroyBoolExpr(expression)
endif
call expression_clear()
endmethod
method destroy takes nothing returns nothing
call clean()
call List(this).remove()
endmethod
public method operator sibling takes nothing returns thistype
if (root != 0) then
if (root.left == this) then
return root.right
else
return root.left
endif
endif
return 0
endmethod
method updateHeight takes nothing returns nothing
if (left.height > right.height) then
set height = left.height + 1
else
set height = right.height + 1
endif
endmethod
method operator factor takes nothing returns integer
return left.height - right.height
endmethod
method setRoot takes thistype newNode returns nothing
local thistype root = this.root
if (root != 0) then
if (this == root.left) then
set root.left = newNode
else
set root.right = newNode
endif
endif
set newNode.root = root
endmethod
method rotateRight takes nothing returns thistype
local thistype newRoot = left
call setRoot(newRoot)
set root = newRoot
set left = newRoot.right
set left.root = this
set newRoot.right = this
call updateHeight()
call newRoot.updateHeight()
call join()
call newRoot.join()
return newRoot
endmethod
method rotateLeft takes nothing returns thistype
local thistype newRoot = right
call setRoot(newRoot)
set root = newRoot
set right = newRoot.left
set right.root = this
set newRoot.left = this
call updateHeight()
call newRoot.updateHeight()
call join()
call newRoot.join()
return newRoot
endmethod
method balance takes nothing returns thistype
local integer factor
local thistype node
loop
call updateHeight()
set factor = this.factor
if (factor > 1) then
if (left.factor < 0) then
call left.rotateLeft()
endif
set this = rotateRight()
exitwhen true
elseif (factor < -1) then
if (right.factor > 0) then
call right.rotateRight()
endif
set this = rotateLeft()
exitwhen true
else
call join()
endif
set this = root
exitwhen this == 0
endloop
if (this != 0) then
set node = root
loop
exitwhen node == 0
call node.updateHeight()
call node.join()
set node = node.root
endloop
endif
return this
endmethod
private static method init takes nothing returns nothing
//! runtextmacro INITIALIZE_TABLE_FIELD("root")
//! runtextmacro INITIALIZE_TABLE_FIELD("left")
//! runtextmacro INITIALIZE_TABLE_FIELD("right")
//! runtextmacro INITIALIZE_TABLE_FIELD("height")
//! runtextmacro INITIALIZE_TABLE_FIELD("expression")
//! runtextmacro INITIALIZE_TABLE_FIELD("canDestroy")
endmethod
implement Init
endstruct
private struct Tree extends array
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "root", "TreeNode")
public static method create takes boolean reversed returns thistype
local thistype this = List.create()
set List(this).reversed = reversed
return this
endmethod
method clear takes nothing returns nothing
local List node = List(this).first
loop
exitwhen node == 0
call TreeNode(node).clean()
set node = node.next
endloop
call List(this).clear()
call root_clear()
endmethod
method destroy takes nothing returns nothing
call clear()
call List(this).destroy()
endmethod
method operator reversed takes nothing returns boolean
return List(this).reversed
endmethod
method operator reversed= takes boolean b returns nothing
if (b == reversed) then
return
endif
set List(this).reversed = b
if (root != 0) then
call root.rebuild()
endif
endmethod
method updateRoot takes TreeNode node returns nothing
if (node != 0 and node.root == 0) then
set this.root = node
endif
endmethod
method insert takes boolexpr expression returns TreeNode
local TreeNode sibling = List(this).last
local TreeNode node = TreeNode.create(this)
local TreeNode root = 0
local TreeNode grandroot = 0
if (expression != null) then
set node.expression = expression
endif
if (sibling != 0) then
set root = TreeNode.createData(this)
set grandroot = sibling.root
set root.left = sibling
set root.right = node
set node.root = root
set sibling.root = root
set root.height = 2
set root.root = grandroot
call root.join()
if (grandroot != 0) then
set grandroot.right = root
call updateRoot(grandroot.balance())
else
set this.root = root
endif
else
set this.root = node
call node.root_clear()
endif
call node.left_clear()
call node.right_clear()
return node
endmethod
method delete takes TreeNode node returns nothing
local TreeNode sibling = node.sibling
local TreeNode root = node.root
local TreeNode grandroot
if (root != 0) then
set grandroot = root.root
endif
if (sibling != 0) then
if (sibling.isData) then
set sibling.root = grandroot
if (grandroot != 0) then
if (grandroot.left == root) then
set grandroot.left = sibling
else
set grandroot.right = sibling
endif
call updateRoot(grandroot.balance())
else
set this.root = sibling
endif
call root.destroy()
else
set root.left = sibling.left
set root.right = sibling.right
call root.updateHeight()
call root.join()
if (sibling.left != 0) then
set sibling.left.root = root
endif
if (sibling.right != 0) then
set sibling.right.root = root
endif
call sibling.destroy()
if (grandroot != 0) then
call updateRoot(grandroot.balance())
endif
endif
else
set this.root = 0
endif
call node.destroy()
endmethod
private static method init takes nothing returns nothing
//! runtextmacro INITIALIZE_TABLE_FIELD("root")
endmethod
implement Init
endstruct
struct BooleanExpression extends array
method operator expression takes nothing returns boolexpr
debug call ThrowError(not List(this).isList, "BooleanExpression", "expression", "BooleanExpression", this, "Attempted To Read Null Boolean Expression.")
if (Tree(this).root != 0) then
return Tree(this).root.expression
endif
return null
endmethod
method operator reversed takes nothing returns boolean
debug call ThrowError(not List(this).isList, "BooleanExpression", "reversed", "BooleanExpression", this, "Attempted To Read Null Boolean Expression.")
return Tree(this).reversed
endmethod
method operator reversed= takes boolean b returns nothing
debug call ThrowError(not List(this).isList, "BooleanExpression", "reversed", "BooleanExpression", this, "Attempted To Set Null Boolean Expression.")
set Tree(this).reversed = b
endmethod
static method create takes boolean reversed returns thistype
return Tree.create(reversed)
endmethod
method destroy takes nothing returns nothing
debug call ThrowError(not List(this).isList, "BooleanExpression", "reversed", "BooleanExpression", this, "Attempted To Destroy Null Boolean Expression.")
call Tree(this).destroy()
endmethod
method register takes boolexpr expression returns BooleanExpression
return Tree(this).insert(expression)
endmethod
method unregister takes nothing returns nothing
debug call ThrowError(not TreeNode(this).isData, "BooleanExpression", "unregister", "BooleanExpression", this, "Attempted To Unregister Null Boolean Expression.")
call Tree(List(this).list).delete(this)
endmethod
method replace takes boolexpr expression returns nothing
debug call ThrowError(not TreeNode(this).isData, "BooleanExpression", "replace", "BooleanExpression", this, "Attempted To Replace Null Boolean Expression.")
call TreeNode(this).replace(expression)
endmethod
method clear takes nothing returns nothing
debug call ThrowError(not List(this).isList, "BooleanExpression", "clear", "BooleanExpression", this, "Attempted To Clear Null Boolean Expression.")
call Tree(this).clear()
endmethod
private static string indentation = " "
static method printEx takes TreeNode node, string indent, boolean height returns nothing
if (node != 0) then
call printEx(node.right, indent + indentation, height)
if (height) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, indent + I2S(node.height))
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, indent + I2S(node))
endif
call printEx(node.left, indent + indentation, height)
endif
endmethod
method print takes boolean height returns nothing
call printEx(Tree(this).root, "", height)
call DisplayTimedTextFromPlayer(GetLocalPlayer(), 0, 0, 60000, "------------------------------------")
endmethod
debug static method calculateMemoryUsage takes nothing returns integer
debug return List.calculateMemoryUsage()
debug endmethod
debug static method getAllocatedMemoryAsString takes nothing returns string
debug return List.getAllocatedMemoryAsString()
debug endmethod
endstruct
endlibrary
library Trigger /* v1.1.0.2
************************************************************************************
*
* */ uses /*
*
* */ ErrorMessage /*
* */ BooleanExpression /*
* */ NxListT /*
* */ UniqueNxListT /*
* */ Init /*
* */ AllocT /*
*
************************************************************************************
*
* struct Trigger extends array
*
* Fields
* -------------------------
*
* readonly trigger trigger
* - use to register events, nothing else
* - keep in mind that triggers referencing this trigger won't fire when events fire
* - this trigger will fire when triggers referencing this trigger are fired
*
* boolean enabled
*
* Methods
* -------------------------
*
* static method create takes boolean reversed returns Trigger
* - when reverse is true, the entire expression is run in reverse
*
* method destroy takes nothing returns nothing
*
* method register takes boolexpr expression returns TriggerCondition
*
* method reference takes Trigger trig returns TriggerReference
* - like register, but for triggers instead
*
* method fire takes nothing returns nothing
*
* method clear takes nothing returns nothing
* - clears expressions
* method clearReferences takes nothing returns nothing
* - clears trigger references
* method clearBackReferences takes nothing returns nothing
* - removes references for all triggers referencing this trigger
* method clearEvents takes nothing returns nothing
* - clears events
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************
*
* struct TriggerReference extends array
*
* Methods
* -------------------------
*
* method destroy takes nothing returns nothing
*
* method replace takes Trigger trigger returns nothing
*
************************************************************************************
*
* struct TriggerCondition extends array
*
* Methods
* -------------------------
*
* method destroy takes nothing returns nothing
*
* method replace takes boolexpr expr returns nothing
*
************************************************************************************/
private struct TriggerMemory extends array
//! runtextmacro CREATE_TABLE_FIELD("public", "trigger", "trig", "trigger")
//! runtextmacro CREATE_TABLE_FIELD("public", "triggercondition", "tc", "triggercondition")
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "expression", "BooleanExpression") //the trigger's expression
//! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "enabled", "boolean")
method updateTrigger takes nothing returns nothing
if (tc != null) then
call TriggerRemoveCondition(trig, tc)
endif
if (enabled and expression.expression != null) then
set tc = TriggerAddCondition(trig, expression.expression)
else
call tc_clear()
endif
endmethod
private static method init takes nothing returns nothing
//! runtextmacro INITIALIZE_TABLE_FIELD("trig")
//! runtextmacro INITIALIZE_TABLE_FIELD("tc")
//! runtextmacro INITIALIZE_TABLE_FIELD("expression")
//! runtextmacro INITIALIZE_TABLE_FIELD("enabled")
endmethod
implement Init
endstruct
private struct TriggerAllocator extends array
implement AllocT
endstruct
private keyword TriggerReferencedList
private struct TriggerReferenceListData extends array
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "trig", "TriggerMemory") //the referenced trigger
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "ref", "TriggerReferencedList") //the TriggerReferencedList data for that trigger (relationship in 2 places)
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "expr", "BooleanExpression")
implement NxListT
private static method init takes nothing returns nothing
//! runtextmacro INITIALIZE_TABLE_FIELD("trig")
//! runtextmacro INITIALIZE_TABLE_FIELD("ref")
//! runtextmacro INITIALIZE_TABLE_FIELD("expr")
endmethod
implement Init
endstruct
/*
* List of triggers referencing current trigger
*/
private struct TriggerReferencedList extends array
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "trig", "TriggerMemory") //the trigger referencing this trigger
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "ref", "TriggerReferenceListData") //the ref
implement NxListT
method updateExpression takes nothing returns nothing
local thistype node
local boolexpr expr
/*
* Retrieve the expression of the referenced trigger
*/
if (TriggerMemory(this).enabled) then
set expr = TriggerMemory(this).expression.expression
else
set expr = null
endif
/*
* Iterate over all triggers referencing this trigger
*/
set node = first
loop
exitwhen node == 0
/*
* Replace expression and then update the target trigger
*/
call node.ref.expr.replace(expr)
call node.trig.updateTrigger()
call TriggerReferencedList(node.trig).updateExpression()
set node = node.next
endloop
set expr = null
endmethod
method purge takes nothing returns nothing
local thistype node = first
loop
exitwhen node == 0
/*
* Unregister the expression from the referencing trigger
* Update that trigger
*/
call node.ref.expr.unregister()
call node.trig.updateTrigger()
call node.ref.remove()
call TriggerReferencedList(node.trig).updateExpression()
set node = node.next
endloop
call destroy()
endmethod
method clearReferences takes nothing returns nothing
local thistype node = first
loop
exitwhen node == 0
/*
* Unregister the expression from the referencing trigger
* Update that trigger
*/
call node.ref.expr.unregister()
call node.trig.updateTrigger()
call node.ref.remove()
call TriggerReferencedList(node.trig).updateExpression()
set node = node.next
endloop
call clear()
endmethod
private static method init takes nothing returns nothing
//! runtextmacro INITIALIZE_TABLE_FIELD("trig")
//! runtextmacro INITIALIZE_TABLE_FIELD("ref")
endmethod
implement Init
endstruct
/*
* List of triggers current trigger references
*/
private struct TriggerReferenceList extends array
method add takes TriggerReferencedList trig returns thistype
local TriggerReferenceListData node = TriggerReferenceListData(this).enqueue()
/*
* Register the trigger as a reference
*/
set node.trig = trig
set node.ref = TriggerReferencedList(trig).enqueue()
set node.ref.trig = this
set node.ref.ref = node
/*
* Add the reference's expression
*
* Add even if null to ensure correct order
*/
if (TriggerMemory(trig).enabled) then
set node.expr = TriggerMemory(this).expression.register(TriggerMemory(trig).expression.expression)
else
set node.expr = TriggerMemory(this).expression.register(null)
endif
call TriggerMemory(this).updateTrigger()
/*
* Update the expressions of triggers referencing this trigger
*/
call TriggerReferencedList(this).updateExpression()
/*
* Return the reference
*/
return node
endmethod
method erase takes nothing returns nothing
local TriggerReferenceListData node = this //the node
set this = node.ref.trig //this trigger
call node.expr.unregister()
call TriggerMemory(this).updateTrigger()
call TriggerReferencedList(this).updateExpression()
call node.ref.remove()
call node.remove()
endmethod
method replace takes TriggerMemory trig returns nothing
local TriggerReferenceListData node = this
set this = node.list
call node.ref.remove()
set node.trig = trig
set node.ref = TriggerReferencedList(trig).enqueue()
set node.ref.trig = this
set node.ref.ref = node
if (trig.enabled) then
call node.expr.replace(trig.expression.expression)
else
call node.expr.replace(null)
endif
call TriggerMemory(this).updateTrigger()
call TriggerReferencedList(this).updateExpression()
endmethod
/*
* Purges all references
*/
method purge takes nothing returns nothing
local TriggerReferenceListData node = TriggerReferenceListData(this).first
loop
exitwhen node == 0
/*
* Removes the reference from the referenced list
* (triggers no longer referenced by this)
*/
call node.ref.remove()
set node = node.next
endloop
/*
* Destroy all references by triggers referencing this
*/
call TriggerReferencedList(this).purge()
call TriggerReferenceListData(this).destroy()
endmethod
method clearReferences takes nothing returns nothing
local TriggerReferenceListData node = TriggerReferenceListData(this).first
loop
exitwhen node == 0
/*
* Removes the reference from the referenced list
* (triggers no longer referenced by this)
*/
call node.ref.remove()
/*
* unregisters code
*/
call node.expr.unregister()
set node = node.next
endloop
call TriggerReferenceListData(this).clear()
endmethod
endstruct
private struct TriggerReferenceData extends array
static if DEBUG_MODE then
//! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isTriggerReference", "boolean")
endif
static method create takes TriggerReferenceList origin, TriggerMemory ref returns thistype
local thistype this = origin.add(ref)
debug set isTriggerReference = true
return this
endmethod
method destroy takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Null TriggerReferenceData.")
debug call ThrowError(not isTriggerReference, "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Invalid TriggerReferenceData.")
debug set isTriggerReference = false
call TriggerReferenceList(this).erase()
endmethod
method replace takes Trigger trig returns nothing
debug call ThrowError(this == 0, "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Null TriggerReferenceData.")
debug call ThrowError(not isTriggerReference, "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Invalid TriggerReferenceData.")
call TriggerReferenceList(this).replace(trig)
endmethod
private static method init takes nothing returns nothing
static if DEBUG_MODE then
//! runtextmacro INITIALIZE_TABLE_FIELD("isTriggerReference")
endif
endmethod
implement Init
endstruct
private struct TriggerConditionDataCollection extends array
implement UniqueNxListT
endstruct
private struct TriggerConditionData extends array
static if DEBUG_MODE then
//! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isCondition", "boolean")
endif
//! runtextmacro CREATE_TABLE_FIELD("private", "integer", "trig", "TriggerMemory")
private static method updateTrigger takes TriggerMemory trig returns nothing
call trig.updateTrigger()
call TriggerReferencedList(trig).updateExpression()
endmethod
static method create takes TriggerMemory trig, boolexpr expression returns thistype
local thistype this = trig.expression.register(expression)
set this.trig = trig
debug set isCondition = true
call TriggerConditionDataCollection(trig).enqueue(this)
call updateTrigger(trig)
return this
endmethod
method destroy takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Null TriggerConditionData.")
debug call ThrowError(not isCondition, "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Invalid TriggerConditionData.")
call BooleanExpression(this).unregister()
call TriggerConditionDataCollection(this).remove()
debug set isCondition = false
/*
* Update the expression
*/
call updateTrigger(trig)
endmethod
method replace takes boolexpr expr returns nothing
debug call ThrowError(this == 0, "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Null TriggerConditionData.")
debug call ThrowError(not isCondition, "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Invalid TriggerConditionData.")
call BooleanExpression(this).replace(expr)
call updateTrigger(trig)
endmethod
private static method init takes nothing returns nothing
static if DEBUG_MODE then
//! runtextmacro INITIALIZE_TABLE_FIELD("isCondition")
endif
//! runtextmacro INITIALIZE_TABLE_FIELD("trig")
endmethod
implement Init
endstruct
struct TriggerReference extends array
method destroy takes nothing returns nothing
call TriggerReferenceData(this).destroy()
endmethod
method replace takes Trigger trig returns nothing
call TriggerReferenceData(this).replace(trig)
endmethod
endstruct
struct TriggerCondition extends array
method destroy takes nothing returns nothing
call TriggerConditionData(this).destroy()
endmethod
method replace takes boolexpr expr returns nothing
call TriggerConditionData(this).replace(expr)
endmethod
endstruct
struct Trigger extends array
static if DEBUG_MODE then
//! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isTrigger", "boolean")
endif
static method create takes boolean reversed returns thistype
local thistype this = TriggerAllocator.allocate()
debug set isTrigger = true
set TriggerMemory(this).enabled = true
call TriggerReferencedList(this).clear()
call TriggerReferenceListData(this).clear()
call TriggerConditionDataCollection(this).clear()
set TriggerMemory(this).expression = BooleanExpression.create(reversed)
set TriggerMemory(this).trig = CreateTrigger()
return this
endmethod
static if DEBUG_MODE then
method destroy takes nothing returns nothing
call destroy_p()
endmethod
private method destroy_p takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Invalid Trigger.")
debug set isTrigger = false
call TriggerReferenceList(this).purge()
call TriggerConditionDataCollection(this).destroy()
if (TriggerMemory(this).tc != null) then
call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
endif
call TriggerMemory(this).tc_clear()
call DestroyTrigger(TriggerMemory(this).trig)
call TriggerMemory(this).trig_clear()
call TriggerMemory(this).expression.destroy()
call TriggerAllocator(this).deallocate()
endmethod
else
method destroy takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Invalid Trigger.")
debug set isTrigger = false
call TriggerReferenceList(this).purge()
call TriggerConditionDataCollection(this).destroy()
if (TriggerMemory(this).tc != null) then
call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
endif
call TriggerMemory(this).tc_clear()
call DestroyTrigger(TriggerMemory(this).trig)
call TriggerMemory(this).trig_clear()
call TriggerMemory(this).expression.destroy()
call TriggerAllocator(this).deallocate()
endmethod
endif
static if DEBUG_MODE then
method register takes boolexpr expression returns TriggerCondition
return register_p(expression)
endmethod
private method register_p takes boolexpr expression returns TriggerCondition
debug call ThrowError(this == 0, "Trigger", "register", "Trigger", this, "Attempted To Register To Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "register", "Trigger", this, "Attempted To Register To Invalid Trigger.")
/*
* Register the expression
*/
return TriggerConditionData.create(this, expression)
endmethod
else
method register takes boolexpr expression returns TriggerCondition
debug call ThrowError(this == 0, "Trigger", "register", "Trigger", this, "Attempted To Register To Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "register", "Trigger", this, "Attempted To Register To Invalid Trigger.")
/*
* Register the expression
*/
return TriggerConditionData.create(this, expression)
endmethod
endif
static if DEBUG_MODE then
method clear takes nothing returns nothing
call clear_p()
endmethod
private method clear_p takes nothing returns nothing
local TriggerConditionDataCollection node = TriggerConditionDataCollection(this).first
debug call ThrowError(this == 0, "Trigger", "clear", "Trigger", this, "Attempted To Clear Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "clear", "Trigger", this, "Attempted To Clear Invalid Trigger.")
loop
exitwhen node == 0
call BooleanExpression(node).unregister()
set node = node.next
endloop
call TriggerConditionDataCollection(this).clear()
call TriggerMemory(this).updateTrigger()
call TriggerReferencedList(this).updateExpression()
endmethod
else
method clear takes nothing returns nothing
local TriggerConditionDataCollection node = TriggerConditionDataCollection(this).first
debug call ThrowError(this == 0, "Trigger", "clear", "Trigger", this, "Attempted To Clear Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "clear", "Trigger", this, "Attempted To Clear Invalid Trigger.")
loop
exitwhen node == 0
call BooleanExpression(node).unregister()
set node = node.next
endloop
call TriggerConditionDataCollection(this).clear()
call TriggerMemory(this).updateTrigger()
call TriggerReferencedList(this).updateExpression()
endmethod
endif
static if DEBUG_MODE then
method clearReferences takes nothing returns nothing
call clearReferences_p()
endmethod
private method clearReferences_p takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Invalid Trigger.")
call TriggerReferenceList(this).clearReferences()
call TriggerMemory(this).updateTrigger()
call TriggerReferencedList(this).updateExpression()
endmethod
else
method clearReferences takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Invalid Trigger.")
call TriggerReferenceList(this).clearReferences()
call TriggerMemory(this).updateTrigger()
call TriggerReferencedList(this).updateExpression()
endmethod
endif
static if DEBUG_MODE then
method clearBackReferences takes nothing returns nothing
call clearBackReferences_p()
endmethod
private method clearBackReferences_p takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Invalid Trigger.")
call TriggerReferencedList(this).clearReferences()
endmethod
else
method clearBackReferences takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Invalid Trigger.")
call TriggerReferencedList(this).clearReferences()
endmethod
endif
static if DEBUG_MODE then
method reference takes thistype trig returns TriggerReference
return reference_p(trig)
endmethod
private method reference_p takes thistype trig returns TriggerReference
debug call ThrowError(this == 0, "Trigger", "reference", "Trigger", this, "Attempted To Make Null Trigger Reference Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "reference", "Trigger", this, "Attempted To Make Invalid Trigger Reference Trigger.")
debug call ThrowError(trig == 0, "Trigger", "reference", "Trigger", this, "Attempted To Reference Null Trigger (" + I2S(trig) + ").")
debug call ThrowError(not trig.isTrigger, "Trigger", "reference", "Trigger", this, "Attempted To Reference Invalid Trigger (" + I2S(trig) + ").")
return TriggerReferenceData.create(this, trig)
endmethod
else
method reference takes thistype trig returns TriggerReference
debug call ThrowError(this == 0, "Trigger", "reference", "Trigger", this, "Attempted To Make Null Trigger Reference Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "reference", "Trigger", this, "Attempted To Make Invalid Trigger Reference Trigger.")
debug call ThrowError(trig == 0, "Trigger", "reference", "Trigger", this, "Attempted To Reference Null Trigger (" + I2S(trig) + ").")
debug call ThrowError(not trig.isTrigger, "Trigger", "reference", "Trigger", this, "Attempted To Reference Invalid Trigger (" + I2S(trig) + ").")
return TriggerReferenceData.create(this, trig)
endmethod
endif
static if DEBUG_MODE then
method clearEvents takes nothing returns nothing
call clearEvents_p()
endmethod
private method clearEvents_p takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Invalid Trigger.")
if (TriggerMemory(this).tc != null) then
call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
endif
call DestroyTrigger(TriggerMemory(this).trig)
set TriggerMemory(this).trig = CreateTrigger()
if (TriggerMemory(this).enabled) then
set TriggerMemory(this).tc = TriggerAddCondition(TriggerMemory(this).trig, TriggerMemory(this).expression.expression)
else
call TriggerMemory(this).tc_clear()
endif
endmethod
else
method clearEvents takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Invalid Trigger.")
if (TriggerMemory(this).tc != null) then
call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
endif
call DestroyTrigger(TriggerMemory(this).trig)
set TriggerMemory(this).trig = CreateTrigger()
if (TriggerMemory(this).enabled) then
set TriggerMemory(this).tc = TriggerAddCondition(TriggerMemory(this).trig, TriggerMemory(this).expression.expression)
else
call TriggerMemory(this).tc_clear()
endif
endmethod
endif
method fire takes nothing returns nothing
debug call ThrowError(this == 0, "Trigger", "fire", "Trigger", this, "Attempted To Fire Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "fire", "Trigger", this, "Attempted To Fire Invalid Trigger.")
call TriggerEvaluate(TriggerMemory(this).trig)
endmethod
method operator trigger takes nothing returns trigger
debug call ThrowError(this == 0, "Trigger", "trigger", "Trigger", this, "Attempted To Read Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "trigger", "Trigger", this, "Attempted To Read Invalid Trigger.")
return TriggerMemory(this).trig
endmethod
method operator enabled takes nothing returns boolean
debug call ThrowError(this == 0, "Trigger", "enabled", "Trigger", this, "Attempted To Read Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "enabled", "Trigger", this, "Attempted To Read Invalid Trigger.")
return TriggerMemory(this).enabled
endmethod
static if DEBUG_MODE then
method operator enabled= takes boolean enable returns nothing
set enabled_p = enable
endmethod
private method operator enabled_p= takes boolean enable returns nothing
debug call ThrowError(this == 0, "Trigger", "enabled=", "Trigger", this, "Attempted To Set Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "enabled=", "Trigger", this, "Attempted To Set Invalid Trigger.")
debug call ThrowWarning(TriggerMemory(this).enabled == enable, "Trigger", "enabled=", "Trigger", this, "Setting Enabled To Its Value.")
set TriggerMemory(this).enabled = enable
call TriggerMemory(this).updateTrigger()
call TriggerReferencedList(this).updateExpression()
endmethod
else
method operator enabled= takes boolean enable returns nothing
debug call ThrowError(this == 0, "Trigger", "enabled=", "Trigger", this, "Attempted To Set Null Trigger.")
debug call ThrowError(not isTrigger, "Trigger", "enabled=", "Trigger", this, "Attempted To Set Invalid Trigger.")
debug call ThrowWarning(TriggerMemory(this).enabled == enable, "Trigger", "enabled=", "Trigger", this, "Setting Enabled To Its Value.")
set TriggerMemory(this).enabled = enable
call TriggerMemory(this).updateTrigger()
call TriggerReferencedList(this).updateExpression()
endmethod
endif
static if DEBUG_MODE then
static method calculateMemoryUsage takes nothing returns integer
return /*
*/ TriggerAllocator.calculateMemoryUsage() + /*
*/ TriggerConditionDataCollection.calculateMemoryUsage() + /*
*/ TriggerReferenceListData.calculateMemoryUsage() + /*
*/ TriggerReferencedList.calculateMemoryUsage() + /*
*/ BooleanExpression.calculateMemoryUsage()
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
return /*
*/ "(Trigger)[" + TriggerAllocator.getAllocatedMemoryAsString() + "], " + /*
*/ "(Trigger TriggerConditionDataCollection)[" + TriggerConditionDataCollection.getAllocatedMemoryAsString() + "], " + /*
*/ "(Trigger Reference)[" + TriggerReferenceListData.getAllocatedMemoryAsString() + "], " + /*
*/ "(Trigger Reference Back)[" + TriggerReferencedList.getAllocatedMemoryAsString() + "], " + /*
*/ "(Boolean Expression (all))[" + BooleanExpression.getAllocatedMemoryAsString() + "]"
endmethod
endif
private static method init takes nothing returns nothing
static if DEBUG_MODE then
//! runtextmacro INITIALIZE_TABLE_FIELD("isTrigger")
endif
endmethod
implement Init
endstruct
endlibrary
/*
* Only use this if you are not going to use the install script
*/
/*
* Rather than using the install script, you may copy the following ability to your map
*
* Object Editor -> Abilities -> Unit Indexing (Unit Indexing)
*/
library UnitIndexerSettings
globals
constant integer ABILITIES_UNIT_INDEXER = 'A000'
endglobals
endlibrary
/*
* This is for World Editor
*
* You will need to
*
* 1. Enable This Trigger
* 2. Save Your Map
* 3. Close Your Map
* 4. Open Your Map
* 5. Disable This Trigger
* 6. Save Your Map
*/
//! externalblock extension=lua ObjectMerger $FILENAME$
//! i do
//! i dofile("GetVarObject")
//! i local id = getvarobject("Adef", "abilities", "ABILITIES_UNIT_INDEXER", true)
//! i createobject("Adef", id)
//! i makechange(current, "aart", "")
//! i makechange(current, "arac", "0")
//! i makechange(current, "anam", "Unit Indexer")
//! i makechange(current, "ansf", "Unit Indexer")
//! i updateobjects()
//! i end
//! endexternalblock
/*
* This is for a .lua file
*
* Can run this through command line using grimex exe
*
dofile("GetVarObject")
local id = getvarobject("Adef", "abilities", "ABILITIES_UNIT_INDEXER", true)
createobject("Adef", id)
makechange(current, "aart", "")
makechange(current, "arac", "0")
makechange(current, "anam", "Unit Indexer")
makechange(current, "ansf", "Unit Indexer")
updateobjects()
*/
/*
* You must have a valid installation of warcraft 3 in order to run these scripts
*
* These scripts depend on the warcraft 3 registry. Without it, they can't run. If you are running off of a USB, you won't
* be able to use these.
*/
/*
* Writes map header to map (run once, but multiple times won't hurt)
*
******************************************************************************/
/*
* comment after initialization
*/
///*
//! externalblock extension=lua FileExporter $FILENAME$
//! runtextmacro LUA_FILE_HEADER()
//! i initmap()
//! endexternalblock
//*/
/*
* replace FILE_NAME with the name of your map
*
* uncomment after initialization
*/
///! import "luajass.FILE_NAME.j"
/*
* for initialization, you will also have to do the following
*
* CTRL + F
* //! i local FILENAME
*/
/******************************************************************************
*
* API
*
* import and run lua script to current script (see Lua reference manual)
*
* lua scripts are shared across all maps
* jass scripts are local to a map
*
* - function dofile(name)
* - function require(name)
* - function loadfile(name)
*
* returns code inside of file
*
* - function readlua(name)
* - function readjass(name)
*
* writes code to file
*
* - function writelua(name, code)
* - function writejass(name, code)
*
* deletes file
*
* - function deletelua(name)
* - function deletejass(name)
*
* output directories containing map files
* this is used to zip the files up and share them with other people
* working on the same map
*
* - function outputdirectories()
*
* output logs is used to display logs so that you don't have
* to go to grimex.txt and reload it
*
* - function outputlogs()
*/
//! textmacro LUA_FILE_HEADER
//! i do
/*
* replace "FILE_NAME" with the name of the map
*
* must be valid directory name
*/
//! i local FILENAME = "FILE_NAME"
/*
* War3 Path Initialization
*/
//! i local PATH_WAR3 = string.sub(package.path, string.find(package.path, ".:.-Warcraft III")) .. "\\"
/*
* jassnewgenpack Initialization
*/
//! i local PATH_JASSNEWGENPACK = PATH_WAR3
//! i local function scandir(directory)
//! i local t = {}
//! i for filename in io.popen('dir "' .. directory .. '" /b'):lines() do
//! i t[#t + 1] = filename
//! i end
//! i log("")
//! i return t
//! i end
//! i war3files = scandir(PATH_WAR3)
//! i for i, name in ipairs(war3files) do
//! i if (string.find(name, "jassnewgenpack") ~= nil) then
//! i PATH_JASSNEWGENPACK = PATH_JASSNEWGENPACK .. name .. "\\"
//! i break
//! i end
//! i end
/*
* grimext initialization
*/
//! i local PATH_GRIMEXT = PATH_JASSNEWGENPACK .. "grimext" .. "\\"
//! i local PATH_LUA = PATH_GRIMEXT .. "luadir" .. "\\"
//! i local PATH_LUA_JASS = PATH_LUA .. FILENAME .. "_dir" .. "\\"
/*
* jass initialization
*/
//! i local PATH_JASS = PATH_JASSNEWGENPACK .. "jass\\luajass." .. FILENAME .. ".j"
/*
* system and map initialization
*/
//! i function initmap()
/*
* initialize system directories
*/
//! i os.execute("if not exist \"" .. PATH_LUA .. "\" mkdir \"" .. PATH_LUA .. "\"")
/*
* initialize map JASS file
*/
//! i local file = io.open(PATH_JASS, "r")
//! i if (file == nil) then
//! i io.open(PATH_JASS, "w"):close()
//! i else
//! i file:close()
//! i end
/*
* initialize map directory
*/
//! i os.execute("if not exist \"" .. PATH_LUA_JASS .. "\" mkdir \"" .. PATH_LUA_JASS .. "\"")
//! i end
/*
* dofile
*/
//! i local olddofile = dofile
//! i local oldrequire = require
//! i local oldloadfile = loadfile
//! i function dofile(name)
//! i olddofile(PATH_LUA .. name .. ".lua")
//! i end
//! i function require(name)
//! i oldrequire(PATH_LUA .. name .. ".lua")
//! i end
//! i function loadfile(name)
//! i oldloadfile(PATH_LUA .. name .. ".lua")
//! i end
/*
* path formatting
*/
//! i local function getluapath(name)
//! i return ("grimext\\luadir\\" .. name .. ".lua")
//! i end
//! i local function getjasspath(name)
//! i return ("grimext\\luadir\\" .. FILENAME .. "_dir" .. "\\" .. name .. ".luajass.j")
//! i end
//! i local function getjassimport(name)
//! i return ("\/\/! import \"..\\" .. getjasspath(name) .. "\"")
//! i end
/*
* file handling
*/
//! i local function del(name)
//! i os.remove(name)
//! i end
//! i local function read(path)
//! i local file = io.open(path, "r")
//! i code = nil
//! i if (file ~= nil) then
//! i code = file:read("*all")
//! i file:close()
//! i end
//! i return code
//! i end
//! i local function write(path, code)
//! i file = io.open(path, "w")
//! i file:write(code)
//! i file:close()
//! i end
//! i local function import(name)
//! i local code = read(PATH_JASS)
//! i local line = getjassimport(name) .. "\n"
//! i if (code:find("\n" .. line) == nil and code:sub(1, line:len()) ~= line) then
//! i write(PATH_JASS, code .. line)
//! i end
//! i end
/*
* script handling
*/
//! i function readlua(name)
//! i return read(getluapath(name))
//! i end
//! i function writelua(name, code)
//! i write(getluapath(name), code)
//! i end
//! i function readjass(name)
//! i return read(getjasspath(name))
//! i end
//! i function writejass(name, code)
//! i write(getjasspath(name), code)
//! i import(name)
//! i end
//! i function deletelua(name)
//! i del(getluapath(name))
//! i end
//! i function deletejass(name)
//! i del(getjasspath(name))
//! i local line = getjassimport(name) .. "\n"
//! i local code = read(PATH_JASS)
//! i local s, k = code:find("\n" .. line)
//! i if (s ~= nil) then
//! i write(PATH_JASS, code:sub(1, s) .. code:sub(k + 1))
//! i else
//! i s, k = 1, line:len()
//! i if (code:sub(1, line:len()) == line) then
//! i write(PATH_JASS, code:sub(1, s - 1) .. code:sub(k + 1))
//! i end
//! i end
//! i end
/*
* output
*/
//! i local function print(...)
/*
* cmd output
*/
/*
//! i local print = ""
//! i for i,v in ipairs(arg) do
//! i if (print ~= "") then
//! i print = print .. " & "
//! i end
//! i print = print .. " echo " .. tostring(v)
//! i end
//! i os.execute("start cmd @cmd /k \"" .. print .. "\"")
*/
/*
* notepad output
*/
//! i local print = ""
//! i for i,v in ipairs(arg) do
//! i if (print ~= "") then
//! i print = print .. "\n"
//! i end
//! i print = print .. tostring(v)
//! i end
//! i local file = io.open(PATH_JASSNEWGENPACK .. "logs\\" .. "luaprint.out", "w")
//! i file:write(print)
//! i file:close()
//! i os.execute("start notepad.exe " .. PATH_JASSNEWGENPACK .. "logs\\" .. "luaprint.out")
//! i end
//! i function outputdirectories()
//! i print(PATH_LUA_JASS, PATH_JASS)
//! i end
//! i function outputlogs()
//! i os.execute("start notepad.exe " .. PATH_JASSNEWGENPACK .. "logs\\" .. "grimex.txt")
//! i end
/*
* clean
*/
//! i do
//! i local temp = string.sub(debug.getinfo(1).short_src, string.find(debug.getinfo(1).short_src, ".*Temp\\"))
//! i tempfiles = scandir(temp)
//! i for i, name in ipairs(tempfiles) do
//! i if (string.find(name, "^(V)") ~= nil and (string.find(name, "(\.tmp)$") ~= nil or string.find(name, "(\.tmp\.lua)$") ~= nil)) then
//! i os.remove(temp .. name)
//! i end
//! i end
//! i end
//! i end
//! endtextmacro
/*
* function getobjectid(objectbase, objecttype)
*
* generates a unique object id
*
* objectbase
*
* - refers to the base of the object
*
* Examples: "hpea" "Amoy" "Bphx"
*
* objecttype
*
* - refers to the type of object to create
*
* Examples: "units", "abilities", "items"
*
*/
//! externalblock extension=lua FileExporter $FILENAME$
//! runtextmacro LUA_FILE_HEADER()
//! i writelua("GetObjectId", [[
//////////////////////////////////////////////////////////////////
//code
//! i function getobjectid(objectbase, objecttype)
/*
* set object type
*/
//! i if (currentobjecttype() ~= objecttype) then
//! i setobjecttype(objecttype)
//! i end
/*
* the object id
*/
//! i local objectid
/*
* find a unique object id that does not contain
*
* ' \ , /
*/
//! i repeat
//! i objectid = generateid(objectbase)
//! i until
//! i (
//! i objectexists(objectid) or
//! i string.find(objectid, "'", 1, true) ~= nil or
//! i string.find(objectid, '\\', 1, true) ~= nil or
//! i string.find(objectid, ',', 1, true) ~= nil or
//! i string.find(objectid, '/', 1, true) ~= nil
//! i )
//! i return objectid
//! i end
//end code
//////////////////////////////////////////////////////////////////
//! i ]])
//! endexternalblock
/*
* function getvarobject(base, objtype, varname, import)
*
* creates a new object and puts it into the map
* it also creates a new JASS variable and binds it to that
* object
*
* base (string)
*
* - refers to the base id of the object
*
* Examples: "hpea" "Amoy" "Bphx"
*
* objtype (string)
*
* - refers to the type of object
*
* Examples: "units" "abilities" "items"
*
* varname (string)
*
* - name assigned to the variable
*
* Convention: OBJTYPE_NAME
*
* Examples: "UNITS_MY_UNIT" "ABILITIES_RAIN_OF_CHAOS"
*
* import (boolean)
*
* - if true, imports the variable into the map as a global
*
* function getvarobjectname(value)
*
* given a value, retrieves the name of an object
*
* Examples: getvarobjectname("hpea") -> "UNITS_PEASANT"?
* getvarobjectname("Hpal") -> "UNITS_PALADIN"?
*
* function getvarobjectvalue(objectname)
*
* given a name, retrieves the value of an object
*
* Examples: getvarobjectvalue("UNITS_MY_UNIT") -> "hpea"?
* getvarobjectvalue("UNITS_MY_ABIL") -> "abil"?
*
* function updateobjects()
*
* updates the object table
*
* this should always be called at the end of any script
*
* Example
*
* getvarobject("hpea", "units", "UNITS_NEW_PEASANT", true)
* updateobjects()
*/
//! externalblock extension=lua FileExporter $FILENAME$
//! runtextmacro LUA_FILE_HEADER()
//! i writelua("GetVarObject", [[
//////////////////////////////////////////////////////////////////
//code
//! i local filename = "JassGlobals"
//! i local filename_lua = getfilename() .. "_VAR_OBJECT_JassGlobals1"
//! i dofile("GetObjectId")
//! i local vars = readlua(filename_lua)
//! i local vars2 = readjass(filename)
//! i local varsdata
//! i local newvars = ""
//! i if (vars == nil) then
//! i vars = {}
//! i vars2 = ""
//! i varsdata = ""
//! i else
//! i if (vars ~= "return {}") then
//! i varsdata = vars:sub(9,vars:len()-1)
//! i vars = loadstring(vars)()
//! i else
//! i varsdata = ""
//! i vars = {}
//! i end
//! i if (vars2 == nil) then
//! i vars2 = ""
//! i else
//! i vars2 = vars2:sub(string.len("globals")+1, vars2:len()-string.len("\nendglobals"))
//! i end
//! i end
//! i local imports = {}
//! i do
//! i local s,k = vars2:find("constant integer ")
//! i local s2,k2
//! i while (s ~= nil) do
//! i s2,k2 = vars2:find("=", k)
//! i imports[vars2:sub(k+1, s2-1)] = true
//! i s,k = vars2:find("constant integer ", k2)
//! i end
//! i end
//! i function getvarobject(base, objtype, varname, import)
//! i local value = vars[varname]
//! i local imported
//! i if (import == nil) then
//! i import = false
//! i end
//! i if (value == nil) then
//! i imported = false
//! i value = getobjectid(base, objtype)
//! i while (vars["1" .. value] ~= nil) do
//! i value = getobjectid(base, objtype)
//! i end
//! i vars[varname] = value
//! i vars["1" .. value] = varname
//! i if (newvars == "") then
//! i newvars = "['" .. varname .. "']='" .. vars[varname] .. "',['1" .. value .. "']='" .. varname .. "'"
//! i else
//! i newvars = newvars .. ",['" .. varname .. "']='" .. vars[varname] .. "',['1" .. value .. "']='" .. varname .. "'"
//! i end
//! i else
//! i imported = imports[varname] or false
//! i if (currentobjecttype() ~= objtype) then
//! i setobjecttype(objtype)
//! i end
//! i end
//! i if (import ~= imported) then
//! i if (not imported) then
//! i vars2 = vars2 .. "\nconstant integer " .. varname .. "='" .. value .. "'"
//! i elseif (imported) then
//! i local s,k = string.find(vars2, "\nconstant integer " .. varname .. "='" .. value .. "'")
//! i vars2 = vars2:sub(1,s-1) .. vars2:sub(k+1, vars2:len())
//! i end
//! i imports[varname] = import
//! i end
//! i return value
//! i end
//! i function getvarobjectname(value)
//! i return vars["1" .. value]
//! i end
//! i function getvarobjectvalue(objectname)
//! i return vars[objectname]
//! i end
//! i function updateobjects()
//! i writejass(filename, "globals" .. vars2 .. "\nendglobals")
//! i if (varsdata == "") then
//! i varsdata = newvars
//! i elseif (newvars ~= "") then
//! i varsdata = varsdata .. "," .. newvars
//! i end
//! i newvars = ""
//! i writelua(filename_lua, "return {" .. varsdata .. "}")
//! i end
//end code
//////////////////////////////////////////////////////////////////
//! i ]])
//! endexternalblock
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitIndexer uses WorldBounds, Event, UnitIndexerSettings
globals
private trigger q=CreateTrigger()
private trigger l=CreateTrigger()
private unit array e
private integer r=0
private integer y=0
private integer o=0
private boolean a=false
private integer array n
private integer array p
private integer array lc
endglobals
function GetIndexedUnitId takes nothing returns integer
return o
endfunction
function GetIndexedUnit takes nothing returns unit
return e[o]
endfunction
//! runtextmacro optional UNIT_LIST_LIB()
private struct PreLoader extends array
public static method run takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
set a=true
endmethod
public static method eval takes trigger t returns nothing
local integer f=n[0]
local integer d=o
loop
exitwhen 0==f
if (IsTriggerEnabled(t)) then
set o=f
if (TriggerEvaluate(t)) then
call TriggerExecute(t)
endif
else
exitwhen true
endif
set f=n[f]
endloop
set o=d
endmethod
public static method evalb takes boolexpr c returns nothing
local trigger t=CreateTrigger()
local thistype f=n[0]
local integer d=o
call TriggerAddCondition(t,c)
loop
exitwhen 0==f
set o=f
call TriggerEvaluate(t)
set f=n[f]
endloop
call DestroyTrigger(t)
set t=null
set o=d
endmethod
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO()
private module UnitIndexerInit
private static method onInit takes nothing returns nothing
local integer i=15
local boolexpr bc=Condition(function thistype.onLeave)
local boolexpr bc2=Condition(function thistype.onEnter)
local group g=CreateGroup()
local player p
set INDEX=CreateEvent()
set DEINDEX=CreateEvent()
call TriggerRegisterEnterRegion(q,WorldBounds.worldRegion,bc2)
loop
set p=Player(i)
call TriggerRegisterPlayerUnitEvent(l,p,EVENT_PLAYER_UNIT_ISSUED_ORDER,bc)
call SetPlayerAbilityAvailable(p,ABILITIES_UNIT_INDEXER,false)
call GroupEnumUnitsOfPlayer(g,p,bc2)
exitwhen 0==i
set i=i-1
endloop
call DestroyGroup(g)
set bc=null
set g=null
set bc2=null
set p=null
call TimerStart(CreateTimer(),0,false,function PreLoader.run)
endmethod
endmodule
struct UnitIndex extends array
method operator locks takes nothing returns integer
return lc[this]
endmethod
method operator locks= takes integer v returns nothing
set lc[this] = v
endmethod
method lock takes nothing returns nothing
debug if (null!=e[this]) then
set lc[this]=lc[this]+1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO LOCK NULL INDEX")
debug endif
endmethod
method unlock takes nothing returns nothing
debug if (0<lc[this]) then
set lc[this]=lc[this]-1
if (0==lc[this] and null==e[this]) then
set n[this]=y
set y=this
endif
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO UNLOCK UNLOCKED INDEX")
debug endif
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
static method operator [] takes unit whichUnit returns thistype
return GetUnitUserData(whichUnit)
endmethod
endstruct
struct UnitIndexer extends array
readonly static Event INDEX
readonly static Event DEINDEX
static boolean enabled = true
private static method onEnter takes nothing returns boolean
local unit Q=GetFilterUnit()
local integer i
local integer d=o
if (enabled and Q!=e[GetUnitUserData(Q)] and 0==GetUnitUserData(Q)) then
if (0==y) then
set r=r+1
set i=r
else
set i=y
set y=n[y]
endif
call UnitAddAbility(Q,ABILITIES_UNIT_INDEXER)
call UnitMakeAbilityPermanent(Q,true,ABILITIES_UNIT_INDEXER)
call SetUnitUserData(Q,i)
set e[i]=Q
static if not LIBRARY_UnitList then
if (not a)then
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
endif
else
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
call GroupAddUnit(g,e[i])
endif
set o=i
call FireEvent(INDEX)
set o=d
endif
set Q=null
return false
endmethod
private static method onLeave takes nothing returns boolean
static if LIBRARY_UnitEvent then
implement optional UnitEventModule
else
local unit u=GetFilterUnit()
local integer i=GetUnitUserData(u)
local integer d=o
if (0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER) and u==e[i]) then
static if not LIBRARY_UnitList then
if (not a)then
set n[p[i]]=n[i]
set p[n[i]]=p[i]
endif
else
set n[p[i]]=n[i]
set p[n[i]]=p[i]
call GroupRemoveUnit(g,e[i])
endif
set o=i
call FireEvent(DEINDEX)
set o=d
if (0==lc[i]) then
set n[i]=y
set y=i
endif
set e[i]=null
endif
set u=null
endif
return false
endmethod
implement UnitIndexerInit
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO_2()
function RegisterUnitIndexEvent takes boolexpr c,integer ev returns nothing
call RegisterEvent(c, ev)
if (not a and ev==UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.evalb(c)
endif
endfunction
function TriggerRegisterUnitIndexEvent takes trigger t,integer ev returns nothing
call TriggerRegisterEvent(t,ev)
if (not a and ev == UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.eval(t)
endif
endfunction
function GetUnitById takes integer W returns unit
return e[W]
endfunction
function GetUnitId takes unit u returns integer
return GetUnitUserData(u)
endfunction
function IsUnitIndexed takes unit u returns boolean
return u==e[GetUnitUserData(u)]
endfunction
function IsUnitDeindexing takes unit u returns boolean
return IsUnitIndexed(u) and 0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER)
endfunction
module UnitIndexStructMethods
static method operator [] takes unit u returns thistype
return GetUnitUserData(u)
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
endmodule
module UnitIndexStruct
implement UnitIndexStructMethods
static if thistype.filter.exists then
static if thistype.index.exists then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
elseif (thistype.index.exists) then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
static if thistype.index.exists then
private static method onIndexEvent takes nothing returns boolean
static if thistype.filter.exists then
if (filter(e[o])) then
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
else
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
return false
endmethod
endif
static if thistype.deindex.exists then
private static method onDeindexEvent takes nothing returns boolean
static if thistype.filter.exists then
static if thistype.index.exists then
if (thistype(o).allocated) then
set thistype(o).allocated=false
call thistype(o).deindex()
endif
else
if (filter(e[o])) then
call thistype(o).deindex()
endif
endif
else
static if thistype.index.exists then
set thistype(o).allocated=false
endif
call thistype(o).deindex()
endif
return false
endmethod
endif
static if thistype.index.exists then
static if thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
else
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
endmethod
endif
elseif thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
endif
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitIndexer /* v5.3.0.1
************************************************************************************
*
* */ uses /*
*
* */ WorldBounds /*
* */ Init /*
* */ AllocQ /*
* */ ErrorMessage /*
* */ StaticUniqueList /*
* */ UnitIndexerSettings /*
* */ Trigger /*
*
********************************************************************************
*
* struct UnitIndexer extends array
*
* Fields
* -------------------------
*
* static boolean enabled
* - is UnitIndexer onUnitIndex enabled?
*
* readonly static Trigger GlobalEvent.ON_INDEX
* - this is a global event that runs whenever any unit is indexed
*
* Examples: UnitIndexer.GlobalEvent.ON_INDEX.reference(yourTrigger)
* UnitIndexer.GlobalEvent.ON_INDEX.register(yourCode)
*
* Examples: unitIndex.indexer.Event.ON_DEINDEX.reference(yourTrigger)
* unitIndex.indexer.Event.ON_DEINDEX.register(yourCode)
*
* readonly Trigger Event.ON_DEINDEX
* - this is a local event that runs whenever a specific unit is deindexed
*
* Examples: unitIndex.indexer.Event.ON_DEINDEX.reference(yourTrigger)
* unitIndex.indexer.Event.ON_DEINDEX.register(yourCode)
*
* readonly static Trigger GlobalEvent.ON_DEINDEX
* - this is ON_DEINDEX, but global
*
* Examples: UnitIndexer.GlobalEvent.ON_DEINDEX.reference(yourTrigger)
* UnitIndexer.GlobalEvent.ON_DEINDEX.register(yourCode)
*
* readonly static UnitIndex eventIndex
* - when a unit is indexed or deindexed, this value stores
* the index of that unit
*
* readonly static unit eventUnit
* - when a unit is indexed or deindexed, this value stores
* the unit
*
************************************************************************************
*
* struct UnitIndex extends array
*
* Fields
* -------------------------
*
* readonly unit unit
* - converts a unit index into a unit
*
* readonly UnitIndexer indexer
* - the indexer in charge of handling the unit
* useful for deindex event, which is unit specific
*
* Operators
* -------------------------
*
* static method operator [] takes unit whichUnit returns UnitIndex
* - converts a unit into a UnitIndex
*
* Methods
* -------------------------
*
* static method exists takes unit whichUnit returns boolean
* - determines whether the unit is indexed or not
*
* static method isDeindexing takes unit whichUnit returns boolean
* - determines whether the unit is in the process of being deindexed or not
*
************************************************************************************
*
* module GlobalUnitIndex
*
* This has absolutely no module support
*
* Fields
* -------------------------
*
* static constant boolean GLOBAL_UNIT_INDEX = true
* - this is used to ensure that only one unit index module is implemented.
*
* readonly unit unit
* - converts a unit index into a unit
*
* readonly boolean isUnitIndexed
* - is the unit index indexed
*
* readonly UnitIndexer unitIndexer
* - the indexer in charge of handling the unit
* useful for deindex event, which is unit specific
*
* Methods
* -------------------------
*
* static method exists takes unit whichUnit returns boolean
* - determines whether the unit is indexed
*
* static method isDeindexing takes unit whichUnit returns boolean
* - determines whether the unit is in the process of being deindexed or not
*
* Interface
* -------------------------
*
* interface private method onUnitIndex takes nothing returns nothing
* interface private method onUnitDeindex takes nothing returns nothing
*
* Operators
* -------------------------
*
* static method operator [] takes unit whichUnit returns thistype
* - converts a unit into thistype
*
************************************************************************************
*
* module UnitIndex
*
* If you would like to create modules that work off of the UnitIndex module, implement
* UnitIndex at the top of your module
*
* Fields
* -------------------------
*
* static constant boolean UNIT_INDEX = true
* - this is used to ensure that only one unit index module is implemented.
*
* static boolean enabled
* - is this UnitIndex struct enabled?
* - this can only be disabed if onUnitIndex exists
*
* readonly unit unit
* - converts a unit index into a unit
*
* readonly boolean isUnitIndexed
* - is the unit index indexed for the struct?
*
* readonly UnitIndexer unitIndexer
* - the indexer in charge of handling the unit
* useful for deindex event, which is unit specific
*
* Operators
* -------------------------
*
* static method operator [] takes unit whichUnit returns thistype
* - converts a unit into thistype
*
* Methods
* -------------------------
*
* static method exists takes unit whichUnit returns boolean
* - determines whether the unit is indexed or not for the struct
*
* static method isDeindexing takes unit whichUnit returns boolean
* - determines whether the unit is in the process of being deindexed or not
*
* Interface
* -------------------------
*
* interface private method onUnitIndex takes nothing returns boolean
* - if return true, index the unit for this struct
*
* interface private method onUnitDeindex takes nothing returns nothing
* - only runs for units indexed for this struct
* - if not onUnitIndex method is declared, it will run for all units
*
************************************************************************************
*
* module UnitIndexEx
*
* If you would like to create modules that work off of the UnitIndexEx module, implement
* UnitIndexEx at the top of your module
*
* Fields
* -------------------------
*
* static constant boolean UNIT_INDEX_EX = true
* - this is used for modules that rely on local events
* it allows these modules to differentiate between UnitIndex
* and UnitIndexEx
*
* static boolean enabled
* - is this UnitIndex struct enabled?
* - this can only be disabed if onUnitIndex exists
*
* readonly unit unit
* - converts a unit index into a unit
*
* readonly boolean isUnitIndexed
* - is the unit index indexed for the struct?
*
* readonly UnitIndexer unitIndexer
* - the indexer in charge of handling the unit
* useful for deindex event, which is unit specific
*
* readonly static Trigger ON_INDEX
* - this is a local event that runs whenever any unit is indexed for the struct
* - this is primarily used for other resources that work off of your struct
*
* Examples: Struct.ON_INDEX.reference(yourTrigger)
* Struct.ON_INDEX.register(yourCode)
*
* readonly Trigger Event.ON_DEINDEX
* readonly static Trigger Event.ON_DEINDEX
* - this is a unit specific event that runs when your local unit is deindexed
* - this is static if onUnitIndex does not exist
*
* Examples: struct.ON_DEINDEX.reference(yourTrigger)
* struct.ON_DEINDEX.register(yourCode)
*
* Operators
* -------------------------
*
* static method operator [] takes unit whichUnit returns thistype
* - converts a unit into thistype
*
* Methods
* -------------------------
*
* static method exists takes unit whichUnit returns boolean
* - determines whether the unit is indexed or not for the struct
*
* static method isDeindexing takes unit whichUnit returns boolean
* - determines whether the unit is in the process of being deindexed or not
*
* Interface
* -------------------------
*
* interface private method onUnitIndex takes nothing returns boolean
* - if return true, index the unit for this struct
*
* interface private method onUnitDeindex takes nothing returns nothing
* - only runs for units indexed for this struct
* - if not onUnitIndex method is declared, it will run for all units
*
************************************************************************************
*
* //! textmacro CREATE_LOCAL_UNIT_INDEX
*
* A macro was chosen because multiple modules utilizing this code may be
* implemented into one struct. If this was a module, then all but one
* of those modules would break.
*
* Interface
* -------------------------
*
* interface private method onLocalUnitIndex takes nothing returns nothing
* - runs whenever a unit is indexed for this struct
*
* interface private method onLocalUnitDeindex takes nothing returns nothing
* - runs whenever a unit is deindexed for this struct
*
* interface private static method localInit takes nothing returns nothing
* - the macro requires the usage of onInit. Declare this method if you
* would like onInit.
*
************************************************************************************/
globals
private UnitIndex p_eventIndex = 0
endglobals
//! runtextmacro UNIT_INDEXER_UNIT_INDEX()
//! runtextmacro UNIT_INDEXER_PREGAME_EVENT()
//! runtextmacro UNIT_INDEXER_UNIT_INDEXER()
module GlobalUnitIndex
static if thistype.UNIT_INDEX then
elseif thistype.UNIT_INDEX_EX then
else
static constant boolean GLOBAL_UNIT_INDEX = true
static method operator [] takes unit whichUnit returns thistype
return p_UnitIndex[whichUnit]
endmethod
method operator unit takes nothing returns unit
return p_UnitIndex(this).unit
endmethod
method operator unitIndexer takes nothing returns UnitIndexer
return p_UnitIndex(this).indexer
endmethod
method operator isUnitIndexed takes nothing returns boolean
return p_UnitIndex(this).isAllocated
endmethod
static method exists takes unit whichUnit returns boolean
return p_UnitIndex.exists(whichUnit)
endmethod
static method isDeindexing takes unit whichUnit returns boolean
return p_UnitIndex.isDeindexing(whichUnit)
endmethod
static if thistype.GLOBAL_UNIT_INDEX then
static if thistype.onUnitIndex.exists then
private static method onIndexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onUnitIndex()
return false
endmethod
endif
static if thistype.onUnitDeindex.exists then
private static method onDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onUnitDeindex()
return false
endmethod
endif
static if thistype.onUnitIndex.exists then
private static method onInit takes nothing returns nothing
elseif thistype.onUnitDeindex.exists then
private static method onInit takes nothing returns nothing
endif
static if thistype.onUnitIndex.exists then
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
endif
static if thistype.onUnitDeindex.exists then
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
endif
static if thistype.onUnitIndex.exists then
endmethod
elseif thistype.onUnitDeindex.exists then
endmethod
endif
endif
endif
endmodule
module UnitIndex
static if thistype.GLOBAL_UNIT_INDEX then
private static method error takes nothing returns nothing
A module requires UnitIndex to operate correctly.
This struct is currently implementing GlobalUnitIndex.
endmethod
elseif thistype.UNIT_INDEX_EX then
else
static constant boolean UNIT_INDEX = true
/*
* [] is included because the struct automatically overrides it
*
* eventIndex is included to return thistype instead of UnitIndex
*/
static method operator [] takes unit whichUnit returns thistype
return UnitIndex[whichUnit]
endmethod
method operator unitIndexer takes nothing returns UnitIndexer
return this
endmethod
method operator unit takes nothing returns unit
return UnitIndex(this).unit
endmethod
static method isDeindexing takes unit whichUnit returns boolean
return UnitIndex.isDeindexing(whichUnit)
endmethod
/*
* the method is done in the second case because when there is no
* onUnitIndex method, indexed depends on whether the actual
* instance is allocated or not
*/
static if thistype.onUnitIndex.exists then
readonly boolean isUnitIndexed
else
method operator isUnitIndexed takes nothing returns boolean
return p_UnitIndex(this).isAllocated
endmethod
endif
static if thistype.onUnitIndex.exists then
static method exists takes unit whichUnit returns boolean
return UnitIndex.exists(whichUnit) and thistype(GetUnitUserData(whichUnit)).isUnitIndexed
endmethod
else
static method exists takes unit whichUnit returns boolean
return UnitIndex.exists(whichUnit)
endmethod
endif
/*
* this is used to run local events
*/
static if thistype.onUnitIndex.exists then
/*
* this is where UnitIndex is located
*/
private static TriggerCondition entryPoint
/*
* this stores private onUnitIndex method
*/
private static boolexpr onIndexExpression
/*
* enable works with code inside of entryPoint here
*/
private static boolean p_enabled = true
static method operator enabled takes nothing returns boolean
return p_enabled
endmethod
static method operator enabled= takes boolean enable returns nothing
set p_enabled = enable
if (enable) then
call entryPoint.replace(onIndexExpression)
else
call entryPoint.replace(null)
endif
endmethod
else
/*
* if onUnitIndex does not exist, the struct can't be disabled
*/
static method operator enabled takes nothing returns boolean
return true
endmethod
static method operator enabled= takes boolean enable returns nothing
set enable = true
endmethod
endif
/*
* onUnitDeindex
*
* This must be implemented if onUnitIndex exists to clear isUnitIndexed
*/
static if thistype.onUnitDeindex.exists then
static if thistype.onUnitIndex.exists then
private static boolexpr onDeindexExpression
endif
private static method onDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onUnitDeindex()
static if thistype.onUnitIndex.exists then
set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
endif
return false
endmethod
elseif thistype.onUnitIndex.exists then
static if thistype.onUnitIndex.exists then
private static boolexpr onDeindexExpression
endif
private static method onDeindexEvent takes nothing returns boolean
set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
return false
endmethod
endif
/*
* onUnitIndex
*/
static if thistype.onUnitIndex.exists then
private static method onIndexEvent takes nothing returns boolean
if (thistype(UnitIndexer.eventIndex).onUnitIndex()) then
set thistype(UnitIndexer.eventIndex).isUnitIndexed = true
/*
* this is always registered to clear isUnitIndexed
*/
call UnitIndexer(UnitIndexer.eventIndex).Event.ON_DEINDEX.register(onDeindexExpression)
endif
return false
endmethod
endif
static if thistype.onUnitIndex.exists then
private static method onInit takes nothing returns nothing
set onIndexExpression = Condition(function thistype.onIndexEvent)
set onDeindexExpression = Condition(function thistype.onDeindexEvent)
set entryPoint = UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
endmethod
elseif thistype.onUnitDeindex.exists then
private static method onInit takes nothing returns nothing
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
endmethod
endif
endif
endmodule
private struct UnitIndexList extends array
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "unitIndex2Node", "thistype")
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "node2UnitIndex", "thistype")
method add takes thistype index returns nothing
local thistype node = enqueue()
set node.node2UnitIndex = index
set index.unitIndex2Node = node
endmethod
method delete takes nothing returns nothing
call unitIndex2Node.remove()
endmethod
private static method init takes nothing returns nothing
//! runtextmacro INITIALIZE_TABLE_FIELD("unitIndex2Node")
//! runtextmacro INITIALIZE_TABLE_FIELD("node2UnitIndex")
endmethod
implement NxListT
implement Init
endstruct
private struct UnitIndexModuleTrigger extends array
method reference takes Trigger whichTrigger returns TriggerReference
local TriggerReference triggerReference = Trigger(this).reference(whichTrigger)
local UnitIndexList node = UnitIndexList(this).first
local integer prevIndexedUnitId = p_eventIndex
loop
exitwhen node == UnitIndexList.sentinel or not whichTrigger.enabled
set p_eventIndex = node.node2UnitIndex
call whichTrigger.fire()
set node = node.next
endloop
set p_eventIndex = prevIndexedUnitId
return triggerReference
endmethod
method register takes boolexpr whichExpression returns TriggerCondition
local TriggerCondition triggerCondition = Trigger(this).register(whichExpression)
local trigger triggerContainer = CreateTrigger()
local UnitIndexList node = UnitIndexList(this).first
local integer prevIndexedUnitId = p_eventIndex
call TriggerAddCondition(triggerContainer, whichExpression)
loop
exitwhen node == UnitIndexList.sentinel
set p_eventIndex = node.node2UnitIndex
call TriggerEvaluate(triggerContainer)
set node = node.next
endloop
call TriggerClearConditions(triggerContainer)
call DestroyTrigger(triggerContainer)
set triggerContainer = null
set p_eventIndex = prevIndexedUnitId
return triggerCondition
endmethod
endstruct
module UnitIndexEx
static if thistype.GLOBAL_UNIT_INDEX then
private static method error takes nothing returns nothing
A module requires UnitIndexEx to operate correctly.
This struct is currently implementing GlobalUnitIndex.
endmethod
elseif thistype.UNIT_INDEX then
private static method error takes nothing returns nothing
A module requires UnitIndexEx to operate correctly.
This struct is currently implementing UnitIndex.
endmethod
else
static constant boolean UNIT_INDEX_EX = true
private static UnitIndex delegate unitIndex = 0
/*
* [] is included because the struct automatically overrides it
*
* eventIndex is included to return thistype instead of UnitIndex
*/
static method operator [] takes unit whichUnit returns thistype
return UnitIndex[whichUnit]
endmethod
method operator unit takes nothing returns unit
return UnitIndex(this).unit
endmethod
method operator unitIndexer takes nothing returns UnitIndexer
return this
endmethod
static method isDeindexing takes unit whichUnit returns boolean
return UnitIndex.isDeindexing(whichUnit)
endmethod
/*
* the method is done in the second case because when there is no
* onUnitIndex method, indexed depends on whether the actual
* instance is allocated or not
*/
static if thistype.onUnitIndex.exists then
readonly boolean isUnitIndexed
else
method operator isUnitIndexed takes nothing returns boolean
return p_UnitIndex(this).isAllocated
endmethod
endif
static if thistype.onUnitIndex.exists then
static method exists takes unit whichUnit returns boolean
return UnitIndex.exists(whichUnit) and thistype(GetUnitUserData(whichUnit)).isUnitIndexed
endmethod
else
static method exists takes unit whichUnit returns boolean
return UnitIndex.exists(whichUnit)
endmethod
endif
/*
* this is used to run local events
*/
static if thistype.onUnitIndex.exists then
readonly static UnitIndexModuleTrigger ON_INDEX
else
readonly static WrappedTrigger ON_INDEX
endif
static if thistype.onUnitIndex.exists then
/*
* this is where UnitIndex is located
*/
private static TriggerCondition entryPoint
/*
* this stores private onUnitIndex method
*/
private static boolexpr onIndexExpression
/*
* enable works with code inside of entryPoint here
*/
private static boolean p_enabled = true
static method operator enabled takes nothing returns boolean
return p_enabled
endmethod
static method operator enabled= takes boolean enable returns nothing
set p_enabled = enable
if (enable) then
call entryPoint.replace(onIndexExpression)
else
call entryPoint.replace(null)
endif
endmethod
else
/*
* if onUnitIndex does not exist, the struct can't be disabled
*/
static method operator enabled takes nothing returns boolean
return true
endmethod
static method operator enabled= takes boolean enable returns nothing
set enable = true
endmethod
endif
/*
* this is here so that the module runs after code that relies on the module
*/
static if thistype.onUnitIndex.exists then
readonly Trigger ON_DEINDEX
else
readonly static Trigger ON_DEINDEX
endif
/*
* onUnitDeindex
*/
static if thistype.onUnitDeindex.exists then
static if thistype.onUnitIndex.exists then
private static boolexpr onDeindexExpression
endif
private static method onDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onUnitDeindex()
static if thistype.onUnitIndex.exists then
set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.destroy()
if (not PreGameEvent.isGameLoaded) then
call UnitIndexList(UnitIndexer.eventIndex).delete()
endif
endif
return false
endmethod
elseif thistype.onUnitIndex.exists then
private static boolexpr onDeindexExpression
private static method onDeindexEvent takes nothing returns boolean
set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.destroy()
if (not PreGameEvent.isGameLoaded) then
call UnitIndexList(UnitIndexer.eventIndex).delete()
endif
return false
endmethod
endif
/*
* onUnitIndex
*/
static if thistype.onUnitIndex.exists then
private static method onIndexEvent takes nothing returns boolean
if (thistype(UnitIndexer.eventIndex).onUnitIndex()) then
set thistype(UnitIndexer.eventIndex).isUnitIndexed = true
set thistype(UnitIndexer.eventIndex).ON_DEINDEX = Trigger.create(true)
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onDeindexExpression)
call UnitIndexer(UnitIndexer.eventIndex).Event.ON_DEINDEX.reference(thistype(UnitIndexer.eventIndex).ON_DEINDEX)
if (not PreGameEvent.isGameLoaded) then
call UnitIndexList(ON_INDEX).add(UnitIndexer.eventIndex)
endif
call Trigger(thistype.ON_INDEX).fire()
endif
return false
endmethod
endif
private static method destroyPregameUnitList takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
call UnitIndexList(ON_INDEX).destroy()
endmethod
private static method onInit takes nothing returns nothing
set ON_INDEX = Trigger.create(false)
static if thistype.onUnitIndex.exists then
set onIndexExpression = Condition(function thistype.onIndexEvent)
set onDeindexExpression = Condition(function thistype.onDeindexEvent)
call UnitIndexList(ON_INDEX).clear()
call TimerStart(CreateTimer(), 0, false, function thistype.destroyPregameUnitList)
set entryPoint = UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
else
set ON_DEINDEX = Trigger.create(true)
static if thistype.onUnitDeindex.exists then
call ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
endif
call UnitIndexer.GlobalEvent.ON_DEINDEX.reference(ON_DEINDEX)
call UnitIndexer.GlobalEvent.ON_INDEX.reference(ON_INDEX)
endif
endmethod
endif
endmodule
//! textmacro CREATE_LOCAL_UNIT_INDEX
/*
* There are three cases
*
* Case 1: UnitIndex is implemented
* Case 2: UnitIndexEx is implemented
* Case 3: Nothing is implemented, go to Case 2
*/
static if thistype.UNIT_INDEX then
/*
* Here, UnitIndex is implemented
*/
/*
* There are two cases
*
* onUnitEvent exists, which means that events are conditionally local
* onUnitEven does not exist, meaning all events are global
*/
static if thistype.onUnitIndex.exists then
/*
* Here, events are conditionally local
*/
static if thistype.onLocalUnitDeindex.exists then
private static boolexpr onLocalUnitDeindexEventExpr
endif
static if thistype.onLocalUnitIndex.exists then
/*
* The user has a local unit index event
*/
private static method onLocalUnitIndexEvent takes nothing returns boolean
/*
* Here, the event is only run if the unit happened to be indexed
*/
if (thistype(UnitIndexer.eventIndex).isUnitIndexed) then
static if thistype.onLocalUnitDeindex.exists then
call UnitIndexer.eventIndex.indexer.Event.ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
endif
call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
endif
return false
endmethod
elseif thistype.onLocalUnitDeindex.exists then
/*
* The user did not declare a local unit index event
*
* onLocalUnitIndexEvent is still required because the deindex events are local
*/
private static method onLocalUnitIndexEvent takes nothing returns boolean
if (thistype(UnitIndexer.eventIndex).isUnitIndexed) then
call UnitIndexer.eventIndex.indexer.Event.ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
endif
return false
endmethod
endif
static if thistype.onLocalUnitDeindex.exists then
private static method onLocalUnitDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
return false
endmethod
endif
/*
* onLocalUnitDeindexEvent is not registered globally here because these are local
* events. It must be created inside of onLocalUnitIndexEvent whether or not
* onLocalUnitIndex exists.
*/
static if thistype.onLocalUnitIndex.exists then
private static method onInit takes nothing returns nothing
static if thistype.onLocalUnitDeindex.exists then
set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
endif
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
static if thistype.localInit.exists then
call localInit()
endif
endmethod
elseif thistype.onLocalUnitDeindex.exists then
private static method onInit takes nothing returns nothing
set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
static if thistype.localInit.exists then
call localInit()
endif
endmethod
endif
else
/*
* Here, all events are global
*/
static if thistype.onLocalUnitIndex.exists then
private static method onLocalUnitIndexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
return false
endmethod
endif
static if thistype.onLocalUnitDeindex.exists then
private static method onLocalUnitDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
return false
endmethod
endif
static if thistype.onLocalUnitIndex.exists then
private static method onInit takes nothing returns nothing
static if thistype.onLocalUnitDeindex.exists then
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
endif
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
static if thistype.localInit.exists then
call localInit()
endif
endmethod
elseif thistype.onLocalUnitDeindex.exists then
private static method onInit takes nothing returns nothing
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
static if thistype.localInit.exists then
call localInit()
endif
endmethod
endif
endif
elseif thistype.GLOBAL_UNIT_INDEX then
private static method error takes nothing returns nothing
A module requires either UnitIndex or UnitIndexEx to operate correctly.
This struct is currently implementing GlobalUnitIndex.
endmethod
else
/*
* Here, UnitIndexEx is either implemented or nothing is implemented
*
* Implement UnitIndexEx and work with its local events
*/
implement UnitIndexEx
static if thistype.onUnitIndex.exists then
/*
* local events
*/
static if thistype.onLocalUnitDeindex.exists then
private static boolexpr onLocalUnitDeindexEventExpr
endif
/*
* if onUnitIndex exists, then onLocalUnitDeindex is local
*
* this means that if onLocalUnitDeindex exists, the onLocalUnitIndexEvent must be
* made so that it can register onLocalUnitDeindex locally
*/
static if thistype.onLocalUnitIndex.exists then
private static method onLocalUnitIndexEvent takes nothing returns boolean
static if thistype.onLocalUnitDeindex.exists then
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
endif
call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
return false
endmethod
elseif thistype.onLocalUnitDeindex.exists then
private static method onLocalUnitIndexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
return false
endmethod
endif
elseif thistype.onLocalUnitIndex.exists then
/*
* global events
*
* onLocalUnitDeindex is run globally, so it doesn't need onLocalUnitIndexEvent
* anymore
*/
private static method onLocalUnitIndexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
return false
endmethod
endif
static if thistype.onLocalUnitDeindex.exists then
private static method onLocalUnitDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
return false
endmethod
endif
/*
* The reason why ON_INDEX is used is so that the module can be enabled/disabled
* correctly
*/
private static method onInit takes nothing returns nothing
static if thistype.onUnitIndex.exists then
/*
* local events
*/
static if thistype.onLocalUnitDeindex.exists then
set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
endif
/*
* onLocalUnitIndexEvent is registered for onLocalUnitdeindex because onLocalUnitDeindex
* must be registered to each unit. This means that it must register as units are indexed.
*/
static if thistype.onLocalUnitIndex.exists then
call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
elseif thistype.onLocalUnitDeindex.exists then
call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
endif
else
/*
* global events
*
* ON_DEINDEX is used here instead of UnitIndexer.GlobalEvent.ON_DEINDEX for proper
* execution order
*/
static if thistype.onLocalUnitDeindex.exists then
call thistype.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
endif
static if thistype.onLocalUnitIndex.exists then
call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
endif
endif
static if thistype.localInit.exists then
call localInit()
endif
endmethod
endif
//! endtextmacro
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
* requires
*
* Alloc
* ErrorMessage
*
* private struct p_UnitIndex extends array
*
* method operator isAllocated takes nothing returns boolean
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
* method operator indexer takes nothing returns UnitIndexer
* method operator unit takes nothing returns unit
* static method operator [] takes unit whichUnit returns thistype
* static method exists takes unit whichUnit returns boolean
*
* struct UnitIndex extends array
*
* readonly unit unit
* readonly UnitIndexer indexer
*
* static method operator [] takes unit whichUnit returns UnitIndex
*
* static method exists takes unit whichUnit returns boolean
* static method isDeindexing takes unit whichUnit returns boolean
*/
//! textmacro UNIT_INDEXER_UNIT_INDEX
private struct p_UnitIndex extends array
implement AllocQ
private unit p_unit
static method create takes unit whichUnit returns thistype
local thistype this = allocate()
set p_unit = whichUnit
call SetUnitUserData(whichUnit, this)
call UnitAddAbility(whichUnit, ABILITIES_UNIT_INDEXER)
call UnitMakeAbilityPermanent(whichUnit, true, ABILITIES_UNIT_INDEXER)
return this
endmethod
method destroy takes nothing returns nothing
set p_unit = null
call deallocate()
endmethod
method operator indexer takes nothing returns UnitIndexer
debug call ThrowWarning(not isAllocated, "UnitIndexer", "indexer", "thistype", this, "Getting indexer from a deallocated unit index.")
return this
endmethod
method operator unit takes nothing returns unit
debug call ThrowWarning(not isAllocated, "UnitIndexer", "unit", "thistype", this, "Getting unit from a deallocated unit index.")
return p_unit
endmethod
static method operator [] takes unit whichUnit returns thistype
debug call ThrowWarning(GetUnitTypeId(whichUnit) == 0, "UnitIndexer", "[]", "thistype", 0, "Getting unit index of a null unit.")
debug call ThrowWarning(thistype(GetUnitUserData(whichUnit)).p_unit != whichUnit, "UnitIndexer", "[]", "thistype", 0, "Getting unit index of a unit that isn't indexed.")
return GetUnitUserData(whichUnit)
endmethod
static method exists takes unit whichUnit returns boolean
debug call ThrowWarning(GetUnitTypeId(whichUnit) == 0, "UnitIndexer", "exists", "thistype", 0, "Checking for the existence of a null unit.")
return thistype(GetUnitUserData(whichUnit)).p_unit == whichUnit
endmethod
static method isDeindexing takes unit whichUnit returns boolean
return GetUnitTypeId(whichUnit) != 0 and GetUnitAbilityLevel(whichUnit, ABILITIES_UNIT_INDEXER) == 0 and thistype(GetUnitUserData(whichUnit)).p_unit == whichUnit
endmethod
endstruct
struct UnitIndex extends array
method operator unit takes nothing returns unit
return p_UnitIndex(this).unit
endmethod
static method operator [] takes unit whichUnit returns thistype
return p_UnitIndex[whichUnit]
endmethod
static method exists takes unit whichUnit returns boolean
return p_UnitIndex.exists(whichUnit)
endmethod
static method isDeindexing takes unit whichUnit returns boolean
return p_UnitIndex.isDeindexing(whichUnit)
endmethod
method operator indexer takes nothing returns UnitIndexer
return p_UnitIndex(this).indexer
endmethod
endstruct
//! endtextmacro
//TESH.scrollpos=126
//TESH.alwaysfold=0
/*
* requires
*
* Event
* WorldBounds
*
* struct UnitIndexer extends array
*
* static boolean enabled = true
*
* readonly static Trigger GlobalEvent.ON_INDEX
* readonly static Trigger GlobalEvent.ON_DEINDEX
* readonly Trigger Event.ON_DEINDEX
*
* readonly UnitIndex eventIndex = 0
* readonly unit eventUnit = null
*
* private struct WrappedTrigger extends array
*
* method reference takes Trigger whichTrigger returns nothing
*
* method register takes boolexpr whichExpression returns nothing
*
*/
//! textmacro UNIT_INDEXER_UNIT_INDEXER
private struct WrappedTrigger extends array
static if DEBUG_MODE then
method reference takes Trigger whichTrigger returns TriggerReference
return reference_p(whichTrigger)
endmethod
method register takes boolexpr whichExpression returns TriggerCondition
return register_p(whichExpression)
endmethod
private method reference_p takes Trigger whichTrigger returns TriggerReference
local TriggerReference triggerReference = Trigger(this).reference(whichTrigger)
call PreGameEvent.fireTrigger(whichTrigger)
return triggerReference
endmethod
private method register_p takes boolexpr whichExpression returns TriggerCondition
local TriggerCondition triggerCondition = Trigger(this).register(whichExpression)
call PreGameEvent.fireExpression(whichExpression)
return triggerCondition
endmethod
else
method reference takes Trigger whichTrigger returns TriggerReference
local TriggerReference triggerReference = Trigger(this).reference(whichTrigger)
call PreGameEvent.fireTrigger(whichTrigger)
return triggerReference
endmethod
method register takes boolexpr whichExpression returns TriggerCondition
local TriggerCondition triggerCondition = Trigger(this).register(whichExpression)
call PreGameEvent.fireExpression(whichExpression)
return triggerCondition
endmethod
endif
endstruct
private struct UnitIndexerTriggerGlobal extends array
readonly static WrappedTrigger ON_INDEX
readonly static Trigger ON_DEINDEX
private static method init takes nothing returns nothing
set ON_INDEX = Trigger.create(false)
set ON_DEINDEX = Trigger.create(true)
endmethod
implement Init
endstruct
private keyword ON_DEINDEX_MAIN
private struct UnitIndexerTrigger extends array
readonly Trigger ON_DEINDEX
method createDeindex takes nothing returns nothing
set ON_DEINDEX = Trigger.create(true)
call ON_DEINDEX.reference(UnitIndexerTriggerGlobal.ON_DEINDEX)
endmethod
method destroyDeindex takes nothing returns nothing
call ON_DEINDEX.destroy()
endmethod
endstruct
struct UnitIndexer extends array
private trigger deindexTrigger
private static boolexpr onDeindexCondition
static method operator eventIndex takes nothing returns UnitIndex
return p_eventIndex
endmethod
static method operator eventUnit takes nothing returns unit
return eventIndex.unit
endmethod
static method operator GlobalEvent takes nothing returns UnitIndexerTriggerGlobal
return 0
endmethod
method operator Event takes nothing returns UnitIndexerTrigger
return this
endmethod
static boolean enabled = true
private static method fire takes Trigger whichTrigger, integer whichIndex returns nothing
local integer prevIndexedUnit = p_eventIndex
set p_eventIndex = whichIndex
call whichTrigger.fire()
set p_eventIndex = prevIndexedUnit
endmethod
private static method onIndex takes nothing returns boolean
local unit indexedUnit = GetFilterUnit()
local p_UnitIndex index
if (enabled and not p_UnitIndex.exists(indexedUnit)) then
set index = p_UnitIndex.create(indexedUnit)
set thistype(index).deindexTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(thistype(index).deindexTrigger, indexedUnit, EVENT_UNIT_ISSUED_ORDER)
call TriggerAddCondition(thistype(index).deindexTrigger, onDeindexCondition)
call PreGameEvent.addUnitIndex(index)
call thistype(index).Event.createDeindex()
call fire(GlobalEvent.ON_INDEX, index)
endif
set indexedUnit = null
return false
endmethod
private static method onDeindex takes nothing returns boolean
local p_UnitIndex index = GetUnitUserData(GetTriggerUnit())
if (GetUnitAbilityLevel(GetTriggerUnit(), ABILITIES_UNIT_INDEXER) == 0) then
call PreGameEvent.removeUnitIndex(index)
call fire(thistype(index).Event.ON_DEINDEX, index)
call thistype(index).Event.destroyDeindex()
call DestroyTrigger(thistype(index).deindexTrigger)
set thistype(index).deindexTrigger = null
call index.destroy()
endif
return false
endmethod
private static method init takes nothing returns nothing
local trigger indexTrigger = CreateTrigger()
local boolexpr onIndexCondition = Condition(function thistype.onIndex)
local group enumGroup = CreateGroup()
local integer currentPlayerId = 15
local player currentPlayer
set onDeindexCondition= Condition(function thistype.onDeindex)
call TriggerRegisterEnterRegion(indexTrigger, WorldBounds.worldRegion, onIndexCondition)
loop
set currentPlayer = Player(currentPlayerId)
call SetPlayerAbilityAvailable(currentPlayer, ABILITIES_UNIT_INDEXER, false)
call GroupEnumUnitsOfPlayer(enumGroup, currentPlayer, onIndexCondition)
exitwhen currentPlayerId == 0
set currentPlayerId = currentPlayerId - 1
endloop
call DestroyGroup(enumGroup)
set onIndexCondition = null
set enumGroup = null
set currentPlayer = null
set indexTrigger = null
endmethod
implement Init
endstruct
//! endtextmacro
/*
* requires
*
* StaticUniqueList
*
* private struct PreGameEvent extends array
*
* Evaluates all triggers and functions registered to
* Unit Indexer before game start for all indexed units.
*
*
* static method fireTrigger takes trigger whichTrigger returns nothing
* static method fireExpression takes boolexpr whichExpression returns nothing
*
* static method addUnitIndex takes integer whichUnitIndex returns nothing
* static method removeUnitIndex takes integer whichUnitIndex returns nothing
*/
//! textmacro UNIT_INDEXER_PREGAME_EVENT
private struct PreGameEvent extends array
readonly static boolean isGameLoaded = false
implement StaticUniqueList
private static method p_fireTrigger takes Trigger whichTrigger returns nothing
local thistype this = first
local integer prevIndexedUnitId = p_eventIndex
loop
exitwhen this == sentinel or not whichTrigger.enabled
set p_eventIndex = this
call whichTrigger.fire()
set this = next
endloop
set p_eventIndex = prevIndexedUnitId
endmethod
static method fireTrigger takes Trigger whichTrigger returns nothing
if (first != 0) then
call p_fireTrigger(whichTrigger)
endif
endmethod
private static method p_fireExpression takes boolexpr whichExpression returns nothing
local trigger triggerContainer = CreateTrigger()
local thistype this = first
local integer prevIndexedUnitId = p_eventIndex
call TriggerAddCondition(triggerContainer, whichExpression)
loop
exitwhen this == sentinel
set p_eventIndex = this
call TriggerEvaluate(triggerContainer)
set this = next
endloop
call TriggerClearConditions(triggerContainer)
call DestroyTrigger(triggerContainer)
set triggerContainer = null
set p_eventIndex = prevIndexedUnitId
endmethod
static method fireExpression takes boolexpr whichExpression returns nothing
if (first != 0) then
call p_fireExpression(whichExpression)
endif
endmethod
static method addUnitIndex takes integer whichUnitIndex returns nothing
if (isGameLoaded) then
return
endif
call enqueue(whichUnitIndex)
endmethod
static method removeUnitIndex takes integer whichUnitIndex returns nothing
if (isGameLoaded) then
return
endif
call thistype(whichUnitIndex).remove()
endmethod
private static method run takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
set isGameLoaded = true
call clear()
endmethod
private static method init takes nothing returns nothing
call TimerStart(CreateTimer(), 0, false, function thistype.run)
endmethod
implement Init
endstruct
//! endtextmacro
struct test extends array
private static method tester takes integer unitTypeId returns nothing
local unit u = CreateUnit(Player(0), unitTypeId, 0, 0, 270)
if (thistype[u].isIndexed) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(u) + " is indexed")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(u) + " is not indexed")
endif
call RemoveUnit(u)
set u = null
endmethod
private static method onInit takes nothing returns nothing
call tester('hkni')
call tester('hfoo')
endmethod
private method onUnitIndex takes nothing returns boolean
if (GetUnitTypeId(unit) == 'hkni') then
return false
endif
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Indexed Unit " + GetUnitName(unit) + " to " + I2S(this))
return true
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Deindexed Unit " + GetUnitName(unit) + " from " + I2S(this))
endmethod
implement UnitIndex
endstruct
struct test extends array
private static method tester takes integer unitTypeId returns nothing
local unit u = CreateUnit(Player(0), unitTypeId, 0, 0, 270)
if (thistype[u].isIndexed) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(u) + " is indexed")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(u) + " is not indexed")
endif
call RemoveUnit(u)
set u = null
endmethod
private static method onInit takes nothing returns nothing
call tester('hkni')
call tester('hfoo')
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Deindexed Unit " + GetUnitName(unit) + " from " + I2S(this))
endmethod
implement UnitIndex
endstruct
struct test extends array
private static method tester takes integer unitTypeId returns nothing
local unit u = CreateUnit(Player(0), unitTypeId, 0, 0, 270)
if (thistype[u].isIndexed) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(u) + " is indexed")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(u) + " is not indexed")
endif
call RemoveUnit(u)
set u = null
endmethod
private static method onInit takes nothing returns nothing
call tester('hkni')
call tester('hfoo')
endmethod
private method onUnitIndex takes nothing returns boolean
if (GetUnitTypeId(unit) == 'hkni') then
return false
endif
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Indexed Unit " + GetUnitName(unit) + " to " + I2S(this))
return true
endmethod
implement UnitIndex
endstruct
struct test extends array
private static method tester takes integer unitTypeId returns nothing
local unit u = CreateUnit(Player(0), unitTypeId, 0, 0, 270)
if (thistype[u].isIndexed) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(u) + " is indexed")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(u) + " is not indexed")
endif
call RemoveUnit(u)
set u = null
endmethod
private static method onInit takes nothing returns nothing
call tester('hkni')
call tester('hfoo')
endmethod
implement UnitIndex
endstruct
struct CreateUnits extends array
private static method init takes nothing returns nothing
local unit u
set u = CreateUnit(Player(0), 'hfoo', -200, 0, 270)
set u = CreateUnit(Player(0), 'hpea', -200, 0, 270)
set u = CreateUnit(Player(0), 'hfoo', -200, 0, 270)
set u = CreateUnit(Player(0), 'hfoo', -200, 0, 270)
call RemoveUnit(u)
set u = null
endmethod
implement Init
endstruct
struct UnitIndex1 extends array
private method onUnitIndex takes nothing returns boolean
if (GetUnitTypeId(unit) != 'hfoo') then
return false
endif
return true
endmethod
implement UnitIndexEx
endstruct
struct UnitIndexExtend extends array
private static boolexpr onUnitDeindexExpr
private static method onUnitIndex takes nothing returns boolean
local thistype this = UnitIndexer.eventIndex
call UnitIndex1(this).ON_DEINDEX.register(onUnitDeindexExpr)
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(UnitIndexer.eventUnit) + " was indexed for thistype")
return false
endmethod
private static method onUnitDeindex takes nothing returns boolean
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(UnitIndexer.eventUnit) + " was deindexed for thistype")
return false
endmethod
private static method onInit takes nothing returns nothing
set onUnitDeindexExpr = Condition(function thistype.onUnitDeindex)
call UnitIndex1.ON_INDEX.register(Condition(function thistype.onUnitIndex))
endmethod
endstruct
struct CreateUnits2 extends array
private static method onInit takes nothing returns nothing
local unit u
set u = CreateUnit(Player(0), 'hfoo', -200, 0, 270)
set u = CreateUnit(Player(0), 'hpea', -200, 0, 270)
set u = CreateUnit(Player(0), 'hfoo', -200, 0, 270)
call RemoveUnit(u)
set u = null
endmethod
endstruct
/*************************************************************************************
*
* These test for proper code execution of local events.
*/
//! runtextmacro AA()
//! runtextmacro START()
// tests
//
// remove x at front to enable
// add x to front to disable
//
// (1 must be enabled) U UX
// (1+ must be enabled) IM DM IS DS
//
// ----------------------------------
//! runtextmacro optional xIM()
//! runtextmacro optional xDM()
//! runtextmacro CREATE_LOCAL_UNIT_INDEX()
//! runtextmacro MID()
//! runtextmacro optional xIS()
//! runtextmacro optional xDS()
//
//! runtextmacro optional xU()
//! runtextmacro optional xUX()
//! runtextmacro END()
/************************************************************************************/
//! textmacro AA
globals
string WHICH_TEST = ""
string output = ""
string expectedOutput = ""
endglobals
function AppendOutput takes string str returns nothing
if (output != "") then
set output = output + "\n"
endif
set output = output + str
endfunction
//! endtextmacro
//! textmacro IM
static constant boolean IM = true
private method onLocalUnitIndex takes nothing returns nothing
call AppendOutput(I2S(GetUnitTypeId(unit)) + " im")
endmethod
//! endtextmacro
//! textmacro DM
static constant boolean DM = true
private method onLocalUnitDeindex takes nothing returns nothing
call AppendOutput(I2S(GetUnitTypeId(unit)) + " dm")
endmethod
//! endtextmacro
//! textmacro IS
static constant boolean IS = true
private method onUnitIndex takes nothing returns boolean
if (GetUnitTypeId(unit) != 'hkni') then
return false
endif
call AppendOutput(I2S(GetUnitTypeId(unit)) + " is")
return true
endmethod
//! endtextmacro
//! textmacro DS
static constant boolean DS = true
private method onUnitDeindex takes nothing returns nothing
call AppendOutput(I2S(GetUnitTypeId(unit)) + " ds")
endmethod
//! endtextmacro
//! textmacro U
static constant boolean U = true
implement UnitIndex
//! endtextmacro
//! textmacro UX
static constant boolean UX = true
implement UnitIndexEx
//! endtextmacro
//! textmacro START
module UnitModule1
//! endtextmacro
//! textmacro MID
endmodule
struct UnitIndex1 extends array
//! endtextmacro
//! textmacro END
implement UnitModule1
endstruct
//! endtextmacro
function Error takes nothing returns nothing
if (output != expectedOutput) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, WHICH_TEST + " failed (output/expectedOutput)")
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, output)
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "--------------------------------------------")
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, expectedOutput)
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, WHICH_TEST + " succeeded")
endif
set output = ""
set expectedOutput = ""
endfunction
struct RunTests extends array
private static method perform takes integer unitTypeId, boolean enable returns nothing
local unit u
local UnitIndex1 unitIndex
if (not enable) then
set UnitIndex1.enabled = false
endif
set u = CreateUnit(Player(0), unitTypeId, 0, 0, 270)
set unitIndex = GetUnitUserData(u)
if (not enable) then
set UnitIndex1.enabled = true
endif
call RemoveUnit(u)
set u = null
endmethod
/*
* u: ds
*/
private static hashtable testTable = InitHashtable()
private static string array testArray
private static integer testCount = 0
private static method createTest takes string test, string output returns nothing
call SaveInteger(testTable, StringHash(test), 0, testCount)
set testArray[testCount] = output
set testCount = testCount + 1
endmethod
private static method omg takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
call Error()
endmethod
private static method test takes nothing returns nothing
set expectedOutput = testArray[LoadInteger(testTable, StringHash(WHICH_TEST), 0)]
call perform('hkni', true)
call perform('hfoo', true)
call perform('hkni', false)
call perform('hfoo', false)
call TimerStart(CreateTimer(), 0, false, function thistype.omg)
endmethod
private static method init takes nothing returns nothing
call createTest("u: ds", /* pass
*/I2S('hkni') + " ds\n" + /* enable
*/I2S('hfoo') + " ds\n" + /* enable
*/I2S('hkni') + " ds\n" + /* disable
*/I2S('hfoo') + " ds" /* disable
*/)
call createTest("u: ds/is", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " ds" /* enable
*/)
call createTest("u: ds/dm", /* pass
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hkni') + " ds\n" + /* enable
*/I2S('hfoo') + " dm\n" + /* enable
*/I2S('hfoo') + " ds\n" + /* enable
*/I2S('hkni') + " dm\n" + /* disable
*/I2S('hkni') + " ds\n" + /* disable
*/I2S('hfoo') + " dm\n" + /* disable
*/I2S('hfoo') + " ds" /* disable
*/)
call createTest("u: ds/im", /* pass
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hfoo') + " im\n" + /* enable
*/I2S('hkni') + " im\n" + /* disable
*/I2S('hfoo') + " im\n" + /* disable
*/I2S('hkni') + " ds\n" + /* enable
*/I2S('hfoo') + " ds\n" + /* enable
*/I2S('hkni') + " ds\n" + /* disable
*/I2S('hfoo') + " ds" /* disable
*/)
call createTest("u: is", /* pass
*/I2S('hkni') + " is" /* enable
*/)
call createTest("u: is/dm", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " dm" /* enable
*/)
call createTest("u: is/im", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " im" /* enable
*/)
call createTest("u: dm", /* pass
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hfoo') + " dm\n" + /* enable
*/I2S('hkni') + " dm\n" + /* disable
*/I2S('hfoo') + " dm" /* disable
*/)
call createTest("u: dm/im", /* pass
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hfoo') + " im\n" + /* enable
*/I2S('hkni') + " im\n" + /* disable
*/I2S('hfoo') + " im\n" + /* disable
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hfoo') + " dm\n" + /* enable
*/I2S('hkni') + " dm\n" + /* disable
*/I2S('hfoo') + " dm" /* disable
*/)
call createTest("u: im", /* pass
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hfoo') + " im\n" + /* enable
*/I2S('hkni') + " im\n" + /* disable
*/I2S('hfoo') + " im" /* disable
*/)
call createTest("u: ds/is/dm", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hkni') + " ds" /* enable
*/)
call createTest("u: ds/is/im", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hkni') + " ds" /* enable
*/)
call createTest("u: ds/dm/im", /* pass
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hfoo') + " im\n" + /* enable
*/I2S('hkni') + " im\n" + /* disable
*/I2S('hfoo') + " im\n" + /* disable
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hkni') + " ds\n" + /* enable
*/I2S('hfoo') + " dm\n" + /* enable
*/I2S('hfoo') + " ds\n" + /* enable
*/I2S('hkni') + " dm\n" + /* disable
*/I2S('hkni') + " ds\n" + /* disable
*/I2S('hfoo') + " dm\n" + /* disable
*/I2S('hfoo') + " ds" /* disable
*/)
call createTest("u: is/dm/im", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hkni') + " dm" /* enable
*/)
call createTest("u: ds/is/dm/im", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hkni') + " ds" /* enable
*/)
call createTest("ux: ds", /* pass
*/I2S('hkni') + " ds\n" + /* enable
*/I2S('hfoo') + " ds\n" + /* enable
*/I2S('hkni') + " ds\n" + /* disable
*/I2S('hfoo') + " ds" /* disable
*/)
call createTest("ux: ds/is", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " ds" /* enable
*/)
call createTest("ux: ds/dm", /* pass
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hkni') + " ds\n" + /* enable
*/I2S('hfoo') + " dm\n" + /* enable
*/I2S('hfoo') + " ds\n" + /* enable
*/I2S('hkni') + " dm\n" + /* disable
*/I2S('hkni') + " ds\n" + /* disable
*/I2S('hfoo') + " dm\n" + /* disable
*/I2S('hfoo') + " ds" /* disable
*/)
call createTest("ux: ds/im", /* pass
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hfoo') + " im\n" + /* enable
*/I2S('hkni') + " im\n" + /* disable
*/I2S('hfoo') + " im\n" + /* disable
*/I2S('hkni') + " ds\n" + /* enable
*/I2S('hfoo') + " ds\n" + /* enable
*/I2S('hkni') + " ds\n" + /* disable
*/I2S('hfoo') + " ds" /* disable
*/)
call createTest("ux: is", /* pass
*/I2S('hkni') + " is" /* enable
*/)
call createTest("ux: is/dm", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " dm" /* enable
*/)
call createTest("ux: is/im", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " im" /* enable
*/)
call createTest("ux: dm", /* pass
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hfoo') + " dm\n" + /* enable
*/I2S('hkni') + " dm\n" + /* disable
*/I2S('hfoo') + " dm" /* disable
*/)
call createTest("ux: dm/im", /* pass
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hfoo') + " im\n" + /* enable
*/I2S('hkni') + " im\n" + /* disable
*/I2S('hfoo') + " im\n" + /* disable
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hfoo') + " dm\n" + /* enable
*/I2S('hkni') + " dm\n" + /* disable
*/I2S('hfoo') + " dm" /* disable
*/)
call createTest("ux: im", /* pass
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hfoo') + " im\n" + /* enable
*/I2S('hkni') + " im\n" + /* disable
*/I2S('hfoo') + " im" /* disable
*/)
call createTest("ux: ds/is/dm", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hkni') + " ds" /* enable
*/)
call createTest("ux: ds/is/im", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hkni') + " ds" /* enable
*/)
call createTest("ux: ds/dm/im", /* pass
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hfoo') + " im\n" + /* enable
*/I2S('hkni') + " im\n" + /* disable
*/I2S('hfoo') + " im\n" + /* disable
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hkni') + " ds\n" + /* enable
*/I2S('hfoo') + " dm\n" + /* enable
*/I2S('hfoo') + " ds\n" + /* enable
*/I2S('hkni') + " dm\n" + /* disable
*/I2S('hkni') + " ds\n" + /* disable
*/I2S('hfoo') + " dm\n" + /* disable
*/I2S('hfoo') + " ds" /* disable
*/)
call createTest("ux: is/dm/im", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hkni') + " dm" /* enable
*/)
call createTest("ux: ds/is/dm/im", /* pass
*/I2S('hkni') + " is\n" + /* enable
*/I2S('hkni') + " im\n" + /* enable
*/I2S('hkni') + " dm\n" + /* enable
*/I2S('hkni') + " ds" /* enable
*/)
static if UnitIndex1.U then
set WHICH_TEST = "u: "
elseif UnitIndex1.UX then
set WHICH_TEST = "ux: "
endif
static if UnitIndex1.DS then
set WHICH_TEST = WHICH_TEST + "ds/"
endif
static if UnitIndex1.IS then
set WHICH_TEST = WHICH_TEST + "is/"
endif
static if UnitIndex1.DM then
set WHICH_TEST = WHICH_TEST + "dm/"
endif
static if UnitIndex1.IM then
set WHICH_TEST = WHICH_TEST + "im"
endif
if (SubString(WHICH_TEST, StringLength(WHICH_TEST) - 1, StringLength(WHICH_TEST)) == "/") then
set WHICH_TEST = SubString(WHICH_TEST, 0, StringLength(WHICH_TEST) - 1)
endif
call test()
endmethod
implement InitTimer
endstruct
/*
* Unit Indexer is best used with structs
*
* To use Unit Indexer, just implement the module at the bottom of your struct
*
* This will convert your struct into a global UnitIndex.
*/
/*
* Unit Indexer is best used with structs
*
* To use Unit Indexer, just implement the module at the bottom of your struct
*
* This will convert your struct into a global UnitIndex. It will also inherit from UnitIndexer.
*
* A global unit index is a unit index that is from the set of all unit indexes
*/
struct UseUnitIndexer extends array
implement GlobalUnitIndex
endstruct
/*
* There are two unit index events. When the methods are declared in your struct, they
* will be called.
*/
private method onUnitIndex takes nothing returns nothing
private method onUnitDeindex takes nothing returns nothing
/*
* onUnitIndex is called whenever any unit is indexed
*
* onUnitDeindex is called whenever any unit is deindexed
*/
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
struct UnitIndex1 extends array
private method onUnitIndex takes nothing returns nothing
// what do you think unit does?
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Indexed " + GetUnitName(unit))
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Deindexed " + GetUnitName(unit))
endmethod
implement GlobalUnitIndex
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
call RemoveUnit(CreateUnit(Player(0), 'hpea', 0, 0, 270))
endmethod
endstruct
/*
* GlobalUnitIndex only has things that work with plain unit indexes. It's goal to be as
* light as possible while providing a nice API. Be sure to check the documentation in the
* UnitIndexer trigger to see the rest of the API for GlobalUnitIndex.
*
* The next type of module is called UnitIndex.
*/
struct UseUnitIndexer extends array
implement UnitIndex
endstruct
/*
* Just like GlobalUnitIndex, it has the two unit index events.
*/
private method onUnitIndex takes nothing returns boolean
private method onUnitDeindex takes nothing returns nothing
/*
* There is one key difference. onUnitIndex returns a boolean!
*
* UnitIndex structs are subsets of all unit indexes. The boolean states whether to allocate the unit index
* for your struct or not.
*
* onUnitDeindex will only run for units indexed in the struct
*/
private method onUnitIndex takes nothing returns boolean
/*
* because this always returns false, no unit is ever indexed
* for this struct
*
* this means that onUnitDeindex will never run
*/
return false
endmethod
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
struct UnitIndex1 extends array
private method onUnitIndex takes nothing returns boolean
return false
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1")
endmethod
implement UnitIndex
endstruct
struct UnitIndex2 extends array
private method onUnitIndex takes nothing returns boolean
return true
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2")
endmethod
implement UnitIndex
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
call RemoveUnit(CreateUnit(Player(0), 'hpea', 0, 0, 270))
endmethod
endstruct
/*
* onUnitIndex and onUnitDeindex are both optional.
*
* Depending on what is implemented, the UnitIndex struct has a different behavior
*
* If onUnitIndex is implemented, it has standard behavior.
*
* If it isn't implemented, then all indexed units are allocated for the struct.
*
* To determine whether a unit is allocated for a struct or not, isUnitIndexed is used
*
* Be sure to check the documentation to see the differences in wording between GlobalUnitIndex's isUnitIndexed
* and UnitIndex's isUnitIndexed
*/
readonly boolean isUnitIndexed
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
struct UnitIndex1 extends array
private method onUnitIndex takes nothing returns boolean
return false
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1")
endmethod
implement UnitIndex
endstruct
struct UnitIndex2 extends array
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2")
endmethod
implement UnitIndex
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u = CreateUnit(Player(0), 'hpea', 0, 0, 270)
/*
* Note that [] converts a unit into a unit index
*/
if (UnitIndex1[u].isUnitIndexed) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Allocated")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Not Allocated")
endif
if (UnitIndex2[u].isUnitIndexed) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2 Allocated")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2 Not Allocated")
endif
call RemoveUnit(u)
set u = null
endmethod
endstruct
/*
* enabled controls whether UnitIndexer is enabled or not. This only controls
* onUnitIndex. onUnitDeindex will always run given onUnitIndex returned true.
* If onUnitIndex isn't declared, onUnitDeindex always runs.
*
* if enabled is false, onUnitIndex will not run and units will not be indexed.
* However, this is only true if onUnitIndex exists. If it does not exist, the
* struct can't be disabled.
*
* This was done for efficiency purposes. If you want to be able to disable the
* struct but don't want onUnitIndex, then just do
*
* private method onUnitIndex takes nothing returns boolean
* return true
* endmethod
*
* This is inherited from UnitIndexer (see API).
*/
static boolean enabled
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
struct UnitIndex1 extends array
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1")
endmethod
implement UnitIndex
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u
set UnitIndexer.enabled = false
set u = CreateUnit(Player(0), 'hpea', 0, 0, 270)
/*
* Note that [] converts a unit into a unit index
*/
if (UnitIndex1[u].isUnitIndexed) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Allocated")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Not Allocated")
endif
set UnitIndexer.enabled = true
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hpea', 0, 0, 270)
if (UnitIndex1[u].isUnitIndexed) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Allocated")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Not Allocated")
endif
set UnitIndexer.enabled = false
call RemoveUnit(u)
set UnitIndexer.enabled = true
set u = null
endmethod
endstruct
/*
* Lab 3 will throw a warning. This is because the first unit isn't indexed but the code
* tries to access its index.
*
* If you want to avoid this warning, you can use the following method, which is
* inherited from UnitIndex
*/
static method exists takes unit whichUnit returns boolean
/*
* This will determine whether or not a unit is indexed for the struct
*/
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
struct UnitIndex1 extends array
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1")
endmethod
implement UnitIndex
endstruct
struct UnitIndex2 extends array
private method onUnitIndex takes nothing returns boolean
return false
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2")
endmethod
implement UnitIndex
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u
set UnitIndexer.enabled = false
set u = CreateUnit(Player(0), 'hpea', 0, 0, 270)
/*
* Note that [] converts a unit into a unit index
*/
if (UnitIndex1.exists(u)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Allocated")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Not Allocated")
endif
if (UnitIndex2.exists(u)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2 Allocated")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2 Not Allocated")
endif
set UnitIndexer.enabled = true
set UnitIndex1.enabled = false
set UnitIndex2.enabled = false
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hpea', 0, 0, 270)
if (UnitIndex1.exists(u)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Allocated")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex1 Not Allocated")
endif
if (UnitIndex2.exists(u)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2 Allocated")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "UnitIndex2 Not Allocated")
endif
set UnitIndexer.enabled = false
set UnitIndex1.enabled = true
set UnitIndex2.enabled = true
call RemoveUnit(u)
set UnitIndexer.enabled = true
set u = null
endmethod
endstruct
/*
* isDeindexing tells whether the unit is currently in the process of being deindexed or
* not. A unit is deindexing when the undefend ability that unit indexer relies on to catch
* indexing is 0 and the unit is currently indexed.
*
* This will always return true in the onUnitDeindexed method.
*/
static method isDeindexing takes unit whichUnit returns boolean
/*
* Given a unit index, that index can be converted back into a unit via the unit field (lab 0)
*/
readonly unit unit
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
struct UnitIndex1 extends array
private method onUnitDeindex takes nothing returns nothing
if (isDeindexing(unit)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " is being deindexed")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " is not being deindexed")
endif
endmethod
implement UnitIndex
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
call RemoveUnit(CreateUnit(Player(0), 'hpea', 0, 0, 270))
endmethod
endstruct
/*
* The module does not have to be used in order to capture unit index events
*/
scope CaptureUnitIndexing initializer init
private function DeindexMahUnit takes nothing returns boolean
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(UnitIndexer.eventUnit) + " was deindexed")
return false
endfunction
private function ThisIsMyOnIndex takes nothing returns boolean
/*
* the unit deindex event is unit specific, so it needs
* to be registered for each unit
*/
/*
* UnitIndexer provides two fields that give access to the
* unit being acted upon
*
* static readonly thistype eventIndex
* - the indexed unit's index
*
* static readonly unit eventUnit
* - the indexed unit
*/
/*
* only capture knights
*/
if (GetUnitTypeId(UnitIndexer.eventUnit) == 'hkni') then
/*
* each UnitIndex has its own Indexer. Use these to get to the unit specific events.
*/
call UnitIndexer.eventIndex.indexer.Event.ON_DEINDEX.register(Condition(function DeindexMahUnit))
endif
return false
endfunction
private function init takes nothing returns nothing
/*
* this will register ThisIsMyOnIndex to UnitIndexer ON_INDEX event
*
* this captures all unit index events
*/
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function ThisIsMyOnIndex))
call RemoveUnit(CreateUnit(Player(0), 'hfoo', 0, 0, 270))
call RemoveUnit(CreateUnit(Player(0), 'hkni', 0, 0, 270))
endfunction
endscope
/*
* UnitIndexer uses Trigger to handle events, meaning that you can set up entry points
* to the UnitIndexer indexing events. This is useful to do stages of unit indexing.
*
* Triggers run before registered code.
*/
scope CaptureUnitIndexing initializer init
globals
Trigger customOnIndex
endglobals
private function DeindexMahUnit takes nothing returns boolean
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(UnitIndexer.eventUnit) + " was deindexed")
return false
endfunction
private function ThisIsMyOnIndex takes nothing returns boolean
if (GetUnitTypeId(UnitIndexer.eventUnit) == 'hkni') then
call UnitIndexer.eventIndex.indexer.Event.ON_DEINDEX.register(Condition(function DeindexMahUnit))
endif
return false
endfunction
private function init takes nothing returns nothing
/*
* false here refers to whether the Trigger should run in reverse or not
* reversed triggers are good for things like deindex events
*/
set customOnIndex = Trigger.create(false)
call UnitIndexer.GlobalEvent.ON_INDEX.reference(customOnIndex)
/*
* now you can register code to your custom trigger and have it run
*
* this works the same way with deindexing
*/
call customOnIndex.register(Condition(function ThisIsMyOnIndex))
call RemoveUnit(CreateUnit(Player(0), 'hfoo', 0, 0, 270))
call RemoveUnit(CreateUnit(Player(0), 'hkni', 0, 0, 270))
endfunction
endscope
/*
* There is also a global deindex event
*
* readonly static Trigger GlobalEvent.ON_DEINDEX
*
* Global deindex events run after unit specific deindex events
*
* The reason for the order is as follows
*
* Global creation events generally set up data for local creation events
*
* If a combat system is a global creation event, then damage modifiers that work with that combat
* system would be local. These local events depend on the global event. It is never the other way around.
* The reason it is impossible the other way around is because a local event may or may not exist. A global
* event always exists.
*
* Global destruction generally destroys data that local events rely on. This means that if a global event
* runs before a local event, that data gets lost. Global events can never rely on the data of local events
* because that data may or may not exist
*
* Thus, the order should be as follows for the lifetime of any given event
*
* Global Create
* Local Create
* Local Destroy
* Global Destroy
*
* And for UnitIndexer
*
* ON_INDEX
* ON_DEINDEX local
* ON_DEINDEX global
*/
struct UnitIndexGlobal extends array
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + ": Global Deindex Event Via Module")
endmethod
implement UnitIndex
endstruct
struct UnitIndexLocal extends array
private method onUnitIndex takes nothing returns boolean
return true
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + ": Local Deindex Event Via Module")
endmethod
implement UnitIndex
endstruct
/*
* The above struct gets registered first, meaning that it's deindex event will run after the below code.
* Remember that Triggers can be reversed (mentioned in Lab 7). This is the reason why the order is the way it is.
*/
scope CaptureUnitIndexing initializer init
private function DeindexMahUnit takes nothing returns boolean
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(UnitIndexer.eventUnit) + ": Global Deindex Event Via Function")
return false
endfunction
private function init takes nothing returns nothing
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function DeindexMahUnit))
call RemoveUnit(CreateUnit(Player(0), 'hfoo', 0, 0, 270))
call RemoveUnit(CreateUnit(Player(0), 'hkni', 0, 0, 270))
endfunction
endscope
/*
* The UnitIndex module is for standalone structs. These structs don't play nicely with
* other resources, like Unit Event. They are good if you don't plan on using any other
* resources in them that rely on local indexing events.
*
* UnitIndexEx provides local indexing events for a struct.
*/
readonly static Trigger ON_INDEX
readonly Trigger ON_DEINDEX
readonly static Trigger ON_DEINDEX
/*
* While these events exist, it is not recommend that you use them directly because the resulting code is
* relatively complex and is always the same for any given module. As such, UnitIndexer has a textmacro
* that you can use.
*
*/
//! textmacro CREATE_LOCAL_UNIT_INDEX
/*
* This textmacro works both with UnitIndex and UnitIndexEx. The reason for both of these modules will be
* covered later. The events won't be covered in until later.
*
* The textmacro is meant to be implemented in custom user modules that latch on to local UnitIndex events.
*
* Rather than onUnitIndex and onUnitDeindex, the macro provides
*/
private method onLocalUnitIndex takes nothing returns nothing
private method onLocalUnitDeindex takes nothing returns nothing
/*
* The reason onLocalUnitIndex does not return a boolean is because only the struct can filter indexes.
* The most you can do is listen in.
*
* Besides this, a method is also provided to replace onInit. The macro depends on onInit. As such, you can't
* use it in your modules.
*/
private static method localInit takes nothing returns nothing
/*
* A full example of using the macro. The methods are all optional as usual.
*/
module MyCustomModule
private method onLocalUnitIndex takes nothing returns nothing
endmethod
private method onLocalUnitDeindex takes nothing returns nothing
endmethod
private static method localInit takes nothing returns nothing
endmethod
//! runtextmacro CREATE_LOCAL_UNIT_INDEX()
endmodule
/*
* The thing to really keep in mind is that these events are local to the struct. If a unit gets indexed
* but doesn't make it through the struct's filter, these will never run.
*/
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*
* Remember that deindex events run in reverse.
*/
module MyCustomModule
private method onLocalUnitIndex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was indexed for thistype (module)")
endmethod
private method onLocalUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (module)")
endmethod
//! runtextmacro CREATE_LOCAL_UNIT_INDEX()
endmodule
struct UnitIndex1 extends array
private method onUnitIndex takes nothing returns boolean
if (GetUnitTypeId(unit) != 'hkni') then
return false
endif
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was indexed for thistype (struct)")
return true
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (struct)")
endmethod
/*
* One cool thing about the textmacro is that it automtaically implements
* UnitIndexEx
*/
implement MyCustomModule
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u
set u = CreateUnit(Player(0), 'hpea', 0, 0, 270)
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hkni', 0, 0, 270)
call RemoveUnit(u)
set u = null
endmethod
endstruct
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
module MyCustomModule
private method onLocalUnitIndex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was indexed for thistype (module)")
endmethod
private method onLocalUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (module)")
endmethod
//! runtextmacro CREATE_LOCAL_UNIT_INDEX()
endmodule
struct UnitIndex1 extends array
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (struct)")
endmethod
implement MyCustomModule
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u
set UnitIndex1.enabled = false
set u = CreateUnit(Player(0), 'hfoo', 0, 0, 270)
set UnitIndex1.enabled = true
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hkni', 0, 0, 270)
call RemoveUnit(u)
set u = null
endmethod
endstruct
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
module MyCustomModule
private method onLocalUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (module)")
endmethod
//! runtextmacro CREATE_LOCAL_UNIT_INDEX()
endmodule
struct UnitIndex1 extends array
private method onUnitIndex takes nothing returns boolean
if (GetUnitTypeId(unit) != 'hkni') then
return false
endif
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was indexed for thistype (struct)")
return true
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (struct)")
endmethod
implement MyCustomModule
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u
set UnitIndex1.enabled = false
set u = CreateUnit(Player(0), 'hkni', 0, 0, 270)
set UnitIndex1.enabled = true
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hkni', 0, 0, 270)
call RemoveUnit(u)
set u = null
endmethod
endstruct
/*
* The output, except for the order of messages on Lab 10, should have been rather straight forward.
*
* Just like before, there were local and global events. If onUnitIndex did not exist, the the struct
* had only global index events. As a result, the module also had global events.
*
* When onUnitIndex did exist, then the module had local events. Even when onLocalUnitIndex was removed, the module
* still had local events.
*
* What happens when UnitIndex is used instead of UnitIndexEx?
*/
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
module MyCustomModule
private method onLocalUnitIndex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was indexed for thistype (module)")
endmethod
private method onLocalUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (module)")
endmethod
//! runtextmacro CREATE_LOCAL_UNIT_INDEX()
endmodule
struct UnitIndex1 extends array
private method onUnitIndex takes nothing returns boolean
if (GetUnitTypeId(unit) != 'hkni') then
return false
endif
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was indexed for thistype (struct)")
return true
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (struct)")
endmethod
/*
* Forcefully implement UnitIndex
*/
implement UnitIndex
implement MyCustomModule
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u
set UnitIndex1.enabled = false
set u = CreateUnit(Player(0), 'hkni', 0, 0, 270)
set UnitIndex1.enabled = true
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hkni', 0, 0, 270)
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hfoo', 0, 0, 270)
call RemoveUnit(u)
set u = null
endmethod
endstruct
/*
* The correct events ran and they were in the correct order
*
* index struct
* index module
* deindex module
* deindex struct
*
* UnitIndex does not have local events? The module is running independently from the struct.
* The module gets registered after the struct.
*
* Register Struct Index
* Register Module Index
* Register Struct Deindex
* Register Module Deindex
*
* Remember that the deindex trigger is reversed.
*
* How did the module run the correct events? It conditionally ran/registered events by checking
* isUnitIndexed, which if you recall, is the set of all indexes for the struct, not the system.
*
* If both UnitIndex and UnitIndexEx give the same output, why use UnitIndexEx at all?
*
* UnitIndexEx has local events (the triggers). This means that if you disable your struct, you disable
* all structs that go through it. UnitIndex does not have this advantage.
*
* Modules that work off of UnitIndex will register their ON_INDEX events globally to the system. This means
* that they will always run, whether or not the unit made it through the filter or your struct was even enabled.
* Remember, they are not dependent on the struct when using UnitIndex, rather they just check to see if the struct
* let the unit through or not and mimic that. When using UnitIndexEx, they actually depend on the struct.
*
* UnitIndexEx was originally made because Trigger didn't have a reverse flag, meaning that the order of the
* events was wrong when using UnitIndex.
*
* index struct
* index module
* deindex struct
* deindex module
*
* Since the reverse flag came about, it's safe to use either UnitIndex or UnitIndexEx. Just remember that UnitIndex makes
* modules and other structs run in parallel with it and UnitIndexEx makes modules and other structs run through it. UnitIndex
* makes everyone else have to mimic your struct. UnitIndexEx makes your struct a gateway that lets other structs through.
*/
//TESH.scrollpos=9
//TESH.alwaysfold=0
/*
* When UnitIndexEx is implemented in the module. An error will be thrown if UnitIndex was already
* implemented.
*/
/*
* Enable this trigger
*/
/*
* First, determine what the output will be in the game. Next, run the game to check how you did.
*/
module MyCustomModule
private method onLocalUnitIndex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was indexed for thistype (module)")
endmethod
private method onLocalUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (module)")
endmethod
implement UnitIndexEx
//! runtextmacro CREATE_LOCAL_UNIT_INDEX()
endmodule
struct UnitIndex1 extends array
private method onUnitIndex takes nothing returns boolean
if (GetUnitTypeId(unit) != 'hkni') then
return false
endif
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was indexed for thistype (struct)")
return true
endmethod
private method onUnitDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, GetUnitName(unit) + " was deindexed for thistype (struct)")
endmethod
/*
* Forcefully implement UnitIndex
*/
implement UnitIndex
implement MyCustomModule
endstruct
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u
set UnitIndex1.enabled = false
set u = CreateUnit(Player(0), 'hkni', 0, 0, 270)
set UnitIndex1.enabled = true
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hkni', 0, 0, 270)
call RemoveUnit(u)
set u = CreateUnit(Player(0), 'hfoo', 0, 0, 270)
call RemoveUnit(u)
set u = null
endmethod
endstruct
/*
* By this point you know how to create standalone structs, libraries, and modules that become local
* to the struct that they are implemented in. The only thing left is to create structs that become
* local to the structs they register to.
*
* Example:
*
* Suppose you have a struct called Hero. Whenever a hero is made, it creates various things
* for that hero. Suppose one such thing is a military rank.
*
* Let's say that you want to give all heroes a number of guards based on their rank. This
* struct would work off of the Hero struct and depend on rank. As this struct depends on the
* data of Hero in both indexing and deindexing events, Hero should really implement UnitIndexEx.
*
* We're going to create the above in the next lab!
*
* When working off of structs, their local events will be used. ON_DEINDEX is static if the struct
* has no onUnitIndex declared. Structs that implement UnitIndex can be used as well, but they are much
* more difficult to work with.
*
* UnitIndex and UnitIndexEx can be identified by the following
*/
static constant boolean UNIT_INDEX = true
static constant boolean UNIT_INDEX_EX = true
/*
* A struct will only ever have one of the above booleans.
*/
//TESH.scrollpos=9
//TESH.alwaysfold=0
/*
* this is a module that sets the hero level/rank to something random
*
* this is not a good example of a module
*
* think of a big resource like UnitEvent for a good example
*/
module RandomHeroLevel
private method onLocalUnitIndex takes nothing returns nothing
local integer level = GetRandomInt(1, 10)
if (level > 1) then
call SetHeroLevel(unit, level, false)
set rank = GetHeroLevel(unit)
endif
endmethod
//! runtextmacro CREATE_LOCAL_UNIT_INDEX()
endmodule
/*
* hero is the hero
*/
struct Hero extends array
integer rank
private method onUnitIndex takes nothing returns boolean
if (not IsUnitType(unit, UNIT_TYPE_HERO)) then
return false
endif
set rank = 1
return true
endmethod
implement RandomHeroLevel
endstruct
/*
* This manages the guards
*/
struct HeroGuard extends array
private static boolexpr onUnitDeindexExpr
private group guards
private static method onUnitIndex takes nothing returns boolean
local thistype this = UnitIndexer.eventIndex
local integer i
call Hero(this).ON_DEINDEX.register(onUnitDeindexExpr)
set guards = CreateGroup()
set i = Hero(this).rank
loop
exitwhen 0 == i
call GroupAddUnit(guards, CreateUnit(GetOwningPlayer(UnitIndexer.eventUnit), 'hfoo', GetUnitX(UnitIndexer.eventUnit), GetUnitY(UnitIndexer.eventUnit), 270))
set i = i - 1
endloop
return false
endmethod
/*
* don't have to unregister because it's UnitIndexEx
* the local event will be destroyed
*/
private static method onUnitDeindex takes nothing returns boolean
local thistype this = UnitIndexer.eventIndex
local unit guard
loop
set guard = FirstOfGroup(guards)
exitwhen guard == null
call GroupRemoveUnit(guards, guard)
call KillUnit(guard)
endloop
call DestroyGroup(guards)
set guards = null
return false
endmethod
/*
* I don't do static ON_DEINDEX here because it doesn't make sense to do so
* with the Hero struct. The Hero struct should only ever index heroes, so it
* doesn't make sense to expect it not to have a filter.
*/
private static method init takes nothing returns nothing
set onUnitDeindexExpr = Condition(function thistype.onUnitDeindex)
call Hero.ON_INDEX.register(Condition(function thistype.onUnitIndex))
endmethod
implement Init
endstruct
/*
* Heroes are awesome, so if they are ever selected, we're going to remove them
*/
struct RemoveHero extends array
static if not Hero.UNIT_INDEX_EX then
private static method error takes nothing returns nothing
Hero needs to implement UNIT_INDEX_EX
endmethod
else
private static boolexpr onUnitDeindexExpr
private static boolexpr onUnitSelectExpr
private trigger onSelect
private static method onUnitSelect takes nothing returns boolean
call RemoveUnit(GetTriggerUnit())
return false
endmethod
private static method onUnitIndex takes nothing returns boolean
local thistype this = UnitIndexer.eventIndex
call Hero(this).ON_DEINDEX.register(onUnitDeindexExpr)
set onSelect = CreateTrigger()
call TriggerAddCondition(onSelect, onUnitSelectExpr)
call TriggerRegisterUnitEvent(onSelect, UnitIndexer.eventUnit, EVENT_UNIT_SELECTED)
return false
endmethod
private static method onUnitDeindex takes nothing returns boolean
local thistype this = UnitIndexer.eventIndex
call DestroyTrigger(onSelect)
set onSelect = null
return false
endmethod
private static method init takes nothing returns nothing
set onUnitDeindexExpr = Condition(function thistype.onUnitDeindex)
set onUnitSelectExpr = Condition(function thistype.onUnitSelect)
call Hero.ON_INDEX.register(Condition(function thistype.onUnitIndex))
endmethod
implement Init
endif
endstruct
/*
* for lulz
*
* this can't work with modules or other structs because it is
* using GlobalUnitIndex
*/
struct MountainKing extends array
private method onUnitIndex takes nothing returns nothing
if (GetUnitTypeId(unit) != 'Hmkg') then
return
endif
call SetUnitScale(unit, 2, 2, 2)
endmethod
implement GlobalUnitIndex
endstruct
/*
* we're going to give non-hero units something
*/
struct Colorz extends array
private method onUnitIndex takes nothing returns nothing
if (Hero(this).isUnitIndexed) then
return
endif
call SetUnitVertexColor(unit, GetRandomInt(0, 255), GetRandomInt(0, 255), GetRandomInt(0, 255), 255)
endmethod
implement GlobalUnitIndex
endstruct
/*
* Create the units
*/
struct Initialize extends array
private static method onInit takes nothing returns nothing
local unit u
set u = CreateUnit(Player(0), 'hkni', -200, 0, 270)
set u = CreateUnit(Player(0), 'Hpal', 0, 0, 270)
set u = CreateUnit(Player(0), 'Hmkg', 0, 400, 270)
/*
* the following is a hero, but we're not going to make it
* a Hero
*/
set Hero.enabled = false
set u = CreateUnit(Player(0), 'Hmkg', 200, 0, 270)
set Hero.enabled = true
set u = null
endmethod
endstruct