library UnitIndexer requires /*
*/WorldBounds, /*hiveworkshop.com/forums/showthread.php?t=180494
*/Event, /*hiveworkshop.com/forums/showthread.php?t=186555
*/optional Table //hiveworkshop.com/forums/showthread.php?t=188084
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Unit Indexer ~~ By Nestharus ~~ Version 4.1.0.0 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Events:
// static constant Event UnitIndexer.INDEX
// static constant Event UnitIndexer.DEINDEX
//
//Fields:
// static boolean UnitIndexer.enabled
// Enables/Disables unit indexing
//
//Functions:
// function RegisterUnitIndexEvent takes boolexpr c, integer ev returns nothing
// function TriggerRegisterUnitIndexEvent takes trigger t, integer ev returns nothing
//
// function GetUnitById takes integer index returns unit
// Returns unit given a unit index
//
// function GetUnitId takes unit u returns integer
// Returns unit index given a unit
//
// function IsUnitIndexed takes unit u returns boolean
//
// function GetIndexedUnitId takes nothing returns integer
// function GetIndexedUnit takes nothing returns unit
//
//UnitIndexStruct
//////////////////////////////////////////////////////////////
// A pseudo module interface that runs a set of methods if they exist and provides
// a few fields and operators. Runs on static ifs to minimize code.
//
// static method operator [] takes unit u returns thistype
// Return GetUnitId(u)
//
// readonly unit unit
// The indexed unit of the struct
//
// allocated
// Is unit allocated for the struct
//
// Interface:
// private method index takes nothing returns nothing
// private method deindex takes nothing returns nothing
//
// private static method filter takes unit u returns boolean
// Determines whether or not to apply struct to unit
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
globals
// If this is false and the Table library is present, a hashtable will
// be used instead of UnitUserData.
private constant boolean USER_DATA = true
private keyword PreLoader
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
endglobals
function GetIndexedUnitId takes nothing returns integer
return o
endfunction
function GetIndexedUnit takes nothing returns unit
return e[o]
endfunction
function GetUnitId takes unit u returns integer
static if (LIBRARY_Table and not USER_DATA) then
return PreLoader.tb[GetHandleId(u)]
else
return GetUnitUserData(u)
endif
endfunction
function GetUnitById takes integer W returns unit
return e[W]
endfunction
function IsUnitIndexed takes unit u returns boolean
return e[GetUnitId(u)] == u
endfunction
private module tbMod
static if (LIBRARY_Table and not USER_DATA) then
Table tb
private static method onInit takes nothing returns nothing
set tb = Table.create()
endmethod
endif
endmodule
private struct PreLoader extends array
implement tbMod
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 f == 0
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 f == 0
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 = 16
local boolexpr bc = Condition(function thistype.onLeave)
local boolexpr bc2 = Condition(function thistype.onEnter)
local group g = CreateGroup()
set INDEX = CreateEvent()
set DEINDEX = CreateEvent()
call TriggerRegisterEnterRegion(CreateTrigger(), WorldBounds.worldRegion, bc2)
loop
set i = i - 1
call TriggerRegisterPlayerUnitEvent(l, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, bc)
call SetPlayerAbilityAvailable(Player(i), ABILITIES_UNIT_INDEXER, false)
call GroupEnumUnitsOfPlayer(g, Player(i), bc2)
exitwhen i == 0
endloop
call DestroyGroup(g)
set bc = null
set g = null
set bc2 = null
call TimerStart(CreateTimer(), 0, false, function PreLoader.run)
endmethod
endmodule
struct UnitIndexer extends array
readonly static Event INDEX
readonly static Event DEINDEX
static boolean enabled = true
private static method onEnter takes nothing returns boolean
//retrieve unit and unit type id
local unit Q = GetFilterUnit()
local integer i
local integer d = o
if (enabled and e[GetUnitId(Q)] != Q) then
if (y == 0) 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)
static if (LIBRARY_Table and not USER_DATA) then
set tb[GetHandleId(Q)] = i
else
call SetUnitUserData(Q, i)
endif
set e[i] = Q
if (not a)then
set p[i] = p[0]
set n[p[i]] = i
set n[i] = 0
set p[0] = 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 = GetUnitId(u)
local integer d = o
if (GetUnitAbilityLevel(u, ABILITIES_UNIT_INDEXER) == 0 and e[i] == u) then
if (not a)then
set n[p[i]] = n[i]
set p[n[i]] = p[i]
endif
set o = i
call FireEvent(DEINDEX)
set o = d
static if (LIBRARY_Table and not USER_DATA) then
call tb.remove(GetHandleId(u))
endif
set n[i] = y
set y = i
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 n[0] != 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 n[0] != 0) then
call PreLoader.eval(t)
endif
endfunction
module UnitIndexStruct
static method operator [] takes unit u returns thistype
return GetUnitId(u)
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
static if thistype.filter.exists then
static if thistype.index.exists then
readonly boolean allocated
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 GetUnitId(e[this]) == this
endmethod
endif
else
method operator allocated takes nothing returns boolean
return GetUnitId(e[this]) == 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
set thistype(o).allocated = true
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.unitDeindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent), UnitIndexer.DEINDEX)
endmethod
endif
endmodule
endlibrary