Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
AOEDamageEvent | real | No | |
ClearDamageEvent | trigger | No | |
DAMAGE_FACTOR_BRACERS | real | No | |
DAMAGE_FACTOR_ELUNES | real | No | |
DAMAGE_FACTOR_ETHEREAL | real | No | |
DamageBlockingAbility | abilcode | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventsWasted | integer | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageModifierEvent | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypeReduced | integer | No | |
DmgEvBracers | itemcode | No | |
DmgEvRecursionN | integer | No | |
DmgEvRunning | boolean | No | |
DmgEvStarted | boolean | No | |
DmgEvTimer | timer | No | |
DmgEvTrig | trigger | No | |
EnhancedDamageTarget | unit | No | |
HideDamageFrom | boolean | Yes | |
IsDamageSpell | boolean | No | |
IsUnitPreplaced | boolean | Yes | |
LastDamageHP | real | No | |
LastDmgPrevAmount | real | Yes | |
LastDmgPrevType | integer | Yes | |
LastDmgSource | unit | Yes | |
LastDmgTarget | unit | Yes | |
LastDmgValue | real | Yes | |
LastDmgWasSpell | boolean | Yes | |
NextDamageOverride | boolean | No | |
NextDamageType | integer | No | |
PDMS_AppliedEvent | real | No | |
PDMS_Apply | trigger | No | |
PDMS_AT | attacktype | Yes | |
PDMS_CanKill | boolean | Yes | |
PDMS_CanStackDamage | boolean | Yes | |
PDMS_Check | trigger | No | |
PDMS_Debug | boolean | No | |
PDMS_DefaultAttachPoint | string | Yes | |
PDMS_DefaultSfxModel | string | Yes | |
PDMS_DT | damagetype | Yes | |
PDMS_ExpiredEvent | real | No | |
PDMS_Interval | real | Yes | |
PDMS_IsDealingDamage | boolean | No | |
PDMS_IsUnitInEffect | boolean | No | |
PDMS_LastAppliedSource | unit | No | |
PDMS_LastAppliedTarget | unit | No | |
PDMS_LastAppliedType | integer | No | |
PDMS_LastExpiredSource | unit | No | |
PDMS_LastExpiredTarget | unit | No | |
PDMS_LastExpiredType | integer | No | |
PDMS_LastRefreshedSource | unit | No | |
PDMS_LastRefreshedTarget | unit | No | |
PDMS_LastRefreshedType | integer | No | |
PDMS_LastRegisteredType | integer | No | |
PDMS_LastStackedSource | unit | No | |
PDMS_LastStackedTarget | unit | No | |
PDMS_LastStackedType | integer | No | |
PDMS_NonWc3Style | boolean | Yes | |
PDMS_Param_Damage | real | No | |
PDMS_Param_Duration | real | No | |
PDMS_Param_Flag | boolean | No | |
PDMS_Param_Source | unit | No | |
PDMS_Param_Target | unit | No | |
PDMS_Param_Type | integer | No | |
PDMS_PdTypeIndex | integer | No | |
PDMS_RefreshedEvent | real | No | |
PDMS_Register | trigger | No | |
PDMS_Register_AttachPoint | string | No | |
PDMS_Register_AttackType | attacktype | No | |
PDMS_Register_CanKill | boolean | No | |
PDMS_Register_DamageType | damagetype | No | |
PDMS_Register_Interval | real | No | |
PDMS_Register_NonWc3Style | boolean | No | |
PDMS_Register_SfxModel | string | No | |
PDMS_Register_StackCap | integer | No | |
PDMS_Register_StackDamage | boolean | No | |
PDMS_Remove | trigger | No | |
PDMS_SetImmunity | trigger | No | |
PDMS_StackCap | integer | Yes | |
PDMS_StackedEvent | real | No | |
PDMS_Table | hashtable | No | |
PDMS_Timeout | real | No | |
PDMS_Type_Bleed | integer | No | |
PDMS_Type_Ignite | integer | No | |
PDMS_Type_Poison | integer | No | |
SpellDamageAbility | abilcode | No | |
TempInteger | integer | No | |
TempPoint | location | No | |
TestTimer | timer | No | |
TestTimer2 | timer | No | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UnitDamageRegistered | boolean | Yes | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitIndexLock | integer | Yes |
//===========================================================================
// Damage Engine lets you detect, amplify, block or nullify damage. It even
// lets you detect if the damage was physical or from a spell. Just reference
// DamageEventAmount/Source/Target or the boolean IsDamageSpell, to get the
// necessary damage event data.
//
// - Detect damage: use the event "DamageEvent Equal to 1.00"
// - To change damage before it's dealt: use the event "DamageModifierEvent Equal to 1.00"
// - Detect damage after it was applied, use the event "AfterDamageEvent Equal to 1.00"
// - Detect spell damage: use the condition "IsDamageSpell Equal to True"
// - Detect zero-damage: use the event "DamageEvent Equal to 2.00" (an AfterDamageEvent will not fire for this)
//
// You can specify the DamageEventType before dealing triggered damage. To prevent an already-improbable error, I recommend running the trigger "ClearDamageEvent (Checking Conditions)" after dealing triggered damage from within a damage event:
// - Set NextDamageType = DamageTypeWhatever
// - Unit - Cause...
// - Trigger - Run ClearDamageEvent (Checking Conditions)
//
// You can modify the DamageEventAmount and the DamageEventType from a "DamageModifierEvent Equal to 1.00" trigger.
// - If the amount is modified to negative, it will count as a heal.
// - If the amount is set to 0, no damage will be dealt.
//
// If you need to reference the original in-game damage, use the variable "DamageEventPrevAmt".
//
//===========================================================================
// Programming note about "integer i" and "udg_DmgEvRecursionN": integer i
// ranges from -1 upwards. "udg_DmgEvRecursionN" ranges from 0 upwards.
// "integer i" is always 1 less than "udg_DmgEvRecursionN"
//
function DmgEvResetVars takes nothing returns nothing
local integer i = udg_DmgEvRecursionN - 2
set udg_DmgEvRecursionN = i + 1
if i >= 0 then
set udg_DamageEventPrevAmt = udg_LastDmgPrevAmount[i]
set udg_DamageEventAmount = udg_LastDmgValue[i]
set udg_DamageEventSource = udg_LastDmgSource[i]
set udg_DamageEventTarget = udg_LastDmgTarget[i]
set udg_IsDamageSpell = udg_LastDmgWasSpell[i]
set udg_DamageEventType = udg_LastDmgPrevType[i]
endif
endfunction
function CheckDamagedLifeEvent takes boolean clear returns nothing
if clear then
set udg_NextDamageOverride = false
set udg_NextDamageType = 0
endif
if udg_DmgEvTrig != null then
call DestroyTrigger(udg_DmgEvTrig)
set udg_DmgEvTrig = null
if udg_IsDamageSpell then
call SetWidgetLife(udg_DamageEventTarget, RMaxBJ(udg_LastDamageHP, 0.41))
if udg_LastDamageHP <= 0.405 then
if udg_DamageEventType < 0 then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
//Kill the unit
call DisableTrigger(udg_DamageEventTrigger)
call UnitDamageTarget(udg_DamageEventSource, udg_DamageEventTarget, -999, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
call EnableTrigger(udg_DamageEventTrigger)
endif
elseif GetUnitAbilityLevel(udg_DamageEventTarget, udg_DamageBlockingAbility) > 0 then
call UnitRemoveAbility(udg_DamageEventTarget, udg_DamageBlockingAbility)
call SetWidgetLife(udg_DamageEventTarget, udg_LastDamageHP)
endif
if udg_DamageEventAmount != 0.00 and not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_AfterDamageEvent = 0.00
set udg_AfterDamageEvent = 1.00
set udg_AfterDamageEvent = 0.00
endif
call DmgEvResetVars()
endif
endfunction
function DmgEvOnAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
set udg_AOEDamageEvent = 0.00
set udg_AOEDamageEvent = 1.00
set udg_AOEDamageEvent = 0.00
set udg_DamageEventAOE = 1
endif
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
call GroupClear(udg_DamageEventAOEGroup)
endfunction
function DmgEvOnExpire takes nothing returns nothing
set udg_DmgEvStarted = false
call CheckDamagedLifeEvent(true)
//Reset things so they don't perpetuate for AoE/Level target detection
call DmgEvOnAOEEnd()
set udg_DamageEventTarget = null
set udg_DamageEventSource = null
endfunction
function PreCheckDamagedLifeEvent takes nothing returns boolean
call CheckDamagedLifeEvent(true)
return false
endfunction
function OnUnitDamage takes nothing returns boolean
local boolean override = udg_DamageEventOverride
local integer i
local integer e = udg_DamageEventLevel
local integer a = udg_DamageEventAOE
local string s
local real prevAmount
local real life
local real prevLife
local unit u
local unit f
call CheckDamagedLifeEvent(false) //in case the unit state event failed and the 0.00 second timer hasn't yet expired
set i = udg_DmgEvRecursionN - 1 //Had to be moved here due to false recursion tracking
if i < 0 then
//Added 25 July 2017 to detect AOE damage or multiple single-target damage
set u = udg_DamageEventTarget
set f = udg_DamageEventSource
elseif i < 16 then
set udg_LastDmgPrevAmount[i]= udg_DamageEventPrevAmt
set udg_LastDmgValue[i] = udg_DamageEventAmount
set udg_LastDmgSource[i] = udg_DamageEventSource
set udg_LastDmgTarget[i] = udg_DamageEventTarget
set udg_LastDmgWasSpell[i] = udg_IsDamageSpell
set udg_LastDmgPrevType[i] = udg_DamageEventType
else
set s = "WARNING: Recursion error when dealing damage! Make sure when you deal damage from within a DamageEvent trigger, do it like this:\n\n"
set s = s + "Trigger - Turn off (This Trigger)\n"
set s = s + "Unit - Cause...\n"
set s = s + "Trigger - Turn on (This Trigger)"
//Delete the next couple of lines to disable the in-game recursion crash warnings
call ClearTextMessages()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, 999.00, s)
return false
endif
set udg_DmgEvRecursionN = i + 2
set prevAmount = GetEventDamage()
set udg_DamageEventTarget = GetTriggerUnit()
set udg_DamageEventSource = GetEventDamageSource()
set udg_DamageEventAmount = prevAmount
set udg_DamageEventType = udg_NextDamageType
set udg_NextDamageType = 0
set udg_DamageEventOverride = udg_NextDamageOverride
set udg_NextDamageOverride = false
if i < 0 then
//Added 25 July 2017 to detect AOE damage or multiple single-target damage
if udg_DamageEventType == 0 then
if f == udg_DamageEventSource then
//Source has damaged more than once
if IsUnitInGroup(udg_DamageEventTarget, udg_DamageEventAOEGroup) then
//Added 5 August 2017 to improve tracking of enhanced damage against, say, Pulverize
set udg_DamageEventLevel = udg_DamageEventLevel + 1
set udg_EnhancedDamageTarget = udg_DamageEventTarget
else
//Multiple targets hit by this source - flag as AOE
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
else
//New damage source - unflag everything
set u = udg_DamageEventSource
set udg_DamageEventSource = f
call DmgEvOnAOEEnd()
set udg_DamageEventSource = u
endif
call GroupAddUnit(udg_DamageEventAOEGroup, udg_DamageEventTarget)
endif
if not udg_DmgEvStarted then
set udg_DmgEvStarted = true
call TimerStart(udg_DmgEvTimer, 0.00, false, function DmgEvOnExpire)
endif
endif
if prevAmount == 0.00 then
if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_DamageEventPrevAmt = 0.00
set udg_DamageEvent = 0.00
set udg_DamageEvent = 2.00
set udg_DamageEvent = 0.00
endif
call DmgEvResetVars()
else
set u = udg_DamageEventTarget
set udg_IsDamageSpell = prevAmount < 0.00
if udg_IsDamageSpell then
set prevAmount = -udg_DamageEventAmount
set life = 1.00
if IsUnitType(u, UNIT_TYPE_ETHEREAL) and not IsUnitType(u, UNIT_TYPE_HERO) then
set life = life*udg_DAMAGE_FACTOR_ETHEREAL //1.67
endif
if GetUnitAbilityLevel(u, 'Aegr') > 0 then
set life = life*udg_DAMAGE_FACTOR_ELUNES //0.80
endif
if udg_DmgEvBracers != 0 and IsUnitType(u, UNIT_TYPE_HERO) then
//Inline of UnitHasItemOfTypeBJ without the potential handle ID leak.
set i = 6
loop
set i = i - 1
if GetItemTypeId(UnitItemInSlot(u, i)) == udg_DmgEvBracers then
set life = life*udg_DAMAGE_FACTOR_BRACERS //0.67
exitwhen true
endif
exitwhen i == 0
endloop
endif
set udg_DamageEventAmount = prevAmount*life
endif
set udg_DamageEventPrevAmt = prevAmount
set udg_DamageModifierEvent = 0.00
if not udg_DamageEventOverride then
set udg_DamageModifierEvent = 1.00
if not udg_DamageEventOverride then
set udg_DamageModifierEvent = 2.00
set udg_DamageModifierEvent = 3.00
endif
endif
set udg_DamageEventOverride = override
if udg_DamageEventAmount > 0.00 then
set udg_DamageModifierEvent = 4.00
endif
set udg_DamageModifierEvent = 0.00
if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_DamageEvent = 0.00
set udg_DamageEvent = 1.00
set udg_DamageEvent = 0.00
endif
call CheckDamagedLifeEvent(true) //in case the unit state event failed from a recursive damage event
//All events have run and the damage amount is finalized.
set life = GetWidgetLife(u)
set udg_DmgEvTrig = CreateTrigger()
call TriggerAddCondition(udg_DmgEvTrig, Filter(function PreCheckDamagedLifeEvent))
if not udg_IsDamageSpell then
if udg_DamageEventAmount != prevAmount then
set life = life + prevAmount - udg_DamageEventAmount
if GetUnitState(u, UNIT_STATE_MAX_LIFE) < life then
set udg_LastDamageHP = life - prevAmount
call UnitAddAbility(u, udg_DamageBlockingAbility)
endif
call SetWidgetLife(u, RMaxBJ(life, 0.42))
endif
call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, LESS_THAN, RMaxBJ(0.41, life - prevAmount/2.00))
else
set udg_LastDamageHP = GetUnitState(u, UNIT_STATE_MAX_LIFE)
set prevLife = life
if life + prevAmount*0.75 > udg_LastDamageHP then
set life = RMaxBJ(udg_LastDamageHP - prevAmount/2.00, 1.00)
call SetWidgetLife(u, life)
set life = (life + udg_LastDamageHP)/2.00
else
set life = life + prevAmount*0.50
endif
set udg_LastDamageHP = prevLife - (prevAmount - (prevAmount - udg_DamageEventAmount))
call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, GREATER_THAN, life)
endif
endif
set u = null
set f = null
return false
endfunction
function CreateDmgEvTrg takes nothing returns nothing
set udg_DamageEventTrigger = CreateTrigger()
call TriggerAddCondition(udg_DamageEventTrigger, Filter(function OnUnitDamage))
endfunction
function SetupDmgEv takes nothing returns boolean
local integer i = udg_UDex
local unit u
if udg_UnitIndexEvent == 1.00 then
set u = udg_UDexUnits[i]
if GetUnitAbilityLevel(u, 'Aloc') == 0 and TriggerEvaluate(gg_trg_Damage_Engine_Config) then
set udg_UnitDamageRegistered[i] = true
call TriggerRegisterUnitEvent(udg_DamageEventTrigger, u, EVENT_UNIT_DAMAGED)
call UnitAddAbility(u, udg_SpellDamageAbility)
call UnitMakeAbilityPermanent(u, true, udg_SpellDamageAbility)
endif
set u = null
else
set udg_HideDamageFrom[i] = false
if udg_UnitDamageRegistered[i] then
set udg_UnitDamageRegistered[i] = false
set udg_DamageEventsWasted = udg_DamageEventsWasted + 1
if udg_DamageEventsWasted == 32 then //After 32 registered units have been removed...
set udg_DamageEventsWasted = 0
//Rebuild the mass EVENT_UNIT_DAMAGED trigger:
call DestroyTrigger(udg_DamageEventTrigger)
call CreateDmgEvTrg()
set i = udg_UDexNext[0]
loop
exitwhen i == 0
if udg_UnitDamageRegistered[i] then
call TriggerRegisterUnitEvent(udg_DamageEventTrigger, udg_UDexUnits[i], EVENT_UNIT_DAMAGED)
endif
set i = udg_UDexNext[i]
endloop
endif
endif
endif
return false
endfunction
//===========================================================================
function InitTrig_Damage_Engine takes nothing returns nothing
local unit u = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), 'uloc', 0, 0, 0)
local integer i = bj_MAX_PLAYERS //Fixed in 3.8
//Create this trigger with UnitIndexEvents in order add and remove units
//as they are created or removed.
local trigger t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 1.00)
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 2.00)
call TriggerAddCondition(t, Filter(function SetupDmgEv))
set t = null
//Run the configuration trigger to set all configurables:
if gg_trg_Damage_Engine_Config == null then
//It's possible this InitTrig_ function ran first, in which case use ExecuteFunc.
call ExecuteFunc("Trig_Damage_Engine_Config_Actions")
else
call TriggerExecute(gg_trg_Damage_Engine_Config)
endif
//Create trigger for storing all EVENT_UNIT_DAMAGED events.
call CreateDmgEvTrg()
//Create GUI-friendly trigger for cleaning up after UnitDamageTarget.
set udg_ClearDamageEvent = CreateTrigger()
call TriggerAddCondition(udg_ClearDamageEvent, Filter(function PreCheckDamagedLifeEvent))
//Disable SpellDamageAbility for every player.
loop
set i = i - 1
call SetPlayerAbilityAvailable(Player(i), udg_SpellDamageAbility, false)
exitwhen i == 0
endloop
//Preload abilities.
call UnitAddAbility(u, udg_DamageBlockingAbility)
call UnitAddAbility(u, udg_SpellDamageAbility)
call RemoveUnit(u)
set u = null
endfunction
//===========================================================================
//=
//= ===========================================
//= P.D.M.S - Periodic Damage Management System
//= Version 1.0
//= By Rheiko
//= ===========================================
//=
//= Description:
//= A lightweight and flexible system that allows map creators to
//= define, apply, remove, stack, and refresh periodic damage on
//= units.
//=
//===========================================================================
//= ====
//= API:
//= ====
//=
//= function PDMS_RegisterType takes attacktype AT, damagetype DT, boolean damageStack, boolean nonWc3Style, integer stackCap, boolean canKill, real interval, string sfxModel, string attachPoint returns integer
//= - Register a new type of PDMS Effect
//=
//= function PDMS_ApplyNonStack takes unit source, real damage, unit target, real duration, integer pdType returns boolean
//= - Apply a non-stacking PDMS Effect on a unit
//=
//= function PDMS_ApplyWc3Stack takes unit source, real damage, unit target, real duration, integer pdType returns boolean
//= - Apply a stacking PDMS Effect on a unit with Wc3 Stacking Behavior (Stack can only be increased once by different source)
//=
//= function PDMS_ApplyCustomStack takes unit source, real damage, unit target, real duration, integer pdType returns boolean
//= - Apply a stacking PDMS Effect on a unit with Custom Stacking Behavior (Stack can be increased by single source)
//=
//= function PDMS_RemoveByType takes unit target, integer pdType returns nothing
//= - Remove a certain type of PDMS Effect from a unit
//=
//= function PDMS_RemoveAll takes unit target returns nothing
//= - Remove all kind of PDMS Effect from a unit
//=
//= function PDMS_IsUnitInEffect takes unit target, integer pdType returns boolean
//= - Check whether a unit is under the effect of certain type of PDMS Effect
//=
//= function PDMS_SetImmunity takes unit target, integer pdType, boolean flag returns nothing
//= - Apply/Remove immunity towards specific periodic damage type from a unit
//=
//= function PDMS_IsImmune takes unit target, integer pdType returns boolean
//= - Check whether a unit is immune to a specific periodic damage type
//=
//===========================================================================
//= ===========
//= Event List:
//= ===========
//=
//= Game - PDMS_AppliedEvent becomes equal to 1.00
//= -> This event fires when PDMS Effect is applied for the first time on a unit.
//=
//= Game - PDMS_StackedEvent becomes equal to 1.00
//= -> This event fires when a stackable PDMS Effect is re-applied on the same unit.
//=
//= Game - PDMS_RefreshedEvent becomes equal to 1.00
//= -> This event fires when a non-stackable PDMS Effect is re-applied on the same unit.
//=
//= Game - PDMS_ExpiredEvent becomes equal to 1.00
//= -> This event fires when PDMS Effect wears off
//=
//===========================================================================
//= ==================
//= List of Variables:
//= ==================
//=
//= - The following variables are used to register a new type of PDMS Effect.
//=
//= = Variable Name = = Data Type = = Description =
//= udg_PDMS_Register_AttackType Attack Type Assign the attack type of PDMS type
//= udg_PDMS_Register_DamageType Damage Type Assign the damage type of PDMS type
//= udg_PDMS_Register_SfxModel String Assign the model path used as special effect
//= udg_PDMS_Register_AttachPoint String Assign the attachment point for special effect
//= udg_PDMS_Register_StackDamage Boolean Enable stacking/non-stacking behavior
//= udg_PDMS_Register_NonWc3Style Boolean Enable single-source stacking behavior
//= udg_PDMS_Register_StackCap Boolean Assign the maximum cap of stacks
//= udg_PDMS_Register_CanKill Boolean Enable kill
//= udg_PDMS_Register_Interval Boolean Assign the damage interval for PDMS type
//=
//= - The following variables are used to as a parameter to call available APIs.
//=
//= = Variable Name = = Data Type = = Description =
//= udg_PDMS_Param_Source Unit Assign the source of PDMS Effect
//= udg_PDMS_Param_Target Unit Assign the target of PDMS Effect
//= udg_PDMS_Param_Damage Real Assign the damage value of PDMS Effect
//= udg_PDMS_Param_Duration Real Assign the duration of PDMS Effect
//= udg_PDMS_Param_Type Integer Assign the Periodic Damage Type Index
//= udg_PDMS_Param_Flag Boolean Assign the immunity flag towards certain Periodic Damage Type
//=
//= - The following variables are used to trigger a function that calls available APIs.
//=
//= = Variable Name = = Data Type = = Description =
//= udg_PDMS_Apply Trigger Allow the user to trigger Apply Function
//= udg_PDMS_Remove Trigger Allow the user to trigger RemoveByType / RemoveAll Function
//= udg_PDMS_Check Trigger Allow the user to trigger Check Function
//= udg_PDMS_Register Trigger Trigger the type registration function
//= udg_PDMS_SetImmunity Trigger Allow the user to toggle the immunity flag for certain Periodic Damage Type
//=
//= - The following variables are event getters, should be used as a read-only.
//=
//= = Variable Name = = Data Type = = Description =
//= udg_PDMS_LastRegisteredType Integer Refer to the Periodic Damage Type Index when registered a new type
//= udg_PDMS_IsUnitInEffect Boolean Refer to the boolean value when udg_PDMS_Check is triggered
//= udg_PDMS_IsDealingDamage Boolean Refer to the state of PDMS when dealing damage
//= udg_PDMS_LastExpiredSource Unit Refer to the source unit of last expired event
//= udg_PDMS_LastExpiredTarget Unit Refer to the target unit of last expired event
//= udg_PDMS_LastExpiredType Integer Refer to the type index of last expired event
//= udg_PDMS_LastAppliedSource Unit Refer to the source unit of last applied event
//= udg_PDMS_LastAppliedTarget Unit Refer to the target unit of last applied event
//= udg_PDMS_LastAppliedType Integer Refer to the type index of last applied event
//= udg_PDMS_LastStackedSource Unit Refer to the source unit of last stacked event
//= udg_PDMS_LastStackedTarget Unit Refer to the target unit of last stacked event
//= udg_PDMS_LastStackedType Integer Refer to the type index of last stacked event
//= udg_PDMS_LastRefreshedSource Unit Refer to the source unit of last refreshed event
//= udg_PDMS_LastRefreshedTarget Unit Refer to the target unit of last refreshed event
//= udg_PDMS_LastRefreshedType Integer Refer to the type index of last refreshed event
//=
//= - The following variables are used as the internals for the core system
//=
//= = Variable Name = = Data Type = = Description =
//= udg_PDMS_Hashtable Hashtable Main System Data Storage
//= udg_PDMS_Timeout Real Internal Clock Interval
//= udg_PDMS_PdTypeIndex Integer Periodic Damage Type Index
//= udg_PDMS_AT Attack Type Arr Store the attack type of each Periodic Damage Type
//= udg_PDMS_DT Damage Type Arr Store the damage type of each Periodic Damage Type
//= udg_PDMS_DefaultSfxModel String Arr Store the model file path for special effect of each Periodic Damage Type
//= udg_PDMS_DefaultAttachPoint String Arr Store the attachment point for special effect of each Periodic Damage Type
//= udg_PDMS_CanStackDamage Boolean Arr Enable stacking/non-stacking behavior of each Periodic Damage Type
//= udg_PDMS_NonWc3Style Boolean Arr Enable single-source stacking behavior
//= udg_PDMS_StackCap Boolean Arr Assign the maximum cap of stacks
//= udg_PDMS_CanKill Boolean Arr Enable kill for each Periodic Damage Type
//= udg_PDMS_Interval Real arr Store the interval value of each Periodic Damage Type
//=
//===========================================================================
//= ===================
//= Hashtable Mappings:
//= ===================
//=
//= (targetId, pdType) = isActive flag
//= (targetId, pdType + 1000) = Source handle of current instance
//= (targetId, pdType + 2000) = Duration value
//= (targetId, pdType + 3000) = Interval value
//= (targetId, pdType + 4000) = Damage value
//= (targetId, pdType + 5000) = Sfx handle
//=
//= (targetId, pdType + 6000) = Damage Counter
//= (targetId, (10000 * pdType) + 7000 + damageCounter) = Damage value
//= (targetId, (10000 * pdType) + 8000 + damageCounter) = Time Remaining
//= (targetId, (10000 * pdType) + 9000 + damageCounter) = Source ID of each instance
//=
//= (targetId, pdType + 7000) = Immunity flag
//=
//= (sourceId, targetId) = isNotFirst flag
//=
//= (timerId, 0) = Target handle
//= (timerId, 1) = Periodic Damage Type
//=
//===========================================================================
function PDMS_Configuration takes nothing returns nothing
//===========================================================================
//= Configuration
//===========================================================================
//-----------------------------------------------------------------------
//-- This will show debug messages if you set it to true
//-----------------------------------------------------------------------
set udg_PDMS_Debug = false
//-----------------------------------------------------------------------
//-- This is the Internal Clock Interval
//-----------------------------------------------------------------------
set udg_PDMS_Timeout = 0.05
//===========================================================================
//= Enf of Config
//===========================================================================
endfunction
//===========================================================================
//= This function registers a new type of PDMS Effect
//===========================================================================
function PDMS_RegisterType takes attacktype AT, damagetype DT, boolean damageStack, boolean nonWc3Style, integer stackCap, boolean canKill, real interval, string sfxModel, string attachPoint returns integer
set udg_PDMS_PdTypeIndex = udg_PDMS_PdTypeIndex + 1
set udg_PDMS_AT[udg_PDMS_PdTypeIndex] = AT
set udg_PDMS_DT[udg_PDMS_PdTypeIndex] = DT
set udg_PDMS_DefaultSfxModel[udg_PDMS_PdTypeIndex] = sfxModel
set udg_PDMS_DefaultAttachPoint[udg_PDMS_PdTypeIndex] = attachPoint
set udg_PDMS_CanKill[udg_PDMS_PdTypeIndex] = canKill
set udg_PDMS_CanStackDamage[udg_PDMS_PdTypeIndex] = damageStack
set udg_PDMS_NonWc3Style[udg_PDMS_PdTypeIndex] = nonWc3Style
set udg_PDMS_StackCap[udg_PDMS_PdTypeIndex] = stackCap
set udg_PDMS_Interval[udg_PDMS_PdTypeIndex] = interval
//-- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "New Type is Registered at Index " + I2S(udg_PDMS_PdTypeIndex))
endif
return udg_PDMS_PdTypeIndex
endfunction
//===========================================================================
//= This function checks whether a unit is affected by specific type of PDMS effect
//===========================================================================
function PDMS_IsUnitInEffect takes unit target, integer pdType returns boolean
local integer targetId = GetHandleId(target)
//-- Load the value to check for active instance
local integer isActive = LoadInteger(udg_PDMS_Table, targetId, pdType)
if isActive == 0 then
return false
endif
return true
endfunction
//===========================================================================
//= This function removes specific type of PDMS effect
//===========================================================================
function PDMS_RemoveByType takes unit target, integer pdType returns nothing
//-- Local vars
local integer i = 0
//-- Get TargetId
local integer targetId = GetHandleId(target)
//-- Load Sfx and source
local effect sfx = LoadEffectHandle(udg_PDMS_Table, targetId, pdType + 5000)
local unit source = LoadUnitHandle(udg_PDMS_Table, targetId, pdType + 1000)
local integer sourceId = GetHandleId(source)
local integer damageCounter
local integer prevSourceId
//-- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Removing Periodic Damage by Specific Type")
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Destroying effect for the type index " + I2S(pdType))
endif
//-- Destroy Effect
call DestroyEffect(sfx)
//-- Clean up hashtable
if udg_PDMS_CanStackDamage[pdType] == true then
set damageCounter = LoadInteger(udg_PDMS_Table, targetId, pdType + 6000)
loop
set i = i + 1
exitwhen i > damageCounter
set prevSourceId = LoadInteger(udg_PDMS_Table, targetId, (10000 * pdType) + 9000 + i)
call RemoveSavedInteger(udg_PDMS_Table, prevSourceId, targetId)
endloop
else
call RemoveSavedInteger(udg_PDMS_Table, sourceId, targetId)
endif
call RemoveSavedInteger( udg_PDMS_Table, targetId, pdType)
call RemoveSavedHandle( udg_PDMS_Table, targetId, pdType + 1000)
call RemoveSavedReal( udg_PDMS_Table, targetId, pdType + 2000)
call RemoveSavedReal( udg_PDMS_Table, targetId, pdType + 3000)
call RemoveSavedReal( udg_PDMS_Table, targetId, pdType + 4000)
call RemoveSavedHandle( udg_PDMS_Table, targetId, pdType + 5000)
call RemoveSavedInteger( udg_PDMS_Table, targetId, pdType + 6000)
set udg_PDMS_LastExpiredType = pdType
set udg_PDMS_LastExpiredSource = source
set udg_PDMS_LastExpiredTarget = target
set udg_PDMS_ExpiredEvent = 1.00
set udg_PDMS_ExpiredEvent = 0.00
set source = null
set sfx = null
endfunction
//===========================================================================
//= This function removes all type of PDMS effect
//===========================================================================
function PDMS_RemoveAll takes unit target returns nothing
//-- Local vars
local integer i = 0
//-- Get TargetId
local integer targetId = GetHandleId(target)
loop
set i = i + 1
exitwhen i > udg_PDMS_PdTypeIndex
call PDMS_RemoveByType(target, i)
endloop
//-- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Removed All Periodic Damage from a unit")
endif
endfunction
//===========================================================================
//= This function toggles the immunity flag of certain pdType for a unit
//===========================================================================
function PDMS_SetImmunity takes unit target, integer pdType, boolean flag returns nothing
//-- Get TargetId
local integer targetId = GetHandleId(target)
call SaveBoolean(udg_PDMS_Table, targetId, pdType + 7000, flag)
if flag == true then
call PDMS_RemoveByType(target, pdType)
endif
endfunction
//===========================================================================
//= This function checks for the immunity flag of certain pdType for a unit
//===========================================================================
function PDMS_IsImmune takes unit target, integer pdType returns boolean
//-- Get TargetId
local integer targetId = GetHandleId(target)
return LoadBoolean(udg_PDMS_Table, targetId, pdType + 7000)
endfunction
//===========================================================================
//= This function handles the loop logic of non stacking version
//===========================================================================
function PDMS_LoopNonStack takes nothing returns nothing
//-- Get the expired timer and retrieve the ID
local timer t = GetExpiredTimer()
local integer timerId = GetHandleId(t)
//-- Load the previously attached data
local unit target = LoadUnitHandle(udg_PDMS_Table, timerId, 0)
local integer targetId = GetHandleId(target)
local integer pdType = LoadInteger(udg_PDMS_Table, timerId, 1)
//-- Load source unit
local unit source
//-- Load duration, and active flag
local integer isActive = LoadInteger(udg_PDMS_Table, targetId, pdType)
local real duration = LoadReal(udg_PDMS_Table, targetId, pdType + 2000)
//-- Prepare container for interval and damage
local real interval
local real damage
//-- Guard clause when the effect wears off
if duration <= 0 then
//-- Duration is over but still active; must remove
if isActive == 1 then
call PDMS_RemoveByType(target, pdType)
endif
//-- Clean up hashtable and destroy timer
call FlushChildHashtable(udg_PDMS_Table, timerId)
call DestroyTimer(t)
//- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Timer is successfully destroyed")
endif
//-- Null local handles
set t = null
set source = null
set target = null
return
endif
//-- Load the interval value to be updated
set interval = LoadReal(udg_PDMS_Table, targetId, pdType + 3000)
//-- Decrease the duration value and update the storage
set duration = duration - udg_PDMS_Timeout
call SaveReal(udg_PDMS_Table, targetId, pdType + 2000, duration)
//-- Decrease the interval value and update the storage
set interval = interval - udg_PDMS_Timeout
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, interval)
//--
if interval <= 0 then
//-- Load source
set source = LoadUnitHandle(udg_PDMS_Table, targetId, pdType + 1000)
//-- Load damage value
set damage = LoadReal(udg_PDMS_Table, targetId, pdType + 4000)
//-- Validate the damage value
if damage >= 0 then
//-- Check if it allows kill
if udg_PDMS_CanKill[pdType] == false and (GetWidgetLife(target) - damage) <= 0 then
call SetWidgetLife(target, GetWidgetLife(target) + damage)
endif
set udg_PDMS_IsDealingDamage = true
call UnitDamageTarget(source, target, damage, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
set udg_PDMS_IsDealingDamage = false
else
call SetWidgetLife(target, GetWidgetLife(target) + damage)
endif
//- Debug
// if udg_PDMS_Debug == true then
// call BJDebugMsg("[|cffffcc00System Debug|r] - " + GetUnitName(source) + " deals " + R2S(damage) + " damage to " + GetUnitName(target))
// endif
//-- Reset the interval value back to default
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, udg_PDMS_Interval[pdType])
endif
//-- Null local handles
set t = null
set source = null
set target = null
endfunction
//===========================================================================
//= This function applies periodic damage of non stacking version
//===========================================================================
function PDMS_ApplyNonStack takes unit source, real damage, unit target, real duration, integer pdType returns boolean
//-- Local variables for later
local timer t
local integer timerId
local integer targetId
//-- Variable to check for active instance
local integer isActive
//-- Variables to load the value of current instance if exist
local unit currentSource
local real currentDuration
local real currentDamage
//-- Variable to load effect handle
local effect sfx
//-- Type check!
if pdType < 1 or pdType > udg_PDMS_PdTypeIndex then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Periodic Damage Type does not exist")
return false
endif
//-- Dead check
if IsUnitType(target, UNIT_TYPE_DEAD) or GetWidgetLife(target) <= 0.405 then
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Trying to apply PDMS on dead unit")
endif
return false
endif
//-- Immunity check
if PDMS_IsImmune(target, pdType) == true then
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Trying to apply PDMS on a unit that's immune")
endif
return false
endif
//-- Get the IDs of each actor
set targetId = GetHandleId(target)
//-- Load the value to check for active instance
set isActive = LoadInteger(udg_PDMS_Table, targetId, pdType)
//-- Load the value of current instance if exist
set currentDuration = LoadReal(udg_PDMS_Table, targetId, pdType + 2000)
set currentDamage = LoadReal(udg_PDMS_Table, targetId, pdType + 4000)
//-- Load the handle to check for active effect
set sfx = LoadEffectHandle(udg_PDMS_Table, targetId, pdType + 5000)
//-- Create new sfx when there is still none
if sfx == null then
set sfx = AddSpecialEffectTarget(udg_PDMS_DefaultSfxModel[pdType], target, udg_PDMS_DefaultAttachPoint[pdType])
call SaveEffectHandle(udg_PDMS_Table, targetId, pdType + 5000, sfx)
endif
//-- Refresh duration and replace source if the new one is stronger
if duration >= currentDuration and damage >= currentDamage then
//-- Refresh duration
set currentDuration = duration
call SaveReal(udg_PDMS_Table, targetId, pdType + 2000, currentDuration)
//-- Replace source
set currentSource = source
call SaveUnitHandle(udg_PDMS_Table, targetId, pdType + 1000, currentSource)
//-- Replace damage if the new one is greater
set currentDamage = damage
call SaveReal(udg_PDMS_Table, targetId, pdType + 4000, currentDamage)
//-- Save Interval
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, udg_PDMS_Interval[pdType])
//-- RefreshedEvent
set udg_PDMS_LastRefreshedType = pdType
set udg_PDMS_LastRefreshedSource = source
set udg_PDMS_LastRefreshedTarget = target
set udg_PDMS_RefreshedEvent = 1.00
set udg_PDMS_RefreshedEvent = 0.00
endif
//-- Start a timer if there is no active instances yet
if isActive == 0 then
//-- Create and start the timer
set t = CreateTimer()
call TimerStart(t, udg_PDMS_Timeout, true, function PDMS_LoopNonStack)
//-- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Timer is successfully started")
endif
//-- Get its ID to attach data
set timerId = GetHandleId(t)
//-- Attach these data:
//-- - target handle
//-- - pd type
call SaveUnitHandle(udg_PDMS_Table, timerId, 0, target)
call SaveInteger(udg_PDMS_Table, timerId, 1, pdType)
//-- switch active flag
call SaveInteger(udg_PDMS_Table, targetId, pdType, 1)
//-- AppliedEvent
set udg_PDMS_LastAppliedType = pdType
set udg_PDMS_LastAppliedSource = source
set udg_PDMS_LastAppliedTarget = target
set udg_PDMS_AppliedEvent = 1.00
set udg_PDMS_AppliedEvent = 0.00
endif
//-- Null local handles
set sfx = null
set currentSource = null
return true
endfunction
//===========================================================================
//= This function handles the loop logic for stacking periodic damage
//===========================================================================
function PDMS_LoopWc3Stack takes nothing returns nothing
//-- Get the expired timer and retrieve the ID
local timer t = GetExpiredTimer()
local integer timerId = GetHandleId(t)
local integer i = 0
local integer prevSourceId
local real damageStackDuration
local real currentDamage
local real damage
//-- Load the previously attached data
local unit target = LoadUnitHandle(udg_PDMS_Table, timerId, 0)
local integer targetId = GetHandleId(target)
local integer pdType = LoadInteger(udg_PDMS_Table, timerId, 1)
//-- Prepare source container
local unit source
//-- Load duration, and active flag
local integer isActive = LoadInteger(udg_PDMS_Table, targetId, pdType)
local real duration = LoadReal(udg_PDMS_Table, targetId, pdType + 2000)
//-- Prepare interval and damageCounter container
local real interval
local integer damageCounter
//-- Guard clause when the effect wears off
if duration <= 0 then
//-- Duration is over but still active; must remove
if isActive == 1 then
call PDMS_RemoveByType(target, pdType)
endif
//-- Clean up hashtable and destroy timer
call FlushChildHashtable(udg_PDMS_Table, timerId)
call DestroyTimer(t)
//- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Timer is successfully destroyed")
endif
//-- Null local handles
set t = null
set target = null
return
endif
//-- Load source data
set source = LoadUnitHandle(udg_PDMS_Table, targetId, pdType + 1000)
//-- Load interval and damageCounter
set interval = LoadReal(udg_PDMS_Table, targetId, pdType + 3000)
set damageCounter = LoadInteger(udg_PDMS_Table, targetId, pdType + 6000)
//-- Decrease the duration value and update the storage
set duration = duration - udg_PDMS_Timeout
call SaveReal(udg_PDMS_Table, targetId, pdType + 2000, duration)
//-- Decrease the interval value and update the storage
set interval = interval - udg_PDMS_Timeout
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, interval)
//-- Decrease the previous duration value and update the storage
set currentDamage = 0
loop
set i = i + 1
exitwhen i > damageCounter
//-- Load the damage of each instance and add them to currentDamage
set damage = LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + i)
set currentDamage = currentDamage + damage
//-- Load the time remaining value of each damage instance and decrement them if they are greater than 0
set damageStackDuration = LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + i)
if damageStackDuration > 0 then
set damageStackDuration = damageStackDuration - udg_PDMS_Timeout
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + i, damageStackDuration)
endif
//-- Check if the time remaining is over and the damage has not been dissipated
if damageStackDuration <= 0 then
// //-- dissipate the damage by resetting the value to 0
// call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + i, 0)
//-- dissipate the damage by resetting the value to 0
set prevSourceId = LoadInteger(udg_PDMS_Table, targetId, (10000 * pdType) + 9000 + i)
call RemoveSavedInteger(udg_PDMS_Table, prevSourceId, targetId)
set prevSourceId = LoadInteger(udg_PDMS_Table, targetId, (10000 * pdType) + 9000 + damageCounter)
call SaveInteger(udg_PDMS_Table, targetId, (10000 * pdType) + 9000 + i, prevSourceId)
set damage = LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + damageCounter)
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + i, damage)
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + damageCounter, 0)
set damageStackDuration = LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + damageCounter)
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + i, damageStackDuration)
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + damageCounter, 0)
set i = i - 1
set damageCounter = damageCounter - 1
call SaveInteger(udg_PDMS_Table, targetId, pdType + 6000, damageCounter)
endif
endloop
//--
if interval <= 0 then
//- Validate the damage value
if currentDamage >= 0 then
//-- Check if it allows kill
if udg_PDMS_CanKill[pdType] == false and (GetWidgetLife(target) - currentDamage) <= 0 then
call SetWidgetLife(target, GetWidgetLife(target) + currentDamage)
endif
set udg_PDMS_IsDealingDamage = true
call UnitDamageTarget(source, target, currentDamage, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
set udg_PDMS_IsDealingDamage = false
else
call SetWidgetLife(target, GetWidgetLife(target) + currentDamage)
endif
// //- Debug
// if udg_PDMS_Debug == true then
// call BJDebugMsg("[|cffffcc00System Debug|r] - " + GetUnitName(source) + " deals " + R2S(currentDamage) + " damage to " + GetUnitName(target))
// endif
// //- Debug
// if udg_PDMS_Debug == true then
// set i = 0
// loop
// set i = i + 1
// exitwhen i > damageCounter
// call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Instance[" + I2S(i) + "]'s damage time remaining: " + R2S(LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + i)))
// endloop
// endif
//-- Reset the interval value back to default
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, udg_PDMS_Interval[pdType])
endif
//-- Null local handles
set t = null
set source = null
set target = null
endfunction
//===========================================================================
//= This function applies stacking periodic damage wc3 style
//===========================================================================
function PDMS_ApplyWc3Stack takes unit source, real damage, unit target, real duration, integer pdType returns boolean
//-- Local variables
local timer t
local integer timerId
local real damageStackDuration //-- Variable to store the time remaining of a damage from a new instance
local effect sfx //-- Variable to load special effect
local integer isNotFirst //-- Variable to check for first encounter
//-- Variables to get the IDs of each actor
local integer sourceId
local integer targetId
//-- Variable to check for active instance
local integer isActive
//-- Variables to load the value of current instance if exist
local real currentDuration
local integer damageCounter
//-- Type Check!
if pdType < 1 or pdType > udg_PDMS_PdTypeIndex then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Periodic Damage Type does not exist")
return false
endif
//-- Dead check
if IsUnitType(target, UNIT_TYPE_DEAD) or GetWidgetLife(target) <= 0.405 then
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Trying to apply PDMS on dead unit")
endif
return false
endif
//-- Immunity check
if PDMS_IsImmune(target, pdType) == true then
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Trying to apply PDMS on a unit that's immune")
endif
return false
endif
//-- Get the IDs
set sourceId = GetHandleId(source)
set targetId = GetHandleId(target)
//-- Load the value to check for active instances
set isActive = LoadInteger(udg_PDMS_Table, targetId, pdType)
//-- Load the value of current instance if exist
set currentDuration = LoadReal(udg_PDMS_Table, targetId, pdType + 2000)
set damageCounter = LoadInteger(udg_PDMS_Table, targetId, pdType + 6000)
//-- Load the value to check if it is the first encounter
set isNotFirst = LoadInteger(udg_PDMS_Table, sourceId, targetId)
//-- Load the effect handle
set sfx = LoadEffectHandle(udg_PDMS_Table, targetId, pdType + 5000)
//-- Create new sfx when there is still none
if sfx == null then
set sfx = AddSpecialEffectTarget(udg_PDMS_DefaultSfxModel[pdType], target, udg_PDMS_DefaultAttachPoint[pdType])
call SaveEffectHandle(udg_PDMS_Table, targetId, pdType + 5000, sfx)
endif
//-- Check if it is the first encounter
if isNotFirst == 0 then
//-- Switch the flag if it is the first encounter
set isNotFirst = 1
call SaveInteger(udg_PDMS_Table, sourceId, targetId, isNotFirst)
//-- Increment damageCounter then update the storage
set damageCounter = damageCounter + 1
call SaveInteger(udg_PDMS_Table, targetId, pdType + 6000, damageCounter)
//-- Save the source id of this instance
call SaveInteger(udg_PDMS_Table, targetId, (10000 * pdType) + 9000 + damageCounter, sourceId)
//-- Save the new damage
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + damageCounter, damage)
//-- StackedEvent
set udg_PDMS_LastStackedType = pdType
set udg_PDMS_LastStackedSource = source
set udg_PDMS_LastStackedTarget = target
set udg_PDMS_StackedEvent = 1.00
set udg_PDMS_StackedEvent = 0.00
endif
//-- Check duration and overwrite if it is stronger than the current one
if duration > currentDuration then
//-- Save the new duration of the damage from this instance
set damageStackDuration = duration
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + damageCounter, damageStackDuration)
//-- Overwrite the old duration with the new one
set currentDuration = duration
call SaveReal(udg_PDMS_Table, targetId, pdType + 2000, currentDuration)
endif
//-- Always replace source with the latest one
call SaveUnitHandle(udg_PDMS_Table, targetId, pdType + 1000, source)
//-- Start a timer if there is no active instances yet
if isActive == 0 then
//-- Save Interval
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, udg_PDMS_Interval[pdType])
//-- Create and start the timer
set t = CreateTimer()
call TimerStart(t, udg_PDMS_Timeout, true, function PDMS_LoopWc3Stack)
//-- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Timer is successfully started")
endif
//-- Get its ID to attach data
set timerId = GetHandleId(t)
//-- Attach these data:
//-- - target handle
//-- - pd type
call SaveUnitHandle(udg_PDMS_Table, timerId, 0, target)
call SaveInteger(udg_PDMS_Table, timerId, 1, pdType)
//-- switch active flag
call SaveInteger(udg_PDMS_Table, targetId, pdType, 1)
//-- AppliedEvent
set udg_PDMS_LastAppliedType = pdType
set udg_PDMS_LastAppliedSource = source
set udg_PDMS_LastAppliedTarget = target
set udg_PDMS_AppliedEvent = 1.00
set udg_PDMS_AppliedEvent = 0.00
//-- Null local handle
set t = null
endif
//-- Null local handles
set sfx = null
return true
endfunction
//===========================================================================
//= This function handles the loop logic for custom stacking periodic damage
//===========================================================================
function PDMS_LoopCustomStack takes nothing returns nothing
//-- Get the expired timer and retrieve the ID
local timer t = GetExpiredTimer()
local integer timerId = GetHandleId(t)
local integer i = 0
local real damageStackDuration
local real currentDamage
local real damage
//-- Load the previously attached data
local unit target = LoadUnitHandle(udg_PDMS_Table, timerId, 0)
local integer targetId = GetHandleId(target)
local integer pdType = LoadInteger(udg_PDMS_Table, timerId, 1)
//-- Prepare source container
local unit source
local integer sourceId
//-- Load duration, and active flag
local integer isActive = LoadInteger(udg_PDMS_Table, targetId, pdType)
local real duration = LoadReal(udg_PDMS_Table, targetId, pdType + 2000)
//-- Prepare interval and damageCounter container
local real interval
local integer damageCounter
//-- Guard clause when the effect wears off
if duration <= 0 then
//-- Duration is over but still active; must remove
if isActive == 1 then
call PDMS_RemoveByType(target, pdType)
endif
//-- Clean up hashtable and destroy timer
call FlushChildHashtable(udg_PDMS_Table, timerId)
call DestroyTimer(t)
//- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Timer is successfully destroyed")
endif
//-- Null local handles
set t = null
set target = null
return
endif
//-- Load source data
set source = LoadUnitHandle(udg_PDMS_Table, targetId, pdType + 1000)
//-- Load interval and damageCounter
set interval = LoadReal(udg_PDMS_Table, targetId, pdType + 3000)
set damageCounter = LoadInteger(udg_PDMS_Table, targetId, pdType + 6000)
//-- Decrease the duration value and update the storage
set duration = duration - udg_PDMS_Timeout
call SaveReal(udg_PDMS_Table, targetId, pdType + 2000, duration)
//-- Decrease the interval value and update the storage
set interval = interval - udg_PDMS_Timeout
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, interval)
//-- Decrease the previous duration value and update the storage
set currentDamage = 0
loop
set i = i + 1
exitwhen i > damageCounter
//-- Load the damage of each instance and add them to currentDamage
set damage = LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + i)
set currentDamage = currentDamage + damage
//-- Load the time remaining value of each damage instance and decrement them if they are greater than 0
set damageStackDuration = LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + i)
if damageStackDuration > 0 then
set damageStackDuration = damageStackDuration - udg_PDMS_Timeout
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + i, damageStackDuration)
endif
//-- Check if the time remaining is over
if damageStackDuration <= 0 then
//-- dissipate the damage by resetting the value to 0
set damage = LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + damageCounter)
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + i, damage)
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + damageCounter, 0)
set damageStackDuration = LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + damageCounter)
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + i, damageStackDuration)
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + damageCounter, 0)
set i = i - 1
set damageCounter = damageCounter - 1
call SaveInteger(udg_PDMS_Table, targetId, pdType + 6000, damageCounter)
endif
endloop
//--
if interval <= 0 then
//- Validate the damage value
if currentDamage >= 0 then
//-- Check if it allows kill
if udg_PDMS_CanKill[pdType] == false and (GetWidgetLife(target) - currentDamage) <= 0 then
call SetWidgetLife(target, GetWidgetLife(target) + currentDamage)
endif
set udg_PDMS_IsDealingDamage = true
call UnitDamageTarget(source, target, currentDamage, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
set udg_PDMS_IsDealingDamage = false
else
call SetWidgetLife(target, GetWidgetLife(target) + currentDamage)
endif
// //- Debug
// if udg_PDMS_Debug == true then
// call BJDebugMsg("[|cffffcc00System Debug|r] - " + GetUnitName(source) + " deals " + R2S(currentDamage) + " damage to " + GetUnitName(target))
// endif
// //- Debug
// if udg_PDMS_Debug == true then
// set i = 0
// loop
// set i = i + 1
// exitwhen i > damageCounter
// call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Instance[" + I2S(i) + "]'s damage time remaining: " + R2S(LoadReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + i)))
// endloop
// endif
//-- Reset the interval value back to default
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, udg_PDMS_Interval[pdType])
endif
//-- Null local handles
set t = null
set source = null
set target = null
endfunction
//===========================================================================
//= This function applies periodic damage of custom stacking version
//===========================================================================
function PDMS_ApplyCustomStack takes unit source, real damage, unit target, real duration, integer pdType returns boolean
//-- Local vars
local timer t
local integer timerId
local real damageStackDuration //-- Variable to store the time remaining of a damage from a new instance
local effect sfx //-- Variable to load special effect
//-- Variables to get the IDs of each actor
local integer targetId
//-- Variable to check for active instance
local integer isActive
//-- Variables to load the value of current instance if exist
local real currentDuration
local integer damageCounter
//-- Type Check!
if pdType < 1 or pdType > udg_PDMS_PdTypeIndex then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Periodic Damage Type does not exist")
return false
endif
//-- Dead check
if IsUnitType(target, UNIT_TYPE_DEAD) or GetWidgetLife(target) <= 0.405 then
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Trying to apply PDMS on dead unit")
endif
return false
endif
//-- Immunity check
if PDMS_IsImmune(target, pdType) == true then
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Trying to apply PDMS on a unit that's immune")
endif
return false
endif
//-- Get the IDs
set targetId = GetHandleId(target)
set damageCounter = LoadInteger(udg_PDMS_Table, targetId, pdType + 6000)
//-- Cap check
if damageCounter == udg_PDMS_StackCap[pdType] then
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffff0000PDMS Error|r] - " + "Stack has reached maximum cap")
endif
return false
endif
//-- Load the value to check for active instances
set isActive = LoadInteger(udg_PDMS_Table, targetId, pdType)
//-- Load the value of current instance if exist
set currentDuration = LoadReal(udg_PDMS_Table, targetId, pdType + 2000)
//-- Load the effect handle
set sfx = LoadEffectHandle(udg_PDMS_Table, targetId, pdType + 5000)
//-- Create new sfx when there is still none
if sfx == null then
set sfx = AddSpecialEffectTarget(udg_PDMS_DefaultSfxModel[pdType], target, udg_PDMS_DefaultAttachPoint[pdType])
call SaveEffectHandle(udg_PDMS_Table, targetId, pdType + 5000, sfx)
endif
//-- Increment damageCounter then update the storage
set damageCounter = damageCounter + 1
call SaveInteger(udg_PDMS_Table, targetId, pdType + 6000, damageCounter)
//-- Save the new damage
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 7000 + damageCounter, damage)
//-- StackedEvent
set udg_PDMS_LastStackedType = pdType
set udg_PDMS_LastStackedSource = source
set udg_PDMS_LastStackedTarget = target
set udg_PDMS_StackedEvent = 1.00
set udg_PDMS_StackedEvent = 0.00
//-- Check duration and overwrite if it is stronger than the current one
if duration > currentDuration then
//-- Save the new duration of the damage from this instance
set damageStackDuration = duration
call SaveReal(udg_PDMS_Table, targetId, (10000 * pdType) + 8000 + damageCounter, damageStackDuration)
//-- Overwrite the old duration with the new one
set currentDuration = duration
call SaveReal(udg_PDMS_Table, targetId, pdType + 2000, currentDuration)
endif
//-- Always replace source with the latest one
call SaveUnitHandle(udg_PDMS_Table, targetId, pdType + 1000, source)
//-- Start a timer if there is no active instances yet
if isActive == 0 then
//-- Save Interval
call SaveReal(udg_PDMS_Table, targetId, pdType + 3000, udg_PDMS_Interval[pdType])
//-- Create and start the timer
set t = CreateTimer()
call TimerStart(t, udg_PDMS_Timeout, true, function PDMS_LoopCustomStack)
//-- Debug
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Timer is successfully started")
endif
//-- Get its ID to attach data
set timerId = GetHandleId(t)
//-- Attach these data:
//-- - target handle
//-- - pd type
call SaveUnitHandle(udg_PDMS_Table, timerId, 0, target)
call SaveInteger(udg_PDMS_Table, timerId, 1, pdType)
//-- switch active flag
call SaveInteger(udg_PDMS_Table, targetId, pdType, 1)
//-- AppliedEvent
set udg_PDMS_LastAppliedType = pdType
set udg_PDMS_LastAppliedSource = source
set udg_PDMS_LastAppliedTarget = target
set udg_PDMS_AppliedEvent = 1.00
set udg_PDMS_AppliedEvent = 0.00
//-- Null local handle
set t = null
endif
//-- Null local handles
set sfx = null
return true
endfunction
//===========================================================================
//= These functions below are callbacks for GUI triggers
//===========================================================================
function Trig_PDMS_OnDeath takes nothing returns boolean
local integer i = 0
local unit target = GetTriggerUnit()
loop
set i = i + 1
exitwhen i > udg_PDMS_PdTypeIndex
if PDMS_IsUnitInEffect(target, i) then
call PDMS_RemoveByType(target, i)
endif
endloop
set target = null
return false
endfunction
function Trig_PDMS_SetImmunity takes nothing returns boolean
//-- Local variables
local unit target = udg_PDMS_Param_Target
local integer pdType = udg_PDMS_Param_Type
local boolean flag = udg_PDMS_Param_Flag
//-- Make API call
call PDMS_SetImmunity(target, pdType, flag)
set udg_PDMS_Param_Target = null
set udg_PDMS_Param_Type = 0
set udg_PDMS_Param_Flag = false
//-- Null local handle
set target = null
return false
endfunction
function Trig_PDMS_Apply takes nothing returns boolean
//-- Local variables
local unit s = udg_PDMS_Param_Source
local unit t = udg_PDMS_Param_Target
local real dmg = udg_PDMS_Param_Damage
local real dur = udg_PDMS_Param_Duration
local integer pdType = udg_PDMS_Param_Type
//-- Make API call
if udg_PDMS_CanStackDamage[pdType] == false then
call PDMS_ApplyNonStack(s, dmg, t, dur, pdType)
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Applying Non-Stacking Periodic Damage")
endif
elseif udg_PDMS_NonWc3Style[pdType] == true then
call PDMS_ApplyCustomStack(s, dmg, t, dur, pdType)
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Applying Custom Stacking Periodic Damage")
endif
elseif udg_PDMS_NonWc3Style[pdType] == false then
call PDMS_ApplyWc3Stack(s, dmg, t, dur, pdType)
if udg_PDMS_Debug == true then
call BJDebugMsg("[|cffffcc00System Debug|r] - " + "Applying Wc3-Style Stacking Periodic Damage")
endif
endif
//-- Null global parameters
set udg_PDMS_Param_Source = null
set udg_PDMS_Param_Target = null
set udg_PDMS_Param_Damage = 0.0
set udg_PDMS_Param_Duration = 0.0
set udg_PDMS_Param_Type = 0
//-- Null local handle
set s = null
set t = null
return false
endfunction
function Trig_PDMS_Remove takes nothing returns boolean
local unit target = udg_PDMS_Param_Target
local integer pdType = udg_PDMS_Param_Type
if pdType == 0 then
call PDMS_RemoveAll(target)
else
call PDMS_RemoveByType(target, pdType)
endif
//-- Null global parameters
set udg_PDMS_Param_Target = null
set udg_PDMS_Param_Type = 0
//-- Null local handle
set target = null
return false
endfunction
function Trig_PDMS_Check takes nothing returns boolean
local unit target = udg_PDMS_Param_Target
local integer pdType = udg_PDMS_Param_Type
set udg_PDMS_IsUnitInEffect = PDMS_IsUnitInEffect(target, pdType)
//-- Null global parameters
set udg_PDMS_Param_Target = null
set udg_PDMS_Param_Type = 0
//-- Null local handle
set target = null
return false
endfunction
function Trig_PDMS_Register takes nothing returns boolean
//-- Assign locals
local attacktype AT = udg_PDMS_Register_AttackType
local damagetype DT = udg_PDMS_Register_DamageType
local boolean canKill = udg_PDMS_Register_CanKill
local boolean canStackDamage = udg_PDMS_Register_StackDamage
local boolean stackStyle = udg_PDMS_Register_NonWc3Style
local integer stackCap = udg_PDMS_Register_StackCap
local real interval = udg_PDMS_Register_Interval
local string sfxModel = udg_PDMS_Register_SfxModel
local string attachPoint = udg_PDMS_Register_AttachPoint
//-- Make API call
set udg_PDMS_LastRegisteredType = PDMS_RegisterType(AT, DT, canStackDamage, stackStyle, stackCap, canKill, interval, sfxModel, attachPoint)
//-- Null Globals
set udg_PDMS_Register_AttackType = null
set udg_PDMS_Register_DamageType = null
set udg_PDMS_Register_CanKill = false
set udg_PDMS_Register_StackDamage = false
set udg_PDMS_Register_NonWc3Style = false
set udg_PDMS_Register_StackCap = 0
set udg_PDMS_Register_Interval = 0.0
set udg_PDMS_Register_SfxModel = ""
set udg_PDMS_Register_AttachPoint = ""
//-- Null local handles
set AT = null
set DT = null
return false
endfunction
//===========================================================================
//= This function starts on Initialization
//===========================================================================
function InitTrig_PDMS takes nothing returns nothing
//-- Local variables
local integer i = 0
local trigger deathTrg
//-- Create triggers
set deathTrg = CreateTrigger()
set udg_PDMS_Apply = CreateTrigger()
set udg_PDMS_Remove = CreateTrigger()
set udg_PDMS_Check = CreateTrigger()
set udg_PDMS_Register = CreateTrigger()
set udg_PDMS_SetImmunity = CreateTrigger()
//-- Register death event
loop
call TriggerRegisterPlayerUnitEvent(deathTrg, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
//-- Register functions
call TriggerAddCondition(deathTrg, Condition(function Trig_PDMS_OnDeath))
call TriggerAddCondition(udg_PDMS_Apply, Condition(function Trig_PDMS_Apply))
call TriggerAddCondition(udg_PDMS_Remove, Condition(function Trig_PDMS_Remove))
call TriggerAddCondition(udg_PDMS_Check, Condition(function Trig_PDMS_Check))
call TriggerAddCondition(udg_PDMS_Register, Condition(function Trig_PDMS_Register))
call TriggerAddCondition(udg_PDMS_SetImmunity, Condition(function Trig_PDMS_SetImmunity))
//-- Initialize hashtable
set udg_PDMS_Table = InitHashtable()
//-- Initialize config
call PDMS_Configuration()
//-- Null local handle
set deathTrg = null
endfunction