@@ -25,17 +25,33 @@ EXAMPLE: `/cursive curse Corruption|target` will attempt to cast Corruption on y
|
||||
|
||||
### Multicurse
|
||||
`/cursive multicurse <spellName:str>|<priority?:str>|<options?:str>`: Picks target based on priority and casts spell if not already on target and they aren't cc'ed.
|
||||
Priority options: HIGHEST_HP, RAID_MARK
|
||||
|
||||
EXAMPLE: `/cursive multicurse Corruption|HIGHEST_HP` will attempt to cast Corruption picking the target with the highest HP that doesn't already have it and will warn you if it does nothing.
|
||||
## Priority Options
|
||||
- HIGHEST_HP - Target highest HP enemy without a curse first.
|
||||
- RAID_MARK - Target largest raid mark enemy without a curse first. Raid mark priority is as follows:
|
||||
- Skull = 8 (1st priority)
|
||||
- Cross = 7
|
||||
- Square = 6
|
||||
- Moon = 5
|
||||
- Triangle = 4
|
||||
- Circle = 3
|
||||
- Star = 2
|
||||
- Diamond = 1 (8th priority)
|
||||
- No mark = 0
|
||||
- HIGHEST_HP_RAID_MARK - Target highest HP enemy with a raid (use raid mark priorities for identical hp), then highest HP enemy without a mark.
|
||||
|
||||
|
||||
## Command Options
|
||||
All commands can take the following options separated by commas:
|
||||
- ["warnings"] : "Display text warnings when a curse fails to cast.",
|
||||
- ["resistsound"] : "Play a sound when a curse is resisted.",
|
||||
- ["expiringsound"] : "Play a sound when a curse is about to expire.",
|
||||
- `warnings` : "Display text warnings when a curse fails to cast.",
|
||||
- `resistsound` : "Play a sound when a curse is resisted.",
|
||||
- `expiringsound` : "Play a sound when a curse is about to expire.",
|
||||
- `allowooc` : "Allow out of combat targets to be multicursed. Would only consider using this solo to avoid potentially griefing raids/dungeons by pulling unintended mobs.",
|
||||
- `minhp=<number>` : "Minimum HP for a target to be considered.",
|
||||
- `refreshtime=<number>` : "Time threshold at which to allow refreshing a curse. Default is 0 seconds.",
|
||||
|
||||
EXAMPLE: `/cursive multicurse Corruption|HIGHEST_HP|warnings,resistsound,expiringsound`
|
||||
EXAMPLE: `/cursive multicurse Corruption|HIGHEST_HP|warnings,resistsound,expiringsound,minhp=10000,refreshtime=2`
|
||||
|
||||
## Important info
|
||||
|
||||
@@ -54,14 +70,3 @@ All commands will ignore targets with the following CCs on them:
|
||||
- Banish
|
||||
|
||||
Multicurse will only ever target enemies that are already in combat (except if you target a mob directly first) to prevent pulling things you didn't intend like marked patrols.
|
||||
|
||||
Raid mark priority is based on the following order:
|
||||
- Skull = 8
|
||||
- Cross = 7
|
||||
- Square = 6
|
||||
- Moon = 5
|
||||
- Triangle = 4
|
||||
- Circle = 3
|
||||
- Star = 2
|
||||
- Diamond = 1
|
||||
- No mark = 0
|
||||
|
||||
+75
-23
@@ -1,15 +1,25 @@
|
||||
local curseCommands = "|cffffcc00Cursive:|cffffaaaa Commands:"
|
||||
local priorityChoices = "Priority choices:"
|
||||
local curseOptions = "Options (separate with ,):"
|
||||
|
||||
local commandOptions = {
|
||||
["warnings"] = "Display text warnings when a curse fails to cast.",
|
||||
["resistsound"] = "Play a sound when a curse is resisted.",
|
||||
["expiringsound"] = "Play a sound when a curse is about to expire.",
|
||||
warnings = "Display text warnings when a curse fails to cast.",
|
||||
resistsound = "Play a sound when a curse is resisted.",
|
||||
expiringsound = "Play a sound when a curse is about to expire.",
|
||||
allowooc = "Allow out of combat targets to be multicursed. Would only consider using this solo to avoid potentially griefing raids/dungeons by pulling unintended mobs.",
|
||||
minhp = "Minimum HP for a target to be considered. Example usage minhp=10000. ",
|
||||
refreshtime = "Time threshold at which to allow refreshing a curse. Default is 0 seconds."
|
||||
}
|
||||
|
||||
local commands = {
|
||||
["curse"] = "/cursive curse <spellName:str>|<guid?:str>|<options?:List<str>>: Casts spell if not already on target/guid",
|
||||
["multicurse"] = "/cursive multicurse <spellName:str>|<priority?:str>|<options?:List<str>>: Picks target based on priority and casts spell if not already on target. Priority options: HIGHEST_HP, RAID_MARK.",
|
||||
["multicurse"] = "/cursive multicurse <spellName:str>|<priority?:str>|<options?:List<str>>: Picks target based on priority and casts spell if not already on target",
|
||||
}
|
||||
|
||||
local priorities = {
|
||||
["HIGHEST_HP"] = "Target with the highest HP.",
|
||||
["RAID_MARK"] = "Target with the highest raid mark.",
|
||||
["HIGHEST_HP_RAID_MARK"] = "Target with the highest HP and raid mark.",
|
||||
}
|
||||
|
||||
local curseNoTarget = "|cffffcc00Cursive:|cffffaaaa Couldn't find a target to curse."
|
||||
@@ -19,7 +29,18 @@ local function parseOptions(optionsStr)
|
||||
|
||||
if optionsStr then
|
||||
for option, _ in pairs(commandOptions) do
|
||||
if string.find(optionsStr, option) then
|
||||
-- special case for minhp as it takes a param
|
||||
if option == "minhp" then
|
||||
local _, _, minHp = string.find(optionsStr, "minhp=(%d+)")
|
||||
if minHp then
|
||||
options["minhp"] = tonumber(minHp)
|
||||
end
|
||||
elseif option == "refreshtime" then
|
||||
local _, _, refreshTime = string.find(optionsStr, "refreshtime=(%d+)")
|
||||
if refreshTime then
|
||||
options["refreshtime"] = tonumber(refreshTime)
|
||||
end
|
||||
elseif string.find(optionsStr, option) then
|
||||
options[option] = true
|
||||
end
|
||||
end
|
||||
@@ -34,6 +55,11 @@ local function handleSlashCommands(msg, editbox)
|
||||
for command, description in pairs(commands) do
|
||||
DEFAULT_CHAT_FRAME:AddMessage(description)
|
||||
end
|
||||
DEFAULT_CHAT_FRAME:AddMessage(priorityChoices)
|
||||
for priority, description in pairs(priorities) do
|
||||
DEFAULT_CHAT_FRAME:AddMessage(priority .. ": " .. description)
|
||||
end
|
||||
|
||||
DEFAULT_CHAT_FRAME:AddMessage(curseOptions)
|
||||
for option, description in pairs(commandOptions) do
|
||||
DEFAULT_CHAT_FRAME:AddMessage(option .. ": " .. description)
|
||||
@@ -134,33 +160,56 @@ local function isMobCrowdControlled(guid)
|
||||
return false
|
||||
end
|
||||
|
||||
local function pickTarget(selectedPriority, spellNameNoRank, checkRange)
|
||||
local function pickTarget(selectedPriority, spellNameNoRank, checkRange, options)
|
||||
-- Curse the target that best matches the selected priority
|
||||
local highestPriorityValue = -1
|
||||
local highestPrimaryValue = -1
|
||||
local highestSecondaryValue = -1
|
||||
local targetedGuid = nil
|
||||
|
||||
local minHp = options["minhp"]
|
||||
local ignoreInFight = options["allowooc"]
|
||||
local refreshTime = options["refreshtime"]
|
||||
|
||||
local _, currentTargetGuid = UnitExists("target")
|
||||
|
||||
local seenRaidMark = nil -- if we have seen a raid mark
|
||||
|
||||
for guid, time in pairs(Cursive.core.guids) do
|
||||
-- apply filters
|
||||
local shouldDisplay = Cursive:ShouldDisplayGuid(guid)
|
||||
-- check if target displayed
|
||||
if shouldDisplay then
|
||||
-- check if in combat already or player is actively targeting the mob
|
||||
if Cursive.filter.infight(guid) or guid == currentTargetGuid then
|
||||
if ignoreInFight or Cursive.filter.infight(guid) or guid == currentTargetGuid then
|
||||
-- prioritize targets within 28 yards first to improve chances of being in range
|
||||
if checkRange == false or CheckInteractDistance(guid, 4) then
|
||||
-- check if the target has the curse
|
||||
if not Cursive.curses:HasCurse(spellNameNoRank, guid) and not isMobCrowdControlled(guid) then
|
||||
local value
|
||||
if selectedPriority == "HIGHEST_HP" then
|
||||
value = UnitHealth(guid)
|
||||
elseif selectedPriority == "RAID_MARK" then
|
||||
value = GetRaidTargetIndex(guid) or 0
|
||||
end
|
||||
if not Cursive.curses:HasCurse(spellNameNoRank, guid, refreshTime) and not isMobCrowdControlled(guid) then
|
||||
local mobHp = UnitHealth(guid)
|
||||
if not minHp or mobHp >= minHp then
|
||||
local primaryValue
|
||||
local secondaryValue = -1
|
||||
if selectedPriority == "HIGHEST_HP" then
|
||||
primaryValue = UnitHealth(guid)
|
||||
elseif selectedPriority == "RAID_MARK" then
|
||||
primaryValue = GetRaidTargetIndex(guid) or 0
|
||||
elseif selectedPriority == "HIGHEST_HP_RAID_MARK" then
|
||||
secondaryValue = GetRaidTargetIndex(guid) or 0
|
||||
if secondaryValue > 0 and not seenRaidMark then
|
||||
highestPrimaryValue = -1 -- reset highestPriorityValue if this is the first raid mark we've seen
|
||||
seenRaidMark = true
|
||||
end
|
||||
primaryValue = UnitHealth(guid)
|
||||
end
|
||||
|
||||
if value > highestPriorityValue then
|
||||
highestPriorityValue = value
|
||||
targetedGuid = guid
|
||||
if primaryValue > highestPrimaryValue then
|
||||
highestPrimaryValue = primaryValue
|
||||
highestSecondaryValue = secondaryValue
|
||||
targetedGuid = guid
|
||||
elseif primaryValue == highestPrimaryValue and secondaryValue > highestSecondaryValue then
|
||||
highestSecondaryValue = secondaryValue
|
||||
targetedGuid = guid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -170,7 +219,7 @@ local function pickTarget(selectedPriority, spellNameNoRank, checkRange)
|
||||
|
||||
-- run again if no target found ignoring range
|
||||
if not targetedGuid and checkRange == true then
|
||||
targetedGuid = pickTarget(selectedPriority, spellNameNoRank, false)
|
||||
targetedGuid = pickTarget(selectedPriority, spellNameNoRank, false, options)
|
||||
end
|
||||
|
||||
return targetedGuid
|
||||
@@ -206,7 +255,7 @@ function Cursive:Curse(spellName, targetedGuid, options)
|
||||
-- remove (Rank x) from spellName if it exists
|
||||
local spellNameNoRank = string.gsub(spellName, "%(.+%)", "")
|
||||
|
||||
if targetedGuid and not Cursive.curses:HasCurse(spellNameNoRank, targetedGuid) and not isMobCrowdControlled(targetedGuid) then
|
||||
if targetedGuid and not Cursive.curses:HasCurse(spellNameNoRank, targetedGuid, options["refreshtime"]) and not isMobCrowdControlled(targetedGuid) then
|
||||
castSpellWithOptions(spellName, spellNameNoRank, targetedGuid, options)
|
||||
elseif options["warnings"] then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(curseNoTarget)
|
||||
@@ -219,8 +268,11 @@ function Cursive:Multicurse(spellName, priority, options)
|
||||
return
|
||||
end
|
||||
|
||||
if priority and (priority ~= "HIGHEST_HP" and priority ~= "RAID_MARK") then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(commands["multicurse"])
|
||||
if priority and not priorities[priority] then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(priorityChoices)
|
||||
for choice, description in pairs(priorities) do
|
||||
DEFAULT_CHAT_FRAME:AddMessage(choice .. ": " .. description)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
@@ -229,7 +281,7 @@ function Cursive:Multicurse(spellName, priority, options)
|
||||
-- remove (Rank x) from spellName if it exists
|
||||
local spellNameNoRank = string.gsub(spellName, "%(.+%)", "")
|
||||
|
||||
local targetedGuid = pickTarget(selectedPriority, spellNameNoRank, true)
|
||||
local targetedGuid = pickTarget(selectedPriority, spellNameNoRank, true, options)
|
||||
|
||||
if targetedGuid then
|
||||
castSpellWithOptions(spellName, spellNameNoRank, targetedGuid, options)
|
||||
|
||||
+9
-3
@@ -172,12 +172,18 @@ function curses:ShouldPlayResistSound(guid)
|
||||
return false
|
||||
end
|
||||
|
||||
function curses:HasCurse(spellName, targetGuid)
|
||||
function curses:HasCurse(spellName, targetGuid, minRemaining)
|
||||
if not minRemaining then
|
||||
minRemaining = 0 -- default to 0
|
||||
end
|
||||
|
||||
if curses.guids[targetGuid] and curses.guids[targetGuid][spellName] then
|
||||
local remaining = Cursive.curses:TimeRemaining(curses.guids[targetGuid][spellName])
|
||||
return remaining > 0
|
||||
if remaining > minRemaining then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
return nil
|
||||
end
|
||||
|
||||
function curses:ApplyCurse(spellID, targetGuid, startTime)
|
||||
|
||||
Reference in New Issue
Block a user