You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1170 lines
57 KiB
1170 lines
57 KiB
---@class DBMCoreNamespace
|
|
local private = select(2, ...)
|
|
|
|
local L = DBM_CORE_L
|
|
local CL = DBM_COMMON_L
|
|
|
|
local DBMScheduler = private:GetModule("DBMScheduler")
|
|
local stringUtils = private:GetPrototype("StringUtils")
|
|
local checkEntry = private:GetPrototype("TableUtils").checkEntry
|
|
|
|
---@class DBM
|
|
local DBM = private:GetPrototype("DBM")
|
|
---@class Announce
|
|
local announcePrototype = private:GetPrototype("Announce")
|
|
---@class DBMMod
|
|
local bossModPrototype = private:GetPrototype("DBMMod")
|
|
|
|
local test = private:GetPrototype("DBMTest")
|
|
|
|
local playerName = UnitName("player")
|
|
|
|
---@diagnostic disable: inject-field
|
|
local frame = CreateFrame("Frame", "DBMSpecialWarning", UIParent)
|
|
local font1 = frame:CreateFontString("DBMSpecialWarning1", "OVERLAY", "ZoneTextFont")
|
|
font1:SetWidth(1024)
|
|
font1:SetHeight(0)
|
|
font1:SetPoint("TOP", 0, 0)
|
|
local font2 = frame:CreateFontString("DBMSpecialWarning2", "OVERLAY", "ZoneTextFont")
|
|
font2:SetWidth(1024)
|
|
font2:SetHeight(0)
|
|
font2:SetPoint("TOP", font1, "BOTTOM", 0, 0)
|
|
frame:SetMovable(true)
|
|
frame:SetWidth(1)
|
|
frame:SetHeight(1)
|
|
frame:SetFrameStrata("HIGH")
|
|
frame:SetClampedToScreen(true)
|
|
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
|
|
|
|
local font1elapsed, font2elapsed, moving
|
|
|
|
local function fontHide1()
|
|
local duration = DBM.Options.SpecialWarningDuration2
|
|
if font1elapsed > duration * 1.3 then
|
|
font1:Hide()
|
|
if frame.font1ticker then
|
|
frame.font1ticker:Cancel()
|
|
frame.font1ticker = nil
|
|
end
|
|
elseif font1elapsed > duration then
|
|
font1elapsed = font1elapsed + 0.05
|
|
local alpha = 1 - (font1elapsed - duration) / (duration * 0.3)
|
|
font1:SetAlpha(alpha > 0 and alpha or 0)
|
|
else
|
|
font1elapsed = font1elapsed + 0.05
|
|
font1:SetAlpha(1)
|
|
end
|
|
end
|
|
|
|
local function fontHide2()
|
|
local duration = DBM.Options.SpecialWarningDuration2
|
|
if font2elapsed > duration * 1.3 then
|
|
font2:Hide()
|
|
if frame.font2ticker then
|
|
frame.font2ticker:Cancel()
|
|
frame.font2ticker = nil
|
|
end
|
|
elseif font2elapsed > duration then
|
|
font2elapsed = font2elapsed + 0.05
|
|
local alpha = 1 - (font2elapsed - duration) / (duration * 0.3)
|
|
font2:SetAlpha(alpha > 0 and alpha or 0)
|
|
else
|
|
font2elapsed = font2elapsed + 0.05
|
|
font2:SetAlpha(1)
|
|
end
|
|
end
|
|
|
|
function DBM:UpdateSpecialWarningOptions()
|
|
frame:ClearAllPoints()
|
|
local font = self.Options.SpecialWarningFont == "standardFont" and private.standardFont or self.Options.SpecialWarningFont
|
|
frame:SetPoint(self.Options.SpecialWarningPoint, UIParent, self.Options.SpecialWarningPoint, self.Options.SpecialWarningX, self.Options.SpecialWarningY)
|
|
font1:SetFont(font, self.Options.SpecialWarningFontSize2, self.Options.SpecialWarningFontStyle == "None" and nil or self.Options.SpecialWarningFontStyle)
|
|
font2:SetFont(font, self.Options.SpecialWarningFontSize2, self.Options.SpecialWarningFontStyle == "None" and nil or self.Options.SpecialWarningFontStyle)
|
|
font1:SetTextColor(unpack(self.Options.SpecialWarningFontCol))
|
|
font2:SetTextColor(unpack(self.Options.SpecialWarningFontCol))
|
|
if self.Options.SpecialWarningFontShadow then
|
|
font1:SetShadowOffset(1, -1)
|
|
font2:SetShadowOffset(1, -1)
|
|
else
|
|
font1:SetShadowOffset(0, 0)
|
|
font2:SetShadowOffset(0, 0)
|
|
end
|
|
end
|
|
|
|
function DBM:AddSpecialWarning(text, force, specWarnObject)
|
|
local added = false
|
|
if not frame.font1ticker then
|
|
font1elapsed = 0
|
|
font1.lastUpdate = GetTime()
|
|
font1:SetText(text)
|
|
font1:Show()
|
|
added = true
|
|
frame.font1ticker = frame.font1ticker or C_Timer.NewTicker(0.05, fontHide1)
|
|
elseif not frame.font2ticker or force then
|
|
font2elapsed = 0
|
|
font2.lastUpdate = GetTime()
|
|
font2:SetText(text)
|
|
font2:Show()
|
|
added = true
|
|
frame.font2ticker = frame.font2ticker or C_Timer.NewTicker(0.05, fontHide2)
|
|
end
|
|
if not added then
|
|
local prevText1 = font2:GetText()
|
|
font1:SetText(prevText1)
|
|
font1elapsed = font2elapsed
|
|
self:AddSpecialWarning(text, true, specWarnObject)
|
|
else
|
|
test:Trace(specWarnObject and specWarnObject.mod or self, "ShowSpecialWarning", specWarnObject, text)
|
|
end
|
|
end
|
|
|
|
local anchorFrame
|
|
local function moveEnd(self)
|
|
moving = false
|
|
anchorFrame:Hide()
|
|
font1elapsed = self.Options.SpecialWarningDuration2
|
|
font2elapsed = self.Options.SpecialWarningDuration2
|
|
frame:SetFrameStrata("HIGH")
|
|
self:Unschedule(moveEnd)
|
|
DBT:CancelBar(L.MOVE_SPECIAL_WARNING_BAR)
|
|
end
|
|
|
|
function DBM:MoveSpecialWarning()
|
|
if not anchorFrame then
|
|
anchorFrame = CreateFrame("Frame", nil, frame)
|
|
anchorFrame:SetWidth(32)
|
|
anchorFrame:SetHeight(32)
|
|
anchorFrame:EnableMouse(true)
|
|
anchorFrame:SetPoint("TOP", frame, "TOP", 0, 32)
|
|
anchorFrame:RegisterForDrag("LeftButton")
|
|
anchorFrame:SetClampedToScreen(true)
|
|
anchorFrame:Hide()
|
|
local texture = anchorFrame:CreateTexture()
|
|
texture:SetTexture("Interface\\Addons\\DBM-Core\\textures\\dot.blp")
|
|
texture:SetPoint("CENTER", anchorFrame, "CENTER", 0, 0)
|
|
texture:SetWidth(32)
|
|
texture:SetHeight(32)
|
|
anchorFrame:SetScript("OnDragStart", function()
|
|
frame:StartMoving()
|
|
self:Unschedule(moveEnd)
|
|
DBT:CancelBar(L.MOVE_SPECIAL_WARNING_BAR)
|
|
end)
|
|
anchorFrame:SetScript("OnDragStop", function()
|
|
frame:StopMovingOrSizing()
|
|
local point, _, _, xOfs, yOfs = frame:GetPoint(1)
|
|
self.Options.SpecialWarningPoint = point
|
|
self.Options.SpecialWarningX = xOfs
|
|
self.Options.SpecialWarningY = yOfs
|
|
self:Schedule(15, moveEnd, self)
|
|
DBT:CreateBar(15, L.MOVE_SPECIAL_WARNING_BAR, private.isRetail and 237538 or 136106)
|
|
end)
|
|
end
|
|
if anchorFrame:IsShown() then
|
|
moveEnd(self)
|
|
else
|
|
moving = true
|
|
anchorFrame:Show()
|
|
self:AddSpecialWarning(L.MOVE_SPECIAL_WARNING_TEXT)
|
|
self:AddSpecialWarning(L.MOVE_SPECIAL_WARNING_TEXT)
|
|
self:Schedule(15, moveEnd, self)
|
|
DBT:CreateBar(15, L.MOVE_SPECIAL_WARNING_BAR, private.isRetail and 237538 or 136106)
|
|
frame:Show()
|
|
frame:SetFrameStrata("TOOLTIP")
|
|
frame:SetAlpha(1)
|
|
end
|
|
end
|
|
|
|
---@class SpecialWarning
|
|
local specialWarningPrototype = private:GetPrototype("SpecialWarning")
|
|
local mt = {__index = specialWarningPrototype}
|
|
|
|
local function classColoringFunction(cap)
|
|
cap = cap:sub(2, -2)
|
|
local noStrip = cap:match("noStrip ")
|
|
if not noStrip then
|
|
local name = cap
|
|
local playerClass, playerIcon = DBM:GetRaidClass(name)
|
|
if playerClass ~= "UNKNOWN" then
|
|
cap = DBM:GetShortServerName(cap)--Only run strip code on valid player classes
|
|
if DBM.Options.SWarnClassColor then
|
|
local playerColor = RAID_CLASS_COLORS[playerClass]
|
|
if playerColor then
|
|
if playerIcon > 0 and playerIcon <= 8 then
|
|
cap = ("|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_%d:0|t"):format(playerIcon) .. ("|r|cff%.2x%.2x%.2x%s|r|cff%.2x%.2x%.2x"):format(playerColor.r * 255, playerColor.g * 255, playerColor.b * 255, cap, DBM.Options.SpecialWarningFontCol[1] * 255, DBM.Options.SpecialWarningFontCol[2] * 255, DBM.Options.SpecialWarningFontCol[3] * 255)
|
|
else
|
|
cap = ("|r|cff%.2x%.2x%.2x%s|r|cff%.2x%.2x%.2x"):format(playerColor.r * 255, playerColor.g * 255, playerColor.b * 255, cap, DBM.Options.SpecialWarningFontCol[1] * 255, DBM.Options.SpecialWarningFontCol[2] * 255, DBM.Options.SpecialWarningFontCol[3] * 255)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
cap = cap:sub(9)
|
|
end
|
|
return cap
|
|
end
|
|
|
|
local textureCode = " |T%s:12:12|t "
|
|
|
|
local specInstructionalRemapTable = {
|
|
["dispel"] = "target",
|
|
["interrupt"] = "spell",
|
|
["interruptcount"] = "count",
|
|
["defensive"] = "spell",
|
|
["taunt"] = "target",
|
|
["soak"] = "spell",
|
|
["soakcount"] = "count",
|
|
["soakpos"] = "spell",
|
|
["switch"] = "spell",
|
|
["switchcustom"] = "spell",
|
|
["switchcount"] = "count",
|
|
-- ["adds"] = "spell",
|
|
-- ["addscount"] = "spell",
|
|
-- ["addscustom"] = "spell",
|
|
["targetchange"] = "target",
|
|
["gtfo"] = "spell",
|
|
["bait"] = "soon",
|
|
["youpos"] = "you",
|
|
["youposcount"] = "youcount",
|
|
["move"] = "spell",
|
|
["keepmove"] = "spell",
|
|
["stopmove"] = "spell",
|
|
["dodge"] = "spell",
|
|
["dodgecount"] = "count",
|
|
["dodgeloc"] = "spell",
|
|
["moveaway"] = "spell",
|
|
["moveawaycount"] = "count",
|
|
["moveawaytarget"] = "spell",
|
|
["moveto"] = "spell",
|
|
["jump"] = "spell",
|
|
["run"] = "spell",
|
|
["runcount"] = "spell",
|
|
["cast"] = "spell",
|
|
["lookaway"] = "spell",
|
|
["reflect"] = "target",
|
|
}
|
|
|
|
local function setText(announceType, spellId, stacks, customName)
|
|
local text, spellName
|
|
if customName then
|
|
spellName = customName
|
|
else
|
|
spellName = DBM:ParseSpellName(spellId, announceType) or CL.UNKNOWN
|
|
end
|
|
if announceType == "prewarn" then
|
|
if type(stacks) == "string" then
|
|
text = L.AUTO_SPEC_WARN_TEXTS[announceType]:format(spellName, stacks)
|
|
else
|
|
text = L.AUTO_SPEC_WARN_TEXTS[announceType]:format(spellName, L.SEC_FMT:format(tostring(stacks or 5)))
|
|
end
|
|
else
|
|
if DBM.Options.SpamSpecInformationalOnly then
|
|
local remapType = specInstructionalRemapTable[announceType]
|
|
if remapType then
|
|
local newType = remapType
|
|
text = L.AUTO_SPEC_WARN_TEXTS[newType]:format(spellName)
|
|
else
|
|
text = L.AUTO_SPEC_WARN_TEXTS[announceType]:format(spellName)
|
|
end
|
|
else
|
|
text = L.AUTO_SPEC_WARN_TEXTS[announceType]:format(spellName)
|
|
end
|
|
end
|
|
return text, spellName
|
|
end
|
|
|
|
function specialWarningPrototype:SetText(customName)
|
|
local text, spellName = setText(self.announceType, self.spellId, self.stacks, customName)
|
|
self.text = text
|
|
self.spellName = spellName
|
|
end
|
|
|
|
---Not to be confused with SetText, which only sets the text of object.
|
|
---<br>This changes actual ID so announce callback also swaps ID for WAs
|
|
---@param altSpellId string|number
|
|
function specialWarningPrototype:UpdateKey(altSpellId)
|
|
self.spellId = altSpellId
|
|
self.icon = DBM:ParseSpellIcon(altSpellId, self.announceType, self.icon)
|
|
if self.announceType then
|
|
--Regenerate auto localized text if it's an auto localized alert
|
|
local text, spellName = setText(self.announceType, self.spellId, self.stacks)
|
|
self.text = text
|
|
self.spellName = spellName
|
|
else--Just regenerating spellName not message text because it's likely a custom text object such as NewSpecialWarning
|
|
self.spellName = DBM:ParseSpellName(altSpellId)
|
|
end
|
|
end
|
|
|
|
---@param self SpecialWarning
|
|
---@param soundId number?
|
|
---@return boolean
|
|
local function canVoiceReplace(self, soundId)
|
|
if private.voiceSessionDisabled or DBM.Options.ChosenVoicePack2 == "None" then
|
|
return false
|
|
end
|
|
soundId = soundId or self.option and self.mod.Options[self.option .. "SWSound"] or self.flash
|
|
local isVoicePackUsed
|
|
if self.announceType == "gtfo" then
|
|
isVoicePackUsed = DBM.Options.VPReplacesGTFO
|
|
elseif type(soundId) == "number" and soundId < 5 then--Value 1-4 are SW1 defaults, otherwise it's file data ID and handled by Custom
|
|
isVoicePackUsed = DBM.Options["VPReplacesSA" .. soundId]
|
|
else
|
|
isVoicePackUsed = DBM.Options.VPReplacesCustom
|
|
end
|
|
return isVoicePackUsed
|
|
end
|
|
|
|
local specTypeFilterTable = {
|
|
["dispel"] = "dispel",
|
|
["interrupt"] = "interrupt",
|
|
["interruptcount"] = "interrupt",
|
|
["defensive"] = "defensive",
|
|
["taunt"] = "taunt",
|
|
["soak"] = "soak",
|
|
["soakcount"] = "soak",
|
|
["soakpos"] = "soak",
|
|
["stack"] = "stack",
|
|
["switch"] = "switch",
|
|
["switchcount"] = "switch",
|
|
["switchcustom"] = "switch",
|
|
["adds"] = "switch",
|
|
["addscount"] = "switch",
|
|
["addscustom"] = "switch",
|
|
["targetchange"] = "switch",
|
|
["gtfo"] = "gtfo",
|
|
}
|
|
|
|
---@class SpecAnnounce0: SpecialWarning
|
|
---@field Show fun(self: SpecAnnounce0)
|
|
---@class SpecAnnounce1num: SpecialWarning
|
|
---@field Show fun(self: SpecAnnounce1num, arg1: number)
|
|
---@class SpecAnnounce1str: SpecialWarning
|
|
---@field Show fun(self: SpecAnnounce1str, arg1: string)
|
|
---@class SpecAnnounce1Annoying: SpecialWarning
|
|
---@field Show fun(self: SpecAnnounce1Annoying, arg1: string|unknown|nil)
|
|
---@class SpecAnnounce2strnum: SpecialWarning
|
|
---@field Show fun(self: SpecAnnounce2strnum, arg1: string, arg2: number)
|
|
---@class SpecAnnounce2numstr: SpecialWarning
|
|
---@field Show fun(self: SpecAnnounce2numstr, arg1: number, arg2: string)
|
|
|
|
function specialWarningPrototype:Show(...)
|
|
--Check if option for this warning is even enabled
|
|
if (not self.option or self.mod.Options[self.option]) and not moving and frame then
|
|
--Now, check if all special warning filters are enabled to save cpu and abort immediately if true.
|
|
if DBM.Options.DontPlaySpecialWarningSound and DBM.Options.DontShowSpecialWarningFlash and DBM.Options.DontShowSpecialWarningText then return end
|
|
--Next, we check if trash mod warning and if so check the filter trash warning filter for trivial difficulties
|
|
if self.mod.isTrashMod and DBM.Options.FilterTrashWarnings2 and (self.mod:IsEasyDungeon() or DBM:IsTrivial()) then return end
|
|
--We also check if person has the role filter turned on (typical for highest end raiders who don't want as much handholding from DBM)
|
|
local filterType = specTypeFilterTable[self.announceType]
|
|
if filterType then
|
|
if DBM.Options["SpamSpecRole" .. filterType] then return end
|
|
end
|
|
--Lastly, we check if it's a tank warning and filter if not in tank spec. This is done because tank warnings on by default and handled fluidly by spec, not option setting
|
|
if self.announceType == "taunt" and DBM.Options.FilterTankSpec and not self.mod:IsTank() then return end--Don't tell non tanks to taunt, ever.
|
|
local argTable = {...}
|
|
-- add a default parameter for move away warnings
|
|
if self.announceType == "gtfo" then
|
|
if DBM:UnitBuff("player", 27827) then return end--Don't tell a priest in spirit of redemption form to GTFO, they can't, and they don't take damage from it anyhow
|
|
if #argTable == 0 then
|
|
argTable[1] = L.BAD
|
|
end
|
|
end
|
|
if #self.combinedtext > 0 then
|
|
--Throttle spam.
|
|
if DBM.Options.SWarningAlphabetical then
|
|
table.sort(self.combinedtext)
|
|
end
|
|
local combinedText = table.concat(self.combinedtext, "<, >")
|
|
if self.combinedcount == 1 then
|
|
combinedText = combinedText .. " " .. L.GENERIC_WARNING_OTHERS
|
|
elseif self.combinedcount > 1 then
|
|
combinedText = combinedText .. " " .. L.GENERIC_WARNING_OTHERS2:format(self.combinedcount)
|
|
end
|
|
--Process
|
|
for i = 1, #argTable do
|
|
if type(argTable[i]) == "string" then
|
|
argTable[i] = combinedText
|
|
end
|
|
end
|
|
end
|
|
--Grab count for both the callback and the notes feature
|
|
local announceCount
|
|
if self.announceType and self.announceType:find("count") then
|
|
if self.announceType == "interruptcount" then
|
|
announceCount = argTable[2]--Count should be second arg in table
|
|
else
|
|
announceCount = argTable[1]--Count should be first arg in table
|
|
end
|
|
if type(announceCount) == "string" then
|
|
--Probably a hypehnated double count like inferno slice or marked for death
|
|
--This is pretty atypical in newer content cause it's a bit hacky
|
|
local mainCount = string.split("-", announceCount)
|
|
announceCount = tonumber(mainCount)
|
|
end
|
|
end
|
|
local message = stringUtils.pformat(self.text, unpack(argTable))
|
|
local text = ("%s%s%s"):format(
|
|
(DBM.Options.SpecialWarningIcon and self.icon and textureCode:format(self.icon)) or "",
|
|
message,
|
|
(DBM.Options.SpecialWarningIcon and self.icon and textureCode:format(self.icon)) or ""
|
|
)
|
|
local noteHasName = nil
|
|
if self.option then
|
|
local noteText = self.mod.Options[self.option .. "SWNote"]
|
|
if noteText and type(noteText) == "string" and noteText ~= "" then--Filter false bool and empty strings
|
|
if announceCount then--Counts support different note for EACH count
|
|
local notesTable = {string.split("/", noteText)}
|
|
noteText = notesTable[announceCount]
|
|
if noteText and type(noteText) == "string" and noteText ~= "" then--Refilter after string split to make sure a note for this count exists
|
|
local hasPlayerName = noteText:find(playerName)
|
|
if DBM.Options.SWarnNameInNote and hasPlayerName then
|
|
noteHasName = 5
|
|
end
|
|
--Terminate special warning, it's an interrupt count warning without player name and filter enabled
|
|
if (self.announceType == "interruptcount") and DBM.Options.FilterInterruptNoteName and not hasPlayerName then return end
|
|
noteText = " (" .. noteText .. ")"
|
|
text = text .. noteText
|
|
end
|
|
else--Non count warnings will have one note, period
|
|
if DBM.Options.SWarnNameInNote and noteText:find(playerName) then
|
|
noteHasName = 5
|
|
end
|
|
if self.announceType and not self.announceType:find("switch") then
|
|
noteText = noteText:gsub(">.-<", classColoringFunction)--Class color note text before combining with warning text.
|
|
end
|
|
noteText = " (" .. noteText .. ")"
|
|
text = text .. noteText
|
|
end
|
|
end
|
|
end
|
|
--Text is disabled, suresss text from screen and chat frame
|
|
if not DBM.Options.DontShowSpecialWarningText then
|
|
--No stripping on switch warnings, ever. They will NEVER have player name, but often have adds with "-" in name
|
|
if self.announceType and not self.announceType:find("switch") then
|
|
text = text:gsub(">.-<", classColoringFunction)
|
|
end
|
|
DBM:AddSpecialWarning(text, nil, self)
|
|
if DBM.Options.ShowSWarningsInChat then
|
|
local colorCode = ("|cff%.2x%.2x%.2x"):format(DBM.Options.SpecialWarningFontCol[1] * 255, DBM.Options.SpecialWarningFontCol[2] * 255, DBM.Options.SpecialWarningFontCol[3] * 255)
|
|
self.mod:AddMsg(colorCode .. "[" .. L.MOVE_SPECIAL_WARNING_TEXT .. "] " .. text .. "|r", nil)
|
|
end
|
|
end
|
|
self.combinedcount = 0
|
|
self.combinedtext = {}
|
|
if not UnitIsDeadOrGhost("player") then
|
|
if noteHasName then
|
|
if not DBM.Options.DontShowSpecialWarningFlash and DBM.Options.SpecialWarningFlash5 then--Not included in above if statement on purpose. we don't want to trigger else rule if noteHasName is true but SpecialWarningFlash5 is false
|
|
local repeatCount = DBM.Options.SpecialWarningFlashCount5 or 1
|
|
DBM.Flash:Show(DBM.Options.SpecialWarningFlashCol5[1], DBM.Options.SpecialWarningFlashCol5[2], DBM.Options.SpecialWarningFlashCol5[3], DBM.Options.SpecialWarningFlashDura5, DBM.Options.SpecialWarningFlashAlph5, repeatCount - 1)
|
|
end
|
|
if not DBM.Options.DontDoSpecialWarningVibrate and DBM.Options.SpecialWarningVibrate5 then
|
|
DBM:VibrateController()
|
|
end
|
|
else
|
|
local number = self.flash
|
|
if not DBM.Options.DontShowSpecialWarningFlash and DBM.Options["SpecialWarningFlash" .. number] then
|
|
local repeatCount = DBM.Options["SpecialWarningFlashCount" .. number] or 1
|
|
local flashcolor = DBM.Options["SpecialWarningFlashCol" .. number]
|
|
DBM.Flash:Show(flashcolor[1], flashcolor[2], flashcolor[3], DBM.Options["SpecialWarningFlashDura" .. number], DBM.Options["SpecialWarningFlashAlph" .. number], repeatCount - 1)
|
|
end
|
|
if not DBM.Options.DontDoSpecialWarningVibrate and DBM.Options["SpecialWarningVibrate" .. number] then
|
|
DBM:VibrateController()
|
|
end
|
|
end
|
|
end
|
|
--Text: Full message text
|
|
--Icon: Texture path/id for icon
|
|
--Type: Announce type
|
|
----Types: spell, ends, fades, soon, bait, dispel, interrupt, interruptcount, you, youcount, youpos, soakpos, target, targetcount, defensive, taunt, close, move, keepmove, stopmove,
|
|
----gtfo, dodge, dodgecount, dodgeloc, moveaway, moveawaycount, moveto, soak, jump, run, cast, lookaway, reflect, count, sooncount, stack, switch, switchcount, adds, addscount, addscustom, targetchange, prewarn
|
|
------General Target Messages (but since it's a special warning, it applies to you in some way): target, targetcount
|
|
------Fight Changes (Stages, adds, boss buff/debuff, etc): adds, addscount, addscustom, targetchange, switch, switchcount, ends
|
|
------General (can really apply to anything): spell, count, soon, sooncount, prewarn
|
|
------Personal/Role (Applies to you, or your job): Everything Else
|
|
--SpellId: Raw spell or encounter journal Id if available.
|
|
--Mod ID: Encounter ID as string, or a generic string for mods that don't have encounter ID (such as trash, dummy/test mods)
|
|
--boolean: Whether or not this warning is a special warning (higher priority). BW would call this "emphasized"
|
|
--announceCount: If it's a count announce, this will provide access to the number value of that count. This, along with spellId should be used instead of message text scanning for most weak auras that need to target specific count casts
|
|
DBM:FireEvent("DBM_Announce", text, self.icon, self.type, self.spellId, self.mod.id, true, announceCount)
|
|
if self.sound and not DBM.Options.DontPlaySpecialWarningSound and (not self.option or self.mod.Options[self.option .. "SWSound"] ~= "None") then
|
|
local soundId = self.option and self.mod.Options[self.option .. "SWSound"] or self.flash
|
|
if noteHasName and type(soundId) == "number" then soundId = noteHasName end--Change number to 5 if it's not a custom sound, else, do nothing with it
|
|
if self.hasVoice and not DBM.Options.VPDontMuteSounds and canVoiceReplace(self, soundId) and self.hasVoice <= private.swFilterDisabled then return end
|
|
DBM:PlaySpecialWarningSound(soundId or 1)
|
|
end
|
|
else
|
|
self.combinedcount = 0
|
|
self.combinedtext = {}
|
|
end
|
|
end
|
|
|
|
---Object that's used when precision isn't possible (number of targets variable or unknown
|
|
---@param delay number
|
|
---@param ... any
|
|
function specialWarningPrototype:CombinedShow(delay, ...)
|
|
--Check if option for this warning is even enabled
|
|
if self.option and not self.mod.Options[self.option] then return end
|
|
--Now, check if all special warning filters are enabled to save cpu and abort immediately if true.
|
|
if DBM.Options.DontPlaySpecialWarningSound and DBM.Options.DontShowSpecialWarningFlash and DBM.Options.DontShowSpecialWarningText then return end
|
|
--Next, we check if trash mod warning and if so check the filter trash warning filter for trivial difficulties
|
|
if self.mod:IsEasyDungeon() and self.mod.isTrashMod and DBM.Options.FilterTrashWarnings2 then return end
|
|
local argTable = {...}
|
|
for i = 1, #argTable do
|
|
if type(argTable[i]) == "string" then
|
|
if #self.combinedtext < 6 then--Throttle spam. We may not need more than 5 targets..
|
|
if not checkEntry(self.combinedtext, argTable[i]) then
|
|
self.combinedtext[#self.combinedtext + 1] = argTable[i]
|
|
end
|
|
else
|
|
self.combinedcount = self.combinedcount + 1
|
|
end
|
|
end
|
|
end
|
|
DBMScheduler:Unschedule(self.Show, self.mod, self)
|
|
local id = DBMScheduler:Schedule(delay or 0.5, self.Show, self.mod, self, ...)
|
|
test:Trace(self.mod, "SchedulerHideFromTraceIfUnscheduled", id)
|
|
test:Trace(self.mod, "SetScheduleMethodName", id, self, "CombinedShow", ...)
|
|
end
|
|
|
|
---New object that allows defining count instead of scheduling for more efficient and immediate warnings when precise count is known
|
|
---@param maxTotal number
|
|
---@param ... any
|
|
function specialWarningPrototype:PreciseShow(maxTotal, ...)
|
|
test:Trace(self.mod, "CombinedWarningPreciseShow", self, maxTotal)
|
|
--Check if option for this warning is even enabled
|
|
if self.option and not self.mod.Options[self.option] then return end
|
|
--Now, check if all special warning filters are enabled to save cpu and abort immediately if true.
|
|
if DBM.Options.DontPlaySpecialWarningSound and DBM.Options.DontShowSpecialWarningFlash and DBM.Options.DontShowSpecialWarningText then return end
|
|
--Next, we check if trash mod warning and if so check the filter trash warning filter for trivial difficulties
|
|
if self.mod:IsEasyDungeon() and self.mod.isTrashMod and DBM.Options.FilterTrashWarnings2 then return end
|
|
local argTable = {...}
|
|
for i = 1, #argTable do
|
|
if type(argTable[i]) == "string" then
|
|
if #self.combinedtext < 6 then--Throttle spam. We may not need more than 5 targets..
|
|
if not checkEntry(self.combinedtext, argTable[i]) then
|
|
self.combinedtext[#self.combinedtext + 1] = argTable[i]
|
|
end
|
|
else
|
|
self.combinedcount = self.combinedcount + 1
|
|
end
|
|
end
|
|
end
|
|
DBMScheduler:Unschedule(self.Show, self.mod, self)
|
|
local viableTotal = DBM:NumRealAlivePlayers()
|
|
if (maxTotal == #self.combinedtext) or (viableTotal == #self.combinedtext) then--All targets gathered, show immediately
|
|
self:Show(...)--Does this need self or mod? will it have this bug? https://github.com/DeadlyBossMods/DBM-Unified/issues/153
|
|
test:Trace(self.mod, "CombinedWarningPreciseShowSuccess", self, maxTotal)
|
|
else--And even still, use scheduling backup in case counts still fail
|
|
local id = DBMScheduler:Schedule(1.2, self.Show, self.mod, self, ...)
|
|
test:Trace(self.mod, "SchedulerHideFromTraceIfUnscheduled", id)
|
|
test:Trace(self.mod, "SetScheduleMethodName", id, self, "PreciseShow", maxTotal, ...)
|
|
end
|
|
end
|
|
|
|
---Used as a lazy antispam. Does NOT combine. Use CombinedShow for that
|
|
---@param delay number?
|
|
---@param ... any
|
|
function specialWarningPrototype:DelayedShow(delay, ...)
|
|
DBMScheduler:Unschedule(self.Show, self.mod, self, ...)
|
|
local id = DBMScheduler:Schedule(delay or 0.5, self.Show, self.mod, self, ...)
|
|
test:Trace(self.mod, "SchedulerHideFromTraceIfUnscheduled", id)
|
|
test:Trace(self.mod, "SetScheduleMethodName", id, self, "DelayedShow", ...)
|
|
end
|
|
|
|
---@param t number
|
|
---@param ... any
|
|
function specialWarningPrototype:Schedule(t, ...)
|
|
local id = DBMScheduler:Schedule(t, self.Show, self.mod, self, ...)
|
|
test:Trace(self.mod, "SetScheduleMethodName", id, self, "Schedule", ...)
|
|
return id
|
|
end
|
|
|
|
---@param time number
|
|
---@param numAnnounces number?
|
|
---@param ... any
|
|
function specialWarningPrototype:Countdown(time, numAnnounces, ...)
|
|
DBMScheduler:ScheduleCountdown(time, numAnnounces, self.Show, self.mod, self, ...)
|
|
end
|
|
|
|
function specialWarningPrototype:Cancel(_, ...) -- t, ...
|
|
return DBMScheduler:Unschedule(self.Show, self.mod, self, ...)
|
|
end
|
|
|
|
--Several voice lines still need generic alternatives that don't feel "instructional"
|
|
local specInstructionalRemapVoiceTable = {
|
|
-- ["dispel"] = "target",
|
|
-- ["interrupt"] = "spell",
|
|
-- ["interruptcount"] = "count",
|
|
-- ["defensive"] = "spell",
|
|
["taunt"] = "changemt",--Remaps sound to say a swap is happening, rather than telling you to taunt boss
|
|
-- ["soak"] = "spell",
|
|
-- ["soakcount"] = "count",
|
|
-- ["soakpos"] = "spell",
|
|
-- ["switch"] = "spell",
|
|
-- ["switchcount"] = "count",
|
|
["adds"] = "mobsoon",--Remaps sound to say mobs incoming only, not to kill them or cc them or anything else.
|
|
["addscount"] = "mobsoon",
|
|
["addscustom"] = "mobsoon",--Remaps sound to say mobs incoming only, not to kill them or cc them or anything else.
|
|
-- ["targetchange"] = "target",
|
|
-- ["gtfo"] = "spell",
|
|
-- ["bait"] = "soon",
|
|
["you"] = "targetyou",--Remaps personal alert to just say "target you", without instruction
|
|
["youpos"] = "targetyou",--Remaps personal alert to just say "target you", without instruction
|
|
["youposcount"] = "targetyou",--Remaps personal alert to just say "target you", without instruction
|
|
-- ["move"] = "spell",
|
|
-- ["keepmove"] = "spell",
|
|
-- ["stopmove"] = "spell",
|
|
-- ["dodge"] = "spell",
|
|
-- ["dodgecount"] = "count",
|
|
-- ["dodgeloc"] = "spell",
|
|
["moveaway"] = "targetyou",--Remaps personal alert to just say "target you", without instruction
|
|
["moveawaycount"] = "targetyou",--Remaps personal alert to just say "target you", without instruction
|
|
-- ["moveto"] = "spell",
|
|
-- ["jump"] = "spell",
|
|
-- ["run"] = "spell",
|
|
-- ["runcount"] = "spell",
|
|
-- ["cast"] = "spell",
|
|
-- ["lookaway"] = "spell",
|
|
-- ["reflect"] = "target",
|
|
}
|
|
|
|
---@param name VPSound?
|
|
---@param customPath? string|number
|
|
function specialWarningPrototype:Play(name, customPath)
|
|
local always = DBM.Options.AlwaysPlayVoice
|
|
local voice = DBM.Options.ChosenVoicePack2
|
|
local soundId = self.option and self.mod.Options[self.option .. "SWSound"] or self.flash
|
|
if not canVoiceReplace(self, soundId) then return end
|
|
if self.mod:IsEasyDungeon() and self.mod.isTrashMod and DBM.Options.FilterTrashWarnings2 then return end
|
|
local filterType = specTypeFilterTable[self.announceType]
|
|
if filterType then
|
|
--Filtered warning, filtered voice
|
|
if DBM.Options["SpamSpecRole" .. filterType] then return end
|
|
elseif DBM.Options.SpamSpecInformationalOnly then
|
|
local remapType = specInstructionalRemapVoiceTable[self.announceType]
|
|
if remapType then
|
|
--Instructional disabled, remap to a less instructional voice line
|
|
name = remapType
|
|
end
|
|
end
|
|
if ((not self.option or self.mod.Options[self.option]) or always) and self.hasVoice <= private.swFilterDisabled then
|
|
--Filter tank specific voice alerts for non tanks if tank filter enabled
|
|
--But still allow AlwaysPlayVoice to play as well.
|
|
if (name == "changemt" or name == "tauntboss") and DBM.Options.FilterTankSpec and not self.mod:IsTank() and not always then return end
|
|
--Mute VP if SW sound is set to None in the boss mod.
|
|
if soundId == "None" then return end
|
|
local path = customPath or ("Interface\\AddOns\\DBM-VP" .. voice .. "\\" .. name .. ".ogg")
|
|
DBM:PlaySoundFile(path)
|
|
end
|
|
end
|
|
|
|
---@param t number
|
|
---@param name VPSound?
|
|
---@param customPath? string|number
|
|
function specialWarningPrototype:ScheduleVoice(t, name, customPath)
|
|
if not canVoiceReplace(self) then return end
|
|
DBMScheduler:Unschedule(self.Play, self.mod, self)--Allow ScheduleVoice to be used in same way as CombinedShow
|
|
local id = DBMScheduler:Schedule(t, self.Play, self.mod, self, name, customPath)
|
|
test:Trace(self.mod, "SetScheduleMethodName", id, self, "ScheduleVoice", name, customPath)
|
|
return id
|
|
end
|
|
|
|
---Object Permits scheduling voice multiple times for same object
|
|
---@param t number
|
|
---@param name VPSound?
|
|
---@param customPath? string|number
|
|
function specialWarningPrototype:ScheduleVoiceOverLap(t, name, customPath)
|
|
if not canVoiceReplace(self) then return end
|
|
local id = DBMScheduler:Schedule(t, self.Play, self.mod, self, name, customPath)
|
|
test:Trace(self.mod, "SetScheduleMethodName", id, self, "ScheduleVoiceOverLap", name, customPath)
|
|
return id
|
|
end
|
|
|
|
function specialWarningPrototype:CancelVoice(...)
|
|
if not canVoiceReplace(self) then return end
|
|
return DBMScheduler:Unschedule(self.Play, self.mod, self, ...)
|
|
end
|
|
|
|
---old constructor (no auto-localize)
|
|
---@param text string
|
|
---@param optionDefault SpecFlags|boolean?
|
|
---@param optionName string|boolean? String for custom option name. Using false hides option completely
|
|
---@param optionVersion any optional: has to be number, but luaLS has a fit if we tell it that
|
|
---@param runSound number? 1 = Personal, 2 = Everyone, 3 = Very Important, 4 = Run Away
|
|
---@param hasVoice boolean|number? Voice pack version required for used sound file.
|
|
---@param difficulty number? Raid Difficulty index used for displaying difficulty icon next to option
|
|
---@param icon number|string? Use number for spellId, -number for journalID, number as string for textureID
|
|
---@param spellID string|number? Used to define a spellID used for GroupSpells and WeakAura key
|
|
---@param waCustomName any? Used to show custom name/text for Spell header (usually used when a made up SpellID is used)
|
|
function bossModPrototype:NewSpecialWarning(text, optionDefault, optionName, optionVersion, runSound, hasVoice, difficulty, icon, spellID, waCustomName)
|
|
if not text then
|
|
error("NewSpecialWarning: you must provide special warning text", 2)
|
|
end
|
|
if type(text) == "string" and text:match("OptionVersion") then
|
|
error("NewSpecialWarning: you must provide remove optionversion hack for " .. optionDefault)
|
|
end
|
|
runSound = runSound or 1
|
|
if hasVoice == true then--if not a number, set it to 2, old mods that don't use new numbered system
|
|
hasVoice = 2
|
|
end
|
|
icon = DBM:ParseSpellIcon(icon)
|
|
---@class SpecialWarning
|
|
local obj = setmetatable(
|
|
{
|
|
objClass = "SpecialWarning",
|
|
text = self.localization.warnings[text],
|
|
combinedtext = {},
|
|
combinedcount = 0,
|
|
mod = self,
|
|
sound = runSound > 0,
|
|
flash = runSound,--Set flash color to hard coded runsound (even if user sets custom sounds)
|
|
hasVoice = hasVoice,
|
|
difficulty = difficulty,
|
|
spellId = spellID,--For WeakAuras / other callbacks
|
|
icon = icon,
|
|
},
|
|
mt
|
|
)
|
|
test:Trace(self, "NewSpecialWarning", obj, "untyped")
|
|
local optionId = optionName or optionName ~= false and text
|
|
if optionId then
|
|
obj.voiceOptionId = hasVoice and "Voice" .. optionId or nil
|
|
obj.option = optionId .. (optionVersion or "")
|
|
self:AddSpecialWarningOption(obj.option, optionDefault, runSound, "announce", spellID, nil, waCustomName)
|
|
end
|
|
tinsert(self.specwarns, obj)
|
|
return obj
|
|
end
|
|
|
|
---@return SpecialWarning|SpecAnnounce0
|
|
local function newSpecialWarning(self, announceType, spellId, stacks, optionDefault, optionName, optionVersion, runSound, hasVoice, difficulty)
|
|
if not spellId then
|
|
error("newSpecialWarning: you must provide spellId", 2)
|
|
end
|
|
if runSound == true then
|
|
runSound = 2
|
|
elseif not runSound then
|
|
runSound = 1
|
|
end
|
|
if hasVoice == true then--if not a number, set it to 2, old mods that don't use new numbered system
|
|
hasVoice = 2
|
|
end
|
|
local alternateSpellId
|
|
if type(optionName) == "number" then
|
|
if DBM.Options.SpecialWarningShortText then
|
|
alternateSpellId = optionName
|
|
end
|
|
optionName = nil
|
|
end
|
|
local text, spellName = setText(announceType, alternateSpellId or spellId, stacks)
|
|
local icon = DBM:ParseSpellIcon(spellId)
|
|
---@class SpecialWarning
|
|
local obj = setmetatable( -- todo: fix duplicate code
|
|
{
|
|
objClass = "SpecialWarning",
|
|
text = text,
|
|
combinedtext = {},
|
|
combinedcount = 0,
|
|
announceType = announceType,
|
|
mod = self,
|
|
sound = runSound > 0,
|
|
flash = runSound,--Set flash color to hard coded runsound (even if user sets custom sounds)
|
|
hasVoice = hasVoice,
|
|
difficulty = difficulty,
|
|
type = announceType,
|
|
spellId = spellId,
|
|
spellName = spellName,
|
|
stacks = stacks,
|
|
icon = icon,
|
|
},
|
|
mt
|
|
)
|
|
test:Trace(self, "NewSpecialWarning", obj, announceType)
|
|
if optionName then
|
|
obj.option = optionName
|
|
elseif optionName ~= false then
|
|
local difficultyIcon = ""
|
|
if difficulty then
|
|
--1 LFR, 2 Normal, 3 Heroic, 4 Mythic
|
|
--Likely 1 and 2 will never be used, but being prototyped just in case
|
|
local path = private.isRetail and "EncounterJournal" or "AddOns\\DBM-Core\\textures"
|
|
if difficulty == 3 then
|
|
difficultyIcon = "|TInterface\\" .. path .. "\\UI-EJ-Icons.blp:18:18:0:0:255:66:102:118:7:27|t"
|
|
elseif difficulty == 4 then
|
|
difficultyIcon = "|TInterface\\" .. path .. "\\UI-EJ-Icons.blp:18:18:0:0:255:66:133:153:40:58|t"
|
|
end
|
|
end
|
|
obj.option = "SpecWarn" .. spellId .. announceType .. (optionVersion or "")
|
|
if announceType == "stack" then
|
|
self.localization.options[obj.option] = difficultyIcon .. L.AUTO_SPEC_WARN_OPTIONS[announceType]:format(stacks or 3, spellId)
|
|
elseif announceType == "prewarn" then
|
|
self.localization.options[obj.option] = difficultyIcon .. L.AUTO_SPEC_WARN_OPTIONS[announceType]:format(tostring(stacks or 5), spellId)
|
|
else
|
|
self.localization.options[obj.option] = difficultyIcon .. L.AUTO_SPEC_WARN_OPTIONS[announceType]:format(spellId)
|
|
end
|
|
end
|
|
if obj.option then
|
|
self:AddSpecialWarningOption(obj.option, optionDefault, runSound, "announce", spellId, announceType)
|
|
end
|
|
obj.voiceOptionId = hasVoice and "Voice" .. spellId or nil
|
|
tinsert(self.specwarns, obj)
|
|
return obj
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningSpell(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "spell", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningEnd(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "ends", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningFades(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "fades", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningSoon(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "soon", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningBait(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "bait", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningDispel(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "dispel", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningInterrupt(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "interrupt", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce2strnum
|
|
function bossModPrototype:NewSpecialWarningInterruptCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce2strnum
|
|
return newSpecialWarning(self, "interruptcount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningYou(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "you", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningYouCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "youcount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningYouPos(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "youpos", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce2numstr
|
|
function bossModPrototype:NewSpecialWarningYouPosCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce2numstr
|
|
return newSpecialWarning(self, "youposcount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningSoakPos(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "soakpos", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningTarget(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "target", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce2numstr
|
|
function bossModPrototype:NewSpecialWarningTargetCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce2numstr
|
|
return newSpecialWarning(self, "targetcount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningDefensive(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "defensive", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningTaunt(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "taunt", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningClose(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "close", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningMove(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "move", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningKeepMove(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "keepmove", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningStopMove(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "stopmove", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecialWarning
|
|
function bossModPrototype:NewSpecialWarningGTFO(spellId, optionDefault, ...)
|
|
return newSpecialWarning(self, "gtfo", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningDodge(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "dodge", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningDodgeCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "dodgecount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningDodgeLoc(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "dodgeloc", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningMoveAway(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "moveaway", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningMoveAwayCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "moveawaycount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningMoveAwayTarget(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "moveawaytarget", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1Annoying
|
|
function bossModPrototype:NewSpecialWarningMoveTo(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1Annoying
|
|
return newSpecialWarning(self, "moveto", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningSoak(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "soak", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningSoakCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "soakcount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningJump(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "jump", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningRun(spellId, optionDefault, optionName, optionVersion, runSound, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "run", spellId, nil, optionDefault, optionName, optionVersion, runSound or 4, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningRunCount(spellId, optionDefault, optionName, optionVersion, runSound, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "runcount", spellId, nil, optionDefault, optionName, optionVersion, runSound or 4, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningCast(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "cast", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningLookAway(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "lookaway", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningReflect(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "reflect", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "count", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningSoonCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "sooncount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, stacks: number, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningStack(spellId, optionDefault, stacks, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "stack", spellId, stacks, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningSwitch(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "switch", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningSwitchCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "switchcount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningSwitchCustom(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "switchcustom", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningAdds(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "adds", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1num
|
|
function bossModPrototype:NewSpecialWarningAddsCount(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1num
|
|
return newSpecialWarning(self, "addscount", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningAddsCustom(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "addscustom", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce1str
|
|
function bossModPrototype:NewSpecialWarningTargetChange(spellId, optionDefault, ...)
|
|
---@type SpecAnnounce1str
|
|
return newSpecialWarning(self, "targetchange", spellId, nil, optionDefault, ...)
|
|
end
|
|
|
|
---@overload fun(self: DBMMod, spellId: number|string, optionDefault: SpecFlags|boolean?, time: number, optionName: number|string|boolean?, optionVersion: number?, runSound: number|boolean?, hasVoice: number?, difficulty: number?): SpecAnnounce0
|
|
function bossModPrototype:NewSpecialWarningPreWarn(spellId, optionDefault, time, ...)
|
|
---@type SpecAnnounce0
|
|
return newSpecialWarning(self, "prewarn", spellId, time, optionDefault, ...)
|
|
end
|
|
|
|
---@param number number
|
|
---@param forceVoice string?
|
|
---@param forcePath string?
|
|
function DBM:PlayCountSound(number, forceVoice, forcePath)
|
|
if number > 10 then return end
|
|
local voice
|
|
if forceVoice then--For options example
|
|
voice = forceVoice
|
|
else
|
|
voice = self.Options.CountdownVoice
|
|
end
|
|
local path
|
|
local maxCount = 5
|
|
if forcePath then
|
|
path = forcePath
|
|
else
|
|
for _, count in pairs(DBM:GetCountSounds()) do
|
|
if count.value == voice then
|
|
path = count.path
|
|
maxCount = count.max
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if not path or (number > maxCount) then return end
|
|
self:PlaySoundFile(path .. number .. ".ogg")
|
|
end
|
|
|
|
---@param soundId number|string
|
|
---@param force boolean?
|
|
function DBM:PlaySpecialWarningSound(soundId, force)
|
|
local sound
|
|
if not force and self:IsTrivial() and self.Options.DontPlayTrivialSpecialWarningSound then
|
|
sound = self.Options.RaidWarningSound
|
|
else
|
|
sound = type(soundId) == "number" and self.Options["SpecialWarningSound" .. (soundId == 1 and "" or soundId)] or soundId or self.Options.SpecialWarningSound
|
|
end
|
|
self:PlaySoundFile(sound, nil, true)
|
|
end
|
|
|
|
local function testWarningEnd()
|
|
frame:SetFrameStrata("HIGH")
|
|
end
|
|
|
|
---@param text string?
|
|
---@param number number?
|
|
---@param noSound boolean?
|
|
---@param force boolean?
|
|
function DBM:ShowTestSpecialWarning(text, number, noSound, force)
|
|
if moving then
|
|
return
|
|
end
|
|
self:AddSpecialWarning(text or L.MOVE_SPECIAL_WARNING_TEXT)
|
|
frame:SetFrameStrata("TOOLTIP")
|
|
self:Unschedule(testWarningEnd)
|
|
self:Schedule(self.Options.SpecialWarningDuration2 * 1.3, testWarningEnd)
|
|
if number and not noSound then
|
|
self:PlaySpecialWarningSound(number, force)
|
|
end
|
|
if number then
|
|
if self.Options["SpecialWarningFlash" .. number] then
|
|
if not force and self:IsTrivial() and self.Options.DontPlayTrivialSpecialWarningSound then return end--No flash if trivial
|
|
local flashColor = self.Options["SpecialWarningFlashCol" .. number]
|
|
local repeatCount = self.Options["SpecialWarningFlashCount" .. number] or 1
|
|
self.Flash:Show(flashColor[1], flashColor[2], flashColor[3], self.Options["SpecialWarningFlashDura" .. number], self.Options["SpecialWarningFlashAlph" .. number], repeatCount - 1)
|
|
end
|
|
if not self.Options.DontDoSpecialWarningVibrate and self.Options["SpecialWarningVibrate" .. number] then
|
|
self:VibrateController()
|
|
end
|
|
end
|
|
end
|
|
|