library CustomHarvestLumber initializer init requires TimerUtils, SpellEffectEvent
/*
This system also requires a Unit Indexer that uses custom values. I use Bribe's.
I'm a bit pressed for time, so I'm unable to make detailed notes.
*/
globals
private constant integer CUSTOM_EAT_TREE = 'A003'
private constant integer EATTREE = 852146
private boolean array ignoreOrder //I use this boolean to ensure all instanced triggers know not to interrupt the worker
private boolean array newCycle //This tells the system to animate the worker's attack after a cycle has ended
private integer array instance //This stores the most recent instance of the harvest action. If there's a mismatch from the struct timer, the instance terminates.
public real array BackswingPoint //Setup on indexing
public real array DamagePoint //Setup on indexing
public string array HarvestAnimation //The animation the unit will perform to 'hit' the tree. Setup on indexing.
endglobals
struct CustomHarvestLumber
unit harvester
destructable tree
boolean terminate_instance
trigger trg
real x
real y
private static method PassCheck takes unit u, integer id, thistype this returns boolean
if (not this.terminate_instance) and GetWidgetLife(this.tree) > .405 and (not IsUnitHidden(u)) and GetUnitX(u) == this.x and GetUnitY(u) == this.y and instance[id] == this then
return true
else
return false
endif
endmethod
private method destroy takes nothing returns nothing
set this.harvester = null
set this.tree = null
set this.terminate_instance = false
set this.trg = null
call this.deallocate()
endmethod
private static method CooldownTimer takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local integer id = GetUnitUserData(this.harvester)
/*/*if the unit passes all the checks, order it to use eattree again.*/*/
if PassCheck(this.harvester, id, this) then
set ignoreOrder[id] = true
set newCycle[id] = true
call IssueTargetOrderById(this.harvester, EATTREE, this.tree)
/*/*if the unit doesn't pass all the checks, end the instance.*/*/
else
call DestroyTrigger(this.trg)
call this.destroy()
call BJDebugMsg("cancelled on 'cooldown'")
endif
call ReleaseTimer(t)
set t = null
endmethod
private static method AttackTimer takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local integer id = GetUnitUserData(this.harvester)
call ReleaseTimer(t)
set t = null
/*/*if the unit passes all the checks, 'hit' the tree once.*/*/
if thistype.PassCheck(this.harvester, id, this) then
call SetDestructableAnimation(this.tree, "stand hit")
set t = NewTimerEx(this)
call TimerStart(t, BackswingPoint[id], false, function thistype.CooldownTimer)
set t = null
/*/*if the unit doesn't pass all the checks, end the instance.*/*/
else
call DestroyTrigger(this.trg)
call this.destroy()
call BJDebugMsg("cancelled on 'attack'")
endif
endmethod
/*private static method InterruptOrder takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local integer id = GetUnitUserData(this.harvester)
set ignoreOrder[id] = true
call IssueImmediateOrderById(this.harvester, 851973)//order stunned
call IssueImmediateOrderById(this.harvester, 851972) //order stop
set ignoreOrder[id] = false
call ReleaseTimer(t)
set t = null
endmethod*/
private static method HarvesterEventTrack takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetUnitUserData(u)
local integer issuedOrder = GetIssuedOrderId()
local thistype this = instance[id]
if not ignoreOrder[id] then
if GetTriggerEventId() == EVENT_UNIT_ISSUED_TARGET_ORDER then
if issuedOrder == EATTREE or issuedOrder == 851971 then//order smart
if GetOrderTargetDestructable() == this.tree then
call BJDebugMsg("same tree")
else
set this.terminate_instance = true
call BJDebugMsg("different tree")
endif
endif
else
call BJDebugMsg("other order")
set this.terminate_instance = true
endif
else
set ignoreOrder[id] = false
endif
set u = null
endmethod
static method createInstance takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetUnitUserData(u)
local timer t = null
local destructable d = GetSpellTargetDestructable()
local thistype this = instance[id]
if this.tree == null or this.tree != d then
set this = allocate()
set instance[id] = this
set this.harvester = u
set this.tree = d
set this.x = GetUnitX(u)
set this.y = GetUnitY(u)
if this.trg == null then
set this.trg = CreateTrigger()
call TriggerRegisterUnitEvent(this.trg, u, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.trg, u, EVENT_UNIT_ISSUED_TARGET_ORDER)
call TriggerRegisterUnitEvent(this.trg, u, EVENT_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterUnitEvent(this.trg, u, EVENT_UNIT_ISSUED_ORDER)
call TriggerAddCondition(this.trg, function thistype.HarvesterEventTrack)
endif
set ignoreOrder[id] = true
call IssueImmediateOrderById(u, 851973)//order stunned
call SetUnitAnimation(u, HarvestAnimation[id])
set t = NewTimerEx(this)
call TimerStart(t, DamagePoint[id], false, function thistype.AttackTimer)
set t = null
elseif this.tree == d then
set ignoreOrder[id] = true
call IssueImmediateOrderById(u, 851973)//order stunned
if newCycle[id] then//this exist to tell the system that a full cycle has completed and to animate the attack again
set newCycle[id] = false
call SetUnitAnimation(u, HarvestAnimation[id])
set t = NewTimerEx(this)
call TimerStart(t, DamagePoint[id], false, function thistype.AttackTimer)
set t = null
endif
endif
set u = null
set d = null
endmethod
endstruct
//===========================================================================
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(CUSTOM_EAT_TREE, function CustomHarvestLumber.createInstance)
endfunction
endlibrary