- Joined
- May 9, 2014
- Messages
- 1,820
This is a damage detection system that detects damage dealt. It has three events, a detection event, a finalization of damage event, and the actual dealing of damage event.
The ability to modify damage via variable has been outsourced and simplified. The library will also adjust some abilities automatically for the spell detection to work properly with some of them.
[note="Adage"]
From Rising_Dusk's priority damage registration, I got some of my damage trigger design.
From jesus4lyf's DDS, I figured out how to block damage
From Leandrotp's bracers trick, I got spell detection.
From Wietlol's discussion on AfterDamage events, I got an after damage event.
From Unit Indexers, I automated registration of units to the damage trigger.
Thank you all for inspiring me to make this damage detection library.
[/note]
Core Damage Detection:
Damage Manipulation
Ability Fixes:
Drain Life Fix:
Bracers Fix
A straightforward damage detection system that detects physical and spell damage, and the after-damage event that utilizes a bucket technique for saving mass trigger creation. It uses either the UnitDex library for catching the indexing and deindexing event and registering the affected unit to the system.
(Speculation at this point)
Though redundant at this point, this damage detection trigger provides near-flawless after-damage event detection, using a specialized
Modifier Event
Damage Instance Event
The ability to modify damage via variable has been outsourced and simplified. The library will also adjust some abilities automatically for the spell detection to work properly with some of them.
[note="Adage"]
From Rising_Dusk's priority damage registration, I got some of my damage trigger design.
From jesus4lyf's DDS, I figured out how to block damage
From Leandrotp's bracers trick, I got spell detection.
From Wietlol's discussion on AfterDamage events, I got an after damage event.
From Unit Indexers, I automated registration of units to the damage trigger.
Thank you all for inspiring me to make this damage detection library.
[/note]
Code:
Documentation
Demo
Core Damage Detection:
JASS:
library DamageDetection uses AllocationAndLinks, /*
*/ optional EventStruct, /*
*/ optional UnitEventV, /* not Bribe's version.
*/ optional UnitDex, /*
*/ optional Table,/*
*/ optional OneTimer
native UnitAlive takes unit id returns boolean
globals
private constant real ETHEREAL_OFFSET = 1.66
endglobals
function IsUnitAffectByMagic takes unit which returns boolean
return not IsUnitType(which, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(which, UNIT_TYPE_MECHANICAL) and not IsUnitType(which, UNIT_TYPE_ANCIENT) and not IsUnitType(which, UNIT_TYPE_STRUCTURE)
endfunction
// You should set the global health to the same value as the externalblock HEALTH...
/*
//! externalblock extension=lua ObjectMerger $FILENAME$
//! i HEALTH = 50000000
//! i CONDITION = false
//! i function health_cheat_create()
//! i if CONDITION then
//! i setobjecttype("abilities")
//! i createobject("AIlf", "@hth")
//! i makechange(current, "anam", "Health Cheat")
//! i makechange(current, "alev", 1)
//! i makechange(current, "Ilif", 1, HEALTH)
//! i end
//! i end
//! i function spell_differentiation()
//! i if CONDITION then
//! i setobjecttype("abilities")
// Make new Bracers
//! i createobject("AIsr", "@spl")
//! i makechange(current, "isr2", 1, 2.00)
//! i makechange(current, "anam", "Spell Detection")
//! i end
//! i end
//! i function mana_shield()
//! i setobjecttype("abilities")
//! i modifyobject("ACmf")
//! i makechange(current, "Nms2", 1, 1.)
//! i makechange(current, "Nms1", 1, 0.)
//! i modifyobject("ANms")
//! i makechange(current, "Nms2", 1, 1.)
//! i makechange(current, "Nms2", 2, 1.)
//! i makechange(current, "Nms2", 3, 1.)
//! i makechange(current, "Nms1", 1, 0.)
//! i makechange(current, "Nms1", 2, 0.)
//! i makechange(current, "Nms1", 3, 0.)
//! i end
//! i function mechanics_change()
//! i if CONDITION then
//! i setobjecttype("abilities")
// Modify Locust Swarm
//! i modifyobject("AUls")
//! i makechange(current, "Uls4", 1, -0.75)
// Make new Anti-Magic Shell
//! i createobject("AUfa", ";ams")
//! i makechange(current, "aart", "ReplaceableTextures\\CommandButtons\\BTNAntiMagicShell.blp")
//! i makechange(current, "Ufa2", 1, 0.00)
//! i makechange(current, "Ufa1", 1, 90.00)
//! i makechange(current, "abuf", 1, "Bams,Bam2")
//! i makechange(current, "aran", 1, 500.00)
//! i makechange(current, "acdn", 1, 0.00)
//! i makechange(current, "ahdu", 1, 0.01)
//! i makechange(current, "adur", 1, 0.01)
//! i makechange(current, "aher", 0)
//! i makechange(current, "alev", 1)
//! i makechange(current, "atar", 1, "air,ground,vuln,invu")
//! i makechange(current, "areq", "Ruba")
//! i makechange(current, "anam", "Anti-magic Shield")
//! i makechange(current, "ansf", "(Triggered)")
//! i makechange(current, "ahky", "N")
//! i makechange(current, "atp1", 1, "A|cffffcc00n|rti-magic Shell")
//! i makechange(current, "aub1", 1, "Creates a barrier that stops spells from affecting a target unit. |nLasts <;ams:AUfa,Dur1> seconds. |n|n|cffffcc00Triggered|r")
// Give ability to banshee
//! i setobjecttype("units")
//! i modifyobject("uban")
//! i makechange(current, "uabi", ";ams,Acrs,Apos,Aiun")
// Modify Mana Shield
//! i mana_shield()
//! i end
//! i end
//! i health_cheat_create()
//! i spell_differentiation()
//! i mechanics_change()
//! endexternalblock
*/
/*
globals
constant real HEALTH = 50000000
endglobals
*/
globals
private constant trigger DAMAGE_TRIG = CreateTrigger()
private constant integer DMG_MAX_REG = 60
endglobals
globals
constant integer HEALTH_CHEAT = '@hth'
constant integer BRACERS = '@spl'
endglobals
private struct DmgEventS extends array
static if LIBRARY_EventStruct then
static Event DmgEvent = 0
static Event ZeroDmgEvent = 0
else
static real DmgEvent = -8191.
static real ZeroDmgEvent = -8191.
endif
endstruct
static if LIBRARY_EventStruct then
constant function GetDamageEventType takes integer value returns Event
if value == 0 then
return DmgEventS.ZeroDmgEvent
elseif value == 1 then
return DmgEventS.DmgEvent
endif
return 0
endfunction
private module Init_m
private static method onInit takes nothing returns nothing
set DmgEventS.ZeroDmgEvent = Event.create()
set DmgEventS.DmgEvent = Event.create()
endmethod
endmodule
private struct Init_s extends array
implement Init_m
endstruct
endif
static if LIBRARY_Table then
private module DamageEvent_Bucket_m
private static method onInit takes nothing returns nothing
set Bucket = Table.create()
endmethod
endmodule
endif
public struct DamageEventInterface extends array
static real currHP = 0.
endstruct
struct DamageEvent extends array
implement Alloc_MyPad
static if not LIBRARY_Table then
implement DoubleLink
endif
// Trigger Creation portion
private trigger trig
private group group
private integer event_count
private integer unit_count
// Damage Detection mechanism
private static real finalHP = 0.
readonly static unit source = null
readonly static unit target = null
readonly static real dmg = 0.
readonly static real finalDmg = 0.
readonly static player p_source = null
readonly static player p_target = null
readonly static boolean spell = false
// Arrays
private static boolean detect = true
private static integer count = 0
private static boolean array detect_a
private static real array finalHP_a
private static trigger array trigger_a
readonly static unit array source_a
readonly static unit array target_a
readonly static real array dmg_a
readonly static real array finalDmg_a
readonly static player array p_source_a
readonly static player array p_target_a
readonly static boolean array spell_a
static if LIBRARY_Table then
private static Table Bucket = 0
implement DamageEvent_Bucket_m
private static method bucket_s takes unit u, thistype that returns nothing
set Bucket.integer[GetUnitData(u)] = that
endmethod
private static method bucket takes unit u returns thistype
return Bucket.integer[GetUnitData(u)]
endmethod
endif
private static method get takes unit u returns thistype
static if LIBRARY_Hashtable then
return bucket(u)
else
local thistype this = thistype(0).next
loop
exitwhen this == 0 or IsUnitInGroup(u, group)
set this = next
endloop
return this
endif
endmethod
// UnitDamageTarget made safe
static method damage takes unit u, unit u2, real r, boolean b1, boolean b2, attacktype a, damagetype d, weapontype w returns boolean
local thistype this = get(u2)
local boolean br = false
set detect = false
set br = UnitDamageTarget(u, u2, r, b1, b2, a, d, w)
set detect = true
return br
endmethod
// Pure damage is detectable by the damage trigger, but does not fire any more events...
static method deal_pure takes unit u, unit u2, real r returns boolean
local boolean br = false
if GetWidgetLife(u2) - r >= 0.406 then
set br = damage(u, u2, 0., true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
if br then
call SetWidgetLife(u2, GetWidgetLife(u2) - r)
endif
return br
endif
set br = UnitDamageTarget(u, u2, r, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
return br
endmethod
private static method get_trigger takes trigger t returns integer
local integer i = 1
loop
exitwhen i > count or trigger_a[i] == t
set i = i + 1
endloop
if i > count then
set i = 0
endif
return i
endmethod
private static method onDamage_null_vars takes integer i returns nothing
set source_a[i] = null
set target_a[i] = null
set dmg_a[i] = 0.
set p_source_a[i] = null
set p_target_a[i] = null
set detect_a[i] = false
set spell_a[i] = false
set finalDmg_a[i] = 0.
set finalHP_a[i] = 0.
set trigger_a[i] = null
set count = count - 1
if count <= 0 then
set count = 0
endif
endmethod
private static method onDamage_reset_vars takes integer i returns nothing
set source = source_a[i]
set target = target_a[i]
set dmg = dmg_a[i]
set p_source = p_source_a[i]
set p_target = p_target_a[i]
set detect = detect_a[i]
set spell = spell_a[i]
endmethod
// Damage Detection Event handling
private static method onLifeEvent takes nothing returns nothing
local trigger t = GetTriggeringTrigger()
local integer arr = get_trigger(t)
if GetTriggerEventId() == EVENT_UNIT_STATE_LIMIT then
call UnitRemoveAbility(target_a[arr], HEALTH_CHEAT)
call SetWidgetLife(target_a[arr], finalHP_a[arr])
set DamageEventInterface.currHP = GetWidgetLife(target_a[arr])
if detect_a[arr] then
static if LIBRARY_EventStruct then
set DmgEventS.DmgEvent.fire = 2.
else
set DmgEventS.DmgEvent = 2.
set DmgEventS.DmgEvent = -8191.
endif
endif
endif
call DisableTrigger(t)
call DestroyTrigger(t)
call onDamage_null_vars(arr)
set t = null
endmethod
private static method onDamage_init_vars takes nothing returns nothing
set source_a[count] = source
set target_a[count] = target
set dmg_a[count] = dmg
set p_source_a[count] = p_source
set p_target_a[count] = p_target
set detect_a[count] = detect
set spell_a[count] = spell
set trigger_a[count] = CreateTrigger()
endmethod
private static method onDamage takes nothing returns nothing
local trigger t
local real modHP
local real maxHP
local real curHP
local integer i
set source = GetEventDamageSource()
set target = GetTriggerUnit()
set dmg = GetEventDamage()
set p_source = GetOwningPlayer(source)
set p_target = GetTriggerPlayer()
set maxHP = GetUnitState(target, UNIT_STATE_MAX_LIFE)
set curHP = GetWidgetLife(target)
set spell = (dmg <= 0.)
set count = count + 1
set i = count
if spell and dmg != 0 then
set dmg = -dmg
endif
call onDamage_init_vars()
if dmg != 0 then
if dmg > maxHP then
call UnitAddAbility(target_a[i], HEALTH_CHEAT)
call SetWidgetLife(target_a[i], curHP)
if spell then
set maxHP = GetUnitState(target_a[i], UNIT_STATE_MAX_LIFE)
endif
endif
set DamageEventInterface.currHP = curHP
if detect_a[i] then
static if LIBRARY_EventStruct then
set DmgEventS.DmgEvent.fire = 0.
else
set DmgEventS.DmgEvent = 0.
set DmgEventS.DmgEvent = -8191.
endif
endif
call onDamage_reset_vars(i)
set modHP = GetWidgetLife(target)
set finalHP = DamageEventInterface.currHP - dmg_a[i]
set finalDmg = curHP - finalHP
set finalHP_a[i] = finalHP
set finalDmg_a[i] = finalDmg
if detect_a[i] then
static if LIBRARY_EventStruct then
set DmgEventS.DmgEvent.fire = 1.
else
set DmgEventS.DmgEvent = 1.
set DmgEventS.DmgEvent = -8191.
endif
endif
call onDamage_reset_vars(i)
if not spell_a[i] then
call SetWidgetLife(target_a[i], dmg_a[i] + 64)
else
call SetWidgetLife(target_a[i], RMaxBJ(GetWidgetLife(target_a[i]) - dmg_a[i], 0.406))
endif
set modHP = GetWidgetLife(target_a[i])
set t = trigger_a[i]
// Inaccuracies may be produced ...
if spell_a[i] then
call TriggerRegisterUnitStateEvent(t, target_a[i], UNIT_STATE_LIFE, GREATER_THAN, RMinBJ(modHP + dmg, maxHP))
call TriggerRegisterUnitStateEvent(t, target_a[i], UNIT_STATE_LIFE, LESS_THAN, RMinBJ(modHP + dmg, maxHP))
call BJDebugMsg("to detect: " + R2S(RMinBJ(modHP + dmg, maxHP)))
call BJDebugMsg("Final life should be: " + R2S(finalHP))
else
call TriggerRegisterUnitStateEvent(t, target_a[i], UNIT_STATE_LIFE, GREATER_THAN, modHP - dmg_a[i])
call TriggerRegisterUnitStateEvent(t, target_a[i], UNIT_STATE_LIFE, LESS_THAN, modHP - dmg_a[i])
endif
call TriggerRegisterTimerEvent(t, 0., false)
call TriggerAddCondition(t, function thistype.onLifeEvent)
set t = null
else
if detect_a[i] then
static if LIBRARY_EventStruct then
set DmgEventS.ZeroDmgEvent.fire = 0.
else
set DmgEventS.ZeroDmgEvent = 0.
set DmgEventS.ZeroDmgEvent = -8191.
endif
endif
call onDamage_null_vars(i)
endif
endmethod
// Trigger Registry and Creation portion
private static thistype current = 0
private method destroy takes nothing returns nothing
call DestroyTrigger(trig)
call GroupClear(group)
set event_count = 0
set unit_count = 0
static if not LIBRARY_Table then
call pop()
endif
call deallocate()
endmethod
private static method create takes nothing returns thistype
local thistype this = allocate()
set trig = CreateTrigger()
call TriggerAddCondition(trig, function thistype.onDamage)
if GetHandleId(group) == 0 then
set group = CreateGroup()
endif
set event_count = 0
set unit_count = 0
static if not LIBRARY_Table then
call push()
endif
return this
endmethod
static method register takes unit u returns nothing
local thistype this = get(u)
if this == 0 then
if current == 0 then
set current = create()
endif
set this = current
call UnitAddAbility(u, BRACERS)
call UnitMakeAbilityPermanent(u, true, BRACERS)
call TriggerRegisterUnitEvent(trig, u, EVENT_UNIT_DAMAGED)
call GroupAddUnit(group, u)
static if LIBRARY_Table then
call bucket_s(u, this)
endif
set event_count = event_count + 1
set unit_count = unit_count + 1
if event_count >= DMG_MAX_REG then
set current = 0
endif
endif
endmethod
static method unregister takes unit u returns nothing
local thistype this = get(u)
if this == 0 then
return
endif
call GroupRemoveUnit(group, u)
set unit_count = unit_count - 1
if unit_count <= 0 and event_count >= DMG_MAX_REG then
call destroy()
endif
endmethod
private static method onUnitScope takes nothing returns nothing
if GetRealEvent() == 1.00 or GetRealEvent() == 0.5 then
call register(GetEventTriggerUnit())
elseif GetRealEvent() == 2.00 then
call unregister(GetEventTriggerUnit())
endif
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local unit u
static if LIBRARY_UnitEventV then
call TriggerRegisterAuxUnitEvent(t, 1.00)
call TriggerRegisterAuxUnitEvent(t, 0.50)
call TriggerRegisterAuxUnitEvent(t, 2.00)
else
endif
call TriggerAddCondition(t, function thistype.onUnitScope)
set t = null
set u = CreateUnit(Player(15), 'uloc', 0, 0, 0)
call UnitAddAbility(u, HEALTH_CHEAT)
call UnitAddAbility(u, BRACERS)
call RemoveUnit(u)
set u = null
endmethod
endstruct
function TriggerRegisterDamageEvent takes trigger t, real r returns nothing
static if LIBRARY_EventStruct then
call EventTrigs.register(DmgEventS.DmgEvent, r, t)
else
call TriggerRegisterVariableEvent(t, "s__" + SCOPE_PREFIX + "_DmgEventS_DmgEvent", EQUAL, 0.)
endif
endfunction
function TriggerRegisterZeroDamageEvent takes trigger t returns nothing
static if LIBRARY_EventStruct then
call EventTrigs.register(DmgEventS.ZeroDmgEvent, 0., t)
else
call TriggerRegisterVariableEvent(t, "s__" + SCOPE_PREFIX + "_DmgEventS_ZeroDmgEvent", EQUAL, 0.)
endif
endfunction
// ========================= //
// Utilities //
// ========================= //
function UnitDamageTargetPure takes unit u, unit u2, real r returns boolean
return DamageEvent.deal_pure(u, u2, r)
endfunction
function UnitDamageTargetEx takes unit u, unit u2, real r, boolean b1, boolean b2, attacktype a, damagetype d, weapontype w returns boolean
return DamageEvent.damage(u, u2, r, b1, b2, a, d, w)
endfunction
endlibrary
Damage Manipulation
JASS:
library DamageDetectionAddOns requires DamageDetection, AllocationAndLinks, /*
*/ optional EventStruct /* https://www.hiveworkshop.com/threads/library-pseudo-var-event.292870/#post-3148385
*/
// ========================= //
// Damage Modification //
// ========================= //
private struct DmgModEventS extends array
static if LIBRARY_EventStruct then
static Event DmgModEvent = 0
else
static real DmgModEvent = -8191
endif
endstruct
static if LIBRARY_EventStruct then
function GetDamageModEvent takes nothing returns Event
return DmgModEventS.DmgModEvent
endfunction
else
function GetDamageModEvent takes nothing returns real
return DmgModEventS.DmgModEvent
endfunction
endif
static if LIBRARY_EventStruct then
private module Init_m2
private static method onInit takes nothing returns nothing
set DmgModEventS.DmgModEvent = Event.create()
endmethod
endmodule
private struct Init_s2 extends array
implement Init_m2
endstruct
endif
struct DamageModEvent extends array
implement AllocLinkBundle
private static constant boolean HIGHER_PRIO_FIRST = true
private real real
static real appliedDmg = 0.
private static method get takes real r returns thistype
local thistype this = thistype(0).next
loop
exitwhen this == 0 or real == r
set this = next
endloop
return this
endmethod
private method list_sort takes nothing returns nothing
local thistype that = thistype(0).next
loop
exitwhen (that.real > real and that.prev.real < real) or that == 0
set that = that.next
endloop
call insert(that)
endmethod
// Explicit call
private static method create takes real r returns thistype
local thistype this = allocate()
set real = r
call list_sort()
return this
endmethod
static method register takes trigger t, real r returns nothing
local thistype this = get(r)
if this == 0 then
set this = create(r)
endif
static if LIBRARY_EventStruct then
call EventTrigs.register(DmgModEventS.DmgModEvent, r, t)
else
call TriggerRegisterVariableEvent(t, "s__" + SCOPE_PRIVATE + "_DmgModEventS_DmgModEvent", EQUAL, r)
endif
endmethod
private static method onDamage takes nothing returns nothing
local thistype this = 0
local real curHP
local real maxHP
set appliedDmg = DamageEvent.dmg
static if HIGHER_PRIO_FIRST then
set this = prev
loop
exitwhen this == 0
static if LIBRARY_EventStruct then
set DmgModEventS.DmgModEvent.fire = real
else
set DmgModEventS.DmgModEvent = real
endif
set this = prev
endloop
static if not LIBRARY_EventStruct then
set DmgModEventS.DmgModEvent = -8191.
endif
else
set this = next
loop
exitwhen this == 0
static if LIBRARY_EventStruct then
set DmgModEventS.DmgModEvent.fire = real
else
set DmgModEventS.DmgModEvent = real
endif
set this = next
endloop
static if not LIBRARY_EventStruct then
set DmgModEventS.DmgModEvent = -8191.
endif
endif
set curHP = GetWidgetLife(DamageEvent.target)
set maxHP = GetUnitState(DamageEvent.target, UNIT_STATE_MAX_LIFE)
set DamageDetection_DamageEventInterface.currHP = curHP + DamageEvent.dmg - appliedDmg
set curHP = RMaxBJ(DamageDetection_DamageEventInterface.currHP, 0.406)
if curHP > maxHP then
call UnitAddAbility(DamageEvent.target, HEALTH_CHEAT)
endif
call SetWidgetLife(DamageEvent.target, curHP)
endmethod
private static method onSecInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterDamageEvent(t, 0.)
call TriggerAddCondition(t, function thistype.onDamage)
set t = null
call DestroyTimer(GetExpiredTimer())
endmethod
private static method onInit takes nothing returns nothing
call TimerStart(CreateTimer(), 0., false, function thistype.onSecInit)
endmethod
endstruct
function TriggerRegisterDamageModEvent takes trigger t, real r returns nothing
call DamageModEvent.register(t, r)
endfunction
endlibrary
Ability Fixes:
Drain Life Fix:
JASS:
library DrainLifeFix requires Hashtable, AllocationAndLinks, DamageDetection, optional Illusion
private module LifeDrainMod
private static method abil_Init takes nothing returns nothing
call register('ACdr')
call register('ANdr')
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
set Registered = GenerateKey()
//set TrigIndex = GenerateKey()
//set TrigIndexR = GenerateKey()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
call TriggerAddCondition(t, function thistype.onEffect)
set t = CreateTrigger()
call TriggerRegisterDamageEvent(t, 2.00)
call TriggerAddCondition(t, function thistype.onDamage)
call abil_Init()
set t = null
endmethod
endmodule
///! runtextmacro link_module("unlink", "private")
public struct LifeDrain extends array
implement AllocLinkBundle
//private static constant timer timer = CreateTimer()
//! runtextmacro Add_ReadonlyOp("Registered", "registered", "boolean", "Boolean", "Boolean", "false")
///! runtextmacro AddOp("private", "TrigIndex", "index", "integer", "Integer", "Integer", "0")
///! runtextmacro AddOp("private", "TrigIndexR", "life", "real", "Real", "Real", "0.")
readonly unit caster
readonly unit target
//implement DoubleLink_unlink
private method destroy takes nothing returns nothing
if this == 0 then
debug call BJDebugMsg("Error, attempted to deallocate head.")
return
endif
set caster = null
set target = null
call pop()
call deallocate()
endmethod
private static method get takes unit caster returns thistype
local thistype this = thistype(0).next
loop
exitwhen this == 0 or .caster == caster
set this = next
endloop
return this
endmethod
private static method create takes unit caster, unit target returns thistype
local thistype this = get(caster)
if this == 0 then
set this = allocate()
set .caster = caster
set .target = target
call push()
endif
return this
endmethod
static method register takes integer abil returns nothing
set thistype(abil).registered = true
endmethod
/*
private static method onDamage_Debug takes nothing returns nothing
local trigger t = GetTriggeringTrigger()
local thistype this = thistype(GetHandleId(t)).index
call SetWidgetLife(caster, thistype(GetHandleId(t)).life)
set thistype(GetHandleId(t)).index = 0
set thistype(GetHandleId(t)).life = 0.
call DestroyTrigger(t)
set t = null
endmethod
*/
private static method onDamage takes nothing returns nothing
local trigger t
local thistype this = get(DamageEvent.source)
if IsUnitEnemy(DamageEvent.target, DamageEvent.p_source) and this != 0 then
call SetWidgetLife(caster, GetWidgetLife(caster) + DamageEvent.finalDmg)
endif
endmethod
private static method onDestroy_ex takes nothing returns nothing
endmethod
private static method onEffect takes nothing returns nothing
local unit caster
local thistype this
if GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_EFFECT then
set caster = GetTriggerUnit()
if thistype(GetSpellAbilityId()).registered then
call create(caster, GetSpellTargetUnit())
endif
elseif GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_ENDCAST then
set caster = GetTriggerUnit()
if thistype(GetSpellAbilityId()).registered then
call get(caster).destroy()
endif
call PauseTimer(timer)
call TimerStart(timer, 0., false, function thistype.onDestroy_ex)
endif
set caster = null
endmethod
implement LifeDrainMod
endstruct
endlibrary
Bracers Fix
JASS:
library BracersFix initializer Init requires Hashtable, AllocationAndLinks, DamageDetection, optional DrainLifeFix
function GetUnitItemCount takes unit which, integer itemtyper returns integer
local integer i = 0
local integer result = 0
loop
exitwhen i > 5
if GetItemTypeId(UnitItemInSlot(which, i)) == itemtyper then
set result = result + 1
endif
set i = i + 1
endloop
return result
endfunction
struct IA extends array
implement AllocLinkBundle
readonly integer typer
readonly boolean ability_type
readonly boolean stacks
readonly integer max
readonly RealGroup multi
private static method get takes integer typ returns thistype
local thistype this = thistype(0).next
loop
exitwhen this == 0 or typer == typ
set this = next
endloop
return this
endmethod
method setStacks takes boolean stacker, integer amount returns nothing
if not ability_type then
set stacks = stacker
if stacks then
set max = amount
endif
endif
endmethod
static method create takes integer typers, boolean isAbil returns thistype
local thistype this = get(typers)
if this == 0 then
set this = allocate()
set typer = typers
set ability_type = isAbil
set multi = RealGroup.create()
call push()
endif
return this
endmethod
public static method onCond takes nothing returns nothing
local thistype this = thistype(0).next
if DamageEvent.spell then
loop
exitwhen this == 0
if not ability_type then
if GetUnitItemCount(DamageEvent.target, typer) != 0 then
if not stacks then
set Dmg_IF.system_damage = DamageModEvent.appliedDmg*(1 - multi.real)
else
set Dmg_IF.system_damage = DamageModEvent.appliedDmg*Pow(1 - multi.real, Math.max(GetUnitItemCount(DamageEvent.target, typer), max))
endif
endif
else
if GetUnitAbilityLevel(DamageEvent.target, typer) != 0 then
set Dmg_IF.system_damage = DamageModEvent.appliedDmg*(1 - multi[GetUnitAbilityLevel(DamageEvent.target, typer)].real)
endif
endif
set this = next
endloop
endif
endmethod
endstruct
//! runtextmacro ModInitStart("SecInit")
local IA that = IA.create('brac', false)
set that.multi.real = 0.33
call that.setStacks(false, 0)
//! runtextmacro ModInitEnd("SecInit")
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterDamageModEvent(t, 4.00)
call TriggerAddCondition(t, function IA.onCond)
set t = null
endfunction
endlibrary
A straightforward damage detection system that detects physical and spell damage, and the after-damage event that utilizes a bucket technique for saving mass trigger creation. It uses either the UnitDex library for catching the indexing and deindexing event and registering the affected unit to the system.
(Speculation at this point)
Though redundant at this point, this damage detection trigger provides near-flawless after-damage event detection, using a specialized
Modifier Event
JASS:
scope DemoCode initializer Init
private function Cond takes nothing returns nothing
set DamageModEvent.appliedDmg = 25
// This sets the damage to 25
set DamageModEvent.appliedDmg = DamageEvent.dmg
// This sets the damage to the event damage...
set DamageModEvent.appliedDmg = -25
// This heals the unit by about 25 hp. Float inaccuracies may occur to units with a lot of health.
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterDamageModEvent(t, 1.00)
call TriggerAddCondition(t, Filter(function Cond))
set t = null
endfunction
endscope
Damage Instance Event
JASS:
scope DemoCode2 initializer Init
private function Cond takes nothing returns nothing
call UnitDamageTargetEx(DamageEvent.source, DamageEvent.target, 25, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterDamageEvent(t, 1.00)
call TriggerAddCondition(t, Filter(function Cond))
set t = null
endfunction
endscope
Last edited: