4 Commits
Author SHA1 Message Date
Brues d4931b1ba7 defeats the purpose of the addon and confuses users 2026-07-20 15:37:53 -05:00
Brues 73fd6803ab Replace Babble-Spell library with Nampower GetSpellRecField
Drop the bundled Babble-Spell-2.2 localization library and resolve spell
names from their IDs via Nampower's GetSpellRecField(id, "name"). Adds a
shared MikSBT.SpellName(id, fallback) helper that returns the client's
localized name when Nampower is present and falls back to the English name
otherwise, so DEFAULT_CONFIG still builds without a Lua error when Nampower
is absent.

Also removes the now-redundant BS:GetSpellIcon fallback in the icon
resolver (the Nampower spellIconID path already covers it) and drops the
lib from the .toc.
2026-07-19 02:46:43 -05:00
Brues 496979f486 Add BigWigs packager config to bundle both addons in one zip
Add .pkgmeta (package-as MikScrollingBattleText, move-folders pulling both addon folders to top-level siblings) and a tag-triggered GitHub Actions workflow using BigWigsMods/packager that attaches the single zip to an auto-created GitHub release. Switch both TOCs' Version to the @project-version@ substitution token so the packager stamps the git tag version.
2026-06-23 13:26:13 -05:00
Brues a5e46a62b8 Change nampower school table to sequential index keys
nampowerSchoolToType now uses sequential keys (0=Physical, then implicit 1-6 for Holy/Fire/Nature/Frost/Shadow/Arcane) instead of the previous power-of-two bitmask keys (0,1,2,4,8,16,32).
2026-06-23 13:25:13 -05:00
7 changed files with 934 additions and 541 deletions
Binary file not shown.
File diff suppressed because it is too large Load Diff
+164 -70
View File
@@ -1,4 +1,4 @@
-------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text
-- Author: Mik
-- Maintainer: Athene
@@ -133,22 +133,33 @@ NO_ICON_CACHE = {}
-- Cache for spellId-based icon lookups (bypasses Babble-Spell and tooltip scanning).
local spellIdIconCache = {}
-- Damage type → color prefix lookup (lazily initialized after globals are available).
local damageTypeColors
local function GetDamageTypeColor(dt)
if not damageTypeColors then
damageTypeColors = {
[SPELL_SCHOOL1_CAP] = "\124cffF6F99E\124h",
[SPELL_SCHOOL2_CAP] = "\124cffFF4444\124h",
[SPELL_SCHOOL3_CAP] = "\124cff44FF44\124h",
[SPELL_SCHOOL4_CAP] = "\124cff4488FF\124h",
[SPELL_SCHOOL5_CAP] = "\124cff6600CC\124h",
[SPELL_SCHOOL6_CAP] = "\124cffCC66FF\124h",
["Inconnu"] = "\124cffCC66FF\124h",
}
end
return damageTypeColors[dt]
end
-- Damage type → {r, g, b} float lookup for SetTextColor (lazily initialized).
local damageTypeFontColors
local function GetDamageTypeFontColor(dt)
if not damageTypeFontColors then
local function CreateSpellColor(r, g, b)
local color = CreateColor(r, g, b)
color.colorStr = color:GenerateHexColorMarkup() .. "\124h"
return color
end
damageTypeFontColors = {
[SPELL_SCHOOL1_CAP] = CreateSpellColor(0.965, 0.976, 0.620), -- Holy
[SPELL_SCHOOL2_CAP] = CreateSpellColor(0.933, 0.490, 0.501), -- Fire
[SPELL_SCHOOL3_CAP] = CreateSpellColor(0.631, 0.858, 0.396), -- Nature
[SPELL_SCHOOL4_CAP] = CreateSpellColor(0.462, 0.792, 0.929), -- Frost
[SPELL_SCHOOL5_CAP] = CreateSpellColor(0.356, 0.290, 0.596), -- Shadow
[SPELL_SCHOOL6_CAP] = CreateSpellColor(0.956, 0.658, 0.894), -- Arcane
[SPELL_SCHOOL2_CAP] = { r=1.0, g=0.27, b=0.27 }, -- Fire (red)
[SPELL_SCHOOL3_CAP] = { r=0.27, g=1.0, b=0.27 }, -- Nature (green)
[SPELL_SCHOOL4_CAP] = { r=0.27, g=0.53, b=1.0 }, -- Frost (blue)
[SPELL_SCHOOL5_CAP] = { r=0.4, g=0.0, b=0.8 }, -- Shadow (deep purple)
[SPELL_SCHOOL6_CAP] = { r=0.8, g=0.4, b=1.0 }, -- Arcane (purple/pink)
}
end
return damageTypeFontColors[dt]
@@ -524,6 +535,13 @@ function MikSBT.Init()
-- Register the triggers with the combat event helper.
MikSBT.RegisterTriggers();
-- Enable Nampower CVars for enhanced combat events when available.
if MikCEH.hasNampower then
pcall(SetCVar, "NP_EnableAutoAttackEvents", "1")
pcall(SetCVar, "NP_EnableSpellHealEvents", "1")
pcall(SetCVar, "NP_EnableSpellEnergizeEvents", "1")
end
-- Disable or enable the mod depending on the saved setting.
MikSBT.SetOptionUserDisabled(MikSBT_Save.UserDisabled)
end
@@ -1126,9 +1144,9 @@ function MikSBT.FormatEventText(animationEvent)
outputString = string_gsub(outputString, "-%%a", "\124cffff0000\124h-\124h\124r%%a");
if animationEvent.DamageType then
local color = GetDamageTypeFontColor(animationEvent.DamageType)
local color = GetDamageTypeColor(animationEvent.DamageType)
if color then
outputString = string_gsub(outputString, "%%a", color.colorStr .. "%%a\124h\124r")
outputString = string_gsub(outputString, "%%a", color .. "%%a\124h\124r")
end
end
@@ -1322,7 +1340,7 @@ function MikSBT.UpdateProfiles()
if (profile.CreationVersion < 4.1) then
if profile.Triggers.MSBT_TRIGGER_WINDFURY then -- Fix Windfury Trigger
profile.Triggers.MSBT_TRIGGER_WINDFURY.TriggerSettings.SearchPatterns[1] = string.format(AURAADDEDSELFHELPFUL, string_gsub(C_Spell.GetSpellName(8512) or "", "-", "%%-")) -- Windfury Totem (ID verified vs Spell.dbc)
profile.Triggers.MSBT_TRIGGER_WINDFURY.TriggerSettings.SearchPatterns[1] = string.format(AURAADDEDSELFHELPFUL, string_gsub(MikSBT.SpellName(8512, "Windfury Totem"), "-", "%%-"))
end
if profile.Triggers.MSBT_TRIGGER_HAND_OF_JUSTICE then -- Delete Hand of Justice Trigger
@@ -1396,7 +1414,7 @@ function MikSBT.UpdateProfiles()
end
if (profile.CreationVersion < 4.6) then
-- Add missing incoming evade/reflect event settings (needed for combat log miss events).
-- Add missing incoming evade/reflect event settings (needed for Nampower events).
local incomingMissEvents = {
"MSBT_EVENTTYPE_INCOMING_EVADE",
"MSBT_EVENTTYPE_INCOMING_SPELL_EVADE",
@@ -1765,7 +1783,9 @@ function MikSBT.AddAnimation(animationEvent)
if animationEvent.DamageType and animationEvent.EventType then
local dtColor = GetDamageTypeFontColor(animationEvent.DamageType)
if dtColor then
animDisplayInfo.ColorR, animDisplayInfo.ColorG, animDisplayInfo.ColorB = dtColor:GetRGB()
animDisplayInfo.ColorR = dtColor.r
animDisplayInfo.ColorG = dtColor.g
animDisplayInfo.ColorB = dtColor.b
end
end
@@ -1831,36 +1851,54 @@ function MikSBT.AddAnimation(animationEvent)
local sid = animationEvent.SpellId
if spellIdIconCache[sid] then
texture = spellIdIconCache[sid]
elseif GetSpellInfo then
local ok, _, _, tex = pcall(GetSpellInfo, sid)
elseif MikCEH.hasSuperWoW and SpellInfo then
local ok, _, _, tex = pcall(SpellInfo, sid)
if ok and tex then texture = tex; spellIdIconCache[sid] = tex end
elseif MikCEH.hasNampower and GetSpellRecField and GetSpellIconTexture then
local ok, iconId = pcall(GetSpellRecField, sid, "spellIconID")
if ok and iconId then
local ok2, tex = pcall(GetSpellIconTexture, iconId)
if ok2 and tex then texture = tex; spellIdIconCache[sid] = tex end
end
end
end
if animationEvent.EffectName then
local name = string_gsub(animationEvent.EffectName, " %(%d+%)", "")
local lowerName = strlower(name)
-- DEFAULT_CHAT_FRAME:AddMessage(animationEvent.EffectName)
-- DEFAULT_CHAT_FRAME:AddMessage(name)
if ICON_CACHE[lowerName] then
texture = ICON_CACHE[lowerName]
elseif not texture and MikSBT.GetAuraIcon(name) then
texture = MikSBT.GetAuraIcon(name)
ICON_CACHE[lowerName] = texture
elseif not texture and GetSpellInfo then
local ok, sid = pcall(function(n) return select(10, GetSpellInfo(n)) end, name)
if ok and sid and sid ~= 0 then
local ok2, _, _, tex = pcall(GetSpellInfo, sid)
if ok2 and tex then texture = tex; ICON_CACHE[lowerName] = tex end
end
elseif not texture then
local itemIcon = MikSBT.FindItemIcon(lowerName)
if itemIcon then
texture = itemIcon
ICON_CACHE[lowerName] = itemIcon
if ICON_CACHE[strlower(name)] then
texture = ICON_CACHE[strlower(name)]
elseif not texture and MikSBT.FindBuff(name) then
local bufftype,index,_ = MikSBT.FindBuff(name)
local icon
if bufftype == "buff" then
icon = UnitBuff("player", index)
ICON_CACHE[strlower(name)] = icon
texture = icon
elseif bufftype == "debuff" then
icon = UnitDebuff("player", index)
ICON_CACHE[strlower(name)] = icon
texture = icon
else
NO_ICON_CACHE[lowerName] = 1
texture = nil
NO_ICON_CACHE[strlower(name)] = 1
end
elseif not texture and MikCEH.hasNampower and GetSpellIdForName then
local ok, sid = pcall(GetSpellIdForName, name)
if ok and sid and sid ~= 0 then
local ok2, iconId = pcall(GetSpellRecField, sid, "spellIconID")
if ok2 and iconId then
local ok3, tex = pcall(GetSpellIconTexture, iconId)
if ok3 and tex then texture = tex; ICON_CACHE[strlower(name)] = tex end
end
end
elseif not texture and MikSBT.FindItemIcon(name) then
texture = MikSBT.FindItemIcon(name)
ICON_CACHE[strlower(name)] = MikSBT.FindItemIcon(name)
elseif not texture then
texture = nil
NO_ICON_CACHE[strlower(name)] = 1
end
end
@@ -1919,50 +1957,106 @@ function ItemLinkToName(link)
end
function MikSBT.FindItemIcon(item)
if ( not item ) then return end
if ( not item ) then return; end
item = string.lower(item);
for slot = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED + 4 do
local itemLocation = ItemLocation:CreateFromEquipmentSlot(slot)
local itemName = C_Item.GetItemName(itemLocation)
if itemName and item == string.lower(itemName) then
return C_Item.GetItemIcon(itemLocation)
end
end
for i = 0, NUM_BAG_FRAMES do
for j = 1, GetContainerNumSlots(i) do
local itemName = C_Item.GetItemName(ItemLocation:CreateFromBagAndSlot(i,j))
if itemName and item == string.lower(itemName) then
return (GetContainerItemInfo(i,j))
local link;
for i = 1,23 do
link = GetInventoryItemLink("player",i);
if ( link ) then
if ( item == string.lower(ItemLinkToName(link)) )then
return i, nil, GetInventoryItemTexture('player', i), GetInventoryItemCount('player', i);
end
end
end
local count, bag, slot, texture;
for i = 0,NUM_BAG_FRAMES do
for j = 1,MAX_CONTAINER_ITEMS do
link = GetContainerItemLink(i,j);
if ( link ) then
if ( item == string.lower(ItemLinkToName(link))) then
bag, slot = i, j;
texture, count = GetContainerItemInfo(i,j);
end
end
end
end
return texture;
end
-- **********************************************************************************
-- Returns the icon for an active buff/debuff or temporary weapon enchant whose
-- name matches, or nil. Uses ClassicAPI (C_UnitAuras / C_Item) instead of the old
-- tooltip-scanning approach.
-- This function return the buff texture based on
-- it's name.
-- **********************************************************************************
function MikSBT.GetAuraIcon(name, unit)
unit = unit or "player";
-- Buffs and debuffs (helpful then harmful) -- AuraData carries the icon directly.
local aura = C_UnitAuras.GetAuraDataBySpellName(unit, name);
if ( aura and aura.icon ) then return aura.icon end
-- Temporary weapon enchant (oils, poisons, imbues) matching this name.
local hasMain, _, _, mainID, hasOff, _, _, offID = C_Item.GetWeaponEnchantInfo();
if ( hasMain and mainID ) then
local info = C_Item.GetEnchantInfo(mainID);
if ( info and info.name == name and info.spellID ) then
return C_Spell.GetSpellTexture(info.spellID);
end
function MikSBT.FindBuff( obuff, unit, item)
local buff=strlower(obuff);
local tooltip=MSBT_Tooltip;
local textleft1=getglobal(tooltip:GetName().."TextLeft1");
if ( not unit ) then
unit ='player';
end
if ( hasOff and offID ) then
local info = C_Item.GetEnchantInfo(offID);
if ( info and info.name == name and info.spellID ) then
return C_Spell.GetSpellTexture(info.spellID);
local my, me, mc, oy, oe, oc = GetWeaponEnchantInfo();
if ( my ) then
tooltip:SetOwner(UIParent, "ANCHOR_NONE");
tooltip:SetInventoryItem( unit, 16);
for i=1, 23 do
local text = getglobal("MSBT_TooltipTextLeft"..i):GetText();
if ( not text ) then
break;
elseif (text and strlower(text) == buff) then
tooltip:Hide();
return "main",me, mc;
end
end
tooltip:Hide();
elseif ( oy ) then
tooltip:SetOwner(UIParent, "ANCHOR_NONE");
tooltip:SetInventoryItem( unit, 17);
for i=1, 23 do
local text = getglobal("MSBT_TooltipTextLeft"..i):GetText();
if ( not text ) then
break;
elseif (text and strlower(text) == buff) then
tooltip:Hide();
return "off", oe, oc;
end
end
tooltip:Hide();
end
if ( item ) then return end
tooltip:SetOwner(UIParent, "ANCHOR_NONE");
tooltip:SetTrackingSpell();
local b = textleft1:GetText();
if ( b and strlower(b) == buff ) then
tooltip:Hide();
return "track",b;
end
local c=nil;
for i=1, 32 do
tooltip:SetOwner(UIParent, "ANCHOR_NONE");
tooltip:SetUnitBuff(unit, i);
b = textleft1:GetText();
tooltip:Hide();
if ( b and strlower(b) == buff ) then
return "buff", i, b;
elseif ( c==b ) then
break;
end
--c = b;
end
c=nil;
for i=1, 16 do
tooltip:SetOwner(UIParent, "ANCHOR_NONE");
tooltip:SetUnitDebuff(unit, i);
b = textleft1:GetText();
tooltip:Hide();
if ( b and strlower(b) == buff ) then
return "debuff", i, b;
elseif ( c==b) then
break;
end
--c = b;
end
tooltip:Hide();
end
-- **********************************************************************************
@@ -3,7 +3,6 @@
## Title: Mik's Scrolling Battle Text
## Notes: Scrolls battle information around the character model.
## Notes-ruRU: Прокрутка информации боя вокруг модели персонажа.
## Dependencies: !!!ClassicAPI
## OptionalDeps: SW_FixLogStrings
## SavedVariables: MikSBT_Save
@@ -11,6 +11,15 @@
</Scripts>
</Frame>
<!-- Tooltip -->
<GameTooltip name="MSBT_Tooltip" frameStrata="TOOLTIP" hidden="true" parent="UIParent" inherits="GameTooltipTemplate">
<Scripts>
<OnLoad>
this:SetOwner(WorldFrame, "ANCHOR_NONE");
</OnLoad>
</Scripts>
</GameTooltip>
<!-- Incoming Scroll Area -->
<Frame name="MSBTFrameIncoming" toplevel="true" enableMouse="false" parent="UIParent" frameStrata="HIGH" hidden="true">
<Size>
+22 -15
View File
@@ -20,9 +20,17 @@ MikSBT.COMMAND = "/msbt";
local L = AceLibrary("AceLocale-2.2"):new(MikSBT.MOD_NAME)
-- Resolves a spell's localized name from its ID via ClassicAPI (C_Spell), replacing
-- the old Babble-Spell localization library. Any rank's spell ID yields the same name.
local function SpellName(id) return C_Spell.GetSpellName(id) or "" end
-- Resolves a spell's localized name from its ID via Nampower's GetSpellRecField,
-- replacing the old Babble-Spell library. Falls back to the given English name when
-- Nampower is absent (vanilla has no built-in spellId->name lookup). Shared across
-- files via the MikSBT namespace; localization.lua loads first per the .toc.
function MikSBT.SpellName(id, fallback)
if GetSpellRecField then
local ok, n = pcall(GetSpellRecField, id, "name")
if ok and n and n ~= "" then return n end
end
return fallback
end
-------------------------------------------------------------------------------
-- English (Default)
@@ -129,7 +137,6 @@ MikSBT.AVAILABLE_FONTS = {
[30] = {Name="PT-Sans-Narrow-Regular", Path="Interface\\Addons\\MikScrollingBattleText\\Fonts\\PT-Sans-Narrow-Regular.ttf"},
[31] = {Name="Simhei", Path="Interface\\Addons\\MikScrollingBattleText\\Fonts\\simhei.ttf"},
[32] = {Name="Archangelsk", Path="Interface\\Addons\\MikScrollingBattleText\\Fonts\\archangelsk.ttf"},
[32] = {Name="Numen", Path="Interface\\Addons\\MikScrollingBattleText\\Fonts\\Numen.ttf"},
};
end
@@ -1138,7 +1145,7 @@ MikSBT.DEFAULT_CONFIG = {
MSBT_TRIGGER_EXECUTE = {
EventSettings = {
Show = true,
Message = SpellName(5308).."!", -- Execute
Message = MikSBT.SpellName(5308, "Execute").."!",
IsSticky = true,
FontSettings = {
Color = {r=1, g=1, b=0},
@@ -1155,7 +1162,7 @@ MikSBT.DEFAULT_CONFIG = {
MSBT_TRIGGER_HAMMER_OF_WRATH = {
EventSettings = {
Show = true,
Message = SpellName(24275).."!", -- Hammer of Wrath
Message = MikSBT.SpellName(24275, "Hammer of Wrath").."!",
IsSticky = true,
FontSettings = {
Color = {r=1, g=1, b=0},
@@ -1172,7 +1179,7 @@ MikSBT.DEFAULT_CONFIG = {
MSBT_TRIGGER_COUNTER_ATTACK = {
EventSettings = {
Show = true,
Message = SpellName(19306).."!", -- Counterattack
Message = MikSBT.SpellName(19306, "Counterattack").."!",
IsSticky = true,
FontSettings = {
Color = {r=1, g=1, b=0},
@@ -1191,7 +1198,7 @@ MikSBT.DEFAULT_CONFIG = {
MSBT_TRIGGER_MONGOOSE_BITE = {
EventSettings = {
Show = true,
Message = SpellName(1495).."!", -- Mongoose Bite
Message = MikSBT.SpellName(1495, "Mongoose Bite").."!",
IsSticky = true,
FontSettings = {
Color = {r=1, g=1, b=0},
@@ -1210,7 +1217,7 @@ MikSBT.DEFAULT_CONFIG = {
MSBT_TRIGGER_CLEARCAST = {
EventSettings = {
Show = true,
Message = SpellName(16246).."!", -- Clearcasting
Message = MikSBT.SpellName(16246, "Clearcasting").."!",
IsSticky = true,
FontSettings = {
Color = {r=1, g=1, b=0},
@@ -1221,14 +1228,14 @@ MikSBT.DEFAULT_CONFIG = {
Classes = {MAGE=true,SHAMAN=true},
TriggerType = 6,
TriggerEvents = {"CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"},
SearchPatterns = {string.format(AURAADDEDSELFHELPFUL, SpellName(16246))}, -- Clearcasting (ID verified vs Spell.dbc)
SearchPatterns = {string.format(AURAADDEDSELFHELPFUL, MikSBT.SpellName(16246, "Clearcasting"))},
},
Texture = "Interface\\Icons\\spell_shadow_manaburn"
},
MSBT_TRIGGER_RIPOSTE = {
EventSettings = {
Show = true,
Message = SpellName(14251).."!", -- Riposte
Message = MikSBT.SpellName(14251, "Riposte").."!",
IsSticky = true,
FontSettings = {
Color = {r=1, g=1, b=0},
@@ -1257,14 +1264,14 @@ MikSBT.DEFAULT_CONFIG = {
TriggerSettings = {
TriggerType = 6,
TriggerEvents = {"CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"},
SearchPatterns = {string.format(AURAADDEDSELFHELPFUL, string.gsub(SpellName(8512), "-", "%%-"))}, -- Windfury Totem (ID verified vs Spell.dbc). "Vous gagnez Totem Furie-des-vents" -- escape char !
SearchPatterns = {string.format(AURAADDEDSELFHELPFUL, string.gsub(MikSBT.SpellName(8512, "Windfury Totem"), "-", "%%-"))}, --"Vous gagnez Totem Furie-des-vents" -- escape char !
},
Texture = "Interface\\Icons\\spell_nature_cyclone"
},
MSBT_TRIGGER_NIGHTFALL = {
EventSettings = {
Show = true,
Message = SpellName(18094).."!", -- Nightfall (talent)
Message = MikSBT.SpellName(18094, "Nightfall").."!",
IsSticky = true,
FontSettings = {
Color = {r=0.709, g=0, b=0.709},
@@ -1275,14 +1282,14 @@ MikSBT.DEFAULT_CONFIG = {
Classes = {WARLOCK=true},
TriggerType = 6,
TriggerEvents = {"CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"},
SearchPatterns = {string.format(AURAADDEDSELFHELPFUL, SpellName(17941))}, -- Shadow Trance (ID verified vs Spell.dbc)
SearchPatterns = {string.format(AURAADDEDSELFHELPFUL, MikSBT.SpellName(17941, "Shadow Trance"))},
},
Texture = "Interface\\Icons\\spell_shadow_twilight"
},
MSBT_TRIGGER_OVERPOWER = {
EventSettings = {
Show = true,
Message = SpellName(7384).."!", -- Overpower
Message = MikSBT.SpellName(7384, "Overpower").."!",
IsSticky = true,
FontSettings = {
Color = {r=1, g=1, b=0},
+17 -17
View File
@@ -4,10 +4,6 @@ A World of Warcraft 1.12 (Vanilla) addon that displays scrolling combat text aro
**Interface:** 11200 | **Version:** 4.43
## Requirements
- **ClassicAPI** — a client-side DLL that backports modern WoW API calls to the 1.12 client (no companion addon required). MSBT relies on it for `C_Spell.GetSpellName`, `C_Item.GetItemName`/`GetItemIcon`, `ItemLocation`, and `CreateColor`/`GetRGB` — used for spell-name lookups, item-icon resolution, and damage-type text coloring. These are not optional fast paths; the addon expects them to be present.
## Features
- Scrolling combat text across three display areas: **Incoming** (right), **Outgoing** (left), and **Notification** (center)
@@ -64,28 +60,32 @@ Interface/
| `/msbt debug` | Toggle debug mode |
| `/msbt help` | Show command usage |
## ClassicAPI Combat Log Integration
## Nampower / SuperWoW / UnitXP SP3 Integration
MSBT reads structured combat data from ClassicAPI's `COMBAT_LOG_EVENT_UNFILTERED` instead of relying on string-based combat log parsing alone, for significantly better performance in heavy combat scenarios (raids, AoE, battlegrounds).
When these enhanced client mods are detected, MSBT automatically switches from string-based combat log parsing to structured event handling for significantly better performance in heavy combat scenarios (raids, AoE, battlegrounds).
### What Changes
- **ClassicAPI combat log**: Registers for the unfiltered combat log (`SPELL_DAMAGE`, `SWING_DAMAGE`, `SPELL_HEAL`, `SPELL_ENERGIZE`, `SPELL_MISSED`, `SPELL_AURA_APPLIED`, `ENVIRONMENTAL_DAMAGE`, `PARTY_KILL`, etc.) which carries pre-parsed amounts, GUIDs, crit flags, miss types and spell info. Redundant `CHAT_MSG_*` events are unregistered to avoid duplicates. No opt-in CVars are needed.
- **SpellId icons**: SpellIds from combat log events resolve icons directly through ClassicAPI's `GetSpellInfo`, bypassing Babble-Spell dictionary lookups and tooltip scanning.
### Removed: SuperWoW / UnitXP SP3 / Nampower
SuperWoW, UnitXP SP3 and Nampower integration has been removed in favor of ClassicAPI (for spell/item lookups, GUIDs and structured combat events). ClassicAPI is a hard dependency (see the `.toc`).
- **Nampower**: Registers for structured events (`SPELL_DAMAGE_EVENT_SELF`, `AUTO_ATTACK_SELF`, `SPELL_HEAL_ON_SELF`, etc.) that provide pre-parsed combat data. Redundant `CHAT_MSG_*` events are unregistered to avoid duplicates. Enables `NP_EnableAutoAttackEvents`, `NP_EnableSpellHealEvents`, and `NP_EnableSpellEnergizeEvents` CVars.
- **SuperWoW**: Provides O(1) unit lookups by name via `UnitExists(name)` (replacing O(n) raid/party iteration) and `SpellInfo(spellId)` for spell icon resolution.
- **UnitXP SP3**: Detected for compatibility; used for GUID-based unit resolution.
### Fallback
`CHAT_MSG_*` parsing stays registered for everything with no combat log equivalent (honor, reputation, skill, XP, item enchantments, some power gains/losses) and as a fallback until each combat log event actually fires.
When none of these mods are present, the addon falls back to the original string-parsing pipeline with no changes in behavior.
### Verification
```lua
-- Check detection status in-game:
/run MikSBT.Print("NP="..tostring(MikCEH.hasNampower).." SW="..tostring(MikCEH.hasSuperWoW).." UXP="..tostring(MikCEH.hasUnitXP))
```
## Performance Optimizations
- **Upvalue caching**: Frequently called standard library functions (`string.find`, `string.gsub`, `table.insert`, `table.getn`, `GetTime`, etc.) are cached as local variables
- **Dispatch table**: Combat event routing uses O(1) table lookup instead of an if/elseif chain
- **SpellId icon cache**: SpellIds from combat log events resolve icons directly through ClassicAPI and are cached, bypassing Babble-Spell dictionary lookups and tooltip scanning
- **SpellId icon cache**: When spellIds are available (via Nampower/SuperWoW), icons are resolved directly and cached, bypassing Babble-Spell dictionary lookups and tooltip scanning
- **Event throttling**: UNIT_HEALTH and UNIT_MANA trigger checks are throttled to 150ms intervals
- **Table recycling**: `MikTRO` (Table Recycler Object) pools and reuses table allocations to reduce garbage collection pressure
@@ -102,9 +102,9 @@ SuperWoW, UnitXP SP3 and Nampower integration has been removed in favor of Class
### Event Processing Pipeline
```
WoW CHAT_MSG_* events (or ClassicAPI COMBAT_LOG_EVENT_UNFILTERED)
-> MikCEH.OnEvent() / MikCEH.OnCombatLogEvent()
-> ParseCombatEvents() dispatch table (or combat log handler)
WoW CHAT_MSG_* events (or Nampower structured events)
-> MikCEH.OnEvent() / MikCEH.OnNampowerEvent()
-> ParseCombatEvents() dispatch table (or Nampower handler)
-> Creates CombatEventData tables
-> MikSBT.CombatEventsHandler()
-> Formats text with templates (%a=amount, %n=name, %s=spell, %t=type)