From 4c9c6fff603d9beac20448bb4f3db6d237b99a35 Mon Sep 17 00:00:00 2001 From: Jrc13245 Date: Wed, 8 Oct 2025 20:46:03 -0400 Subject: [PATCH] new pet conditional --- Conditionals.lua | 28 ++++++++++++ Console.lua | 6 +++ Core.lua | 81 +++++++++++++++++++++++++++++++--- Extensions/Tooltip/Generic.lua | 36 +++++++++++++++ Init.lua | 2 + README.md | 53 +++++++++++----------- 6 files changed, 173 insertions(+), 33 deletions(-) diff --git a/Conditionals.lua b/Conditionals.lua index 8d05921..27873d6 100644 --- a/Conditionals.lua +++ b/Conditionals.lua @@ -1542,5 +1542,33 @@ CleveRoids.Keywords = { return And(conditionals.noclass, function(forbiddenClass) return string.lower(forbiddenClass) ~= string.lower(localizedClass) and string.lower(forbiddenClass) ~= string.lower(englishClass) end) + end, + + pet = function(conditionals) + if not UnitExists("pet") then + return false + end + + return Or(conditionals.pet, function(petType) + local currentPet = UnitCreatureFamily("pet") + if not currentPet then + return false + end + return string.lower(currentPet) == string.lower(petType) + end) + end, + + nopet = function(conditionals) + if not UnitExists("pet") then + return true + end + + return And(conditionals.nopet, function(petType) + local currentPet = UnitCreatureFamily("pet") + if not currentPet then + return true + end + return string.lower(currentPet) ~= string.lower(petType) + end) end } diff --git a/Console.lua b/Console.lua index 17ac7fc..3e8cdcb 100644 --- a/Console.lua +++ b/Console.lua @@ -63,6 +63,12 @@ SLASH_CANCELAURA2 = "/unbuff" SlashCmdList.CANCELAURA = CleveRoids.DoConditionalCancelAura +SLASH_CASTPET1 = "/castpet" + +SlashCmdList.CASTPET = function(msg) + CleveRoids.DoCastPet(msg) +end + -- Define original implementations before hooking them. -- This ensures we have a fallback for non-conditional use. local StartAttack = function(msg) diff --git a/Core.lua b/Core.lua index b9654cc..aa5faf5 100644 --- a/Core.lua +++ b/Core.lua @@ -614,29 +614,28 @@ end function CleveRoids.CreateActionInfo(action, conditionals) local _, _, text = string.find(action, "!?%??~?(.*)") local spell = CleveRoids.GetSpell(text) + local petSpell -- Add this line local item, macroName, macro, macroTooltip, actionType, texture -- NEW: Check if the action is a slot number local slotId = tonumber(text) if slotId and slotId >= 1 and slotId <= 19 then actionType = "item" - -- Use the most reliable method first to get the texture for an equipped item. local itemTexture = GetInventoryItemTexture("player", slotId) - - -- Check if the texture was successfully found. if itemTexture then texture = itemTexture else - -- If the primary method fails, fall back to the unknown texture. - -- This prevents errors if the slot is empty or the item data is unusual. texture = CleveRoids.unknownTexture end else -- Original logic for named items and spells if not spell then + petSpell = CleveRoids.GetPetSpell(text) -- Add this line + end + if not spell and not petSpell then -- Modify this line item = CleveRoids.GetItem(text) end - if not item then + if not item and not petSpell then -- Modify this line macroName = CleveRoids.GetMacroNameFromAction(text) macro = CleveRoids.GetMacro(macroName) macroTooltip = (macro and macro.actions) and macro.actions.tooltip @@ -645,6 +644,9 @@ function CleveRoids.CreateActionInfo(action, conditionals) if spell then actionType = "spell" texture = spell.texture or CleveRoids.unknownTexture + elseif petSpell then -- Add this block + actionType = "petspell" + texture = petSpell.texture or CleveRoids.unknownTexture elseif item then actionType = "item" texture = (item and item.texture) or CleveRoids.unknownTexture @@ -660,6 +662,7 @@ function CleveRoids.CreateActionInfo(action, conditionals) action = text, item = item, spell = spell, + petSpell = petSpell, -- Add this line macro = macroTooltip, type = actionType, texture = texture, @@ -1226,14 +1229,66 @@ function CleveRoids.DoCast(msg) local handled = false for k, v in pairs(CleveRoids.splitStringIgnoringQuotes(msg)) do + -- Define a custom action that handles both regular and pet spells + local castAction = function(spellName) + -- First try regular spell + local spell = CleveRoids.GetSpell(spellName) + if spell then + if CleveRoids.hasSuperwow then + local castMsg = spellName + if not string.find(spellName, "%(.*%)") then + local rank = spell.rank or (spell.highest and spell.highest.rank) + if rank and rank ~= "" then + castMsg = spellName .. "(" .. rank .. ")" + end + end + CastSpellByName(castMsg) + else + CastSpellByName(spellName) + end + return true + end + + -- If not a regular spell, try pet spell + local petSpell = CleveRoids.GetPetSpell(spellName) + if petSpell and petSpell.slot then + CastPetAction(petSpell.slot) + return true + end + + return false + end + if CleveRoids.DoWithConditionals(v, CleveRoids.Hooks.CAST_SlashCmd, CleveRoids.FixEmptyTarget, not CleveRoids.hasSuperwow, CastSpellByName) then - -- If a spell is successfully attempted, immediately exit to prevent casting multiple spells. return true end end return false end +-- Casts a pet spell by name +function CleveRoids.DoCastPet(msg) + local handled = false + + local action = function(spellName) + local petSpell = CleveRoids.GetPetSpell(spellName) + if petSpell and petSpell.slot then + CastPetAction(petSpell.slot) + return true + end + return false + end + + for k, v in pairs(CleveRoids.splitStringIgnoringQuotes(msg)) do + if CleveRoids.DoWithConditionals(v, action, CleveRoids.FixEmptyTarget, false, action) then + handled = true + break + end + end + + return handled +end + -- Target using GUIDs (actually unit tokens) and correct targeting. function CleveRoids.DoTarget(msg) local action, conditionals = CleveRoids.GetParsedMsg(msg) @@ -2057,6 +2112,7 @@ CleveRoids.Frame:RegisterEvent("SPELLS_CHANGED") CleveRoids.Frame:RegisterEvent("ACTIONBAR_SLOT_CHANGED") CleveRoids.Frame:RegisterEvent("BAG_UPDATE") CleveRoids.Frame:RegisterEvent("UNIT_INVENTORY_CHANGED") +CleveRoids.Frame:RegisterEvent("UNIT_PET") -- == STATE CHANGE EVENT REGISTRATION (for performance) == CleveRoids.Frame:RegisterEvent("PLAYER_TARGET_CHANGED") @@ -2132,10 +2188,20 @@ local function CRM_SM_InstallHook() CleveRoids.SM_RunLineHooked = true end +function CleveRoids.Frame:UNIT_PET() + if arg1 == "player" then + CleveRoids.IndexPetSpells() + if CleveRoidMacros.realtime == 0 then + CleveRoids.QueueActionUpdate() + end + end +end + function CleveRoids.Frame:PLAYER_LOGIN() _, CleveRoids.playerClass = UnitClass("player") _, CleveRoids.playerGuid = UnitExists("player") CleveRoids.IndexSpells() + CleveRoids.IndexPetSpells() CleveRoids.initializationTimer = GetTime() + 1.5 CRM_SM_InstallHook() if not CleveRoids.hasSuperwow or not IsSpellInRange then @@ -2282,6 +2348,7 @@ function CleveRoids.Frame:UPDATE_MACROS() CleveRoids.IndexSpells() CleveRoids.IndexTalents() + CleveRoids.IndexPetSpells() CleveRoids.IndexActionBars() if CleveRoidMacros.realtime == 0 then CleveRoids.QueueActionUpdate() diff --git a/Extensions/Tooltip/Generic.lua b/Extensions/Tooltip/Generic.lua index 68c3efc..0abdb1c 100644 --- a/Extensions/Tooltip/Generic.lua +++ b/Extensions/Tooltip/Generic.lua @@ -63,6 +63,42 @@ function CleveRoids.IndexSpells() CleveRoids.Spells = spells end +-- Indexes all pet spells and their action bar slots +function CleveRoids.IndexPetSpells() + local petSpells = {} + + if not UnitExists("pet") then + CleveRoids.PetSpells = petSpells + return + end + + for i = 1, NUM_PET_ACTION_SLOTS do + local name, subtext, texture, isToken = GetPetActionInfo(i) + + if name and not isToken then + -- Store the spell name and its slot + petSpells[name] = { + slot = i, + name = name, + subtext = subtext, + texture = texture + } + end + end + + CleveRoids.PetSpells = petSpells +end + +-- Gets a pet spell by name +function CleveRoids.GetPetSpell(spellName) + if not spellName or not CleveRoids.PetSpells then + return nil + end + + spellName = CleveRoids.Trim(spellName) + return CleveRoids.PetSpells[spellName] +end + function CleveRoids.IndexTalents() local talents = {[1] = true} for tab = 1, GetNumTalentTabs() do diff --git a/Init.lua b/Init.lua index 6c4312e..8d318b6 100644 --- a/Init.lua +++ b/Init.lua @@ -22,6 +22,7 @@ CleveRoids.supported = (CleveRoids.hasSuperwow or CleveRoids.hasTurtle) CleveRoids.ParsedMsg = {} CleveRoids.Items = {} CleveRoids.Spells = {} +CleveRoids.PetSpells = {} CleveRoids.Talents = {} CleveRoids.Cooldowns = {} CleveRoids.Macros = {} @@ -53,6 +54,7 @@ CleveRoids.CurrentSpell = { CleveRoids.dynamicCmds = { ["/cast"] = true, + ["/castpet"] = true, ["/castsequence"] = true, ["/use"] = true, ["/equip"] = true, diff --git a/README.md b/README.md index 21f0e2d..014487b 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ Check slash command and all conditional lists for new usages! | Command | Conditionals Supported | Purpose | |-----------------------| :-: |---------| | /cleveroid | | show update settings. /cleveroid realtime 0/1 : /cleveroid refresh 1-10 | -| /target | | takes limited conditionals. will target by name first and then if conditionals are not valid will target your last target or clear target. help/harm check in a 40 yd cone in front of you. this is due to client limitations. available conditionals: (help,harm,alive,dead,exists,isplayer,isnpc,type,(no)inrange,(no(de))buff,(raw)hp,(raw)power,(no)casting) | +| /target | * | takes limited conditionals. will target by name first and then if conditionals are not valid will target your last target or clear target. help/harm check in a 40 yd cone in front of you. this is due to client limitations. available conditionals: (help,harm,alive,dead,exists,isplayer,isnpc,type,(no)inrange,(no(de))buff,(raw)hp,(raw)power,(no)casting) | | /retarget | | Clears your target if it doesn't exist, has 0 hp or if you can't attack it and then targets the nearest enemy. | | /startattack | * | Starts auto-attacking. | | /stopattack | * | Stops auto-attacking. | @@ -278,29 +278,30 @@ Check slash command and all conditional lists for new usages! | Conditional | Syntax Examples | Multi | Noable | Tests For | |----------------|---------------| :-: | :-: |-----------| | cdgcd | [cdgcd]
[cdgcd:"Name"]
[cdgcd:"Name">X] | * | * | If the Spell or Item is on cooldown and optionally if the amount of time left is >= or <= than X seconds. **GCD NOT IGNORED** | -| channeled | [channeled] | | | If the player is currently channeling a spell. | -| combo | [combo:>#3]
[combo:#2]
[combo:<#5] | | * | If the player has the specified number of combo points. | +| channeled | [channeled] | | * | If the player is currently channeling a spell. | +| combo | [combo:>#3]
[combo:#2]
[combo:<#5] | * | * | If the player has the specified number of combo points. | | cooldown | [cooldown]
[cooldown:"Name"]
[cooldown:"Name"= or <= than X seconds. **GCD (if exatly 1.5 sec) IGNORED** | | equipped | [equipped:"Name"]
[equipped:Shields]
[equipped:Daggers2] | * | * | If the player has an item name/id or item type equipped. See [below](#weapon-types) for a list of valid Weapon Types. | -| form | [form:0/1/2/3/4/5] | * | | Alias of `stance` | +| form | [form:0/1/2/3/4/5] | * | * | Alias of `stance` | | group | [group]
[group:party/raid] | * | * | If the player is in any group or specific group type. | | known | [known]
[known:"Name"]
[known:"Name">#2] | * | * | If the player knows a spell or talent. Can optionally check the rank. | -| mybuff | [mybuff]
[mybuff:"Name"]
[mybuff:"Name">#X]
[mybuff:Optionally compared to X number of stacks.
Optionally compared to X time remaining. | -| mydebuff | [mydebuff]
[mydebuff:"Name"]
[mydebuff:"Name">#X]
[mydebuff:Optionally compared to X number of stacks.
Optionally compared to X time remaining. | -| myhp | [myhp:<=X]
[myhp:>=X/<=Y] | * | | The player's health **PERCENT** compared to X. | +| mybuff | [mybuff]
[mybuff:"Name"]
[mybuff:"Name">#X]
[mybuff:Optionally compared to X number of stacks.
Optionally compared to X time remaining. | +| mydebuff | [mydebuff]
[mydebuff:"Name"]
[mydebuff:"Name">#X]
[mydebuff:Optionally compared to X number of stacks.
Optionally compared to X time remaining. | +| myhp | [myhp:<=X]
[myhp:>=X/<=Y] | * | * | The player's health **PERCENT** compared to X. | | myhplost | [myhplost:>=X]
[myhplost:>=X/<=Y] | * | | The player's lost health compared to X. | -| mypower | [mypower:>=X]
[mypower:>=X/<=Y] | * | | The player's power (mana/rage/energy) **PERCENT** compared to X. | +| mypower | [mypower:>=X]
[mypower:>=X/<=Y] | * | * | The player's power (mana/rage/energy) **PERCENT** compared to X. | | mypowerlost | [mypowerlost:>=X]
[mypowerlost:>=X/<=Y] | * | | The player's lost power (mana/rage/energy) compared to X. | -| myrawhp | [myrawhp:>=X]
[myrawhp:>=X/<=Y] | * | | The player's health compared to X. | -| myrawpower | [myrawpower:>=X]
[myrawpower:>=X/<=Y] | * | | The player's power (mana/rage/energy) compared to X. | +| myrawhp | [myrawhp:>=X]
[myrawhp:>=X/<=Y] | * | * | The player's health compared to X. | +| myrawpower | [myrawpower:>=X]
[myrawpower:>=X/<=Y] | * | * | The player's power (mana/rage/energy) compared to X. | | druidmana | [druidmana:>=X]
[druidmana:>=X/<=Y] | * | | The druid's mana compared to X. **ONLY FOR DRUIDS** **Works in Cat or Bear form.** | -| reactive | [reactive]
[reactive:Overpower] | * | | If the player has the reactive ability (Revenge, Overpower, Riposte, etc.) available to use.

**NOTE: Currently requires the reactive ability to be somewhere on your actionbars in addition to any macros you're using it in. A planned future update will remove this requirement if using [Nampower](https://github.com/pepopo978/nampower).** | +| reactive | [reactive]
[reactive:Overpower] | * | * | If the player has the reactive ability (Revenge, Overpower, Riposte, etc.) available to use.

**NOTE: Currently requires the reactive ability to be somewhere on your actionbars in addition to any macros you're using it in. A planned future update will remove this requirement if using [Nampower](https://github.com/pepopo978/nampower).** | | resting | [resting] | | * | If the player is resting (in an inn/capital city/etc.) | -| stance | [stance:0/1/2/3/4/5] | * | | If the player is in stance #.
Supports Shadowform and Stealth as stance 1.| +| stance | [stance:0/1/2/3/4/5] | * | * | If the player is in stance #.
Supports Shadowform and Stealth as stance 1.| | stealth | [stealth] | | * | If the player is in Stealth or Prowl. | | zone | [zone:"Zone"]
[zone:"Zone"/"Another Zone"] | * | * | If the player is in one or more zones of the given name. | | checkchanneled | [checkchanneled] | * | | Prevents a spell from being cast if you are already channeling it. | | stat | [stat:stat>=x] | | | Check if one of the players statistics is greater or less than a specific number. Available Stats: str/strength, agi/agility, stam/stamina, int/intellect, spi/spirit, ap/attackpower, rap/rangedattackpower, healing/healingpower, arcane_power, fire_power, frost_power, nature_power, shadow_power, armor, defense, arcane_res, fire_res, frost_res, nature_res, shadow_res. | +| pet | [pet]
[pet:Voidwalker]
[pet:Imp/Felhunter] | * | * | If the player has a pet summoned and optionally if it matches the specified pet type(s). Works for Warlock demons and Hunter pets. | ### Unit Based ### The default @unitid is usually @target if you don't specify one @@ -308,25 +309,25 @@ Check slash command and all conditional lists for new usages! | Conditional | Syntax | Multi | Noable | Tests For | |----------------|---------------| :-: | :-: |-----------| | alive | [alive] | | * | If the @unitid is NOT dead or a ghost. | -| buff | [buff]
[buff:"Name"]
[buff:"Name">#X]
[buff:"Name"= or <= than X number of stacks. | +| buff | [buff]
[buff:"Name"]
[buff:"Name">#X]
[buff:"Name"= or <= than X number of stacks. | | casting | [casting]
[casting:"Spell Name"] | * | * | If the @unitid is casting any or one or more specific spells. | -| combat | [combat]
[combat:target] | | * | If the unitid (default is player) is in combat. | +| combat | [combat]
[combat:target] | * | * | If the unitid (default is player) is in combat. | | dead | [dead] | | * | If the @unitid is dead or a ghost. | -| debuff | [debuff]
[debuff:"Name"]
[debuff:"Name">#X]
[debuff:= or <= than X number of stacks. | -| harm | [harm] | | | If the @unitid is an enemy. | -| help | [help] | | | If the @unitid is friendly. | -| hp | [hp:>=X]
[hp:>=X/<=Y] | | | The @unitid health **PERCENT** compared to X. | -| hplost | [hplost:>=X]
[hplost:>=X/<=Y] | | | The @unitid health lost compared to X. | +| debuff | [debuff]
[debuff:"Name"]
[debuff:"Name">#X]
[debuff:= or <= than X number of stacks. | +| harm | [harm] | | * | If the @unitid is an enemy. | +| help | [help] | | * | If the @unitid is friendly. | +| hp | [hp:>=X]
[hp:>=X/<=Y] | * | | The @unitid health **PERCENT** compared to X. | +| hplost | [hplost:>=X]
[hplost:>=X/<=Y] | * | | The @unitid health lost compared to X. | | inrange | [inrange]
[inrange:"Name"] | * | * | If the specified @unitid is in range of the spell. | -| isnpc | [isnpc] | * | | If the @unitid is an npc.
See this [article](https://wowpedia.fandom.com/wiki/UnitId) for a list of unitids.
Not all units are valid in vanilla. | -| isplayer | [isplayer] | * | | If the @unitid is a player.
See this [article](https://wowpedia.fandom.com/wiki/UnitId) for a list of unitids.
Not all units are valid in vanilla. | -| member | [member] | | * | If the @unitid is in your party OR raid. | +| isnpc | [isnpc] | | | If the @unitid is an npc.
See this [article](https://wowpedia.fandom.com/wiki/UnitId) for a list of unitids.
Not all units are valid in vanilla. | +| isplayer | [isplayer] | | | If the @unitid is a player.
See this [article](https://wowpedia.fandom.com/wiki/UnitId) for a list of unitids.
Not all units are valid in vanilla. | +| member | [member] | * | | If the @unitid is in your party OR raid. | | party | [party] | | * | If the @unitid is in your party. | -| power | [power:>=X]
[power:>=X/<=Y] | | | The @unitid power (mana/rage/energy) **PERCENT** compared to X. | -| powerlost | [powerlost:>=X]
[powerlost:>=X/<=Y] | | | The @unitid power (mana/rage/energy) lost compared to X. | +| power | [power:>=X]
[power:>=X/<=Y] | * | | The @unitid power (mana/rage/energy) **PERCENT** compared to X. | +| powerlost | [powerlost:>=X]
[powerlost:>=X/<=Y] | * | | The @unitid power (mana/rage/energy) lost compared to X. | | raid | [raid] | | * | If the @unitid is in your raid. | -| rawphp | [rawhp:>=X]
[rawhp:>=X/<=Y] | | | The @unitid health compared to X. | -| rawpower | [rawpower:>=X]
[rawpower:>=X/<=Y] | | | The @unitid power (mana/rage/energy) compared to X. | +| rawphp | [rawhp:>=X]
[rawhp:>=X/<=Y] | * | | The @unitid health compared to X. | +| rawpower | [rawpower:>=X]
[rawpower:>=X/<=Y] | * | | The @unitid power (mana/rage/energy) compared to X. | | type | [type:"Creature Type"] | * | * | If the @unitid is the specified creature type. See [below](#creature-types) for a list of valid Creature Types. | | targeting | [targeting:unitid] | * | * | If the @unitid is targeting the specified unitid.
See this [article](https://wowpedia.fandom.com/wiki/UnitId) for a list of unitids.
Not all units are valid in vanilla. | | exists | [exists] | | * | If the @unitid exists. |