mirror of
https://github.com/brues-code/SuperCleveRoidMacros.git
synced 2026-09-16 03:38:00 +00:00
Add [locked]/[nolocked] school-interrupt conditional via C_LossOfControl
Detects a spell-school interrupt lockout (Counterspell/Kick/Pummel/Earth Shock) on the player -- the server-side lockout that no debuff scan can see, since it's a SMSG_SPELL_COOLDOWN packet, not an aura. ClassicAPI's C_LossOfControl aggregates it as SCHOOL_INTERRUPT with a lockoutSchool mask. ClassicAPI.GetSchoolLockout() returns the locked school mask; ValidateSchoolLocked tests a school name against it (bitmask check without the 5.1-only % operator). [locked] = any school kicked, [locked:frost] = that school, [locked:fire/frost] = either; [nolocked:...] negates with AND (neither). Registered in BOOLEAN_CONDITIONALS for the bare form; LOSS_OF_CONTROL_ADDED/UPDATE wired to refresh the icon. Full silences remain [mycc:silence].
This commit is contained in:
@@ -208,6 +208,31 @@ function API.GetEnchantName(enchantID)
|
||||
return info and info.name or nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Loss Of Control
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Locked spell-school mask from an active SCHOOL_INTERRUPT (Counterspell / Kick /
|
||||
-- Pummel / Earth Shock lockout) on the player, or 0 when not kicked. Read from
|
||||
-- C_LossOfControl, which synthesizes the lockout from the server's own
|
||||
-- SMSG_SPELL_COOLDOWN packet -- a state no debuff scan can see. Also returns the
|
||||
-- seconds remaining (nil if ClassicAPI didn't observe the applying cast). Returns
|
||||
-- 0 for a client without C_LossOfControl. Player-only (vanilla LoC is local-only).
|
||||
function API.GetSchoolLockout()
|
||||
if type(C_LossOfControl) ~= "table"
|
||||
or type(C_LossOfControl.GetActiveLossOfControlDataCount) ~= "function" then
|
||||
return 0, nil
|
||||
end
|
||||
local n = C_LossOfControl.GetActiveLossOfControlDataCount() or 0
|
||||
for i = 1, n do
|
||||
local d = C_LossOfControl.GetActiveLossOfControlData(i)
|
||||
if d and d.locType == "SCHOOL_INTERRUPT" then
|
||||
return d.lockoutSchool or 0, d.timeRemaining
|
||||
end
|
||||
end
|
||||
return 0, nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Spell
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
+58
-21
@@ -2953,11 +2953,8 @@ function CleveRoids.CountEnemiesMatching(checkFunc)
|
||||
tryUnit("targettarget")
|
||||
tryUnit("targettargettarget")
|
||||
tryUnit("pettarget")
|
||||
if pfUI and pfUI.uf and pfUI.uf.focus and pfUI.uf.focus.label and pfUI.uf.focus.id then
|
||||
local focusUnit = pfUI.uf.focus.label .. pfUI.uf.focus.id
|
||||
tryUnit(focusUnit)
|
||||
tryUnit(focusUnit .. "target")
|
||||
end
|
||||
tryUnit("focus")
|
||||
tryUnit("focustarget")
|
||||
for i = 1, 4 do
|
||||
tryUnit("party" .. i .. "target")
|
||||
end
|
||||
@@ -2967,22 +2964,8 @@ function CleveRoids.CountEnemiesMatching(checkFunc)
|
||||
end
|
||||
end
|
||||
|
||||
-- 3. Nameplate scan: visible nameplates give live GUIDs without target switching.
|
||||
-- ClassicAPI's C_NamePlate.GetNamePlateGUIDs() lists every unit with an
|
||||
-- allocated nameplate (including default vanilla nameplates), replacing the
|
||||
-- old WorldFrame child-walk + frame:GetName(1) GUID-extraction.
|
||||
local plateGuids = CleveRoids.ClassicAPI.GetNamePlateGUIDs()
|
||||
if plateGuids then
|
||||
for i = 1, table.getn(plateGuids) do
|
||||
local guid = plateGuids[i]
|
||||
if guid and not checked[guid] and UnitExists(guid) and UnitCanAttack("player", guid) then
|
||||
checked[guid] = true
|
||||
CleveRoids.knownEnemyGuids[guid] = true
|
||||
if checkFunc(guid) then
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
for i = 1, 40 do
|
||||
tryUnit("nameplate"..i)
|
||||
end
|
||||
|
||||
-- During tooltip evaluation, skip known-enemy cache iteration.
|
||||
@@ -5228,6 +5211,33 @@ function CleveRoids.GetSpellMechanic(spellID)
|
||||
return CleveRoids.ClassicAPI.GetSpellMechanicByID(spellID) or 0
|
||||
end
|
||||
|
||||
-- School name -> spell-school mask bit (WoW SPELL_SCHOOL_MASK_*).
|
||||
local LOCKOUT_SCHOOL_MASK = {
|
||||
physical = 1, holy = 2, fire = 4, nature = 8, frost = 16, shadow = 32, arcane = 64,
|
||||
}
|
||||
|
||||
-- Is `bit` set in `mask`? Shift right past `bit`, then test the low bit with
|
||||
-- math.mod (the % operator is 5.1-only; 1.12 is Lua 5.0, but math.mod exists).
|
||||
local function SchoolMaskHasBit(mask, bit)
|
||||
if not mask or mask < bit then return false end
|
||||
return math.mod(math.floor(mask / bit), 2) == 1
|
||||
end
|
||||
|
||||
-- [locked] / [locked:school] -- player is under a spell-school interrupt lockout
|
||||
-- (Counterspell / Kick / Pummel / Earth Shock), read from C_LossOfControl. This
|
||||
-- is the lockout no debuff scan can detect; full silences stay on [mycc:silence].
|
||||
-- school nil/true = any school kicked; a name matches that school's mask bit.
|
||||
function CleveRoids.ValidateSchoolLocked(school)
|
||||
local mask = CleveRoids.ClassicAPI.GetSchoolLockout()
|
||||
if not mask or mask == 0 then return false end
|
||||
if school == nil or school == true or school == "" then
|
||||
return true
|
||||
end
|
||||
local bit = LOCKOUT_SCHOOL_MASK[string.lower(school)]
|
||||
if not bit then return false end
|
||||
return SchoolMaskHasBit(mask, bit)
|
||||
end
|
||||
|
||||
-- Validate CC on a unit (target, focus, player, etc.)
|
||||
-- Returns true if the unit has the specified CC mechanic active
|
||||
function CleveRoids.ValidateUnitCC(unit, ccType)
|
||||
@@ -8499,6 +8509,33 @@ CleveRoids.Keywords = {
|
||||
end, conditionals, "nomycc")
|
||||
end,
|
||||
|
||||
-- [locked] / [locked:school] - player is under a spell-school interrupt
|
||||
-- lockout (Counterspell/Kick/Pummel/Earth Shock), via ClassicAPI
|
||||
-- C_LossOfControl -- the server lockout no debuff scan can see. Bare = any
|
||||
-- school kicked; [locked:frost] = that school; [locked:fire/frost] = either.
|
||||
-- Full silences are separate ([mycc:silence]). Player-only.
|
||||
locked = function(conditionals)
|
||||
local v = conditionals.locked
|
||||
if v == nil or v == true or (type(v) == "table" and table.getn(v) == 0) then
|
||||
return CleveRoids.ValidateSchoolLocked(nil)
|
||||
end
|
||||
return Or(v, function(school)
|
||||
return CleveRoids.ValidateSchoolLocked(school)
|
||||
end)
|
||||
end,
|
||||
|
||||
-- [nolocked:school] - player is NOT school-locked. AND logic on negation:
|
||||
-- [nolocked:fire/frost] = neither Fire nor Frost is kicked.
|
||||
nolocked = function(conditionals)
|
||||
local v = conditionals.nolocked
|
||||
if v == nil or v == true or (type(v) == "table" and table.getn(v) == 0) then
|
||||
return not CleveRoids.ValidateSchoolLocked(nil)
|
||||
end
|
||||
return NegatedMulti(v, function(school)
|
||||
return not CleveRoids.ValidateSchoolLocked(school)
|
||||
end, conditionals, "nolocked")
|
||||
end,
|
||||
|
||||
-- ========================================================================
|
||||
-- RESIST TRACKING CONDITIONALS
|
||||
-- ========================================================================
|
||||
|
||||
@@ -151,6 +151,8 @@ local BOOLEAN_CONDITIONALS = {
|
||||
nomhenchant = true,
|
||||
ohenchant = true,
|
||||
noohenchant = true,
|
||||
locked = true,
|
||||
nolocked = true,
|
||||
group = true,
|
||||
nogroup = true,
|
||||
moving = true,
|
||||
@@ -1581,18 +1583,9 @@ function CleveRoids.TryTargetFocus()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Resolves the player's focus to a usable unit token.
|
||||
-- Prefers pfUI's emulated focus (resolves to a real token like "party2"/"raid5")
|
||||
-- for pfUI users, then falls back to ClassicAPI's native "focus" token (which
|
||||
-- every UnitX function accepts) for everyone else.
|
||||
-- Returns the resolved token, or nil when no focus is set so @focus clauses
|
||||
-- silently fall through to the next macro alternative (no warning spam).
|
||||
function CleveRoids.GetFocusUnitId()
|
||||
if pfUI and pfUI.uf and pfUI.uf.focus and pfUI.uf.focus.label and pfUI.uf.focus.id
|
||||
and UnitExists(pfUI.uf.focus.label .. pfUI.uf.focus.id) then
|
||||
return pfUI.uf.focus.label .. pfUI.uf.focus.id
|
||||
end
|
||||
-- ClassicAPI native focus token (set via /focus or the FOCUSTARGET keybind)
|
||||
if UnitExists("focus") then
|
||||
return "focus"
|
||||
end
|
||||
@@ -4860,6 +4853,13 @@ CleveRoids.Frame:RegisterEvent("PLAYER_REGEN_ENABLED") -- Left actual combat (n
|
||||
CleveRoids.Frame:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
|
||||
CleveRoids.Frame:RegisterEvent("SPELL_UPDATE_COOLDOWN")
|
||||
CleveRoids.Frame:RegisterEvent("PLAYER_STARTED_MOVING")
|
||||
-- ClassicAPI loss-of-control (school-interrupt lockout) for [locked]/[nolocked].
|
||||
-- Gated on the namespace so an older ClassicAPI without it doesn't error on an
|
||||
-- unknown event.
|
||||
if type(C_LossOfControl) == "table" then
|
||||
CleveRoids.Frame:RegisterEvent("LOSS_OF_CONTROL_ADDED")
|
||||
CleveRoids.Frame:RegisterEvent("LOSS_OF_CONTROL_UPDATE")
|
||||
end
|
||||
-- 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")
|
||||
@@ -5799,6 +5799,13 @@ function CleveRoids.Frame:PLAYER_FOCUS_CHANGED()
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
-- School-interrupt lockout applied/changed -> refresh [locked]/[nolocked] icons.
|
||||
function CleveRoids.Frame:LOSS_OF_CONTROL_ADDED()
|
||||
if CleveRoidMacros.realtime == 0 then
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
CleveRoids.Frame.LOSS_OF_CONTROL_UPDATE = CleveRoids.Frame.LOSS_OF_CONTROL_ADDED
|
||||
function CleveRoids.Frame:UPDATE_SHAPESHIFT_FORM()
|
||||
if CleveRoidMacros.realtime == 0 then
|
||||
CleveRoids.QueueActionUpdate()
|
||||
|
||||
Reference in New Issue
Block a user