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 - name: Package and release to GitHub
uses: BigWigsMods/packager@v2 uses: BigWigsMods/packager@v2
env: 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 }} GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}
+71
View File
@@ -119,6 +119,55 @@ function API.GetActionInfo(slot)
return GetActionInfo(slot) return GetActionInfo(slot)
end 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 -- State
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@@ -133,6 +182,28 @@ function API.IsSwimming()
return IsSwimming() and true or false return IsSwimming() and true or false
end 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 -- NamePlate
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
+55 -255
View File
@@ -273,24 +273,17 @@ local function BuildEquipmentCache()
end end
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 for slot = 1, 19 do
local link = GetInventoryItemLink("player", slot) local id = GetInventoryItemID("player", slot)
if link then if id then
local _, _, id = string_find(link, "item:(%d+)") _equippedItemIDs[slot] = id
local _, _, nameInBrackets = string_find(link, "%[(.+)%]") local name = C_Item.GetItemName({ equipmentSlotIndex = slot })
if name then
if id then _equippedItemNames[slot] = string_lower(name)
_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
end end
end end
end end
@@ -350,8 +343,7 @@ function CleveRoids.FindItemLocation(item)
if numericItem then if numericItem then
-- Check if it's an equipment slot (1-19) -- Check if it's an equipment slot (1-19)
if numericItem >= 1 and numericItem <= 19 then if numericItem >= 1 and numericItem <= 19 then
local link = GetInventoryItemLink("player", numericItem) if GetInventoryItemID("player", numericItem) then
if link then
return { type = "inventory", inventoryID = numericItem } return { type = "inventory", inventoryID = numericItem }
end end
return nil return nil
@@ -2094,34 +2086,21 @@ end
-- weaponType: The name of the weapon's type (e.g. Axe, Shield, etc.) -- weaponType: The name of the weapon's type (e.g. Axe, Shield, etc.)
-- returns: True when equipped, otherwhise false -- returns: True when equipped, otherwhise false
function CleveRoids.HasWeaponEquipped(weaponType) function CleveRoids.HasWeaponEquipped(weaponType)
if not CleveRoids.WeaponTypeNames[weaponType] then local def = CleveRoids.WeaponTypeNames[weaponType]
if not def then
return false return false
end end
local slotName = CleveRoids.WeaponTypeNames[weaponType].slot local slotId = GetInventorySlotInfo(def.slot)
local localizedName = CleveRoids.WeaponTypeNames[weaponType].name local itemId = CleveRoids.ClassicAPI.GetInventoryItemID("player", slotId)
local slotId = GetInventorySlotInfo(slotName) if not itemId then
local slotLink = GetInventoryItemLink("player",slotId)
if not slotLink then
return false return false
end end
local _,_,itemId = string.find(slotLink,"item:(%d+)") -- Compare locale-independent item class/subclass instead of matching the
if not itemId then -- Also good to check if itemId was found -- localized subtype string (GetItemInfoInstant: ..., classID, subClassID).
return false local _, _, _, _, _, classID, subClassID = C_Item.GetItemInfoInstant(itemId)
end return classID == def.class and def.subClass[subClassID] == true
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
end end
-- Checks whether or not the given UnitId is in your party or your raid -- 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 -- If this is a numeric slot (1-19), resolve to the equipped item's name
local slotNum = tonumber(name) local slotNum = tonumber(name)
if slotNum and slotNum >= 1 and slotNum <= 19 then if slotNum and slotNum >= 1 and slotNum <= 19 then
local link = GetInventoryItemLink("player", slotNum) local itemName = C_Item.GetItemName({ equipmentSlotIndex = slotNum })
if link then if itemName then name = itemName end
local _, _, itemName = string.find(link, "%[(.+)%]")
if itemName then name = itemName end
end
end end
args = {name = name} args = {name = name}
else 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 -- If this is a numeric slot (1-19), resolve to the equipped item's name
local slotNum = tonumber(name) local slotNum = tonumber(name)
if slotNum and slotNum >= 1 and slotNum <= 19 then if slotNum and slotNum >= 1 and slotNum <= 19 then
local link = GetInventoryItemLink("player", slotNum) local itemName = C_Item.GetItemName({ equipmentSlotIndex = slotNum })
if link then if itemName then name = itemName end
local _, _, itemName = string.find(link, "%[(.+)%]")
if itemName then name = itemName end
end
end end
args.name = name args.name = name
else else
@@ -4882,13 +4855,11 @@ function CleveRoids.HasItem(item)
if type(item) == "string" and item ~= "" then if type(item) == "string" and item ~= "" then
local itemLower = string.lower(item) local itemLower = string.lower(item)
-- Check equipped slots for substring match -- Check equipped slots for substring match (decorated name, no link build)
for slot = 0, 19 do for slot = 1, 19 do
local link = GetInventoryItemLink("player", slot) local name = C_Item.GetItemName({ equipmentSlotIndex = slot })
if link then if name and string.find(string.lower(name), itemLower, 1, true) then
if string.find(string.lower(link), itemLower, 1, true) then return true
return true
end
end end
end end
@@ -4897,11 +4868,9 @@ function CleveRoids.HasItem(item)
local size = GetContainerNumSlots(bag) local size = GetContainerNumSlots(bag)
if size and size > 0 then if size and size > 0 then
for slotIndex = 1, size do for slotIndex = 1, size do
local link = GetContainerItemLink(bag, slotIndex) local name = C_Item.GetItemName({ bagID = bag, slotIndex = slotIndex })
if link then if name and string.find(string.lower(name), itemLower, 1, true) then
if string.find(string.lower(link), itemLower, 1, true) then return true
return true
end
end end
end end
end end
@@ -4946,14 +4915,12 @@ function CleveRoids.GetItemCooldown(item)
local itemLower = string.lower(item) local itemLower = string.lower(item)
local start, dur, en local start, dur, en
-- Check equipped slots for substring match -- Check equipped slots for substring match (decorated name, no link build)
for slot = 0, 19 do for slot = 1, 19 do
local link = GetInventoryItemLink("player", slot) local name = C_Item.GetItemName({ equipmentSlotIndex = slot })
if link then if name and string.find(string.lower(name), itemLower, 1, true) then
if string.find(string.lower(link), itemLower, 1, true) then start, dur, en = GetInventoryItemCooldown("player", slot)
start, dur, en = GetInventoryItemCooldown("player", slot) return _norm(start, dur, en)
return _norm(start, dur, en)
end
end end
end end
@@ -4962,12 +4929,10 @@ function CleveRoids.GetItemCooldown(item)
local size = GetContainerNumSlots(bag) local size = GetContainerNumSlots(bag)
if size and size > 0 then if size and size > 0 then
for slotIndex = 1, size do for slotIndex = 1, size do
local link = GetContainerItemLink(bag, slotIndex) local name = C_Item.GetItemName({ bagID = bag, slotIndex = slotIndex })
if link then if name and string.find(string.lower(name), itemLower, 1, true) then
if string.find(string.lower(link), itemLower, 1, true) then start, dur, en = GetContainerItemCooldown(bag, slotIndex)
start, dur, en = GetContainerItemCooldown(bag, slotIndex) return _norm(start, dur, en)
return _norm(start, dur, en)
end
end end
end end
end end
@@ -5187,165 +5152,6 @@ CleveRoids.CCTypesLossOfControl = {
[30] = true, -- sap (now part of stun group) [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 -- Check if BuffLib is available with full mechanic support
function CleveRoids.HasBuffLib() function CleveRoids.HasBuffLib()
-- Defensive: ensure BuffLib.SpellData is a table, not a function -- Defensive: ensure BuffLib.SpellData is a table, not a function
@@ -5354,7 +5160,7 @@ function CleveRoids.HasBuffLib()
and BuffLib.SpellData.GetMechanic and BuffLib.SpellData.GetMechanic
end 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) function CleveRoids.GetSpellMechanic(spellID)
if not spellID or spellID <= 0 then return 0 end if not spellID or spellID <= 0 then return 0 end
@@ -5367,8 +5173,8 @@ function CleveRoids.GetSpellMechanic(spellID)
end end
end end
-- Fall back to built-in table -- Fall back to ClassicAPI's Spell.dbc reader (always present; covers every spell)
return CleveRoids.CCSpellMechanics[spellID] or 0 return CleveRoids.ClassicAPI.GetSpellMechanicByID(spellID) or 0
end end
-- Validate CC on a unit (target, focus, player, etc.) -- 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>=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:SetName] — true if any pieces of that set are equipped (count > 0)
-- [set:123>=3] — numeric IDs also supported (Nampower only, no Reliquary needed) -- [set:123>=3] — numeric IDs also supported
-- Name lookup requires Reliquary (for DBC set name); ID lookup requires Nampower -- Both name and ID lookups resolve from ItemSet.dbc via ClassicAPI
set = function(conditionals) set = function(conditionals)
return Multi(conditionals.set, function(args) return Multi(conditionals.set, function(args)
if type(args) == "table" and args.operator and args.amount then if type(args) == "table" and args.operator and args.amount then
@@ -6059,13 +5865,10 @@ CleveRoids.Keywords = {
local itemName = name local itemName = name
local slotNum = tonumber(name) local slotNum = tonumber(name)
if slotNum and slotNum >= 1 and slotNum <= 19 then if slotNum and slotNum >= 1 and slotNum <= 19 then
-- Resolve slot number to item name -- Resolve slot number to item name (decorated, no link build)
local link = GetInventoryItemLink("player", slotNum) local extractedName = C_Item.GetItemName({ equipmentSlotIndex = slotNum })
if link then if extractedName then
local _, _, extractedName = string.find(link, "%[(.+)%]") itemName = extractedName
if extractedName then
itemName = extractedName
end
end end
end end
@@ -6097,13 +5900,10 @@ CleveRoids.Keywords = {
local itemName = name local itemName = name
local slotNum = tonumber(name) local slotNum = tonumber(name)
if slotNum and slotNum >= 1 and slotNum <= 19 then if slotNum and slotNum >= 1 and slotNum <= 19 then
-- Resolve slot number to item name -- Resolve slot number to item name (decorated, no link build)
local link = GetInventoryItemLink("player", slotNum) local extractedName = C_Item.GetItemName({ equipmentSlotIndex = slotNum })
if link then if extractedName then
local _, _, extractedName = string.find(link, "%[(.+)%]") itemName = extractedName
if extractedName then
itemName = extractedName
end
end end
end end
+4
View File
@@ -67,6 +67,10 @@ SLASH_UNSHIFT1 = "/unshift"
SlashCmdList.UNSHIFT = CleveRoids.DoUnshift SlashCmdList.UNSHIFT = CleveRoids.DoUnshift
SLASH_CANCELFORM1 = "/cancelform"
SlashCmdList.CANCELFORM = CleveRoids.DoCancelForm
SLASH_UNQUEUE1 = "/unqueue" SLASH_UNQUEUE1 = "/unqueue"
SlashCmdList.UNQUEUE = SpellStopCasting 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 -- 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() local function InstallHooks()
if hooked then return end if hooked then return end
if not MacroFrameText or not MacroFrame then return end if not MacroFrameText or not MacroFrame then return end
@@ -1325,6 +1375,15 @@ local function InstallHooks()
end end
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 hooked = true
end end
+69 -98
View File
@@ -58,11 +58,7 @@ function CleveRoids.IndexSpells()
bookType = CleveRoids.bookTypes[book] bookType = CleveRoids.bookTypes[book]
spells[bookType] = {} spells[bookType] = {}
else else
local cost, reagent = CleveRoids.GetSpellCost(i, bookType) local cost, reagent, reagentId = CleveRoids.GetSpellCost(i, bookType, spellId)
-- Fallback for known reagent spells if tooltip scan failed
if (not reagent or reagent == "") and CleveRoids.ReagentBySpell then
reagent = CleveRoids.ReagentBySpell[spellName]
end
if not spells[bookType][spellName] then if not spells[bookType][spellName] then
spells[bookType][spellName] = { spells[bookType][spellName] = {
spellSlot = i, spellSlot = i,
@@ -71,7 +67,7 @@ function CleveRoids.IndexSpells()
bookType = bookType, bookType = bookType,
texture = texture, texture = texture,
cost = cost, cost = cost,
reagent = reagent, reagentId = reagentId,
} }
end end
if spellRank and not spells[bookType][spellName][spellRank] then if spellRank and not spells[bookType][spellName][spellRank] then
@@ -83,7 +79,7 @@ function CleveRoids.IndexSpells()
bookType = bookType, bookType = bookType,
texture = texture, texture = texture,
cost = cost, cost = cost,
reagent = reagent reagentId = reagentId,
} }
spells[bookType][spellName].highest = spells[bookType][spellName][spellRank] spells[bookType][spellName].highest = spells[bookType][spellName][spellRank]
end end
@@ -94,6 +90,13 @@ function CleveRoids.IndexSpells()
if reagent then if reagent then
CleveRoids.countedItemTypes[reagent] = true 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 end
end end
@@ -156,10 +159,9 @@ end
function CleveRoids.IndexEquippedItems() function CleveRoids.IndexEquippedItems()
local items = CleveRoids.Items or {} local items = CleveRoids.Items or {}
for inventoryID = 0, 19 do for inventoryID = 1, 19 do
local link = GetInventoryItemLink("player", inventoryID) local itemID = GetInventoryItemID("player", inventoryID)
if link then if itemID then
local _, _, itemID = string.find(link, "item:(%d+)")
local name, link, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID) local name, link, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID)
if name then if name then
local count = GetInventoryItemCount("player", inventoryID) local count = GetInventoryItemCount("player", inventoryID)
@@ -199,10 +201,9 @@ function CleveRoids.IndexEquipSlot(inventoryID)
if not inventoryID then return end if not inventoryID then return end
local items = CleveRoids.Items or {} local items = CleveRoids.Items or {}
local link = GetInventoryItemLink("player", inventoryID) local itemID = GetInventoryItemID("player", inventoryID)
if link then if itemID then
local _, _, itemID = string.find(link, "item:(%d+)")
local name, itemLink, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID) local name, itemLink, _, _, itemType, itemSubType, _, _, texture = GetItemInfo(itemID)
if name then if name then
local count = GetInventoryItemCount("player", inventoryID) local count = GetInventoryItemCount("player", inventoryID)
@@ -265,21 +266,17 @@ function CleveRoids.IndexItems()
-- PERFORMANCE: Local function references -- PERFORMANCE: Local function references
local GetContainerNumSlots = GetContainerNumSlots local GetContainerNumSlots = GetContainerNumSlots
local GetContainerItemLink = GetContainerItemLink
local GetContainerItemInfo = GetContainerItemInfo local GetContainerItemInfo = GetContainerItemInfo
local GetInventoryItemLink = GetInventoryItemLink
local GetInventoryItemCount = GetInventoryItemCount local GetInventoryItemCount = GetInventoryItemCount
-- Scan bags (reverse order to prefer first stack) -- Scan bags (reverse order to prefer first stack)
for bagID = 0, NUM_BAG_SLOTS do for bagID = 0, NUM_BAG_SLOTS do
local numSlots = GetContainerNumSlots(bagID) local numSlots = GetContainerNumSlots(bagID)
for slot = numSlots, 1, -1 do for slot = numSlots, 1, -1 do
local link = GetContainerItemLink(bagID, slot) local itemID = C_Container.GetContainerItemID(bagID, slot)
if link then if itemID then
local _, _, itemID = string_find(link, "item:(%d+)") -- Decorated name for the duplicate fast-path (no link string built)
local linkName = C_Item.GetItemName({ bagID = bagID, slotIndex = slot })
-- PERFORMANCE: Try to extract name from link first to check for duplicates
local _, _, linkName = string_find(link, "%[(.+)%]")
local existing = linkName and items[linkName] local existing = linkName and items[linkName]
if existing then if existing then
@@ -317,13 +314,11 @@ function CleveRoids.IndexItems()
end end
-- Scan equipped items -- Scan equipped items
for inventoryID = 0, 19 do for inventoryID = 1, 19 do
local link = GetInventoryItemLink("player", inventoryID) local itemID = GetInventoryItemID("player", inventoryID)
if link then if itemID then
local _, _, itemID = string_find(link, "item:(%d+)") -- Decorated name for the duplicate fast-path (no link string built)
local linkName = C_Item.GetItemName({ equipmentSlotIndex = inventoryID })
-- PERFORMANCE: Try to extract name from link first
local _, _, linkName = string_find(link, "%[(.+)%]")
local existing = linkName and items[linkName] local existing = linkName and items[linkName]
if existing then 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 link = GetInventoryItemLink("player", inventoryID) end
if not link then return end if not link then return end
local _, _, itemID = string_find(link, "item:(%d+)") local itemID = GetInventoryItemID("player", inventoryID)
itemID = itemID and tonumber(itemID) or nil local name = C_Item.GetItemName({ equipmentSlotIndex = inventoryID })
local name = itemID and GetItemInfo(itemID) or nil
local texture = GetInventoryItemTexture("player", inventoryID) local texture = GetInventoryItemTexture("player", inventoryID)
local count = GetInventoryItemCount("player", inventoryID) local count = GetInventoryItemCount("player", inventoryID)
@@ -509,14 +502,12 @@ local function makeBagItem(bagID, slot, link, Items)
end end
if not link then return end if not link then return end
local _, _, itemID = string_find(link, "item:(%d+)") local itemID = C_Container.GetContainerItemID(bagID, slot)
itemID = itemID and tonumber(itemID) or nil
local name, _, _, _, _, _, _, _, texture = GetItemInfo(itemID) local name = C_Item.GetItemName({bagID = bagID, slotIndex = slot})
local count = 0 local count = 0
local tex, itemCount = GetContainerItemInfo(bagID, slot) local texture, itemCount = GetContainerItemInfo(bagID, slot)
if itemCount then count = itemCount end if itemCount then count = itemCount end
if not texture then texture = tex end
local it = { local it = {
bagID = bagID, bagID = bagID,
@@ -574,9 +565,7 @@ function CleveRoids.GetItem(text)
for inv = 1, 19 do for inv = 1, 19 do
local link = GetInventoryItemLink("player", inv) local link = GetInventoryItemLink("player", inv)
if link then if link then
local _, _, itemID = string_find(link, "item:(%d+)") local itemID = GetInventoryItemID("player", inv)
itemID = itemID and tonumber(itemID) or nil
if qid and itemID and qid == itemID then if qid and itemID and qid == itemID then
return makeInventoryItem(inv, link, Items) return makeInventoryItem(inv, link, Items)
elseif qname then elseif qname then
@@ -595,9 +584,7 @@ function CleveRoids.GetItem(text)
for slot = 1, slots do for slot = 1, slots do
local link = GetContainerItemLink(bag, slot) local link = GetContainerItemLink(bag, slot)
if link then if link then
local _, _, itemID = string_find(link, "item:(%d+)") local itemID = C_Container.GetContainerItemID(bag, slot)
itemID = itemID and tonumber(itemID) or nil
if qid and itemID and qid == itemID then if qid and itemID and qid == itemID then
return makeBagItem(bag, slot, link, Items) return makeBagItem(bag, slot, link, Items)
elseif qname then elseif qname then
@@ -720,18 +707,16 @@ function CleveRoids.FindItemQuick(text)
if cached then if cached then
-- Validate: check if item is actually at the cached location -- Validate: check if item is actually at the cached location
if cached.inventoryID then if cached.inventoryID then
local link = GetInventoryItemLink("player", cached.inventoryID) if qid then
if link then if GetInventoryItemID("player", cached.inventoryID) == qid then
local nm = GetNameFromLink(link) 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 if nm and qname and string_lower(nm) == qname then
cached._validated = true cached._validated = true
return cached -- Cache is valid 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
end end
-- Cache is stale - item not at cached equipped slot, invalidate -- Cache is stale - item not at cached equipped slot, invalidate
@@ -740,18 +725,16 @@ function CleveRoids.FindItemQuick(text)
Items[string_lower(cached.name)] = nil Items[string_lower(cached.name)] = nil
end end
elseif cached.bagID and cached.slot then elseif cached.bagID and cached.slot then
local link = GetContainerItemLink(cached.bagID, cached.slot) if qid then
if link then if C_Container.GetContainerItemID(cached.bagID, cached.slot) == qid then
local nm = GetNameFromLink(link) 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 if nm and qname and string_lower(nm) == qname then
cached._validated = true cached._validated = true
return cached -- Cache is valid 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
end end
-- Cache is stale - item not at cached bag slot, invalidate -- Cache is stale - item not at cached bag slot, invalidate
@@ -767,20 +750,17 @@ function CleveRoids.FindItemQuick(text)
for inv = 1, 19 do for inv = 1, 19 do
local link = GetInventoryItemLink("player", inv) local link = GetInventoryItemLink("player", inv)
if link then if link then
local _, _, itemID = string_find(link, "item:(%d+)") local itemID = GetInventoryItemID("player", inv)
if itemID then -- ID match: fast path
itemID = tonumber(itemID) if qid and qid == itemID then
-- ID match: fast path return makeInventoryItem(inv, link, Items)
if qid and qid == itemID then 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) return makeInventoryItem(inv, link, Items)
end 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 end
end end
@@ -791,20 +771,17 @@ function CleveRoids.FindItemQuick(text)
for slot = 1, slots do for slot = 1, slots do
local link = GetContainerItemLink(bag, slot) local link = GetContainerItemLink(bag, slot)
if link then if link then
local _, _, itemID = string_find(link, "item:(%d+)") local itemID = C_Container.GetContainerItemID(bag, slot)
if itemID then -- ID match: fast path
itemID = tonumber(itemID) if qid and qid == itemID then
-- ID match: fast path return makeBagItem(bag, slot, link, Items)
if qid and qid == itemID then 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) return makeBagItem(bag, slot, link, Items)
end 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 end
end end
@@ -818,25 +795,19 @@ end
function CleveRoids.IsItemEquipped(text, inventoryId) function CleveRoids.IsItemEquipped(text, inventoryId)
if not text or not inventoryId then return false end if not text or not inventoryId then return false end
local link = GetInventoryItemLink("player", inventoryId) local currentID = GetInventoryItemID("player", inventoryId)
if not link then return false end
local _, _, currentID = string_find(link, "item:(%d+)")
if not currentID then return false end if not currentID then return false end
-- Check by ID (fast path) -- Check by ID (fast path)
local textId = tonumber(text) local textId = tonumber(text)
if textId and textId == tonumber(currentID) then if textId and textId == currentID then
return true return true
end end
-- Check by name - extract from link instead of GetItemInfo for performance -- Check by name (decorated, so suffixed gear still matches)
local currentName = GetNameFromLink(link) local currentName = C_Item.GetItemName({ equipmentSlotIndex = inventoryId })
if currentName then if currentName and string_lower(currentName) == string_lower(text) then
local textLower = string_lower(text) return true
if string_lower(currentName) == textLower then
return true
end
end end
return false return false
+23 -28
View File
@@ -22,7 +22,6 @@ CleveRoids.mouseOverUnit = nil
-- Environment flags -- Environment flags
CleveRoids.hasSuperwow = SetAutoloot and true or false CleveRoids.hasSuperwow = SetAutoloot and true or false
CleveRoids.hasTurtle = (type(_G.TURTLE_WOW_VERSION) ~= "nil") CleveRoids.hasTurtle = (type(_G.TURTLE_WOW_VERSION) ~= "nil")
CleveRoids.hasReliquary = (RQ_GetVersion ~= nil)
CleveRoids.supported = CleveRoids.hasTurtle CleveRoids.supported = CleveRoids.hasTurtle
CleveRoids.ParsedMsg = {} CleveRoids.ParsedMsg = {}
@@ -242,28 +241,32 @@ CleveRoids.auraTextures = {
-- I need to make a 2h modifier -- 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 = { CleveRoids.WeaponTypeNames = {
Daggers = { slot = "MainHandSlot", name = CleveRoids.Localized.Dagger }, Daggers = { slot = "MainHandSlot", class = 2, subClass = { [15] = true } },
Fists = { slot = "MainHandSlot", name = CleveRoids.Localized.FistWeapon }, Fists = { slot = "MainHandSlot", class = 2, subClass = { [13] = true } },
Axes = { slot = "MainHandSlot", name = CleveRoids.Localized.Axe }, Axes = { slot = "MainHandSlot", class = 2, subClass = { [0] = true, [1] = true } },
Swords = { slot = "MainHandSlot", name = CleveRoids.Localized.Sword }, Swords = { slot = "MainHandSlot", class = 2, subClass = { [7] = true, [8] = true } },
Staves = { slot = "MainHandSlot", name = CleveRoids.Localized.Staff }, Staves = { slot = "MainHandSlot", class = 2, subClass = { [10] = true } },
Maces = { slot = "MainHandSlot", name = CleveRoids.Localized.Mace }, Maces = { slot = "MainHandSlot", class = 2, subClass = { [4] = true, [5] = true } },
Polearms = { slot = "MainHandSlot", name = CleveRoids.Localized.Polearm }, Polearms = { slot = "MainHandSlot", class = 2, subClass = { [6] = true } },
-- OH -- OH
Daggers2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Dagger }, Daggers2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [15] = true } },
Fists2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.FistWeapon }, Fists2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [13] = true } },
Axes2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Axe }, Axes2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [0] = true, [1] = true } },
Swords2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Sword }, Swords2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [7] = true, [8] = true } },
Maces2 = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Mace }, Maces2 = { slot = "SecondaryHandSlot", class = 2, subClass = { [4] = true, [5] = true } },
Shields = { slot = "SecondaryHandSlot", name = CleveRoids.Localized.Shield }, Shields = { slot = "SecondaryHandSlot", class = 4, subClass = { [6] = true } },
-- ranged -- ranged
Guns = { slot = "RangedSlot", name = CleveRoids.Localized.Gun }, Guns = { slot = "RangedSlot", class = 2, subClass = { [3] = true } },
Crossbows = { slot = "RangedSlot", name = CleveRoids.Localized.Crossbow }, Crossbows = { slot = "RangedSlot", class = 2, subClass = { [18] = true } },
Bows = { slot = "RangedSlot", name = CleveRoids.Localized.Bow }, Bows = { slot = "RangedSlot", class = 2, subClass = { [2] = true } },
Thrown = { slot = "RangedSlot", name = CleveRoids.Localized.Thrown }, Thrown = { slot = "RangedSlot", class = 2, subClass = { [16] = true } },
Wands = { slot = "RangedSlot", name = CleveRoids.Localized.Wand }, Wands = { slot = "RangedSlot", class = 2, subClass = { [19] = true } },
} }
-- Detect available features -- Detect available features
@@ -287,14 +290,6 @@ local function PrintFeatures()
end end
end end
if CleveRoids.hasUnitXP then table.insert(features, "UnitXP") 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 CleveRoids.hasTurtle then table.insert(features, "Turtle") end
if table.getn(features) > 0 then if table.getn(features) > 0 then
-245
View File
@@ -8,26 +8,9 @@ CleveRoids.Locale = GetLocale()
CleveRoids.Localized = {} CleveRoids.Localized = {}
if CleveRoids.Locale == "enUS" or CleveRoids.Locale == "enGB" then 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.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot" CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot" CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
-- target creature and run: -- target creature and run:
-- /script local ct, uc = UnitCreatureType("target"),UnitClassification("target"); DEFAULT_CHAT_FRAME:AddMessage("\n\nUnitCreatureType: ["..ct.."]\nUnitClassificationType: ["..uc.."]\n\n"); -- /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", ["Stealth"] = "Stealth",
["Prowl"] = "Prowl", ["Prowl"] = "Prowl",
["Shadowmeld"] = "Shadowmeld", ["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 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.Attack = "Angriff"
CleveRoids.Localized.AutoShot = "Automatischer Schuss" CleveRoids.Localized.AutoShot = "Automatischer Schuss"
CleveRoids.Localized.Shoot = "Schießen" CleveRoids.Localized.Shoot = "Schießen"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = { CleveRoids.Localized.CreatureTypes = {
["Beast"] = "Wildtier", ["Beast"] = "Wildtier",
@@ -108,42 +59,11 @@ elseif CleveRoids.Locale == "deDE" then
["Stealth"] = "Verstohlenheit", ["Stealth"] = "Verstohlenheit",
["Prowl"] = "Schleichen", ["Prowl"] = "Schleichen",
["Shadowmeld"] = "Schattenmimik", ["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 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.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot" CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot" CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = { CleveRoids.Localized.CreatureTypes = {
["Beast"] = "Bête", ["Beast"] = "Bête",
@@ -164,41 +84,11 @@ elseif CleveRoids.Locale == "frFR" then
["Stealth"] = "Camouflage", ["Stealth"] = "Camouflage",
["Prowl"] = "Rôder", ["Prowl"] = "Rôder",
["Shadowmeld"] = "Camouflage dans l'ombre", ["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 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.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot" CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot" CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = { CleveRoids.Localized.CreatureTypes = {
["Beast"] = "야수", ["Beast"] = "야수",
@@ -219,41 +109,11 @@ elseif CleveRoids.Locale == "koKR" then
["Stealth"] = "은신", ["Stealth"] = "은신",
["Prowl"] = "숨기", ["Prowl"] = "숨기",
["Shadowmeld"] = "그림자 숨기", ["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 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.Attack = "攻击"
CleveRoids.Localized.AutoShot = "自动射击" CleveRoids.Localized.AutoShot = "自动射击"
CleveRoids.Localized.Shoot = "射击" CleveRoids.Localized.Shoot = "射击"
CleveRoids.Localized.SpellRank = "%(等级 %d+%)"
CleveRoids.Localized.CreatureTypes = { CleveRoids.Localized.CreatureTypes = {
["Beast"] = "野兽", ["Beast"] = "野兽",
@@ -274,41 +134,11 @@ elseif CleveRoids.Locale == "zhCN" then
["Stealth"] = "潜行", ["Stealth"] = "潜行",
["Prowl"] = "潜行", ["Prowl"] = "潜行",
["Shadowmeld"] = "影遁", ["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 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.Attack = "攻擊"
CleveRoids.Localized.AutoShot = "自動射擊" CleveRoids.Localized.AutoShot = "自動射擊"
CleveRoids.Localized.Shoot = "射擊" CleveRoids.Localized.Shoot = "射擊"
CleveRoids.Localized.SpellRank = "%(等級 %d+%)"
CleveRoids.Localized.CreatureTypes = { CleveRoids.Localized.CreatureTypes = {
["Beast"] = "野獸", ["Beast"] = "野獸",
@@ -329,41 +159,11 @@ elseif CleveRoids.Locale == "zhTW" then
["Stealth"] = "隱形", ["Stealth"] = "隱形",
["Prowl"] = "徘徊", ["Prowl"] = "徘徊",
["Shadowmeld"] = "影遁", ["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 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.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot" CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot" CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = { CleveRoids.Localized.CreatureTypes = {
["Beast"] = "Животное", ["Beast"] = "Животное",
@@ -384,41 +184,11 @@ elseif CleveRoids.Locale == "ruRU" then
["Stealth"] = "Незаметность", ["Stealth"] = "Незаметность",
["Prowl"] = "Крадущийся зверь", ["Prowl"] = "Крадущийся зверь",
["Shadowmeld"] = "Слияние с тенью", ["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 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.Attack = "Attack"
CleveRoids.Localized.AutoShot = "Auto Shot" CleveRoids.Localized.AutoShot = "Auto Shot"
CleveRoids.Localized.Shoot = "Shoot" CleveRoids.Localized.Shoot = "Shoot"
CleveRoids.Localized.SpellRank = "%(Rank %d+%)"
CleveRoids.Localized.CreatureTypes = { CleveRoids.Localized.CreatureTypes = {
["Beast"] = "Bestia", ["Beast"] = "Bestia",
@@ -439,21 +209,6 @@ elseif CleveRoids.Locale == "esES" then
["Stealth"] = "Sigilo", ["Stealth"] = "Sigilo",
["Prowl"] = "Acechar", ["Prowl"] = "Acechar",
["Shadowmeld"] = "Fusión con las sombras", ["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 end
+59 -190
View File
@@ -1493,15 +1493,12 @@ function API.GetEquippedItems(unitToken)
local items = {} local items = {}
for slot = 0, 18 do for slot = 0, 18 do
local link = GetInventoryItemLink("player", slot + 1) local itemId = CleveRoids.ClassicAPI.GetInventoryItemID("player", slot + 1)
if link then if itemId then
local _, _, itemId = string.find(link, "item:(%d+)") items[slot] = {
if itemId then itemId = itemId,
items[slot] = { -- Other fields not available without native API
itemId = tonumber(itemId), }
-- Other fields not available without native API
}
end
end end
end end
@@ -1524,14 +1521,11 @@ function API.GetEquippedItem(unitToken, slot)
return nil return nil
end end
local link = GetInventoryItemLink("player", slot + 1) -- 1-indexed local itemId = CleveRoids.ClassicAPI.GetInventoryItemID("player", slot + 1) -- 1-indexed
if link then if itemId then
local _, _, itemId = string.find(link, "item:(%d+)") return {
if itemId then itemId = itemId,
return { }
itemId = tonumber(itemId),
}
end
end end
return nil return nil
@@ -1560,16 +1554,13 @@ function API.GetBagItems(bagIndex)
local bagContents = {} local bagContents = {}
local numSlots = GetContainerNumSlots(bagIndex) or 0 local numSlots = GetContainerNumSlots(bagIndex) or 0
for slot = 1, numSlots do for slot = 1, numSlots do
local link = GetContainerItemLink(bagIndex, slot) local itemId = CleveRoids.ClassicAPI.GetContainerItemID(bagIndex, slot)
if link then if itemId then
local _, _, itemId = string.find(link, "item:(%d+)")
local _, count = GetContainerItemInfo(bagIndex, slot) local _, count = GetContainerItemInfo(bagIndex, slot)
if itemId then bagContents[slot] = {
bagContents[slot] = { itemId = itemId,
itemId = tonumber(itemId), stackCount = count or 1,
stackCount = count or 1, }
}
end
end end
end end
return bagContents return bagContents
@@ -1582,16 +1573,13 @@ function API.GetBagItems(bagIndex)
if numSlots > 0 then if numSlots > 0 then
bags[bag] = {} bags[bag] = {}
for slot = 1, numSlots do for slot = 1, numSlots do
local link = GetContainerItemLink(bag, slot) local itemId = CleveRoids.ClassicAPI.GetContainerItemID(bag, slot)
if link then if itemId then
local _, _, itemId = string.find(link, "item:(%d+)")
local _, count = GetContainerItemInfo(bag, slot) local _, count = GetContainerItemInfo(bag, slot)
if itemId then bags[bag][slot] = {
bags[bag][slot] = { itemId = itemId,
itemId = tonumber(itemId), stackCount = count or 1,
stackCount = count or 1, }
}
end
end end
end end
end end
@@ -1609,16 +1597,13 @@ function API.GetBagItem(bagIndex, slot)
end end
-- Fallback: manual lookup -- Fallback: manual lookup
local link = GetContainerItemLink(bagIndex, slot) local itemId = CleveRoids.ClassicAPI.GetContainerItemID(bagIndex, slot)
if link then if itemId then
local _, _, itemId = string.find(link, "item:(%d+)")
local _, count = GetContainerItemInfo(bagIndex, slot) local _, count = GetContainerItemInfo(bagIndex, slot)
if itemId then return {
return { itemId = itemId,
itemId = tonumber(itemId), stackCount = count or 1,
stackCount = count or 1, }
}
end
end end
return nil return nil
@@ -1779,14 +1764,13 @@ function API.FindBagItem(itemIdOrName)
for bag = 0, 4 do for bag = 0, 4 do
local numSlots = GetContainerNumSlots(bag) or 0 local numSlots = GetContainerNumSlots(bag) or 0
for slot = 1, numSlots do for slot = 1, numSlots do
local link = GetContainerItemLink(bag, slot) if checkId then
if link then if CleveRoids.ClassicAPI.GetContainerItemID(bag, slot) == checkId then
if checkId then return bag, slot
local _, _, currentId = string.find(link, "item:(%d+)") end
if currentId and tonumber(currentId) == checkId then elseif checkName then
return bag, slot local link = GetContainerItemLink(bag, slot)
end if link then
elseif checkName then
local _, _, currentName = string.find(link, "|h%[(.-)%]|h") local _, _, currentName = string.find(link, "|h%[(.-)%]|h")
if currentName and string.lower(currentName) == checkName then if currentName and string.lower(currentName) == checkName then
return bag, slot return bag, slot
@@ -2103,26 +2087,28 @@ function API.GetTrinkets(copy)
for bag = 0, 4 do for bag = 0, 4 do
local numSlots = GetContainerNumSlots(bag) or 0 local numSlots = GetContainerNumSlots(bag) or 0
for slot = 1, numSlots do for slot = 1, numSlots do
local link = GetContainerItemLink(bag, slot) local numItemId = CleveRoids.ClassicAPI.GetContainerItemID(bag, slot)
if link then if numItemId then
local _, _, itemId = string.find(link, "item:(%d+)") local invType = API.GetItemInventoryType(numItemId)
if itemId then if invType == 12 then -- Trinket
local numItemId = tonumber(itemId) -- Only build the link string for actual trinkets, to read the name.
local invType = API.GetItemInventoryType(numItemId) local link = GetContainerItemLink(bag, slot)
if invType == 12 then -- Trinket local name
local _, _, name = string.find(link, "|h%[(.-)%]|h") if link then
local texture = GetContainerItemInfo(bag, slot) local _
local itemLevel = API.GetItemLevel(numItemId) _, _, name = string.find(link, "|h%[(.-)%]|h")
trinkets[index] = {
itemId = numItemId,
trinketName = name or "Unknown",
texture = texture,
itemLevel = itemLevel,
bagIndex = bag,
slotIndex = slot,
}
index = index + 1
end 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 end
end end
@@ -2183,18 +2169,13 @@ function API.GetTrinketCooldown(slot)
end end
-- Get item ID from equipped slot -- Get item ID from equipped slot
local link = GetInventoryItemLink("player", equipSlot) local itemId = CleveRoids.ClassicAPI.GetInventoryItemID("player", equipSlot)
if not link then
return -1
end
local _, _, itemId = string.find(link, "item:(%d+)")
if not itemId then if not itemId then
return -1 return -1
end end
-- Get cooldown info -- Get cooldown info
return API.GetItemCooldownInfo(tonumber(itemId)) return API.GetItemCooldownInfo(itemId)
end end
-- Use an equipped trinket -- Use an equipped trinket
@@ -3550,117 +3531,5 @@ function API.GetUnitMaxPower(unitToken, powerType)
return UnitManaMax(unitToken) return UnitManaMax(unitToken)
end 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 -- Expose API globally for other addons
_G.CleveRoidsNampowerAPI = API _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 to get equipped item ID in a specific slot
function CleveRoids.GetEquippedItemID(slotID) function CleveRoids.GetEquippedItemID(slotID)
local itemLink = GetInventoryItemLink("player", slotID) return CleveRoids.ClassicAPI.GetInventoryItemID("player", slotID)
if not itemLink then return nil end
local _, _, itemID = string.find(itemLink, "item:(%d+)")
return tonumber(itemID)
end end
-- Apply equipment modifiers to a debuff duration -- Apply equipment modifiers to a debuff duration
@@ -6922,12 +6918,7 @@ function CleveRoids.ApplyEquipmentModifier(spellID, baseDuration)
local modifiedDuration = modifier.modifier(baseDuration, itemID) local modifiedDuration = modifier.modifier(baseDuration, itemID)
if modifiedDuration ~= baseDuration and CleveRoids.debug then if modifiedDuration ~= baseDuration and CleveRoids.debug then
local itemName = "Unknown" local itemName = C_Item.GetItemName({ equipmentSlotIndex = modifier.slot }) or "Unknown"
local itemLink = GetInventoryItemLink("player", modifier.slot)
if itemLink then
local _, _, _n = string.find(itemLink, "%[(.-)%]")
itemName = _n or "Unknown"
end
DEFAULT_CHAT_FRAME:AddMessage( DEFAULT_CHAT_FRAME:AddMessage(
string.format("|cffff00ff[Equipment Modifier]|r %s (ID:%d): %ds -> %ds (item: %s [%d])", 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 -- Database of set bonus modifiers for debuff durations
-- Structure: [spellID] = { items = {itemID1, itemID2, ...}, threshold = X, modifier = function(baseDuration) } -- 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 {} 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 = {} 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) local function ResolveSetItems(modifier)
-- If items are already provided (hardcoded), use them directly -- If items are already provided (hardcoded), use them directly
if modifier.items and table.getn(modifier.items) > 0 then if modifier.items and table.getn(modifier.items) > 0 then
return modifier.items return modifier.items
end end
-- Try Reliquary DBC lookup by setId -- DBC lookup by setId via ClassicAPI
if modifier.setId and CleveRoids.NampowerAPI then if modifier.setId then
-- Check cache first -- Check cache first
if setItemCache[modifier.setId] then if setItemCache[modifier.setId] then
return setItemCache[modifier.setId] return setItemCache[modifier.setId]
end end
local items = CleveRoids.NampowerAPI.GetItemSetItems(modifier.setId) local info = CleveRoids.ClassicAPI.GetItemSetInfo(modifier.setId)
if items then local items = info and info.items
if items and table.getn(items) > 0 then
setItemCache[modifier.setId] = items setItemCache[modifier.setId] = items
return items return items
end end
@@ -7073,24 +7066,20 @@ local function ResolveSetItems(modifier)
end end
-- Function to count how many items from a set are currently equipped -- 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) function CleveRoids.CountEquippedSetItems(items)
if not items or type(items) ~= "table" then return 0 end if not items or type(items) ~= "table" then return 0 end
local count = 0 local count = 0
-- Check all equipment slots (1-19) -- Check all equipment slots (1-19)
for slot = 1, 19 do for slot = 1, 19 do
local itemLink = GetInventoryItemLink("player", slot) local itemID = CleveRoids.GetEquippedItemID(slot)
if itemLink then if itemID then
local _, _, itemID = string.find(itemLink, "item:(%d+)") -- Check if this item is in the set
if itemID then for _, setItemID in ipairs(items) do
itemID = tonumber(itemID) if itemID == setItemID then
-- Check if this item is in the set count = count + 1
for _, setItemID in ipairs(items) do break
if itemID == setItemID then
count = count + 1
break
end
end end
end end
end end
@@ -7099,40 +7088,19 @@ function CleveRoids.CountEquippedSetItems(items)
return count return count
end end
-- Count equipped set items by set ID (uses Nampower to check each slot's itemSet field) -- Count equipped set items by set ID, comparing each equipped slot's own set
-- Falls back to CountEquippedSetItems with Reliquary item list if GetItemStatsField unavailable -- membership (ClassicAPI GetItemSetIDByID) against the target set.
function CleveRoids.CountEquippedSetItemsBySetId(setId) function CleveRoids.CountEquippedSetItemsBySetId(setId)
if not setId then return 0 end if not setId then return 0 end
-- Fast path: use Nampower GetItemStatsField to check itemSet directly per slot local count = 0
if CleveRoids.NampowerAPI and CleveRoids.NampowerAPI.GetItemField then for slot = 1, 19 do
local count = 0 local itemID = CleveRoids.GetEquippedItemID(slot)
for slot = 1, 19 do if itemID and CleveRoids.ClassicAPI.GetItemSetIDByID(itemID) == setId then
local itemLink = GetInventoryItemLink("player", slot) count = count + 1
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
end end
return count
end end
return count
-- 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
end end
-- Apply set bonus modifiers to a debuff duration -- Apply set bonus modifiers to a debuff duration
@@ -7183,7 +7151,7 @@ end
-- Helper function to register a set bonus modifier -- Helper function to register a set bonus modifier
-- Usage: CleveRoids.RegisterSetBonusModifier(spellID, itemsTable, threshold, modifierFunction) -- 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) function CleveRoids.RegisterSetBonusModifier(spellID, items, threshold, modifierFunc, setId)
if not spellID or not threshold or not modifierFunc then if not spellID or not threshold or not modifierFunc then
return false return false
@@ -7202,17 +7170,17 @@ function CleveRoids.RegisterSetBonusModifier(spellID, items, threshold, modifier
return true return true
end 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 -- Returns: setName, setId, equippedCount, totalPieces, items or nil
function CleveRoids.GetEquippedItemSetInfo(itemId) 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 if not setId then return nil end
local setData = CleveRoids.NampowerAPI.GetItemSet(setId) local info = CleveRoids.ClassicAPI.GetItemSetInfo(setId)
local setName = setData and setData.name_enUS or nil local setName = info and info.name or nil
local items = CleveRoids.NampowerAPI.GetItemSetItems(setId) local items = info and info.items or nil
local totalPieces = items and table.getn(items) or 0 local totalPieces = items and table.getn(items) or 0
local equippedCount = CleveRoids.CountEquippedSetItemsBySetId(setId) local equippedCount = CleveRoids.CountEquippedSetItemsBySetId(setId)
@@ -7222,7 +7190,7 @@ end
-- Count equipped pieces of a named or ID-referenced item set -- Count equipped pieces of a named or ID-referenced item set
-- nameOrId: set name (string, e.g. "Judgement Battlegear") or set ID (number) -- nameOrId: set name (string, e.g. "Judgement Battlegear") or set ID (number)
-- Returns: equipped count (number), setId (number or nil) -- 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) function CleveRoids.GetEquippedSetPieceCount(nameOrId)
if not nameOrId then return 0, nil end if not nameOrId then return 0, nil end
@@ -7232,28 +7200,17 @@ function CleveRoids.GetEquippedSetPieceCount(nameOrId)
return CleveRoids.CountEquippedSetItemsBySetId(numericId), numericId return CleveRoids.CountEquippedSetItemsBySetId(numericId), numericId
end end
-- String: scan equipped items and match by set name from DBC -- String: scan equipped items and match by set name from ItemSet.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
local lowerName = string.lower(nameOrId) local lowerName = string.lower(nameOrId)
for slot = 1, 19 do for slot = 1, 19 do
local itemLink = GetInventoryItemLink("player", slot) local itemID = CleveRoids.GetEquippedItemID(slot)
if itemLink then if itemID then
local _, _, itemID = string.find(itemLink, "item:(%d+)") local setId = CleveRoids.ClassicAPI.GetItemSetIDByID(itemID)
if itemID then if setId then
local setId = CleveRoids.NampowerAPI.GetItemSetId(tonumber(itemID)) local info = CleveRoids.ClassicAPI.GetItemSetInfo(setId)
if setId then if info and info.name and string.lower(info.name) == lowerName then
local setData = CleveRoids.NampowerAPI.GetItemSet(setId) return CleveRoids.CountEquippedSetItemsBySetId(setId), setId
if setData then
local dbcName = setData.name_enUS
if dbcName and string.lower(dbcName) == lowerName then
return CleveRoids.CountEquippedSetItemsBySetId(setId), setId
end
end
end end
end end
end end
@@ -7262,18 +7219,9 @@ function CleveRoids.GetEquippedSetPieceCount(nameOrId)
return 0, nil return 0, nil
end 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 -- DRUID set bonus modifiers
-- Dreamwalker Regalia (4/9): Increases Moonfire duration by 3 seconds and Insect Swarm by 2 seconds -- 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 DREAMWALKER_SET_ID = 536
local dreamwalkerItems = { 47372, 47373, 47374, 47375, 47376, 47377, 47378, 47379, 47380 } local dreamwalkerItems = { 47372, 47373, 47374, 47375, 47376, 47377, 47378, 47379, 47380 }
local dreamwalkerMoonfireModifier = function(base) return base + 3 end 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 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 -- 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 HARUSPEX_SET_ID = 474
local haruspexItems = { 19613, 19955, 19840, 19839, 19838 } local haruspexItems = { 19613, 19955, 19840, 19839, 19838 }
local haruspexFaerieFireModifier = function(base) return base + 5 end local haruspexFaerieFireModifier = function(base) return base + 5 end
@@ -7810,7 +7758,7 @@ end
-- CC IMMUNITY TRACKING -- 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 -- Returns: CC type name (e.g., "stun", "fear") or nil if not a CC spell
-- EffectApplyAuraName → CC type mapping (fallback when mechanics are unset) -- EffectApplyAuraName → CC type mapping (fallback when mechanics are unset)
-- Uses vanilla 1.12.1 aura type enum values -- Uses vanilla 1.12.1 aura type enum values
@@ -7864,9 +7812,11 @@ local function GetSpellCCType(spellID)
end end
end end
-- Priority 2: Hardcoded table fallback (CCSpellMechanics in Conditionals.lua) -- Priority 2: ClassicAPI Spell.dbc reader (always present; covers every spell).
local mechanic = CleveRoids.CCSpellMechanics and CleveRoids.CCSpellMechanics[spellID] -- A subset of Priority 1's per-effect/aura checks, used when nampower's
if mechanic and MECHANIC_TO_CC_TYPE[mechanic] then -- 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] return MECHANIC_TO_CC_TYPE[mechanic]
end end