Cokemonkey11
Spell Reviewer
- Joined
- May 9, 2006
- Messages
- 3,575
Guardian
Preface:
Guardian is an extremely simple system which prevents a unit from taking lethal damage. If a unit is logged in the system, it will propagate a chain of callback effects assigned by the user. This system is made purely for preventing units from dying, and exists as a separate script for modularity purposes.
Design Explanation:
Limitations:
API:
The script:
Requires http://www.hiveworkshop.com/forums/...uctureddd-structured-damage-detection-216968/
Example Test Scope:
(Yes, it's that simple)
Change Log:
2013.05.27 - Initial submission to Hive: Jass Resources: Submissions
Special Thanks:
Preface:
Guardian is an extremely simple system which prevents a unit from taking lethal damage. If a unit is logged in the system, it will propagate a chain of callback effects assigned by the user. This system is made purely for preventing units from dying, and exists as a separate script for modularity purposes.
Design Explanation:
- User adds a Guardian instance in the form of a (unit,code) pair.
- Whenever a unit in the system takes damage that would kill it, the damage is prevented and all callback functions are called.
- Callback functions can use Guardian.mitigated and Guardian.who to see how much damage was prevented and act further on the unit.
Limitations:
- Guardian requires StructuredDD and thus will not work with other Damage Detection Systems.
- Guardian requires the original Table by Vexorian and thus will not work with other versions that have different API's.
- Guardian is written in vJass and therefore requires Jass Newgen Pack (or JassHelper externally) to preprocess.
API:
Guardian.LIFE_SHIM
- Set this to the rawcode of the "bonus life" ability (see test map). If you don't configure this, the unit will not properly avoid damage whose magnitude is greater than their max hit points.
Guardian.mitigated
- In the scope of a callback function, Guardian.mitigated can be used to check how much damage was avoided using Guardian.Guardian.who
- In the scope of a callback function, Guardian.who can be used to see which unit avoided death.
Guardian.exists(unit)
- Method used for checking if unit is indexed by Guardian (therefore it is unkillable).Guardian.add(unit,string)
- Method for adding a callback function to a unit's avoidance of death. u is indexed and a function with the name s will be called when u would otherwise die.Guardian.remove(unit,string)
- Method for removing a callback node from a unit in the system. Returns a warning in debug mode if the node doesn't exist.
The script:
Requires http://www.hiveworkshop.com/forums/...uctureddd-structured-damage-detection-216968/
JASS:
//* API:
//* static real mitigated: In the scope of a callback function, Guardian.mitigated
//* can be used to check how much damage was avoided using
//* Guardian.
//* static unit who: In the scope of a callback function, Guardian.who can
//* be used to see which unit avoided death.
//* static method exists: Method used for checking if a unit is indexed by
//* Guardian (therefore it is unkillable).
//* static method add: Method for adding a callback function to a unit's
//* avoidance of death. Arguments are of the form (unit
//* 'u',string 's') where u is indexed and a function with
//* the name s will be called when u would otherwise die.
//* static method remove: Method for removing a callback node from a unit in
//* the system. Returns a warning in debug mode if the
//* node doesn't exist.
library Guardian requires StructuredDD, Table
//* Contains data for callback functions. Each instance is a node in a linked
//* list for an indexed unit.
private struct callback
string cbf
thistype prev=-1
thistype next=-1
endstruct
//* Shim structure for assigning a unique integer for a unit temporarily.
private struct unitShim
unit who
endstruct
//* The struct shim which gives the API its sexy style that everyone loves
//* (Guardian is never instanciated)
struct Guardian extends array
//<< BEGIN CUSTOMIZE SECTION
//* The rawcode of the "bonus life" ability. If it's not configured, the
//* unit will die if it's attacked with damage greater than its max hit
//* points.
private static constant integer LIFE_SHIM='A000'
//>> END CUSTOMIZE SECTION
private static constant string WARNING="|cffffcc00[Guardian] [Guardian.remove] Warning: Attempted to remove an instance that doesn't exist."
private static HandleTable ht
private static HandleTable fromTimers
//* In the scope of a callback function, used to see how much damage was
//* avoided using Guardian
readonly static real mitigated=-1.
//* In the scope of a callback function, used to see which unit prevented
//* death by means of Guardian
readonly static unit who
//* Used to check if a unit is indexed in Guardian.
public static method exists takes unit u returns boolean
return ht.exists(u)
endmethod
//* Adds a callback function to a unit when preventing death.
public static method add takes unit u, string cb returns nothing
local callback newDat=callback.create()
local callback otherDat
set newDat.cbf=cb
if ht.exists(u) then
set otherDat=ht[u]
set newDat.next=otherDat
set otherDat.prev=newDat
endif
set ht[u]=newDat
endmethod
//* Removes a callback function from a unit. If it's the last node left
//* in the linked list, the unit will no longer avoid death.
public static method remove takes unit u, string cb returns nothing
local callback temp
local callback otherDat
if ht.exists(u) then
set temp=ht[u]
loop
exitwhen temp==-1
if temp.cbf==cb then
if temp.prev==-1 and temp.next!=-1 then
set otherDat=temp.next
set otherDat.prev=-1
set ht[u]=otherDat
elseif temp.prev!=-1 and temp.next!=-1 then
set otherDat=temp.next
set otherDat.prev=temp.prev
set otherDat=temp.prev
set otherDat.next=temp.next
elseif temp.prev==-1 and temp.next==-1 then
call ht.flush(u)
else
set otherDat=temp.prev
set otherDat.next=-1
endif
call temp.destroy()
return
endif
set temp=temp.next
endloop
endif
debug call DisplayTextToPlayer(GetLocalPlayer(),0.,0.,thistype.WARNING)
endmethod
//* Auxillary method used by timers to set a units life after 0 seconds.
private static method delay takes nothing returns nothing
local timer time=GetExpiredTimer()
local unitShim tempUS=fromTimers[time]
call DestroyTimer(time)
call fromTimers.flush(time)
set time=null
call UnitRemoveAbility(tempUS.who,thistype.LIFE_SHIM)
call SetWidgetLife(tempUS.who,.406)
call tempUS.destroy()
endmethod
//* StructuredDD handler used to look for units about to die.
private static method h takes nothing returns nothing
local unit tU=GetTriggerUnit()
local real damage=GetEventDamage()
local real life=GetWidgetLife(tU)
local timer time
local unitShim tempUS
local callback temp
if ht.exists(tU) and damage>life-.405 then
set thistype.mitigated=damage+.406-life
set thistype.who=tU
if damage<GetUnitState(tU,UNIT_STATE_MAX_LIFE) then
call SetWidgetLife(tU,damage+.406)
else
call UnitAddAbility(tU,thistype.LIFE_SHIM)
call SetWidgetLife(tU,damage+.406)
set time=CreateTimer()
set tempUS=unitShim.create()
set tempUS.who=tU
set fromTimers[time]=tempUS
call TimerStart(time,0.,false,function thistype.delay)
set time=null
endif
set temp=ht[tU]
loop
exitwhen temp==-1
call ExecuteFunc(temp.cbf)
set temp=temp.next
endloop
endif
set tU=null
endmethod
//* Initialization method
private static method onInit takes nothing returns nothing
set ht=HandleTable.create()
set fromTimers=HandleTable.create()
call StructuredDD.addHandler(function thistype.h)
endmethod
endstruct
endlibrary
Example Test Scope:
JASS:
scope test initializer i
globals
private unit u
endglobals
private function cbf takes nothing returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0.,0.,"OMG!")
endfunction
private function c takes nothing returns boolean
call Guardian.remove(u,SCOPE_PRIVATE+"cbf")
return false
endfunction
private function i takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterPlayerEvent(t,Player(0),EVENT_PLAYER_END_CINEMATIC)
call TriggerAddCondition(t,Condition(function c))
set u=CreateUnit(Player(0),'hfoo',0.,0.,0.)
call SetWidgetLife(u,1.)
call Guardian.add(u,SCOPE_PRIVATE+"cbf")
endfunction
endscope
(Yes, it's that simple)
Change Log:
2013.05.27 - Initial submission to Hive: Jass Resources: Submissions
Special Thanks:
- Magtheridon96 for trying to standardize warning/error formatting
- -Kobas- for creating a map submission template, which turned out useful for system submissions as well.
- Vexorian for developing JassHelper. Without vJass, I almost certainly would not still be scripting for wc3.
- The various developers of JNGP including PitzerMike and MindworX. Integrating JassHelper and TESH is a godsend.
Attachments
Last edited: