- Joined
- Apr 24, 2012
- Messages
- 5,111
God forsaken my comprehensive skills:
API (current)
Here is a demo that attaches a lifesteal amount to an indexed attack if a unit has the item 'I000'
The result from the demo code.
You might ask "what's the difference with this and PDD?" or "what's so special about this?
When writing a LifeSteal library and you use PDD, it will allow you to lifesteal from physical attacks, right? now imagine, your lifesteal system requires the unit to have an specific ability to lifeteal, you release an attack that has a missile speed of 200 but you don't have that ability then suddenly, in mid air, receives the ability, this will cause the attack you launched before to lifesteal. That is broken.
Meanwhile if you are going to write a LifeSteal library, you are going to use AttackIndexer. If we still have the scenario above but with the use of Attack Indexer + PDD, the released attack will no longer lifesteal damage if the unit doesn't have the item, regardless if you receive the item after the attack has been launched.
API (current)
JASS:
library AttackIndexer requires AllocFast UnitDex DamageEvent
globals
private constant real ATTACK_DURATION = 90
private constant integer MAX_ATTACKS = 64
endglobals
private module Init
private static method onInit takes nothing returns nothing
call init()
endmethod
endmodule
private struct AttackQueue extends array
implement AllocFast
private boolean indexed
private real time
private thistype attacks
private thistype front
private thistype back
private static thistype array next
static method operator [] takes unit u returns thistype
local thistype this = GetUnitId(u)
if not indexed and this != 0 then
set indexed = true
set attacks = 0
endif
return this
endmethod
method push takes real gameTime returns thistype
local thistype newNode = 0
if indexed then
/*
* Check if:
* - the oldest node has expired
* - the number of attack instances has reached the max attacks
*/
if gameTime - front.time > ATTACK_DURATION or attacks >= MAX_ATTACKS then
/*
* If true, use the front node as the new node
*/
set newNode = front
set front = next[front]
else
/*
* if not, allocate an attack
*/
set newNode = allocate()
set attacks = attacks + 1
endif
/*
* if the queue has only one instance, we make sure that the new node
* also becomes the front node
*/
if front == 0 then
set front = newNode
endif
/*
* push the node to the back
*/
set next[back] = newNode
set next[newNode] = 0
set back = newNode
/*
* set the current game time
*/
set time = gameTime
endif
return newNode
endmethod
method pop takes nothing returns thistype
local thistype node = 0
if indexed and attacks > 0 then
call front.deallocate()
set node = front
set front = next[front]
set attacks = attacks - 1
endif
return node
endmethod
method has takes thistype node returns boolean
local thistype n = front
loop
exitwhen 0 == n
if n == node then
return true
endif
set n = next[n]
endloop
return false
endmethod
method empty takes nothing returns boolean
return front == 0 or attacks == 0
endmethod
method destroy takes nothing returns nothing
loop
exitwhen 0 == front
call front.deallocate()
set time = 0
set front = next[front]
endloop
set attacks = 0
endmethod
endstruct
struct Attack extends array
readonly static integer indexed
readonly static integer deindexed
private static trigger indexHandler = CreateTrigger()
private static trigger deindexHandler = CreateTrigger()
private static constant timer gameTime = CreateTimer()
static method register takes code c, boolean onIndex returns nothing
if onIndex then
call TriggerAddCondition(indexHandler, Condition(c))
else
call TriggerAddCondition(deindexHandler, Condition(c))
endif
endmethod
private static method fire takes boolean onIndex returns nothing
if onIndex then
call TriggerEvaluate(indexHandler)
else
call TriggerEvaluate(deindexHandler)
endif
endmethod
static method isValid takes unit u, integer attackId returns boolean
return AttackQueue[u].has(attackId)
endmethod
static method isEmpty takes unit u returns boolean
return AttackQueue[u].empty()
endmethod
static method pop takes unit u returns integer
return AttackQueue[u].pop()
endmethod
private static method attack takes nothing returns boolean
local unit u = GetAttacker()
if GetUnitId(u) != 0 then
set indexed = AttackQueue[u].push(TimerGetElapsed(gameTime))
call fire(true)
endif
return false
endmethod
private static method damaged takes nothing returns boolean
if PDDS.damageType == PHYSICAL then
if AttackQueue[PDDS.source].empty() then
set PDDS.amount = 0
else
set deindexed = AttackQueue[PDDS.source].pop()
call fire(false)
endif
endif
return false
endmethod
private static method init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerAddCondition(t, Condition(function thistype.attack))
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
call AddDamageHandler(function thistype.damaged)
call TimerStart(gameTime, 31557600, false, null)
endmethod
implement Init
endstruct
endlibrary
Here is a demo that attaches a lifesteal amount to an indexed attack if a unit has the item 'I000'
JASS:
library LifeSteal requires AttackIndexer
private struct T extends array
private static real array factor
static method attacked takes nothing returns boolean
if UnitHasItemOfTypeBJ(GetAttacker(), 'I000') then
set factor[Attack.indexed] = GetRandomReal(0, 1)
call BJDebugMsg("Attack indexed! :" + I2S(Attack.indexed))
call BJDebugMsg("Attached lifesteal factor: " + R2S(factor[Attack.indexed]))
endif
return false
endmethod
static method damaged takes nothing returns boolean
if PDDS.amount != 0 then
call SetWidgetLife(PDDS.source, GetWidgetLife(PDDS.source) + PDDS.amount*factor[Attack.deindexed])
call BJDebugMsg("Attack deindexed! :" + I2S(Attack.deindexed))
call BJDebugMsg("Attached lifesteal factor: " + R2S(factor[Attack.deindexed]))
endif
return false
endmethod
private static method onInit takes nothing returns nothing
call Attack.register(function thistype.attacked, true)
call Attack.register(function thistype.damaged, false)
endmethod
endstruct
endlibrary
The result from the demo code.
You might ask "what's the difference with this and PDD?" or "what's so special about this?
When writing a LifeSteal library and you use PDD, it will allow you to lifesteal from physical attacks, right? now imagine, your lifesteal system requires the unit to have an specific ability to lifeteal, you release an attack that has a missile speed of 200 but you don't have that ability then suddenly, in mid air, receives the ability, this will cause the attack you launched before to lifesteal. That is broken.
Meanwhile if you are going to write a LifeSteal library, you are going to use AttackIndexer. If we still have the scenario above but with the use of Attack Indexer + PDD, the released attack will no longer lifesteal damage if the unit doesn't have the item, regardless if you receive the item after the attack has been launched.
Attachments
Last edited: