diff --git a/Conditionals.lua b/Conditionals.lua index 036ade7..1dc488a 100644 --- a/Conditionals.lua +++ b/Conditionals.lua @@ -5149,6 +5149,66 @@ CleveRoids.Keywords = { return NegatedMulti(conditionals.noresisted, function(resistType) return not CleveRoids.CheckResistState(resistType) end, conditionals, "noresisted") + end, + + -- ======================================================================== + -- EXACT NAME MATCHING CONDITIONALS + -- ======================================================================== + + -- [name:UnitName] - Check if target's name EXACTLY matches (case-insensitive) + -- Unlike /target which fuzzy-matches, this requires an exact match + -- Supports underscores for spaces: [name:Onyxia] or [name:Kor_kron_Elite] + -- Multi-value OR: [name:Onyxia/Nefarian] = Onyxia OR Nefarian + -- Examples: [name:Onyxia] [@focus,name:Ragnaros] [name:"Kor'kron Elite"] + name = function(conditionals) + local target = conditionals.target or "target" + + -- Unit must exist + if not UnitExists(target) then + return false + end + + local unitName = UnitName(target) + if not unitName then + return false + end + + -- Lowercase for case-insensitive comparison + local unitNameLower = string.lower(unitName) + + -- Check for exact match with any provided name (OR logic) + return Or(conditionals.name, function(requiredName) + -- Normalize underscores to spaces and lowercase + local normalizedRequired = string.lower(CleveRoids.NormalizeName(requiredName)) + return unitNameLower == normalizedRequired + end) + end, + + -- [noname:UnitName] - Check if target's name does NOT match (case-insensitive) + -- Uses AND logic: [noname:Onyxia/Nefarian] = not Onyxia AND not Nefarian + -- Examples: [noname:Onyxia] [@mouseover,noname:"Training Dummy"] + noname = function(conditionals) + local target = conditionals.target or "target" + + -- No unit = no name = passes the "not this name" check + if not UnitExists(target) then + return true + end + + local unitName = UnitName(target) + if not unitName then + return true + end + + -- Lowercase for case-insensitive comparison + local unitNameLower = string.lower(unitName) + + -- Check that name does NOT match any provided name (AND logic - must not match ALL) + return NegatedMulti(conditionals.noname, function(forbiddenName) + -- Normalize underscores to spaces and lowercase + local normalizedForbidden = string.lower(CleveRoids.NormalizeName(forbiddenName)) + return unitNameLower ~= normalizedForbidden + end, conditionals, "noname") end } diff --git a/Core.lua b/Core.lua index 4802fa6..4efe6f1 100644 --- a/Core.lua +++ b/Core.lua @@ -2456,7 +2456,10 @@ function CleveRoids.DoTarget(msg) -- UnitXP 3D enemy scanning: cycles through enemies in world space (no nameplate required) -- This is the most powerful scan - finds enemies by line of sight and distance - if wantsHarm and CleveRoids.hasUnitXP then + -- Always enabled unless explicitly looking for friendlies only ([help] without [harm]) + -- UnitXP only finds enemies, so this is safe for any /target with conditionals + local wantsFriendlyOnly = wantsHelp and not wantsHarm + if not wantsFriendlyOnly and CleveRoids.hasUnitXP then -- Try nearestEnemy first - most common case and most efficient local found = UnitXP("target", "nearestEnemy") if found and UnitExists("target") and IsGuidValid("target", conditionals) then diff --git a/README.md b/README.md index 2fc6718..3cbd834 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ All conditionals support negation with `no` prefix (e.g., `[nocombat]`, `[nobuff | `hastarget` | `[hastarget]` | Player has a target | | `notarget` | `[notarget]` | Player has no target | | `pet` | `[pet]` `[pet:Cat/Wolf]` | Has pet (with family) | +| `name` | `[name:Onyxia]` | Exact name match (case-insensitive) | ### Range & Position | Conditional | Example | Description | @@ -221,20 +222,57 @@ Scans enemies and soft-casts without changing your target. Requires UnitXP_SP3. ## Slash Commands +### Commands with Conditional Support + +These commands accept `[conditionals]` and use UnitXP 3D enemy scanning when applicable. + +| Command | Conditionals | UnitXP Scan | Description | +|---------|:------------:|:-----------:|-------------| +| `/cast [cond] Spell` | ✅ | — | Cast spell with conditionals | +| `/castpet [cond] Spell` | ✅ | — | Cast pet spell | +| `/use [cond] Item` | ✅ | — | Use item by name/ID/slot | +| `/equip [cond] Item` | ✅ | — | Equip item (same as /use) | +| `/target [cond]` | ✅ | ✅ | Target with conditionals + enemy scan | +| `/startattack [cond]` | ✅ | — | Start auto-attack if conditions met | +| `/stopattack [cond]` | ✅ | — | Stop auto-attack if conditions met | +| `/stopcasting [cond]` | ✅ | — | Stop casting if conditions met | +| `/unqueue [cond]` | ✅ | — | Clear spell queue if conditions met | +| `/cleartarget [cond]` | ✅ | — | Clear target if conditions met | +| `/cancelaura [cond] Name` | ✅ | — | Cancel buff if conditions met | +| `/quickheal [cond]` | ✅ | — | Smart heal (requires QuickHeal) | +| `/stopmacro [cond]` | ✅ | — | Stop macro execution if conditions met | +| `/petattack [cond]` | ✅ | — | Pet attack with conditionals | +| `/petfollow [cond]` | ✅ | — | Pet follow with conditionals | +| `/petwait [cond]` | ✅ | — | Pet stay with conditionals | +| `/petpassive [cond]` | ✅ | — | Pet passive with conditionals | +| `/petdefensive [cond]` | ✅ | — | Pet defensive with conditionals | +| `/petaggressive [cond]` | ✅ | — | Pet aggressive with conditionals | +| `/castsequence` | ✅ | — | Sequence with reset conditionals | +| `/equipmh [cond] Item` | ✅ | — | Equip to main hand | +| `/equipoh [cond] Item` | ✅ | — | Equip to off hand | +| `/equip11` - `/equip14 [cond]` | ✅ | — | Equip to slot (rings/trinkets) | +| `/unshift [cond]` | ✅ | — | Cancel shapeshift if conditions met | + +### Commands without Conditional Support + | Command | Description | |---------|-------------| -| `/cast [cond] Spell` | Cast with conditionals | -| `/use [cond] Item` | Use item by name/ID/slot | -| `/castsequence reset=X Spell1, Spell2` | Cast sequence | -| `/startattack` `/stopattack` | Auto-attack control | -| `/stopcasting` `/unqueue` | Stop cast / clear queue | -| `/equip` `/equipmh` `/equipoh` | Equip items | -| `/unshift` | Cancel shapeshift | -| `/cancelaura Name` | Cancel buff | -| `/target [@unit,cond]` | Target with conditionals | -| `/retarget` | Clear invalid, target nearest | -| `/quickheal` `/qh` | Smart heal (QuickHeal addon) | -| `/pet*` | Pet commands (attack, follow, wait, aggressive, defensive, passive) | +| `/retarget` | Clear invalid target, target nearest enemy | +| `/runmacro Name` | Execute macro by name (use `{MacroName}` in `/cast` for conditionals) | +| `/rl` | Reload UI | + +### UnitXP 3D Enemy Scanning + +`/target` with any conditionals automatically uses UnitXP 3D scanning to find enemies in line of sight, even without nameplates visible. The only exception is `[help]` without `[harm]` (friendly-only targeting). + +```lua +/target [name:Onyxia] -- Scans for exact name match +/target [nodead,harm] -- Scans for living enemies +/target [hp:<30] -- Scans for low HP enemies +/target [cc:stun] -- Scans for stunned enemies +``` + +If no matching target is found, your original target is preserved. ---