- Joined
- Jul 10, 2007
- Messages
- 6,306
JASS:
library DamageModificationEffect /* v1.0.1.2
*************************************************************************************
*
* Apply damage modifiers to units
*
*************************************************************************************
*
* */uses/*
*
* */ AdvDamageEvent /* hiveworkshop.com/forums/submissions-414/extension-advanced-damage-event-213572/
* */ AVL /* hiveworkshop.com/forums/jass-resources-412/snippet-avl-tree-203168/
* */ Table /* hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
* */ DamagePriority /* hiveworkshop.com/forums/submissions-414/repo-damage-priority-213750/
*
*************************************************************************************
*
* Outgoing Vs Incoming Damage
* - If incoming, will evaluate code whenever the unit takes damage
* - If outgoing, will evaluate code whenever the unit applies damage
* - Incoming damage always runs after outgoing damage regardless of priority
*
* struct DamageModificationEffect extends AdvDamageEvent, UnitIndexStructMethods
*
* readonly static DamageModificationEffect event
* - The evaluated DamageModificationEffect. Use to retrieve instance within passed in code.
*
* integer priority
*
* boolexpr code
* - Code to be evaluated when effect runs
* - Must return true
*
* method apply takes boolexpr func, boolean incoming, integer priority returns thistype
* - Applies damage effect to unit (this is UnitIndex)
* - DamageModificationEffect[whichUnit].apply(...)
*
* method destroy takes nothing returns nothing
* - Destroys a damage modification effect (this is DamageModificationEffect)
* - set effect = DamageModificationEffect[whichUnit].apply(...)
* - call effect.destroy()
*
*
* method clearOutgoing takes nothing returns nothing
* - Clears all outgoing effects
* - call DamageModificationEffect[whichUnit].clearOutgoing()
* method clearIncoming takes nothing returns nothing
* - Clears all incoming effects
* - call DamageModificationEffect[whichUnit].clearIncoming()
* method clear takes nothing returns nothing
* - Clears unit of all damage modification effects currently on it (this is UnitIndex)
* - call DamageModificationEffect[whichUnit].clear()
*
* module DamageModificationEffect extends AdvDamageEvent, UnitIndexStructMethods
*
* method apply takes boolean incoming returns thistype (returns 0 if neither onDamageOutgoing or onDamageIncoming exist)
* - Applies damage effect to unit (this is UnitIndex)
* - thistype[whichUnit].apply(...)
*
* method destroy takes nothing returns nothing
* - Destroys a damage modification effect (this is thistype)
* - set effect = thistype[whichUnit].apply(...)
* - call effect.destroy()
*
* method clearOutgoing takes nothing returns nothing (only exists when onDamageOutgoing exists)
* - Clears all outgoing effects
* - call thistype[whichUnit].clearOutgoing()
* method clearIncoming takes nothing returns nothing (only exists when onDamageIncoming exists)
* - Clears all incoming effects
* - call thistype[whichUnit].clearIncoming()
* method clear takes nothing returns nothing
* - Clears unit of all damage modification effects currently on it (this is UnitIndex)
* - call thistype[whichUnit].clear()
*
* Interface:
* private static constant integer PRIORITY takes nothing returns integer (optional)
* - defined priority for module
* private method onDamageIncoming takes nothing returns nothing (optional)
* - this is the current struct instance returned from apply
* private method onDamageOutgoing takes nothing returns nothing (optional)
* - this is the current struct instance returned from apply
*
*************************************************************************************/
private struct Tree extends array
method lessThan takes thistype value returns boolean
return integer(this) < integer(value)
endmethod
method greaterThan takes thistype value returns boolean
return integer(this) > integer(value)
endmethod
implement AVL
endstruct
private module PriorityListMod
private static method onInit takes nothing returns nothing
set next_pp = Table.create()
set prev_pp = Table.create()
set head_pp = Table.create()
set superhead_pp = Table.create()
endmethod
endmodule
private struct PriorityList extends array
private static integer instanceCount = 0
private static Table next_pp
private static Table prev_pp
private static Table head_pp
private static Table superhead_pp
implement PriorityListMod
method operator next_p takes nothing returns thistype
return next_pp[this]
endmethod
method operator next_p= takes thistype val returns nothing
set next_pp[this] = val
endmethod
method operator prev_p takes nothing returns thistype
return prev_pp[this]
endmethod
method operator prev_p= takes thistype val returns nothing
set prev_pp[this] = val
endmethod
method operator head_p takes nothing returns thistype
return head_pp[this]
endmethod
method operator head_p= takes thistype val returns nothing
set head_pp[this] = val
endmethod
method operator superhead_p takes nothing returns thistype
return superhead_pp[this]
endmethod
method operator superhead_p= takes thistype val returns nothing
set superhead_pp[this] = val
endmethod
thistype first_p
private static method allocate takes nothing returns thistype
local thistype this = thistype(0).next_p
if (0 == this) then
set this = instanceCount + 1
set instanceCount = this
else
set thistype(0).next_p = next_p
endif
return this
endmethod
private method deallocate takes nothing returns nothing
set next_p = thistype(0).next_p
set thistype(0).next_p = this
endmethod
private static method deallocateRange takes thistype first, thistype last returns nothing
set last.next_p = thistype(0).next_p
set thistype(0).next_p = first
endmethod
static method create takes nothing returns thistype
return Tree.create()
endmethod
method destroy takes nothing returns nothing
local Tree priority = this
/*
* Loop through priorities
*/
loop
set priority = priority.next
exitwhen priority.head
/*
* Deallocate list on priority
*/
if (0 != thistype(priority).first_p) then
call deallocateRange(thistype(priority).first_p, thistype(priority).first_p.prev_p)
set thistype(priority).first_p = 0
endif
endloop
call Tree(this).destroy()
endmethod
method clear takes nothing returns nothing
local Tree priority = this
/*
* Loop through priorities
*/
loop
set priority = priority.next
exitwhen priority.head
/*
* Deallocate list on priority
*/
if (0 != thistype(priority).first_p) then
call deallocateRange(thistype(priority).first_p, thistype(priority).first_p.prev_p)
set thistype(priority).first_p = 0
endif
endloop
call Tree(this).clear()
endmethod
private method add_p takes thistype node returns nothing
/*
* Add to list
*/
if (0 == first_p) then
set first_p = node
set node.next_p = node
set node.prev_p = node
else
set node.next_p = first_p
set node.prev_p = first_p.prev_p
set first_p.prev_p.next_p = node
set first_p.prev_p = node
endif
set node.head_p = this
endmethod
method add takes integer priority returns thistype
local thistype node = allocate()
call thistype(Tree(this).add(priority)).add_p(node)
set node.superhead_p = this
return node
endmethod
private method remove_p takes nothing returns nothing
local thistype node = this
/*
* Get list
*/
set this = head_p
/*
* Remove from list
*/
set node.prev_p.next_p = next_p
set node.next_p.prev_p = prev_p
if (node == first_p) then
set first_p = node.next_p
if (node == first_p) then
set first_p = 0
endif
endif
endmethod
method remove takes nothing returns nothing
call remove_p()
call deallocate()
endmethod
method operator priority takes nothing returns integer
return Tree(head_p).value
endmethod
method operator priority= takes integer priority returns nothing
if (this.priority != priority) then
call remove_p()
call thistype(Tree(superhead_p).add(priority)).add_p(this)
endif
endmethod
endstruct
private module DamageModificationEffectMod
private static method onInit takes nothing returns nothing
set evalForce = CreateForce()
endmethod
endmodule
struct DamageModificationEffect extends array
private static constant method PRIORITY takes nothing returns integer
return DAMAGE_PRIORITY_EXECUTION_DAMAGE_MODIFIER_EFFECTS
endmethod
private PriorityList listOutgoing
private PriorityList listIncoming
boolexpr code
readonly static thistype event = 0
private static force evalForce
implement DamageModificationEffectMod
method operator priority takes nothing returns integer
return PriorityList(this).priority
endmethod
method operator priority= takes integer priority returns nothing
set PriorityList(this).priority = priority
endmethod
method apply takes boolexpr func, boolean incoming, integer priority returns thistype
local thistype node
if (incoming) then
set node = listIncoming.add(priority)
else
set node = listOutgoing.add(priority)
endif
set node.code = func
return node
endmethod
method destroy takes nothing returns nothing
call PriorityList(this).remove()
endmethod
method clearOutgoing takes nothing returns nothing
call listOutgoing.clear()
endmethod
method clearIncoming takes nothing returns nothing
call listIncoming.clear()
endmethod
method clear takes nothing returns nothing
call clearOutgoing()
call clearIncoming()
endmethod
private static method applyDamage takes Tree priority returns nothing
local thistype node
local thistype prevEvent
if (0 != priority) then
/*
* Loop through all priorities
*/
loop
set priority = priority.prev
exitwhen priority.head
/*
* Loop through all nodes
*/
set node = PriorityList(priority).first_p
if (0 != node) then
set PriorityList(priority).first_p.prev_p.next_p = 0
set prevEvent = event
loop
set event = node
call ForceEnumPlayersCounted(evalForce, node.code, 1)
set node = PriorityList(node).next_p
exitwhen 0 == node
endloop
set event = prevEvent
set PriorityList(priority).first_p.prev_p.next_p = PriorityList(priority).first_p
endif
endloop
endif
endmethod
private static method onDamage takes nothing returns nothing
call applyDamage(thistype(sourceId).listOutgoing)
call applyDamage(thistype(targetId).listIncoming)
endmethod
private method index takes nothing returns nothing
set listIncoming = PriorityList.create()
set listOutgoing = PriorityList.create()
endmethod
private method deindex takes nothing returns nothing
call listIncoming.destroy()
call listOutgoing.destroy()
endmethod
implement DamageEvent
implement UnitIndexStruct
endstruct
private module ModuleListMod
private static Table next_p
private static Table prev_p
private static Table head_p
method operator next takes nothing returns thistype
return next_p[this]
endmethod
method operator next= takes thistype val returns nothing
set next_p[this] = val
endmethod
method operator prev takes nothing returns thistype
return prev_p[this]
endmethod
method operator prev= takes thistype val returns nothing
set prev_p[this] = val
endmethod
method operator head takes nothing returns thistype
return head_p[this]
endmethod
method operator head= takes thistype val returns nothing
set head_p[this] = val
endmethod
private static method onInit takes nothing returns nothing
set next_p = Table.create()
set prev_p = Table.create()
set head_p = Table.create()
endmethod
endmodule
private struct ModuleList extends array
implement ModuleListMod
private static integer instanceCount = 0
static method create takes nothing returns thistype
local thistype this = thistype(0).next
if (0 == this) then
set this = instanceCount + 1
set instanceCount = this
else
set thistype(0).next = next
endif
set next = this
set prev = this
return this
endmethod
method clear takes nothing returns nothing
if (this != next) then
set prev.next = thistype(0).next
set thistype(0).next = next
set next = this
set prev = this
endif
endmethod
method destroy takes nothing returns nothing
set prev.next = thistype(0).next
set thistype(0).next = this
endmethod
method add takes nothing returns thistype
local thistype node = create()
set node.next = this
set node.prev = prev
set prev.next = node
set prev = node
set node.head = this
return node
endmethod
method remove takes nothing returns nothing
local thistype node = this
/*
* Get list
*/
set this = head
/*
* Remove from list
*/
set node.prev.next = node.next
set node.next.prev = node.prev
set node.next = thistype(0).next
set thistype(0).next = node
endmethod
endstruct
module DamageModificationEffect
static if thistype.onDamageIncoming.exists then
private static boolexpr codeIncoming
private ModuleList listIncoming
endif
static if thistype.onDamageOutgoing.exists then
private static boolexpr codeOutgoing
private ModuleList listOutgoing
endif
static if thistype.onDamageIncoming.exists then
private static method onDamageIncoming_p takes nothing returns boolean
local ModuleList list = thistype(targetId).listIncoming
local thistype node
set list.prev.next = 0
/*
* Loop through all nodes
*/
set node = list.next
loop
exitwhen 0 == node
call node.onDamageIncoming()
set node = ModuleList(node).next
endloop
set list.prev.next = list
return true
endmethod
endif
static if thistype.onDamageOutgoing.exists then
private static method onDamageOutgoing_p takes nothing returns boolean
local ModuleList list = thistype(sourceId).listOutgoing
local thistype node
set list.prev.next = 0
/*
* Loop through all nodes
*/
set node = list.next
loop
exitwhen 0 == node
call node.onDamageOutgoing()
set node = ModuleList(node).next
endloop
set list.prev.next = list
return true
endmethod
endif
method apply takes boolean incoming returns thistype
local thistype node = 0
if (incoming) then
static if thistype.onDamageIncoming.exists then
set node = listIncoming.add()
endif
else
static if thistype.onDamageOutgoing.exists then
set node = listOutgoing.add()
endif
endif
return node
endmethod
method destroy takes nothing returns nothing
call ModuleList(this).remove()
endmethod
static if thistype.onDamageOutgoing.exists then
method clearOutgoing takes nothing returns nothing
call listOutgoing.clear()
endmethod
endif
static if thistype.onDamageIncoming.exists then
method clearIncoming takes nothing returns nothing
call listIncoming.clear()
endmethod
endif
method clear takes nothing returns nothing
static if thistype.onDamageOutgoing.exists then
call clearOutgoing()
endif
static if thistype.onDamageIncoming.exists then
call clearIncoming()
endif
endmethod
private static method index_p takes nothing returns boolean
local thistype this = GetIndexedUnitId()
static if thistype.onDamageIncoming.exists then
set listIncoming = ModuleList.create()
static if thistype.PRIORITY.exists then
call DamageModificationEffect(this).apply(codeIncoming, true, PRIORITY())
else
call DamageModificationEffect(this).apply(codeIncoming, true, 0)
endif
endif
static if thistype.onDamageOutgoing.exists then
set listOutgoing = ModuleList.create()
static if thistype.PRIORITY.exists then
call DamageModificationEffect(this).apply(codeOutgoing, false, PRIORITY())
else
call DamageModificationEffect(this).apply(codeOutgoing, false, 0)
endif
endif
return false
endmethod
private static method deindex_p takes nothing returns boolean
local thistype this = GetIndexedUnitId()
static if thistype.onDamageIncoming.exists then
call listIncoming.destroy()
endif
static if thistype.onDamageOutgoing.exists then
call listOutgoing.destroy()
endif
return false
endmethod
private static method onInit takes nothing returns nothing
static if thistype.onDamageIncoming.exists then
set codeIncoming = Condition(function thistype.onDamageIncoming_p)
endif
static if thistype.onDamageOutgoing.exists then
set codeOutgoing = Condition(function thistype.onDamageOutgoing_p)
endif
call RegisterUnitIndexEvent(Condition(function thistype.index_p), UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.deindex_p), UnitIndexer.DEINDEX)
endmethod
implement ExtendDamageEvent
implement UnitIndexStructMethods
endmodule
endlibrary
Last edited: