add optional resist/expiry sounds

This commit is contained in:
pepopo978
2024-05-27 16:49:05 -07:00
parent 02b5505443
commit 258e5a0476
5 changed files with 148 additions and 14 deletions
+26
View File
@@ -11,13 +11,39 @@
Cursive combines ShaguScan unit scanning with curse tracking similar to DotTimer and the ability to automatically curse targets similar to Decursive.
## Commands
`/cursive` for commands, minimap icon to edit options.
### Curse
`/cursive curse <spellName:str>|<guid?:str>|<noFailureWarning?:int[0,1]`: Casts spell if not already on target/guid
EXAMPLE: `/cursive curse Corruption|target|1` will attempt to cast Corruption on your target if it's not already on them and won't warn you if it does nothing.
### Multicurse
`/cursive multicurse <spellName:str>|<priority?:str>|<noFailureWarning?:int[0,1]`: Picks target based on priority and casts spell if not already on target.
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.
## 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.",
EXAMPLE: `/cursive multicurse Corruption|HIGHEST_HP|warnings,resistsound,expiringsound`
## Important info
All commands will prioritize targets within 28 yards of you first to have a better chance of being in range.
All commands will ignore targets with the following CCs on them:
- Sleep
- Entangling Roots
- Shackle Undead
- Polymorph
- Turn Undead
- Blind
- Sap
- Gouge
- Freezing Trap
+52 -13
View File
@@ -1,28 +1,53 @@
local curseCommands = "|cffffcc00Cursive:|cffffaaaa Commands:"
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.",
}
local commands = {
["curse"] = "/cursive curse <spellName:str>|<guid?:str>|<noFailureWarning:int[0,1]: Casts spell if not already on target/guid",
["multicurse"] = "/cursive multicurse <spellName:str>|<priority?:str>|<noFailureWarning:int[0,1]: Picks target based on priority and casts spell if not already on target. Priority options: HIGHEST_HP, RAID_MARK.",
["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.",
}
local curseNoTarget = "|cffffcc00Cursive:|cffffaaaa Couldn't find a target to curse."
local function parseOptions(optionsStr)
local options = { }
for option, _ in pairs(commandOptions) do
if string.find(optionsStr, option) then
options[option] = true
end
end
return options
end
local function handleSlashCommands(msg, editbox)
if not msg or msg == "" then
DEFAULT_CHAT_FRAME:AddMessage(curseCommands)
for command, description in pairs(commands) do
DEFAULT_CHAT_FRAME:AddMessage(description)
end
DEFAULT_CHAT_FRAME:AddMessage(curseOptions)
for option, description in pairs(commandOptions) do
DEFAULT_CHAT_FRAME:AddMessage(option .. ": " .. description)
end
return
end
-- get first word in string
local _, _, command, args = string.find(msg, "(%w+) (.*)")
if command == "curse" then
local spellName, targetedGuid, noFailureWarning = Cursive.utils.strsplit("|", args)
Cursive:Curse(spellName, targetedGuid, noFailureWarning)
local spellName, targetedGuid, optionsStr = Cursive.utils.strsplit("|", args)
local options = parseOptions(optionsStr)
Cursive:Curse(spellName, targetedGuid, options)
elseif command == "multicurse" then
local spellName, priority, noFailureWarning = Cursive.utils.strsplit("|", args)
Cursive:Multicurse(spellName, priority, noFailureWarning)
local spellName, priority, optionsStr = Cursive.utils.strsplit("|", args)
local options = parseOptions(optionsStr)
Cursive:Multicurse(spellName, priority, options)
end
end
@@ -68,6 +93,10 @@ local crowdControlledSpellIds = {
[8629] = { name = "Gouge", rank = 3, duration = 4 },
[11285] = { name = "Gouge", rank = 4, duration = 4 },
[11286] = { name = "Gouge", rank = 5, duration = 4 },
[3355] = { name = "Freezing Trap", rank = 1, duration = 10 },
[14308] = { name = "Freezing Trap", rank = 2, duration = 15 },
[14309] = { name = "Freezing Trap", rank = 3, duration = 20 },
}
local function isMobCrowdControlled(guid)
@@ -168,7 +197,17 @@ local function pickRaidMarkTarget(selectedPriority, spellNameNoRank, skipCheckRa
return targetedGuid
end
function Cursive:Curse(spellName, targetedGuid, noFailureWarning)
local function castSpellWithOptions(spellName, targetedGuid, options)
if options["resistsound"] then
Cursive.curses:EnableResistSound(targetedGuid)
end
if options["expiringsound"] then
Cursive.curses:RequestExpiringSound(spellName, targetedGuid)
end
CastSpellByName(spellName, targetedGuid)
end
function Cursive:Curse(spellName, targetedGuid, options)
if not spellName or not targetedGuid then
DEFAULT_CHAT_FRAME:AddMessage(commands["curse"])
return
@@ -178,7 +217,7 @@ function Cursive:Curse(spellName, targetedGuid, noFailureWarning)
_, targetedGuid = UnitExists(targetedGuid)
if not targetedGuid then
if not (noFailureWarning and noFailureWarning == "1") then
if options["warnings"] then
DEFAULT_CHAT_FRAME:AddMessage(curseNoTarget)
end
return
@@ -189,13 +228,13 @@ function Cursive:Curse(spellName, targetedGuid, noFailureWarning)
local spellNameNoRank = string.gsub(spellName, "%(.+%)", "")
if targetedGuid and not Cursive.curses:HasCurse(spellNameNoRank, targetedGuid) and not isMobCrowdControlled(targetedGuid) then
CastSpellByName(spellName, targetedGuid)
elseif not (noFailureWarning and noFailureWarning == "1") then
castSpellWithOptions(spellName, targetedGuid, options)
elseif options["warnings"] then
DEFAULT_CHAT_FRAME:AddMessage(curseNoTarget)
end
end
function Cursive:Multicurse(spellName, priority, noFailureWarning)
function Cursive:Multicurse(spellName, priority, options)
if not spellName then
DEFAULT_CHAT_FRAME:AddMessage(commands["multicurse"])
return
@@ -219,8 +258,8 @@ function Cursive:Multicurse(spellName, priority, noFailureWarning)
end
if targetedGuid then
CastSpellByName(spellName, targetedGuid)
elseif not (noFailureWarning and noFailureWarning == "1") then
castSpellWithOptions(spellName, targetedGuid, options)
elseif options["warnings"] then
DEFAULT_CHAT_FRAME:AddMessage(curseNoTarget)
end
end
+54
View File
@@ -6,6 +6,9 @@ local curses = {
trackedCurseIds = {},
trackedCurseNamesToTextures = {},
guids = {},
resistSoundGuids = {},
expiringSoundGuids = {},
requestedExpiringSoundGuids = {} -- guid added on spellcast, moved to expiringSoundGuids once rendered by ui
}
-- combat events for curses
@@ -65,6 +68,10 @@ Cursive:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE",
if spell and target then
if curses.trackedCurseNamesToTextures[spell] and lastGuid then
Cursive:CancelScheduledEvent("addCurse" .. lastGuid .. spell)
-- check if sound should be played
if curses:ShouldPlayResistSound(lastGuid) then
PlaySoundFile("Interface\\AddOns\\Cursive\\Sounds\\resist.mp3")
end
end
end
end
@@ -74,6 +81,50 @@ function curses:TimeRemaining(curseData)
return math.ceil(curseData.duration - (GetTime() - curseData.start))
end
function curses:EnableResistSound(guid)
curses.resistSoundGuids[guid] = true
end
function curses:EnableExpiringSound(spellName, guid)
if curses.requestedExpiringSoundGuids[guid] and curses.requestedExpiringSoundGuids[guid][spellName] then
curses.requestedExpiringSoundGuids[guid][spellName] = nil
end
if not curses.expiringSoundGuids[guid] then
curses.expiringSoundGuids[guid] = {}
end
curses.expiringSoundGuids[guid][spellName] = true
end
function curses:RequestExpiringSound(spellName, guid)
if not curses.requestedExpiringSoundGuids[guid] then
curses.requestedExpiringSoundGuids[guid] = {}
end
curses.requestedExpiringSoundGuids[guid][spellName] = true
end
function curses:HasRequestedExpiringSound(spellName, guid)
return curses.requestedExpiringSoundGuids[guid] and curses.requestedExpiringSoundGuids[guid][spellName]
end
function curses:ShouldPlayExpiringSound(spellName, guid)
if curses.expiringSoundGuids[guid] and curses.expiringSoundGuids[guid][spellName] then
curses.expiringSoundGuids[guid][spellName] = nil -- remove entry to avoid playing sound multiple times
return true
end
return false
end
function curses:ShouldPlayResistSound(guid)
if curses.resistSoundGuids[guid] then
curses.resistSoundGuids[guid] = nil -- remove entry to avoid playing sound multiple times
return true
end
return false
end
function curses:HasCurse(spellName, targetGuid)
if curses.guids[targetGuid] and curses.guids[targetGuid][spellName] then
local remaining = Cursive.curses:TimeRemaining(curses.guids[targetGuid][spellName])
@@ -101,6 +152,9 @@ end
function curses:RemoveGuid(guid)
curses.guids[guid] = nil
curses.resistSoundGuids[guid] = nil
curses.expiringSoundGuids[guid] = nil
curses.requestedExpiringSoundGuids[guid] = nil
end
Cursive.curses = curses
+16 -1
View File
@@ -321,6 +321,14 @@ local function DisplayGuid(guid, row, col)
curse.timer:SetText(remaining)
curse.timer:Show()
curse:Show()
if remaining < 1 then
if Cursive.curses:ShouldPlayExpiringSound(curseName, guid) then
PlaySoundFile("Interface\\AddOns\\Cursive\\sounds\\expiring.mp3")
end
elseif Cursive.curses:HasRequestedExpiringSound(curseName, guid) then
Cursive.curses:EnableExpiringSound(curseName, guid)
end
else
curse.timer:Hide()
curse:Hide()
@@ -343,7 +351,7 @@ ui:SetScript("OnUpdate", function()
if (this.tick or 1) > GetTime() then
return
else
this.tick = GetTime() + .8
this.tick = GetTime() + .2
end
if not ui.rootBarFrame then
@@ -386,6 +394,13 @@ ui:SetScript("OnUpdate", function()
end
local active = UnitExists(guid) and Cursive.filter.alive(guid)
if active then
local old = GetTime() - time >= 900 -- >= 15 minutes old
if old and not UnitIsVisible(guid) then
active = false
end
end
if not active then
-- remove from core
Cursive.core.remove(guid)