You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7903 lines
295 KiB

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6 months ago
---@type details
local Details = _G.Details
local addonName, Details222 = ...
local Loc = LibStub("AceLocale-3.0"):GetLocale("Details")
local detailsFramework = DetailsFramework
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--local pointers
6 months ago
Details.challengeModeMapId = nil
local UnitHealthMax = UnitHealthMax
Details.HealthMaxFrame = CreateFrame("Frame")
if not detailsFramework.IsMidnightWow() then
Details.HealthMaxFrame:RegisterEvent("UNIT_MAXHEALTH")
end
6 months ago
Details.HealthCache = {}
Details.HealthMaxCache = {}
Details.HealthMaxCalls = 0
Details.HealthMaxFrame:SetScript("OnEvent", function(self, event, unitId)
local unitGUID = UnitGUID(unitId)
if (unitGUID) then
Details.HealthMaxCache[unitGUID] = max(UnitHealthMax(unitId), SMALL_FLOAT)
Details.HealthMaxCalls = Details.HealthMaxCalls + 1
end
end)
3 years ago
local UnitAffectingCombat = UnitAffectingCombat
local UnitHealth = UnitHealth
local UnitGUID = UnitGUID
--local IsInGroup = IsInGroup
3 years ago
local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo
local GetTime = GetTime
local tonumber = tonumber
local tinsert = table.insert
--local select = select
3 years ago
local bitBand = bit.band
local floor = math.floor
local ipairs = ipairs
local type = type
local meleeString = _G["MELEE"]
3 years ago
local _UnitGroupRolesAssigned = detailsFramework.UnitGroupRolesAssigned
local _GetSpellInfo = Details.getspellinfo
local GetSpellInfo = Details222.GetSpellInfo
local isERA = detailsFramework.IsClassicWow()
local isCLASSIC = detailsFramework.IsCataWow() or detailsFramework.IsPandaWow() or isERA or detailsFramework.IsWotLKWow() or detailsFramework.IsTBCWow()
local _tempo = time()
_ = nil
3 years ago
6 months ago
local shield_cache = Details.ShieldCache
local parser = Details.parser
6 months ago
local crowdControlSpells = Details.CrowdControlSpellIdsCache or {} --built during startup, can be edited to add or remove spells
local spellContainerClass = Details.container_habilidades --details local
3 years ago
--localize the cooldown table from the framework
local defensive_cooldowns = {}
3 years ago
if (LIB_OPEN_RAID_COOLDOWNS_INFO) then
--check if the cooldown is type 2 or 3 or 4 and add to the defensive_cooldowns table
for spellId, spellTable in pairs(LIB_OPEN_RAID_COOLDOWNS_INFO) do
if (spellTable.type == 2 or spellTable.type == 3 or spellTable.type == 4) then
defensive_cooldowns[spellId] = spellTable
end
end
end
--cache the addition functions for each attribute
local _spell_damage_func = Details.habilidade_dano.Add
local _spell_damageMiss_func = Details.habilidade_dano.AddMiss
local _spell_heal_func = Details.habilidade_cura.Add
local _spell_energy_func = Details.habilidade_e_energy.Add
local _spell_utility_func = Details.habilidade_misc.Add
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--cache
--cache current combat
local _current_combat = Details.tabela_vigente or {} --placeholder table
3 years ago
--cache total table
local _current_total = _current_combat.totals
local _current_gtotal = _current_combat.totals_grupo
3 years ago
--cache actors containers
local _current_damage_container = _current_combat [1]
local _current_heal_container = _current_combat [2]
local _current_energy_container = _current_combat [3]
local _current_misc_container = _current_combat [4]
--pet container cache
---@type petcontainer
local petContainer = Details222.PetContainer
local names_cache = {}
3 years ago
--damage
local damage_cache = setmetatable({}, Details.weaktable)
local damage_cache_pets = setmetatable({}, Details.weaktable)
local damage_cache_petsOwners = setmetatable({}, Details.weaktable)
3 years ago
--heaing
local healing_cache = setmetatable({}, Details.weaktable)
local banned_healing_spells = {
}
3 years ago
--energy
local energy_cache = setmetatable({}, Details.weaktable)
3 years ago
--misc
local misc_cache = setmetatable({}, Details.weaktable)
local misc_cache_pets = setmetatable({}, Details.weaktable)
local misc_cache_petsOwners = setmetatable({}, Details.weaktable)
3 years ago
--party & raid members
local raid_members_cache = setmetatable({}, Details.weaktable)
3 years ago
--tanks
local tanks_members_cache = setmetatable({}, Details.weaktable)
3 years ago
--auto regen
local auto_regen_cache = setmetatable({}, Details.weaktable)
3 years ago
--bitfield swap cache
local bitfield_swap_cache = {}
3 years ago
--damage and heal last events
local last_events_cache = {} --just initialize table (placeholder)
--hunter pet frenzy cache
local pet_frenzy_cache = {}
3 years ago
--npcId cache
local npcid_cache = {}
--enemy cast cache
local enemy_cast_cache = {}
--shield spellid cache
local shield_spellid_cache = {}
3 years ago
--pets
local petCache = petContainer.Pets
--interrupt overlap cache
local interruptOverlapCache = {}
3 years ago
--ignore deaths
local ignore_death_cache = {}
3 years ago
--cache
local cacheAnything = {
arenaHealth = {},
paladin_vivaldi_blessings = {},
track_hunter_frenzy = false,
rampage_cast_amount = {},
}
--store the gear of each player
local gearCache = {}
--cache the data for passive trinkets procs
local _trinket_data_cache = {}
3 years ago
--spell containers for special cases
local monk_guard_talent = {} --guard talent for bm monks
3 years ago
--spell reflection
local reflection_damage = {} --self-inflicted damage
local reflection_debuffs = {} --self-inflicted debuffs
local reflection_events = {} --spell_missed reflected events
local reflection_auras = {} --active reflecting auras
local reflection_dispels = {} --active reflecting dispels
local reflection_spellid = {
3 years ago
--we can track which spell caused the reflection
--this is used to credit this aura as the one doing the damage
[23920] = true, --warrior spell reflection
[216890] = true, --warrior spell reflection (pvp talent)
[213915] = true, --warrior mass spell reflection
[212295] = true, --warlock nether ward
--check pally legendary
}
local reflection_dispelid = {
3 years ago
--some dispels also reflect, and we can track them
[122783] = true, --monk diffuse magic
3 years ago
--[205604] = true, --demon hunter reverse magic
3 years ago
--this last one is an odd one, like most dh spells is kindy buggy combatlog wise
--for now it doesn't fire SPELL_DISPEL events even when dispelling stuff (thanks blizzard)
--maybe someone can figure out something to track it... but for now it doesnt work
}
local reflection_ignore = {
3 years ago
--common self-harm spells that we know weren't reflected
--this list can be expanded
[111400] = true, --warlock burning rush
[124255] = true, --monk stagger
[196917] = true, --paladin light of the martyr
[217979] = true, --warlock health funnel
}
4 years ago
--army od the dead cache
local dk_pets_cache = {
army = {},
apoc = {},
}
--list of buffs that should be credited to the target of the buff
4 years ago
local buffs_to_other_players = {
--[10060] = true, --power infusion
[413426] = true, --rippling anthem (trinket 10.1)
[405734] = true, --spore tender
[406785] = true, --invigorating spore cloud
}
---@class evokerinfo : table
---@field key1 serial
---@field key2 actorname
---@field key3 controlflags
---@field key4 valueamount
---@class evokereonsbreathinfo : table
---@field key1 serial
---@field key2 actorname
---@field key3 controlflags
---@field key4 unit
---@field key5 unixtime
---@field key6 number
---@field key7 number
local augmentation_aura_list = {
[395152] = true, --ebon might (evoker 10.1.5) 395296 = the evoker buff on it self
[413984] = true, --Shifting Sands
[410089] = true, --prescience (evoker 10.1.5)
[409560] = true, --Temporal Wound
[360827] = true, --Blistering Scales
[410263] = true, --Inferno's Blessing
}
--list of buffs given by another player but should also be credited to the which received it
local buffs_on_target = {
--[395152] = true, --ebon might (evoker 10.1.5)
[395152] = true, --ebon might (evoker 10.1.5) 395296 = the evoker buff on it self
[410089] = true, --prescience (evoker 10.1.5)
[10060] = true, --power infusion
[194384] = true, --atonement uptime
[378134] = true, --rallied to victory
6 months ago
[436159] = true, --ring boon of binding buff
}
6 months ago
Details.CreditBuffToTarget = buffs_on_target
---@type table<spellid, boolean>
local ignoredWorldAuras = Details222.IgnoredWorldAuras
--store all information about augmentation evokers ~roskash
local augmentation_cache = {
ebon_might = {},
prescience = {},
prescience_stacks = {},
---@type table<serial, evokereonsbreathinfo[]>
breath_targets = {},
flyaway = {},
flyaway_timer = {},
shield = {},
ss = {},
infernobless = {},
4 years ago
}
6 months ago
---@class bombardmentinfo : table
---@field only_one_scalecomander boolean
---@field spellId number
---@field evoker_name string
---@field serial string
---@type bombardmentinfo
local bombardment_stuff = {
only_one_scalecomander = true,
spellId = 434481,
evoker_name = "",
serial = "",
}
Details.augmentation_cache = augmentation_cache
Details222.SpecHelpers[1473].augmentation_cache = augmentation_cache
local empower_cache = {}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--constants
local container_misc = Details.container_type.CONTAINER_MISC_CLASS
4 years ago
local OBJECT_TYPE_ENEMY = 0x00000040
local OBJECT_TYPE_PLAYER = 0x00000400
local OBJECT_TYPE_PETS = 0x00003000
local AFFILIATION_GROUP = 0x00000007
4 years ago
local REACTION_FRIENDLY = 0x00000010
local ENVIRONMENTAL_FALLING_NAME = Loc ["STRING_ENVIRONMENTAL_FALLING"]
local ENVIRONMENTAL_DROWNING_NAME = Loc ["STRING_ENVIRONMENTAL_DROWNING"]
local ENVIRONMENTAL_FATIGUE_NAME = Loc ["STRING_ENVIRONMENTAL_FATIGUE"]
local ENVIRONMENTAL_FIRE_NAME = Loc ["STRING_ENVIRONMENTAL_FIRE"]
local ENVIRONMENTAL_LAVA_NAME = Loc ["STRING_ENVIRONMENTAL_LAVA"]
local ENVIRONMENTAL_SLIME_NAME = Loc ["STRING_ENVIRONMENTAL_SLIME"]
4 years ago
local RAID_TARGET_FLAGS = {
[128] = true, --0x80 skull
[64] = true, --0x40 cross
[32] = true, --0x20 square
[16] = true, --0x10 moon
[8] = true, --0x8 triangle
[4] = true, --0x4 diamond
[2] = true, --0x2 circle
[1] = true, --0x1 star
}
4 years ago
3 years ago
--spellIds override
local override_spellId = {}
if (detailsFramework.IsCataWow() or detailsFramework.IsPandaWow()) then
3 years ago
override_spellId = {
--Scourge Strike
6 months ago
[55265] = 55090,
[55270] = 55090,
[70890] = 55090, --shadow
3 years ago
--Frost Strike
6 months ago
[51416] = 49143,
[51417] = 49143,
[51418] = 49143,
[51419] = 49143,
[66962] = 49143, --offhand
[66196] = 49143, --frost dk frost strike offhand
3 years ago
--Obliterate
6 months ago
[51423] = 49020,
[51424] = 49020,
[66974] = 49020, --offhand
[66198] = 49020, --frost dk obliterate offhand
3 years ago
--Death Strike
6 months ago
[49999] = 49998,
[45463] = 49998,
[49923] = 49998,
[66953] = 49998, --offhand
3 years ago
--Blood Strike
6 months ago
[49926] = 45902,
[49927] = 45902,
[49928] = 45902,
[49929] = 45902,
[66979] = 45902, --offhand
3 years ago
--Rune Strike
[6621] = 56815, --offhand
--Plague Strike
6 months ago
[49917] = 45462,
[49918] = 45462,
[49919] = 45462,
[49920] = 45462,
[66992] = 45462, --offhand
3 years ago
--Seal of Command
[20424] = 69403, --53739 and 53733
}
else --retail
override_spellId = { --~merge
[184707] = 218617, --warrior rampage
[184709] = 218617, --warrior rampage
[201364] = 218617, --warrior rampage
[201363] = 218617, --warrior rampage
[85384] = 96103, --warrior raging blow
[85288] = 96103, --warrior raging blow
[280849] = 5308, --warrior execute
[163558] = 5308, --warrior execute
[217955] = 5308, --warrior execute
[217956] = 5308, --warrior execute
[217957] = 5308, --warrior execute
[224253] = 5308, --warrior execute
[260798] = 5308, --warrior execute
[199850] = 199658, --warrior whirlwind
[190411] = 199658, --warrior whirlwind
[44949] = 199658, --warrior whirlwind
[199667] = 199658, --warrior whirlwind
[199852] = 199658, --warrior whirlwind
[199851] = 199658, --warrior whirlwind
[411547] = 199658, --arms warrior whirlwind
[385228] = 199658, --arms warrior whirlwind
[105771] = 126664, --warrior charge
[385060] = 385062, --fury warrior odyn fury
[385061] = 385062, --fury warrior odyn fury offhand
6 months ago
[335097] = 335100, --fury warrior crushing blow
[335098] = 335100, --fury warrior crushing blow offhand
[458459] = 845, --arms warrior cleave
[440884] = 440886, --arms warrior demolish
[440888] = 440886, --arms warrior demolish
[95738] = 50622, --fury warrior bladestorm offhand
[460670] = 435791, --fury warrior lightning strike
3 years ago
[222031] = 199547, --deamonhunter ChaosStrike
[200685] = 199552, --deamonhunter Blade Dance
[391378] = 199552, --^
[391374] = 199552, --^
[210155] = 210153, --deamonhunter Death Sweep
[393055] = 210153, --^
[393054] = 210153, --^
[393035] = 337819, --demonhunter throw glaive
[227518] = 201428, --deamonhunter Annihilation
[187727] = 178741, --deamonhunter Immolation Aura
[201789] = 201628, --deamonhunter Fury of the Illidari
[225921] = 225919, --deamonhunter Fracture talent
3 years ago
[205164] = 205165, --death knight Crystalline Swords
3 years ago
[193315] = 197834, --rogue Saber Slash
[202822] = 202823, --rogue greed
[280720] = 282449, --rogue Secret Technique
[280719] = 282449, --rogue Secret Technique
[27576] = 5374, --rogue mutilate
[385897] = 8676, --rogue Ambush
[430023] = 8676, --rogue Ambush
3 years ago
[233496] = 233490, --warlock Unstable Affliction
[233497] = 233490, --warlock Unstable Affliction
[233498] = 233490, --warlock Unstable Affliction
[233499] = 233490, --warlock Unstable Affliction
3 years ago
[261947] = 261977, --monk fist of the white tiger talent
[32175] = 17364, -- shaman Stormstrike (from Turkar on github)
[32176] = 17364, -- shaman Stormstrike
[45284] = 188196, --shaman lightining bolt overloaded
4 years ago
[45297] = 188443, -- shaman chain lightning overload
[120588] = 117014, -- shaman elemental blast overload
[285466] = 285452, -- shaman lava burst overload
[298765] = 77478, -- shaman earthquake overload
[219271] = 210714, -- shaman icefury overload
4 years ago
[228361] = 228360, --shadow priest void erruption
[401422] = 401428, --vessel of searing shadow (trinket)
[417134] = 414532, --rage of Fyr'alath
[413584] = 414532,
[424094] = 414532,
[228649] = 100784, --monk blackout kick
6 months ago
[436304] = 439843, --frost dk reaper's mark
[439594] = 439843, --frost dk reaper's mark
[66198] = 222024, --frost dk obliterate offhand
[66196] = 222026, --frost dk frost strike offhand
[383312] = 383313, --frost dk abom limb
[441424] = 441426, --frost dk exterminate
}
--all totem
--377461 382133
--377458 377459
end
4 years ago
local override_aura_spellid = {
[426672] = { --Pip's Emerald Friendship Badge Urctos
CanOverride = function(auraName, texture, count, auraType, duration, expirationTime, sourceUnit, isStealable, nameplateShowPersonal, spellId, canApplyAura, isBossAura, isFromPlayerOrPlayerPet, nameplateShowAll, timeMod, ...)
if (duration and duration >= 1 and duration <= 60) then
return true
end
end,
NewSpellId = 426674,
},
[426676] = { --Pip's Emerald Friendship Badge Aerwynn
CanOverride = function(auraName, texture, count, auraType, duration, expirationTime, sourceUnit, isStealable, nameplateShowPersonal, spellId, canApplyAura, isBossAura, isFromPlayerOrPlayerPet, nameplateShowAll, timeMod, ...)
if (duration and duration >= 1 and duration <= 60) then
return true
end
end,
NewSpellId = 426677,
},
[426647] = { --Pip's Emerald Friendship Badge Pip
CanOverride = function(auraName, texture, count, auraType, duration, expirationTime, sourceUnit, isStealable, nameplateShowPersonal, spellId, canApplyAura, isBossAura, isFromPlayerOrPlayerPet, nameplateShowAll, timeMod, ...)
if (duration and duration >= 1 and duration <= 60) then
return true
end
end,
NewSpellId = 426648
},
}
local bitfield_debuffs = {}
for _, spellid in ipairs(Details.BitfieldSwapDebuffsIDs) do
4 years ago
local spellname = GetSpellInfo(spellid)
if (spellname) then
bitfield_debuffs[spellname] = true
else
bitfield_debuffs[spellid] = true
end
end
for spellId in pairs(Details.BitfieldSwapDebuffsSpellIDs) do
bitfield_debuffs [spellId] = true
end
Details.bitfield_debuffs_table = bitfield_debuffs
4 years ago
--tbc spell caches
local TBC_PrayerOfMendingCache = {}
local TBC_EarthShieldCache = {}
--expose the override spells table to external scripts
Details.OverridedSpellIds = override_spellId
3 years ago
--list of ignored npcs by the user
Details.default_ignored_npcs = {
--DH Havoc Talent Fodder to the Flame
4 years ago
[169421] = true,
[169425] = true,
[168932] = true,
[169426] = true,
[169429] = true,
[169428] = true,
[169430] = true,
3 years ago
--Volatile Spark on razga'reth
[194999] = true,
--Ozumat - Throne of Tides
[44566] = true,
--Smoldering Seedling trinket
[212590] = true,
4 years ago
}
local ignored_npcids = {}
3 years ago
--ignore soul link (damage from the warlock on his pet - current to demonology only)
local SPELLID_WARLOCK_SOULLINK = 108446
3 years ago
--brewmaster monk guard talent
local SPELLID_MONK_GUARD = 115295
3 years ago
--shaman earth shield (bcc)
local SPELLID_SHAMAN_EARTHSHIELD_HEAL = 379
local SPELLID_SHAMAN_EARTHSHIELD_BUFF_RANK1 = 974
local SPELLID_SHAMAN_EARTHSHIELD_BUFF_RANK2 = 32593
local SPELLID_SHAMAN_EARTHSHIELD_BUFF_RANK3 = 32594
local SHAMAN_EARTHSHIELD_BUFF = {
[SPELLID_SHAMAN_EARTHSHIELD_BUFF_RANK1] = true,
[SPELLID_SHAMAN_EARTHSHIELD_BUFF_RANK2] = true,
[SPELLID_SHAMAN_EARTHSHIELD_BUFF_RANK3] = true,
}
3 years ago
--holy priest prayer of mending (bcc)
local SPELLID_PRIEST_POM_BUFF = 41635
local SPELLID_PRIEST_POM_HEAL = 33110
local SPELLID_SANGUINE_HEAL = 226510
3 years ago
--spells with special treatment
local special_damage_spells = {
[98021] = true, --spirit link toten
[124255] = true, --stagger
[282449] = true, --akaari's soul rogue
[196917] = true, --light of the martyr
[388009] = true, --blessing of spring
[388012] = true, --blessing of summer
[384601] = true, --Anti Magic Bomb
[392171] = true, --Rose of the Vale
[392166] = true, --Azure Stone of Might
[379020] = true, --Wand of Negation
[372824] = true, --Burning Chains
[469704] = true, --Tempered in Battle (Acts like Spirit Link, paladin hero talent)
4 years ago
}
3 years ago
--damage spells to ignore
local damage_spells_to_ignore = {
--the damage that the warlock apply to its pet through soullink is ignored
--it is not useful for damage done or friendly fire
[SPELLID_WARLOCK_SOULLINK] = true,
6 months ago
[74040] = true, --grim batol drake
[457658] = true, --grim batol drake
[467230] = true, --11.1 raid blaze of glory
[465741] = true, --11.1 raid garbage dump
[1246948] = true, --11.2 raid Shooting Star
}
3 years ago
--expose the ignore spells table to external scripts
Details.SpellsToIgnore = damage_spells_to_ignore
3 years ago
--is parser allowed to replace spellIDs?
local is_using_spellId_override = false
--cache data for fast access during parsing
local _in_combat = false
local _current_encounter_id
local _in_resting_zone = false
local _global_combat_counter = 0
6 months ago
local _parser_options = {}
3 years ago
---amount of events allowed to store in the table which records the latest events that happened to a player before his death, this value can also be retrieved with Details.deadlog_events
local _amount_of_last_events = 16
3 years ago
--map type
local _is_in_instance = false
3 years ago
--hooks
local _hook_cooldowns = false
local _hook_deaths = false
local _hook_battleress = false
local _hook_interrupt = false
3 years ago
local _hook_cooldowns_container = Details.hooks ["HOOK_COOLDOWN"]
local _hook_deaths_container = Details.hooks ["HOOK_DEATH"]
local _hook_battleress_container = Details.hooks ["HOOK_BATTLERESS"]
local _hook_interrupt_container = Details.hooks ["HOOK_INTERRUPT"]
3 years ago
--regen overflow
local auto_regen_power_specs = {
[103] = Enum.PowerType.Energy, --druid feral
[259] = Enum.PowerType.Energy, --rogue ass
[260] = Enum.PowerType.Energy, --rogue outlaw
[261] = Enum.PowerType.Energy, --rogue sub
[254] = Enum.PowerType.Focus, --hunter mm
[253] = Enum.PowerType.Focus, --hunter bm
[255] = Enum.PowerType.Focus, --hunter survival
[268] = Enum.PowerType.Energy, --monk brewmaster
[269] = Enum.PowerType.Energy, --monk windwalker
}
local AUTO_REGEN_PRECISION = 2 --todo: replace the amount of wasted resource by the amount of time the player "sitted" at max power
3 years ago
--cache a spellName and the value is the spellId
--the container actor will use this name to create a fake player actor where its name is the spellName and the specIcon is the spellIcon
4 years ago
Details.SpecialSpellActorsName = {}
--sanguine affix for m+
Details.SanguineHealActorName = GetSpellInfo(SPELLID_SANGUINE_HEAL)
if (not isCLASSIC) then
if (Details.SanguineHealActorName) then
Details.SpecialSpellActorsName[Details.SanguineHealActorName] = SPELLID_SANGUINE_HEAL
end
end
--Damage spells that trigger outside of combat, which we don't want to have start a combat.
--387846 Fel Armor
--352561 Undulating Maneuvers
--111400 warlock's burning rush
--368637 is buff from trinket "Scars of Fraternal Strife" which make the player bleed even out-of-combat
--371070 is "Iced Phial of Corrupting Rage" effect triggers randomly, even out-of-combat
--401394 is "Vessel of Seared Shadows" trinket
--146739 is corruption that doesn't expire
local spells_cant_start_combat = {
[368637] = true, --The Third Rune
[371070] = true, --Rotting from Within
[146739] = true, --Corruption
[387846] = true, --Fel Armor
[352561] = true, --Undulating Maneuvers
[401394] = true, --Unstable Flames
[111400] = true, --Burning Rush
[12654] = true, --Ignite
[419800] = true, --Intensifying Flame
[448744] = true, --Authority of Radiant Power
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--internal functions
-----------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--DAMAGE serach key: ~damage |
-----------------------------------------------------------------------------------------------------------------------------------------
local whoAggro = function(self)
if ((Details.LastPullMsg or 0) + 30 > time()) then
Details.WhoAggroTimer = nil
return
end
Details.LastPullMsg = time()
local hitLine = self.HitBy or "|cFFFFBB00First Hit|r: *?*"
local targetLine = ""
3 years ago
if (Details.bossTargetAtPull) then
targetLine = " |cFFFFBB00Boss First Target|r: " .. Details.bossTargetAtPull
else
for i = 1, 5 do
local boss = UnitExists("boss" .. i)
if (boss) then
local target = UnitName ("boss" .. i .. "target")
if (target and type(target) == "string") then
targetLine = " |cFFFFBB00Boss First Target|r: " .. target
break
end
end
end
end
3 years ago
Details:Msg(hitLine .. targetLine)
Details.WhoAggroTimer = nil
Details.bossTargetAtPull = nil
end
3 years ago
local lastRecordFound = {id = 0, diff = 0, combatTime = 0}
3 years ago
Details.PrintEncounterRecord = function(self)
3 years ago
--this block won't execute if the storage isn't loaded
--self is a timer reference from C_Timer
local diffNumberToName = Details222.storage.DiffIdToName
local encounterID = self.Boss
local diff = self.Diff
3 years ago
if (diff == 15 or diff == 16) then --might give errors
local value, rank, combatTime = 0, 0, 0
3 years ago
if (encounterID == lastRecordFound.id and diff == lastRecordFound.diff) then
3 years ago
--is the same encounter, no need to find the value again.
value, rank, combatTime = lastRecordFound.value, lastRecordFound.rank, lastRecordFound.combatTime
else
local db = Details.GetStorage()
3 years ago
local role = _UnitGroupRolesAssigned("player")
local isDamage = (role == "DAMAGER") or (role == "TANK") --or true
---@type details_storage_unitresult, details_encounterkillinfo
local bestRank, encounterTable = Details222.storage.GetBestFromPlayer(diffNumberToName[diff], encounterID, isDamage and "DAMAGER" or "HEALER", Details.playername, true)
3 years ago
if (bestRank) then
---@type number
local rankPosition = Details222.storage.GetUnitGuildRank(diffNumberToName[diff], encounterID, isDamage and "DAMAGER" or "HEALER", Details.playername, true)
value = bestRank.total or 0
rank = rankPosition or 0
combatTime = encounterTable.elapsed
3 years ago
--if found the result, cache the values so no need to search again next pull
lastRecordFound.value = value
lastRecordFound.rank = rank
lastRecordFound.id = encounterID
lastRecordFound.diff = diff
lastRecordFound.combatTime = combatTime
else
3 years ago
--if didn't found, no reason to search again on next pull
lastRecordFound.value = 0
lastRecordFound.rank = 0
lastRecordFound.combatTime = 0
lastRecordFound.id = encounterID
lastRecordFound.diff = diff
end
end
3 years ago
4 years ago
if (value and combatTime and value > 0 and combatTime > 0) then
Details:Msg("|cFFFFBB00Your Best Score|r:", Details:ToK2 ((value) / combatTime) .. " [|cFFFFFF00Guild Rank: " .. rank .. "|r]") --localize-me
4 years ago
end
3 years ago
if ((not combatTime or combatTime == 0) and not Details.SyncWarning) then
Details:Msg("|cFFFF3300you may need sync the rank within the guild, type '|cFFFFFF00/details rank|r'|r") --localize-me
Details.SyncWarning = true
end
end
3 years ago
end
--~spell ~spelldamage
function parser:spell_dmg(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetRaidFlags, spellId, spellName, spellType, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand, isreflected)
3 years ago
--early checks and fixes
if (sourceSerial == "") then
if (sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_PETS) ~= 0) then
3 years ago
--pets must have a serial
return
end
end
--melee
if (token == "SWING_DAMAGE") then
spellId, spellName, spellType, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand = 1, meleeString, 00000001, spellId, spellName, spellType, amount, overkill, school, resisted, blocked, absorbed, critical
end
3 years ago
if (not targetName) then
--no target name, just quit
return
elseif (not sourceName) then
--no actor name, use spell name instead
sourceName = names_cache[spellName]
if (not sourceName) then
sourceName = "[*] " .. spellName
names_cache[spellName] = sourceName
end
sourceFlags = 0xa48
sourceSerial = ""
end
--check if the spell is in the backlist and return if true
if (damage_spells_to_ignore[spellId]) then
return
end
--> spell reflection code by github user @m4tjz
if (sourceSerial == targetSerial and not reflection_ignore[spellId]) then --~reflect
--this spell could've been reflected, check it
if (reflection_events[sourceSerial] and reflection_events[sourceSerial][spellId] and time-reflection_events[sourceSerial][spellId].time > 3.5 and (not reflection_debuffs[sourceSerial] or (reflection_debuffs[sourceSerial] and not reflection_debuffs[sourceSerial][spellId]))) then
--here we check if we have to filter old reflection data
--we check for two conditions
--the first is to see if this is an old reflection
--if more than 3.5 seconds have past then we can say that it is old... but!
--the second condition is to see if there is an active debuff with the same spellid
--if there is one then we ignore the timer and skip this
--this should be cleared afterwards somehow... don't know how...
reflection_events[sourceSerial][spellId] = nil
if (next(reflection_events[sourceSerial]) == nil) then
--there should be some better way of handling this kind of filtering, any suggestion?
reflection_events[sourceSerial] = nil
end
end
local reflection = reflection_events[sourceSerial] and reflection_events[sourceSerial][spellId]
if (reflection) then
--if we still have the reflection data then we conclude it was reflected
--extend the duration of the timer to catch the rare channelling spells
reflection_events[sourceSerial][spellId].time = time
3 years ago
--crediting the source of the reflection aura
sourceSerial = reflection.who_serial
sourceName = reflection.who_name
sourceFlags = reflection.who_flags
3 years ago
--data of the aura that caused the reflection
isreflected = spellId --which spell was reflected
spellId = reflection.spellid --which spell made the reflection
spellName = reflection.spellname
spellType = reflection.spelltype
3 years ago
return parser:spell_dmg(token,time,sourceSerial,sourceName,sourceFlags,targetSerial,targetName,targetFlags,targetRaidFlags,spellId,spellName,0x400,amount,-1,nil,nil,nil,nil,false,false,false,false, isreflected)
else
--saving information about this damage because it may occurred before a reflect event
reflection_damage[sourceSerial] = reflection_damage[sourceSerial] or {}
reflection_damage[sourceSerial][spellId] = {
amount = amount,
time = time,
}
end
end
--> if the parser are allowed to replace spellIDs
if (is_using_spellId_override) then
spellId = override_spellId[spellId] or spellId
end
6 months ago
if (spellId == bombardment_stuff.spellId) then
if (bombardment_stuff.only_one_scalecomander) then
sourceSerial, sourceName = bombardment_stuff.serial, bombardment_stuff.evoker_name
end
end
--> npcId check for ignored npcs
--> get the npcId from the cache, if it's not there then get it from the serial and add it to the cache
local npcId = npcid_cache[targetSerial] --target npc
if (not npcId) then
--this string manipulation is running on every event
6 months ago
--npcId = tonumber(select(6, strsplit("-", targetSerial)) or 0)
npcId = tonumber(targetSerial:match("^[^%-]*%-[^%-]*%-[^%-]*%-[^%-]*%-[^%-]*%-([^%-]*)"))
npcid_cache[targetSerial] = npcId
end
if (ignored_npcids[npcId]) then
return
end
npcId = npcid_cache[sourceSerial] --source npc
if (not npcId) then
npcId = tonumber(select(6, strsplit("-", sourceSerial)) or 0)
npcid_cache[sourceSerial] = npcId
end
if (ignored_npcids[npcId]) then
return
end
4 years ago
if (npcId == 24207) then --army of the dead
--check if this is a army or apoc pet
if (dk_pets_cache.army[sourceSerial]) then
local cachedName = names_cache[24207001]
if (not cachedName) then
sourceName = sourceName .. "|T237511:0|t"
names_cache[24207001] = sourceName
else
sourceName = cachedName
end
else
local cachedName = names_cache[24207002]
if (not cachedName) then
sourceName = sourceName .. "|T1392565:0|t"
names_cache[24207002] = sourceName
4 years ago
else
sourceName = cachedName
end
end
end
--check if the spellId has an especial treatment
if (special_damage_spells[spellId]) then
3 years ago
--stagger
if (spellId == 124255) then
return parser:MonkStagger_damage(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, spellId, spellName, spellType, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand)
3 years ago
--spirit link totem or tempered in battle
elseif (spellId == 98021 or spellId == 469704) then
return parser:SLT_damage(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, spellId, spellName, spellType, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand)
--rogue's secret technique | when akari's soul gives damage | dragonflight | --REMOVE ON 11.0 - maybe
elseif (spellId == 282449) then
--npcID
if (npcId == 144961) then
local ownerName, ownerGUID, ownerFlags = Details222.Pets.AkaarisSoulOwner(sourceSerial, sourceName)
if (ownerName and ownerGUID) then
sourceSerial = ownerGUID
sourceName = ownerName
sourceFlags = ownerFlags
end
end
3 years ago
--Light of the Martyr - paladin spell which causes damage to the caster it self
elseif (spellId == 196917) then -- or spellid == 183998 < healing part
return parser:LOTM_damage(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, spellId, spellName, spellType, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand)
elseif (spellId == 388009 or spellId == 388012) then --damage from the paladin blessings of the seasons
local blessingSource = cacheAnything.paladin_vivaldi_blessings[sourceSerial]
if (blessingSource) then
sourceSerial, sourceName, sourceFlags = unpack(blessingSource)
end
6 months ago
--elseif (Details.NeltharusWeaponSpellIds[spellId]) then
-- sourceName = Details.NeltharusWeaponActorName
-- sourceFlags = 0x514
-- sourceSerial = "Creature-0-3134-2289-28065-" .. spellId .. "-000164C698"
end
end
4 years ago
------------------------------------------------------------------------------------------------
--check if need start an combat
6 months ago
if (not Details.in_combat) then --~startcombat ~combatstart
if ( token ~= "SPELL_PERIODIC_DAMAGE" and
4 years ago
(
(sourceFlags and bitBand(sourceFlags, AFFILIATION_GROUP) ~= 0 and UnitAffectingCombat(sourceName)) --error here, need to remove the realm from sourceName
3 years ago
or
(targetFlags and bitBand(targetFlags, AFFILIATION_GROUP) ~= 0 and UnitAffectingCombat(targetName))
or
(not Details.in_group and sourceFlags and bitBand(sourceFlags, AFFILIATION_GROUP) ~= 0)
)
4 years ago
) then
if (spells_cant_start_combat[spellId] and sourceName == Details.playername) then
return
end
if (Details.encounter_table.id and Details.encounter_table["start"] >= GetTime() - 3 and Details.announce_firsthit.enabled) then
local link = _GetSpellInfo(spellId) --Removed check for the id being <= 10, both branches were the same.
3 years ago
if (Details.WhoAggroTimer) then
Details.WhoAggroTimer:Cancel()
end
3 years ago
Details.WhoAggroTimer = C_Timer.NewTimer(0.1, whoAggro)
Details.WhoAggroTimer.HitBy = "|cFFFFFF00First Hit|r: " .. (link or "") .. " from " .. (sourceName or "Unknown")
if (Details.announce_firsthit.enabled) then
Details:Msg("", Details.WhoAggroTimer.HitBy)
end
end
3 years ago
--local spellInfo = C_Spell.GetSpellInfo(spellId)
Details222.StartCombat(sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags)
else
3 years ago
--entrar em combate se for dot e for do jogador e o ultimo combate ter sido a mais de 10 segundos atr�s
if (token == "SPELL_PERIODIC_DAMAGE" and sourceName == Details.playername) then
if (spells_cant_start_combat[spellId]) then
return
end
3 years ago
--can't start a combat with a dot with the latest combat finished less than 10 seconds ago
if (Details.last_combat_time + 10 < _tempo) then
Details222.StartCombat(sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags)
end
end
end
end
3 years ago
--[[statistics]]-- _detalhes.statistics.damage_calls = _detalhes.statistics.damage_calls + 1
_current_damage_container.need_refresh = true
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--get actors
---@type actor, actor
local sourceActor, ownerActor = damage_cache[sourceSerial] or damage_cache_pets[sourceSerial] or damage_cache[sourceName], damage_cache_petsOwners[sourceSerial]
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_damage_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
3 years ago
if (ownerActor) then --the actor is a pet
if (sourceSerial ~= "") then
--insert in the pet cache
damage_cache_pets[sourceSerial] = sourceActor
damage_cache_petsOwners[sourceSerial] = ownerActor
end
--check if the pet owner is already in the cache
if (not damage_cache[ownerActor.serial] and ownerActor.serial ~= "") then
damage_cache[ownerActor.serial] = ownerActor
end
if (ownerActor) then
if (Details222.Debug.DebugPets) then
Details:Msg("Parser|DebugPets|ActorCreated|PetName:", sourceActor:Name(), "sourceName:", sourceName, "ownerName:", ownerActor:Name())
elseif (Details222.Debug.DebugPlayerPets and sourceName == Details.playername) then
Details:Msg("Parser|DebugPets|ActorCreated|PetName:", sourceActor:Name(), "sourceName:", sourceName, "ownerName:", ownerActor:Name())
end
end
else
--there's no owner actor
if (sourceFlags) then
if (sourceSerial ~= "") then
--insert the sourceActor into the cache
damage_cache[sourceSerial] = sourceActor
else
if (names_cache[spellName]) then
damage_cache[sourceName] = sourceActor
local _, _, spellIcon = _GetSpellInfo(spellId or 1)
sourceActor.spellicon = spellIcon
end
end
end
end
3 years ago
--if a owner actor isn't found and debug pets is enabled and this is a pet or guardian
if (not ownerActor and (Details222.Debug.DebugPets or Details222.Debug.DebugPlayerPets) and bitBand(sourceFlags, 0x00003000) ~= 0) then --OBJECT_TYPE_PETGUARDIAN
--note: the actor wasn't found in the cache and got created
Details:Msg("DebugPets|Parser|Owner Actor Not Found|", sourceName, sourceSerial, sourceFlags, bitBand(sourceFlags, 0x00003000) ~= 0)
---@type petdata?
local petData = petContainer.GetPetInfo(sourceSerial)
if (sourceName == "Fire Spirit") then
Details:Msg("DebugPets|Parser|PetData|Exists?", petData, sourceName, "Dumping petData on dumpt.")
dumpt(petData)
end
end
elseif (ownerActor) then --has (sourceActor and ownerActor)
--sourceName is the name of the pet
local cachedPetName = names_cache[sourceSerial]
if (not cachedPetName) then
--add the owner name into the sourceName
sourceName = sourceName .. " <" .. ownerActor.nome .. ">"
names_cache[sourceSerial] = sourceName
else
sourceName = cachedPetName
end
end
if (not sourceActor) then
return
end
4 years ago
---@type actor, actor
local targetActor, targetOwner = damage_cache[targetSerial] or damage_cache_pets[targetSerial] or damage_cache[targetName], damage_cache_petsOwners[targetSerial]
3 years ago
if (not targetActor) then
targetActor, targetOwner, targetName = _current_damage_container:GetOrCreateActor(targetSerial, targetName, targetFlags, true)
if (targetOwner) then
if (targetSerial ~= "") then
--insert in the pet cache
damage_cache_pets[targetSerial] = targetActor
damage_cache_petsOwners[targetSerial] = targetOwner
end
--check if the pet owner is already in the cache
if (not damage_cache[targetOwner.serial] and targetOwner.serial ~= "") then
damage_cache[targetOwner.serial] = targetOwner
end
else
if (targetFlags and targetSerial ~= "") then --ter certeza que n�o � um pet
damage_cache [targetSerial] = targetActor
end
end
3 years ago
elseif (targetOwner) then
--sourceName is the name of the pet
local cachedPetName = names_cache[targetSerial]
if (not cachedPetName) then
--add the owner name into the sourceName
targetName = targetName .. " <" .. targetOwner.nome .. ">"
names_cache[targetSerial] = targetName
else
targetName = cachedPetName
end
end
if (not targetActor) then
local instanceName, _, _, _, _, _, _, instanceId = GetInstanceInfo()
Details:Msg("D! Report 0x885488", targetName, instanceName, instanceId, damage_cache[targetSerial] and "true")
return
end
3 years ago
--last event
sourceActor.last_event = _tempo
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--group checks and avoidance
6 months ago
local healthChange = amount
if (absorbed) then
amount = absorbed + (amount or 0)
end
if (_is_in_instance) then
if (overkill and overkill > 0) then
4 years ago
overkill = overkill + 1
--if enabled it'll cut the amount of overkill from the last hit (which killed the actor)
--when disabled it'll show the total damage done for the latest hit
4 years ago
amount = amount - overkill
end
end
6 months ago
if ((sourceActor.grupo or (sourceActor.owner and sourceActor.owner.grupo)) and not sourceActor.arena_enemy and not sourceActor.enemy and not targetActor.arena_enemy) then --source = friendly player/pet and not an enemy player
--dano to adversario estava caindo aqui por nao estar checando .enemy
_current_gtotal[1] = _current_gtotal[1] + amount
elseif (targetActor.grupo) then --source = arena enemy or friendly player
if (targetActor.arena_enemy) then
_current_gtotal[1] = _current_gtotal[1] + amount
end
6 months ago
if (tanks_members_cache[targetSerial] and targetActor.classe == "MONK") then
if (absorbed) then
--the absorbed amount was staggered and should not be count as damage taken now
--this absorbed will hit the player with the stagger debuff
amount = (amount or 0) - absorbed
end
end
3 years ago
--record avoidance only for tank actors
6 months ago
if (_parser_options.tank_avoidance and tanks_members_cache[targetSerial]) then
--advanced damage taken
--if advanced damage taken is enabled, the damage taken to tanks acts like the monk stuff above
if (Details.damage_taken_everything and targetActor.classe ~= "MONK") then
if (absorbed) then
amount = (amount or 0) - absorbed
end
end
3 years ago
--avoidance
local avoidance = targetActor.avoidance
if (not avoidance) then
targetActor.avoidance = Details:CreateActorAvoidanceTable()
avoidance = targetActor.avoidance
end
3 years ago
local overall = avoidance.overall
local mob = avoidance[sourceName]
3 years ago
if (not mob) then --if isn't in the table, build on the fly
mob = Details:CreateActorAvoidanceTable(true)
avoidance[sourceName] = mob
3 years ago
end
overall["ALL"] = overall["ALL"] + 1 --qualtipo de hit ou absorb
mob["ALL"] = mob["ALL"] + 1 --qualtipo de hit ou absorb
3 years ago
if (not isERA and spellId < 3) then
3 years ago
--overall
overall["HITS"] = overall["HITS"] + 1
mob["HITS"] = mob["HITS"] + 1
end
3 years ago
if (blocked and blocked > 0) then
overall["BLOCKED_HITS"] = overall["BLOCKED_HITS"] + 1
mob["BLOCKED_HITS"] = mob["BLOCKED_HITS"] + 1
overall["BLOCKED_AMT"] = overall["BLOCKED_AMT"] + blocked
mob["BLOCKED_AMT"] = mob["BLOCKED_AMT"] + blocked
end
3 years ago
--absorbs status
if (absorbed) then
3 years ago
--aqui pode ser apenas absorb parcial
overall["ABSORB"] = overall["ABSORB"] + 1
overall["PARTIAL_ABSORBED"] = overall["PARTIAL_ABSORBED"] + 1
overall["PARTIAL_ABSORB_AMT"] = overall["PARTIAL_ABSORB_AMT"] + absorbed
overall["ABSORB_AMT"] = overall["ABSORB_AMT"] + absorbed
mob["ABSORB"] = mob["ABSORB"] + 1
mob["PARTIAL_ABSORBED"] = mob["PARTIAL_ABSORBED"] + 1
mob["PARTIAL_ABSORB_AMT"] = mob["PARTIAL_ABSORB_AMT"] + absorbed
mob["ABSORB_AMT"] = mob["ABSORB_AMT"] + absorbed
else
--add aos hits sem absorbs
overall["FULL_HIT"] = overall["FULL_HIT"] + 1
overall["FULL_HIT_AMT"] = overall["FULL_HIT_AMT"] + amount
mob["FULL_HIT"] = mob["FULL_HIT"] + 1
mob["FULL_HIT_AMT"] = mob["FULL_HIT_AMT"] + amount
end
end
3 years ago
6 months ago
if (Details.HealthCache[targetSerial]) then --if the check passes, it is guaranteed to be a player character
--record death log
---local ttt = debugprofilestop()
3 years ago
6 months ago
local actorLatestEvents = last_events_cache[targetName]
if (not actorLatestEvents) then
actorLatestEvents = _current_combat:CreateLastEventsTable(targetName)
end
6 months ago
Details.HealthCache[targetSerial] = Details.HealthCache[targetSerial] - healthChange
if (Details.HealthCache[targetSerial] < 0) then
Details.HealthCache[targetSerial] = 0
end
6 months ago
local i = actorLatestEvents.n
6 months ago
local thisEvent = actorLatestEvents[i]
thisEvent[1] = true --true if this is a damage || false for healing
thisEvent[2] = spellId --spellid || false if this is a battle ress line
thisEvent[3] = amount --amount of damage or healing
thisEvent[4] = time --parser time
--current unit healh
if (targetActor.arena_enemy) then
--this is an arena enemy, get the heal with the unit Id
local unitId = Details.arena_enemies[targetName]
if (not unitId) then
unitId = Details:GuessArenaEnemyUnitId(targetName)
end
if (unitId) then
local maxHealth = max(UnitHealthMax(unitId), SMALL_FLOAT)
thisEvent[5] = UnitHealth(unitId) / maxHealth
else
thisEvent[5] = cacheAnything.arenaHealth[targetName] or 100000
end
6 months ago
cacheAnything.arenaHealth[targetName] = thisEvent[5]
else
6 months ago
thisEvent[5] = Details.HealthCache[targetSerial] / Details.HealthMaxCache[targetSerial]
end
6 months ago
thisEvent[6] = sourceName --source name
thisEvent[7] = absorbed
thisEvent[8] = spellType or school
thisEvent[9] = false
thisEvent[10] = overkill
thisEvent[11] = critical
thisEvent[12] = crushing
3 years ago
6 months ago
i = i + 1
6 months ago
if (i == _amount_of_last_events + 1) then
actorLatestEvents.n = 1
else
actorLatestEvents.n = i
end
end
end
3 years ago
------------------------------------------------------------------------------------------------
--~activity time
if (not sourceActor.dps_started) then
--register on time machine
sourceActor:GetOrChangeActivityStatus(true)
if (ownerActor and not ownerActor.dps_started) then
ownerActor:GetOrChangeActivityStatus(true)
if (ownerActor.end_time) then
ownerActor.end_time = nil
else
ownerActor.start_time = _tempo
end
end
3 years ago
if (sourceActor.end_time) then
sourceActor.end_time = nil
else
sourceActor.start_time = _tempo
end
--'player'
if (sourceActor.nome == Details.playername and token ~= "SPELL_PERIODIC_DAMAGE") then
3 years ago
if (UnitAffectingCombat("player")) then
Details:SendEvent("COMBAT_PLAYER_TIMESTARTED", nil, _current_combat, sourceActor)
end
end
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--firendly fire ~friendlyfire
local is_friendly_fire = false
3 years ago
if (_is_in_instance) then
local npcId = npcid_cache[targetSerial]
if (npcId ~= 207341) then
if (bitfield_swap_cache [sourceSerial] or ownerActor and bitfield_swap_cache [ownerActor.serial]) then
if (targetActor.grupo or targetOwner and targetOwner.grupo) then
is_friendly_fire = true
end
else
if (bitfield_swap_cache [targetSerial] or targetOwner and bitfield_swap_cache [targetOwner.serial]) then
else
--Astral Nova explosion from Astral Bomb (Spectral Invoker - Algeth'ar Academy) should get friend zone here
if ((targetActor.grupo or targetOwner and targetOwner.grupo) and (sourceActor.grupo or ownerActor and ownerActor.grupo)) then
is_friendly_fire = true
end
end
end
end
else
if (
(bitBand(targetFlags, REACTION_FRIENDLY) ~= 0 and bitBand(sourceFlags, REACTION_FRIENDLY) ~= 0) or --ajdt d' brx
(raid_members_cache [targetSerial] and raid_members_cache [sourceSerial] and targetSerial:find("Player") and sourceSerial:find("Player")) --amrl
) then
is_friendly_fire = true
end
end
3 years ago
6 months ago
--double check for Astral Nova explosion (only inside AA dungeon, dragonflight)
--if (spellId == 387848 and not is_friendly_fire) then
-- if ((targetActor.grupo or targetOwner and targetOwner.grupo) and (sourceActor.grupo or ownerActor and ownerActor.grupo)) then
-- is_friendly_fire = true
-- end
--end
if (is_friendly_fire) then
if (sourceActor.grupo) then --se tiver ele n�o adiciona o evento l� em cima
local t = last_events_cache[targetName]
3 years ago
if (not t) then
t = _current_combat:CreateLastEventsTable(targetName)
end
3 years ago
local i = t.n
local thisEvent = t [i]
thisEvent[1] = true --true if this is a damage || false for healing
thisEvent[2] = spellId --spellid || false if this is a battle ress line
thisEvent[3] = amount --amount of damage or healing
thisEvent[4] = time --parser time
thisEvent[5] = UnitHealth(targetName) / max(UnitHealthMax(targetName), SMALL_FLOAT) --current unit heal
thisEvent[6] = sourceName --source name
thisEvent[7] = absorbed
thisEvent[8] = spellType or school
thisEvent[9] = true
thisEvent[10] = overkill
i = i + 1
3 years ago
if (i == _amount_of_last_events+1) then
t.n = 1
else
t.n = i
end
end
sourceActor.friendlyfire_total = sourceActor.friendlyfire_total + amount
3 years ago
local friend = sourceActor.friendlyfire[targetName] or sourceActor:CreateFFTable(targetName)
friend.total = friend.total + amount
friend.spells[spellId] = (friend.spells[spellId] or 0) + amount
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--damage taken
--target
targetActor.damage_taken = targetActor.damage_taken + amount - (absorbed or 0) --adiciona o dano tomado
if (not targetActor.damage_from[sourceName]) then --adiciona a pool de dano tomado de quem
targetActor.damage_from[sourceName] = true
end
return true
else
_current_total[1] = _current_total[1] + amount
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--damage taken
--target
targetActor.damage_taken = targetActor.damage_taken + amount --adiciona o dano tomado
if (not targetActor.damage_from[sourceName]) then --adiciona a pool de dano tomado de quem
targetActor.damage_from[sourceName] = true
end
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--amount add
--~roskash - augmentation evoker damage buff
if (augmentation_cache.ebon_might[sourceSerial] or (ownerActor and augmentation_cache.ebon_might[ownerActor.serial])) then
--get the serial number of the player who did the damage, in case of a pet or minion use the owner serial
local thisSourceSerial = (augmentation_cache.ebon_might[sourceSerial] and sourceSerial) or ownerActor.serial
---actor buffed with ebonmight -> list of evokers whose buffed
---@type table<serial, evokerinfo[]>
local evokersWhoBuffedThisPlayer = augmentation_cache.ebon_might[thisSourceSerial]
for i, evokerInfo in ipairs(evokersWhoBuffedThisPlayer) do
---@cast evokerInfo evokerinfo
---@type serial, actorname, controlflags
local evokerSourceSerial, evokerSourceName, evokerSourceFlags, attributedGained = unpack(evokerInfo)
if (evokerSourceSerial ~= thisSourceSerial) then
---@type actor
local evokerActor = damage_cache[evokerSourceSerial]
if (not evokerActor) then
evokerActor = _current_damage_container:GetOrCreateActor(evokerSourceSerial, evokerSourceName, evokerSourceFlags, true)
end
if (evokerActor) then
local extraSpellId = 395152
evokerActor.augmentedSpellsContainer = evokerActor.augmentedSpellsContainer or spellContainerClass:CreateSpellContainer(Details.container_type.CONTAINER_DAMAGE_CLASS)
local augmentedSpell = evokerActor.augmentedSpellsContainer._ActorTable[extraSpellId]
if (not augmentedSpell) then
augmentedSpell = evokerActor.augmentedSpellsContainer:GetOrCreateSpell(extraSpellId, true, token)
end
--> calculate tier and ilevel bonuses; this values could be cached at the start of the combat
--local bHasFourPieces = gearCache[evokerSourceSerial] and gearCache[evokerSourceSerial].tierAmount >= 4
local tierPieceMultiplier = 1 --bHasFourPieces and 1.08 or 1
local evokerItemLevel = gearCache[evokerSourceSerial] and gearCache[evokerSourceSerial].ilevel or 400
evokerItemLevel = max(evokerItemLevel, 400)
local itemLevelMultiplier = 1 -- + ((evokerItemLevel - 400) * 0.006)
local predictedAmount = 0
if (Details.zone_type == "raid") then --0x410b
predictedAmount = amount * (0.06947705 * tierPieceMultiplier * itemLevelMultiplier)
else
predictedAmount = amount * (0.07590444 * tierPieceMultiplier * itemLevelMultiplier)
end
--local damageSpellName = GetSpellInfo(spellId)
--print("EbonMight Cache:", Details.augmentation_cache, evokerSourceSerial, floor(amount), floor(predictedAmount), floor(predictedAmount/amount*100) .. "%", damageSpellName)
evokerActor.total_extra = evokerActor.total_extra + predictedAmount
augmentedSpell.total = augmentedSpell.total + predictedAmount
augmentedSpell.targets[sourceName] = (augmentedSpell.targets[sourceName] or 0) + predictedAmount
if (Details.debug) then
DetailsParserDebugFrame:BlinkIcon(extraSpellId, 1)
DetailsParserDebugFrame.AllTexts[1]:SetText("Evokers Buffed: " .. #evokersWhoBuffedThisPlayer .. " (" .. floor(predictedAmount / amount * 100) .. "%)")
end
end
end
end
end
if (augmentation_cache.ss[sourceSerial] or (ownerActor and augmentation_cache.ss[ownerActor.serial])) then --actor buffed with ss
--get the serial number of the player who did the damage, in case of a pet or minion use the owner serial
local thisSourceSerial = augmentation_cache.ss[sourceSerial] and sourceSerial or ownerActor.serial
---@type table<serial, evokerinfo[]>
local currentlyBuffedWithSS = augmentation_cache.ss[thisSourceSerial]
for i, evokerInfo in ipairs(currentlyBuffedWithSS) do
---@cast evokerInfo evokerinfo
---@type serial, actorname, controlflags
local evokerSourceSerial, evokerSourceName, evokerSourceFlags, versaBuff = unpack(evokerInfo)
if (evokerSourceSerial ~= thisSourceSerial) then
---@type actor
local evokerActor = damage_cache[evokerSourceSerial]
if (not evokerActor) then
evokerActor = _current_damage_container:GetOrCreateActor(evokerSourceSerial, evokerSourceName, evokerSourceFlags, true)
end
if (evokerActor) then
local extraSpellId = 413984
evokerActor.augmentedSpellsContainer = evokerActor.augmentedSpellsContainer or spellContainerClass:CreateSpellContainer(Details.container_type.CONTAINER_DAMAGE_CLASS)
local augmentedSpell = evokerActor.augmentedSpellsContainer._ActorTable[extraSpellId]
if (not augmentedSpell) then
augmentedSpell = evokerActor.augmentedSpellsContainer:GetOrCreateSpell(extraSpellId, true, token)
end
versaBuff = versaBuff / 100
local predictedAmount = amount * versaBuff * 0.73548755 --0x410f
evokerActor.total_extra = evokerActor.total_extra + predictedAmount
augmentedSpell.total = augmentedSpell.total + predictedAmount
augmentedSpell.targets[sourceName] = (augmentedSpell.targets[sourceName] or 0) + predictedAmount
if (Details.debug) then
--DetailsParserDebugFrame:BlinkIcon(extraSpellId, 2)
end
end
end
end
end
if (spellId == 360828 and augmentation_cache.shield[sourceSerial]) then --shield
---actor buffed with the shield -> list of evokers whose buffed
---@type table<serial, evokerinfo[]>
local currentlyBuffedWithShield = augmentation_cache.shield[sourceSerial]
for i, evokerInfo in ipairs(currentlyBuffedWithShield) do
---@cast evokerInfo evokerinfo
---@type serial, actorname, controlflags
local evokerSourceSerial, evokerSourceName, evokerSourceFlags = unpack(evokerInfo)
if (evokerSourceSerial ~= sourceSerial) then
---@type actor
local evokerActor = damage_cache[evokerSourceSerial]
if (not evokerActor) then
evokerActor = _current_damage_container:GetOrCreateActor(evokerSourceSerial, evokerSourceName, evokerSourceFlags, true)
end
if (evokerActor) then
local extraSpellId = 360828
evokerActor.augmentedSpellsContainer = evokerActor.augmentedSpellsContainer or spellContainerClass:CreateSpellContainer(Details.container_type.CONTAINER_DAMAGE_CLASS)
local augmentedSpell = evokerActor.augmentedSpellsContainer._ActorTable[extraSpellId]
if (not augmentedSpell) then
augmentedSpell = evokerActor.augmentedSpellsContainer:GetOrCreateSpell(extraSpellId, true, token)
end
local damageSplitted = amount / #currentlyBuffedWithShield
evokerActor.total_extra = evokerActor.total_extra + damageSplitted
augmentedSpell.total = augmentedSpell.total + damageSplitted
augmentedSpell.targets[sourceName] = (augmentedSpell.targets[sourceName] or 0) + damageSplitted
if (Details.debug) then
--DetailsParserDebugFrame:BlinkIcon(extraSpellId, 3)
end
end
end
end
end
if (spellId == 404908 and augmentation_cache.prescience[sourceSerial]) then --fate mirror
---actor buffed with prescience -> list of evokers whose buffed
---@type table<serial, evokerinfo[]>
local currentlyBuffedWithPrescience = augmentation_cache.prescience[sourceSerial]
for i, evokerInfo in ipairs(currentlyBuffedWithPrescience) do
---@cast evokerInfo evokerinfo
---@type serial, actorname, controlflags
local evokerSourceSerial, evokerSourceName, evokerSourceFlags = unpack(evokerInfo)
if (evokerSourceSerial ~= sourceSerial) then
---@type actor
local evokerActor = damage_cache[evokerSourceSerial]
if (not evokerActor) then
evokerActor = _current_damage_container:GetOrCreateActor(evokerSourceSerial, evokerSourceName, evokerSourceFlags, true)
end
if (evokerActor) then
local extraSpellId = 404908
evokerActor.augmentedSpellsContainer = evokerActor.augmentedSpellsContainer or spellContainerClass:CreateSpellContainer(Details.container_type.CONTAINER_DAMAGE_CLASS)
local augmentedSpell = evokerActor.augmentedSpellsContainer._ActorTable[extraSpellId]
if (not augmentedSpell) then
augmentedSpell = evokerActor.augmentedSpellsContainer:GetOrCreateSpell(extraSpellId, true, token)
end
local fateMirror_plus_Prescience = amount + amount * 0.58782001
evokerActor.total_extra = evokerActor.total_extra + fateMirror_plus_Prescience
augmentedSpell.total = augmentedSpell.total + fateMirror_plus_Prescience
augmentedSpell.targets[sourceName] = (augmentedSpell.targets[sourceName] or 0) + fateMirror_plus_Prescience
if (Details.debug) then
--DetailsParserDebugFrame:BlinkIcon(extraSpellId, 4)
end
end
end
end
end
if (spellId == 410265 and augmentation_cache.infernobless[sourceSerial]) then
---@type table<serial, evokerinfo[]>
local currentlyBuffedWithInfernoBless = augmentation_cache.infernobless[sourceSerial]
for i, evokerInfo in ipairs(currentlyBuffedWithInfernoBless) do
---@cast evokerInfo evokerinfo
---@type serial, actorname, controlflags
local evokerSourceSerial, evokerSourceName, evokerSourceFlags = unpack(evokerInfo)
if (evokerSourceSerial ~= sourceSerial) then
---@type actor
local evokerActor = damage_cache[evokerSourceSerial]
if (not evokerActor) then
evokerActor = _current_damage_container:GetOrCreateActor(evokerSourceSerial, evokerSourceName, evokerSourceFlags, true)
end
if (evokerActor) then
local extraSpellId = 410265
evokerActor.augmentedSpellsContainer = evokerActor.augmentedSpellsContainer or spellContainerClass:CreateSpellContainer(Details.container_type.CONTAINER_DAMAGE_CLASS)
local augmentedSpell = evokerActor.augmentedSpellsContainer._ActorTable[extraSpellId]
if (not augmentedSpell) then
augmentedSpell = evokerActor.augmentedSpellsContainer:GetOrCreateSpell(extraSpellId, true, token)
end
evokerActor.total_extra = evokerActor.total_extra + amount
augmentedSpell.total = augmentedSpell.total + amount
augmentedSpell.targets[sourceName] = (augmentedSpell.targets[sourceName] or 0) + amount
if (Details.debug) then
--DetailsParserDebugFrame:BlinkIcon(extraSpellId, 5)
end
end
end
end
end
if (spellId == 409632) then
local breathTargets = augmentation_cache.breath_targets
---@type evokereonsbreathinfo[]
local evokerWithEonsApplications = breathTargets[targetSerial]
if (evokerWithEonsApplications) then
--this table consists in a list of evokers who applied eon's breath on the target
for i = 1, #evokerWithEonsApplications do
---@type evokereonsbreathinfo
local evokerInfo = evokerWithEonsApplications[i]
---@type guid, actorname, controlflags, unit, unixtime, auraduration, gametime
local evokerSerial, evokerName, evokerFlags, unitIDAffected, appliedTime, duration, expirationTime = unpack(evokerInfo)
if (evokerSerial ~= sourceSerial) then
if (detailsFramework:IsNearlyEqual(time, appliedTime + duration, 0.12)) then
---@type actor
local evokerActor = damage_cache[evokerSerial]
if (not evokerActor) then
evokerActor = _current_damage_container:GetOrCreateActor(evokerSerial, evokerName, evokerFlags, true)
end
if (evokerActor) then
local extraSpellId = 409632
evokerActor.augmentedSpellsContainer = evokerActor.augmentedSpellsContainer or spellContainerClass:CreateSpellContainer(Details.container_type.CONTAINER_DAMAGE_CLASS)
local augmentedSpell = evokerActor.augmentedSpellsContainer._ActorTable[extraSpellId]
if (not augmentedSpell) then
augmentedSpell = evokerActor.augmentedSpellsContainer:GetOrCreateSpell(extraSpellId, true, token)
end
evokerActor.total_extra = evokerActor.total_extra + amount
augmentedSpell.total = augmentedSpell.total + amount
augmentedSpell.targets[sourceName] = (augmentedSpell.targets[sourceName] or 0) + amount
end
end
end
end
end
end
3 years ago
--actor owner (if any)
6 months ago
targetRaidFlags = targetRaidFlags and bitBand(targetRaidFlags, COMBATLOG_OBJECT_RAIDTARGET_MASK)
if (ownerActor) then --se for dano de um Pet
ownerActor.total = ownerActor.total + amount --e adiciona o dano ao pet
3 years ago
--add owner targets
ownerActor.targets[targetName] = (ownerActor.targets[targetName] or 0) + amount
ownerActor.last_event = _tempo
3 years ago
if (RAID_TARGET_FLAGS[targetRaidFlags]) then
3 years ago
--add the amount done for the owner
ownerActor.raid_targets [targetRaidFlags] = (ownerActor.raid_targets [targetRaidFlags] or 0) + amount
end
end
3 years ago
--raid targets
if (RAID_TARGET_FLAGS[targetRaidFlags]) then
sourceActor.raid_targets[targetRaidFlags] = (sourceActor.raid_targets[targetRaidFlags] or 0) + amount
end
3 years ago
--actor
sourceActor.total = sourceActor.total + amount
3 years ago
--actor without pets
sourceActor.total_without_pet = sourceActor.total_without_pet + amount
3 years ago
--actor targets
sourceActor.targets[targetName] = (sourceActor.targets[targetName] or 0) + amount
3 years ago
--actor spells table
local spellTable = sourceActor.spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.spells:GetOrCreateSpell(spellId, true, token)
spellTable.spellschool = spellType or school
if (_current_combat.is_boss and sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_ENEMY) ~= 0) then
Details.spell_school_cache[spellName] = spellType or school
end
if (isreflected) then
spellTable.isReflection = true
end
end
3 years ago
--empowerment data
if (empower_cache[sourceSerial]) then
local empowerSpellInfo = empower_cache[sourceSerial][spellName]
if (empowerSpellInfo) then
if (not empowerSpellInfo.counted_healing) then
--total of empowerment
spellTable.e_total = (spellTable.e_total or 0) + empowerSpellInfo.empowerLevel --usado para calcular o average empowerment
--total amount of empowerment
spellTable.e_amt = (spellTable.e_amt or 0) + 1 --usado para calcular o average empowerment
--amount of casts on each level
spellTable.e_lvl = spellTable.e_lvl or {}
spellTable.e_lvl[empowerSpellInfo.empowerLevel] = (spellTable.e_lvl[empowerSpellInfo.empowerLevel] or 0) + 1
empowerSpellInfo.counted_healing = true
end
--damage bracket
spellTable.e_dmg = spellTable.e_dmg or {}
spellTable.e_dmg[empowerSpellInfo.empowerLevel] = (spellTable.e_dmg[empowerSpellInfo.empowerLevel] or 0) + amount
end
end
6 months ago
if (_trinket_data_cache[spellId] and Details.in_combat) then --~trinket
---@type trinketdata
local thisData = _trinket_data_cache[spellId]
if (thisData.lastCombatId == _global_combat_counter) then
if (thisData.lastPlayerName == sourceName) then
if (thisData.lastActivation < (time - 40)) then
local cooldownTime = time - thisData.lastActivation
thisData.totalCooldownTime = thisData.totalCooldownTime + cooldownTime
thisData.activations = thisData.activations + 1
thisData.lastActivation = time
thisData.averageTime = floor(thisData.totalCooldownTime / thisData.activations)
if (cooldownTime < thisData.minTime) then
thisData.minTime = cooldownTime
end
if (cooldownTime > thisData.maxTime) then
thisData.maxTime = cooldownTime
end
end
end
else
thisData.lastCombatId = _global_combat_counter
thisData.lastActivation = time
thisData.lastPlayerName = sourceName
end
if (_current_combat.trinketProcs) then
---@type table <actorname, trinketprocdata>
local playerTrinketData = _current_combat.trinketProcs[sourceName] or {}
_current_combat.trinketProcs[sourceName] = playerTrinketData
---@type trinketprocdata
local trinketData = playerTrinketData[spellId] or {cooldown = 0, total = 0}
playerTrinketData[spellId] = trinketData
if (trinketData.cooldown < time) then
trinketData.cooldown = time + 20
trinketData.total = trinketData.total + 1
end
end
end
3 years ago
return _spell_damage_func(spellTable, targetSerial, targetName, targetFlags, amount, sourceName, resisted, blocked, absorbed, critical, glacing, token, isoffhand, isreflected)
end
--special behavior for monk stagger debuff periodic damage
--using it as a separate function to avoid the overhead of checking if the spell is stagger on every damage event
function parser:MonkStagger_damage(token, time, sourceSerial, sourceName, sourceFlags, alvo_serial, alvo_name, alvo_flags, spellId, spellname, spelltype, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand)
3 years ago
--tag the container to refresh
_current_damage_container.need_refresh = true
3 years ago
--get the monk damage object
local sourceActor, ownerActor = damage_cache[sourceSerial] or damage_cache_pets[sourceSerial] or damage_cache[sourceName], damage_cache_petsOwners[sourceSerial]
3 years ago
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_damage_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (ownerActor) then --� um pet
if (sourceSerial ~= "") then
damage_cache_pets[sourceSerial] = sourceActor
damage_cache_petsOwners[sourceSerial] = ownerActor
end
--conferir se o dono j� esta no cache
if (not damage_cache[ownerActor.serial] and ownerActor.serial ~= "") then
damage_cache[ownerActor.serial] = ownerActor
end
else
if (sourceFlags) then --ter certeza que n�o � um pet
if (sourceSerial ~= "") then
damage_cache[sourceSerial] = sourceActor
else
if (sourceName:find("%[")) then --need to use the cache here
damage_cache[sourceName] = sourceActor
local _, _, icon = _GetSpellInfo(spellId or 1)
sourceActor.spellicon = icon
end
end
end
end
3 years ago
elseif (ownerActor) then --has (sourceActor and ownerActor)
--sourceName is the name of the pet
local cachedPetName = names_cache[sourceSerial]
if (not cachedPetName) then
--add the owner name into the sourceName
sourceName = sourceName .. " <" .. ownerActor.nome .. ">"
names_cache[sourceSerial] = sourceName
else
sourceName = cachedPetName
end
end
3 years ago
--last event
sourceActor.last_event = _tempo
3 years ago
--amount
amount = (amount or 0)
3 years ago
--damage taken
sourceActor.damage_taken = sourceActor.damage_taken + amount
if (not sourceActor.damage_from[sourceName]) then
sourceActor.damage_from[sourceName] = true
end
3 years ago
--friendly fire total
sourceActor.friendlyfire_total = sourceActor.friendlyfire_total + amount
--friendly fire from who
local friend = sourceActor.friendlyfire[sourceName] or sourceActor:CreateFFTable(sourceName)
friend.total = friend.total + amount
friend.spells[spellId] = (friend.spells[spellId] or 0) + amount
3 years ago
--record death log
local t = last_events_cache[sourceName]
3 years ago
if (not t) then
t = _current_combat:CreateLastEventsTable(sourceName)
end
3 years ago
local i = t.n
3 years ago
local this_event = t[i]
3 years ago
if (not this_event) then
return Details:Msg("Parser Event Error -> Set to 16 DeathLogs and /reload", i, _amount_of_last_events)
end
3 years ago
this_event [1] = true --true if this is a damage || false for healing
this_event [2] = spellId --spellid || false if this is a battle ress line
this_event [3] = amount --amount of damage or healing
this_event [4] = time --parser time
6 months ago
this_event [5] = UnitHealth(sourceName) / (max(UnitHealthMax(sourceName), 0.1)) --current unit heal
this_event [6] = sourceName --source name
this_event [7] = absorbed
this_event [8] = school
this_event [9] = true --friendly fire
this_event [10] = overkill
3 years ago
i = i + 1
3 years ago
if (i == _amount_of_last_events+1) then
t.n = 1
else
t.n = i
end
3 years ago
--avoidance
local avoidance = sourceActor.avoidance
if (not avoidance) then
sourceActor.avoidance = Details:CreateActorAvoidanceTable()
avoidance = sourceActor.avoidance
end
3 years ago
local overall = avoidance.overall
3 years ago
local mob = avoidance [sourceName]
if (not mob) then --if isn't in the table, build on the fly
mob = Details:CreateActorAvoidanceTable (true)
avoidance [sourceName] = mob
end
3 years ago
overall ["ALL"] = overall ["ALL"] + 1 --qualtipo de hit ou absorb
mob ["ALL"] = mob ["ALL"] + 1 --qualtipo de hit ou absorb
3 years ago
if (blocked and blocked > 0) then
overall ["BLOCKED_HITS"] = overall ["BLOCKED_HITS"] + 1
mob ["BLOCKED_HITS"] = mob ["BLOCKED_HITS"] + 1
overall ["BLOCKED_AMT"] = overall ["BLOCKED_AMT"] + blocked
mob ["BLOCKED_AMT"] = mob ["BLOCKED_AMT"] + blocked
end
3 years ago
--absorbs status
if (absorbed) then
--aqui pode ser apenas absorb parcial
overall ["ABSORB"] = overall ["ABSORB"] + 1
overall ["PARTIAL_ABSORBED"] = overall ["PARTIAL_ABSORBED"] + 1
overall ["PARTIAL_ABSORB_AMT"] = overall ["PARTIAL_ABSORB_AMT"] + absorbed
overall ["ABSORB_AMT"] = overall ["ABSORB_AMT"] + absorbed
mob ["ABSORB"] = mob ["ABSORB"] + 1
mob ["PARTIAL_ABSORBED"] = mob ["PARTIAL_ABSORBED"] + 1
mob ["PARTIAL_ABSORB_AMT"] = mob ["PARTIAL_ABSORB_AMT"] + absorbed
mob ["ABSORB_AMT"] = mob ["ABSORB_AMT"] + absorbed
else
--add aos hits sem absorbs
overall ["FULL_HIT"] = overall ["FULL_HIT"] + 1
overall ["FULL_HIT_AMT"] = overall ["FULL_HIT_AMT"] + amount
mob ["FULL_HIT"] = mob ["FULL_HIT"] + 1
mob ["FULL_HIT_AMT"] = mob ["FULL_HIT_AMT"] + amount
end
end
3 years ago
--special rule for LOTM
function parser:LOTM_damage (token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spelltype, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand)
3 years ago
if (absorbed) then
amount = absorbed + (amount or 0)
end
3 years ago
local healingActor = healing_cache [who_serial]
if (healingActor and healingActor.spells) then
healingActor.total = healingActor.total - (amount or 0)
3 years ago
local spellTable = healingActor.spells:GetSpell (183998)
if (spellTable) then
spellTable.anti_heal = (spellTable.anti_heal or 0) + amount
end
end
3 years ago
local t = last_events_cache [who_name]
3 years ago
if (not t) then
t = _current_combat:CreateLastEventsTable (who_name)
end
3 years ago
local i = t.n
3 years ago
local this_event = t [i]
3 years ago
if (not this_event) then
return Details:Msg("Parser Event Error -> Set to 16 DeathLogs and /reload", i, _amount_of_last_events)
3 years ago
end
this_event [1] = true --true if this is a damage || false for healing
this_event [2] = spellid --spellid || false if this is a battle ress line
this_event [3] = amount --amount of damage or healing
this_event [4] = time --parser time
this_event [5] = UnitHealth(who_name) / UnitHealthMax(who_name) --current unit heal
3 years ago
this_event [6] = who_name --source name
this_event [7] = absorbed
this_event [8] = school
3 years ago
this_event [9] = true --friendly fire
this_event [10] = overkill
3 years ago
i = i + 1
3 years ago
if (i == _amount_of_last_events+1) then
t.n = 1
else
t.n = i
3 years ago
end
local damageActor = damage_cache [who_serial]
if (damageActor) then
--damage taken
damageActor.damage_taken = damageActor.damage_taken + amount
3 years ago
if (not damageActor.damage_from [who_name]) then --adiciona a pool de dano tomado de quem
damageActor.damage_from [who_name] = true
end
3 years ago
--friendly fire
damageActor.friendlyfire_total = damageActor.friendlyfire_total + amount
local friend = damageActor.friendlyfire [who_name] or damageActor:CreateFFTable (who_name)
friend.total = friend.total + amount
friend.spells [spellid] = (friend.spells [spellid] or 0) + amount
end
end
3 years ago
--special rule of SLT
function parser:SLT_damage (token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spelltype, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand)
3 years ago
--damager
local este_jogador, meu_dono = damage_cache [who_serial] or damage_cache_pets [who_serial] or damage_cache [who_name], damage_cache_petsOwners [who_serial]
3 years ago
if (not este_jogador) then --pode ser um desconhecido ou um pet
este_jogador, meu_dono, who_name = _current_damage_container:GetOrCreateActor (who_serial, who_name, who_flags, true)
3 years ago
if (meu_dono) then --� um pet
if (who_serial ~= "") then
damage_cache_pets [who_serial] = este_jogador
damage_cache_petsOwners [who_serial] = meu_dono
end
--conferir se o dono j� esta no cache
if (not damage_cache [meu_dono.serial] and meu_dono.serial ~= "") then
damage_cache [meu_dono.serial] = meu_dono
end
else
3 years ago
if (who_flags) then --ter certeza que n�o � um pet
if (who_serial ~= "") then
damage_cache [who_serial] = este_jogador
else
3 years ago
if (who_name:find("%[")) then
damage_cache [who_name] = este_jogador
3 years ago
local _, _, icon = _GetSpellInfo(spellid or 1)
este_jogador.spellicon = icon
else
3 years ago
--_detalhes:Msg("Unknown actor with unknown serial ", spellname, who_name)
end
end
end
end
3 years ago
elseif (meu_dono) then
3 years ago
--� um pet
who_name = who_name .. " <" .. meu_dono.nome .. ">"
end
3 years ago
--his target
local jogador_alvo, alvo_dono = damage_cache [alvo_serial] or damage_cache_pets [alvo_serial] or damage_cache [alvo_name], damage_cache_petsOwners [alvo_serial]
3 years ago
if (not jogador_alvo) then
3 years ago
jogador_alvo, alvo_dono, alvo_name = _current_damage_container:GetOrCreateActor (alvo_serial, alvo_name, alvo_flags, true)
3 years ago
if (alvo_dono) then
if (alvo_serial ~= "") then
damage_cache_pets [alvo_serial] = jogador_alvo
damage_cache_petsOwners [alvo_serial] = alvo_dono
end
--conferir se o dono j� esta no cache
if (not damage_cache [alvo_dono.serial] and alvo_dono.serial ~= "") then
damage_cache [alvo_dono.serial] = alvo_dono
end
else
3 years ago
if (alvo_flags and alvo_serial ~= "") then --ter certeza que n�o � um pet
damage_cache [alvo_serial] = jogador_alvo
end
end
3 years ago
elseif (alvo_dono) then
3 years ago
--� um pet
alvo_name = alvo_name .. " <" .. alvo_dono.nome .. ">"
end
3 years ago
--last event
este_jogador.last_event = _tempo
3 years ago
--record death log
local t = last_events_cache [alvo_name]
3 years ago
if (not t) then
t = _current_combat:CreateLastEventsTable (alvo_name)
end
3 years ago
local i = t.n
3 years ago
local this_event = t [i]
3 years ago
if (not this_event) then
return Details:Msg("Parser Event Error -> Set to 16 DeathLogs and /reload", i, _amount_of_last_events)
3 years ago
end
this_event [1] = true --true if this is a damage || false for healing
this_event [2] = spellid --spellid || false if this is a battle ress line
this_event [3] = amount --amount of damage or healing
this_event [4] = time --parser time
this_event [5] = UnitHealth(alvo_name) / UnitHealthMax(alvo_name) --current unit heal
3 years ago
this_event [6] = who_name --source name
this_event [7] = absorbed
this_event [8] = spelltype or school
this_event [9] = false
this_event [10] = overkill
3 years ago
i = i + 1
3 years ago
if (i == _amount_of_last_events+1) then
t.n = 1
else
t.n = i
end
end
--extra attacks - disabled
function parser:spell_dmg_extra_attacks(token, time, who_serial, who_name, who_flags, _, _, _, _, spellid, spellName, spelltype, arg1)
--print("this is even exists on ingame cleu?")
local este_jogador = damage_cache [who_serial]
if (not este_jogador) then
local meu_dono
este_jogador, meu_dono, who_name = _current_damage_container:GetOrCreateActor (who_serial, who_name, who_flags, true)
if (not este_jogador) then
3 years ago
return --just return if actor doen't exist yet
end
end
3 years ago
--actor spells table
local spell = este_jogador.spells._ActorTable[1] --melee damage
if (not spell) then
return
end
spell.extra["extra_attack"] = (spell.extra["extra_attack"] or 0) + 1
end
3 years ago
--function parser:swingmissed (token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, missType, isOffHand, amountMissed)
function parser:swingmissed(token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, alvo_flags2, missType, isOffHand, amountMissed) --, isOffHand, amountMissed, arg1
return parser:missed(token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, alvo_flags2, 1, "Corpo-a-Corpo", 00000001, missType, isOffHand, amountMissed) --, isOffHand, amountMissed, arg1
end
function parser:rangemissed(token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, alvo_flags2, spellid, spellname, spelltype, missType, isOffHand, amountMissed) --, isOffHand, amountMissed, arg1
return parser:missed(token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, alvo_flags2, 2, "Tiro-Autom�tico", 00000001, missType, isOffHand, amountMissed) --, isOffHand, amountMissed, arg1
end
-- ~miss
function parser:missed(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellType, missType, isOffHand, amountMissed)
if (not targetName) then
3 years ago
--no target name, just quit
return
3 years ago
elseif (not sourceName) then
3 years ago
--no actor name, use spell name instead
sourceName = "[*] " .. spellName
sourceFlags = 0xa48
sourceSerial = ""
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--get actors
4 years ago
--todo tbc seems to not have misses? need further investigation
3 years ago
--print("MISS", "|", missType, "|", isOffHand, "|", amountMissed, "|", arg1)
--print(missType, who_name, spellname, amountMissed)
--'misser'
---@type actor
local sourceActor = damage_cache[sourceSerial]
if (not sourceActor) then
local ownerActor
sourceActor, ownerActor, sourceName = _current_damage_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not sourceActor) then
3 years ago
return --just return if actor doen't exist yet
end
end
3 years ago
sourceActor.last_event = _tempo
3 years ago
if (tanks_members_cache[targetSerial]) then --only track tanks for avoidance
local targetActor = damage_cache[targetSerial]
if (targetActor) then
local avoidance = targetActor.avoidance
3 years ago
if (not avoidance) then
targetActor.avoidance = Details:CreateActorAvoidanceTable()
avoidance = targetActor.avoidance
end
--not to confuse with overall data, this is the overall miss table counting avoidance for all mobs
local overallMissTable = avoidance.overall[missType]
3 years ago
if (overallMissTable) then
local overall = avoidance.overall
overall[missType] = overallMissTable + 1 --add to the amount of misses
--avoidance for this mob only
local missTableMob = avoidance[sourceName]
if (not missTableMob) then --if isn't in the table, build on the fly
missTableMob = Details:CreateActorAvoidanceTable(true)
avoidance[sourceName] = missTableMob
end
3 years ago
missTableMob[missType] = missTableMob[missType] + 1
3 years ago
if (missType == "ABSORB") then --full absorb
overall["ALL"] = overall["ALL"] + 1 --qualtipo de hit ou absorb
overall["FULL_ABSORBED"] = overall["FULL_ABSORBED"] + 1 --amount
overall["ABSORB_AMT"] = overall["ABSORB_AMT"] + (amountMissed or 0)
overall["FULL_ABSORB_AMT"] = overall["FULL_ABSORB_AMT"] + (amountMissed or 0)
missTableMob["ALL"] = missTableMob["ALL"] + 1 --qualtipo de hit ou absorb
missTableMob["FULL_ABSORBED"] = missTableMob["FULL_ABSORBED"] + 1 --amount
missTableMob["ABSORB_AMT"] = missTableMob["ABSORB_AMT"] + (amountMissed or 0)
missTableMob["FULL_ABSORB_AMT"] = missTableMob["FULL_ABSORB_AMT"] + (amountMissed or 0)
end
end
end
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--amount add
if (missType == "ABSORB") then
if (token == "SWING_MISSED") then
sourceActor.totalabsorbed = sourceActor.totalabsorbed + amountMissed
return parser:spell_dmg("SWING_DAMAGE", time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, amountMissed, -1, 1, nil, nil, nil, false, false, false, false)
3 years ago
elseif (token == "RANGE_MISSED") then
sourceActor.totalabsorbed = sourceActor.totalabsorbed + amountMissed
return parser:spell_dmg("RANGE_DAMAGE", time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellType, amountMissed, -1, 1, nil, nil, nil, false, false, false, false)
3 years ago
else
sourceActor.totalabsorbed = sourceActor.totalabsorbed + amountMissed
return parser:spell_dmg(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellType, amountMissed, -1, 1, nil, nil, nil, false, false, false, false)
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--spell reflection
elseif (missType == "REFLECT" and reflection_auras[targetSerial]) then --~reflect
3 years ago
--a reflect event and we have the reflecting aura data
if (reflection_damage[sourceSerial] and reflection_damage[sourceSerial][spellId] and time-reflection_damage[sourceSerial][spellId].time > 3.5 and (not reflection_debuffs[sourceSerial] or (reflection_debuffs[sourceSerial] and not reflection_debuffs[sourceSerial][spellId]))) then
3 years ago
--here we check if we have to filter old damage data
--we check for two conditions
--the first is to see if this is an old damage
--if more than 3.5 seconds have past then we can say that it is old... but!
--the second condition is to see if there is an active debuff with the same spellid
--if there is one then we ignore the timer and skip this
--this should be cleared afterwards somehow... don't know how...
reflection_damage[sourceSerial][spellId] = nil
if (next(reflection_damage[sourceSerial]) == nil) then
3 years ago
--there should be some better way of handling this kind of filtering, any suggestion?
reflection_damage[sourceSerial] = nil
end
end
local damage = reflection_damage[sourceSerial] and reflection_damage[sourceSerial][spellId]
local reflection = reflection_auras[targetSerial]
if (damage) then
3 years ago
--damage ocurred first, so we have its data
local amount = reflection_damage[sourceSerial][spellId].amount
local isreflected = spellId --which spell was reflected
targetSerial = reflection.who_serial
targetName = reflection.who_name
targetFlags = reflection.who_flags
spellId = reflection.spellid
spellName = reflection.spellname
spellType = reflection.spelltype
3 years ago
--crediting the source of the aura that caused the reflection
--also saying that the damage came from the aura that reflected the spell
reflection_damage[sourceSerial][spellId] = nil
if next(reflection_damage[sourceSerial]) == nil then
3 years ago
--this is so bad at clearing, there should be a better way of handling this
reflection_damage[sourceSerial] = nil
end
return parser:spell_dmg(token, time, targetSerial, targetName, targetFlags, sourceSerial, sourceName, sourceFlags, nil, spellId, spellName, spellType, amount, -1, nil, nil, nil, nil, false, false, false, false, isreflected)
else
3 years ago
--saving information about this reflect because it occurred before the damage event
reflection_events[sourceSerial] = reflection_events[sourceSerial] or {}
reflection_events[sourceSerial][spellId] = reflection
reflection_events[sourceSerial][spellId].time = time
end
else
--colocando aqui apenas pois ele confere o override dentro do damage
if (is_using_spellId_override) then
spellId = override_spellId[spellId] or spellId
end
3 years ago
--actor spells table
local spell = sourceActor.spells._ActorTable[spellId]
if (not spell) then
spell = sourceActor.spells:GetOrCreateSpell(spellId, true, token)
spell.spellschool = spellType
if (_current_combat.is_boss and sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_ENEMY) ~= 0) then
Details.spell_school_cache[spellName] = spellType
end
end
return _spell_damageMiss_func(spell, targetSerial, targetName, targetFlags, sourceName, missType)
end
end
3 years ago
-----------------------------------------------------------------------------------------------------------------------------------------
--SPELL_EMPOWER
-----------------------------------------------------------------------------------------------------------------------------------------
function parser:spell_empower(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetRaidFlags, spellId, spellName, spellSchool, empowerLevel)
--empowerLevel only exists on _END and _INTERRUPT
if (token == "SPELL_EMPOWER_START" or token == "SPELL_EMPOWER_INTERRUPT") then
return
end
if (not empowerLevel) then
return
end
--early checks
if (not sourceSerial or not sourceName or not sourceFlags) then
return
end
--source damager, should this only register for Players?
if (sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_PLAYER) == 0) then
return
end
local sourceObject = damage_cache[sourceSerial] or damage_cache[sourceName]
if (not sourceObject) then
sourceObject = _current_damage_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
end
if (not sourceObject) then
return
end
--add to the amount of spell casts
--nop, SPELL_EMPOWER_END does not trigger when Tip The Scales is enabled
--perhaps UNIT_SPELLCAST_SUCCEEDED checking if tip the scales buff is enabled and checking if the spell is an empowered spell
--parser:spellcast(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetRaidFlags, spellId, spellName)
empower_cache[sourceSerial] = empower_cache[sourceSerial] or {}
local empowerTable = {
spellName = spellName,
empowerLevel = empowerLevel,
time = time,
counted_healing = false,
counted_damage = false,
}
empower_cache[sourceSerial][spellName] = empowerTable
end
--parser.spell_empower
--10/30 15:32:11.515 SPELL_EMPOWER_START,Player-4184-00242A35,"Isodrak-Valdrakken",0x514,0x0,Player-4184-00242A35,"Isodrak-Valdrakken",0x514,0x0,382266,"Fire Breath",0x4
--10/30 15:32:12.433 SPELL_EMPOWER_END,Player-4184-00242A35,"Isodrak-Valdrakken",0x514,0x0,0000000000000000,nil,0x80000000,0x80000000,382266,"Fire Breath",0x4,1
--10/30 15:33:45.970 SPELL_EMPOWER_INTERRUPT,Player-4184-00218B4F,"Minng-Valdrakken",0x512,0x0,0000000000000000,nil,0x80000000,0x80000000,382266,"Fire Breath",0x4,1
--10/30 15:34:47.249 SPELL_EMPOWER_START,Player-4184-0048EE5B,"Nezaland-Valdrakken",0x514,0x0,Player-4184-0048EE5B,"Nezaland-Valdrakken",0x514,0x0,382266,"Fire Breath",0x4
--357209 damage spell is different from the spell cast
-----------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--SUMMON serach key: ~summon |
-----------------------------------------------------------------------------------------------------------------------------------------
function parser:summon(token, time, sourceSerial, sourceName, sourceFlags, petGuid, petName, petFlags, petRaidFlags, summonSpellId, summonSpellName)
if (not sourceName) then
sourceName = "[*] " .. summonSpellName
end
local npcId = tonumber(select(6, strsplit("-", petGuid)) or 0)
if (Details222.Debug.DebugPets) then
6 months ago
end
--differenciate army and apoc pets for DK
if (summonSpellId == 42651) then --army of the dead
dk_pets_cache.army[petGuid] = sourceName
end
--If fire elemental totem on Wrath, then ignore the summon of the fire elemental totem itself and instead create the Greater Fire Elemental early.
--Greater Fire Elemental and Fire Elemental Totem have the same serial besides the npc id.
--There are cases where the Greater Fire Elemental could attack and the SWING_DAMAGE event happens before the spell_summon for it. Same frame.
--[[12/14 21:14:44.545 SPELL_SUMMON,Player-4384-03852552,"Toekruh-Mankrik",0x512,0x0,Creature-0-4391-615-3107-15439-00001A8313,"Fire Elemental Totem",0xa28,0x0,2894,"Fire Elemental Totem",0x1
12/14 21:14:44.545 SWING_DAMAGE,Creature-0-4391-615-3107-15438-00001A8313,"Greater Fire Elemental",0x2112,0x0,Creature-0-4391-615-3107-28860-00001A8258,"Sartharion",0xa48,0x0,Creature-0-4391-615-3107-15438-00001A8313,Creature-0-4391-615-3107-15439-00001A8313,4274,4274,0,0,0,-1,0,0,0,3261.68,530.04,155,3.3324,208,188,187,-1,4,0,0,0,nil,nil,nil
12/14 21:14:44.545 SPELL_CAST_SUCCESS,Creature-0-4391-615-3107-15438-00001A8313,"Greater Fire Elemental",0x2112,0x0,Creature-0-4391-615-3107-28860-00001A8258,"Sartharion",0xa48,0x0,57984,"Fire Blast",0x4,Creature-0-4391-615-3107-15438-00001A8313,Creature-0-4391-615-3107-15439-00001A8313,4274,4274,0,0,0,-1,0,0,0,3261.68,530.04,155,3.3324,208
12/14 21:14:44.545 SPELL_CAST_SUCCESS,Creature-0-4391-615-3107-15439-00001A8313,"Fire Elemental Totem",0x2112,0x0,0000000000000000,nil,0x80000000,0x80000000,32982,"Fire Elemental Totem",0x1,Creature-0-4391-615-3107-15439-00001A8313,Player-4384-03852552,3888,3888,0,0,0,-1,0,0,0,3257.01,531.82,155,5.1330,208
12/14 21:14:44.545 SPELL_SUMMON,Creature-0-4391-615-3107-15439-00001A8313,"Fire Elemental Totem",0x2112,0x0,Creature-0-4391-615-3107-15438-00001A8313,"Greater Fire Elemental",0x2112,0x0,32982,"Fire Elemental Totem",0x1
]]
6 months ago
if (isCLASSIC) then
if (npcId == 15439) then
petContainer.AddPet(petGuid:gsub("%-15439%-", "%-15438%-"), "Greater Fire Elemental", petFlags, sourceSerial, sourceName, sourceFlags, summonSpellId)
elseif (npcId == 15438) then
4 years ago
return
end
6 months ago
-- Brann Bronzebeard in delves
elseif (npcId == 210759) then
return
end
3 years ago
--send the summonSpellId to spellcache in order to identify if the pet is from an item, for instance: a trinket
local newPetName = Details222.Pets.GetPetNameFromCustomSpells(petName, summonSpellId, npcId)
if (newPetName ~= petName) then
--print("Details! debug trinket summon| player:", sourceName, "| old pet name:", petName, "| new pet name:", newPetName, "| spellId:", summonSpellId)
petName = newPetName
end
--if the caster is inside the petCache, it means this is a pet summoning another pet
---@type petdata
local petTable = petCache[sourceSerial]
if (petTable) then
sourceName, sourceSerial, sourceFlags = petTable.ownerName, petTable.ownerGuid, petTable.ownerFlags
end
3 years ago
petTable = petCache[petGuid]
if (petTable) then
sourceName, sourceSerial, sourceFlags = petTable[1], petTable[2], petTable[3]
end
3 years ago
petContainer.AddPet(petGuid, petName, petFlags, sourceSerial, sourceName, sourceFlags, summonSpellId)
end
-----------------------------------------------------------------------------------------------------------------------------------------
--HEALING serach key: ~healing ~heal |
-----------------------------------------------------------------------------------------------------------------------------------------
local ignored_shields = {
[142862] = true, -- Ancient Barrier (Malkorok)
[114556] = true, -- Purgatory (DK)
[115069] = true, -- Stance of the Sturdy Ox (Monk)
[20711] = true, -- Spirit of Redemption (Priest)
[184553] = true, --Soul Capacitor
[357170] = true, --Time Dilation
}
3 years ago
local ignored_overheal = { --during refresh, some shield does not replace the old value for the new one
[47753] = true, -- Divine Aegis
[86273] = true, -- Illuminated Healing
[114908] = true, --Spirit Shell
[152118] = true, --Clarity of Will
6 months ago
[447134] = true, --Ravenous Scarab
}
3 years ago
function parser:heal_denied(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellIdAbsorb, spellNameAbsorb, spellSchoolAbsorb, serialHealer, nameHealer, flagsHealer, flags2Healer, spellIdHeal, spellNameHeal, typeHeal, amountDenied)
if (not _in_combat) then
return
end
3 years ago
--check invalid serial against pets
if (sourceSerial == "") then
if (sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_PETS) ~= 0) then --is pet
return
end
end
3 years ago
--no name, use spellname
if (not sourceName) then
sourceName = "[*] " .. (spellNameHeal or "--unknown spell--")
end
3 years ago
--no target, just ignore
if (not targetName) then
return
end
3 years ago
--if no spellid
if (not spellIdAbsorb) then
spellIdAbsorb = 1
spellNameAbsorb = "unknown"
spellSchoolAbsorb = 1
end
3 years ago
if (is_using_spellId_override) then
spellIdAbsorb = override_spellId[spellIdAbsorb] or spellIdAbsorb
spellIdHeal = override_spellId[spellIdHeal] or spellIdHeal
end
3 years ago
--source actor
---@type actor
local sourceActor, ownerActor = healing_cache[sourceSerial]
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_heal_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not ownerActor and sourceFlags and sourceSerial ~= "") then --add to cache if isn't a pet
healing_cache[sourceSerial] = sourceActor
end
end
3 years ago
local targetActor, targetOwner = healing_cache[targetSerial]
if (not targetActor) then
targetActor, targetOwner, targetName = _current_heal_container:GetOrCreateActor(targetSerial, targetName, targetFlags, true)
if (not targetOwner and targetFlags and targetSerial ~= "") then
healing_cache[targetSerial] = targetActor
end
end
3 years ago
sourceActor.last_event = _tempo
------------------------------------------------
3 years ago
sourceActor.totaldenied = sourceActor.totaldenied + amountDenied
3 years ago
--actor spells table
local spell = sourceActor.spells._ActorTable[spellIdAbsorb]
if (not spell) then
spell = sourceActor.spells:GetOrCreateSpell(spellIdAbsorb, true, token)
if (_current_combat.is_boss and sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_ENEMY) ~= 0) then
Details.spell_school_cache[spellNameAbsorb] = spellSchoolAbsorb or 1
end
end
3 years ago
return _spell_heal_func(spell, targetSerial, targetName, targetFlags, amountDenied, spellIdHeal, token, nameHealer) --, overhealing
end
3 years ago
function parser:heal_absorb(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellSchool, shieldOwnerSerial, shieldOwnerName, shieldOwnerFlags, shieldOwnerFlags2, shieldSpellId, shieldName, shieldType, amount)
6 months ago
if (isCLASSIC) then
if (not amount) then
--melee
shieldOwnerSerial, shieldOwnerName, shieldOwnerFlags, shieldOwnerFlags2, shieldSpellId, shieldName, shieldType, amount = spellId, spellName, spellSchool, shieldOwnerSerial, shieldOwnerName, shieldOwnerFlags, shieldOwnerFlags2, shieldSpellId
end
return parser:heal(token, time, shieldOwnerSerial, shieldOwnerName, shieldOwnerFlags, targetSerial, targetName, targetFlags, targetFlags2, shieldSpellId, shieldName, shieldType, amount, 0, 0, nil, true)
else
--retail
if (type(shieldName) == "boolean") then
shieldOwnerSerial, shieldOwnerName, shieldOwnerFlags, shieldOwnerFlags2, shieldSpellId, shieldName, shieldType, amount = spellId, spellName, spellSchool, shieldOwnerSerial, shieldOwnerName, shieldOwnerFlags, shieldOwnerFlags2, shieldSpellId
end
end
if (ignored_shields[shieldSpellId]) then
return
elseif (shieldSpellId == 110913) then
--dark bargain
local max_health = UnitHealthMax(shieldOwnerName)
if ((amount or 0) > (max_health or 1) * 4) then
return
end
end
--diminuir o escudo nas tabelas de ShieldCache
6 months ago
if (_parser_options.shield_overheal) then
local shieldsOnTarget = shield_cache[targetName]
if (shieldsOnTarget) then
local shieldsBySpellId = shieldsOnTarget[shieldSpellId]
if (shieldsBySpellId) then
local shieldAmount = shieldsBySpellId[shieldOwnerName]
if (shieldAmount) then
shieldsBySpellId[shieldOwnerName] = shieldAmount - amount
end
end
end
shield_spellid_cache[shieldSpellId] = true
end
3 years ago
return parser:heal(token, time, shieldOwnerSerial, shieldOwnerName, shieldOwnerFlags, targetSerial, targetName, targetFlags, targetFlags2, shieldSpellId, shieldName, shieldType, amount, 0, 0, nil, true)
end
function parser:heal(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellType, amount, overHealing, absorbed, critical, bIsShield)
3 years ago
--only capture heal if is in combat
if (not _in_combat) then
if (not _in_resting_zone) then --and not in a resting zone
return
end
end
3 years ago
--check invalid serial against pets
if (sourceSerial == "") then
if (sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_PETS) ~= 0) then
--it's a pet without a serial number, ignore
return
end
end
--no target, no heal
if (not targetName) then
return
end
3 years ago
--check for banned spells
if (banned_healing_spells[spellId]) then
return
end
3 years ago
--> npcId check for ignored npcs
--> get the npcId from the cache, if it's not there then get it from the serial and add it to the cache
local npcId = npcid_cache[targetSerial] --target npc
if (not npcId) then
--this string manipulation is running on every event
npcId = tonumber(select(6, strsplit("-", targetSerial)) or 0)
npcid_cache[targetSerial] = npcId
end
if (ignored_npcids[npcId]) then
return
end
if (not sourceName) then
--no actor name, use spell name instead
sourceName = names_cache[spellName]
if (not sourceName) then
sourceName = "[*] " .. spellName
--cache the string manipulation
names_cache[spellName] = sourceName
end
end
if (spellId == 98021 or spellId == 469704) then --spirit link totem or tempered in battle
return parser:SLT_healing(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, spellId, spellName, spellType, amount, overHealing, absorbed, critical, bIsShield)
end
3 years ago
6 months ago
if (is_using_spellId_override) then
spellId = override_spellId[spellId] or spellId
end
--sanguine ichor mythic dungeon affix (heal enemies)
6 months ago
if (spellId == SPELLID_SANGUINE_HEAL) then --not used in 11.1 patch (season 2 tww)
sourceName = Details.SanguineHealActorName
sourceFlags = 0x518
sourceSerial = "Creature-0-3134-2289-28065-" .. SPELLID_SANGUINE_HEAL .. "-000164C698"
end
3 years ago
local effectiveHeal = absorbed
if (bIsShield) then
--shield has the correct amount of 'healing done'
effectiveHeal = amount
else
effectiveHeal = effectiveHeal + amount - overHealing
end
6 months ago
if (isCLASSIC) then
--earth shield
if (spellId == SPELLID_SHAMAN_EARTHSHIELD_HEAL) then
--get the information of who placed the buff into this actor
local sourceData = TBC_EarthShieldCache[sourceName]
if (sourceData) then
sourceSerial, sourceName, sourceFlags = unpack(sourceData)
end
--prayer of mending
elseif (spellId == SPELLID_PRIEST_POM_HEAL) then
local sourceData = TBC_PrayerOfMendingCache[sourceName]
if (sourceData) then
sourceSerial, sourceName, sourceFlags = unpack(sourceData)
TBC_PrayerOfMendingCache[sourceName] = nil
end
elseif (spellId == 27163) then --Judgement of Light (paladin), reattribute healing to the person getting healed. Stops 'sniping' the JoL to parse
--Removed old version 10/27/23 Flamanis
sourceSerial, sourceName, sourceFlags = targetSerial, targetName, targetFlags
end
end
_current_heal_container.need_refresh = true
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--get actors
6 months ago
--healer
local sourceActor, ownerActor = healing_cache[sourceSerial], nil
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_heal_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not ownerActor and sourceFlags and sourceSerial ~= "") then --if isn't a pet, add to the cache
healing_cache[sourceSerial] = sourceActor
end
end
--target
local targetActor, targetOwner = healing_cache[targetSerial], nil
if (not targetActor) then
targetActor, targetOwner, targetName = _current_heal_container:GetOrCreateActor(targetSerial, targetName, targetFlags, true)
if (not targetOwner and targetFlags and targetSerial ~= "") then --if isn't a pet, add to the cache
healing_cache[targetSerial] = targetActor
end
end
3 years ago
sourceActor.last_event = _tempo
------------------------------------------------------------------------------------------------
3 years ago
--an enemy healing enemy or an player actor healing a enemy
if (spellId == SPELLID_SANGUINE_HEAL) then --sanguine ichor (heal enemies)
sourceActor.grupo = true
elseif (bitBand(targetFlags, REACTION_FRIENDLY) == 0 and not Details.is_in_arena and not Details.is_in_battleground) then
if (not sourceActor.heal_enemy[spellId]) then
sourceActor.heal_enemy[spellId] = effectiveHeal
else
sourceActor.heal_enemy[spellId] = sourceActor.heal_enemy[spellId] + effectiveHeal
end
3 years ago
sourceActor.heal_enemy_amt = sourceActor.heal_enemy_amt + effectiveHeal
return true
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--group checks
if (sourceActor.grupo and not targetActor.arena_enemy) then
_current_gtotal[2] = _current_gtotal[2] + effectiveHeal
end
3 years ago
6 months ago
if (targetActor.grupo and Details.HealthCache[targetSerial]) then
---local ttt = debugprofilestop()
local t = last_events_cache[targetName]
if (not t) then
t = _current_combat:CreateLastEventsTable(targetName)
end
3 years ago
6 months ago
Details.HealthCache[targetSerial] = Details.HealthCache[targetSerial] + max(amount - overHealing, 0)
if (Details.HealthCache[targetSerial] > Details.HealthMaxCache[targetSerial]) then
Details.HealthCache[targetSerial] = Details.HealthMaxCache[targetSerial]
end
local i = t.n
3 years ago
--consolidate if the spellId is the same and the time is the same as well
local previousEvent = t[i-1]
if (previousEvent and previousEvent[1] == false and previousEvent[2] == spellId and floor(previousEvent[4]) == floor(time)) then
previousEvent[3] = previousEvent[3] + amount
if (absorbed) then
previousEvent[8] = (previousEvent[8] or 0) + absorbed
end
previousEvent[7] = previousEvent[7] or bIsShield
previousEvent[1] = false --true if this is a damage || false for healing
6 months ago
previousEvent[5] = Details.HealthCache[targetSerial] / Details.HealthMaxCache[targetSerial]
--previousEvent[5] = UnitHealth(targetName) / Details.HealthMaxCache[targetSerial]
previousEvent[11] = (previousEvent[11] or 0) + 1 --attempt to perform arithmetic on a boolean value (during battlegrounds - fix 02 Nov 2023)
else
local thisEvent = t[i]
3 years ago
thisEvent[1] = false --true if this is a damage || false for healing
thisEvent[2] = spellId --spellid || false if this is a battle ress line
thisEvent[3] = amount --amount of damage or healing
thisEvent[4] = time --parser time
thisEvent[11] = nil
--current unit heal
if (targetActor.arena_enemy) then
--this is an arena enemy, get the heal with the unit Id
local unitId = Details.arena_enemies[targetName]
if (not unitId) then
unitId = Details:GuessArenaEnemyUnitId(targetName)
end
if (unitId) then
thisEvent[5] = UnitHealth(unitId) / max(UnitHealthMax(unitId), SMALL_FLOAT)
else
thisEvent[5] = 0
end
else
6 months ago
--thisEvent[5] = UnitHealth(targetName) / Details.HealthMaxCache[targetSerial]
thisEvent[5] = Details.HealthCache[targetSerial] / Details.HealthMaxCache[targetSerial]
end
thisEvent[6] = sourceName
thisEvent[7] = bIsShield
thisEvent[8] = absorbed
3 years ago
i = i + 1
3 years ago
if (i == _amount_of_last_events + 1) then
t.n = 1
else
t.n = i
end
end
end
------------------------------------------------------------------------------------------------
--~activity time
6 months ago
if (not sourceActor.iniciar_hps) then
sourceActor:GetOrChangeActivityStatus(true)
if (ownerActor and not ownerActor.iniciar_hps) then
ownerActor:GetOrChangeActivityStatus(true)
if (ownerActor.end_time) then
ownerActor.end_time = nil
else
ownerActor.start_time = _tempo
end
end
3 years ago
if (sourceActor.end_time) then --o combate terminou, reabrir o tempo
sourceActor.end_time = nil
else
sourceActor.start_time = _tempo
end
end
------------------------------------------------------------------------------------------------
3 years ago
--add amount
6 months ago
--actor target
if (effectiveHeal > 0) then
3 years ago
--combat total
_current_total[2] = _current_total[2] + effectiveHeal
3 years ago
--actor healing amount
sourceActor.total = sourceActor.total + effectiveHeal
sourceActor.total_without_pet = sourceActor.total_without_pet + effectiveHeal
3 years ago
--healing taken
targetActor.healing_taken = targetActor.healing_taken + effectiveHeal --adiciona o dano tomado
if (not targetActor.healing_from[sourceName]) then --adiciona a pool de dano tomado de quem
targetActor.healing_from[sourceName] = true
end
if (bIsShield) then
sourceActor.totalabsorb = sourceActor.totalabsorb + effectiveHeal
sourceActor.targets_absorbs[targetName] = (sourceActor.targets_absorbs[targetName] or 0) + effectiveHeal
end
3 years ago
--pet
if (ownerActor) then
ownerActor.total = ownerActor.total + effectiveHeal --heal do pet
ownerActor.targets[targetName] = (ownerActor.targets[targetName] or 0) + effectiveHeal
end
3 years ago
--target amount
sourceActor.targets[targetName] = (sourceActor.targets[targetName] or 0) + effectiveHeal
end
3 years ago
if (ownerActor) then
ownerActor.last_event = _tempo
end
3 years ago
if (overHealing > 0) then
sourceActor.totalover = sourceActor.totalover + overHealing
sourceActor.targets_overheal[targetName] = (sourceActor.targets_overheal[targetName] or 0) + overHealing
3 years ago
if (ownerActor) then
ownerActor.totalover = ownerActor.totalover + overHealing
end
end
3 years ago
--actor spells table
local spellTable = sourceActor.spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.spells:GetOrCreateSpell(spellId, true, token)
if (bIsShield) then
spellTable.is_shield = true
end
spellTable.spellschool = spellType
if (_current_combat.is_boss and sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_ENEMY) ~= 0) then
Details.spell_school_cache[spellName] = spellType
end
end
3 years ago
--empowerment data
if (empower_cache[sourceSerial]) then
local empowerSpellInfo = empower_cache[sourceSerial][spellName]
if (empowerSpellInfo) then
if (not empowerSpellInfo.counted_damage) then
--total of empowerment
spellTable.e_total = (spellTable.e_total or 0) + empowerSpellInfo.empowerLevel --used to calculate the average empowerment
--total amount of empowerment
spellTable.e_amt = (spellTable.e_amt or 0) + 1 --used to calculate the average empowerment
--amount of casts on each level
spellTable.e_lvl = spellTable.e_lvl or {}
spellTable.e_lvl[empowerSpellInfo.empowerLevel] = (spellTable.e_lvl[empowerSpellInfo.empowerLevel] or 0) + 1
empowerSpellInfo.counted_damage = true
end
--healing bracket
spellTable.e_heal = spellTable.e_heal or {}
spellTable.e_heal[empowerSpellInfo.empowerLevel] = (spellTable.e_heal[empowerSpellInfo.empowerLevel] or 0) + effectiveHeal
end
end
3 years ago
if (bIsShield) then
return _spell_heal_func(spellTable, targetSerial, targetName, targetFlags, effectiveHeal, sourceName, 0, nil, overHealing, true)
else
return _spell_heal_func(spellTable, targetSerial, targetName, targetFlags, effectiveHeal, sourceName, absorbed, critical, overHealing)
end
end
function parser:SLT_healing (token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spelltype, amount, overhealing, absorbed, critical, is_shield)
3 years ago
--get actors
local este_jogador, meu_dono = healing_cache [who_serial]
3 years ago
if (not este_jogador) then --pode ser um desconhecido ou um pet
este_jogador, meu_dono, who_name = _current_heal_container:GetOrCreateActor (who_serial, who_name, who_flags, true)
if (not meu_dono and who_flags and who_serial ~= "") then --se n�o for um pet, add no cache
healing_cache [who_serial] = este_jogador
end
end
local jogador_alvo, alvo_dono = healing_cache [alvo_serial]
if (not jogador_alvo) then
jogador_alvo, alvo_dono, alvo_name = _current_heal_container:GetOrCreateActor (alvo_serial, alvo_name, alvo_flags, true)
if (not alvo_dono and alvo_flags and alvo_serial ~= "") then
healing_cache [alvo_serial] = jogador_alvo
end
end
3 years ago
este_jogador.last_event = _tempo
local t = last_events_cache [alvo_name]
3 years ago
if (not t) then
t = _current_combat:CreateLastEventsTable (alvo_name)
end
3 years ago
local i = t.n
3 years ago
local this_event = t [i]
3 years ago
this_event [1] = false --true if this is a damage || false for healing
this_event [2] = spellid --spellid || false if this is a battle ress line
this_event [3] = amount --amount of damage or healing
this_event [4] = time --parser time
this_event [5] = UnitHealth(alvo_name) / UnitHealthMax(alvo_name) --current unit heal
3 years ago
this_event [6] = who_name --source name
this_event [7] = is_shield
this_event [8] = absorbed
3 years ago
i = i + 1
3 years ago
if (i == _amount_of_last_events+1) then
t.n = 1
else
t.n = i
end
3 years ago
local spell = este_jogador.spells._ActorTable [spellid]
if (not spell) then
spell = este_jogador.spells:GetOrCreateSpell(spellid, true, token)
spell.neutral = true
end
3 years ago
return _spell_heal_func (spell, alvo_serial, alvo_name, alvo_flags, absorbed + amount - overhealing, who_name, absorbed, critical, overhealing, nil)
end
3 years ago
-----------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--BUFFS & DEBUFFS search key: ~buff ~aura ~shield |
-----------------------------------------------------------------------------------------------------------------------------------------
6 months ago
--aura ddebugger
local function aura_debugger_parserfile(type, spellName, sourceName, targetName)
do return end --don't enable on releases
if (Details.zone_type == "party" or true) then
if (sourceName == UnitName("player")) then
--print("buff", type, spellName, sourceName, "on", targetName)
end
end
end
function parser:buff(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellschool, auraType, amount, arg1, arg2, arg3)
if (ignoredWorldAuras[spellId]) then
return
end
--not yet well know about unnamed buff casters
if (not targetName) then
targetName = "[*] Unknown shield target"
elseif (not sourceName) then
sourceName = names_cache[spellName]
if (not sourceName) then
sourceName = "[*] " .. spellName
names_cache[spellName] = sourceName
end
sourceFlags = 0xa48
sourceSerial = ""
3 years ago
end
if (augmentation_aura_list[spellId]) then
Details222.SpecHelpers[1473].BuffIn(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellschool, auraType, amount)
end
------------------------------------------------------------------------------------------------
--spell reflection
if (reflection_spellid[spellId]) then --~reflect
3 years ago
--this is a spell reflect aura
--we save the info on who received this aura and from whom
--this will be used to credit this spell as the one doing the damage
reflection_auras[targetSerial] = {
who_serial = sourceSerial,
who_name = sourceName,
who_flags = sourceFlags,
spellid = spellId,
spellname = spellName,
spelltype = spellschool,
}
end
if (auraType == "BUFF") then
6 months ago
--aura_debugger_parserfile("IN", spellName, sourceName, targetName)
if (LIB_OPEN_RAID_BLOODLUST[spellId]) then --~bloodlust
if (Details.playername == targetName) then
_current_combat.bloodlust = _current_combat.bloodlust or {}
_current_combat.bloodlust[#_current_combat.bloodlust+1] = _current_combat:GetCombatTime()
end
end
if (override_aura_spellid[spellId] and sourceName == Details.playername) then
local auraName, texture, count, auraType, duration, expirationTime, sourceUnit, isStealable, nameplateShowPersonal, spellId, canApplyAura, isBossAura, isFromPlayerOrPlayerPet, nameplateShowAll, timeMod, v1, v2, v3, v4, v5 = Details:FindBuffCastedByUnitName(sourceName, spellId, sourceName)
if (auraName) then
local overrideTable = override_aura_spellid[spellId]
if (overrideTable.CanOverride(auraName, texture, count, auraType, duration, expirationTime, sourceUnit, isStealable, nameplateShowPersonal, spellId, canApplyAura, isBossAura, isFromPlayerOrPlayerPet, nameplateShowAll, timeMod, v1, v2, v3, v4, v5)) then
--proc
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, overrideTable.NewSpellId, spellName, "BUFF_UPTIME_IN")
local bAddToTarget, bOverrideTime = false, true
parser:add_buff_uptime(token, time+duration, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, overrideTable.NewSpellId, spellName, "BUFF_UPTIME_OUT", bAddToTarget, bOverrideTime)
--standard buff (not discounting the time with proc, this give the player how much time the buff was active overall)
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_IN")
return
end
end
elseif (spellId == 388007 or spellId == 388011) then --buff: bleesing of the summer and winter
cacheAnything.paladin_vivaldi_blessings[targetSerial] = {sourceSerial, sourceName, sourceFlags}
3 years ago
elseif (spellId == 27827) then --spirit of redemption (holy ~priest) ~spirit
local deathLog = last_events_cache[targetName]
if (not deathLog) then
deathLog = _current_combat:CreateLastEventsTable(targetName)
4 years ago
end
local i = deathLog.n
local thisEvent = deathLog[i]
3 years ago
if (not thisEvent) then
return Details:Msg("Parser Event Error -> Set to 16 DeathLogs and /reload", i, _amount_of_last_events)
end
3 years ago
thisEvent[1] = 5 --5 = buff aplication
thisEvent[2] = spellId --spellid
thisEvent[3] = 1
thisEvent[4] = time --parser time
thisEvent[5] = UnitHealth(targetName) / UnitHealthMax(targetName) --current unit heal
thisEvent[6] = sourceName --source name
thisEvent[7] = false
thisEvent[8] = false
thisEvent[9] = false
thisEvent[10] = false
i = i + 1
if (i == _amount_of_last_events+1) then
deathLog.n = 1
else
deathLog.n = i
end
C_Timer.After(0.05, function() --25/12/2022: enabled the delay to wait the combatlog dump damage events which will happen after the buff is applied
parser:dead("UNIT_DIED", time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags)
ignore_death_cache [sourceName] = true
end)
return
elseif (spellId == SPELLID_MONK_GUARD) then
--BfA monk talent
monk_guard_talent [sourceSerial] = amount
4 years ago
elseif (spellId == 272790 and cacheAnything.track_hunter_frenzy) then --hunter pet Frenzy quick fix for show the Frenzy uptime
if (pet_frenzy_cache[sourceName]) then
if (detailsFramework:IsNearlyEqual(pet_frenzy_cache[sourceName], time, 0.2)) then
return
end
end
if (not Details.in_combat) then
C_Timer.After(1, function()
if (Details.in_combat) then
if (pet_frenzy_cache[sourceName]) then
if (detailsFramework:IsNearlyEqual(pet_frenzy_cache[sourceName], time, 0.2)) then
return
end
end
return parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, sourceSerial, sourceName, sourceFlags, 0x0, spellId, spellName, "BUFF_UPTIME_IN")
end
end)
return
end
pet_frenzy_cache[sourceName] = time --when the buffIN happened
return parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, sourceSerial, sourceName, sourceFlags, 0x0, spellId, spellName, "BUFF_UPTIME_IN")
end
6 months ago
if (isCLASSIC) then
if (SHAMAN_EARTHSHIELD_BUFF[spellId]) then
TBC_EarthShieldCache[targetName] = {sourceSerial, sourceName, sourceFlags}
3 years ago
elseif (spellId == SPELLID_PRIEST_POM_BUFF) then
TBC_PrayerOfMendingCache [targetName] = {sourceSerial, sourceName, sourceFlags}
end
end
if (buffs_on_target[spellId]) then
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_IN", true)
elseif (sourceName == targetName and raid_members_cache[sourceSerial] and _in_combat) then
--player itself
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_IN")
elseif (petCache[sourceSerial] and petCache[sourceSerial][2] == targetSerial) then
--pet putting an aura on its owner
parser:add_buff_uptime(token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_IN")
elseif (buffs_to_other_players[spellId]) then
--e.g. power infusion
parser:add_buff_uptime(token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_IN")
end
3 years ago
--healing done absorbs
6 months ago
if (_parser_options.shield_overheal) then
if (shield_spellid_cache[spellId] and amount) then
if (not shield_cache[targetName]) then
shield_cache[targetName] = {}
shield_cache[targetName][spellId] = {}
shield_cache[targetName][spellId][sourceName] = amount
elseif (not shield_cache[targetName][spellId]) then
shield_cache[targetName][spellId] = {}
shield_cache[targetName][spellId][sourceName] = amount
else
shield_cache[targetName][spellId][sourceName] = amount
end
end
end
------------------------------------------------------------------------------------------------
3 years ago
--recording debuffs applied by player
elseif (auraType == "DEBUFF") then
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--spell reflection
if (sourceSerial == targetSerial and not reflection_ignore[spellId]) then
3 years ago
--self-inflicted debuff that could've been reflected
--just saving it as a boolean to check for reflections
reflection_debuffs[sourceSerial] = reflection_debuffs[sourceSerial] or {}
reflection_debuffs[sourceSerial][spellId] = true
end
if (_in_combat) then
------------------------------------------------------------------------------------------------
--buff uptime
if (crowdControlSpells[spellId] or Details.CrowdControlSpellNamesCache[spellName]) then --
--print("adding cc done", sourceName, targetName, spellId, spellName)
parser:add_cc_done (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName)
end
3 years ago
if ((bitfield_debuffs[spellName] or bitfield_debuffs[spellId]) and raid_members_cache[targetSerial]) then
bitfield_swap_cache[targetSerial] = true
end
3 years ago
if (raid_members_cache [sourceSerial]) then
--call record debuffs uptime
parser:add_debuff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "DEBUFF_UPTIME_IN")
3 years ago
elseif (raid_members_cache [targetSerial] and not raid_members_cache [sourceSerial]) then --alvo � da raide e who � alguem de fora da raide
parser:add_bad_debuff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellschool, "DEBUFF_UPTIME_IN")
end
end
end
end
3 years ago
--~refresh
function parser:buff_refresh(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellschool, tipo, amount)
if (ignoredWorldAuras[spellId]) then
return
end
if (not sourceName) then
sourceName = names_cache[spellName]
if (not sourceName) then
sourceName = "[*] " .. spellName
names_cache[spellName] = sourceName
end
sourceFlags = 0xa48
sourceSerial = ""
end
if (augmentation_aura_list[spellId]) then
Details222.SpecHelpers[1473].BuffRefresh(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellschool, tipo, amount)
end
if (tipo == "BUFF") then
6 months ago
--aura_debugger_parserfile("RE", spellName, sourceName, targetName)
if (spellId == 272790 and cacheAnything.track_hunter_frenzy) then --hunter pet Frenzy spellid
local miscActorObject = misc_cache[sourceName]
if (miscActorObject) then
--fastest way to query utility spell data
local spellTable = miscActorObject.buff_uptime_spells and miscActorObject.buff_uptime_spells._ActorTable[spellId]
if (spellTable) then
if (spellTable.actived and pet_frenzy_cache[sourceName]) then
if (detailsFramework:IsNearlyEqual(pet_frenzy_cache[sourceName], time, 0.2)) then
return
end
end
end
end
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, sourceSerial, sourceName, sourceFlags, 0x0, spellId, spellName, "BUFF_UPTIME_REFRESH")
pet_frenzy_cache[sourceName] = time
return
end
3 years ago
if (buffs_on_target[spellId]) then
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_REFRESH", true)
elseif (sourceName == targetName and raid_members_cache [sourceSerial] and _in_combat) then
--call record buffs uptime
parser:add_buff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_REFRESH")
3 years ago
elseif (petCache [sourceSerial] and petCache [sourceSerial][2] == targetSerial) then
--um pet colocando uma aura do dono
parser:add_buff_uptime (token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_REFRESH")
3 years ago
elseif (buffs_to_other_players[spellId]) then
parser:add_buff_uptime(token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_REFRESH")
end
6 months ago
if (_parser_options.shield_overheal) then
if (shield_spellid_cache[spellId] and amount) then
if (shield_cache[targetName] and shield_cache[targetName][spellId] and shield_cache[targetName][spellId][sourceName]) then
if (ignored_overheal[spellId]) then
shield_cache[targetName][spellId][sourceName] = amount --refresh gives the updated amount
return
end
--get the shield overheal
local overhealAmount = shield_cache[targetName][spellId][sourceName]
--set the new shield amount
shield_cache[targetName][spellId][sourceName] = amount
3 years ago
if (overhealAmount > 0) then
return parser:heal(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, nil, 0, ceil (overhealAmount), 0, nil, true)
end
end
end
end
------------------------------------------------------------------------------------------------
3 years ago
--recording debuffs applied by player
elseif (tipo == "DEBUFF") then
4 years ago
if (_in_combat) then
------------------------------------------------------------------------------------------------
--buff uptime
if (raid_members_cache [sourceSerial]) then
--call record debuffs uptime
parser:add_debuff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "DEBUFF_UPTIME_REFRESH")
elseif (raid_members_cache [targetSerial] and not raid_members_cache [sourceSerial]) then --alvo � da raide e o caster � inimigo
parser:add_bad_debuff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellschool, "DEBUFF_UPTIME_REFRESH", amount)
end
end
end
end
-- ~unbuff
function parser:unbuff(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellSchool, tipo, amount)
if (ignoredWorldAuras[spellId]) then
return
end
if (not sourceName) then
sourceName = names_cache[spellName]
if (not sourceName) then
sourceName = "[*] " .. spellName
names_cache[spellName] = sourceName
end
sourceFlags = 0xa48
sourceSerial = ""
end
3 years ago
if (augmentation_aura_list[spellId]) then
Details222.SpecHelpers[1473].BuffOut(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellSchool, tipo, amount)
end
if (tipo == "BUFF") then
6 months ago
--aura_debugger_parserfile("OUT", spellName, sourceName, targetName)
if (spellId == 272790 and cacheAnything.track_hunter_frenzy) then --hunter pet Frenzy spellid
if (not pet_frenzy_cache[sourceName]) then
return
end
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, sourceSerial, sourceName, sourceFlags, 0x0, spellId, spellName, "BUFF_UPTIME_OUT")
pet_frenzy_cache[sourceName] = nil
return
end
3 years ago
if (buffs_on_target[spellId]) then
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_OUT", true)
elseif (sourceName == targetName and raid_members_cache[sourceSerial] and _in_combat) then
--call record buffs uptime
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_OUT")
elseif (petCache[sourceSerial] and petCache[sourceSerial][2] == targetSerial) then
--um pet colocando uma aura do dono
parser:add_buff_uptime(token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_OUT")
3 years ago
elseif (buffs_to_other_players[spellId]) then
parser:add_buff_uptime(token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "BUFF_UPTIME_OUT")
end
if (spellId == SPELLID_MONK_GUARD) then
--BfA monk talent
if (monk_guard_talent[sourceSerial]) then
local damage_prevented = monk_guard_talent[sourceSerial] - (amount or 0)
parser:heal(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellSchool, damage_prevented, ceil (amount or 0), 0, 0, true)
end
3 years ago
elseif (spellId == 388007 or spellId == 388011) then --buff: bleesing of the summer
cacheAnything.paladin_vivaldi_blessings[targetSerial] = nil
end
------------------------------------------------------------------------------------------------
--shield overheal
6 months ago
if (_parser_options.shield_overheal) then
if (shield_spellid_cache[spellId]) then
if (shield_cache [targetName] and shield_cache [targetName][spellId] and shield_cache [targetName][spellId][sourceName]) then
if (amount) then
3 years ago
-- o amount � o que sobrou do escudo
--local overheal = escudo [alvo_name][spellid][who_name] --usando o 'amount' passado pela função
--overheal não esta dando refresh quando um valor é adicionado ao escudo
shield_cache [targetName][spellId][sourceName] = 0
3 years ago
--can't use monk guard since its overheal is computed inside the unbuff
if (amount > 0 and spellId ~= SPELLID_MONK_GUARD) then
3 years ago
--removing the nil at the end before true for is_shield, I have no documentation change about it, not sure the reason why it was addded
return parser:heal (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, nil, 0, ceil (amount), 0, 0, true) --0, 0, nil, true
else
return
end
end
shield_cache [targetName][spellId][sourceName] = 0
3 years ago
end
end
end
------------------------------------------------------------------------------------------------
3 years ago
--recording debuffs applied by player
elseif (tipo == "DEBUFF") then
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--spell reflection
if (reflection_dispels[targetSerial] and reflection_dispels[targetSerial][spellId]) then
3 years ago
--debuff was dispelled by a reflecting dispel and could've been reflected
--save the data about whom dispelled who and the spell that was dispelled
local reflection = reflection_dispels[targetSerial][spellId]
reflection_events[sourceSerial] = reflection_events[sourceSerial] or {}
reflection_events[sourceSerial][spellId] = {
who_serial = reflection.who_serial,
who_name = reflection.who_name,
who_flags = reflection.who_flags,
spellid = reflection.spellid,
spellname = reflection.spellname,
spelltype = reflection.spelltype,
time = time,
}
reflection_dispels[targetSerial][spellId] = nil
if (next(reflection_dispels[targetSerial]) == nil) then
--suggestion on how to make this better?
reflection_dispels[targetSerial] = nil
end
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--spell reflection
if (reflection_debuffs[sourceSerial] and reflection_debuffs[sourceSerial][spellId]) then
3 years ago
--self-inflicted debuff was removed, so we just clear this data
reflection_debuffs[sourceSerial][spellId] = nil
if (next(reflection_debuffs[sourceSerial]) == nil) then
3 years ago
--better way of doing this? accepting suggestions
reflection_debuffs[sourceSerial] = nil
end
end
3 years ago
if (_in_combat) then
------------------------------------------------------------------------------------------------
3 years ago
--buff uptime
if (raid_members_cache [sourceSerial]) then
--call record debuffs uptime
parser:add_debuff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, "DEBUFF_UPTIME_OUT")
elseif (raid_members_cache [targetSerial] and not raid_members_cache [sourceSerial]) then --alvo � da raide e o caster � inimigo
parser:add_bad_debuff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellSchool, "DEBUFF_UPTIME_OUT")
end
3 years ago
if ((bitfield_debuffs[spellName] or bitfield_debuffs[spellId]) and targetSerial) then
bitfield_swap_cache[targetSerial] = nil
end
end
end
end
--~crowd control ~ccdone
function parser:add_cc_done(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName)
_current_misc_container.need_refresh = true
---@type actor
local sourceActor, ownerActor = misc_cache[sourceName]
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not ownerActor) then
misc_cache[sourceName] = sourceActor
end
end
sourceActor.last_event = _tempo
if (not sourceActor.cc_done) then
sourceActor.cc_done = Details:GetOrderNumber()
sourceActor.cc_done_spells = spellContainerClass:CreateSpellContainer(container_misc)
sourceActor.cc_done_targets = {}
end
--add amount
sourceActor.cc_done = sourceActor.cc_done + 1
sourceActor.cc_done_targets[targetName] = (sourceActor.cc_done_targets[targetName] or 0) + 1
--actor spells table
local spellTable = sourceActor.cc_done_spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.cc_done_spells:GetOrCreateSpell(spellId, true)
end
spellTable.targets[targetName] = (spellTable.targets[targetName] or 0) + 1
spellTable.counter = spellTable.counter + 1
--add the crowd control for the pet owner
if (ownerActor) then
if (not ownerActor.cc_done) then
ownerActor.cc_done = Details:GetOrderNumber()
ownerActor.cc_done_spells = spellContainerClass:CreateSpellContainer(container_misc)
ownerActor.cc_done_targets = {}
end
--add amount
ownerActor.cc_done = ownerActor.cc_done + 1
ownerActor.cc_done_targets[targetName] = (ownerActor.cc_done_targets[targetName] or 0) + 1
--actor spells table
local ownerSpellTable = ownerActor.cc_done_spells._ActorTable[spellId]
if (not ownerSpellTable) then
ownerSpellTable = ownerActor.cc_done_spells:GetOrCreateSpell(spellId, true)
end
ownerSpellTable.targets[targetName] = (ownerSpellTable.targets[targetName] or 0) + 1
ownerSpellTable.counter = ownerSpellTable.counter + 1
end
if (not sourceActor.classe) then
if (sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_PLAYER) ~= 0) then
if (sourceActor.classe == "UNKNOW" or sourceActor.classe == "UNGROUPPLAYER") then
---@type actor
local damageActor = damage_cache [sourceSerial]
if (damageActor and (damageActor.classe ~= "UNKNOW" and damageActor.classe ~= "UNGROUPPLAYER")) then
sourceActor.classe = damageActor.classe
else
---@type actor
local healingActor = healing_cache[sourceSerial]
if (healingActor and (healingActor.classe ~= "UNKNOW" and healingActor.classe ~= "UNGROUPPLAYER")) then
sourceActor.classe = healingActor.classe
end
end
end
end
end
end
-----------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--MISC search key: ~buffuptime ~buffsuptime |
-----------------------------------------------------------------------------------------------------------------------------------------
function parser:add_bad_debuff_uptime(token, time, sourceGuid, sourceName, sourceFlags, targetGuid, targetName, targetFlags, targetsFlags2, spellId, spellName, spellSchool, sInOrOut, stackSize)
if (ignoredWorldAuras[spellId]) then
return
elseif (not targetName) then
3 years ago
--no target name, just quit
return
elseif (not sourceName) then
3 years ago
--no actor name, use spell name instead
sourceName = "[*] "..spellName
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--get actors
--nome do debuff ser� usado para armazenar o nome do ator
local sourceActor = misc_cache[spellName]
if (not sourceActor) then --pode ser um desconhecido ou um pet
sourceActor = _current_misc_container:GetOrCreateActor (sourceGuid, spellName, sourceFlags, true)
misc_cache[spellName] = sourceActor
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--build containers on the fly
if (not sourceActor.debuff_uptime) then
sourceActor.boss_debuff = true
sourceActor.damage_twin = sourceName
sourceActor.spellschool = spellSchool
sourceActor.damage_spellid = spellId
sourceActor.debuff_uptime = 0
sourceActor.debuff_uptime_spells = spellContainerClass:CreateSpellContainer (container_misc)
sourceActor.debuff_uptime_targets = {}
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--add amount
--update last event
sourceActor.last_event = _tempo
3 years ago
--actor target
local este_alvo = sourceActor.debuff_uptime_targets [targetName]
if (not este_alvo) then
este_alvo = Details.atributo_misc:CreateBuffTargetObject()
sourceActor.debuff_uptime_targets [targetName] = este_alvo
end
3 years ago
if (sInOrOut == "DEBUFF_UPTIME_IN") then
este_alvo.actived = true
este_alvo.activedamt = este_alvo.activedamt + 1
if (este_alvo.actived_at and este_alvo.actived) then
este_alvo.uptime = este_alvo.uptime + _tempo - este_alvo.actived_at
sourceActor.debuff_uptime = sourceActor.debuff_uptime + _tempo - este_alvo.actived_at
end
este_alvo.actived_at = _tempo
3 years ago
--death log
3 years ago
--record death log
local t = last_events_cache[targetName]
3 years ago
if (not t) then
t = _current_combat:CreateLastEventsTable(targetName)
end
3 years ago
local i = t.n
3 years ago
local thisEvent = t[i]
3 years ago
if (not thisEvent) then
return Details:Msg("Parser Event Error -> Set to 16 DeathLogs and /reload", i, _amount_of_last_events)
end
3 years ago
thisEvent[1] = 4 --4 = debuff aplication
thisEvent[2] = spellId --spellid
thisEvent[3] = 1
thisEvent[4] = time --parser time
thisEvent[5] = UnitHealth(targetName) / UnitHealthMax(targetName) --current unit heal
thisEvent[6] = sourceName --source name
thisEvent[7] = false
thisEvent[8] = false
thisEvent[9] = false
thisEvent[10] = false
i = i + 1
if (i == _amount_of_last_events+1) then
t.n = 1
else
t.n = i
end
3 years ago
elseif (sInOrOut == "DEBUFF_UPTIME_REFRESH") then
if (este_alvo.actived_at and este_alvo.actived) then
este_alvo.uptime = este_alvo.uptime + _tempo - este_alvo.actived_at
sourceActor.debuff_uptime = sourceActor.debuff_uptime + _tempo - este_alvo.actived_at
end
este_alvo.actived_at = _tempo
este_alvo.actived = true
3 years ago
--death log
3 years ago
--local name, texture, count, debuffType, duration, expirationTime, caster, canStealOrPurge, nameplateShowPersonal, spellId = UnitAura (alvo_name, spellname, nil, "HARMFUL")
--UnitAura ("Kastfall", "Gulp Frog Toxin", nil, "HARMFUL")
--6/27 15:06:18.113 SPELL_AURA_APPLIED_DOSE,Creature-0-2085-2657-20918-227617-0000FDAA05,"Cosmic Simulacrum",0xa48,0x0,Player-4184-005CFB2D,"nil",0x511,0x0,459273,"Cosmic Shards",0x20,DEBUFF,4
--6/27 15:06:18.114 SPELL_AURA_REFRESH,Creature-0-2085-2657-20918-227617-0000FDAA05,"Cosmic Simulacrum",0xa48,0x0,Player-4184-005CFB2D,"nil",0x511,0x0,459273,"Cosmic Shards",0x20,DEBUFF
3 years ago
--record death log
local t = last_events_cache[targetName]
3 years ago
if (not t) then
t = _current_combat:CreateLastEventsTable(targetName)
end
3 years ago
local i = t.n
3 years ago
local bCanAdd = true
local previousEvent = t[i-1]
if (previousEvent) then
if (previousEvent[1] == 4 and previousEvent[2] == spellId and detailsFramework.Math.IsNearlyEqual(time, previousEvent[4], 0.01)) then
--don't repeat the application of the same debuff
bCanAdd = false
end
end
3 years ago
if (bCanAdd) then
local thisEvent = t[i]
if (not thisEvent) then
return Details:Msg("Parser Event Error -> Set to 16 DeathLogs and /reload", i, _amount_of_last_events)
end
thisEvent[1] = 4 --4 = debuff aplication
thisEvent[2] = spellId --spellid
thisEvent[3] = stackSize or 1
thisEvent[4] = time --parser time
thisEvent[5] = UnitHealth(targetName) / UnitHealthMax(targetName) --current unit heal
thisEvent[6] = sourceName --source name
thisEvent[7] = false
thisEvent[8] = false
thisEvent[9] = false
thisEvent[10] = false
i = i + 1
if (i == _amount_of_last_events+1) then
t.n = 1
else
t.n = i
end
end
3 years ago
elseif (sInOrOut == "DEBUFF_UPTIME_OUT") then
if (este_alvo.actived_at and este_alvo.actived) then
este_alvo.uptime = este_alvo.uptime + Details._tempo - este_alvo.actived_at
sourceActor.debuff_uptime = sourceActor.debuff_uptime + _tempo - este_alvo.actived_at --token = actor misc object
end
3 years ago
este_alvo.activedamt = este_alvo.activedamt - 1
3 years ago
if (este_alvo.activedamt == 0) then
este_alvo.actived = false
este_alvo.actived_at = nil
else
este_alvo.actived_at = _tempo
end
end
end
-- ~debuff
---@param token string
---@param time unixtime
---@param sourceSerial guid
---@param sourceName actorname
---@param sourceFlags controlflags
---@param targetSerial guid
---@param targetName actorname
---@param targetFlags controlflags
---@param targetFlags2 number
---@param spellId spellid
---@param spellName spellname
---@param sAuraInOrOut string
---@param bAddToTarget boolean|nil not in use on debuffs at the moment
function parser:add_debuff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, sAuraInOrOut, bAddToTarget)
if (ignoredWorldAuras[spellId]) then
return
end
_current_misc_container.need_refresh = true
3 years ago
local sourceActor = misc_cache[sourceName]
if (not sourceActor) then
sourceActor = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
misc_cache[sourceName] = sourceActor
end
3 years ago
if (not sourceActor.debuff_uptime) then
sourceActor.debuff_uptime = 0
sourceActor.debuff_uptime_spells = spellContainerClass:CreateSpellContainer(container_misc)
sourceActor.debuff_uptime_targets = {}
end
3 years ago
sourceActor.last_event = _tempo
3 years ago
--actor spells table
do
local spellTable = sourceActor.debuff_uptime_spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.debuff_uptime_spells:GetOrCreateSpell(spellId, true, "DEBUFF_UPTIME")
end
return _spell_utility_func(spellTable, targetName, sourceActor, "BUFF_OR_DEBUFF", sAuraInOrOut)
end
end
--~buff
---@param token string
---@param time unixtime
---@param sourceSerial guid
---@param sourceName actorname
---@param sourceFlags controlflags
---@param targetSerial guid
---@param targetName actorname
---@param targetFlags controlflags
---@param targetFlags2 number
---@param spellId spellid
---@param spellName spellname
---@param sAuraInOrOut string
---@param bAddToTarget boolean? --special auras which has to be added to the caster and target
---@param bOverrideTime boolean?
function parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, sAuraInOrOut, bAddToTarget, bOverrideTime)
if (ignoredWorldAuras[spellId]) then
return
end
_current_misc_container.need_refresh = true
3 years ago
local sourceActor = misc_cache[sourceName]
if (not sourceActor) then
sourceActor = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
misc_cache[sourceName] = sourceActor
end
3 years ago
sourceActor.last_event = _tempo
3 years ago
--build containers on the fly if not exist
if (not sourceActor.buff_uptime) then
sourceActor.buff_uptime = 0
sourceActor.buff_uptime_spells = spellContainerClass:CreateSpellContainer(container_misc)
sourceActor.buff_uptime_targets = {}
3 years ago
end
3 years ago
--actor spells table
do
---@type spelltable
local spellTable = sourceActor.buff_uptime_spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.buff_uptime_spells:GetOrCreateSpell(spellId, true, "BUFF_UPTIME")
end
_spell_utility_func(spellTable, targetName, sourceActor, "BUFF_OR_DEBUFF", sAuraInOrOut, bOverrideTime and floor(time))
end
3 years ago
if (bAddToTarget and sourceSerial ~= targetSerial) then
local targetActor = misc_cache[targetName]
if (not targetActor) then
targetActor = _current_misc_container:GetOrCreateActor(targetSerial, targetName, targetFlags, true)
misc_cache[targetName] = targetActor
end
targetActor.last_event = _tempo
--build containers on the fly if not exist
if (not targetActor.buff_uptime) then
targetActor.buff_uptime = 0
targetActor.buff_uptime_spells = spellContainerClass:CreateSpellContainer(container_misc)
targetActor.buff_uptime_targets = {}
end
--build containers on the fly if not exist
if (not targetActor.received_buffs_spells) then
targetActor.received_buffs_spells = spellContainerClass:CreateSpellContainer(container_misc)
end
local nameWithSpellId = sourceName .. "@" .. spellId
---@type spelltable
local spellTable = targetActor.received_buffs_spells._ActorTable[nameWithSpellId]
if (not spellTable) then
spellTable = targetActor.received_buffs_spells:GetOrCreateSpell(nameWithSpellId, true, "BUFF_UPTIME")
spellTable.id = spellId
end
_spell_utility_func(spellTable, sourceName, targetActor, "BUFF_OR_DEBUFF", sAuraInOrOut, bOverrideTime and floor(time))
end
end
-----------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--ENERGY serach key: ~energy |
-----------------------------------------------------------------------------------------------------------------------------------------
local PowerEnum = Enum and Enum.PowerType
local SPELL_POWER_MANA = SPELL_POWER_MANA or (PowerEnum and PowerEnum.Mana) or 0
local SPELL_POWER_RAGE = SPELL_POWER_RAGE or (PowerEnum and PowerEnum.Rage) or 1
local SPELL_POWER_FOCUS = SPELL_POWER_FOCUS or (PowerEnum and PowerEnum.Focus) or 2
local SPELL_POWER_ENERGY = SPELL_POWER_ENERGY or (PowerEnum and PowerEnum.Energy) or 3
local SPELL_POWER_COMBO_POINTS2 = SPELL_POWER_COMBO_POINTS or (PowerEnum and PowerEnum.ComboPoints) or 4
local SPELL_POWER_RUNES = SPELL_POWER_RUNES or (PowerEnum and PowerEnum.Runes) or 5
local SPELL_POWER_RUNIC_POWER = SPELL_POWER_RUNIC_POWER or (PowerEnum and PowerEnum.RunicPower) or 6
local SPELL_POWER_SOUL_SHARDS = SPELL_POWER_SOUL_SHARDS or (PowerEnum and PowerEnum.SoulShards) or 7
local SPELL_POWER_LUNAR_POWER = SPELL_POWER_LUNAR_POWER or (PowerEnum and PowerEnum.LunarPower) or 8
local SPELL_POWER_HOLY_POWER = SPELL_POWER_HOLY_POWER or (PowerEnum and PowerEnum.HolyPower) or 9
local SPELL_POWER_ALTERNATE_POWER = SPELL_POWER_ALTERNATE_POWER or (PowerEnum and PowerEnum.Alternate) or 10
local SPELL_POWER_MAELSTROM = SPELL_POWER_MAELSTROM or (PowerEnum and PowerEnum.Maelstrom) or 11
local SPELL_POWER_CHI = SPELL_POWER_CHI or (PowerEnum and PowerEnum.Chi) or 12
local SPELL_POWER_INSANITY = SPELL_POWER_INSANITY or (PowerEnum and PowerEnum.Insanity) or 13
local SPELL_POWER_OBSOLETE = SPELL_POWER_OBSOLETE or (PowerEnum and PowerEnum.Obsolete) or 14
local SPELL_POWER_OBSOLETE2 = SPELL_POWER_OBSOLETE2 or (PowerEnum and PowerEnum.Obsolete2) or 15
local SPELL_POWER_ARCANE_CHARGES = SPELL_POWER_ARCANE_CHARGES or (PowerEnum and PowerEnum.ArcaneCharges) or 16
local SPELL_POWER_FURY = SPELL_POWER_FURY or (PowerEnum and PowerEnum.Fury) or 17
local SPELL_POWER_PAIN = SPELL_POWER_PAIN or (PowerEnum and PowerEnum.Pain) or 18
local energy_types = {
[SPELL_POWER_MANA] = true,
[SPELL_POWER_RAGE] = true,
[SPELL_POWER_ENERGY] = true,
[SPELL_POWER_RUNIC_POWER] = true,
}
3 years ago
local resource_types = {
[SPELL_POWER_INSANITY] = true, --shadow priest
[SPELL_POWER_CHI] = true, --monk
[SPELL_POWER_HOLY_POWER] = true, --paladins
[SPELL_POWER_LUNAR_POWER] = true, --balance druids
[SPELL_POWER_SOUL_SHARDS] = true, --warlock affliction
[SPELL_POWER_COMBO_POINTS2] = true, --combo points
[SPELL_POWER_MAELSTROM] = true, --shamans
[SPELL_POWER_PAIN] = true, --demonhunter tank
[SPELL_POWER_RUNES] = true, --dk
[SPELL_POWER_ARCANE_CHARGES] = true, --mage
[SPELL_POWER_FURY] = true, --warrior demonhunter dps
}
3 years ago
local resourcePowerType = {
[SPELL_POWER_COMBO_POINTS2] = SPELL_POWER_ENERGY, --combo points
[SPELL_POWER_SOUL_SHARDS] = SPELL_POWER_MANA, --warlock
[SPELL_POWER_LUNAR_POWER] = SPELL_POWER_MANA, --druid
[SPELL_POWER_HOLY_POWER] = SPELL_POWER_MANA, --paladin
[SPELL_POWER_INSANITY] = SPELL_POWER_MANA, --shadowpriest
[SPELL_POWER_MAELSTROM] = SPELL_POWER_MANA, --shaman
[SPELL_POWER_CHI] = SPELL_POWER_MANA, --monk
[SPELL_POWER_PAIN] = SPELL_POWER_ENERGY, --demonhuinter
[SPELL_POWER_RUNES] = SPELL_POWER_RUNIC_POWER, --dk
[SPELL_POWER_ARCANE_CHARGES] = SPELL_POWER_MANA, --mage
[SPELL_POWER_FURY] = SPELL_POWER_RAGE, --warrior
}
3 years ago
Details.resource_strings = {
[SPELL_POWER_COMBO_POINTS2] = "Combo Point",
[SPELL_POWER_SOUL_SHARDS] = "Soul Shard",
[SPELL_POWER_LUNAR_POWER] = "Lunar Power",
[SPELL_POWER_HOLY_POWER] = "Holy Power",
[SPELL_POWER_INSANITY] = "Insanity",
[SPELL_POWER_MAELSTROM] = "Maelstrom",
[SPELL_POWER_CHI] = "Chi",
[SPELL_POWER_PAIN] = "Pain",
[SPELL_POWER_RUNES] = "Runes",
[SPELL_POWER_ARCANE_CHARGES] = "Arcane Charge",
[SPELL_POWER_FURY] = "Rage",
}
3 years ago
Details.resource_icons = {
[SPELL_POWER_COMBO_POINTS2] = {file = [[Interface\PLAYERFRAME\ClassOverlayComboPoints]], coords = {58/128, 74/128, 25/64, 39/64}},
[SPELL_POWER_SOUL_SHARDS] = {file = [[Interface\PLAYERFRAME\UI-WARLOCKSHARD]], coords = {3/64, 17/64, 2/128, 16/128}},
[SPELL_POWER_LUNAR_POWER] = {file = [[Interface\PLAYERFRAME\DruidEclipse]], coords = {117/256, 140/256, 83/128, 115/128}},
[SPELL_POWER_HOLY_POWER] = {file = [[Interface\PLAYERFRAME\PALADINPOWERTEXTURES]], coords = {75/256, 94/256, 87/128, 100/128}},
[SPELL_POWER_INSANITY] = {file = [[Interface\PLAYERFRAME\Priest-ShadowUI]], coords = {119/256, 150/256, 61/128, 94/128}},
[SPELL_POWER_MAELSTROM] = {file = [[Interface\PLAYERFRAME\MonkNoPower]], coords = {0, 1, 0, 1}},
[SPELL_POWER_CHI] = {file = [[Interface\PLAYERFRAME\MonkLightPower]], coords = {0, 1, 0, 1}},
[SPELL_POWER_PAIN] = {file = [[Interface\PLAYERFRAME\Deathknight-Energize-Blood]], coords = {0, 1, 0, 1}},
[SPELL_POWER_RUNES] = {file = [[Interface\PLAYERFRAME\UI-PlayerFrame-Deathknight-SingleRune]], coords = {0, 1, 0, 1}},
[SPELL_POWER_ARCANE_CHARGES] = {file = [[Interface\PLAYERFRAME\MageArcaneCharges]], coords = {68/256, 90/256, 68/128, 91/128}},
[SPELL_POWER_FURY] = {file = [[Interface\PLAYERFRAME\UI-PlayerFrame-Deathknight-Blood-On]], coords = {0, 1, 0, 1}},
}
3 years ago
local alternatePowerEnableFrame = CreateFrame("frame", "DetailsAlternatePowerEventHandler")
local alternatePowerMonitorFrame = CreateFrame("frame", "DetailsAlternatePowerMonitor")
if not detailsFramework:IsAddonApocalypseWow() then
alternatePowerEnableFrame:RegisterEvent("UNIT_POWER_BAR_SHOW")
alternatePowerEnableFrame:RegisterEvent("ENCOUNTER_END")
end
alternatePowerEnableFrame.IsRunning = false
3 years ago
--alternate power will only run when the encounter has a alternate power bar
alternatePowerEnableFrame:SetScript("OnEvent", function(self, event)
if (event == "UNIT_POWER_BAR_SHOW") then
alternatePowerMonitorFrame:RegisterEvent("UNIT_POWER_UPDATE") -- 8.0
alternatePowerEnableFrame.IsRunning = true
elseif (alternatePowerEnableFrame.IsRunning and (event == "ENCOUNTER_END" or event == "PLAYER_REGEN_ENABLED")) then
alternatePowerMonitorFrame:UnregisterEvent("UNIT_POWER_UPDATE")
alternatePowerEnableFrame.IsRunning = false
end
end)
local onUnitPowerUpdate = function(self, event, unitID, powerType)
if (powerType == "ALTERNATE") then
local actorName = Details:GetFullName(unitID)
if (actorName) then
--weird bug on cata as described below
if (not _current_combat.alternate_power) then
_current_combat.alternate_power = {}
end
local power = _current_combat.alternate_power[actorName] --cata: 120x Details/core/parser.lua:3694: attempt to index field 'alternate_power' (a nil value)
if (not power) then
power = _current_combat:CreateAlternatePowerTable(actorName)
end
local currentPower = UnitPower(unitID, 10)
if (currentPower and currentPower > power.last) then
local addPower = currentPower - power.last
power.total = power.total + addPower
3 years ago
--main actor
local actorObject = energy_cache[actorName]
if (not actorObject) then
--as alternate power bars does not trigger for pets, this is guaranteed to be a player actor
actorObject = _current_energy_container:GetOrCreateActor(UnitGUID(unitID), actorName, 0x514, true)
energy_cache[actorName] = actorObject
end
3 years ago
actorObject.alternatepower = actorObject.alternatepower + addPower
_current_energy_container.need_refresh = true
end
3 years ago
power.last = currentPower or 0
end
end
end
alternatePowerMonitorFrame:SetScript("OnEvent", onUnitPowerUpdate)
---this function captures when the energy of a unit is at its max capacity on classes which auto regenerates it's power such like Rogues
---staying at max capacity prevents it to generate more energy and causes a power overflow
local regen_power_overflow_check = function()
if (not _in_combat) then
return
end
3 years ago
for playerName, powerType in pairs(auto_regen_cache) do
local currentPower = UnitPower(playerName, powerType) or 0
local maxPower = UnitPowerMax(playerName, powerType) or 1
3 years ago
if (currentPower == maxPower) then
--power overflow
local energyObject = energy_cache[playerName]
if (energyObject) then
energyObject.passiveover = energyObject.passiveover + AUTO_REGEN_PRECISION
end
end
end
end
3 years ago
-- ~energy ~resource
function parser:energize (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellType, amount, overpower, powerType, altpower)
if (not sourceName) then
sourceName = "[*] " .. spellName
elseif (not targetName) then
return
end
3 years ago
--get resource type
local bIsResource, resourceAmount, resourceId = resourcePowerType[powerType], amount, powerType
3 years ago
--check if is valid
if (not energy_types[powerType] and not bIsResource) then
return
3 years ago
elseif (bIsResource) then
powerType = bIsResource
amount = 0
end
3 years ago
overpower = overpower or 0
_current_energy_container.need_refresh = true
--get actors
---@type actor
local sourceActor = energy_cache[sourceName]
local ownerActor
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_energy_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
sourceActor.powertype = powerType
if (ownerActor) then
ownerActor.powertype = powerType
end
if (not ownerActor) then
energy_cache[sourceName] = sourceActor
end
end
3 years ago
if (not sourceActor.powertype) then
sourceActor.powertype = powerType
end
3 years ago
---@type actor
local targetActor = energy_cache[targetName]
local ownerTarget
if (not targetActor) then
targetActor, ownerTarget, targetName = _current_energy_container:GetOrCreateActor(targetSerial, targetName, targetFlags, true)
targetActor.powertype = powerType
if (ownerTarget) then
ownerTarget.powertype = powerType
end
if (not ownerTarget) then
energy_cache[targetName] = targetActor
end
end
3 years ago
if (targetActor.powertype ~= sourceActor.powertype) then
return
end
3 years ago
sourceActor.last_event = _tempo
3 years ago
--amount add
3 years ago
if (not bIsResource) then
3 years ago
--add to targets
sourceActor.targets[targetName] = (sourceActor.targets[targetName] or 0) + amount
3 years ago
--add to combat total
_current_total[3][powerType] = _current_total[3][powerType] + amount
3 years ago
if (sourceActor.grupo) then
_current_gtotal [3] [powerType] = _current_gtotal [3] [powerType] + amount
end
3 years ago
--regen produced amount
sourceActor.total = sourceActor.total + amount
sourceActor.totalover = sourceActor.totalover + overpower
3 years ago
--target regenerated amount
targetActor.received = targetActor.received + amount
3 years ago
--owner
if (ownerActor) then
ownerActor.total = ownerActor.total + amount
end
3 years ago
--actor spells table
local spellTable = sourceActor.spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.spells:GetOrCreateSpell(spellId, true, token)
end
3 years ago
--return spell:Add (alvo_serial, alvo_name, alvo_flags, amount, who_name, powertype)
return _spell_energy_func (spellTable, targetSerial, targetName, targetFlags, amount, sourceName, powerType, overpower)
else
3 years ago
--is a resource
sourceActor.resource = sourceActor.resource + resourceAmount
sourceActor.resource_type = resourceId
end
end
3 years ago
-----------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--MISC search key: ~cooldown |
-----------------------------------------------------------------------------------------------------------------------------------------
3 years ago
function parser:add_defensive_cooldown(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName)
_current_misc_container.need_refresh = true
3 years ago
local sourceActor, ownerActor = misc_cache[sourceName], nil
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not ownerActor) then
misc_cache[sourceName] = sourceActor
end
end
3 years ago
if (not sourceActor.cooldowns_defensive) then
sourceActor.cooldowns_defensive = Details:GetOrderNumber(sourceName)
sourceActor.cooldowns_defensive_targets = {}
sourceActor.cooldowns_defensive_spells = spellContainerClass:CreateSpellContainer(container_misc)
end
3 years ago
--actor cooldowns used
sourceActor.cooldowns_defensive = sourceActor.cooldowns_defensive + 1
3 years ago
--combat totals
_current_total[4].cooldowns_defensive = _current_total[4].cooldowns_defensive + 1
if (sourceActor.grupo) then
_current_gtotal[4].cooldowns_defensive = _current_gtotal[4].cooldowns_defensive + 1
if (sourceName == targetName) then
3 years ago
--last events
local t = last_events_cache[sourceName]
3 years ago
if (not t) then
t = _current_combat:CreateLastEventsTable(sourceName)
end
3 years ago
local i = t.n
local thisEvent = t [i]
3 years ago
thisEvent[1] = 1 --true if this is a damage || false for healing || 1 for cooldown
thisEvent[2] = spellId --spellid || false if this is a battle ress line
thisEvent[3] = 1 --amount of damage or healing
thisEvent[4] = time
thisEvent[5] = UnitHealth(sourceName) / UnitHealthMax(sourceName)
thisEvent[6] = sourceName
3 years ago
i = i + 1
if (i == _amount_of_last_events+1) then
t.n = 1
else
t.n = i
end
3 years ago
sourceActor.last_cooldown = {time, spellId}
end
end
3 years ago
--update last event
sourceActor.last_event = _tempo
3 years ago
--actor targets
sourceActor.cooldowns_defensive_targets[targetName] = (sourceActor.cooldowns_defensive_targets [targetName] or 0) + 1
3 years ago
--actor spells table
local spellTable = sourceActor.cooldowns_defensive_spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.cooldowns_defensive_spells:GetOrCreateSpell(spellId, true, token)
end
3 years ago
if (_hook_cooldowns) then
3 years ago
--send event to registred functions
for i = 1, #_hook_cooldowns_container do
local successful, errorText = pcall(_hook_cooldowns_container[i], nil, token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, spellId, spellName)
if (not successful) then
Details:Msg("error occurred on a cooldown hook function:", errorText)
end
end
end
3 years ago
return _spell_utility_func(spellTable, targetName, token, "BUFF_OR_DEBUFF", "COOLDOWN")
end
3 years ago
--serach key: ~interrupt
---comment: this function is called when a spell is interrupted
---@param token string
---@param time unixtime
---@param sourceSerial guid
---@param sourceName actorname
---@param sourceFlags controlflags
---@param targetGUID guid
---@param targetName actorname
---@param targetFlags controlflags
---@param targetFlags2 number
---@param spellId spellid
---@param spellName spellname
---@param spellType spellschool
---@param extraSpellID spellid
---@param extraSpellName spellname
---@param extraSchool spellschool
function parser:interrupt(token, time, sourceSerial, sourceName, sourceFlags, targetGUID, targetName, targetFlags, targetFlags2, spellId, spellName, spellType, extraSpellID, extraSpellName, extraSchool)
--quake affix from mythic+
if (spellId == 240448) then
return
end
if (not sourceName) then
sourceName = "[*] " .. spellName
elseif (not targetName) then
return
end
3 years ago
_current_misc_container.need_refresh = true
------------------------------------------------------------------------------------------------
3 years ago
--get actors
local petName, ownerName, ownerGUID, ownerFlags
---@type actorutility, actorutility
local sourceActor, ownerActor = misc_cache[sourceName], nil
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not ownerActor) then
misc_cache[sourceName] = sourceActor
end
end
3 years ago
if (not ownerActor) then
petName, ownerName, ownerGUID, ownerFlags = petContainer.GetOwner(sourceSerial, targetName)
if (petName) then
ownerActor = _current_misc_container:GetOrCreateActor(ownerGUID, ownerName, ownerFlags, true)
end
end
------------------------------------------------------------------------------------------------
3 years ago
--build containers on the fly
if (not sourceActor.interrupt) then
sourceActor.interrupt = Details:GetOrderNumber()
sourceActor.interrupt_cast_overlap = 0
sourceActor.interrupt_targets = {}
sourceActor.interrupt_spells = spellContainerClass:CreateSpellContainer(container_misc)
sourceActor.interrompeu_oque = {}
end
3 years ago
------------------------------------------------------------------------------------------------
3 years ago
--add amount
3 years ago
--actor interrupt amount
sourceActor.interrupt = sourceActor.interrupt + 1
3 years ago
--combat totals
_current_total[4].interrupt = _current_total[4].interrupt + 1
3 years ago
if (sourceActor.grupo) then
_current_gtotal[4].interrupt = _current_gtotal[4].interrupt + 1
end
3 years ago
--update last event
sourceActor.last_event = _tempo
3 years ago
--spells interrupted
sourceActor.interrompeu_oque[extraSpellID] = (sourceActor.interrompeu_oque[extraSpellID] or 0) + 1
3 years ago
--actor targets
sourceActor.interrupt_targets[targetName] = (sourceActor.interrupt_targets[targetName] or 0) + 1
3 years ago
--actor spells table
local spell = sourceActor.interrupt_spells._ActorTable[spellId]
if (not spell) then
spell = sourceActor.interrupt_spells:GetOrCreateSpell(spellId, true, token)
end
_spell_utility_func(spell, targetName, token, extraSpellID, extraSpellName)
if (spellId == 19647) then
--spell lock (warlock pet)
--Details:Msg("warlock pet interrupt, owner:", (ownerActor and ownerActor.nome or "no owner"))
end
3 years ago
--interrupt overlaps
--get the list of interrupt attempts by this player
---@type table<guid, interrupt_overlap[]>
local interruptCastsOnTarget = interruptOverlapCache[targetGUID]
if (interruptCastsOnTarget) then
--iterate among interrupt attempts on this target and find the one that matches the time of the interrupt and the source name
for i = #interruptCastsOnTarget, 1, -1 do
---@type interrupt_overlap
local interruptAttempt = interruptCastsOnTarget[i]
if (interruptAttempt.sourceName == sourceName) then
if (detailsFramework.Math.IsNearlyEqual(time, interruptAttempt.time, 0.1)) then
--mark as a success interrupt
interruptAttempt.interrupted = true
break
end
end
end
end
--if the interrupt is from a pet, then we need to add the interrupt to the owner
if (ownerActor) then
if (not ownerActor.interrupt) then
ownerActor.interrupt = Details:GetOrderNumber()
ownerActor.interrupt_targets = {}
ownerActor.interrupt_spells = spellContainerClass:CreateSpellContainer(container_misc)
ownerActor.interrompeu_oque = {}
end
3 years ago
ownerActor.last_event = _tempo
--total interrupts
ownerActor.interrupt = ownerActor.interrupt + 1
3 years ago
--add to interrupt targets
ownerActor.interrupt_targets[targetName] = (ownerActor.interrupt_targets[targetName] or 0) + 1
3 years ago
--which spells this actor interrupted
ownerActor.interrompeu_oque[extraSpellID] = (ownerActor.interrompeu_oque[extraSpellID] or 0) + 1
3 years ago
--owner spells table
local spell = ownerActor.interrupt_spells._ActorTable[spellId]
if (not spell) then
spell = ownerActor.interrupt_spells:GetOrCreateSpell(spellId, true, token)
end
_spell_utility_func(spell, targetName, token, extraSpellID, extraSpellName)
3 years ago
--pet interrupt
if (_hook_interrupt) then
3 years ago
for _, func in ipairs(_hook_interrupt_container) do
func(nil, token, time, ownerActor.serial, ownerActor.nome, ownerActor.flag_original, targetGUID, targetName, targetFlags, spellId, spellName, spellType, extraSpellID, extraSpellName, extraSchool)
end
end
else
3 years ago
--player interrupt
if (_hook_interrupt) then
3 years ago
for _, func in ipairs(_hook_interrupt_container) do
func(nil, token, time, sourceSerial, sourceName, sourceFlags, targetGUID, targetName, targetFlags, spellId, spellName, spellType, extraSpellID, extraSpellName, extraSchool)
end
end
end
end
3 years ago
6 months ago
---search key: ~spellcast ~castspell ~cast ~casts
---comment: this function is called when a spell is casted
---@param token string
---@param time number
---@param sourceSerial string
---@param sourceName string
---@param sourceFlags number
---@param targetGUID string
---@param targetName string
---@param targetFlags number
---@param targetRaidFlags number
---@param spellId number
---@param spellName string
---@param spellType number?
---@param extraSpellID number?
---@param extraSpellName string?
---@param extraSchool number?
function parser:spellcast(token, time, sourceSerial, sourceName, sourceFlags, targetGUID, targetName, targetFlags, targetRaidFlags, spellId, spellName, spellType, extraSpellID, extraSpellName, extraSchool)
3 years ago
--only capture if is in combat
if (not _in_combat) then
return
end
3 years ago
if (not sourceName) then
sourceName = "[*] " .. spellName
end
6 months ago
if (Details.debug_spell_cast) then
if (LIB_OPEN_RAID_CROWDCONTROL[spellId]) then
Details:Msg("Spell casted (parser):", sourceName, targetName, spellName, spellId)
end
end
---@type actor, actor
local sourceActor, ownerActor = misc_cache[sourceSerial] or misc_cache_pets[sourceSerial] or misc_cache[sourceName], misc_cache_petsOwners[sourceSerial]
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (ownerActor) then
if (sourceSerial ~= "") then
misc_cache_pets [sourceSerial] = sourceActor
misc_cache_petsOwners [sourceSerial] = ownerActor
end
if (not misc_cache[ownerActor.serial] and ownerActor.serial ~= "") then
misc_cache[ownerActor.serial] = ownerActor
end
else
if (sourceFlags) then
misc_cache[sourceName] = sourceActor
end
end
end
3 years ago
--check if this is an item usage
spellId = Details222.OnUseItem.Trinkets[spellId] or spellId
------------------------------------------------------------------------------------------------
3 years ago
--build containers on the fly
--amount of casts by actors ~casts
local castsByPlayer = _current_combat.amountCasts[sourceName]
if (not castsByPlayer) then
castsByPlayer = {}
_current_combat.amountCasts[sourceName] = castsByPlayer
end
if (ownerActor) then
--add a cast to the owner
local ownerName = ownerActor.nome
castsByPlayer = _current_combat.amountCasts[ownerName]
if (not castsByPlayer) then
castsByPlayer = {}
_current_combat.amountCasts[ownerName] = castsByPlayer
end
end
--rampage cast spam
if (spellId == 184367 or spellId == 184707 or spellId == 201364) then --rampage spellIds (IDs from Retail - wow patch 10.1.0)
local latestRampageCastByPlayer = (cacheAnything.rampage_cast_amount[sourceName] or 0)
if (latestRampageCastByPlayer > time - 0.8) then
return
end
cacheAnything.rampage_cast_amount[sourceName] = time
end
local amountOfCasts = _current_combat.amountCasts[sourceName][spellName] or 0
amountOfCasts = amountOfCasts + 1
_current_combat.amountCasts[sourceName][spellName] = amountOfCasts
3 years ago
--pet cast add to owner
if (ownerActor) then
local ownerName = ownerActor.nome
local amountOfCasts = _current_combat.amountCasts[ownerName][spellName] or 0
amountOfCasts = amountOfCasts + 1
_current_combat.amountCasts[ownerName][spellName] = amountOfCasts
end
6 months ago
if (Details.debug_spell_cast) then
if (LIB_OPEN_RAID_CROWDCONTROL[spellId]) then
Details:Msg("Spell casted (db):", sourceActor.nome, targetName, spellName, spellId)
end
end
--spell interrupt overlap
local interruptSpells = LIB_OPEN_RAID_SPELL_INTERRUPT
--check if this is an interrupt spell
if (interruptSpells[spellId]) then
interruptOverlapCache[targetGUID] = interruptOverlapCache[targetGUID] or {}
---@type interrupt_overlap
local spellOverlapData = {
time = time,
sourceName = sourceName,
spellId = spellId,
targetName = targetName,
extraSpellID = extraSpellID,
used = false,
interrupted = false,
}
--store the interrupt attempt in a table
table.insert(interruptOverlapCache[targetGUID], spellOverlapData)
end
------------------------------------------------------------------------------------------------
--record cooldowns cast which can't track with buff applyed
--a player is the caster
if (raid_members_cache[sourceSerial]) then
--check if is a cooldown
local cooldownInfo = defensive_cooldowns[spellId]
if (cooldownInfo) then
if (not targetName) then
if (cooldownInfo.type == 2 or cooldownInfo.type == 3) then
targetName = sourceName
elseif (cooldownInfo.type == 4) then
targetName = Loc ["STRING_RAID_WIDE"]
else
targetName = "--x--x--"
end
end
return parser:add_defensive_cooldown(token, time, sourceSerial, sourceName, sourceFlags, targetGUID, targetName, targetFlags, targetRaidFlags, spellId, spellName)
end
else
3 years ago
--enemy successful casts (not interrupted)
if (bitBand(sourceFlags, 0x00000040) ~= 0 and sourceName) then --byte 2 = 4 (enemy)
3 years ago
--damager
---@type actor
local enemyActorObject = damage_cache[sourceSerial]
if (not enemyActorObject) then
enemyActorObject = _current_damage_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
end
if (enemyActorObject) then
3 years ago
--actor spells table
---@type spelltable
local spellTable = enemyActorObject.spells._ActorTable[spellId]
if (not spellTable) then
spellTable = enemyActorObject.spells:GetOrCreateSpell(spellId, true, token)
end
spellTable.successful_casted = spellTable.successful_casted + 1
end
--add the spellId in the enemy_cast_cache table to store the time the enemy successfully cast a spell
--check if the spell is in the table
local enemyName = sourceName
if (not enemy_cast_cache[time]) then
enemy_cast_cache[time] = {enemyName, spellId, 1}
else
enemy_cast_cache[time][3] = enemy_cast_cache[time][3] + 1
end
end
end
end
3 years ago
--serach key: ~dispel
---@param token string
---@param time unixtime
---@param sourceSerial string
---@param sourceName string
---@param sourceFlags number
---@param targetSerial string
---@param targetName string
---@param targetFlags number
---@param targetFlags2 number
---@param spellId number
---@param spellName string
---@param spellType number
---@param extraSpellID number
---@param extraSpellName string
---@param extraSchool number
function parser:dispell(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellType, extraSpellID, extraSpellName, extraSchool, auraType)
if (not sourceName) then
sourceName = "[*] " .. extraSpellName
end
if (not targetName) then
targetName = "[*] " .. spellId
end
3 years ago
_current_misc_container.need_refresh = true
3 years ago
---@type actor, actor
local sourceActor, ownerActor = misc_cache[sourceName]
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not ownerActor) then
misc_cache[sourceName] = sourceActor
end
end
--build containers on the fly
if (not sourceActor.dispell) then
---@type number
sourceActor.dispell = Details:GetOrderNumber(sourceName)
---@type table<actorname, number>
sourceActor.dispell_targets = {}
---@type spellcontainer
sourceActor.dispell_spells = spellContainerClass:CreateSpellContainer(container_misc)
---@type table<spellid, number>
sourceActor.dispell_oque = {}
end
3 years ago
--spell reflection
if (reflection_dispelid[spellId]) then
3 years ago
--this aura could've been reflected to the caster after the dispel
--save data about whom was dispelled by who and what spell it was
reflection_dispels[targetSerial] = reflection_dispels[targetSerial] or {}
reflection_dispels[targetSerial][extraSpellID] = {
who_serial = sourceSerial,
who_name = sourceName,
who_flags = sourceFlags,
spellid = spellId,
spellname = spellName,
spelltype = spellType,
}
end
3 years ago
--last event update
sourceActor.last_event = _tempo
3 years ago
--total dispells in combat
_current_total[4].dispell = _current_total[4].dispell + 1
3 years ago
if (sourceActor.grupo) then
_current_gtotal[4].dispell = _current_gtotal[4].dispell + 1
end
3 years ago
--actor dispell amount
sourceActor.dispell = sourceActor.dispell + 1
3 years ago
--dispelled what
if (extraSpellID) then
sourceActor.dispell_oque[extraSpellID] = (sourceActor.dispell_oque[extraSpellID] or 0) + 1
end
3 years ago
--actor targets
sourceActor.dispell_targets[targetName] = (sourceActor.dispell_targets[targetName] or 0) + 1
3 years ago
--actor spells table
---@type spelltable
local spellTable = sourceActor.dispell_spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.dispell_spells:GetOrCreateSpell(spellId, true, token)
end
_spell_utility_func(spellTable, targetName, token, extraSpellID, extraSpellName)
3 years ago
--is has an owner, add the dispel to the owner as well
if (ownerActor) then
if (not ownerActor.dispell) then
ownerActor.dispell = Details:GetOrderNumber(sourceName)
ownerActor.dispell_targets = {}
ownerActor.dispell_spells = spellContainerClass:CreateSpellContainer(container_misc)
ownerActor.dispell_oque = {}
end
3 years ago
ownerActor.dispell = ownerActor.dispell + 1
ownerActor.dispell_targets[targetName] = (ownerActor.dispell_targets[targetName] or 0) + 1
ownerActor.last_event = _tempo
if (extraSpellID) then
ownerActor.dispell_oque[extraSpellID] = (ownerActor.dispell_oque[extraSpellID] or 0) + 1
end
end
end
--serach key: ~ress
function parser:ress(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName)
if (bitBand(sourceFlags, AFFILIATION_GROUP) == 0) then
return
end
3 years ago
--do not register ress if not in combat
if (not Details.in_combat) then
return
end
_current_misc_container.need_refresh = true
3 years ago
--main actor
local sourceActor, ownerActor = misc_cache[sourceName]
if (not sourceActor) then
sourceActor, ownerActor, sourceName = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not ownerActor) then --if not a pet, add no cache
misc_cache[sourceName] = sourceActor
end
end
3 years ago
--update last event
sourceActor.last_event = _tempo
--build containers on the fly
if (not sourceActor.ress) then
sourceActor.ress = Details:GetOrderNumber(sourceName)
sourceActor.ress_targets = {}
sourceActor.ress_spells = spellContainerClass:CreateSpellContainer(container_misc) --cria o container das habilidades usadas para interromper
end
3 years ago
--add amount
_current_total[4].ress = _current_total[4].ress + 1
if (sourceActor.grupo) then
_current_combat.totals_grupo[4].ress = _current_combat.totals_grupo[4].ress + 1
3 years ago
end
3 years ago
--add ress amount
sourceActor.ress = sourceActor.ress + 1
3 years ago
--add battle ress
if (UnitAffectingCombat(sourceName)) then
--search for the latest death of the target actor
3 years ago
for i = 1, #_current_combat.last_events_tables do
if (_current_combat.last_events_tables[i][3] == targetName) then
local deathLog = _current_combat.last_events_tables[i][1] --deathinfo index 1 = a table with the death log
local jaTem = false
for _, evento in ipairs(deathLog) do
if (evento[1] and not evento[3]) then
jaTem = true
end
end
3 years ago
if (not jaTem) then
tinsert(_current_combat.last_events_tables[i][1], 1, {
2,
spellId,
3 years ago
1,
time,
UnitHealth(targetName) / UnitHealthMax(targetName),
sourceName
})
break
end
end
end
3 years ago
if (_hook_battleress) then
3 years ago
for _, func in ipairs(_hook_battleress_container) do
func (nil, token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, spellId, spellName)
end
end
3 years ago
end
--actor targets
sourceActor.ress_targets[targetName] = (sourceActor.ress_targets[targetName] or 0) + 1
3 years ago
--actor spells table
local spellTable = sourceActor.ress_spells._ActorTable[spellId]
if (not spellTable) then
spellTable = sourceActor.ress_spells:GetOrCreateSpell(spellId, true, token)
end
return _spell_utility_func(spellTable, targetName, token)
end
--serach key: ~cc
function parser:break_cc(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellType, extraSpellID, extraSpellName, extraSchool, auraType)
if (not crowdControlSpells[spellId]) then
3 years ago
return
elseif (bitBand(sourceFlags, AFFILIATION_GROUP) == 0) then
return
3 years ago
elseif (not targetName) then
return --no target name, just quit
end
if (not spellName) then
spellName = "Melee"
end
3 years ago
if (not sourceName) then
sourceName = "[*] " .. spellName --if there's no sourceName, use spellName instead
sourceFlags = 0xa48
sourceSerial = ""
end
_current_misc_container.need_refresh = true
---@type actorutility, actorutility
local sourceActor, ownerActor = misc_cache[sourceName], nil
if (not sourceActor) then --unknown if is a pet or player
sourceActor, ownerActor, sourceName = _current_misc_container:GetOrCreateActor(sourceSerial, sourceName, sourceFlags, true)
if (not ownerActor) then --not a pet: add to cache
misc_cache[sourceName] = sourceActor
end
end
3 years ago
--create the spell container on the fly
if (not sourceActor.cc_break) then
sourceActor.cc_break = Details:GetOrderNumber()
sourceActor.cc_break_targets = {}
sourceActor.cc_break_oque = {}
---@type spellcontainer
sourceActor.cc_break_spells = spellContainerClass:CreateSpellContainer(container_misc)
end
3 years ago
sourceActor.last_event = _tempo
--add amount
_current_total[4].cc_break = _current_total[4].cc_break + 1
if (sourceActor.grupo) then
_current_combat.totals_grupo[4].cc_break = _current_combat.totals_grupo[4].cc_break + 1
3 years ago
end
3 years ago
--add amount
sourceActor.cc_break = sourceActor.cc_break + 1
3 years ago
--broke what
sourceActor.cc_break_oque[spellId] = (sourceActor.cc_break_oque[spellId] or 0) + 1
3 years ago
--actor targets
sourceActor.cc_break_targets[targetName] = (sourceActor.cc_break_targets[targetName] or 0) + 1
---@type spelltable
local spellTable = sourceActor.cc_break_spells._ActorTable[extraSpellID]
if (not spellTable) then
spellTable = sourceActor.cc_break_spells:GetOrCreateSpell(extraSpellID, true, token)
end
return _spell_utility_func(spellTable, targetName, token, spellId, spellName)
end
--serach key: ~dead ~death ~morte
---when a player dies, save the events that lead to his death
---this is used to show the last events before the player died under the Deaths display
---the first index of the table which hold a single event tells the type of event happened, there are the types:
---boolean true: the player took damage
---boolean false: the player received heal from someone
---number 1: the player used a cooldown
---number 2: the player received a battle res
---number 3: tell which was the latest cooldown used by the player
---number 4: debuff the player received
---number 5: buff the player received
---number 6: emeny casted a spell
---@param token string
---@param time number
---@param sourceSerial string
---@param sourceName string
---@param sourceFlags number
---@param targetSerial string
---@param targetName string
---@param targetFlags number
function parser:dead(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags)
---@cast Details222 details222
if (petContainer.Pets[targetSerial]) then
petContainer.RemovePet(targetSerial)
end
--early checks and fixes
if (not targetName) then
return
end
---@type actordamage
local damageActor = _current_damage_container:GetActor(targetName)
--check if the dead actor is an actor outside the player group, for instance a pvp player or a npc
if (_in_combat and targetFlags and (not damageActor or (bitBand(targetFlags, 0x00000008) ~= 0 and not damageActor.grupo))) then
3 years ago
--frags
if (Details.only_pvp_frags and (bitBand(targetFlags, 0x00000400) == 0 or (bitBand(targetFlags, 0x00000040) == 0 and bitBand(targetFlags, 0x00000020) == 0))) then --byte 2 = 4 (HOSTILE) byte 3 = 4 (OBJECT_TYPE_PLAYER)
return
end
3 years ago
if (not _current_combat.frags[targetName]) then
_current_combat.frags[targetName] = 1
else
_current_combat.frags[targetName] = _current_combat.frags[targetName] + 1
end
3 years ago
_current_combat.frags_need_refresh = true
3 years ago
--player death
elseif (not UnitIsFeignDeath(targetName)) then
if (
3 years ago
--player in your group
(bitBand(targetFlags, AFFILIATION_GROUP) ~= 0 or (damageActor and damageActor.grupo)) and
3 years ago
--must be a player
bitBand(targetFlags, OBJECT_TYPE_PLAYER) ~= 0 and
3 years ago
--must be in combat
_in_combat
) then
if (ignore_death_cache[targetName]) then
ignore_death_cache[targetName] = nil
return
end
local bIsMythicRun = false
--check if this is a mythic+ run for overall deaths
6 months ago
local mythicLevel = C_ChallengeMode and C_ChallengeMode.GetActiveKeystoneInfo and C_ChallengeMode.GetActiveKeystoneInfo() --classic wow doesn't not have C_ChallengeMode API
if (mythicLevel and type(mythicLevel) == "number" and mythicLevel >= 2) then --several checks to be future proof
bIsMythicRun = true
end
_current_misc_container.need_refresh = true
3 years ago
--combat totals
_current_total[4].dead = _current_total[4].dead + 1
_current_gtotal[4].dead = _current_gtotal[4].dead + 1
3 years ago
--main actor no container de misc que ir� armazenar a morte
local thisPlayer, meu_dono = misc_cache [targetName]
3 years ago
if (not thisPlayer) then --pode ser um desconhecido ou um pet
thisPlayer, meu_dono, sourceName = _current_misc_container:GetOrCreateActor (targetSerial, targetName, targetFlags, true)
if (not meu_dono) then --se n�o for um pet, add no cache
misc_cache [targetName] = thisPlayer
end
end
--table where the events will be placed in order, other events will also be added, for example, the last cooldown used by the player
local eventsBeforePlayerDeath = {}
3 years ago
--get the table where is registered the last events before the player died
local recordedEvents = last_events_cache[targetName]
if (not recordedEvents) then
recordedEvents = _current_combat:CreateLastEventsTable(targetName)
end
3 years ago
--during a regular combat, 99.9% of the events aren't used by the death log
--hence the process of getting data for the death log is made as fast as it can be
--when a death occurs, the death log data is then parsed and built, the next 200 lines does this processing
--lesses index = older / higher index = newer
3 years ago
--[=[
eventTable [1] = type of the event
eventTable [2] = spellId --spellid or false if this is a battle ress event
eventTable [3] = amount --amount of damage or healing
eventTable [4] = time --unix time
eventTable [5] = player health when the event happened
eventTable [6] = name of the actor which caused this event
eventTable [7] = absorbed
eventTable [8] = spell school
eventTable [9] = friendly fire
eventTable [10] = amount of overkill damage
--]=]
--get the index of the last event recorded
local lastIndex = recordedEvents.n
--first, remove all healing events where the player was at full health
--here the event log gets reordered as in the parser it work with index recycling
if (lastIndex < _amount_of_last_events+1 and not recordedEvents[lastIndex][4]) then
--the last events table amount of indexes is less than the amount of events to store
for i = 1, lastIndex-1 do
if (recordedEvents[i][4] and recordedEvents[i][4]+_amount_of_last_events > time) then
tinsert(eventsBeforePlayerDeath, recordedEvents[i])
end
end
else
--go from the index where the last event was stored to the end of the table
for i = lastIndex, _amount_of_last_events do
if (recordedEvents[i][4] and recordedEvents[i][4]+_amount_of_last_events > time) then
tinsert(eventsBeforePlayerDeath, recordedEvents[i])
end
end
--go from the start of the table to the index where the last event minus 1 was stored
for i = 1, lastIndex-1 do
if (recordedEvents[i][4] and recordedEvents[i][4]+_amount_of_last_events > time) then
tinsert(eventsBeforePlayerDeath, recordedEvents[i])
end
end
end
local bHadDeathEvent = false
local firstEventTime
local lastEventTime
if (eventsBeforePlayerDeath[1]) then
bHadDeathEvent = true
firstEventTime = eventsBeforePlayerDeath[1][4]
lastEventTime = eventsBeforePlayerDeath[#eventsBeforePlayerDeath][4]
end
--enemy_cast_cache store the time of the event as key and a table as value
--the value has [1] = enemyName, [2] = spellid, [3] = amount of casts on that time (in case many enemies casted the same spell at the same time)
--enemy_cast_cache[time] = {enemyName, spellId, 1}
local enemyCastCache = enemy_cast_cache
--as multiple enemies can have casted the same spell at the same time, iterate over the enemyCastCache and merge the casts that happened really close to each other
--transfer the casts that happened within the event window of the player death to a new indexed table
local enemyCastCacheIndexed = {}
if (bHadDeathEvent) then
for time, enemyCastTable in pairs(enemyCastCache) do
if (time >= firstEventTime and time <= lastEventTime) then
enemyCastCacheIndexed[#enemyCastCacheIndexed+1] = {time, unpack(enemyCastTable)} --time, enemyName, spellId, amount of casts
end
end
end
--sort enemy casts events to place earlier casts in the first indexes of the table
table.sort(enemyCastCacheIndexed, function(t1, t2) return t1[1] < t2[1] end)
--iterate among the enemy cast events and remove cast events that are too close to each other
for i = #enemyCastCacheIndexed, 1, -1 do
local previousEnemyCastEvent = enemyCastCacheIndexed[i-1]
if (previousEnemyCastEvent) then
local nextEnemyCastEvent = enemyCastCacheIndexed[i]
if (previousEnemyCastEvent[1]+0.1 > nextEnemyCastEvent[1]) then
if (previousEnemyCastEvent[3] == nextEnemyCastEvent[3]) then
enemyCastCacheIndexed[i] = nil
--as the event got removed, add a cast event to the previous event
previousEnemyCastEvent[4] = previousEnemyCastEvent[4] + 1
end
end
end
end
--iterage among eventsBeforePlayerDeath and add the enemy casts events that happened within the last events time window
local currentEnemyCastIndex = 1
for i = 1, #eventsBeforePlayerDeath do
local eventTable = eventsBeforePlayerDeath[i]
local eventTime = eventTable[4]
for enemyCastEventIndex = currentEnemyCastIndex, #enemyCastCacheIndexed do
local enemyCastEvent = enemyCastCacheIndexed[enemyCastEventIndex]
if (enemyCastEvent) then
local enemyCastTime = enemyCastEvent[1]
local enemyName = enemyCastEvent[2]
local spellId = enemyCastEvent[3]
local castAmount = enemyCastEvent[4]
if (enemyCastTime+0.1 > eventTime and enemyCastTime+0.1 - eventTime < 0.3) then
--create a new event to show the cast and add it to the list of events before death
local eventType = 6 --cast
local newEventTable = {}
newEventTable[1] = eventType
newEventTable[2] = spellId --spellId
newEventTable[3] = castAmount --amount of casts
newEventTable[4] = enemyCastTime --when the event happened using unix time
newEventTable[5] = 0 --player health when the event happened
newEventTable[6] = enemyName --source name
tinsert(eventsBeforePlayerDeath, i, newEventTable)
currentEnemyCastIndex = enemyCastEventIndex + 1
break
end
end
end
end
3 years ago
--verify if a cooldown near the death event was used
if (thisPlayer.last_cooldown) then
--create a new event to show the latest cooldown the player used before death and add it to the list of events before death
local eventType = 3 --last cooldown used
local eventTable = {}
eventTable[1] = eventType
eventTable[2] = thisPlayer.last_cooldown[2] --spellId
eventTable[3] = 0 --amount of damage or healing but in this case is 0
eventTable[4] = thisPlayer.last_cooldown[1] --when the event happened using unix time
eventTable[5] = 0 --player health when the event happened
eventTable[6] = targetName --source name
eventsBeforePlayerDeath[#eventsBeforePlayerDeath+1] = eventTable
else
--no last cooldown found so just add a last cooldown used event with no spellId and time 0
local eventTable = {}
eventTable[1] = 3 --event type
eventTable[2] = 0 --spellId
eventTable[3] = 0 --amount of damage or healing but in this case is 0
eventTable[4] = 0 --when the event happened using unix time
eventTable[5] = 0 --player health when the event happened
eventTable[6] = targetName --source name
eventsBeforePlayerDeath[#eventsBeforePlayerDeath+1] = eventTable
end
3 years ago
local maxHealth
if (thisPlayer.arena_enemy) then
--this is an arena enemy, get the heal with the unit Id
local unitId = Details.arena_enemies[thisPlayer.nome]
if (not unitId) then
unitId = Details:GuessArenaEnemyUnitId(thisPlayer.nome)
end
if (unitId) then
maxHealth = UnitHealthMax(unitId)
end
if (not maxHealth) then
maxHealth = 0
end
else
maxHealth = UnitHealthMax(thisPlayer.nome)
end
local playerDeathTable
local combatElapsedTime = GetTime() - _current_combat:GetStartTime()
do
local minutes, seconds = floor(combatElapsedTime / 60), floor(combatElapsedTime % 60)
playerDeathTable = {
eventsBeforePlayerDeath, --table
time, --number unix time
thisPlayer.nome, --string player name
thisPlayer.classe, --string player class
maxHealth, --number max health
minutes .. "m " .. seconds .. "s", --time of death as string
["dead"] = true,
["last_cooldown"] = thisPlayer.last_cooldown,
["dead_at"] = combatElapsedTime,
["spec"] = thisPlayer.spec,
}
end
tinsert(_current_combat.last_events_tables, #_current_combat.last_events_tables+1, playerDeathTable)
--check if this is a mythic+ run for overall deaths
if (bIsMythicRun) then
3 years ago
--more checks for integrity
if (Details.tabela_overall and Details.tabela_overall.last_events_tables) then
--this is a mythic dungeon run, add the death to overall data
--need to adjust the time of death, since this will show all deaths in the mythic run
--first copy the table
local overallDeathTable = detailsFramework.table.copy({}, playerDeathTable)
3 years ago
--get the elapsed time
local mythicPlusElapsedTime = GetTime() - Details.tabela_overall:GetStartTime()
local minutes, seconds = floor(mythicPlusElapsedTime/60), floor(mythicPlusElapsedTime % 60)
overallDeathTable[6] = minutes .. "m " .. seconds .. "s"
overallDeathTable.dead_at = mythicPlusElapsedTime
3 years ago
--save data about the mythic run in the deathTable which goes in the regular segment
--confused? 'playerDeathTable' is added into the '_current_combat.last_events_tables' ~20 above on a tinsert
playerDeathTable["mythic_plus"] = true
playerDeathTable["mythic_plus_dead_at"] = mythicPlusElapsedTime
playerDeathTable["mythic_plus_dead_at_string"] = overallDeathTable[6]
3 years ago
--now add the death table into the overall data (this is the regular overall data, not the mythic plus overall data)
tinsert(Details.tabela_overall.last_events_tables, #Details.tabela_overall.last_events_tables + 1, overallDeathTable)
end
end
if (_hook_deaths) then
--send event to registred functions
for _, func in ipairs(_hook_deaths_container) do
local successful, errortext = pcall(func, nil, token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, playerDeathTable, thisPlayer.last_cooldown, combatElapsedTime, maxHealth, playerDeathTable["mythic_plus_dead_at"] or 0)
if (not successful) then
Details:Msg("error occurred on a death hook function:", errortext)
end
end
end
--remove the player death events from the cache
last_events_cache[targetName] = nil
end
end
end
--local WA_OnPlayerDeath = function(isFakeDeath, token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, deathLog, lastCooldown, combatElapsedTime, maxHealth, mythicPlusElapsedTime)
--check auras with details! death log enabled
--run a script in the aura which receives interesting data from the WA_OnPlayerDeath()
--end
--Details:InstallHook("HOOK_DEATH", WA_OnPlayerDeath)
function parser:environment(token, time, sourceSerial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, alvo_flags2, env_type, amount)
local spelId
3 years ago
if (env_type == "Falling") then
who_name = ENVIRONMENTAL_FALLING_NAME
spelId = 3
elseif (env_type == "Drowning") then
who_name = ENVIRONMENTAL_DROWNING_NAME
spelId = 4
elseif (env_type == "Fatigue") then
who_name = ENVIRONMENTAL_FATIGUE_NAME
spelId = 5
elseif (env_type == "Fire") then
who_name = ENVIRONMENTAL_FIRE_NAME
spelId = 6
elseif (env_type == "Lava") then
who_name = ENVIRONMENTAL_LAVA_NAME
spelId = 7
elseif (env_type == "Slime") then
who_name = ENVIRONMENTAL_SLIME_NAME
spelId = 8
end
3 years ago
return parser:spell_dmg(token, time, sourceSerial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, alvo_flags2, spelId or 1, env_type, 00000003, amount, -1, 1)
end
3 years ago
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--core
function parser:WipeSourceCache()
Details:Destroy(monk_guard_talent)
end
local token_list = {
-- neutral
["SPELL_SUMMON"] = parser.summon,
--["SPELL_CAST_FAILED"] = parser.spell_fail
}
--[==[@debug@
Details.token_list = token_list
--@end-debug@]==]
--serach key: ~capture
Details.capture_types = {"damage", "heal", "energy", "miscdata", "aura", "spellcast"}
Details.capture_schedules = {}
function Details:CaptureIsAllEnabled()
for _, thisType in ipairs(Details.capture_types) do
if (not Details.capture_real[thisType]) then
return false
end
end
return true
end
3 years ago
function Details:CaptureIsEnabled(capture)
if (Details.capture_real[capture]) then
return true
end
return false
end
3 years ago
function Details:CaptureRefresh()
for _, thisType in ipairs(Details.capture_types) do
if (Details.capture_current[thisType]) then
Details:CaptureEnable(thisType)
else
Details:CaptureDisable(thisType)
end
end
end
3 years ago
function Details:CaptureGet(captureType)
return Details.capture_real[captureType]
end
function Details:CaptureReset()
Details:CancelAllCaptureSchedules()
for _, thisType in ipairs(Details.capture_types) do
Details:CaptureSet(true, thisType, true)
end
end
function Details:CaptureSet(onOff, captureType, real, time)
if (onOff == nil) then
onOff = Details.capture_real[captureType]
end
3 years ago
if (real) then
3 years ago
--hard switch
Details.capture_real[captureType] = onOff
Details.capture_current[captureType] = onOff
else
3 years ago
--soft switch
Details.capture_current[captureType] = onOff
if (time) then
local scheduleId = math.random(1, 10000000)
local new_schedule = Details:ScheduleTimer("CaptureTimeout", time, {captureType, scheduleId}) --todo: use Details.Schedule
tinsert(Details.capture_schedules, {new_schedule, scheduleId})
end
end
3 years ago
Details:CaptureRefresh()
end
function Details:CancelAllCaptureSchedules()
for i = 1, #Details.capture_schedules do
local schedule_table, schedule_id = unpack(Details.capture_schedules[i])
Details:CancelTimer(schedule_table)
end
Details:Destroy(Details.capture_schedules)
end
3 years ago
6 months ago
function Details:CaptureTimeout (table3)
local capture_type, schedule_id = unpack(table3)
Details.capture_current [capture_type] = Details.capture_real [capture_type]
Details:CaptureRefresh()
3 years ago
6 months ago
for index, table2 in ipairs(Details.capture_schedules) do
local id = table2 [2]
if (schedule_id == id) then
6 months ago
table.remove(Details.capture_schedules, index)
break
end
end
end
function Details:CaptureDisable (capture_type)
3 years ago
capture_type = string.lower(capture_type)
if (capture_type == "damage") then
token_list ["SPELL_PERIODIC_DAMAGE"] = nil
token_list ["SPELL_EXTRA_ATTACKS"] = nil
token_list ["SPELL_DAMAGE"] = nil
token_list ["SWING_DAMAGE"] = nil
token_list ["RANGE_DAMAGE"] = nil
token_list ["DAMAGE_SHIELD"] = nil
token_list ["DAMAGE_SPLIT"] = nil
token_list ["RANGE_MISSED"] = nil
token_list ["SWING_MISSED"] = nil
token_list ["SPELL_MISSED"] = nil
token_list ["SPELL_BUILDING_MISSED"] = nil
token_list ["SPELL_PERIODIC_MISSED"] = nil
token_list ["DAMAGE_SHIELD_MISSED"] = nil
token_list ["ENVIRONMENTAL_DAMAGE"] = nil
token_list ["SPELL_BUILDING_DAMAGE"] = nil
token_list ["SPELL_EMPOWER_START"] = nil
token_list ["SPELL_EMPOWER_END"] = nil
token_list ["SPELL_EMPOWER_INTERRUPT"] = nil
3 years ago
elseif (capture_type == "heal") then
token_list ["SPELL_HEAL"] = nil
token_list ["SPELL_PERIODIC_HEAL"] = nil
token_list ["SPELL_HEAL_ABSORBED"] = nil
token_list ["SPELL_ABSORBED"] = nil
3 years ago
elseif (capture_type == "aura") then
token_list ["SPELL_AURA_APPLIED"] = parser.buff
token_list ["SPELL_AURA_REMOVED"] = parser.unbuff
token_list ["SPELL_AURA_REFRESH"] = parser.buff_refresh
token_list ["SPELL_AURA_APPLIED_DOSE"] = parser.buff_refresh
3 years ago
elseif (capture_type == "energy") then
token_list ["SPELL_ENERGIZE"] = nil
token_list ["SPELL_PERIODIC_ENERGIZE"] = nil
3 years ago
elseif (capture_type == "spellcast") then
token_list ["SPELL_CAST_SUCCESS"] = nil
3 years ago
elseif (capture_type == "miscdata") then
-- dispell
token_list ["SPELL_DISPEL"] = nil
token_list ["SPELL_STOLEN"] = nil
-- cc broke
token_list ["SPELL_AURA_BROKEN"] = nil
token_list ["SPELL_AURA_BROKEN_SPELL"] = nil
-- ress
token_list ["SPELL_RESURRECT"] = nil
-- interrupt
token_list ["SPELL_INTERRUPT"] = nil
-- dead
token_list ["UNIT_DIED"] = nil
token_list ["UNIT_DESTROYED"] = nil
3 years ago
end
end
3 years ago
--SPELL_DRAIN --need research
--SPELL_LEECH --need research
--SPELL_PERIODIC_DRAIN --need research
--SPELL_PERIODIC_LEECH --need research
--SPELL_DISPEL_FAILED --need research
--SPELL_BUILDING_HEAL --need research
function Details:CaptureEnable (capture_type)
3 years ago
capture_type = string.lower(capture_type)
--retail
if (capture_type == "damage") then
token_list ["SPELL_PERIODIC_DAMAGE"] = parser.spell_dmg
token_list ["SPELL_EXTRA_ATTACKS"] = nil --parser.spell_dmg_extra_attacks
token_list ["SPELL_DAMAGE"] = parser.spell_dmg
token_list ["SPELL_BUILDING_DAMAGE"] = parser.spell_dmg
token_list ["SWING_DAMAGE"] = parser.spell_dmg --parser.swing
token_list ["RANGE_DAMAGE"] = parser.spell_dmg --parser.range
token_list ["DAMAGE_SHIELD"] = parser.spell_dmg
token_list ["DAMAGE_SPLIT"] = parser.spell_dmg
token_list ["RANGE_MISSED"] = parser.rangemissed
token_list ["SWING_MISSED"] = parser.swingmissed
token_list ["SPELL_MISSED"] = parser.missed
token_list ["SPELL_PERIODIC_MISSED"] = parser.missed
token_list ["SPELL_BUILDING_MISSED"] = parser.missed
token_list ["DAMAGE_SHIELD_MISSED"] = parser.missed
token_list ["ENVIRONMENTAL_DAMAGE"] = parser.environment
token_list ["SPELL_EMPOWER_START"] = parser.spell_empower --evoker only
token_list ["SPELL_EMPOWER_END"] = parser.spell_empower --evoker only
token_list ["SPELL_EMPOWER_INTERRUPT"] = parser.spell_empower --evoker only
elseif (capture_type == "heal") then
token_list ["SPELL_HEAL"] = parser.heal
token_list ["SPELL_PERIODIC_HEAL"] = parser.heal
token_list ["SPELL_HEAL_ABSORBED"] = parser.heal_denied
token_list ["SPELL_ABSORBED"] = parser.heal_absorb
elseif (capture_type == "aura") then
token_list ["SPELL_AURA_APPLIED"] = parser.buff
token_list ["SPELL_AURA_REMOVED"] = parser.unbuff
token_list ["SPELL_AURA_REFRESH"] = parser.buff_refresh
token_list ["SPELL_AURA_APPLIED_DOSE"] = parser.buff_refresh
elseif (capture_type == "energy") then
6 months ago
if (_parser_options.energy_resources) then
token_list ["SPELL_ENERGIZE"] = parser.energize
token_list ["SPELL_PERIODIC_ENERGIZE"] = parser.energize
end
elseif (capture_type == "spellcast") then
token_list ["SPELL_CAST_SUCCESS"] = parser.spellcast
elseif (capture_type == "miscdata") then
-- dispell
token_list ["SPELL_DISPEL"] = parser.dispell
token_list ["SPELL_STOLEN"] = parser.dispell
-- cc broke
token_list ["SPELL_AURA_BROKEN"] = parser.break_cc
token_list ["SPELL_AURA_BROKEN_SPELL"] = parser.break_cc
-- ress
token_list ["SPELL_RESURRECT"] = parser.ress
-- interrupt
token_list ["SPELL_INTERRUPT"] = parser.interrupt
-- dead
token_list ["UNIT_DIED"] = parser.dead
token_list ["UNIT_DESTROYED"] = parser.dead
3 years ago
end
end
parser.original_functions = {
["spell_dmg"] = parser.spell_dmg,
["spell_dmg_extra_attacks"] = nil, --parser.spell_dmg_extra_attacks,
["swing"] = parser.spell_dmg, --parser.swing,
["range"] = parser.spell_dmg, --parser.range,
["rangemissed"] = parser.rangemissed,
["swingmissed"] = parser.swingmissed,
["missed"] = parser.missed,
["environment"] = parser.environment,
["heal"] = parser.heal,
["heal_absorb"] = parser.heal_absorb,
["heal_denied"] = parser.heal_denied,
["buff"] = parser.buff,
["unbuff"] = parser.unbuff,
["buff_refresh"] = parser.buff_refresh,
["energize"] = parser.energize,
["spellcast"] = parser.spellcast,
["dispell"] = parser.dispell,
["break_cc"] = parser.break_cc,
["ress"] = parser.ress,
["interrupt"] = parser.interrupt,
["dead"] = parser.dead,
["spell_empower"] = parser.spell_empower,
}
3 years ago
local all_parser_tokens = {
["SPELL_PERIODIC_DAMAGE"] = "spell_dmg",
["SPELL_EXTRA_ATTACKS"] = nil, --"spell_dmg_extra_attacks",
["SPELL_DAMAGE"] = "spell_dmg",
["SPELL_BUILDING_DAMAGE"] = "spell_dmg",
["SWING_DAMAGE"] = "spell_dmg", --"swing"
["RANGE_DAMAGE"] = "spell_dmg", --"range",
["DAMAGE_SHIELD"] = "spell_dmg",
["DAMAGE_SPLIT"] = "spell_dmg",
["RANGE_MISSED"] = "rangemissed",
["SWING_MISSED"] = "swingmissed",
["SPELL_MISSED"] = "missed",
["SPELL_PERIODIC_MISSED"] = "missed",
["SPELL_BUILDING_MISSED"] = "missed",
["DAMAGE_SHIELD_MISSED"] = "missed",
["ENVIRONMENTAL_DAMAGE"] = "environment",
["SPELL_HEAL"] = "heal",
["SPELL_PERIODIC_HEAL"] = "heal",
["SPELL_HEAL_ABSORBED"] = "heal_denied",
["SPELL_ABSORBED"] = "heal_absorb",
["SPELL_AURA_APPLIED"] = "buff",
["SPELL_AURA_REMOVED"] = "unbuff",
["SPELL_AURA_REFRESH"] = "buff_refresh",
["SPELL_AURA_APPLIED_DOSE"] = "buff_refresh",
["SPELL_ENERGIZE"] = "energize",
["SPELL_PERIODIC_ENERGIZE"] = "energize",
3 years ago
["SPELL_CAST_SUCCESS"] = "spellcast",
["SPELL_DISPEL"] = "dispell",
["SPELL_STOLEN"] = "dispell",
["SPELL_AURA_BROKEN"] = "break_cc",
["SPELL_AURA_BROKEN_SPELL"] = "break_cc",
["SPELL_RESURRECT"] = "ress",
["SPELL_INTERRUPT"] = "interrupt",
["UNIT_DIED"] = "dead",
["UNIT_DESTROYED"] = "dead",
}
3 years ago
function parser:RefreshFunctions()
3 years ago
for CLUE_ID, token in pairs(all_parser_tokens) do
if (token_list [CLUE_ID]) then --not disabled
token_list [CLUE_ID] = parser [token]
end
end
end
3 years ago
function Details:CallWipe (from_slash)
Details:Msg("Wipe has been called by your raid leader.")
if (Details.wipe_called) then
if (from_slash) then
return Details:Msg(Loc ["STRING_WIPE_ERROR1"])
else
return
end
elseif (not Details.encounter_table.id) then
if (from_slash) then
return Details:Msg(Loc ["STRING_WIPE_ERROR2"])
else
return
end
end
3 years ago
local eTable = Details.encounter_table
3 years ago
--finish the encounter
local successful_ended = Details.parser_functions:ENCOUNTER_END (eTable.id, eTable.name, eTable.diff, eTable.size, 0)
3 years ago
if (successful_ended) then
3 years ago
--we wiped
Details.wipe_called = true
3 years ago
--cancel the on going captures schedules
Details:CancelAllCaptureSchedules()
3 years ago
--disable it
Details:CaptureSet (false, "damage", false)
Details:CaptureSet (false, "energy", false)
Details:CaptureSet (false, "aura", false)
Details:CaptureSet (false, "energy", false)
Details:CaptureSet (false, "spellcast", false)
3 years ago
if (from_slash) then
if (UnitIsGroupLeader ("player")) then
Details:SendHomeRaidData ("WI")
end
end
3 years ago
local lower_instance = Details:GetLowerInstanceNumber()
if (lower_instance) then
lower_instance = Details:GetInstance(lower_instance)
lower_instance:InstanceAlert (Loc ["STRING_WIPE_ALERT"], {[[Interface\CHARACTERFRAME\UI-StateIcon]], 18, 18, false, 0.5, 1, 0, 0.5}, 4)
end
else
if (from_slash) then
return Details:Msg(Loc ["STRING_WIPE_ERROR3"])
else
return
end
end
end
-- PARSER
--serach key: ~parser ~events ~start ~inicio
function Details:FlagNewCombat_PVPState()
if (Details.is_in_battleground) then
Details.tabela_vigente.pvp = true
Details.tabela_vigente.is_pvp = {name = Details.zone_name, mapid = Details.zone_id}
3 years ago
elseif (Details.is_in_arena) then
Details.tabela_vigente.arena = true
Details.tabela_vigente.is_arena = {name = Details.zone_name, zone = Details.zone_name, mapid = Details.zone_id}
end
end
3 years ago
function Details:GetZoneType()
return Details.zone_type
end
local gotAggro = false
function Details.parser_functions:UNIT_FLAGS(...)
if (gotAggro) then
return
end
if (Details:GetZoneType() ~= "raid" and Details:GetZoneType() ~= "party") then
return
end
local unitId = ...
if (UnitExists(unitId)) then
if (UnitAffectingCombat(unitId) and not UnitAffectingCombat("player")) then
Details.LastAggro = UnitName(unitId)
gotAggro = true
C_Timer.After(1, function()
gotAggro = false
end)
end
end
end
6 months ago
function Details.parser_functions:SCENARIO_COMPLETED(...)
end
function Details.parser_functions:ZONE_CHANGED_NEW_AREA(...)
return Details.Schedules.After(1, Details.Check_ZONE_CHANGED_NEW_AREA)
end
3 years ago
--~zone ~area
function Details:Check_ZONE_CHANGED_NEW_AREA()
6 months ago
local zoneName, zoneType, difficultyID, difficultyName, _, _, _, zoneMapID = GetInstanceInfo()
3 years ago
Details.zone_type = zoneType
Details.zone_id = zoneMapID
Details.zone_name = zoneName
Details:SetDeathLogTemporaryLimit(nil) --reset the temp amount
6 months ago
--Details222.ContextManager:CheckContextInterest(zoneMapID, zoneName, zoneType, difficultyID)
_in_resting_zone = IsResting()
3 years ago
if (_in_resting_zone) then
Details:CaptureReset()
end
parser:WipeSourceCache()
Details.listener:UnregisterEvent("UNIT_FLAGS")
3 years ago
_is_in_instance = false
3 years ago
if (zoneType == "party" or zoneType == "raid") then
_is_in_instance = true
end
3 years ago
if (Details.last_zone_type ~= zoneType) then
Details:SendEvent("ZONE_TYPE_CHANGED", nil, zoneType)
Details.last_zone_type = zoneType
3 years ago
for index, instancia in ipairs(Details.tabela_instancias) do
if (instancia.ativa) then
instancia:AdjustAlphaByContext(true)
end
end
Details222.Cache.ClearAugmentationCache()
end
3 years ago
Details.time_type = Details.time_type_original
3 years ago
if (Details.is_in_arena and zoneType ~= "arena") then
Details:LeftArena()
end
--check if the player left a battleground
if (Details.is_in_battleground and zoneType ~= "pvp") then
Details.pvp_parser_frame:StopBgUpdater()
Details.is_in_battleground = nil
Details.time_type = Details.time_type_original
end
3 years ago
if (zoneType == "pvp") then --battlegrounds
if (Details.debug) then
Details:Msg("(debug) zone type is now 'pvp'.")
end
3 years ago
if(not Details.is_in_battleground and Details.overall_clear_pvp) then
Details.tabela_historico:ResetOverallData()
3 years ago
end
Details.is_in_battleground = true
3 years ago
if (_in_combat and not _current_combat.pvp) then
Details:SairDoCombate()
end
3 years ago
if (not _in_combat) then
Details222.StartCombat()
end
3 years ago
_current_combat.pvp = true
_current_combat.is_pvp = {name = zoneName, mapid = zoneMapID}
3 years ago
if (Details.use_battleground_server_parser) then
if (Details.time_type == 1) then
Details.time_type_original = 1
Details.time_type = 2
end
Details.pvp_parser_frame:StartBgUpdater()
else
if (Details.force_activity_time_pvp) then
Details.time_type_original = Details.time_type
Details.time_type = 1
end
end
3 years ago
Details.lastBattlegroundStartTime = GetTime()
elseif (zoneType == "arena") then
if (Details.debug) then
Details:Msg("(debug) zone type is now 'arena'.")
end
3 years ago
if (Details.force_activity_time_pvp) then
Details.time_type_original = Details.time_type
Details.time_type = 1
end
3 years ago
if (not Details.is_in_arena) then
if (Details.overall_clear_pvp) then
Details.tabela_historico:ResetOverallData()
3 years ago
end
--reset spec cache if broadcaster requested
if (Details.streamer_config.reset_spec_cache) then
Details:Destroy(Details.cached_specs)
end
end
3 years ago
--increase the deathlog amount for arenas
Details:SetDeathLogTemporaryLimit(100)
Details.is_in_arena = true
Details:EnteredInArena()
else
local inInstance = IsInInstance()
if ((zoneType == "raid" or zoneType == "party") and inInstance) then
Details:CheckForAutoErase(zoneMapID)
3 years ago
--if the current raid is current tier raid, pre-load the storage database
if (zoneType == "raid") then
6 months ago
if (not Details222.EJCache.CacheCreated) then
--this is running right after the player login, wait a few seconds for the cache to be created
C_Timer.After(5, function()
if (Details:IsZoneIdFromCurrentExpansion(zoneMapID)) then
Details.ScheduleLoadStorage()
end
end)
else
if (Details:IsZoneIdFromCurrentExpansion(zoneMapID)) then
Details.ScheduleLoadStorage()
end
end
end
Details.listener:RegisterEvent("UNIT_FLAGS")
end
3 years ago
if (Details:IsInInstance()) then
Details.last_instance = zoneMapID
end
3 years ago
--if (_current_combat.pvp) then
-- _current_combat.pvp = false
--end
end
3 years ago
Details222.AutoRunCode.DispatchAutoRunCode("on_zonechanged")
Details:SchedulePetUpdate(7)
Details:CheckForPerformanceProfile()
end
3 years ago
function Details.parser_functions:PLAYER_ENTERING_WORLD ()
return Details.parser_functions:ZONE_CHANGED_NEW_AREA()
end
4 years ago
-- ~encounter
4 years ago
--ENCOUNTER START
function Details.parser_functions:ENCOUNTER_START(...)
if (Details.debug) then
Details:Msg("(debug) |cFFFFFF00ENCOUNTER_START|r event triggered.")
end
3 years ago
Details:Destroy(Details.encounter_table)
Details222.Perf.WindowUpdate = 0
Details222.Perf.WindowUpdateC = true
Details.latest_ENCOUNTER_END = Details.latest_ENCOUNTER_END or 0
if (Details.latest_ENCOUNTER_END + 10 > GetTime()) then
return
end
if not detailsFramework.IsAddonApocalypseWow() then
--leave the current combat when the encounter start, if is doing a mythic plus dungeons, check if the options allows to create a dedicated segment for the boss fight
if ((_in_combat and not Details.tabela_vigente.is_boss) and (not Details.MythicPlus.Started or Details.mythic_plus.boss_dedicated_segment)) then
Details:SairDoCombate()
end
end
3 years ago
local encounterID, encounterName, difficultyID, raidSize = select(1, ...)
local zoneName, zoneType, _, _, _, _, _, zoneMapID = GetInstanceInfo()
if not detailsFramework.IsAddonApocalypseWow() then
if (zoneType == "party") then
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true)
if (openRaidLib) then
openRaidLib.KeystoneInfoManager.SendPlayerKeystoneInfoToParty()
end
end
end
if (Details:IsZoneIdFromCurrentExpansion(zoneMapID)) then
6 months ago
--print("encouter is from current expansion")
Details.current_exp_raid_encounters[encounterID] = true
end
3 years ago
Details222.DebugMsg("|cFFFFFF00Who Aggro by UNIT_FLAGS:", Details.LastAggro)
if not detailsFramework.IsAddonApocalypseWow() then
if (not Details.WhoAggroTimer and Details.announce_firsthit.enabled) then
Details.WhoAggroTimer = C_Timer.NewTimer(0.1, whoAggro)
for i = 1, 5 do
local boss = UnitExists("boss" .. i)
if (boss) then
local targetName = UnitName("boss" .. i .. "target")
if (targetName and type(targetName) == "string") then
Details.bossTargetAtPull = targetName
break
end
end
end
end
end
3 years ago
if (IsInGuild() and IsInRaid() and Details.announce_damagerecord.enabled and Details222.storageLoaded) then
Details.TellDamageRecord = C_Timer.NewTimer(0.6, Details.PrintEncounterRecord)
Details.TellDamageRecord.Boss = encounterID
Details.TellDamageRecord.Diff = difficultyID
end
_current_encounter_id = encounterID
Details.boss1_health_percent = 1
3 years ago
local DBM_MOD, DBM_TIME = Details.encounter_table.DBM_Mod, Details.encounter_table.DBM_ModTime
Details:Destroy(Details.encounter_table)
3 years ago
Details.encounter_table.phase = 1
3 years ago
--store the encounter time inside the encounter table for the encounter plugin
Details.encounter_table.start = GetTime()
Details.encounter_table["end"] = nil
Details.encounter_table.id = encounterID
Details.encounter_table.name = encounterName
Details.encounter_table.diff = difficultyID
Details.encounter_table.size = raidSize
Details.encounter_table.zone = zoneName
Details.encounter_table.mapid = zoneMapID
3 years ago
if (DBM_MOD and DBM_TIME == time()) then
Details.encounter_table.DBM_Mod = DBM_MOD
end
local encounterTable, bossIndex = Details:GetBossEncounterDetailsFromEncounterId(zoneMapID, encounterID)
if (encounterTable) then
Details.encounter_table.index = bossIndex
end
3 years ago
Details:SendEvent("COMBAT_ENCOUNTER_START", nil, ...)
4 years ago
Details222.CacheKeystoneForAllGroupMembers()
end
4 years ago
6 months ago
---@param self details
---@return details_encounter_table
function Details:GetCurrentEncounterInfo()
return Details.encounter_table
end
4 years ago
--ENCOUNRTER_END
function Details.parser_functions:ENCOUNTER_END(...)
if (Details.debug) then
Details:Msg("(debug) |cFFFFFF00ENCOUNTER_END|r event triggered.")
end
3 years ago
Details222.Perf.WindowUpdateC = false
_current_encounter_id = nil
3 years ago
local encounterID, encounterName, difficultyID, raidSize, endStatus = select(1, ...)
if (not Details.encounter_table.start) then
6 months ago
--Details:Msg("encounter table without start time.")
return
end
3 years ago
Details.latest_ENCOUNTER_END = Details.latest_ENCOUNTER_END or 0
if (Details.latest_ENCOUNTER_END + 15 > GetTime()) then
return
end
Details.latest_ENCOUNTER_END = GetTime()
Details.encounter_table["end"] = GetTime()
3 years ago
local bossIcon = Details:GetBossEncounterTexture(encounterName)
_current_combat.bossIcon = bossIcon
_current_combat.EncounterName = encounterName
if (_in_combat) then
if (endStatus == 1) then
Details.encounter_table.kill = true
Details.encounter_table.end_status = 1
if not detailsFramework.IsAddonApocalypseWow() then
Details:SairDoCombate(true, {encounterID, encounterName, difficultyID, raidSize, endStatus}) --killed
end
else
Details.encounter_table.kill = false
Details.encounter_table.end_status = 0
if not detailsFramework.IsAddonApocalypseWow() then
Details:SairDoCombate(false, {encounterID, encounterName, difficultyID, raidSize, endStatus}) --wipe
end
end
else
if not detailsFramework.IsAddonApocalypseWow() then
if ((Details.tabela_vigente:GetEndTime() or 0) + 2 >= Details.encounter_table ["end"]) then
Details.tabela_vigente:SetStartTime(Details.encounter_table ["start"])
Details.tabela_vigente:SetEndTime(Details.encounter_table ["end"])
Details:RefreshMainWindow(-1, true)
end
end
end
if not detailsFramework.IsAddonApocalypseWow() then
petContainer.Reset()
C_Timer.After(1, function() petContainer.PetScan("ENCOUNTER_END") end)
--tag item level of all players
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true)
local allPlayersGear = openRaidLib and openRaidLib.GetAllUnitsGear()
local status = xpcall(function()
for actorIndex, actorObject in Details:GetCurrentCombat():GetContainer(DETAILS_ATTRIBUTE_DAMAGE):ListActors() do
local gearInfo = allPlayersGear and allPlayersGear[actorObject:Name()]
if (gearInfo) then
actorObject.ilvl = gearInfo.ilevel
end
end
end, geterrorhandler())
if (not status) then
Details:Msg("ilvl error:", status)
end
end
if not detailsFramework.IsAddonApocalypseWow() then
Details:SendEvent("COMBAT_ENCOUNTER_END", nil, ...)
Details222.Cache.ClearAugmentationCache()
Details:Destroy(Details.encounter_table)
Details:Destroy(dk_pets_cache.army)
Details:Destroy(dk_pets_cache.apoc)
Details:Destroy(empower_cache)
end
4 years ago
return true
end
3 years ago
function Details.parser_functions:UNIT_PET(unitId) --unitId is a secret
if detailsFramework.IsAddonApocalypseWow() then
return
end
petContainer.UNIT_PET(unitId)
Details:SchedulePetUpdate(1)
end
local autoSwapDynamicOverallData = function(instance, inCombat)
local mainDisplayGroup, subDisplay = instance:GetDisplay()
local customDisplayAttributeId = 5
--entering in combat, swap to dynamic overall damage
if (inCombat) then
if (mainDisplayGroup == DETAILS_ATTRIBUTE_DAMAGE and subDisplay == DETAILS_SUBATTRIBUTE_DAMAGEDONE) then
local segment = instance:GetSegment()
if (segment == DETAILS_SEGMENTID_OVERALL) then
local dynamicOverallDataCustomID = Details222.GetCustomDisplayIDByName(Loc["STRING_CUSTOM_DYNAMICOVERAL"])
instance:SetDisplay(segment, customDisplayAttributeId, dynamicOverallDataCustomID)
end
end
else
--leaving combat
if (mainDisplayGroup == customDisplayAttributeId) then
local dynamicOverallDataCustomID = Details222.GetCustomDisplayIDByName(Loc["STRING_CUSTOM_DYNAMICOVERAL"])
if (subDisplay == dynamicOverallDataCustomID) then
local segment = instance:GetSegment()
if (segment == DETAILS_SEGMENTID_OVERALL) then
instance:SetDisplay(true, DETAILS_ATTRIBUTE_DAMAGE, DETAILS_SUBATTRIBUTE_DAMAGEDONE)
end
end
end
end
end
function Details.parser_functions:PLAYER_REGEN_DISABLED(...)
C_Timer.After(0, function()
if (not Details.bossTargetAtPull) then
if (UnitExists("boss1")) then
local bossTarget = UnitName("boss1target")
if (bossTarget) then
Details.bossTargetAtPull = bossTarget
end
end
end
end)
6 months ago
if (detailsFramework.ExpansionHasEvoker()) then
if (IsInRaid()) then
--check if there is only one bombardment evoker in the group
local evokerCount = 0
local evokerName = ""
local evokerSerial = ""
--get the open raid lib
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true)
for i = 1, #Details222.UnitIdCache.Raid do
local unitId = Details222.UnitIdCache.Raid[i]
if (UnitExists(unitId)) then
local unitName = GetUnitName(unitId, true)
local unitInfo = openRaidLib.GetUnitInfo(unitId)
local unitClass = select(2, UnitClass(unitName))
if (unitClass == "EVOKER") then
if (unitInfo and unitInfo.specId and unitInfo.specId ~= 1468) then
evokerCount = evokerCount + 1
evokerName = unitName
evokerSerial = UnitGUID(unitId)
else
evokerCount = evokerCount + 1
evokerName = unitName
evokerSerial = UnitGUID(unitId)
end
end
else
break
end
end
if (evokerCount == 1) then
--this combat can reatribute bombardments
bombardment_stuff.only_one_scalecomander = true
bombardment_stuff.evoker_name = evokerName
bombardment_stuff.serial = evokerSerial
--print("only one scaler commander found, yoinking bombardments damage for:", bombardment_stuff.evoker_name)
else
bombardment_stuff.only_one_scalecomander = false
bombardment_stuff.evoker_name = ""
bombardment_stuff.serial = ""
end
elseif (IsInGroup()) then
local evokerCount = 0
local evokerName = ""
local evokerSerial = ""
--get the open raid lib
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true)
for i = 1, #Details222.UnitIdCache.Party do
local unitId = Details222.UnitIdCache.Party[i]
if (UnitExists(unitId)) then
local unitName = GetUnitName(unitId, true)
local unitInfo = openRaidLib.GetUnitInfo(unitId)
local unitClass = select(2, UnitClass(unitName))
if (unitClass == "EVOKER") then
if (unitInfo and unitInfo.specId and unitInfo.specId ~= 1468) then
evokerCount = evokerCount + 1
evokerName = unitName
evokerSerial = UnitGUID(unitId)
else
evokerCount = evokerCount + 1
evokerName = unitName
evokerSerial = UnitGUID(unitId)
end
end
end
end
if (evokerCount == 1) then
--this combat can reatribute bombardments
bombardment_stuff.only_one_scalecomander = true
bombardment_stuff.evoker_name = evokerName
bombardment_stuff.serial = evokerSerial
--print("only one scaler commander found, yoinking bombardments damage for:", bombardment_stuff.evoker_name)
else
bombardment_stuff.only_one_scalecomander = false
bombardment_stuff.evoker_name = ""
bombardment_stuff.serial = ""
end
else
local evokerCount = 0
local evokerName = ""
local evokerSerial = ""
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true)
local unitName = GetUnitName("player", true)
local unitInfo = openRaidLib.GetUnitInfo("player")
local unitClass = select(2, UnitClass(unitName))
if unitClass == "EVOKER" then
if unitInfo and unitInfo.specId and unitInfo.specId ~= 1468 then
evokerCount = evokerCount + 1
evokerName = unitName
evokerSerial = UnitGUID("player")
else
evokerCount = evokerCount + 1
evokerName = unitName
evokerSerial = UnitGUID("player")
end
end
if evokerCount == 1 then
--this combat can reatribute bombardments
bombardment_stuff.only_one_scalecomander = true
bombardment_stuff.evoker_name = evokerName
bombardment_stuff.serial = evokerSerial
--print("only one scaler commander found, yoinking bombardments damage for:", bombardment_stuff.evoker_name)
else
bombardment_stuff.only_one_scalecomander = false
bombardment_stuff.evoker_name = ""
bombardment_stuff.serial = ""
end
end
end
table.wipe(interruptOverlapCache)
if (Details.auto_swap_to_dynamic_overall) then
Details:InstanceCall(autoSwapDynamicOverallData, true)
end
Details.combat_id_global = Details.combat_id_global + 1
_global_combat_counter = Details.combat_id_global
_trinket_data_cache = Details:GetTrinketData()
if (Details.zone_type == "pvp" and not Details.use_battleground_server_parser) then
if (_in_combat) then
Details:SairDoCombate()
end
Details222.StartCombat()
end
3 years ago
if (not Details:CaptureGet("damage")) then
Details222.StartCombat()
end
3 years ago
--essa parte do solo mode ainda sera usada?
if (Details.solo and Details.PluginCount.SOLO > 0) then --solo mode
local esta_instancia = Details.tabela_instancias[Details.solo]
esta_instancia.atualizando = true
end
3 years ago
for index, instancia in ipairs(Details.tabela_instancias) do
3 years ago
if (instancia.ativa) then --1 = none, we doesn't need to call
instancia:AdjustAlphaByContext(true)
end
end
3 years ago
Details222.AutoRunCode.DispatchAutoRunCode("on_entercombat")
3 years ago
Details.tabela_vigente.CombatStartedAt = GetTime()
local bSilentOnError = true
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", bSilentOnError) --isWOTLK isERA
if (openRaidLib) then
wipe(gearCache)
local bNeedPlayerGear = true
if (IsInRaid()) then
local unitIdCache = Details222.UnitIdCache.Raid
bNeedPlayerGear = false
for i = 1, 40 do
local unitId = unitIdCache[i]
local guid = UnitGUID(unitId)
if (guid) then
local unitGearInfo = openRaidLib.GetUnitGear(unitId)
if (unitGearInfo) then
gearCache[guid] = {
tierAmount = unitGearInfo.tierAmount or 0,
ilevel = unitGearInfo.ilevel or 0,
}
end
end
end
elseif (IsInGroup()) then
local unitIdCache = Details222.UnitIdCache.Party
6 months ago
for i = 1, 5 do
local unitId = unitIdCache[i]
local guid = UnitGUID(unitId)
if (guid) then
local unitGearInfo = openRaidLib.GetUnitGear(unitId)
if (unitGearInfo) then
gearCache[guid] = {
tierAmount = unitGearInfo.tierAmount or 0,
ilevel = unitGearInfo.ilevel or 0,
}
end
end
end
end
if (bNeedPlayerGear) then
local playerGearInfo = openRaidLib.GetUnitGear("player")
if (playerGearInfo) then
gearCache[UnitGUID("player")] = {
tierAmount = playerGearInfo.tierAmount or 0,
ilevel = playerGearInfo.ilevel or 0,
}
end
end
end
end
3 years ago
--in case the player left the raid during the encounter
--this function clear the encounter_id from the cache
local checkIfEncounterIsDone = function()
if (not _current_encounter_id) then
return
end
3 years ago
if (IsInRaid()) then
--raid
local inCombat = false
for i = 1, GetNumGroupMembers() do
3 years ago
if (UnitAffectingCombat("raid" .. i)) then
inCombat = true
break
end
end
3 years ago
if (not inCombat) then
_current_encounter_id = nil
end
3 years ago
elseif (IsInGroup()) then
--party (dungeon)
local inCombat = false
for i = 1, GetNumGroupMembers() -1 do
3 years ago
if (UnitAffectingCombat("party" .. i)) then
inCombat = true
break
end
end
3 years ago
if (not inCombat) then
_current_encounter_id = nil
end
3 years ago
else
_current_encounter_id = nil
end
end
3 years ago
--this function is guaranteed to run after a combat is done
--can also run when the player leaves combat state (regen enabled)
function Details:RunScheduledEventsAfterCombat(OnRegenEnabled)
if (Details.debug) then
--Details:Msg("(debug) running scheduled events after combat end.")
end
3 years ago
--when the user requested data from the storage but is in combat lockdown
if (Details.schedule_storage_load) then
Details.schedule_storage_load = nil
Details.ScheduleLoadStorage()
end
3 years ago
--store a boss encounter when out of combat since it might need to load the storage
if (Details.schedule_store_boss_encounter) then
if (not Details.logoff_saving_data) then
3 years ago
local successful, errortext = pcall(Details.Database.StoreEncounter)
if (not successful) then
Details:Msg("error occurred on Details.Database.StoreEncounter():", errortext)
end
end
Details.schedule_store_boss_encounter = nil
end
if (Details.schedule_store_boss_encounter_wipe) then
if (not Details.logoff_saving_data) then
3 years ago
local successful, errortext = pcall(Details.Database.StoreWipe)
if (not successful) then
Details:Msg("error occurred on Details.Database.StoreWipe():", errortext)
end
end
Details.schedule_store_boss_encounter_wipe = nil
end
3 years ago
--when a large amount of data has been removed and the player is in combat, schedule to run the hard garbage collector (the blizzard one, not the details! internal)
if (Details.schedule_hard_garbage_collect) then
if (Details.debug) then
Details:Msg("(debug) found schedule collectgarbage().")
end
Details.schedule_hard_garbage_collect = false
collectgarbage()
end
3 years ago
for index, instancia in ipairs(Details.tabela_instancias) do
3 years ago
if (instancia.ativa) then --1 = none, we doesn't need to call
instancia:AdjustAlphaByContext(true)
end
end
3 years ago
if (not OnRegenEnabled) then
Details:Destroy(bitfield_swap_cache)
Details:Destroy(empower_cache)
Details222.AutoRunCode.DispatchAutoRunCode("on_leavecombat")
end
3 years ago
if (Details.solo and Details.PluginCount.SOLO > 0) then --code too old and I don't have documentation for it
if (Details.SoloTables.Plugins [Details.SoloTables.Mode].Stop) then
Details.SoloTables.Plugins [Details.SoloTables.Mode].Stop()
end
end
end
3 years ago
function Details.parser_functions:CHALLENGE_MODE_END(...) --doesn't exists
Details:Msg("CHALLENGE_MODE_END", GetTime())
end
6 months ago
local startMythicPlusRun = function()
if (DetailsMythicPlusFrame.ZoneLeftTimer and not DetailsMythicPlusFrame.ZoneLeftTimer:IsCancelled()) then
DetailsMythicPlusFrame.ZoneLeftTimer:Cancel()
end
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
if (difficultyID == 8) then
6 months ago
Details.challengeModeMapId = C_ChallengeMode.GetActiveChallengeMapID()
Details222.MythicPlus.CHALLENGE_MODE_START_AT = GetTime()
Details222.MythicPlus.RUN_START_AT = time()
Details222.MythicPlus.WorldStateTimerEndAt = nil
local activeKeystoneLevel, activeAffixIDs, wasActiveKeystoneCharged = C_ChallengeMode.GetActiveKeystoneInfo and C_ChallengeMode.GetActiveKeystoneInfo()
Details222.MythicPlus.Level = activeKeystoneLevel or 2
Details:SendEvent("COMBAT_MYTHICDUNGEON_START")
Details222.MythicPlus.WorldStateTimerStartAt = time()
--debug auras
Details222.MythicPlus.debug_auras = {}
end
end
3 years ago
6 months ago
--challenge mode start is triggered when the loading screen is done
function Details.parser_functions:CHALLENGE_MODE_START(...) --~challenge ~mythic+ ~m+
--send mythic dungeon start event
if (Details.debug) then
end
6 months ago
Details222.MythicPlus.LogStep("CHALLENGE_MODE_START, starting 10 seconds timer.")
detailsFramework.Schedules.NewTimer (10, function()
Details222.MythicPlus.LogStep("CHALLENGE_MODE_START timer ended, starting the dungeon.")
startMythicPlusRun()
end)
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
if (difficultyID == 8) then
Details222.MythicPlus.CHALLENGE_MODE_START_AT = GetTime()
Details222.MythicPlus.WorldStateTimerStartAt = nil
Details222.MythicPlus.WorldStateTimerEndAt = nil
Details222.MythicPlus.LogStep("Event: CHALLENGE_MODE_START")
6 months ago
local activeKeystoneLevel, activeAffixIDs, wasActiveKeystoneCharged = C_ChallengeMode.GetActiveKeystoneInfo and C_ChallengeMode.GetActiveKeystoneInfo()
Details222.MythicPlus.Level = activeKeystoneLevel or 2
Details.challengeModeMapId = C_ChallengeMode.GetActiveChallengeMapID()
Details222.MythicPlus.debug_auras = {}
end
end
local keystoneLevels = {}
local playerRatings = {}
Details.KeystoneLevels = keystoneLevels
Details.PlayerRatings = playerRatings
--save the keystone and rating level for each of the 5 party members
local saveGroupMembersKeystoneAndRatingLevel = function()
wipe(keystoneLevels)
local libOpenRaid = LibStub("LibOpenRaid-1.0", true)
if (libOpenRaid) then
for i = 1, GetNumGroupMembers()-1 do
local unitId = "party" .. i
if (UnitExists(unitId)) then
local unitKeystoneInfo = libOpenRaid.GetKeystoneInfo(unitId)
if (unitKeystoneInfo) then
local unitName = Details:GetFullName(unitId)
keystoneLevels[unitName] = unitKeystoneInfo.level
playerRatings[unitName] = unitKeystoneInfo.rating
end
end
end
local unitId = "player"
if (UnitExists(unitId)) then
local unitKeystoneInfo = libOpenRaid.GetKeystoneInfo(unitId)
if (unitKeystoneInfo) then
local unitName = Details:GetFullName(unitId)
keystoneLevels[unitName] = unitKeystoneInfo.level
playerRatings[unitName] = unitKeystoneInfo.rating
end
end
end
end
function Details222.CacheKeystoneForAllGroupMembers()
local _, instanceType, difficultyID = GetInstanceInfo()
if (instanceType == "party") then
saveGroupMembersKeystoneAndRatingLevel()
end
end
function Details.parser_functions:CHALLENGE_MODE_COMPLETED(...) --~complete ~finish ~mythic ~m+
Details222.MythicPlus.WorldStateTimerEndAt = time()
--wait until the keystone is updated and send it to the party
saveGroupMembersKeystoneAndRatingLevel()
6 months ago
local completionInfo = C_ChallengeMode.GetChallengeCompletionInfo()
local primaryAffix = 0
local mapID = completionInfo.mapChallengeModeID or Details.challengeModeMapId or C_ChallengeMode.GetActiveChallengeMapID()
local upgradeMembers = completionInfo.members
local level = completionInfo.level
local completionTime = completionInfo.time
local onTime = completionInfo.onTime
local keystoneUpgradeLevels = completionInfo.keystoneUpgradeLevels
local practiceRun = completionInfo.practiceRun
local isAffixRecord = completionInfo.isAffixRecord
local isMapRecord = completionInfo.isMapRecord
local isEligibleForScore = completionInfo.isEligibleForScore
local oldDungeonScore = completionInfo.oldOverallDungeonScore
local newDungeonScore = completionInfo.newOverallDungeonScore
Details222.MythicPlus.MapID = mapID
Details222.MythicPlus.Level = level --level of the key just finished
6 months ago
Details222.MythicPlus.ElapsedTime = completionTime --total time of the mythic+ run
Details222.MythicPlus.OnTime = onTime
Details222.MythicPlus.KeystoneUpgradeLevels = keystoneUpgradeLevels
Details222.MythicPlus.PracticeRun = practiceRun
Details222.MythicPlus.OldDungeonScore = oldDungeonScore
Details222.MythicPlus.NewDungeonScore = newDungeonScore
Details222.MythicPlus.IsAffixRecord = isAffixRecord
Details222.MythicPlus.IsMapRecord = isMapRecord
Details222.MythicPlus.PrimaryAffix = primaryAffix
Details222.MythicPlus.IsEligibleForScore = isEligibleForScore
Details222.MythicPlus.UpgradeMembers = upgradeMembers
6 months ago
Details222.MythicPlus.RUN_END_AT = time()
local dungeonName, id, timeLimit, texture, backgroundTexture, instanceMapId = C_ChallengeMode.GetMapUIInfo(mapID)
Details222.MythicPlus.DungeonName = dungeonName
Details222.MythicPlus.DungeonID = id
Details222.MythicPlus.TimeLimit = timeLimit
Details222.MythicPlus.Texture = texture
Details222.MythicPlus.BackgroundTexture = backgroundTexture
Details222.MythicPlus.InstanceMapID = instanceMapId
6 months ago
--store the data of the mythic+ run that just finished, this table always exists when COMBAT_MYTHICDUNGEON_END is triggered
Details.LastMythicPlusData = {
MapID = mapID,
Level = level,
ElapsedTime = completionTime or 0.1,
TimeWithoutDeaths = completionTime or 0.1,
OnTime = onTime,
KeystoneUpgradeLevels = keystoneUpgradeLevels,
PracticeRun = practiceRun,
IsAffixRecord = isAffixRecord,
IsMapRecord = isMapRecord,
PrimaryAffix = primaryAffix,
IsEligibleForScore = isEligibleForScore,
UpgradeMembers = upgradeMembers,
OldDungeonScore = oldDungeonScore,
NewDungeonScore = newDungeonScore,
DungeonName = dungeonName,
DungeonId = id,
TimeLimit = timeLimit,
Texture = texture,
BackgroundTexture = backgroundTexture,
StartTime = Details222.MythicPlus.RUN_START_AT,
EndTime = Details222.MythicPlus.RUN_END_AT,
time = completionTime or 0.1,
}
if (completionTime) then
--Subtract death time from time of run to get the true time
local deaths = C_ChallengeMode.GetDeathCount and C_ChallengeMode.GetDeathCount()
if deaths and deaths > 0 then
local secondsPerDeath = 5
if level >= 7 then
secondsPerDeath = 15
end
completionTime = completionTime - deaths * (secondsPerDeath * 1000)
end
Details222.MythicPlus.time = math.floor(completionTime / 1000)
Details.LastMythicPlusData.TimeWithoutDeaths = Details222.MythicPlus.time
Details:Msg("run elapsed time:", DetailsFramework:IntegerToTimer(completionTime / 1000))
else
Details222.MythicPlus.time = 0.1
end
if (Details.mythic_plus.show_damage_graphic) then
C_Timer.After(0, function()
6 months ago
--if (ChallengeModeCompleteBanner) then
-- ChallengeModeCompleteBanner.timeToHold = 0.01
--end
end)
end
--send mythic dungeon end event
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
if (difficultyID == 8) then
Details:SendEvent("COMBAT_MYTHICDUNGEON_END")
end
Details222.MythicPlus.LogStep("===== Mythic+ Finished =====")
end
---@param self frame
---@param bIsInCombat boolean
function Details.parser_functions:PLAYER_IN_COMBAT_CHANGED(bIsInCombat)
if (bIsInCombat) then
--or not, let me think.
else
end
end
function Details.parser_functions:PLAYER_REGEN_ENABLED(...)
--check if the player is a rogue and has the aura Vanish
if (not IsInGroup() and not IsInRaid()) then
if (Details.playerclass == "ROGUE") then
--if the player has vanish aura, skip this check
---@type aurainfo
local auraInfo = C_UnitAuras.GetPlayerAuraBySpellID(11327)
if (auraInfo) then
return true
end
end
end
if (Details.auto_swap_to_dynamic_overall) then
Details:InstanceCall(autoSwapDynamicOverallData, false)
end
--elapsed combat time
Details.LatestCombatDone = GetTime()
local currentCombat = Details:GetCurrentCombat()
currentCombat.CombatEndedAt = GetTime()
currentCombat.TotalElapsedCombatTime = currentCombat.CombatEndedAt - (currentCombat.CombatStartedAt or 0)
C_Timer.After(10, checkIfEncounterIsDone)
3 years ago
--playing alone, just finish the combat right now
if (not IsInGroup() and not IsInRaid()) then
currentCombat.playing_solo = true
Details:SairDoCombate()
else
--is in a raid or party group
3 years ago
C_Timer.After(1, function()
if (IsInRaid()) then
local raidUnitIdCache = Details222.UnitIdCache.Raid
local bInCombat = false
for i = 1, GetNumGroupMembers() do
if (UnitAffectingCombat(raidUnitIdCache[i])) then
bInCombat = true
break
end
end
3 years ago
if (not bInCombat) then
Details:RunScheduledEventsAfterCombat(true)
end
3 years ago
elseif (IsInGroup()) then
local bInCombat = false
local partyUnitIds = Details222.UnitIdCache.Party
for i = 1, #partyUnitIds do
if (UnitExists(partyUnitIds[i]) and UnitAffectingCombat(partyUnitIds[i])) then
bInCombat = true
break
end
end
3 years ago
if (not bInCombat) then
Details:RunScheduledEventsAfterCombat(true)
end
end
end)
end
end
3 years ago
function Details.parser_functions:PLAYER_TALENT_UPDATE()
if (IsInGroup() or IsInRaid()) then
if (Details.SendTalentTimer and not Details.SendTalentTimer:IsCancelled()) then
Details.SendTalentTimer:Cancel()
end
Details.SendTalentTimer = C_Timer.NewTimer(11, function()
Details:SendCharacterData()
end)
end
end
3 years ago
function Details:RefreshPlayerSpecialization()
local specIndex = detailsFramework.GetSpecialization()
if (specIndex) then
local specID = detailsFramework.GetSpecializationInfo(specIndex)
if (specID and specID ~= 0) then
3 years ago
local guid = UnitGUID("player")
if (guid) then
Details.cached_specs[guid] = specID
Details.playerspecid = specID
end
end
end
end
function Details.parser_functions:PLAYER_SPECIALIZATION_CHANGED()
--some parts of details! does call this function, check first for past expansions
if (detailsFramework.IsTimewalkWoW()) then
return
end
Details:RefreshPlayerSpecialization()
3 years ago
if (IsInGroup() or IsInRaid()) then
if (Details.SendTalentTimer and not Details.SendTalentTimer:IsCancelled()) then
Details.SendTalentTimer:Cancel()
end
Details.SendTalentTimer = C_Timer.NewTimer(11, function()
Details:SendCharacterData()
end)
end
end
3 years ago
--[=[
3 years ago
--this is mostly triggered when the player enters in a dual against another player
function Details.parser_functions:UNIT_FACTION(unit)
if (true) then
3 years ago
--disable until figure out how to make this work properlly
--at the moment this event is firing at bgs, arenas, etc making horde icons to show at random
return
end
3 years ago
--check if outdoors
--unit was nil, nameplate might bug here, it should track after the event
if (Details.zone_type == "none" and unit) then
3 years ago
local serial = UnitGUID(unit)
--the serial is valid and isn't THE player and the serial is from a player?
if (serial and serial ~= UnitGUID("player") and serial:find("Player")) then
Details.duel_candidates[serial] = GetTime()
3 years ago
local playerName = Details:GetFullName(unit)
3 years ago
--check if the player is inside the current combat and flag the objects
if (playerName and _current_combat) then
3 years ago
local enemyPlayer1 = _current_combat:GetActor(1, playerName)
local enemyPlayer2 = _current_combat:GetActor(2, playerName)
local enemyPlayer3 = _current_combat:GetActor(3, playerName)
local enemyPlayer4 = _current_combat:GetActor(4, playerName)
if (enemyPlayer1) then
3 years ago
--set to show when the player is solo play
enemyPlayer1.grupo = true
enemyPlayer1.enemy = true
3 years ago
if (IsInGroup()) then
3 years ago
--broadcast the enemy to group members so they can "watch" the damage
end
end
3 years ago
if (enemyPlayer2) then
enemyPlayer2.grupo = true
enemyPlayer2.enemy = true
end
3 years ago
if (enemyPlayer3) then
enemyPlayer3.grupo = true
enemyPlayer3.enemy = true
end
3 years ago
if (enemyPlayer4) then
enemyPlayer4.grupo = true
enemyPlayer4.enemy = true
end
end
end
end
end
--]=]
3 years ago
function Details.parser_functions:ROLE_CHANGED_INFORM(...)
if (Details.last_assigned_role ~= _UnitGroupRolesAssigned("player")) then
Details:CheckSwitchOnLogon (true)
Details.last_assigned_role = _UnitGroupRolesAssigned("player")
end
end
3 years ago
function Details.parser_functions:PLAYER_ROLES_ASSIGNED(...)
if (Details.last_assigned_role ~= _UnitGroupRolesAssigned("player")) then
Details:CheckSwitchOnLogon (true)
Details.last_assigned_role = _UnitGroupRolesAssigned("player")
end
end
3 years ago
function Details:InGroup()
return Details.in_group
end
3 years ago
function Details.parser_functions:GROUP_ROSTER_UPDATE(...)
local bIsInGroup = IsInGroup() or IsInRaid()
if (not Details.in_group) then
Details.in_group = bIsInGroup
3 years ago
if (Details.in_group) then
--player entered in a group, cleanup and set the new enviromnent
Details222.GarbageCollector.RestartInternalGarbageCollector(true)
petContainer.Reset()
Details:SchedulePetUpdate(1)
Details:InstanceCall(Details.AdjustAlphaByContext)
3 years ago
Details:CheckSwitchOnLogon()
Details:CheckVersion()
Details:SendEvent("GROUP_ONENTER")
3 years ago
Details222.AutoRunCode.DispatchAutoRunCode("on_groupchange")
3 years ago
Details:Destroy(Details.trusted_characters)
C_Timer.After(5, Details.ScheduleSyncPlayerActorData)
end
3 years ago
else
Details.in_group = bIsInGroup
3 years ago
if (not Details.in_group) then
--player left the group, run routines to cleanup the environment
Details222.GarbageCollector.RestartInternalGarbageCollector(true)
petContainer.Reset()
Details:SchedulePetUpdate(1)
Details:Destroy(Details.details_users)
Details:InstanceCall(Details.AdjustAlphaByContext)
Details:CheckSwitchOnLogon()
Details:SendEvent("GROUP_ONLEAVE")
Details222.AutoRunCode.DispatchAutoRunCode("on_groupchange")
Details:Destroy(Details.trusted_characters)
else
--player is still in a group
Details:SchedulePetUpdate(2)
3 years ago
--send char data
if (Details.SendCharDataOnGroupChange and not Details.SendCharDataOnGroupChange:IsCancelled()) then
return
end
3 years ago
Details.SendCharDataOnGroupChange = C_Timer.NewTimer(11, function()
Details:SendCharacterData()
Details.SendCharDataOnGroupChange = nil
end)
end
end
3 years ago
Details:SchedulePetUpdate(6)
end
function Details.parser_functions:START_TIMER(...) --~timer
if (Details.debug) then
Details:Msg("(debug) found a timer.")
end
local _, zoneType = GetInstanceInfo()
--check if the player is inside an arena
if (zoneType == "arena") then
if (Details.debug) then
Details:Msg("(debug) timer is an arena countdown.")
end
Details:StartArenaSegment(...)
3 years ago
--check if the player is inside a battleground
elseif (zoneType == "battleground") then
if (Details.debug) then
3 years ago
Details:Msg("(debug) timer is a battleground countdown.")
end
3 years ago
local _, timeSeconds = select(1, ...)
if (Details.start_battleground) then
Details.Schedules.Cancel(Details.start_battleground)
end
--create new schedule
Details.start_battleground = Details.Schedules.NewTimer(timeSeconds, Details.CreateBattlegroundSegment)
Details.Schedules.SetName(Details.start_battleground, "Battleground Start Timer")
end
end
3 years ago
function Details:CreateBattlegroundSegment()
if (_in_combat) then
Details222.discardSegment = true
Details:EndCombat()
end
3 years ago
Details.lastBattlegroundStartTime = GetTime()
Details222.StartCombat()
3 years ago
if (Details.debug) then
Details:Msg("(debug) a battleground has started.")
end
end
3 years ago
--~load
local TurnTheSpeakersOn = function()
if (not Details.gump) then
3 years ago
--failed to load the framework
if (not Details.instance_load_failed) then
Details:CreatePanicWarning()
end
Details.instance_load_failed.text:SetText("Framework for Details! isn't loaded.\nIf you just updated the addon, please reboot the game client.\nWe apologize for the inconvenience and thank you for your comprehension.")
return
end
3 years ago
Details222.AutoRunCode.Code = {}
3 years ago
Details.popup = _G.GameCooltip
Details.in_group = IsInGroup() or IsInRaid()
Details.temp_table1 = {}
Details.encounter = {}
Details.in_combat = false
Details.combat_id = 0
Details.opened_windows = 0
local _, _, _, toc = GetBuildInfo()
if (toc >= 100200) then
Details.playername = UnitName("player") .. "-" .. (GetRealmName():gsub("[%s-]", ''))
else
Details.playername = UnitName("player")
end
3 years ago
Details.playerclass = select(2, UnitClass("player"))
Details.playername = Details:Ambiguate(Details.playername)
--player faction and enemy faction
Details.faction = UnitFactionGroup("player")
if (Details.faction == PLAYER_FACTION_GROUP[0]) then --player is horde
Details.faction_against = PLAYER_FACTION_GROUP[1] --ally
Details.faction_id = 0
3 years ago
elseif (Details.faction == PLAYER_FACTION_GROUP[1]) then --player is alliance
Details.faction_against = PLAYER_FACTION_GROUP[0] --horde
Details.faction_id = 1
end
3 years ago
--this function applies the Details.default_profile to Details object, this isn't yet the player profile which will load later
Details222.LoadSavedVariables.DefaultProfile()
--load up data from savedvariables for the character
Details222.LoadSavedVariables.CharacterData()
if detailsFramework.IsAddonApocalypseWow() then
Details222.BParser.SetSessionCache(Details.damage_meter_sessions)
end
--load up data from saved variables for the account (shared among all the players' characters; this is not the Blizzard account, lol).
Details222.LoadSavedVariables.SharedData()
--load data of the segments saved from latest game session
Details222.LoadSavedVariables.CombatSegments()
3 years ago
--load the profiles
Details:LoadConfig()
3 years ago
Details:UpdateParserGears()
--load auto run code
Details222.AutoRunCode.StartAutoRun()
Details.isLoaded = true
end
function Details.IsLoaded()
return Details.isLoaded
end
3 years ago
function Details.parser_functions:ADDON_LOADED(...)
local addonName = select(1, ...)
if (addonName == "Details") then
TurnTheSpeakersOn()
3 years ago
end
end
3 years ago
local playerLogin = CreateFrame("frame")
playerLogin:RegisterEvent("PLAYER_LOGIN")
playerLogin:SetScript("OnEvent", function()
Details222.StartUp.StartMeUp()
6 months ago
crowdControlSpells = Details.CrowdControlSpellIdsCache
end)
3 years ago
function Details.parser_functions:PET_BATTLE_OPENING_START(...)
Details.pet_battle = true
for index, instance in ipairs(Details.tabela_instancias) do
if (instance.ativa) then
if (Details.debug) then
Details:Msg("(debug) hidding windows for Pet Battle.")
end
3 years ago
instance:SetWindowAlphaForCombat(true, true, 0)
end
end
end
3 years ago
function Details.parser_functions:PET_BATTLE_CLOSE(...)
Details.pet_battle = false
for index, instance in ipairs(Details.tabela_instancias) do
if (instance.ativa) then
if (Details.debug) then
Details:Msg("(debug) Pet Battle finished, calling AdjustAlphaByContext().")
end
instance:AdjustAlphaByContext(true)
end
end
end
3 years ago
function Details.parser_functions:UNIT_NAME_UPDATE(unitId)
Details:SchedulePetUpdate(5)
end
3 years ago
function Details.parser_functions:PLAYER_TARGET_CHANGED(...)
Details:SendEvent("PLAYER_TARGET")
end
local parser_functions = Details.parser_functions
3 years ago
function Details:OnEvent(event, ...)
3 years ago
local func = parser_functions[event]
if (func) then
3 years ago
return func(nil, ...)
end
end
Details.listener:SetScript("OnEvent", Details.OnEvent)
---return the backup table with regular logs, error and backups /dumpt __details_backup._general_logs
function Details222.SaveVariables.GetBackupLogs()
---@type {_general_logs: table, _exit_error: table, _instance_backup: table}
local backupTable = __details_backup
if (not backupTable) then
__details_backup = { --[[GLOBAL]]
_general_logs = {},
_exit_error = {},
_instance_backup = {},
}
return __details_backup
end
backupTable._general_logs = backupTable._general_logs or {}
backupTable._exit_error = backupTable._exit_error or {}
backupTable._instance_backup = backupTable._instance_backup or {}
3 years ago
return backupTable
end
function Details222.SaveVariables.LogEvent(...)
local args = {...}
local newArgs = {}
for index, value in ipairs(args) do
if (type(value) == "string" or type(value) == "number" or type(value) == "boolean") then
newArgs[index] = tostring(value)
end
end
local currentDate = Details222.Date.GetDateForLogs()
local text = currentDate .. " | " .. table.concat(newArgs, ", ")
local backupLogs = Details222.SaveVariables.GetBackupLogs()
table.insert(backupLogs._general_logs, 1, text)
table.remove(backupLogs._general_logs, 30)
end
--logout function ~save ~logout ~savedata
---@type frame
local databaseSaver = CreateFrame("frame")
databaseSaver:RegisterEvent("PLAYER_LOGOUT")
databaseSaver:SetScript("OnEvent", function(...)
--maximum amount of exit errors to be logged, new error are always added to the top of the list (index 1)
local exitErrorsMaxSize = 10
--safe guard logs and user settings
local backupLogs = Details222.SaveVariables.GetBackupLogs()
---@type table
local exitErrors = backupLogs._exit_error
---@param text string the error to be logged
local addToExitErrors = function(text)
table.insert(exitErrors, 1, Details222.Date.GetDateForLogs() .. " | " .. text)
table.remove(exitErrors, 11)
end
---@type string current step of the logout process, used to log which is the current step when an error happens
local currentStep = ""
3 years ago
--save the time played on this class, run protected
local savePlayTimeClass, savePlayTimeErrorText = pcall(function() Details.SavePlayTimeOnClass() end)
if (not savePlayTimeClass) then
addToExitErrors("Saving Play Time: " .. savePlayTimeErrorText)
end
---@type table record a log of events that happened during the logout process
3 years ago
_detalhes_global.exit_log = {}
---@type table record errors that happened during the logout process
3 years ago
_detalhes_global.exit_errors = _detalhes_global.exit_errors or {}
3 years ago
currentStep = "Checking the framework integrity"
if (not Details.gump) then
3 years ago
--failed to load the framework
tinsert(_detalhes_global.exit_log, "The framework wasn't in Details member 'gump'.")
tinsert(_detalhes_global.exit_errors, 1, currentStep .. " | " .. Details222.Date.GetDateForLogs() .. " | " .. Details.GetVersionString() .. " | Framework wasn't loaded |")
return
end
local logSaverError = function(errortext)
local writeLog = function()
_detalhes_global = _detalhes_global or {}
tinsert(_detalhes_global.exit_errors, 1, currentStep .. " | " .. Details222.Date.GetDateForLogs() .. " | " .. Details.GetVersionString() .. " | " .. errortext .. " | " .. debugstack())
6 months ago
table.remove(_detalhes_global.exit_errors, exitErrorsMaxSize)
addToExitErrors(currentStep .. " | " .. Details222.Date.GetDateForLogs() .. " | " .. Details.GetVersionString() .. " | " .. errortext .. " | " .. debugstack())
end
xpcall(writeLog, addToExitErrors)
end
Details.saver_error_func = logSaverError
Details.logoff_saving_data = true
3 years ago
--close breakdown window
if (Details.CloseBreakdownWindow) then
tinsert(_detalhes_global.exit_log, "1 - Closing Breakdown Window.")
currentStep = "Closing Breakdown Window"
xpcall(Details.CloseBreakdownWindow, logSaverError)
3 years ago
end
--do not save window pos
if (Details.tabela_instancias) then
local clearInstances = function()
currentStep = "Dealing With Instances"
tinsert(_detalhes_global.exit_log, "2 - Clearing user placed position from instance windows.")
for id, instance in Details:ListInstances() do
if (id) then
tinsert(_detalhes_global.exit_log, " - " .. id .. " has baseFrame: " .. (instance.baseframe and "yes" or "no") .. ".")
if (instance.baseframe) then
instance.baseframe:SetUserPlaced(false)
instance.baseframe:SetDontSavePosition(true)
end
end
end
end
xpcall(clearInstances, logSaverError)
else
tinsert(_detalhes_global.exit_errors, 1, "not _detalhes.tabela_instancias")
6 months ago
table.remove(_detalhes_global.exit_errors, exitErrorsMaxSize)
addToExitErrors("not _detalhes.tabela_instancias | " .. Details.GetVersionString())
3 years ago
end
--if is in combat during the logout, stop the combat
if (Details.in_combat and Details.tabela_vigente) then
3 years ago
tinsert(_detalhes_global.exit_log, "3 - Leaving current combat.")
currentStep = "Leaving Current Combat"
xpcall(Details.SairDoCombate, logSaverError)
Details.can_panic_mode = true
3 years ago
end
--switch back to default, settings changed by automation
if (Details.CheckSwitchOnLogon and Details.tabela_instancias and Details.tabela_instancias[1] and getmetatable(Details.tabela_instancias[1])) then
3 years ago
tinsert(_detalhes_global.exit_log, "4 - Reversing switches.")
currentStep = "Check Switch on Logon"
xpcall(Details.CheckSwitchOnLogon, logSaverError)
3 years ago
end
--user requested a wipe of the full configuration
if (Details.wipe_full_config) then
3 years ago
tinsert(_detalhes_global.exit_log, "5 - Is a full config wipe.")
addToExitErrors("true: _detalhes.wipe_full_config | " .. Details.GetVersionString())
3 years ago
_detalhes_global = nil
_detalhes_database = nil
return
end
--save the config
3 years ago
tinsert(_detalhes_global.exit_log, "6 - Saving Config.")
currentStep = "Saving Config"
xpcall(Details.SaveConfig, logSaverError)
3 years ago
tinsert(_detalhes_global.exit_log, "7 - Saving Profiles.")
currentStep = "Saving Profile"
xpcall(Details.SaveProfile, logSaverError)
3 years ago
--save the nicktag cache
3 years ago
tinsert(_detalhes_global.exit_log, "8 - Saving nicktag cache.")
local saveNicktabCache = function()
_detalhes_database.nick_tag_cache = Details.CopyTable(_detalhes_database.nick_tag_cache)
end
xpcall(saveNicktabCache, logSaverError)
--save auto run code data
tinsert(_detalhes_global.exit_log, "9 - Saving Auto Run Code.")
local saveAutoRunCode = function()
Details222.AutoRunCode.OnLogout()
end
xpcall(saveAutoRunCode, logSaverError)
end) --end of saving data
3 years ago
local eraNamedSpellsToID = {}
function Details222.Parser.CountInterruptOverlaps()
for _, interruptCastsOnTarget in pairs(interruptOverlapCache) do
--store clusters of interrupts that was attempted on the same target within 1.5 seconds
--this is a table of tables, where each table is a cluster of interrupts
local interruptClusters = {}
--find interrupt casts casted on the same target within 1.5 seconds of each other
local index = 1
while (index < #interruptCastsOnTarget) do
---@type interrupt_overlap
local interruptAttempt = interruptCastsOnTarget[index]
local thisCluster = {interruptAttempt}
local lastIndex = index
for j = index+1, #interruptCastsOnTarget do --from the next interrupt to the end of the table
lastIndex = j
---@type interrupt_overlap
local nextInterruptAttempt = interruptCastsOnTarget[j]
if (detailsFramework.Math.IsNearlyEqual(interruptAttempt.time, nextInterruptAttempt.time, 1.5)) then
table.insert(thisCluster, nextInterruptAttempt)
else
break
end
end
index = lastIndex
if (#thisCluster > 1) then
--add the cluster to the list of clusters
table.insert(interruptClusters, thisCluster)
end
end
local currentCombat = Details:GetCurrentCombat()
for _, thisCluster in ipairs(interruptClusters) do
--iterate among the cluster and add a overlap if those interrupts without success
for i = 1, #thisCluster do
---@type interrupt_overlap
local interruptAttempt = thisCluster[i]
if (not interruptAttempt.interrupted) then
local sourceName = interruptAttempt.sourceName
local utilityActor = currentCombat:GetActor(4, sourceName) --utility container
if (utilityActor) then
utilityActor.interrupt_cast_overlap = (utilityActor.interrupt_cast_overlap or 0) + 1
end
end
end
end
end
end
-- ~parserstart ~startparser ~cleu ~parser
function Details222.Parser.OnParserEvent()
local time, token, hidding, who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12 = CombatLogGetCurrentEventInfo()
local func = token_list[token]
if (func) then
return func(nil, token, time, who_serial, who_name, who_flags, target_serial, target_name, target_flags, target_flags2, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)
end
end
function Details222.Parser.OnParserEventPVP()
local time, token, hidding, sourceGUID, sourceName, sourceFlags, sourceFlags2, targetGUID, targetName, targetFlags, targetFlags2, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12 = CombatLogGetCurrentEventInfo()
local func = token_list[token]
if (func) then
return func(nil, token, time, sourceGUID, sourceName, sourceFlags, targetGUID, targetName, targetFlags, targetFlags2, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)
end
end
--[=[
local midnightEvents = function()
local eventList = {
"DAMAGE_METER_RESET",
"DAMAGE_METER_COMBAT_SESSION_UPDATED",
}
end
--]=]
--open world out of combat spell damage
local outofcombat_spell_damage = function(unused, token, time, whoGUID, whoName, whoFlags, targetGUID, targetName, targetFlags, targetFlags2, ...)
--identify if the attacker is a group member
local IS_GROUP_OBJECT = 0x00000007
local bIsValidGroupMember = bitBand(whoFlags, IS_GROUP_OBJECT) ~= 0
if (bIsValidGroupMember) then
token_list[token](nil, token, time, whoGUID, whoName, whoFlags, targetGUID, targetName, targetFlags, targetFlags2, ...)
end
end
local out_of_combat_interresting_events = {
["SPELL_SUMMON"] = parser.summon,
["SWING_DAMAGE"] = outofcombat_spell_damage,
["SPELL_DAMAGE"] = outofcombat_spell_damage,
}
3 years ago
--OutOfCombat parser is only used in open world to avoid getting information from people that are outside of the group
function Details222.Parser.OnParserEventOutOfCombat()
local time, token, hidding, who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12 = CombatLogGetCurrentEventInfo()
local func = out_of_combat_interresting_events[token]
3 years ago
if (func) then
return func(nil, token, time, who_serial, who_name, who_flags, target_serial, target_name, target_flags, target_flags2, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)
end
end
local parserDebug = {}
function Details.OnParserEventDebug() --buffs: spellschool, auraType, amount, arg1, arg2, arg3
local time, token, hidding, sourceSerial, sourceName, sourceFlags, who_flags2, targetSerial, targetName, targetFlags, target_flags2, spellId, spellName, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, unknown1, unknown2, unknown3, unknown4, unknown5 = CombatLogGetCurrentEventInfo()
if (not parserDebug[token]) then
parserDebug[token] = true
end
end
6 months ago
---~parser ~cleu ~parserevent
Details222.parser_frame:SetScript("OnEvent", Details222.Parser.OnParserEvent)
Details222.PFrame = Details222.parser_frame
function Details:UpdateParser()
_tempo = Details._tempo
end
3 years ago
function Details:GetActorFromCache(value)
return damage_cache[value] or damage_cache_pets[value] or damage_cache_petsOwners[value]
end
---return tables containing the cache of actors
---@return table damageCache, table damageCachePets, table damageCachePetOwners, table healingCache
function Details222.Cache.GetParserCacheTables()
return damage_cache, damage_cache_pets, damage_cache_petsOwners, healing_cache
end
function Details:PrintParserCacheIndexes()
local amount = 0
3 years ago
for n, nn in pairs(damage_cache) do
amount = amount + 1
end
Details:Msg("parser damage_cache", amount)
3 years ago
amount = 0
3 years ago
for n, nn in pairs(damage_cache_pets) do
amount = amount + 1
end
Details:Msg("parser damage_cache_pets", amount)
3 years ago
amount = 0
3 years ago
for n, nn in pairs(damage_cache_petsOwners) do
amount = amount + 1
end
Details:Msg("parser damage_cache_petsOwners", amount)
3 years ago
amount = 0
3 years ago
for n, nn in pairs(healing_cache) do
amount = amount + 1
end
Details:Msg("parser healing_cache", amount)
3 years ago
amount = 0
3 years ago
for n, nn in pairs(energy_cache) do
amount = amount + 1
end
Details:Msg("parser energy_cache", amount)
amount = 0
3 years ago
for n, nn in pairs(misc_cache) do
amount = amount + 1
end
Details:Msg("parser misc_cache", amount)
Details:Msg("group damage", #Details.cache_damage_group)
Details:Msg("group damage", #Details.cache_healing_group)
end
function Details:GetActorsOnDamageCache()
return Details.cache_damage_group
end
3 years ago
function Details:GetActorsOnHealingCache()
return Details.cache_healing_group
end
3 years ago
--called when the zone type changes and ENCOUNTER_END event
function Details222.Cache.ClearAugmentationCache()
Details:Destroy(augmentation_cache.ebon_might) --~roskash
Details:Destroy(augmentation_cache.prescience)
Details:Destroy(augmentation_cache.shield)
Details:Destroy(augmentation_cache.infernobless)
Details:Destroy(augmentation_cache.breath_targets)
Details:Destroy(augmentation_cache.prescience_stacks)
end
--called when restaring the garbage collector, on some options change, at the end of a combat (before COMBAT_PLAYER_LEAVE and after COMBAT_PLAYER_LEAVING)
function Details:ClearParserCache(bIsFromCombatStart) --~wipe
Details:Destroy(damage_cache)
Details:Destroy(damage_cache_pets)
Details:Destroy(damage_cache_petsOwners)
Details:Destroy(healing_cache)
Details:Destroy(energy_cache)
Details:Destroy(misc_cache)
Details:Destroy(misc_cache_pets)
Details:Destroy(misc_cache_petsOwners)
Details:Destroy(npcid_cache)
Details:Destroy(enemy_cast_cache)
Details:Destroy(empower_cache)
3 years ago
Details:Destroy(ignore_death_cache)
3 years ago
Details:Destroy(reflection_damage)
Details:Destroy(reflection_debuffs)
Details:Destroy(reflection_events)
Details:Destroy(reflection_auras)
Details:Destroy(reflection_dispels)
3 years ago
Details:Destroy(dk_pets_cache.army)
Details:Destroy(dk_pets_cache.apoc)
3 years ago
Details:Destroy(cacheAnything.paladin_vivaldi_blessings)
Details:Destroy(cacheAnything.rampage_cast_amount)
if (not bIsFromCombatStart) then
--check if the player is in a mythic dungeon run, if so, don't clear the cache
if (Details.zone_type ~= "party") then
Details:Destroy(augmentation_cache.ebon_might) --~roskash
Details:Destroy(augmentation_cache.prescience)
Details:Destroy(augmentation_cache.prescience_stacks)
Details:Destroy(augmentation_cache.shield)
Details:Destroy(augmentation_cache.infernobless)
end
end
Details:Destroy(augmentation_cache.breath_targets)
cacheAnything.track_hunter_frenzy = Details.combat_log.track_hunter_frenzy
if (Details.combat_log.merge_gemstones_1007) then
6 months ago
--11.0.7 | 468666 = "Cyrce's Circlet"
override_spellId[462526] = 468666 --Roaring War-Queen's Citrine
override_spellId[462527] = 468666 --Seabed Leviathan's Citrine
override_spellId[462528] = 468666 --Legendary Skipper's Citrine
override_spellId[462530] = 468666 --Mariner's Hallowed Citrine
override_spellId[462531] = 468666 --Old Salt's Bardic Citrine
override_spellId[462532] = 468666 --Storm Sewer's Citrine
override_spellId[462534] = 468666 --Windsinger's Runed Citrine
override_spellId[462535] = 468666 --Fathomdweller's Runed Citrine
override_spellId[462536] = 468666 --Stormbringer's Runed Citrine
override_spellId[462538] = 468666 --Undersea Overseer's Citrine
override_spellId[462539] = 468666 --Squall Sailor's Citrine
override_spellId[462540] = 468666 --Thunderlord's Crackling Citrine
override_spellId[462951] = 468666 --Thunderlord's Crackling Citrine
override_spellId[462952] = 468666 --Squall Sailor's Citrine
override_spellId[462953] = 468666 --Undersea Overseer's Citrine
override_spellId[462958] = 468666 --Storm Sewer's Citrine
override_spellId[462959] = 468666 --Old Salt's Bardic Citrine
override_spellId[462960] = 468666 --Mariner's Hallowed Citrine
override_spellId[462962] = 468666 --Legendary Skipper's Citrine
override_spellId[462963] = 468666 --Seabed Leviathan's Citrine
override_spellId[462964] = 468666 --Roaring War-Queen's Citrine
override_spellId[465961] = 468666 --Stormbringer's Runed Citrine
override_spellId[465962] = 468666 --Fathomdweller's Runed Citrine
override_spellId[465963] = 468666 --Windsinger's Runed Citrine
override_spellId[468422] = 468666 --Storm Sewer's Citrine
override_spellId[468990] = 468666 --Seabed Leviathan's Citrine
override_spellId[469397] = 468666 --Roaring War-Queen's Citrine
override_spellId[470821] = 468666 --Pluck Out Singing Citrine
--10.0.7 ring powers merged, https://gist.github.com/ljosberinn/65abe150133ff3a08cd70f840f7dd019 (by Gerrit Alex - WCL)
override_spellId[403225] = 404884 --Flame Licked Stone
override_spellId[404974] = 404884 --Shining Obsidian Stone
override_spellId[405220] = 404884 --Pestilent Plague Stone
override_spellId[405221] = 404884 --Pestilent Plague Stone
override_spellId[405209] = 404884 --Humming Arcane Stone
override_spellId[403391] = 404884 --Freezing Ice Stone
override_spellId[404911] = 404884 --Desirous Blood Stone
override_spellId[404941] = 404884 --Shining Obsidian Stone
override_spellId[403087] = 404884 --Storm Infused Stone
override_spellId[403273] = 404884 --Fel Flame via Entropic Fel Stone
override_spellId[403171] = 404884 --Uncontainable Charge via Echoing Thunder Stone
override_spellId[405235] = 404884 --Wild Spirit Stone
override_spellId[403381] = 404884 --Deluging Water Stone
override_spellId[405118] = 404884 --Exuding Steam Stone
override_spellId[403408] = 404884 --Exuding Steam Stone
override_spellId[403336] = 404884 --Indomitable Earth Stone
override_spellId[403392] = 404884 --Cold Frost Stone
override_spellId[403376] = 404884 --Gleaming Iron Stone
override_spellId[403253] = 404884 --Raging Magma Stone
override_spellId[403257] = 404884 --Searing Smokey Stone
else
6 months ago
--11.0.7
override_spellId[462526] = nil --Roaring War-Queen's Citrine
override_spellId[462527] = nil --Seabed Leviathan's Citrine
override_spellId[462528] = nil --Legendary Skipper's Citrine
override_spellId[462530] = nil --Mariner's Hallowed Citrine
override_spellId[462531] = nil --Old Salt's Bardic Citrine
override_spellId[462532] = nil --Storm Sewer's Citrine
override_spellId[462534] = nil --Windsinger's Runed Citrine
override_spellId[462535] = nil --Fathomdweller's Runed Citrine
override_spellId[462536] = nil --Stormbringer's Runed Citrine
override_spellId[462538] = nil --Undersea Overseer's Citrine
override_spellId[462539] = nil --Squall Sailor's Citrine
override_spellId[462540] = nil --Thunderlord's Crackling Citrine
override_spellId[462951] = nil --Thunderlord's Crackling Citrine
override_spellId[462952] = nil --Squall Sailor's Citrine
override_spellId[462953] = nil --Undersea Overseer's Citrine
override_spellId[462958] = nil --Storm Sewer's Citrine
override_spellId[462959] = nil --Old Salt's Bardic Citrine
override_spellId[462960] = nil --Mariner's Hallowed Citrine
override_spellId[462962] = nil --Legendary Skipper's Citrine
override_spellId[462963] = nil --Seabed Leviathan's Citrine
override_spellId[462964] = nil --Roaring War-Queen's Citrine
override_spellId[465961] = nil --Stormbringer's Runed Citrine
override_spellId[465962] = nil --Fathomdweller's Runed Citrine
override_spellId[465963] = nil --Windsinger's Runed Citrine
override_spellId[468422] = nil --Storm Sewer's Citrine
override_spellId[468990] = nil --Seabed Leviathan's Citrine
override_spellId[469397] = nil --Roaring War-Queen's Citrine
override_spellId[470821] = nil --Pluck Out Singing Citrine
--10.0.7
override_spellId[403225] = nil --Flame Licked Stone
override_spellId[404974] = nil --Shining Obsidian Stone
override_spellId[405220] = nil --Pestilent Plague Stone
override_spellId[405221] = nil --Pestilent Plague Stone
override_spellId[405209] = nil --Humming Arcane Stone
override_spellId[403391] = nil --Freezing Ice Stone
override_spellId[404911] = nil --Desirous Blood Stone
override_spellId[404941] = nil --Shining Obsidian Stone
override_spellId[403087] = nil --Storm Infused Stone
override_spellId[403273] = nil --Fel Flame via Entropic Fel Stone
override_spellId[403171] = nil --Uncontainable Charge via Echoing Thunder Stone
override_spellId[405235] = nil --Wild Spirit Stone
override_spellId[403381] = nil --Deluging Water Stone
override_spellId[405118] = nil --Exuding Steam Stone
override_spellId[403408] = nil --Exuding Steam Stone
override_spellId[403336] = nil --Indomitable Earth Stone
override_spellId[403392] = nil --Cold Frost Stone
override_spellId[403376] = nil --Gleaming Iron Stone
override_spellId[403253] = nil --Raging Magma Stone
override_spellId[403257] = nil --Searing Smokey Stone
end
if (Details.combat_log.merge_critical_heals) then
override_spellId[94472] = 81751 --disc priest attonement and crit. Crits use separate id.
override_spellId[281469] = 270501 --disc priest contrition attonement and crit. Crits use separate id.
override_spellId[388025] = 388024 --MW monk Ancient Teachings, heals from damage, crit and normal are separate.
override_spellId[389325] = 389328 --MW monk Awakened Faeline, ^
else
override_spellId[94472] = nil --disc priest attonement and crit. Crits use separate id.
override_spellId[281469] = nil --disc priest contrition attonement and crit. Crits use separate id.
override_spellId[388025] = nil --MW monk Ancient Teachings, heals from damage, crit and normal are separate.
override_spellId[389325] = nil --MW monk Awakened Faeline, ^
end
damage_cache = setmetatable({}, Details.weaktable)
damage_cache_pets = setmetatable({}, Details.weaktable)
damage_cache_petsOwners = setmetatable({}, Details.weaktable)
3 years ago
healing_cache = setmetatable({}, Details.weaktable)
3 years ago
energy_cache = setmetatable({}, Details.weaktable)
3 years ago
misc_cache = setmetatable({}, Details.weaktable)
misc_cache_pets = setmetatable({}, Details.weaktable)
misc_cache_petsOwners = setmetatable({}, Details.weaktable)
end
3 years ago
function parser:RevomeActorFromCache(actor_serial, actor_name)
if (actor_name) then
3 years ago
damage_cache[actor_name] = nil
damage_cache_pets[actor_name] = nil
damage_cache_petsOwners[actor_name] = nil
healing_cache[actor_serial] = nil
energy_cache[actor_name] = nil
misc_cache[actor_name] = nil
misc_cache_pets[actor_name] = nil
misc_cache_petsOwners[actor_name] = nil
end
3 years ago
if (actor_serial) then
3 years ago
damage_cache[actor_serial] = nil
damage_cache_pets[actor_serial] = nil
damage_cache_petsOwners[actor_serial] = nil
healing_cache[actor_serial] = nil
energy_cache[actor_serial] = nil
misc_cache[actor_serial] = nil
misc_cache_pets[actor_serial] = nil
misc_cache_petsOwners[actor_serial] = nil
end
end
function Details:UptadeRaidMembersCache()
Details:Destroy(raid_members_cache)
Details:Destroy(tanks_members_cache)
Details:Destroy(auto_regen_cache)
Details:Destroy(bitfield_swap_cache)
Details:Destroy(empower_cache)
3 years ago
local currentCombat = Details:GetCurrentCombat()
local groupRoster = currentCombat.raid_roster
3 years ago
if (IsInRaid()) then
local unitIdCache = Details222.UnitIdCache.Raid
6 months ago
Details:Destroy(Details.HealthCache)
Details:Destroy(Details.HealthMaxCache)
Details.HealthMaxCalls = 0
local max = math.max
local UnitHealth = UnitHealth
local UnitHealthMax = UnitHealthMax
3 years ago
for i = 1, GetNumGroupMembers() do
local unitId = unitIdCache[i]
local unitName = GetUnitName(unitId, true)
local unitGUID = UnitGUID(unitId)
local _, unitClass = UnitClass(unitId)
Details222.ClassCache.ByName[unitName] = unitClass
Details222.ClassCache.ByGUID[unitGUID] = unitClass
3 years ago
raid_members_cache[unitGUID] = unitName
groupRoster[unitName] = unitGUID
3 years ago
local role = _UnitGroupRolesAssigned(unitName)
if (role == "TANK") then
tanks_members_cache[unitGUID] = true
end
3 years ago
if (auto_regen_power_specs[Details.cached_specs[unitGUID]]) then
auto_regen_cache[unitName] = auto_regen_power_specs[Details.cached_specs[unitGUID]]
end
6 months ago
Details.HealthCache[unitGUID] = UnitHealth(unitId)
Details.HealthMaxCache[unitGUID] = max(UnitHealthMax(unitId), SMALL_FLOAT)
end
3 years ago
elseif (IsInGroup()) then
local unitIdCache = Details222.UnitIdCache.Party
6 months ago
for i = 1, GetNumGroupMembers() do
local unitId = unitIdCache[i]
3 years ago
local unitName = GetUnitName(unitId, true)
local unitGUID = UnitGUID(unitId)
3 years ago
raid_members_cache[unitGUID] = unitName
groupRoster[unitName] = unitGUID
local role = _UnitGroupRolesAssigned(unitName)
if (role == "TANK") then
tanks_members_cache[unitGUID] = true
end
3 years ago
if (auto_regen_power_specs[Details.cached_specs[unitGUID]]) then
auto_regen_cache[unitName] = auto_regen_power_specs[Details.cached_specs[unitGUID]]
end
6 months ago
Details.HealthCache[unitGUID] = UnitHealth(unitId)
Details.HealthMaxCache[unitGUID] = max(UnitHealthMax(unitId), SMALL_FLOAT)
end
3 years ago
--player
local playerName = Details.playername
local playerGUID = UnitGUID("player")
3 years ago
raid_members_cache[playerGUID] = playerName
groupRoster[playerName] = playerGUID
3 years ago
local role = _UnitGroupRolesAssigned(playerName)
if (role == "TANK") then
tanks_members_cache[playerGUID] = true
end
3 years ago
if (auto_regen_power_specs[Details.cached_specs[playerGUID]]) then
auto_regen_cache[playerName] = auto_regen_power_specs[Details.cached_specs[playerGUID]]
end
6 months ago
Details.HealthCache[playerGUID] = UnitHealth("player")
Details.HealthMaxCache[playerGUID] = max(UnitHealthMax("player"), SMALL_FLOAT)
else
local playerName = Details.playername
local playerGUID = UnitGUID("player")
3 years ago
raid_members_cache[playerGUID] = playerName
groupRoster[playerName] = playerGUID
3 years ago
local role = _UnitGroupRolesAssigned(playerName)
if (role == "TANK") then
tanks_members_cache[playerGUID] = true
else
local spec = detailsFramework.GetSpecialization()
if (spec and spec ~= 0) then
if not detailsFramework.IsTBCWow() then
if (detailsFramework.GetSpecializationRole (spec) == "TANK") then
tanks_members_cache[playerGUID] = true
end
end
end
end
3 years ago
if (auto_regen_power_specs[Details.cached_specs[playerGUID]]) then
auto_regen_cache[playerName] = auto_regen_power_specs[Details.cached_specs[playerGUID]]
end
6 months ago
Details.HealthCache[playerGUID] = UnitHealth("player")
Details.HealthMaxCache[playerGUID] = max(UnitHealthMax("player"), SMALL_FLOAT)
end
if (Details.iam_a_tank) then
3 years ago
tanks_members_cache[UnitGUID("player")] = true
end
end
6 months ago
---returns a table containing crowd control spells.
---the table maps spell names to a boolean value indicating whether the spell is a crowd control spell.
---@param self details
---@return table<spellid, boolean> crowdControlSpellsTable table of crowd control spells.
function Details:GetCrowdControlSpells()
return crowdControlSpells
end
---return true or false
---@param unitGUID string
---@return boolean
function Details:IsATank(unitGUID)
return tanks_members_cache[unitGUID] or false
end
3 years ago
---returns the unit name
---@param unitGUID string
---@return string
function Details:IsInCache(unitGUID)
return raid_members_cache[unitGUID]
end
---return the internal raid members cache, containing the unitGUID as key and the unitName as value
---@return table
function Details:GetParserPlayerCache()
return raid_members_cache
end
3 years ago
function Details:SetDeathLogTemporaryLimit(limitAmount) --when the zone type changes, this is automatically called with value nil (remove the temp limit)
if (limitAmount and limitAmount > Details.deadlog_events) then
Details.temp_deathlog_limit = limitAmount
_amount_of_last_events = Details.temp_deathlog_limit or Details.deadlog_events
else
Details.temp_deathlog_limit = nil
_amount_of_last_events = Details.deadlog_events
end
end
--serach key: ~cache
function Details:UpdateParserGears(bIsFromCombatStart)
3 years ago
--refresh combat tables
_current_combat = Details.tabela_vigente
3 years ago
--last events pointer
last_events_cache = _current_combat.player_last_events
_amount_of_last_events = Details.deadlog_events
6 months ago
_parser_options = Details.parser_options
shield_spellid_cache = Details.shield_spellid_cache
3 years ago
--refresh total containers
_current_total = _current_combat.totals
_current_gtotal = _current_combat.totals_grupo
3 years ago
--refresh actors containers
_current_damage_container = _current_combat[1]
_current_heal_container = _current_combat[2]
_current_energy_container = _current_combat[3]
_current_misc_container = _current_combat[4]
--refresh data capture options
--_recording_self_buffs = _detalhes.RecordPlayerSelfBuffs --can be deprecated
--_recording_healing = _detalhes.RecordHealingDone --can be deprecated
--_recording_took_damage = _detalhes.RecordRealTimeTookDamage
--_recording_ability_with_buffs = _detalhes.RecordPlayerAbilityWithBuffs --can be deprecated
_in_combat = Details.in_combat
6 months ago
crowdControlSpells = Details.CrowdControlSpellIdsCache
Details:Destroy(ignored_npcids)
3 years ago
4 years ago
--fill it with the default npcs ignored
for npcId in pairs(Details.default_ignored_npcs) do
4 years ago
ignored_npcids[npcId] = true
end
3 years ago
4 years ago
--fill it with the npcs the user ignored
for npcId in pairs(Details.npcid_ignored) do
4 years ago
ignored_npcids[npcId] = true
end
ignored_npcids[0] = nil
if (_in_combat) then
if (Details.parser_options.energy_overflow) then
if (not Details.AutoRegenThread or Details.AutoRegenThread:IsCancelled()) then
Details.AutoRegenThread = C_Timer.NewTicker(AUTO_REGEN_PRECISION / 10, regen_power_overflow_check) --at the moment, runs 5 times per second
end
end
else
if (Details.AutoRegenThread and not Details.AutoRegenThread:IsCancelled()) then
Details.AutoRegenThread:Cancel()
Details.AutoRegenThread = nil
end
end
3 years ago
if (Details.hooks["HOOK_COOLDOWN"].enabled) then
_hook_cooldowns = true
else
_hook_cooldowns = false
end
3 years ago
if (Details.hooks["HOOK_DEATH"].enabled) then
_hook_deaths = true
else
_hook_deaths = false
end
3 years ago
if (Details.hooks["HOOK_BATTLERESS"].enabled) then
_hook_battleress = true
else
_hook_battleress = false
end
3 years ago
if (Details.hooks["HOOK_INTERRUPT"].enabled) then
_hook_interrupt = true
else
_hook_interrupt = false
end
3 years ago
is_using_spellId_override = Details.override_spellids
3 years ago
Details:ClearParserCache(bIsFromCombatStart)
end
4 years ago
function Details.DumpIgnoredNpcs()
4 years ago
return ignored_npcids
end
3 years ago
--serach key: ~api
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--details api functions
3 years ago
--number of combat
function Details:GetCombatId()
return Details.combat_id
end
---return true if in combat
---@return boolean bIsInCombat
function Details:IsInCombat()
return _in_combat
end
3 years ago
function Details:IsInEncounter()
return Details.encounter_table.id and true or false
end
3 years ago
function Details:GetAllActors(_combat, _actorname)
return Details:GetActor(_combat, 1, _actorname), Details:GetActor(_combat, 2, _actorname), Details:GetActor(_combat, 3, _actorname), Details:GetActor(_combat, 4, _actorname)
end
3 years ago
--get player
function Details:GetPlayer(_actorname, _combat, _attribute)
return Details:GetActor(_combat, _attribute, _actorname)
end
3 years ago
--get an actor
function Details:GetActor(combatId, attribute, actorName)
if (not combatId) then
combatId = "current" --current combat
end
3 years ago
if (not attribute) then
attribute = 1 --damage
end
3 years ago
if (not actorName) then
actorName = Details.playername
end
3 years ago
if (combatId == 0 or combatId == "current") then
local actor = Details.tabela_vigente(attribute, actorName)
if (actor) then
return actor
else
3 years ago
return nil
end
3 years ago
elseif (combatId == -1 or combatId == "overall") then
local actor = Details.tabela_overall(attribute, actorName)
if (actor) then
return actor
else
3 years ago
return nil
end
3 years ago
elseif (type(combatId) == "number") then
local segmentsTable = Details:GetCombatSegments()
---@type combat
local combatObject = segmentsTable[combatId]
if (combatObject) then
---@type actor
local actorObject = combatObject(attribute, actorName)
if (actorObject) then
return actorObject
else
3 years ago
return nil
end
else
3 years ago
return nil
end
else
3 years ago
return nil
end
end
function Details:GetUnitId(unitName)
unitName = unitName or self.nome
unitName = Details:Ambiguate(unitName)
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true)
if (openRaidLib) then
local unitId = openRaidLib.GetUnitID(unitName)
if (unitId) then
return unitId
end
end
if (IsInRaid()) then
for i = 1, GetNumGroupMembers() do
local unitId = "raid" .. i
if (GetUnitName(unitId, true) == unitName) then
return unitId
end
end
elseif (IsInGroup()) then
for i = 1, GetNumGroupMembers() -1 do
local unitId = "party" .. i
if (GetUnitName(unitId, true) == unitName) then
return unitId
end
end
if (Details.playername == unitName) then
return "player"
end
end
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 years ago
--battleground parser
Details.pvp_parser_frame:SetScript("OnEvent", function(self, event)
self:ReadPvPData()
end)
3 years ago
function Details:BgScoreUpdate()
RequestBattlefieldScoreData()
end
3 years ago
--start the virtual parser
function Details.pvp_parser_frame:StartBgUpdater()
Details.pvp_parser_frame:RegisterEvent("UPDATE_BATTLEFIELD_SCORE")
if (Details.pvp_parser_frame.ticker) then
Details.Schedules.Cancel(Details.pvp_parser_frame.ticker)
end
3 years ago
Details.pvp_parser_frame.ticker = Details.Schedules.NewTicker(10, Details.BgScoreUpdate)
Details.Schedules.SetName(Details.pvp_parser_frame.ticker, "Battleground Updater")
end
3 years ago
--stop the virtual parser
function Details.pvp_parser_frame:StopBgUpdater()
Details.pvp_parser_frame:UnregisterEvent("UPDATE_BATTLEFIELD_SCORE")
Details.Schedules.Cancel(Details.pvp_parser_frame.ticker)
Details.pvp_parser_frame.ticker = nil
end
3 years ago
function Details.pvp_parser_frame:ReadPvPData()
local players = GetNumBattlefieldScores()
local _player, realmName = UnitFullName("player")
if (not realmName) then
realmName = GetRealmName()
realmName = realmName:gsub("[%s-]", "")
end
local currentCombat = Details:GetCurrentCombat()
for i = 1, players do
local name, killingBlows, honorableKills, deaths, honorGained, faction, race, rank, class, classToken, damageDone, healingDone, bgRating, ratingChange, preMatchMMR, mmrChange, talentSpec
6 months ago
if (isCLASSIC) then
name, killingBlows, honorableKills, deaths, honorGained, faction, rank, race, class, classToken, damageDone, healingDone, bgRating, ratingChange, preMatchMMR, mmrChange, talentSpec = GetBattlefieldScore(i)
else
name, killingBlows, honorableKills, deaths, honorGained, faction, race, class, classToken, damageDone, healingDone, bgRating, ratingChange, preMatchMMR, mmrChange, talentSpec = GetBattlefieldScore(i)
end
3 years ago
6 months ago
if (not isCLASSIC) then --Must be dragonflight
if (not name:match("%-")) then
name = name .. "-" .. realmName
end
end
name = Details:Ambiguate(name)
--damage done
local actor = currentCombat:GetActor(DETAILS_ATTRIBUTE_DAMAGE, name)
if (actor) then
if (damageDone == 0) then
damageDone = damageDone + Details:GetOrderNumber()
end
actor.total = damageDone
actor.classe = classToken or "UNKNOW"
3 years ago
elseif (name ~= "Unknown" and type(name) == "string" and string.len(name) > 1) then
local guid = UnitGUID(Details:Ambiguate(name))
if (guid) then
local flag
if (Details.faction_id == faction) then --is from the same faction
flag = 0x514
else
flag = 0x548
end
3 years ago
actor = _current_damage_container:GetOrCreateActor (guid, name, flag, true)
if (actor) then
actor.total = Details:GetOrderNumber()
actor.classe = classToken or "UNKNOW"
if (flag == 0x548) then
--oponent
actor.enemy = true
end
actor.made_by_pvpparser = true
end
end
end
3 years ago
--healing done
local actor = currentCombat:GetActor(DETAILS_ATTRIBUTE_HEAL, name)
if (actor) then
if (healingDone == 0) then
healingDone = healingDone + Details:GetOrderNumber()
end
actor.total = healingDone
actor.classe = classToken or "UNKNOW"
3 years ago
elseif (name ~= "Unknown" and type(name) == "string" and string.len(name) > 1) then
local guid = UnitGUID(name)
if (guid) then
local flag
if (Details.faction_id == faction) then --is from the same faction
flag = 0x514
else
flag = 0x548
end
3 years ago
actor = _current_heal_container:GetOrCreateActor (guid, name, flag, true)
if (actor) then
actor.total = Details:GetOrderNumber()
actor.classe = classToken or "UNKNOW"
if (flag == 0x548) then
--oponent
actor.enemy = true
end
actor.made_by_pvpparser = true
end
end
end
end
end
--[=
local detailsParserDebugFrame = CreateFrame("frame", "DetailsParserDebugFrame", UIParent)
detailsParserDebugFrame:SetSize(100, 200)
DetailsFramework:ApplyStandardBackdrop(detailsParserDebugFrame)
detailsParserDebugFrame:SetPoint("left", UIParent, "left", 2, 350)
detailsParserDebugFrame.AllIcons = {}
detailsParserDebugFrame.AllTexts = {}
local iconSize = 40
detailsParserDebugFrame:Hide()
local spellIcon1 = detailsParserDebugFrame:CreateTexture(nil, "overlay")
spellIcon1:SetSize(iconSize, iconSize)
spellIcon1:SetPoint("topleft", detailsParserDebugFrame, "topleft", 2, -5)
local text1 = detailsParserDebugFrame:CreateFontString(nil, "overlay", "GameFontNormal")
text1:SetPoint("left", spellIcon1, "right", 2, 0)
local spellIcon2 = detailsParserDebugFrame:CreateTexture(nil, "overlay")
spellIcon2:SetSize(iconSize, iconSize)
spellIcon2:SetPoint("topleft", spellIcon1, "bottomleft", 0, -2)
local text2 = detailsParserDebugFrame:CreateFontString(nil, "overlay", "GameFontNormal")
text2:SetPoint("left", spellIcon2, "right", 2, 0)
local spellIcon3 = detailsParserDebugFrame:CreateTexture(nil, "overlay")
spellIcon3:SetSize(iconSize, iconSize)
spellIcon3:SetPoint("topleft", spellIcon2, "bottomleft", 0, -2)
local text3 = detailsParserDebugFrame:CreateFontString(nil, "overlay", "GameFontNormal")
text3:SetPoint("left", spellIcon3, "right", 2, 0)
local spellIcon4 = detailsParserDebugFrame:CreateTexture(nil, "overlay")
spellIcon4:SetSize(iconSize, iconSize)
spellIcon4:SetPoint("topleft", spellIcon3, "bottomleft", 0, -2)
local text4 = detailsParserDebugFrame:CreateFontString(nil, "overlay", "GameFontNormal")
text4:SetPoint("left", spellIcon4, "right", 2, 0)
local spellIcon5 = detailsParserDebugFrame:CreateTexture(nil, "overlay")
spellIcon5:SetSize(iconSize, iconSize)
spellIcon5:SetPoint("topleft", spellIcon4, "bottomleft", 0, -2)
local text5 = detailsParserDebugFrame:CreateFontString(nil, "overlay", "GameFontNormal")
text5:SetPoint("left", spellIcon5, "right", 2, 0)
tinsert(detailsParserDebugFrame.AllIcons, spellIcon1)
tinsert(detailsParserDebugFrame.AllIcons, spellIcon2)
tinsert(detailsParserDebugFrame.AllIcons, spellIcon3)
tinsert(detailsParserDebugFrame.AllIcons, spellIcon4)
tinsert(detailsParserDebugFrame.AllIcons, spellIcon5)
tinsert(detailsParserDebugFrame.AllTexts, text1)
tinsert(detailsParserDebugFrame.AllTexts, text2)
tinsert(detailsParserDebugFrame.AllTexts, text3)
tinsert(detailsParserDebugFrame.AllTexts, text4)
tinsert(detailsParserDebugFrame.AllTexts, text5)
function detailsParserDebugFrame:BlinkIcon(spellId, iconId)
local spellName, _, spellIcon = GetSpellInfo(spellId)
local icon = self.AllIcons[iconId]
if (spellIcon) then
icon:SetTexture(spellIcon)
icon:Show()
C_Timer.After(1, function()
icon:Hide()
end)
end
end
--]=]
--end