22 Commits

Author SHA1 Message Date
Brues 1770f7b6e1 Make SendChatMessage reclaim cycle-safe and cover LVL
The previous reclaim stack-overflowed when LeafVillageAchievements loaded
after us (its captured "original" was our own function, so reclaiming onto
the top created an ours<->LVA loop). Add a reentrancy guard plus a base
SendChatMessage reference so a hook cycle routes straight to the base
function instead of recursing.

Gate the reclaim on LeafVillageAchievements OR LeafVillageLegends (both hook
SendChatMessage and can bump ours off the top -- LVA orphans it, LVL wraps
and re-installs on timers). Keep the anchored ^#showtooltip match since being
on top means we see the pristine line.
2026-07-24 14:09:36 -05:00
Brues d060b04908 Reclaim SendChatMessage hook so #showtooltip stays filtered
Our #showtooltip filter hooks the global SendChatMessage. An addon that
snapshots SendChatMessage at its own file-load and later calls that
snapshot directly (e.g. LeafVillageAchievements at PLAYER_ENTERING_WORLD+3s)
orphans our hook if it loaded before us -- its snapshot predates our filter,
so #showtooltip leaks to chat. This bites the fork specifically: it sorts
after LeafVillageAchievements alphabetically, so it loads too late to be in
the snapshot, whereas upstream "CleveRoidMacros" sorted before it.

Make the filter a named function and add EnsureSendChatMessageHook, which
re-asserts it as the outermost SendChatMessage hook (no-op once on top).
OnUpdate calls it each throttled tick via a cheap identity check, so we
reclaim the top of the chain within a frame of being displaced. Normal
messages still flow through the chained-over hook untouched.
2026-07-24 09:41:26 -05:00
Brues 6ac69501f5 pass base object rather than ItemLocation 2026-07-20 10:35:09 -05:00
Brues 782c685fba Replace tooltip-scanning GetSpellCost with ClassicAPI DBC reads
GetSpellCost now reads power cost and reagents straight from Spell.dbc via
C_Spell.GetSpellPowerCost (effective, talent-modified cost) and
C_Spell.GetSpellReagents (itemID), dropping the GameTooltip owner/scan
frames, their font strings, and all locale-dependent line parsing.

Reagent counting is now itemID-based end to end: GetReagentCount takes an
itemID and matches by id in the Items cache / bag scan. This removes the
hardcoded English reagent tables (_ReagentBySpell, _ReagentIdByName) and
the name-matching bag-scan tooltip, so it works on any client locale.
Verified in-game that GetSpellReagents covers DBC reagent spells (Vanish
-> Flash Powder), which the hand table previously special-cased.

The localized reagent name is still used for countedItemTypes registration
(recognizing a reagent item placed on the action bar); when that name
isn't cached yet, warm it via the ClassicAPI Item mixin
(Item:CreateFromItemID/ContinueOnItemLoad) and register it once it lands.
2026-07-19 16:34:19 -05:00
Brues 97e898f14c Add /cancelform command and CancelShapeshiftForm
Adds a new /cancelform slash command (Console.lua) wired to CleveRoids.DoCancelForm. Replaces the previous _unshiftAction with _cancelFormAction that calls CancelShapeshiftForm, and updates DoUnshift to delegate to DoCancelForm for backwards compatibility. Also fixes a unit name check by replacing GetUnitName with UnitName in DoRetarget.
2026-07-19 14:32:13 -05:00
Brues b84835a567 Use GetInventoryItemID instead of string parsing 2026-07-17 21:25:25 -05:00
Brues 40cf2c8010 More ClassicAPI porting 2026-07-15 19:45:31 -05:00
Brues a5a0b9c00a Adopt ClassicAPI C_Item.GetItemName in Utility.lua equip-modifier debug
Replace the debug-only GetInventoryItemLink name scrape with the
decorated C_Item.GetItemName location form.
2026-07-15 19:36:18 -05:00
Brues 6e57ff01dc Adopt ClassicAPI C_Item item reads in Tooltip/Generic.lua indexers
Migrate the link-scrape-then-discard sites to direct ClassicAPI reads:

- IndexEquippedItems / IndexEquipSlot: GetInventoryItemID for the id
  (GetItemInfo still supplies the stored base link/texture)
- IndexItems bag+equip scans: GetContainerItemID/GetInventoryItemID +
  C_Item.GetItemName (decorated) for the dedup fast-path; drop the now
  dead GetContainerItemLink/GetInventoryItemLink locals
- GetItemFast cache validation: alloc-free id compare via
  GetInventoryItemID/GetContainerItemID, decorated-name compare otherwise
- IsItemEquipped: GetInventoryItemID + C_Item.GetItemName

Left untouched: makeInventoryItem/makeBagItem and the GetItem/GetItemFast
scan loops, which build a real link that is stored on the item and later
fed to GameTooltip:SetHyperlink.

Note: the equipped-scan loops now start at slot 1 (GetInventoryItemID
requires slot>=1), so the ammo slot (0) is no longer walked by these
indexers -- ammo is not referenced by name anywhere in the addon.
2026-07-15 19:33:07 -05:00
Brues 9cd79d682d Adopt ClassicAPI C_Item item reads in Conditionals.lua
Replace GetInventoryItemLink/GetContainerItemLink link-scraping with
direct ClassicAPI reads across the item conditionals:

- [equipped] cache build: GetInventoryItemID + C_Item.GetItemName
  (decorated name replaces the old bracket-name / GetItemInfo two-step)
- slot-number -> item name resolves ([cd], [usable]/[nousable]):
  C_Item.GetItemName location form
- HasItem / GetItemCooldown substring fallbacks: match the decorated
  name instead of the raw link string
- numeric-slot presence check: GetInventoryItemID

Suffix decoration is preserved via the location form, so partial/
suffixed [equipped:...] matches behave as before.
2026-07-15 19:17:00 -05:00
Brues f54eda5ae3 Adopt ClassicAPI C_Item/C_Container item reads in Core.lua
Replace GetInventoryItemLink/GetContainerItemLink link-scraping (built
solely to regex out item:ID or the bracketed name) with direct ClassicAPI
reads:

- id/presence: GetInventoryItemID, C_Container.GetContainerItemID
- suffix-sensitive names (equip-by-name on gear): C_Item.GetItemName
  location form, which now carries random-suffix decoration
- suffix-free names (consumables/reagents/poisons) in hot bag scans:
  id + C_Item.GetItemNameByID (base name, zero table allocation)

Also covers /use equipped-slot resolution and the WDB warm scans. Drops
the now-dead GetContainerItemLink/GetInventoryItemLink/string_find
upvalue aliases. No behavior change; equip-by-name keeps full suffixed
matching via the decorated location form.
2026-07-15 19:12:56 -05:00
Brues 653f8db3d7 Reconcile /startattack against real action-bar state, not cached flag
The autoAttack flag could drift stale-true (optimistic set after
AttackTarget, or a target dying without PLAYER_LEAVE_COMBAT), making
/startattack skip the attack until the target was dropped and reselected.
The old fallback called the overridden IsCurrentAction, which just echoes
the cached flag for the attack slot, so it never detected drift. Use the
original Hooks.IsCurrentAction as ground truth and sync the flag to it.
2026-07-04 19:38:37 -05:00
Brues 86fb0254e6 Show autoattack icon and glow 2026-06-30 12:34:34 -05:00
Brues fc640abb07 Render known-spell action tooltips via spellbook slot, not spellID
GameTooltip.SetAction used GameTooltip:SetSpellByID for spell actions, which
renders the static DBC tooltip. For spells we resolved from the player's own
spellbook, use GameTooltip:SetSpell(spellSlot, bookType) instead so the
tooltip shows live player-accurate data (mana cost, cooldown, range coloring,
reagent counts). spellSlot/bookType/id all come from the same spellbook index
entry, so it renders the identical spell and rank. SetSpellByID remains as a
defensive fallback for entries without a slot. Applied to both the direct and
nested-macro tooltip paths.
2026-06-23 12:41:17 -05:00
Brues 3384765faa dont need pcall around registering events 2026-06-22 13:04:05 -05:00
Brues ceaf7c2c43 Refresh [moving] macro icons on movement via ClassicAPI
Register PLAYER_STARTED_MOVING (ClassicAPI, edge-detected off the WASD/
autorun key state) and queue an action update so [moving]/[nomoving] macro
icons repaint when movement starts.

PLAYER_STOPPED_MOVING is deliberately NOT used -- it's key-release based and
misses real stops (running into geometry, click-to-move, roots, knockback).
Instead, STARTED kicks off a 0.1s C_Timer.NewTicker that watches
IsPlayerMoving() (the same speed>0/falling signal [moving] evaluates) and, on
the actual stop, refreshes once and cancels itself. No timer exists while
stopped, so there's no idle cost; guarded on isShuttingDown and event-driven
mode (realtime==0).
2026-06-22 12:58:59 -05:00
Brues 963ad21297 Show resolved icon for question-mark macros in the macro list
Macros with no chosen icon (e.g. "#showtooltip Shoot") display Blizzard's
default question mark in the macro UI. After each MacroFrame_Update, swap
that placeholder for the icon the action bar would show, resolved from the
macro's #showtooltip/first action via GetMacroByIndex.

- Only replaces icons that are currently the question mark, so user-chosen
  icons are never touched.
- Covers both the list buttons (MacroButtonNIcon) and the selected-macro
  detail icon.
- Purely cosmetic: never changes the saved icon; Blizzard repaints the
  default on the next refresh if resolution fails or the macro changes.
- Installed in MacroErrorUI's existing hook path (gated on Blizzard_MacroUI
  load and the SuperMacro guard).
2026-06-22 00:35:19 -05:00
Brues ae09b23afd Resolve item sets via ClassicAPI; drop Reliquary dependency
Item-set membership and set info now read ItemSet.dbc directly through
ClassicAPI instead of the nampower/Reliquary glue, so set features no
longer require the Reliquary DLL to be installed.

- ClassicAPI.lua: add GetItemSetIDByID and GetItemSetInfo wrappers.
- Utility.lua: repoint ResolveSetItems, CountEquippedSetItemsBySetId,
  GetEquippedItemSetInfo, and GetEquippedSetPieceCount at the ClassicAPI
  accessors. Set-name matching now uses the DBC name (localized; identical
  to the old enUS path on English clients).
- NampowerAPI.lua: remove the now-unused GetItemSet/GetItemSetId/
  GetItemSetItems/GetItemSetBonuses, the dead GetSpellEffectRadius (no
  callers, only radius source was Reliquary), and the orphaned RQ_SafeCall.
- Init.lua: drop hasReliquary detection and its startup feature line.
- Conditionals.lua: update the [set:] comment (no longer Reliquary-gated).
2026-06-21 14:29:28 -05:00
Brues a8bf7fbc0f Identify equipped weapon type by item subclass, not localized name
HasWeaponEquipped matched the localized GetItemInfo subtype string, which
required a hand-maintained translation of all 13 weapon/shield subtypes per
locale plus brittle "^Fist"/last-word string parsing.

Use the locale-independent class/subclass IDs from C_Item.GetItemInfoInstant
instead:
- Init.lua: WeaponTypeNames entries now carry numeric class + subClass set
  (Axes/Swords/Maces span their 1H+2H subclasses; Shields are armor class 4).
- Conditionals.lua: HasWeaponEquipped resolves the slot's itemID via
  ClassicAPI GetInventoryItemID, then compares classID/subClassID -- no link
  parsing, no string munging.
- Localization.lua: drop the now-unused weapon-subtype strings from every
  locale block (112 lines).
2026-06-21 14:16:56 -05:00
Brues f0f57330c5 Drop dead localization entries
Remove localization data with no consumers anywhere in the addon:
- ItemTypes tables (Consumable/Reagent/Projectile/Trade Goods) - unused
- SpellRank patterns - unused (the live GetSpellRank is a BuffLib method)
- Spells keys Revenge, Overpower, Riposte, Surprise Attack, Lacerate,
  Baited Shot, Counterattack, Arcane Surge - unused; only Shadowform,
  Stealth, Prowl, Shadowmeld are referenced.

133 lines removed across all locale blocks; no behavior change.
2026-06-21 14:12:33 -05:00
Brues f21f90d0f1 Adopt ClassicAPI accessors: cursor, item IDs, spell mechanic
Lean on ClassicAPI's backported readers instead of link-string parsing
and a hand-maintained mechanic table.

- ClassicAPI.lua: add wrappers GetCursorInfo/CursorHoldsItemID,
  GetContainerItemID, GetInventoryItemID, and GetSpellMechanicByID.
- Core.lua: in the manual equip fallback, verify the cursor holds the
  intended item (CursorHoldsItemID) before EquipCursorItem, aborting only
  on a definitive mismatch so empty/unknown cursors behave as before.
- NampowerAPI.lua / Utility.lua: replace GetContainerItemLink /
  GetInventoryItemLink + "item:(%d+)" parsing with direct C_Container/
  inventory ID lookups at the sites that only need the itemID; route the
  equipped-set scans through the GetEquippedItemID helper.
- Conditionals.lua / Utility.lua: replace the 785-entry CCSpellMechanics
  fallback table with C_Spell.GetSpellMechanicByID in GetSpellMechanic and
  GetSpellCCType (BuffLib / nampower paths unchanged); delete the table.
2026-06-21 14:02:49 -05:00
Brues d435d90871 useless comment 2026-06-21 03:38:50 -05:00
11 changed files with 672 additions and 1388 deletions
-2
View File
@@ -20,6 +20,4 @@ jobs:
- name: Package and release to GitHub
uses: BigWigsMods/packager@v2
env:
# Only GITHUB_OAUTH is set, so the packager attaches the zip to a
# GitHub Release and uploads nothing to CurseForge/WoWInterface/Wago.
GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}
+71
View File
@@ -119,6 +119,55 @@ function API.GetActionInfo(slot)
return GetActionInfo(slot)
end
--------------------------------------------------------------------------------
-- Container
--------------------------------------------------------------------------------
-- Base itemID in (bagID, slot), or nil for an empty/invalid slot. Same value
-- the "item:(%d+)" parse of GetContainerItemLink yields, but resolved straight
-- from the CGItem -- no link string built, no Lua pattern match.
function API.GetContainerItemID(bagID, slot)
return C_Container.GetContainerItemID(bagID, slot)
end
-- Base itemID equipped in `unit`'s 1-based inventory `slot` (1-19), or nil for
-- an empty slot / NPC unit. Same arg shape as GetInventoryItemLink and the same
-- value its "item:(%d+)" parse yields, resolved straight from the item instance.
function API.GetInventoryItemID(unit, slot)
return GetInventoryItemID(unit, slot)
end
--------------------------------------------------------------------------------
-- Item Set
--------------------------------------------------------------------------------
-- ItemSet.dbc ID that `itemID` belongs to, or nil if it isn't part of a set
-- (or isn't cached yet). Reads the item's m_itemSet field directly -- no
-- Reliquary, no per-set ItemID[] scan.
function API.GetItemSetIDByID(itemID)
return C_Item.GetItemSetIDByID(itemID)
end
-- Table describing an ItemSet.dbc row, or nil if `setID` doesn't resolve:
-- { setID, name (localized), requiredSkill, requiredSkillRank,
-- items = { itemID, ... }, bonuses = { { spellID, threshold }, ... } }
function API.GetItemSetInfo(setID)
return C_Item.GetItemSetInfo(setID)
end
--------------------------------------------------------------------------------
-- Spell
--------------------------------------------------------------------------------
-- WoW SpellMechanic enum ID for a spell, read straight from Spell.dbc -- covers
-- every spell the client knows, not just the spellbook (1=Charm, 5=Fear,
-- 7=Root, 12=Stun, 17=Polymorph, ...). Returns (mechanicID, enUS name); the ID
-- is 0 for a known spell with no mechanic, and the whole call is nil for an
-- invalid spell ID. Replaces hand-maintained spellID -> mechanic tables.
function API.GetSpellMechanicByID(spellID)
return C_Spell.GetSpellMechanicByID(spellID)
end
--------------------------------------------------------------------------------
-- State
--------------------------------------------------------------------------------
@@ -133,6 +182,28 @@ function API.IsSwimming()
return IsSwimming() and true or false
end
--------------------------------------------------------------------------------
-- Cursor
--------------------------------------------------------------------------------
function API.GetCursorInfo()
return GetCursorInfo()
end
-- Tri-state check of whether the cursor holds the item with `itemID`:
-- true -> cursor holds exactly that item
-- false -> cursor holds a DIFFERENT item
-- nil -> can't tell (cursor empty / not an item / itemID unknown)
-- Callers should only act on an explicit `false`, leaving the nil case to the
-- existing CursorHasItem() behavior.
function API.CursorHoldsItemID(itemID)
if not itemID then return nil end
local kind, id = GetCursorInfo()
if kind ~= "item" then return nil end
if not id then return nil end
return id == itemID
end
--------------------------------------------------------------------------------
-- NamePlate
--------------------------------------------------------------------------------
+55 -255
View File
@@ -273,24 +273,17 @@ local function BuildEquipmentCache()
end
end
-- Fallback: manual slot enumeration
-- Fallback: manual slot enumeration via ClassicAPI (id + decorated name),
-- no link string built. C_Item.GetItemName carries random-suffix decoration
-- and falls back to the base name internally, so it replaces the old
-- bracket-name / GetItemInfo two-step in a single call.
for slot = 1, 19 do
local link = GetInventoryItemLink("player", slot)
if link then
local _, _, id = string_find(link, "item:(%d+)")
local _, _, nameInBrackets = string_find(link, "%[(.+)%]")
if id then
_equippedItemIDs[slot] = tonumber(id)
end
if nameInBrackets then
_equippedItemNames[slot] = string_lower(nameInBrackets)
elseif id then
-- Fallback: resolve via GetItemInfo
local itemName = GetItemInfo(tonumber(id))
if itemName then
_equippedItemNames[slot] = string_lower(itemName)
end
local id = GetInventoryItemID("player", slot)
if id then
_equippedItemIDs[slot] = id
local name = C_Item.GetItemName({ equipmentSlotIndex = slot })
if name then
_equippedItemNames[slot] = string_lower(name)
end
end
end
@@ -350,8 +343,7 @@ function CleveRoids.FindItemLocation(item)
if numericItem then
-- Check if it's an equipment slot (1-19)
if numericItem >= 1 and numericItem <= 19 then
local link = GetInventoryItemLink("player", numericItem)
if link then
if GetInventoryItemID("player", numericItem) then
return { type = "inventory", inventoryID = numericItem }
end
return nil
@@ -2094,34 +2086,21 @@ end
-- weaponType: The name of the weapon's type (e.g. Axe, Shield, etc.)
-- returns: True when equipped, otherwhise false
function CleveRoids.HasWeaponEquipped(weaponType)
if not CleveRoids.WeaponTypeNames[weaponType] then
local def = CleveRoids.WeaponTypeNames[weaponType]
if not def then
return false
end
local slotName = CleveRoids.WeaponTypeNames[weaponType].slot
local localizedName = CleveRoids.WeaponTypeNames[weaponType].name
local slotId = GetInventorySlotInfo(slotName)
local slotLink = GetInventoryItemLink("player",slotId)
if not slotLink then
local slotId = GetInventorySlotInfo(def.slot)
local itemId = CleveRoids.ClassicAPI.GetInventoryItemID("player", slotId)
if not itemId then
return false
end
local _,_,itemId = string.find(slotLink,"item:(%d+)")
if not itemId then -- Also good to check if itemId was found
return false
end
local _name,_link,_,_lvl,_type,subtype = GetItemInfo(itemId)
-- just had to be special huh?
local fist = string.find(subtype,"^Fist")
-- drops things like the One-Handed prefix
local _,_,subtype = string.find(subtype,"%s?(%S+)$")
if subtype == localizedName or (fist and (CleveRoids.WeaponTypeNames[weaponType].name == CleveRoids.Localized.FistWeapon)) then
return true
end
return false
-- Compare locale-independent item class/subclass instead of matching the
-- localized subtype string (GetItemInfoInstant: ..., classID, subClassID).
local _, _, _, _, _, classID, subClassID = C_Item.GetItemInfoInstant(itemId)
return classID == def.class and def.subClass[subClassID] == true
end
-- Checks whether or not the given UnitId is in your party or your raid
@@ -3479,11 +3458,8 @@ function CleveRoids.ValidateCooldown(args, ignoreGCD)
-- If this is a numeric slot (1-19), resolve to the equipped item's name
local slotNum = tonumber(name)
if slotNum and slotNum >= 1 and slotNum <= 19 then
local link = GetInventoryItemLink("player", slotNum)
if link then
local _, _, itemName = string.find(link, "%[(.+)%]")
if itemName then name = itemName end
end
local itemName = C_Item.GetItemName({ equipmentSlotIndex = slotNum })
if itemName then name = itemName end
end
args = {name = name}
else
@@ -3494,11 +3470,8 @@ function CleveRoids.ValidateCooldown(args, ignoreGCD)
-- If this is a numeric slot (1-19), resolve to the equipped item's name
local slotNum = tonumber(name)
if slotNum and slotNum >= 1 and slotNum <= 19 then
local link = GetInventoryItemLink("player", slotNum)
if link then
local _, _, itemName = string.find(link, "%[(.+)%]")
if itemName then name = itemName end
end
local itemName = C_Item.GetItemName({ equipmentSlotIndex = slotNum })
if itemName then name = itemName end
end
args.name = name
else
@@ -4882,13 +4855,11 @@ function CleveRoids.HasItem(item)
if type(item) == "string" and item ~= "" then
local itemLower = string.lower(item)
-- Check equipped slots for substring match
for slot = 0, 19 do
local link = GetInventoryItemLink("player", slot)
if link then
if string.find(string.lower(link), itemLower, 1, true) then
return true
end
-- Check equipped slots for substring match (decorated name, no link build)
for slot = 1, 19 do
local name = C_Item.GetItemName({ equipmentSlotIndex = slot })
if name and string.find(string.lower(name), itemLower, 1, true) then
return true
end
end
@@ -4897,11 +4868,9 @@ function CleveRoids.HasItem(item)
local size = GetContainerNumSlots(bag)
if size and size > 0 then
for slotIndex = 1, size do
local link = GetContainerItemLink(bag, slotIndex)
if link then
if string.find(string.lower(link), itemLower, 1, true) then
return true
end
local name = C_Item.GetItemName({ bagID = bag, slotIndex = slotIndex })
if name and string.find(string.lower(name), itemLower, 1, true) then
return true
end
end
end
@@ -4946,14 +4915,12 @@ function CleveRoids.GetItemCooldown(item)
local itemLower = string.lower(item)
local start, dur, en
-- Check equipped slots for substring match
for slot = 0, 19 do
local link = GetInventoryItemLink("player", slot)
if link then
if string.find(string.lower(link), itemLower, 1, true) then
start, dur, en = GetInventoryItemCooldown("player", slot)
return _norm(start, dur, en)
end
-- Check equipped slots for substring match (decorated name, no link build)
for slot = 1, 19 do
local name = C_Item.GetItemName({ equipmentSlotIndex = slot })
if name and string.find(string.lower(name), itemLower, 1, true) then
start, dur, en = GetInventoryItemCooldown("player", slot)
return _norm(start, dur, en)
end
end
@@ -4962,12 +4929,10 @@ function CleveRoids.GetItemCooldown(item)
local size = GetContainerNumSlots(bag)
if size and size > 0 then
for slotIndex = 1, size do
local link = GetContainerItemLink(bag, slotIndex)
if link then
if string.find(string.lower(link), itemLower, 1, true) then
start, dur, en = GetContainerItemCooldown(bag, slotIndex)
return _norm(start, dur, en)
end
local name = C_Item.GetItemName({ bagID = bag, slotIndex = slotIndex })
if name and string.find(string.lower(name), itemLower, 1, true) then
start, dur, en = GetContainerItemCooldown(bag, slotIndex)
return _norm(start, dur, en)
end
end
end
@@ -5187,165 +5152,6 @@ CleveRoids.CCTypesLossOfControl = {
[30] = true, -- sap (now part of stun group)
}
-- Complete spell ID to mechanic mapping from DBC data
-- Extracted from BuffLib SpellData - 785 spells with mechanics
-- Mechanic IDs: 1=Charm, 2=Disorient, 3=Disarm, 5=Fear, 7=Root, 9=Silence,
-- 10=Sleep, 11=Snare, 12=Stun, 13=Freeze, 14=Knockout,
-- 15=Bleed, 17=Polymorph, 18=Banish, 20=Shackle, 21=Mount,
-- 23=Turn, 24=Horror, 25=Invuln, 27=Daze
CleveRoids.CCSpellMechanics = {
[17] = 19, [56] = 12, [89] = 11, [113] = 7, [118] = 17, [228] = 17,
[246] = 11, [339] = 7, [408] = 12, [451] = 9, [458] = 21, [459] = 21,
[468] = 21, [470] = 21, [471] = 21, [472] = 21, [474] = 6, [498] = 25,
[507] = 6, [512] = 7, [578] = 21, [579] = 21, [580] = 21, [581] = 21,
[592] = 19, [593] = 6, [600] = 19, [605] = 1, [642] = 25, [676] = 3,
[700] = 10, [703] = 15, [710] = 18, [745] = 7, [746] = 16, [771] = 1,
[772] = 15, [835] = 12, [851] = 17, [853] = 12, [861] = 9, [867] = 6,
[998] = 6, [1020] = 25, [1022] = 25, [1062] = 7, [1079] = 15, [1090] = 10,
[1098] = 1, [1159] = 16, [1513] = 5, [1776] = 14, [1777] = 14, [1833] = 12,
[1943] = 15, [2070] = 14, [2094] = 2, [2637] = 10, [2878] = 23, [2880] = 12,
[2937] = 10, [3109] = 5, [3143] = 12, [3147] = 15, [3242] = 12, [3263] = 12,
[3267] = 16, [3268] = 16, [3355] = 13, [3363] = 21, [3409] = 11, [3410] = 11,
[3446] = 12, [3542] = 7, [3551] = 12, [3589] = 9, [3600] = 11, [3604] = 11,
[3609] = 12, [3635] = 12, [3636] = 10, [3747] = 19, [4060] = 17, [4064] = 12,
[4065] = 12, [4066] = 12, [4067] = 12, [4068] = 12, [4069] = 12, [4102] = 15,
[4244] = 15, [4962] = 7, [5106] = 12, [5116] = 11, [5134] = 5, [5159] = 11,
[5164] = 12, [5195] = 7, [5196] = 7, [5211] = 12, [5246] = 5, [5259] = 3,
[5276] = 12, [5376] = 4, [5403] = 12, [5484] = 5, [5530] = 12, [5531] = 12,
[5567] = 7, [5573] = 25, [5588] = 12, [5589] = 12, [5597] = 15, [5598] = 15,
[5599] = 25, [5627] = 23, [5648] = 12, [5649] = 12, [5703] = 12, [5708] = 12,
[5782] = 5, [5784] = 21, [5917] = 6, [5918] = 12, [6065] = 19, [6066] = 19,
[6136] = 11, [6146] = 11, [6213] = 5, [6215] = 5, [6253] = 12, [6266] = 12,
[6304] = 12, [6358] = 1, [6388] = 11, [6409] = 12, [6435] = 12, [6466] = 12,
[6524] = 12, [6533] = 7, [6546] = 15, [6547] = 15, [6548] = 15, [6605] = 5,
[6607] = 12, [6608] = 3, [6648] = 21, [6653] = 21, [6654] = 21, [6713] = 3,
[6726] = 9, [6728] = 12, [6730] = 12, [6749] = 12, [6770] = 14, [6777] = 21,
[6788] = 19, [6798] = 12, [6896] = 21, [6897] = 21, [6898] = 21, [6899] = 21,
[6927] = 12, [6942] = 9, [6945] = 12, [6982] = 12, [6984] = 11, [6985] = 11,
[7074] = 9, [7093] = 5, [7139] = 12, [7279] = 11, [7321] = 11, [7399] = 5,
[7645] = 1, [7803] = 12, [7922] = 12, [7926] = 16, [7927] = 16, [7964] = 12,
[7967] = 10, [7992] = 11, [8040] = 10, [8122] = 5, [8124] = 5, [8142] = 7,
[8150] = 12, [8208] = 12, [8225] = 5, [8242] = 12, [8281] = 9, [8285] = 12,
[8312] = 7, [8346] = 7, [8377] = 7, [8379] = 3, [8391] = 12, [8394] = 21,
[8395] = 21, [8396] = 21, [8399] = 10, [8629] = 14, [8631] = 15, [8632] = 15,
[8633] = 15, [8639] = 15, [8640] = 15, [8643] = 12, [8646] = 12, [8715] = 5,
[8716] = 11, [8818] = 15, [8901] = 10, [8902] = 10, [8980] = 21, [8983] = 12,
[8988] = 9, [8994] = 18, [9005] = 12, [9007] = 15, [9080] = 11, [9159] = 10,
[9484] = 20, [9485] = 20, [9552] = 9, [9823] = 12, [9824] = 15, [9826] = 15,
[9827] = 12, [9852] = 7, [9853] = 7, [9896] = 15, [9915] = 7, [10017] = 7,
[10234] = 10, [10253] = 17, [10266] = 15, [10278] = 25, [10308] = 12,
[10326] = 23, [10787] = 21, [10788] = 21, [10789] = 21, [10790] = 21,
[10792] = 21, [10793] = 21, [10795] = 21, [10796] = 21, [10798] = 21,
[10799] = 21, [10800] = 21, [10801] = 21, [10802] = 21, [10803] = 21,
[10804] = 21, [10838] = 16, [10839] = 16, [10851] = 3, [10852] = 7,
[10855] = 11, [10856] = 12, [10873] = 21, [10888] = 5, [10890] = 5,
[10898] = 19, [10899] = 19, [10900] = 19, [10901] = 19, [10911] = 1,
[10912] = 1, [10955] = 20, [10969] = 21, [10987] = 11, [11020] = 12,
[11201] = 11, [11264] = 7, [11273] = 15, [11274] = 15, [11275] = 15,
[11285] = 14, [11286] = 14, [11289] = 15, [11290] = 15, [11297] = 14,
[11428] = 12, [11430] = 12, [11436] = 11, [11446] = 1, [11572] = 15,
[11573] = 15, [11574] = 15, [11578] = 12, [11579] = 12, [11641] = 17, [11650] = 12, [11725] = 1,
[11726] = 1, [11820] = 7, [11831] = 7, [11836] = 12, [11876] = 12,
[11879] = 3, [11922] = 7, [11958] = 13, [11977] = 15, [12023] = 7,
[12024] = 7, [12054] = 15, [12096] = 5, [12098] = 10, [12252] = 7,
[12323] = 11, [12355] = 12, [12421] = 12, [12461] = 12, [12484] = 11,
[12485] = 11, [12486] = 11, [12494] = 7, [12528] = 9, [12531] = 11,
[12540] = 14, [12542] = 5, [12543] = 12, [12551] = 11, [12562] = 12,
[12674] = 7, [12705] = 11, [12721] = 15, [12730] = 5, [12734] = 12,
[12747] = 7, [12748] = 7, [12798] = 12, [12809] = 12, [12824] = 17,
[12825] = 17, [12826] = 17, [12946] = 9, [13005] = 12, [13099] = 7,
[13119] = 7, [13138] = 7, [13181] = 1, [13237] = 12, [13318] = 15,
[13323] = 17, [13327] = 14, [13443] = 15, [13445] = 15, [13534] = 3,
[13579] = 14, [13608] = 7, [13704] = 5, [13738] = 15, [13747] = 11,
[13808] = 12, [13810] = 11, [13819] = 21, [13902] = 12, [14030] = 7,
[14087] = 15, [14100] = 5, [14102] = 12, [14118] = 15, [14180] = 3,
[14207] = 11, [14308] = 13, [14309] = 13, [14326] = 5, [14327] = 5,
[14331] = 15, [14515] = 1, [14621] = 17, [14874] = 15, [14897] = 11,
[14902] = 12, [14903] = 15, [14907] = 7, [15063] = 7, [15091] = 14,
[15269] = 12, [15283] = 12, [15398] = 12, [15471] = 7, [15474] = 7,
[15487] = 9, [15531] = 7, [15532] = 7, [15534] = 17, [15535] = 12,
[15583] = 15, [15593] = 12, [15609] = 7, [15618] = 12, [15621] = 12,
[15652] = 12, [15655] = 12, [15744] = 14, [15752] = 3, [15753] = 12,
[15779] = 21, [15780] = 21, [15781] = 21, [15822] = 10, [15859] = 1,
[15878] = 12, [15970] = 10, [15976] = 15, [16045] = 18, [16046] = 14,
[16050] = 11, [16053] = 1, [16055] = 21, [16056] = 21, [16058] = 21,
[16059] = 21, [16060] = 21, [16075] = 12, [16080] = 21, [16081] = 21,
[16082] = 21, [16083] = 21, [16084] = 21, [16095] = 15, [16096] = 5,
[16097] = 17, [16104] = 12, [16350] = 12, [16393] = 15, [16403] = 15,
[16406] = 15, [16451] = 18, [16469] = 7, [16497] = 12, [16508] = 5,
[16509] = 15, [16566] = 7, [16568] = 11, [16600] = 12, [16707] = 17,
[16708] = 17, [16709] = 17, [16727] = 12, [16790] = 12, [16798] = 10,
[16803] = 12, [16838] = 9, [16869] = 12, [16922] = 12, [17011] = 12,
[17145] = 14, [17153] = 15, [17165] = 11, [17172] = 17, [17174] = 11,
[17229] = 21, [17276] = 12, [17277] = 14, [17286] = 12, [17293] = 12,
[17308] = 12, [17405] = 1, [17450] = 21, [17453] = 21, [17454] = 21,
[17455] = 21, [17456] = 21, [17458] = 21, [17459] = 21, [17460] = 21,
[17461] = 21, [17462] = 21, [17463] = 21, [17464] = 21, [17465] = 21,
[17481] = 21, [17500] = 12, [17504] = 15, [17738] = 17, [17928] = 5,
[18075] = 15, [18078] = 15, [18093] = 12, [18103] = 12, [18106] = 15,
[18118] = 11, [18144] = 12, [18200] = 15, [18202] = 15, [18223] = 11,
[18278] = 9, [18327] = 9, [18328] = 11, [18363] = 21, [18395] = 12,
[18425] = 9, [18431] = 5, [18469] = 9, [18498] = 9, [18503] = 17,
[18608] = 16, [18610] = 16, [18647] = 18, [18657] = 10, [18658] = 10,
[18763] = 12, [18802] = 11, [18812] = 12, [18972] = 11, [18989] = 21,
[18990] = 21, [18991] = 21, [18992] = 21, [19128] = 12, [19134] = 5,
[19136] = 12, [19137] = 11, [19185] = 7, [19229] = 7, [19364] = 12,
[19386] = 10, [19393] = 9, [19408] = 5, [19410] = 12, [19469] = 1,
[19482] = 12, [19496] = 11, [19501] = 2, [19503] = 2, [19641] = 12,
[19718] = 3, [19769] = 12, [19771] = 15, [19780] = 12, [19784] = 12,
[19821] = 9, [19970] = 7, [19971] = 7, [19972] = 7, [19973] = 7,
[19974] = 7, [19975] = 7, [20066] = 14, [20170] = 12, [20253] = 12,
[20276] = 12, [20277] = 12, [20310] = 12, [20511] = 5, [20549] = 12,
[20604] = 1, [20614] = 12, [20615] = 12, [20654] = 7, [20663] = 10,
[20669] = 10, [20683] = 12, [20685] = 12, [20699] = 7, [20706] = 19,
[20740] = 1, [20882] = 1, [20907] = 15, [20908] = 15, [20989] = 10,
[21099] = 12, [21152] = 12, [21330] = 5, [21331] = 7, [21748] = 12,
[21749] = 12, [21869] = 5, [21898] = 5, [21949] = 15, [21990] = 12,
[22127] = 7, [22274] = 17, [22289] = 12, [22356] = 11, [22415] = 7,
[22419] = 3, [22424] = 14, [22427] = 12, [22519] = 7, [22566] = 17,
[22570] = 14, [22592] = 12, [22639] = 11, [22645] = 7, [22666] = 9,
[22678] = 5, [22686] = 5, [22691] = 3, [22692] = 12, [22717] = 21,
[22718] = 21, [22719] = 21, [22720] = 21, [22721] = 21, [22722] = 21,
[22723] = 21, [22724] = 21, [22744] = 7, [22752] = 19, [22800] = 7,
[22884] = 5, [22914] = 11, [22915] = 12, [22919] = 11, [22924] = 7,
[22994] = 7, [23039] = 14, [23103] = 12, [23113] = 14, [23161] = 21,
[23207] = 9, [23214] = 21, [23219] = 21, [23220] = 21, [23221] = 21,
[23222] = 21, [23223] = 21, [23225] = 21, [23227] = 21, [23228] = 21,
[23229] = 21, [23238] = 21, [23239] = 21, [23240] = 21, [23241] = 21,
[23242] = 21, [23243] = 21, [23246] = 21, [23247] = 21, [23248] = 21,
[23249] = 21, [23250] = 21, [23251] = 21, [23252] = 21, [23275] = 5,
[23338] = 21, [23364] = 12, [23365] = 3, [23454] = 12, [23509] = 21,
[23510] = 21, [23567] = 16, [23568] = 16, [23569] = 16, [23600] = 11,
[23603] = 17, [23618] = 12, [23694] = 7, [23696] = 16, [23918] = 9,
[23919] = 12, [23953] = 11, [24004] = 10, [24053] = 17, [24110] = 7,
[24118] = 15, [24119] = 15, [24120] = 15, [24132] = 10, [24133] = 10,
[24152] = 7, [24192] = 15, [24213] = 12, [24225] = 11, [24242] = 21,
[24252] = 21, [24259] = 9, [24327] = 1, [24331] = 15, [24332] = 15,
[24333] = 12, [24335] = 10, [24360] = 10, [24375] = 12, [24394] = 12,
[24412] = 16, [24413] = 16, [24414] = 16, [24415] = 11, [24576] = 21,
[24600] = 12, [24648] = 7, [24664] = 10, [24671] = 12, [24687] = 9,
[24698] = 14, [24712] = 17, [24713] = 17, [24735] = 17, [24736] = 17,
[24778] = 10, [25022] = 11, [25049] = 14, [25056] = 12, [25057] = 3,
[25187] = 11, [25189] = 12, [25260] = 5, [25654] = 12, [25655] = 3,
[25675] = 21, [25771] = 25, [25809] = 11, [25815] = 5, [25852] = 12,
[25858] = 21, [25859] = 21, [25863] = 21, [25953] = 21, [25999] = 7,
[26042] = 5, [26054] = 21, [26055] = 21, [26056] = 21, [26069] = 9,
[26070] = 5, [26071] = 7, [26078] = 11, [26108] = 2, [26141] = 11,
[26143] = 11, [26157] = 17, [26180] = 10, [26211] = 11, [26272] = 17,
[26273] = 17, [26274] = 17, [26379] = 11, [26580] = 5, [26641] = 5,
[26655] = 21, [26740] = 1, [27555] = 15, [27556] = 15, [27559] = 9,
[27565] = 18, [27581] = 3, [27607] = 19, [27610] = 5, [27615] = 12,
[27619] = 13, [27634] = 11, [27638] = 15, [27640] = 11, [27641] = 5,
[27758] = 12, [27760] = 17, [27880] = 12, [27990] = 5, [27993] = 11,
[28270] = 17, [28271] = 17, [28272] = 17, [28314] = 12, [28315] = 5,
[28445] = 12, [28456] = 14, [28725] = 12, [28858] = 7, [28911] = 15,
[28913] = 15, [28991] = 7, [29059] = 21, [29168] = 5, [29407] = 11,
[29419] = 5, [29544] = 5, [29685] = 5, [29848] = 17, [29849] = 7,
[29915] = 15, [29943] = 9, [30001] = 5, [30002] = 5, [30020] = 16,
[30094] = 7, [30174] = 21, [30225] = 9, [30285] = 15, [31365] = 5,
[31700] = 21,
}
-- Check if BuffLib is available with full mechanic support
function CleveRoids.HasBuffLib()
-- Defensive: ensure BuffLib.SpellData is a table, not a function
@@ -5354,7 +5160,7 @@ function CleveRoids.HasBuffLib()
and BuffLib.SpellData.GetMechanic
end
-- Get mechanic for a spell ID (uses BuffLib if available, otherwise built-in table)
-- Get mechanic for a spell ID (uses BuffLib if available, otherwise ClassicAPI's DBC reader)
function CleveRoids.GetSpellMechanic(spellID)
if not spellID or spellID <= 0 then return 0 end
@@ -5367,8 +5173,8 @@ function CleveRoids.GetSpellMechanic(spellID)
end
end
-- Fall back to built-in table
return CleveRoids.CCSpellMechanics[spellID] or 0
-- Fall back to ClassicAPI's Spell.dbc reader (always present; covers every spell)
return CleveRoids.ClassicAPI.GetSpellMechanicByID(spellID) or 0
end
-- Validate CC on a unit (target, focus, player, etc.)
@@ -5923,8 +5729,8 @@ CleveRoids.Keywords = {
-- [set:SetName>=N] — true if equipped piece count of named set meets comparison
-- [set:SetName] — true if any pieces of that set are equipped (count > 0)
-- [set:123>=3] — numeric IDs also supported (Nampower only, no Reliquary needed)
-- Name lookup requires Reliquary (for DBC set name); ID lookup requires Nampower
-- [set:123>=3] — numeric IDs also supported
-- Both name and ID lookups resolve from ItemSet.dbc via ClassicAPI
set = function(conditionals)
return Multi(conditionals.set, function(args)
if type(args) == "table" and args.operator and args.amount then
@@ -6059,13 +5865,10 @@ CleveRoids.Keywords = {
local itemName = name
local slotNum = tonumber(name)
if slotNum and slotNum >= 1 and slotNum <= 19 then
-- Resolve slot number to item name
local link = GetInventoryItemLink("player", slotNum)
if link then
local _, _, extractedName = string.find(link, "%[(.+)%]")
if extractedName then
itemName = extractedName
end
-- Resolve slot number to item name (decorated, no link build)
local extractedName = C_Item.GetItemName({ equipmentSlotIndex = slotNum })
if extractedName then
itemName = extractedName
end
end
@@ -6097,13 +5900,10 @@ CleveRoids.Keywords = {
local itemName = name
local slotNum = tonumber(name)
if slotNum and slotNum >= 1 and slotNum <= 19 then
-- Resolve slot number to item name
local link = GetInventoryItemLink("player", slotNum)
if link then
local _, _, extractedName = string.find(link, "%[(.+)%]")
if extractedName then
itemName = extractedName
end
-- Resolve slot number to item name (decorated, no link build)
local extractedName = C_Item.GetItemName({ equipmentSlotIndex = slotNum })
if extractedName then
itemName = extractedName
end
end
+4
View File
@@ -67,6 +67,10 @@ SLASH_UNSHIFT1 = "/unshift"
SlashCmdList.UNSHIFT = CleveRoids.DoUnshift
SLASH_CANCELFORM1 = "/cancelform"
SlashCmdList.CANCELFORM = CleveRoids.DoCancelForm
SLASH_UNQUEUE1 = "/unqueue"
SlashCmdList.UNQUEUE = SpellStopCasting
+281 -469
View File
File diff suppressed because it is too large Load Diff
+59
View File
@@ -1274,6 +1274,56 @@ end
-- Hook Installation
-- ============================================================================
-- ============================================================================
-- Dynamic macro-list icons
-- Blizzard shows the default question-mark icon for macros with no chosen icon
-- (e.g. "#showtooltip Shoot"). Replace it with the icon the action bar would
-- show -- resolved from the macro's #showtooltip/first action -- but ONLY when
-- the saved icon is the question mark, so user-chosen icons are never touched.
-- Purely cosmetic: Blizzard repaints from GetMacroInfo on the next update, so
-- if resolution fails or the macro changes, the default simply returns.
-- ============================================================================
local QUESTION_MARK = string.lower(CleveRoids.unknownTexture or "Interface\\Icons\\INV_Misc_QuestionMark")
local function IsQuestionMark(iconTexture)
local tex = iconTexture and iconTexture:GetTexture()
return type(tex) == "string" and string.lower(tex) == QUESTION_MARK
end
-- Resolved tooltip texture for a Blizzard macro index, or nil when it resolves
-- to nothing better than the question mark (no #showtooltip, unresolved spell).
local function ResolveMacroIcon(macroIndex)
if not macroIndex or macroIndex < 1 then return nil end
local ok, macro = pcall(CleveRoids.GetMacroByIndex, macroIndex)
if not ok or not macro or not macro.actions or not macro.actions.tooltip then return nil end
local tex = macro.actions.tooltip.texture
if type(tex) == "string" and string.lower(tex) ~= QUESTION_MARK then
return tex
end
return nil
end
local function FixMacroListIcons()
if not MacroFrame or not MacroFrame:IsVisible() then return end
local base = MacroFrame.macroBase or 0
for i = 1, (MAX_MACROS or 18) do
local icon = getglobal("MacroButton" .. i .. "Icon")
if icon and IsQuestionMark(icon) then
local tex = ResolveMacroIcon(base + i)
if tex then icon:SetTexture(tex) end
end
end
-- Large icon for the currently-selected macro (details pane).
if MacroFrame.selectedMacro and MacroFrameSelectedMacroButtonIcon
and IsQuestionMark(MacroFrameSelectedMacroButtonIcon) then
local tex = ResolveMacroIcon(MacroFrame.selectedMacro)
if tex then MacroFrameSelectedMacroButtonIcon:SetTexture(tex) end
end
end
local function InstallHooks()
if hooked then return end
if not MacroFrameText or not MacroFrame then return end
@@ -1325,6 +1375,15 @@ local function InstallHooks()
end
end)
-- After every Blizzard macro-list refresh, swap question-mark icons for the
-- dynamically-resolved ones. Post-hook so Blizzard has already set the
-- default texture we test against.
if hooksecurefunc and type(MacroFrame_Update) == "function" then
hooksecurefunc("MacroFrame_Update", function()
pcall(FixMacroListIcons)
end)
end
hooked = true
end
+69 -98
View File
@@ -58,11 +58,7 @@ function CleveRoids.IndexSpells()
bookType = CleveRoids.bookTypes[book]
spells[bookType] = {}
else
local cost, reagent = CleveRoids.GetSpellCost(i, bookType)
-- Fallback for known reagent spells if tooltip scan failed
if (not reagent or reagent == "") and CleveRoids.ReagentBySpell then
reagent = CleveRoids.ReagentBySpell[spellName]
end
local cost, reagent, reagentId = CleveRoids.GetSpellCost(i, bookType, spellId)
if not spells[bookType][spellName] then
spells[bookType][spellName] = {
spellSlot = i,
@@ -71,7 +67,7 @@ function CleveRoids.IndexSpells()
bookType = bookType,
texture = texture,
cost = cost,
reagent = reagent,
reagentId = reagentId,
}
end
if spellRank and not spells[bookType][spellName][spellRank] then
@@ -83,7 +79,7 @@ function CleveRoids.IndexSpells()
bookType = bookType,
texture = texture,
cost = cost,
reagent = reagent
reagentId = reagentId,
}
spells[bookType][spellName].highest = spells[bookType][spellName][spellRank]
end
@@ -94,6 +90,13 @@ function CleveRoids.IndexSpells()
if reagent then
CleveRoids.countedItemTypes[reagent] = true
elseif reagentId and Item then
Item:CreateFromItemID(reagentId):ContinueOnItemLoad(function()
local loadedName = C_Item.GetItemNameByID(reagentId)
if loadedName and loadedName ~= "" then
CleveRoids.countedItemTypes[loadedName] = true
end
end)
end
end
end
@@ -156,10 +159,9 @@ end
function CleveRoids.IndexEquippedItems()
local items = CleveRoids.Items or {}
for inventoryID = 0, 19 do
local link = GetInventoryItemLink("player", inventoryID)
if link then
local _, _, itemID = string.find(link, "item:(%d+)")
for inventoryID = 1, 19 do
local itemID = GetInventoryItemID("player", inventoryID)
if itemID then
local name, link, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID)
if name then
local count = GetInventoryItemCount("player", inventoryID)
@@ -199,10 +201,9 @@ function CleveRoids.IndexEquipSlot(inventoryID)
if not inventoryID then return end
local items = CleveRoids.Items or {}
local link = GetInventoryItemLink("player", inventoryID)
local itemID = GetInventoryItemID("player", inventoryID)
if link then
local _, _, itemID = string.find(link, "item:(%d+)")
if itemID then
local name, itemLink, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID)
if name then
local count = GetInventoryItemCount("player", inventoryID)
@@ -265,21 +266,17 @@ function CleveRoids.IndexItems()
-- PERFORMANCE: Local function references
local GetContainerNumSlots = GetContainerNumSlots
local GetContainerItemLink = GetContainerItemLink
local GetContainerItemInfo = GetContainerItemInfo
local GetInventoryItemLink = GetInventoryItemLink
local GetInventoryItemCount = GetInventoryItemCount
-- Scan bags (reverse order to prefer first stack)
for bagID = 0, NUM_BAG_SLOTS do
local numSlots = GetContainerNumSlots(bagID)
for slot = numSlots, 1, -1 do
local link = GetContainerItemLink(bagID, slot)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
-- PERFORMANCE: Try to extract name from link first to check for duplicates
local _, _, linkName = string_find(link, "%[(.+)%]")
local itemID = C_Container.GetContainerItemID(bagID, slot)
if itemID then
-- Decorated name for the duplicate fast-path (no link string built)
local linkName = C_Item.GetItemName({ bagID = bagID, slotIndex = slot })
local existing = linkName and items[linkName]
if existing then
@@ -317,13 +314,11 @@ function CleveRoids.IndexItems()
end
-- Scan equipped items
for inventoryID = 0, 19 do
local link = GetInventoryItemLink("player", inventoryID)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
-- PERFORMANCE: Try to extract name from link first
local _, _, linkName = string_find(link, "%[(.+)%]")
for inventoryID = 1, 19 do
local itemID = GetInventoryItemID("player", inventoryID)
if itemID then
-- Decorated name for the duplicate fast-path (no link string built)
local linkName = C_Item.GetItemName({ equipmentSlotIndex = inventoryID })
local existing = linkName and items[linkName]
if existing then
@@ -477,10 +472,8 @@ local function makeInventoryItem(inventoryID, link, Items)
if not link then link = GetInventoryItemLink("player", inventoryID) end
if not link then return end
local _, _, itemID = string_find(link, "item:(%d+)")
itemID = itemID and tonumber(itemID) or nil
local name = itemID and GetItemInfo(itemID) or nil
local itemID = GetInventoryItemID("player", inventoryID)
local name = C_Item.GetItemName({ equipmentSlotIndex = inventoryID })
local texture = GetInventoryItemTexture("player", inventoryID)
local count = GetInventoryItemCount("player", inventoryID)
@@ -509,14 +502,12 @@ local function makeBagItem(bagID, slot, link, Items)
end
if not link then return end
local _, _, itemID = string_find(link, "item:(%d+)")
itemID = itemID and tonumber(itemID) or nil
local itemID = C_Container.GetContainerItemID(bagID, slot)
local name, _, _, _, _, _, _, _, texture = GetItemInfo(itemID)
local name = C_Item.GetItemName({bagID = bagID, slotIndex = slot})
local count = 0
local tex, itemCount = GetContainerItemInfo(bagID, slot)
local texture, itemCount = GetContainerItemInfo(bagID, slot)
if itemCount then count = itemCount end
if not texture then texture = tex end
local it = {
bagID = bagID,
@@ -574,9 +565,7 @@ function CleveRoids.GetItem(text)
for inv = 1, 19 do
local link = GetInventoryItemLink("player", inv)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
itemID = itemID and tonumber(itemID) or nil
local itemID = GetInventoryItemID("player", inv)
if qid and itemID and qid == itemID then
return makeInventoryItem(inv, link, Items)
elseif qname then
@@ -595,9 +584,7 @@ function CleveRoids.GetItem(text)
for slot = 1, slots do
local link = GetContainerItemLink(bag, slot)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
itemID = itemID and tonumber(itemID) or nil
local itemID = C_Container.GetContainerItemID(bag, slot)
if qid and itemID and qid == itemID then
return makeBagItem(bag, slot, link, Items)
elseif qname then
@@ -720,18 +707,16 @@ function CleveRoids.FindItemQuick(text)
if cached then
-- Validate: check if item is actually at the cached location
if cached.inventoryID then
local link = GetInventoryItemLink("player", cached.inventoryID)
if link then
local nm = GetNameFromLink(link)
if qid then
if GetInventoryItemID("player", cached.inventoryID) == qid then
cached._validated = true
return cached -- Cache is valid
end
else
local nm = C_Item.GetItemName({ equipmentSlotIndex = cached.inventoryID })
if nm and qname and string_lower(nm) == qname then
cached._validated = true
return cached -- Cache is valid
elseif qid then
local _, _, itemID = string_find(link, "item:(%d+)")
if itemID and tonumber(itemID) == qid then
cached._validated = true
return cached -- Cache is valid
end
end
end
-- Cache is stale - item not at cached equipped slot, invalidate
@@ -740,18 +725,16 @@ function CleveRoids.FindItemQuick(text)
Items[string_lower(cached.name)] = nil
end
elseif cached.bagID and cached.slot then
local link = GetContainerItemLink(cached.bagID, cached.slot)
if link then
local nm = GetNameFromLink(link)
if qid then
if C_Container.GetContainerItemID(cached.bagID, cached.slot) == qid then
cached._validated = true
return cached -- Cache is valid
end
else
local nm = C_Item.GetItemName({ bagID = cached.bagID, slotIndex = cached.slot })
if nm and qname and string_lower(nm) == qname then
cached._validated = true
return cached -- Cache is valid
elseif qid then
local _, _, itemID = string_find(link, "item:(%d+)")
if itemID and tonumber(itemID) == qid then
cached._validated = true
return cached -- Cache is valid
end
end
end
-- Cache is stale - item not at cached bag slot, invalidate
@@ -767,20 +750,17 @@ function CleveRoids.FindItemQuick(text)
for inv = 1, 19 do
local link = GetInventoryItemLink("player", inv)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
if itemID then
itemID = tonumber(itemID)
-- ID match: fast path
if qid and qid == itemID then
local itemID = GetInventoryItemID("player", inv)
-- ID match: fast path
if qid and qid == itemID then
return makeInventoryItem(inv, link, Items)
end
-- Name match: extract name from link (faster than GetItemInfo)
if qname then
local nm = GetNameFromLink(link)
if nm and string_lower(nm) == qname then
return makeInventoryItem(inv, link, Items)
end
-- Name match: extract name from link (faster than GetItemInfo)
if qname then
local nm = GetNameFromLink(link)
if nm and string_lower(nm) == qname then
return makeInventoryItem(inv, link, Items)
end
end
end
end
end
@@ -791,20 +771,17 @@ function CleveRoids.FindItemQuick(text)
for slot = 1, slots do
local link = GetContainerItemLink(bag, slot)
if link then
local _, _, itemID = string_find(link, "item:(%d+)")
if itemID then
itemID = tonumber(itemID)
-- ID match: fast path
if qid and qid == itemID then
local itemID = C_Container.GetContainerItemID(bag, slot)
-- ID match: fast path
if qid and qid == itemID then
return makeBagItem(bag, slot, link, Items)
end
-- Name match: extract name from link (faster than GetItemInfo)
if qname then
local nm = GetNameFromLink(link)
if nm and string_lower(nm) == qname then
return makeBagItem(bag, slot, link, Items)
end
-- Name match: extract name from link (faster than GetItemInfo)
if qname then
local nm = GetNameFromLink(link)
if nm and string_lower(nm) == qname then
return makeBagItem(bag, slot, link, Items)
end
end
end
end
end
@@ -818,25 +795,19 @@ end
function CleveRoids.IsItemEquipped(text, inventoryId)
if not text or not inventoryId then return false end
local link = GetInventoryItemLink("player", inventoryId)
if not link then return false end
local _, _, currentID = string_find(link, "item:(%d+)")
local currentID = GetInventoryItemID("player", inventoryId)
if not currentID then return false end
-- Check by ID (fast path)
local textId = tonumber(text)
if textId and textId == tonumber(currentID) then
if textId and textId == currentID then
return true
end
-- Check by name - extract from link instead of GetItemInfo for performance
local currentName = GetNameFromLink(link)
if currentName then
local textLower = string_lower(text)
if string_lower(currentName) == textLower then
return true
end
-- Check by name (decorated, so suffixed gear still matches)
local currentName = C_Item.GetItemName({ equipmentSlotIndex = inventoryId })
if currentName and string_lower(currentName) == string_lower(text) then
return true
end
return false
+23 -28
View File
@@ -22,7 +22,6 @@ CleveRoids.mouseOverUnit = nil
-- Environment flags
CleveRoids.hasSuperwow = SetAutoloot and true or false
CleveRoids.hasTurtle = (type(_G.TURTLE_WOW_VERSION) ~= "nil")
CleveRoids.hasReliquary = (RQ_GetVersion ~= nil)
CleveRoids.supported = CleveRoids.hasTurtle
CleveRoids.ParsedMsg = {}
@@ -242,28 +241,32 @@ CleveRoids.auraTextures = {
-- I need to make a 2h modifier
-- Maps easy to use weapon type names (e.g. Axes, Shields) to their inventory slot name and their localized tooltip name
-- Maps easy-to-use weapon type names (e.g. Axes, Shields) to their inventory
-- slot plus the locale-independent item class/subclass IDs that identify them
-- (read via C_Item.GetItemInfoInstant). class 2 = Weapon, 4 = Armor (shields).
-- subClass is a set because the logical "Axes"/"Swords"/"Maces" types span both
-- the one-handed and two-handed weapon subclasses.
CleveRoids.WeaponTypeNames = {
Daggers = { slot = "MainHandSlot", name = CleveRoids.Localized.Dagger },
Fists = { slot = "MainHandSlot", name = CleveRoids.Localized.FistWeapon },
Axes = { slot = "MainHandSlot", name = CleveRoids.Localized.Axe },
Swords = { slot = "MainHandSlot", name = CleveRoids.Localized.Sword },
Staves = { slot = "MainHandSlot", name = CleveRoids.Localized.Staff },
Maces = { slot = "MainHandSlot", name = CleveRoids.Localized.Mace },
Polearms = { slot = "MainHandSlot", name = CleveRoids.Localized.Polearm },
Daggers = { slot = "MainHandSlot", class = 2, subClass = { [15] = true } },
Fists = { slot = "MainHandSlot", class = 2, subClass = { [13] = true } },
Axes = { slot = "MainHandSlot", class = 2, subClass = { [0] = true, [1] = true } },
Swords = { slot = "MainHandSlot", class = 2, subClass = { [7] = true, [8] = true } },
Staves = { slot = "MainHandSlot", class = 2, subClass = { [10] = true } },
Maces = { slot = "MainHandSlot", class = 2, subClass = { [4] = true, [5] = true } },
Polearms = { slot = "MainHandSlot", class = 2, subClass = { [6] = true } },
-- OH
Daggers2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Dagger },
Fists2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.FistWeapon },
Axes2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Axe },
Swords2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Sword },
Maces2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Mace },
Shields = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Shield },
Daggers2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [15] = true } },
Fists2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [13] = true } },
Axes2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [0] = true, [1] = true } },
Swords2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [7] = true, [8] = true } },
Maces2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [4] = true, [5] = true } },
Shields = { slot = "SecondaryHandSlot", class = 4, subClass = { [6] = true } },
-- ranged
Guns = { slot = "RangedSlot", name = CleveRoids.Localized.Gun },
Crossbows = { slot = "RangedSlot", name = CleveRoids.Localized.Crossbow },
Bows = { slot = "RangedSlot", name = CleveRoids.Localized.Bow },
Thrown = { slot = "RangedSlot", name = CleveRoids.Localized.Thrown },
Wands = { slot = "RangedSlot", name = CleveRoids.Localized.Wand },
Guns = { slot = "RangedSlot", class = 2, subClass = { [3] = true } },
Crossbows = { slot = "RangedSlot", class = 2, subClass = { [18] = true } },
Bows = { slot = "RangedSlot", class = 2, subClass = { [2] = true } },
Thrown = { slot = "RangedSlot", class = 2, subClass = { [16] = true } },
Wands = { slot = "RangedSlot", class = 2, subClass = { [19] = true } },
}
-- Detect available features
@@ -287,14 +290,6 @@ local function PrintFeatures()
end
end
if CleveRoids.hasUnitXP then table.insert(features, "UnitXP") end
if CleveRoids.hasReliquary then
local ok, major, minor, patch = pcall(RQ_GetVersion)
if ok and major then
table.insert(features, string.format("Reliquary v%d.%d.%d", major, minor, patch))
else
table.insert(features, "Reliquary")
end
end
if CleveRoids.hasTurtle then table.insert(features, "Turtle") end
if table.getn(features) > 0 then
-245
View File
@@ -8,26 +8,9 @@ CleveRoids.Locale = GetLocale()
CleveRoids.Localized = {}
if CleveRoids.Locale == "enUS" or CleveRoids.Locale == "enGB" then
-- place item in backpack slot 1 and run:
-- /script local l=GetContainerItemLink(0,1);local _,_,id=string.find(l,"item:(%d+)");local n,_,_,_,t,st=GetItemInfo(id);DEFAULT_CHAT_FRAME:AddMessage("\n\nID: ["..id.."]\nName: ["..n.."]\nType: ["..t.."]\nSub Type: ["..st.."]\n\n");
CleveRoids.Localized.Shield = "Shields"
CleveRoids.Localized.Bow = "Bows"
CleveRoids.Localized.Crossbow = "Crossbows"
CleveRoids.Localized.Gun = "Guns"
CleveRoids.Localized.Thrown = "Thrown"
CleveRoids.Localized.Wand = "Wands"
CleveRoids.Localized.Sword = "Swords"
CleveRoids.Localized.Staff = "Staves"
CleveRoids.Localized.Polearm = "Polearms"
CleveRoids.Localized.Mace = "Maces"
CleveRoids.Localized.FistWeapon = "Fist Weapons"
CleveRoids.Localized.Dagger = "Daggers"
CleveRoids.Localized.Axe = "Axes"
CleveRoids.Localized.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
-- target creature and run:
-- /script local ct, uc = UnitCreatureType("target"),UnitClassification("target"); DEFAULT_CHAT_FRAME:AddMessage("\n\nUnitCreatureType: ["..ct.."]\nUnitClassificationType: ["..uc.."]\n\n");
@@ -50,43 +33,11 @@ if CleveRoids.Locale == "enUS" or CleveRoids.Locale == "enGB" then
["Stealth"] = "Stealth",
["Prowl"] = "Prowl",
["Shadowmeld"] = "Shadowmeld",
["Revenge"] = "Revenge",
["Overpower"] = "Overpower",
["Riposte"] = "Riposte",
["Surprise Attack"] = "Surprise Attack",
["Lacerate"] = "Lacerate",
["Baited Shot"] = "Baited Shot",
["Counterattack"] = "Counterattack",
["Arcane Surge"] = "Arcane Surge",
}
-- place item in backpack slot 1 and run:
-- /script local l=GetContainerItemLink(0,1);local _,_,id=string.find(l,"item:(%d+)");local n,_,_,_,t,st=GetItemInfo(id);DEFAULT_CHAT_FRAME:AddMessage("\n\nID: ["..id.."]\nName: ["..n.."]\nType: ["..t.."]\nSub Type: ["..st.."]\n\n");
CleveRoids.Localized.ItemTypes = {
["Consumable"] = "Consumable",
["Reagent"] = "Reagent",
["Projectile"] = "Projectile",
["Trade Goods"] = "Trade Goods",
}
elseif CleveRoids.Locale == "deDE" then
CleveRoids.Localized.Shield = "Schilde"
CleveRoids.Localized.Bow = "Bögen"
CleveRoids.Localized.Crossbow = "Armbrüste"
CleveRoids.Localized.Gun = "Waffen"
CleveRoids.Localized.Thrown = "Geworfen"
CleveRoids.Localized.Wand = "Zauberstäbe"
CleveRoids.Localized.Sword = "Schwerter"
CleveRoids.Localized.Staff = "Dauben"
CleveRoids.Localized.Polearm = "Stangenwaffen"
CleveRoids.Localized.Mace = "Streitkolben"
CleveRoids.Localized.FistWeapon = "Faustwaffen"
CleveRoids.Localized.Dagger = "Dolche"
CleveRoids.Localized.Axe = "Äxte"
CleveRoids.Localized.Attack = "Angriff"
CleveRoids.Localized.AutoShot = "Automatischer Schuss"
CleveRoids.Localized.Shoot = "Schießen"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = {
["Beast"] = "Wildtier",
@@ -108,42 +59,11 @@ elseif CleveRoids.Locale == "deDE" then
["Stealth"] = "Verstohlenheit",
["Prowl"] = "Schleichen",
["Shadowmeld"] = "Schattenmimik",
["Revenge"] = "Rache",
["Overpower"] = "Überwältigen",
["Riposte"] = "Riposte",
["Surprise Attack"] = "Überraschungsangriff",
["Lacerate"] = "Zerfleischen",
["Baited Shot"] = "Köderschuss",
["Counterattack"] = "Gegenangriff",
["Arcane Surge"] = "Arkane Woge",
}
CleveRoids.Localized.ItemTypes = {
["Consumable"] = "Verbrauchsmaterial",
["Reagent"] = "Reagens",
["Projectile"] = "Projektil",
["Trade Goods"] = "Handwerkswaren",
}
elseif CleveRoids.Locale == "frFR" then
CleveRoids.Localized.Shield = "Boucliers"
CleveRoids.Localized.Bow = "Arcs"
CleveRoids.Localized.Crossbow = "Arbalètes"
CleveRoids.Localized.Gun = "Armes à feu"
CleveRoids.Localized.Thrown = "Thrown"
CleveRoids.Localized.Wand = "Wands"
CleveRoids.Localized.Sword = "Swords"
CleveRoids.Localized.Staff = "Staves"
CleveRoids.Localized.Polearm = "Polearms"
CleveRoids.Localized.Mace = "Maces"
CleveRoids.Localized.FistWeapon = "Fist Weapons"
CleveRoids.Localized.Dagger = "Daggers"
CleveRoids.Localized.Axe = "Axes"
CleveRoids.Localized.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = {
["Beast"] = "Bête",
@@ -164,41 +84,11 @@ elseif CleveRoids.Locale == "frFR" then
["Stealth"] = "Camouflage",
["Prowl"] = "Rôder",
["Shadowmeld"] = "Camouflage dans l'ombre",
["Revenge"] = "Vengeance",
["Overpower"] = "Fulgurance",
["Riposte"] = "Riposte",
["Surprise Attack"] = "Attaque surprise",
["Lacerate"] = "Lacérer",
["Baited Shot"] = "Tir appâté",
["Counterattack"] = "Contre-attaque",
["Arcane Surge"] = "Éruption d’arcanes",
}
CleveRoids.Localized.ItemTypes = {
["Consumable"] = "Consommable",
["Reagent"] = "Reagent",
["Projectile"] = "Projectile",
["Trade Goods"] = "Artisanat",
}
elseif CleveRoids.Locale == "koKR" then
CleveRoids.Localized.Shield = "Shields"
CleveRoids.Localized.Bow = "Bows"
CleveRoids.Localized.Crossbow = "Crossbows"
CleveRoids.Localized.Gun = "Guns"
CleveRoids.Localized.Thrown = "Thrown"
CleveRoids.Localized.Wand = "Wands"
CleveRoids.Localized.Sword = "Swords"
CleveRoids.Localized.Staff = "Staves"
CleveRoids.Localized.Polearm = "Polearms"
CleveRoids.Localized.Mace = "Maces"
CleveRoids.Localized.FistWeapon = "Fist Weapons"
CleveRoids.Localized.Dagger = "Daggers"
CleveRoids.Localized.Axe = "Axes"
CleveRoids.Localized.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = {
["Beast"] = "야수",
@@ -219,41 +109,11 @@ elseif CleveRoids.Locale == "koKR" then
["Stealth"] = "은신",
["Prowl"] = "숨기",
["Shadowmeld"] = "그림자 숨기",
["Revenge"] = "복수",
["Overpower"] = "제압",
["Riposte"] = "반격",
["Surprise Attack"] = "기습",
["Lacerate"] = "괴롭히다",
["Baited Shot"] = "베이티드 샷",
["Counterattack"] = "역습",
["Arcane Surge"] = "비전 쇄도",
}
CleveRoids.Localized.ItemTypes = {
["Consumable"] = "소모품",
["Reagent"] = "재료",
["Projectile"] = "발사체",
["Trade Goods"] = "거래 용품",
}
elseif CleveRoids.Locale == "zhCN" then
CleveRoids.Localized.Shield = "盾牌"
CleveRoids.Localized.Bow = "弓"
CleveRoids.Localized.Crossbow = "弩"
CleveRoids.Localized.Gun = "枪械"
CleveRoids.Localized.Thrown = "投掷武器"
CleveRoids.Localized.Wand = "魔杖"
CleveRoids.Localized.Sword = "剑"
CleveRoids.Localized.Staff = "法杖"
CleveRoids.Localized.Polearm = "长柄武器"
CleveRoids.Localized.Mace = "锤"
CleveRoids.Localized.FistWeapon = "拳套"
CleveRoids.Localized.Dagger = "匕首"
CleveRoids.Localized.Axe = "斧"
CleveRoids.Localized.Attack = "攻击"
CleveRoids.Localized.AutoShot = "自动射击"
CleveRoids.Localized.Shoot = "射击"
CleveRoids.Localized.SpellRank = "%(等级 %d+%)"
CleveRoids.Localized.CreatureTypes = {
["Beast"] = "野兽",
@@ -274,41 +134,11 @@ elseif CleveRoids.Locale == "zhCN" then
["Stealth"] = "潜行",
["Prowl"] = "潜行",
["Shadowmeld"] = "影遁",
["Revenge"] = "复仇",
["Overpower"] = "压制",
["Riposte"] = "还击",
["Surprise Attack"] = "偷袭",
["Lacerate"] = "划破",
["Baited Shot"] = "诱饵射击",
["Counterattack"] = "反击",
["Arcane Surge"] = "奥术涌动",
}
CleveRoids.Localized.ItemTypes = {
["Consumable"] = "消耗品",
["Reagent"] = "材料",
["Projectile"] = "弹药",
["Trade Goods"] = "商品",
}
elseif CleveRoids.Locale == "zhTW" then
CleveRoids.Localized.Shield = "盾牌"
CleveRoids.Localized.Bow = "長弓"
CleveRoids.Localized.Crossbow = "弩"
CleveRoids.Localized.Gun = "槍械"
CleveRoids.Localized.Thrown = "投擲武器"
CleveRoids.Localized.Wand = "魔杖"
CleveRoids.Localized.Sword = "劍"
CleveRoids.Localized.Staff = "法杖"
CleveRoids.Localized.Polearm = "長柄武器"
CleveRoids.Localized.Mace = "錘"
CleveRoids.Localized.FistWeapon = "拳套"
CleveRoids.Localized.Dagger = "匕首"
CleveRoids.Localized.Axe = "斧"
CleveRoids.Localized.Attack = "攻擊"
CleveRoids.Localized.AutoShot = "自動射擊"
CleveRoids.Localized.Shoot = "射擊"
CleveRoids.Localized.SpellRank = "%(等級 %d+%)"
CleveRoids.Localized.CreatureTypes = {
["Beast"] = "野獸",
@@ -329,41 +159,11 @@ elseif CleveRoids.Locale == "zhTW" then
["Stealth"] = "隱形",
["Prowl"] = "徘徊",
["Shadowmeld"] = "影遁",
["Revenge"] = "復仇",
["Overpower"] = "壓倒",
["Riposte"] = "還擊",
["Surprise Attack"] = "偷襲",
["Lacerate"] = "劃破",
["Baited Shot"] = "誘餌射擊",
["Counterattack"] = "反擊",
["Arcane Surge"] = "奧術湧動",
}
CleveRoids.Localized.ItemTypes = {
["Consumable"] = "消耗品",
["Reagent"] = "材料",
["Projectile"] = "彈藥",
["Trade Goods"] = "貿易貨物",
}
elseif CleveRoids.Locale == "ruRU" then
CleveRoids.Localized.Shield = "Shields"
CleveRoids.Localized.Bow = "Bows"
CleveRoids.Localized.Crossbow = "Crossbows"
CleveRoids.Localized.Gun = "Guns"
CleveRoids.Localized.Thrown = "Thrown"
CleveRoids.Localized.Wand = "Wands"
CleveRoids.Localized.Sword = "Swords"
CleveRoids.Localized.Staff = "Staves"
CleveRoids.Localized.Polearm = "Polearms"
CleveRoids.Localized.Mace = "Maces"
CleveRoids.Localized.FistWeapon = "Fist Weapons"
CleveRoids.Localized.Dagger = "Daggers"
CleveRoids.Localized.Axe = "Axes"
CleveRoids.Localized.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = {
["Beast"] = "Животное",
@@ -384,41 +184,11 @@ elseif CleveRoids.Locale == "ruRU" then
["Stealth"] = "Незаметность",
["Prowl"] = "Крадущийся зверь",
["Shadowmeld"] = "Слияние с тенью",
["Revenge"] = "Реванш",
["Overpower"] = "Превосходство",
["Riposte"] = "Ответный удар",
["Surprise Attack"] = "Внезапная атака",
["Lacerate"] = "Разрыв",
["Baited Shot"] = "Выстрел с наживкой",
["Counterattack"] = "Контратака",
["Arcane Surge"] = "Чародейский выброс",
}
CleveRoids.Localized.ItemTypes = {
["Consumable"] = "Расходный материал",
["Reagent"] = "Reagent",
["Projectile"] = "Projectile",
["Trade Goods"] = "Хозяйственные товары",
}
elseif CleveRoids.Locale == "esES" then
CleveRoids.Localized.Shield = "Shields"
CleveRoids.Localized.Bow = "Bows"
CleveRoids.Localized.Crossbow = "Crossbows"
CleveRoids.Localized.Gun = "Guns"
CleveRoids.Localized.Thrown = "Thrown"
CleveRoids.Localized.Wand = "Wands"
CleveRoids.Localized.Sword = "Swords"
CleveRoids.Localized.Staff = "Staves"
CleveRoids.Localized.Polearm = "Polearms"
CleveRoids.Localized.Mace = "Maces"
CleveRoids.Localized.FistWeapon = "Fist Weapons"
CleveRoids.Localized.Dagger = "Daggers"
CleveRoids.Localized.Axe = "Axes"
CleveRoids.Localized.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = {
["Beast"] = "Bestia",
@@ -439,21 +209,6 @@ elseif CleveRoids.Locale == "esES" then
["Stealth"] = "Sigilo",
["Prowl"] = "Acechar",
["Shadowmeld"] = "Fusión con las sombras",
["Revenge"] = "Revancha",
["Overpower"] = "Abrumar",
["Riposte"] = "Estocada",
["Surprise Attack"] = "Ataque sorpresa",
["Lacerate"] = "Lacerar",
["Baited Shot"] = "Disparo con cebo",
["Counterattack"] = "Contraataque",
["Arcane Surge"] = "Oleada Arcana",
}
CleveRoids.Localized.ItemTypes = {
["Consumable"] = "Consumible",
["Reagent"] = "Reagent",
["Projectile"] = "Projectile",
["Trade Goods"] = "Objetos comerciables",
}
end
+59 -190
View File
@@ -1493,15 +1493,12 @@ function API.GetEquippedItems(unitToken)
local items = {}
for slot = 0, 18 do
local link = GetInventoryItemLink("player", slot + 1)
if link then
local _, _, itemId = string.find(link, "item:(%d+)")
if itemId then
items[slot] = {
itemId = tonumber(itemId),
-- Other fields not available without native API
}
end
local itemId = CleveRoids.ClassicAPI.GetInventoryItemID("player", slot + 1)
if itemId then
items[slot] = {
itemId = itemId,
-- Other fields not available without native API
}
end
end
@@ -1524,14 +1521,11 @@ function API.GetEquippedItem(unitToken, slot)
return nil
end
local link = GetInventoryItemLink("player", slot + 1) -- 1-indexed
if link then
local _, _, itemId = string.find(link, "item:(%d+)")
if itemId then
return {
itemId = tonumber(itemId),
}
end
local itemId = CleveRoids.ClassicAPI.GetInventoryItemID("player", slot + 1) -- 1-indexed
if itemId then
return {
itemId = itemId,
}
end
return nil
@@ -1560,16 +1554,13 @@ function API.GetBagItems(bagIndex)
local bagContents = {}
local numSlots = GetContainerNumSlots(bagIndex) or 0
for slot = 1, numSlots do
local link = GetContainerItemLink(bagIndex, slot)
if link then
local _, _, itemId = string.find(link, "item:(%d+)")
local itemId = CleveRoids.ClassicAPI.GetContainerItemID(bagIndex, slot)
if itemId then
local _, count = GetContainerItemInfo(bagIndex, slot)
if itemId then
bagContents[slot] = {
itemId = tonumber(itemId),
stackCount = count or 1,
}
end
bagContents[slot] = {
itemId = itemId,
stackCount = count or 1,
}
end
end
return bagContents
@@ -1582,16 +1573,13 @@ function API.GetBagItems(bagIndex)
if numSlots > 0 then
bags[bag] = {}
for slot = 1, numSlots do
local link = GetContainerItemLink(bag, slot)
if link then
local _, _, itemId = string.find(link, "item:(%d+)")
local itemId = CleveRoids.ClassicAPI.GetContainerItemID(bag, slot)
if itemId then
local _, count = GetContainerItemInfo(bag, slot)
if itemId then
bags[bag][slot] = {
itemId = tonumber(itemId),
stackCount = count or 1,
}
end
bags[bag][slot] = {
itemId = itemId,
stackCount = count or 1,
}
end
end
end
@@ -1609,16 +1597,13 @@ function API.GetBagItem(bagIndex, slot)
end
-- Fallback: manual lookup
local link = GetContainerItemLink(bagIndex, slot)
if link then
local _, _, itemId = string.find(link, "item:(%d+)")
local itemId = CleveRoids.ClassicAPI.GetContainerItemID(bagIndex, slot)
if itemId then
local _, count = GetContainerItemInfo(bagIndex, slot)
if itemId then
return {
itemId = tonumber(itemId),
stackCount = count or 1,
}
end
return {
itemId = itemId,
stackCount = count or 1,
}
end
return nil
@@ -1779,14 +1764,13 @@ function API.FindBagItem(itemIdOrName)
for bag = 0, 4 do
local numSlots = GetContainerNumSlots(bag) or 0
for slot = 1, numSlots do
local link = GetContainerItemLink(bag, slot)
if link then
if checkId then
local _, _, currentId = string.find(link, "item:(%d+)")
if currentId and tonumber(currentId) == checkId then
return bag, slot
end
elseif checkName then
if checkId then
if CleveRoids.ClassicAPI.GetContainerItemID(bag, slot) == checkId then
return bag, slot
end
elseif checkName then
local link = GetContainerItemLink(bag, slot)
if link then
local _, _, currentName = string.find(link, "|h%[(.-)%]|h")
if currentName and string.lower(currentName) == checkName then
return bag, slot
@@ -2103,26 +2087,28 @@ function API.GetTrinkets(copy)
for bag = 0, 4 do
local numSlots = GetContainerNumSlots(bag) or 0
for slot = 1, numSlots do
local link = GetContainerItemLink(bag, slot)
if link then
local _, _, itemId = string.find(link, "item:(%d+)")
if itemId then
local numItemId = tonumber(itemId)
local invType = API.GetItemInventoryType(numItemId)
if invType == 12 then -- Trinket
local _, _, name = string.find(link, "|h%[(.-)%]|h")
local texture = GetContainerItemInfo(bag, slot)
local itemLevel = API.GetItemLevel(numItemId)
trinkets[index] = {
itemId = numItemId,
trinketName = name or "Unknown",
texture = texture,
itemLevel = itemLevel,
bagIndex = bag,
slotIndex = slot,
}
index = index + 1
local numItemId = CleveRoids.ClassicAPI.GetContainerItemID(bag, slot)
if numItemId then
local invType = API.GetItemInventoryType(numItemId)
if invType == 12 then -- Trinket
-- Only build the link string for actual trinkets, to read the name.
local link = GetContainerItemLink(bag, slot)
local name
if link then
local _
_, _, name = string.find(link, "|h%[(.-)%]|h")
end
local texture = GetContainerItemInfo(bag, slot)
local itemLevel = API.GetItemLevel(numItemId)
trinkets[index] = {
itemId = numItemId,
trinketName = name or "Unknown",
texture = texture,
itemLevel = itemLevel,
bagIndex = bag,
slotIndex = slot,
}
index = index + 1
end
end
end
@@ -2183,18 +2169,13 @@ function API.GetTrinketCooldown(slot)
end
-- Get item ID from equipped slot
local link = GetInventoryItemLink("player", equipSlot)
if not link then
return -1
end
local _, _, itemId = string.find(link, "item:(%d+)")
local itemId = CleveRoids.ClassicAPI.GetInventoryItemID("player", equipSlot)
if not itemId then
return -1
end
-- Get cooldown info
return API.GetItemCooldownInfo(tonumber(itemId))
return API.GetItemCooldownInfo(itemId)
end
-- Use an equipped trinket
@@ -3550,117 +3531,5 @@ function API.GetUnitMaxPower(unitToken, powerType)
return UnitManaMax(unitToken)
end
--------------------------------------------------------------------------------
-- RELIQUARY DBC FUNCTIONS (optional DLL)
--------------------------------------------------------------------------------
-- Safe Reliquary call wrapper — returns nil on missing DLL or lookup failure
local function RQ_SafeCall(func, ...)
if not func then return nil end
local ok, result = pcall(func, unpack(arg))
if ok then return result end
return nil
end
-- Get item set data from DBC by set ID
-- Returns: { name, itemId_1..17, setSpellId_1..8, setThreshold_1..8 } or nil
function API.GetItemSet(setId)
if not setId or not _G.RQ_GetItemSet then return nil end
return RQ_SafeCall(_G.RQ_GetItemSet, setId)
end
-- Get the set ID for an item (via Nampower's GetItemStatsField)
-- Returns: setId (number) or nil if item has no set
function API.GetItemSetId(itemId)
if not itemId then return nil end
local setId = API.GetItemField(itemId, "itemSet")
if setId and setId ~= 0 then return setId end
return nil
end
-- Get all item IDs belonging to a set (from Reliquary DBC)
-- Returns: { itemId1, itemId2, ... } or nil
function API.GetItemSetItems(setId)
local setData = API.GetItemSet(setId)
if not setData then return nil end
local items = {}
for i = 1, 17 do
local id = setData["itemId_" .. i]
if id then
id = tonumber(id)
if id and id ~= 0 then
table.insert(items, id)
end
end
end
if table.getn(items) > 0 then return items end
return nil
end
-- Get set bonus spell/threshold pairs from DBC
-- Returns: { { spellId = N, threshold = N }, ... } or nil
function API.GetItemSetBonuses(setId)
local setData = API.GetItemSet(setId)
if not setData then return nil end
local bonuses = {}
for i = 1, 8 do
local spellId = setData["setSpellId_" .. i]
local threshold = setData["setThreshold_" .. i]
if spellId and threshold then
spellId = tonumber(spellId)
threshold = tonumber(threshold)
if spellId and spellId ~= 0 and threshold and threshold > 0 then
table.insert(bonuses, { spellId = spellId, threshold = threshold })
end
end
end
if table.getn(bonuses) > 0 then return bonuses end
return nil
end
-- Get spell effect radius in yards from DBC
-- spellId: the spell to look up
-- effectIndex: 1, 2, or 3 (which effect slot, default 1)
-- Returns: radius (number) or nil
function API.GetSpellEffectRadius(spellId, effectIndex)
effectIndex = effectIndex or 1
if not spellId then return nil end
-- Get the radius index from the spell's effect via Nampower
local radiusField = "effectRadiusIndex"
local rec = API.GetSpellRecord(spellId)
if not rec then return nil end
-- effectRadiusIndex is an array field — access by effect index
local radiusIndex = nil
if rec.effectRadiusIndex then
if type(rec.effectRadiusIndex) == "table" then
radiusIndex = rec.effectRadiusIndex[effectIndex]
else
-- Single value (effect 1 only)
if effectIndex == 1 then
radiusIndex = rec.effectRadiusIndex
end
end
end
if not radiusIndex or radiusIndex == 0 then return nil end
-- Try Reliquary for the SpellRadius DBC lookup
if _G.RQ_GetSpellRadius then
local radiusData = RQ_SafeCall(_G.RQ_GetSpellRadius, radiusIndex)
if radiusData and radiusData.radius then
local radius = tonumber(radiusData.radius)
if radius and radius > 0 then return radius end
end
end
return nil
end
-- Expose API globally for other addons
_G.CleveRoidsNampowerAPI = API
+51 -101
View File
@@ -6892,11 +6892,7 @@ CleveRoids.equipmentModifiers[9904] = { slot = 18, modifier = ripRakeIdolModifie
-- Function to get equipped item ID in a specific slot
function CleveRoids.GetEquippedItemID(slotID)
local itemLink = GetInventoryItemLink("player", slotID)
if not itemLink then return nil end
local _, _, itemID = string.find(itemLink, "item:(%d+)")
return tonumber(itemID)
return CleveRoids.ClassicAPI.GetInventoryItemID("player", slotID)
end
-- Apply equipment modifiers to a debuff duration
@@ -6922,12 +6918,7 @@ function CleveRoids.ApplyEquipmentModifier(spellID, baseDuration)
local modifiedDuration = modifier.modifier(baseDuration, itemID)
if modifiedDuration ~= baseDuration and CleveRoids.debug then
local itemName = "Unknown"
local itemLink = GetInventoryItemLink("player", modifier.slot)
if itemLink then
local _, _, _n = string.find(itemLink, "%[(.-)%]")
itemName = _n or "Unknown"
end
local itemName = C_Item.GetItemName({ equipmentSlotIndex = modifier.slot }) or "Unknown"
DEFAULT_CHAT_FRAME:AddMessage(
string.format("|cffff00ff[Equipment Modifier]|r %s (ID:%d): %ds -> %ds (item: %s [%d])",
@@ -7042,28 +7033,30 @@ end
-- Database of set bonus modifiers for debuff durations
-- Structure: [spellID] = { items = {itemID1, itemID2, ...}, threshold = X, modifier = function(baseDuration) }
-- When Reliquary is available, items can be omitted and setId used instead (auto-resolves from DBC)
-- When a setId is given, items can be omitted and resolved from ItemSet.dbc
CleveRoids.setbonusModifiers = CleveRoids.setbonusModifiers or {}
-- Cache: setId -> { itemId1, itemId2, ... } (resolved from Reliquary or hardcoded)
-- Cache: setId -> { itemId1, itemId2, ... } (resolved from ItemSet.dbc or hardcoded)
local setItemCache = {}
-- Resolve set items: use Reliquary DBC if available, otherwise fall back to hardcoded list
-- Resolve set items: use the ItemSet.dbc lookup when a setId is given, otherwise
-- fall back to the hardcoded list on the modifier.
local function ResolveSetItems(modifier)
-- If items are already provided (hardcoded), use them directly
if modifier.items and table.getn(modifier.items) > 0 then
return modifier.items
end
-- Try Reliquary DBC lookup by setId
if modifier.setId and CleveRoids.NampowerAPI then
-- DBC lookup by setId via ClassicAPI
if modifier.setId then
-- Check cache first
if setItemCache[modifier.setId] then
return setItemCache[modifier.setId]
end
local items = CleveRoids.NampowerAPI.GetItemSetItems(modifier.setId)
if items then
local info = CleveRoids.ClassicAPI.GetItemSetInfo(modifier.setId)
local items = info and info.items
if items and table.getn(items) > 0 then
setItemCache[modifier.setId] = items
return items
end
@@ -7073,24 +7066,20 @@ local function ResolveSetItems(modifier)
end
-- Function to count how many items from a set are currently equipped
-- Accepts either a direct items table or a modifier entry with setId for Reliquary lookup
-- Accepts either a direct items table or a modifier entry with setId for DBC lookup
function CleveRoids.CountEquippedSetItems(items)
if not items or type(items) ~= "table" then return 0 end
local count = 0
-- Check all equipment slots (1-19)
for slot = 1, 19 do
local itemLink = GetInventoryItemLink("player", slot)
if itemLink then
local _, _, itemID = string.find(itemLink, "item:(%d+)")
if itemID then
itemID = tonumber(itemID)
-- Check if this item is in the set
for _, setItemID in ipairs(items) do
if itemID == setItemID then
count = count + 1
break
end
local itemID = CleveRoids.GetEquippedItemID(slot)
if itemID then
-- Check if this item is in the set
for _, setItemID in ipairs(items) do
if itemID == setItemID then
count = count + 1
break
end
end
end
@@ -7099,40 +7088,19 @@ function CleveRoids.CountEquippedSetItems(items)
return count
end
-- Count equipped set items by set ID (uses Nampower to check each slot's itemSet field)
-- Falls back to CountEquippedSetItems with Reliquary item list if GetItemStatsField unavailable
-- Count equipped set items by set ID, comparing each equipped slot's own set
-- membership (ClassicAPI GetItemSetIDByID) against the target set.
function CleveRoids.CountEquippedSetItemsBySetId(setId)
if not setId then return 0 end
-- Fast path: use Nampower GetItemStatsField to check itemSet directly per slot
if CleveRoids.NampowerAPI and CleveRoids.NampowerAPI.GetItemField then
local count = 0
for slot = 1, 19 do
local itemLink = GetInventoryItemLink("player", slot)
if itemLink then
local _, _, itemID = string.find(itemLink, "item:(%d+)")
if itemID then
local itemSetId = CleveRoids.NampowerAPI.GetItemSetId(tonumber(itemID))
if itemSetId == setId then
count = count + 1
end
end
end
local count = 0
for slot = 1, 19 do
local itemID = CleveRoids.GetEquippedItemID(slot)
if itemID and CleveRoids.ClassicAPI.GetItemSetIDByID(itemID) == setId then
count = count + 1
end
return count
end
-- Fallback: resolve set item list and count matches
local items = setItemCache[setId]
if not items and CleveRoids.NampowerAPI then
items = CleveRoids.NampowerAPI.GetItemSetItems(setId)
if items then setItemCache[setId] = items end
end
if items then
return CleveRoids.CountEquippedSetItems(items)
end
return 0
return count
end
-- Apply set bonus modifiers to a debuff duration
@@ -7183,7 +7151,7 @@ end
-- Helper function to register a set bonus modifier
-- Usage: CleveRoids.RegisterSetBonusModifier(spellID, itemsTable, threshold, modifierFunction)
-- With Reliquary: CleveRoids.RegisterSetBonusModifier(spellID, nil, threshold, modifierFunction, setId)
-- With a setId: CleveRoids.RegisterSetBonusModifier(spellID, nil, threshold, modifierFunction, setId)
function CleveRoids.RegisterSetBonusModifier(spellID, items, threshold, modifierFunc, setId)
if not spellID or not threshold or not modifierFunc then
return false
@@ -7202,17 +7170,17 @@ function CleveRoids.RegisterSetBonusModifier(spellID, items, threshold, modifier
return true
end
-- Get info about an equipped item's set (combines Nampower + Reliquary)
-- Get info about an equipped item's set (from ItemSet.dbc via ClassicAPI)
-- Returns: setName, setId, equippedCount, totalPieces, items or nil
function CleveRoids.GetEquippedItemSetInfo(itemId)
if not itemId or not CleveRoids.NampowerAPI then return nil end
if not itemId then return nil end
local setId = CleveRoids.NampowerAPI.GetItemSetId(itemId)
local setId = CleveRoids.ClassicAPI.GetItemSetIDByID(itemId)
if not setId then return nil end
local setData = CleveRoids.NampowerAPI.GetItemSet(setId)
local setName = setData and setData.name_enUS or nil
local items = CleveRoids.NampowerAPI.GetItemSetItems(setId)
local info = CleveRoids.ClassicAPI.GetItemSetInfo(setId)
local setName = info and info.name or nil
local items = info and info.items or nil
local totalPieces = items and table.getn(items) or 0
local equippedCount = CleveRoids.CountEquippedSetItemsBySetId(setId)
@@ -7222,7 +7190,7 @@ end
-- Count equipped pieces of a named or ID-referenced item set
-- nameOrId: set name (string, e.g. "Judgement Battlegear") or set ID (number)
-- Returns: equipped count (number), setId (number or nil)
-- Name lookup requires Reliquary; ID lookup requires Nampower
-- Both name and ID lookups resolve from ItemSet.dbc via ClassicAPI
function CleveRoids.GetEquippedSetPieceCount(nameOrId)
if not nameOrId then return 0, nil end
@@ -7232,28 +7200,17 @@ function CleveRoids.GetEquippedSetPieceCount(nameOrId)
return CleveRoids.CountEquippedSetItemsBySetId(numericId), numericId
end
-- String: scan equipped items and match by set name from DBC
if not CleveRoids.NampowerAPI or not CleveRoids.NampowerAPI.GetItemSetId then
return 0, nil
end
-- Scan equipped items to resolve set name → set ID, then count via fast path
-- String: scan equipped items and match by set name from ItemSet.dbc
local lowerName = string.lower(nameOrId)
for slot = 1, 19 do
local itemLink = GetInventoryItemLink("player", slot)
if itemLink then
local _, _, itemID = string.find(itemLink, "item:(%d+)")
if itemID then
local setId = CleveRoids.NampowerAPI.GetItemSetId(tonumber(itemID))
if setId then
local setData = CleveRoids.NampowerAPI.GetItemSet(setId)
if setData then
local dbcName = setData.name_enUS
if dbcName and string.lower(dbcName) == lowerName then
return CleveRoids.CountEquippedSetItemsBySetId(setId), setId
end
end
local itemID = CleveRoids.GetEquippedItemID(slot)
if itemID then
local setId = CleveRoids.ClassicAPI.GetItemSetIDByID(itemID)
if setId then
local info = CleveRoids.ClassicAPI.GetItemSetInfo(setId)
if info and info.name and string.lower(info.name) == lowerName then
return CleveRoids.CountEquippedSetItemsBySetId(setId), setId
end
end
end
@@ -7262,18 +7219,9 @@ function CleveRoids.GetEquippedSetPieceCount(nameOrId)
return 0, nil
end
-- Get spell effect radius in yards (Nampower + Reliquary)
-- spellId: the spell to look up
-- effectIndex: 1, 2, or 3 (which effect slot, default 1)
-- Returns: radius in yards or nil
function CleveRoids.GetSpellEffectRadius(spellId, effectIndex)
if not CleveRoids.NampowerAPI then return nil end
return CleveRoids.NampowerAPI.GetSpellEffectRadius(spellId, effectIndex)
end
-- DRUID set bonus modifiers
-- Dreamwalker Regalia (4/9): Increases Moonfire duration by 3 seconds and Insect Swarm by 2 seconds
-- setId 536 = Dreamwalker Regalia; hardcoded items as fallback when Reliquary unavailable
-- setId 536 = Dreamwalker Regalia; hardcoded items as fallback when DBC lookup unavailable
local DREAMWALKER_SET_ID = 536
local dreamwalkerItems = { 47372, 47373, 47374, 47375, 47376, 47377, 47378, 47379, 47380 }
local dreamwalkerMoonfireModifier = function(base) return base + 3 end
@@ -7299,7 +7247,7 @@ CleveRoids.setbonusModifiers[24976] = { setId = DREAMWALKER_SET_ID, items = drea
CleveRoids.setbonusModifiers[24977] = { setId = DREAMWALKER_SET_ID, items = dreamwalkerItems, threshold = 4, modifier = dreamwalkerInsectSwarmModifier } -- Insect Swarm Rank 5
-- Haruspex's Garb (3/5): Increases Faerie Fire duration by 5 seconds
-- setId 474 = Haruspex's Garb; hardcoded items as fallback when Reliquary unavailable
-- setId 474 = Haruspex's Garb; hardcoded items as fallback when DBC lookup unavailable
local HARUSPEX_SET_ID = 474
local haruspexItems = { 19613, 19955, 19840, 19839, 19838 }
local haruspexFaerieFireModifier = function(base) return base + 5 end
@@ -7810,7 +7758,7 @@ end
-- CC IMMUNITY TRACKING
-- Get CC type from a spell ID using the CCSpellMechanics table from Conditionals.lua
-- Get CC type from a spell ID via DBC mechanic lookup (nampower, then ClassicAPI)
-- Returns: CC type name (e.g., "stun", "fear") or nil if not a CC spell
-- EffectApplyAuraName → CC type mapping (fallback when mechanics are unset)
-- Uses vanilla 1.12.1 aura type enum values
@@ -7864,9 +7812,11 @@ local function GetSpellCCType(spellID)
end
end
-- Priority 2: Hardcoded table fallback (CCSpellMechanics in Conditionals.lua)
local mechanic = CleveRoids.CCSpellMechanics and CleveRoids.CCSpellMechanics[spellID]
if mechanic and MECHANIC_TO_CC_TYPE[mechanic] then
-- Priority 2: ClassicAPI Spell.dbc reader (always present; covers every spell).
-- A subset of Priority 1's per-effect/aura checks, used when nampower's
-- GetSpellRecField is unavailable.
local mechanic = CleveRoids.ClassicAPI.GetSpellMechanicByID(spellID)
if mechanic and mechanic > 0 and MECHANIC_TO_CC_TYPE[mechanic] then
return MECHANIC_TO_CC_TYPE[mechanic]
end