mirror of
https://github.com/brues-code/SuperCleveRoidMacros.git
synced 2026-09-16 03:38:00 +00:00
revert multi target tracker
This commit is contained in:
+19
-1
@@ -574,7 +574,25 @@ function CleveRoids.ShowComboTracking()
|
||||
end
|
||||
end
|
||||
|
||||
-- Combo commands now consolidated under /cleveroid combotrack, comboclear, combodebug
|
||||
-- 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
|
||||
|
||||
+13
-259
@@ -4815,31 +4815,6 @@ CleveRoids.MULTISCAN_PRIORITIES = {
|
||||
triangle = 4, diamond = 3, circle = 2, star = 1,
|
||||
}
|
||||
|
||||
-- Multiscan options (Cursive-inspired filters that can combine with any priority)
|
||||
-- Usage: [multiscan:priority,option1,option2,minhp=1000,refreshtime=3,name="Mob Name"]
|
||||
-- Options:
|
||||
-- allowooc - Allow out of combat targets (default: only in-combat)
|
||||
-- priotarget - Always prioritize current target first
|
||||
-- ignoretarget - Ignore current target when scanning
|
||||
-- playeronly - Only target players, ignore NPCs
|
||||
-- npconly - Only target NPCs, ignore players
|
||||
-- tracked - Only consider targets in MultiTargetTracker
|
||||
-- minhp=X - Minimum HP threshold (raw value)
|
||||
-- maxhp=X - Maximum HP threshold (raw value)
|
||||
-- minhppct=X - Minimum HP percentage (0-100)
|
||||
-- maxhppct=X - Maximum HP percentage (0-100)
|
||||
-- refreshtime=X - Only target if debuff has less than X seconds remaining (for DoT refresh)
|
||||
-- name=X - Filter by name (partial match, use quotes for spaces: name="Mob Name")
|
||||
-- noname=X - Exclude targets with name containing X
|
||||
CleveRoids.MULTISCAN_OPTIONS = {
|
||||
allowooc = true,
|
||||
priotarget = true,
|
||||
ignoretarget = true,
|
||||
playeronly = true,
|
||||
npconly = true,
|
||||
tracked = true,
|
||||
}
|
||||
|
||||
-- Static conditionals that don't depend on target (checked before scanning)
|
||||
CleveRoids.STATIC_CONDITIONALS = {
|
||||
group = true, nogroup = true,
|
||||
@@ -4866,30 +4841,19 @@ CleveRoids.STATIC_CONDITIONALS = {
|
||||
--- @param priority string Priority type (e.g., "nearest", "highesthp")
|
||||
--- @param currentTargetGuid string|nil GUID of player's current target (exempt from combat check)
|
||||
--- @param specifiedUnitGuid string|nil GUID of @unit specified in macro (also exempt from combat check)
|
||||
--- @param options table|nil Parsed multiscan options
|
||||
--- @param conditionals table|nil Full conditionals for options checking
|
||||
--- @return number|nil Score (lower = better) or nil if invalid candidate
|
||||
function CleveRoids.GetMultiscanScore(unit, priority, currentTargetGuid, specifiedUnitGuid, options, conditionals)
|
||||
function CleveRoids.GetMultiscanScore(unit, priority, currentTargetGuid, specifiedUnitGuid)
|
||||
if not unit or not UnitExists(unit) then return nil end
|
||||
if UnitIsDeadOrGhost(unit) then return nil end
|
||||
|
||||
-- Must be attackable
|
||||
if not UnitCanAttack("player", unit) then return nil end
|
||||
|
||||
-- Combat check: must be in combat with player, UNLESS it's current target OR specified @unit
|
||||
local _, unitGuid = UnitExists(unit)
|
||||
local isCurrentTarget = currentTargetGuid and unitGuid == currentTargetGuid
|
||||
local isSpecifiedUnit = specifiedUnitGuid and unitGuid == specifiedUnitGuid
|
||||
|
||||
-- Combat check: must be in combat with player, UNLESS:
|
||||
-- - it's current target OR specified @unit
|
||||
-- - OR allowooc option is set
|
||||
local allowOOC = options and options.allowooc
|
||||
if not allowOOC and not isCurrentTarget and not isSpecifiedUnit and not UnitAffectingCombat(unit) then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Check additional options filters
|
||||
if options and not CleveRoids.CheckMultiscanOptions(unit, unitGuid, options, conditionals, currentTargetGuid) then
|
||||
if not isCurrentTarget and not isSpecifiedUnit and not UnitAffectingCombat(unit) then
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -4971,212 +4935,6 @@ function CleveRoids.CheckStaticConditionals(conditionals)
|
||||
return true
|
||||
end
|
||||
|
||||
--- Parse multiscan options from the conditional value
|
||||
--- @param multiscanValue string|table The raw multiscan conditional value
|
||||
--- @return string priority, table options
|
||||
function CleveRoids.ParseMultiscanOptions(multiscanValue)
|
||||
local options = {
|
||||
allowooc = false,
|
||||
priotarget = false,
|
||||
ignoretarget = false,
|
||||
playeronly = false,
|
||||
npconly = false,
|
||||
tracked = false,
|
||||
minhp = nil,
|
||||
maxhp = nil,
|
||||
minhppct = nil,
|
||||
maxhppct = nil,
|
||||
refreshtime = nil,
|
||||
name = nil,
|
||||
noname = nil,
|
||||
}
|
||||
|
||||
local priority = nil
|
||||
local values = {}
|
||||
|
||||
-- Collect all values
|
||||
if type(multiscanValue) == "table" then
|
||||
for i = 1, table.getn(multiscanValue) do
|
||||
table.insert(values, multiscanValue[i])
|
||||
end
|
||||
elseif type(multiscanValue) == "string" then
|
||||
-- Single value, might contain commas? No, conditionals system splits by /
|
||||
-- The value is just the priority in this case
|
||||
table.insert(values, multiscanValue)
|
||||
end
|
||||
|
||||
-- First value is always the priority
|
||||
if table.getn(values) > 0 then
|
||||
priority = string.lower(CleveRoids.Trim(values[1]))
|
||||
end
|
||||
|
||||
-- Remaining values are options
|
||||
for i = 2, table.getn(values) do
|
||||
local opt = CleveRoids.Trim(values[i])
|
||||
local optLower = string.lower(opt)
|
||||
|
||||
-- Check for key=value options
|
||||
local eqStart, eqEnd = string.find(optLower, "=")
|
||||
if eqStart then
|
||||
local key = string.sub(optLower, 1, eqStart - 1)
|
||||
local value = string.sub(opt, eqEnd + 1) -- Keep original case for name
|
||||
|
||||
-- Remove quotes from value if present
|
||||
if string.sub(value, 1, 1) == '"' and string.sub(value, -1) == '"' then
|
||||
value = string.sub(value, 2, -2)
|
||||
end
|
||||
|
||||
if key == "minhp" then
|
||||
options.minhp = tonumber(value)
|
||||
elseif key == "maxhp" then
|
||||
options.maxhp = tonumber(value)
|
||||
elseif key == "minhppct" then
|
||||
options.minhppct = tonumber(value)
|
||||
elseif key == "maxhppct" then
|
||||
options.maxhppct = tonumber(value)
|
||||
elseif key == "refreshtime" then
|
||||
options.refreshtime = tonumber(value)
|
||||
elseif key == "name" then
|
||||
options.name = value
|
||||
elseif key == "noname" then
|
||||
options.noname = value
|
||||
end
|
||||
else
|
||||
-- Boolean flag options
|
||||
if optLower == "allowooc" then
|
||||
options.allowooc = true
|
||||
elseif optLower == "priotarget" then
|
||||
options.priotarget = true
|
||||
elseif optLower == "ignoretarget" then
|
||||
options.ignoretarget = true
|
||||
elseif optLower == "playeronly" then
|
||||
options.playeronly = true
|
||||
elseif optLower == "npconly" then
|
||||
options.npconly = true
|
||||
elseif optLower == "tracked" then
|
||||
options.tracked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return priority, options
|
||||
end
|
||||
|
||||
--- Check if a unit passes multiscan options filters
|
||||
--- @param unit string Unit token
|
||||
--- @param guid string Unit GUID
|
||||
--- @param options table Parsed options
|
||||
--- @param conditionals table Full conditionals table (for refreshtime spell check)
|
||||
--- @param currentTargetGuid string|nil Current target GUID
|
||||
--- @return boolean passes
|
||||
function CleveRoids.CheckMultiscanOptions(unit, guid, options, conditionals, currentTargetGuid)
|
||||
-- ignoretarget: Skip current target
|
||||
if options.ignoretarget and currentTargetGuid and guid == currentTargetGuid then
|
||||
return false
|
||||
end
|
||||
|
||||
-- playeronly: Only players
|
||||
if options.playeronly and not UnitIsPlayer(unit) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- npconly: Only NPCs
|
||||
if options.npconly and UnitIsPlayer(unit) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- tracked: Only tracked targets
|
||||
if options.tracked then
|
||||
local tracker = CleveRoids.MultiTargetTracker
|
||||
if tracker and tracker.IsTracked then
|
||||
if not tracker.IsTracked(guid) then
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false -- Tracker not available
|
||||
end
|
||||
end
|
||||
|
||||
-- minhp: Minimum raw HP
|
||||
if options.minhp then
|
||||
local hp = UnitHealth(unit)
|
||||
if hp < options.minhp then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- maxhp: Maximum raw HP
|
||||
if options.maxhp then
|
||||
local hp = UnitHealth(unit)
|
||||
if hp > options.maxhp then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- minhppct: Minimum HP percentage
|
||||
if options.minhppct then
|
||||
local maxHp = UnitHealthMax(unit)
|
||||
if maxHp > 0 then
|
||||
local pct = (UnitHealth(unit) / maxHp) * 100
|
||||
if pct < options.minhppct then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- maxhppct: Maximum HP percentage
|
||||
if options.maxhppct then
|
||||
local maxHp = UnitHealthMax(unit)
|
||||
if maxHp > 0 then
|
||||
local pct = (UnitHealth(unit) / maxHp) * 100
|
||||
if pct > options.maxhppct then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- name: Filter by name (partial match)
|
||||
if options.name then
|
||||
local unitName = UnitName(unit) or ""
|
||||
if not string.find(string.lower(unitName), string.lower(options.name)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- noname: Exclude by name (partial match)
|
||||
if options.noname then
|
||||
local unitName = UnitName(unit) or ""
|
||||
if string.find(string.lower(unitName), string.lower(options.noname)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- refreshtime: Only target if debuff expires within X seconds
|
||||
-- Uses the spell from conditionals.action (the spell being cast)
|
||||
if options.refreshtime then
|
||||
local tracker = CleveRoids.MultiTargetTracker
|
||||
if tracker and tracker.GetActiveDebuffs then
|
||||
local debuffs, count = tracker.GetActiveDebuffs(guid)
|
||||
if debuffs and count > 0 then
|
||||
-- Check if any debuff has more than refreshtime remaining
|
||||
local hasLongDebuff = false
|
||||
for i = 1, count do
|
||||
if debuffs[i].remaining > options.refreshtime then
|
||||
hasLongDebuff = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if hasLongDebuff then
|
||||
return false -- Has debuff with too much time remaining
|
||||
end
|
||||
end
|
||||
-- No debuffs or all debuffs are expiring soon - pass
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Main multiscan resolution function
|
||||
--- Scans enemies using UnitXP, finds best target matching priority and conditionals
|
||||
--- @param conditionals table The conditionals table containing multiscan value
|
||||
@@ -5188,10 +4946,16 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Parse priority and options from conditionals.multiscan
|
||||
local priority, options = CleveRoids.ParseMultiscanOptions(conditionals.multiscan)
|
||||
-- Parse priority from conditionals.multiscan
|
||||
local priority = nil
|
||||
if type(conditionals.multiscan) == "table" then
|
||||
priority = conditionals.multiscan[1]
|
||||
elseif type(conditionals.multiscan) == "string" then
|
||||
priority = conditionals.multiscan
|
||||
end
|
||||
|
||||
if not priority then return nil end
|
||||
priority = string.lower(CleveRoids.Trim(priority))
|
||||
|
||||
-- Validate priority type
|
||||
local priorityType = CleveRoids.MULTISCAN_PRIORITIES[priority]
|
||||
@@ -5331,7 +5095,7 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
end
|
||||
end
|
||||
|
||||
local score = CleveRoids.GetMultiscanScore(unit, priorityType, currentTargetGuid, specifiedUnitGuid, options, conditionals)
|
||||
local score = CleveRoids.GetMultiscanScore(unit, priorityType, currentTargetGuid, specifiedUnitGuid)
|
||||
if not score then return end
|
||||
|
||||
-- Validate against target-dependent conditionals
|
||||
@@ -5340,18 +5104,8 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
end
|
||||
end
|
||||
|
||||
-- Handle priotarget option: always check current target first
|
||||
if options.priotarget and currentTargetGuid then
|
||||
evaluateCandidate("target")
|
||||
-- If current target is valid, return it immediately
|
||||
if table.getn(candidates) > 0 then
|
||||
return candidates[1].guid
|
||||
end
|
||||
end
|
||||
|
||||
-- Always consider current target (exempt from combat check via GetMultiscanScore)
|
||||
-- Skip if priotarget already checked it
|
||||
if currentTargetGuid and not options.priotarget then
|
||||
if currentTargetGuid then
|
||||
evaluateCandidate("target")
|
||||
end
|
||||
|
||||
|
||||
-12
@@ -51,18 +51,6 @@ SlashCmdList.EQUIPMH = CleveRoids.DoEquipMainhand
|
||||
SLASH_EQUIPOH1 = "/equipoh"
|
||||
SlashCmdList.EQUIPOH = CleveRoids.DoEquipOffhand
|
||||
|
||||
SLASH_EQSLOT111 = "/equip11"
|
||||
SlashCmdList.EQSLOT11 = CleveRoids.DoEquipRing1
|
||||
|
||||
SLASH_EQSLOT121 = "/equip12"
|
||||
SlashCmdList.EQSLOT12 = CleveRoids.DoEquipRing2
|
||||
|
||||
SLASH_EQSLOT131 = "/equip13"
|
||||
SlashCmdList.EQSLOT13 = CleveRoids.DoEquipTrinket1
|
||||
|
||||
SLASH_EQSLOT141 = "/equip14"
|
||||
SlashCmdList.EQSLOT14 = CleveRoids.DoEquipTrinket2
|
||||
|
||||
SLASH_UNSHIFT1 = "/unshift"
|
||||
|
||||
SlashCmdList.UNSHIFT = CleveRoids.DoUnshift
|
||||
|
||||
@@ -2794,9 +2794,9 @@ function CleveRoids.DoUse(msg)
|
||||
return false
|
||||
end
|
||||
|
||||
function CleveRoids.EquipBagItem(msg, slotOrOffhand)
|
||||
function CleveRoids.EquipBagItem(msg, offhand)
|
||||
if CleveRoids.equipDebugLog then
|
||||
CleveRoids.Print("|cff00ffff[EquipLog] EquipBagItem called: '" .. tostring(msg) .. "' slot=" .. tostring(slotOrOffhand) .. "|r")
|
||||
CleveRoids.Print("|cff00ffff[EquipLog] EquipBagItem called: '" .. tostring(msg) .. "' offhand=" .. tostring(offhand) .. "|r")
|
||||
end
|
||||
|
||||
if CleveRoids.equipInProgress then
|
||||
@@ -2806,13 +2806,7 @@ function CleveRoids.EquipBagItem(msg, slotOrOffhand)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Accept slot number directly, or boolean for backward compatibility (false=16/MH, true=17/OH)
|
||||
local invslot
|
||||
if type(slotOrOffhand) == "number" then
|
||||
invslot = slotOrOffhand
|
||||
else
|
||||
invslot = slotOrOffhand and 17 or 16
|
||||
end
|
||||
local invslot = offhand and 17 or 16
|
||||
local API = CleveRoids.NampowerAPI
|
||||
|
||||
-- v2.18+: Use native fast lookup for item ID or name
|
||||
@@ -2925,38 +2919,7 @@ function CleveRoids.EquipBagItem(msg, slotOrOffhand)
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if item is already equipped in the paired slot (swap case)
|
||||
-- EquipItemByName doesn't handle swapping equipped items, so we must do it manually
|
||||
-- Paired slots: trinkets (13<->14), weapons (16<->17), rings (11<->12)
|
||||
local pairedSlots = {[13] = 14, [14] = 13, [16] = 17, [17] = 16, [11] = 12, [12] = 11}
|
||||
local checkSlot = pairedSlots[invslot]
|
||||
if checkSlot then
|
||||
local link = GetInventoryItemLink("player", checkSlot)
|
||||
if link then
|
||||
local _, _, slotItemName = string_find(link, "|h%[(.-)%]|h")
|
||||
if slotItemName and string_lower(slotItemName) == string_lower(msg) then
|
||||
-- Found item in paired slot - swap it manually
|
||||
if CleveRoids.equipDebugLog then
|
||||
CleveRoids.Print("|cff00ffff[EquipLog] Swapping from slot " .. checkSlot .. " to slot " .. invslot .. "|r")
|
||||
end
|
||||
ClearCursor()
|
||||
PickupInventoryItem(checkSlot)
|
||||
if CursorHasItem and CursorHasItem() then
|
||||
EquipCursorItem(invslot)
|
||||
ClearCursor()
|
||||
if CleveRoids.Items then
|
||||
CleveRoids.Items[msg] = nil
|
||||
CleveRoids.Items[string_lower(msg)] = nil
|
||||
end
|
||||
InvalidateDisplacedItem()
|
||||
return true
|
||||
end
|
||||
ClearCursor()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- PERFORMANCE: Try EquipItemByName for bag items (fast path)
|
||||
-- PERFORMANCE: Try EquipItemByName FIRST before any lookups
|
||||
-- This is the fastest path - no item lookup, no cursor operations
|
||||
if EquipItemByName then
|
||||
local ok = pcall(EquipItemByName, msg, invslot)
|
||||
@@ -3056,14 +3019,6 @@ local function _equipOffhandAction(msg)
|
||||
return CleveRoids.EquipBagItem(msg, true)
|
||||
end
|
||||
|
||||
local function _equipTrinket1Action(msg)
|
||||
return CleveRoids.EquipBagItem(msg, 13)
|
||||
end
|
||||
|
||||
local function _equipTrinket2Action(msg)
|
||||
return CleveRoids.EquipBagItem(msg, 14)
|
||||
end
|
||||
|
||||
local function _unshiftAction()
|
||||
local currentShapeshiftIndex = CleveRoids.GetCurrentShapeshiftIndex()
|
||||
if currentShapeshiftIndex ~= 0 then
|
||||
@@ -3095,118 +3050,6 @@ function CleveRoids.DoEquipOffhand(msg)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Trinket equip using slot 13 (which works), then swap if needed for slot 14
|
||||
local function DoEquipTrinketSlot13(msg)
|
||||
local action = function(m) return CleveRoids.EquipBagItem(m, 13) end
|
||||
local parts = CleveRoids.splitStringIgnoringQuotes(msg)
|
||||
for i = 1, table.getn(parts) do
|
||||
local v = string.gsub(parts[i], "^%?", "")
|
||||
if CleveRoids.DoWithConditionals(v, action, CleveRoids.FixEmptyTarget, false, action) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- For slot 14: normal API for bag items, manual for already-equipped
|
||||
local function DoEquipTrinketSlot14(msg)
|
||||
local action = function(m)
|
||||
-- Find item location
|
||||
local item = CleveRoids.GetItem(m)
|
||||
if not item then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Item in bags: use normal EquipBagItem
|
||||
if item.bagID and item.slot then
|
||||
return CleveRoids.EquipBagItem(m, 14)
|
||||
end
|
||||
|
||||
-- Item already equipped: manual pickup and swap
|
||||
if item.inventoryID then
|
||||
ClearCursor()
|
||||
PickupInventoryItem(item.inventoryID)
|
||||
if CursorHasItem and CursorHasItem() then
|
||||
EquipCursorItem(14)
|
||||
-- If displaced item on cursor, put it in original slot
|
||||
if CursorHasItem and CursorHasItem() then
|
||||
EquipCursorItem(item.inventoryID)
|
||||
end
|
||||
ClearCursor()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
local parts = CleveRoids.splitStringIgnoringQuotes(msg)
|
||||
for i = 1, table.getn(parts) do
|
||||
local v = string.gsub(parts[i], "^%?", "")
|
||||
if CleveRoids.DoWithConditionals(v, action, CleveRoids.FixEmptyTarget, false, action) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
CleveRoids.DoEquipTrinket1 = function(msg) return DoEquipTrinketSlot13(msg) end
|
||||
CleveRoids.DoEquipTrinket2 = function(msg) return DoEquipTrinketSlot14(msg) end
|
||||
|
||||
-- Ring slot 11: normal equip
|
||||
local function DoEquipRingSlot11(msg)
|
||||
local action = function(m) return CleveRoids.EquipBagItem(m, 11) end
|
||||
local parts = CleveRoids.splitStringIgnoringQuotes(msg)
|
||||
for i = 1, table.getn(parts) do
|
||||
local v = string.gsub(parts[i], "^%?", "")
|
||||
if CleveRoids.DoWithConditionals(v, action, CleveRoids.FixEmptyTarget, false, action) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Ring slot 12: normal API for bag items, manual for already-equipped
|
||||
local function DoEquipRingSlot12(msg)
|
||||
local action = function(m)
|
||||
local item = CleveRoids.GetItem(m)
|
||||
if not item then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Item in bags: use normal EquipBagItem
|
||||
if item.bagID and item.slot then
|
||||
return CleveRoids.EquipBagItem(m, 12)
|
||||
end
|
||||
|
||||
-- Item already equipped: manual pickup and swap
|
||||
if item.inventoryID then
|
||||
ClearCursor()
|
||||
PickupInventoryItem(item.inventoryID)
|
||||
if CursorHasItem and CursorHasItem() then
|
||||
EquipCursorItem(12)
|
||||
if CursorHasItem and CursorHasItem() then
|
||||
EquipCursorItem(item.inventoryID)
|
||||
end
|
||||
ClearCursor()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
local parts = CleveRoids.splitStringIgnoringQuotes(msg)
|
||||
for i = 1, table.getn(parts) do
|
||||
local v = string.gsub(parts[i], "^%?", "")
|
||||
if CleveRoids.DoWithConditionals(v, action, CleveRoids.FixEmptyTarget, false, action) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
CleveRoids.DoEquipRing1 = function(msg) return DoEquipRingSlot11(msg) end
|
||||
CleveRoids.DoEquipRing2 = function(msg) return DoEquipRingSlot12(msg) end
|
||||
|
||||
function CleveRoids.DoUnshift(msg)
|
||||
local handled
|
||||
-- PERFORMANCE: Use numeric iteration to avoid pairs() iterator allocation
|
||||
@@ -4929,7 +4772,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
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)')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid combodebug - Toggle combo tracking debug output')
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Talent Modifiers:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid talenttabs - Show talent tab IDs for your class')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid listtab <tab> - List all talents in a tab with their IDs')
|
||||
@@ -4940,8 +4782,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid testequip <spellID> - Test equipment modifier for a spell')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid equipdebug <item name> - Debug item lookup for /equip')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid equiplog - Toggle real-time equip command logging')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid equipqueue clear - Clear pending equipment queue')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid equipqueue status - Show queue status')
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Reactive Proc Tracking:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid listprocs - Show active reactive ability procs')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid setproc <spell> [duration] - Manually set proc (testing)')
|
||||
@@ -4957,8 +4797,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid slamdebug - Show Slam cast time and clip window calculations')
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Debuff Tracking Debug:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid debuffdebug [spell] - Debug debuff tracking on target')
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Multi-Target Tracker:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid mtt - Show Multi-Target Tracker commands')
|
||||
return
|
||||
end
|
||||
|
||||
@@ -5618,13 +5456,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
return
|
||||
end
|
||||
|
||||
-- combodebug (toggle combo tracking debug)
|
||||
if cmd == "combodebug" then
|
||||
CleveRoids.debug = not CleveRoids.debug
|
||||
CleveRoids.Print("Combo tracking debug: " .. (CleveRoids.debug and "ON" or "OFF"))
|
||||
return
|
||||
end
|
||||
|
||||
-- talenttabs (show talent tab IDs)
|
||||
if cmd == "talenttabs" or cmd == "tabs" then
|
||||
CleveRoids.Print("=== Talent Tabs ===")
|
||||
@@ -6383,96 +6214,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
return
|
||||
end
|
||||
|
||||
-- equipqueue (Equipment Queue management)
|
||||
if cmd == "equipqueue" or cmd == "eq" then
|
||||
if val == "clear" then
|
||||
-- Release all entries back to pool
|
||||
for i = 1, CleveRoids.equipmentQueueLen do
|
||||
local entry = CleveRoids.equipmentQueue[i]
|
||||
if entry then
|
||||
CleveRoids.equipmentQueue[i] = nil
|
||||
-- Return to pool if space available
|
||||
if table.getn(CleveRoids.queueEntryPool) < 10 then
|
||||
entry.item = nil
|
||||
entry.slotName = nil
|
||||
entry.inventoryId = nil
|
||||
table.insert(CleveRoids.queueEntryPool, entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
CleveRoids.equipmentQueueLen = 0
|
||||
if CleveRoids.equipQueueFrame then
|
||||
CleveRoids.equipQueueFrame:Hide()
|
||||
end
|
||||
CleveRoids.Print("Equipment queue cleared")
|
||||
elseif val == "status" then
|
||||
local count = CleveRoids.equipmentQueueLen
|
||||
CleveRoids.Print("Equipment queue has " .. count .. " pending items")
|
||||
for i = 1, count do
|
||||
local entry = CleveRoids.equipmentQueue[i]
|
||||
if entry then
|
||||
local itemName = (entry.item and entry.item.name) or "Unknown"
|
||||
local slotName = entry.slotName or "Unknown"
|
||||
local retries = entry.retries or 0
|
||||
CleveRoids.Print(i .. ". " .. itemName .. " -> " .. slotName .. " (retries: " .. retries .. ")")
|
||||
end
|
||||
end
|
||||
else
|
||||
CleveRoids.Print("Equipment Queue commands:")
|
||||
CleveRoids.Print(" /cleveroid equipqueue clear - Clear pending equipment queue")
|
||||
CleveRoids.Print(" /cleveroid equipqueue status - Show queue status")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- mtt (Multi-Target Tracker)
|
||||
if cmd == "mtt" then
|
||||
local tracker = CleveRoids.MultiTargetTracker
|
||||
if not tracker then
|
||||
CleveRoids.Print("Multi-Target Tracker not loaded!")
|
||||
return
|
||||
end
|
||||
|
||||
if val == "unlock" then
|
||||
tracker.Unlock()
|
||||
elseif val == "lock" then
|
||||
tracker.Lock()
|
||||
elseif val == "show" then
|
||||
tracker.Show()
|
||||
CleveRoids.Print("Multi-Target Tracker: Enabled (will show when tracking)")
|
||||
elseif val == "hide" then
|
||||
tracker.Hide()
|
||||
CleveRoids.Print("Multi-Target Tracker: Disabled (persists across reloads)")
|
||||
elseif val == "toggle" then
|
||||
tracker.Toggle()
|
||||
if tracker.IsDisabled and tracker.IsDisabled() then
|
||||
CleveRoids.Print("Multi-Target Tracker: Disabled (persists across reloads)")
|
||||
else
|
||||
CleveRoids.Print("Multi-Target Tracker: Enabled (will show when tracking)")
|
||||
end
|
||||
elseif val == "clear" then
|
||||
tracker.ClearTargets()
|
||||
elseif val == "reset" then
|
||||
tracker.ResetPosition()
|
||||
elseif val == "debug" then
|
||||
tracker.Debug()
|
||||
elseif val == "dump" then
|
||||
tracker.DumpState()
|
||||
else
|
||||
CleveRoids.Print("Multi-Target Tracker commands:")
|
||||
CleveRoids.Print(" /cleveroid mtt unlock - Show frame for positioning")
|
||||
CleveRoids.Print(" /cleveroid mtt lock - Lock and resume auto-hide")
|
||||
CleveRoids.Print(" /cleveroid mtt show - Enable tracker (persists)")
|
||||
CleveRoids.Print(" /cleveroid mtt hide - Disable tracker (persists)")
|
||||
CleveRoids.Print(" /cleveroid mtt toggle - Toggle enabled state (persists)")
|
||||
CleveRoids.Print(" /cleveroid mtt clear - Clear all tracked targets")
|
||||
CleveRoids.Print(" /cleveroid mtt reset - Reset frame position")
|
||||
CleveRoids.Print(" /cleveroid mtt debug - Toggle debug mode")
|
||||
CleveRoids.Print(" /cleveroid mtt dump - Dump tracking state")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Unknown command fallback
|
||||
CleveRoids.Print("Usage:")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid - Show current settings")
|
||||
@@ -6497,12 +6238,43 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
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)')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid combodebug - Toggle combo tracking debug output')
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Equipment Queue:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid equipqueue clear - Clear pending equipment queue')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid equipqueue status - Show queue status')
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Multi-Target Tracker:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid mtt - Show Multi-Target Tracker commands')
|
||||
end
|
||||
|
||||
-- Equipment queue commands consolidated under /cleveroid equipqueue clear|status
|
||||
SLASH_CLEAREQUIPQUEUE1 = "/clearequipqueue"
|
||||
SlashCmdList.CLEAREQUIPQUEUE = function()
|
||||
-- Release all entries back to pool
|
||||
for i = 1, CleveRoids.equipmentQueueLen do
|
||||
local entry = CleveRoids.equipmentQueue[i]
|
||||
if entry then
|
||||
CleveRoids.equipmentQueue[i] = nil
|
||||
-- Return to pool if space available
|
||||
if table.getn(CleveRoids.queueEntryPool) < 10 then
|
||||
entry.item = nil
|
||||
entry.slotName = nil
|
||||
entry.inventoryId = nil
|
||||
table.insert(CleveRoids.queueEntryPool, entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
CleveRoids.equipmentQueueLen = 0
|
||||
if CleveRoids.equipQueueFrame then
|
||||
CleveRoids.equipQueueFrame:Hide()
|
||||
end
|
||||
CleveRoids.Print("Equipment queue cleared")
|
||||
end
|
||||
|
||||
SLASH_EQUIPQUEUESTATUS1 = "/equipqueuestatus"
|
||||
SlashCmdList.EQUIPQUEUESTATUS = function()
|
||||
local count = CleveRoids.equipmentQueueLen
|
||||
CleveRoids.Print("Equipment queue has " .. count .. " pending items")
|
||||
|
||||
for i = 1, count do
|
||||
local entry = CleveRoids.equipmentQueue[i]
|
||||
if entry then
|
||||
local itemName = (entry.item and entry.item.name) or "Unknown"
|
||||
local slotName = entry.slotName or "Unknown"
|
||||
local retries = entry.retries or 0
|
||||
CleveRoids.Print(i .. ". " .. itemName .. " -> " .. slotName .. " (retries: " .. retries .. ")")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -112,10 +112,6 @@ CleveRoids.dynamicCmds = {
|
||||
["/equip"] = true,
|
||||
["/equipmh"] = true,
|
||||
["/equipoh"] = true,
|
||||
["/equip11"] = true,
|
||||
["/equip12"] = true,
|
||||
["/equip13"] = true,
|
||||
["/equip14"] = true,
|
||||
}
|
||||
|
||||
-- Equipment swap queue system
|
||||
|
||||
@@ -347,52 +347,6 @@ Works with ALL casting methods:
|
||||
|
||||
---
|
||||
|
||||
## Multi-Target Tracker
|
||||
|
||||
Visual UI extension that tracks your debuffs across multiple enemy targets. Displays health bars with debuff icons and timers, styled to match Cursive/ShaguScan.
|
||||
|
||||
### Features
|
||||
- Tracks up to 15 targets simultaneously
|
||||
- Shows health bar, name, raid icon, and debuff timers per target
|
||||
- Automatic cleanup when targets die or leave combat
|
||||
- Only shows YOUR debuffs (class-aware filtering)
|
||||
- Click target rows to target that enemy
|
||||
|
||||
### Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/cleveroid mtt` | Show all MTT commands |
|
||||
| `/cleveroid mtt unlock` | Unlock frame for repositioning |
|
||||
| `/cleveroid mtt lock` | Lock and resume auto-hide |
|
||||
| `/cleveroid mtt show` | Show the tracker frame |
|
||||
| `/cleveroid mtt hide` | Hide the tracker frame |
|
||||
| `/cleveroid mtt toggle` | Toggle frame visibility |
|
||||
| `/cleveroid mtt clear` | Clear all tracked targets |
|
||||
| `/cleveroid mtt reset` | Reset frame position |
|
||||
| `/cleveroid mtt debug` | Toggle debug mode |
|
||||
| `/cleveroid mtt dump` | Dump tracking state |
|
||||
|
||||
### Tracked Debuff Categories
|
||||
|
||||
**AoE Debuffs** (multi-target tracking):
|
||||
|
||||
**Proc/Special Debuffs** (item procs, taunts):
|
||||
|
||||
**Personal Debuffs**:
|
||||
All class-specific DoTs, debuffs, and effects from the debuff timer system are automatically tracked.
|
||||
|
||||
**Shared Debuffs**:
|
||||
Debuffs like Sunder Armor, Faerie Fire, and Judgements are only shown if YOU can cast them (class-aware filtering prevents showing other players' debuffs).
|
||||
|
||||
### Auto-Cleanup Behavior
|
||||
- Dead targets are removed immediately
|
||||
- Targets with no active debuffs are removed when:
|
||||
- The target leaves combat, OR
|
||||
- You leave combat
|
||||
|
||||
---
|
||||
|
||||
## Talent Modifiers
|
||||
|
||||
Automatically applies talent-based duration modifications to debuff tracking.
|
||||
@@ -555,10 +509,6 @@ Default `[noimmune]` checks the debuff school (bleed).
|
||||
| /equip | * | Equip item by name/ID |
|
||||
| /equipmh | * | Equip main hand |
|
||||
| /equipoh | * | Equip off-hand |
|
||||
| /equip11 | * | Equip ring slot 1 |
|
||||
| /equip12 | * | Equip ring slot 2 |
|
||||
| /equip13 | * | Equip trinket slot 1 |
|
||||
| /equip14 | * | Equip trinket slot 2 |
|
||||
| /unshift | * | Cancel shapeshift form |
|
||||
| /cancelaura | | Cancel buff/aura |
|
||||
| /unbuff | | Alias for cancelaura |
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Author: DWG, _brain, Torio, yani9o, Avitasia
|
||||
## Title: [Super]CleveRoidMacros
|
||||
## Notes: /cleveroid for settings
|
||||
## Version: 1.9
|
||||
## Version: 1.8
|
||||
## OptionalDeps: ClassicFocus, FocusFrame, pfUI, SuperMacro, Bongos_ActionBar
|
||||
## SavedVariables: CleveRoidMacros, CleveRoids_LearnedDurations, CleveRoids_AuraTextures, CleveRoids_ImmunityData, CleveRoids_ComboDurations, CleveRoids_SpellSchools
|
||||
Localization.lua
|
||||
@@ -35,4 +35,3 @@ Extensions\Mouseover\ag_UnitFrames.lua
|
||||
|
||||
Extensions\Tooltip\Generic.lua
|
||||
|
||||
Extensions\MultiTargetTracker.lua
|
||||
|
||||
+8
-58
@@ -17,30 +17,13 @@ local tonumber = tonumber
|
||||
local tostring = tostring
|
||||
local GetTime = GetTime
|
||||
|
||||
-- GUID normalization: ensures consistent string format for table keys
|
||||
-- Preserves original format (including 0x prefix) for SuperWoW API compatibility
|
||||
-- GUID normalization: ensure all GUIDs are strings for consistent table key lookups
|
||||
-- In Lua, table["123"] is different from table[123], so we must normalize
|
||||
function CleveRoids.NormalizeGUID(guid)
|
||||
if not guid then return nil end
|
||||
return tostring(guid)
|
||||
end
|
||||
|
||||
-- Compare two GUIDs for equality, handling format differences (0x prefix, case)
|
||||
-- Use this when comparing GUIDs from different sources (e.g., UnitExists vs AURA_CAST_ON_OTHER)
|
||||
function CleveRoids.GUIDsMatch(guid1, guid2)
|
||||
if not guid1 or not guid2 then return false end
|
||||
local s1 = tostring(guid1)
|
||||
local s2 = tostring(guid2)
|
||||
-- Strip 0x prefix if present for comparison
|
||||
if string.sub(s1, 1, 2) == "0x" or string.sub(s1, 1, 2) == "0X" then
|
||||
s1 = string.sub(s1, 3)
|
||||
end
|
||||
if string.sub(s2, 1, 2) == "0x" or string.sub(s2, 1, 2) == "0X" then
|
||||
s2 = string.sub(s2, 3)
|
||||
end
|
||||
-- Case-insensitive comparison
|
||||
return string.lower(s1) == string.lower(s2)
|
||||
end
|
||||
|
||||
-- Hidden tooltip for scanning spell info
|
||||
local SpellScanTooltip = nil
|
||||
|
||||
@@ -614,18 +597,6 @@ lib.personalDebuffs = lib.personalDebuffs or {
|
||||
|
||||
[12323] = 6, -- Piercing Howl
|
||||
|
||||
[12721] = 12, -- Deep Wound (Rank 1) - actual debuff, not talent trigger
|
||||
[12722] = 12, -- Deep Wound (Rank 2)
|
||||
[12723] = 12, -- Deep Wound (Rank 3)
|
||||
|
||||
[355] = 3, -- Taunt
|
||||
[1161] = 6, -- Challenging Shout
|
||||
[694] = 6, -- Mocking Blow (Rank 1)
|
||||
[7400] = 6, -- Mocking Blow (Rank 2)
|
||||
[7402] = 6, -- Mocking Blow (Rank 3)
|
||||
[20559] = 6, -- Mocking Blow (Rank 4)
|
||||
[20560] = 6, -- Mocking Blow (Rank 5)
|
||||
|
||||
-- ROGUE
|
||||
[2094] = 10, -- Blind
|
||||
[21060] = 10, -- Blind (alternate?)
|
||||
@@ -640,17 +611,8 @@ lib.personalDebuffs = lib.personalDebuffs or {
|
||||
[11285] = 4, -- Gouge (Rank 4)
|
||||
[11286] = 4, -- Gouge (Rank 5)
|
||||
|
||||
-- NOTE: Rupture/Kidney Shot durations calculated by ComboPointTracker
|
||||
-- Base durations here for MultiTargetTracker recognition
|
||||
[1943] = 16, -- Rupture (Rank 1) - base 8s + 2s per CP (max 5CP = 16s)
|
||||
[8639] = 16, -- Rupture (Rank 2)
|
||||
[8640] = 16, -- Rupture (Rank 3)
|
||||
[11273] = 16, -- Rupture (Rank 4)
|
||||
[11274] = 16, -- Rupture (Rank 5)
|
||||
[11275] = 16, -- Rupture (Rank 6)
|
||||
|
||||
[408] = 6, -- Kidney Shot (Rank 1) - base 1s + 1s per CP (max 5CP = 6s)
|
||||
[8643] = 6, -- Kidney Shot (Rank 2)
|
||||
-- NOTE: Rupture removed - handled by ComboPointTracker (base 8s + 2s per CP)
|
||||
-- NOTE: Kidney Shot removed - handled by ComboPointTracker (base 1s/2s + 1s per CP)
|
||||
|
||||
[703] = 18, -- Garrote (Rank 1)
|
||||
[8631] = 18, -- Garrote (Rank 2)
|
||||
@@ -792,18 +754,6 @@ lib.personalDebuffs = lib.personalDebuffs or {
|
||||
[9824] = 18, -- Pounce Bleed (Rank 2) - triggered by Pounce 9823
|
||||
[9826] = 18, -- Pounce Bleed (Rank 3) - triggered by Pounce 9827
|
||||
|
||||
[9005] = 2, -- Pounce Stun (Rank 1)
|
||||
[9823] = 3, -- Pounce Stun (Rank 2)
|
||||
[9827] = 3, -- Pounce Stun (Rank 3)
|
||||
|
||||
[99] = 30, -- Demoralizing Roar (Rank 1)
|
||||
[1735] = 30, -- Demoralizing Roar (Rank 2)
|
||||
[9490] = 30, -- Demoralizing Roar (Rank 3)
|
||||
[9747] = 30, -- Demoralizing Roar (Rank 4)
|
||||
[9898] = 30, -- Demoralizing Roar (Rank 5)
|
||||
|
||||
[5209] = 6, -- Challenging Roar
|
||||
|
||||
-- WARLOCK
|
||||
[172] = 12, -- Corruption (Rank 1)
|
||||
[6222] = 15, -- Corruption (Rank 2)
|
||||
@@ -1000,10 +950,10 @@ lib.sharedDebuffs = lib.sharedDebuffs or {
|
||||
[11597] = 30, -- Sunder Armor (Rank 5)
|
||||
|
||||
[6343] = 10, -- Thunder Clap (Rank 1)
|
||||
[8198] = 14, -- Thunder Clap (Rank 2)
|
||||
[8205] = 18, -- Thunder Clap (Rank 3)
|
||||
[11580] = 22, -- Thunder Clap (Rank 4)
|
||||
[11581] = 30, -- Thunder Clap (Rank 5)
|
||||
[8198] = 10, -- Thunder Clap (Rank 2)
|
||||
[8205] = 10, -- Thunder Clap (Rank 3)
|
||||
[11580] = 10, -- Thunder Clap (Rank 4)
|
||||
[11581] = 10, -- Thunder Clap (Rank 5)
|
||||
|
||||
[1160] = 30, -- Demoralizing Shout (Rank 1)
|
||||
[6190] = 30, -- Demoralizing Shout (Rank 2)
|
||||
|
||||
Reference in New Issue
Block a user