Name | Type | is_array | initial_value |
IsUnitPreplaced | boolean | Yes | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No |
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
library TableBC requires Table
/*
Backwards-compatibility add-on for scripts employing Vexorian's Table.
Added 31 July 2015: introduced static method operator [] and
static method flush2D for Table, HandleTable and StringTable. Now,
almost all of the Vexorian API has been replicated (minus the .flush paradox).
The Table library itself was unchanged to implement these
enhancements, so you need only update this library to experience the
improved syntax compatibility.
Disclaimer:
The following error does not occur with HandleTables & StringTables, only
with the standard, integer-based Table, so you do not need to make any
changes to StringTable/HandleTable-employing scripts.
The this.flush(key) method from the original Table cannot be parsed with
the new Table. For the scripts that use this method, they need to be up-
dated to use the more fitting this.remove(key) method.
Please don't try using StringTables/HandleTables with features exclusive
to the new Table as they will cause syntax errors. I do not have any plan
to endorse these types of Tables because delegation in JassHelper is not
advanced enough for three types of Tables without copying every single
method over again (as you can see this already generates plenty of code).
StringTable & HandleTable are wrappers for StringHash & GetHandleId, so
just type them out.
*/
//! textmacro TABLE_BC_METHODS
method reset takes nothing returns nothing
call this.flush()
endmethod
method exists takes integer key returns boolean
return this.has(key)
endmethod
static method operator [] takes string id returns Table
local integer index = StringHash(id)
local Table t = Table(thistype.typeid)[index]
if t == 0 then
set t = Table.create()
set Table(thistype.typeid)[index] = t
endif
return t
endmethod
static method flush2D takes string id returns nothing
local integer index = StringHash(id)
local Table t = Table(thistype.typeid)[index]
if t != 0 then
call t.destroy()
call Table(thistype.typeid).remove(index)
endif
endmethod
//! endtextmacro
//! textmacro TABLE_BC_STRUCTS
struct HandleTable extends array
static method operator [] takes string index returns thistype
return Table[index]
endmethod
static method flush2D takes string index returns nothing
call Table.flush2D(index)
endmethod
method operator [] takes handle key returns integer
return Table(this)[GetHandleId(key)]
endmethod
method operator []= takes handle key, integer value returns nothing
set Table(this)[GetHandleId(key)] = value
endmethod
method flush takes handle key returns nothing
call Table(this).remove(GetHandleId(key))
endmethod
method exists takes handle key returns boolean
return Table(this).has(GetHandleId(key))
endmethod
method reset takes nothing returns nothing
call Table(this).flush()
endmethod
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
struct StringTable extends array
static method operator [] takes string index returns thistype
return Table[index]
endmethod
static method flush2D takes string index returns nothing
call Table.flush2D(index)
endmethod
method operator [] takes string key returns integer
return Table(this)[StringHash(key)]
endmethod
method operator []= takes string key, integer value returns nothing
set Table(this)[StringHash(key)] = value
endmethod
method flush takes string key returns nothing
call Table(this).remove(StringHash(key))
endmethod
method exists takes string key returns boolean
return Table(this).has(StringHash(key))
endmethod
method reset takes nothing returns nothing
call Table(this).flush()
endmethod
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
//! endtextmacro
endlibrary
library AttachObject /*
AttachObject v2.05
by
Spellbound
________DESCRIPTION_____________________________________________________________________________
AttachObject (formetly AttachUnit) will bind a unit or special effect to a unit, with respect
to angle, distance and, optionally, facing angle of the host. Carrier units are called Hosts
and attached units/effects are called Guests.
AttachObject comes with a turret functionality that allows unit Guests to rotate and attack
normally, after which they will return to a specific facing position. They can also be made
to slowly rotate over time, which maybe be useful for sci-fi type attachements.
________REQUIREMENTS____________________________________________________________________________
*/ requires /*
*/ ListT, /* https://www.hiveworkshop.com/threads/containers-list-t.249011/
*/ optional /*
*/ RiseAndFall /* https://www.hiveworkshop.com/threads/riseandfall.306703/
________INSTALLATION____________________________________________________________________________
Simply copy-paste this trigger into your map and install a unit indexer that uses custom values.
If you get an error telling you that UnitAlive or BlzGetUnitMovementType have been re-declared,
comment out the corresponding line:
*/
native UnitAlive takes unit whichUnit returns boolean
native BlzGetUnitMovementType takes unit whichUnit returns integer
/*
________API_____________________________________________________________________________________
/* IMPORTANT */ For units to function as Guests, they must have a positive, non-zero movement
speed. Otherwise they will not move along with their Host.
STRUCTS
¯¯¯¯¯¯¯
GuestEx
GuestEx is you main referrence struct. When you attach a unit or a special effect, the
funciton will return a GuestEx instance.
GuestEx members are readonly:
.host
.guest
.fx
EffectTimed
EffectTimed is used internally to destroy special effects after a certain time, similar
to an expiration timer on units.
EffectTimed.start(whichEffect, whichDuration)
Destroys whichEffect after whichDuration.
FUNCTIONS
¯¯¯¯¯¯¯¯¯
call AttachUnitToHost takes unit g, unit host, real angle, real distance, real zOffset, real offsetFix, boolean staticAngle returns GuestEx
^ This function will attach a unit to a host. Returns the guest instance.
[_PARAMETERS_]
unit guest - the unit to attach (aka the Guest)
unit host - the Host
real angle - the angle relative to the Host's facing angle at which the Guest is offset to. In degrees.
real distance - the distance between the Host and the Guest
real zOffset - the height difference from the Host
real offsetFix - if your Guest is off-center, try setting this to -16 or 16.
boolean staticAngle - if true, the Guest's angle offset will ignore the Host's facing direction
call AttachEffectToHost takes effect fx, unit h, real angle, real distance, real zOffset, real offsetFix, boolean staticAngle returns GuestEx
Similarly you may attach a special effect to a host instead of a unit. The only difference is the unit parameter is instead a special effect parameter.
call SetUnitFacingProperties takes unit guest, real startAngle, real rate, real cooldown, boolean dynamicFacing, boolean turretMode
^ This sets an attached unit's facing properties. If this is not called, the unit will always face the same direction.
[_PARAMETERS_]
unit guest - the attached unit (aka Guest)
real startAngle - the angle at which the Guest begins at. If dynamicFacing (see below) is false, the guest will always face this specific angle.
real rate - the speed at which the Guest rotates over time. Set to zero to ignore.
real cooldown - this is neccessary if the Guest can attack. It will resume it facing parameters after that cooldown has expired.
boolean dynamicFacing - if this is true, the facing angle of the Guest will depend on the facing of the Host.
boolean turretMode - Set this to true if you want your Guest to be able to attack. Otherwise, the facing parameters will keep interferring.
call SetEffectFacingProperties takes effect fx, real startAngle, real rate, boolean dynamicFacing
With a special effect, the facing parameters have fewer options. Use this function instead of SetUnitFacingProperties.
call DettachUnit takes unit g, boolean resetHeight, real duration
^ Call this function when you want to Dettach a Guest from a Host. real duration is for how long after Dettachement do you want the Guest to die.
Set real time to zero if you don't want the Guest to die. This function is called automatically when a Guest dies.
call DettachEffect takes effect fx, real duration
^ same as above, but specific to attached effects. real duration call EffectTimed.start(guest.fx, duration) internally if duration is greater than zero.
call DettachAllGuests takes unit h, boolean resetHeight, real duration
^ Call this function on a Host to Dettach all its Guests. This function will NOT get called automatically on Host death and must be done manually.
Similarly to DettachGuest, real duration will determine how long after Dettachment will the Guest die. Set to zero to not destroy your Dettached Guests.
call GetRandomGuest takes unit h, boolepx guestFilter returns unit
^ This will return a random Guest attached to a Host. Set guestFilter to null if you do not wish to filter your guests.
/* IMPORTANT */ In your filter you MUST use the variable 'FilterGuest' and NOT GetFilterUnit().
call GetNumberOfGuests takes unit h returns integer
^ This will return the number of Guests currently connected to a Host.
call GroupUnitGuests takes unit h returns group
^ this will take all UNIT Guests attached to a Host and put them in a unit group via:
set YourGroup = GrouGuests(host).
call GetGuestList takes unit h returns integer
^ this will copy the Guest list of a host and return either an IntegerList instance or
LinkedList instance. When you are done with that copy, YOU MUST DESTROY IT with
list.destroy().
The list returned will be an IntegerList type. See the trigger HowToIterateThroughLists
if you are unfamiliar with linked lists.
GetGuestList() is not wait-safe as the list is not being updated if Guests are
added or removed.
call IsUnitHost takes unit h returns boolean
^ Returns true if a unit is a Host.
call IsUnitGuest takes unit g returns boolean
^ Returns true if a unit is a Guest.
call IsEffectGuest takes effect fx returns boolean
^ Returns true if an effect is a Guest.
call IsGuestUnit takes GuestEx ex returns boolean
^ Returns true if a Guest is a unit.
call IsGuestEffect takes GuestEx ex returns boolean
^ Returns true if a Guest is a special effect.
call GetHost takes GuestEx ex returns unit
^ Returns the Host unit of a Guest.
call GetGuestUnitId takes unit g returns GuestEx
^ Returns the readonly instance id of a unit Guest.
call GetGuestEffectId takes effect fx returns GuestEx
^ Returns the readonly instance id of an effect Guest.
call ShowGuests takes unit h returns nothing
^ Cycles through all the Guests of a Host and unhides them.
This function is called automatically when a Host is unhidden.
call HideGuests takes unit h returns nothing
^ Cycles through all Guests a Host has and hides them.
This function is called automatically when a Host is hidden.
call ShowGuest takes GuestEx ex returns nothing
^ not to be mistaken with ShowGuests, this will reveal ONE Guest. ShowGuest does
not break locaut ('Aloc').
*/
globals
// interval between Guest updates. Do not change this or things will look choppy.
private constant real TIMEOUT = .03125
// order attack for turret mode
private constant integer ORDER_ATTACK = 851983
// If true then Guests will reset to their default fly height when they are dettached.
private constant boolean RESET_HEIGHT = true
// the speed at which they rise/fall if RESET_HEIGHT is true.
private constant real FALL_SPEED = 300.
unit FilterGuest = null
private trigger FilterTrig = CreateTrigger()
private hashtable TurretStorage = InitHashtable()
private hashtable HostIdStorage = InitHashtable()
private hashtable GuestIdStorage = InitHashtable()
private timer Clock = CreateTimer()
private group GuestGroup = CreateGroup()
endglobals
//! runtextmacro optional DEFINE_LIST("", "AOList", "integer")
private struct GlobalListT
static AOList Guests = 0
static AOList Hosts = 0
endstruct
function ListTGetRandom takes AOList list returns AOListItem
local integer size = list.size()
local integer i
local AOListItem node = 0
debug if size == 0 then
debug call BJDebugMsg("the list is empty")
debug return 0
debug endif
// thanks to Wareditor for that bit of code
if size > 0 then
set i = GetRandomInt(1, size)
if i > size / 2 then
set i = size - i
set node = list.last
loop
exitwhen i == 0
set node = node.prev
set i = i - 1
endloop
else
set i = i - 1
set node = list.first
loop
exitwhen i == 0
set node = node.next
set i = i - 1
endloop
endif
endif
return node
endfunction
// specfic for reading Guest data
struct GuestEx
readonly unit host
readonly unit guest
readonly effect fx
method destroy takes nothing returns nothing
set this.host = null
set this.guest = null
set this.fx = null
call this.deallocate()
endmethod
static method create takes unit h, unit g, effect fx returns thistype
local thistype this = allocate()
set this.host = h
set this.guest = g
set this.fx = fx
return this
endmethod
endstruct
private struct Guest
real cooldown
real cooldownReset
trigger turretTrigger
boolean dynamicFacing
boolean updateFacing
boolean isHidden
real distance
real angle
real zOffset
real offsetFix
real angleRate
real facing
real idleAngle
boolean staticAngle
unit parent
unit u
effect fx
GuestEx ex
method destroy takes nothing returns nothing
if this.fx != null then
call FlushChildHashtable(GuestIdStorage, GetHandleId(this.fx))
set this.fx = null
else
call FlushChildHashtable(GuestIdStorage, GetHandleId(this.u))
set this.u = null
endif
set this.parent = null
set this.staticAngle = false
set this.dynamicFacing = false
set this.updateFacing = false
set this.isHidden = false
set this.angleRate = 0.
set this.idleAngle = 0.
call this.ex.destroy()
set this.ex = 0
call this.deallocate()
endmethod
static method create takes unit g, effect fx, unit h returns thistype
local thistype this = allocate()
call GlobalListT.Guests.push(this)
set this.parent = h
set this.u = g
set this.fx = fx
set this.ex = GuestEx.create(h, g, fx)
if g == null then
call SaveInteger(GuestIdStorage, GetHandleId(fx), 0, this)
else
call SaveInteger(GuestIdStorage, GetHandleId(g), 0, this)
endif
return this
endmethod
endstruct
private struct Host
real x
real y
real z
real t
real f
unit u
boolean hiddenState
AOList guestList
method destroy takes nothing returns nothing
call FlushChildHashtable(HostIdStorage, GetHandleId(this.u))
call this.guestList.destroy()
set this.u = null
set this.hiddenState = false
call GlobalListT.Hosts.removeElem(this)
if GlobalListT.Hosts.empty() then
call PauseTimer(Clock)
endif
call this.deallocate()
endmethod
method addGuest takes Guest guest returns nothing
call this.guestList.push(guest)
endmethod
static method create takes unit h returns thistype
local thistype this = allocate()
set this.guestList = AOList.create()
call GlobalListT.Hosts.push(this)
set this.u = h
set this.hiddenState = IsUnitHidden(h)
call SaveInteger(HostIdStorage, GetHandleId(h), 0, this)
return this
endmethod
endstruct
struct EffectTimed
private effect fx
private real dur
private static timer clock = CreateTimer()
static AOList fxList
private static method update takes nothing returns nothing
local thistype this
local AOListItem node = thistype.fxList.first
local AOListItem nodeNext
loop
exitwhen node == 0
set nodeNext = node.next
set this = node.data
set this.dur = this.dur - TIMEOUT
if this.dur <= 0. then
call DestroyEffect(this.fx)
set this.fx = null
call this.deallocate()
endif
set node = nodeNext
endloop
if thistype.fxList.size() < 1 then
call PauseTimer(thistype.clock)
endif
endmethod
static method start takes effect vfx, real duration returns nothing
local thistype this = allocate()
set this.fx = vfx
set this.dur = duration
call thistype.fxList.push(this)
if thistype.fxList.size() == 1 then
call TimerStart(thistype.clock, TIMEOUT, true, function thistype.update)
endif
endmethod
endstruct
//REFERENCE AND OTHER USEFUL FUNCTIONS
// library use only
private function GetPrivateHostUnitId takes unit h returns Host
return LoadInteger(HostIdStorage, GetHandleId(h), 0)
endfunction
private function GetPrivateGuestUnitId takes unit g returns Guest
return LoadInteger(GuestIdStorage, GetHandleId(g), 0)
endfunction
private function GetPrivateGuestEffectId takes effect e returns Guest
return LoadInteger(GuestIdStorage, GetHandleId(e), 0)
endfunction
// public use
function GetHost takes Guest guest returns unit
return guest.parent
endfunction
function IsUnitHost takes unit h returns boolean
return LoadInteger(HostIdStorage, GetHandleId(h), 0) != 0
endfunction
function IsUnitGuest takes unit g returns boolean
return LoadInteger(GuestIdStorage, GetHandleId(g), 0) != 0
endfunction
function IsEffectGuest takes effect e returns boolean
return LoadInteger(GuestIdStorage, GetHandleId(e), 0) != 0
endfunction
function IsGuestUnit takes GuestEx ex returns boolean
return ex.guest != null
endfunction
function IsGuestEffect takes GuestEx ex returns boolean
return ex.fx != null
endfunction
function GetGuestUnitId takes unit g returns GuestEx
local Guest guest = LoadInteger(GuestIdStorage, GetHandleId(g), 0)
return guest.ex
endfunction
function GetGuestEffectId takes effect e returns GuestEx
local Guest guest = LoadInteger(GuestIdStorage, GetHandleId(e), 0)
return guest.ex
endfunction
function GetNumberOfGuests takes unit h returns integer
local Host host = GetPrivateHostUnitId(h)
return host.guestList.size()
endfunction
function GroupUnitGuests takes unit h returns group
local Host host = GetPrivateHostUnitId(h)
local Guest guest
local AOListItem node = host.guestList.first
if GuestGroup == null then
set GuestGroup = CreateGroup()
else
call GroupClear(GuestGroup)
endif
if IsUnitHost(h) then
loop
exitwhen node == 0
set guest = node.data
call GroupAddUnit(GuestGroup, guest.u)
set node = node.next
endloop
endif
return GuestGroup
endfunction
function GetGuestList takes unit h returns IntegerList
local Host host = GetPrivateHostUnitId(h)
local Guest guest
local IntegerList list = IntegerList.create()
local IntegerListItem node = host.guestList.first
loop
exitwhen node == 0
set guest = node.data
call list.push(guest.ex)
set node = node.next
endloop
return list
endfunction
function GetRandomGuest takes unit h, boolexpr guestFilter returns unit
local Host host = GetPrivateHostUnitId(h)
local Guest guest
local AOListItem node = ListTGetRandom(host.guestList)
local unit u
local triggercondition tcnd
local boolean firstPass = false
local integer n = host.guestList.size()
if guestFilter == null then
set guest = node.data
return guest.u
else
set firstPass = (node == host.guestList.first)
set FilterGuest = null
loop
exitwhen node == 0 and firstPass
if node == 0 and not firstPass then
set node = host.guestList.first
set firstPass = true
endif
set guest = node.data
set u = guest.u
set tcnd = TriggerAddCondition(FilterTrig, guestFilter)
if TriggerEvaluate(FilterTrig) then
set FilterGuest = u
endif
call TriggerRemoveCondition(FilterTrig, tcnd)
set node = node.next
endloop
set u = null
set tcnd = null
return FilterGuest
endif
return null
endfunction
function ShowGuest takes GuestEx ex returns nothing
local Guest guest
if ex.guest != null then
set guest = GetGuestUnitId(ex.guest)
if IsUnitHidden(guest.u) then
call ShowUnit(guest.u, true)
if GetUnitAbilityLevel(guest.u, 'Aloc') > 0 then
call UnitRemoveAbility(guest.u, 'Aloc')
call UnitAddAbility(guest.u, 'Aloc')
endif
endif
else
set guest = GetGuestEffectId(ex.fx)
endif
set guest.isHidden = false
endfunction
private function ShowGuestEx takes Guest guest returns nothing
set guest.isHidden = false
if guest.u != null then
if IsUnitHidden(guest.u) then
call ShowUnit(guest.u, true)
if GetUnitAbilityLevel(guest.u, 'Aloc') > 0 then
call UnitRemoveAbility(guest.u, 'Aloc')
call UnitAddAbility(guest.u, 'Aloc')
endif
endif
endif
endfunction
function ShowGuestsEx takes unit h, boolean flag returns nothing
local Host host = GetPrivateHostUnitId(h)
local Guest guest
local AOListItem node = host.guestList.first
loop
exitwhen node == 0
set guest = node.data
if flag then
call ShowGuestEx(guest)
else
call ShowUnit(guest.u, false)
call BlzSetSpecialEffectZ(guest.fx, -1000.)
set guest.isHidden = true
endif
set node = node.next
endloop
endfunction
function ShowGuests takes unit h returns nothing
call ShowGuestsEx(h, true)
endfunction
function HideGuests takes unit h returns nothing
call ShowGuestsEx(h, false)
endfunction
//Core function to dettach guests from hosts
private function DettachObject takes Guest guest, boolean resetHeight, real time returns nothing
local Host host
static if LIBRARY_RiseAndFall then
local real hc // height current
local real hd // height default
local integer moveType
local real duration
endif
if guest.turretTrigger != null then
call FlushChildHashtable(TurretStorage, GetHandleId(guest.turretTrigger))
call DestroyTrigger(guest.turretTrigger)
set guest.turretTrigger = null
endif
if guest.parent != null then
set host = GetPrivateHostUnitId(guest.parent)
call host.guestList.removeElem(guest)
if guest.u != null then
if UnitAlive(guest.u) and time > 0. then
call UnitApplyTimedLife(guest.u , 'BTLF', time)
endif
static if RESET_HEIGHT then
if resetHeight then
static if LIBRARY_RiseAndFall then
set hc = GetUnitFlyHeight(guest.u)
set hd = GetUnitDefaultFlyHeight(guest.u)
set moveType = BlzGetUnitMovementType(guest.u)
set duration = (hc - hd) / FALL_SPEED
if duration < 0. then
set duration = -duration
endif
call RiseAndFall.create(guest.u, hc, hd, duration, (moveType == 8 or moveType == 2))
else
call SetUnitFlyHeight(guest.u, GetUnitDefaultFlyHeight(guest.u), FALL_SPEED)
endif
endif
endif
endif
if guest.fx != null and time > 0. then
call EffectTimed.start(guest.fx, time)
endif
call SetUnitPropWindow(guest.u, GetUnitDefaultPropWindow(guest.u) * bj_DEGTORAD)
call UnitRemoveAbility(guest.u, 'Aeth')
call SetUnitPathing(guest.u, true)
if host.guestList.empty() then
call host.destroy()
endif
endif
call guest.destroy()
endfunction
private function DettachAllObjects takes Host host, boolean resetHeight, real time returns nothing
local Guest guest
local AOListItem node = host.guestList.first
local AOListItem nodeNext
loop
exitwhen node == 0
set nodeNext = node.next
set guest = node.data
call DettachObject(guest, resetHeight, time)
set node = nodeNext
endloop
endfunction
function DettachEffect takes effect fx, boolean resetHeight, real time returns nothing
call DettachObject(GetPrivateGuestEffectId(fx), resetHeight, time)
endfunction
function DettachUnit takes unit g, boolean resetHeight, real time returns nothing
call DettachObject(GetPrivateGuestUnitId(g), resetHeight, time)
endfunction
function DettachAllGuests takes unit h, boolean resetHeight, real time returns nothing
call DettachAllObjects(GetPrivateHostUnitId(h), resetHeight, time)
endfunction
private function TurretActions takes nothing returns nothing
local Guest guest = LoadInteger(TurretStorage, GetHandleId(GetTriggeringTrigger()), 0)
set guest.cooldown = guest.cooldownReset
if GetUnitCurrentOrder(guest.u) != ORDER_ATTACK then
call IssuePointOrderById(guest.u, ORDER_ATTACK, GetUnitX(guest.u), GetUnitY(guest.u))
endif
endfunction
private function UpdateGuests takes nothing returns nothing
local real x
local real y
local real z
local real t
local real f
local real a
local real xNew
local real yNew
local AOListItem node = GlobalListT.Hosts.first
local AOListItem nodeNext
local AOListItem nNode
local AOListItem nNodeNext
local Host host
local Guest guest
// This loop cycles through all the Hosts and a secondary loop inside cycles through their
// attached Guests, updating their x, y and z coordiates.
loop
exitwhen node == 0
set nodeNext = node.next
set host = node.data
set x = GetUnitX(host.u)
set y = GetUnitY(host.u)
set z = GetUnitFlyHeight(host.u) // fly height
set t = BlzGetLocalUnitZ(host.u) // terrain height
set f = GetUnitFacing(host.u)
if not IsUnitHidden(host.u) then
// unhide guests if host was previously hidden
if host.hiddenState then
set host.hiddenState = false
call ShowGuestsEx(host.u, true)
endif
if x != host.x or y != host.y or z != host.z or t != host.t or f != host.f then
set nNode = host.guestList.first
loop
exitwhen nNode == 0
set nNodeNext = nNode.next
set guest = nNode.data
// required for manually hidden special effects
if not guest.isHidden then
if guest.staticAngle then
set a = 0.
else
set a = f * bj_DEGTORAD
endif
set xNew = guest.offsetFix + x + Cos(guest.angle + a) * guest.distance
set yNew = guest.offsetFix + y + Sin(guest.angle + a) * guest.distance
if guest.u != null then
call SetUnitX(guest.u, xNew)
call SetUnitY(guest.u, yNew)
if z != host.z then
call SetUnitFlyHeight(guest.u, z + guest.zOffset, 0.)
endif
endif
if guest.fx != null then
call BlzSetSpecialEffectPosition(guest.fx, xNew, yNew, t + z + guest.zOffset)
endif
endif
set nNode = nNodeNext
endloop
set host.x = x
set host.y = y
set host.z = z
set host.t = t
set host.f = f * bj_RADTODEG
endif
else
// hide guests if host was not previously hidden
if not host.hiddenState then
set host.hiddenState = true
call ShowGuestsEx(host.u, false)
endif
endif
set node = nodeNext
endloop
set node = GlobalListT.Guests.first
// Updates the facing angle of Guests that rotate when idle and when not to turn (eg when in combat).
loop
exitwhen node == 0
set nodeNext = node.next
set guest = node.data
if guest.u != null and not UnitAlive(guest.u) then
call DettachObject(guest, true, 0.)
else
if guest.updateFacing and not guest.isHidden then
if guest.dynamicFacing then
set f = GetUnitFacing(guest.parent)
else
set f = 0.
endif
set guest.facing = guest.facing + guest.angleRate
if guest.u == null then
call BlzSetSpecialEffectYaw(guest.fx, guest.facing + f * bj_DEGTORAD)
else
if GetUnitCurrentOrder(guest.u) != 0 then
if guest.cooldown > 0. then
set guest.cooldown = guest.cooldown - TIMEOUT
else
set guest.cooldown = guest.cooldownReset
call IssueImmediateOrderById(guest.u, 851973) //order stunned
call SetUnitFacing(guest.u, guest.idleAngle + f)
endif
if guest.angleRate != 0. then
// Store the facing of the unit if it needs to rotate later
set guest.facing = GetUnitFacing(guest.u)
endif
else
call SetUnitFacing(guest.u, guest.facing + f)
endif
endif
endif
endif
set node = nodeNext
endloop
endfunction
private function SetFacingProperties takes Guest guest, real startAngle, real rate, real cooldown, boolean dynamicFacing, boolean turretMode returns nothing
if guest != 0 then
set guest.cooldownReset = cooldown
set guest.cooldown = cooldown
set guest.updateFacing = true
set guest.angleRate = rate * TIMEOUT
set guest.dynamicFacing = dynamicFacing
if guest.u == null then
set guest.facing = startAngle * bj_DEGTORAD
set guest.idleAngle = guest.facing
set guest.angleRate = guest.angleRate * bj_DEGTORAD
call BlzSetSpecialEffectYaw(guest.fx, guest.facing)
else
set guest.facing = startAngle
set guest.idleAngle = startAngle
call SetUnitFacing(guest.u, guest.facing)
endif
if turretMode and guest.u != null then
set guest.turretTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(guest.turretTrigger, guest.u, EVENT_UNIT_ACQUIRED_TARGET)
call TriggerRegisterUnitEvent(guest.turretTrigger, guest.u, EVENT_UNIT_TARGET_IN_RANGE)
call SaveInteger(TurretStorage, GetHandleId(guest.turretTrigger), 0, guest)
call TriggerAddCondition(guest.turretTrigger, Condition(function TurretActions))
endif
endif
endfunction
function SetEffectFacingProperties takes effect fx, real startAngle, real rate, boolean dynamicFacing returns nothing
call SetFacingProperties(GetPrivateGuestEffectId(fx), startAngle, rate, 0., dynamicFacing, false)
endfunction
function SetUnitFacingProperties takes unit g, real startAngle, real rate, real cooldown, boolean dynamicFacing, boolean turretMode returns nothing
call SetFacingProperties(GetPrivateGuestUnitId(g), startAngle, rate, cooldown, dynamicFacing, turretMode)
endfunction
private function AttachObject takes unit g, effect fx, unit h, real angle, real distance, real zOffset, real offsetFix, boolean staticAngle returns GuestEx
local Host host = GetPrivateHostUnitId(h)
local Guest guest
local AOListItem node = GlobalListT.Hosts.first
local real x = GetUnitX(h)
local real y = GetUnitY(h)
local real z = GetUnitFlyHeight(h)
local real t = BlzGetLocalUnitZ(h)
local real f = GetUnitFacing(h)
local real a
local real xNew
local real yNew
if g == null then
set guest = GetPrivateGuestUnitId(g)
else
set guest = GetPrivateGuestEffectId(fx)
endif
// if there is no host or not effect and guest unit, end the function
if h == null or (g == null and fx == null) then
return 0
endif
// if guest instance is not null then it's already attached to a unit
if guest != 0 then
if guest.parent == h then
return 0
else
call DettachObject(guest, false, 0.)
endif
endif
// check if the Host has an instance
if host == 0 then
set host = Host.create(h)
set host.x = x
set host.y = y
set host.z = z
set host.t = t
set host.f = f
endif
set guest = Guest.create(g, fx, h)
call host.addGuest(guest)
set guest.angle = angle * bj_DEGTORAD
set guest.staticAngle = staticAngle
set guest.distance = distance
set guest.zOffset = zOffset
set guest.offsetFix = offsetFix
// if angle is static then ignore the Host's facing angle.
if staticAngle then
set a = guest.angle
else
set a = guest.angle + f * bj_DEGTORAD
endif
set xNew = offsetFix + x + Cos(a) * distance
set yNew = offsetFix + y + Sin(a) * distance
if g == null then
set guest.facing = f * bj_DEGTORAD
call BlzSetSpecialEffectPosition(fx, xNew, yNew, t + z + zOffset)
call BlzSetSpecialEffectYaw(fx, guest.facing)
else
set guest.facing = f
call SetUnitX(g, xNew)
call SetUnitY(g, yNew)
call SetUnitFlyHeight(g, z + zOffset, 0.)
call SetUnitFacing(g, guest.facing)
call SetUnitPropWindow(g, 0.)
call UnitAddAbility(g, 'Aeth')
call SetUnitPathing(g, false)
endif
if GlobalListT.Hosts.size() == 1 then
call TimerStart(Clock, TIMEOUT, true, function UpdateGuests)
endif
return guest.ex
endfunction
function AttachEffectToHost takes effect fx, unit h, real angle, real distance, real zOffset, real offsetFix, boolean staticAngle returns Guest
return AttachObject(null, fx, h, angle, distance, zOffset, offsetFix, staticAngle)
endfunction
function AttachUnitToHost takes unit g, unit h, real angle, real distance, real zOffset, real offsetFix, boolean staticAngle returns Guest
return AttachObject(g, null, h, angle, distance, zOffset, offsetFix, staticAngle)
endfunction
// Initialisation - the module, the module's method and the struct must all be private. The method must be static.
private module init
private static method onInit takes nothing returns nothing
set GlobalListT.Guests = AOList.create()
set GlobalListT.Hosts = AOList.create()
set EffectTimed.fxList = AOList.create()
endmethod
endmodule
private struct Init
implement init
endstruct
endlibrary
/*****************************************************************************
*
* List<T> v2.1.2.3
* by Bannar
*
* Doubly-linked list.
*
******************************************************************************
*
* Requirements:
*
* Table by Bribe
* hiveworkshop.com/threads/snippet-new-table.188084/
*
* Alloc - choose whatever you like
* e.g.: by Sevion hiveworkshop.com/threads/snippet-alloc.192348/
*
******************************************************************************
*
* Implementation:
*
* macro DEFINE_LIST takes ACCESS, NAME, TYPE
*
* macro DEFINE_STRUCT_LIST takes ACCESS, NAME, TYPE
*
* ACCESS - encapsulation, choose restriction access
* NAME - name of list type
* TYPE - type of values stored
*
* Implementation notes:
*
* - DEFINE_STRUCT_LIST macro purpose is to provide natural typecasting syntax for struct types.
* - <NAME>Item structs inline directly into hashtable operations thus generate basically no code.
* - Lists defined with DEFINE_STRUCT_LIST are inlined nicely into single create method and single integer array.
*
******************************************************************************
*
* struct API:
*
* struct <NAME>Item:
*
* | <TYPE> data
* | <NAME>Item next
* | <NAME>Item prev
*
*
* General:
*
* | static method create takes nothing returns thistype
* | Default ctor.
* |
* | static method operator [] takes thistype other returns thistype
* | Copy ctor.
* |
* | method destroy takes nothing returns nothing
* | Default dctor.
* |
* | method empty takes nothing returns boolean
* | Checks whether the list is empty.
* |
* | method size takes nothing returns integer
* | Returns size of a list.
*
*
* Access:
*
* | readonly <NAME>Item first
* | readonly <NAME>Item last
* |
* | method front takes nothing returns $TYPE$
* | Retrieves first element.
* |
* | method back takes nothing returns $TYPE$
* | Retrieves last element.
*
*
* Modifiers:
*
* | method clear takes nothing returns nothing
* | Flushes list and recycles its nodes.
* |
* | method push takes $TYPE$ value returns thistype
* | Adds elements to the end.
* |
* | method unshift takes $TYPE$ value returns thistype
* | Adds elements to the front.
* |
* | method pop takes nothing returns thistype
* | Removes the last element.
* |
* | method shift takes nothing returns thistype
* | Removes the first element.
* |
* | method find takes $TYPE$ value returns $NAME$Item
* | Returns the first node which data equals value.
* |
* | method erase takes $NAME$Item node returns boolean
* | Removes node from the list, returns true on success.
* |
* | method removeElem takes $TYPE$ value returns thistype
* | Removes first element that equals value from the list.
*
*
*****************************************************************************/
library ListT requires Table, Alloc
//! runtextmacro DEFINE_LIST("", "IntegerList", "integer")
// Run here any global list types you want to be defined.
//! textmacro_once DEFINE_LIST takes ACCESS, NAME, TYPE
$ACCESS$ struct $NAME$Item extends array
// No default ctor and dctor due to limited array size
method operator data takes nothing returns $TYPE$
return Table(this).$TYPE$[-1] // hashtable[ node, -1 ] = data
endmethod
method operator data= takes $TYPE$ value returns nothing
set Table(this).$TYPE$[-1] = value
endmethod
method operator next takes nothing returns thistype
return Table(this)[-2] // hashtable[ node, -2 ] = next
endmethod
method operator next= takes thistype value returns nothing
set Table(this)[-2] = value
endmethod
method operator prev takes nothing returns thistype
return Table(this)[-3] // hashtable[ node, -3 ] = prev
endmethod
method operator prev= takes thistype value returns nothing
set Table(this)[-3] = value
endmethod
endstruct
$ACCESS$ struct $NAME$ extends array
readonly $NAME$Item first
readonly $NAME$Item last
private integer count
implement Alloc
private static method setNodeOwner takes $NAME$Item node, $NAME$ owner returns nothing
set Table(node)[-4] = owner
endmethod
private static method getNodeOwner takes $NAME$Item node returns thistype
return Table(node)[-4]
endmethod
private method createNode takes $TYPE$ value returns $NAME$Item
local $NAME$Item node = Table.create()
set node.data = value
call setNodeOwner(node, this) // ownership
return node
endmethod
private method deleteNode takes $NAME$Item node returns nothing
call Table(node).destroy() // also removes ownership
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
set count = 0
return this
endmethod
method clear takes nothing returns nothing
local $NAME$Item node = first
local $NAME$Item temp
loop // recycle all Table indexes
exitwhen 0 == node
set temp = node.next
call deleteNode(node)
set node = temp
endloop
set first = 0
set last = 0
set count = 0
endmethod
method destroy takes nothing returns nothing
call clear()
call deallocate()
endmethod
method front takes nothing returns $TYPE$
return first.data
endmethod
method back takes nothing returns $TYPE$
return last.data
endmethod
method empty takes nothing returns boolean
return count == 0
endmethod
method size takes nothing returns integer
return count
endmethod
method push takes $TYPE$ value returns thistype
local $NAME$Item node = createNode(value)
if not empty() then
set last.next = node
set node.prev = last
else
set first = node
set node.prev = 0
endif
set last = node
set node.next = 0
set count = count + 1
return this
endmethod
method unshift takes $TYPE$ value returns thistype
local $NAME$Item node = createNode(value)
if not empty() then
set first.prev = node
set node.next = first
else
set last = node
set node.next = 0
endif
set first = node
set node.prev = 0
set count = count + 1
return this
endmethod
method pop takes nothing returns thistype
local $NAME$Item node
if not empty() then
set node = last
set last = last.prev
if last == 0 then
set first = 0
else
set last.next = 0
endif
call deleteNode(node)
set count = count - 1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::pop failed for instance "+I2S(this)+". List is empty.")
endif
return this
endmethod
method shift takes nothing returns thistype
local $NAME$Item node
if not empty() then
set node = first
set first = first.next
if first == 0 then
set last = 0
else
set first.prev = 0
endif
call deleteNode(node)
set count = count - 1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::shift failed for instance "+I2S(this)+". List is empty.")
endif
return this
endmethod
static method operator [] takes thistype other returns thistype
local thistype instance = create()
local $NAME$Item node = other.first
loop
exitwhen node == 0
call instance.push(node.data)
set node = node.next
endloop
return instance
endmethod
method find takes $TYPE$ value returns $NAME$Item
local $NAME$Item node = first
loop
exitwhen node == 0 or node.data == value
set node = node.next
endloop
return node
endmethod
method erase takes $NAME$Item node returns boolean
if getNodeOwner(node) == this then // match ownership
if node == first then
call shift()
elseif node == last then
call pop()
else
set node.prev.next = node.next
set node.next.prev = node.prev
call deleteNode(node)
set count = count - 1
endif
return true
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::erase failed for instance "+I2S(this)+". Attempted to remove invalid node "+I2S(node)+".")
endif
return false
endmethod
method remove takes $NAME$Item node returns boolean
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Method $NAME$::remove is obsolete, use $NAME$::erase instead.")
return erase(node)
endmethod
method removeElem takes $TYPE$ value returns thistype
local $NAME$Item node = find(value)
if node != 0 then
call erase(node)
endif
return this
endmethod
endstruct
//! endtextmacro
//! textmacro_once DEFINE_STRUCT_LIST takes ACCESS, NAME, TYPE
$ACCESS$ struct $NAME$Item extends array
// Cannot inherit methods via delegate due to limited array size
method operator data takes nothing returns $TYPE$
return IntegerListItem(this).data
endmethod
method operator data= takes $TYPE$ value returns nothing
set IntegerListItem(this).data = value
endmethod
method operator next takes nothing returns thistype
return IntegerListItem(this).next
endmethod
method operator next= takes thistype value returns nothing
set IntegerListItem(this).next = value
endmethod
method operator prev takes nothing returns thistype
return IntegerListItem(this).prev
endmethod
method operator prev= takes thistype value returns nothing
set IntegerListItem(this).prev = value
endmethod
endstruct
$ACCESS$ struct $NAME$ extends array
private delegate IntegerList parent
static method create takes nothing returns thistype
local thistype this = IntegerList.create()
set parent = this
return this
endmethod
method front takes nothing returns $TYPE$
return parent.front()
endmethod
method back takes nothing returns $TYPE$
return parent.back()
endmethod
endstruct
//! endtextmacro
endlibrary
library Alloc /* v1.3.1.1
*************************************************************************************
*
* */ uses /*
*
* */ optional ErrorMessage /* github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage
* */ optional MemoryAnalysis /*
*
*************************************************************************************
*
* Minimizes code generation and global variables while maintaining
* excellent performance.
*
* local thistype this = recycler[0]
*
* if (recycler[this] == 0) then
* set recycler[0] = this + 1
* else
* set recycler[0] = recycler[this]
* endif
*
************************************************************************************
*
* module Alloc
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
* The Following Require Error Message To Be In The Map
* --------------------------------------------------------
*
* debug readonly boolean allocated
*
* The Following Require Memory Analysis To Be In The Map
* --------------------------------------------------------
*
* debug readonly integer monitorCount
* - the amount of global memory being monitored by this
* debug readonly integer monitorString
* - gets a string representation of all global memory being monitored by this
* debug readonly integer address
* - global memory address for debugging
* - used with monitor and stopMonitor
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
* debug method monitor takes string label, integer address returns nothing
* - monitor a global memory address with a label
* - used to identify memory leaks
* - should be memory that ought to be destroyed by the time this is destroyed
* debug method stopMonitor takes integer address returns nothing
* - stops monitoring global memory
* debug method stopMonitorValue takes handle monitoredHandle returns nothing
* - stops monitoring handle values
*
* The Following Are Used To Monitor Handle Values
*
* debug method monitor_widget takes string label, widget handleToTrack returns nothing
* debug method monitor_destructable takes string label, destructable handleToTrack returns nothing
* debug method monitor_item takes string label, item handleToTrack returns nothing
* debug method monitor_unit takes string label, unit handleToTrack returns nothing
* debug method monitor_timer takes string label, timer handleToTrack returns nothing
* debug method monitor_trigger takes string label, trigger handleToTrack returns nothing
* debug method monitor_triggercondition takes string label, triggercondition handleToTrack returns nothing
* debug method monitor_triggeraction takes string label, triggeraction handleToTrack returns nothing
* debug method monitor_force takes string label, force handleToTrack returns nothing
* debug method monitor_group takes string label, group handleToTrack returns nothing
* debug method monitor_location takes string label, location handleToTrack returns nothing
* debug method monitor_rect takes string label, rect handleToTrack returns nothing
* debug method monitor_boolexpr takes string label, boolexpr handleToTrack returns nothing
* debug method monitor_effect takes string label, effect handleToTrack returns nothing
* debug method monitor_unitpool takes string label, unitpool handleToTrack returns nothing
* debug method monitor_itempool takes string label, itempool handleToTrack returns nothing
* debug method monitor_quest takes string label, quest handleToTrack returns nothing
* debug method monitor_defeatcondition takes string label, defeatcondition handleToTrack returns nothing
* debug method monitor_timerdialog takes string label, timerdialog handleToTrack returns nothing
* debug method monitor_leaderboard takes string label, leaderboard handleToTrack returns nothing
* debug method monitor_multiboard takes string label, multiboard handleToTrack returns nothing
* debug method monitor_multiboarditem takes string label, multiboarditem handleToTrack returns nothing
* debug method monitor_dialog takes string label, dialog handleToTrack returns nothing
* debug method monitor_button takes string label, button handleToTrack returns nothing
* debug method monitor_texttag takes string label, texttag handleToTrack returns nothing
* debug method monitor_lightning takes string label, lightning handleToTrack returns nothing
* debug method monitor_image takes string label, image handleToTrack returns nothing
* debug method monitor_ubersplat takes string label, ubersplat handleToTrack returns nothing
* debug method monitor_region takes string label, region handleToTrack returns nothing
* debug method monitor_fogmodifier takes string label, fogmodifier handleToTrack returns nothing
* debug method monitor_hashtable takes string label, hashtable handleToTrack returns nothing
*
*
* Thanks to Ruke for the algorithm
************************************************************************************/
module Alloc
/*
* stack
*/
private static integer array recycler
static if LIBRARY_MemoryAnalysis then
debug private MemoryMonitor globalAddress
debug method operator address takes nothing returns integer
debug call ThrowError(recycler[this] != -1, "Alloc", "address", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress
debug endmethod
endif
/*
* allocation
*/
static method allocate takes nothing returns thistype
local thistype this = recycler[0]
static if LIBRARY_ErrorMessage then
debug call ThrowError(this == 8192, "Alloc", "allocate", "thistype", 0, "Overflow.")
endif
if (recycler[this] == 0) then
set recycler[0] = this + 1
else
set recycler[0] = recycler[this]
endif
static if LIBRARY_ErrorMessage then
debug set recycler[this] = -1
endif
static if LIBRARY_MemoryAnalysis then
debug set globalAddress = MemoryMonitor.allocate("thistype")
endif
return this
endmethod
method deallocate takes nothing returns nothing
static if LIBRARY_ErrorMessage then
debug call ThrowError(recycler[this] != -1, "Alloc", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
endif
static if LIBRARY_MemoryAnalysis then
debug call globalAddress.deallocate()
debug set globalAddress = 0
endif
set recycler[this] = recycler[0]
set recycler[0] = this
endmethod
static if LIBRARY_MemoryAnalysis then
debug method monitor takes string label, integer address returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor(label, address)
debug endmethod
debug method stopMonitor takes integer address returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "stopMonitor", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.stopMonitor(address)
debug endmethod
debug method stopMonitorValue takes handle monitoredHandle returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "stopMonitorValue", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.stopMonitorValue(monitoredHandle)
debug endmethod
debug method operator monitorCount takes nothing returns integer
debug call ThrowError(recycler[this] != -1, "Alloc", "monitorCount", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress.monitorCount
debug endmethod
debug method operator monitorString takes nothing returns string
debug call ThrowError(recycler[this] != -1, "Alloc", "monitorString", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress.monitorString
debug endmethod
debug method monitor_widget takes string label, widget handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_widget", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_widget(label, handleToTrack)
debug endmethod
debug method monitor_destructable takes string label, destructable handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_destructable", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_destructable(label, handleToTrack)
debug endmethod
debug method monitor_item takes string label, item handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_item", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_item(label, handleToTrack)
debug endmethod
debug method monitor_unit takes string label, unit handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_unit", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_unit(label, handleToTrack)
debug endmethod
debug method monitor_timer takes string label, timer handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_timer", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_timer(label, handleToTrack)
debug endmethod
debug method monitor_trigger takes string label, trigger handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_trigger", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_trigger(label, handleToTrack)
debug endmethod
debug method monitor_triggercondition takes string label, triggercondition handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_triggercondition", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_triggercondition(label, handleToTrack)
debug endmethod
debug method monitor_triggeraction takes string label, triggeraction handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_triggeraction", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_triggeraction(label, handleToTrack)
debug endmethod
debug method monitor_force takes string label, force handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_force", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_force(label, handleToTrack)
debug endmethod
debug method monitor_group takes string label, group handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_group", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_group(label, handleToTrack)
debug endmethod
debug method monitor_location takes string label, location handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_location", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_location(label, handleToTrack)
debug endmethod
debug method monitor_rect takes string label, rect handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_rect", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_rect(label, handleToTrack)
debug endmethod
debug method monitor_boolexpr takes string label, boolexpr handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_boolexpr", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_boolexpr(label, handleToTrack)
debug endmethod
debug method monitor_effect takes string label, effect handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_effect", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_effect(label, handleToTrack)
debug endmethod
debug method monitor_unitpool takes string label, unitpool handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_unitpool", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_unitpool(label, handleToTrack)
debug endmethod
debug method monitor_itempool takes string label, itempool handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_itempool", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_itempool(label, handleToTrack)
debug endmethod
debug method monitor_quest takes string label, quest handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_quest", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_quest(label, handleToTrack)
debug endmethod
debug method monitor_defeatcondition takes string label, defeatcondition handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_defeatcondition", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_defeatcondition(label, handleToTrack)
debug endmethod
debug method monitor_timerdialog takes string label, timerdialog handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_timerdialog", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_timerdialog(label, handleToTrack)
debug endmethod
debug method monitor_leaderboard takes string label, leaderboard handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_leaderboard", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_leaderboard(label, handleToTrack)
debug endmethod
debug method monitor_multiboard takes string label, multiboard handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_multiboard", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_multiboard(label, handleToTrack)
debug endmethod
debug method monitor_multiboarditem takes string label, multiboarditem handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_multiboarditem", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_multiboarditem(label, handleToTrack)
debug endmethod
debug method monitor_dialog takes string label, dialog handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_dialog", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_dialog(label, handleToTrack)
debug endmethod
debug method monitor_button takes string label, button handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_button", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_button(label, handleToTrack)
debug endmethod
debug method monitor_texttag takes string label, texttag handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_texttag", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_texttag(label, handleToTrack)
debug endmethod
debug method monitor_lightning takes string label, lightning handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_lightning", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_lightning(label, handleToTrack)
debug endmethod
debug method monitor_image takes string label, image handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_image", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_image(label, handleToTrack)
debug endmethod
debug method monitor_ubersplat takes string label, ubersplat handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_ubersplat", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_ubersplat(label, handleToTrack)
debug endmethod
debug method monitor_region takes string label, region handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_region", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_region(label, handleToTrack)
debug endmethod
debug method monitor_fogmodifier takes string label, fogmodifier handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_fogmodifier", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_fogmodifier(label, handleToTrack)
debug endmethod
debug method monitor_hashtable takes string label, hashtable handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_hashtable", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_hashtable(label, handleToTrack)
debug endmethod
static if DEBUG_MODE then
//! runtextmacro optional MEMORY_ANALYSIS_STATIC_FIELD_NEW("recycler")
static method calculateMemoryUsage takes nothing returns integer
return calculateAllocatedMemory__recycler()
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
return allocatedMemoryString__recycler()
endmethod
endif
endif
/*
* analysis
*/
static if LIBRARY_ErrorMessage then
debug method operator allocated takes nothing returns boolean
debug return recycler[this] == -1
debug endmethod
endif
/*
* initialization
*/
private static method onInit takes nothing returns nothing
set recycler[0] = 1
endmethod
endmodule
endlibrary
library RiseAndFall requires ListT optional UnitDex
/*
RiseAndFall v1.05
by Spellbound
Special thanks to Wareditor for the math and re-organising my code and got rid of a lot of
needless lines and methods.
This simple library can be used to simulate an airborne effect by causing units to bob up and
down. It can also be used to make a unit fall from a certain height or rise in the air. The
purpose of this library is to be used with AttachObject, but one could always find some other
use for it.
_________________________________________________________________________
REQUIREMENTS
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Required:
ListT: https://www.hiveworkshop.com/threads/containers-list-t.249011/
Optional
UnitDex: https://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
UnitDex will replace hashtables for retrieving airbone instances. Highly recommended so
as to avoid the hashtable limit.
PS if you want units with non-hover or non-flying movement type to be able to levitate, you
need to give them and then immediately remove Crow Form from the. Alternatively, just get an
Autofly library and make your life easier. One is available in the test map. Requires UnitDex.
_________________________________________________________________________
API
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
operator:
RiseAndFall[yourUnit] will return the RiseAndFall instance of a unit.
static methods:
RiseAndFall.create(unit u, real currentZ, real endZ, real duration, boolean flag)
^ This will cause a unit to changed its height from currentZ to endZ over duration.
If the flag is true, the unit will decelerate as they reach destination height. This
can be useful for units that fly or hover.
This function returns the struct instance if you wish to store it.
RiseAndFall.createAirborne(unit u, real currentZ, real endZ, real duration)
^ This will make your unit appear to levitate between currentZ and endZ over duration.
Set a narrow distance for a more realistic effect.
This function returns the struct instance if you wish to store it.
RiseAndFall.isUnitAirborne(unit u)
^ This returns true if a unit is airborne/falling/rising.
non-static methods:
RiseAndFall.end(real endZ, real speed)
^ Ends the Rise/Fall/Airborne of a unit. real endZ determines the height at which you
want the unit to end at and speed determines how fast in gets there. use Warcraft 3
missile speed for referrence.
Set to the current height of the unit to terminate immediately.
*/
globals
private constant real INTERVAL = .03125
endglobals
private module Init
private static method onInit takes nothing returns nothing
static if not LIBRARY_UnitDex then
set instance_storage = InitHashtable()
endif
set list = IntegerList.create()
endmethod
endmodule
struct RiseAndFall
private unit u
private real heightStart
private real heightEnd
private real speed
private real progress
private boolean useSmoothstep
private boolean isAirborne
private static IntegerList list
private static timer clock = CreateTimer()
static if LIBRARY_UnitDex then
private static integer array instance
else
private static hashtable instance_storage
endif
static method operator [] takes unit u returns thistype
static if LIBRARY_UnitDex then
return instance[GetUnitId(u)]
else
return LoadInteger(instance_storage, GetHandleId(u), 0)
endif
endmethod
static method isUnitAirborne takes unit u returns boolean
static if LIBRARY_UnitDex then
return instance[GetUnitId(u)] != 0
else
return LoadInteger(instance_storage, GetHandleId(u), 0) != 0
endif
endmethod
method destroy takes nothing returns nothing
static if LIBRARY_UnitDex then
set instance[GetUnitId(u)] = 0
else
call FlushChildHashtable(instance_storage, GetHandleId(.u))
endif
set .u = null
call list.removeElem(this)
if list.size() == 0 then
call PauseTimer(clock)
endif
call .deallocate()
endmethod
private static method update takes nothing returns nothing
local thistype this
local IntegerListItem node = list.first
local IntegerListItem nodeNext
local real s
local real hs
loop
exitwhen node == 0
set nodeNext = node.next
set this = node.data
set .progress = .progress + .speed
if .progress >= 1.then
call SetUnitFlyHeight(.u, .heightEnd, 0.)
if .isAirborne then
set hs = .heightStart
set .heightStart = .heightEnd
set .heightEnd = hs
set .progress = 0.
else
call .destroy()
endif
else
set s = .progress
if .useSmoothstep then
call SetUnitFlyHeight(.u, .heightStart + ( .heightEnd - .heightStart ) * (s * s * s * (s * (s * 6 - 15) + 10)), 0.) //smoothstep
else
call SetUnitFlyHeight(.u, .heightStart + ( .heightEnd - .heightStart ) * (s * s), 0.)
endif
endif
set node = nodeNext
endloop
endmethod
method end takes real endZ, real spd returns nothing
local real height = GetUnitFlyHeight(.u)
if endZ != height then
set .heightStart = height
set .heightEnd = endZ
set .progress = 0.
set .isAirborne = false
set .useSmoothstep = false
if spd == 0. then // divide by zero prevention
set spd = 600.
endif
set .speed = INTERVAL / ((.heightStart - .heightEnd) / spd)
else
call .destroy()
endif
endmethod
private static method createEx takes unit u, real currentZ, real endZ, real duration, boolean smooth, boolean airborn returns thistype
local thistype this = RiseAndFall[u]
if this != 0 then
call this.end(GetUnitFlyHeight(u), 1.)
endif
set this = allocate()
set this.u = u
set this.heightStart = currentZ
set this.heightEnd = endZ
set this.progress = 0.
set this.speed = INTERVAL/duration
set this.useSmoothstep = smooth
set this.isAirborne = airborn
static if LIBRARY_UnitDex then
set instance[GetUnitId(u)] = this
else
call SaveInteger(instance_storage, GetHandleId(u), 0, this)
endif
call list.push(this)
if list.size() == 1 then
call TimerStart(clock, INTERVAL, true, function thistype.update)
endif
return this
endmethod
static method create takes unit u, real currentZ, real endZ, real duration, boolean smooth returns thistype
return createEx(u, currentZ, endZ, duration, smooth, false)
endmethod
static method createAirborne takes unit u, real currentZ, real endZ, real duration returns thistype
return createEx(u, currentZ, endZ, duration, true, true)
endmethod
implement Init
endstruct
endlibrary
//TESH.scrollpos=9
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Timer32 ~~ By Jesus4Lyf ~~ Version 1.06 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Timer32?
// - Timer32 implements a fully optimised timer loop for a struct.
// - Instances can be added to the loop, which will call .periodic every
// PERIOD until .stopPeriodic() is called.
//
// =Pros=
// - Efficient.
// - Simple.
//
// =Cons=
// - Only allows one period.
// - The called method must be named ".periodic".
//
// Methods:
// - struct.startPeriodic()
// - struct.stopPeriodic()
//
// - private method periodic takes nothing returns nothing
//
// This must be defined in structs that implement Periodic Module.
// It will be executed by the module every PERIOD until .stopPeriodic() is called.
// Put "implement T32x" BELOW this method.
//
// Modules:
// - T32x
// Has no safety on .stopPeriodic or .startPeriodic (except debug messages
// to warn).
//
// - T32xs
// Has safety on .stopPeriodic and .startPeriodic so if they are called
// multiple times, or while otherwise are already stopped/started respectively,
// no error will occur, the call will be ignored.
//
// - T32
// The original, old version of the T32 module. This remains for backwards
// compatability, and is deprecated. The periodic method must return a boolean,
// false to continue running or true to stop.
//
// Details:
// - Uses one timer.
//
// - Do not, within a .periodic method, follow a .stopPeriodic call with a
// .startPeriodic call.
//
// How to import:
// - Create a trigger named T32.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Infinitegde for finding a bug in the debug message that actually altered
// system operation (when in debug mode).
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library T32 initializer OnInit
globals
public constant real PERIOD=0.03125
public constant integer FPS=R2I(1/PERIOD)
public integer Tick=0 // very useful.
//==============================================================================
private trigger Trig=CreateTrigger()
endglobals
//==============================================================================
// The standard T32 module, T32x.
//
module T32x
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
method stopPeriodic takes nothing returns nothing
debug if this.prev==0 and thistype(0).next!=this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had stopPeriodic called while not running!")
debug endif
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The standard T32 module with added safety checks on .startPeriodic() and
// .stopPeriodic(), T32xs.
//
module T32xs
private thistype next
private thistype prev
private boolean runningPeriodic
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
if not this.runningPeriodic then
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
set this.runningPeriodic=true
endif
endmethod
method stopPeriodic takes nothing returns nothing
if this.runningPeriodic then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
set this.runningPeriodic=false
endif
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The original T32 module, for backwards compatability only.
//
module T32 // deprecated.
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
if this.periodic() then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endif
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// System Core.
//
private function OnExpire takes nothing returns nothing
set Tick=Tick+1
call TriggerEvaluate(Trig)
endfunction
private function OnInit takes nothing returns nothing
call TimerStart(CreateTimer(),PERIOD,true,function OnExpire)
endfunction
endlibrary
//TESH.scrollpos=75
//TESH.alwaysfold=0
/*
Lightning System v1.03
by Adiktuz
Basically it allows you to easily create timed or un-timed lightning effects
Features:
->You can create lightnings between two points, two unit, or a point and a unit.
->For lightnings attached to a unit, the system automatically updates the lightning
for changes on the unit (like unit position, height etc)
->Specify the height of the lightning
->Create timed-lightnings that get automatically destroyed when their duration is over
->Supports moving points too (but the lightnings are forced to be timed)
->Allows you to add actions that will run when a lightning has ended and during
update (time of which is equal to T32's period)
->Allows you to attach any type of custom data to each instance
Methods available
How to use: call Lightning.methodName(parameters)
unitToPoint takes unit unit1, real x, real y, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
unitToUnit takes unit unit1, unit unit2, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
pointToPoint takes real sourceX, real sourceY,real targetX, real targetY, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
pointToPointEx takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real targetZ, real duration, string leffect, integer eventkey returns thistype
unitToPointEx takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real duration, string leffect, integer eventkey returns thistype
pointToPointExZ takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real sourceCurZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey returns thistype
unitToPointExZ takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey returns thistype
Parameters:
unit unit1 -> unit end of the lightning
unit unit2 -> other unit end of the lightning for the UTU methods
real x,y -> X,Y coordinates of the point end of the lightning for the UTP methods
real sourceX,sourceY -> X,Y coordinates of the first point of the lightning for the PTP methods
real sourceZ,targetZ -> height of the lightning at each ends (actual height is calculated as z + height of unit (if there's a unit end) + locationZ)
real deltaSourceX,deltaSourceY,deltaTargetX,deltaTargetY,sourceCurZ,targetCurZ -> for the Ex and ExZ methods, the final value of each coordinate/height
(the lightning moves from sourceX to deltaSourceX, etc through the given time)
boolean timed -> whether the lightning has a timed life or not, defaulted to true for the Ex and ExZ methods
real duration -> timed life of the lightning
string leffect -> string name of the lightning effect
integer eventkey -> a key used to determine the correct update and end functions to run if available
(if you're not using the update and end events, you're probably saf to just set it to 0)
Note: all of the above methods return the Lightning instance so you can save it in a variable
Extra/Interface/Events:
registerUpdateEvent(integer eventkey, code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning with the
same eventkey as the one registered is updated (every T32_PERIOD)
registerEndEvent(integer eventkey, code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning with the
same eventkey as the one registered ends
NOTE: If you're going to use the next three functions/methods, make sure you set the
corresponding boolean at the globals block to true
registerGlobalUpdateEvent(code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning
is updated (every T32_PERIOD)
registerGlobalEndEvent(code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning ends
registerGlobalCreateEvent(code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning is created
To allow creation and usage of custom data that is attached to every instance
turn the boolean USE_CUSTOM_DATA to true
then to add a custom data to an instance:
for integers:
set YourLightningInstance.customData[integer key] = value
for others:
set YourLightningInstance.customData.type[integer key] = value
->type can be real,unit,trigger,effect, etc...
->integer key is the key that will point to the data, you can utilize StringHash if you want to use strings
something like: customData.real[StringHash("damage")]
then to load data:
YourLightningInstance.customData.type[integer key]
To forcefully remove a lightning:
remove() returns nothing
To obtain which lightning instance triggered the events:
instance()
*/
//DO NOT EDIT ANYTHING BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING
//Note: I've set the checkvisibility field to false because the lightnings look
// weird when I set it to true (sometimes they "jump")
library LightningSystem requires T32, Table
globals
//Set this to true if you're gonna use the global update event handler
private constant boolean USE_GLOBAL_UPDATE = false
//Set this to true if you're gonna use the global end event handler
private constant boolean USE_GLOBAL_END = false
//Set this to true if you're gonna use the global create event handler
private constant boolean USE_GLOBAL_CREATE = false
//Set this to true if you're gonna use the custom data feature
private constant boolean USE_CUSTOM_DATA = true
private location loc = Location(0,0)
public Table UpdateTable
public Table EndTable
private trigger globalUpdate
private trigger globalEnd
private trigger globalCreate
endglobals
private module init
static method onInit takes nothing returns nothing
set EndTable = Table.create()
set UpdateTable = Table.create()
static if USE_GLOBAL_UPDATE then
set globalUpdate = CreateTrigger()
endif
static if USE_GLOBAL_END then
set globalEnd = CreateTrigger()
endif
static if USE_GLOBAL_CREATE then
set globalCreate = CreateTrigger()
endif
endmethod
endmodule
struct Lightning extends array
lightning light
real sourceX
real targetX
real sourceY
real targetY
real sourceZ
real targetZ
real sourceZOffset
real targetZOffset
real deltaSourceX
real deltaTargetX
real deltaSourceY
real deltaTargetY
real sourceCurZ
real targetCurZ
real deltaSourceZ
real deltaTargetZ
unit u1
unit u2
integer xtype
boolean timed
boolean moving
real duration
integer eventkey
Table customData
static thistype instance
private static integer instanceCount = 0
private static thistype recycle = 0
private thistype recycleNext
static method registerEndEvent takes integer eventkey, code toDo returns nothing
if not EndTable.handle.has(eventkey) then
set EndTable.trigger[eventkey] = CreateTrigger()
endif
call TriggerAddCondition(EndTable.trigger[eventkey],Filter(toDo))
endmethod
static method registerUpdateEvent takes integer eventkey, code toDo returns nothing
if not UpdateTable.handle.has(eventkey) then
set UpdateTable.trigger[eventkey] = CreateTrigger()
endif
call TriggerAddCondition(UpdateTable.trigger[eventkey],Filter(toDo))
endmethod
static method registerGlobalEndEvent takes code toDo returns nothing
call TriggerAddCondition(globalEnd,Filter(toDo))
endmethod
static method registerGlobalUpdateEvent takes code toDo returns nothing
call TriggerAddCondition(globalUpdate,Filter(toDo))
endmethod
static method registerGlobalCreateEvent takes code toDo returns nothing
call TriggerAddCondition(globalCreate,Filter(toDo))
endmethod
method remove takes nothing returns nothing
call DestroyLightning(this.light)
set instance = this
if EndTable.handle.has(this.eventkey) then
call TriggerEvaluate(EndTable.trigger[this.eventkey])
endif
static if USE_GLOBAL_END then
call TriggerEvaluate(globalEnd)
endif
call this.stopPeriodic()
set this.deltaSourceZ = 0.0
set this.deltaTargetZ = 0.0
set .recycleNext=recycle
set recycle=this
endmethod
static method new takes nothing returns thistype
local thistype this
if (recycle == 0) then
set instanceCount = instanceCount + 1
return instanceCount
else
set this = recycle
set recycle = recycle.recycleNext
endif
return this
endmethod
private method periodic takes nothing returns nothing
if this.xtype == 1 then
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.sourceCurZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
if this.moving then
set this.targetX = this.targetX + this.deltaTargetX
set this.targetY = this.targetY + this.deltaTargetY
endif
if this.deltaTargetZ != 0.0 then
set this.targetZ = this.targetZ + this.deltaTargetZ
endif
set this.targetCurZ = targetZ + this.deltaTargetZ
call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
elseif this.xtype == 2 then
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = GetUnitX(this.u2)
set this.targetY = GetUnitY(this.u2)
set this.sourceCurZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
set this.targetCurZ = targetZOffset + BlzGetLocalUnitZ(this.u2) + GetUnitFlyHeight(this.u2)
call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
else
if this.moving then
set this.sourceX = this.sourceX + this.deltaSourceX
set this.targetX = this.targetX + this.deltaTargetX
set this.sourceY = this.sourceY + this.deltaSourceY
set this.targetY = this.targetY + this.deltaTargetY
if this.deltaSourceZ != 0.0 then
set this.sourceZ = this.sourceZ + this.deltaSourceZ
endif
if this.deltaTargetZ != 0.0 then
set this.targetZ = this.targetZ + this.deltaTargetZ
endif
set this.sourceCurZ = sourceZ + this.deltaSourceZ
set this.targetCurZ = targetZ + this.deltaTargetZ
call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
endif
endif
set instance = this
if UpdateTable.handle.has(this.eventkey) then
call TriggerEvaluate(UpdateTable.trigger[this.eventkey])
endif
static if USE_GLOBAL_UPDATE then
call TriggerEvaluate(globalUpdate)
endif
if this.timed then
set this.duration = this.duration - T32_PERIOD
if this.duration <= 0.0 then
call this.remove()
endif
endif
endmethod
implement T32x
static method unitToPoint takes unit unit1, real x, real y, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = unit1
set this.u2 = null
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = x
set this.targetY = y
set this.sourceZOffset =sourceZ
//call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = timed
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 1
set this.moving = false
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method unitToUnit takes unit unit1, unit unit2, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = unit1
set this.u2 = unit2
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = GetUnitX(this.u2)
set this.targetY = GetUnitY(this.u2)
set this.sourceZOffset =sourceZ
set this.targetZOffset =targetZ
//call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
//call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZOffset + BlzGetLocalUnitZ(this.u2) + GetUnitFlyHeight(this.u2)
set this.timed = timed
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 2
set this.moving = false
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method pointToPoint takes real sourceX, real sourceY,real targetX, real targetY, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = null
set this.u2 = null
set this.sourceX = sourceX
set this.sourceY = sourceY
set this.targetX = targetX
set this.targetY = targetY
call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZ + GetLocationZ(loc)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = timed
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 3
set this.moving = false
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method pointToPointEx takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real targetZ, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = null
set this.u2 = null
set this.sourceX = sourceX
set this.sourceY = sourceY
set this.targetX = targetX
set this.targetY = targetY
set this.deltaSourceX = (deltaSourceX - sourceX)*(T32_PERIOD/duration)
set this.deltaSourceY = (deltaSourceY - sourceY)*(T32_PERIOD/duration)
set this.deltaTargetX = (deltaTargetX - targetX)*(T32_PERIOD/duration)
set this.deltaTargetY = (deltaTargetY - targetY)*(T32_PERIOD/duration)
call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZ + GetLocationZ(loc)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = true
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 3
set this.moving = true
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method unitToPointEx takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = unit1
set this.u2 = null
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = x
set this.targetY = y
set this.sourceZOffset =sourceZ
set this.deltaTargetX = (xx - x)*(T32_PERIOD/duration)
set this.deltaTargetY = (yx - y)*(T32_PERIOD/duration)
//call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = true
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 1
set this.moving = true
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method pointToPointExZ takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real sourceCurZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = null
set this.u2 = null
set this.sourceX = sourceX
set this.sourceY = sourceY
set this.targetX = targetX
set this.targetY = targetY
set this.deltaSourceZ = (sourceCurZ - sourceZ)*(T32_PERIOD/duration)
set this.deltaTargetZ = (targetCurZ-targetZ)*(T32_PERIOD/duration)
set this.deltaSourceX = (deltaSourceX - sourceX)*(T32_PERIOD/duration)
set this.deltaSourceY = (deltaSourceY - sourceY)*(T32_PERIOD/duration)
set this.deltaTargetX = (deltaTargetX - targetX)*(T32_PERIOD/duration)
set this.deltaTargetY = (deltaTargetY - targetY)*(T32_PERIOD/duration)
call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZ + GetLocationZ(loc)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = true
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 3
set this.moving = true
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method unitToPointExZ takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = unit1
set this.u2 = null
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = x
set this.targetY = y
set this.sourceZOffset =sourceZ
set this.deltaTargetZ = (targetCurZ - targetZ)*(T32_PERIOD/duration)
set this.deltaTargetX = (xx - x)*(T32_PERIOD/duration)
set this.deltaTargetY = (yx - y)*(T32_PERIOD/duration)
//call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = true
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 1
set this.moving = true
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
implement init
endstruct
endlibrary
//TESH.scrollpos=114
//TESH.alwaysfold=0
/*
Lightning Utilities v1.01
by Adiktuz
A set of methods that can help you make more out of the
lightning system.
I chose to separate it from the main system because these are
extra methods only to extend the capabilities of the LS.
This way, the user has the option of not using LU library
as the LS will work fine without it.
How to use:
LightningUtils.method(parameters)
Methods:
enumUnits(group g, Lightning light, real radius)
Parameters:
group g -> group that you want to fill with the units between the Lightning's ends
Lightning light -> the Lightning object
real radius -> radius around the Lightning in which unit's will be picked
Note: the following Gradient methods are only for timed lightnings
registerGradientKey(integer eventkey)
->eventkey of the Lightning's that you want to have a color/alpha gradient
Notes:
->it is important that you register first the eventkey using this method
before using the next method which sets the gradient of each Lightning
instance.
->Do this registration only once per eventkey
addLightningGradient(Lightning light, real red1, real blue1, real green1, real alpha1,real red2, real blue2, real green2, real alpha2)
Parameters:
Lightning light -> the Lightning instance that you want to have a gradient
real red1,blue1,green1,alpha1 -> the initial values of the colors/alpha of the Lightning
real red2,blue2,green2,alpha2 -> the final values of the colors/alpha of the Lightning
->these reals are from 0.0 up to 1.0
Notes:
->Make sure that the eventkey used by this Lightning is already registered using the
method above (registerGradientKey)
->This method automatically fetches the duration of the Lightning
->Do not modify the Lightning's duration afterwards else it might look bad
See the Example trigger for an example of how to use these methods.
*/
library LightningUtilities requires LightningSystem
private module init
static method onInit takes nothing returns nothing
set thistype.redTable = Table.create()
set thistype.blueTable = Table.create()
set thistype.greenTable = Table.create()
set thistype.alphaTable = Table.create()
set thistype.redCTable = Table.create()
set thistype.blueCTable = Table.create()
set thistype.greenCTable = Table.create()
set thistype.alphaCTable = Table.create()
endmethod
endmodule
struct LightningUtils extends array
private static group tmpGroup = CreateGroup()
private static unit tmpUnit = null
private static Table redTable
private static Table blueTable
private static Table greenTable
private static Table alphaTable
private static Table redCTable
private static Table blueCTable
private static Table greenCTable
private static Table alphaCTable
static method enumUnits takes group g, Lightning light, real radius returns nothing
local real tdy = (light.targetY-light.sourceY)
local real tdx = (light.targetX-light.sourceX)
local real angle = Atan2(tdy,tdx)
local real distance = (tdy*tdy)+(tdx*tdx)
local integer iend = R2I(distance/(radius*radius))
local real dx = tdx/iend
local real dy = tdy/iend
//we only get units in between the lightning
local integer i = 1
set iend = iend - 1
call GroupClear(g)
loop
call GroupEnumUnitsInRange(tmpGroup,light.sourceX+i*dx,light.sourceY+i*dy,radius,null)
loop
set tmpUnit = FirstOfGroup(tmpGroup)
exitwhen tmpUnit == null
if not IsUnitInGroup(tmpUnit,g) then
call GroupAddUnit(g,tmpUnit)
endif
call GroupRemoveUnit(tmpGroup,tmpUnit)
endloop
set i = i + 1
exitwhen i > iend
endloop
endmethod
//I used Table to save the RGBA values because if I use the GeLightningColor natives, it returns
//rounded down values, resulting to bad behavior at durations > 4.0
static method updateGradient takes nothing returns nothing
set redCTable.real[Lightning.instance] = redCTable.real[Lightning.instance] + redTable.real[Lightning.instance]
set blueCTable.real[Lightning.instance] = blueCTable.real[Lightning.instance] + blueTable.real[Lightning.instance]
set greenCTable.real[Lightning.instance] = greenCTable.real[Lightning.instance] + greenTable.real[Lightning.instance]
set alphaCTable.real[Lightning.instance] = alphaCTable.real[Lightning.instance] + alphaTable.real[Lightning.instance]
call SetLightningColor(Lightning.instance.light, redCTable.real[Lightning.instance],greenCTable.real[Lightning.instance],blueCTable.real[Lightning.instance],alphaCTable.real[Lightning.instance])
endmethod
static method addLightningGradient takes Lightning light, real red1, real blue1, real green1, real alpha1,real red2, real blue2, real green2, real alpha2 returns nothing
set redCTable.real[light] = red1
set blueCTable.real[light] = blue1
set greenCTable.real[light] = green1
set alphaCTable.real[light] = alpha1
set redTable.real[light] = (((red2-red1)/light.duration)*T32_PERIOD)
set blueTable.real[light] = (((blue2-blue1)/light.duration)*T32_PERIOD)
set greenTable.real[light] = (((green2-green1)/light.duration)*T32_PERIOD)
set alphaTable.real[light] = (((alpha2-alpha1)/light.duration)*T32_PERIOD)
endmethod
static method registerGradientKey takes integer eventkey returns nothing
call Lightning.registerUpdateEvent(eventkey,function thistype.updateGradient)
endmethod
implement init
endstruct
endlibrary
scope ElemetalLaserFx initializer onInit
//handles the graphical configuration for the elemental laser, the damage and projectile configuration is done in the object editor
globals
private constant integer UNIT_ID = 'h000' //Unit ID of the elemental laser
private constant integer DUMMY_ID = 'dumi' //Unit ID of the dummy for attaching effects and lightnings
private constant string CORE_FX_PATH = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl" //Effect path for the core
private constant real CORE_FX_SCALE = 2.0 //Scale for the core effect
private constant real CORE_FX_ANGLE = 0. //Angle offset for the core effect (For attach object)
private constant real CORE_FX_DISTANCE = 0. //Distance offset for the core effect (For attach object)
private constant real CORE_FX_HEIGHT = 0. //Height offset for the core effect (For attach object)
private constant string CONTAINMENT_FX_PATH = "war3mapImported\\Sacred Guard Red.mdl" //Effect path for the field around the core
private constant real CONTAINMENT_FX_SCALE = 1.5 //Scale for the field effect
private constant real CONTAINMENT_FX_ANGLE = CORE_FX_ANGLE //Angle offset for the field effect (For attach object)
private constant real CONTAINMENT_FX_DISTANCE = CORE_FX_DISTANCE //Distace offset for the field effect (For attach object)
private constant real CONTAINMENT_FX_HEIGHT = CORE_FX_HEIGHT //Height offset for the field effect (For attach object)
private constant string FRAME_POINT_FX_PATH = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl" //Effect of the points of the outer frame
private constant real FRAME_POINT_FX_SCALE = 2.0 //Scale for the point effect
private constant real FRAME_POINT_FX_ANGLE = 45. //Base Angle for the core effect
private constant real FRAME_POINT_FX_DISTANCE = 100. //Base Distance for the core effect
private constant real FRAME_POINT_FX_HEIGHT = 100. //Base Height for the core effect
private constant string FRAME_LIGHTNING_EFFECT = "BLPA" //Lightning effect froming the frame
private constant string EMITTER_FX_PATH = "Abilities\\Weapons\\AncestralGuardianMissile\\AncestralGuardianMissile.mdl" //Effect of the of the emitter
private constant real EMITTER_FX_SCALE = 2.0 //Scale for the emitter effect
private constant real EMITTER_FX_ANGLE = 0. //Angle for the field effect, recommended value is 0. so the laser can aim
private constant real EMITTER_FX_DISTANCE = 200. //Distance for the field effect recommended value is equal to the laser unit's projectile launch z so the projectile fires from the emitter
private constant real EMITTER_FX_HEIGHT = 0. //Base Height for the emitter effect recommended value is equal to the laser unit's projectile launch y so the projectile fires from the emitter
private constant string EMITTER_LIGHTNING_EFFECT = "REPA"//Lightning effect froming the frame to the emitter
private hashtable table = InitHashtable()
endglobals
private function onEnterConditions takes nothing returns boolean
return GetUnitTypeId(udg_UDexUnits[udg_UDex]) == UNIT_ID
endfunction
private function onEnterActions takes nothing returns nothing
local unit u = udg_UDexUnits[udg_UDex]
//core
local unit dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
local effect fx=AddSpecialEffectTarget(CORE_FX_PATH,dummy,"origin")
local unit framepoint1
local unit framepoint2
local unit framepoint3
local unit framepoint4
local unit framepoint5
local unit framepoint6
local unit framepoint7
local unit framepoint8
local unit emitter
call SetUnitScale(dummy,CORE_FX_SCALE,CORE_FX_SCALE,CORE_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,CORE_FX_ANGLE,CORE_FX_DISTANCE,CORE_FX_HEIGHT,0., false)
//containment field
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(CONTAINMENT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,CONTAINMENT_FX_SCALE,CONTAINMENT_FX_SCALE,CONTAINMENT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,CONTAINMENT_FX_ANGLE,CONTAINMENT_FX_DISTANCE,CONTAINMENT_FX_HEIGHT,0., false)
//framepoint 1
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(FRAME_POINT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,FRAME_POINT_FX_ANGLE,FRAME_POINT_FX_DISTANCE,FRAME_POINT_FX_HEIGHT,0., false)
set framepoint1 = dummy
//framepoint 2
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(FRAME_POINT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,-FRAME_POINT_FX_ANGLE,FRAME_POINT_FX_DISTANCE,FRAME_POINT_FX_HEIGHT,0., false)
set framepoint2 = dummy
//framepoint3
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(FRAME_POINT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,FRAME_POINT_FX_ANGLE,-FRAME_POINT_FX_DISTANCE,FRAME_POINT_FX_HEIGHT,0., false)
set framepoint3 = dummy
//framepoint4
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(FRAME_POINT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,FRAME_POINT_FX_ANGLE,FRAME_POINT_FX_DISTANCE,-FRAME_POINT_FX_HEIGHT,0., false)
set framepoint4 = dummy
//framepoint5
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(FRAME_POINT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,-FRAME_POINT_FX_ANGLE,-FRAME_POINT_FX_DISTANCE,FRAME_POINT_FX_HEIGHT,0., false)
set framepoint5 = dummy
//framepoint6
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(FRAME_POINT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,FRAME_POINT_FX_ANGLE,-FRAME_POINT_FX_DISTANCE,-FRAME_POINT_FX_HEIGHT,0., false)
set framepoint6 = dummy
//framepoint7
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(FRAME_POINT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,-FRAME_POINT_FX_ANGLE,FRAME_POINT_FX_DISTANCE,-FRAME_POINT_FX_HEIGHT,0., false)
set framepoint7 = dummy
//framepoint8
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(FRAME_POINT_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE,FRAME_POINT_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,-FRAME_POINT_FX_ANGLE,-FRAME_POINT_FX_DISTANCE,-FRAME_POINT_FX_HEIGHT,0., false)
set framepoint8 = dummy
//emitter
set dummy=CreateUnit(GetOwningPlayer(u),DUMMY_ID,GetUnitX(u),GetUnitY(u), 0.)
set fx=AddSpecialEffectTarget(EMITTER_FX_PATH,dummy,"origin")
call SetUnitScale(dummy,EMITTER_FX_SCALE,EMITTER_FX_SCALE,EMITTER_FX_SCALE)
call SaveEffectHandle(table,GetHandleId(dummy),0,fx)
call AttachUnitToHost(dummy,u,EMITTER_FX_ANGLE,EMITTER_FX_DISTANCE,EMITTER_FX_HEIGHT,0., false)
set emitter = dummy
//frame lightnings
call SaveInteger(table,GetHandleId(framepoint1),1,Lightning.unitToUnit(framepoint1,framepoint2,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint1),2,Lightning.unitToUnit(framepoint1,framepoint4,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint1),3,Lightning.unitToUnit(framepoint1,framepoint5,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint2),1,Lightning.unitToUnit(framepoint2,framepoint3,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint2),2,Lightning.unitToUnit(framepoint2,framepoint7,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint3),1,Lightning.unitToUnit(framepoint3,framepoint5,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint3),2,Lightning.unitToUnit(framepoint3,framepoint6,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint4),1,Lightning.unitToUnit(framepoint4,framepoint7,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint4),2,Lightning.unitToUnit(framepoint4,framepoint8,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint6),1,Lightning.unitToUnit(framepoint6,framepoint7,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint6),2,Lightning.unitToUnit(framepoint6,framepoint8,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(framepoint8),1,Lightning.unitToUnit(framepoint8,framepoint5,0.,0.,false,0.,FRAME_LIGHTNING_EFFECT,0))
//emiter lightnings
call SaveInteger(table,GetHandleId(emitter),1,Lightning.unitToUnit(emitter,framepoint1,0.,0.,false,0.,EMITTER_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(emitter),2,Lightning.unitToUnit(emitter,framepoint2,0.,0.,false,0.,EMITTER_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(emitter),3,Lightning.unitToUnit(emitter,framepoint4,0.,0.,false,0.,EMITTER_LIGHTNING_EFFECT,0))
call SaveInteger(table,GetHandleId(emitter),4,Lightning.unitToUnit(emitter,framepoint7,0.,0.,false,0.,EMITTER_LIGHTNING_EFFECT,0))
set u=null
set fx=null
set dummy=null
set framepoint1 = null
set framepoint2 = null
set framepoint3 = null
set framepoint4 = null
set framepoint5 = null
set framepoint6 = null
set framepoint7 = null
set framepoint8 = null
set emitter = null
endfunction
private function onHostDeathConditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == UNIT_ID
endfunction
private function onHostDeathActions takes nothing returns nothing
call DettachAllGuests(GetTriggerUnit(), true, 0.03)
endfunction
private function onGuestDeathConditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == DUMMY_ID // or GetUnitTypeId(GetTriggerUnit()) == EMITTER_ID
endfunction
private function onGuestDeathActions takes nothing returns nothing
local Lightning light = 0
local integer i = 0
call DestroyEffect(LoadEffectHandle(table, GetHandleId(GetTriggerUnit()),0))
loop
exitwhen i > 4
if HaveSavedInteger(table,GetHandleId(GetTriggerUnit()),i) then
set light = LoadInteger(table,GetHandleId(GetTriggerUnit()),i)
call light.remove()
call RemoveSavedInteger(table,GetHandleId(GetTriggerUnit()),i)
endif
set i = i + 1
endloop
endfunction
private function onInit takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 1.0)
call TriggerAddCondition(t,Condition(function onEnterConditions))
call TriggerAddAction(t,function onEnterActions)
set t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t,Condition(function onHostDeathConditions))
call TriggerAddAction(t,function onHostDeathActions)
set t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t,Condition(function onGuestDeathConditions))
call TriggerAddAction(t,function onGuestDeathActions)
set t=null
endfunction
endscope