local ADDON_NAME = "HailMaryGuildTools" local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME) if not HMGT then return end local RT = HMGT.RaidTimeline if not RT then return end local function TrimText(value) local text = tostring(value or "") text = string.gsub(text, "^%s+", "") text = string.gsub(text, "%s+$", "") return text end local function StripBarDisplayText(value) local text = tostring(value or "") text = string.gsub(text, "|T.-|t", "") text = string.gsub(text, "|c%x%x%x%x%x%x%x%x", "") text = string.gsub(text, "|r", "") return TrimText(text) end local function NormalizeBossAbilityBarName(value) local text = TrimText(value) if text == "" then return "" end text = string.gsub(text, "%s*%(%d+%)%s*$", "") text = string.gsub(text, "%s*%([Cc]ount%)%s*$", "") text = string.gsub(text, "^%s*%[([A-Za-z])%]%s*", "%1 ") text = string.gsub(text, "%s*%[([A-Za-z])%]%s*$", " (%1)") text = string.gsub(text, "%s*%(([A-Za-z])%)%s*$", " (%1)") text = string.lower(text) return TrimText(text) end local function EnsureBigWigsBridge() if RT._bigWigsBridgeRegistered == true then return true end if type(BigWigsLoader) ~= "table" or type(BigWigsLoader.RegisterMessage) ~= "function" then return false end RT._bigWigsObservedBars = RT._bigWigsObservedBars or setmetatable({}, { __mode = "k" }) RT._bigWigsReceiver = RT._bigWigsReceiver or {} function RT._bigWigsReceiver:OnBigWigsBarCreated(_, plugin, bar, module, key, text, time) RT._bigWigsObservedBars[bar] = { plugin = plugin, module = module, key = key, createdText = tostring(text or ""), duration = tonumber(time) or 0, } end function RT._bigWigsReceiver:OnBigWigsStopBar(_, plugin, module, text) local targetText = StripBarDisplayText(text) for bar, info in pairs(RT._bigWigsObservedBars) do local currentText = "" if type(bar) == "table" and type(bar.GetText) == "function" then currentText = StripBarDisplayText(bar:GetText()) end if (info and info.plugin == plugin or not info or not info.plugin) and (currentText == targetText or StripBarDisplayText(info and info.createdText) == targetText) then RT._bigWigsObservedBars[bar] = nil end end end BigWigsLoader.RegisterMessage(RT._bigWigsReceiver, "BigWigs_BarCreated", "OnBigWigsBarCreated") BigWigsLoader.RegisterMessage(RT._bigWigsReceiver, "BigWigs_StopBar", "OnBigWigsStopBar") RT._bigWigsBridgeRegistered = true return true end function RT:GetObservedBigWigsBars() local observed = {} if not EnsureBigWigsBridge() then return observed end for bar, info in pairs(self._bigWigsObservedBars or {}) do local rawText = nil if type(bar) == "table" and type(bar.GetText) == "function" then rawText = bar:GetText() end rawText = StripBarDisplayText(rawText or (info and info.createdText) or "") local remaining = math.max(0, tonumber(bar and bar.remaining) or 0) if rawText ~= "" and remaining > 0 then observed[#observed + 1] = { rawText = rawText, normalizedName = NormalizeBossAbilityBarName(rawText), count = tonumber(string.match(rawText, "%((%d+)%)%s*$")) or 1, seconds = remaining, key = info and info.key or nil, } else self._bigWigsObservedBars[bar] = nil end end return observed end function RT:ProbeBossAbilityEntry(entryIndex, entry) if not self:IsLocalEditor() or not self.activeEncounterId or self:GetTriggerType(entry) ~= "bossAbility" then return end local desiredRawName = TrimText(entry and entry.bossAbilityBarName or "") local desiredName = NormalizeBossAbilityBarName(desiredRawName) local desiredSelector = self:NormalizeCastCountSelector(entry and entry.castCount) local desiredSelectorText = self:FormatCastCountSelector(desiredSelector) if desiredName == "" then self:LogBossAbilityProbe( entryIndex, entry, "missing-bar-name", "RaidTimeline BigWigs probe encounter=%s slot=%s skipped=missing-bar-name", tostring(self.activeEncounterId), tostring(entryIndex) ) return end local bars = self:GetObservedBigWigsBars() if #bars == 0 then self:LogBossAbilityProbe( entryIndex, entry, "no-bars", "RaidTimeline BigWigs probe encounter=%s slot=%s target=%s normalized=%s selector=%s foundBar=false bars=0", tostring(self.activeEncounterId), tostring(entryIndex), tostring(desiredRawName), tostring(desiredName), tostring(desiredSelectorText) ) return end local seenNames = {} local foundName = false for _, observed in ipairs(bars) do seenNames[#seenNames + 1] = string.format("%s{key=%s}[%d]=%.1fs", tostring(observed.rawText), tostring(observed.key), tonumber(observed.count) or 1, tonumber(observed.seconds) or 0) if observed.normalizedName == desiredName then foundName = true if self:DoesCastCountSelectorMatch(desiredSelector, observed.count) then self:LogBossAbilityProbe( entryIndex, entry, string.format("match:%s:%s:%d", desiredName, tostring(desiredSelector), tonumber(observed.count) or 1), "RaidTimeline BigWigs probe encounter=%s slot=%s target=%s normalized=%s selector=%s foundBar=true countMatch=true observed=%s key=%s observedCount=%d remaining=%.1f", tostring(self.activeEncounterId), tostring(entryIndex), tostring(desiredRawName), tostring(desiredName), tostring(desiredSelectorText), tostring(observed.rawText), tostring(observed.key), tonumber(observed.count) or 1, tonumber(observed.seconds) or 0 ) self:TryDispatchBossAbilityEntry(entryIndex, entry, observed.count, observed.seconds) return end self:LogBossAbilityProbe( entryIndex, entry, string.format("count-mismatch:%s:%d", desiredName, observed.count), "RaidTimeline BigWigs probe encounter=%s slot=%s target=%s normalized=%s selector=%s foundBar=true countMatch=false observed=%s key=%s observedCount=%d remaining=%.1f", tostring(self.activeEncounterId), tostring(entryIndex), tostring(desiredRawName), tostring(desiredName), tostring(desiredSelectorText), tostring(observed.rawText), tostring(observed.key), tonumber(observed.count) or 1, tonumber(observed.seconds) or 0 ) end end if not foundName then self:LogBossAbilityProbe( entryIndex, entry, string.format("name-miss:%s", desiredName), "RaidTimeline BigWigs probe encounter=%s slot=%s target=%s normalized=%s selector=%s foundBar=false bars=%s", tostring(self.activeEncounterId), tostring(entryIndex), tostring(desiredRawName), tostring(desiredName), tostring(desiredSelectorText), table.concat(seenNames, ", ") ) end end