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
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
* 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
//TESH.scrollpos=132
//TESH.alwaysfold=0
/*
* 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=283
//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=192
//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
//TESH.scrollpos=6
//TESH.alwaysfold=0
/*
* 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
//TESH.scrollpos=6
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
=================================B U F F S Y S T E M====================================
This system has two parts:
- CREATE_BUFF_OBJECT: Create ability and buff to use for this system.
+ When the first time you create buff object, you MUST CLOSED Jassnewgen and RE-OPEN it.
+ If you use JNGP 2.0, dont worry about external object each times you save map (RECOMMENDED).
+ If you use JNGP v5d or else, please put CREATE_BUFF_OBJECT to a seperate trigger (DISABLE it when create buff finished).
- CREATE_BUFF: Create core code that you have to create if you want to use this system.
+ Create a struct contents all things of a specific buff.
+ Put in a seperate trigger or inside Buff Trigger.
REQUIREMENTS
- JassNewGen Pack v5d or higher.
Link: (blizzardmodding.info/4263/the-jass-newgen-pack-jngp-2-0/)
- Vexorian - Jass Helper 0.A.2.B
Link: (www.wc3c.net/showthread.php?t=88142)
- Vexorian - Timer Utils
Link: (www.wc3c.net/showthread.php?t=101322)
- Nestharus - Unit Indexer
Link: (www.hiveworkshop.com/forums/spells-569/unit-indexer-v5-3-0-1-a-260859/)
- Nestharus - Trigger
Link: (www.hiveworkshop.com/forums/spells-569/trigger-v1-1-0-2-a-260933/)
HOW TO USE:
STEP 1: Create buff object through textmacro CREATE_BUFF_OBJECT.
//! textmacro CREATE_BUFF_OBJECT takes RAWCODE, NAME, ICON, DESCRIPTION
+ RAWCODE: I recommended you use 3 DIGITS.
+ EXAMPLE:
//! runtextmacro CREATE_BUFF_OBJECT("rag","Rage", "ReplaceableTextures\CommandButtons\BTNAncestralSpirit.blp", "This unit is affected by Rage.")
+ Above line that you have created a buff called "Rage" with AbilityId = 'Arag', BuffId = 'Brag'.
STEP 2: Create specific buff struct.
//! textmacro CREATE_BUFF takes RAWCODE, NAME
+ RAWCODE: I recommended you use 3 DIGITS (same as with RAWCODE of buff object)
+ EXAMPLE:
//! runtextmacro CREATE_BUFF("rag","Rage")
struct BuffRage extends array will be created.
if you want to apply BuffRage to a specific unit (whichUnit) use this function:
call BuffRage[whichUnit].apply()
apply a buff: call Buff$NAME$[whichUnit].apply()
To remove a buff from a specific unit use this function:
call BuffRage[whichUnit].remove()
remove a buff: call Buff$NAME$[whichUnit].remove()
To apply a buff to a unit for a duration, you can set buff duration:
set BuffRage[whichUnit].duration = real Duration
The buff will exist pernament if you didnt set duration or set duration <= 0
Extra function:
function RegisterApplyBuff$NAME$Event takes boolexpr whichBoolexpr returns TriggerCondition
function RegisterRemoveBuff$NAME$Event takes boolexpr whichBoolexpr returns TriggerCondition
STEP 3: Feel free to use and modify.
The EXAMPLE is inside Buff trigger and Test Category.
===========================================N O T I C E====================================================
If you want to USE this system, you MUST have KNOWLEDGE about vJASS. At least, you must understand how to use.
===========================================C R E D I T====================================================
Special thanks to:
Veroxian
Nestharus
The Hiveworkshop
//TESH.scrollpos=56
//TESH.alwaysfold=0
library Buff requires UnitIndexer, TimerUtils
//! textmacro CREATE_BUFF_OBJECT takes RAWCODE, NAME, ICON, DESCRIPTION
//! external ObjectMerger w3a Aasl A$RAWCODE$ ansf "(Buff System)" anam "$NAME$" abuf 1 B$RAWCODE$ Slo1 1 0 aare 1 0 atar 1 self
//! external ObjectMerger w3h Basl B$RAWCODE$ fnsf "(Buff System)" ftip "$NAME$" fube "$DESCRIPTION$" fart "$ICON$"
//! endtextmacro
//! textmacro CREATE_BUFF takes RAWCODE, NAME
struct Buff$NAME$ extends array
readonly static integer Ability = 'A$RAWCODE$'
readonly static integer Id = 'B$RAWCODE$'
readonly static Trigger ApplyTrigger
readonly static Trigger RemoveTrigger
readonly static unit TriggerUnit
readonly timer Timer
static method onRemove takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
set TriggerUnit = null
call this.remove()
call ReleaseTimer(t)
endmethod
method operator duration= takes real t returns nothing
if t > 0 then
if this.Timer != null then
call PauseTimer(this.Timer)
call ReleaseTimer(this.Timer)
endif
set this.Timer = NewTimerEx(this)
call TimerStart(this.Timer, t, false, function thistype.onRemove)
else
if this.Timer != null then
call PauseTimer(this.Timer)
call ReleaseTimer(this.Timer)
endif
endif
endmethod
method operator duration takes nothing returns real
return TimerGetRemaining(this.Timer)
endmethod
method apply takes nothing returns nothing
set TriggerUnit = null
if GetUnitAbilityLevel(this.unit, Ability) == 0 then
set TriggerUnit = this.unit
call ApplyTrigger.fire()
call UnitMakeAbilityPermanent(this.unit, true, Ability)
call UnitAddAbility(this.unit, Ability)
endif
endmethod
method remove takes nothing returns nothing
set TriggerUnit = null
if GetUnitAbilityLevel(this.unit, Ability) != 0 then
set TriggerUnit = this.unit
call RemoveTrigger.fire()
call UnitRemoveAbility(this.unit, Ability)
call UnitRemoveAbility(this.unit, Id)
endif
endmethod
private static method onInit takes nothing returns nothing
set ApplyTrigger = Trigger.create(false)
set RemoveTrigger = Trigger.create(false)
endmethod
implement GlobalUnitIndex
endstruct
function RegisterApplyBuff$NAME$Event takes boolexpr whichBoolexpr returns TriggerCondition
return Buff$NAME$.ApplyTrigger.register(whichBoolexpr)
endfunction
function RegisterRemoveBuff$NAME$Event takes boolexpr whichBoolexpr returns TriggerCondition
return Buff$NAME$.RemoveTrigger.register(whichBoolexpr)
endfunction
//! endtextmacro
/* Put your textmacro here */
// 2 lines below is test Create Buff.
//! runtextmacro CREATE_BUFF_OBJECT("rag","Rage", "ReplaceableTextures\CommandButtons\BTNAncestralSpirit.blp", "This unit is affected by Rage.")
//! runtextmacro CREATE_BUFF("rag", "Rage")
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope test initializer inittest
globals
unit uu
endglobals
private function a takes nothing returns boolean
local unit u = BuffRage.TriggerUnit
call SetWidgetLife(u, 1)
call BJDebugMsg(GetUnitName(u) + " is applied Rage Buff!!!")
return false
endfunction
private function b takes nothing returns boolean
local unit u = BuffRage.TriggerUnit
call SetWidgetLife(u, 220)
call BJDebugMsg(GetUnitName(u) + " is removed Rage Buff!!!")
return false
endfunction
private function inittest takes nothing returns nothing
set uu = CreateUnit(Player(0), 'hpea', 0, 0, 0)
call RegisterApplyBuffRageEvent(Filter(function a))
call RegisterRemoveBuffRageEvent(Filter(function b))
call BuffRage[uu].apply()
set BuffRage[uu].duration = 5
endfunction
endscope