//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
TempPoint | location | No |
//TESH.scrollpos=14
//TESH.alwaysfold=0
//==============================================================================
// FAERIE DRAGON SPELLPACK v1.1
// BY Ayanami
//==============================================================================
//==============================================================================
// REQUIREMENTS
//==============================================================================
//
// - JNGP
// - RegisterPlayerUnitEvent
// - SpellEffectEvent
// - Timer Tools
// - Unit Indexer
// - World Bounds
//
//==============================================================================
//==============================================================================
// IMPLEMENTATION
//==============================================================================
//
// 1) Copy the whole "Required Systems" Trigger folder & paste in map
// 2) Copy all 3 abilities under "Night Elf - Units" & paste in map
// 3) Copy all 4 abilities under "Night Elf - Hero" & paste in map
// 4) Copy all 2 buffs under "Night Elf" & paste in map
// 5) Ensure that the following abilities have their buff set properly:
// Waning Rift (Silence) - Waning Rift
// Dream Coil (Stun) - Dream Coil
// 6) Copy the whole "Faerie Dragon" Trigger folder
// 7) Go through all the spell Configurations
//
//==============================================================================
//TESH.scrollpos=103
//TESH.alwaysfold=0
library IllusoryOrb uses RegisterPlayerUnitEvent, SpellEffectEvent, Tt, UnitIndexer, WorldBounds
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABIL_ID = 'ABIO' // raw code of ability "Illusory Orb"
private constant integer DUM_ABIL_ID = 'AIO0' // raw code of ability "Ethereal Jaunt"
private constant integer DUMMY_ID = 'duIO' // raw code of unit "Ilusory Orb Dummy"
private constant integer RED = 255 // red vertex color of DUMMY_ID
private constant integer GREEN = 255 // green vertex color of DUMMY_ID
private constant integer BLUE = 255 // blue vertex color of DUMMY_ID
private constant integer TRANS = 255 // transparency of DUMMY_ID, where 0 is fully transparent
private constant integer SCALE = 4 // scale size of DUMMY_ID
private constant real HEIGHT = 150. // height of DUMMY_ID
private constant real SPEED = 600. // distance travelled per second by orb
private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map
private constant boolean PRELOAD = true // preloads resources if true
private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type
private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type
endglobals
// area of effect
private constant function GetArea takes integer level returns real
return 300.0
endfunction
// damage dealt
private constant function GetDamage takes integer level returns real
return 70.0 * level
endfunction
// distance travelled by orb
private constant function GetDistance takes integer level returns real
return 1800.
endfunction
// target types allowed for dealing damage
private constant function GetFilter takes unit caster, unit target returns boolean
return /*
*/ not IsUnitType(target, UNIT_TYPE_DEAD) and /* // target is alive
*/ IsUnitEnemy(target, GetOwningPlayer(caster)) and /* // target is an enemy of caster
*/ not IsUnitType(target, UNIT_TYPE_STRUCTURE) and /* // target is not a structure
*/ not IsUnitType(target, UNIT_TYPE_MECHANICAL) // target is not mechanic
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
globals
private constant sound ERROR = CreateSoundFromLabel("InterfaceError", false, false, false, 10, 10)
private constant player NEUTRAL_PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
private group G = bj_lastCreatedGroup
endglobals
private struct Main extends array
private group g
private unit u
private unit dummy
private real area
private real dmg
private real dist
private real sin
private real cos
private static integer array store
private static constant real TIMEOUT = 0.031250000
private static constant real TRUE_SPEED = SPEED * TIMEOUT
implement CTTC
local unit u
local real x
local real y
implement CTTCExpire
set x = GetUnitX(this.dummy) + this.cos
set y = GetUnitY(this.dummy) + this.sin
if x > WorldBounds.minX and y > WorldBounds.minY and x < WorldBounds.maxX and y < WorldBounds.maxY then
call SetUnitX(this.dummy, x)
call SetUnitY(this.dummy, y)
endif
set this.dist = this.dist - TRUE_SPEED
call GroupEnumUnitsInRange(G, x, y, this.area + ENUM_RADIUS, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
call GroupRemoveUnit(G, u)
if not IsUnitInGroup(u, this.g) and GetFilter(this.u, u) and IsUnitInRangeXY(u, x, y, this.area) then
call GroupAddUnit(this.g, u)
call UnitDamageTarget(this.u, u, this.dmg, true, false, ATK, DMG, null)
endif
endloop
if this.dist <= 0 then
if thistype.store[GetUnitId(this.u)] == this then
set thistype.store[GetUnitId(this.u)] = 0
endif
call GroupClear(this.g)
call DestroyGroup(this.g)
call KillUnit(this.dummy)
set this.g = null
call this.destroy()
endif
implement CTTCEnd
private static method onCast takes nothing returns boolean
local thistype this = thistype.create()
local integer level
local real a
set this.g = CreateGroup()
set this.u = GetTriggerUnit()
set a = Atan2(GetSpellTargetY() - GetUnitY(this.u), GetSpellTargetX() - GetUnitX(this.u))
set this.dummy = CreateUnit(NEUTRAL_PASSIVE, DUMMY_ID, GetUnitX(this.u), GetUnitY(this.u), a * bj_RADTODEG)
set level = GetUnitAbilityLevel(this.u, ABIL_ID)
set this.area = GetArea(level)
set this.dmg = GetDamage(level)
set this.dist = GetDistance(level)
set this.sin = TRUE_SPEED * Sin(a)
set this.cos = TRUE_SPEED * Cos(a)
set thistype.store[GetUnitId(this.u)] = this
call SetUnitVertexColor(this.dummy, RED, GREEN, BLUE, TRANS)
call SetUnitScale(this.dummy, SCALE, 0, 0)
call SetUnitFlyHeight(this.dummy, 100., 0)
return false
endmethod
private static method onDummyCast takes nothing returns boolean
local thistype this
if thistype.store[GetUnitId(GetTriggerUnit())] > 0 then
set this = thistype.store[GetUnitId(GetTriggerUnit())]
set thistype.store[GetUnitId(this.u)] = 0
call SetUnitX(this.u, GetUnitX(this.dummy))
call SetUnitY(this.u, GetUnitY(this.dummy))
call GroupClear(this.g)
call DestroyGroup(this.g)
call KillUnit(this.dummy)
set this.g = null
call this.destroy()
else
if GetLocalPlayer() == GetOwningPlayer(GetTriggerUnit()) then
call ClearTextMessages()
call StartSound(ERROR)
endif
call DisplayTimedTextToPlayer(GetOwningPlayer(GetTriggerUnit()), 0.52, -1., 2., "|cffffcc00No Illusory Orb found.|r")
endif
return false
endmethod
private static method onLearn takes nothing returns boolean
if GetLearnedSkill() == ABIL_ID and GetUnitAbilityLevel(GetTriggerUnit(), ABIL_ID) == 1 then
call UnitAddAbility(GetTriggerUnit(), DUM_ABIL_ID)
endif
return false
endmethod
private static method onInit takes nothing returns nothing
static if PRELOAD then
local unit u = CreateUnit(NEUTRAL_PASSIVE, DUMMY_ID, 0, 0, 0)
call UnitAddAbility(u, DUM_ABIL_ID)
call RemoveUnit(u)
set u = null
endif
call RegisterSpellEffectEvent(ABIL_ID, function thistype.onCast)
call RegisterSpellEffectEvent(DUM_ABIL_ID, function thistype.onDummyCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.onLearn)
endmethod
endstruct
endlibrary
//TESH.scrollpos=51
//TESH.alwaysfold=0
library WaningRift uses SpellEffectEvent, Tt, UnitIndexer
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABIL_ID = 'ABWR' // raw code of ability "Waning Rift"
private constant integer DUM_ABIL_ID = 'AWR0' // raw code of ability "Waning Rift (Silence)"
private constant integer BUFF_ID = 'BBWR' // raw code of buff "Waning Rift"
private constant integer CASTER_ID = 'cAST' // raw code of unit "Caster Dummy"
private constant string ORDER_ID = "soulburn" // order string of ability "Waning Rift (Silence)"
private constant string FX = "Abilities\\Spells\\Items\\StaffOfPurification\\PurificationCaster.mdl" // effect uesd on caster upon cast
private constant string FX_AT = "origin" // attachment point of FX
private constant string HIT_FX = "Abilities\\Spells\\Items\\StaffOfPurification\\PurificationTarget.mdl" // effect used on targets upon cast
private constant string HIT_FX_AT = "origin" // attachment point of HIT_FX
private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map
private constant boolean PRELOAD = true // preload resources if true
private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type
private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type
endglobals
// area of effect
private function GetArea takes integer level returns real
return 400.0
endfunction
// damage dealt
private constant function GetDamage takes integer level returns real
return 60.0 * level
endfunction
// silence duration
private constant function GetDuration takes integer level returns real
return 0.75 * level
endfunction
// target types allowed for dealing damage
private constant function GetFilter takes unit caster, unit target returns boolean
return /*
*/ not IsUnitType(target, UNIT_TYPE_DEAD) and /* // target is alive
*/ IsUnitEnemy(target, GetOwningPlayer(caster)) and /* // target is an enemy of caster
*/ not IsUnitType(target, UNIT_TYPE_STRUCTURE) and /* // target is not a structure
*/ not IsUnitType(target, UNIT_TYPE_MECHANICAL) // target is not mechanic
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
globals
private group G = bj_lastCreatedGroup
endglobals
private struct Main extends array
private unit u
private real dur
private static unit castDummy
private static integer array store
private static constant real TIMEOUT = 0.031250000
implement CTTCExpire
set this.dur = this.dur - TIMEOUT
if this.dur <= 0 then
call UnitRemoveAbility(this.u, BUFF_ID)
call this.destroy()
endif
implement CTTCEnd
private static method onCast takes nothing returns boolean
local thistype this
local unit caster = GetTriggerUnit()
local unit u
local integer level = GetUnitAbilityLevel(caster, ABIL_ID)
local real area = GetArea(level)
local real dmg = GetDamage(level)
local real dur = GetDuration(level)
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
call DestroyEffect(AddSpecialEffectTarget(FX, caster, FX_AT))
call GroupEnumUnitsInRange(G, x, y, area + ENUM_RADIUS, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
call GroupRemoveUnit(G, u)
if GetFilter(caster, u) and IsUnitInRangeXY(u, x, y, area) then
set this = thistype.store[GetUnitId(u)]
if this == 0 then
set this = thistype.create()
set this.u = u
endif
set this.dur = dur
call DestroyEffect(AddSpecialEffectTarget(HIT_FX, u, HIT_FX_AT))
call UnitDamageTarget(caster, u, dmg, true, false, ATK, DMG, null)
call IssueTargetOrder(thistype.castDummy, ORDER_ID, u)
endif
endloop
set caster = null
return false
endmethod
private static method onInit takes nothing returns nothing
static if PRELOAD then
call Preload(FX)
call Preload(HIT_FX)
endif
set thistype.castDummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), CASTER_ID, 0, 0, 0)
call UnitAddAbility(thistype.castDummy, DUM_ABIL_ID)
call RegisterSpellEffectEvent(ABIL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary
//TESH.scrollpos=101
//TESH.alwaysfold=0
library DreamCoil uses SpellEffectEvent, Tt, UnitIndexer
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABIL_ID = 'ABDC' // raw code of ability "Dream Coil"
private constant integer DUM_ABIL_ID = 'ADC0' // raw code of ability "Dream Coil (Stun)"
private constant integer BUFF_ID = 'BBDC' // raw code of buff "Dream Coil"
private constant integer CASTER_ID = 'cAST' // raw code of unit "Caster Dummy"
private constant integer DUMMY_ID = 'duDC' // raw code of unit "Dream Coil Dummy"
private constant string ANIM = "channel" // animation of dummy
private constant integer RED = 255 // red vertex color of DUMMY_ID
private constant integer GREEN = 255 // green vertex color of DUMMY_ID
private constant integer BLUE = 255 // blue vertex color of DUMMY_ID
private constant integer TRANS = 255 // transparency of DUMMY_ID, where 0 is fully transparent
private constant integer SCALE = 1 // scale size of DUMMY_ID
private constant real HEIGHT = 100. // height of DUMMY_ID
private constant string LIGHTNING = "MFPB" // lightning type used
private constant integer LIGHTNING_RED = 255 // red vertex color of LIGHTNING
private constant integer LIGHTNING_GREEN = 255 // green vertex color ot LIGHTNING
private constant integer LIGHTNING_BLUE = 255 // blue vertex color ot LIGHTNING
private constant integer LIGHTNING_TRANS = 255 // transparency of LIGHTNING, where 0 is fully transparent
private constant real LIGHTNING_HEIGHT = 50. // lightning attachment height offset (relative to unit's fly height)
private constant string ORDER_ID = "firebolt" // order string of ability "Dream Coil (Stun)"
private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map
private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type
private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type
endglobals
// area of effect
private constant function GetArea takes integer level returns real
return 375.
endfunction
// duration of coil
private constant function GetDuration takes integer level returns real
return 5.
endfunction
// initial damage dealt
private constant function GetInitialDamage takes integer level returns real
return 50. * level + 50.
endfunction
// initial stun duration
private constant function GetInitialDuration takes integer level returns real
return 0.5
endfunction
// distance in which the coil snaps
private constant function GetSnapArea takes integer level returns real
return 600.
endfunction
// break damage dealt
private constant function GetSnapDamage takes integer level returns real
return 50. * level + 50.
endfunction
// break stun duration
private constant function GetSnapDuration takes integer level returns real
return 0.75 * level + 0.75
endfunction
// target types allowed for dealing damage
private constant function GetFilter takes unit caster, unit target returns boolean
return /*
*/ not IsUnitType(target, UNIT_TYPE_DEAD) and /* // target is alive
*/ IsUnitEnemy(target, GetOwningPlayer(caster)) and /* // target is an enemy of caster
*/ not IsUnitType(target, UNIT_TYPE_STRUCTURE) and /* // target is not a structure
*/ not IsUnitType(target, UNIT_TYPE_MECHANICAL) // target is not mechanic
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
globals
private constant player NEUTRAL_PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
private constant real TRUE_RED = LIGHTNING_RED / 255
private constant real TRUE_GREEN = LIGHTNING_GREEN / 255
private constant real TRUE_BLUE = LIGHTNING_BLUE / 255
private constant real TRUE_TRANS = LIGHTNING_TRANS / 255
private group G = bj_lastCreatedGroup
endglobals
private struct Main extends array
private lightning l
private unit u
private unit target
private boolean b
private boolean check
private real dmg
private real dist
private real dur
private real stun
private real snapStun
private real x
private real y
private static unit castDummy
private static integer array store
private static constant real TIMEOUT = 0.031250000
implement CTTC
local real x
local real y
implement CTTCExpire
if IsUnitType(this.target, UNIT_TYPE_DEAD) or GetUnitTypeId(this.target) == 0 then
call DestroyLightning(this.l)
set this.l = null
call this.destroy()
else
if this.b then
if this.stun > 0 then
set this.stun = this.stun - TIMEOUT
if this.stun <= 0 then
call UnitRemoveAbility(this.target, BUFF_ID)
elseif GetUnitAbilityLevel(this.target, BUFF_ID) == 0 then
call IssueTargetOrder(thistype.castDummy, ORDER_ID, this.target)
endif
endif
set this.dur = this.dur - TIMEOUT
if this.dur <= 0 then
if this.check then
set this.check = false
call DestroyLightning(this.l)
set this.l = null
endif
if this.stun <= 0 then
call this.destroy()
endif
else
set x = GetUnitX(this.target)
set y = GetUnitY(this.target)
call MoveLightningEx(this.l, true, this.x, this.y, HEIGHT, x, y, GetUnitFlyHeight(this.target) + LIGHTNING_HEIGHT)
set x = x - this.x
set y = y - this.y
if x * x + y * y > this.dist then
set this.b = false
set thistype.store[GetUnitId(this.target)] = this
call DestroyLightning(this.l)
call UnitDamageTarget(this.u, this.target, this.dmg, true, false, ATK, DMG, null)
call IssueTargetOrder(thistype.castDummy, ORDER_ID, this.target)
set this.l = null
endif
endif
else
set this.snapStun = this.snapStun - TIMEOUT
if this.snapStun <= 0 then
call UnitRemoveAbility(this.target, BUFF_ID)
call this.destroy()
elseif GetUnitAbilityLevel(this.target, BUFF_ID) == 0 then
call IssueTargetOrder(thistype.castDummy, ORDER_ID, this.target)
endif
endif
endif
implement CTTCEnd
private static method onDeath takes nothing returns boolean
call RemoveUnit(GetTriggerUnit())
call DestroyTrigger(GetTriggeringTrigger())
return false
endmethod
private static method onCast takes nothing returns boolean
local thistype this
local trigger t = CreateTrigger()
local unit caster = GetTriggerUnit()
local unit u
local integer level = GetUnitAbilityLevel(caster, ABIL_ID)
local real area = GetArea(level)
local real dur = GetDuration(level)
local real dmg = GetInitialDamage(level)
local real stun = GetInitialDuration(level)
local real snapArea = GetSnapArea(level)
local real snapDmg = GetSnapDamage(level)
local real snapStun = GetSnapDuration(level)
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
set snapArea = snapArea * snapArea
set u = CreateUnit(NEUTRAL_PASSIVE, DUMMY_ID, x, y, 0)
call SetUnitVertexColor(u, RED, GREEN, BLUE, TRANS)
call SetUnitScale(u, SCALE, 0, 0)
call SetUnitFlyHeight(u, HEIGHT, 0)
call SetUnitAnimation(u, ANIM)
call UnitApplyTimedLife(u, 'BTLF', dur)
call TriggerRegisterUnitEvent(t, u, EVENT_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function thistype.onDeath))
call GroupEnumUnitsInRange(G, x, y, area + ENUM_RADIUS, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
call GroupRemoveUnit(G, u)
if GetFilter(caster, u) and IsUnitInRangeXY(u, x, y, area) then
set this = thistype.create()
set this.l = AddLightningEx(LIGHTNING, true, x, y, HEIGHT, GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u) + LIGHTNING_HEIGHT)
set this.u = caster
set this.target = u
set this.b = true
set this.check = true
set this.dmg = snapDmg
set this.dist = snapArea
set this.dur = dur
set this.stun = stun
set this.snapStun = snapStun
set this.x = x
set this.y = y
call SetLightningColor(this.l, TRUE_RED, TRUE_GREEN, TRUE_BLUE, TRUE_TRANS)
call UnitDamageTarget(caster, u, dmg, true, false, ATK, DMG, null)
call IssueTargetOrder(thistype.castDummy, ORDER_ID, u)
endif
endloop
set t = null
set caster = null
return false
endmethod
private static method onInit takes nothing returns nothing
set thistype.castDummy = CreateUnit(NEUTRAL_PASSIVE, CASTER_ID, 0, 0, 0)
call UnitAddAbility(thistype.castDummy, DUM_ABIL_ID)
call RegisterSpellEffectEvent(ABIL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Event
//2.0.0.1
/////////////////////////////////////////////////////////////////////////
//function CreateEvent takes nothing returns integer
//function TriggerRegisterEvent takes trigger t, integer ev returns nothing
//function RegisterEvent takes boolexpr c, integer ev returns nothing
//function FireEvent takes integer ev returns nothing
//struct Event extends array
//static method create takes nothing returns thistype
//method registerTrigger takes trigger t returns nothing
//method register takes boolexpr c returns nothing
//method fire takes nothing returns nothing
/////////////////////////////////////////////////////////////////////////
globals
private real q=0
endglobals
struct Event extends array
private static integer w=0
private static trigger array e
static method create takes nothing returns thistype
set w=w+1
set e[w]=CreateTrigger()
return w
endmethod
method registerTrigger takes trigger t returns nothing
call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)
endmethod
method register takes boolexpr c returns nothing
call TriggerAddCondition(e[this],c)
endmethod
method fire takes nothing returns nothing
set q=0
set q=this
call TriggerEvaluate(e[this])
endmethod
endstruct
function CreateEvent takes nothing returns Event
return Event.create()
endfunction
function TriggerRegisterEvent takes trigger t,Event ev returns nothing
call ev.registerTrigger(t)
endfunction
function RegisterEvent takes boolexpr c,Event ev returns nothing
call ev.register(c)
endfunction
function FireEvent takes Event ev returns nothing
call ev.fire()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/**************************************************************
*
* RegisterPlayerUnitEvent
* v4.1.0.0
* By Magtheridon96
*
* This library was made to replace that GTrigger
* monster by Jesus4Lyf at TheHelper. I would like
* to give a special thanks to Bribe and azlier for
* improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must
* return false. They can return nothing as well.
*
* API:
* ----
*
* function RegisterPlayerUnitEvent
* takes
* playerunitevent whichEvent : The event that will be registered.
* code whichFunction : The function that will fire when the event occurs.
* returns
* nothing
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
private boolexpr array b
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = 15
if null == t[i] then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen 0 == k
set k = k - 1
endloop
set b[i] = Filter(c)
else
call TriggerClearConditions(t[i])
set b[i] = Or(b[i], Filter(c))
endif
call TriggerAddCondition(t[i], b[i])
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//============================================================================
// SpellEffectEvent
// - Version 1.0.0.1
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, Table
globals
private Table tb
endglobals
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
if not tb.handle.has(abil) then
set tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(tb.trigger[abil], Filter(onCast))
endfunction
//============================================================================
private module M
static method onCast takes nothing returns boolean
return TriggerEvaluate(tb.trigger[GetSpellAbilityId()])
endmethod
private static method onInit takes nothing returns nothing
set tb = Table.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.0.1
One map, one hashtable. Welcome to NewTable 3.1
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key)
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb)
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=161
//TESH.alwaysfold=0
library Tt /* v2.1.6.0
*************************************************************************************
*
* Timer tools timers use a special merging algorithm. When two timers merge, they
* both expire on the same timer. The first tick accuracy is based on the size of the timer's timeout.
* The larger the timeout, the more inaccurate the first tick can be. The tick only becomes inaccurate
* if it merges with another timer.
*
* Max Timeout for CTM: 81.90
* Min Timeout for CTM: .01
*
* Specializes in repeating timers.
*
************************************************************************************
*
* SETTINGS
*/
/*
* Checks if any CTM modules appear to be constant
*/
static if DEBUG_MODE then
private struct DEBI extends array
static constant boolean SUGGEST_MODULE_CHANGES = true
endstruct
endif
globals
/*************************************************************************************
*
* RELATIVE_MERGE
*
* Effects the accuracy of first tick. The smaller the merge value, the less chance two
* timers have of sharing the same first tick, which leads to worse performance.
* However, a larger merge value decreases the accuracy of the first tick.
*
* Formula: Ln(RELATIVE_MERGE/timeout)/230.258509*3600*timeout
* Ln(64000/3600)/230.258509*3600=44.995589035797596625536391805959 seconds max off
*
*************************************************************************************/
private constant real RELATIVE_MERGE = 64000
/*************************************************************************************
*
* CONSTANT_MERGE
*
* Effects the accuracy of the first tick. This is a constant merge. If this value +.01 is
* greater than the value calculated from RELATIVE_MERGE, the timer auto merges.
*
* Constant merge must be greater than 0.
*
*************************************************************************************/
private constant real CONSTANT_MERGE = .1
endglobals
/*
************************************************************************************
*
* Functions
*
* function GetExpired takes nothing returns integer
* - Gets the expiring timer. This is not the expiring timer method instance! This is read
* - inside of GetTimerFirstInstance, which is why timer instances can only be retrieved inside of
* - an expiring timer method.
* -
* - Boolean expressions on the same timer will expire for that same timer. Use timer methods instead.
*
* function TimerMethodAddInstance takes TimerList list, integer timerMethod returns integer
* - Adds a new instance to a timer list. These must be looped through inside of the boolean expression method.
* - Returns a timer instance.
* function TimerMethodRemoveInstance takes integer timerInstance returns nothing
* - Removes an instance from a timer method. Timer method is destroyed after it is done expiring when no instances
* - are left.
* function CreateTimerMethod takes boolexpr method returns integer
* - Creates a new timer method from a boolean expression. This boolean expression is run whenever the timer
* - expires.
*
* function TimerGetElapsedEx takes integer timerInstance returns real
* function TimerGetRemainingEx takes integer timerInstance returns real
* function TimerGetTimeoutEx takes integer timerInstance returns real
*
* function GetTimerFirstInstance takes integer timerMethod returns integer
* - Gets first timer instance in a timer method. Can only be called within an expiring timer method.
* function GetTimerNext takes integer timerInstance returns integer
* - Gets next timer instance given a timer instance.
* - Sentinel is 0.
*
* function GetTimerFirst takes nothing returns integer
* - Can only be called right after adding a new instance to a timer method
* - Useful for storing first into an array
* function GetTimerFutureFirst takes nothing returns integer
* - Can only be called right after adding a new instance to a timer method
* - Useful for storing future first into an array so that the first
* - can be updated after the timer expires.
* function GetTimerParent takes nothing returns integer
* - Retrieves parent of newly added instance
* - Can only be used directly after adding instance
*
* - set first[GetTimerParent()] = GetTimerFirst()
* - set futureFirst[GetTimerParent()] = GetTimerFutureFirst()
*
* function TimerMethodAddInstanceC takes TimerList list, integer timerMethod returns integer
* - Adds a new instance to a timer method on a constant merging timer list.
* function TimerMethodRemoveInstanceC takes integer timerInstance returns nothing
* - Removes an instance from a timer method on a constant merging timer list.
*
* function GetTimerFirstC takes integer timerMethod returns integer
* - Retrieves the first node given a timer method on a constant merging timer list. Can be called at any point.
*
* set this = GetTimerFirstC(myTimerMethod)
* loop
* exitwhen 0 == this
* set this = GetTimerNext(this)
* endloop
*
************************************************************************************
*
* struct TimerList extends array
*
* method register takes boolexpr b returns integer
* - Registers a boolean expression to timer
* method unregister takes integer i returns nothing
* - Unregisters boolean expression from timer
* - Timer is automatically destroyed if no boolean expressions are left
*
************************************************************************************
*
* struct Timer extends array
* static method operator [] takes real timeout returns thistype
* - Converts a timeout to a timer group
* method operator list takes nothing returns TimerList
* - Creates a new timer in the timer group if there are no viable currently
* - existing timers. Will return an existing timer if that timer either expires soon enough
* - or has enough time left to be close enough to the timeout.
*
************************************************************************************
*
* Modules
*
* module CTM (optional)
* locals
* module CTMExpire (not optional)
* expiration code
* module CTMNull (optional)
* null locals
* module CTMEnd (not optional)
* static method create takes real timeout returns thistype
* method destroy takes nothing returns nothing
* method operator elapsed takes nothing returns real
* method operator remaining takes nothing returns real
* method operator timeout takes nothing returns real
*
* Method: Constant
* Timeout: Not Constant
* Timeout List: Not Constant
*
* module CTT (optional)
* locals
* module CTTExpire (not optional)
* expiration code
* module CTTNull (optional)
* null locals
* module CTTEnd (not optional)
* static method create takes nothing returns thistype
* method destroy takes nothing returns nothing
* method operator elapsed takes nothing returns real
* method operator remaining takes nothing returns real
* method operator timeout takes nothing returns real
*
* Requires: private static constant real TIMEOUT
*
* Method: Constant
* Timeout: Constant
* Timeout List: Not Constant
*
* module CTTC (optional)
* locals
* module CTTCExpire (not optional)
* expiration code
* module CTTCNull (optional)
* null locals
* module CTTCEnd (not optional)
* static method create takes nothing returns thistype
* method destroy takes nothing returns nothing
* method operator elapsed takes nothing returns real
* method operator remaining takes nothing returns real
* method operator timeout takes nothing returns real
*
* Requires: private static constant real TIMEOUT that will be constant merge
*
* Method: Constant
* Timeout: Constant
* Timeout List: Constant
*
************************************************************************************/
globals
//list
private integer array lf //timeout first node
private integer array ln //node next
private integer array lp //node previous
private integer array lr //node recycler
private integer lc = 0 //node instance count
private timer array tm //node timer
//nodes
private trigger array nt //node trigger
private integer array nc //node instance count
private integer array nh //node head (timeout*100)
private boolean array aa //node set to add after
private boolean array nr //node running
//trigger condition instancing
private integer ntcc = 0 //instance count
private integer array ntcr //recycler
private triggercondition array ntc //condition
private boolean array nprm //not permanent
//trigger condition add after
private integer array paf //first
private integer array pan //next
private integer array pap //prev
private boolexpr array pab //set to add after
//trigger condition destroy after
private integer array ds //to destroy
private integer dsc = 0 //destroy count
//expiring timer
private integer exp = 0
//module
//timer method instancing, stores boolean expressions
//timer method can't be destroyed
private integer mtfr = 0 //instance count
private boolexpr array mb //boolexpr
private integer mnf = 0 //module node first return on add
private integer mnft = 0 //module node future first return on add
private integer mnp = 0 //module node parent
//first[mnp] = mnf
//futureFirst[mnp] = mnft
//list
private hashtable mlt = InitHashtable() //stores firsts and counts
//instance count: + +
//method first: - -
//method future first: - +
//registered method instance: + -
//actual expiring nodes
private integer array mln //expiration next
private integer array mlp //expiration previous
//instantly updated list
private integer array mlnd //expiration next true
private integer array mlpd //expiration prev true
//add instances after expiration
private integer array mlnp //previous
private integer array mlpp //next
private boolean array mlap //is set to add after
private integer array mlfp //first to add after
//recycler
private integer array mlr //module node recycler
private integer mlc = 0 //module node instance count
//nodes
private integer array mnh //module node head (head is timeout node)
private integer array mno //module node origin (origin is timer method instance, boolexpr)
//destroy after
private integer array mds //node to destroy
private integer mdsc = 0 //node to destroy count
private boolean array mdb //is node marked to destroy
private integer array mpf //module perm first
private integer array mpff //module perm future first
private integer array mptc //module perm tc
private boolean array mp //module perm
endglobals
//hiveworkshop.com/forums/jass-functions-413/snippet-natural-logarithm-108059/
//credits to BlinkBoy
private function Ln takes real a returns real
local real s=0
loop
exitwhen a<2.71828
set a=a/2.71828
set s=s+1
endloop
return s+(a-1)*(1+8/(1+a)+1/a)/6
endfunction
static if DEBUG_MODE then
private struct DEB extends array
static boolean array al //is timeout node allocated
static boolean array alm //is module node allocated
static boolean en = true //is system enabled
static timer array tm2 //timer to verify paused/started timers don't freak out
endstruct
/*
* Disable System
*/
private function DIS takes nothing returns nothing
set DEB.en = false
//pause all running timers
loop
exitwhen 0 == lc
call PauseTimer(tm[lc])
debug call PauseTimer(DEB.tm2[lc])
set lc = lc - 1
endloop
endfunction
private function CMQ takes real a returns boolean
local real m = Ln(RELATIVE_MERGE/a)/230.258509*a
if (m < CONSTANT_MERGE) then
set m = CONSTANT_MERGE
endif
return CONSTANT_MERGE >= (a-m)/2
endfunction
endif
/*
* Allocate Timeout Node
*/
private function AL takes nothing returns integer
//standard allocation
local integer i = lr[0]
if (0 == i) then
set lc = lc + 1
debug if (8191 < lc) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"INSTANE OVERLOAD")
debug call DIS()
debug endif
debug set DEB.al[lc] = true
set tm[lc] = CreateTimer()
set nt[lc] = CreateTrigger()
return lc
endif
set lr[0] = lr[i]
debug set DEB.al[i] = true
return i
endfunction
function GetExpired takes nothing returns integer
return exp
endfunction
/*
* Delete Module Node
*/
private function DELM takes integer i returns nothing
debug if (DEB.en) then
debug if (DEB.alm[i]) then
set mlr[i] = mlr[0]
set mlr[0] = i
debug set DEB.alm[i] = false
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DOUBLE FREE: "+I2S(i))
debug call DIS()
debug endif
debug endif
endfunction
//! textmacro TIMER_TOOLS_ADD_NODE takes D
debug if (DEB.en) then
debug if (DEB.alm[i]) then
set mln$D$[i] = 0
if (0 == mlp$D$[t]) then
set mlp$D$[i] = t
set mln$D$[t] = i
else
set mlp$D$[i] = mlp$D$[t]
set mln$D$[mlp$D$[i]] = i
endif
set mlp$D$[t] = i
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"ATTEMPTED TO ADD NULL NODE: "+I2S(i)+" on "+I2S(mnh[i]))
debug call DIS()
debug endif
debug endif
//! endtextmacro
/*
* Add Module Node
*/
private function ADDM takes integer i, integer t returns nothing
//! runtextmacro TIMER_TOOLS_ADD_NODE("")
endfunction
/*
* Add Module Node To Instant Update True List
*/
private function ADDMD takes integer i, integer t returns nothing
//! runtextmacro TIMER_TOOLS_ADD_NODE("d")
endfunction
/*
* Add Module Node To Add After
*/
private function ADDMP takes integer i, integer t returns nothing
//! runtextmacro TIMER_TOOLS_ADD_NODE("p")
endfunction
//! textmacro TIMER_TOOLS_REMOVE_NODE takes D
debug if (DEB.en) then
debug if (DEB.alm[i]) then
if (0 != f) then
if (0 == mln$D$[i]) then
set mlp$D$[f] = mlp$D$[i]
else
set mlp$D$[mln$D$[i]] = mlp$D$[i]
endif
set mln$D$[mlp$D$[i]] = mln$D$[i]
if (f == mln$D$[f]) then
set mln$D$[f] = 0
set mlp$D$[f] = 0
else
set mln$D$[mlp$D$[f]] = 0
endif
endif
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"ATTEMPTED TO REMOVE NULL NODE: "+I2S(i)+" on "+I2S(mnh[i]))
debug call DIS()
debug endif
debug endif
//! endtextmacro
/*
* Remove Module Node
*/
private function REMM takes integer i, integer f returns nothing
//! runtextmacro TIMER_TOOLS_REMOVE_NODE("")
endfunction
/*
* Remove Module Node From Instant Update True List
*/
private function REMMD takes integer i, integer f returns nothing
//! runtextmacro TIMER_TOOLS_REMOVE_NODE("d")
endfunction
/*
* Remove Module Node From Add After List
*/
private function REMMP takes integer i, integer f returns nothing
//! runtextmacro TIMER_TOOLS_REMOVE_NODE("p")
endfunction
/*
* Add Module Node To Destroy After Stack
*/
private function DAF takes integer i returns nothing
debug if (DEB.en) then
debug if (not mdb[i]) then
set mdb[i] = true
set mds[mdsc] = i
set mdsc = mdsc + 1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DOUBLE FREE ATTEMPT: "+I2S(i))
debug call DIS()
debug endif
debug endif
endfunction
/*
* On Expiration
*/
private function EXP takes nothing returns nothing
//retrieve timeout instance
local integer e = R2I(TimerGetTimeout(GetExpiredTimer())*100)
local integer i = e
//retrieve first node on timeout
local integer n = lf[i]
local integer t
local integer f
//set first = first.next
set lf[i] = ln[n]
debug if (DEB.en) then
debug if (not DEB.al[n]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG NODE: "+I2S(n))
debug call DIS()
debug return
debug endif
debug if (0 != TimerGetRemaining(DEB.tm2[n])) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG TIMEOUT NODE: "+I2S(n)+" "+R2S(TimerGetRemaining(DEB.tm2[n])))
debug call DIS()
debug return
debug endif
set nr[n] = true //node running = true
set exp = n //expiring = node
call TriggerEvaluate(nt[n]) //evaluate all registered methods
set exp = 0 //expiring = 0
set nr[n] = false //node running = false
//add all to add after to node
set i = paf[n]
set paf[n] = 0
loop
exitwhen 0 == i
set ntc[i] = TriggerAddCondition(nt[n], pab[i])
set pab[i] = null
set ntcr[i] = ntcr[0]
set ntcr[0] = i
set i = pan[i]
endloop
//add all to add after to modules
set i = mlfp[n]
set mlfp[n] = 0
loop
exitwhen 0 == i
if (mp[i]) then
set t = mpf[mno[i]]
else
set t = LoadInteger(mlt, -mno[i], -mnh[i]) //mlf
endif
call ADDM(i, t)
set i = mlnp[i]
endloop
//destroy all to destroy after from node
set i = dsc
loop
exitwhen 0 == i
set i = i - 1
call TriggerRemoveCondition(nt[n], ntc[ds[i]])
set ntc[ds[i]] = null
endloop
set dsc = 0
//destroy all to destroy after from modules
set t = mdsc
loop
exitwhen 0 == t
set t = t - 1
set i = mds[t]
set mdb[i] = false
if (mp[i]) then
set f = mpf[mno[i]]
if (f == i) then
set f = mpff[mno[i]]
if (f == i) then
set f = 0
endif
set mpf[mno[i]] = f
endif
else
set f = LoadInteger(mlt, -mno[i], -mnh[i]) //mlf
if (f == i) then
set f = LoadInteger(mlt, -mno[i], mnh[i]) //mlf2
if (f == i) then
set f = 0
endif
call SaveInteger(mlt, -mno[i], -mnh[i], f) //mlf
endif
endif
call REMM(i, f)
call DELM(i)
set mlap[i] = false
endloop
set mdsc = 0
//if no methods are left on the node, destroy the node
if (0 == nc[n]) then
//handle timer
call PauseTimer(tm[n])
debug call PauseTimer(DEB.tm2[n])
if (nprm[e]) then
debug call DestroyTimer(DEB.tm2[n])
debug set DEB.tm2[n] = null
//remove from timeout list
if (lf[nh[n]] == n) then
set lf[nh[n]] = ln[n]
endif
set ln[lp[n]] = ln[n]
set lp[ln[n]] = lp[n]
if (ln[n] == n) then
set lf[nh[n]] = 0
endif
//recycler
set lr[n] = lr[0]
set lr[0] = n
endif
debug set DEB.al[n] = false
endif
debug endif
endfunction
struct TimerList extends array
method register takes boolexpr b returns integer
local integer h = nh[this]
//allocate new trigger condition
local integer i = ntcr[0]
if (0 == i) then
set i = ntcc + 1
set ntcc = i
else
set ntcr[0] = ntcr[i]
endif
if (0 == nc[this] and not nprm[h]) then
call TimerStart(tm[this], h/100., true, function EXP)
debug call TimerStart(DEB.tm2[this], h/100., true, null)
set ntc[i] = TriggerAddCondition(nt[this], b)
debug set DEB.al[this] = true
//if to add after (to add after is marked when TimerList is retrieved)
//only store TimerList for perm
elseif ((not nprm[h] and nr[this]) or (nprm[h] and aa[this])) then
//add it to add after list
if (0 == paf[this]) then
set paf[this] = i
set pan[i] = 0
set pap[i] = i
else
set pan[i] = 0
set pap[i] = pap[paf[this]]
set pan[pap[i]] = i
set pap[paf[this]] = i
endif
set pab[i] = b
else
//register condition
set ntc[i] = TriggerAddCondition(nt[this], b)
endif
//increase node count
set nc[this] = nc[this] + 1
return i
endmethod
method unregister takes integer i returns nothing
local integer h = nh[this]
//if the node has not been set to be added after
if (null == pab[i]) then
//if node running, add to destroy after stack
if (nr[this]) then
set ds[dsc] = i
set dsc = dsc + 1
else
//remove instantly
call TriggerRemoveCondition(nt[this], ntc[i])
set ntc[i] = null
endif
else
//remove from to add after list
if (paf[this] == i) then
set paf[this] = pan[i]
endif
if (0 == pan[i]) then
set pap[paf[this]] = pap[i]
else
set pap[pan[i]] = pap[i]
endif
if (0 == pap[i]) then
set pan[paf[this]] = pan[i]
else
set pan[pap[i]] = pan[i]
endif
//mark as not to add after
set pab[i] = null
//recycler
set ntcr[i] = ntcr[0]
set ntcr[0] = i
endif
//if the node isn't running, do instant update
set nc[this] = nc[this] - 1
//destroy node
if (not nr[this] and 0 == nc[this]) then
//handle timer
call PauseTimer(tm[this])
if (nprm[h]) then
debug call PauseTimer(DEB.tm2[this])
debug call DestroyTimer(DEB.tm2[this])
debug set DEB.tm2[this] = null
//remove node from timeout list
if (lf[nh[this]] == this) then
set lf[nh[this]] = ln[this]
endif
set ln[lp[this]] = ln[this]
set lp[ln[this]] = lp[this]
if (ln[this] == this) then
set lf[nh[this]] = 0
endif
//recycler
set lr[this] = lr[0]
set lr[0] = this
debug set DEB.al[this] = false
endif
endif
endmethod
endstruct
struct Timer extends array
static method operator [] takes real timeout returns thistype
local integer i = R2I(timeout*100)
if (0 == i) then
return 1
elseif (8191 < i) then
return 8191
endif
return i
endmethod
method operator list takes nothing returns TimerList
local integer t = lf[this] //first timeout node
local integer l
local real tl
local real a //timeout
local integer n
//if no first timeout node
if (0 == t) then
set a = this/100.
//allocate
set t = AL()
debug set DEB.tm2[this] = CreateTimer()
//initialize list
set lf[this] = t
set lp[t] = t
set ln[t] = t
if (not nprm[this]) then
set tl = Ln(RELATIVE_MERGE/a)/230.258509*a
if (tl < CONSTANT_MERGE) then
set tl = CONSTANT_MERGE
endif
set nprm[this] = CONSTANT_MERGE < (a-tl)/2
endif
if (nprm[this]) then
debug if (DEB.en) then
//start timer
call TimerStart(tm[t], a, true, function EXP)
debug call TimerStart(DEB.tm2[t], a, true, null)
debug endif
endif
//head is always timeout for a timeout node
set nh[t] = this
//not adding after (added now)
set aa[t] = false
return t
endif
if (nprm[this]) then
set a = this/100.
//calculate relative timeout limit
set tl = Ln(RELATIVE_MERGE/a)/230.258509*a
//if the relative limit is less than the constant limit
//make it the constant limit
if (tl < CONSTANT_MERGE) then
set tl = CONSTANT_MERGE
endif
set l = lp[t]
if (TimerGetElapsed(tm[t]) < tl) then
//merge first node before
set aa[t] = false
return t
elseif (TimerGetRemaining(tm[l]) < tl) then
//merge last node after
set aa[l] = true
return l
elseif (TimerGetElapsed(tm[l]) < tl) then
//merge last node before
set aa[l] = false
return l
endif
//create new node
set n = AL()
debug if (DEB.en) then
call TimerStart(tm[n], a, true, function EXP)
debug set DEB.tm2[n] = CreateTimer()
debug call TimerStart(DEB.tm2[n], a, true, null)
debug endif
//add to list
set ln[l] = n
set lp[t] = n
set ln[n] = t
set lp[n] = l
set nh[n] = this
//add immediately
set aa[n] = false
return n
endif
return t
endmethod
endstruct
/*
* Allocate module node
*/
private function ALM takes nothing returns integer
local integer i = mlr[0]
debug if (DEB.alm[i]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DOUBLE ALLOCATE: "+I2S(i))
debug call DIS()
debug return 0
debug endif
if (0 == i) then
set mlc = mlc + 1
debug if (8191 < mlc) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"INSTANCE OVERLOAD")
debug call DIS()
debug endif
debug set DEB.alm[mlc] = true
return mlc
endif
set mlr[0] = mlr[i]
set mp[i] = false
debug set DEB.alm[i] = true
return i
endfunction
private function RegisterMethod takes integer this, integer t, integer i, boolean after returns nothing
//this: timeout head
//t: node timeout head
//i: module node
//always add to true list for an instant update
call ADDMD(i, t)
//if not adding after, can add to actual list as well
if (not after) then
call ADDM(i, t)
else
//add to add after list
set t = mlfp[this]
if (0 == t) then
set mlfp[this] = i
set mlnp[i] = 0
set mlpp[i] = 0
else
call ADDMP(i, t)
endif
endif
//only called when a timer method is initialized (no first)
endfunction
function TimerMethodAddInstance takes TimerList this, integer o returns integer
local integer t = LoadInteger(mlt, -o, this) //mlf2
local integer n
//return head (timeout)
set mnp = this
//if no first, initialize
if (0 == t) then
set t = ALM()
call SaveInteger(mlt, -o, -this, t) //mlf, first
call SaveInteger(mlt, -o, this, t) //mlf2, future first
call SaveInteger(mlt, o, -this, this.register(mb[o])) //mnt, condition
//initialize lists
set mlp[t] = 0
set mln[t] = 0
set mlpd[t] = 0
set mlnd[t] = 0
//head, origin (o = timer method)
set mnh[t] = this
set mno[t] = o
//first, future first
set mnf = t
set mnft = t
return t
endif
//first and future first will always be t as n is always added to t
set mnf = t
set mnft = t
set n = ALM()
//head is timeout, o is method
set mnh[n] = this
set mno[n] = o
//add n to t
call RegisterMethod(this, t, n, aa[this])
return n
endfunction
function TimerMethodRemoveInstance takes integer i returns nothing
local TimerList this = mnh[i] //timeout
local integer o = mno[i] //method
local integer f = LoadInteger(mlt, -o, this) //mlf2
debug if (not DEB.alm[i]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Attempted To Deallocate Null: "+I2S(i))
debug call DIS()
debug return
debug endif
//update future*** first
if (f == i) then
set f = mlnd[i]
if (0 == f) then
call this.unregister(LoadInteger(mlt, o, -this))
endif
call SaveInteger(mlt, -o, this, f) //mlf2
endif
set mnft = f
//remove from true list
call REMMD(i, f)
//if set to add after, remove from add after list, first does not change
if (mlap[i]) then
set mnf = LoadInteger(mlt, -o, -this) //mlf, first
//remove from to add after list
call REMMP(i, mlfp[this])
//set to add after to false
set mlap[i] = false
//delete
call DELM(i)
else
//if node is running, mark to destroy after
if (nr[this]) then
call DAF(i)
//first doesn't change
set mnf = LoadInteger(mlt, -o, -this) //mlf
else
//first can** change
set f = LoadInteger(mlt, -o, -this) //mlf
//if deallocated node is first, set first to next
if (f == i) then
set f = mln[i]
endif
//remove from list
call REMM(i, f)
//delete
call DELM(i)
//update first
call SaveInteger(mlt, -o, -this, f) //mlf
//return possibly new first
set mnf = f
endif
endif
endfunction
function TimerMethodAddInstanceC takes TimerList this, integer o returns integer
local integer t = mpff[o]
local integer n
debug if (nprm[nh[this]]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"ATTEMPTED TO USE CONSTANT MERGE FOR NON CONSTANT MERGE TIMEOUT")
debug call DIS()
debug endif
//if no first, initialize
if (0 == t) then
set t = ALM()
set mp[t] = true
set mpf[o] = t
set mpff[o] = t
set mptc[o] = this.register(mb[o])
//initialize lists
set mlp[t] = 0
set mln[t] = 0
set mlpd[t] = 0
set mlnd[t] = 0
//head, origin (o = timer method)
set mnh[t] = this
set mno[t] = o
return t
endif
set n = ALM()
set mp[n] = true
//head is timeout, o is method
set mnh[n] = this
set mno[n] = o
//add n to t
call RegisterMethod(this, t, n, aa[this])
return n
endfunction
function TimerMethodRemoveInstanceC takes integer i returns nothing
local TimerList this = mnh[i] //timeout
local integer o = mno[i] //method
local integer f = mpff[o]
debug if (nprm[nh[this]]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"ATTEMPTED TO USE CONSTANT MERGE FOR NON CONSTANT MERGE TIMEOUT")
debug call DIS()
debug endif
debug if (not DEB.alm[i]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Attempted To Deallocate Null: "+I2S(i))
debug call DIS()
debug return
debug endif
//update future*** first
if (f == i) then
set f = mlnd[i]
if (0 == f) then
call this.unregister(mptc[o])
endif
set mpff[o] = f
endif
//remove from true list
call REMMD(i, f)
//if set to add after, remove from add after list, first does not change
if (mlap[i]) then
//remove from to add after list
call REMMP(i, mlfp[this])
//set to add after to false
set mlap[i] = false
//delete
call DELM(i)
else
//if node is running, mark to destroy after
if (nr[this]) then
call DAF(i)
else
//first can** change
set f = mpf[o]
//if deallocated node is first, set first to next
if (f == i) then
set f = mln[i]
endif
//remove from list
call REMM(i, f)
//delete
call DELM(i)
//update first
set mpf[o] = f
endif
endif
endfunction
function CreateTimerMethod takes boolexpr b returns integer
//allocate new timer method (simple)
set mtfr = mtfr + 1
set mb[mtfr] = b
return mtfr
endfunction
function TimerGetElapsedEx takes integer i returns real
return TimerGetElapsed(tm[mnh[i]])
endfunction
function TimerGetRemainingEx takes integer i returns real
return TimerGetRemaining(tm[mnh[i]])
endfunction
function TimerGetTimeoutEx takes integer i returns real
return TimerGetTimeout(tm[mnh[i]])
endfunction
function GetTimerFirstInstance takes integer timerMethod returns integer
return LoadInteger(mlt, -timerMethod, -exp) //mlf
endfunction
function GetTimerNext takes integer timerInstance returns integer
return mln[timerInstance]
endfunction
function GetTimerFirst takes nothing returns integer
return mnf
endfunction
function GetTimerFutureFirst takes nothing returns integer
return mnft
endfunction
function GetTimerParent takes nothing returns integer
return mnp
endfunction
function GetTimerFirstC takes integer o returns integer
return mpf[o]
endfunction
module CTM
debug private static integer created = 0
debug private static boolean array timerH
debug private static integer timerCount = 0
static integer CTMf //timer method
static integer array CTMq //current first
static integer array CTMqt //future first
static method create takes real t returns thistype
local integer i
local integer n
debug if (DEB.en) then
//get new instance
set i = TimerMethodAddInstance(Timer[t].list, CTMf)
debug if (DEBI.SUGGEST_MODULE_CHANGES) then
debug set created = created + 1
debug if (not timerH[Timer[t]]) then
debug set timerH[Timer[t]] = true
debug set timerCount = timerCount + 1
debug endif
debug if (created > 30 and timerCount == 1) then
debug if (CMQ(t)) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"IT APPEARS THAT THIS MODULE IS A CONSTANT MERGE TIMEOUT, TRY USING CTTC INSTEAD OF CTM: "+R2S(t))
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"IT APPEARS THAT THIS MODULE IS A CONSTANT TIMEOUT, TRY USING CTT INSTEAD OF CTM: "+R2S(t))
debug endif
debug call DIS()
debug endif
debug endif
//update firsts
set CTMq[mnp] = mnf
set CTMqt[mnp] = mnft
debug if (mnf != LoadInteger(mlt, -CTMf, -mnh[i])) then //mlf
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"CREATE FIRST DESYNC: "+I2S(mnf)+"!="+I2S(LoadInteger(mlt, -CTMf, -mnh[i]))) //mlf
debug call DIS()
debug endif
debug if (mnft != LoadInteger(mlt, -CTMf, mnh[i])) then //mlf2
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"CREATE FIRST DESYNC TEMP: "+I2S(mnft)+"!="+I2S(LoadInteger(mlt, -CTMf, mnh[i]))) //mlf2
debug call DIS()
debug endif
return i
debug endif
debug return 0
endmethod
method destroy takes nothing returns nothing
local integer n
debug if (DEB.en) then
//destroy
call TimerMethodRemoveInstance(this)
//update firsts
set CTMq[mnh[this]] = mnf
set CTMqt[mnh[this]] = mnft
debug if (mnf != LoadInteger(mlt, -CTMf, -mnh[this])) then //mlf
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DESTROY FIRST DESYNC: "+I2S(mnf)+"!="+I2S(LoadInteger(mlt, -CTMf, -mnh[this]))) //mlf
debug call DIS()
debug endif
debug if (mnft != LoadInteger(mlt, -CTMf, mnh[this])) then //mlf2
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DESTROY FIRST DESYNC TEMP: "+I2S(mnft)+"!="+I2S(LoadInteger(mlt, -CTMf, mnh[this]))) //mlf2
debug call DIS()
debug endif
debug endif
endmethod
method operator elapsed takes nothing returns real
return TimerGetElapsedEx(this)
endmethod
method operator remaining takes nothing returns real
return TimerGetRemainingEx(this)
endmethod
method operator timeout takes nothing returns real
return TimerGetTimeoutEx(this)
endmethod
static method CTMe takes nothing returns boolean
//get first
local thistype this = CTMq[exp]
debug local boolean array hit
endmodule
module CTMExpire
implement CTM
debug if (not DEB.en) then
debug return false
debug endif
debug if (CTMq[exp] != LoadInteger(mlt, -CTMf, -exp)) then //mlf
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG FIRST DESYNC: "+I2S(CTMq[exp])+"!="+I2S(LoadInteger(mlt, -CTMf, -exp))+" from "+I2S(exp)) //mlf
debug call DIS()
debug return false
debug endif
debug if (CTMqt[exp] != LoadInteger(mlt, -CTMf, exp)) then //mlf2
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG FIRST DESYNC TEMP: "+I2S(CTMqt[exp])+"!="+I2S(LoadInteger(mlt, -CTMf, exp))+" from "+I2S(exp)) //mlf2
debug call DIS()
debug return false
debug endif
debug if (0 == this) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"NULL TIMER EXPIRED ON "+I2S(exp))
debug call DIS()
debug endif
//loop through all instances
loop
exitwhen 0 == this
debug if (hit[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG: HIT "+I2S(this)+" MORE THAN ONCE FROM "+I2S(exp))
debug call DIS()
debug return false
debug endif
debug set hit[this] = true
endmodule
module CTMNull
debug if (mnh[this] != exp) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG: "+I2S(this)+" "+I2S(mnh[this])+"!="+I2S(exp)+" from "+I2S(exp))
debug call DIS()
debug return false
debug endif
debug if (not DEB.alm[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG NOT ALLOCATED: "+I2S(this)+" from "+I2S(exp))
debug call DIS()
debug return false
debug endif
set this = mln[this]
endloop
//update first to future first
set CTMq[exp] = CTMqt[exp]
endmodule
module CTMEnd
implement CTMNull
return false
endmethod
private static method onInit takes nothing returns nothing
//initialize timer method
set CTMf = CreateTimerMethod(Condition(function thistype.CTMe))
endmethod
endmodule
module CTT
static Timer CTMt //timout
static integer CTMf //timer method
static integer array CTMq //current first
static integer array CTMqt //future first
static method create takes nothing returns thistype
local integer i
local integer n
debug if (DEB.en) then
//get new instance
set i = TimerMethodAddInstance(CTMt.list, CTMf)
//update firsts
set CTMq[mnp] = mnf
set CTMqt[mnp] = mnft
debug if (mnf != LoadInteger(mlt, -CTMf, -mnh[i])) then //mlf
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"CREATE FIRST DESYNC: "+I2S(mnf)+"!="+I2S(LoadInteger(mlt, -CTMf, -mnh[i]))) //mlf
debug call DIS()
debug endif
debug if (mnft != LoadInteger(mlt, -CTMf, mnh[i])) then //mlf2
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"CREATE FIRST DESYNC TEMP: "+I2S(mnft)+"!="+I2S(LoadInteger(mlt, -CTMf, mnh[i]))) //mlf2
debug call DIS()
debug endif
return i
debug endif
debug return 0
endmethod
method destroy takes nothing returns nothing
local integer n
debug if (DEB.en) then
//destroy
call TimerMethodRemoveInstance(this)
//update firsts
set CTMq[mnh[this]] = mnf
set CTMqt[mnh[this]] = mnft
debug if (mnf != LoadInteger(mlt, -CTMf, -mnh[this])) then //mlf
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DESTROY FIRST DESYNC: "+I2S(mnf)+"!="+I2S(LoadInteger(mlt, -CTMf, -mnh[this]))) //mlf
debug call DIS()
debug endif
debug if (mnft != LoadInteger(mlt, -CTMf, mnh[this])) then //mlf2
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DESTROY FIRST DESYNC TEMP: "+I2S(mnft)+"!="+I2S(LoadInteger(mlt, -CTMf, mnh[this]))) //mlf2
debug call DIS()
debug endif
debug endif
endmethod
method operator elapsed takes nothing returns real
return TimerGetElapsedEx(this)
endmethod
method operator remaining takes nothing returns real
return TimerGetRemainingEx(this)
endmethod
method operator timeout takes nothing returns real
return TIMEOUT
endmethod
static method CTMe takes nothing returns boolean
//get first
local thistype this = CTMq[exp]
debug local boolean array hit
endmodule
module CTTExpire
implement CTT
debug if (not DEB.en) then
debug return false
debug endif
debug if (CTMq[exp] != LoadInteger(mlt, -CTMf, -exp)) then //mlf
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG FIRST DESYNC: "+I2S(CTMq[exp])+"!="+I2S(LoadInteger(mlt, -CTMf, -exp))+" from "+I2S(exp)) //mlf
debug call DIS()
debug return false
debug endif
debug if (CTMqt[exp] != LoadInteger(mlt, -CTMf, exp)) then //mlf2
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG FIRST DESYNC TEMP: "+I2S(CTMqt[exp])+"!="+I2S(LoadInteger(mlt, -CTMf, exp))+" from "+I2S(exp)) //mlf2
debug call DIS()
debug return false
debug endif
debug if (0 == this) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"NULL TIMER EXPIRED ON "+I2S(exp))
debug call DIS()
debug endif
//loop through all instances
loop
exitwhen 0 == this
debug if (hit[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG: HIT "+I2S(this)+" MORE THAN ONCE FROM "+I2S(exp))
debug call DIS()
debug return false
debug endif
debug set hit[this] = true
endmodule
module CTTNull
debug if (mnh[this] != exp) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG: "+I2S(this)+" "+I2S(mnh[this])+"!="+I2S(exp)+" from "+I2S(exp))
debug call DIS()
debug return false
debug endif
debug if (not DEB.alm[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG NOT ALLOCATED: "+I2S(this)+" from "+I2S(exp))
debug call DIS()
debug return false
debug endif
set this = mln[this]
endloop
//update first to future first
set CTMq[exp] = CTMqt[exp]
endmodule
module CTTEnd
implement CTTNull
return false
endmethod
private static method onInit takes nothing returns nothing
//initialize timer method
set CTMf = CreateTimerMethod(Condition(function thistype.CTMe))
set CTMt = Timer[TIMEOUT]
debug if (CMQ(TIMEOUT)) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"THIS MODULE SHOULD BE CTTC AS TIMEOUT QUALIFIES FOR CONSTANT MERGE: "+R2S(TIMEOUT))
debug call DIS()
debug endif
endmethod
endmodule
module CTTC
static TimerList CTMt //timout list
static integer CTMf //timer method
static method create takes nothing returns thistype
local integer i
local integer n
debug if (DEB.en) then
//get new instance
set i = TimerMethodAddInstanceC(CTMt, CTMf)
return i
debug endif
debug return 0
endmethod
method destroy takes nothing returns nothing
local integer n
debug if (DEB.en) then
//destroy
call TimerMethodRemoveInstanceC(this)
debug endif
endmethod
method operator elapsed takes nothing returns real
return TimerGetElapsedEx(this)
endmethod
method operator remaining takes nothing returns real
return TimerGetRemainingEx(this)
endmethod
method operator timeout takes nothing returns real
return TIMEOUT
endmethod
static method CTMe takes nothing returns boolean
//get first
local thistype this = mpf[CTMf]
debug local boolean array hit
endmodule
module CTTCExpire
implement CTTC
debug if (not DEB.en) then
debug return false
debug endif
debug if (0 == this) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"NULL TIMER EXPIRED ON "+I2S(exp))
debug call DIS()
debug endif
//loop through all instances
loop
exitwhen 0 == this
debug if (hit[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG: HIT "+I2S(this)+" MORE THAN ONCE FROM "+I2S(exp))
debug call DIS()
debug return false
debug endif
debug set hit[this] = true
endmodule
module CTTCNull
debug if (mnh[this] != exp) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG: "+I2S(this)+" "+I2S(mnh[this])+"!="+I2S(exp)+" from "+I2S(exp))
debug call DIS()
debug return false
debug endif
debug if (not DEB.alm[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"BUG NOT ALLOCATED: "+I2S(this)+" from "+I2S(exp))
debug call DIS()
debug return false
debug endif
set this = mln[this]
endloop
endmodule
module CTTCEnd
implement CTTCNull
return false
endmethod
private static method onInit takes nothing returns nothing
//initialize timer method
set CTMf = CreateTimerMethod(Condition(function thistype.CTMe))
set CTMt = Timer[TIMEOUT].list
debug if (nprm[Timer[TIMEOUT]]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"ATTEMPTED TO USE CONSTANT MERGE MODULE FOR NON CONSTANT MERGE TIMEOUT: "+R2S(TIMEOUT))
debug call DIS()
debug endif
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitIndexer /* v4.0.2.5
*************************************************************************************
*
* Assigns unique indexes to units via unit user data.
*
*************************************************************************************
*
* */uses/*
* */ WorldBounds /* hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
* */ Event /* hiveworkshop.com/forums/submissions-414/snippet-event-186555/
*
************************************************************************************
*
* SETTINGS
*/
globals
constant integer ABILITIES_UNIT_INDEXER = 'A001'
endglobals
/*
************************************************************************************
*
* Functions
*
* function RegisterUnitIndexEvent takes boolexpr codeToRegister, Event unitIndexEvent returns nothing
* function TriggerRegisterUnitIndexEvent takes trigger triggerToRegister, Event unitIndexEvent 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 IsUnitDeindexing takes unit u returns boolean
*
* function GetIndexedUnitId takes nothing returns integer
* function GetIndexedUnit takes nothing returns unit
*
************************************************************************************
*
* module 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 GetUnitUserData(u)
*
* readonly unit unit
* - The indexed unit of the struct
* readonly boolean allocated
* - Is unit allocated for the struct
*
* Interface:
*
* - These methods don't have to exist. If they don't exist, the code
* - that calls them won't even be in the module.
*
* private method index takes nothing returns nothing
* - called when a unit is indexed and passes the filter.
* -
* - thistype this: Unit's index
* private method deindex takes nothing returns nothing
* - called when a unit is deindexed and is allocated for struct
* -
* - thistype this: Unit's index
* private static method filter takes unit unitToIndex returns boolean
* - Determines whether or not to allocate struct for unit
* -
* - unit unitToIndex: Unit being filtered
*
************************************************************************************
*
* struct UnitIndexer extends array
*
* - Controls the unit indexer system.
*
* static constant Event UnitIndexer.INDEX
* static constant Event UnitIndexer.DEINDEX
* - Don't register functions and triggers directly to the events. Register them via
* - RegisterUnitIndexEvent and TriggerRegisterUnitIndexEvent.
*
* static boolean enabled
* - Enables and disables unit indexing. Useful for filtering out dummy units.
*
************************************************************************************
*
* struct UnitIndex extends array
*
* - Constrols specific unit indexes.
*
* method lock takes nothing returns nothing
* - Locks an index. When an index is locked, it will not be recycled
* - when the unit is deindexed until all locks are removed. Deindex
* - events still fire at the appropriate times, the index just doesn't
* - get thrown into the recycler.
* method unlock takes nothing returns nothing
* - Unlocks an index.
*
************************************************************************************/
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 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
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)]) 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 UnitIndexStruct
static method operator [] takes unit u returns thistype
return GetUnitUserData(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
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=13
//TESH.alwaysfold=0
library WorldBounds
//struct WorldBounds extends array
//static readonly rect world
// same as GetWorldBounds()
//static readonly region worldRegion
// contains world for triggers
//static readonly real maxX
//static readonly real maxY
//static readonly real minX
//static readonly real minY
//static readonly real centerX
//static readonly real centerY
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=GetRectMaxX(world)
set maxY=GetRectMaxY(world)
set minX=GetRectMinX(world)
set minY=GetRectMinY(world)
set centerX=(maxX+minX)/2
set centerY=(minY+maxY)/2
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static real maxX
readonly static real maxY
readonly static real minX
readonly static real minY
readonly static real centerX
readonly static real centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary