mirror of
https://github.com/brues-code/SuperCleveRoidMacros.git
synced 2026-09-16 03:38:00 +00:00
@@ -0,0 +1,582 @@
|
||||
--[[
|
||||
ComboPoint Tracker for Duration-Scaling Spells
|
||||
Author: Extension for CleveRoids
|
||||
Purpose: Track combo points used when casting spells that scale duration with combo points
|
||||
]]
|
||||
|
||||
local _G = _G or getfenv(0)
|
||||
local CleveRoids = _G.CleveRoids or {}
|
||||
|
||||
-- Initialize combo point tracking table
|
||||
CleveRoids.ComboPointTracking = CleveRoids.ComboPointTracking or {}
|
||||
CleveRoids.spell_tracking = CleveRoids.spell_tracking or {}
|
||||
CleveRoids.lastComboPoints = CleveRoids.lastComboPoints or 0 -- Track last known CP count
|
||||
|
||||
-- Initialize SavedVariable for learned combo durations
|
||||
-- Structure: CleveRoids_ComboDurations[spellID][comboPoints] = duration
|
||||
CleveRoids_ComboDurations = CleveRoids_ComboDurations or {}
|
||||
|
||||
-- Define spells that scale with combo points by SPELL ID and their duration formulas
|
||||
-- Duration = base + (combo_points - 1) * increment
|
||||
CleveRoids.ComboScalingSpellsByID = {
|
||||
-- ROGUE: Rupture - 8 sec base, +2 sec per additional combo point
|
||||
[1943] = { base = 8, increment = 2, name = "Rupture" }, -- Rank 1
|
||||
[8639] = { base = 8, increment = 2, name = "Rupture" }, -- Rank 2
|
||||
[8640] = { base = 8, increment = 2, name = "Rupture" }, -- Rank 3
|
||||
[11273] = { base = 8, increment = 2, name = "Rupture" }, -- Rank 4
|
||||
[11274] = { base = 8, increment = 2, name = "Rupture" }, -- Rank 5
|
||||
[11275] = { base = 8, increment = 2, name = "Rupture" }, -- Rank 6
|
||||
|
||||
-- ROGUE: Kidney Shot - Rank 1: 1 sec base, Rank 2: 2 sec base, +1 sec per CP
|
||||
[408] = { base = 1, increment = 1, name = "Kidney Shot" }, -- Rank 1
|
||||
[8643] = { base = 2, increment = 1, name = "Kidney Shot" }, -- Rank 2
|
||||
|
||||
-- DRUID: Rip - 12 sec base, +4 sec per additional combo point (Source: Vanilla WoW Wiki)
|
||||
-- Note: Some sources say 10+2, but testing shows 12+4 is accurate for 1.12
|
||||
[1079] = { base = 10, increment = 2, name = "Rip" }, -- Rank 1
|
||||
[9492] = { base = 10, increment = 2, name = "Rip" }, -- Rank 2
|
||||
[9493] = { base = 10, increment = 2, name = "Rip" }, -- Rank 3
|
||||
[9752] = { base = 10, increment = 2, name = "Rip" }, -- Rank 4
|
||||
[9894] = { base = 10, increment = 2, name = "Rip" }, -- Rank 5
|
||||
[9896] = { base = 10, increment = 2, name = "Rip" }, -- Rank 6
|
||||
}
|
||||
|
||||
-- Legacy name-based table for backwards compatibility
|
||||
CleveRoids.ComboScalingSpells = {
|
||||
["Rupture"] = { base_duration = 8, increment = 2, all_ranks = true },
|
||||
["Kidney Shot(Rank 1)"] = { base_duration = 1, increment = 1 },
|
||||
["Kidney Shot(Rank 2)"] = { base_duration = 2, increment = 1 },
|
||||
["Rip"] = { base_duration = 10, increment = 2, all_ranks = true }
|
||||
}
|
||||
|
||||
-- Function to get current combo points
|
||||
function CleveRoids.GetComboPoints()
|
||||
return GetComboPoints("player", "target") or 0
|
||||
end
|
||||
|
||||
-- Update stored combo points (call this frequently)
|
||||
function CleveRoids.UpdateComboPoints()
|
||||
local current = CleveRoids.GetComboPoints()
|
||||
if current > 0 then
|
||||
CleveRoids.lastComboPoints = current
|
||||
end
|
||||
end
|
||||
|
||||
-- Function to check if a spell scales with combo points
|
||||
function CleveRoids.IsComboScalingSpell(spellName)
|
||||
if not spellName then return false end
|
||||
|
||||
-- Check exact match first
|
||||
if CleveRoids.ComboScalingSpells[spellName] then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Check for spells marked as all_ranks
|
||||
for spell, data in pairs(CleveRoids.ComboScalingSpells) do
|
||||
if data.all_ranks then
|
||||
-- Remove rank from spell name for comparison
|
||||
local baseName = string.gsub(spell, "%(Rank %d+%)", "")
|
||||
local checkName = string.gsub(spellName, "%(Rank %d+%)", "")
|
||||
if baseName == checkName then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- Function to get spell data for combo scaling
|
||||
function CleveRoids.GetComboScalingData(spellName)
|
||||
if not spellName then return nil end
|
||||
|
||||
-- Check exact match first
|
||||
if CleveRoids.ComboScalingSpells[spellName] then
|
||||
return CleveRoids.ComboScalingSpells[spellName]
|
||||
end
|
||||
|
||||
-- Check for spells marked as all_ranks
|
||||
for spell, data in pairs(CleveRoids.ComboScalingSpells) do
|
||||
if data.all_ranks then
|
||||
local baseName = string.gsub(spell, "%(Rank %d+%)", "")
|
||||
local checkName = string.gsub(spellName, "%(Rank %d+%)", "")
|
||||
if baseName == checkName then
|
||||
return data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Special handling for Kidney Shot ranks
|
||||
if string.find(spellName, "Kidney Shot") then
|
||||
local _, _, rank = string.find(spellName, "Kidney Shot%(Rank (%d+)%)")
|
||||
if rank then
|
||||
rank = tonumber(rank)
|
||||
if rank == 1 then
|
||||
return CleveRoids.ComboScalingSpells["Kidney Shot(Rank 1)"]
|
||||
elseif rank == 2 then
|
||||
return CleveRoids.ComboScalingSpells["Kidney Shot(Rank 2)"]
|
||||
end
|
||||
end
|
||||
-- Default to base Kidney Shot data
|
||||
return CleveRoids.ComboScalingSpells["Kidney Shot"]
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Function to calculate duration based on combo points
|
||||
function CleveRoids.CalculateComboScaledDuration(spellName, comboPoints)
|
||||
local data = CleveRoids.GetComboScalingData(spellName)
|
||||
if not data then return nil end
|
||||
|
||||
comboPoints = comboPoints or CleveRoids.GetComboPoints()
|
||||
if comboPoints < 1 then comboPoints = 1 end -- Minimum 1 combo point
|
||||
if comboPoints > 5 then comboPoints = 5 end -- Maximum 5 combo points
|
||||
|
||||
return data.base_duration + (comboPoints - 1) * data.increment
|
||||
end
|
||||
|
||||
-- NEW: Check if spell ID is a combo scaling spell
|
||||
function CleveRoids.IsComboScalingSpellID(spellID)
|
||||
return CleveRoids.ComboScalingSpellsByID[spellID] ~= nil
|
||||
end
|
||||
|
||||
-- NEW: Get combo scaling data by spell ID
|
||||
function CleveRoids.GetComboScalingDataByID(spellID)
|
||||
return CleveRoids.ComboScalingSpellsByID[spellID]
|
||||
end
|
||||
|
||||
-- NEW: Get learned duration for specific combo point count
|
||||
function CleveRoids.GetLearnedComboDuration(spellID, comboPoints)
|
||||
if CleveRoids_ComboDurations[spellID] and CleveRoids_ComboDurations[spellID][comboPoints] then
|
||||
return CleveRoids_ComboDurations[spellID][comboPoints]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- NEW: Calculate duration by spell ID and combo points (uses learned durations first)
|
||||
function CleveRoids.CalculateComboScaledDurationByID(spellID, comboPoints)
|
||||
local data = CleveRoids.GetComboScalingDataByID(spellID)
|
||||
if not data then return nil end
|
||||
|
||||
comboPoints = comboPoints or CleveRoids.GetComboPoints()
|
||||
if comboPoints < 1 then comboPoints = 1 end -- Minimum 1 combo point
|
||||
if comboPoints > 5 then comboPoints = 5 end -- Maximum 5 combo points
|
||||
|
||||
-- Check for learned duration first
|
||||
local learned = CleveRoids.GetLearnedComboDuration(spellID, comboPoints)
|
||||
if learned then
|
||||
return learned
|
||||
end
|
||||
|
||||
-- Fall back to formula
|
||||
return data.base + (comboPoints - 1) * data.increment
|
||||
end
|
||||
|
||||
-- Function to track combo points when casting (by spell name)
|
||||
function CleveRoids.TrackComboPointCast(spellName)
|
||||
if not CleveRoids.IsComboScalingSpell(spellName) then
|
||||
return
|
||||
end
|
||||
|
||||
local comboPoints = CleveRoids.GetComboPoints()
|
||||
local duration = CleveRoids.CalculateComboScaledDuration(spellName, comboPoints)
|
||||
local currentTime = GetTime()
|
||||
|
||||
-- Only update if this is a better (higher CP) value than existing, or if existing is stale
|
||||
local existing = CleveRoids.ComboPointTracking[spellName]
|
||||
if existing then
|
||||
local age = currentTime - existing.cast_time
|
||||
-- Keep existing if it's fresh (<0.5s) and EITHER has more combo points OR is confirmed
|
||||
if age < 0.5 then
|
||||
if existing.combo_points > comboPoints then
|
||||
-- Don't overwrite better data with worse data
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff888888CleveRoids:|r ComboTrack: Ignoring %s with %d CP (have %d CP)",
|
||||
spellName, comboPoints, existing.combo_points)
|
||||
)
|
||||
end
|
||||
return
|
||||
elseif existing.confirmed then
|
||||
-- Don't overwrite confirmed tracking with unconfirmed evaluation
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff888888CleveRoids:|r ComboTrack: Ignoring %s - already confirmed",
|
||||
spellName)
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Store the tracking data
|
||||
CleveRoids.ComboPointTracking[spellName] = {
|
||||
combo_points = comboPoints,
|
||||
duration = duration,
|
||||
cast_time = currentTime,
|
||||
target = UnitName("target") or "Unknown",
|
||||
confirmed = false -- Will be set to true by SPELLCAST_START
|
||||
}
|
||||
|
||||
-- Also store in spell_tracking for integration with existing system
|
||||
if not CleveRoids.spell_tracking[spellName] then
|
||||
CleveRoids.spell_tracking[spellName] = {}
|
||||
end
|
||||
|
||||
CleveRoids.spell_tracking[spellName].last_combo_points = comboPoints
|
||||
CleveRoids.spell_tracking[spellName].last_duration = duration
|
||||
CleveRoids.spell_tracking[spellName].last_cast_time = currentTime
|
||||
|
||||
-- Debug output
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff4b7dccCleveRoids:|r ComboTrack: %s cast with %d CP, duration: %d seconds",
|
||||
spellName, comboPoints, duration)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
-- NEW: Track combo points by spell ID (for UNIT_CASTEVENT integration)
|
||||
function CleveRoids.TrackComboPointCastByID(spellID, targetGUID)
|
||||
if not CleveRoids.IsComboScalingSpellID(spellID) then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Get current combo points, but if they're 0 (already consumed), use last known value
|
||||
local comboPoints = CleveRoids.GetComboPoints()
|
||||
|
||||
-- If combo points are 0, try multiple fallback sources
|
||||
if comboPoints == 0 then
|
||||
-- First, try lastComboPoints
|
||||
if CleveRoids.lastComboPoints > 0 then
|
||||
comboPoints = CleveRoids.lastComboPoints
|
||||
CleveRoids.lastComboPoints = 0 -- Reset after using
|
||||
else
|
||||
-- Second, check if name-based tracking has recent data for this spell
|
||||
local spellName = SpellInfo(spellID)
|
||||
if spellName then
|
||||
-- Remove rank info for comparison
|
||||
local baseName = string.gsub(spellName, "%s*%(Rank %d+%)", "")
|
||||
if CleveRoids.ComboPointTracking[spellName] then
|
||||
local tracking = CleveRoids.ComboPointTracking[spellName]
|
||||
if tracking.combo_points and tracking.combo_points > 0 and
|
||||
(GetTime() - tracking.cast_time) < 0.5 then -- Within last 0.5 seconds
|
||||
comboPoints = tracking.combo_points
|
||||
end
|
||||
elseif CleveRoids.ComboPointTracking[baseName] then
|
||||
local tracking = CleveRoids.ComboPointTracking[baseName]
|
||||
if tracking.combo_points and tracking.combo_points > 0 and
|
||||
(GetTime() - tracking.cast_time) < 0.5 then
|
||||
comboPoints = tracking.combo_points
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local duration = CleveRoids.CalculateComboScaledDurationByID(spellID, comboPoints)
|
||||
|
||||
if not duration then return nil end
|
||||
|
||||
-- Store tracking data by spell ID
|
||||
if not CleveRoids.ComboPointTracking.byID then
|
||||
CleveRoids.ComboPointTracking.byID = {}
|
||||
end
|
||||
|
||||
CleveRoids.ComboPointTracking.byID[spellID] = {
|
||||
combo_points = comboPoints,
|
||||
duration = duration,
|
||||
cast_time = GetTime(),
|
||||
target_guid = targetGUID
|
||||
}
|
||||
|
||||
-- Debug output
|
||||
if CleveRoids.debug then
|
||||
local data = CleveRoids.ComboScalingSpellsByID[spellID]
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff4b7dccCleveRoids:|r ComboTrack: %s (ID:%d) cast with %d CP, duration: %d seconds",
|
||||
data.name, spellID, comboPoints, duration)
|
||||
)
|
||||
end
|
||||
|
||||
return duration
|
||||
end
|
||||
|
||||
-- API function to get last tracked combo points for a spell
|
||||
function CleveRoids.GetLastComboPointsForSpell(spellName)
|
||||
if CleveRoids.ComboPointTracking[spellName] then
|
||||
return CleveRoids.ComboPointTracking[spellName].combo_points
|
||||
elseif CleveRoids.spell_tracking[spellName] then
|
||||
return CleveRoids.spell_tracking[spellName].last_combo_points
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- API function to get last calculated duration for a spell
|
||||
function CleveRoids.GetLastDurationForSpell(spellName)
|
||||
if CleveRoids.ComboPointTracking[spellName] then
|
||||
return CleveRoids.ComboPointTracking[spellName].duration
|
||||
elseif CleveRoids.spell_tracking[spellName] then
|
||||
return CleveRoids.spell_tracking[spellName].last_duration
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Utility function to display current combo tracking info
|
||||
function CleveRoids.ShowComboTracking()
|
||||
CleveRoids.Print("=== Combo Point Tracking ===")
|
||||
local hasData = false
|
||||
for spell, data in pairs(CleveRoids.ComboPointTracking) do
|
||||
if spell ~= "byID" and data.combo_points then
|
||||
CleveRoids.Print(string.format("%s: %d CP, %ds duration, target: %s",
|
||||
spell, data.combo_points, data.duration, data.target))
|
||||
hasData = true
|
||||
end
|
||||
end
|
||||
if not hasData then
|
||||
CleveRoids.Print("No combo finishers tracked yet. Cast Rupture, Rip, or Kidney Shot!")
|
||||
end
|
||||
end
|
||||
|
||||
-- Slash command for debugging
|
||||
SLASH_COMBOTRACK1 = "/combotrack"
|
||||
SlashCmdList.COMBOTRACK = function(msg)
|
||||
if msg == "show" then
|
||||
CleveRoids.ShowComboTracking()
|
||||
elseif msg == "clear" then
|
||||
CleveRoids.ComboPointTracking = {}
|
||||
CleveRoids.ComboPointTracking.byID = {}
|
||||
CleveRoids.Print("Combo tracking data cleared")
|
||||
elseif msg == "debug" then
|
||||
CleveRoids.debug = not CleveRoids.debug
|
||||
CleveRoids.Print("Combo tracking debug: " .. (CleveRoids.debug and "ON" or "OFF"))
|
||||
else
|
||||
CleveRoids.Print("ComboTrack commands:")
|
||||
CleveRoids.Print(" /combotrack show - Display current tracking data")
|
||||
CleveRoids.Print(" /combotrack clear - Clear tracking data")
|
||||
CleveRoids.Print(" /combotrack debug - Toggle debug output")
|
||||
end
|
||||
end
|
||||
|
||||
-- Export to global namespace NOW, before Extension registration
|
||||
_G["CleveRoids"] = CleveRoids
|
||||
|
||||
-- DEBUG: Confirm ShowComboTracking is defined
|
||||
if CleveRoids.ShowComboTracking then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00ComboPointTracker: ShowComboTracking defined and exported!|r")
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000ComboPointTracker: ERROR - ShowComboTracking NOT defined!|r")
|
||||
end
|
||||
|
||||
-- Hook into the existing DoCast function (safe to fail)
|
||||
if not CleveRoids.RegisterExtension then
|
||||
-- ExtensionsManager not loaded yet, skip extension system
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000ComboPointTracker: RegisterExtension not found, skipping Extension system|r")
|
||||
return
|
||||
end
|
||||
|
||||
local Extension = CleveRoids.RegisterExtension("ComboPointTracker")
|
||||
|
||||
function Extension.OnLoad()
|
||||
-- Register for cast events
|
||||
Extension.RegisterEvent("SPELLCAST_START", "OnSpellcastStart")
|
||||
Extension.RegisterEvent("SPELLCAST_STOP", "OnSpellcastStop")
|
||||
Extension.RegisterEvent("SPELLCAST_FAILED", "OnSpellcastFailed")
|
||||
Extension.RegisterEvent("SPELLCAST_INTERRUPTED", "OnSpellcastInterrupted")
|
||||
Extension.RegisterEvent("PLAYER_TARGET_CHANGED", "OnTargetChanged")
|
||||
Extension.RegisterEvent("UNIT_AURA", "OnUnitAura")
|
||||
Extension.RegisterEvent("PLAYER_COMBO_POINTS", "OnComboPointsChanged")
|
||||
|
||||
-- Set up OnUpdate to track combo points
|
||||
Extension.internal.frame:SetScript("OnUpdate", function()
|
||||
CleveRoids.UpdateComboPoints()
|
||||
end)
|
||||
|
||||
-- Hook the spell cast functions if they exist
|
||||
if CleveRoids.CastSpell then
|
||||
Extension.Hook("CleveRoids.CastSpell", "CastSpell_Hook")
|
||||
end
|
||||
|
||||
if CastSpellByName then
|
||||
Extension.Hook("CastSpellByName", "CastSpellByName_Hook")
|
||||
end
|
||||
|
||||
-- Hook global CastSpell and UseAction for confirmation
|
||||
if _G.CastSpell then
|
||||
local originalCastSpell = _G.CastSpell
|
||||
_G.CastSpell = function(id, bookType)
|
||||
-- Call original first
|
||||
originalCastSpell(id, bookType)
|
||||
|
||||
-- Confirm tracking for combo spells
|
||||
local spellName = GetSpellName(id, bookType)
|
||||
if spellName and CleveRoids.IsComboScalingSpell(spellName) and
|
||||
CleveRoids.ComboPointTracking[spellName] then
|
||||
CleveRoids.ComboPointTracking[spellName].confirmed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if _G.UseAction then
|
||||
local originalUseAction = _G.UseAction
|
||||
_G.UseAction = function(slot, target, button)
|
||||
-- Call original first
|
||||
originalUseAction(slot, target, button)
|
||||
|
||||
-- Try to determine spell name from action slot
|
||||
if not GetActionText(slot) and IsCurrentAction(slot) then
|
||||
local spellName = GetActionText(slot)
|
||||
if not spellName then
|
||||
-- Try to get from tooltip
|
||||
GameTooltip:SetAction(slot)
|
||||
spellName = GameTooltipTextLeft1:GetText()
|
||||
end
|
||||
|
||||
if spellName and CleveRoids.IsComboScalingSpell(spellName) and
|
||||
CleveRoids.ComboPointTracking[spellName] then
|
||||
CleveRoids.ComboPointTracking[spellName].confirmed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Update combo points on relevant events
|
||||
function Extension.OnTargetChanged()
|
||||
CleveRoids.UpdateComboPoints()
|
||||
end
|
||||
|
||||
function Extension.OnUnitAura()
|
||||
if arg1 == "target" or arg1 == "player" then
|
||||
CleveRoids.UpdateComboPoints()
|
||||
end
|
||||
end
|
||||
|
||||
function Extension.OnComboPointsChanged()
|
||||
CleveRoids.UpdateComboPoints()
|
||||
end
|
||||
|
||||
-- Event handlers
|
||||
function Extension.OnSpellcastStart()
|
||||
-- Track combo points at cast start for channeled combo spells
|
||||
local spellName = arg1
|
||||
if spellName and CleveRoids.IsComboScalingSpell(spellName) then
|
||||
CleveRoids.TrackComboPointCast(spellName)
|
||||
|
||||
-- Mark this tracking as confirmed (actual cast, not just evaluation)
|
||||
if CleveRoids.ComboPointTracking[spellName] then
|
||||
CleveRoids.ComboPointTracking[spellName].confirmed = true
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff00[Confirmed]|r %s tracking confirmed (SPELLCAST_START)",
|
||||
spellName)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Extension.OnSpellcastStop()
|
||||
-- Track combo points at successful cast completion
|
||||
local spellName = arg1
|
||||
if spellName and CleveRoids.IsComboScalingSpell(spellName) then
|
||||
-- Update tracking if spell successfully completed
|
||||
local tracking = CleveRoids.ComboPointTracking[spellName]
|
||||
if tracking and (GetTime() - tracking.cast_time) < 1 then
|
||||
-- Cast was recent, mark as successful
|
||||
tracking.successful = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Extension.OnSpellcastFailed()
|
||||
-- Clear tracking for failed casts
|
||||
local spellName = arg1
|
||||
if spellName and CleveRoids.ComboPointTracking[spellName] then
|
||||
local tracking = CleveRoids.ComboPointTracking[spellName]
|
||||
if tracking and (GetTime() - tracking.cast_time) < 1 then
|
||||
-- Recent cast failed, clear confirmed flag and the tracking
|
||||
tracking.confirmed = false
|
||||
CleveRoids.ComboPointTracking[spellName] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Extension.OnSpellcastInterrupted()
|
||||
-- Clear tracking for interrupted casts
|
||||
Extension.OnSpellcastFailed()
|
||||
end
|
||||
|
||||
-- Hook CastSpellByName to track combo points
|
||||
function Extension.CastSpellByName_Hook(spellName, onSelf)
|
||||
if spellName and CleveRoids.IsComboScalingSpell(spellName) then
|
||||
CleveRoids.TrackComboPointCast(spellName)
|
||||
|
||||
-- Confirm the tracking immediately - this only fires on actual casts
|
||||
if CleveRoids.ComboPointTracking[spellName] then
|
||||
CleveRoids.ComboPointTracking[spellName].confirmed = true
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff00[Confirmed]|r %s tracking confirmed (CastSpellByName)",
|
||||
spellName)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Hook CleveRoids.CastSpell if it exists
|
||||
function Extension.CastSpell_Hook(spellName)
|
||||
if spellName and CleveRoids.IsComboScalingSpell(spellName) then
|
||||
CleveRoids.TrackComboPointCast(spellName)
|
||||
|
||||
-- Confirm the tracking immediately - this only fires on actual casts
|
||||
if CleveRoids.ComboPointTracking[spellName] then
|
||||
CleveRoids.ComboPointTracking[spellName].confirmed = true
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff00[Confirmed]|r %s tracking confirmed (CleveRoids.CastSpell)",
|
||||
spellName)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Integration with DoCast function (moved before Extension registration)
|
||||
if CleveRoids.DoCast then
|
||||
local originalDoCast = CleveRoids.DoCast
|
||||
CleveRoids.DoCast = function(msg)
|
||||
-- Extract spell name from message
|
||||
local spellName = msg
|
||||
|
||||
-- Remove conditionals if present
|
||||
local condEnd = string.find(msg, "]")
|
||||
if condEnd then
|
||||
spellName = string.sub(msg, condEnd + 1)
|
||||
end
|
||||
|
||||
spellName = CleveRoids.Trim(spellName)
|
||||
|
||||
-- Track combo points if it's a scaling spell
|
||||
if CleveRoids.IsComboScalingSpell(spellName) then
|
||||
CleveRoids.TrackComboPointCast(spellName)
|
||||
|
||||
-- Confirm the tracking - DoCast only fires on actual casts
|
||||
if CleveRoids.ComboPointTracking[spellName] then
|
||||
CleveRoids.ComboPointTracking[spellName].confirmed = true
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff00[Confirmed]|r %s tracking confirmed (DoCast)",
|
||||
spellName)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Call original function
|
||||
return originalDoCast(msg)
|
||||
end
|
||||
end
|
||||
@@ -91,6 +91,171 @@ function Extension.HandleSendChatMessageHook()
|
||||
end
|
||||
end
|
||||
|
||||
-- Hook pfUI's libdebuff to use our combo-aware durations
|
||||
function Extension.HookPfUILibdebuff()
|
||||
if not pfUI or not pfUI.api or not pfUI.api.libdebuff then
|
||||
return false
|
||||
end
|
||||
|
||||
local pflib = pfUI.api.libdebuff
|
||||
|
||||
-- Hook GetDuration if it exists
|
||||
if pflib.GetDuration and not Extension.pfLibDebuffHooked then
|
||||
local originalGetDuration = pflib.GetDuration
|
||||
|
||||
pflib.GetDuration = function(self, spellID, casterGUID, comboPoints)
|
||||
-- Check if this is a combo scaling spell first
|
||||
if CleveRoids.IsComboScalingSpellID and CleveRoids.IsComboScalingSpellID(spellID) then
|
||||
-- If combo points provided, check learned combo durations
|
||||
if comboPoints and CleveRoids_ComboDurations and CleveRoids_ComboDurations[spellID] then
|
||||
local comboDur = CleveRoids_ComboDurations[spellID][comboPoints]
|
||||
if comboDur and comboDur > 0 then
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff00[pfUI Hook]|r Returning %ds for spell %d at %d CP",
|
||||
comboDur, spellID, comboPoints)
|
||||
)
|
||||
end
|
||||
return comboDur
|
||||
end
|
||||
end
|
||||
|
||||
-- Fallback: check for highest learned combo duration
|
||||
if CleveRoids_ComboDurations and CleveRoids_ComboDurations[spellID] then
|
||||
for cp = 5, 1, -1 do
|
||||
if CleveRoids_ComboDurations[spellID][cp] then
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff00[pfUI Hook]|r Returning %ds for spell %d (fallback %d CP)",
|
||||
CleveRoids_ComboDurations[spellID][cp], spellID, cp)
|
||||
)
|
||||
end
|
||||
return CleveRoids_ComboDurations[spellID][cp]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Not a combo spell or no learned duration, use original
|
||||
return originalGetDuration(self, spellID, casterGUID, comboPoints)
|
||||
end
|
||||
|
||||
Extension.pfLibDebuffHooked = true
|
||||
Extension.DLOG("Hooked pfUI.api.libdebuff.GetDuration for combo duration support")
|
||||
end
|
||||
|
||||
-- Hook AddEffect if it exists to inject combo-aware durations
|
||||
if pflib.AddEffect and not Extension.pfLibAddEffectHooked then
|
||||
local originalAddEffect = pflib.AddEffect
|
||||
|
||||
pflib.AddEffect = function(self, unit, unitlevel, effect, duration, caster)
|
||||
-- effect is a spell name, not ID
|
||||
-- Check if this is a combo scaling spell by name
|
||||
if CleveRoids.IsComboScalingSpell and CleveRoids.IsComboScalingSpell(effect) then
|
||||
-- Use name-based tracking which is populated BEFORE pfUI's AddEffect
|
||||
if CleveRoids.ComboPointTracking and CleveRoids.ComboPointTracking[effect] then
|
||||
local tracking = CleveRoids.ComboPointTracking[effect]
|
||||
-- Only use tracking if it's confirmed (actual cast, not just evaluation)
|
||||
if tracking.duration and tracking.confirmed and (GetTime() - tracking.cast_time) < 0.5 then
|
||||
duration = tracking.duration
|
||||
-- Don't clear confirmed flag - let time-based expiry handle it
|
||||
-- pfUI may call AddEffect multiple times for the same spell
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff00[pfUI AddEffect Hook]|r Overriding %s duration to %ds (from confirmed tracking)",
|
||||
effect, duration)
|
||||
)
|
||||
end
|
||||
elseif CleveRoids.debug and tracking.duration and not tracking.confirmed and (GetTime() - tracking.cast_time) < 0.5 then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffaaaa00[pfUI AddEffect Hook]|r Ignoring %s tracking (not confirmed - evaluation only)",
|
||||
effect)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return originalAddEffect(self, unit, unitlevel, effect, duration, caster)
|
||||
end
|
||||
|
||||
Extension.pfLibAddEffectHooked = true
|
||||
Extension.DLOG("Hooked pfUI.api.libdebuff.AddEffect for combo duration support")
|
||||
end
|
||||
|
||||
return Extension.pfLibDebuffHooked or Extension.pfLibAddEffectHooked
|
||||
end
|
||||
|
||||
-- Synchronize combo durations to pfUI's libdebuff objects
|
||||
function Extension.SyncComboDurationToPfUI(guid, spellID, duration)
|
||||
if not pfUI or not pfUI.api or not pfUI.api.libdebuff then
|
||||
return
|
||||
end
|
||||
|
||||
-- Get unit name from GUID
|
||||
local unitName = nil
|
||||
local unitLevel = 0
|
||||
|
||||
-- Check if this is the current target
|
||||
local _, targetGUID = UnitExists("target")
|
||||
if targetGUID == guid then
|
||||
unitName = UnitName("target")
|
||||
unitLevel = UnitLevel("target") or 0
|
||||
end
|
||||
|
||||
-- If we couldn't find the unit, use GUID to name mapping from libdebuff
|
||||
if not unitName and CleveRoids.libdebuff and CleveRoids.libdebuff.guidToName then
|
||||
unitName = CleveRoids.libdebuff.guidToName[guid]
|
||||
-- Default to level 0 if we don't have the unit targeted
|
||||
unitLevel = 0
|
||||
end
|
||||
|
||||
if not unitName then
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[pfUI Sync]|r Could not find unit name for GUID")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Get spell name from spell ID
|
||||
local spellName = SpellInfo(spellID)
|
||||
if not spellName then
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[pfUI Sync]|r Could not find spell name for ID " .. spellID)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Remove rank from spell name to match pfUI's format
|
||||
local effectName = string.gsub(spellName, "%s*%(Rank %d+%)", "")
|
||||
|
||||
-- Update pfUI's stored debuff duration
|
||||
local pflib = pfUI.api.libdebuff
|
||||
if pflib.objects and pflib.objects[unitName] then
|
||||
-- Try both the specific level and level 0 (fallback)
|
||||
for _, level in ipairs({unitLevel, 0}) do
|
||||
if pflib.objects[unitName][level] and pflib.objects[unitName][level][effectName] then
|
||||
local old_duration = pflib.objects[unitName][level][effectName].duration
|
||||
pflib.objects[unitName][level][effectName].duration = duration
|
||||
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ffaa[pfUI Sync]|r Updated %s on %s (L%d): %ds -> %ds",
|
||||
effectName, unitName, level, old_duration or 0, duration)
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffaaaa00[pfUI Sync]|r Effect not found in pfUI storage: %s on %s",
|
||||
effectName, unitName)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
-- Main compatibility check and setup
|
||||
function Extension.SetupCompatibility()
|
||||
Extension.pfUILoaded = (pfUI ~= nil)
|
||||
@@ -99,6 +264,9 @@ function Extension.SetupCompatibility()
|
||||
if Extension.pfUILoaded then
|
||||
Extension.DLOG("pfUI detected")
|
||||
|
||||
-- Hook libdebuff for combo duration support
|
||||
Extension.HookPfUILibdebuff()
|
||||
|
||||
if Extension.macrotweakLoaded then
|
||||
Extension.DLOG("pfUI macrotweak module detected")
|
||||
|
||||
@@ -115,6 +283,9 @@ function Extension.OnLoad()
|
||||
Extension.DLOG("Extension pfUI Loaded.")
|
||||
Extension.HookMethod(CleveRoids, "GetFocusName", "FocusNameHook", true)
|
||||
|
||||
-- Export extension for external access
|
||||
CleveRoids.Compatibility_pfUI = Extension
|
||||
|
||||
-- Initial compatibility check
|
||||
Extension.SetupCompatibility()
|
||||
end
|
||||
|
||||
@@ -2250,7 +2250,7 @@ function CleveRoids.OnUpdate(self)
|
||||
end
|
||||
|
||||
for guid,cast in pairs(CleveRoids.spell_tracking) do
|
||||
if time > cast.expires then
|
||||
if cast.expires and time > cast.expires then
|
||||
CleveRoids.spell_tracking[guid] = nil
|
||||
end
|
||||
end
|
||||
@@ -3113,12 +3113,30 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
if b then val = b else val = "" end
|
||||
if c then val2 = c else val2 = "" end
|
||||
|
||||
-- No command: show current value
|
||||
-- No command: show current value and available commands
|
||||
if cmd == "" then
|
||||
CleveRoids.Print("Current Settings:")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("realtime (force fast updates, CPU intensive) = " .. CleveRoidMacros.realtime .. " (Default: 0)")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("refresh (updates per second) = " .. CleveRoidMacros.refresh .. " (Default: 5)")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("debug (show learning messages) = " .. (CleveRoids.debug and "1" or "0") .. " (Default: 0)")
|
||||
DEFAULT_CHAT_FRAME:AddMessage(" ")
|
||||
CleveRoids.Print("Available Commands:")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid realtime 0 or 1 - Force realtime updates")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid refresh X - Set refresh rate (1-10 updates/sec)")
|
||||
if CleveRoids.hasSuperwow then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid learn <spellID> <duration> - Manually set spell duration")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid forget <spellID|all> - Forget learned duration(s)")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid debug [0|1] - Toggle learning debug messages")
|
||||
end
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Immunity Tracking:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid listimmune [school] - List immunity data')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid addimmune "<NPC>" <school> [buff] - Add immunity')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid removeimmune "<NPC>" <school> - Remove immunity')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid clearimmune [school] - Clear immunity data')
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Combo Point Tracking:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid combotrack - Show combo point tracking info')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid comboclear - Clear combo tracking data')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid combolearn - Show learned combo durations (per CP)')
|
||||
return
|
||||
end
|
||||
|
||||
@@ -3268,6 +3286,39 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
return
|
||||
end
|
||||
|
||||
-- combotrack (show combo point tracking info)
|
||||
if cmd == "combotrack" or cmd == "combo" then
|
||||
CleveRoids.ShowComboTracking()
|
||||
return
|
||||
end
|
||||
|
||||
-- comboclear (clear combo tracking data)
|
||||
if cmd == "comboclear" then
|
||||
CleveRoids.ComboPointTracking = {}
|
||||
CleveRoids.ComboPointTracking.byID = {}
|
||||
CleveRoids.Print("Combo point tracking data cleared")
|
||||
return
|
||||
end
|
||||
|
||||
-- combolearn (show learned combo durations)
|
||||
if cmd == "combolearn" or cmd == "combodurations" then
|
||||
CleveRoids.Print("=== Learned Combo Durations ===")
|
||||
if not CleveRoids_ComboDurations or not next(CleveRoids_ComboDurations) then
|
||||
CleveRoids.Print("No learned combo durations yet. Cast finishers and let them expire!")
|
||||
else
|
||||
for spellID, cpData in pairs(CleveRoids_ComboDurations) do
|
||||
local spellName = SpellInfo(spellID) or ("Spell " .. spellID)
|
||||
CleveRoids.Print(spellName .. " (ID:" .. spellID .. "):")
|
||||
for cp = 1, 5 do
|
||||
if cpData[cp] then
|
||||
CleveRoids.Print(" " .. cp .. " CP = " .. cpData[cp] .. "s")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Unknown command fallback
|
||||
CleveRoids.Print("Usage:")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid - Show current settings")
|
||||
@@ -3283,6 +3334,10 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid addimmune "<NPC>" <school> [buff] - Add immunity')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid removeimmune "<NPC>" <school> - Remove immunity')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid clearimmune [school] - Clear immunity data')
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Combo Point Tracking:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid combotrack - Show combo point tracking info')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid comboclear - Clear combo tracking data')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid combolearn - Show learned combo durations (per CP)')
|
||||
end
|
||||
|
||||
SLASH_CLEAREQUIPQUEUE1 = "/clearequipqueue"
|
||||
|
||||
@@ -31,10 +31,13 @@ Check slash command and all conditional lists for new usages!
|
||||
* `/cleveroid refresh X` - Set refresh rate (1 to 10 updates per second. Default: 5)
|
||||
* `/cleveroid learn <spellID> <duration>` - Manually set spell duration in seconds
|
||||
* `/cleveroid forget <spellID|all>` - Forget learned spell duration(s)
|
||||
* `/cleveroid listimmune [school]` - List all or specific school immunities
|
||||
* `/cleveroid addimmune "<NPC>" <school> [buff]` - Add manual immunity
|
||||
* `/cleveroid debug [0|1]` - Toggle learning debug messages
|
||||
* `/cleveroid listimmune [school]` - List all or specific school immunities
|
||||
* `/cleveroid addimmune "<NPC>" <school> [buff]` - Add manual immunity
|
||||
* `/cleveroid removeimmune "<NPC>" <school>` - Remove immunity
|
||||
* `/cleveroid clearimmune [school]` - Clear data
|
||||
* `/cleveroid clearimmune [school]` - Clear immunity data
|
||||
* `/cleveroid combotrack` - Show combo point tracking info (Rip, Rupture, Kidney Shot)
|
||||
* `/cleveroid comboclear` - Clear combo tracking data
|
||||
|
||||
---
|
||||
|
||||
@@ -171,6 +174,25 @@ The system includes pre-configured durations for 329+ debuffs across all classes
|
||||
- **Paladin:** Judgements, Hammer of Justice, etc.
|
||||
- **Shaman:** Flame Shock, Frost Shock, etc.
|
||||
|
||||
### Combo Point Scaling
|
||||
The addon automatically tracks combo point finishers that scale duration with combo points:
|
||||
- **Rogue Rupture** (all ranks): 8s base + 2s per combo point (8s @ 1 CP, 16s @ 5 CP)
|
||||
- **Rogue Kidney Shot**: Rank 1: 1s + 1s per CP, Rank 2: 2s + 1s per CP
|
||||
- **Druid Rip** (all ranks): 12s base + 4s per combo point (12s @ 1 CP, 28s @ 5 CP)
|
||||
|
||||
The system automatically detects combo points at cast time and calculates the correct duration:
|
||||
```lua
|
||||
-- Will show accurate duration based on combo points used
|
||||
/cast [nodebuff:Rip] Rip
|
||||
/cast [debuff:Rip<4] Rip
|
||||
|
||||
-- Rupture duration tracking with combo point awareness
|
||||
/cast [nodebuff:Rupture] Rupture
|
||||
/cast [debuff:Rupture<2] Rupture
|
||||
```
|
||||
|
||||
Use `/cleveroid combotrack` to see recent combo finisher casts and their calculated durations.
|
||||
|
||||
### Technical Details
|
||||
- Uses **UNIT_CASTEVENT** for precise cast detection (only tracks successful hits)
|
||||
- Uses **RAW_COMBATLOG** to detect when debuffs fade
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
## Notes: /cleveroid for settings
|
||||
## Version: 1.3
|
||||
## OptionalDeps: ClassicFocus, FocusFrame, pfUI, SuperMacro, Bongos_ActionBar
|
||||
## SavedVariables: CleveRoidMacros, CleveRoids_LearnedDurations, CleveRoids_AuraTextures, CleveRoids_ImmunityData
|
||||
## SavedVariables: CleveRoidMacros, CleveRoids_LearnedDurations, CleveRoids_AuraTextures, CleveRoids_ImmunityData, CleveRoids_ComboDurations
|
||||
Localization.lua
|
||||
Init.lua
|
||||
Utility.lua
|
||||
@@ -12,6 +12,7 @@ Core.lua
|
||||
Conditionals.lua
|
||||
Console.lua
|
||||
ExtensionsManager.lua
|
||||
ComboPointTracker.lua
|
||||
|
||||
Compatibility\SuperMacro.lua
|
||||
Compatibility\pfUI.lua
|
||||
|
||||
+149
-13
@@ -373,7 +373,7 @@ lib.durations = lib.durations or {
|
||||
[2070] = 35, -- Sap (Rank 2)
|
||||
[11297] = 45, -- Sap (Rank 3)
|
||||
|
||||
[1776] = 4, -- Gouge (Rank 1) - base duration
|
||||
[1776] = 4, -- Gouge (Rank 1) - Scales with talent
|
||||
[1777] = 4, -- Gouge (Rank 2)
|
||||
[8629] = 4, -- Gouge (Rank 3)
|
||||
[11285] = 4, -- Gouge (Rank 4)
|
||||
@@ -718,15 +718,47 @@ lib.learnCastTimers = lib.learnCastTimers or {}
|
||||
|
||||
CleveRoids_LearnedDurations = CleveRoids_LearnedDurations or {}
|
||||
|
||||
function lib:GetDuration(spellID, casterGUID)
|
||||
function lib:GetDuration(spellID, casterGUID, comboPoints)
|
||||
-- Check combo-specific learned durations first if this is a combo spell
|
||||
if comboPoints and CleveRoids_ComboDurations and CleveRoids_ComboDurations[spellID] then
|
||||
local comboDuration = CleveRoids_ComboDurations[spellID][comboPoints]
|
||||
if comboDuration and comboDuration > 0 then
|
||||
if CleveRoids.debug then
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffccccff[DEBUG GetDuration]|r %s (ID:%d) CP:%d -> %ds (from learned combo)",
|
||||
spellName, spellID, comboPoints, comboDuration)
|
||||
)
|
||||
end
|
||||
return comboDuration
|
||||
end
|
||||
end
|
||||
|
||||
-- Check caster-specific learned durations
|
||||
if casterGUID and CleveRoids_LearnedDurations[spellID] then
|
||||
local learned = CleveRoids_LearnedDurations[spellID][casterGUID]
|
||||
if learned and learned > 0 then
|
||||
if CleveRoids.debug then
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffccccff[DEBUG GetDuration]|r %s (ID:%d) -> %ds (from learned caster)",
|
||||
spellName, spellID, learned)
|
||||
)
|
||||
end
|
||||
return learned
|
||||
end
|
||||
end
|
||||
|
||||
return self.durations[spellID] or 0
|
||||
-- Fall back to static database
|
||||
local staticDur = self.durations[spellID] or 0
|
||||
if CleveRoids.debug and staticDur > 0 then
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffccccff[DEBUG GetDuration]|r %s (ID:%d) -> %ds (from static DB)",
|
||||
spellName, spellID, staticDur)
|
||||
)
|
||||
end
|
||||
return staticDur
|
||||
end
|
||||
|
||||
function lib:AddEffect(guid, unitName, spellID, duration, stacks, caster)
|
||||
@@ -746,6 +778,15 @@ function lib:AddEffect(guid, unitName, spellID, duration, stacks, caster)
|
||||
rec.caster = caster
|
||||
|
||||
lib.objects[guid][spellID] = rec
|
||||
|
||||
-- DEBUG: Show what we stored
|
||||
if CleveRoids.debug then
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ffff[DEBUG AddEffect]|r %s (ID:%d) stored duration:%ds on %s",
|
||||
spellName, spellID, duration, unitName or "Unknown")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function lib:UnitDebuff(unit, id)
|
||||
@@ -756,7 +797,7 @@ function lib:UnitDebuff(unit, id)
|
||||
|
||||
if not texture or not spellID then
|
||||
texture, stacks, spellID = UnitBuff(unit, id)
|
||||
-- Only accept buffs that are known debuffs (either static or learned durations)
|
||||
-- Only accept buffs that are known debuffs (either static or learned durations, including combo durations)
|
||||
if texture and spellID and lib:GetDuration(spellID) <= 0 then
|
||||
return nil
|
||||
end
|
||||
@@ -797,6 +838,25 @@ local function SeedUnit(unit)
|
||||
local duration = lib:GetDuration(spellID)
|
||||
if duration > 0 then
|
||||
if not (lib.objects[guid] and lib.objects[guid][spellID]) then
|
||||
-- For combo spells, try to use the highest learned duration as a fallback
|
||||
if CleveRoids.IsComboScalingSpellID and CleveRoids.IsComboScalingSpellID(spellID) and
|
||||
CleveRoids_ComboDurations and CleveRoids_ComboDurations[spellID] then
|
||||
-- Use the longest learned duration (assume 5 CP)
|
||||
for cp = 5, 1, -1 do
|
||||
if CleveRoids_ComboDurations[spellID][cp] then
|
||||
duration = CleveRoids_ComboDurations[spellID][cp]
|
||||
if CleveRoids.debug then
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffaaff00[DEBUG SeedUnit Debuff]|r %s (ID:%d) using learned %dCP duration:%ds",
|
||||
spellName, spellID, cp, duration)
|
||||
)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
duration = duration or lib:GetDuration(spellID)
|
||||
lib:AddEffect(guid, unitName, spellID, duration, stacks)
|
||||
end
|
||||
end
|
||||
@@ -811,6 +871,25 @@ local function SeedUnit(unit)
|
||||
local duration = lib:GetDuration(spellID)
|
||||
if duration > 0 then
|
||||
if not (lib.objects[guid] and lib.objects[guid][spellID]) then
|
||||
-- For combo spells, try to use the highest learned duration as a fallback
|
||||
if CleveRoids.IsComboScalingSpellID and CleveRoids.IsComboScalingSpellID(spellID) and
|
||||
CleveRoids_ComboDurations and CleveRoids_ComboDurations[spellID] then
|
||||
-- Use the longest learned duration (assume 5 CP)
|
||||
for cp = 5, 1, -1 do
|
||||
if CleveRoids_ComboDurations[spellID][cp] then
|
||||
duration = CleveRoids_ComboDurations[spellID][cp]
|
||||
if CleveRoids.debug then
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffaaff00[DEBUG SeedUnit Buff]|r %s (ID:%d) using learned %dCP duration:%ds",
|
||||
spellName, spellID, cp, duration)
|
||||
)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
duration = duration or lib:GetDuration(spellID)
|
||||
lib:AddEffect(guid, unitName, spellID, duration, stacks)
|
||||
end
|
||||
end
|
||||
@@ -843,9 +922,33 @@ ev:SetScript("OnEvent", function()
|
||||
local _, playerGUID = UnitExists("player")
|
||||
if casterGUID == playerGUID and targetGUID then
|
||||
|
||||
local duration = lib:GetDuration(spellID, casterGUID)
|
||||
-- Check if this is a combo point scaling spell first
|
||||
local duration = nil
|
||||
local comboPoints = nil
|
||||
if CleveRoids.TrackComboPointCastByID then
|
||||
duration = CleveRoids.TrackComboPointCastByID(spellID, targetGUID)
|
||||
-- Get combo points used from tracking
|
||||
if CleveRoids.ComboPointTracking and CleveRoids.ComboPointTracking.byID and
|
||||
CleveRoids.ComboPointTracking.byID[spellID] then
|
||||
comboPoints = CleveRoids.ComboPointTracking.byID[spellID].combo_points
|
||||
end
|
||||
end
|
||||
|
||||
if duration > 0 then
|
||||
-- If not a combo scaling spell, use normal duration lookup
|
||||
if not duration then
|
||||
duration = lib:GetDuration(spellID, casterGUID)
|
||||
end
|
||||
|
||||
-- DEBUG: Show what duration we calculated
|
||||
if CleveRoids.debug and duration then
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffff00ff[DEBUG CAST]|r %s (ID:%d) CP:%s duration:%ds",
|
||||
spellName, spellID, tostring(comboPoints or "nil"), duration)
|
||||
)
|
||||
end
|
||||
|
||||
if duration and duration > 0 then
|
||||
local targetName = lib.guidToName[targetGUID]
|
||||
if not targetName then
|
||||
local _, currentTargetGUID = UnitExists("target")
|
||||
@@ -858,6 +961,22 @@ ev:SetScript("OnEvent", function()
|
||||
end
|
||||
lib:AddEffect(targetGUID, targetName, spellID, duration, 0, "player")
|
||||
|
||||
-- Sync combo duration to pfUI if it's loaded
|
||||
if comboPoints and CleveRoids.Compatibility_pfUI and
|
||||
CleveRoids.Compatibility_pfUI.SyncComboDurationToPfUI then
|
||||
CleveRoids.Compatibility_pfUI.SyncComboDurationToPfUI(targetGUID, spellID, duration)
|
||||
end
|
||||
|
||||
-- ALWAYS set up learning for combo spells (even if we have calculated duration)
|
||||
if comboPoints then
|
||||
lib.learnCastTimers[targetGUID] = lib.learnCastTimers[targetGUID] or {}
|
||||
lib.learnCastTimers[targetGUID][spellID] = {
|
||||
start = GetTime(),
|
||||
caster = casterGUID,
|
||||
comboPoints = comboPoints -- Store CP count for learning
|
||||
}
|
||||
end
|
||||
|
||||
else
|
||||
lib.learnCastTimers[targetGUID] = lib.learnCastTimers[targetGUID] or {}
|
||||
lib.learnCastTimers[targetGUID][spellID] = {
|
||||
@@ -912,14 +1031,31 @@ evLearn:SetScript("OnEvent", function()
|
||||
local casterGUID = lib.learnCastTimers[targetGUID][spellID].caster
|
||||
local actualDuration = timestamp - castTime
|
||||
|
||||
CleveRoids_LearnedDurations[spellID] = CleveRoids_LearnedDurations[spellID] or {}
|
||||
CleveRoids_LearnedDurations[spellID][casterGUID] = floor(actualDuration + 0.5)
|
||||
-- Check if this is a combo point spell - if so, learn it with combo point context
|
||||
local comboPoints = lib.learnCastTimers[targetGUID][spellID].comboPoints
|
||||
if comboPoints and CleveRoids.IsComboScalingSpellID and CleveRoids.IsComboScalingSpellID(spellID) then
|
||||
-- Learn combo spell duration
|
||||
CleveRoids_ComboDurations = CleveRoids_ComboDurations or {}
|
||||
CleveRoids_ComboDurations[spellID] = CleveRoids_ComboDurations[spellID] or {}
|
||||
CleveRoids_ComboDurations[spellID][comboPoints] = floor(actualDuration + 0.5)
|
||||
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
"|cff4b7dccCleveRoids:|r Learned " .. spellName ..
|
||||
" (ID:" .. spellID .. ") = " .. floor(actualDuration + 0.5) .. "s"
|
||||
)
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
"|cff4b7dccCleveRoids:|r Learned combo spell " .. spellName ..
|
||||
" (ID:" .. spellID .. ") at " .. comboPoints .. " CP = " .. floor(actualDuration + 0.5) .. "s"
|
||||
)
|
||||
end
|
||||
else
|
||||
-- Learn normal spell duration
|
||||
CleveRoids_LearnedDurations[spellID] = CleveRoids_LearnedDurations[spellID] or {}
|
||||
CleveRoids_LearnedDurations[spellID][casterGUID] = floor(actualDuration + 0.5)
|
||||
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
"|cff4b7dccCleveRoids:|r Learned " .. spellName ..
|
||||
" (ID:" .. spellID .. ") = " .. floor(actualDuration + 0.5) .. "s"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
lib.learnCastTimers[targetGUID][spellID] = nil
|
||||
|
||||
Reference in New Issue
Block a user