Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
AMSAmount | real | Yes | |
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 | |
DmgEvMana | real | No | |
DmgEvManaMult | real | No | |
DmgEvMSlvl | integer | No | |
DmgEvRecursionN | integer | No | |
DmgEvRunning | boolean | No | |
DmgEvStarted | boolean | No | |
DmgEvTimer | timer | No | |
DmgEvTrig | trigger | No | |
DTR_ActivePairs | integer | No | |
DTR_AutoCleanup | boolean | No | |
DTR_CleanupTime | real | No | |
DTR_GetData | trigger | No | |
DTR_IsRegistered | boolean | Yes | |
DTR_OverallContribution | real | Yes | |
DTR_PhysContribution | real | Yes | |
DTR_RegistrationMode | integer | No | |
DTR_Source | unit | No | |
DTR_SourceArr | unit | Yes | |
DTR_SourceParam | unit | No | |
DTR_Sources | group | No | |
DTR_SpellContribution | real | Yes | |
DTR_Table | hashtable | No | |
DTR_Target | unit | No | |
DTR_TargetArr | unit | Yes | |
DTR_TargetPairGroup | group | Yes | |
DTR_TargetParam | unit | No | |
DTR_TimeCounter | real | Yes | |
DTR_TimeInterval | real | No | |
DTR_Timer | timer | No | |
DTR_TopContribution | real | No | |
DTR_TopContributor | unit | No | |
DTR_TopPhysContribution | real | No | |
DTR_TopPhysContributor | unit | No | |
DTR_TopSpellContribution | real | No | |
DTR_TopSpellContributor | unit | No | |
DTR_TotalDamageTaken | real | No | |
DTR_TotalPhysDamageTaken | real | No | |
DTR_TotalPhysicalDamage | real | No | |
DTR_TotalPlayerDamage | real | Yes | |
DTR_TotalPlayerDamageT | real | Yes | |
DTR_TotalPlayerPhysDamage | real | Yes | |
DTR_TotalPlayerPhysDamageT | real | Yes | |
DTR_TotalPlayerSpellDamage | real | Yes | |
DTR_TotalPlayerSpellDamageT | real | Yes | |
DTR_TotalSpellDamage | real | No | |
DTR_TotalSpellDamageTaken | real | No | |
DTR_TotalUnitDamage | real | No | |
DTR_TrackEvent | real | No | |
EnhancedDamageTarget | unit | No | |
HideDamageFrom | boolean | Yes | |
IsDamageSpell | boolean | No | |
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 | |
SpellDamageAbility | abilcode | No | |
TempInteger | integer | No | |
TempPoint | location | 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 | |
UnitMoving | boolean | 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
//TESH.scrollpos=12
//TESH.alwaysfold=0
constant function GetAMSBuffId takes nothing returns integer
return 'Bams'
endfunction
constant function GetAMSAbilId takes nothing returns integer
return 'A002'
endfunction
constant function GetAMSShieldVal takes nothing returns real
return 300.00
endfunction
function Trig_Anti_Magic_Shield_Fix_Actions takes nothing returns nothing
local integer id = GetUnitUserData(udg_DamageEventTarget)
local real shield = udg_AMSAmount[id]- udg_DamageEventAmount
if shield <= 0.00 then
set udg_DamageEventAmount = -shield
set shield = 0.00
call UnitRemoveAbility(udg_DamageEventTarget, GetAMSBuffId())
else
set udg_DamageEventAmount = 0.00
if udg_DamageEventType == 0 then
set udg_DamageEventType = udg_DamageTypeBlocked
endif
endif
set udg_AMSAmount[id] = shield
endfunction
function Trig_Anti_Magic_Shield_Fix_Conditions takes nothing returns boolean
if udg_IsDamageSpell then
if GetUnitAbilityLevel(udg_DamageEventTarget, GetAMSBuffId()) > 0 then
call Trig_Anti_Magic_Shield_Fix_Actions()
else
set udg_AMSAmount[GetUnitUserData(udg_DamageEventTarget)] = 0.00
endif
endif
return false
endfunction
function AMS_Refresh_Conditions takes nothing returns boolean
if GetSpellAbilityId() == GetAMSAbilId() then
set udg_AMSAmount[GetUnitUserData(GetSpellTargetUnit())] = GetAMSShieldVal()
endif
return false
endfunction
function InitTrig_Anti_Magic_Shield_Fix takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_DamageModifierEvent", EQUAL, 4.00)
call TriggerAddCondition(t, Condition(function Trig_Anti_Magic_Shield_Fix_Conditions))
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Filter(function AMS_Refresh_Conditions))
endfunction
//===========================================================================
// Rheiko Presents
// Damage Tracker v1.2.3
//===========================================================================
//
// Requirements:
// - Unit Indexer by Bribe
// - Damage Engine v3.8 by Bribe
//
// Damage Tracker allows you to easily retrieve a total amount of damage that
// a unit has dealt by using Damage Engine to detect when a unit takes damage
// then store the damage information into a hashtable. When the unit taking
// damage dies, the system clean up the information.
//
// Features:
// - Allows you to retrieve Total Overall/Spell/Physical Damage dealt by a unit
// - Allows you to retrieve Total Overall/Spell/Physical Damage taken by a unit
// - Allows you to retrieve Damage Contribution (in percentage %) by a unit
// - Allows you to retrieve Total Damage dealt by a player
//
// In order to keep memory usage minimum and used only as necessary, the system
// requires you to register the units whose damage you wish to track first. To
// do so, simply set DTR_IsRegistered[(Custom value of (Your unit))] = True
//
// Damage Tracker has custom events that can help you retrieve damage info,
// they are:
// - DTR_TrackerEvent Equal to 1.00
// - DTR_TrackerEvent Equal to 2.00
//
// You can treat DTR_TrackerEvent Equal to 1.00 just like DamageEvent Equal to 1.00
// (because it actually is based on that) from here, you can retrieve damage dealt
// and damage taken by the actors corresponding to these events, they are DTR_Source
// and DTR_Target.
//
// You can treat DTR_TrackerEvent Equal to 2.00 just like Unit - A unit dies event.
// However, in this event and in this event only, you can also retrieve Damage
// Contribution by a unit.
//
// Finally, you have a variable called DTR_TotalPlayerDamage[PlayerId] which
// contain the total damage done by each player. This variable is an array
// and the index is based on PlayerId. Be noted that the index starts from 0.
//
// Make sure to check the examples to further explore the capability of this system.
// If you have any feedbacks or suggestions, feel free to let me know at
// https://www.hiveworkshop.com/members/rheiko.232216/
//
//===========================================================================
//=========== API ============
function GetDamageTrackerData takes nothing returns boolean
local integer SourceKey
local integer TargetKey
if udg_DTR_SourceParam != null and udg_DTR_TargetParam != null then
set SourceKey = GetHandleId(udg_DTR_SourceParam)
set TargetKey = GetHandleId(udg_DTR_TargetParam)
// Load all the total damage taken
set udg_DTR_TotalDamageTaken = LoadReal(udg_DTR_Table, 0, TargetKey)
set udg_DTR_TotalSpellDamageTaken = LoadReal(udg_DTR_Table, 1, TargetKey)
set udg_DTR_TotalPhysDamageTaken = LoadReal(udg_DTR_Table, 2, TargetKey)
// Load all the total damage dealt
set udg_DTR_TotalUnitDamage = LoadReal(udg_DTR_Table, TargetKey, SourceKey)
set udg_DTR_TotalSpellDamage = LoadReal(udg_DTR_Table, TargetKey + 100000, SourceKey)
set udg_DTR_TotalPhysicalDamage = LoadReal(udg_DTR_Table, TargetKey + 200000, SourceKey)
return true
endif
return false
endfunction
//===========================================================================
function IsUnitAlive takes unit u returns boolean
return (GetWidgetLife(u) > 0.405)
endfunction
function DTR_ValidateUnit takes unit Source, unit Target returns boolean
local integer Mode = udg_DTR_RegistrationMode
local integer SourceId = GetUnitUserData(Source)
local integer TargetId = GetUnitUserData(Target)
return (Mode == 1 and not udg_DTR_IsRegistered[SourceId]) or (Mode == 2 and not udg_DTR_IsRegistered[TargetId]) or (Mode == 3 and (not udg_DTR_IsRegistered[SourceId] or not udg_DTR_IsRegistered[TargetId]))
endfunction
function DTR_ClearTableData takes integer TargetKey returns nothing
call RemoveSavedReal(udg_DTR_Table, 0, TargetKey)
call RemoveSavedReal(udg_DTR_Table, 1, TargetKey)
call RemoveSavedReal(udg_DTR_Table, 2, TargetKey)
call RemoveSavedReal(udg_DTR_Table, 3, TargetKey)
call RemoveSavedReal(udg_DTR_Table, 4, TargetKey)
call FlushChildHashtable(udg_DTR_Table, TargetKey)
call FlushChildHashtable(udg_DTR_Table, TargetKey + 100000)
call FlushChildHashtable(udg_DTR_Table, TargetKey + 200000)
endfunction
function DTR_LoadTableData takes integer SourceKey, integer TargetKey returns nothing
// Load all the total damage taken
set udg_DTR_TotalDamageTaken = LoadReal(udg_DTR_Table, 0, TargetKey)
set udg_DTR_TotalSpellDamageTaken = LoadReal(udg_DTR_Table, 1, TargetKey)
set udg_DTR_TotalPhysDamageTaken = LoadReal(udg_DTR_Table, 2, TargetKey)
// Load all the total damage dealt
set udg_DTR_TotalUnitDamage = LoadReal(udg_DTR_Table, TargetKey, SourceKey)
set udg_DTR_TotalSpellDamage = LoadReal(udg_DTR_Table, TargetKey + 100000, SourceKey)
set udg_DTR_TotalPhysicalDamage = LoadReal(udg_DTR_Table, TargetKey + 200000, SourceKey)
endfunction
function DTR_UpdateTopContributor takes unit source, real damage, integer damageType returns nothing
if damageType == 1 then
if damage > udg_DTR_TopContribution then
set udg_DTR_TopContribution = damage
set udg_DTR_TopContributor = source
endif
endif
if damageType == 2 then
if damage > udg_DTR_TopSpellContribution then
set udg_DTR_TopSpellContribution = damage
set udg_DTR_TopSpellContributor = source
endif
endif
if damageType == 3 then
if damage > udg_DTR_TopPhysContribution then
set udg_DTR_TopPhysContribution = damage
set udg_DTR_TopPhysContributor = source
endif
endif
endfunction
function DTR_TimerCallback takes nothing returns nothing
// Assign locals
local integer i = 0
local integer SourceKey
local integer TargetKey
local integer TargetId
// Loop through active pairs
loop
set i = i + 1
exitwhen i > udg_DTR_ActivePairs
set SourceKey = GetHandleId(udg_DTR_SourceArr[i])
set TargetKey = GetHandleId(udg_DTR_TargetArr[i])
// Increase counter if its not expired yet
if udg_DTR_TimeCounter[i] < udg_DTR_CleanupTime and IsUnitAlive(udg_DTR_TargetArr[i]) then
set udg_DTR_TimeCounter[i] = LoadReal(udg_DTR_Table, 4, TargetKey)
set udg_DTR_TimeCounter[i] = udg_DTR_TimeCounter[i] + 1
call SaveReal(udg_DTR_Table, 4, TargetKey, udg_DTR_TimeCounter[i])
else
// Clear data
if IsUnitAlive(udg_DTR_TargetArr[i]) then
set TargetId = GetUnitUserData(udg_DTR_TargetArr[i])
call DTR_ClearTableData(TargetKey)
call GroupRemoveUnit(udg_DTR_TargetPairGroup[TargetId], udg_DTR_SourceArr[i])
endif
// Deindex
set udg_DTR_SourceArr[i] = udg_DTR_SourceArr[udg_DTR_ActivePairs]
set udg_DTR_SourceArr[udg_DTR_ActivePairs] = null
set udg_DTR_TargetArr[i] = udg_DTR_TargetArr[udg_DTR_ActivePairs]
set udg_DTR_TargetArr[udg_DTR_ActivePairs] = null
set udg_DTR_TimeCounter[i] = udg_DTR_TimeCounter[udg_DTR_ActivePairs]
set i = i - 1
set udg_DTR_ActivePairs = udg_DTR_ActivePairs - 1
if udg_DTR_ActivePairs == 0 then
call PauseTimer(udg_DTR_Timer)
endif
endif
endloop
endfunction
function DTR_OnUnitDeath takes nothing returns boolean
// Assign locals
local unit Killer = GetKillingUnit()
local unit Target = GetTriggerUnit()
local integer KillerKey = GetHandleId(Killer)
local integer TargetKey = GetHandleId(Target)
local integer TargetId = GetUnitUserData(Target)
local integer SourceKey
local integer SourceId
local group g
local unit u
// Validate whether source and/or target registered
if DTR_ValidateUnit(Killer, Target) then
set Killer = null
set Target = null
return false
endif
// Loop through the group owned by the target which contains sources
set g = udg_DTR_TargetPairGroup[TargetId]
set u = FirstOfGroup(g)
loop
set SourceKey = GetHandleId(u)
set SourceId = GetUnitUserData(u)
// Load data of each source
call DTR_LoadTableData(SourceKey, TargetKey)
set udg_DTR_OverallContribution[SourceId] = 0.0
set udg_DTR_SpellContribution[SourceId] = 0.0
set udg_DTR_PhysContribution[SourceId] = 0.0
// Ensure total damage taken is not 0
if udg_DTR_TotalDamageTaken > 0.0 then
set udg_DTR_OverallContribution[SourceId] = (udg_DTR_TotalUnitDamage / udg_DTR_TotalDamageTaken) * 100
endif
if udg_DTR_TotalSpellDamageTaken > 0.0 then
set udg_DTR_SpellContribution[SourceId] = (udg_DTR_TotalSpellDamage / udg_DTR_TotalSpellDamageTaken) * 100
endif
if udg_DTR_TotalPhysDamageTaken > 0.0 then
set udg_DTR_PhysContribution[SourceId] = (udg_DTR_TotalPhysicalDamage / udg_DTR_TotalPhysDamageTaken) * 100
endif
// Calculate top contributors
call DTR_UpdateTopContributor(u, udg_DTR_OverallContribution[SourceId], 1)
call DTR_UpdateTopContributor(u, udg_DTR_SpellContribution[SourceId], 2)
call DTR_UpdateTopContributor(u, udg_DTR_PhysContribution[SourceId], 3)
// Add them to a temp group for accessibility
call GroupAddUnit(udg_DTR_Sources, u)
call GroupRemoveUnit(g, u)
set u = FirstOfGroup(g)
exitwhen u==null
endloop
// Load data of the killer
call DTR_LoadTableData(KillerKey, TargetKey)
set udg_DTR_Source = Killer
set udg_DTR_Target = Target
set udg_DTR_TrackEvent = 0.0
set udg_DTR_TrackEvent = 2.0
set udg_DTR_TrackEvent = 0.0
// Reset data
set g = udg_DTR_TargetPairGroup[TargetId]
set u = FirstOfGroup(g)
loop
set SourceId = GetUnitUserData(u)
set udg_DTR_OverallContribution[SourceId] = 0.0
set udg_DTR_SpellContribution[SourceId] = 0.0
set udg_DTR_PhysContribution[SourceId] = 0.0
call GroupRemoveUnit(g, u)
set u = FirstOfGroup(g)
exitwhen u==null
endloop
set udg_DTR_TopContribution = 0.0
set udg_DTR_TopSpellContribution = 0.0
set udg_DTR_TopPhysContribution = 0.0
set udg_DTR_TotalDamageTaken = 0.0
set udg_DTR_TotalUnitDamage = 0.0
set udg_DTR_TotalSpellDamageTaken = 0.0
set udg_DTR_TotalSpellDamage = 0.0
set udg_DTR_TotalPhysDamageTaken = 0.0
set udg_DTR_TotalPhysicalDamage = 0.0
set udg_DTR_Source = null
set udg_DTR_Target = null
call DTR_ClearTableData(TargetKey)
call DestroyGroup(udg_DTR_TargetPairGroup[TargetId])
set udg_DTR_TargetPairGroup[TargetId] = null
call GroupClear(udg_DTR_Sources)
set g = null
set Killer = null
set Target = null
return false
endfunction
function DTR_BeforeUnitDamage takes nothing returns boolean
// Assign locals
local unit Source = udg_DamageEventSource
local unit Target = udg_DamageEventTarget
local integer TargetKey = GetHandleId(Target)
local real TargetHP = GetUnitState(Target, UNIT_STATE_LIFE)
// Validate whether source and/or target registered
if DTR_ValidateUnit(Source, Target) then
set Source = null
set Target = null
return false
endif
// Save HP value before taking damage for comparison later
call SaveReal(udg_DTR_Table, 3, TargetKey, TargetHP)
set Source = null
set Target = null
return false
endfunction
function DTR_OnUnitDamage takes nothing returns boolean
// Assign locals
local unit Source = udg_DamageEventSource
local unit Target = udg_DamageEventTarget
local integer SourceKey = GetHandleId(Source)
local integer TargetKey = GetHandleId(Target)
local integer SourcePId = GetPlayerId(GetOwningPlayer(Source))
local integer TargetPId = GetPlayerId(GetOwningPlayer(Target))
local integer TargetId = GetUnitUserData(Target)
local real TempDmg = udg_DamageEventAmount
local real TargetHP = 0.0
// Validate whether source and/or target registered
if DTR_ValidateUnit(Source, Target) then
set Source = null
set Target = null
return false
endif
// -> Load data <-
set TargetHP = LoadReal(udg_DTR_Table, 3, TargetKey)
// Damage Correction when damage value is over current HP value
if TargetHP <= TempDmg then
set TempDmg = TargetHP
endif
call DTR_LoadTableData(SourceKey, TargetKey)
// Prepares a group to contain all the damage sources
if udg_DTR_TargetPairGroup[TargetId] == null then
set udg_DTR_TargetPairGroup[TargetId] = CreateGroup()
endif
// Add the source if its not already in the group
if not IsUnitInGroup(Source, udg_DTR_TargetPairGroup[TargetId]) then
call GroupAddUnit(udg_DTR_TargetPairGroup[TargetId], Source)
endif
// Start a timer if auto clean is on
if udg_DTR_TotalDamageTaken == 0.0 and udg_DTR_AutoCleanup == true then
// New entry
set udg_DTR_ActivePairs = udg_DTR_ActivePairs + 1
set udg_DTR_TimeCounter[udg_DTR_ActivePairs] = 0.0
set udg_DTR_SourceArr[udg_DTR_ActivePairs] = Source
set udg_DTR_TargetArr[udg_DTR_ActivePairs] = Target
if udg_DTR_ActivePairs == 1 then
call TimerStart(udg_DTR_Timer, udg_DTR_TimeInterval, true, function DTR_TimerCallback)
endif
endif
// Update Data
call SaveReal(udg_DTR_Table, 4, TargetKey, 0.0) // Reset the counter to prolong its timer
set udg_DTR_TotalPlayerDamage[SourcePId] = udg_DTR_TotalPlayerDamage[SourcePId] + TempDmg
set udg_DTR_TotalPlayerDamageT[TargetPId] = udg_DTR_TotalPlayerDamageT[TargetPId] + TempDmg
set udg_DTR_TotalDamageTaken = udg_DTR_TotalDamageTaken + TempDmg
call SaveReal(udg_DTR_Table, 0, TargetKey, udg_DTR_TotalDamageTaken)
set udg_DTR_TotalUnitDamage = udg_DTR_TotalUnitDamage + TempDmg
call SaveReal(udg_DTR_Table, TargetKey, SourceKey, udg_DTR_TotalUnitDamage)
if udg_IsDamageSpell == true then
set udg_DTR_TotalSpellDamageTaken = udg_DTR_TotalSpellDamageTaken + TempDmg
call SaveReal(udg_DTR_Table, 1, TargetKey, udg_DTR_TotalSpellDamageTaken)
set udg_DTR_TotalSpellDamage = udg_DTR_TotalSpellDamage + TempDmg
call SaveReal(udg_DTR_Table, TargetKey + 100000, SourceKey, udg_DTR_TotalSpellDamage)
set udg_DTR_TotalPlayerSpellDamage[SourcePId] = udg_DTR_TotalPlayerSpellDamage[SourcePId] + TempDmg
set udg_DTR_TotalPlayerSpellDamageT[TargetPId] = udg_DTR_TotalPlayerSpellDamageT[TargetPId] + TempDmg
else
set udg_DTR_TotalPhysDamageTaken = udg_DTR_TotalPhysDamageTaken + TempDmg
call SaveReal(udg_DTR_Table, 2, TargetKey, udg_DTR_TotalPhysDamageTaken)
set udg_DTR_TotalPhysicalDamage = udg_DTR_TotalPhysicalDamage + TempDmg
call SaveReal(udg_DTR_Table, TargetKey + 200000, SourceKey, udg_DTR_TotalPhysicalDamage)
set udg_DTR_TotalPlayerPhysDamage[SourcePId] = udg_DTR_TotalPlayerPhysDamage[SourcePId] + TempDmg
set udg_DTR_TotalPlayerPhysDamageT[TargetPId] = udg_DTR_TotalPlayerPhysDamageT[TargetPId] + TempDmg
endif
set udg_DTR_Source = Source
set udg_DTR_Target = Target
set udg_DTR_TrackEvent = 0.0
set udg_DTR_TrackEvent = 1.0
set udg_DTR_TrackEvent = 0.0
// Reset data
set udg_DTR_TotalDamageTaken = 0.0
set udg_DTR_TotalUnitDamage = 0.0
set udg_DTR_TotalSpellDamageTaken = 0.0
set udg_DTR_TotalSpellDamage = 0.0
set udg_DTR_TotalPhysDamageTaken = 0.0
set udg_DTR_TotalPhysicalDamage = 0.0
set udg_DTR_Source = null
set udg_DTR_Target = null
set Source = null
set Target = null
return false
endfunction
//===========================================================================
function InitTrig_Damage_Tracker takes nothing returns nothing
local integer i = bj_MAX_PLAYERS
local trigger mainTrg = CreateTrigger()
local trigger secondTrg = CreateTrigger()
local trigger deathTrg = CreateTrigger()
set udg_DTR_GetData = CreateTrigger()
call TriggerAddCondition( udg_DTR_GetData, Condition( function GetDamageTrackerData ) )
call TriggerRegisterVariableEvent(mainTrg, "udg_DamageEvent", EQUAL, 1.00)
call TriggerRegisterVariableEvent(secondTrg, "udg_DamageModifierEvent", EQUAL, 1.00)
loop
set i = i - 1
call TriggerRegisterPlayerUnitEvent(deathTrg, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
exitwhen i == 0
endloop
call TriggerAddCondition( mainTrg, Condition( function DTR_OnUnitDamage ))
call TriggerAddCondition( secondTrg, Condition( function DTR_BeforeUnitDamage ))
call TriggerAddCondition( deathTrg, Condition( function DTR_OnUnitDeath ))
set udg_DTR_Table = InitHashtable()
set mainTrg = null
set secondTrg = null
set deathTrg = null
endfunction