twthreat conditional integration, ttk conditional integration, quickheal conditional integration

This commit is contained in:
Jrc13245
2025-12-05 22:38:43 -05:00
parent 86fa4476f6
commit fdaa2a108c
4 changed files with 582 additions and 3 deletions
+2
View File
@@ -26,6 +26,8 @@ do
-- pet
petattack=true, petfollow=true, petpassive=true,
petaggressive=true, petdefensive=true, petwait=true,
-- healing (requires QuickHeal addon)
quickheal=true, qh=true,
}
-- alias map (if CRM only registers /cancelaura, but /unbuff appears)
+343
View File
@@ -127,6 +127,80 @@ local function NegatedMulti(t, func, conditionals, condition)
end
end
-- ============================================================================
-- THREAT TRACKING (reads server data via CHAT_MSG_ADDON like TWThreat)
-- ============================================================================
-- Storage for threat data
CleveRoids.ThreatData = {
playerName = UnitName("player"),
threats = {}, -- [playerName] = { threat, perc, tank, melee }
lastUpdate = 0,
}
-- Parse threat packet from server (same format as TWThreat)
-- Format: TWTv4=player1:tank:threat:perc:melee;player2:tank:threat:perc:melee;...
local function ParseThreatPacket(packet)
local threatApi = "TWTv4="
local startPos = string.find(packet, threatApi, 1, true)
if not startPos then return end
local playersString = string.sub(packet, startPos + string.len(threatApi))
local playerName = CleveRoids.ThreatData.playerName
-- Clear old data
CleveRoids.ThreatData.threats = {}
CleveRoids.ThreatData.lastUpdate = GetTime()
-- Split by semicolon
for playerData in string.gfind(playersString, "[^;]+") do
-- Split by colon: player:tank:threat:perc:melee
local parts = {}
for part in string.gfind(playerData, "[^:]+") do
table.insert(parts, part)
end
if parts[1] and parts[2] and parts[3] and parts[4] and parts[5] then
local name = parts[1]
local tank = parts[2] == "1"
local threat = tonumber(parts[3]) or 0
local perc = tonumber(parts[4]) or 0
local melee = parts[5] == "1"
CleveRoids.ThreatData.threats[name] = {
threat = threat,
perc = perc,
tank = tank,
melee = melee,
}
end
end
end
-- Get player's threat percentage
function CleveRoids.GetPlayerThreatPercent()
local playerName = CleveRoids.ThreatData.playerName
local data = CleveRoids.ThreatData.threats[playerName]
if data then
return data.perc
end
return nil
end
-- Create frame to listen for threat addon messages
local threatFrame = CreateFrame("Frame", "CleveRoidsThreatFrame")
threatFrame:RegisterEvent("CHAT_MSG_ADDON")
threatFrame:SetScript("OnEvent", function()
if event == "CHAT_MSG_ADDON" then
-- arg1 = prefix, arg2 = message, arg3 = channel, arg4 = sender
if arg2 and string.find(arg2, "TWTv4=", 1, true) then
ParseThreatPacket(arg2)
end
end
end)
-- ============================================================================
-- pfUI debuff time helper (Vanilla 1.12.1 / Lua 5.0 safe)
local function PFUI_HasLibDebuff()
return type(pfUI) == "table"
@@ -494,6 +568,91 @@ function CleveRoids.ValidateLevel(unit, operator, amount)
return false
end
--- Validates a threat percentage conditional using server threat data.
--- Usage: [threat:>80] [threat:<50] [threat:=100]
--- operator: Comparison operator (>, <, =, >=, <=, ~=)
--- amount: Threat percentage (0-100+, where 100 = will pull aggro)
--- returns: True if playerThreat [operator] amount
--- Note: Requires TWThreat addon to be running (sends threat requests to server)
function CleveRoids.ValidateThreat(operator, amount)
if not operator or not amount then return false end
-- Get threat percentage from parsed server data
local threatpct = CleveRoids.GetPlayerThreatPercent()
-- No threat data available
if threatpct == nil then
return false
end
-- Compare threat percentage against threshold
if CleveRoids.operators[operator] then
return CleveRoids.comparators[operator](threatpct, amount)
end
return false
end
--- Validates a Time-To-Kill conditional using TimeToKill addon.
--- Usage: [ttk:<10] [ttk:>30] [ttk:=5]
--- operator: Comparison operator (>, <, =, >=, <=, ~=)
--- amount: Time in seconds until target death
--- returns: True if TTK [operator] amount
function CleveRoids.ValidateTTK(operator, amount)
if not operator or not amount then return false end
-- Check if TimeToKill is loaded
if type(TimeToKill) ~= "table" or type(TimeToKill.GetTTK) ~= "function" then
-- Only show error once per session
if not CleveRoids._ttkErrorShown then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [ttk] conditional requires the TimeToKill addon.", 1, 0.5, 0.5)
CleveRoids._ttkErrorShown = true
end
return false
end
local ttk = TimeToKill.GetTTK()
if ttk == nil then
return false -- Not tracking TTK
end
-- Compare TTK against threshold
if CleveRoids.operators[operator] then
return CleveRoids.comparators[operator](ttk, amount)
end
return false
end
--- Validates a Time-To-Execute conditional using TimeToKill addon.
--- Usage: [tte:<5] [tte:>10]
--- operator: Comparison operator (>, <, =, >=, <=, ~=)
--- amount: Time in seconds until target reaches 20% HP
--- returns: True if TTE [operator] amount
function CleveRoids.ValidateTTE(operator, amount)
if not operator or not amount then return false end
-- Check if TimeToKill is loaded
if type(TimeToKill) ~= "table" or type(TimeToKill.GetTTE) ~= "function" then
if not CleveRoids._ttkErrorShown then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [tte] conditional requires the TimeToKill addon.", 1, 0.5, 0.5)
CleveRoids._ttkErrorShown = true
end
return false
end
local tte = TimeToKill.GetTTE()
if tte == nil then
return false -- Not tracking or already in execute phase
end
if CleveRoids.operators[operator] then
return CleveRoids.comparators[operator](tte, amount)
end
return false
end
function CleveRoids.ValidateKnown(args)
if not args then
return false
@@ -3166,6 +3325,190 @@ CleveRoids.Keywords = {
end, conditionals, "nostimer")
end,
-- Threat percentage conditional (reads server data via CHAT_MSG_ADDON)
-- Usage: [threat:>80] - true if threat is above 80%
-- 100% = will pull aggro
-- Note: Requires TWThreat addon to request threat data from server
threat = function(conditionals)
return Multi(conditionals.threat, function(args)
if type(args) ~= "table" then return false end
-- Handle multi-comparison (e.g., >50&<90)
if args.comparisons and type(args.comparisons) == "table" then
local threatpct = CleveRoids.GetPlayerThreatPercent()
if threatpct == nil then return false end
-- ALL comparisons must pass (AND logic)
for _, comp in ipairs(args.comparisons) do
if not CleveRoids.operators[comp.operator] then
return false
end
if not CleveRoids.comparators[comp.operator](threatpct, comp.amount) then
return false
end
end
return true
end
return CleveRoids.ValidateThreat(args.operator, args.amount)
end, conditionals, "threat")
end,
-- Negated threat conditional
nothreat = function(conditionals)
return NegatedMulti(conditionals.nothreat, function(args)
if type(args) ~= "table" then return false end
if args.comparisons and type(args.comparisons) == "table" then
local threatpct = CleveRoids.GetPlayerThreatPercent()
if threatpct == nil then return true end
for _, comp in ipairs(args.comparisons) do
if not CleveRoids.operators[comp.operator] then
return true
end
if not CleveRoids.comparators[comp.operator](threatpct, comp.amount) then
return true
end
end
return false
end
return not CleveRoids.ValidateThreat(args.operator, args.amount)
end, conditionals, "nothreat")
end,
-- Time-To-Kill conditional (requires TimeToKill addon)
-- Usage: [ttk:<10] - true if target will die in less than 10 seconds
ttk = function(conditionals)
return Multi(conditionals.ttk, function(args)
if type(args) ~= "table" then return false end
-- Handle multi-comparison (e.g., >5&<15)
if args.comparisons and type(args.comparisons) == "table" then
if type(TimeToKill) ~= "table" or type(TimeToKill.GetTTK) ~= "function" then
if not CleveRoids._ttkErrorShown then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [ttk] conditional requires the TimeToKill addon.", 1, 0.5, 0.5)
CleveRoids._ttkErrorShown = true
end
return false
end
local ttk = TimeToKill.GetTTK()
if ttk == nil then return false end
for _, comp in ipairs(args.comparisons) do
if not CleveRoids.operators[comp.operator] then
return false
end
if not CleveRoids.comparators[comp.operator](ttk, comp.amount) then
return false
end
end
return true
end
return CleveRoids.ValidateTTK(args.operator, args.amount)
end, conditionals, "ttk")
end,
-- Negated TTK conditional
nottk = function(conditionals)
return NegatedMulti(conditionals.nottk, function(args)
if type(args) ~= "table" then return false end
if args.comparisons and type(args.comparisons) == "table" then
if type(TimeToKill) ~= "table" or type(TimeToKill.GetTTK) ~= "function" then
if not CleveRoids._ttkErrorShown then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [ttk] conditional requires the TimeToKill addon.", 1, 0.5, 0.5)
CleveRoids._ttkErrorShown = true
end
return true
end
local ttk = TimeToKill.GetTTK()
if ttk == nil then return true end
for _, comp in ipairs(args.comparisons) do
if not CleveRoids.operators[comp.operator] then
return true
end
if not CleveRoids.comparators[comp.operator](ttk, comp.amount) then
return true
end
end
return false
end
return not CleveRoids.ValidateTTK(args.operator, args.amount)
end, conditionals, "nottk")
end,
-- Time-To-Execute conditional (requires TimeToKill addon)
-- Usage: [tte:<5] - true if target will reach 20% HP in less than 5 seconds
tte = function(conditionals)
return Multi(conditionals.tte, function(args)
if type(args) ~= "table" then return false end
if args.comparisons and type(args.comparisons) == "table" then
if type(TimeToKill) ~= "table" or type(TimeToKill.GetTTE) ~= "function" then
if not CleveRoids._ttkErrorShown then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [tte] conditional requires the TimeToKill addon.", 1, 0.5, 0.5)
CleveRoids._ttkErrorShown = true
end
return false
end
local tte = TimeToKill.GetTTE()
if tte == nil then return false end
for _, comp in ipairs(args.comparisons) do
if not CleveRoids.operators[comp.operator] then
return false
end
if not CleveRoids.comparators[comp.operator](tte, comp.amount) then
return false
end
end
return true
end
return CleveRoids.ValidateTTE(args.operator, args.amount)
end, conditionals, "tte")
end,
-- Negated TTE conditional
notte = function(conditionals)
return NegatedMulti(conditionals.notte, function(args)
if type(args) ~= "table" then return false end
if args.comparisons and type(args.comparisons) == "table" then
if type(TimeToKill) ~= "table" or type(TimeToKill.GetTTE) ~= "function" then
if not CleveRoids._ttkErrorShown then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [tte] conditional requires the TimeToKill addon.", 1, 0.5, 0.5)
CleveRoids._ttkErrorShown = true
end
return true
end
local tte = TimeToKill.GetTTE()
if tte == nil then return true end
for _, comp in ipairs(args.comparisons) do
if not CleveRoids.operators[comp.operator] then
return true
end
if not CleveRoids.comparators[comp.operator](tte, comp.amount) then
return true
end
end
return false
end
return not CleveRoids.ValidateTTE(args.operator, args.amount)
end, conditionals, "notte")
end,
-- Checks if the target uses a specific power type (mana, rage, energy)
powertype = function(conditionals)
local unit = conditionals.target or "target"
+84
View File
@@ -290,3 +290,87 @@ SlashCmdList.STOPMACRO = function(msg)
CleveRoids.DoStopMacro(msg)
end
-- QuickHeal with conditionals support (requires QuickHeal addon)
-- Usage: /quickheal [conditionals] [target] [type]
-- Examples:
-- /quickheal -- Smart heal (auto-select target)
-- /quickheal target -- Heal current target
-- /quickheal [combat] party -- Heal party member if in combat
-- /quickheal [mypower:>50] mt -- Heal tank if mana > 50%
-- /quickheal [threat:<80] hot -- Apply HoT if threat is low
SLASH_QUICKHEAL1 = "/quickheal"
SLASH_QUICKHEAL2 = "/qh"
SlashCmdList.QUICKHEAL = function(msg)
CleveRoids.DoQuickHeal(msg)
end
--- Execute QuickHeal with optional conditionals
--- @param msg string The command arguments (conditionals + QuickHeal params)
function CleveRoids.DoQuickHeal(msg)
-- Check if QuickHeal addon is loaded
if type(QuickHeal) ~= "function" then
if not CleveRoids._quickHealErrorShown then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The /quickheal command requires the QuickHeal addon.", 1, 0.5, 0.5)
CleveRoids._quickHealErrorShown = true
end
return
end
msg = CleveRoids.Trim(msg or "")
-- Check if there are conditionals
if string.find(msg, "^%[") then
-- Parse the conditionals and remaining args
local actions = CleveRoids.ParseMsg(msg)
if not actions or table.getn(actions) == 0 then
-- No valid actions parsed, just run QuickHeal
QuickHeal()
return
end
-- Find the first action whose conditionals pass
for i = 1, table.getn(actions) do
local action = actions[i]
if CleveRoids.TestAction(action) then
-- Conditionals passed - extract the target/type from action args
local healTarget = nil
local healType = nil
if action.args then
-- Parse args - could be "target", "party", "mt", "hot", etc.
local args = CleveRoids.Trim(action.args)
if args ~= "" then
-- Check if it's a target or type keyword
local lowerArgs = string.lower(args)
if lowerArgs == "hot" or lowerArgs == "heal" or lowerArgs == "hs" or lowerArgs == "chainheal" then
healType = args
else
-- Assume it's a target specifier
healTarget = args
end
end
end
-- Execute QuickHeal with parsed parameters
QuickHeal(healTarget, nil, nil, nil)
return
end
end
-- No conditions matched - don't heal
return
else
-- No conditionals, pass through to QuickHeal directly
-- Parse basic args: target and/or type
local args = msg
if args == "" then
QuickHeal()
else
-- QuickHeal accepts: Target, SpellID, extParam, forceMaxHPS
-- Common targets: player, target, targettarget, party, mt, nonmt, subgroup
-- Common types: heal, hot, hs (paladin), chainheal (shaman)
QuickHeal(args)
end
end
end
+153 -3
View File
@@ -459,6 +459,8 @@ Default `[noimmune]` checks the debuff school (bleed).
| /use | * | Use item by name/ID |
| /cast | * | Cast spell by name |
| /stopmacro | * | Stop macro execution |
| /quickheal | * | Smart heal (QuickHeal) |
| /qh | * | Alias for /quickheal |
---
@@ -525,8 +527,11 @@ Default `[noimmune]` checks the debuff school (bleed).
| stance | [stance:1/2/3] | * | * | In stance # |
| stat | [stat:str>=100] | * | | Player stat check |
| stealth | [stealth] | | * | Stealth/Prowl |
| swingtimer | [swingtimer:<15] | * | * | Swing % elapsed |
| stimer | [stimer:>80] | * | * | Alias for swingtimer |
| swingtimer | [swingtimer:<15] | * | * | Swing % elapsed (SP_SwingTimer) |
| stimer | [stimer:>80] | * | * | Alias for swingtimer (SP_SwingTimer) |
| threat | [threat:>80] | * | * | Player threat % (TWThreat) |
| ttk | [ttk:<10] | * | * | Time to kill seconds (TimeToKill) |
| tte | [tte:<5] | * | * | Time to execute 20% HP (TimeToKill) |
| swimming | [swimming] | | * | Aquatic form available |
| usable | [usable:"Name"] | * | * | Spell/item usable |
| zone | [zone:"Ironforge"] | * | * | In zone |
@@ -636,7 +641,13 @@ agUnitFrames, Blizzard, CT_RaidAssist, CT_UnitFrames, DiscordUnitFrames, FocusFr
Blizzard, Bongos, Discord Action Bars, pfUI
### Other
ClassicFocus/FocusFrame, SuperMacro, ShaguTweaks, SP_SwingTimer
ClassicFocus/FocusFrame, SuperMacro, ShaguTweaks
### Optional Integrations
- [SP_SwingTimer](https://github.com/jrc13245/SP_SwingTimer) - `[swingtimer]` conditional
- [TWThreat](https://github.com/MarcelineVQ/TWThreat) - `[threat]` conditional
- [TimeToKill](https://github.com/jrc13245/TimeToKill) - `[ttk]` and `[tte]` conditionals
- [QuickHeal](https://github.com/jrc13245/QuickHeal) - `/quickheal` command
---
@@ -684,6 +695,145 @@ For 3.5s weapon:
---
# Threat Integration
Requires [TWThreat](https://github.com/MarcelineVQ/TWThreat).
**How It Works:**
Checks your threat percentage on the current target.
**Note:** TWThreat only provides threat data for **elite targets** when you are in a **party or raid**.
**Threat Values:**
- 0-99% = Not tanking
- 100% = Tank/aggro holder
- 110% = Melee pull threshold
- 130% = Ranged pull threshold
**Syntax:**
```lua
[threat:>80] -- Threat above 80%
[threat:<50] -- Threat below 50%
[nothreat:>X] -- NOT above X%
```
**Examples:**
```lua
-- Stop DPS when threat is high
#showtooltip Fireball
/cast [threat:<90] Fireball
-- Fade when about to pull aggro
#showtooltip Fade
/cast [threat:>100] Fade
-- Use threat reduction before pulling
#showtooltip Feign Death
/cast [threat:>105] Feign Death
-- Tank: taunt when losing aggro
#showtooltip Taunt
/cast [threat:<100] Taunt
```
---
# Time-To-Kill Integration
Requires [TimeToKill](https://github.com/jrc13245/TimeToKill).
**How It Works:**
Uses RLS algorithm to predict when target will die or reach execute phase (20% HP).
**Conditionals:**
- `[ttk:<X]` - Time to kill in seconds
- `[tte:<X]` - Time to execute (20% HP) in seconds
**Syntax:**
```lua
[ttk:<10] -- Target dies in less than 10 seconds
[ttk:>30] -- Target dies in more than 30 seconds
[tte:<5] -- Target reaches 20% HP in less than 5 seconds
[nottk:<X] -- NOT dying in less than X seconds
```
**Examples:**
```lua
-- Use execute when target about to enter execute range
#showtooltip Execute
/cast [tte:<3] Execute
-- Pop cooldowns only on long fights
#showtooltip Recklessness
/cast [ttk:>30] Recklessness
-- Finish mob quickly if almost dead
#showtooltip
/cast [ttk:<5] Heroic Strike
/cast Bloodthirst
-- Don't waste DoTs on dying targets
#showtooltip
/cast [ttk:>15] Corruption
/cast Shadow Bolt
```
---
# QuickHeal Integration
Requires [QuickHeal](https://github.com/jrc13245/QuickHeal).
**How It Works:**
Adds `/quickheal` (or `/qh`) command with full conditional support for smart healing.
**Syntax:**
```lua
/quickheal -- Smart heal (auto-select target)
/quickheal target -- Heal current target
/quickheal [conditionals] X -- Heal X if conditionals pass
/qh -- Alias
```
**Target Options:**
- `player` - Self
- `target` - Current target
- `targettarget` - Target's target
- `party` / `subgroup` - Lowest health party member
- `mt` / `nonmt` - Main tanks or non-tanks (raid only)
**Type Options:**
- `heal` - Regular heal (default)
- `hot` - Heal over time
- `hs` - Holy Shock (Paladin)
- `chainheal` - Chain Heal (Shaman)
**Examples:**
```lua
-- Only heal if not in danger
#showtooltip
/quickheal [threat:<80] mt
-- Emergency self-heal
#showtooltip
/quickheal [myhp:<30] player
-- Smart group healing with mana check
#showtooltip
/quickheal [combat,mypower:>25] party
-- HoT when low on mana
#showtooltip
/quickheal [mypower:<40] hot
/quickheal heal
-- Heal tank if they're hurt
#showtooltip
/quickheal [combat] mt
```
---
# HealComm Support
This addon uses SuperWoW's CastSpellByName which is incompatible with standard HealComm-1.0.