Add [mhenchant]/[ohenchant] weapon temp-enchant conditionals

Uses ClassicAPI's modern C_Item.GetWeaponEnchantInfo (12-tuple with
enchant IDs) plus C_Item.GetEnchantInfo (ID -> localized name) to match
WHICH temporary weapon enchant is applied -- by SpellItemEnchantment ID or
name -- not just that one exists. Locale-proof and exact, unlike
[mhimbue:Name]'s green-text tooltip scan.

ClassicAPI.lua gains GetWeaponEnchant(slot) (centralizes the tuple
indexing, vanilla-global fallback) and GetEnchantName(id). ValidateWeaponImbue
now reads through GetWeaponEnchant. New keywords mhenchant/nomhenchant/
ohenchant/noohenchant support bare (any enchant), single ID/name, and
OR-lists ([mhenchant:2823/Deadly_Poison]); registered in BOOLEAN_CONDITIONALS
for the bare form and auto-added to VALID_CONDITIONALS via Keywords.
This commit is contained in:
Brues
2026-07-27 22:42:09 -05:00
parent 0e07eafbf9
commit fd8050aee1
3 changed files with 101 additions and 13 deletions
+34
View File
@@ -174,6 +174,40 @@ function API.IsEquipmentSetEquipped(name)
return isEquipped and true or false
end
--------------------------------------------------------------------------------
-- Weapon Enchant
--------------------------------------------------------------------------------
-- Temporary weapon-enchant state for a slot: "mh" (main), "oh" (off), or
-- "ranged". Returns hasEnchant, expirationMs, charges, enchantID. The enchantID
-- comes from ClassicAPI's modern C_Item.GetWeaponEnchantInfo 12-tuple (the
-- vanilla global omits it), so [mhenchant] can tell WHICH imbue is applied, not
-- just that one exists. Falls back to the vanilla 6-tuple global (enchantID nil,
-- no ranged slot) when the C_Item version is unavailable.
function API.GetWeaponEnchant(slot)
if type(C_Item) == "table" and type(C_Item.GetWeaponEnchantInfo) == "function" then
local hasM, mExp, mChg, mID, hasO, oExp, oChg, oID, hasR, rExp, rChg, rID =
C_Item.GetWeaponEnchantInfo()
if slot == "oh" then return hasO, oExp, oChg, oID
elseif slot == "ranged" then return hasR, rExp, rChg, rID
else return hasM, mExp, mChg, mID end
end
local hasM, mExp, mChg, hasO, oExp, oChg = GetWeaponEnchantInfo()
if slot == "oh" then return hasO, oExp, oChg, nil end
return hasM, mExp, mChg, nil
end
-- Localized name of an item-enchant ID (poison/oil/sharpening stone/permanent),
-- read straight from SpellItemEnchantment.dbc via ClassicAPI -- or nil for an
-- unknown id / a client without C_Item.GetEnchantInfo. Lets [mhenchant:Name]
-- resolve the applied enchant's name without scraping the weapon tooltip.
function API.GetEnchantName(enchantID)
if not enchantID or enchantID == 0 then return nil end
if type(C_Item) ~= "table" or type(C_Item.GetEnchantInfo) ~= "function" then return nil end
local info = C_Item.GetEnchantInfo(enchantID)
return info and info.name or nil
end
--------------------------------------------------------------------------------
-- Spell
--------------------------------------------------------------------------------
+63 -13
View File
@@ -4635,19 +4635,9 @@ function CleveRoids.ValidatePlayerDebuff(args)
end
function CleveRoids.ValidateWeaponImbue(slot, args)
-- Check if weapon has enchant via API
local hasMainEnchant, mainExpiration, mainCharges, hasOffEnchant, offExpiration, offCharges = GetWeaponEnchantInfo()
local hasEnchant, expiration, charges
if slot == "mh" then
hasEnchant = hasMainEnchant
expiration = mainExpiration
charges = mainCharges
else
hasEnchant = hasOffEnchant
expiration = offExpiration
charges = offCharges
end
-- Temp-enchant state for this slot, read via ClassicAPI (centralizes the
-- 12-tuple indexing; enchantID unused here but powers [mhenchant]).
local hasEnchant, expiration, charges = CleveRoids.ClassicAPI.GetWeaponEnchant(slot)
-- Only consider temporary enchants (with time or charges)
-- This filters out permanent enchants like Crusader, Lifestealing, etc.
@@ -4802,6 +4792,48 @@ function CleveRoids.CheckWeaponImbueByName(slot, imbueName)
return false
end
-- Does a single [mhenchant]/[ohenchant] value match the applied enchant?
-- value is a numeric enchant ID (exact) or a name (resolved from the applied
-- enchantID via ClassicAPI's SpellItemEnchantment lookup -- no tooltip scan).
-- Name match is case-insensitive, exact-or-substring (so "Deadly" matches
-- "Deadly Poison"). A parsed-arg table (from an operator form) uses its .name.
local function EnchantValueMatches(value, enchantID)
if type(value) == "table" then value = value.name end
if not value or value == "" then return false end
local wantId = tonumber(value)
if wantId then
return enchantID == wantId
end
local name = CleveRoids.ClassicAPI.GetEnchantName(enchantID)
if not name then return false end
local nlower = GetLowerNormalizedName(name)
local want = GetLowerNormalizedName(value)
return nlower == want or string.find(nlower, want, 1, true) ~= nil
end
-- Matches the temporary weapon enchant on `slot` ("mh"/"oh") by enchant ID or
-- localized name, both resolved via ClassicAPI (C_Item.GetWeaponEnchantInfo +
-- GetEnchantInfo) -- locale-proof and exact, unlike the tooltip-scanned
-- [mhimbue:Name]. value may be true/nil (any temp enchant), a single ID/name,
-- or an OR-list array; returns true if the applied enchant matches any entry.
function CleveRoids.ValidateWeaponEnchant(slot, value)
local hasEnchant, expiration, charges, enchantID = CleveRoids.ClassicAPI.GetWeaponEnchant(slot)
local hasTemp = hasEnchant and ((expiration and expiration > 0) or (charges and charges > 0))
if not hasTemp then return false end
-- Bare [mhenchant]: any temporary enchant present.
if value == nil or value == true then return true end
-- OR-list (e.g. [mhenchant:2823/Deadly_Poison]) is an array of strings.
if type(value) == "table" and not value.name and table.getn(value) > 0 then
for i = 1, table.getn(value) do
if EnchantValueMatches(value[i], enchantID) then return true end
end
return false
end
return EnchantValueMatches(value, enchantID)
end
-- TODO: Look into https://github.com/Stanzilla/WoWUIBugs/issues/47 if needed
-- PERFORMANCE: Uncached version - called by GetCachedCooldown
function CleveRoids._GetCooldownUncached(name, ignoreGCD)
@@ -7669,6 +7701,24 @@ CleveRoids.Keywords = {
return not CleveRoids.ValidateWeaponImbue("oh", args)
end,
-- [mhenchant:ID] / [mhenchant:Name] - main hand has that SPECIFIC temporary
-- weapon enchant, matched by SpellItemEnchantment ID or localized name via
-- ClassicAPI (locale-proof, unlike [mhimbue:Name]'s tooltip scan). Bare
-- [mhenchant] = any temp enchant; [mhenchant:A/B] = either; [nomhenchant:X]
-- = not that enchant. Names use _ for spaces, e.g. [mhenchant:Deadly_Poison].
mhenchant = function(conditionals)
return CleveRoids.ValidateWeaponEnchant("mh", conditionals.mhenchant)
end,
nomhenchant = function(conditionals)
return not CleveRoids.ValidateWeaponEnchant("mh", conditionals.nomhenchant)
end,
ohenchant = function(conditionals)
return CleveRoids.ValidateWeaponEnchant("oh", conditionals.ohenchant)
end,
noohenchant = function(conditionals)
return not CleveRoids.ValidateWeaponEnchant("oh", conditionals.noohenchant)
end,
immune = function(conditionals)
-- Check if target is immune to the spell being cast or damage school
-- Usage: [immune] SpellName OR [immune:SpellName] OR [immune:fire]
+4
View File
@@ -147,6 +147,10 @@ local BOOLEAN_CONDITIONALS = {
nomhimbue = true,
ohimbue = true,
noohimbue = true,
mhenchant = true,
nomhenchant = true,
ohenchant = true,
noohenchant = true,
group = true,
nogroup = true,
moving = true,