- Joined
- Jul 10, 2007
- Messages
- 6,306
Installation Code- Save, Reopen Map, Delete
LUA_GET_VAR_OBJECT
LUA_FILE_HEADER
delete settings if running Lua
LUA_GET_VAR_OBJECT
LUA_FILE_HEADER
JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
//! runtextmacro LUA_FILE_HEADER()
//! i dofile("GetVarObject")
//! i local saveBuff = getvarobject("AIlf", "abilities", "ADV_DAMAGE_EVENT_SAVE_UNIT_ABILITY", true)
//! i createobject("AIlf", saveBuff)
//! i makechange(current, "Ilif", "1", "2000000")
//! i updateobjects()
//! endexternalblock
delete settings if running Lua
JASS:
library AdvDamageEvent /* v1.1.2.0
*************************************************************************************
*
* Able to modify damage
*
*************************************************************************************
*
* */uses/*
*
* */ DamageEvent /* hiveworkshop.com/forums/jass-resources-412/snippet-damageevent-186829/
*
************************************************************************************
*
* SETTINGS
*/
globals
constant integer ADV_DAMAGE_EVENT_SAVE_UNIT_ABILITY = 'A001'
endglobals
/*
*************************************************************************************
*
* struct AdvDamageEvent extends DamageEvent
* readonly static real life
* - The unit's current life.
* static real modifiedAmount
* - This is the current damage that is going to be applied to the unit.
*
*************************************************************************************/
//! textmacro ADV_DAMAGE_EVENT_EXT_CODE
/*
* Stores information for processing when the timer expires
* Life is what life the target currently has
* If the life is <= 0, the source will kill the target via UnitDamageTarget and a massive amount of damage
* If the life is > 0, the target will have its life set via SetWidgetLife
*/
private struct DamageEventStats extends array
private static thistype count = 0
static method operator last takes nothing returns thistype
return count
endmethod
static method operator first takes nothing returns thistype
return 1
endmethod
method operator next takes nothing returns thistype
return this + 1
endmethod
readonly UnitIndex source
readonly UnitIndex target
method operator sourceUnit takes nothing returns unit
return GetUnitById(source)
endmethod
method operator targetUnit takes nothing returns unit
return GetUnitById(target)
endmethod
real life
real actualLife
static method create takes UnitIndex source, UnitIndex target returns thistype
set count = count + 1
set count.source = source
set count.target = target
set count.life = thistype(target).actualLife
/*
* Not having the targets locked could corrupt timesSaved upon deindex
*/
call source.lock()
call target.lock()
return count
endmethod
static method clear takes nothing returns nothing
set count = 0
endmethod
endstruct
/*
* Handles removing/adding abilities
*/
private module AdvDamageEventMod
private static delegate DamageEventStats openDamageStats = 0
private static timer saveTimer
private integer timesSaved
static real modifiedDamage = 0
private method addSave takes nothing returns nothing
if (0 == timesSaved) then
set DamageEventStats(this).actualLife = GetWidgetLife(GetUnitById(this)) - DamageEvent.amount
else
set DamageEventStats(this).actualLife = DamageEventStats(this).actualLife - DamageEvent.amount
endif
set timesSaved = timesSaved + 1
endmethod
private static method removeSave takes nothing returns nothing
/*
* Need this check in case the unit was killed before all of its damage was applied
*/
if (0 == thistype(target).timesSaved) then
return
endif
set thistype(target).timesSaved = thistype(target).timesSaved - 1
if (0 < life) then
/*
* This is nested to make the else statement only run if the life is <= 0
*/
if (0 == thistype(target).timesSaved) then
call UnitRemoveAbility(targetUnit, ADV_DAMAGE_EVENT_SAVE_UNIT_ABILITY)
/*
* The life may very well be higher than the original life. There is no way to check for that from here, but then
* again there is no need. The user can set modifiedDamage to 0 if they don't want it to go into the negatives in the
* after event.
*/
call SetWidgetLife(targetUnit, life)
endif
else
/*
* set timesSaved to 0 so that the unit will not be processed anymore. There is no point
* to processing dead units.
*/
set thistype(target).timesSaved = 0
endif
endmethod
private static method saveUnits takes nothing returns nothing
local integer last = DamageEventStats.last
/*
* DamageEvent has to be disabled because UnitDamageTarget is used when a unit is to be killed
* This native would end up running DamageEvent
*/
set DamageEvent.enabled = false
/*
* Iterate over all units to be saved
*/
set openDamageStats = DamageEventStats.first
loop
call removeSave()
/*
* The target and source were locked in the DamageEventStats create method
* Need to unlock them or they will remain locked. This is done in this loop
* as its the most efficient way to do it.
*/
call target.unlock()
call source.unlock()
/*
* Rather than looping backwards and comparing to 0, loop forwards, this way the
* damage order is maintained.
*/
exitwhen last == openDamageStats
set openDamageStats = openDamageStats.next
endloop
call DamageEventStats.clear()
set DamageEvent.enabled = true
endmethod
private static method startSaveTimer takes nothing returns nothing
if (0 == DamageEventStats.last) then
call TimerStart(saveTimer, 0, false, function thistype.saveUnits)
endif
endmethod
static method onDamage_p_core takes nothing returns nothing
local thistype target = DamageEvent.targetId
local thistype source = DamageEvent.sourceId
/*
* Need to store two damage amounts, the original amount and the modified amount
* With this, users will be able to apply % bonuses using the original amount
*/
set modifiedDamage = DamageEvent.amount
call startSaveTimer()
call target.addSave()
set openDamageStats = DamageEventStats.create(source, target)
endmethod
private static method onInit takes nothing returns nothing
set saveTimer = CreateTimer()
endmethod
endmodule
private struct AdvDamageEvent_p extends array
implement AdvDamageEventMod
endstruct
/*
* A separate struct is needed for the API to ensure proper encapsullation
*/
struct AdvDamageEvent extends array
private static delegate DamageEvent damageEvent = 0
static method operator life takes nothing returns real
return AdvDamageEvent_p.life
endmethod
static method operator modifiedAmount takes nothing returns real
return AdvDamageEvent_p.modifiedDamage
endmethod
static method operator modifiedAmount= takes real modifiedAmount returns nothing
/*
* The modified damage is only active while the damage event is running. It is
* static. When the DamageEvent finishes running, the modified amount is lost.
* The only thing that the DamageEvent needs is the life.
*/
set AdvDamageEvent_p.life = AdvDamageEvent_p.life - (modifiedAmount - thistype.modifiedAmount)
set DamageEventStats(DamageEvent.targetId).actualLife = DamageEventStats(DamageEvent.targetId).actualLife - (modifiedAmount - thistype.modifiedAmount)
set AdvDamageEvent_p.modifiedDamage = modifiedAmount
endmethod
endstruct
//! endtextmacro
//! textmacro ADV_DAMAGE_EVENT_LOC_BEFORE
local real prevModifiedDamage = AdvDamageEvent_p.modifiedDamage
//! endtextmacro
//! textmacro ADV_DAMAGE_EVENT_EXT
call AdvDamageEvent_p.onDamage_p_core()
//! endtextmacro
//! textmacro ADV_DAMAGE_EVENT_LOC_AFTER
set AdvDamageEvent_p.modifiedDamage = prevModifiedDamage
if (GetWidgetLife(GetUnitById(targetId)) - amount < .5 and AdvDamageEvent_p.life > 0) then
call UnitAddAbility(GetUnitById(targetId), ADV_DAMAGE_EVENT_SAVE_UNIT_ABILITY)
call SetWidgetLife(GetUnitById(targetId), GetUnitState(GetUnitById(targetId), UNIT_STATE_MAX_LIFE))
endif
//! endtextmacro
endlibrary
Attachments
Last edited: