- Joined
- Jul 10, 2007
- Messages
- 6,306
JASS:
library DamageEvent /* v3.1.1.4
*************************************************************************************
*
* Simple light damage detection. Will not run 0 damage events as only invalid attacks and spells can cause these.
* Can instance spells and attacks with fireSpell and fireAttack methods.
*
*************************************************************************************
*
* */uses/*
*
* */ UnitIndexer /* hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
* */ PriorityEvent /* hiveworkshop.com/forums/submissions-414/snippet-priority-event-213573/
* */ BinaryHeap /* hiveworkshop.com/forums/jass-resources-412/snippet-binary-heap-199353/
*
************************************************************************************
*
* SETTINGS
*/
globals
/*************************************************************************************
*
* How many units can refresh at a given moment (when a trigger is rebuilt).
* larger size means less triggers but harder refreshes.
*
*************************************************************************************/
private constant integer TRIGGER_SIZE = 80
endglobals
/*
*************************************************************************************
*
* struct DamageEvent extends array
*
* Fields
* ------------------
* static constant PriorityEvent ANY
*
* readonly static UnitIndex targetId
* readonly static UnitIndex sourceId
* readonly static unit target
* readonly static unit source
* readonly static real amount
* readonly static integer depth
* - if depth == 1, then current damage is the original attack, not a modifier
*
* static boolean enabled
*
* readonly static integer damageType
* - useful for custom attack types (spell, hero, chaos, etc)
* readonly static integer damageId
* - useful for things like ability ids
* readonly static integer instance
* - useful for passing in a struct
*
* Methods
* ------------------
* static method unitDamageTarget takes unit attacker, widget target, real amount, integer damageType, integer damageId, integer instance returns boolean
*
*************************************************************************************
*
* module ExtendDamageEvent extends DamageEvent, AdvDamageEvent (if exists)
*
* module DamageEvent extends DamageEvent, AdvDamageEvent (if exists)
*
* Interface
* ------------------
* private static constant method PRIORITY takes nothing returns integer (optional)
* - without this declared, the priority will be set to 0 (no priority)
* private static method onDamage takes nothing returns nothing (optional)
* private static method filter takes nothing returns boolean (optional)
*
*************************************************************************************/
private struct DamageEventProperties extends array
static method operator target takes nothing returns unit
return GetUnitById(DamageEvent.targetId)
endmethod
static method operator source takes nothing returns unit
return GetUnitById(DamageEvent.sourceId)
endmethod
endstruct
//! runtextmacro optional ADV_DAMAGE_EVENT_EXT_CODE()
globals
private boolexpr damageCondition
endglobals
private struct DamageTrigger extends array
private static integer instanceCount = 0
private thistype first
private thistype next
private thistype prev
readonly thistype parent
private integer inactiveUnits
readonly integer activeUnits
private trigger damageTrigger
private method registerUnit takes UnitIndex whichUnit returns boolean
if (activeUnits < TRIGGER_SIZE) then
call TriggerRegisterUnitEvent(damageTrigger, GetUnitById(whichUnit), EVENT_UNIT_DAMAGED)
set activeUnits = activeUnits + 1
return true
endif
return false
endmethod
private method unregisterUnit takes UnitIndex whichUnit returns nothing
set inactiveUnits = inactiveUnits + 1
set activeUnits = activeUnits - 1
endmethod
private method createTrigger takes nothing returns nothing
set damageTrigger = CreateTrigger()
call TriggerAddCondition(damageTrigger, damageCondition)
endmethod
private method remakeTrigger takes nothing returns nothing
call DestroyTrigger(damageTrigger)
call createTrigger()
endmethod
private method rebuildTrigger takes nothing returns nothing
local thistype current = first
call remakeTrigger()
/*
* Iterate over all units registered to the trigger and reregister them
*/
set current.prev.next = 0
loop
exitwhen 0 == current
call TriggerRegisterUnitEvent(damageTrigger, GetUnitById(current), EVENT_UNIT_DAMAGED)
set current = current.next
endloop
set first.prev.next = current
endmethod
private method remake takes nothing returns nothing
if (inactiveUnits == TRIGGER_SIZE) then
set inactiveUnits = 0
call rebuildTrigger()
endif
endmethod
private method addToList takes thistype whichUnit returns nothing
set whichUnit.parent = this
if (0 == first) then
set first = whichUnit
set whichUnit.next = whichUnit
set whichUnit.prev = whichUnit
else
set this = first
set whichUnit.prev = prev
set whichUnit.next = this
set prev.next = whichUnit
set prev = whichUnit
endif
endmethod
method add takes thistype whichUnit returns boolean
if (0 == this) then
return false
endif
if (registerUnit(whichUnit)) then
call addToList(whichUnit)
return true
endif
return false
endmethod
private method removeFromList takes thistype whichUnit returns nothing
set whichUnit.parent = 0
set whichUnit.prev.next = whichUnit.next
set whichUnit.next.prev = whichUnit.prev
if (first == whichUnit) then
set first = whichUnit.next
if (first == whichUnit) then
set first = 0
endif
endif
endmethod
static method remove takes thistype whichUnit returns nothing
local thistype this = whichUnit.parent
call removeFromList(whichUnit)
call unregisterUnit(whichUnit)
call remake()
endmethod
private static method allocate takes nothing returns thistype
set instanceCount = instanceCount + 1
return instanceCount
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
call createTrigger()
return this
endmethod
endstruct
private struct DamageTriggerHeapInner extends array
private static method compare takes DamageTrigger trig1, DamageTrigger trig2 returns boolean
return trig1.activeUnits <= trig2.activeUnits
endmethod
implement BinaryHeap
endstruct
private struct DamageTriggerHeap extends array
private static DamageTriggerHeapInner array parent
static method add takes UnitIndex whichUnit returns nothing
local DamageTrigger damageTrigger = DamageTriggerHeapInner.root.value
if (not damageTrigger.add(whichUnit)) then
set damageTrigger = DamageTrigger.create()
call damageTrigger.add(whichUnit)
set parent[damageTrigger] = DamageTriggerHeapInner.insert(damageTrigger)
else
call parent[damageTrigger].modify(damageTrigger)
endif
endmethod
static method remove takes UnitIndex whichUnit returns nothing
local DamageTrigger damageTrigger = DamageTrigger(whichUnit).parent
call DamageTrigger.remove(whichUnit)
call parent[damageTrigger].modify(damageTrigger)
endmethod
endstruct
private module DamageEventMod
readonly static PriorityEvent ANY
readonly static UnitIndex targetId
readonly static UnitIndex sourceId
readonly static real amount
static boolean enabled
private static integer array damageType_p
private static integer array damageId_p
private static integer array instance_p
private static integer runInstanceCount_p
private static integer runAttackCount_p
private static method allocateAttack takes integer damageType, integer damageId, integer instance returns nothing
set runInstanceCount_p = runInstanceCount_p + 1
set damageType_p[runInstanceCount_p] = damageType
set damageId_p[runInstanceCount_p] = damageId
set instance_p[runInstanceCount_p] = instance
endmethod
static method unitDamageTarget takes unit attacker, widget target, real amount, integer damageType, integer damageId, integer instance returns boolean
if (enabled) then
call allocateAttack(damageType, damageId, instance)
return UnitDamageTarget(attacker, target, amount, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
endif
return false
endmethod
static method operator damageType takes nothing returns integer
return damageType_p[runInstanceCount_p]
endmethod
static method operator damageId takes nothing returns integer
return damageId_p[runInstanceCount_p]
endmethod
static method operator instance takes nothing returns integer
return instance_p[runInstanceCount_p]
endmethod
static method operator depth takes nothing returns integer
return runAttackCount_p
endmethod
private static delegate DamageEventProperties damageEventProperties = 0
private static method damage takes nothing returns boolean
local integer previousTargetId
local integer previousSourceId
local real previousAmount
//! runtextmacro optional ADV_DAMAGE_EVENT_LOC_BEFORE()
if (enabled and 0 != GetEventDamage()) then
/*
* Setup spell
*/
if (runAttackCount_p == runInstanceCount_p) then
set runInstanceCount_p = runInstanceCount_p + 1
endif
set runAttackCount_p = runAttackCount_p + 1
/*
* Store previous amounts
*/
set previousTargetId = targetId
set previousSourceId = sourceId
set previousAmount = amount
/*
* Update amounts to new amounts
*/
set targetId = GetUnitUserData(GetTriggerUnit())
set sourceId = GetUnitUserData(GetEventDamageSource())
set amount = GetEventDamage()
/*
* Fire event
*/
//! runtextmacro optional ADV_DAMAGE_EVENT_EXT()
call ANY.fire()
/*
* Restore previous amounts
*/
set targetId = previousTargetId
set sourceId = previousSourceId
set amount = previousAmount
//! runtextmacro optional ADV_DAMAGE_EVENT_LOC_AFTER()
/*
* Remove spell
*/
set damageType_p[runInstanceCount_p] = 0
set damageId_p[runInstanceCount_p] = 0
set instance_p[runInstanceCount_p] = 0
if (runAttackCount_p == runInstanceCount_p) then
set runInstanceCount_p = runInstanceCount_p - 1
endif
set runAttackCount_p = runAttackCount_p - 1
endif
return false
endmethod
private static method index takes nothing returns boolean
call UnitIndex(GetIndexedUnitId()).lock()
call DamageTriggerHeap.add(GetIndexedUnitId())
return false
endmethod
private static method deindex takes nothing returns boolean
call DamageTriggerHeap.remove(GetIndexedUnitId())
call UnitIndex(GetIndexedUnitId()).unlock()
return false
endmethod
private static method onInit takes nothing returns nothing
set enabled = true
set runInstanceCount_p = 0
set runAttackCount_p = 0
set damageCondition = Condition(function thistype.damage)
set ANY = PriorityEvent.create()
call RegisterUnitIndexEvent(Condition(function thistype.index), UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.deindex), UnitIndexer.DEINDEX)
set targetId = 0
set sourceId = 0
set amount = 0
endmethod
endmodule
struct DamageEvent extends array
implement DamageEventMod
endstruct
module ExtendDamageEvent
static if AdvDamageEvent_p.onDamage_p_core.exists then
private static delegate AdvDamageEvent advDamageEvent = 0
else
private static delegate DamageEvent damageEvent = 0
endif
endmodule
module DamageEvent
implement ExtendDamageEvent
static if thistype.onDamage.exists then
private static method onDamage_p takes nothing returns boolean
static if thistype.filter.exists then
if (filter()) then
call onDamage()
endif
else
call onDamage()
endif
return false
endmethod
private static method onInit takes nothing returns nothing
static if thistype.PRIORITY.exists then
call DamageEvent.ANY.register(Condition(function thistype.onDamage_p), PRIORITY())
else
call DamageEvent.ANY.register(Condition(function thistype.onDamage_p), 0)
endif
endmethod
endif
endmodule
endlibrary
cnp of the above still gives correct line breaks
Code:
library DamageEvent /* v3.1.1.4
*************************************************************************************
*
* Simple light damage detection. Will not run 0 damage events as only invalid attacks and spells can cause these.
* Can instance spells and attacks with fireSpell and fireAttack methods.
*
*************************************************************************************
*
* */uses/*
*
* */ UnitIndexer /* hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
* */ PriorityEvent /* hiveworkshop.com/forums/submissions-414/snippet-priority-event-213573/
* */ BinaryHeap /* hiveworkshop.com/forums/jass-resources-412/snippet-binary-heap-199353/
*
************************************************************************************
*
* SETTINGS
*/
globals
/*************************************************************************************
*
* How many units can refresh at a given moment (when a trigger is rebuilt).
* larger size means less triggers but harder refreshes.
*
*************************************************************************************/
private constant integer TRIGGER_SIZE = 80
endglobals
/*
*************************************************************************************
*
* struct DamageEvent extends array
*
* Fields
* ------------------
* static constant PriorityEvent ANY
*
* readonly static UnitIndex targetId
* readonly static UnitIndex sourceId
* readonly static unit target
* readonly static unit source
* readonly static real amount
* readonly static integer depth
* - if depth == 1, then current damage is the original attack, not a modifier
*
* static boolean enabled
*
* readonly static integer damageType
* - useful for custom attack types (spell, hero, chaos, etc)
* readonly static integer damageId
* - useful for things like ability ids
* readonly static integer instance
* - useful for passing in a struct
*
* Methods
* ------------------
* static method unitDamageTarget takes unit attacker, widget target, real amount, integer damageType, integer damageId, integer instance returns boolean
*
*************************************************************************************
*
* module ExtendDamageEvent extends DamageEvent, AdvDamageEvent (if exists)
*
* module DamageEvent extends DamageEvent, AdvDamageEvent (if exists)
*
* Interface
* ------------------
* private static constant method PRIORITY takes nothing returns integer (optional)
* - without this declared, the priority will be set to 0 (no priority)
* private static method onDamage takes nothing returns nothing (optional)
* private static method filter takes nothing returns boolean (optional)
*
*************************************************************************************/
private struct DamageEventProperties extends array
static method operator target takes nothing returns unit
return GetUnitById(DamageEvent.targetId)
endmethod
static method operator source takes nothing returns unit
return GetUnitById(DamageEvent.sourceId)
endmethod
endstruct
//! runtextmacro optional ADV_DAMAGE_EVENT_EXT_CODE()
globals
private boolexpr damageCondition
endglobals
private struct DamageTrigger extends array
private static integer instanceCount = 0
private thistype first
private thistype next
private thistype prev
readonly thistype parent
private integer inactiveUnits
readonly integer activeUnits
private trigger damageTrigger
private method registerUnit takes UnitIndex whichUnit returns boolean
if (activeUnits < TRIGGER_SIZE) then
call TriggerRegisterUnitEvent(damageTrigger, GetUnitById(whichUnit), EVENT_UNIT_DAMAGED)
set activeUnits = activeUnits + 1
return true
endif
return false
endmethod
private method unregisterUnit takes UnitIndex whichUnit returns nothing
set inactiveUnits = inactiveUnits + 1
set activeUnits = activeUnits - 1
endmethod
private method createTrigger takes nothing returns nothing
set damageTrigger = CreateTrigger()
call TriggerAddCondition(damageTrigger, damageCondition)
endmethod
private method remakeTrigger takes nothing returns nothing
call DestroyTrigger(damageTrigger)
call createTrigger()
endmethod
private method rebuildTrigger takes nothing returns nothing
local thistype current = first
call remakeTrigger()
/*
* Iterate over all units registered to the trigger and reregister them
*/
set current.prev.next = 0
loop
exitwhen 0 == current
call TriggerRegisterUnitEvent(damageTrigger, GetUnitById(current), EVENT_UNIT_DAMAGED)
set current = current.next
endloop
set first.prev.next = current
endmethod
private method remake takes nothing returns nothing
if (inactiveUnits == TRIGGER_SIZE) then
set inactiveUnits = 0
call rebuildTrigger()
endif
endmethod
private method addToList takes thistype whichUnit returns nothing
set whichUnit.parent = this
if (0 == first) then
set first = whichUnit
set whichUnit.next = whichUnit
set whichUnit.prev = whichUnit
else
set this = first
set whichUnit.prev = prev
set whichUnit.next = this
set prev.next = whichUnit
set prev = whichUnit
endif
endmethod
method add takes thistype whichUnit returns boolean
if (0 == this) then
return false
endif
if (registerUnit(whichUnit)) then
call addToList(whichUnit)
return true
endif
return false
endmethod
private method removeFromList takes thistype whichUnit returns nothing
set whichUnit.parent = 0
set whichUnit.prev.next = whichUnit.next
set whichUnit.next.prev = whichUnit.prev
if (first == whichUnit) then
set first = whichUnit.next
if (first == whichUnit) then
set first = 0
endif
endif
endmethod
static method remove takes thistype whichUnit returns nothing
local thistype this = whichUnit.parent
call removeFromList(whichUnit)
call unregisterUnit(whichUnit)
call remake()
endmethod
private static method allocate takes nothing returns thistype
set instanceCount = instanceCount + 1
return instanceCount
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
call createTrigger()
return this
endmethod
endstruct
private struct DamageTriggerHeapInner extends array
private static method compare takes DamageTrigger trig1, DamageTrigger trig2 returns boolean
return trig1.activeUnits <= trig2.activeUnits
endmethod
implement BinaryHeap
endstruct
private struct DamageTriggerHeap extends array
private static DamageTriggerHeapInner array parent
static method add takes UnitIndex whichUnit returns nothing
local DamageTrigger damageTrigger = DamageTriggerHeapInner.root.value
if (not damageTrigger.add(whichUnit)) then
set damageTrigger = DamageTrigger.create()
call damageTrigger.add(whichUnit)
set parent[damageTrigger] = DamageTriggerHeapInner.insert(damageTrigger)
else
call parent[damageTrigger].modify(damageTrigger)
endif
endmethod
static method remove takes UnitIndex whichUnit returns nothing
local DamageTrigger damageTrigger = DamageTrigger(whichUnit).parent
call DamageTrigger.remove(whichUnit)
call parent[damageTrigger].modify(damageTrigger)
endmethod
endstruct
private module DamageEventMod
readonly static PriorityEvent ANY
readonly static UnitIndex targetId
readonly static UnitIndex sourceId
readonly static real amount
static boolean enabled
private static integer array damageType_p
private static integer array damageId_p
private static integer array instance_p
private static integer runInstanceCount_p
private static integer runAttackCount_p
private static method allocateAttack takes integer damageType, integer damageId, integer instance returns nothing
set runInstanceCount_p = runInstanceCount_p + 1
set damageType_p[runInstanceCount_p] = damageType
set damageId_p[runInstanceCount_p] = damageId
set instance_p[runInstanceCount_p] = instance
endmethod
static method unitDamageTarget takes unit attacker, widget target, real amount, integer damageType, integer damageId, integer instance returns boolean
if (enabled) then
call allocateAttack(damageType, damageId, instance)
return UnitDamageTarget(attacker, target, amount, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
endif
return false
endmethod
static method operator damageType takes nothing returns integer
return damageType_p[runInstanceCount_p]
endmethod
static method operator damageId takes nothing returns integer
return damageId_p[runInstanceCount_p]
endmethod
static method operator instance takes nothing returns integer
return instance_p[runInstanceCount_p]
endmethod
static method operator depth takes nothing returns integer
return runAttackCount_p
endmethod
private static delegate DamageEventProperties damageEventProperties = 0
private static method damage takes nothing returns boolean
local integer previousTargetId
local integer previousSourceId
local real previousAmount
//! runtextmacro optional ADV_DAMAGE_EVENT_LOC_BEFORE()
if (enabled and 0 != GetEventDamage()) then
/*
* Setup spell
*/
if (runAttackCount_p == runInstanceCount_p) then
set runInstanceCount_p = runInstanceCount_p + 1
endif
set runAttackCount_p = runAttackCount_p + 1
/*
* Store previous amounts
*/
set previousTargetId = targetId
set previousSourceId = sourceId
set previousAmount = amount
/*
* Update amounts to new amounts
*/
set targetId = GetUnitUserData(GetTriggerUnit())
set sourceId = GetUnitUserData(GetEventDamageSource())
set amount = GetEventDamage()
/*
* Fire event
*/
//! runtextmacro optional ADV_DAMAGE_EVENT_EXT()
call ANY.fire()
/*
* Restore previous amounts
*/
set targetId = previousTargetId
set sourceId = previousSourceId
set amount = previousAmount
//! runtextmacro optional ADV_DAMAGE_EVENT_LOC_AFTER()
/*
* Remove spell
*/
set damageType_p[runInstanceCount_p] = 0
set damageId_p[runInstanceCount_p] = 0
set instance_p[runInstanceCount_p] = 0
if (runAttackCount_p == runInstanceCount_p) then
set runInstanceCount_p = runInstanceCount_p - 1
endif
set runAttackCount_p = runAttackCount_p - 1
endif
return false
endmethod
private static method index takes nothing returns boolean
call UnitIndex(GetIndexedUnitId()).lock()
call DamageTriggerHeap.add(GetIndexedUnitId())
return false
endmethod
private static method deindex takes nothing returns boolean
call DamageTriggerHeap.remove(GetIndexedUnitId())
call UnitIndex(GetIndexedUnitId()).unlock()
return false
endmethod
private static method onInit takes nothing returns nothing
set enabled = true
set runInstanceCount_p = 0
set runAttackCount_p = 0
set damageCondition = Condition(function thistype.damage)
set ANY = PriorityEvent.create()
call RegisterUnitIndexEvent(Condition(function thistype.index), UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.deindex), UnitIndexer.DEINDEX)
set targetId = 0
set sourceId = 0
set amount = 0
endmethod
endmodule
struct DamageEvent extends array
implement DamageEventMod
endstruct
module ExtendDamageEvent
static if AdvDamageEvent_p.onDamage_p_core.exists then
private static delegate AdvDamageEvent advDamageEvent = 0
else
private static delegate DamageEvent damageEvent = 0
endif
endmodule
module DamageEvent
implement ExtendDamageEvent
static if thistype.onDamage.exists then
private static method onDamage_p takes nothing returns boolean
static if thistype.filter.exists then
if (filter()) then
call onDamage()
endif
else
call onDamage()
endif
return false
endmethod
private static method onInit takes nothing returns nothing
static if thistype.PRIORITY.exists then
call DamageEvent.ANY.register(Condition(function thistype.onDamage_p), PRIORITY())
else
call DamageEvent.ANY.register(Condition(function thistype.onDamage_p), 0)
endif
endmethod
endif
endmodule
endlibrary