Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ElectronCloud /*
*/requires /*
*/CTL /* https://github.com/nestharus/JASS/blob/master/jass/Systems/ConstantTimerLoop32/script.j
*/SpellEffectEvent /* https://www.hiveworkshop.com/threads/snippet-spelleffectevent.187193/
*/StunSystem /* https://www.hiveworkshop.com/threads/system-stun.196749/
*/DummyRecycler /* https://www.hiveworkshop.com/threads/dummy-recycler-v1-25.277659/
*/UnitDex /* https://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
*/Alloc /* https://www.hiveworkshop.com/threads/unique-id-allocation.260897/#resource-47368
*/optional Table /* https://www.hiveworkshop.com/threads/snippet-new-table.188084/
*/optional WorldBounds /* https://github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
*/optional ResourcePreloader /* https://www.hiveworkshop.com/threads/snippet-resource-preloader.287358/
*******************************************************************************
Electron Cloud v1.10
by : AGD
Trivia:
An Electron Cloud is a model used to describe the probabilistic location
of electrons in an atom. The cloud can be imagined as a hollow sphere with
a specific thickness where an electron can be found as it moves about the
nucleus in the center.
How to Import:
1. Copy all the necessary object editor data from this demo map to your map.
2. Copy this library together with all its library requirements to your map.
Note:
This spell uses the StunSystem library which breaks when used together with
default object editor stun abilities. Make sure you only use stuns from the
StunSystem library in your map.
*******************************************************************************
* *
* SPELL CONFIGURATION *
* *
*******************************************************************************/
globals
/*========================================================================*
* STATIC CONFIGURATION *
*=========================================================================*/
/*
* Periodic timer timeout
*/
private constant real TIMEOUT = 1.00/32.00
/*
* Spell raw code
*/
private constant integer SPELL_ID = 'DOTS'
/*
* Determines if the target emprisonment feature is enabled
* (Unneeded codes are removed during compile time when set to "false")
*/
private constant boolean ACTIVATE_PRISON = true
/*
* How long does a dummy unit last after death before being removed
*/
private constant real DUMMY_DEATH_DURATION = 2.00
/*
* Attack type
*/
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
/*
* Damage type
*/
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
/*
* Wespon type
*/
private constant weapontype WEAPON_TYPE = null
/*
* Special effect model of the electrons
*/
private constant string ELECTRON_MODEL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
private constant string ELECTRON_ATTACH_POINT = "origin"
/*
* Special effect model of the base of a border post
*/
private constant string BORDER_POST_BOTTOM_MODEL = "Doodads\\Cinematic\\GlowingRunes\\GlowingRunes4.mdl"
private constant string BORDER_POST_BOTTOM_ATTACH_POINT = "origin"
/*
* Special effect model of the top of a border post
*/
private constant string BORDER_POST_TOP_MODEL = "Doodads\\Cinematic\\GlowingRunes\\GlowingRunes4.mdl"
private constant string BORDER_POST_TOP_ATTACH_POINT = "origin"
/*
* Special effect model of the prison boundary marks (bottom)
*/
private constant string PRISON_MARK_BOTTOM_MODEL = "Abilities\\Weapons\\DragonHawkMissile\\DragonHawkMissile.mdl"
private constant string PRISON_MARK_BOTTOM_ATTACH_POINT = "origin"
/*
* Special effect model of the prison boundary marks (top)
*/
private constant string PRISON_MARK_TOP_MODEL = "Abilities\\Weapons\\DragonHawkMissile\\DragonHawkMissile.mdl"
private constant string PRISON_MARK_TOP_ATTACH_POINT = "origin"
/*
* Determines if the electron movement lightning effects are enabled
* (The check is done at compile time so that it gets rid of the unnecessary code parts)
*/
private constant boolean USE_ELECTRON_LIGHTNING_EFFECT = true
/*
* The model of the electron movement's lightning effect
*/
private constant string ELECTRON_LIGHTNING_MODEL = "CLSB"
/*
* How long does the lightning last after an electron arrives to
* the next electron
*/
private constant real ELECTRON_LIGHTNING_DEATH_DURATION = 0.25
/*
* The color of the electron movement's lightning effect
* (1.00 -> 100%)
*/
private constant real ELECTRON_LIGHTNING_ALPHA = 1.00
private constant real ELECTRON_LIGHTNING_RED = 0.20
private constant real ELECTRON_LIGHTNING_GREEN = 1.00
private constant real ELECTRON_LIGHTNING_BLUE = 0.20
/*
* Determines if the border lightning effects are eabled
* (The check is done at compile time so that it gets rid of the unnecessary code parts)
*/
private constant boolean USE_BORDER_POST_LIGHTNING_EFFECT = true
/*
* The model of the border lightning effects
*/
private constant string BORDER_POST_LIGHTNING_MODEL = "DRAM"
/*
* How long does the border lightnings last after the spell ends
*/
private constant real BORDER_POST_LIGHTNING_DEATH_DURATION = 0.25
/*
* The color of the border lightning effects
* (1.00 -> 100%)
*/
private constant real BORDER_POST_LIGHTNING_ALPHA = 1.00
private constant real BORDER_POST_LIGHTNING_RED = 1.00
private constant real BORDER_POST_LIGHTNING_GREEN = 1.00
private constant real BORDER_POST_LIGHTNING_BLUE = 1.00
endglobals
/*============================================================================*
* DYNAMIC CONFIGURATION *
*=============================================================================*/
/*
* The number of instances of electron creation process and electron traversal
*/
private constant function Threads takes integer level returns integer
return 3 + 0*level
endfunction
/*
* The number of electrons per thread
*/
private constant function ElectronCount takes integer level returns integer
return 50 + 20*level
endfunction
/*
* The delay before the spell vanishes after the last electron explodes
*/
private constant function CloudDestructionDelay takes integer level returns real
return 1.00 + 0.00*level
endfunction
/*
* The minimum distance at which an electron can be summoned from the center
*/
private constant function InnerRadius takes integer level returns real
return 400.00 + 0.00*level
endfunction
/*
* The maximum distance at which an electron can be summoned from the center
*/
private constant function OuterRadius takes integer level returns real
return 400.00 + 0.00*level
endfunction
/*
* The minimum height at which an electron can be summoned
*/
private constant function MinHeight takes integer level returns real
return 20.00 + 0.00*level
endfunction
/*
* The maximum height at which an electron can be summoned
*/
private constant function MaxHeight takes integer level returns real
return 340.00 + 0.00*level
endfunction
/*
* The radius of an electron explosion
*/
private constant function ElectronExplosionRadius takes integer level returns real
return 125.00 + 0.00*level
endfunction
/*
* The radius of an electron's damage per second's circular area when moving
*/
private constant function ElectronDpsRadius takes integer level returns real
return 100.00 + 0.00*level
endfunction
/*
* The distance for a unit to trigger an electron explosion when it (the
* electron) is stationary
*/
private constant function ElectronDetectionRadius takes integer level returns real
return 75.00 + 0.00*level
endfunction
/*
* The health damage dealt by an electron explosion
*/
private constant function ElectronExplosionHealthDamage takes integer level returns real
return 75.00 + 0.00*level
endfunction
/*
* The mana damage dealt by an electron explosion
*/
private constant function ElectronExplosionManaDamage takes integer level returns real
return 20.00 + 0.00*level
endfunction
/*
* The health damage per second dealt by an electron when moving
*/
private constant function ElectronHealthDps takes integer level returns real
return 200.00 + 0.00*level
endfunction
/*
* The mana damage per second dealt by an electron when moving
*/
private constant function ElectronManaDps takes integer level returns real
return 100.00 + 0.00*level
endfunction
/*
* The duration of the stun caused by an electron explosion
*/
private constant function ElectronExplosionStunDuration takes integer level returns real
return 0.50 + 0.00*level
endfunction
/*
* The duration of the stun caused by being damaged by a moving electron
*/
private constant function ElectronDpsStunDuration takes integer level returns real
return 0.10 + 0.00*level
endfunction
/*
* The electron creation interval (seconds)
*/
private constant function ElectronReleaseInterval takes integer level returns real
return 0.05 + 0.00*level
endfunction
/*
* The delay before the first electron starts moving after the creation phase
* of the electrons
*/
private constant function ElectronTraversalDelay takes integer level returns real
return 1.00 + 0.00*level
endfunction
/*
* The interval in which the next electron moves just after the current
* electron arrives at its destination
*/
private constant function ElectronTraversalInterval takes integer level returns real
return 0.00 + 0.00*level
endfunction
/*
* Movement speed of the electron in units per second
*/
private constant function ElectronMoveSpeed takes integer level returns real
return 2800.00 + 0.00*level
endfunction
/*
* The distance of the border posts from the center
*/
private constant function BorderPostsOffset takes integer level returns real
return OuterRadius(level)
endfunction
/*
* The height of the border posts' base
*/
private constant function BorderPostsMinHeight takes integer level returns real
return MinHeight(level) - 10.00
endfunction
/*
* The height of the border posts' top
*/
private constant function BorderPostsMaxHeight takes integer level returns real
return MaxHeight(level) + 10.00
endfunction
/*
* The radius of the circular area of emprisonment
*/
private constant function PrisonRadius takes integer level returns real
return BorderPostsOffset(level)
endfunction
/*
* The height of the bottom prison boundary marks
*/
private constant function PrisonBottomMarkHeight takes integer level returns real
return BorderPostsMinHeight(level)
endfunction
/*
* The height of the top prison boundary marks
*/
private constant function PrisonTopMarkHeight takes integer level returns real
return BorderPostsMaxHeight(level)
endfunction
/*
* The number of border posts
*/
private constant function BorderPostsCount takes integer level returns integer
return 16 + 0*level
endfunction
/*
* The number of prison boundary mark pairs (top and bottom)
*/
private constant function PrisonMarkCount takes integer level returns integer
return BorderPostsCount(level)
endfunction
/*
* The scale of the electrons
*/
private constant function ElectronScale takes integer level returns real
return 1.10 + 0.00*level
endfunction
/*
* The scale of the prison boundary marks
*/
private constant function PrisonMarkScale takes integer level returns real
return 0.75 + 0.00*level
endfunction
/*
* The scale of the border posts (base and top)
*/
private constant function BorderPostsDummyScale takes integer level returns real
return 1.10 + 0.00*level
endfunction
/*
* The boolean expression for filtering the units that will be allowed as
* the spell's targets
*/
private function TargetFilter takes unit caster, unit target returns boolean
return UnitAlive(target)
endfunction
/******************************************************************************
* *
* END OF SPELL CONFIGURATION *
* *
*******************************************************************************/
/*============================================================================*/
/* Node: Below is the spell's core code. It is not documented in detail so */
/* modify it at your own discretion. But it is advised not to modify */
/* it if you're not very experienced with vJass or if you're not so */
/* sure on what you're doing. */
/*============================================================================*/
private keyword SpellCore
private keyword StaticList
private keyword List
native UnitAlive takes unit u returns boolean
globals
private group enumGroup = CreateGroup()
endglobals
/*
* Static linked list module
*/
private module StaticList
readonly thistype prev
readonly thistype next
static constant method operator head takes nothing returns thistype
return 0
endmethod
static constant method operator first takes nothing returns thistype
return head.next
endmethod
static constant method operator last takes nothing returns thistype
return head.prev
endmethod
static constant method operator empty takes nothing returns boolean
return first == head
endmethod
method insert takes thistype node returns nothing
local thistype next = this.next
set next.prev = node
set this.next = node
set node.prev = this
set node.next = next
endmethod
method remove takes nothing returns nothing
local thistype prev = this.prev
local thistype next = this.next
set next.prev = prev
set prev.next = next
endmethod
endmodule
/*
* Instantiated linked list module
*/
private module List
readonly thistype prev
readonly thistype next
implement Alloc
method operator empty takes nothing returns boolean
return this.next == this
endmethod
method insert takes thistype node returns nothing
local thistype next = this.next
set next.prev = node
set this.next = node
set node.prev = this
set node.next = next
endmethod
method remove takes nothing returns nothing
local thistype prev = this.prev
local thistype next = this.next
set next.prev = prev
set prev.next = next
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
set this.prev = this
set this.next = this
return this
endmethod
method destroy takes nothing returns nothing
set this.prev = 0
set this.next = 0
call this.deallocate()
endmethod
endmodule
/*
* In case WorldBounds library is not present
*/
static if not LIBRARY_WorldBounds then
private struct MapBounds extends array
readonly static real minX
readonly static real minY
readonly static real maxX
readonly static real maxY
static method init takes nothing returns nothing
local rect bounds = GetWorldBounds()
set minX = GetRectMinX(bounds)
set minY = GetRectMinY(bounds)
set maxX = GetRectMaxX(bounds)
set maxY = GetRectMaxY(bounds)
call RemoveRect(bounds)
set bounds = null
endmethod
endstruct
endif
/*
* Functions used for implementing map bounds
*/
private function BoundedX takes real x returns real
static if LIBRARY_WorldBounds then
if x < WorldBounds.minX then
return I2R(WorldBounds.minX)
elseif x > WorldBounds.maxX then
return I2R(WorldBounds.maxX)
endif
else
if x < MapBounds.minX then
return I2R(MapBounds.minX)
elseif x > MapBounds.maxX then
return I2R(MapBounds.maxX)
endif
endif
return x
endfunction
private function BoundedY takes real y returns real
static if LIBRARY_WorldBounds then
if y < WorldBounds.minY then
return I2R(WorldBounds.minY)
elseif y > WorldBounds.maxY then
return I2R(WorldBounds.maxY)
endif
else
if y < MapBounds.minY then
return I2R(MapBounds.minY)
elseif y > MapBounds.maxY then
return I2R(MapBounds.maxY)
endif
endif
return y
endfunction
/*
* Lightning Struct
*/
static if not USE_ELECTRON_LIGHTNING_EFFECT and not USE_BORDER_POST_LIGHTNING_EFFECT then
else
private struct Lightning extends array
static if LIBRARY_Table then
private static key table
else
private static hashtable table = InitHashtable()
endif
private lightning lightning
implement Alloc
private static method destroyLightning takes nothing returns nothing
local timer expired = GetExpiredTimer()
local integer id = GetHandleId(expired)
static if LIBRARY_Table then
local thistype this = Table(table)[id]
call Table(table).remove(id)
else
local thistype this = LoadInteger(table, 0, id)
call RemoveSavedInteger(table, 0, id)
endif
call DestroyLightning(this.lightning)
set this.lightning = null
call DestroyTimer(expired)
set expired = null
endmethod
static method create takes string codeName, real alpha, real red, real green, real blue, real x1, real y1, real z1, real x2, real y2, real z2 returns thistype
local thistype this = allocate()
set this.lightning = AddLightningEx(codeName, true, x1, y1, z1, x2, y2, z2)
call SetLightningColor(this.lightning, red, green, blue, alpha)
return this
endmethod
method expire takes real delay returns nothing
local timer t = CreateTimer()
call TimerStart(t, delay, false, function thistype.destroyLightning)
static if LIBRARY_Table then
set Table(table)[GetHandleId(t)] = this
else
call SaveInteger(table, 0, GetHandleId(t), this)
endif
set t = null
endmethod
method move takes real x1, real y1, real z1, real x2, real y2, real z2 returns nothing
call MoveLightningEx(this.lightning, true, x1, y1, z1, x2, y2, z2)
endmethod
endstruct
endif
/*
* Electron List
*/
private struct ElectronNode extends array
implement List
endstruct
/*
* Electron Struct
*/
private struct Electron extends array
private integer level
private real healthDpi
private real manaDpi
private real dpsRadius
private real detectionRadius
private real dpsStunDuration
private effect sfx
private unit dummy
private unit owner
static if USE_ELECTRON_LIGHTNING_EFFECT then
private real originalX
private real originalY
private real originalZ
private Lightning lightning
endif
implement StaticList
method operator x takes nothing returns real
return GetUnitX(this.dummy)
endmethod
method operator y takes nothing returns real
return GetUnitY(this.dummy)
endmethod
method operator z takes nothing returns real
return GetUnitFlyHeight(this.dummy)
endmethod
method destroy takes nothing returns nothing
local unit u
local unit owner = this.owner
local integer level = this.level
local real healthDamage = ElectronExplosionHealthDamage(level)
local real manaDamage = ElectronExplosionManaDamage(level)
local real stunDuration = ElectronExplosionStunDuration(level)
call GroupEnumUnitsInRange(enumGroup, this.x, this.y, ElectronExplosionRadius(level), null)
loop
set u = FirstOfGroup(enumGroup)
exitwhen u == null
call GroupRemoveUnit(enumGroup, u)
if TargetFilter(owner, u) then
call UnitDamageTarget(owner, u, healthDamage, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - manaDamage)
call Stun.apply(u, stunDuration, false)
endif
endloop
static if USE_ELECTRON_LIGHTNING_EFFECT then
call this.lightning.expire(ELECTRON_LIGHTNING_DEATH_DURATION)
endif
call DestroyEffect(this.sfx)
call DummyAddRecycleTimer(this.dummy, DUMMY_DEATH_DURATION)
set this.owner = null
set this.dummy = null
set this.sfx = null
set owner = null
call ElectronNode(this).remove()
call ElectronNode(this).deallocate()
endmethod
method move takes real x, real y, real z returns nothing
local unit u
local unit owner = this.owner
local unit dummy = this.dummy
local real healthDpi = this.healthDpi
local real manaDpi = this.manaDpi
local real stunDuration = this.dpsStunDuration
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
call SetUnitFlyHeight(dummy, z, 0.00)
static if USE_ELECTRON_LIGHTNING_EFFECT then
call this.lightning.move(this.originalX, this.originalY, this.originalZ, x, y, z)
endif
call GroupEnumUnitsInRange(enumGroup, x, y, this.dpsRadius, null)
loop
set u = FirstOfGroup(enumGroup)
exitwhen u == null
call GroupRemoveUnit(enumGroup, u)
if TargetFilter(owner, u) then
call UnitDamageTarget(owner, u, healthDpi, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - manaDpi)
call Stun.apply(u, stunDuration, false)
endif
endloop
set dummy = null
set owner = null
endmethod
static if USE_ELECTRON_LIGHTNING_EFFECT then
method createLightning takes nothing returns nothing
set this.lightning = Lightning.create(ELECTRON_LIGHTNING_MODEL, ELECTRON_LIGHTNING_ALPHA, ELECTRON_LIGHTNING_RED, ELECTRON_LIGHTNING_GREEN, ELECTRON_LIGHTNING_BLUE, this.originalX, this.originalY, this.originalZ, x, y, z)
endmethod
endif
implement CT32
local thistype this = first
local unit owner
local unit u
loop
exitwhen this == head
set owner = this.owner
call GroupEnumUnitsInRange(enumGroup, this.x, this.y, this.detectionRadius, null)
loop
set u = FirstOfGroup(enumGroup)
exitwhen u == null
call GroupRemoveUnit(enumGroup, u)
if TargetFilter(owner, u) then
call GroupClear(enumGroup)
call this.disableSensor()
call this.destroy()
set u = null
exitwhen true
endif
endloop
set this = this.next
endloop
if empty then
call stop()
endif
set owner = null
implement CT32End
static method create takes SpellCore spell returns thistype
local thistype this = ElectronNode.allocate()
local integer level = spell.level
local real distance = GetRandomReal(InnerRadius(level), OuterRadius(level))
local real angle = GetRandomReal(0.00, 2*bj_PI)
local real x = BoundedX(spell.centerX + distance*Cos(angle))
local real y = BoundedY(spell.centerY + distance*Sin(angle))
local real z = GetRandomReal(MinHeight(level), MaxHeight(level))
set this.level = level
set this.owner = spell.owner
set this.detectionRadius = ElectronDetectionRadius(level)
set this.dpsRadius = ElectronDpsRadius(level)
set this.healthDpi = ElectronHealthDps(level)*TIMEOUT
set this.manaDpi = ElectronManaDps(level)*TIMEOUT
set this.dpsStunDuration = ElectronDpsStunDuration(level)
set this.dummy = GetRecycledDummy(x, y, z, 0)
set this.sfx = AddSpecialEffectTarget(ELECTRON_MODEL, this.dummy, ELECTRON_ATTACH_POINT)
static if USE_ELECTRON_LIGHTNING_EFFECT then
set this.originalX = x
set this.originalY = y
set this.originalZ = z
endif
call SetUnitScale(this.dummy, ElectronScale(level), 0.00, 0.00)
call last.insert(this)
if this == first then
call start()
endif
return this
endmethod
method disableSensor takes nothing returns nothing
call this.remove()
if empty then
call stop()
endif
endmethod
endstruct
/*
* Border Posts Struct
*/
private struct BorderPostNode extends array
implement List
endstruct
/*
* Border Struct
*/
private struct BorderPosts extends array
private effect topSfx
private effect bottomSfx
private unit top
private unit bottom
static if USE_BORDER_POST_LIGHTNING_EFFECT then
private Lightning lightning
endif
static method create takes SpellCore spell returns thistype
local integer level = spell.level
local integer count = BorderPostsCount(level)
local real dummyScale = BorderPostsDummyScale(level)
local real offset = BorderPostsOffset(level)
local real minHeight = BorderPostsMinHeight(level)
local real maxHeight = BorderPostsMaxHeight(level)
local real centerX = spell.centerX
local real centerY = spell.centerY
local real deltaAngle = 2*bj_PI/count
local real angle
local real facing
local real x
local real y
local thistype node
local BorderPostNode this = BorderPostNode.create()
if count > 0 then
loop
exitwhen count == 0
set count = count - 1
set node = BorderPostNode.allocate()
call this.insert(node)
set angle = deltaAngle*count
set x = BoundedX(centerX + offset*Cos(angle))
set y = BoundedY(centerY + offset*Sin(angle))
set facing = angle*bj_RADTODEG - 180.00
set node.top = GetRecycledDummy(x, y, maxHeight, facing)
set node.bottom = GetRecycledDummy(x, y, minHeight, facing)
set node.topSfx = AddSpecialEffectTarget(BORDER_POST_TOP_MODEL, node.top, BORDER_POST_TOP_ATTACH_POINT)
set node.bottomSfx = AddSpecialEffectTarget(BORDER_POST_BOTTOM_MODEL, node.bottom, BORDER_POST_BOTTOM_ATTACH_POINT)
call SetUnitScale(node.top, dummyScale, 0.00, 0.00)
call SetUnitScale(node.bottom, dummyScale, 0.00, 0.00)
static if USE_BORDER_POST_LIGHTNING_EFFECT then
set node.lightning = Lightning.create(BORDER_POST_LIGHTNING_MODEL, BORDER_POST_LIGHTNING_ALPHA, BORDER_POST_LIGHTNING_RED, BORDER_POST_LIGHTNING_GREEN, BORDER_POST_LIGHTNING_BLUE, x, y, maxHeight, x, y, minHeight)
endif
endloop
endif
return this
endmethod
method destroy takes nothing returns nothing
local thistype node = BorderPostNode(this).next
loop
exitwhen node == this
call DummyAddRecycleTimer(node.top, DUMMY_DEATH_DURATION)
call DummyAddRecycleTimer(node.bottom, DUMMY_DEATH_DURATION)
call DestroyEffect(node.topSfx)
call DestroyEffect(node.bottomSfx)
static if USE_BORDER_POST_LIGHTNING_EFFECT then
call node.lightning.expire(BORDER_POST_LIGHTNING_DEATH_DURATION)
endif
set node.top = null
set node.bottom = null
set node.topSfx = null
set node.bottomSfx = null
call BorderPostNode(node).remove()
call BorderPostNode(node).deallocate()
set node = BorderPostNode(node).next
endloop
call BorderPostNode(this).destroy()
endmethod
endstruct
/*
* Prison Mark List
*/
private struct PrisonNode extends array
implement List
endstruct
/*
* Prison Struct
*/
private struct Prison extends array
private unit top
private unit bottom
private effect topSfx
private effect bottomSfx
static if ACTIVATE_PRISON then
private real radius
private real centerX
private real centerY
private group group
implement StaticList
implement CT32
local thistype this = first
local group tempGroup
local group forSwap
local unit u
local real radius
local real centerX
local real centerY
local real dx
local real dy
local real angle
loop
exitwhen this == head
set tempGroup = this.group
set radius = this.radius
set centerX = this.centerX
set centerY = this.centerY
call GroupEnumUnitsInRange(enumGroup, centerX, centerY, radius, null)
loop
set u = FirstOfGroup(enumGroup)
exitwhen u == null
call GroupRemoveUnit(enumGroup, u)
if not IsUnitInGroup(u, tempGroup) then
call GroupAddUnit(tempGroup, u)
endif
endloop
loop
set u = FirstOfGroup(tempGroup)
exitwhen u == null
call GroupRemoveUnit(tempGroup, u)
call GroupAddUnit(enumGroup, u)
set dx = GetUnitX(u) - centerX
set dy = GetUnitY(u) - centerY
if dx*dx + dy*dy > radius*radius then
set angle = Atan2(dy, dx)
call SetUnitX(u, centerX + radius*Cos(angle))
call SetUnitY(u, centerY + radius*Sin(angle))
endif
endloop
set forSwap = enumGroup
set enumGroup = tempGroup
set this.group = forSwap
set this = this.next
endloop
set forSwap = null
set tempGroup = null
implement CT32End
endif
static method create takes SpellCore spell returns thistype
local thistype this = PrisonNode.create()
local integer level = spell.level
local integer count = PrisonMarkCount(level)
local real offset = PrisonRadius(level)
local real minHeight = PrisonBottomMarkHeight(level)
local real maxHeight = PrisonTopMarkHeight(level)
local real markScale = PrisonMarkScale(level)
local real centerX = spell.centerX
local real centerY = spell.centerY
local real deltaAngle = 2.00*bj_PI/count
local real angle
local real facing
local real x
local real y
local thistype node
if count > 0 then
loop
exitwhen count == 0
set count = count - 1
set node = PrisonNode.allocate()
call PrisonNode(this).insert(node)
set angle = deltaAngle*count
set facing = angle*bj_RADTODEG - 180.00
set x = BoundedX(centerX + offset*Cos(angle))
set y = BoundedY(centerY + offset*Sin(angle))
set node.top = GetRecycledDummy(x, y, maxHeight, facing)
set node.bottom = GetRecycledDummy(x, y, minHeight, facing)
set node.topSfx = AddSpecialEffectTarget(PRISON_MARK_TOP_MODEL, node.top, PRISON_MARK_TOP_ATTACH_POINT)
set node.bottomSfx = AddSpecialEffectTarget(PRISON_MARK_BOTTOM_MODEL, node.bottom, PRISON_MARK_BOTTOM_ATTACH_POINT)
call SetUnitScale(node.top, markScale, 0.00, 0.00)
call SetUnitScale(node.bottom, markScale, 0.00, 0.00)
endloop
endif
static if ACTIVATE_PRISON then
set this.centerX = centerX
set this.centerY = centerY
set this.radius = offset
set this.group = CreateGroup()
call GroupEnumUnitsInRange(this.group, centerX, centerY, offset, null)
call last.insert(this)
if this == first then
call start()
endif
endif
return this
endmethod
method destroy takes nothing returns nothing
local thistype node = PrisonNode(this).next
loop
exitwhen node == this
call DestroyEffect(node.topSfx)
call DestroyEffect(node.bottomSfx)
call DummyAddRecycleTimer(node.top, DUMMY_DEATH_DURATION)
call DummyAddRecycleTimer(node.bottom, DUMMY_DEATH_DURATION)
set node.topSfx = null
set node.bottomSfx = null
set node.top = null
set node.bottom = null
call PrisonNode(node).remove()
call PrisonNode(node).deallocate()
set node = PrisonNode(this).next
endloop
static if ACTIVATE_PRISON then
call DestroyGroup(this.group)
set this.group = null
call this.remove()
if empty then
call stop()
endif
endif
call PrisonNode(this).destroy()
endmethod
static if ACTIVATE_PRISON then
/*
* This method removes the deindexed unit from the groups that
* might have contained it in order to avoid possible bugs with
* the FoG-type loops
*/
private static method onDeindex takes nothing returns nothing
local unit deindexed = GetIndexedUnit()
local thistype node = first
loop
exitwhen node == head
call GroupRemoveUnit(node.group, deindexed)
set node = node.next
endloop
set deindexed = null
endmethod
static method init takes nothing returns nothing
local code onDeindex = function thistype.onDeindex
call OnUnitDeindex(onDeindex)
endmethod
endif
endstruct
/*
* Spell Thread Struct
*/
private struct SpellNode extends array
real elapsed
real delay
integer count
integer phase
integer subPhase
ElectronNode electronList
implement List
endstruct
/*
* Spell Core
*/
private struct SpellCore extends array
readonly unit owner
readonly integer level
readonly real centerX
readonly real centerY
private real releaseInterval
private real traverseInterval
private real vanishDelay
private real speed
private BorderPosts border
private Prison prison
implement StaticList
implement CT32
local thistype this = first
local real dx
local real dy
local real dz
local real dxy
local real xyDistance
local real distance
local real angle
local real zAngle
local ElectronNode electronList
local Electron node
local Electron next
local SpellNode spell
loop
exitwhen this == head
if not SpellNode(this).empty then
set spell = SpellNode(this).next
loop
exitwhen spell == this
/*
* Phase 1: Energy balls creation
*/
if spell.phase == 1 then
if spell.count > 0 then
set spell.elapsed = spell.elapsed + TIMEOUT
if spell.elapsed >= this.releaseInterval then
set spell.elapsed = 0.00
call spell.electronList.prev.insert(Electron.create(this))
set spell.count = spell.count - 1
endif
else
set spell.phase = 2
endif
/*
* Phase 2: Wait for the time of traversal
*/
elseif spell.phase == 2 then
if spell.delay > 0.00 then
set spell.delay = spell.delay - TIMEOUT
else
set spell.phase = 3
endif
/*
* Phase 3: Energy balls traversal
*/
elseif spell.phase == 3 then
set electronList = spell.electronList
set node = electronList.next
set next = ElectronNode(node).next
/*
* If there are no electrons left, go to the next phase
*/
if electronList.empty then
set spell.phase = 4
/*
* Traversal Phase 1: Create lightning effect from the current electron to the next one
*/
elseif spell.subPhase == 1 then
static if USE_ELECTRON_LIGHTNING_EFFECT then
if next != electronList then
call node.createLightning()
endif
endif
call node.disableSensor()
set spell.subPhase = 2
/*
* Traversal Phase 2: Move the current electron to the next one
*/
elseif spell.subPhase == 2 then
if next != electronList then
set distance = this.speed
set dx = next.x - node.x
set dy = next.y - node.y
set dz = next.z - node.z
set dxy = dx*dx + dy*dy
if dxy + dz*dz > distance*distance then
set angle = Atan2(dy, dx)
set zAngle = Atan2(dz, SquareRoot(dxy))
set xyDistance = distance*Cos(zAngle)
call node.move(node.x + xyDistance*Cos(angle), node.y + xyDistance*Sin(angle), node.z + distance*Sin(zAngle))
else
call node.destroy()
set spell.elapsed = this.traverseInterval
set spell.subPhase = 3
endif
else
call node.destroy()
set spell.elapsed = this.traverseInterval
set spell.subPhase = 3
endif
/*
* Traversal Phase 3: Wait for the specified interval then proceed with traversal operations on the next electron
*/
elseif spell.subPhase == 3 then
if spell.elapsed > 0.00 then
set spell.elapsed = spell.elapsed - TIMEOUT
else
set spell.subPhase = 1
endif
endif
/*
* Phase 4: Cleanup
*/
elseif spell.phase == 4 then
call spell.electronList.destroy()
call spell.remove()
call spell.deallocate()
endif
set spell = spell.next
endloop
/*
* Wait for the right time for the electron cloud to be destroyed
*/
elseif this.vanishDelay > 0.00 then
set this.vanishDelay = this.vanishDelay - TIMEOUT
/*
* End of Spell: Destroy Electron Cloud
*/
else
call this.border.destroy()
call this.prison.destroy()
call this.remove()
call SpellNode(this).destroy()
if empty then
call stop()
endif
endif
set this = this.next
endloop
implement CT32End
private static method onCast takes nothing returns nothing
local thistype this
local SpellNode node
local real delay
local integer count
local unit caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(caster, SPELL_ID)
local integer threads = Threads(level)
if threads > 0 then
set this = SpellNode.create()
set this.owner = caster
set this.level = level
set this.centerX = BoundedX(GetSpellTargetX())
set this.centerY = BoundedY(GetSpellTargetY())
set this.releaseInterval = ElectronReleaseInterval(level)
set this.traverseInterval = ElectronTraversalInterval(level)
set this.vanishDelay = CloudDestructionDelay(level)
set this.speed = ElectronMoveSpeed(level)*TIMEOUT
set this.border = BorderPosts.create(this)
set this.prison = Prison.create(this)
set count = ElectronCount(level)
set delay = ElectronTraversalDelay(level)
loop
exitwhen threads == 0
set threads = threads - 1
set node = SpellNode.allocate()
call SpellNode(this).prev.insert(node)
set node.electronList = ElectronNode.create()
set node.phase = 1
set node.subPhase = 1
set node.count = count
set node.delay = delay
endloop
call last.insert(this)
if this == first then
call start()
endif
endif
set caster = null
endmethod
static method init takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
endmethod
endstruct
/*
* Preload Spell Resources
*/
static if LIBRARY_ResourcePreloader then
private function PreloadResource takes nothing returns nothing
call PreloadAbility(SPELL_ID)
call PreloadEffect(ELECTRON_MODEL)
call PreloadEffect(BORDER_POST_BOTTOM_MODEL)
call PreloadEffect(BORDER_POST_TOP_MODEL)
call PreloadEffect(PRISON_MARK_BOTTOM_MODEL)
call PreloadEffect(PRISON_MARK_TOP_MODEL)
endfunction
endif
/*
* Initializer struct
*/
private struct Initializer extends array
private static method onInit takes nothing returns nothing
static if not LIBRARY_WorldBounds then
call MapBounds.init()
endif
static if ACTIVATE_PRISON then
call Prison.init()
endif
static if LIBRARY_ResourcePreloader then
call PreloadResource()
endif
call SpellCore.init()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
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
*
************************************************************************************/
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
//TESH.scrollpos=0
//TESH.alwaysfold=0
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
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ErrorMessage /* v1.0.1.4
*************************************************************************************
*
* Issue Compliant Error Messages
*
************************************************************************************
*
* debug function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
* - In the event of an error the game will be permanently paused
*
* debug function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
*
************************************************************************************/
static if DEBUG_MODE then
private struct Fields extends array
static constant string COLOR_RED = "|cffff0000"
static constant string COLOR_YELLOW = "|cffffff00"
static string lastError = null
endstruct
private function Pause takes nothing returns nothing
call PauseGame(true)
endfunction
private function ThrowMessage takes string libraryName, string functionName, string objectName, integer objectInstance, string description, string errorType, string color returns nothing
local string str
local string color_braces = "|cff66FF99"
local string orange = "|cffff6600"
set str = "->\n-> " + color_braces + "{|r " + "Library" + color_braces + "(" + orange + libraryName + color_braces + ")"
if (objectName != null) then
if (objectInstance > 0) then
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + " (|rinstance = " + orange + I2S(objectInstance) + color_braces + ") )" + "|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
else
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + ")|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
else
set str = str + "|r." + "Function" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
set str = str + color_braces + " }|r " + "has thrown an exception of type " + color_braces + "(" + color + errorType + color_braces + ")|r."
set Fields.lastError = str + "\n->\n" + "-> " + color + description + "|r\n->"
endfunction
function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Error", Fields.COLOR_RED)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
call TimerStart(CreateTimer(), 0, true, function Pause)
set objectInstance = 1/0
endif
endfunction
function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Warning", Fields.COLOR_YELLOW)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
set Fields.lastError = null
endif
endfunction
endif
endlibrary
//TESH.scrollpos=44
//TESH.alwaysfold=0
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
//
// Requires
// --------
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
//
/*
============= Why this is important? =================
1. Does not generate 16 events per spell.
2. This uses one trigger evaluation instead of one for each
individual spell (some maps have quite a few). This helps keep
framerate high and fluid when a spell is cast.
*/
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
//============================================================================
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable ht = InitHashtable()
endif
static method onCast takes nothing returns nothing
static if LIBRARY_Table then
call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
else
call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
endif
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set .tb = Table.create()
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
static if LIBRARY_Table then
if not S.tb.handle.has(abil) then
set S.tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
else
if not HaveSavedHandle(S.ht, 0, abil) then
call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitDex uses optional WorldBounds, optional GroupUtils
/***************************************************************
*
* v1.2.1, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* UnitDex assigns every unit an unique integer. It attempts to make that number within the
* maximum array limit so you can associate it with one.
* _________________________________________________________________________
* 1. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map, save it, then restart the editor and comment out the line below.
*/
// external ObjectMerger w3a Adef uDex anam "Detect Leave" ansf "(UnitDex)" aart "" acat "" arac 0
/* ________________________________________________________________________
* 2. Configuration
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
private module UnitDexConfig
// The raw code of the leave detection ability.
static constant integer DETECT_LEAVE_ABILITY = 'uDex'
// Allow debug messages (debug mode must also be on)
static constant boolean ALLOW_DEBUGGING = true
// Uncomment the lines below to define a filter for units being indexed
/*static method onFilter takes unit u returns boolean
return true
endmethod*/
endmodule
/* _________________________________________________________________________
* 3. Function API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Every function inlines except for UnitDexRemove
*
* function GetUnitId takes unit whichUnit returns integer
* function GetUnitById takes integer index returns unit
*
* function UnitDexEnable takes boolean flag returns nothing
* function UnitDexRemove takes unit u, boolean runEvents returns boolean
*
* function IsUnitIndexed takes unit u returns boolean
* function IsIndexingEnabled takes nothing returns boolean
*
* function GetIndexedUnit takes nothing returns unit
* function GetIndexedUnitId takes nothing returns integer
*
* function RegisterUnitIndexEvent takes boolexpr func, integer eventtype returns indexevent
* function RemoveUnitIndexEvent takes triggercondition c, integer eventtype returns nothing
* function TriggerRegisterUnitIndexEvent takes trigger t, integer eventtype returns nothing
*
* function OnUnitIndex takes code func returns triggercondition
* function OnUnitDeidex takes code func returns triggercondition
* _________________________________________________________________________
* 4. Struct API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* UnitDex.Enabled = false // toggle the indexer
* UnitDex.Initialized // returns true if the preload timer has finished
* UnitDex.Count // returns the amount of units indexed
* UnitDex.Unit[0] // access the UnitDex array directly
* UnitDex.Group // a unit group containing every indexed unit (for enumeration)
* UnitDex.LastIndex // returns the last indexed unit's id
* _________________________________________________________________________
* 5. Public Variables
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* These are to be used with the "eventtype" argument of the event API:
*
* constant integer EVENT_UNIT_INDEX = 0
* constant integer EVENT_UNIT_DEINDEX = 1
* _________________________________________________________________________
* 6. Examples
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* 1. Associate a unit with a variable
*
* set UnitFlag[GetUnitId(yourUnit)] = true
*
* 2. Allocate a struct instance using a units assigned ID
*
* local somestruct data = GetUnitId(yourUnit)
*
* 3. Detect when a unit leaves the map
*
* function Exit takes nothing returns nothing
* call BJDebugMsg("The unit " + GetUnitName(GetIndexedUnit()) + " has left the map.")
* endfunction
*
* call OnUnitDeindex(function Exit)
* // or
* call RegisterUnitIndexEvent(Filter(function Exit), EVENT_UNIT_DEINDEX)
*
*
* _________________________________________________________________________
* 7. How it works
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* 1. Enumerate all preplaced units
* 2. TriggerRegisterEnterRegion native to detect when a unit enters the map
* 3. Assign each unit that enters the map a unique integer
* 4. Give every unit an ability based off of defend. There is no native to accurately
* detect when a unit leaves the map but when a unit dies or is removed from the game
* they are issued the "undefend" order
* 5. Catch the "undefend" order and remove unit from the queue
* _________________________________________________________________________
* 8. Notes
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* - This system is compatable with GUI because it utilizes UnitUserData (custom values for units).
* - The object merger line should be commented out after saving and restarting.
* - All public functions are inlined except UnitDexRemove.
*
* -http://www.hiveworkshop.com/forums/submissions-414/unitdex-lightweight-unit-indexer-248209/
*
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
globals
// Event types
constant integer EVENT_UNIT_INDEX = 0
constant integer EVENT_UNIT_DEINDEX = 1
// System variables
private trigger array IndexTrig
private integer Index = 0
private real E=-1
private boolexpr FilterEnter
endglobals
function GetUnitId takes unit whichUnit returns integer
return GetUnitUserData(whichUnit)
endfunction
function GetUnitById takes integer index returns unit
return UnitDex.Unit[index]
endfunction
function GetIndexedUnit takes nothing returns unit
return UnitDex.Unit[UnitDex.LastIndex]
endfunction
function GetIndexedUnitId takes nothing returns integer
return UnitDex.LastIndex
endfunction
function IsUnitIndexed takes unit u returns boolean
return (GetUnitById(GetUnitId(u)) != null)
endfunction
function UnitDexEnable takes boolean flag returns nothing
set UnitDex.Enabled = flag
endfunction
function IsIndexingEnabled takes nothing returns boolean
return UnitDex.Enabled
endfunction
function RegisterUnitIndexEvent takes boolexpr func, integer eventtype returns triggercondition
return TriggerAddCondition(IndexTrig[eventtype], func)
endfunction
function RemoveUnitIndexEvent takes triggercondition c, integer eventtype returns nothing
call TriggerRemoveCondition(IndexTrig[eventtype], c)
endfunction
function TriggerRegisterUnitIndexEvent takes trigger t, integer eventtype returns nothing
call TriggerRegisterVariableEvent(t, SCOPE_PRIVATE + "E", EQUAL, eventtype)
endfunction
function OnUnitIndex takes code func returns triggercondition
return TriggerAddCondition(IndexTrig[EVENT_UNIT_INDEX], Filter(func))
endfunction
function OnUnitDeindex takes code func returns triggercondition
return TriggerAddCondition(IndexTrig[EVENT_UNIT_DEINDEX], Filter(func))
endfunction
function UnitDexRemove takes unit u, boolean runEvents returns boolean
return UnitDex.Remove(u, runEvents)
endfunction
/****************************************************************/
private keyword UnitDexCore
struct UnitDex extends array
static boolean Enabled = true
readonly static integer LastIndex
readonly static boolean Initialized=false
readonly static group Group=CreateGroup()
readonly static unit array Unit
readonly static integer Count = 0
readonly static integer array List
implement UnitDexConfig
private static integer Counter = 0
implement UnitDexCore
endstruct
/****************************************************************/
private module UnitDexCore
static method Remove takes unit u, boolean runEvents returns boolean
local integer i
if (IsUnitIndexed(u)) then
set i = GetUnitId(u)
set UnitDex.List[i] = Index
set Index = i
call GroupRemoveUnit(UnitDex.Group, u)
call SetUnitUserData(u, 0)
if (runEvents) then
set UnitDex.LastIndex = i
set E = EVENT_UNIT_DEINDEX
call TriggerEvaluate(IndexTrig[EVENT_UNIT_DEINDEX])
set E = -1
endif
set UnitDex.Unit[i] = null
set UnitDex.Count = UnitDex.Count - 1
return true
endif
return false
endmethod
private static method onGameStart takes nothing returns nothing
local integer i = 0
static if (not LIBRARY_GroupUtils) then // Check if GroupUtils exists so we can use it's enumeration group.
local group ENUM_GROUP = CreateGroup() // If not, create the group.
endif
// Index preplaced units
loop
call GroupEnumUnitsOfPlayer(ENUM_GROUP, Player(i), FilterEnter)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
static if (not LIBRARY_GroupUtils) then
call DestroyGroup(ENUM_GROUP)
set ENUM_GROUP = null
endif
// run init triggers
set i = 1
loop
exitwhen i > Counter
set LastIndex = i
call TriggerEvaluate(IndexTrig[EVENT_UNIT_INDEX])
set E = EVENT_UNIT_INDEX
set E = -1
set i = i + 1
endloop
set LastIndex = Counter
set Initialized = true
set FilterEnter = null
call DestroyTimer(GetExpiredTimer())
endmethod
private static method onEnter takes nothing returns boolean
local unit u = GetFilterUnit()
local integer i = GetUnitId(u)
local integer t = Index
if (i == 0 and thistype.Enabled) then
// If a filter was defined pass the unit through it.
static if (thistype.onFilter.exists) then
if (not thistype.onFilter(u)) then
set u = null
return false // check failed
endif
endif
// Handle debugging
static if (thistype.DEBUG_MODE and thistype.ALLOW_DEBUGGING) then
if (t == 0 and Counter+1 >= JASS_MAX_ARRAY_SIZE) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "UnitDex: Maximum number of units reached!")
set u = null
return false
endif
endif
// Add to group of indexed units
call GroupAddUnit(thistype.Group, u)
// Give unit the leave detection ability
call UnitAddAbility(u, thistype.DETECT_LEAVE_ABILITY)
call UnitMakeAbilityPermanent(u, true, thistype.DETECT_LEAVE_ABILITY)
// Allocate index
if (Index != 0) then
set Index = List[t]
else
set Counter = Counter + 1
set t = Counter
endif
set List[t] = -1
set LastIndex = t
set thistype.Unit[t] = u
set Count = Count + 1
// Store the index
call SetUnitUserData(u, t)
if (thistype.Initialized) then
// Execute custom events registered with RegisterUnitIndexEvent
call TriggerEvaluate(IndexTrig[EVENT_UNIT_INDEX])
// Handle TriggerRegisterUnitIndexEvent
set E = EVENT_UNIT_INDEX
// Reset so the event can occur again
set E = -1
endif
endif
set u = null
return false
endmethod
private static method onLeave takes nothing returns boolean
local unit u
local integer i
// Check if order is undefend.
if (thistype.Enabled and GetIssuedOrderId() == 852056) then
set u = GetTriggerUnit()
// If unit was killed (not removed) then don't continue
if (GetUnitAbilityLevel(u, thistype.DETECT_LEAVE_ABILITY) != 0) then
set u = null
return false
endif
set i = GetUnitId(u)
// If unit has been indexed then deindex it
if (i > 0 and i <= Counter and u == GetUnitById(i)) then
// Recycle the index
set List[i] = Index
set Index = i
set LastIndex = i
// Remove to group of indexed units
call GroupRemoveUnit(thistype.Group, u)
// Execute custom events without any associated triggers
call TriggerEvaluate(IndexTrig[EVENT_UNIT_DEINDEX])
// Handle TriggerRegisterUnitIndexEvent
set E = EVENT_UNIT_DEINDEX
// Remove entry
call SetUnitUserData(u, 0)
set thistype.Unit[i] = null
// Decrement unit count
set Count = Count - 1
// Reset so the event can occur again
set E = -1
endif
set u = null
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local player p
local unit u
static if (not LIBRARY_WorldBounds) then // Check if WorldBounts exists, if not then define the necessary vars
local region reg = CreateRegion() // If WorldBounds wasn't found, create the region manually
local rect world = GetWorldBounds()
endif
set FilterEnter = Filter(function thistype.onEnter)
// Begin to index units when they enter the map
static if (LIBRARY_WorldBounds) then
call TriggerRegisterEnterRegion(CreateTrigger(), WorldBounds.worldRegion, FilterEnter)
else
call RegionAddRect(reg, world)
call TriggerRegisterEnterRegion(CreateTrigger(), reg, FilterEnter)
call RemoveRect(world)
set world = null
endif
call TriggerAddCondition(t, Filter(function thistype.onLeave))
set IndexTrig[EVENT_UNIT_INDEX] = CreateTrigger()
set IndexTrig[EVENT_UNIT_DEINDEX] = CreateTrigger()
loop
set p = Player(i)
// Detect "undefend"
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
// Hide the detect ability from players
call SetPlayerAbilityAvailable(p, thistype.DETECT_LEAVE_ABILITY, false)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TimerStart(CreateTimer(), 0, false, function thistype.onGameStart)
endmethod
endmodule
endlibrary
//TESH.scrollpos=17
//TESH.alwaysfold=0
library WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
*
* Fields
* -------------------------
*
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
*
* readonly static integer centerX
* readonly static integer centerY
*
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX = R2I(GetRectMaxX(world))
set maxY = R2I(GetRectMaxY(world))
set minX = R2I(GetRectMinX(world))
set minY = R2I(GetRectMinY(world))
set centerX = R2I((maxX + minX)/2)
set centerY = R2I((minY + maxY)/2)
set worldRegion = CreateRegion()
call RegionAddRect(worldRegion, world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=92
//TESH.alwaysfold=0
library StunSystem uses Table
//********************************************************************************
// Stun - Version 1.2.0.0 - By iAyanami aka Ayanami
//********************************************************************************
//
// Stun:
// - An easy to use system that stuns units
// - Able to keep track of the remaining stun duration
//
// Requirements:
// - JASS NewGen
// - Table
//
// Functions:
// - Stun.apply takes unit whichUnit, real duration, boolean stack returns nothing
// * whichUnit is the target to be stunned
// * duration is the duration of the stun
// * stack is to determine if the stun should be a stacking one or not
// * true - the stun will stack, the duration of the stun will add up with the previous duration
// * false - the stun will not stack, the unit will be stunned for the longer stun duration
//
// - Stun.getDuration takes unit whichUnit returns real
// * whichUnit is the target to check
// * returns the remaining stun duration
//
// - Stun.stop takes unit whichUnit returns nothing
// * removes stun from the target
//
// How to import:
// - Copy the whole "Stun" Trigger Folder into your map
// - Save the map. Close and re-opem the map.
// - You should have a new unit (Stun Dummy), ability (Stun (System)) and buff (Stun (System)) created
// - Read through the Configuration part of the code
//
// Credits:
// - Bribe for Table
//
//********************************************************************************
// CONFIGURABLES
//********************************************************************************
globals
// timer period. lower the value, the more accurate but might cause decrease in
// performance
private constant real PERIOD = 0.031250000
// raw code of ability "Stun (System)"
private constant integer ABILID = 'ASTN'
// raw code of buff "Stun (System)"
private constant integer BUFFID = 'BSTN'
// raw code of unit "Stun Dummy"
private constant integer STUNID = 'sTUN'
endglobals
//********************************************************************************
// CODE
//********************************************************************************
// initialization
module Init
private static method onInit takes nothing returns nothing
set table = Table.create()
set caster = CreateUnit(Player(13), STUNID, 0, 0, 0)
call UnitAddAbility(caster, ABILID)
endmethod
endmodule
struct Stun extends array
private unit u
private real dur
private thistype next
private thistype prev
private static Table table
private static timer t = CreateTimer()
private static unit caster
private static integer count = 0
// remove the stun and deallocate
private method destroy takes nothing returns nothing
call UnitRemoveAbility(this.u, BUFFID)
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
set this.dur = 0
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(t)
endif
call table.remove(GetHandleId(this.u))
endmethod
// iterating through all instances every PERIOD
private static method iterate takes nothing returns nothing
local thistype this = thistype(0)
loop
set this = this.next
exitwhen this == 0
if this.dur <= 0 or IsUnitType(this.u, UNIT_TYPE_DEAD) or GetUnitTypeId(this.u) == 0 then
call this.destroy()
else
set this.dur = this.dur - PERIOD
endif
endloop
endmethod
// immediately removes stun for the specified unit
// ex: call Stun.stop(whichTarget)
static method stop takes unit u returns nothing
local integer id = GetHandleId(u)
if table.has(id) then
call thistype(table[id]).destroy()
endif
endmethod
// gets the duration left for stun, not stunned units always return 0
// ex: local real r = Stun.getDuration(whichTarget)
static method getDuration takes unit u returns real
return thistype(table[GetHandleId(u)]).dur
endmethod
// stunning specified target and to see if the stun is a stacking one or not
// ex: call Stun.apply(whichTarget, 5.0, false)
static method apply takes unit u, real dur, boolean b returns nothing
local thistype this
local integer id = GetHandleId(u)
if table.has(id) then
set this = table[id]
else
if thistype(0).prev == 0 then
set count = count + 1
set this = count
else
set this = thistype(0).prev
set thistype(0).prev = thistype(0).prev.prev
endif
if thistype(0).next == 0 then
call TimerStart(t, PERIOD, true, function thistype.iterate)
else
set thistype(0).next.prev = this
endif
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
set table[id] = this
set this.u = u
set this.dur = 0
call IssueTargetOrder(caster, "firebolt", this.u)
endif
if b and dur > 0 then
set this.dur = this.dur + dur
else
if this.dur < dur then
set this.dur = dur
endif
endif
endmethod
implement Init
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DummyRecycler /*
// DummyRecycler v1.25
// by Flux
//
// A system that recycles dummy units while considering their facing angle.
// It can be used as attachment dummies for visual effects or as dummy caster.
//
// Why is recycling a unit important?
// Because creating a unit is is one of the slowest function in the game
// and there are reports that will always leave a permanent tiny bit of
// memory (0.04 KB).
// On average, retrieving a pending Dummy is approximately 4x faster compared
// to creating a new one and recycling a Dummy compared to removing it is
// approximately 1.3x faster.
// Furthermore, if you're using a lot of "Unit has entered map" events,
// using this system will even result to even more better performance
// because retrieving Dummy units does not cause that event to run.
*/ requires /*
nothing
*/ optional Table/*
if not found, this system will use a hashtable. Hashtables are limited to
255 per map.
*/ optional WorldBounds /*
if not found, this system will initialize its own Map Boundaries.
//
//
// Features:
//
// -- Dummy Sharing
// When a Dummy List gets low on unit count, it will borrow Dummy Units
// from the Dummy List with the highest unit count. The transfer is not
// instant because the shared Dummy Unit has to turn to the appropriate
// angle of its new Dummy List before it can be recycled.
// See BORROW_REQUEST.
//
// -- Self-balancing recycling algorithm
// Recycled Dummy Units will be thrown to the List having the least number
// of Dummy Units.
//
// -- Recycling least used
// Allows recycling a Dummy from the Dummy List with the highest
// unit count. It is useful when the facing angle of the Dummy Unit
// does not matter.
// See GetRecycledDummyAnyAngle.
//
// -- Self-adaptation
// When there are no free Dummy Units from a Dummy List, it will end up creating
// a new unit instead but that unit will be permanently added as a Dummy
// Unit to be recycled increasing the overall total Dummy Unit count.
//
// -- Count control
// Allows limiting the overall number of Dummy Units.
// See MAX_DUMMY_COUNT.
//
// -- Delayed Recycle
// Allows recycling Dummy Units after some delay to allocate time for the
// death animation of Special Effects to be seen.
// See DummyAddRecycleTimer.
//
// ******************************************************************
// ***************************** API: *******************************
// ******************************************************************
//
// function GetRecycledDummy takes real x, real y, real z, real facing returns unit
// - Retrieve an unused Dummy Unit from the List.
// - The equivalent of CreateUnit.
// - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
// function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
// - Use this function if the facing angle of the Dummy doesn't matter to you.
// - It will return a unit from the list having the highest number of unused Dummy Units.
// - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
// function RecycleDummy takes unit u returns nothing
// - Recycle the Dummy unit for it to be used again later.
// - The equivalent of RemoveUnit.
//
// function DummyAddRecycleTimer takes unit u, real time returns nothing
// - Recycle the Dummy unit after a certain time.
// - Use this to allocate time for the the death animation of an effect attached to the
// Dummy Unit to finish..
// - The equivalent of UnitApplyTimedLife.
//
// function ShowDummy takes unit u, boolean flag returns nothing
// - Shows/hides Dummy Unit without conflicting with the Locust ability.
//
//--------------------
// CREDITS
//--------------------
// Bribe - for the MissileRecycler (vJASS) where I got this concept from
// http://www.hiveworkshop.com/forums/jass-resources-412/system-missilerecycler-206086/
// - for the optional Table
// http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
// Vexorian - for the Attachable and Pitch Animation Model (dummy.mdx)
// http://www.wc3c.net/showthread.php?t=101150
// Maker and IcemanBo - for the unit permanent 0.04 KB memory leak of units.
// http://www.hiveworkshop.com/forums/trigger-gui-editor-tutorials-279/memory-leaks-263410/
// Nestharus - for the data structure
// http://www.hiveworkshop.com/forums/2809461-post7.html
// - for the optional WorldBounds
// http://githubusercontent.com/nestharus/JASS/master/jass/Systems/WorldBounds/script.j
// =============================================================== //
// ====================== CONFIGURATION ========================== //
// =============================================================== */
globals
//The rawcode of the Dummy Unit
private constant integer DUMMY_ID = 'dumi'
//The owner of the Dummy Unit
private constant player OWNER = Player(14)
//The number of indexed angle. The higher the value the:
// - Lesser the turning time for the Dummy Units.
// - Higher the total number of Dummy Units created at Map Initialization.
// Recommended Value: 10 (Max difference of 18 degrees)
private constant integer ANGLES_COUNT = 10
//The number of Dummy units per ANGLES_COUNT. The higher the value the:
// - Higher the number of units that can be recycled per angle, when
// no more units are in queue, the system will resort to use CreateUnit.
// - Higher the total number of Dummy Units created at Map Initialization.
// Recommended Value: 3 to 5 (for less overhead in Map Loading Screen)
private constant integer STORED_UNIT_COUNT = 3
//The maximum number of Dummy units that can exist. When the system resort
//to using CreateUnit, the unit will be permanently added to the Dummy
//List. To avoid spamming Dummy Units and having too much free Dummy
//Units to allocate, the maximum number of Dummy Units is capped.
// Recommended Value: 80 to 120
private constant integer MAX_DUMMY_COUNT = 100
//When a certain angle have less than BORROW_REQUEST units in its list,
//it will start to borrow Dummy Units from the list with the highest
//Dummy Unit count.
// Recommended Value: Half of maximum STORED_UNIT_COUNT
private constant integer BORROW_REQUEST = 5
//It will only return a Dummy if the current dummy is close
//to it's appropriate facing angle. This is to avoid returning
//a Dummy which is still turning to face it's list angle.
private constant real ANGLE_TOLERANCE = 10.0
//An additional option to automatically hide recycled dummy units in the
//corner of the map camera bounds
private constant boolean HIDE_ON_MAP_CORNER = true
endglobals
//Every time a new dummy unit is retrieved, it will apply this resets
//If it is redundant/you dont need it, remove it.
//! textmacro DUMMY_UNIT_RESET
call SetUnitScale(bj_lastCreatedUnit, 1, 0, 0)
call SetUnitVertexColor(bj_lastCreatedUnit, 255, 255, 255, 255)
call SetUnitAnimationByIndex(bj_lastCreatedUnit, 90)
call ShowDummy(bj_lastCreatedUnit, true)
//! endtextmacro
// =============================================================== //
// ==================== END CONFIGURATION ======================== //
// =============================================================== //
globals
private integer dummyCount = ANGLES_COUNT*STORED_UNIT_COUNT
private real array angle
private integer array count
private integer array countHead
private integer array countNext
private integer array countPrev
private integer array next
private integer array prev
private unit array dummy
private integer upper
private integer lower
private integer lastInstance
private constant real FACING_OFFSET = 180.0/ANGLES_COUNT
endglobals
static if HIDE_ON_MAP_CORNER and not LIBRARY_WorldBounds then
private module BoundsInit
readonly static real x
readonly static real y
private static method onInit takes nothing returns nothing
local rect map = GetWorldBounds()
set thistype.x = GetRectMaxX(map)
set thistype.y = GetRectMaxY(map)
call RemoveRect(map)
set map = null
endmethod
endmodule
private struct Bounds extends array
implement BoundsInit
endstruct
endif
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable hash = InitHashtable()
endif
private static method onInit takes nothing returns nothing
local real add = 360.0/ANGLES_COUNT
local real a = 0
local integer this = ANGLES_COUNT
local integer head = 0
local integer cHead = JASS_MAX_ARRAY_SIZE - 1 //avoid allocation collision
local integer i = R2I(MAX_DUMMY_COUNT/ANGLES_COUNT + 0.5)
set upper = STORED_UNIT_COUNT
set lower = STORED_UNIT_COUNT
static if LIBRARY_Table then
set tb = Table.create()
endif
//Initialize countHeads
loop
exitwhen i < 0
set countNext[cHead] = cHead
set countPrev[cHead] = cHead
set countHead[i] = cHead
set cHead = cHead - 1
set i = i - 1
endloop
set cHead = countHead[STORED_UNIT_COUNT] //All heads will be inserted here initially
//Create the Dummy units
loop
exitwhen a >= 360
//Initialize head
set next[head] = head
set prev[head] = head
set count[head] = STORED_UNIT_COUNT
set angle[head] = a
//Insert head in the Count List
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
set i = 0
loop
exitwhen i >= STORED_UNIT_COUNT
//Queued Linked List
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
static if HIDE_ON_MAP_CORNER then
static if LIBRARY_WorldBounds then
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, a)
else
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, Bounds.x, Bounds.y, a)
endif
else
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, 0, 0, a)
endif
call PauseUnit(dummy[this], true)
static if LIBRARY_Table then
set tb[GetHandleId(dummy[this])] = this
else
call SaveInteger(hash, GetHandleId(dummy[this]), 0, this)
endif
set this = this + 1
set i = i + 1
endloop
set head = head + 1
set a = a + add
endloop
set lastInstance = this
endmethod
endmodule
private struct S extends array
implement M
endstruct
private function GetHead takes integer facing returns integer
if facing < 0 or facing >= 360 then
set facing = facing - (facing/360)*360
if facing < 0 then
set facing = facing + 360
endif
endif
return R2I((facing*ANGLES_COUNT/360.0))
endfunction
function ShowDummy takes unit u, boolean flag returns nothing
if IsUnitHidden(u) == flag then
call ShowUnit(u, flag)
if flag and GetUnitTypeId(u) == DUMMY_ID then
call UnitRemoveAbility(u, 'Aloc')
call UnitAddAbility(u, 'Aloc')
endif
endif
endfunction
function GetRecycledDummy takes real x, real y, real z, real facing returns unit
local integer head = GetHead(R2I(facing + FACING_OFFSET))
local integer this = next[head]
local integer cHead
//If there are Dummy Units in the Queue List already facing close to the appropriate angle
if this != head and RAbsBJ(GetUnitFacing(dummy[this]) - angle[head]) <= ANGLE_TOLERANCE then
//Remove from the Queue List
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
//For double free protection
set next[this] = -1
//Unit Properties
set bj_lastCreatedUnit = dummy[this]
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitFacing(bj_lastCreatedUnit, facing)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
//! runtextmacro DUMMY_UNIT_RESET()
//Update Count and Bounds
set count[head] = count[head] - 1
//------------------------------------------------
// Unit Sharing
//------------------------------------------------
if count[head] < BORROW_REQUEST and count[countNext[countHead[upper]]] > count[head] then
set count[head] = count[head] + 1
set this = next[countNext[countHead[upper]]]
call SetUnitFacing(dummy[this], angle[head])
//Remove
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
//Add to the Current List
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
set head = countNext[countHead[upper]]
set count[head] = count[head] - 1
endif
//---------------------------
//Update Count Lists
//---------------------------
//Remove from the current Count List
set countNext[countPrev[head]] = countNext[head]
set countPrev[countNext[head]] = countPrev[head]
//Add to the new Count List
set cHead = countHead[count[head]]
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
//---------------------------
// Update Bounds
//---------------------------
set cHead = countHead[upper]
if countNext[cHead] == cHead then
set upper = upper - 1
endif
if count[head] < lower then
set lower = count[head]
endif
else
set bj_lastCreatedUnit = CreateUnit(OWNER, DUMMY_ID, x, y, facing)
call PauseUnit(bj_lastCreatedUnit, true)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
if dummyCount < MAX_DUMMY_COUNT then
set this = lastInstance
//For double free protection
set next[this] = -1
set dummy[this] = bj_lastCreatedUnit
static if LIBRARY_Table then
set S.tb[GetHandleId(bj_lastCreatedUnit)] = this
else
call SaveInteger(S.hash, GetHandleId(bj_lastCreatedUnit), 0, this)
endif
set lastInstance = lastInstance + 1
endif
set dummyCount = dummyCount + 1
endif
return bj_lastCreatedUnit
endfunction
function RecycleDummy takes unit u returns nothing
static if LIBRARY_Table then
local integer this = S.tb[GetHandleId(u)]
else
local integer this = LoadInteger(S.hash, GetHandleId(u), 0)
endif
local integer head
local integer cHead
//If the unit is a legit Dummy Unit
if this > 0 and next[this] == -1 then
//Find where to insert based on the list having the least number of units
set head = countNext[countHead[lower]]
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
//Update Status
call SetUnitFacing(u, angle[head])
call PauseUnit(u, true)
call SetUnitOwner(u, OWNER, false)
static if HIDE_ON_MAP_CORNER then
static if LIBRARY_WorldBounds then
call SetUnitX(u, WorldBounds.maxX)
call SetUnitY(u, WorldBounds.maxY)
else
call SetUnitX(u, Bounds.x)
call SetUnitY(u, Bounds.y)
endif
else
call SetUnitScale(u, 0, 0, 0)
call SetUnitVertexColor(u, 0, 0, 0, 0)
endif
set count[head] = count[head] + 1
//---------------------------
// Update Count Lists
//---------------------------
//Remove
set countNext[countPrev[head]] = countNext[head]
set countPrev[countNext[head]] = countPrev[head]
//Add to the new Count List
set cHead = countHead[count[head]]
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
//---------------------------
// Update Bounds
//---------------------------
set cHead = countHead[lower]
if countNext[cHead] == cHead then
set lower = lower + 1
endif
if count[head] > upper then
set upper = count[head]
endif
elseif this == 0 then
call RemoveUnit(u)
debug elseif next[this] != -1 then
debug call BJDebugMsg("|cffffcc00[DummyRecycler]:|r Attempted to recycle a pending/free Dummy Unit.")
endif
endfunction
private function Expires takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
static if LIBRARY_Table then
call RecycleDummy(S.tb.unit[id])
call S.tb.unit.remove(id)
else
call RecycleDummy(LoadUnitHandle(S.hash, id, 0))
call FlushChildHashtable(S.hash, id)
endif
call DestroyTimer(t)
set t = null
endfunction
function DummyAddRecycleTimer takes unit u, real time returns nothing
local timer t = CreateTimer()
static if LIBRARY_Table then
set S.tb.unit[GetHandleId(t)] = u
else
call SaveUnitHandle(S.hash, GetHandleId(t), 0, u)
endif
call TimerStart(t, time, false, function Expires)
set t = null
endfunction
function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
return GetRecycledDummy(x, y, z, angle[countNext[countHead[upper]]])
endfunction
// runtextmacro DUMMY_DEBUG_TOOLS()
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CTL /* v1.2.0.3
*************************************************************************************
*
* CTL or Constant Timer Loop provides a loop for constant merged timers of timeout .03125
*
* Similar to T32 but pauses timer when no structs have instances and removes structs
* from timer trigger when those structs have no instances.
*
* This can also create new timers after destroying a previous timer and generates less
* code in the module. It also generates no triggers so long as the module is implemented
* at the top of the struct.
*
************************************************************************************
*
* module CTL
*
* Allows creation/destruction of timers in a struct. Provides instancing of those timers.
*
* - static method create takes nothing returns thistype
* - method destroy takes nothing returns nothing
*
* CTL (optional)
* local variables, code before running any timers
* CTLExpire (not optional)
* timer code
* CTLNull (optional)
* null any locals, runs after all timers
* CTLEnd (not optional)
*
* module CT32
*
* Converts struct into a timer group. Allows the timer group to be started and stopped.
* Instancing and looping through active timers is up to the user.
*
* - static method start takes nothing returns nothing
* - static method stop takes nothing returns nothing
*
* CT32 (not optional)
* timer code
* CT32End (not optional)
*
* struct TimerGroup32 extends array
*
* Allows for the creation of timer groups. Timer instancing and looping is entirely up
* to the user.
*
* - static method create takes code func returns thistype
* - method destroy takes nothing returns nothing
* - method start takes nothing returns nothing
* - method stop takes nothing returns nothing
*
************************************************************************************/
globals
private integer tgc = 0 //timer group count
private integer array tgr //timer group recycler
private integer ic=0 //instance count
private integer tc=0 //timer count
private integer array rf //root first
private integer array n //next
private integer array p //previous
private integer array th //timer head
private integer array ns //next stack
private trigger t=CreateTrigger()
private timer m=CreateTimer()
private triggercondition array ct
private conditionfunc array rc
private boolean array e32 //enabled
private integer array i32r //ct32 recycler
private integer i32cr = 0 //ct32 count recycler
private boolean array ir32 //is recycling
private boolean array id32 //is destroying
endglobals
private function E takes nothing returns nothing
local integer i=ns[0]
set ns[0]=0
loop
exitwhen 0==i
if (0==p[i]) then
if (0==n[i]) then
call TriggerRemoveCondition(t,ct[th[i]])
set ct[th[i]]=null
set tc=tc-1
set rf[th[i]]=0
else
set rf[th[i]]=n[i]
set p[n[i]]=0
endif
else
set p[n[i]]=p[i]
set n[p[i]]=n[i]
endif
set n[i]=n[0]
set n[0]=i
set i=ns[i]
endloop
loop
exitwhen 0 == i32cr
set i32cr = i32cr - 1
set i = i32r[i32cr]
if (not e32[i]) then
call TriggerRemoveCondition(t,ct[i])
set ct[i] = null
if (id32[i]) then
set tgr[i] = tgr[0]
set tgr[0] = i
set id32[i] = false
endif
set ir32[i] = false
endif
endloop
if (0==tc) then
call PauseTimer(m)
else
call TriggerEvaluate(t)
endif
endfunction
private function CT takes integer r returns integer
local integer i
local integer f
if (0==n[0]) then
set i=ic+1
set ic=i
else
set i=n[0]
set n[0]=n[i]
endif
set th[i]=r
set ns[i]=-1
set f=rf[r]
if (0==f) then
set n[i]=0
set p[i]=0
set rf[r]=i
set ct[r]=TriggerAddCondition(t,rc[r])
//set ct[r] = null
if (0==tc) then
call TimerStart(m,.031250000,true,function E)
endif
set tc=tc+1
else
set n[i]=f
set p[i]=0
set p[f]=i
set rf[r]=i
endif
return i
endfunction
private function DT takes integer t returns nothing
debug if (0>ns[t]) then
set ns[t]=ns[0]
set ns[0]=t
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"TIMER LOOP ERROR: ATTEMPT TO DESTROY NULL TIMER")
debug endif
endfunction
private function A takes code c returns integer
local integer i = tgr[0]
if (0 == i) then
set i = tgc + 1
set tgc = i
else
set tgr[0] = tgr[i]
endif
set rc[i]=Condition(c)
return i
endfunction
private function A32 takes integer i returns nothing
if (not (e32[i] or id32[i])) then
if (ir32[i]) then
set ir32[i] = false
else
set ct[i] = TriggerAddCondition(t, rc[i])
endif
if (0 == tc) then
call TimerStart(m,.031250000,true,function E)
endif
set tc = tc + 1
set e32[i] = true
endif
endfunction
private function SR32 takes integer i returns nothing
if (e32[i]) then
if (not (ir32[i] or id32[i])) then
set i32r[i32cr] = i
set i32cr = i32cr + 1
set ir32[i] = true
endif
set e32[i] = false
set tc = tc - 1
endif
endfunction
private function DT32 takes integer i returns nothing
if (not id32[i]) then
if (not ir32[i]) then
set ir32[i] = true
set tc = tc - 1
set i32r[i32cr] = i
set i32cr = i32cr + 1
set e32[i] = false
endif
set id32[i] = true
endif
endfunction
private keyword r
private keyword e
module CTL
static integer rctl32
static method create takes nothing returns thistype
return CT(rctl32)
endmethod
method destroy takes nothing returns nothing
call DT(this)
endmethod
static method ectl32 takes nothing returns boolean
local thistype this=rf[rctl32]
endmodule
module CTLExpire
implement CTL
loop
exitwhen 0==this
endmodule
module CTLNull
set this=n[this]
endloop
endmodule
module CTLEnd
implement CTLNull
return false
endmethod
private static method onInit takes nothing returns nothing
set rctl32 = A(function thistype.ectl32)
endmethod
endmodule
module CT32
static integer rctl32
static method start takes nothing returns nothing
call A32(rctl32)
endmethod
static method stop takes nothing returns nothing
call SR32(rctl32)
endmethod
static method ectl32 takes nothing returns boolean
endmodule
module CT32End
return false
endmethod
private static method onInit takes nothing returns nothing
set rctl32 = A(function thistype.ectl32)
endmethod
endmodule
struct TimerGroup32 extends array
static method create takes code c returns thistype
return A(c)
endmethod
method destroy takes nothing returns nothing
call DT32(this)
endmethod
method start takes nothing returns nothing
call A32(this)
endmethod
method stop takes nothing returns nothing
call SR32(this)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ResourcePreloader /* v1.4c
*/uses /*
*/optional BJObjectId /* http://www.hiveworkshop.com/threads/bjobjectid.287128/
*/optional Table /* http://www.hiveworkshop.com/threads/snippet-new-table.188084/
*/optional UnitRecycler /* http://www.hiveworkshop.com/threads/snippet-unit-recycler.286701/
*///! novjass
|================|
| Written by AGD |
|================|
[CREDITS]
/* IcemanBo - for suggesting further improvements
Silvenon - for the sound preloading method */
|-----|
| API |
|-----|
function PreloadUnit takes integer rawcode returns nothing/*
- Assigns a certain type of unit to be preloaded
*/function PreloadItem takes integer rawcode returns nothing/*
- Assigns a certain type of item to be preloaded
*/function PreloadAbility takes integer rawcode returns nothing/*
- Assigns a certain type of ability to be preloaded
*/function PreloadEffect takes string modelPath returns nothing/*
- Assigns a certain type of effect to be preloaded
*/function PreloadSound takes string soundPath returns nothing/*
- Assigns a certain type of sound to be preloaded
The following functions requires the BJObjectId library:
*/function PreloadUnitEx takes integer start, integer end returns nothing/*
- Assigns a range of units to be preloaded
*/function PreloadItemEx takes integer start, integer end returns nothing/*
- Assigns a range of items to be preloaded
*/function PreloadAbilityEx takes integer start, integer end returns nothing/*
- Assigns a range of abilities to be preloaded
*///! endnovjass
/*========================================================================================================*/
/* Do not try to change below this line if you're not so sure on what you're doing. */
/*========================================================================================================*/
private keyword S
/*============================================== TextMacros ==============================================*/
//! textmacro PRELOAD_TYPE takes NAME, ARG, TYPE, INDEX, I
function Preload$NAME$ takes $ARG$ what returns nothing
static if LIBRARY_Table then
if S.tb[$I$].boolean[$INDEX$] then
return
endif
set S.tb[$I$].boolean[$INDEX$] = true
call Do$NAME$Preload(what)
else
if LoadBoolean(S.tb, $I$, $INDEX$) then
return
endif
call SaveBoolean(S.tb, $I$, $INDEX$, true)
call Do$NAME$Preload(what)
endif
endfunction
//! endtextmacro
//! textmacro RANGED_PRELOAD_TYPE takes NAME
function Preload$NAME$Ex takes integer start, integer end returns nothing
local boolean mode = start < end
loop
call Preload$NAME$(start)
exitwhen start == end
if mode then
set start = BJObjectId(start).plus_1()
exitwhen start > end
else
set start = BJObjectId(start).minus_1()
exitwhen start < end
endif
endloop
endfunction
//! endtextmacro
/*========================================================================================================*/
private function DoUnitPreload takes integer id returns nothing
static if LIBRARY_UnitRecycler then
call RecycleUnitEx(CreateUnit(Player(15), id, 0, 0, 270))
else
call RemoveUnit(CreateUnit(Player(15), id, 0, 0, 0))
endif
endfunction
private function DoItemPreload takes integer id returns nothing
call RemoveItem(UnitAddItemById(S.dummy, id))
endfunction
private function DoAbilityPreload takes integer id returns boolean
return UnitAddAbility(S.dummy, id) and UnitRemoveAbility(S.dummy, id)
endfunction
private function DoEffectPreload takes string path returns nothing
call DestroyEffect(AddSpecialEffectTarget(path, S.dummy, "origin"))
endfunction
private function DoSoundPreload takes string path returns nothing
local sound s = CreateSound(path, false, false, false, 10, 10, "")
call SetSoundVolume(s, 0)
call StartSound(s)
call KillSoundWhenDone(s)
set s = null
endfunction
//! runtextmacro PRELOAD_TYPE("Unit", "integer", "unit", "what", "0")
//! runtextmacro PRELOAD_TYPE("Item", "integer", "item", "what", "1")
//! runtextmacro PRELOAD_TYPE("Ability", "integer", "ability", "what", "2")
//! runtextmacro PRELOAD_TYPE("Effect", "string", "effect", "StringHash(what)", "3")
//! runtextmacro PRELOAD_TYPE("Sound", "string", "sound", "StringHash(what)", "4")
static if LIBRARY_BJObjectId then
//! runtextmacro RANGED_PRELOAD_TYPE("Unit")
//! runtextmacro RANGED_PRELOAD_TYPE("Item")
//! runtextmacro RANGED_PRELOAD_TYPE("Ability")
endif
/*========================================================================================================*/
private module Init
private static method onInit takes nothing returns nothing
local rect world = GetWorldBounds()
static if LIBRARY_Table then
set tb = TableArray[5]
endif
set dummy = CreateUnit(Player(15), 'hpea', 0, 0, 0)
call UnitAddAbility(dummy, 'AInv')
call UnitAddAbility(dummy, 'Avul')
call UnitRemoveAbility(dummy, 'Amov')
call SetUnitY(dummy, GetRectMaxY(world) + 1000)
call RemoveRect(world)
set world = null
endmethod
endmodule
private struct S extends array
static if LIBRARY_Table then
static TableArray tb
else
static hashtable tb = InitHashtable()
endif
static unit dummy
implement Init
endstruct
endlibrary
//TESH.scrollpos=72
//TESH.alwaysfold=0
/*****************************************************************************
*
* RegisterNativeEvent v1.0.0.0
* by Bannar aka Spinnaker
*
* Storage of trigger handles for native events.
*
******************************************************************************
*
* Optional requirements:
*
* Table by Bribe
* hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
******************************************************************************
*
* Important:
*
* Avoid using TriggerSleepAction within functions registered
* Destroy native event trigger on your own responsibility
*
******************************************************************************
*
* Functions:
*
* function IsNativeEventRegistered takes integer whichIndex, integer eventId returns boolean
* whether index whichIndex has already been attached to event with id eventId
*
* function RegisterNativeEvent takes integer whichIndex, integer eventId returns boolean
* attaches index whichIndex to eventId if it hasn't been attached already and creates new trigger handle if needed
*
* function GetNativeEventTrigger takes integer eventId returns trigger
* retrieves trigger handle for event with id eventId
*
*****************************************************************************/
library RegisterNativeEvent uses optional Table
globals
private trigger array triggers
endglobals
private module NativeEventInit
static if LIBRARY_Table then
private static method onInit takes nothing returns nothing
set table = TableArray[122]
endmethod
endif
endmodule
private struct NativeEvent extends array
static if LIBRARY_Table then
static TableArray table
else
static hashtable table = InitHashtable()
endif
// 122 native events, unfortunatelly ids are not continuous
static method operator[] takes integer eventId returns integer
if ( eventId > 286 ) then
return eventId - 174
elseif ( eventId > 259 ) then
return eventId - 165
elseif ( eventId > 91 ) then
return eventId - 164
endif
return eventId
endmethod
implement NativeEventInit
endstruct
private function RegisterEvent takes integer whichIndex, integer eventId returns nothing
static if LIBRARY_Table then
set NativeEvent.table[NativeEvent[eventId]].integer[whichIndex] = eventId
else
call SaveInteger(NativeEvent.table, NativeEvent[eventId], whichIndex, eventId)
endif
endfunction
function IsNativeEventRegistered takes integer whichIndex, integer eventId returns boolean
static if LIBRARY_Table then
return NativeEvent.table[NativeEvent[eventId]].has(whichIndex)
else
return HaveSavedInteger(NativeEvent.table, NativeEvent[eventId], whichIndex)
endif
endfunction
function RegisterNativeEvent takes integer whichIndex, integer eventId returns boolean
if not IsNativeEventRegistered(whichIndex, eventId) then
call RegisterEvent(whichIndex, eventId)
if ( triggers[eventId] == null ) then
set triggers[eventId] = CreateTrigger()
endif
return true
endif
return false
endfunction
function GetNativeEventTrigger takes integer eventId returns trigger
return triggers[eventId]
endfunction
endlibrary
//TESH.scrollpos=45
//TESH.alwaysfold=0
/*****************************************************************************
*
* RegisterPlayerUnitEvent v1.0.1.0
* by Bannar aka Spinnaker
*
* Register version of TriggerRegisterPlayerUnitEvent.
*
******************************************************************************
*
* Requirements:
*
* RegisterNativeEvent by Bannar
* hiveworkshop.com/forums/submissions-414/snippet-registerevent-pack-250266/
*
******************************************************************************
*
* constant boolean RPUE_VERSION_NEW
* Defines API style. Choose between compatibility with standard RPUE or Blizzard alike interface
*
*
* Functions:
*
* function Register(Any)PlayerUnitEvent takes playerunitevent whichEvent, code cb returns nothing
* registers generic playerunitevent whichEvent adding code cb as callback
*
* function RegisterPlayerUnitEvent(ForPlayer) takes player whichPlayer, playerunitevent whichEvent, code cb returns nothing
* registers playerunitevent whichEvent for player whichPlayer adding code cb as callback
*
* function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* retrieves trigger handle for playerunitevent whichEvent
*
*****************************************************************************/
library RegisterPlayerUnitEvent requires RegisterNativeEvent
globals
constant boolean RPUE_VERSION_NEW = false
endglobals
//! textmacro_once DEFINE_REGISTER_PLAYER_UNIT_EVENT takes GENERIC, SPECIFIC
function Register$GENERIC$PlayerUnitEvent takes playerunitevent whichEvent, code cb returns nothing
local integer eventId = GetHandleId(whichEvent)
local integer index = 0
loop
if RegisterNativeEvent(index, eventId) then
call TriggerRegisterPlayerUnitEvent(GetNativeEventTrigger(eventId), Player(index), whichEvent, null)
endif
set index = index + 1
exitwhen index == 16
endloop
call TriggerAddCondition(GetNativeEventTrigger(eventId), Condition(cb))
endfunction
function RegisterPlayerUnitEvent$SPECIFIC$ takes player whichPlayer, playerunitevent whichEvent, code cb returns nothing
local integer eventId = GetHandleId(whichEvent)
if RegisterNativeEvent(GetPlayerId(whichPlayer), eventId) then
call TriggerRegisterPlayerUnitEvent(GetNativeEventTrigger(eventId), whichPlayer, whichEvent, null)
endif
call TriggerAddCondition(GetNativeEventTrigger(eventId), Condition(cb))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction
//! endtextmacro
static if RPUE_VERSION_NEW then
//! runtextmacro DEFINE_REGISTER_PLAYER_UNIT_EVENT("Any", "")
else
//! runtextmacro DEFINE_REGISTER_PLAYER_UNIT_EVENT("", "ForPlayer")
endif
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Init initializer InitFunction
private function A takes nothing returns nothing
local unit u = GetTriggerUnit()
if IsUnitType(u, UNIT_TYPE_HERO) then
call ReviveHero(u, 0.00, 0.00, false)
else
call CreateUnit(GetOwningPlayer(u), GetUnitTypeId(u), GetRandomReal(-1000.00, 1000.00), GetRandomReal(-1000.00, 1000.00), GetRandomReal(0, 360))
call TriggerSleepAction(10)
call RemoveUnit(u)
endif
set u = null
endfunction
private function B takes nothing returns nothing
call SetCameraField(CAMERA_FIELD_ZOFFSET, GetCameraField(CAMERA_FIELD_ZOFFSET) + 200, 0)
endfunction
private function InitFunction takes nothing returns nothing
local unit u = CreateUnit(Player(0), 'PLDN', 0, 0, 0)
local player p = Player(1)
local real dist = 1300
local integer creepcount = 20
local integer campcount = 15
local integer i = 0
local integer f = 360
local real x
local real y
local integer a
local real facing
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
call FogEnable(false)
call FogMaskEnable(false)
call PanCameraToTimed(0.00, 0.00, 0.00)
call SetPlayerState(p, PLAYER_STATE_GIVES_BOUNTY, 1)
call SetHeroLevel(u, 10, false)
call SelectUnit(u, true )
loop
exitwhen i == f
set i = i + f/campcount
set x = dist*Cos(i*bj_DEGTORAD)
set y = dist*Sin(i*bj_DEGTORAD)
set facing = bj_RADTODEG*Atan2(y, x)
set a = 0
loop
set a = a + 1
call CreateUnit(p, 'hpea', x, y, facing)
exitwhen a == creepcount
endloop
endloop
set u = null
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(t1, function A)
call TriggerRegisterPlayerEvent(t2, Player(0), EVENT_PLAYER_END_CINEMATIC)
call TriggerAddAction(t2, function B)
set t1 = null
set t2 = null
endfunction
endscope