From 33b8b58255aa2338963568254c154ba1189a5275 Mon Sep 17 00:00:00 2001 From: Jrc13245 Date: Fri, 13 Feb 2026 16:27:29 -0500 Subject: [PATCH] fix old errors and improve efficiency and resource usage --- .../MikCombatEventHelper.lua | 136 ++++---- .../MikScrollingBattleText.lua | 316 ++++++++++-------- .../MikTableRecyclerObject.lua | 24 +- MikScrollingBattleTextOptions/MSBTOptions.lua | 8 +- 4 files changed, 255 insertions(+), 229 deletions(-) diff --git a/MikScrollingBattleText/MikCombatEventHelper.lua b/MikScrollingBattleText/MikCombatEventHelper.lua index 08e699b..cd94890 100644 --- a/MikScrollingBattleText/MikCombatEventHelper.lua +++ b/MikScrollingBattleText/MikCombatEventHelper.lua @@ -142,6 +142,9 @@ local globalStringInfoArray = {}; local playerName; local playerClass; +-- Cached pet name, updated once per event dispatch. +local cachedPetName; + -- Tables to hold ordered/unordered captured data. local orderedCaptureData = {}; local unorderedCaptureData = {}; @@ -176,12 +179,13 @@ local hasNampower = false local hasSuperWoW = false local hasUnitXP = false --- Runtime detection flags for CVar-gated Nampower events. +-- Runtime detection flags for Nampower events. -- These start false and flip true on first invocation of the corresponding handler, --- so CHAT_MSG parsing remains active until the CVar-gated events actually fire. +-- so CHAT_MSG parsing remains active until the Nampower events actually fire. local nampowerHealsActive = false local nampowerAutoAttackActive = false local nampowerEnergizeActive = false +local nampowerSpellDamageActive = false -- Cached player GUID for Nampower event handlers (set in Init when SuperWoW/Nampower present). local playerGUID = nil @@ -479,9 +483,9 @@ combatEventDispatch["CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES"] = handleIncomingM combatEventDispatch["CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES"] = handleIncomingMeleeMisses combatEventDispatch["CHAT_MSG_COMBAT_PARTY_MISSES"] = handleIncomingMeleeMisses --- Incoming Spell/Ability Damage + Power Losses +-- Incoming Spell/Ability Damage + Power Losses (Nampower: SPELL_DAMAGE_EVENT_OTHER) local function handleIncomingSpellDamage(msg) - if not hasNampower then + if not nampowerSpellDamageActive then MikCEH.ParseForIncomingSpellHitsAndMisses(msg) end MikCEH.ParseForPowerLosses(msg) @@ -491,8 +495,9 @@ combatEventDispatch["CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE"] = handleIncomi combatEventDispatch["CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"] = handleIncomingSpellDamage combatEventDispatch["CHAT_MSG_SPELL_PARTY_DAMAGE"] = handleIncomingSpellDamage --- Incoming damage from shields +-- Incoming damage from shields (Nampower: SPELL_DAMAGE_EVENT_OTHER) combatEventDispatch["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] = function(msg) + if nampowerSpellDamageActive then return end MikCEH.ParseForIncomingDamageShieldDamage(msg) end @@ -506,7 +511,7 @@ combatEventDispatch["CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF"] = handleIncomingSpel -- Incoming Debuffs, DoTs, Power Gains combatEventDispatch["CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE"] = function(msg) - if not hasNampower then + if not nampowerSpellDamageActive then MikCEH.ParseForIncomingDebuffs(msg) end if not nampowerEnergizeActive then @@ -518,7 +523,7 @@ end combatEventDispatch["CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"] = function(msg) if not nampowerHealsActive then if not MikCEH.ParseForIncomingSpellHeals(msg) then - if not hasNampower then + if not nampowerSpellDamageActive then MikCEH.ParseForIncomingBuffs(msg) end MikCEH.ParseForOutgoingHoTs(msg) @@ -541,13 +546,15 @@ combatEventDispatch["CHAT_MSG_COMBAT_SELF_MISSES"] = function(msg) MikCEH.ParseForOutgoingMisses(msg) end --- Outgoing Spell/Ability Damage +-- Outgoing Spell/Ability Damage (Nampower: SPELL_DAMAGE_EVENT_SELF) combatEventDispatch["CHAT_MSG_SPELL_SELF_DAMAGE"] = function(msg) + if nampowerSpellDamageActive then return end MikCEH.ParseForOutgoingSpellHitsAndMisses(msg) end --- Outgoing damage from shields +-- Outgoing damage from shields (Nampower: SPELL_DAMAGE_EVENT_SELF) combatEventDispatch["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] = function(msg) + if nampowerSpellDamageActive then return end MikCEH.ParseForOutgoingDamageShieldDamage(msg) end @@ -571,9 +578,9 @@ combatEventDispatch["CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS"] = handleOutg combatEventDispatch["CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS"] = handleOutgoingHoTs combatEventDispatch["CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS"] = handleOutgoingHoTs --- Outgoing DoTs, Power Losses +-- Outgoing DoTs, Power Losses (Nampower: SPELL_DAMAGE_EVENT_SELF with DoT flag) local function handleOutgoingDoTs(msg) - if not hasNampower then + if not nampowerSpellDamageActive then MikCEH.ParseForOutgoingDoTs(msg) end MikCEH.ParseForPowerLosses(msg) @@ -593,8 +600,9 @@ combatEventDispatch["CHAT_MSG_COMBAT_PET_MISSES"] = function(msg) MikCEH.ParseForOutgoingPetMisses(msg) end --- Outgoing Pet Spell/Ability Damage +-- Outgoing Pet Spell/Ability Damage (Nampower: SPELL_DAMAGE_EVENT_SELF with pet GUID) combatEventDispatch["CHAT_MSG_SPELL_PET_DAMAGE"] = function(msg) + if nampowerSpellDamageActive then return end MikCEH.ParseForOutgoingPetSpellHitsAndMisses(msg) end @@ -638,6 +646,7 @@ end -- This function parses the chat message combat events using the dispatch table. -- ********************************************************************************** function MikCEH.ParseCombatEvents(event, combatMessage) + cachedPetName = UnitName("pet"); local handler = combatEventDispatch[event] if handler then handler(combatMessage) end end @@ -661,6 +670,7 @@ function MikCEH.Init() MikCEH.nampowerHealsActive = false MikCEH.nampowerAutoAttackActive = false MikCEH.nampowerEnergizeActive = false + MikCEH.nampowerSpellDamageActive = false -- Check Nampower version — v2.33.0+ required for correct event support. if not hasNampower then @@ -896,6 +906,9 @@ nampowerHandlers["SPELL_DAMAGE_EVENT_SELF"] = function() return -- Not from player or pet, ignore. end + -- Disable CHAT_MSG fallback now that we've confirmed this handler fires. + nampowerSpellDamageActive = true + local spellName = GetSpellNameFromId(spellId) local damageType = SchoolToDamageType(spellSchool) local targetName = GetNameFromGUID(targetGuid) @@ -1240,6 +1253,8 @@ nampowerHandlers["SPELL_MISS_SELF"] = function() if not IsPlayerGUID(casterGuid) then return end + nampowerSpellDamageActive = true + local spellName = GetSpellNameFromId(spellId) local targetName = GetNameFromGUID(targetGuid) local actionType = nampowerMissToAction[missInfo] or MikCEH.ACTIONTYPE_MISS @@ -1382,22 +1397,13 @@ function MikCEH.SetupNampowerEvents() SetCVar("NP_EnableSpellEnergizeEvents", "1") end - -- Events that Nampower covers unconditionally (NOT CVar-gated) — safe to remove. - -- CVar-gated events (AUTO_ATTACK, SPELL_HEAL, SPELL_ENERGIZE) are NOT listed here; - -- their CHAT_MSG equivalents stay registered as fallback until runtime detection confirms - -- the CVar-gated Nampower events are actually firing. + -- All Nampower event equivalents now use runtime detection flags + -- (nampowerSpellDamageActive, nampowerAutoAttackActive, etc.) instead of + -- permanently unregistering CHAT_MSG events. This ensures fallback to CHAT_MSG + -- parsing if a Nampower event doesn't fire for certain targets (e.g. NPCs). + -- Only CHAT_MSG_SPELL_AURA_GONE_SELF is safe to remove (covered by BUFF/DEBUFF_REMOVED_SELF). local nampowerCoveredEvents = { - -- Outgoing spell damage (covered by SPELL_DAMAGE_EVENT_SELF — always active) - ["CHAT_MSG_SPELL_SELF_DAMAGE"] = true, - ["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] = true, - -- Incoming spell damage shields (covered by SPELL_DAMAGE_EVENT_OTHER — always active) - ["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] = true, - -- Periodic damage (covered by SPELL_DAMAGE_EVENT_SELF with DoT flag — always active) - ["CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"] = true, - -- Aura notifications (covered by BUFF/DEBUFF_ADDED/REMOVED_SELF — always active) ["CHAT_MSG_SPELL_AURA_GONE_SELF"] = true, - -- Pet spell damage (covered by SPELL_DAMAGE_EVENT_SELF with pet GUID — always active) - ["CHAT_MSG_SPELL_PET_DAMAGE"] = true, } -- Events to keep despite Nampower — these have partial or no Nampower equivalent. @@ -1532,7 +1538,7 @@ function MikCEH.ParseForIncomingHits(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "COMBATHITOTHEROTHER", {"%n", "%s", "%a"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_HIT, MikCEH.HITTYPE_NORMAL, MikCEH.DAMAGETYPE_PHYSICAL, capturedData.Amount, nil, capturedData.Name); -- Look for any partial actions and populate them into the event data. @@ -1549,7 +1555,7 @@ function MikCEH.ParseForIncomingHits(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "COMBATHITCRITOTHEROTHER", {"%n", "%s", "%a"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_HIT, MikCEH.HITTYPE_CRIT, MikCEH.DAMAGETYPE_PHYSICAL, capturedData.Amount, nil, capturedData.Name); -- Look for any partial actions and populate them into the event data. @@ -1659,7 +1665,7 @@ function MikCEH.ParseForIncomingMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "MISSEDOTHEROTHER", {"%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_MISS, nil, nil, nil, nil, capturedData.Name); -- Send the event. @@ -1673,7 +1679,7 @@ function MikCEH.ParseForIncomingMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "VSDODGEOTHEROTHER", {"%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_DODGE, nil, nil, nil, nil, capturedData.Name); -- Send the event. @@ -1687,7 +1693,7 @@ function MikCEH.ParseForIncomingMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "VSPARRYOTHEROTHER", {"%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_PARRY, nil, nil, nil, nil, capturedData.Name); -- Send the event. @@ -1701,7 +1707,7 @@ function MikCEH.ParseForIncomingMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "VSBLOCKOTHEROTHER", {"%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_BLOCK, nil, nil, nil, nil, capturedData.Name); -- Send the event. @@ -1715,7 +1721,7 @@ function MikCEH.ParseForIncomingMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "VSABSORBOTHEROTHER", {"%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_ABSORB, nil, nil, nil, nil, capturedData.Name); -- Send the event. @@ -1729,7 +1735,7 @@ function MikCEH.ParseForIncomingMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "VSIMMUNEOTHEROTHER", {"%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_IMMUNE, nil, nil, nil, nil, capturedData.Name); -- Send the event. @@ -1942,7 +1948,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLLOGOTHEROTHER", {"%n", "%s", "%c", "%a"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_HIT, MikCEH.HITTYPE_NORMAL, MikCEH.DAMAGETYPE_PHYSICAL, capturedData.Amount, capturedData.SpellName, capturedData.Name); -- Look for any partial actions and populate them into the event data. @@ -1960,7 +1966,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLLOGCRITOTHEROTHER", {"%n", "%s", "%a"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_HIT, MikCEH.HITTYPE_CRIT, MikCEH.DAMAGETYPE_PHYSICAL, capturedData.Amount, capturedData.SpellName, capturedData.Name); -- Look for any partial actions and populate them into the event data. @@ -1978,7 +1984,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLLOGSCHOOLOTHEROTHER", {"%n", "%s", "%c", "%a", "%t"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_HIT, MikCEH.HITTYPE_NORMAL, capturedData.DamageType, capturedData.Amount, capturedData.SpellName, capturedData.Name); -- Look for any partial actions and populate them into the event data. @@ -1996,7 +2002,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLLOGCRITSCHOOLOTHEROTHER", {"%n", "%s", "%c", "%a", "%t"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_HIT, MikCEH.HITTYPE_CRIT, capturedData.DamageType, capturedData.Amount, capturedData.SpellName, capturedData.Name); -- Look for any partial actions and populate them into the event data. @@ -2014,7 +2020,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLMISSOTHEROTHER", {"%n", "%s", "%c"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_MISS, nil, nil, nil, capturedData.SpellName, capturedData.Name); -- Send the event. @@ -2029,7 +2035,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLDODGEDOTHEROTHER", {"%c", "%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_DODGE, nil, nil, nil, capturedData.SpellName, capturedData.Name); -- Send the event. @@ -2044,7 +2050,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLPARRIEDOTHEROTHER", {"%c", "%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_PARRY, nil, nil, nil, capturedData.SpellName, capturedData.Name); -- Send the event. @@ -2059,7 +2065,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLBLOCKEDOTHEROTHER", {"%c", "%s", "%n"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_BLOCK, nil, nil, nil, capturedData.SpellName, capturedData.Name); -- Send the event. @@ -2074,7 +2080,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLRESISTOTHEROTHER", {"%n", "%s", "%c"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_RESIST, nil, nil, nil, capturedData.SpellName, capturedData.Name); -- Send the event. @@ -2089,7 +2095,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLLOGABSORBOTHEROTHER", {"%n", "%s", "%c"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_ABSORB, nil, nil, nil, capturedData.SpellName, capturedData.Name); -- Send the event. @@ -2104,7 +2110,7 @@ function MikCEH.ParseForIncomingSpellHitsAndMisses(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "SPELLIMMUNEOTHEROTHER", {"%n", "%s", "%c"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetDamageEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.ACTIONTYPE_IMMUNE, nil, nil, nil, capturedData.SpellName, capturedData.Name); -- Send the event. @@ -2347,14 +2353,14 @@ function MikCEH.ParseForIncomingSpellHeals(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "HEALEDCRITOTHEROTHER", {"%n", "%s", "%c", "%a"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetHealEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.HEALTYPE_CRIT, capturedData.Amount, capturedData.SpellName, capturedData.Name); -- Get overheal info. - eventData.Name = UnitName("pet") + eventData.Name = cachedPetName MikCEH.PopulateOverhealData(eventData); -- athenne add eventData.Name = capturedData.Name - + -- Send the event. MikCEH.SendEvent(eventData); @@ -2366,14 +2372,14 @@ function MikCEH.ParseForIncomingSpellHeals(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "HEALEDOTHEROTHER", {"%n", "%s", "%c", "%a"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetHealEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.HEALTYPE_NORMAL, capturedData.Amount, capturedData.SpellName, capturedData.Name); -- Get overheal info. - eventData.Name = UnitName("pet") + eventData.Name = cachedPetName MikCEH.PopulateOverhealData(eventData); -- athenne add eventData.Name = capturedData.Name - + -- Send the event. MikCEH.SendEvent(eventData); @@ -2386,11 +2392,11 @@ function MikCEH.ParseForIncomingSpellHeals(combatMessage) local capturedData = MikCEH.GetCapturedData(combatMessage, "PERIODICAURAHEALOTHEROTHER", {"%c", "%a", "%n", "%s"}); -- If a match was found. - if (capturedData ~= nil and UnitName("pet") and string_find(combatMessage, UnitName("pet"))) then + if (capturedData ~= nil and cachedPetName and string_find(combatMessage, cachedPetName)) then local eventData = MikCEH.GetHealEventData(MikCEH.DIRECTIONTYPE_PET_INCOMING, MikCEH.HEALTYPE_OVER_TIME, capturedData.Amount, capturedData.SpellName, capturedData.Name); -- Get overheal info. - eventData.Name = UnitName("pet") + eventData.Name = cachedPetName if GetLocale() ~= "zhCN" then -- edge case for chinese client (unable to show overheal amount for hot casted on your pet by other) MikCEH.PopulateOverhealData(eventData); -- athenne add end @@ -4388,18 +4394,20 @@ end -- parameters passed. -- ********************************************************************************** function MikCEH.GetUnorderedCaptureDataTable(c1, c2, c3, c4, c5, c6, c7, c8, c9) - -- Erase old unorderd capture data. - MikCEH.EraseTable(unorderedCaptureData); + -- Assign directly by index instead of EraseTable + table_insert. + unorderedCaptureData[1] = c1; + unorderedCaptureData[2] = c2; + unorderedCaptureData[3] = c3; + unorderedCaptureData[4] = c4; + unorderedCaptureData[5] = c5; + unorderedCaptureData[6] = c6; + unorderedCaptureData[7] = c7; + unorderedCaptureData[8] = c8; + unorderedCaptureData[9] = c9; - if (c1 ~= nil) then table_insert(unorderedCaptureData, c1); end - if (c2 ~= nil) then table_insert(unorderedCaptureData, c2); end - if (c3 ~= nil) then table_insert(unorderedCaptureData, c3); end - if (c4 ~= nil) then table_insert(unorderedCaptureData, c4); end - if (c5 ~= nil) then table_insert(unorderedCaptureData, c5); end - if (c6 ~= nil) then table_insert(unorderedCaptureData, c6); end - if (c7 ~= nil) then table_insert(unorderedCaptureData, c7); end - if (c8 ~= nil) then table_insert(unorderedCaptureData, c8); end - if (c9 ~= nil) then table_insert(unorderedCaptureData, c9); end + -- Clear any leftover slots beyond 9. + local i = 10; + while unorderedCaptureData[i] do unorderedCaptureData[i] = nil; i = i + 1; end -- Return the populated unordered capture data table. return unorderedCaptureData; diff --git a/MikScrollingBattleText/MikScrollingBattleText.lua b/MikScrollingBattleText/MikScrollingBattleText.lua index 06765b6..676e574 100644 --- a/MikScrollingBattleText/MikScrollingBattleText.lua +++ b/MikScrollingBattleText/MikScrollingBattleText.lua @@ -11,10 +11,13 @@ -- Upvalue caches for frequently called functions. local string_find, string_gsub = string.find, string.gsub local table_insert, table_getn, table_remove = table.insert, table.getn, table.remove +local table_setn = table.setn +local math_ceil, math_floor, math_random = math.ceil, math.floor, math.random local GetTime = GetTime local getglobal = getglobal local strlower = strlower local tonumber = tonumber +local UnitClass = UnitClass -- Display types for incoming, outgoing, and notification events. MikSBT.DISPLAYTYPE_INCOMING = 1; @@ -194,6 +197,105 @@ local ANIMATION_STYLE_RIGHT_PARABOLA = 3; local MAX_COMBO_POINTS = 5; +-- Pre-built event type string lookup tables (eliminates string concatenation in CombatEventsHandler). +local DIRECTION_SCROLLAREA_KEY = { + [MikCEH.DIRECTIONTYPE_PLAYER_INCOMING] = "Incoming", + [MikCEH.DIRECTIONTYPE_PLAYER_OUTGOING] = "Outgoing", + [MikCEH.DIRECTIONTYPE_PET_OUTGOING] = "Outgoing", + [MikCEH.DIRECTIONTYPE_PET_INCOMING] = "Incoming", +}; + +local DIRECTION_PREFIX = { + [MikCEH.DIRECTIONTYPE_PLAYER_INCOMING] = "MSBT_EVENTTYPE_INCOMING_", + [MikCEH.DIRECTIONTYPE_PLAYER_OUTGOING] = "MSBT_EVENTTYPE_OUTGOING_", + [MikCEH.DIRECTIONTYPE_PET_OUTGOING] = "MSBT_EVENTTYPE_OUTGOING_PET_", + [MikCEH.DIRECTIONTYPE_PET_INCOMING] = "MSBT_EVENTTYPE_INCOMING_PET_", +}; + +-- Action type → suffix string for damage events. +local ACTION_SUFFIX = { + [MikCEH.ACTIONTYPE_MISS] = "MISS", + [MikCEH.ACTIONTYPE_DODGE] = "DODGE", + [MikCEH.ACTIONTYPE_PARRY] = "PARRY", + [MikCEH.ACTIONTYPE_BLOCK] = "BLOCK", + [MikCEH.ACTIONTYPE_RESIST] = "RESIST", + [MikCEH.ACTIONTYPE_ABSORB] = "ABSORB", + [MikCEH.ACTIONTYPE_IMMUNE] = "IMMUNE", + [MikCEH.ACTIONTYPE_EVADE] = "EVADE", + [MikCEH.ACTIONTYPE_REFLECT] = "REFLECT", +}; + +-- Environmental action type → localized effect name. +local ENVIRONMENTAL_NAMES = { + [MikCEH.ACTIONTYPE_DROWNING] = MikSBT.MSG_ENVIRONMENTAL_DROWNING, + [MikCEH.ACTIONTYPE_FALLING] = MikSBT.MSG_ENVIRONMENTAL_FALLING, + [MikCEH.ACTIONTYPE_FATIGUE] = MikSBT.MSG_ENVIRONMENTAL_FATIGUE, + [MikCEH.ACTIONTYPE_FIRE] = MikSBT.MSG_ENVIRONMENTAL_FIRE, + [MikCEH.ACTIONTYPE_LAVA] = MikSBT.MSG_ENVIRONMENTAL_LAVA, + [MikCEH.ACTIONTYPE_SLIME] = MikSBT.MSG_ENVIRONMENTAL_SLIME, +}; + +-- Class name → color prefix string for unit name coloring. +local CLASS_COLORS = { + PALADIN = "|cffF58CBA|h", + DRUID = "|cffFF7D0A|h", + HUNTER = "|cffABD473|h", + MAGE = "|cff69CCF0|h", + PRIEST = "|cffFFFFFF|h", + ROGUE = "|cffFFF569|h", + SHAMAN = "|cff0070DE|h", + WARLOCK = "|cff9482C9|h", + WARRIOR = "|cffC79C6E|h", +}; + +-- Notification type → suffix string. +local NOTIFICATION_SUFFIX = { + [MikCEH.NOTIFICATIONTYPE_DEBUFF] = "DEBUFF", + [MikCEH.NOTIFICATIONTYPE_BUFF] = "BUFF", + [MikCEH.NOTIFICATIONTYPE_ITEM_BUFF] = "ITEM_BUFF", + [MikCEH.NOTIFICATIONTYPE_BUFF_FADE] = "BUFF_FADE", + [MikCEH.NOTIFICATIONTYPE_COMBAT_ENTER] = "COMBAT_ENTER", + [MikCEH.NOTIFICATIONTYPE_COMBAT_LEAVE] = "COMBAT_LEAVE", + [MikCEH.NOTIFICATIONTYPE_POWER_GAIN] = "POWER_GAIN", + [MikCEH.NOTIFICATIONTYPE_POWER_LOSS] = "POWER_LOSS", + [MikCEH.NOTIFICATIONTYPE_CP_GAIN] = "CP_GAIN", + [MikCEH.NOTIFICATIONTYPE_HONOR_GAIN] = "HONOR_GAIN", + [MikCEH.NOTIFICATIONTYPE_REP_GAIN] = "REP_GAIN", + [MikCEH.NOTIFICATIONTYPE_REP_LOSS] = "REP_LOSS", + [MikCEH.NOTIFICATIONTYPE_SKILL_GAIN] = "SKILL_GAIN", + [MikCEH.NOTIFICATIONTYPE_EXPERIENCE_GAIN] = "EXPERIENCE_GAIN", + [MikCEH.NOTIFICATIONTYPE_PC_KILLING_BLOW] = "PC_KILLING_BLOW", + [MikCEH.NOTIFICATIONTYPE_NPC_KILLING_BLOW] = "NPC_KILLING_BLOW", +}; + +-- Pre-build all possible event type strings to avoid runtime concatenation. +-- dmgEventStr[dirType][suffix] for non-spell damage, dmgEventStrSpell[dirType][suffix] for spell damage. +local dmgEventStr = {}; +local dmgEventStrSpell = {}; +local healEventStr = {}; +local notifEventStr = {}; + +do + local suffixes = {"DAMAGE", "DOT", "MISS", "DODGE", "PARRY", "BLOCK", "RESIST", "ABSORB", "IMMUNE", "EVADE", "REFLECT", "ENVIRONMENTAL"}; + for dirType, prefix in pairs(DIRECTION_PREFIX) do + dmgEventStr[dirType] = {}; + dmgEventStrSpell[dirType] = {}; + for _, suffix in ipairs(suffixes) do + dmgEventStr[dirType][suffix] = prefix .. suffix; + dmgEventStrSpell[dirType][suffix] = prefix .. "SPELL_" .. suffix; + end + healEventStr[dirType] = {}; + healEventStr[dirType]["HEAL"] = prefix .. "HEAL"; + healEventStr[dirType]["HOT"] = prefix .. "HOT"; + end + + for notifType, suffix in pairs(NOTIFICATION_SUFFIX) do + notifEventStr[notifType] = "MSBT_EVENTTYPE_NOTIFICATION_" .. suffix; + end + notifEventStr["CP_FULL"] = "MSBT_EVENTTYPE_NOTIFICATION_CP_FULL"; +end + + ------------------------------------------------------------------------------------- -- Private variables. ------------------------------------------------------------------------------------- @@ -344,8 +446,9 @@ function MikSBT.OnUpdate() -- Clear the merged animation events array. local numMergedEvents = table_getn(mergeData.MergedEvents); for i = 1, numMergedEvents do - table_remove(mergeData.MergedEvents, 1); + mergeData.MergedEvents[i] = nil; end + table_setn(mergeData.MergedEvents, 0); -- Reset the last merged time. @@ -506,130 +609,62 @@ function MikSBT.CombatEventsHandler(combatEvent) -- Get a recycled table from the events recycler object. local animationEvent = eventsRecycler:AcquireTable(); - -- Initalize the event type string to the common prefix. - local eventTypeString = "MSBT_EVENTTYPE_"; - - -- Append the appropriate direction type to the event type string. - if (combatEvent.DirectionType == MikCEH.DIRECTIONTYPE_PLAYER_INCOMING) then - animationEvent.ScrollArea = scrollAreas.Incoming; - eventTypeString = eventTypeString .. "INCOMING_"; - elseif (combatEvent.DirectionType == MikCEH.DIRECTIONTYPE_PLAYER_OUTGOING) then - animationEvent.ScrollArea = scrollAreas.Outgoing; - eventTypeString = eventTypeString .. "OUTGOING_"; - elseif (combatEvent.DirectionType == MikCEH.DIRECTIONTYPE_PET_OUTGOING) then - animationEvent.ScrollArea = scrollAreas.Outgoing; - eventTypeString = eventTypeString .. "OUTGOING_PET_"; - elseif (combatEvent.DirectionType == MikCEH.DIRECTIONTYPE_PET_INCOMING) then - animationEvent.ScrollArea = scrollAreas.Incoming; - eventTypeString = eventTypeString .. "INCOMING_PET_"; + -- Look up the scroll area and event type string via pre-built tables (no string concatenation). + local dirType = combatEvent.DirectionType; + local scrollAreaKey = DIRECTION_SCROLLAREA_KEY[dirType]; + if (scrollAreaKey) then + animationEvent.ScrollArea = scrollAreas[scrollAreaKey]; end + local eventTypeString; + -- Check if it's a damage event. if (combatEvent.EventType == MikCEH.EVENTTYPE_DAMAGE) then - -- Check if there is an associated spell/ability name. - if (combatEvent.EffectName ~= nil) then - eventTypeString = eventTypeString .. "SPELL_"; - end + local actionType = combatEvent.ActionType; - -- Append the appropriate action type to the event type string. - if (combatEvent.ActionType == MikCEH.ACTIONTYPE_HIT) then - if (combatEvent.HitType == MikCEH.HITTYPE_OVER_TIME) then - eventTypeString = eventTypeString .. "DOT"; + -- Check for environmental damage (sets EffectName as side effect). + local envName = ENVIRONMENTAL_NAMES[actionType]; + if (envName) then + combatEvent.EffectName = envName; + eventTypeString = dmgEventStr[dirType] and dmgEventStr[dirType]["ENVIRONMENTAL"]; + else + -- Determine the action suffix. + local suffix; + if (actionType == MikCEH.ACTIONTYPE_HIT) then + suffix = (combatEvent.HitType == MikCEH.HITTYPE_OVER_TIME) and "DOT" or "DAMAGE"; else - eventTypeString = eventTypeString .. "DAMAGE"; + suffix = ACTION_SUFFIX[actionType]; + end + + -- Use spell or non-spell variant based on whether there is an effect name. + if (suffix) then + if (combatEvent.EffectName ~= nil) then + eventTypeString = dmgEventStrSpell[dirType] and dmgEventStrSpell[dirType][suffix]; + else + eventTypeString = dmgEventStr[dirType] and dmgEventStr[dirType][suffix]; + end end - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_MISS) then - eventTypeString = eventTypeString .. "MISS"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_DODGE) then - eventTypeString = eventTypeString .. "DODGE"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_PARRY) then - eventTypeString = eventTypeString .. "PARRY"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_BLOCK) then - eventTypeString = eventTypeString .. "BLOCK"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_RESIST) then - eventTypeString = eventTypeString .. "RESIST"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_ABSORB) then - eventTypeString = eventTypeString .. "ABSORB"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_IMMUNE) then - eventTypeString = eventTypeString .. "IMMUNE"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_EVADE) then - eventTypeString = eventTypeString .. "EVADE"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_REFLECT) then - eventTypeString = eventTypeString .. "REFLECT"; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_DROWNING) then - eventTypeString = eventTypeString .. "ENVIRONMENTAL" - combatEvent.EffectName = MikSBT.MSG_ENVIRONMENTAL_DROWNING; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_FALLING) then - eventTypeString = eventTypeString .. "ENVIRONMENTAL" - combatEvent.EffectName = MikSBT.MSG_ENVIRONMENTAL_FALLING; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_FATIGUE) then - eventTypeString = eventTypeString .. "ENVIRONMENTAL" - combatEvent.EffectName = MikSBT.MSG_ENVIRONMENTAL_FATIGUE; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_FIRE) then - eventTypeString = eventTypeString .. "ENVIRONMENTAL" - combatEvent.EffectName = MikSBT.MSG_ENVIRONMENTAL_FIRE; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_LAVA) then - eventTypeString = eventTypeString .. "ENVIRONMENTAL" - combatEvent.EffectName = MikSBT.MSG_ENVIRONMENTAL_LAVA; - elseif (combatEvent.ActionType == MikCEH.ACTIONTYPE_SLIME) then - eventTypeString = eventTypeString .. "ENVIRONMENTAL" - combatEvent.EffectName = MikSBT.MSG_ENVIRONMENTAL_SLIME; end -- Heal event. elseif (combatEvent.EventType == MikCEH.EVENTTYPE_HEAL) then - if (combatEvent.HealType == MikCEH.HEALTYPE_NORMAL or combatEvent.HealType == MikCEH.HEALTYPE_CRIT) then - eventTypeString = eventTypeString .. "HEAL"; - elseif (combatEvent.HealType == MikCEH.HEALTYPE_OVER_TIME) then - eventTypeString = eventTypeString .. "HOT"; - end - + local suffix = (combatEvent.HealType == MikCEH.HEALTYPE_OVER_TIME) and "HOT" or "HEAL"; + eventTypeString = healEventStr[dirType] and healEventStr[dirType][suffix]; -- Notification event. elseif (combatEvent.EventType == MikCEH.EVENTTYPE_NOTIFICATION) then animationEvent.ScrollArea = scrollAreas.Notification; - eventTypeString = eventTypeString .. "NOTIFICATION_"; + local notifType = combatEvent.NotificationType; - -- Append the appropriate notification type to the event type string. - if (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_DEBUFF) then - eventTypeString = eventTypeString .. "DEBUFF"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_BUFF) then - eventTypeString = eventTypeString .. "BUFF"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_ITEM_BUFF) then - eventTypeString = eventTypeString .. "ITEM_BUFF"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_BUFF_FADE) then - eventTypeString = eventTypeString .. "BUFF_FADE"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_COMBAT_ENTER) then - eventTypeString = eventTypeString .. "COMBAT_ENTER"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_COMBAT_LEAVE) then - eventTypeString = eventTypeString .. "COMBAT_LEAVE"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_POWER_GAIN) then - eventTypeString = eventTypeString .. "POWER_GAIN"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_POWER_LOSS) then - eventTypeString = eventTypeString .. "POWER_LOSS"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_CP_GAIN) then - -- Check if we are at max combo points. - if (combatEvent.Amount == MAX_COMBO_POINTS) then - eventTypeString = eventTypeString .. "CP_FULL"; - else - eventTypeString = eventTypeString .. "CP_GAIN"; + -- Special case: combo points at max. + if (notifType == MikCEH.NOTIFICATIONTYPE_CP_GAIN and combatEvent.Amount == MAX_COMBO_POINTS) then + eventTypeString = notifEventStr["CP_FULL"]; + else + eventTypeString = notifEventStr[notifType]; + -- Fallback for unknown notification types. + if (not eventTypeString and notifType ~= nil) then + eventTypeString = "MSBT_EVENTTYPE_NOTIFICATION_" .. notifType; end - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_HONOR_GAIN) then - eventTypeString = eventTypeString .. "HONOR_GAIN"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_REP_GAIN) then - eventTypeString = eventTypeString .. "REP_GAIN"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_REP_LOSS) then - eventTypeString = eventTypeString .. "REP_LOSS"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_SKILL_GAIN) then - eventTypeString = eventTypeString .. "SKILL_GAIN"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_EXPERIENCE_GAIN) then - eventTypeString = eventTypeString .. "EXPERIENCE_GAIN"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_PC_KILLING_BLOW) then - eventTypeString = eventTypeString .. "PC_KILLING_BLOW"; - elseif (combatEvent.NotificationType == MikCEH.NOTIFICATIONTYPE_NPC_KILLING_BLOW) then - eventTypeString = eventTypeString .. "NPC_KILLING_BLOW"; - elseif (combatEvent.NotificationType ~= nil) then - eventTypeString = eventTypeString .. combatEvent.NotificationType; end end @@ -894,14 +929,14 @@ function MikSBT.MergeEvents(mergeData, numEvents) -- Remove the processed animation events from unmerged events queue. for x = 1, numEvents do -- Check if the event was merged into a different animation event. - if (mergeData.UnmergedEvents[1].EventMerged) then + if (mergeData.UnmergedEvents[x] and mergeData.UnmergedEvents[x].EventMerged) then -- Reclaim the animation event table to the events recycler. - eventsRecycler:ReclaimTable(mergeData.UnmergedEvents[1]); + eventsRecycler:ReclaimTable(mergeData.UnmergedEvents[x]); end - -- Remove the event from the unmerged events array. - table_remove(mergeData.UnmergedEvents, 1); + mergeData.UnmergedEvents[x] = nil; end + table_setn(mergeData.UnmergedEvents, 0); end @@ -1695,26 +1730,11 @@ function MikSBT.AddAnimation(animationEvent) local unitID = animationEvent._unitID local uName = animationEvent._unitName if unitID then - local _, Class = UnitClass(unitID) - if Class and Class == "PALADIN" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cffF58CBA|h"..uName.."|h|r") - elseif Class and Class == "DRUID" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cffFF7D0A|h"..uName.."|h|r") - elseif Class and Class == "HUNTER" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cffABD473|h"..uName.."|h|r") - elseif Class and Class == "MAGE" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cff69CCF0|h"..uName.."|h|r") - elseif Class and Class == "PRIEST" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cffFFFFFF|h"..uName.."|h|r") - elseif Class and Class == "ROGUE" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cffFFF569|h"..uName.."|h|r") - elseif Class and Class == "SHAMAN" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cff0070DE|h"..uName.."|h|r") - elseif Class and Class == "WARLOCK" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cff9482C9|h"..uName.."|h|r") - elseif Class and Class == "WARRIOR" then - animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, "|cffC79C6E|h"..uName.."|h|r") - end + local _, class = UnitClass(unitID) + local colorPrefix = class and CLASS_COLORS[class] + if colorPrefix then + animationEvent.Text = string_gsub(animationEvent.Text, animationEvent.Name, colorPrefix .. uName .. "|h|r") + end end -- Get the next available animation display info object for the scroll area. @@ -2229,7 +2249,7 @@ function MikSBT.GetAnimationStartingPosition(animationEvent) -- Check if it's a sticky or a crit and sticky crits are enabled. if (animationEvent.IsSticky or (animationEvent.IsCrit and MikSBT.CurrentProfile.UseStickyCrits)) then -- Set the sticky to the center. - startPositionY = ceil(animationEvent.ScrollArea.DisplaySettings.ScrollHeight / 2); + startPositionY = math_ceil(animationEvent.ScrollArea.DisplaySettings.ScrollHeight / 2); end end @@ -2300,8 +2320,9 @@ function MikSBT.RepositionAnimDisplayInfo(scrollArea) -- Clear the temp non stickies table. for x = 1, numNonStickies do - table_remove(activeNonStickies, 1); + activeNonStickies[x] = nil; end + table_setn(activeNonStickies, 0); end @@ -2339,7 +2360,7 @@ function MikSBT.RepositionStickyAnimDisplayInfo(scrollArea) -- Check if there is more than 1 active sticky animation. if (numStickies > 1) then -- Get the middle active sticky. - local middleSticky = floor((numStickies + 1) / 2); + local middleSticky = math_floor((numStickies + 1) / 2); -- Set the middle sticky to the center of the scroll area. activeStickies[middleSticky].PositionY = scrollArea.DisplaySettings.ScrollHeight / 2; @@ -2361,7 +2382,7 @@ function MikSBT.RepositionStickyAnimDisplayInfo(scrollArea) -- Check if there is more than 1 active sticky animation. if (numStickies > 1) then -- Get the middle active sticky. - local middleSticky = ceil((numStickies + 1) / 2); + local middleSticky = math_ceil((numStickies + 1) / 2); -- Set the middle sticky to the center of the scroll area. activeStickies[middleSticky].PositionY = scrollArea.DisplaySettings.ScrollHeight / 2; @@ -2382,8 +2403,9 @@ function MikSBT.RepositionStickyAnimDisplayInfo(scrollArea) -- Clear the temp stickies table. for x = 1, numStickies do - table_remove(activeStickies, 1); + activeStickies[x] = nil; end + table_setn(activeStickies, 0); end @@ -2430,8 +2452,8 @@ function MikSBT.DoAnimation(animDisplayInfo, scrollArea) animDisplayInfo.originalPositionY = animDisplayInfo.PositionY end if (elapsedTime - animDisplayInfo.timeLastJiggled > 0.05) then - animDisplayInfo.DecalageX = math.random(-1, 1); - animDisplayInfo.DecalageY = math.random(-1, 1); + animDisplayInfo.DecalageX = math_random(-1, 1); + animDisplayInfo.DecalageY = math_random(-1, 1); animDisplayInfo.PositionX = animDisplayInfo.originalPositionX + animDisplayInfo.DecalageX; animDisplayInfo.PositionY = animDisplayInfo.originalPositionY + animDisplayInfo.DecalageY; animDisplayInfo.timeLastJiggled = elapsedTime; @@ -2582,9 +2604,9 @@ function MikSBT.ScrollLeftParabolaUp(animDisplayInfo, scrollArea) -- Calculate the new x position based on equation of a parabola. -- Equation of a parabola at vertex 0,0: x = y^2 / 4a - local parabolaMaxX = ceil((animationMidPoint * animationMidPoint) / (4 * animationMidPoint)); + local parabolaMaxX = math_ceil((animationMidPoint * animationMidPoint) / (4 * animationMidPoint)); local parabolaY = animDisplayInfo.PositionY - animationMidPoint; - local newX = parabolaMaxX - ceil((parabolaY * parabolaY) / (4 * animationMidPoint)); + local newX = parabolaMaxX - math_ceil((parabolaY * parabolaY) / (4 * animationMidPoint)); -- Set the new x position. animDisplayInfo.PositionX = newX * -1; @@ -2607,9 +2629,9 @@ function MikSBT.ScrollLeftParabolaDown(animDisplayInfo, scrollArea) -- Calculate the new x position based on equation of a parabola. -- Equation of a parabola at vertex 0,0: x = y^2 / 4a - local parabolaMaxX = ceil((animationMidPoint * animationMidPoint) / (4 * animationMidPoint)); + local parabolaMaxX = math_ceil((animationMidPoint * animationMidPoint) / (4 * animationMidPoint)); local parabolaY = animDisplayInfo.PositionY - animationMidPoint; - local newX = parabolaMaxX - ceil((parabolaY * parabolaY) / (4 * animationMidPoint)); + local newX = parabolaMaxX - math_ceil((parabolaY * parabolaY) / (4 * animationMidPoint)); -- Set the new x position. animDisplayInfo.PositionX = newX * -1; @@ -2632,9 +2654,9 @@ function MikSBT.ScrollRightParabolaUp(animDisplayInfo, scrollArea) -- Calculate the new x position based on equation of a parabola. -- Equation of a parabola at vertex 0,0: x = y^2 / 4a - local parabolaMaxX = ceil((animationMidPoint * animationMidPoint) / (4 * animationMidPoint)); + local parabolaMaxX = math_ceil((animationMidPoint * animationMidPoint) / (4 * animationMidPoint)); local parabolaY = animDisplayInfo.PositionY - animationMidPoint; - local newX = parabolaMaxX - ceil((parabolaY * parabolaY) / (4 * animationMidPoint)); + local newX = parabolaMaxX - math_ceil((parabolaY * parabolaY) / (4 * animationMidPoint)); -- Set the new x position. animDisplayInfo.PositionX = newX; @@ -2657,9 +2679,9 @@ function MikSBT.ScrollRightParabolaDown(animDisplayInfo, scrollArea) -- Calculate the new x position based on equation of a parabola. -- Equation of a parabola at vertex 0,0: x = y^2 / 4a - local parabolaMaxX = ceil((animationMidPoint * animationMidPoint) / (4 * animationMidPoint)); + local parabolaMaxX = math_ceil((animationMidPoint * animationMidPoint) / (4 * animationMidPoint)); local parabolaY = animDisplayInfo.PositionY - animationMidPoint; - local newX = parabolaMaxX - ceil((parabolaY * parabolaY) / (4 * animationMidPoint)); + local newX = parabolaMaxX - math_ceil((parabolaY * parabolaY) / (4 * animationMidPoint)); -- Set the new x position. animDisplayInfo.PositionX = newX; diff --git a/MikScrollingBattleText/MikTableRecyclerObject.lua b/MikScrollingBattleText/MikTableRecyclerObject.lua index 03d308b..e8846a2 100644 --- a/MikScrollingBattleText/MikTableRecyclerObject.lua +++ b/MikScrollingBattleText/MikTableRecyclerObject.lua @@ -25,6 +25,7 @@ function MikTRO:NewRecyclerObject(maxEntries) -- Create a table to hold the cache entries and set its max permanent size. recyclerObject.PrimaryCache = {}; + recyclerObject.PrimaryCacheSize = 0; recyclerObject.MaxEntries = maxEntries; -- Create some variables to hold stats. @@ -62,10 +63,11 @@ end function MikTRO:AcquireTable() -- Check if there are any tables available in the primary cache and if so -- return one. - if (table.getn(self.PrimaryCache) > 0) then + if (self.PrimaryCacheSize > 0) then -- Increment the number of recycled tables. self.NumRecycled = self.NumRecycled + 1; + self.PrimaryCacheSize = self.PrimaryCacheSize - 1; return table.remove(self.PrimaryCache); -- Check if there are any tables available in the overflow cache and if so @@ -101,12 +103,13 @@ function MikTRO:ReclaimTable(t) self:EraseTable(t); -- Check if the primary cache is already full. - if (table.getn(self.PrimaryCache) >= self.MaxEntries) then + if (self.PrimaryCacheSize >= self.MaxEntries) then -- Insert the table into the overflow cache. table.insert(self.OverflowCache, t); else -- Insert the table into the primary cache. table.insert(self.PrimaryCache, t); + self.PrimaryCacheSize = self.PrimaryCacheSize + 1; end -- Increment the number of reclaimed tables. @@ -123,9 +126,6 @@ function MikTRO:EraseTable(t) return; end - -- Get the amount of memory used before the clear. - local currentMem = gcinfo(); - -- Loop through all the keys in the table and clear it. for key in pairs(t) do t[key] = nil; @@ -134,10 +134,7 @@ function MikTRO:EraseTable(t) -- Set the length of the table to 0. table.setn(t, 0); - -- Increment the amount of memory freed. - self.AmountMemFreed = self.AmountMemFreed + math.abs(gcinfo() - currentMem); - - -- Incremnt the number of tables erased. + -- Increment the number of tables erased. self.NumErased = self.NumErased + 1; end @@ -155,11 +152,11 @@ function MikTRO:PrintStats() "|cff00ff00New Tables: %d|r |cffffff00Recycled Tables: %d|r |cff00ffffCached Tables: %d|r |cffff0000Overflow Tables: %d|r |cff888888Erased Tables: %d|r |cffff00ffMemory Saved: %d KiB|r |cffff0088Tables Lost to GC: %d", self.NumNew, self.NumRecycled, - table.getn(self.PrimaryCache), + self.PrimaryCacheSize, overflowSize, self.NumErased, self.AmountMemFreed + ((32/1024) * self.NumRecycled), - self.NumReclaimed - self.NumRecycled - table.getn(self.PrimaryCache))); + self.NumReclaimed - self.NumRecycled - self.PrimaryCacheSize)); end @@ -167,8 +164,5 @@ end -- Checks if there are any tables in the overflow cache. -- ********************************************************************************** function MikTRO:TablesInOverflow() - -- Loop through all items in the overflow cache. - for i in pairs(self.OverflowCache) do - return true; - end + return next(self.OverflowCache) ~= nil; end \ No newline at end of file diff --git a/MikScrollingBattleTextOptions/MSBTOptions.lua b/MikScrollingBattleTextOptions/MSBTOptions.lua index 25c5a54..4abc398 100644 --- a/MikScrollingBattleTextOptions/MSBTOptions.lua +++ b/MikScrollingBattleTextOptions/MSBTOptions.lua @@ -3388,8 +3388,10 @@ function MikSBTOpt.SetupVariableTriggerControls(triggerKey, showSearch) end -- Loop through all of the trigger events for the trigger. - for _, triggerEvent in triggerData.TriggerSettings.TriggerEvents do - triggerFrame.SelectedTriggerEvents[triggerEvent] = true; + if (triggerData.TriggerSettings.TriggerEvents) then + for _, triggerEvent in triggerData.TriggerSettings.TriggerEvents do + triggerFrame.SelectedTriggerEvents[triggerEvent] = true; + end end -- Populate the appropriate trigger events. @@ -3533,7 +3535,7 @@ function MikSBTOpt.SaveTriggerConfig() -- Save the required stance. if UIDropDownMenu_GetSelectedValue(getglobal(TRIGGER_CONFIGURATION_FRAME_NAME .. "StanceDropdown")) ~= 7 then triggerData.TriggerSettings.Stance = UIDropDownMenu_GetSelectedValue(getglobal(TRIGGER_CONFIGURATION_FRAME_NAME .. "StanceDropdown")); - if not GetShapeshiftFormInfo(triggerData.TriggerSettings.Stance) then + if triggerData.TriggerSettings.Stance > GetNumShapeshiftForms() or not GetShapeshiftFormInfo(triggerData.TriggerSettings.Stance) then MikSBT.Print("No stance found for the selected requirement on this character, this trigger might never occur :o", 1, 1, 0); MikSBT.Print("Also it's dangerous to go alone! take this. o-[====>", 1, 1, 0); --remind me that this is a beta release end