diff --git a/libs/libpredict.lua b/libs/libpredict.lua index ff046ca2..8f67b7b7 100644 --- a/libs/libpredict.lua +++ b/libs/libpredict.lua @@ -134,19 +134,6 @@ local function OnOwnCastStart(spellId, castGUID) local amount = cache[spell_queue[2]][1] local casttime = castTime - if spellName == REGROWTH then - local fullSpell = spell_queue[2] - local _, _, rankStr = fullSpell and string.find(fullSpell, "Rank (%d+)") - local rankNum = rankStr and tonumber(rankStr) or nil - if libpredict.sender.regrowth_timer then - libpredict.sender.regrowth_target_next = target - libpredict.sender.regrowth_rank_next = rankNum - else - libpredict.sender.regrowth_target = target - libpredict.sender.regrowth_rank = rankNum - end - end - if spellName == PRAYER_OF_HEALING then -- target is already correctly set from spell_queue[3]: -- selfcast (ALT) = player, otherwise = current target @@ -207,34 +194,35 @@ local function OnOwnCastSucceeded(spellId, castGUID) libpredict:HealStop(player) local spellName = C_Spell.GetSpellName(spellId) - if spellName == REGROWTH then - local now = pfUI.uf.now or GetTime() - if libpredict.sender.regrowth_timer then - libpredict.sender.regrowth_start_next = now - else - libpredict.sender.regrowth_start = now - end - libpredict.sender.regrowth_timer = now + 0.1 - end libpredict.sender.castGUID = nil libpredict.sender.current_cast = nil libpredict.sender.current_cast_target = nil if not target then return end - -- Instant HoTs — classify by name (rank-independent) instead of a - -- hardcoded per-rank ID table. + -- HoTs — classify by name (rank-independent) instead of a hardcoded + -- per-rank ID table. local hotType if spellName == REJUVENATION then hotType = "Reju" elseif spellName == RENEW then hotType = "Renew" + elseif spellName == REGROWTH then hotType = "Regr" end if hotType then - local duration = hotType == "Reju" and rejuvDuration or renewDuration local rank = 0 local rankSub = C_Spell.GetSpellSubtext(spellId) if rankSub and rankSub ~= "" then rank = tonumber((string.gsub(rankSub, "Rank ", ""))) or 0 end + if hotType == "Regr" then + -- Regrowth's HoT follows its direct heal a moment later + local start = GetTime() + C_Timer.After(0.1, function() + libpredict:Hot(player, target, hotType, 20, start, "UNIT_SPELLCAST_SUCCEEDED", rank) + libpredict.sender:SendHealCommMsg(hotType .. "/" .. target .. "/20/" .. rank .. "/") + end) + return + end + local duration = hotType == "Reju" and rejuvDuration or renewDuration libpredict:Hot(player, target, hotType, duration, nil, "UNIT_SPELLCAST_SUCCEEDED", rank) libpredict.sender:SendHealCommMsg(hotType .. "/" .. target .. "/" .. duration .. "/" .. rank .. "/") end @@ -932,39 +920,33 @@ libpredict.sender.SendResCommMsg = function(self, msg) -- BG groups are handled by RAID channel end -libpredict.sender:SetScript("OnUpdate", function() - -- trigger delayed regrowth timers - local now = pfUI.uf.now or GetTime() - if this.regrowth_timer and now > this.regrowth_timer then - local target = this.regrowth_target or player - local duration = 20 - local startTime = this.regrowth_start - local rank = this.regrowth_rank - - libpredict:Hot(player, target, "Regr", duration, startTime, "OnUpdate", rank) - local rankStr = rank and tostring(rank) or "0" - libpredict.sender:SendHealCommMsg("Regr/"..target.."/"..duration.."/"..rankStr.."/") - - -- Apply next queued Regrowth if available - this.regrowth_target = this.regrowth_target_next - this.regrowth_start = this.regrowth_start_next - this.regrowth_rank = this.regrowth_rank_next - this.regrowth_target_next = nil - this.regrowth_start_next = nil - this.regrowth_rank_next = nil - this.regrowth_timer = nil +-- Own casts arrive as "player". Other casters only matter as group members +-- (the only names resolveNameFromGuid knows), so their events are filtered to +-- the group's tokens, and solo nobody else's casts arrive at all. A member in +-- a raid also fires as raidN for its own casts; the handler drops those by +-- UnitIsUnit, and other repeats by castGUID. +local GROUP_CAST_EVENTS = { + "UNIT_SPELLCAST_START", "UNIT_SPELLCAST_SUCCEEDED", "UNIT_SPELLCAST_INTERRUPTED", +} +local castunits = {} +local function RegisterCastEvents() + local n, token = 0, IsInRaid() and "raid" or "party" + castunits[1] = "player" + for i = 1, IsInRaid() and GetNumRaidMembers() or GetNumPartyMembers() do + castunits[i + 1] = token .. i + n = i end -end) - --- Own casts arrive as "player"; every other caster fires once per unit token --- it currently holds (raidN, target, nameplateN, ...), so other-unit handlers --- drop the repeats by castGUID. -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_SENT") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_START") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_DELAYED") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_FAILED") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED") + for i = table.getn(castunits), n + 2, -1 do castunits[i] = nil end + for i = 1, table.getn(GROUP_CAST_EVENTS) do + libpredict.sender:RegisterUnitEvent(GROUP_CAST_EVENTS[i], unpack(castunits)) + end +end +RegisterCastEvents() +libpredict.sender:RegisterUnitEvent("UNIT_SPELLCAST_SENT", "player") +libpredict.sender:RegisterUnitEvent("UNIT_SPELLCAST_DELAYED", "player") +libpredict.sender:RegisterUnitEvent("UNIT_SPELLCAST_FAILED", "player") +libpredict.sender:RegisterEvent("PARTY_MEMBERS_CHANGED") +libpredict.sender:RegisterEvent("RAID_ROSTER_UPDATE") libpredict.sender:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") -- Shared cleanup helper for failed/interrupted casts @@ -980,12 +962,6 @@ local function onCastFailed() s:SendResCommMsg("RESNO " .. (target or "")) s.resurrecting = nil end - if s.current_cast == REGROWTH then - s.regrowth_timer = nil - s.regrowth_start = nil - s.regrowth_target_next = nil - s.regrowth_start_next = nil - end s.castGUID = nil s.current_cast = nil s.current_cast_target = nil @@ -1041,6 +1017,9 @@ libpredict.sender:SetScript("OnEvent", function() if arg2 == "SPELL_HEAL" then OnHeal() elseif arg2 == "SPELL_RESURRECT" then OnResurrect() end return + elseif event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" then + RegisterCastEvents() + return end -- UNIT_SPELLCAST_SENT: arg1=unit, arg2=target token, arg3=castGUID, arg4=spellID