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