Merge pull request #24 from jrc13245/claude/improve-combodurations-01GHh5y6dXtxNhoizDK8bSw3

Improve combo point duration tracking system
This commit is contained in:
Torio
2025-11-16 10:33:43 -05:00
committed by GitHub
4 changed files with 184 additions and 57 deletions
+102 -45
View File
@@ -9,42 +9,40 @@ local CleveRoids = _G.CleveRoids or {}
-- Initialize combo point tracking table
CleveRoids.ComboPointTracking = CleveRoids.ComboPointTracking or {}
CleveRoids.spell_tracking = CleveRoids.spell_tracking or {}
-- Define spells that scale with combo points and their duration formulas
-- 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 = 12, increment = 4, name = "Rip" }, -- Rank 1
[9492] = { base = 12, increment = 4, name = "Rip" }, -- Rank 2
[9493] = { base = 12, increment = 4, name = "Rip" }, -- Rank 3
[9752] = { base = 12, increment = 4, name = "Rip" }, -- Rank 4
[9894] = { base = 12, increment = 4, name = "Rip" }, -- Rank 5
[9896] = { base = 12, increment = 4, name = "Rip" }, -- Rank 6
}
-- Legacy name-based table for backwards compatibility
CleveRoids.ComboScalingSpells = {
-- Rupture (all ranks): 8 sec base, +2 sec per additional combo point
["Rupture"] = {
base_duration = 8,
increment = 2,
all_ranks = true
},
-- Kidney Shot Rank 1: 1 sec base, +1 sec per additional combo point
["Kidney Shot(Rank 1)"] = {
base_duration = 1,
increment = 1
},
-- Kidney Shot Rank 2: 2 sec base, +1 sec per additional combo point
["Kidney Shot(Rank 2)"] = {
base_duration = 2,
increment = 1
},
-- Kidney Shot (generic for all ranks if rank not specified)
["Kidney Shot"] = {
base_duration = 1, -- Default to rank 1 if rank unknown
increment = 1,
check_rank = true
},
-- Rip (all ranks): 10 sec base, +2 sec per additional combo point
["Rip"] = {
base_duration = 10,
increment = 2,
all_ranks = true
}
["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 },
["Kidney Shot"] = { base_duration = 1, increment = 1, check_rank = true },
["Rip"] = { base_duration = 12, increment = 4, all_ranks = true }
}
-- Function to get current combo points
@@ -118,23 +116,45 @@ end
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
-- Function to track combo points when casting
-- 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: Calculate duration by spell ID and combo points
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
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)
-- Store the tracking data
CleveRoids.ComboPointTracking[spellName] = {
combo_points = comboPoints,
@@ -142,23 +162,60 @@ function CleveRoids.TrackComboPointCast(spellName)
cast_time = GetTime(),
target = UnitName("target") or "Unknown"
}
-- 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 = GetTime()
-- Debug output (remove in production)
if CleveRoids.Debug then
CleveRoids.Print(string.format("ComboTrack: %s cast with %d combo points, duration: %d seconds",
spellName, comboPoints, duration))
-- 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
local comboPoints = CleveRoids.GetComboPoints()
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
-- Hook into the existing DoCast function
local Extension = CleveRoids.RegisterExtension("ComboPointTracker")
+25
View File
@@ -3268,6 +3268,28 @@ SlashCmdList["CLEVEROID"] = function(msg)
return
end
-- combotrack (show combo point tracking info)
if cmd == "combotrack" or cmd == "combo" then
if CleveRoids.ShowComboTracking then
CleveRoids.ShowComboTracking()
else
CleveRoids.Print("Combo point tracking not available")
end
return
end
-- comboclear (clear combo tracking data)
if cmd == "comboclear" then
if CleveRoids.ComboPointTracking then
CleveRoids.ComboPointTracking = {}
CleveRoids.ComboPointTracking.byID = {}
CleveRoids.Print("Combo point tracking data cleared")
else
CleveRoids.Print("Combo point tracking not available")
end
return
end
-- Unknown command fallback
CleveRoids.Print("Usage:")
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid - Show current settings")
@@ -3283,6 +3305,9 @@ 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')
end
SLASH_CLEAREQUIPQUEUE1 = "/clearequipqueue"
+25 -3
View File
@@ -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
+32 -9
View File
@@ -836,9 +836,18 @@ 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
if CleveRoids.TrackComboPointCastByID then
duration = CleveRoids.TrackComboPointCastByID(spellID, targetGUID)
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
if duration and duration > 0 then
local targetName = lib.guidToName[targetGUID]
if not targetName then
local _, currentTargetGUID = UnitExists("target")
@@ -905,14 +914,28 @@ 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 isComboSpell = false
if CleveRoids.IsComboScalingSpellID and CleveRoids.IsComboScalingSpellID(spellID) then
isComboSpell = true
if CleveRoids.debug then
local comboData = CleveRoids.ComboPointTracking.byID and CleveRoids.ComboPointTracking.byID[spellID]
local cpUsed = comboData and comboData.combo_points or "?"
DEFAULT_CHAT_FRAME:AddMessage(
"|cff4b7dccCleveRoids:|r Learned combo spell " .. spellName ..
" (ID:" .. spellID .. ") with " .. cpUsed .. " CP = " .. floor(actualDuration + 0.5) .. "s"
)
end
else
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"
)
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