mirror of
https://github.com/brues-code/SuperCleveRoidMacros.git
synced 2026-09-16 03:38:00 +00:00
Merge branch 'no-superwow'
This commit is contained in:
@@ -489,7 +489,7 @@ function CleveRoids.TrackComboPointCastByID(spellID, targetGUID)
|
||||
end
|
||||
else
|
||||
-- Second, check if name-based tracking has recent data for this spell
|
||||
local spellName = SpellInfo(spellID)
|
||||
local spellName = GetSpellRecField(spellID, "name")
|
||||
if spellName then
|
||||
-- Remove rank info for comparison
|
||||
local baseName = string.gsub(spellName, "%s*%(Rank %d+%)", "")
|
||||
@@ -683,7 +683,7 @@ if _G.UseAction then
|
||||
local spellName = nil
|
||||
|
||||
if actionType == "SPELL" and actionID then
|
||||
spellName = SpellInfo(actionID)
|
||||
spellName = GetSpellRecField(actionID, "name")
|
||||
end
|
||||
|
||||
if currentCP and currentCP > 0 then
|
||||
|
||||
@@ -99,7 +99,7 @@ local function GetCarnageOverride(effect)
|
||||
end
|
||||
|
||||
for spellID, override in pairs(CleveRoids.carnageDurationOverrides) do
|
||||
local spellName = SpellInfo(spellID)
|
||||
local spellName = GetSpellRecField(spellID, "name")
|
||||
if spellName then
|
||||
local baseName = string.gsub(spellName, "%s*%(Rank %d+%)", "")
|
||||
if baseName == effect and override.timestamp and (GetTime() - override.timestamp) < 5 then
|
||||
@@ -190,8 +190,7 @@ function Extension.HookPfUILibdebuff()
|
||||
|
||||
-- Check if this is the current target
|
||||
if UnitName("target") == unit then
|
||||
local _, guid = UnitExists("target")
|
||||
unitGUID = CleveRoids.NormalizeGUID(guid)
|
||||
unitGUID = CleveRoids.GetGUID("target")
|
||||
end
|
||||
|
||||
-- If we couldn't match to current target, check guidToName mapping
|
||||
@@ -210,7 +209,7 @@ function Extension.HookPfUILibdebuff()
|
||||
for spellID, rec in pairs(CleveRoids.libdebuff.objects[unitGUID]) do
|
||||
if rec and rec.start and rec.duration then
|
||||
-- Get spell name for this ID
|
||||
local spellName = SpellInfo(spellID)
|
||||
local spellName = GetSpellRecField(spellID, "name")
|
||||
if spellName then
|
||||
local baseName = string.gsub(spellName, "%s*%(Rank %d+%)", "")
|
||||
if baseName == effect then
|
||||
@@ -360,7 +359,7 @@ function Extension.SyncComboDurationToPfUI(guid, spellID, duration)
|
||||
local unitLevel = 0
|
||||
|
||||
-- Check if this is the current target
|
||||
local _, targetGUID = UnitExists("target")
|
||||
local targetGUID = CleveRoids.GetGUID("target")
|
||||
if targetGUID == guid then
|
||||
unitName = UnitName("target")
|
||||
unitLevel = UnitLevel("target") or 0
|
||||
@@ -381,7 +380,7 @@ function Extension.SyncComboDurationToPfUI(guid, spellID, duration)
|
||||
end
|
||||
|
||||
-- Get spell name from spell ID
|
||||
local spellName = SpellInfo(spellID)
|
||||
local spellName = GetSpellRecField(spellID, "name")
|
||||
if not spellName then
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[pfUI Sync]|r Could not find spell name for ID " .. spellID)
|
||||
|
||||
+198
-159
@@ -48,23 +48,30 @@ function CleveRoids.GetCachedTime()
|
||||
end
|
||||
|
||||
function CleveRoids.GetCachedPlayerHealthPercent()
|
||||
local max = UnitHealthMax("player")
|
||||
return max > 0 and (100 * UnitHealth("player") / max) or 0
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local hp = API and API.GetUnitHealth and API.GetUnitHealth("player") or UnitHealth("player")
|
||||
local max = API and API.GetUnitMaxHealth and API.GetUnitMaxHealth("player") or UnitHealthMax("player")
|
||||
return max > 0 and (100 * hp / max) or 0
|
||||
end
|
||||
|
||||
function CleveRoids.GetCachedPlayerPowerPercent()
|
||||
local max = UnitManaMax("player")
|
||||
return max > 0 and (100 * UnitMana("player") / max) or 0
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local power = API and API.GetUnitPower and API.GetUnitPower("player") or UnitMana("player")
|
||||
local max = API and API.GetUnitMaxPower and API.GetUnitMaxPower("player") or UnitManaMax("player")
|
||||
return max > 0 and (100 * power / max) or 0
|
||||
end
|
||||
|
||||
function CleveRoids.GetCachedPlayerPower()
|
||||
return UnitMana("player")
|
||||
local API = CleveRoids.NampowerAPI
|
||||
return API and API.GetUnitPower and API.GetUnitPower("player") or UnitMana("player")
|
||||
end
|
||||
|
||||
function CleveRoids.GetCachedTargetHealthPercent()
|
||||
if not UnitExists("target") then return 0 end
|
||||
local max = UnitHealthMax("target")
|
||||
return max > 0 and (100 * UnitHealth("target") / max) or 0
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local hp = API and API.GetUnitHealth and API.GetUnitHealth("target") or UnitHealth("target")
|
||||
local max = API and API.GetUnitMaxHealth and API.GetUnitMaxHealth("target") or UnitHealthMax("target")
|
||||
return max > 0 and (100 * hp / max) or 0
|
||||
end
|
||||
|
||||
-- Cooldown uses original function directly
|
||||
@@ -82,7 +89,7 @@ function CleveRoids.GetMacroThrottle() return 0 end
|
||||
|
||||
-- ============================================================================
|
||||
-- PERFORMANCE: Cache spell name -> spell ID mappings for debuff lookups
|
||||
-- This avoids iterating personalDebuffs/sharedDebuffs and calling SpellInfo() repeatedly
|
||||
-- This avoids iterating personalDebuffs/sharedDebuffs and calling GetSpellRecField() repeatedly
|
||||
local _spellNameToIDs = {} -- [spellName] = { spellID1, spellID2, ... }
|
||||
local _spellNameToIDsBuilt = false
|
||||
|
||||
@@ -98,7 +105,7 @@ local function BuildSpellNameCache()
|
||||
|
||||
if lib.personalDebuffs then
|
||||
for sid, _ in pairs(lib.personalDebuffs) do
|
||||
local name = SpellInfo(sid)
|
||||
local name = GetSpellRecField(sid, "name")
|
||||
if name then
|
||||
name = gsub(name, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if not _spellNameToIDs[name] then
|
||||
@@ -111,7 +118,7 @@ local function BuildSpellNameCache()
|
||||
|
||||
if lib.sharedDebuffs then
|
||||
for sid, _ in pairs(lib.sharedDebuffs) do
|
||||
local name = SpellInfo(sid)
|
||||
local name = GetSpellRecField(sid, "name")
|
||||
if name then
|
||||
name = gsub(name, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if not _spellNameToIDs[name] then
|
||||
@@ -468,34 +475,24 @@ local stat_checks = {
|
||||
attackpower = function() local base, pos, neg = UnitAttackPower("player"); return base + pos + neg end,
|
||||
rap = function() local base, pos, neg = UnitRangedAttackPower("player"); return base + pos + neg end,
|
||||
rangedattackpower = function() local base, pos, neg = UnitRangedAttackPower("player"); return base + pos + neg end,
|
||||
healing = function() return GetBonusHealing() end,
|
||||
healingpower = function() return GetBonusHealing() end,
|
||||
healing = function() local _, h = CleveRoids.NampowerAPI.GetSpellPower(); return h or 0 end,
|
||||
healingpower = function() local _, h = CleveRoids.NampowerAPI.GetSpellPower(); return h or 0 end,
|
||||
|
||||
-- Bonus Spell Damage by School
|
||||
arcane_power = function() return GetSpellBonusDamage(6) end,
|
||||
fire_power = function() return GetSpellBonusDamage(3) end,
|
||||
frost_power = function() return GetSpellBonusDamage(4) end,
|
||||
nature_power = function() return GetSpellBonusDamage(2) end,
|
||||
shadow_power = function() return GetSpellBonusDamage(5) end,
|
||||
-- Bonus Spell Damage by School (Nampower v2.31+ GetSpellPower)
|
||||
-- GetSpellPower() returns: physical, holy, fire, nature, frost, shadow, arcane
|
||||
arcane_power = function() return select(7, CleveRoids.NampowerAPI.GetSpellPower()) or 0 end,
|
||||
fire_power = function() return select(3, CleveRoids.NampowerAPI.GetSpellPower()) or 0 end,
|
||||
frost_power = function() return select(5, CleveRoids.NampowerAPI.GetSpellPower()) or 0 end,
|
||||
nature_power = function() return select(4, CleveRoids.NampowerAPI.GetSpellPower()) or 0 end,
|
||||
shadow_power = function() return select(6, CleveRoids.NampowerAPI.GetSpellPower()) or 0 end,
|
||||
|
||||
-- Highest spell power across all schools
|
||||
-- Uses Nampower v2.31+ GetSpellPower when available (single call), falls back to per-school
|
||||
spell_power = function()
|
||||
local API = CleveRoids.NampowerAPI
|
||||
if API and API.features and API.features.hasGetSpellPower then
|
||||
local p, h, fi, n, fr, s, a = API.GetSpellPower()
|
||||
if p then
|
||||
return math.max(p, h, fi, n, fr, s, a)
|
||||
end
|
||||
local p, h, fi, n, fr, s, a = CleveRoids.NampowerAPI.GetSpellPower()
|
||||
if p then
|
||||
return math.max(p, h, fi, n, fr, s, a)
|
||||
end
|
||||
-- Fallback: max of per-school GetSpellBonusDamage calls
|
||||
return math.max(
|
||||
GetSpellBonusDamage(2) or 0,
|
||||
GetSpellBonusDamage(3) or 0,
|
||||
GetSpellBonusDamage(4) or 0,
|
||||
GetSpellBonusDamage(5) or 0,
|
||||
GetSpellBonusDamage(6) or 0
|
||||
)
|
||||
return 0
|
||||
end,
|
||||
|
||||
-- Defensive Stats
|
||||
@@ -940,7 +937,7 @@ function CleveRoids.FindAllCasterAuraByName(targetGuid, searchName)
|
||||
local remaining = auraData.duration + auraData.start - now
|
||||
if remaining > 0 then
|
||||
-- Get spell name and compare
|
||||
local spellName = SpellInfo(spellId)
|
||||
local spellName = GetSpellRecField(spellId, "name")
|
||||
if spellName then
|
||||
-- Strip rank and compare lowercase
|
||||
local baseName = string.gsub(spellName, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
@@ -994,7 +991,7 @@ end
|
||||
local function OnAutoAttackOther(attackerGuid, targetGuid, totalDamage, hitInfo, victimState,
|
||||
subDamageCount, blockedAmount, totalAbsorb, totalResist)
|
||||
-- Check if player is the attacker
|
||||
local _, playerGuid = UnitExists("player")
|
||||
local playerGuid = CleveRoids.GetGUID("player")
|
||||
if not playerGuid or attackerGuid ~= playerGuid then
|
||||
return -- Not player's attack, ignore
|
||||
end
|
||||
@@ -1007,6 +1004,44 @@ local function OnAutoAttackOther(attackerGuid, targetGuid, totalDamage, hitInfo,
|
||||
CleveRoids.LastSwing.absorbAmount = totalAbsorb or 0
|
||||
CleveRoids.LastSwing.resistAmount = totalResist or 0
|
||||
CleveRoids.LastSwing.targetGuid = targetGuid
|
||||
|
||||
-- Paladin: refresh active Judgements on melee hit (Nampower fallback for UNIT_CASTEVENT)
|
||||
if CleveRoids.playerClass == "PALADIN" and targetGuid then
|
||||
local lib = type(CleveRoids.libdebuff) == "table" and CleveRoids.libdebuff or nil
|
||||
if lib and lib.objects then
|
||||
local normalizedTarget = CleveRoids.NormalizeGUID(targetGuid)
|
||||
if normalizedTarget and lib.objects[normalizedTarget] then
|
||||
for spellID, rec in pairs(lib.objects[normalizedTarget]) do
|
||||
if lib.judgementSpells and lib.judgementSpells[spellID] and rec.start and rec.duration then
|
||||
local remaining = rec.duration + rec.start - GetTime()
|
||||
if remaining > 0 and rec.caster == "player" then
|
||||
rec.start = GetTime()
|
||||
|
||||
if CleveRoids.debug then
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellID, "name") or "Unknown"
|
||||
local baseName = spellName and string.gsub(spellName, "%s*%(Rank %d+%)", "") or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ffaa[Judgement Refresh]|r Refreshed %s (ID:%d) on melee hit - new duration: %ds",
|
||||
baseName, spellID, rec.duration)
|
||||
)
|
||||
end
|
||||
|
||||
-- Sync to pfUI if loaded (pre-7.6 only)
|
||||
if not CleveRoids.hasPfUI76 and pfUI and pfUI.api and pfUI.api.libdebuff then
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellID, "name") or nil
|
||||
local baseName = spellName and string.gsub(spellName, "%s*%(Rank %d+%)", "")
|
||||
local targetName = (lib.guidToName and lib.guidToName[normalizedTarget]) or UnitName("target")
|
||||
local targetLevel = UnitLevel("target") or 0
|
||||
if targetName and baseName then
|
||||
pfUI.api.libdebuff:AddEffect(targetName, targetLevel, baseName, rec.duration, "player")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Process AUTO_ATTACK_SELF event (player being attacked)
|
||||
@@ -1102,10 +1137,9 @@ local function OnAuraCastSelf(spellId, casterGuid, targetGuid, effect, effectAur
|
||||
-- Use the isBuffNotDebuff result determined above (avoids redundant slot scanning)
|
||||
local lib = CleveRoids.libdebuff
|
||||
if isBuffNotDebuff and spellId and durationMs and durationMs > 0 and lib and not lib.hasPfUIEnhanced then
|
||||
local spellName = SpellInfo and SpellInfo(spellId)
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellId, "name")
|
||||
if spellName then
|
||||
local _, playerGuidRaw = UnitExists("player")
|
||||
local playerGuid = playerGuidRaw and CleveRoids.NormalizeGUID(playerGuidRaw)
|
||||
local playerGuid = CleveRoids.GetGUID("player")
|
||||
if playerGuid then
|
||||
lib.ownBuffCasts[playerGuid] = lib.ownBuffCasts[playerGuid] or {}
|
||||
lib.ownBuffCasts[playerGuid][spellName] = {
|
||||
@@ -1153,7 +1187,7 @@ local function OnAuraCastOther(spellId, casterGuid, targetGuid, effect, effectAu
|
||||
|
||||
-- Debug output when enabled
|
||||
if CleveRoids.debug then
|
||||
local spellName = SpellInfo(spellId) or "Unknown"
|
||||
local spellName = GetSpellRecField(spellId, "name") or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format(
|
||||
"|cff00ffff[AuraTrack]|r %s (ID:%d) on %s, dur=%.1fs",
|
||||
spellName, spellId, string.sub(tostring(targetGuid), 1, 16), durationMs / 1000
|
||||
@@ -1164,7 +1198,7 @@ local function OnAuraCastOther(spellId, casterGuid, targetGuid, effect, effectAu
|
||||
-- (AURA_CAST_ON_OTHER fires for both buffs and debuffs; BUFF_ADDED_OTHER confirms buff)
|
||||
local lib = CleveRoids.libdebuff
|
||||
if lib and not lib.hasPfUIEnhanced then
|
||||
local spellNameForPending = SpellInfo and SpellInfo(spellId)
|
||||
local spellNameForPending = GetSpellRecField and GetSpellRecField(spellId, "name")
|
||||
if spellNameForPending then
|
||||
local normTargetGuid = CleveRoids.NormalizeGUID(targetGuid)
|
||||
if normTargetGuid then
|
||||
@@ -1285,7 +1319,7 @@ autoAttackFrame:SetScript("OnEvent", function()
|
||||
end
|
||||
|
||||
if spellId and spellId > 0 and durationMs and durationMs > 0 then
|
||||
local _, playerGUID = UnitExists("player")
|
||||
local playerGUID = CleveRoids.GetGUID("player")
|
||||
if playerGUID then
|
||||
if not CleveRoids.AllCasterAuraTracking[playerGUID] then
|
||||
CleveRoids.AllCasterAuraTracking[playerGUID] = {}
|
||||
@@ -1301,7 +1335,7 @@ autoAttackFrame:SetScript("OnEvent", function()
|
||||
}
|
||||
|
||||
if CleveRoids.debug then
|
||||
local spellName = SpellInfo and SpellInfo(spellId) or "Unknown"
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellId, "name") or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format(
|
||||
"|cff88ff88[AuraDurUpdate]|r %s (slot:%d, ID:%d) dur=%.1fs",
|
||||
spellName, auraSlot, spellId, durationSec
|
||||
@@ -1328,7 +1362,7 @@ autoAttackFrame:SetScript("OnEvent", function()
|
||||
|
||||
elseif event == "BUFF_REMOVED_OTHER" or event == "DEBUFF_REMOVED_OTHER" then
|
||||
-- Instant cleanup of AllCasterAuraTracking when auras are removed
|
||||
-- arg1=targetGuid, arg2=spellName, arg3=spellId, arg7=state (v2.32+: 0=added, 1=removed, 2=modified)
|
||||
-- arg1=targetGuid, arg2=luaSlot, arg3=spellId, arg4=stackCount, arg5=auraLevel, arg6=auraSlot, arg7=state (v2.32+: 0=added, 1=removed, 2=modified)
|
||||
local guid = arg1
|
||||
local spellId = arg3
|
||||
local state = arg7
|
||||
@@ -1505,7 +1539,7 @@ function CleveRoids.IsTargetDebuffCapped(unit)
|
||||
if not UnitExists(unit) then return false end
|
||||
|
||||
-- Check cached AURA_CAST data by GUID
|
||||
local _, guid = UnitExists(unit)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if guid then
|
||||
local capData = CleveRoids.AuraCapStatus.targetCapStatus[guid]
|
||||
if capData and (GetTime() - capData.timestamp) < 30 then
|
||||
@@ -1515,20 +1549,6 @@ function CleveRoids.IsTargetDebuffCapped(unit)
|
||||
|
||||
-- Fallback: count debuffs on target manually
|
||||
-- For NPCs: check up to 48 slots (16 debuff + 32 overflow in buff slots)
|
||||
if not CleveRoids.hasSuperwow then
|
||||
-- Without SuperWoW, can only see 16 debuff slots
|
||||
local count = 0
|
||||
for i = 1, 16 do
|
||||
if UnitDebuff(unit, i) then
|
||||
count = count + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return count >= 16
|
||||
end
|
||||
|
||||
-- With SuperWoW: count all debuffs including overflow
|
||||
local debuffCount = 0
|
||||
|
||||
-- Count regular debuff slots (1-16, dense)
|
||||
@@ -1553,7 +1573,7 @@ function CleveRoids.IsTargetBuffCapped(unit)
|
||||
unit = unit or "target"
|
||||
if not UnitExists(unit) then return false end
|
||||
|
||||
local _, guid = UnitExists(unit)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if guid then
|
||||
local capData = CleveRoids.AuraCapStatus.targetCapStatus[guid]
|
||||
if capData and (GetTime() - capData.timestamp) < 30 then
|
||||
@@ -1614,8 +1634,7 @@ local function IsPendingDebuffCast(spellName, targetUnit)
|
||||
-- Get target GUID for verification (only count as pending if casting AT this target)
|
||||
local targetGuid = nil
|
||||
if targetUnit and UnitExists(targetUnit) then
|
||||
local _, guid = UnitExists(targetUnit)
|
||||
targetGuid = guid
|
||||
targetGuid = CleveRoids.GetGUID(targetUnit)
|
||||
end
|
||||
|
||||
-- Check if currently CASTING this spell
|
||||
@@ -1686,29 +1705,7 @@ local function _get_debuff_timeleft(unitToken, auraName)
|
||||
auraName = string.gsub(auraName, "_", " ")
|
||||
end
|
||||
|
||||
-- SuperWoW path: GUID-based lookup
|
||||
-- SuperWoW debuff slots: 1-16 are regular debuffs, 17-48 overflow to buff slots 1-32
|
||||
if CleveRoids.hasSuperwow and lib then
|
||||
local _, guid = UnitExists(unitToken)
|
||||
if guid and lib.objects and lib.objects[guid] then
|
||||
-- Check 1-48: debuff slots 1-16 + overflow debuffs in buff slots 1-32
|
||||
-- NOTE: Slots 1-16 are dense (break on nil), slots 17-48 are sparse (continue on nil)
|
||||
-- Overflow debuffs in buff slots are mixed with regular buffs, so we can't break early
|
||||
for i = 1, 48 do
|
||||
local effect, _, _, _, _, duration, timeleft = lib:UnitDebuff(unitToken, i)
|
||||
-- Only break for slots 1-16 (regular debuffs are dense)
|
||||
-- For overflow slots 17-48, nil means "regular buff filtered out", not "end of list"
|
||||
if not effect and i <= 16 then break end
|
||||
-- Strip rank from effect name for comparison
|
||||
local effectBase = effect and string.gsub(effect, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if effectBase and effectBase == auraName and timeleft and timeleft >= 0 then
|
||||
return timeleft, duration
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Non-SuperWoW fallback
|
||||
-- GUID-based debuff lookup via libdebuff (works with SuperWoW or Nampower)
|
||||
if lib and lib.UnitDebuff then
|
||||
for idx = 1, 48 do
|
||||
local effect, _, _, _, _, duration, timeleft = lib:UnitDebuff(unitToken, idx)
|
||||
@@ -1803,17 +1800,32 @@ function CleveRoids.CancelAura(auraName)
|
||||
|
||||
-- v2.34+ path: cancel by spell ID (works for buff-capped overflow auras too)
|
||||
local API = CleveRoids.NampowerAPI
|
||||
if API and API.features.hasCancelPlayerAuraSpellId and CleveRoids.hasSuperwow then
|
||||
-- First scan visible buffs via GetPlayerBuff (fast, covers normal case)
|
||||
while true do
|
||||
local aura_ix = GetPlayerBuff(ix, "HELPFUL")
|
||||
ix = ix + 1
|
||||
if aura_ix == -1 then break end
|
||||
local bid = GetPlayerBuffID(aura_ix)
|
||||
bid = (bid < -1) and (bid + 65536) or bid
|
||||
if string.lower(SpellInfo(bid)) == auraName then
|
||||
_G.CancelPlayerAuraSpellId(bid, 1)
|
||||
return true
|
||||
if API and API.features.hasCancelPlayerAuraSpellId then
|
||||
-- First scan visible buffs via GetPlayerBuff
|
||||
if CleveRoids.hasSuperwow then
|
||||
-- SuperWoW path: GetPlayerBuffID provides spell ID directly
|
||||
while true do
|
||||
local aura_ix = GetPlayerBuff(ix, "HELPFUL")
|
||||
ix = ix + 1
|
||||
if aura_ix == -1 then break end
|
||||
local bid = GetPlayerBuffID(aura_ix)
|
||||
bid = (bid < -1) and (bid + 65536) or bid
|
||||
if string.lower(GetSpellRecField(bid, "name")) == auraName then
|
||||
_G.CancelPlayerAuraSpellId(bid, 1)
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif API.features.hasGetPlayerAuraDuration and _G.GetPlayerAuraDuration then
|
||||
-- Nampower path: scan buff aura slots 0-31 for spell IDs
|
||||
for slot = 0, 31 do
|
||||
local spellId = _G.GetPlayerAuraDuration(slot)
|
||||
if spellId and spellId > 0 then
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
if name and string.lower(name) == auraName then
|
||||
_G.CancelPlayerAuraSpellId(spellId, 1)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1823,7 +1835,7 @@ function CleveRoids.CancelAura(auraName)
|
||||
for slot = 0, 31 do
|
||||
local spellId = _G.GetPlayerAuraDuration(slot)
|
||||
if spellId and spellId > 0 then
|
||||
local name = SpellInfo(spellId)
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
if name and string.lower(name) == auraName then
|
||||
_G.CancelPlayerAuraSpellId(spellId, 1)
|
||||
return true
|
||||
@@ -1840,7 +1852,7 @@ function CleveRoids.CancelAura(auraName)
|
||||
if entry.durationSec and entry.durationSec > 0 and elapsed > entry.durationSec then
|
||||
CleveRoids.OverflowBuffs[spellId] = nil
|
||||
else
|
||||
local name = SpellInfo(spellId)
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
if name and string.lower(name) == auraName then
|
||||
_G.CancelPlayerAuraSpellId(spellId, 1)
|
||||
CleveRoids.OverflowBuffs[spellId] = nil
|
||||
@@ -1860,7 +1872,7 @@ function CleveRoids.CancelAura(auraName)
|
||||
if CleveRoids.hasSuperwow then
|
||||
local bid = GetPlayerBuffID(aura_ix)
|
||||
bid = (bid < -1) and (bid + 65536) or bid
|
||||
if string.lower(SpellInfo(bid)) == auraName then
|
||||
if string.lower(GetSpellRecField(bid, "name")) == auraName then
|
||||
CancelPlayerBuff(aura_ix)
|
||||
return true
|
||||
end
|
||||
@@ -2751,8 +2763,7 @@ function CleveRoids.CountEnemiesMatching(checkFunc)
|
||||
-- Save current target for restoration
|
||||
local currentTargetGuid = nil
|
||||
if UnitExists("target") then
|
||||
local _, guid = UnitExists("target")
|
||||
currentTargetGuid = guid
|
||||
currentTargetGuid = CleveRoids.GetGUID("target")
|
||||
end
|
||||
|
||||
local count = 0
|
||||
@@ -2774,7 +2785,7 @@ function CleveRoids.CountEnemiesMatching(checkFunc)
|
||||
if not found then break end
|
||||
|
||||
if not UnitExists("target") then break end
|
||||
local _, currentGuid = UnitExists("target")
|
||||
local currentGuid = CleveRoids.GetGUID("target")
|
||||
if not currentGuid then break end
|
||||
|
||||
-- Cycle detection: stop when we see the first target again
|
||||
@@ -2956,7 +2967,7 @@ function CleveRoids.GetCursiveTimeRemaining(unit, spellName)
|
||||
if not CleveRoids.HasCursive() then return nil end
|
||||
if not unit or not UnitExists(unit) then return nil end
|
||||
|
||||
local _, guid = UnitExists(unit)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if not guid then return nil end
|
||||
|
||||
-- Normalize spell name (lowercase, no rank) to match Cursive's format
|
||||
@@ -2978,7 +2989,7 @@ function CleveRoids.ValidateCursiveDebuff(unit, spellName, operator, amount)
|
||||
if not CleveRoids.HasCursive() then return false end
|
||||
if not unit or not UnitExists(unit) then return false end
|
||||
|
||||
local _, guid = UnitExists(unit)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if not guid then return false end
|
||||
|
||||
-- Normalize spell name for Cursive lookup
|
||||
@@ -3009,7 +3020,7 @@ function CleveRoids.HasAnyCursiveDebuff(unit)
|
||||
if not CleveRoids.HasCursive() then return false end
|
||||
if not unit or not UnitExists(unit) then return false end
|
||||
|
||||
local _, guid = UnitExists(unit)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if not guid then return false end
|
||||
|
||||
return Cursive.curses:HasAnyCurse(guid) == true
|
||||
@@ -3095,9 +3106,12 @@ end
|
||||
-- returns: True or false
|
||||
function CleveRoids.ValidatePower(unit, operator, amount)
|
||||
if not unit or not operator or not amount then return false end
|
||||
local powerPercent = 100 / UnitManaMax(unit) * UnitMana(unit)
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local power = API and API.GetUnitPower and API.GetUnitPower(unit) or UnitMana(unit)
|
||||
local maxPower = API and API.GetUnitMaxPower and API.GetUnitMaxPower(unit) or UnitManaMax(unit)
|
||||
local powerPercent = maxPower > 0 and (100 * power / maxPower) or 0
|
||||
|
||||
if powerPercent and CleveRoids.operators[operator] then
|
||||
if CleveRoids.operators[operator] then
|
||||
return CleveRoids.comparators[operator](powerPercent, amount)
|
||||
end
|
||||
|
||||
@@ -3111,7 +3125,8 @@ end
|
||||
-- returns: True or false
|
||||
function CleveRoids.ValidateRawPower(unit, operator, amount)
|
||||
if not unit or not operator or not amount then return false end
|
||||
local power = UnitMana(unit)
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local power = API and API.GetUnitPower and API.GetUnitPower(unit) or UnitMana(unit)
|
||||
|
||||
if power and CleveRoids.operators[operator] then
|
||||
return CleveRoids.comparators[operator](power, amount)
|
||||
@@ -3149,7 +3164,10 @@ end
|
||||
-- returns: True or false
|
||||
function CleveRoids.ValidatePowerLost(unit, operator, amount)
|
||||
if not unit or not operator or not amount then return false end
|
||||
local powerLost = UnitManaMax(unit) - UnitMana(unit)
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local maxPower = API and API.GetUnitMaxPower and API.GetUnitMaxPower(unit) or UnitManaMax(unit)
|
||||
local power = API and API.GetUnitPower and API.GetUnitPower(unit) or UnitMana(unit)
|
||||
local powerLost = maxPower - power
|
||||
|
||||
if CleveRoids.operators[operator] then
|
||||
return CleveRoids.comparators[operator](powerLost, amount)
|
||||
@@ -3165,7 +3183,10 @@ end
|
||||
-- returns: True or false
|
||||
function CleveRoids.ValidateHp(unit, operator, amount)
|
||||
if not unit or not operator or not amount then return false end
|
||||
local hpPercent = 100 / UnitHealthMax(unit) * UnitHealth(unit)
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local hp = API and API.GetUnitHealth and API.GetUnitHealth(unit) or UnitHealth(unit)
|
||||
local maxHp = API and API.GetUnitMaxHealth and API.GetUnitMaxHealth(unit) or UnitHealthMax(unit)
|
||||
local hpPercent = maxHp > 0 and (100 * hp / maxHp) or 0
|
||||
|
||||
if CleveRoids.operators[operator] then
|
||||
return CleveRoids.comparators[operator](hpPercent, amount)
|
||||
@@ -3181,7 +3202,8 @@ end
|
||||
-- returns: True or false
|
||||
function CleveRoids.ValidateRawHp(unit, operator, amount)
|
||||
if not unit or not operator or not amount then return false end
|
||||
local rawhp = UnitHealth(unit)
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local rawhp = API and API.GetUnitHealth and API.GetUnitHealth(unit) or UnitHealth(unit)
|
||||
|
||||
if CleveRoids.operators[operator] then
|
||||
return CleveRoids.comparators[operator](rawhp, amount)
|
||||
@@ -3197,7 +3219,10 @@ end
|
||||
-- returns: True or false
|
||||
function CleveRoids.ValidateHpLost(unit, operator, amount)
|
||||
if not unit or not operator or not amount then return false end
|
||||
local hpLost = UnitHealthMax(unit) - UnitHealth(unit)
|
||||
local API = CleveRoids.NampowerAPI
|
||||
local maxHp = API and API.GetUnitMaxHealth and API.GetUnitMaxHealth(unit) or UnitHealthMax(unit)
|
||||
local hp = API and API.GetUnitHealth and API.GetUnitHealth(unit) or UnitHealth(unit)
|
||||
local hpLost = maxHp - hp
|
||||
|
||||
if CleveRoids.operators[operator] then
|
||||
return CleveRoids.comparators[operator](hpLost, amount)
|
||||
@@ -3287,7 +3312,17 @@ function CleveRoids.GetPlayerAura(index, isbuff)
|
||||
local bid = GetPlayerBuff(index, buffType)
|
||||
if bid < 0 then return end
|
||||
|
||||
local spellID = CleveRoids.hasSuperwow and GetPlayerBuffID(bid)
|
||||
local spellID
|
||||
if CleveRoids.hasSuperwow then
|
||||
spellID = GetPlayerBuffID(bid)
|
||||
elseif _G.GetPlayerAuraDuration then
|
||||
-- Nampower v2.30+: GetPlayerAuraDuration uses same raw aura slot numbering as GetPlayerBuff
|
||||
-- (0-31 for buffs, 32-47 for debuffs)
|
||||
local sid = _G.GetPlayerAuraDuration(bid)
|
||||
if sid and sid > 0 then
|
||||
spellID = sid
|
||||
end
|
||||
end
|
||||
|
||||
return GetPlayerBuffTexture(bid), GetPlayerBuffApplications(bid), spellID, GetPlayerBuffTimeLeft(bid)
|
||||
end
|
||||
@@ -3310,7 +3345,7 @@ local function GetLowercaseSpellName(spellID)
|
||||
local cached = _spellNameCache[spellID]
|
||||
if cached then return cached end
|
||||
|
||||
local name = SpellInfo(spellID)
|
||||
local name = GetSpellRecField(spellID, "name")
|
||||
if not name then return nil end
|
||||
|
||||
-- Strip rank and lowercase
|
||||
@@ -3333,7 +3368,7 @@ local function GetSpellNames(spellID)
|
||||
return cached.base, cached.full
|
||||
end
|
||||
|
||||
local fullName = SpellInfo(spellID)
|
||||
local fullName = GetSpellRecField(spellID, "name")
|
||||
if not fullName then return nil, nil end
|
||||
|
||||
local baseName = _string_gsub(fullName, _RANK_PATTERN, "")
|
||||
@@ -3363,10 +3398,6 @@ end
|
||||
function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
if not args or not UnitExists(unit) then return false end
|
||||
|
||||
if not CleveRoids.hasSuperwow then
|
||||
return false
|
||||
end
|
||||
|
||||
if type(args) ~= "table" then
|
||||
args = {name = args}
|
||||
end
|
||||
@@ -3527,8 +3558,7 @@ function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
if found and remaining == nil and isPlayer and isbuff and searchName then
|
||||
local lib = type(CleveRoids.libdebuff) == "table" and CleveRoids.libdebuff or nil
|
||||
if lib and lib.allBuffAuras then
|
||||
local _, playerGuidRaw = UnitExists("player")
|
||||
local playerGuid = CleveRoids.NormalizeGUID(playerGuidRaw)
|
||||
local playerGuid = CleveRoids.GetGUID("player")
|
||||
if playerGuid and lib.allBuffAuras[playerGuid] then
|
||||
-- Try exact name match first
|
||||
local casters = lib.allBuffAuras[playerGuid][args.name]
|
||||
@@ -3558,7 +3588,7 @@ function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
-- Guard: verify the spell isn't a visible debuff on the target (AllCasterAuraTracking
|
||||
-- stores both buffs and debuffs, so without this check [buff:DebuffName] could false-positive).
|
||||
if not found and not isPlayer and isbuff and (searchID or searchName) then
|
||||
local _, targetGuid = UnitExists(unit)
|
||||
local targetGuid = CleveRoids.GetGUID(unit)
|
||||
if targetGuid then
|
||||
-- Check if the spell is in a visible debuff slot — if so, it's a debuff, not a buff
|
||||
local isDebuff = false
|
||||
@@ -3610,8 +3640,7 @@ function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
if nonPlayerAuraTimeRemaining == nil and isbuff then
|
||||
local lib = type(CleveRoids.libdebuff) == "table" and CleveRoids.libdebuff or nil
|
||||
if lib and lib.allBuffAuras then
|
||||
local _, targetGuid = UnitExists(unit)
|
||||
targetGuid = targetGuid and CleveRoids.NormalizeGUID(targetGuid)
|
||||
local targetGuid = CleveRoids.GetGUID(unit)
|
||||
if targetGuid then
|
||||
local buffEntries = lib.allBuffAuras[targetGuid]
|
||||
if buffEntries then
|
||||
@@ -3648,7 +3677,7 @@ function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
-- Second try: All-caster tracking from AURA_CAST events (works for any caster)
|
||||
-- Only use if libdebuff didn't find it (libdebuff has more accurate timing for player casts)
|
||||
if nonPlayerAuraTimeRemaining == nil then
|
||||
local _, targetGuid = UnitExists(unit)
|
||||
local targetGuid = CleveRoids.GetGUID(unit)
|
||||
if targetGuid then
|
||||
local remaining, casterGuid = CleveRoids.FindAllCasterAuraByName(targetGuid, args.name)
|
||||
|
||||
@@ -3740,21 +3769,12 @@ function CleveRoids.ValidateUnitDebuff(unit, args)
|
||||
local texture, stacks, spellID, remaining
|
||||
local i
|
||||
|
||||
-- PERFORMANCE: For non-SuperWoW, early return if no texture registered
|
||||
if not searchID and not CleveRoids.hasSuperwow and not CleveRoids.auraTextures[args.name] then
|
||||
return false
|
||||
end
|
||||
|
||||
-- For non-player units, check tracking table directly
|
||||
-- SIMPLE: Did the player cast this spell? Is the timer still valid?
|
||||
-- Defensive: verify libdebuff is a table before accessing properties
|
||||
local lib = type(CleveRoids.libdebuff) == "table" and CleveRoids.libdebuff or nil
|
||||
if unit ~= "player" and lib and lib.objects then
|
||||
local _, guid = UnitExists(unit)
|
||||
if not guid then return false end
|
||||
|
||||
-- Normalize GUID to string for consistent table key lookups
|
||||
guid = CleveRoids.NormalizeGUID(guid)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if not guid then return false end
|
||||
|
||||
-- PERFORMANCE: Use cached spell name -> ID mapping instead of iterating every call
|
||||
@@ -3846,7 +3866,7 @@ function CleveRoids.ValidateUnitDebuff(unit, args)
|
||||
-- Includes stack/time checks (e.g., [debuff:Sunder_Armor>#3]) not just existence.
|
||||
-- The isShared gate below ensures personal debuffs still require tracking table data.
|
||||
|
||||
if not found and CleveRoids.hasSuperwow then
|
||||
if not found then
|
||||
-- FALLBACK: Only scan for SHARED debuffs (Sunder, Faerie Fire, etc.)
|
||||
-- Personal debuffs (Rip, Rake, Rupture, etc.) MUST be in tracking table
|
||||
-- to be considered "found" - this ensures [nodebuff] only finds YOUR debuffs
|
||||
@@ -3954,7 +3974,7 @@ function CleveRoids.ValidateUnitDebuff(unit, args)
|
||||
found = true
|
||||
break
|
||||
end
|
||||
elseif CleveRoids.hasSuperwow then
|
||||
elseif spellID then
|
||||
local baseName, fullName = GetSpellNames(spellID)
|
||||
if baseName and (baseName == args.name or fullName == args.name) then
|
||||
found = true
|
||||
@@ -3979,7 +3999,7 @@ function CleveRoids.ValidateUnitDebuff(unit, args)
|
||||
found = true
|
||||
break
|
||||
end
|
||||
elseif CleveRoids.hasSuperwow then
|
||||
elseif spellID then
|
||||
local baseName, fullName = GetSpellNames(spellID)
|
||||
if baseName and (baseName == args.name or fullName == args.name) then
|
||||
found = true
|
||||
@@ -4530,7 +4550,8 @@ function CleveRoids.GetActionButtonInfo(slot)
|
||||
if actionType == "MACRO" then
|
||||
return actionType, id, macroName
|
||||
elseif actionType == "SPELL" and id then
|
||||
local spellName, rank = SpellInfo(id)
|
||||
local spellName = GetSpellRecField(id, "name")
|
||||
local rank = GetSpellRecField(id, "rank")
|
||||
return actionType, id, spellName, rank
|
||||
elseif actionType == "ITEM" and id then
|
||||
local item = CleveRoids.GetItem(id)
|
||||
@@ -4646,13 +4667,11 @@ function CleveRoids.CheckSpellCast(unit, spell)
|
||||
end
|
||||
end
|
||||
|
||||
-- Legacy fallback: UNIT_CASTEVENT-based spell_tracking (requires SuperWoW)
|
||||
if not CleveRoids.hasSuperwow then return false end
|
||||
|
||||
-- Legacy fallback: UNIT_CASTEVENT-based spell_tracking (SuperWoW or Nampower SPELL_START_SELF)
|
||||
if not CleveRoids.spell_tracking[guid] then
|
||||
return false
|
||||
else
|
||||
if spell == SpellInfo(CleveRoids.spell_tracking[guid].spell_id) or (spell == "") then
|
||||
if spell == GetSpellRecField(CleveRoids.spell_tracking[guid].spell_id, "name") or (spell == "") then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
@@ -4934,7 +4953,7 @@ end
|
||||
function CleveRoids.ValidateUnitCCSingleMechanic(unit, mechanic)
|
||||
-- Use BuffLib if available (most accurate - tracks overflow debuffs and hidden auras)
|
||||
if CleveRoids.HasBuffLib() then
|
||||
local _, guid = UnitExists(unit)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if not guid then return false end
|
||||
|
||||
if unit == "player" then
|
||||
@@ -4955,7 +4974,7 @@ function CleveRoids.ValidateUnitAnyCrowdControl(unit)
|
||||
|
||||
-- Use BuffLib if available
|
||||
if CleveRoids.HasBuffLib() then
|
||||
local _, guid = UnitExists(unit)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if not guid then return false end
|
||||
|
||||
if unit == "player" then
|
||||
@@ -4984,10 +5003,9 @@ function CleveRoids.ValidateUnitAnyCrowdControl(unit)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Direct CC check - scans unit debuffs using SuperWoW API
|
||||
-- Direct CC check - scans unit debuffs for spell IDs to determine CC mechanics
|
||||
-- Works without BuffLib by using built-in spell mechanic table
|
||||
function CleveRoids.ValidateUnitCCDirect(unit, mechanic)
|
||||
if not CleveRoids.hasSuperwow then return false end
|
||||
|
||||
-- Players only have 16 debuff slots, no overflow
|
||||
-- Non-player units can have overflow debuffs in buff slots (17-48)
|
||||
@@ -6646,6 +6664,30 @@ CleveRoids.Keywords = {
|
||||
return PlayerIsSwimming() ~= 1
|
||||
end,
|
||||
|
||||
-- [rooted] - Player is currently rooted (Nampower v2.36+)
|
||||
rooted = function(conditionals)
|
||||
if not CleveRoids.NampowerAPI.features.hasPlayerIsRooted then
|
||||
if not CleveRoids._rootedErrorShown then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [rooted] conditional requires Nampower v2.36.0 or newer.", 1, 0.5, 0.5)
|
||||
CleveRoids._rootedErrorShown = true
|
||||
end
|
||||
return false
|
||||
end
|
||||
return PlayerIsRooted() == 1
|
||||
end,
|
||||
|
||||
-- [norooted] - Player is NOT rooted (Nampower v2.36+)
|
||||
norooted = function(conditionals)
|
||||
if not CleveRoids.NampowerAPI.features.hasPlayerIsRooted then
|
||||
if not CleveRoids._rootedErrorShown then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [rooted] conditional requires Nampower v2.36.0 or newer.", 1, 0.5, 0.5)
|
||||
CleveRoids._rootedErrorShown = true
|
||||
end
|
||||
return false
|
||||
end
|
||||
return PlayerIsRooted() ~= 1
|
||||
end,
|
||||
|
||||
distance = function(conditionals)
|
||||
if not CleveRoids.hasUnitXP then return false end
|
||||
|
||||
@@ -7923,6 +7965,7 @@ CleveRoids.STATIC_CONDITIONALS = {
|
||||
mod = true, nomod = true,
|
||||
keydown = true, nokeydown = true,
|
||||
swimming = true, noswimming = true,
|
||||
rooted = true, norooted = true,
|
||||
resting = true, noresting = true,
|
||||
}
|
||||
|
||||
@@ -7940,7 +7983,7 @@ function CleveRoids.GetMultiscanScore(unit, priority, currentTargetGuid, specifi
|
||||
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 unitGuid = CleveRoids.GetGUID(unit)
|
||||
local isCurrentTarget = currentTargetGuid and unitGuid == currentTargetGuid
|
||||
local isSpecifiedUnit = specifiedUnitGuid and unitGuid == specifiedUnitGuid
|
||||
if not isCurrentTarget and not isSpecifiedUnit and not UnitAffectingCombat(unit) then
|
||||
@@ -8062,15 +8105,13 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
-- Save current target for restoration and combat-check exemption
|
||||
local currentTargetGuid = nil
|
||||
if UnitExists("target") then
|
||||
local _, guid = UnitExists("target")
|
||||
currentTargetGuid = guid
|
||||
currentTargetGuid = CleveRoids.GetGUID("target")
|
||||
end
|
||||
|
||||
-- Resolve specified @unit GUID (also exempt from combat check)
|
||||
local specifiedUnitGuid = nil
|
||||
if specifiedUnit and UnitExists(specifiedUnit) then
|
||||
local _, guid = UnitExists(specifiedUnit)
|
||||
specifiedUnitGuid = guid
|
||||
specifiedUnitGuid = CleveRoids.GetGUID(specifiedUnit)
|
||||
end
|
||||
|
||||
-- Handle raid mark priorities (direct unit reference)
|
||||
@@ -8079,8 +8120,7 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
if UnitExists(markUnit) and UnitCanAttack("player", markUnit) then
|
||||
-- Validate against target-dependent conditionals
|
||||
if CleveRoids.ValidateMultiscanCandidate(conditionals, markUnit) then
|
||||
local _, guid = UnitExists(markUnit)
|
||||
return guid
|
||||
return CleveRoids.GetGUID(markUnit)
|
||||
end
|
||||
end
|
||||
return nil -- Raid mark not found or doesn't pass conditionals
|
||||
@@ -8094,8 +8134,7 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
if UnitExists(markUnit) and UnitCanAttack("player", markUnit) then
|
||||
-- Validate against target-dependent conditionals
|
||||
if CleveRoids.ValidateMultiscanCandidate(conditionals, markUnit) then
|
||||
local _, guid = UnitExists(markUnit)
|
||||
return guid
|
||||
return CleveRoids.GetGUID(markUnit)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8108,7 +8147,7 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
if not specifiedUnitGuid then
|
||||
local found = UnitXP("target", "nearestEnemy")
|
||||
if found and UnitExists("target") then
|
||||
local _, foundGuid = UnitExists("target")
|
||||
local foundGuid = CleveRoids.GetGUID("target")
|
||||
-- Restore original target
|
||||
if currentTargetGuid then
|
||||
TargetUnit(currentTargetGuid)
|
||||
@@ -8136,7 +8175,7 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
if not specifiedUnitGuid then
|
||||
local found = UnitXP("target", "mostHP")
|
||||
if found and UnitExists("target") then
|
||||
local _, foundGuid = UnitExists("target")
|
||||
local foundGuid = CleveRoids.GetGUID("target")
|
||||
-- Restore original target
|
||||
if currentTargetGuid then
|
||||
TargetUnit(currentTargetGuid)
|
||||
@@ -8167,7 +8206,7 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
local function evaluateCandidate(unit)
|
||||
if not UnitExists(unit) then return end
|
||||
|
||||
local _, guid = UnitExists(unit)
|
||||
local guid = CleveRoids.GetGUID(unit)
|
||||
if not guid or seenGuids[guid] then return end
|
||||
seenGuids[guid] = true
|
||||
|
||||
@@ -8213,7 +8252,7 @@ function CleveRoids.ResolveMultiscanTarget(conditionals, specifiedUnit)
|
||||
if not found then break end
|
||||
|
||||
if not UnitExists("target") then break end
|
||||
local _, currentGuid = UnitExists("target")
|
||||
local currentGuid = CleveRoids.GetGUID("target")
|
||||
if not currentGuid then break end
|
||||
|
||||
if firstGuid == nil then
|
||||
|
||||
@@ -106,16 +106,11 @@ requirementCheckFrame:SetScript("OnEvent", function()
|
||||
if arg1 ~= "SuperCleveRoidMacros" then return end
|
||||
|
||||
-- Check requirements immediately when our addon loads
|
||||
local hasSuperwow = CleveRoids.hasSuperwow
|
||||
local hasNampower = (IsSpellInRange ~= nil)
|
||||
local hasUnitXP = pcall(UnitXP, "nop", "nop")
|
||||
|
||||
if not hasSuperwow or not hasNampower or not hasUnitXP then
|
||||
if not hasNampower or not hasUnitXP then
|
||||
-- Show errors
|
||||
if not hasSuperwow then
|
||||
CleveRoids.Print("|cFFFF0000SuperCleveRoidMacros|r requires |cFF00FFFFbalakethelock's SuperWoW|r:")
|
||||
CleveRoids.Print("https://github.com/balakethelock/SuperWoW")
|
||||
end
|
||||
if not hasNampower then
|
||||
CleveRoids.Print("|cFFFF0000SuperCleveRoidMacros|r requires |cFF00FFFFAvitasia's Nampower|r:")
|
||||
CleveRoids.Print("https://gitea.com/avitasia/nampower")
|
||||
@@ -2670,7 +2665,7 @@ function CleveRoids.DoTarget(msg)
|
||||
end
|
||||
|
||||
-- Save original target GUID for potential restoration (SuperWoW returns GUID as 2nd value)
|
||||
local _, originalTargetGuid = UnitExists("target")
|
||||
local originalTargetGuid = CleveRoids.GetGUID("target")
|
||||
|
||||
-- Handle [multiscan:priority] - use ResolveMultiscanTarget for enemy scanning
|
||||
-- ResolveMultiscanTarget handles its own target save/restore internally
|
||||
@@ -2829,7 +2824,7 @@ function CleveRoids.DoTarget(msg)
|
||||
found = UnitXP("target", scanMode)
|
||||
if not found then break end
|
||||
|
||||
local _, currentGuid = UnitExists("target")
|
||||
local currentGuid = CleveRoids.GetGUID("target")
|
||||
if not currentGuid then break end
|
||||
|
||||
-- Check if we've cycled back to start
|
||||
@@ -3728,10 +3723,6 @@ function CleveRoids.DoNoFirstAction(msg)
|
||||
end
|
||||
|
||||
function CleveRoids.DoCastSequence(sequence)
|
||||
if not CleveRoids.hasSuperwow then
|
||||
CleveRoids.Print("|cFFFF0000/castsequence|r requires |cFF00FFFFSuperWoW|r.")
|
||||
return
|
||||
end
|
||||
if type(sequence) == "string" then
|
||||
sequence = CleveRoids.GetSequence(sequence)
|
||||
if not sequence then return end
|
||||
@@ -3788,7 +3779,7 @@ function CleveRoids.DoCastSequence(sequence)
|
||||
|
||||
-- Capture target GUID for reset=target (only resets on NEW target, not same target)
|
||||
if sequence.reset and sequence.reset.target and UnitExists("target") then
|
||||
local _, targetGuid = UnitExists("target")
|
||||
local targetGuid = CleveRoids.GetGUID("target")
|
||||
sequence.lastTargetGuid = targetGuid
|
||||
end
|
||||
|
||||
@@ -4927,9 +4918,18 @@ CleveRoids.Frame:RegisterEvent("PLAYER_REGEN_DISABLED") -- Entered actual combat
|
||||
CleveRoids.Frame:RegisterEvent("PLAYER_REGEN_ENABLED") -- Left actual combat (no threat)
|
||||
CleveRoids.Frame:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
|
||||
CleveRoids.Frame:RegisterEvent("SPELL_UPDATE_COOLDOWN")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_AURA")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_HEALTH")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_POWER")
|
||||
-- Use GUID events when available (v2.39+), fall back to standard per-token events
|
||||
if CleveRoids.NampowerAPI.features.hasUnitGuidEvents then
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_AURA_GUID")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_HEALTH_GUID")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_MANA_GUID")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_RAGE_GUID")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_ENERGY_GUID")
|
||||
else
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_AURA")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_HEALTH")
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_POWER")
|
||||
end
|
||||
if CleveRoids.hasSuperwow then
|
||||
CleveRoids.Frame:RegisterEvent("UNIT_CASTEVENT")
|
||||
end
|
||||
@@ -4946,11 +4946,17 @@ CleveRoids.Frame:RegisterEvent("SPELLCAST_STOP")
|
||||
CleveRoids.Frame:RegisterEvent("SPELLCAST_FAILED")
|
||||
CleveRoids.Frame:RegisterEvent("SPELLCAST_INTERRUPTED")
|
||||
|
||||
-- Nampower SPELL_CAST_EVENT for reliable channel tracking
|
||||
-- Nampower SPELL_CAST_EVENT for reliable channel tracking + cast sequence + spell_tracking
|
||||
if GetCurrentCastingInfo then
|
||||
CleveRoids.Frame:RegisterEvent("SPELL_CAST_EVENT")
|
||||
end
|
||||
|
||||
-- Nampower v2.25+: SPELL_START_SELF for spell_tracking and cast sequence (Nampower fallback for UNIT_CASTEVENT)
|
||||
if CleveRoids.NampowerAPI and CleveRoids.NampowerAPI.features and CleveRoids.NampowerAPI.features.hasSpellStartEvents then
|
||||
CleveRoids.Frame:RegisterEvent("SPELL_START_SELF")
|
||||
CleveRoids.Frame:RegisterEvent("SPELL_FAILED_SELF")
|
||||
end
|
||||
|
||||
-- Nampower v2.41+: keyboard input events for [keydown:X] conditional
|
||||
if CleveRoids.NampowerAPI.features.hasKeyEvents then
|
||||
CleveRoids.Frame:RegisterEvent("KEY_DOWN")
|
||||
@@ -5110,7 +5116,7 @@ function CleveRoids.Frame:UNIT_CASTEVENT(caster,target,action,spell_id,cast_time
|
||||
-- Refresh the Judgement by updating the start time
|
||||
rec.start = GetTime()
|
||||
|
||||
local spellName = SpellInfo(spellID)
|
||||
local spellName = GetSpellRecField(spellID, "name")
|
||||
local baseName = spellName and string.gsub(spellName, "%s*%(Rank %d+%)", "") or "Unknown"
|
||||
|
||||
if CleveRoids.debug then
|
||||
@@ -5146,7 +5152,7 @@ function CleveRoids.Frame:UNIT_CASTEVENT(caster,target,action,spell_id,cast_time
|
||||
|
||||
-- Debug channel tracking
|
||||
if CleveRoids.ChannelTimeDebug then
|
||||
local spellName = spell_id and SpellInfo and SpellInfo(spell_id) or "Unknown"
|
||||
local spellName = spell_id and GetSpellRecField and GetSpellRecField(spell_id, "name") or "Unknown"
|
||||
if string.find(spellName, "Arcane") then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff00ff00[UNIT_CASTEVENT]|r %s: %s (ID:%s) caster=%s player=%s",
|
||||
action, spellName, tostring(spell_id), tostring(caster), tostring(CleveRoids.playerGuid)))
|
||||
@@ -5219,7 +5225,8 @@ function CleveRoids.Frame:UNIT_CASTEVENT(caster,target,action,spell_id,cast_time
|
||||
if CleveRoids.currentSequence and caster == CleveRoids.playerGuid then
|
||||
local active = CleveRoids.GetCurrentSequenceAction(CleveRoids.currentSequence)
|
||||
|
||||
local name, rank = SpellInfo(spell_id)
|
||||
local name = GetSpellRecField(spell_id, "name")
|
||||
local rank = GetSpellRecField(spell_id, "rank")
|
||||
local nameRank = (rank and rank ~= "") and (name .. "(" .. rank .. ")") or nil
|
||||
local isSeqSpell = active and active.action and (
|
||||
active.action == name or
|
||||
@@ -5250,7 +5257,7 @@ function CleveRoids.Frame:UNIT_CASTEVENT(caster,target,action,spell_id,cast_time
|
||||
end
|
||||
|
||||
-- Nampower SPELL_CAST_EVENT handler for reliable channel tracking
|
||||
-- This is the PRIMARY source of truth for channel state (not GetCurrentCastingInfo polling)
|
||||
-- Also handles spell_tracking clearing and cast sequence advancement (Nampower fallback for UNIT_CASTEVENT)
|
||||
function CleveRoids.Frame:SPELL_CAST_EVENT(success, spellId, castType, targetGuid, itemId)
|
||||
local CHANNEL = 4
|
||||
|
||||
@@ -5259,7 +5266,7 @@ function CleveRoids.Frame:SPELL_CAST_EVENT(success, spellId, castType, targetGui
|
||||
CleveRoids.CurrentSpell.type = "channeled"
|
||||
CleveRoids.CurrentSpell.castingSpellId = spellId
|
||||
|
||||
local spellName = SpellInfo and SpellInfo(spellId)
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellId, "name")
|
||||
if spellName then
|
||||
CleveRoids.CurrentSpell.spellName = spellName
|
||||
end
|
||||
@@ -5267,6 +5274,149 @@ function CleveRoids.Frame:SPELL_CAST_EVENT(success, spellId, castType, targetGui
|
||||
-- Force immediate action update
|
||||
CleveRoids.TestForAllActiveActions()
|
||||
end
|
||||
|
||||
-- Nampower fallback: spell_tracking and cast sequence (when SuperWoW not available)
|
||||
if not CleveRoids.hasSuperwow and spellId then
|
||||
local playerGuid = CleveRoids.playerGuid or CleveRoids.GetGUID("player")
|
||||
|
||||
-- Clear spell_tracking on success or failure
|
||||
if success == 1 or success == 0 then
|
||||
local cast = CleveRoids.spell_tracking[playerGuid]
|
||||
if cast and cast.spell_id == spellId then
|
||||
CleveRoids.spell_tracking[playerGuid] = nil
|
||||
CleveRoids.spell_tracking["player"] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Cast sequence advancement
|
||||
if CleveRoids.currentSequence and success == 1 then
|
||||
local active = CleveRoids.GetCurrentSequenceAction(CleveRoids.currentSequence)
|
||||
if active and active.action then
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
local rank = GetSpellRecField(spellId, "rank")
|
||||
local nameRank = (rank and rank ~= "") and (name .. "(" .. rank .. ")") or nil
|
||||
local isSeqSpell = (active.action == name or (nameRank and active.action == nameRank))
|
||||
|
||||
if isSeqSpell then
|
||||
CleveRoids.currentSequence.status = 2
|
||||
CleveRoids.currentSequence.lastUpdate = GetTime()
|
||||
CleveRoids.AdvanceSequence(CleveRoids.currentSequence)
|
||||
CleveRoids.currentSequence = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Cast sequence failure handling
|
||||
if CleveRoids.currentSequence and success == 0 then
|
||||
local active = CleveRoids.GetCurrentSequenceAction(CleveRoids.currentSequence)
|
||||
if active and active.action then
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
local isSeqSpell = (active.action == name)
|
||||
if isSeqSpell then
|
||||
CleveRoids.currentSequence.status = 1 -- Reset to retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if CleveRoidMacros.realtime == 0 then
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Nampower SPELL_START_SELF handler (v2.25+)
|
||||
-- Handles spell_tracking population and cast sequence START detection (Nampower fallback for UNIT_CASTEVENT)
|
||||
function CleveRoids.Frame:SPELL_START_SELF(casterGuid, targetGuid, spellId, castTimeMs, durationMs, spellType, ...)
|
||||
-- Skip if SuperWoW is handling this via UNIT_CASTEVENT
|
||||
if CleveRoids.hasSuperwow then return end
|
||||
if not spellId then return end
|
||||
|
||||
local playerGuid = CleveRoids.playerGuid or CleveRoids.GetGUID("player")
|
||||
if casterGuid ~= playerGuid then return end
|
||||
|
||||
-- Populate spell_tracking (equivalent to UNIT_CASTEVENT START/CHANNEL)
|
||||
local isChannel = (spellType == 1)
|
||||
local action = isChannel and "CHANNEL" or "START"
|
||||
|
||||
if castTimeMs and castTimeMs > 0 then
|
||||
CleveRoids.spell_tracking[casterGuid] = {
|
||||
spell_id = spellId,
|
||||
expires = GetTime() + castTimeMs / 1000,
|
||||
type = action
|
||||
}
|
||||
CleveRoids.spell_tracking["player"] = CleveRoids.spell_tracking[casterGuid]
|
||||
|
||||
-- Channel duration capture (equivalent to UNIT_CASTEVENT CHANNEL)
|
||||
if isChannel then
|
||||
CleveRoids.channelStartTime = GetTime()
|
||||
local tooltipDuration = CleveRoids.GetChannelDurationFromTooltipByID(spellId)
|
||||
if tooltipDuration then
|
||||
CleveRoids.channelDuration = tooltipDuration
|
||||
else
|
||||
CleveRoids.channelDuration = castTimeMs / 1000
|
||||
end
|
||||
end
|
||||
|
||||
-- Cast duration capture (equivalent to UNIT_CASTEVENT START)
|
||||
if not isChannel then
|
||||
CleveRoids.castStartTime = GetTime()
|
||||
CleveRoids.castDuration = castTimeMs / 1000
|
||||
end
|
||||
end
|
||||
|
||||
-- Cast sequence: set status=1 (casting) for cast-time spells
|
||||
if CleveRoids.currentSequence and castTimeMs and castTimeMs > 0 then
|
||||
local active = CleveRoids.GetCurrentSequenceAction(CleveRoids.currentSequence)
|
||||
if active and active.action then
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
local rank = GetSpellRecField(spellId, "rank")
|
||||
local nameRank = (rank and rank ~= "") and (name .. "(" .. rank .. ")") or nil
|
||||
local isSeqSpell = (active.action == name or (nameRank and active.action == nameRank))
|
||||
|
||||
if isSeqSpell and CleveRoids.currentSequence.status == 0 then
|
||||
CleveRoids.currentSequence.status = 1
|
||||
CleveRoids.currentSequence.expires = GetTime() + (castTimeMs / 1000) - 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if CleveRoidMacros.realtime == 0 then
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
|
||||
-- Nampower SPELL_FAILED_SELF handler (v2.25+)
|
||||
-- Clears spell_tracking on failure (Nampower fallback for UNIT_CASTEVENT FAIL)
|
||||
function CleveRoids.Frame:SPELL_FAILED_SELF(casterGuid, targetGuid, spellId, ...)
|
||||
-- Skip if SuperWoW is handling this via UNIT_CASTEVENT
|
||||
if CleveRoids.hasSuperwow then return end
|
||||
if not spellId then return end
|
||||
|
||||
local playerGuid = CleveRoids.playerGuid or CleveRoids.GetGUID("player")
|
||||
if casterGuid ~= playerGuid then return end
|
||||
|
||||
-- Clear spell_tracking
|
||||
local cast = CleveRoids.spell_tracking[casterGuid]
|
||||
if cast and cast.spell_id == spellId then
|
||||
CleveRoids.spell_tracking[casterGuid] = nil
|
||||
CleveRoids.spell_tracking["player"] = nil
|
||||
end
|
||||
|
||||
-- Cast sequence failure handling
|
||||
if CleveRoids.currentSequence then
|
||||
local active = CleveRoids.GetCurrentSequenceAction(CleveRoids.currentSequence)
|
||||
if active and active.action then
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
local isSeqSpell = name and (active.action == name)
|
||||
if isSeqSpell then
|
||||
CleveRoids.currentSequence.status = 1 -- Reset to retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if CleveRoidMacros.realtime == 0 then
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
|
||||
function CleveRoids.Frame:SPELLCAST_CHANNEL_START()
|
||||
@@ -5295,7 +5445,7 @@ function CleveRoids.Frame:SPELLCAST_CHANNEL_START()
|
||||
-- Update spell info
|
||||
if spellId then
|
||||
CleveRoids.CurrentSpell.castingSpellId = spellId
|
||||
local spellName = SpellInfo(spellId)
|
||||
local spellName = GetSpellRecField(spellId, "name")
|
||||
if spellName then
|
||||
CleveRoids.CurrentSpell.spellName = spellName
|
||||
end
|
||||
@@ -5375,7 +5525,7 @@ function CleveRoids.Frame:SPELLCAST_START()
|
||||
-- Update spell info
|
||||
if spellId then
|
||||
CleveRoids.CurrentSpell.castingSpellId = spellId
|
||||
local spellName = SpellInfo(spellId)
|
||||
local spellName = GetSpellRecField(spellId, "name")
|
||||
if spellName then
|
||||
CleveRoids.CurrentSpell.spellName = spellName
|
||||
end
|
||||
@@ -5488,8 +5638,7 @@ function CleveRoids.Frame:PLAYER_TARGET_CHANGED()
|
||||
-- Instead of resetting, we remember each target's progress in the sequence
|
||||
local currentGuid = nil
|
||||
if UnitExists("target") then
|
||||
local _, guid = UnitExists("target")
|
||||
currentGuid = guid
|
||||
currentGuid = CleveRoids.GetGUID("target")
|
||||
end
|
||||
|
||||
for _, sequence in pairs(CleveRoids.Sequences) do
|
||||
@@ -5733,6 +5882,39 @@ function CleveRoids.Frame:UNIT_POWER()
|
||||
end
|
||||
end
|
||||
|
||||
-- GUID event handlers (v2.39+): fire once per unit state change instead of per-token
|
||||
function CleveRoids.Frame:UNIT_AURA_GUID()
|
||||
if CleveRoidMacros.realtime == 0 then
|
||||
local now = GetTime()
|
||||
if (now - CleveRoids.lastUnitAuraUpdate) >= CleveRoids.EVENT_THROTTLE then
|
||||
CleveRoids.lastUnitAuraUpdate = now
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
end
|
||||
function CleveRoids.Frame:UNIT_HEALTH_GUID()
|
||||
if CleveRoidMacros.realtime == 0 then
|
||||
local now = GetTime()
|
||||
if (now - CleveRoids.lastUnitHealthUpdate) >= CleveRoids.EVENT_THROTTLE then
|
||||
CleveRoids.lastUnitHealthUpdate = now
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
end
|
||||
-- All power GUID events share the same handler
|
||||
local function OnPowerGuidEvent()
|
||||
if CleveRoidMacros.realtime == 0 then
|
||||
local now = GetTime()
|
||||
if (now - CleveRoids.lastUnitPowerUpdate) >= CleveRoids.EVENT_THROTTLE then
|
||||
CleveRoids.lastUnitPowerUpdate = now
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
end
|
||||
CleveRoids.Frame.UNIT_MANA_GUID = OnPowerGuidEvent
|
||||
CleveRoids.Frame.UNIT_RAGE_GUID = OnPowerGuidEvent
|
||||
CleveRoids.Frame.UNIT_ENERGY_GUID = OnPowerGuidEvent
|
||||
|
||||
function CleveRoids.Frame:SPELL_QUEUE_EVENT()
|
||||
if event == "SPELL_QUEUE_EVENT" then
|
||||
local eventCode = arg1
|
||||
@@ -5751,8 +5933,8 @@ function CleveRoids.Frame:SPELL_QUEUE_EVENT()
|
||||
queueType = eventCode,
|
||||
queueTime = GetTime()
|
||||
}
|
||||
if SpellInfo then
|
||||
local name = SpellInfo(spellId)
|
||||
if GetSpellRecField then
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
if name then
|
||||
CleveRoids.queuedSpell.spellName = name
|
||||
end
|
||||
@@ -5792,8 +5974,8 @@ function CleveRoids.Frame:SPELL_CAST_EVENT()
|
||||
targetGuid = targetGuid,
|
||||
timestamp = GetTime()
|
||||
}
|
||||
if SpellInfo then
|
||||
local name = SpellInfo(spellId)
|
||||
if GetSpellRecField then
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
if name then
|
||||
CleveRoids.lastCastSpell.spellName = name
|
||||
end
|
||||
@@ -5826,7 +6008,7 @@ function CleveRoids.Frame:SPELL_CAST_EVENT()
|
||||
if cp > 0 then
|
||||
CleveRoids.pendingCasts[spellId].comboPoints = cp
|
||||
if CleveRoids.debug then
|
||||
local castSpellName = SpellInfo and SpellInfo(spellId) or "Unknown"
|
||||
local castSpellName = GetSpellRecField and GetSpellRecField(spellId, "name") or "Unknown"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff88[SPELL_CAST_EVENT]|r Captured %d CP for %s (ID:%d)",
|
||||
cp, castSpellName, spellId)
|
||||
@@ -5980,11 +6162,9 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
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)")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid macrocheck 0 or 1 - Enable/disable macro syntax checker")
|
||||
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("/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")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Spell Schools:|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid listschools - List all learned spell schools')
|
||||
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid clearschools - Clear learned spell school data')
|
||||
@@ -6067,18 +6247,14 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
|
||||
-- learn (manual set duration)
|
||||
if cmd == "learn" then
|
||||
if not CleveRoids.hasSuperwow then
|
||||
CleveRoids.Print("Learning system requires SuperWoW client!")
|
||||
return
|
||||
end
|
||||
local spellID = tonumber(val)
|
||||
local duration = tonumber(val2)
|
||||
if spellID and duration then
|
||||
local _, playerGUID = UnitExists("player")
|
||||
local playerGUID = CleveRoids.GetGUID("player")
|
||||
CleveRoids_LearnedDurations = CleveRoids_LearnedDurations or {}
|
||||
CleveRoids_LearnedDurations[spellID] = CleveRoids_LearnedDurations[spellID] or {}
|
||||
CleveRoids_LearnedDurations[spellID][playerGUID] = duration
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
local spellName = GetSpellRecField(spellID, "name") or "Unknown"
|
||||
CleveRoids.Print("Set " .. spellName .. " (ID:" .. spellID .. ") duration to " .. duration .. "s")
|
||||
else
|
||||
CleveRoids.Print("Usage: /cleveroid learn <spellID> <duration> - Manually set spell duration")
|
||||
@@ -6089,17 +6265,13 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
|
||||
-- forget (delete learned duration)
|
||||
if cmd == "forget" or cmd == "unlearn" then
|
||||
if not CleveRoids.hasSuperwow then
|
||||
CleveRoids.Print("Learning system requires SuperWoW client!")
|
||||
return
|
||||
end
|
||||
if val == "all" then
|
||||
CleveRoids_LearnedDurations = {}
|
||||
CleveRoids.Print("Forgot all learned spell durations")
|
||||
else
|
||||
local spellID = tonumber(val)
|
||||
if spellID and CleveRoids_LearnedDurations and CleveRoids_LearnedDurations[spellID] then
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
local spellName = GetSpellRecField(spellID, "name") or "Unknown"
|
||||
CleveRoids_LearnedDurations[spellID] = nil
|
||||
CleveRoids.Print("Forgot " .. spellName .. " (ID:" .. spellID .. ") duration")
|
||||
elseif spellID then
|
||||
@@ -6283,7 +6455,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
|
||||
CleveRoids.Print(schoolColor .. string.upper(school) .. "|r (" .. table.getn(spellIDs) .. " spells):")
|
||||
for _, spellID in ipairs(spellIDs) do
|
||||
local spellName = SpellInfo and SpellInfo(spellID) or "Unknown"
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellID, "name") or "Unknown"
|
||||
CleveRoids.Print(" " .. spellName .. " (ID:" .. spellID .. ")")
|
||||
end
|
||||
end
|
||||
@@ -6326,7 +6498,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
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)
|
||||
local spellName = GetSpellRecField(spellID, "name") or ("Spell " .. spellID)
|
||||
CleveRoids.Print(spellName .. " (ID:" .. spellID .. "):")
|
||||
for cp = 1, 5 do
|
||||
if cpData[cp] then
|
||||
@@ -6408,7 +6580,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
return
|
||||
end
|
||||
|
||||
local spellName = SpellInfo(spellID) or ("Spell " .. spellID)
|
||||
local spellName = GetSpellRecField(spellID, "name") or ("Spell " .. spellID)
|
||||
local modifier = CleveRoids.talentModifiers and CleveRoids.talentModifiers[spellID]
|
||||
|
||||
if not modifier then
|
||||
@@ -6466,14 +6638,13 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
|
||||
CleveRoids.Print("|cff88ff88=== Debuff Tracking Debug ===|r")
|
||||
|
||||
local _, guid = UnitExists("target")
|
||||
local guid = CleveRoids.GetGUID("target")
|
||||
if not guid then
|
||||
CleveRoids.Print("|cffff0000No target selected!|r")
|
||||
return
|
||||
end
|
||||
|
||||
local targetName = UnitName("target") or "Unknown"
|
||||
guid = CleveRoids.NormalizeGUID(guid)
|
||||
CleveRoids.Print("Target: " .. targetName .. " (GUID: " .. tostring(guid) .. ")")
|
||||
|
||||
-- Show tracking table for this target
|
||||
@@ -6485,7 +6656,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
for spellID, rec in pairs(lib.objects[guid]) do
|
||||
if rec and rec.start and rec.duration then
|
||||
local timeRemaining = rec.duration + rec.start - GetTime()
|
||||
local spellName = SpellInfo and SpellInfo(spellID) or "Unknown"
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellID, "name") or "Unknown"
|
||||
local caster = rec.caster or "unknown"
|
||||
local stacks = rec.stacks or 0
|
||||
if timeRemaining > 0 then
|
||||
@@ -6512,7 +6683,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
for i = 1, 16 do
|
||||
local texture, stacks, debuffType, spellID = UnitDebuff("target", i)
|
||||
if texture then
|
||||
local spellName = SpellInfo and SpellInfo(spellID) or "slot" .. i
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellID, "name") or "slot" .. i
|
||||
CleveRoids.Print(string.format(" Slot %d: [%d] %s (stacks: %d)",
|
||||
i, spellID or 0, spellName, stacks or 0))
|
||||
debuffCount = debuffCount + 1
|
||||
@@ -6532,7 +6703,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
-- Check if this might be an overflow debuff by checking libdebuff durations
|
||||
local isDebuff = lib and lib.durations and lib.durations[spellID]
|
||||
if isDebuff then
|
||||
local spellName = SpellInfo and SpellInfo(spellID) or "slot" .. i
|
||||
local spellName = GetSpellRecField and GetSpellRecField(spellID, "name") or "slot" .. i
|
||||
CleveRoids.Print(string.format(" Buff Slot %d (=Debuff %d): [%d] %s (stacks: %d) |cffff8800OVERFLOW|r",
|
||||
i, i + 16, spellID, spellName, stacks or 0))
|
||||
overflowCount = overflowCount + 1
|
||||
@@ -6570,10 +6741,10 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Also check SpellInfo
|
||||
if SpellInfo then
|
||||
-- Also check GetSpellRecField
|
||||
if GetSpellRecField then
|
||||
for id = 1, 30000 do
|
||||
local name = SpellInfo(id)
|
||||
local name = GetSpellRecField(id, "name")
|
||||
if name and string.lower(name) == string.lower(searchName) then
|
||||
local found = false
|
||||
for _, existingID in ipairs(foundIDs) do
|
||||
@@ -6739,7 +6910,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
if auraData.start and auraData.duration then
|
||||
local remaining = auraData.duration + auraData.start - now
|
||||
if remaining > 0 then
|
||||
local spellName = SpellInfo(spellId) or ("ID:" .. spellId)
|
||||
local spellName = GetSpellRecField(spellId, "name") or ("ID:" .. spellId)
|
||||
local display = unitName or (string.sub(targetGuid, 1, 16) .. "...")
|
||||
CleveRoids.Print(string.format(" %s on %s: %.1fs left", spellName, display, remaining))
|
||||
trackingCount = trackingCount + 1
|
||||
@@ -6755,7 +6926,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
if UnitExists("target") then
|
||||
CleveRoids.Print(" ")
|
||||
CleveRoids.Print("|cffffaa00Target Buff Check:|r")
|
||||
local _, targetGuid = UnitExists("target")
|
||||
local targetGuid = CleveRoids.GetGUID("target")
|
||||
CleveRoids.Print(" Target GUID: " .. tostring(targetGuid))
|
||||
local targetData = CleveRoids.AllCasterAuraTracking[targetGuid]
|
||||
if targetData then
|
||||
@@ -6824,11 +6995,9 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid - Show current settings")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid realtime 0 or 1 - Force realtime updates (Default: 0. 1 = on, increases CPU load)")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid refresh X - Set refresh rate (1 to 10 updates per second. Default: 5)")
|
||||
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("/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")
|
||||
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')
|
||||
|
||||
@@ -208,8 +208,10 @@ local function InjectCustomSpells()
|
||||
|
||||
local count = 0
|
||||
for spellID, data in pairs(CleveRoids.CustomCursiveSpells) do
|
||||
-- Get texture from SpellInfo (SuperWoW API)
|
||||
local name, rank, texture = SpellInfo(spellID)
|
||||
-- Get texture from GetSpellRecField + GetSpellIconTexture
|
||||
local name = GetSpellRecField(spellID, "name")
|
||||
local rank = GetSpellRecField(spellID, "rank")
|
||||
local texture = CleveRoids.libdebuff and CleveRoids.libdebuff:GetCachedIcon(spellID)
|
||||
if texture then
|
||||
-- Always update/add (in case Cursive reloaded and cleared them)
|
||||
Cursive.curses.trackedCurseIds[spellID] = {
|
||||
@@ -340,7 +342,7 @@ local function HookJudgementDetection()
|
||||
if event ~= "CAST" or spellID ~= JUDGEMENT_SPELL_ID then return end
|
||||
|
||||
-- Check if it's the player casting
|
||||
local _, playerGuid = UnitExists("player")
|
||||
local playerGuid = CleveRoids.GetGUID("player")
|
||||
if casterGuid ~= playerGuid then return end
|
||||
|
||||
-- Detect which seal is active and get full judgement info
|
||||
@@ -448,7 +450,7 @@ meleeRefreshFrame:SetScript("OnEvent", function()
|
||||
-- Check if current target matches the hit target
|
||||
local currentTargetName = UnitName("target")
|
||||
if currentTargetName and currentTargetName == targetName then
|
||||
local _, targetGuid = UnitExists("target")
|
||||
local targetGuid = CleveRoids.GetGUID("target")
|
||||
if targetGuid then
|
||||
RefreshJudgementsOnTarget(targetGuid)
|
||||
end
|
||||
@@ -465,7 +467,7 @@ meleeAbilityFrame:SetScript("OnEvent", function()
|
||||
if event ~= "CAST" then return end
|
||||
|
||||
-- Check if it's the player casting
|
||||
local _, playerGuid = UnitExists("player")
|
||||
local playerGuid = CleveRoids.GetGUID("player")
|
||||
if casterGuid ~= playerGuid then return end
|
||||
|
||||
-- Skip Judgement itself (20271) - it applies, doesn't refresh
|
||||
@@ -522,7 +524,9 @@ CleveRoids.HandleConsoleCommand = function(msg)
|
||||
return
|
||||
end
|
||||
|
||||
local name, rank, texture = SpellInfo(spellID)
|
||||
local name = GetSpellRecField(spellID, "name")
|
||||
local rank = GetSpellRecField(spellID, "rank")
|
||||
local texture = CleveRoids.libdebuff and CleveRoids.libdebuff:GetCachedIcon(spellID)
|
||||
if not name then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000Error:|r Spell ID " .. spellID .. " not found.")
|
||||
return
|
||||
|
||||
@@ -120,7 +120,7 @@ local function CreateIconButton(parent, index, iconTable)
|
||||
local data = iconTable[index]
|
||||
if not data or not data.spellId then return end
|
||||
GameTooltip:SetOwner(btn, "ANCHOR_BOTTOMLEFT")
|
||||
local spellName = SpellInfo and SpellInfo(data.spellId) or ("Spell " .. data.spellId)
|
||||
local spellName = GetSpellRecField and GetSpellRecField(data.spellId, "name") or ("Spell " .. data.spellId)
|
||||
if spellName then
|
||||
local baseName = string.gsub(spellName, "%s*%(Rank %d+%)", "")
|
||||
GameTooltip:AddLine(baseName, 1, 1, 1)
|
||||
@@ -222,7 +222,10 @@ local function GetPlayerOverflowBuffs()
|
||||
|
||||
local now = GetTime()
|
||||
for spellId, entry in pairs(overflowBuffs) do
|
||||
if entry.timestamp and entry.durationSec then
|
||||
-- v3.0+: Skip hidden auras (not real overflow)
|
||||
if _G.IsAuraHidden and _G.IsAuraHidden(spellId) == 1 then
|
||||
-- Hidden aura, don't show in overflow UI
|
||||
elseif entry.timestamp and entry.durationSec then
|
||||
local remaining = entry.durationSec - (now - entry.timestamp)
|
||||
if remaining > 0 then
|
||||
table.insert(results, {
|
||||
@@ -244,7 +247,7 @@ local function GetTargetOverflowBuffs()
|
||||
if not UnitExists("target") then return results end
|
||||
if not testMode and not (UnitInParty("target") or UnitInRaid("target")) then return results end
|
||||
|
||||
local _, targetGuid = UnitExists("target")
|
||||
local targetGuid = CleveRoids.GetGUID("target")
|
||||
if not targetGuid then return results end
|
||||
|
||||
local trackingData = CleveRoids.AllCasterAuraTracking
|
||||
@@ -267,7 +270,10 @@ local function GetTargetOverflowBuffs()
|
||||
local lib = CleveRoids.libdebuff
|
||||
|
||||
for spellId, auraData in pairs(trackingData[targetGuid]) do
|
||||
if auraData.start and auraData.duration then
|
||||
-- v3.0+: Skip hidden auras (not real overflow)
|
||||
if _G.IsAuraHidden and _G.IsAuraHidden(spellId) == 1 then
|
||||
-- Hidden aura, skip
|
||||
elseif auraData.start and auraData.duration then
|
||||
local remaining = auraData.duration + auraData.start - now
|
||||
if remaining > 0 then
|
||||
local isVisible = false
|
||||
@@ -410,11 +416,7 @@ local function RefreshDurations()
|
||||
|
||||
-- Target durations
|
||||
if targetFrame and targetFrame:IsVisible() then
|
||||
local targetGuid = nil
|
||||
if UnitExists("target") then
|
||||
local _, guid = UnitExists("target")
|
||||
targetGuid = guid
|
||||
end
|
||||
local targetGuid = CleveRoids.GetGUID("target")
|
||||
for i = 1, lastTargetCount do
|
||||
local data = targetIcons[i]
|
||||
if data.spellId and targetGuid then
|
||||
@@ -499,7 +501,7 @@ end
|
||||
-- Inject test entries for the current target
|
||||
local function InjectTestTargetData()
|
||||
if not UnitExists("target") then return end
|
||||
local _, targetGuid = UnitExists("target")
|
||||
local targetGuid = CleveRoids.GetGUID("target")
|
||||
if not targetGuid then return end
|
||||
|
||||
-- Clean up old test target if it changed
|
||||
|
||||
+134
-8
@@ -157,7 +157,15 @@
|
||||
Suffix matching is case-insensitive.
|
||||
Note: GetGUIDFromName is an internal C++ helper, NOT a new Lua global.
|
||||
|
||||
Current version: v2.41.0
|
||||
GetUnitGUID Rename, IsAuraHidden, Hidden Aura luaSlot Fix (v3.0+):
|
||||
- UnitGUID renamed to GetUnitGUID (global function). The addon uses SuperWoW's
|
||||
UnitExists for GUIDs so this rename is not breaking, but GetUnitGUID supports
|
||||
extended tokens (mark1-mark8, <base>owner/target/pet suffixes).
|
||||
- IsAuraHidden(spellId): returns 1 if the spell's aura is hidden from Lua aura
|
||||
APIs (UnitBuff/UnitDebuff won't show it). Useful for detecting hidden CC spells.
|
||||
- luaSlot in BUFF/DEBUFF events now returns 0 for hidden auras (was incorrect before).
|
||||
|
||||
Current version: v3.0.0
|
||||
]]
|
||||
|
||||
local _G = _G or getfenv(0)
|
||||
@@ -352,6 +360,11 @@ API.VERSION_REQUIREMENTS = {
|
||||
-- v2.41+ - Keyboard events and extended unit token support
|
||||
["KeyEvents"] = { 2, 41, 0 }, -- KEY_DOWN / KEY_UP events (keyboard input events)
|
||||
["ExtendedUnitTokens"] = { 2, 41, 0 }, -- Internal unit token resolution now supports "owner"/"target"/"pet"/"mark" in all Nampower functions (SetMouseoverUnit, UseItemIdOrName, etc.)
|
||||
|
||||
-- v3.0+ - GetUnitGUID rename, IsAuraHidden, hidden aura luaSlot fix
|
||||
["GetUnitGUID"] = { 3, 0, 0, "GetUnitGUID" },
|
||||
["IsAuraHidden"] = { 3, 0, 0, "IsAuraHidden" },
|
||||
["HiddenAuraLuaSlotFix"] = { 3, 0, 0 },
|
||||
}
|
||||
|
||||
-- Check if a specific feature is available
|
||||
@@ -530,6 +543,11 @@ local function InitializeFeatures()
|
||||
f.hasKeyEvents = API.HasFeature("KeyEvents")
|
||||
f.hasExtendedUnitTokens = API.HasFeature("ExtendedUnitTokens")
|
||||
|
||||
-- v3.0+ GetUnitGUID, IsAuraHidden, hidden aura luaSlot fix
|
||||
f.hasGetUnitGUID = API.HasFeature("GetUnitGUID")
|
||||
f.hasIsAuraHidden = API.HasFeature("IsAuraHidden")
|
||||
f.hasHiddenAuraLuaSlotFix = API.HasFeature("HiddenAuraLuaSlotFix")
|
||||
|
||||
-- Runtime detection for enhanced spell functions (verify by testing)
|
||||
if f.hasEnhancedSpellFunctions and GetSpellTexture then
|
||||
local success, result = pcall(function()
|
||||
@@ -783,12 +801,6 @@ function API.GetSpellNameById(spellId)
|
||||
if name then return name, rank end
|
||||
end
|
||||
|
||||
-- Fall back to SpellInfo (SuperWoW)
|
||||
if SpellInfo then
|
||||
local name = SpellInfo(spellId)
|
||||
if name then return name end
|
||||
end
|
||||
|
||||
-- Fall back to GetSpellRecField
|
||||
if GetSpellRecField then
|
||||
local name = GetSpellRecField(spellId, "name")
|
||||
@@ -1265,7 +1277,7 @@ function API.FindUnitAuraInfo(unitToken, searchSpellId, searchNameLower)
|
||||
if searchSpellId then
|
||||
matched = (auraId == searchSpellId)
|
||||
elseif searchNameLower then
|
||||
local name = SpellInfo and SpellInfo(auraId)
|
||||
local name = GetSpellRecField and GetSpellRecField(auraId, "name")
|
||||
if name then
|
||||
-- Strip rank suffix for consistent matching
|
||||
local baseName = string.gsub(name, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
@@ -2691,11 +2703,60 @@ end
|
||||
-- INITIALIZATION
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Hook UnitBuff/UnitDebuff to append spell IDs when SuperWoW is not available
|
||||
-- SuperWoW extends these to return spell IDs as extra return values.
|
||||
-- Without SuperWoW, we use GetUnitField(unit, "aura") to look up spell IDs.
|
||||
-- GetUnitField "aura" returns [1-32]=buff spellIDs, [33-48]=debuff spellIDs
|
||||
local function InstallAuraSpellIdHooks()
|
||||
if CleveRoids.hasSuperwow then return end -- SuperWoW already provides spell IDs
|
||||
if not _G.GetUnitField then return end -- Need GetUnitField for aura data
|
||||
|
||||
local _origUnitBuff = _G.UnitBuff
|
||||
local _origUnitDebuff = _G.UnitDebuff
|
||||
|
||||
-- UnitBuff(unit, index) => texture, stacks, spellID
|
||||
-- SuperWoW returns: texture, stacks, spellID
|
||||
_G.UnitBuff = function(unit, index)
|
||||
local texture, stacks = _origUnitBuff(unit, index)
|
||||
if not texture then return nil end
|
||||
|
||||
local spellID = nil
|
||||
local auras = _G.GetUnitField(unit, "aura")
|
||||
if auras then
|
||||
-- Buff index i maps to aura slot i (1-based)
|
||||
spellID = auras[index]
|
||||
if spellID and spellID <= 0 then spellID = nil end
|
||||
end
|
||||
|
||||
return texture, stacks, spellID
|
||||
end
|
||||
|
||||
-- UnitDebuff(unit, index) => texture, stacks, debuffType, spellID
|
||||
-- SuperWoW returns: texture, stacks, debuffType, spellID
|
||||
_G.UnitDebuff = function(unit, index)
|
||||
local texture, stacks, debuffType = _origUnitDebuff(unit, index)
|
||||
if not texture then return nil end
|
||||
|
||||
local spellID = nil
|
||||
local auras = _G.GetUnitField(unit, "aura")
|
||||
if auras then
|
||||
-- Debuff index i maps to aura slot 32 + i (1-based)
|
||||
spellID = auras[32 + index]
|
||||
if spellID and spellID <= 0 then spellID = nil end
|
||||
end
|
||||
|
||||
return texture, stacks, debuffType, spellID
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialize the API module
|
||||
function API.Initialize()
|
||||
-- Detect enhanced spell functions
|
||||
DetectEnhancedSpellFunctions()
|
||||
|
||||
-- Install UnitBuff/UnitDebuff spell ID hooks (when SuperWoW not available)
|
||||
InstallAuraSpellIdHooks()
|
||||
|
||||
-- Auto-enable required Nampower event CVars.
|
||||
-- Nampower reads CVars at DLL load time, so changes take effect on next reload.
|
||||
-- We set them now so every subsequent session works automatically.
|
||||
@@ -3247,5 +3308,70 @@ function API.LearnTalentRank(talentPage, talentIndex, rank)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Get unit GUID by token (v3.0+)
|
||||
-- Supports extended tokens: mark1-mark8, <base>owner/target/pet suffixes
|
||||
function API.GetUnitGUID(unitToken)
|
||||
if not API.features.hasGetUnitGUID or not _G.GetUnitGUID then
|
||||
return nil
|
||||
end
|
||||
return _G.GetUnitGUID(unitToken)
|
||||
end
|
||||
|
||||
-- Check if a spell's aura would be hidden from Lua aura APIs (v3.0+)
|
||||
function API.IsAuraHidden(spellId)
|
||||
if not API.features.hasIsAuraHidden or not _G.IsAuraHidden then
|
||||
return nil
|
||||
end
|
||||
return _G.IsAuraHidden(spellId)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- HEALTH/POWER WRAPPERS (GetUnitField extended token support with fallback)
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Get unit health via GetUnitField (extended token support) with standard API fallback
|
||||
function API.GetUnitHealth(unitToken)
|
||||
if API.features.hasGetUnitField and GetUnitField then
|
||||
local val = GetUnitField(unitToken, "health")
|
||||
if val then return val end
|
||||
end
|
||||
return UnitHealth(unitToken)
|
||||
end
|
||||
|
||||
function API.GetUnitMaxHealth(unitToken)
|
||||
if API.features.hasGetUnitField and GetUnitField then
|
||||
local val = GetUnitField(unitToken, "maxHealth")
|
||||
if val then return val end
|
||||
end
|
||||
return UnitHealthMax(unitToken)
|
||||
end
|
||||
|
||||
-- powerType: nil=current, 0=mana, 1=rage, 2=focus, 3=energy
|
||||
-- GetUnitField uses power1-power4 fields
|
||||
local POWER_FIELDS = { [0] = "power1", [1] = "power2", [2] = "power3", [3] = "power4" }
|
||||
local MAX_POWER_FIELDS = { [0] = "maxPower1", [1] = "maxPower2", [2] = "maxPower3", [3] = "maxPower4" }
|
||||
|
||||
function API.GetUnitPower(unitToken, powerType)
|
||||
if API.features.hasGetUnitField and GetUnitField and powerType then
|
||||
local field = POWER_FIELDS[powerType]
|
||||
if field then
|
||||
local val = GetUnitField(unitToken, field)
|
||||
if val then return val end
|
||||
end
|
||||
end
|
||||
return UnitMana(unitToken)
|
||||
end
|
||||
|
||||
function API.GetUnitMaxPower(unitToken, powerType)
|
||||
if API.features.hasGetUnitField and GetUnitField and powerType then
|
||||
local field = MAX_POWER_FIELDS[powerType]
|
||||
if field then
|
||||
local val = GetUnitField(unitToken, field)
|
||||
if val then return val end
|
||||
end
|
||||
end
|
||||
return UnitManaMax(unitToken)
|
||||
end
|
||||
|
||||
-- Expose API globally for other addons
|
||||
_G.CleveRoidsNampowerAPI = API
|
||||
|
||||
+508
-245
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user