- Joined
- Oct 5, 2008
- Messages
- 355
I hope i get some work done this weekend. I really got sll jnderlying systems up and running, now i need only to wire that tech tree together.
I made the Wellings. What's a TriggerSleepAction? Is it some sort of bug? Point me where that thing is and let me know what it do.@Lord_Earthfire
Was your entry the Wellings? The author of the Wellings, you have a TriggerSleepAction in your triggers.
It's using Waits (GUI). He just means your code could be improved with timers and proper synchronous delays. In some cases it can cause parts of your trigger to fail or cause huge roadblocks to execution in loops, so it might or might not be a serious issue; I didn't look at your code.What's a TriggerSleepAction?
@Lord_Earthfire
Was your entry the Wellings? The author of the Wellings, you have a TriggerSleepAction in your triggers.
According to Kam's first post in the developer update thread, the xp-setting natives are currently unable to delevel a hero even if it goes below the prior level's xp threshold. Described as buggy behavior in the thread.Currently, it cannot reduce Hero levels (couldn't find the native for it yet), but it does drain experience points.
On behalf of my team, we're requesting an extension. We started a month late, perhaps we set our standards too high or something but we're fairly certain we cannot make a polished entry in time.
Merely some rushed monstrosity.
Dreamspawn buildings need Figments to progress. Dreamcatchers, as well as the Dreamspawn town halls, will generate Figment automatically. A building in progress will always attempt to pick the nearest Figment in a 4500 range.
Dreamspawn, huh? It certainly looks cooler than my method of building creation. On that note, I checked the initial post, and it doesn't show your race name, or link to my final product right now. Are you waiting to update it until the end of the contest?I guess I should also be posting WIPs.
My apologies. I had this post on page 11:As far as yours is concerned I was waiting until you posted the final draft, considering the post on page 8 was your 'first draft'. I thought you had additional updates coming.
...which was meant to indicate that my post on page 8 was updated to have the final product. I guess I wasn't clear enough.On a related note, I'll be putting up an update to the Shadefrost Nerubians in a minute here. This will probably be the final version for the contest, unless I get some really important feedback between now and the end date.
If that's the case, wouldn't it make more sense to have that ability be based on Quill Spray? Having that parameter change based on whether or not the ability's on autocast is kind of confusing.the ability doesn't actually cast. It's only here for you to switch targeting parameters. The actual cooldown itself is based on the attack speed of the Soulspinner, which has potential to fluctuate.
...you're right! I had thought that it wasn't one, because its icons don't have the yellow corners, but when I double-checked in the World Editor, it turned out to be a tweaked copypaste of Orb of Annihilation. Oops. Immolation is definitely a toggle-ability, so that should work. It can be modified so that it doesn't need mana. You could also use a modified Defend, since that's a toggle-ability that doesn't take mana in the first place.Isn't Quill Spray an autocast?
[hidden="Aura System"]
library AuraSystem /*
*/ requires /*
--------------------------
*/ UnitDex /*
--------------------------
#? GroupUtils
#? WorldBounds
-> TriggerHappy
link: https://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
--------------------------
*/ ListT /*
--------------------------
# Table
# Alloc
-> Bannar
link: https://www.hiveworkshop.com/threads/containers-list-t.249011/
--------------------------
*/ Eval /*
--------------------------
# Table
-> MyPad
link: https://www.hiveworkshop.com/threads/evaluate-code.307536/
--------------------------
*/ AllocH /*
--------------------------
# AllocT
-> MyPad
--------------------------
*/ Alloc /*
--------------------------
-> Sevion
*/
//! runtextmacro DEFINE_LIST("private", "RealList", "real")
native UnitAlive takes unit id returns boolean
globals
private unit eventUnit = null
endglobals
function GetAuraEventUnit takes nothing returns unit
return eventUnit
endfunction
private function RealToIndex takes real r returns integer
return R2I(RMaxBJ(r, 0.0001) * 10000.)
endfunction
private keyword AuraM
private struct AuraUnitData extends array
implement AllocH
private static group currentGrp = null
private static unit comparator = null
private static real range = 0.
private static EvalCode callback = 0
private static Table lastGroupMap = 0
private static method onClearGroup takes nothing returns nothing
local unit lastRemoved = eventUnit
local unit enumUnit = GetEnumUnit()
if not IsUnitInRange(enumUnit, thistype.comparator, thistype.range) then
call GroupRemoveUnit(thistype.currentGrp, enumUnit)
set eventUnit = enumUnit
call thistype.callback.run()
set eventUnit = lastRemoved
endif
set enumUnit = null
set lastRemoved = null
endmethod
method destroy takes nothing returns nothing
if thistype.lastGroupMap.group.has(this) then
call DestroyGroup(thistype.lastGroupMap.group[this])
call thistype.lastGroupMap.group.remove(this)
call this.deallocate()
debug else
debug call BJDebugMsg("AuraUnitData: Double-free detected!\n" + /*
*/ I2S(this))
endif
endmethod
method operator group takes nothing returns group
return thistype.lastGroupMap.group[this]
endmethod
method clearGroup takes unit comparator, real range, EvalCode callback returns nothing
set thistype.currentGrp = thistype.lastGroupMap.group[this]
set thistype.comparator = comparator
set thistype.range = range
set thistype.callback = callback
call ForGroup(thistype.currentGrp, function thistype.onClearGroup)
set thistype.currentGrp = null
set thistype.comparator = null
set thistype.range = 0.
set thistype.callback = 0
endmethod
static method create takes nothing returns thistype
local thistype result = thistype.allocate()
set thistype.lastGroupMap.group[result] = CreateGroup()
return result
endmethod
private static method init takes nothing returns nothing
set thistype.lastGroupMap = Table.create()
endmethod
implement AuraM
endstruct
private struct AuraUnit extends array
private boolean isAlloc
readonly IntegerList auraList
readonly Table auraMap
readonly Table auraDataMap
method destroy takes nothing returns nothing
if not this.isAlloc then
return
endif
call this.auraDataMap.destroy()
call this.auraMap.destroy()
call this.auraList.destroy()
set this.isAlloc = false
set this.auraList = 0
set this.auraMap = 0
set this.auraDataMap = 0
endmethod
static method operator [] takes unit whichUnit returns AuraUnit
local AuraUnit result = AuraUnit(GetUnitId(whichUnit))
if not result.isAlloc then
set result.isAlloc = true
set result.auraList = IntegerList.create()
set result.auraMap = Table.create()
set result.auraDataMap = Table.create()
endif
return result
endmethod
static method declare takes unit whichUnit, integer auraInstance returns AuraUnit
local AuraUnit temp = AuraUnit[whichUnit]
if not temp.auraMap.integer.has(auraInstance) then
set temp.auraMap.integer[auraInstance] = temp.auraList.push(auraInstance).last
set temp.auraDataMap.integer[auraInstance] = AuraUnitData.create()
endif
return temp
endmethod
static method strip takes unit whichUnit, integer auraInstance returns AuraUnit
local AuraUnit temp = AuraUnit(GetUnitId(whichUnit))
local AuraUnitData tempData
if not temp.isAlloc then
set temp = 0
return temp
endif
if temp.auraMap.integer.has(auraInstance) then
set tempData = AuraUnitData(temp.auraDataMap.integer[auraInstance])
call tempData.destroy()
call temp.auraList.erase(IntegerListItem(temp.auraMap.integer[auraInstance]))
call temp.auraMap.integer.remove(auraInstance)
call temp.auraDataMap.integer.remove(auraInstance)
endif
return temp
endmethod
endstruct
private struct AuraTimer extends array
readonly static Table timerMap = 0
readonly static Table timerListMap = 0
readonly static Table timerTickMap = 0
method operator tick takes nothing returns integer
return thistype.timerTickMap.integer[this]
endmethod
method operator tick= takes integer newTick returns nothing
set thistype.timerTickMap.integer[this] = newTick
endmethod
method operator list takes nothing returns IntegerList
return IntegerList(thistype.timerListMap.integer[this])
endmethod
method operator timer takes nothing returns timer
return thistype.timerMap.timer[this]
endmethod
static method create takes real enumRate returns thistype
local thistype result = RealToIndex(enumRate)
if not thistype.timerMap.timer.has(result) then
set thistype.timerMap.timer[result] = CreateTimer()
set thistype.timerListMap.integer[result] = IntegerList.create()
endif
return result
endmethod
private static method init takes nothing returns nothing
set thistype.timerMap = Table.create()
set thistype.timerListMap = Table.create()
set thistype.timerTickMap = Table.create()
endmethod
implement AuraM
endstruct
struct Aura extends array
implement Alloc
private static unit footman = null
private static filterfunc onCheck = null
private static Table abilMap = 0
// Global variables that can be accessed.
readonly static Aura currentAura = 0
private IntegerListItem node
private RealList range
private group unitGroup
private integer unitGroupCount
private real enumRate
readonly EvalCode onEnum
readonly EvalCode onEnumRemove
readonly integer abilId
readonly group handlerGroup
private method populate takes nothing returns nothing
local integer curLevel
call UnitAddAbility(Aura.footman, this.abilId)
call this.range.push(0.)
set curLevel = GetUnitAbilityLevel(Aura.footman, this.abilId)
loop
call SetUnitAbilityLevel(Aura.footman, this.abilId, curLevel + 1)
exitwhen curLevel == GetUnitAbilityLevel(Aura.footman, this.abilId)
call this.range.push(0.)
set curLevel = GetUnitAbilityLevel(Aura.footman, this.abilId)
endloop
call UnitRemoveAbility(Aura.footman, this.abilId)
endmethod
private static method onCheckGroup takes nothing returns boolean
call GroupAddUnit(bj_lastCreatedGroup, GetEnumUnit())
return true
endmethod
private static method onLoop takes nothing returns nothing
local AuraTimer auraTimer = AuraTimer.create(TimerGetTimeout(GetExpiredTimer()))
local AuraUnitData auraData
local Aura temp
local IntegerListItem iter
local group grp = CreateGroup()
local group lastGrpDest
local group lastGrpCr
local unit enum
local unit lastEventUnit
local integer level
set iter = auraTimer.list.first
loop
exitwhen iter == 0
set temp = Aura(iter.data)
loop
set enum = FirstOfGroup(temp.unitGroup)
exitwhen enum == null
call GroupRemoveUnit(temp.unitGroup, enum)
call GroupAddUnit(grp, enum)
if UnitAlive(enum) then
// Do a lot of stuff...
set level = GetUnitAbilityLevel(enum, temp.abilId)
set auraData = AuraUnitData(AuraUnit[enum].auraDataMap.integer[temp])
call auraData.clearGroup(enum, temp.range[level].data, temp.onEnumRemove)
set lastGrpDest = bj_groupAddGroupDest
set lastGrpCr = bj_lastCreatedGroup
set bj_groupAddGroupDest = temp.handlerGroup
set bj_lastCreatedGroup = auraData.group
call GroupEnumUnitsInRange(temp.handlerGroup, GetUnitX(enum), GetUnitY(enum), temp.range[level].data, Aura.onCheck)
set bj_lastCreatedGroup = lastGrpCr
set bj_groupAddGroupDest = lastGrpDest
set lastGrpDest = null
set lastGrpCr = null
set lastEventUnit = eventUnit
set Aura.currentAura = temp
set eventUnit = enum
call temp.onEnum.run()
set eventUnit = lastEventUnit
set lastEventUnit = null
endif
endloop
call DestroyGroup(temp.unitGroup)
set temp.unitGroup = grp
set grp = CreateGroup()
set iter = iter.next
endloop
set grp = null
endmethod
method removeUnit takes unit whichUnit returns nothing
local AuraTimer object
if (whichUnit == null) or (not IsUnitInGroup(whichUnit, this.unitGroup)) then
return
endif
call GroupRemoveUnit(this.unitGroup, whichUnit)
set this.unitGroupCount = this.unitGroupCount - 1
call AuraUnit.strip(whichUnit, this)
if this.unitGroupCount == 0 then
set object = AuraTimer.create(this.enumRate)
set object.tick = object.tick - 1
if object.tick <= 0 then
call PauseTimer(object.timer)
endif
endif
endmethod
method addUnit takes unit whichUnit returns nothing
local AuraTimer object
if (whichUnit == null) or (IsUnitInGroup(whichUnit, this.unitGroup)) then
return
endif
call GroupAddUnit(this.unitGroup, whichUnit)
set this.unitGroupCount = this.unitGroupCount + 1
call AuraUnit.declare(whichUnit, this)
if this.unitGroupCount == 1 then
set object = AuraTimer.create(this.enumRate)
if object.tick == 0 then
// Define handler function later.
call TimerStart(object.timer, this.enumRate, true, function thistype.onLoop)
endif
set object.tick = object.tick + 1
endif
endmethod
method setRange takes integer level, real range returns nothing
if level <= 0 or level > this.range.size() then
return
endif
set this.range[level].data = range
endmethod
static method create takes integer abilId, real enumRate returns Aura
local Aura result = Aura.abilMap.integer[abilId]
local IntegerList list
if result == 0 then
set result = Aura.allocate()
set result.abilId = abilId
set result.unitGroup = CreateGroup()
set result.handlerGroup = CreateGroup()
set result.enumRate = enumRate
set result.onEnum = EvalCode.create()
set result.onEnumRemove = EvalCode.create()
set result.range = RealList.create()
call result.populate()
set Aura.abilMap.integer[abilId] = result
set list = AuraTimer.create(enumRate).list
set result.node = list.push(result).last
endif
return result
endmethod
private static method onRemove takes nothing returns nothing
local unit removed = GetIndexedUnit()
local AuraUnit auraUnit = AuraUnit(GetIndexedUnitId())
local Aura temp
if auraUnit.auraList != 0 then
loop
exitwhen auraUnit.auraList.empty()
set temp = Aura(auraUnit.auraList.first.data)
call temp.removeUnit(removed)
call auraUnit.auraList.erase(auraUnit.auraList.first)
endloop
call auraUnit.destroy()
endif
set removed = null
endmethod
private static method initVar takes nothing returns nothing
set Aura.abilMap = Table.create()
set Aura.footman = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'hfoo', 0, 0, 0)
set Aura.onCheck = Filter(function Aura.onCheckGroup)
call ShowUnit(Aura.footman, false)
call SetUnitInvulnerable(Aura.footman, true)
endmethod
private static method initListener takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function Aura.onRemove), EVENT_UNIT_DEINDEX)
endmethod
private static method init takes nothing returns nothing
call Aura.initVar()
call Aura.initListener()
endmethod
implement AuraM
endstruct
private module AuraM
private static method onInit takes nothing returns nothing
call thistype.init()
endmethod
endmodule
endlibrary
[/hidden]
[hidden="AllocH"]
library AllocT /*
*/ requires /*
-------------------
*/ Table /*
-------------------
*/
//! runtextmacro Alloc("Alloc", "32766")
//! runtextmacro Alloc("AllocH", "2147483647")
//! textmacro Alloc takes NAME, INSTANCES
module $NAME$
private static Table alloc = 0
method deallocate takes nothing returns nothing
debug if not thistype.alloc.has(this) or (thistype.alloc[this] != Table(0)) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 50000, "|cffffcc00$NAME$ error:|r Double-free detected.")
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 50000, "Faulty instance -> " + I2S(this) + "\n\n")
debug return
debug endif
set thistype.alloc[this] = thistype.alloc[0]
set thistype.alloc[0] = Table(this)
endmethod
static method allocate takes nothing returns thistype
local thistype this = thistype(thistype.alloc[0])
if thistype.alloc[this] == Table(0) then
debug if integer(this) >= $INSTANCES$ then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 50000, "|cffffcc00$NAME$ error:|r Exceeded $INSTANCES$ instances.")
debug return thistype(0)
debug endif
set this = this + 1
set thistype.alloc[0] = Table(this)
else
set thistype.alloc[0] = thistype.alloc[this]
endif
set thistype.alloc[this] = 0
return this
endmethod
private static method onInit takes nothing returns nothing
set thistype.alloc = Table.create()
endmethod
endmodule
//! endtextmacro
endlibrary
library_once Alloc uses AllocT
endlibrary
library_once AllocH uses AllocT
endlibrary
[/hidden]
library AuraSystem /*
*/ requires /*
--------------------------
*/ UnitDex /*
--------------------------
#? GroupUtils
#? WorldBounds
-> TriggerHappy
link: https://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
--------------------------
*/ ListT /*
--------------------------
# Table
# Alloc
-> Bannar
link: https://www.hiveworkshop.com/threads/containers-list-t.249011/
--------------------------
*/ Eval /*
--------------------------
# Table
-> MyPad
link: https://www.hiveworkshop.com/threads/evaluate-code.307536/
--------------------------
*/ AllocH /*
--------------------------
# AllocT
-> MyPad
--------------------------
*/ Alloc /*
--------------------------
-> Sevion
*/
//! runtextmacro DEFINE_LIST("private", "RealList", "real")
native UnitAlive takes unit id returns boolean
globals
private unit eventUnit = null
private unit auraUnit = null
private integer addCounter = 0
endglobals
function GetAuraEventUnit takes nothing returns unit
return eventUnit
endfunction
function GetAuraUnit takes nothing returns unit
return auraUnit
endfunction
function PreventAura takes nothing returns nothing
set addCounter = addCounter - 1
endfunction
function AllowAura takes nothing returns nothing
set addCounter = addCounter + 1
endfunction
private function RealToIndex takes real r returns integer
return R2I(RMaxBJ(r, 0.0001) * 10000.)
endfunction
private function Execute takes code func returns nothing
call ForForce(bj_FORCE_PLAYER[0], func)
endfunction
private keyword AuraM
private struct AuraUnitData extends array
implement AllocH
private static EvalCode callback = 0
private static Table lastGroupMap = 0
private static Table rangeMap = 0
private static Table triggerMap = 0
private static Table triggerIdMap = 0
private static Table unitMap = 0
private static Table auraInstMap = 0
readonly static Table unitListMap = 0
readonly static trigger onEntranceTrig = null
readonly static thistype currentInst = 0
method pushAura takes unit whichUnit returns nothing
local integer unitId = GetUnitId(whichUnit)
local Table table
local IntegerList list
if whichUnit == null then
return
endif
if not thistype.unitListMap.integer.has(unitId) then
set table = Table.create()
set list = IntegerList.create()
set table.integer[-1] = list
set thistype.unitListMap.integer[unitId] = table
else
set table = Table(thistype.unitListMap.integer[unitId])
set list = IntegerList(table.integer[-1])
endif
if not table.integer.has(this) then
set table.integer[this] = list.push(this).last
call GroupAddUnit(thistype.lastGroupMap.group[this], whichUnit)
endif
endmethod
method popAura takes unit whichUnit returns nothing
local integer unitId = GetUnitId(whichUnit)
local Table table
local IntegerList list
if whichUnit == null then
return
endif
if not thistype.unitListMap.integer.has(unitId) then
// no need to pop aura.
return
endif
set table = Table(thistype.unitListMap.integer[unitId])
set list = IntegerList(table.integer[-1])
if table.integer.has(this) then
call list.erase(table.integer[this])
call table.integer.remove(this)
call GroupRemoveUnit(thistype.lastGroupMap.group[this], whichUnit)
endif
endmethod
private static method onEntrance takes nothing returns nothing
local thistype this = thistype.triggerIdMap.integer[GetHandleId(GetTriggeringTrigger())]
local thistype lastInst = thistype.currentInst
local unit lastEventUnit = eventUnit
local unit lastAuraUnit = auraUnit
set eventUnit = thistype.unitMap.unit[this]
set auraUnit = GetTriggerUnit()
set thistype.currentInst = this
set addCounter = 0
call TriggerEvaluate(thistype.onEntranceTrig)
set eventUnit = lastEventUnit
set auraUnit = lastAuraUnit
set thistype.currentInst = lastInst
set lastEventUnit = null
set lastAuraUnit = null
if addCounter >= 0 then
call this.pushAura(GetTriggerUnit())
endif
endmethod
method destroy takes nothing returns nothing
if thistype.lastGroupMap.group.has(this) then
call DestroyGroup(thistype.lastGroupMap.group[this])
call thistype.lastGroupMap.group.remove(this)
else
debug call BJDebugMsg("|cffffcc00AuraUnitData:|r Double-free detected!\n->" + I2S(this))
return
endif
if thistype.triggerMap.trigger.has(this) then
call thistype.triggerIdMap.integer.remove(GetHandleId(thistype.triggerMap.trigger[this]))
call DestroyTrigger(thistype.triggerMap.trigger[this])
call thistype.triggerMap.trigger.remove(this)
endif
call thistype.unitMap.unit.remove(this)
call thistype.rangeMap.unit.remove(this)
call thistype.auraInstMap.integer.remove(this)
call this.deallocate()
endmethod
method operator group= takes group newGroup returns nothing
set thistype.lastGroupMap.group[this] = newGroup
endmethod
method operator group takes nothing returns group
return thistype.lastGroupMap.group[this]
endmethod
method operator range= takes real newRange returns nothing
local real lastRange = thistype.rangeMap.real[this]
local integer trigId
local trigger trig
if not (newRange != range) then
return
endif
set thistype.rangeMap.real[this] = newRange
if thistype.triggerMap.trigger.has(this) then
set trigId = GetHandleId(thistype.triggerMap.trigger[this])
call DestroyTrigger(thistype.triggerMap.trigger[this])
call thistype.triggerIdMap.integer.remove(trigId)
endif
set trig = CreateTrigger()
set thistype.triggerMap.trigger[this] = trig
set trigId = GetHandleId(trig)
set thistype.triggerIdMap.integer[trigId] = this
call TriggerRegisterUnitInRange(trig, thistype.unitMap.unit[this], newRange, null)
call TriggerAddCondition(trig, Condition(function thistype.onEntrance))
endmethod
method operator range takes nothing returns real
return thistype.rangeMap.real[this]
endmethod
method operator aura= takes integer newAura returns nothing
set thistype.auraInstMap.integer[this] = newAura
endmethod
method operator aura takes nothing returns integer
return thistype.auraInstMap.integer[this]
endmethod
static method create takes unit whichUnit returns thistype
local IntegerList list
local Table table
local thistype result = thistype.allocate()
local integer unitId = GetUnitId(whichUnit)
set thistype.lastGroupMap.group[result] = CreateGroup()
set thistype.rangeMap.real[result] = 0.
set thistype.unitMap.unit[result] = whichUnit
call result.pushAura(whichUnit)
return result
endmethod
private static method onRemove takes nothing returns nothing
local integer unitId = GetIndexedUnitId()
local unit u = GetUnitById(unitId)
local Table table
local IntegerList list
local thistype temp
if thistype.unitListMap.integer.has(unitId) then
set table = Table(thistype.unitListMap.integer[unitId])
set list = IntegerList(table.integer[-1])
loop
exitwhen list.empty()
set temp = thistype(list.first.data)
call temp.popAura(u)
endloop
endif
set u = null
endmethod
private static method initVar takes nothing returns nothing
set thistype.lastGroupMap = Table.create()
set thistype.rangeMap = Table.create()
set thistype.triggerMap = Table.create()
set thistype.triggerIdMap = Table.create()
set thistype.unitMap = Table.create()
set thistype.auraInstMap = Table.create()
set thistype.unitListMap = Table.create()
set thistype.onEntranceTrig = CreateTrigger()
endmethod
private static method initListener takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onRemove), EVENT_UNIT_DEINDEX)
endmethod
private static method init takes nothing returns nothing
call thistype.initVar()
call thistype.initListener()
endmethod
implement AuraM
endstruct
private struct AuraUnit extends array
private boolean isAlloc
readonly IntegerList auraList
readonly Table auraMap
readonly Table auraDataMap
method destroy takes nothing returns nothing
if not this.isAlloc then
return
endif
call this.auraDataMap.destroy()
call this.auraMap.destroy()
call this.auraList.destroy()
set this.isAlloc = false
set this.auraList = 0
set this.auraMap = 0
set this.auraDataMap = 0
endmethod
static method operator [] takes unit whichUnit returns AuraUnit
local AuraUnit result = AuraUnit(GetUnitId(whichUnit))
if not result.isAlloc then
set result.isAlloc = true
set result.auraList = IntegerList.create()
set result.auraMap = Table.create()
set result.auraDataMap = Table.create()
endif
return result
endmethod
static method declare takes unit whichUnit, integer auraInstance, real auraRange returns AuraUnit
local AuraUnit temp = AuraUnit[whichUnit]
local AuraUnitData tempData
if not temp.auraMap.integer.has(auraInstance) then
set tempData = AuraUnitData.create(whichUnit)
set tempData.aura = auraInstance
set temp.auraMap.integer[auraInstance] = temp.auraList.push(auraInstance).last
set temp.auraDataMap.integer[auraInstance] = tempData
else
set tempData = AuraUnitData(temp.auraDataMap.integer[auraInstance])
endif
set tempData.range = auraRange
return temp
endmethod
static method strip takes unit whichUnit, integer auraInstance returns AuraUnit
local AuraUnit temp = AuraUnit(GetUnitId(whichUnit))
local AuraUnitData tempData
if not temp.isAlloc then
set temp = 0
return temp
endif
if temp.auraMap.integer.has(auraInstance) then
set tempData = AuraUnitData(temp.auraDataMap.integer[auraInstance])
call tempData.destroy()
call temp.auraList.erase(IntegerListItem(temp.auraMap.integer[auraInstance]))
call temp.auraMap.integer.remove(auraInstance)
call temp.auraDataMap.integer.remove(auraInstance)
endif
return temp
endmethod
endstruct
private struct AuraTimer extends array
readonly static Table timerMap = 0
readonly static Table timerListMap = 0
readonly static Table timerTickMap = 0
method operator tick takes nothing returns integer
return thistype.timerTickMap.integer[this]
endmethod
method operator tick= takes integer newTick returns nothing
set thistype.timerTickMap.integer[this] = newTick
endmethod
method operator list takes nothing returns IntegerList
return IntegerList(thistype.timerListMap.integer[this])
endmethod
method operator timer takes nothing returns timer
return thistype.timerMap.timer[this]
endmethod
static method create takes real enumRate returns thistype
local thistype result = RealToIndex(enumRate)
if not thistype.timerMap.timer.has(result) then
set thistype.timerMap.timer[result] = CreateTimer()
set thistype.timerListMap.integer[result] = IntegerList.create()
endif
return result
endmethod
private static method init takes nothing returns nothing
set thistype.timerMap = Table.create()
set thistype.timerListMap = Table.create()
set thistype.timerTickMap = Table.create()
endmethod
implement AuraM
endstruct
struct Aura extends array
implement Alloc
private static unit footman = null
private static Table abilMap = 0
// Global variables that can be accessed.
readonly static Aura currentAura = 0
private IntegerListItem node
private RealList range
private group unitGroup
private integer unitGroupCount
private real enumRate
readonly EvalCode onEnum
readonly EvalCode onEnumRemove
readonly EvalCode onEnter
readonly integer abilId
readonly group handlerGroup
boolean removeOnDeath
private method populate takes nothing returns nothing
local integer curLevel
call UnitAddAbility(Aura.footman, this.abilId)
call this.range.push(0.)
set curLevel = GetUnitAbilityLevel(Aura.footman, this.abilId)
loop
call SetUnitAbilityLevel(Aura.footman, this.abilId, curLevel + 1)
exitwhen curLevel == GetUnitAbilityLevel(Aura.footman, this.abilId)
call this.range.push(0.)
set curLevel = GetUnitAbilityLevel(Aura.footman, this.abilId)
endloop
call UnitRemoveAbility(Aura.footman, this.abilId)
endmethod
private static constant integer OP_COUNT = 701
private static AuraTimer lastAuraTimer = 0
private static IntegerListItem lastIterable = 0
private static integer ticks = 0
private static integer offset = 0
private static group execOuterGroup = null
private static group execInnerGroup = null
private static unit lastOuterUnit = null
private static unit lastInnerUnit = null
private static boolean hasLoopStarted = false
private static boolean hasCreatedOuterGroup = false
private static boolean hasCreatedInnerGroup = false
private static boolean hasOuterLoopStarted = false
private static boolean hasInnerLoopStarted = false
// Ensure that the loop isn't intensive.
private static method onLoopExec takes nothing returns nothing
local AuraUnitData auraData
local Aura temp
local IntegerListItem iter
local group grp
local group grp2
local group auraDataGrp
local unit enum
local unit lastEventUnit
local unit lastUnit
local integer level
local boolean isAlive
local boolean startedOuterLoop = Aura.hasOuterLoopStarted
local boolean startedInnerLoop = Aura.hasInnerLoopStarted
local real range
if not Aura.hasLoopStarted then
set Aura.hasLoopStarted = true
set iter = lastAuraTimer.list.first
else
set iter = Aura.lastIterable
endif
loop
exitwhen iter == 0 or (ModuloInteger(Aura.ticks + 1, Aura.OP_COUNT) == 0)
set temp = Aura(iter.data)
// If we created any outer group, refer to it.
if Aura.hasCreatedOuterGroup then
set grp = Aura.execOuterGroup
set Aura.hasCreatedOuterGroup = false
else
set grp = CreateGroup()
endif
set Aura.ticks = Aura.ticks + 1
set Aura.hasOuterLoopStarted = true
if startedOuterLoop then
set enum = Aura.lastOuterUnit
else
set enum = FirstOfGroup(temp.unitGroup)
endif
loop
exitwhen (enum == null) or (ModuloInteger(Aura.ticks + 1, Aura.OP_COUNT) == 0)
set Aura.ticks = Aura.ticks + 1
set lastEventUnit = eventUnit
set eventUnit = enum
call GroupRemoveUnit(temp.unitGroup, enum)
call GroupAddUnit(grp, enum)
set auraData = AuraUnitData(AuraUnit[enum].auraDataMap.integer[temp])
if Aura.hasCreatedInnerGroup then
set grp2 = Aura.execInnerGroup
set Aura.hasCreatedInnerGroup = false
else
set grp2 = CreateGroup()
endif
set isAlive = UnitAlive(enum)
set level = GetUnitAbilityLevel(enum, temp.abilId)
set range = temp.range[level].data
set Aura.hasInnerLoopStarted = true
set auraDataGrp = auraData.group
set lastUnit = auraUnit
if startedInnerLoop then
set auraUnit = Aura.lastInnerUnit
else
set auraUnit = FirstOfGroup(auraDataGrp)
endif
loop
exitwhen (auraUnit == null) or (ModuloInteger(Aura.ticks + 1, Aura.OP_COUNT) == 0)
set Aura.ticks = Aura.ticks + 1
if IsUnitInRange(auraUnit, enum, range) and isAlive then
call temp.onEnum.run()
if not UnitAlive(auraUnit) and temp.removeOnDeath then
call temp.onEnumRemove.run()
call auraData.popAura(auraUnit)
else
call GroupAddUnit(grp2, auraUnit)
call GroupRemoveUnit(auraDataGrp, auraUnit)
endif
else
if auraUnit != eventUnit then
call temp.onEnumRemove.run()
call auraData.popAura(auraUnit)
else
call GroupAddUnit(grp2, auraUnit)
call GroupRemoveUnit(auraDataGrp, auraUnit)
endif
endif
set auraUnit = lastUnit
set lastUnit = auraUnit
set auraUnit = FirstOfGroup(auraData.group)
endloop
set eventUnit = lastEventUnit
if (ModuloInteger(Aura.ticks + 1, Aura.OP_COUNT) == 0)then
set Aura.lastOuterUnit = enum
set Aura.lastInnerUnit = auraUnit
set Aura.hasCreatedInnerGroup = true
set Aura.execInnerGroup = grp2
set auraUnit = lastUnit
exitwhen true
endif
set Aura.hasInnerLoopStarted = false
call DestroyGroup(auraDataGrp)
set auraData.group = grp2
set enum = FirstOfGroup(temp.unitGroup)
endloop
if (ModuloInteger(Aura.ticks + 1, Aura.OP_COUNT) == 0) then
set Aura.hasCreatedOuterGroup = true
set Aura.execOuterGroup = grp
set Aura.lastIterable = iter
exitwhen true
endif
set Aura.hasOuterLoopStarted = false
call DestroyGroup(temp.unitGroup)
set temp.unitGroup = grp
set iter = iter.next
endloop
set grp2 = null
set grp = null
set auraDataGrp = null
set enum = null
set lastEventUnit = null
set lastUnit = null
if (ModuloInteger(Aura.ticks + 1, Aura.OP_COUNT) == 0) then
set Aura.ticks = Aura.ticks + 1
set Aura.offset = Aura.offset + 1
call Execute(function Aura.onLoopExec)
else
set Aura.hasLoopStarted = false
set Aura.hasCreatedOuterGroup= false
set Aura.hasCreatedInnerGroup= false
set Aura.hasOuterLoopStarted = false
set Aura.hasInnerLoopStarted = false
set Aura.execOuterGroup = null
set Aura.execInnerGroup = null
set Aura.lastOuterUnit = null
set Aura.lastInnerUnit = null
set Aura.lastIterable = 0
set Aura.lastAuraTimer = 0
set Aura.offset = 0
endif
endmethod
private static method onLoop takes nothing returns nothing
set lastAuraTimer = AuraTimer.create(TimerGetTimeout(GetExpiredTimer()))
set Aura.ticks = 0
call Execute(function Aura.onLoopExec)
endmethod
private method filter takes unit whichUnit, real newRange returns nothing
local unit lastEventUnit
local unit enumUnit
local group newGroup
local group iterGroup
local boolean isInGroup = IsUnitInGroup(whichUnit, this.unitGroup)
local AuraUnitData auraUnitData = AuraUnitData(AuraUnit[whichUnit].auraDataMap.integer[this])
if isInGroup then
set newGroup = CreateGroup()
endif
set lastEventUnit= eventUnit
set eventUnit = whichUnit
set iterGroup = auraUnitData.group
loop
set enumUnit = auraUnit
set auraUnit = FirstOfGroup(iterGroup)
exitwhen auraUnit == null
if not IsUnitInRange(auraUnit, eventUnit, newRange) or ((auraUnit == eventUnit) and not isInGroup) then
call this.onEnumRemove.run()
endif
if isInGroup then
call GroupAddUnit(newGroup, auraUnit)
else
call auraUnitData.popAura(auraUnit)
endif
set auraUnit = enumUnit
endloop
if isInGroup then
call DestroyGroup(auraUnitData.group)
set auraUnitData.group = newGroup
set newGroup = null
endif
set eventUnit = lastEventUnit
set lastEventUnit= null
endmethod
private static Aura filterInstance = 0
private static unit filterParameter = null
private static method filterExec takes nothing returns nothing
call Aura.filterInstance.filter(Aura.filterParameter, 0.)
endmethod
private method filterEx takes unit whichUnit returns nothing
local Aura lastInst = Aura.filterInstance
local unit lastParam = Aura.filterParameter
set Aura.filterParameter = whichUnit
set Aura.filterInstance = this
call Execute(function Aura.filterExec)
set Aura.filterParameter = lastParam
set Aura.filterInstance = lastInst
set lastParam = null
endmethod
method removeUnit takes unit whichUnit returns nothing
local AuraTimer object
if (whichUnit == null) or (not IsUnitInGroup(whichUnit, this.unitGroup)) then
return
endif
call GroupRemoveUnit(this.unitGroup, whichUnit)
set this.unitGroupCount = this.unitGroupCount - 1
// Let onEnumRemove run here...
call this.filterEx(whichUnit)
call AuraUnit.strip(whichUnit, this)
if this.unitGroupCount == 0 then
set object = AuraTimer.create(this.enumRate)
set object.tick = object.tick - 1
if object.tick <= 0 then
call PauseTimer(object.timer)
endif
endif
endmethod
method updateUnitRange takes unit whichUnit returns nothing
local integer level = GetUnitAbilityLevel(whichUnit, this.abilId)
call AuraUnit.declare(whichUnit, this, this.range[level].data)
// This gets updated on next tick anyway
// call this.filter(whichUnit, this.range[level].data)
endmethod
method addUnit takes unit whichUnit returns nothing
local AuraTimer object
local integer level
if (whichUnit == null) then
return
elseif (IsUnitInGroup(whichUnit, this.unitGroup)) then
call this.updateUnitRange(whichUnit)
return
endif
set level = GetUnitAbilityLevel(whichUnit, this.abilId)
call GroupAddUnit(this.unitGroup, whichUnit)
set this.unitGroupCount = this.unitGroupCount + 1
call AuraUnit.declare(whichUnit, this, this.range[level].data)
if this.unitGroupCount == 1 then
set object = AuraTimer.create(this.enumRate)
if object.tick == 0 then
// Define handler function later.
call TimerStart(object.timer, this.enumRate, true, function Aura.onLoop)
endif
set object.tick = object.tick + 1
endif
endmethod
method setRange takes integer level, real range returns nothing
local unit enumUnit
local group newGroup
if level <= 0 or level > this.range.size() then
return
endif
set this.range[level].data = range
set newGroup = CreateGroup()
loop
set enumUnit = FirstOfGroup(this.unitGroup)
exitwhen enumUnit == null
set level = GetUnitAbilityLevel(enumUnit, this.abilId)
call AuraUnit.declare(enumUnit, this, this.range[level].data)
if this.range[level].data < range then
call this.filter(enumUnit, this.range[level].data)
endif
call GroupRemoveUnit(this.unitGroup, enumUnit)
call GroupAddUnit(newGroup, enumUnit)
endloop
call DestroyGroup(this.unitGroup)
set this.unitGroup = newGroup
set newGroup = null
endmethod
static method create takes integer abilId, real enumRate returns Aura
local Aura result = Aura.abilMap.integer[abilId]
local IntegerList list
if result == 0 then
set result = Aura.allocate()
set result.abilId = abilId
set result.unitGroup = CreateGroup()
set result.handlerGroup = CreateGroup()
set result.enumRate = enumRate
set result.onEnum = EvalCode.create()
set result.onEnumRemove = EvalCode.create()
set result.onEnter = EvalCode.create()
set result.range = RealList.create()
set result.removeOnDeath = true
call result.populate()
set Aura.abilMap.integer[abilId] = result
set list = AuraTimer.create(enumRate).list
set result.node = list.push(result).last
endif
return result
endmethod
private static method onRemove takes nothing returns nothing
local unit removed = GetIndexedUnit()
local AuraUnit auraUnit = AuraUnit(GetIndexedUnitId())
local Aura temp
if auraUnit.auraList != 0 then
loop
exitwhen auraUnit.auraList.empty()
set temp = Aura(auraUnit.auraList.first.data)
call temp.removeUnit(removed)
endloop
call auraUnit.destroy()
endif
set removed = null
endmethod
private static method onEntrance takes nothing returns nothing
local Aura curAura = Aura(AuraUnitData.currentInst.aura)
call curAura.onEnter.run()
endmethod
private static method initVar takes nothing returns nothing
set Aura.abilMap = Table.create()
set Aura.footman = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'hfoo', 0, 0, 0)
call ShowUnit(Aura.footman, false)
call SetUnitInvulnerable(Aura.footman, true)
endmethod
private static method initListener takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function Aura.onRemove), EVENT_UNIT_DEINDEX)
call TriggerAddCondition(AuraUnitData.onEntranceTrig, Condition(function Aura.onEntrance))
endmethod
private static method init takes nothing returns nothing
call Aura.initVar()
call Aura.initListener()
endmethod
implement AuraM
endstruct
private module AuraM
private static method onInit takes nothing returns nothing
call thistype.init()
endmethod
endmodule
endlibrary
@xYours Trulyx @EternalOne feel free to make any changes during the extension. There wont be a penalty for either of you.