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.

1787 lines
63 KiB

if not WeakAuras.IsLibsOK() then return end
---@type string
local AddonName = ...
---@class Private
local Private = select(2, ...)
local timer = WeakAuras.timer;
local L = WeakAuras.L
Private.ExecEnv.BossMods = {}
-- DBM
Private.ExecEnv.BossMods.DBM = {
registeredEvents = {},
bars = {},
nextExpire = nil,
recheckTimer = nil,
CopyBarToState = function(self, bar, states, timerId, extendTimer)
extendTimer = extendTimer or 0
states[timerId] = states[timerId] or {}
local state = states[timerId]
state.show = true
state.changed = true
state.icon = bar.icon
state.message = bar.message
state.text = bar.message
state.name = bar.message
state.expirationTime = bar.expirationTime + extendTimer
state.progressType = 'timed'
state.duration = bar.duration + extendTimer
state.timerType = bar.timerType
state.spellId = bar.spellId
state.count = bar.count
state.dbmType = bar.dbmType
state.dbmColor = bar.dbmColor
state.extend = extendTimer
state.isBarEnabled = bar.isBarEnabled
if extendTimer ~= 0 then
state.autoHide = true
end
state.paused = bar.paused
state.remaining = bar.remaining
end,
TimerMatches = function(self, timerId, message, operator, spellId, counter, triggerId, dbmType, noCastBar, isBarEnabled)
if not self.bars[timerId] then
return false
end
local v = self.bars[timerId]
if triggerId and triggerId ~= "" and triggerId ~= timerId then
return false
end
if spellId and spellId ~= "" and spellId ~= v.spellId then
return false
end
if isBarEnabled ~= nil and isBarEnabled ~= v.isBarEnabled then
return false
end
if message and message ~= "" and operator then
if operator == "==" then
if v.message ~= message then
return false
end
elseif operator == "find('%s')" then
if v.message == nil or not v.message:find(message, 1, true) then
return false
end
elseif operator == "match('%s')" then
if v.message == nil or not v.message:match(message) then
return false
end
end
end
if counter then
counter:SetCount(tonumber(v.count) or 0)
if not counter:Match() then
return false
end
end
if noCastBar and v.timerType:find("^cast") then
return false
end
if dbmType and dbmType ~= v.dbmType then
return false
end
return true
end,
TimerMatchesGeneric = function(self, timerId, message, operator, spellId, counter, isBarEnabled)
return self:TimerMatches(timerId, message, operator, spellId, counter, nil, nil, true, isBarEnabled)
end,
GetStage = function()
if DBM then
return DBM:GetStage()
end
return 0, 0
end,
GetAllTimers = function(self)
return self.bars
end,
GetTimerById = function(self, timerId)
return self.bars[timerId]
end,
GetTimer = function(self, message, operator, spellId, extendTimer, count, triggerId, dbmType, noCastBar, isBarEnabled)
local bestMatch
for timerId, bar in pairs(self.bars) do
if self:TimerMatches(timerId, message, operator, spellId, count, triggerId, dbmType, noCastBar, isBarEnabled)
and (bestMatch == nil or bar.expirationTime < bestMatch.expirationTime)
and bar.expirationTime + extendTimer > GetTime()
then
bestMatch = bar
end
end
return bestMatch
end,
GetTimerGeneric = function(self, message, operator, spellId, extendTimer, count, isBarEnabled)
return self:GetTimer(message, operator, spellId, extendTimer, count, nil, nil, true, isBarEnabled)
end,
RecheckTimers = function(self)
local now = GetTime()
self.nextExpire = nil
for timerId, bar in pairs(self.bars) do
if not bar.paused then
if bar.expirationTime < now then
if bar.scheduledScanExpireAt == nil or bar.scheduledScanExpireAt <= GetTime() then
self.bars[timerId] = nil
else
if self.nextExpire == nil then
self.nextExpire = bar.scheduledScanExpireAt
elseif bar.scheduledScanExpireAt < self.nextExpire then
self.nextExpire = bar.scheduledScanExpireAt
end
end
if not bar.expired then
bar.expired = true
Private.ScanEvents("DBM_TimerStop", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerStop", timerId)
end
end
elseif self.nextExpire == nil then
self.nextExpire = bar.expirationTime
elseif bar.expirationTime < self.nextExpire then
self.nextExpire = bar.expirationTime
end
end
end
if self.nextExpire then
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, self.nextExpire - now, self)
end
end,
EventCallback = function(self, event, ...)
if event == "DBM_Announce" then
local message, icon, _, spellId, _, _, count = ...
Private.ScanEvents("DBM_Announce", spellId, message, icon)
if self.isGeneric then
count = count and tostring(count) or "0"
Private.ScanEvents("BossMod_Announce", spellId, message, icon, count)
end
elseif event == "DBM_TimerBegin" then
local timerId, msg, duration, icon, timerType, spellId, dbmType, _, _, _, _, _, timerCount, _, _, _, _, isBarEnabled = ...
local now = GetTime()
local expirationTime = now + duration
self.bars[timerId] = self.bars[timerId] or {}
local bar = self.bars[timerId]
bar.message = msg
bar.expirationTime = expirationTime
bar.duration = duration
bar.icon = icon
bar.timerType = timerType
bar.spellId = tostring(spellId)
bar.count = timerCount and tostring(timerCount) or "0"
bar.dbmType = dbmType
bar.expired = nil
bar.isBarEnabled = isBarEnabled
local r, g, b = 0, 0, 0
if DBT.GetColorForType then
r, g, b = DBT:GetColorForType(dbmType)
r, g, b = r or 0, g or 0, b or 0
else
-- Compability code for DBM versions from around Aberrus
-- Can be removed once we can assume newer versions
local barOptions = DBT.Options
if dbmType == 1 then
r, g, b = barOptions.StartColorAR, barOptions.StartColorAG, barOptions.StartColorAB
elseif dbmType == 2 then
r, g, b = barOptions.StartColorAER, barOptions.StartColorAEG, barOptions.StartColorAEB
elseif dbmType == 3 then
r, g, b = barOptions.StartColorDR, barOptions.StartColorDG, barOptions.StartColorDB
elseif dbmType == 4 then
r, g, b = barOptions.StartColorIR, barOptions.StartColorIG, barOptions.StartColorIB
elseif dbmType == 5 then
r, g, b = barOptions.StartColorRR, barOptions.StartColorRG, barOptions.StartColorRB
elseif dbmType == 6 then
r, g, b = barOptions.StartColorPR, barOptions.StartColorPG, barOptions.StartColorPB
elseif dbmType == 7 then
r, g, b = barOptions.StartColorUIR, barOptions.StartColorUIG, barOptions.StartColorUIB
elseif dbmType == 8 then
r, g, b = barOptions.StartColorI2R, barOptions.StartColorI2G, barOptions.StartColorI2B
else
r, g, b = barOptions.StartColorR, barOptions.StartColorG, barOptions.StartColorB
end
end
bar.dbmColor = {r, g, b}
Private.ScanEvents("DBM_TimerStart", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerStart", timerId)
end
if self.nextExpire == nil then
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, expirationTime - now, self)
self.nextExpire = expirationTime
elseif expirationTime < self.nextExpire then
timer:CancelTimer(self.recheckTimer)
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, expirationTime - now, self)
self.nextExpire = expirationTime
end
elseif event == "DBM_TimerStop" then
local timerId = ...
local bar = self.bars[timerId]
if bar then
if bar.scheduledScanExpireAt == nil or bar.scheduledScanExpireAt <= GetTime() then
self.bars[timerId] = nil
end
bar.expired = true
Private.ScanEvents("DBM_TimerStop", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerStop", timerId)
end
end
elseif event == "DBM_TimerPause" then
local timerId = ...
local bar = self.bars[timerId]
if bar then
bar.paused = true
bar.remaining = bar.expirationTime - GetTime()
Private.ScanEvents("DBM_TimerPause", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerPause", timerId)
end
if self.recheckTimer then
timer:CancelTimer(self.recheckTimer)
end
self:RecheckTimers()
end
elseif event == "DBM_TimerResume" then
local timerId = ...
local bar = self.bars[timerId]
if bar then
bar.paused = nil
bar.expirationTime = GetTime() + (bar.remaining or 0)
bar.remaining = nil
Private.ScanEvents("DBM_TimerResume", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerResume", timerId)
end
if self.nextExpire == nil then
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - GetTime(), self)
self.nextExpire = bar.expirationTime
elseif bar.expirationTime < self.nextExpire then
timer:CancelTimer(self.recheckTimer)
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - GetTime(), self)
self.nextExpire = bar.expirationTime
end
end
elseif event == "DBM_TimerUpdate" then
local timerId, elapsed, duration = ...
local now = GetTime()
local expirationTime = now + duration - elapsed
local bar = self.bars[timerId]
if bar then
bar.duration = duration
bar.expirationTime = expirationTime
if self.nextExpire == nil then
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - now, self)
self.nextExpire = expirationTime
elseif self.nextExpire == nil or expirationTime < self.nextExpire then
timer:CancelTimer(self.recheckTimer)
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - now, self)
self.nextExpire = expirationTime
end
end
Private.ScanEvents("DBM_TimerUpdate", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerUpdate", timerId)
end
elseif event == "DBM_TimerUpdateIcon" then
local timerId, icon = ...
local bar = self.bars[timerId]
if bar then
bar.icon = icon
end
Private.ScanEvents("DBM_TimerUpdateIcon", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerUpdateIcon", timerId)
end
elseif event == "DBM_SetStage" or event == "DBM_Pull" or event == "DBM_Wipe" or event == "DBM_Kill" then
Private.ScanEvents("DBM_SetStage")
if self.isGeneric then
Private.ScanEvents("BossMod_SetStage")
end
end
end,
RegisterCallback = function(self, event)
if self.registeredEvents[event] then
return
end
if DBM then
DBM:RegisterCallback(event, function(...) self:EventCallback(...) end)
self.registeredEvents[event] = true
end
end,
RegisterTimer = function(self)
self:RegisterCallback("DBM_TimerBegin")
self:RegisterCallback("DBM_TimerStop")
self:RegisterCallback("DBM_TimerPause")
self:RegisterCallback("DBM_TimerResume")
self:RegisterCallback("DBM_TimerUpdate")
self:RegisterCallback("DBM_TimerUpdateIcon")
end,
RegisterMessage = function(self)
self:RegisterCallback("DBM_Announce")
end,
RegisterStage = function(self)
self:RegisterCallback("DBM_SetStage")
self:RegisterCallback("DBM_Pull")
self:RegisterCallback("DBM_Kill")
end,
scheduled_scans = {},
DoScan = function(self, fireTime)
self.scheduled_scans[fireTime] = nil
Private.ScanEvents("DBM_TimerUpdate")
if self.isGeneric then
Private.ScanEvents("BossMod_TimerUpdate")
end
end,
ScheduleCheck = function(self, fireTime)
if not self.scheduled_scans[fireTime] then
self.scheduled_scans[fireTime] = timer:ScheduleTimerFixed(self.DoScan, fireTime - GetTime(), self, fireTime)
end
end
}
if not WeakAuras.IsMistsOrRetail() then
Private.event_prototypes["DBM Stage"] = {
type = "addons",
events = {},
internal_events = {
"DBM_SetStage"
},
force_events = "DBM_SetStage",
name = L["DBM Stage"],
init = function(trigger)
Private.ExecEnv.BossMods.DBM:RegisterStage()
return ""
end,
args = {
{
name = "stage",
init = "Private.ExecEnv.BossMods.DBM:GetStage()",
display = L["Journal Stage"],
desc = L["Matches stage number of encounter journal.\nIntermissions are .5\nE.g. 1;2;1;2;2.5;3"],
type = "number",
conditionType = "number",
store = true,
},
{
name = "stageTotal",
init = "select(2, Private.ExecEnv.BossMods.DBM:GetStage())",
display = L["Stage Counter"],
desc = L["Increases by one per stage or intermission."],
type = "number",
conditionType = "number",
store = true,
},
},
automaticrequired = true,
statesParameter = "one",
progressType = "none"
}
Private.category_event_prototype.addons["DBM Stage"] = L["DBM Stage"]
Private.event_prototypes["DBM Announce"] = {
type = "addons",
events = {},
internal_events = {
"DBM_Announce"
},
name = L["DBM Announce"],
init = function(trigger)
Private.ExecEnv.BossMods.DBM:RegisterMessage();
local ret = "local use_cloneId = %s;"
return ret:format(trigger.use_cloneId and "true" or "false");
end,
statesParameter = "all",
args = {
{
name = "spellId",
init = "arg",
display = L["Spell Id"],
type = "spell",
noValidation = true,
showExactOption = false,
negativeIsEJ = true
},
{
name = "message",
init = "arg",
display = L["Message"],
type = "longstring",
store = true,
conditionType = "string"
},
{
name = "name",
init = "message",
hidden = true,
test = "true",
store = true,
},
{
name = "icon",
init = "arg",
store = true,
hidden = true,
test = "true"
},
{
name = "cloneId",
display = L["Clone per Event"],
type = "toggle",
test = "true",
init = "use_cloneId and WeakAuras.GetUniqueCloneId() or ''"
},
},
timedrequired = true,
progressType = "timed"
}
Private.category_event_prototype.addons["DBM Announce"] = L["DBM Announce"]
Private.event_prototypes["DBM Timer"] = {
type = "addons",
events = {},
internal_events = {
"DBM_TimerStart", "DBM_TimerStop", "DBM_TimerUpdate", "DBM_TimerForce", "DBM_TimerResume", "DBM_TimerPause",
"DBM_TimerUpdateIcon"
},
force_events = "DBM_TimerForce",
name = L["DBM Timer"],
progressType = "timed",
triggerFunction = function(trigger)
Private.ExecEnv.BossMods.DBM:RegisterTimer()
local ret = [=[
local triggerCounter = %q
local counter
if triggerCounter and triggerCounter ~= "" then
counter = Private.ExecEnv.CreateTriggerCounter(triggerCounter)
else
counter = Private.ExecEnv.CreateTriggerCounter()
end
return function (states, event, timerId)
local triggerId = %q
local triggerSpellId = %q
local triggerText = %q
local triggerTextOperator = %q
local useClone = %s
local extendTimer = %s
local triggerUseRemaining = %s
local triggerRemaining = %s
local triggerDbmType = %s
local isBarEnabled = %s
local cloneId = useClone and timerId or ""
local state = states[cloneId]
local counter = counter
function copyOrSchedule(bar, cloneId)
local remainingTime
local changed
if bar.paused then
remainingTime = bar.remaining + extendTimer
else
remainingTime = bar.expirationTime - GetTime() + extendTimer
end
if triggerUseRemaining then
if remainingTime > 0 and remainingTime %s triggerRemaining then
Private.ExecEnv.BossMods.DBM:CopyBarToState(bar, states, cloneId, extendTimer)
changed = true
else
local state = states[cloneId]
if state and state.show then
state.show = false
state.changed = true
changed = true
end
end
if not bar.paused then
if extendTimer > 0 then
bar.scheduledScanExpireAt = math.max(bar.scheduledScanExpireAt or 0, bar.expirationTime + extendTimer)
end
if remainingTime >= triggerRemaining then
Private.ExecEnv.BossMods.DBM:ScheduleCheck(bar.expirationTime - triggerRemaining + extendTimer)
end
end
else
if not bar.paused and extendTimer > 0 then
bar.scheduledScanExpireAt = math.max(bar.scheduledScanExpireAt or 0, bar.expirationTime + extendTimer)
end
if remainingTime > 0 then
Private.ExecEnv.BossMods.DBM:CopyBarToState(bar, states, cloneId, extendTimer)
changed = true
end
end
return changed
end
if useClone then
if event == "DBM_TimerStart"
or event == "DBM_TimerPause"
or event == "DBM_TimerResume"
then
if Private.ExecEnv.BossMods.DBM:TimerMatches(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, triggerId, triggerDbmType, isBarEnabled) then
local bar = Private.ExecEnv.BossMods.DBM:GetTimerById(timerId)
if bar then
return copyOrSchedule(bar, cloneId)
end
end
elseif event == "DBM_TimerStop" and state then
local bar_remainingTime = state.expirationTime - GetTime() + (state.extend or 0)
if state.extend == 0 or bar_remainingTime <= 0 then
state.show = false
state.changed = true
return true
end
elseif event == "DBM_TimerUpdate" or event == "DBM_TimerUpdateIcon" then
local changed
for timerId, bar in pairs(Private.ExecEnv.BossMods.DBM:GetAllTimers()) do
if Private.ExecEnv.BossMods.DBM:TimerMatches(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, triggerId, triggerDbmType, isBarEnabled) then
changed = copyOrSchedule(bar, timerId) or changed
else
local state = states[timerId]
if state then
local bar_remainingTime = state.expirationTime - GetTime() + (state.extend or 0)
if state.extend == 0 or bar_remainingTime <= 0 then
state.show = false
state.changed = true
changed = true
end
end
end
end
return changed
elseif event == "DBM_TimerForce" then
local changed
for _, state in pairs(states) do
state.show = false
state.changed = true
changed = true
end
for timerId, bar in pairs(Private.ExecEnv.BossMods.DBM:GetAllTimers()) do
if Private.ExecEnv.BossMods.DBM:TimerMatches(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, triggerId, triggerDbmType, isBarEnabled) then
changed = copyOrSchedule(bar, timerId) or changed
end
end
return changed
end
else
if event == "DBM_TimerStart" or event == "DBM_TimerUpdate" then
if extendTimer ~= 0 then
if Private.ExecEnv.BossMods.DBM:TimerMatches(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, triggerId, triggerDbmType, isBarEnabled) then
local bar = Private.ExecEnv.BossMods.DBM:GetTimerById(timerId)
Private.ExecEnv.BossMods.DBM:ScheduleCheck(bar.expirationTime + extendTimer)
end
end
end
local bar = Private.ExecEnv.BossMods.DBM:GetTimer(triggerText, triggerTextOperator, triggerSpellId, extendTimer, counter, triggerId, triggerDbmType, isBarEnabled)
if bar then
if extendTimer == 0
or not (state and state.show)
or (state and state.show and state.expirationTime > (bar.expirationTime + extendTimer))
then
return copyOrSchedule(bar, cloneId)
end
else
if state and state.show then
local bar_remainingTime = state.expirationTime - GetTime() + (state.extend or 0)
if state.extend == 0 or bar_remainingTime <= 0 then
state.show = false
state.changed = true
return true
end
end
end
end
end
]=]
return ret:format(
trigger.use_count and trigger.count or "",
trigger.use_id and trigger.id or "",
trigger.use_spellId and tostring(trigger.spellId) or "",
trigger.use_message and trigger.message or "",
trigger.use_message and trigger.message_operator or "",
trigger.use_cloneId and "true" or "false",
trigger.use_extend and tonumber(trigger.extend or 0) or 0,
trigger.use_remaining and "true" or "false",
trigger.remaining and tonumber(trigger.remaining or 0) or 0,
trigger.use_dbmType and trigger.dbmType or "nil",
trigger.use_isBarEnabled == nil and "nil" or trigger.use_isBarEnabled and "true" or "false",
trigger.remaining_operator or "<"
)
end,
statesParameter = "full",
args = {
{
name = "id",
display = L["Timer Id"],
type = "string",
},
{
name = "spellId",
display = L["Spell Id"],
store = true,
type = "spell",
conditionType = "string",
noValidation = true,
showExactOption = false,
negativeIsEJ = true
},
{
name = "message",
display = L["Message"],
type = "longstring",
store = true,
conditionType = "string"
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
},
{
name = "extend",
display = L["Offset Timer"],
type = "string",
},
{
name = "count",
display = L["Count"],
desc = L["Occurrence of the event, reset when aura is unloaded\nCan be a range of values\nCan have multiple values separated by a comma or a space\n\nExamples:\n2nd 5th and 6th events: 2, 5, 6\n2nd to 6th: 2-6\nevery 2 events: /2\nevery 3 events starting from 2nd: 2/3\nevery 3 events starting from 2nd and ending at 11th: 2-11/3\n\nOnly if DBM shows it on it's bar"],
type = "string",
conditionType = "string",
},
{
name = "dbmType",
display = L["Type"],
type = "select",
values = "dbm_types",
conditionType = "select",
test = "true"
},
{
name = "isBarEnabled",
display = L["Bar enabled in DBM settings"],
desc = L["Test if bar is enabled in DBM settings"],
type = "tristate",
test = "true",
init = "false",
conditionType = "bool"
},
{
name = "cloneId",
display = L["Clone per Event"],
type = "toggle"
}
},
automaticrequired = true,
}
Private.category_event_prototype.addons["DBM Timer"] = L["DBM Timer"]
end
-- BigWigs
Private.ExecEnv.BossMods.BigWigs = {
registeredEvents = {},
bars = {},
nextExpire = nil,
recheckTimer = nil,
currentStage = 0,
CopyBarToState = function(self, bar, states, timerId, extendTimer)
extendTimer = extendTimer or 0
states[timerId] = states[timerId] or {}
local state = states[timerId]
state.show = true
state.changed = true
state.addon = bar.addon
state.spellId = bar.spellId
state.text = bar.text
state.message = bar.text
state.name = bar.text
state.duration = bar.duration + extendTimer
state.expirationTime = bar.expirationTime + extendTimer
state.bwBarColor = bar.bwBarColor
state.bwTextColor = bar.bwTextColor
state.bwBackgroundColor = bar.bwBackgroundColor
state.count = bar.count
state.cast = bar.cast
state.progressType = "timed"
state.icon = bar.icon
state.extend = extendTimer
if extendTimer ~= 0 then
state.autoHide = true
end
state.paused = bar.paused
state.remaining = bar.remaining
state.isCooldown = bar.isCooldown
state.isBarEnabled = bar.isBarEnabled
end,
TimerMatches = function(self, timerId, message, operator, spellId, counter, cast, cooldown, isBarEnabled)
if not self.bars[timerId] then
return false
end
local v = self.bars[timerId]
if spellId and spellId ~= "" and spellId ~= v.spellId then
return false
end
if isBarEnabled ~= nil and isBarEnabled ~= v.isBarEnabled then
return false
end
if message and message ~= "" and operator then
if operator == "==" then
if v.text ~= message then
return false
end
elseif operator == "find('%s')" then
if v.text == nil or not v.text:find(message, 1, true) then
return false
end
elseif operator == "match('%s')" then
if v.text == nil or not v.text:match(message) then
return false
end
end
end
if counter then
counter:SetCount(tonumber(v.count) or 0)
if not counter:Match() then
return false
end
end
if cast ~= nil and v.cast ~= cast then
return false
end
if cooldown ~= nil and v.isCooldown ~= cooldown then
return false
end
return true
end,
TimerMatchesGeneric = function(self, timerId, message, operator, spellId, counter, isBarEnabled)
return self:TimerMatches(timerId, message, operator, spellId, counter, false, nil, isBarEnabled)
end,
GetStage = function(self)
return self.currentStage
end,
GetAllTimers = function(self)
return self.bars
end,
GetTimerById = function(self, timerId)
return self.bars[timerId]
end,
GetTimer = function(self, text, operator, spellId, extendTimer, counter, cast, cooldown, isBarEnabled)
local bestMatch
for timerId, bar in pairs(self.bars) do
if self:TimerMatches(timerId, text, operator, spellId, counter, cast, cooldown, isBarEnabled)
and (bestMatch == nil or bar.expirationTime < bestMatch.expirationTime)
and bar.expirationTime + extendTimer > GetTime()
then
bestMatch = bar
end
end
return bestMatch
end,
GetTimerGeneric = function(self, text, operator, spellId, extendTimer, counter, isBarEnabled)
return self:GetTimer(text, operator, spellId, extendTimer, counter, false, nil, isBarEnabled)
end,
RecheckTimers = function(self)
local now = GetTime()
self.nextExpire = nil
for timerId, bar in pairs(self.bars) do
if not bar.paused then
if bar.expirationTime < now then
if bar.scheduledScanExpireAt == nil or bar.scheduledScanExpireAt <= GetTime() then
self.bars[timerId] = nil
else
if self.nextExpire == nil then
self.nextExpire = bar.scheduledScanExpireAt
elseif bar.scheduledScanExpireAt < self.nextExpire then
self.nextExpire = bar.scheduledScanExpireAt
end
end
if not bar.expired then
bar.expired = true
Private.ScanEvents("BigWigs_StopBar", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerStop", timerId)
end
end
elseif self.nextExpire == nil then
self.nextExpire = bar.expirationTime
elseif bar.expirationTime < self.nextExpire then
self.nextExpire = bar.expirationTime
end
end
end
if self.nextExpire then
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, self.nextExpire - now, self)
end
end,
EventCallback = function(self, event, ...)
if event == "BigWigs_Message" then
Private.ScanEvents("BigWigs_Message", ...)
if self.isGeneric then
local _, spellId, text, _, icon = ...
local count = text and text:match("%((%d+)%)") or text:match("((%d+))") or "0"
Private.ScanEvents("BossMod_Announce", spellId, text, icon, count)
end
elseif event == "BigWigs_Timer"
or event == "BigWigs_TargetTimer"
or event == "BigWigs_CastTimer"
or event == "BigWigs_StartBreak"
or event == "BigWigs_StartPull"
then
local addon, spellId, duration, _, text, count, icon, isCooldown, isBarEnabled
if event == "BigWigs_Timer" then
addon, spellId, duration, _, text, count, icon, isCooldown, isBarEnabled = ...
elseif event == "BigWigs_TargetTimer" or event == "BigWigs_CastTimer" then
addon, spellId, duration, _, text, count, icon, _, isBarEnabled = ...
isCooldown = false
elseif event == "BigWigs_StartBreak" or event == "BigWigs_StartPull" then
addon, duration = ...
local BwLocale = BigWigsAPI:GetLocale("BigWigs")
text = event == "BigWigs_StartBreak" and BwLocale.breakBar or BwLocale.pull
spellId = 0
count = 0
icon = 136116
isCooldown = false
isBarEnabled = true
end
local now = GetTime()
local expirationTime = now + duration
self.bars[text] = self.bars[text] or {}
local bar = self.bars[text]
bar.addon = addon
bar.spellId = tostring(spellId)
bar.name = text
bar.text = text
bar.duration = duration
bar.expirationTime = expirationTime
bar.icon = icon
bar.isCooldown = isCooldown or false
bar.expired = nil
local BWColorModule = BigWigs:GetPlugin("Colors")
bar.bwBarColor = BWColorModule:GetColorTable("barColor", addon, spellId)
bar.bwTextColor = BWColorModule:GetColorTable("barText", addon, spellId)
bar.bwBackgroundColor = BWColorModule:GetColorTable("barBackground", addon, spellId)
bar.count = count or 0
bar.isBarEnabled = isBarEnabled
bar.cast = event == "BigWigs_CastTimer"
Private.ScanEvents("BigWigs_StartBar", text)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerStart", text)
end
if self.nextExpire == nil then
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, expirationTime - now, self)
self.nextExpire = expirationTime
elseif expirationTime < self.nextExpire then
timer:CancelTimer(self.recheckTimer)
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, expirationTime - now, self)
self.nextExpire = expirationTime
end
elseif event == "BigWigs_StopBar" then
local addon, text = ...
local bar = self.bars[text]
if bar then
if bar.scheduledScanExpireAt == nil or bar.scheduledScanExpireAt <= GetTime() then
self.bars[text] = nil
end
Private.ScanEvents("BigWigs_StopBar", text)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerStop", text)
end
end
elseif event == "BigWigs_PauseBar" then
local addon, text = ...
local bar = self.bars[text]
if bar and not bar.paused then
bar.paused = true
bar.remaining = bar.expirationTime - GetTime()
Private.ScanEvents("BigWigs_PauseBar", text)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerPause", text)
end
if self.recheckTimer then
timer:CancelTimer(self.recheckTimer)
end
self:RecheckTimers()
end
elseif event == "BigWigs_ResumeBar" then
local addon, text = ...
local bar = self.bars[text]
if bar and bar.paused then
bar.paused = nil
bar.expirationTime = GetTime() + (bar.remaining or 0)
bar.remaining = nil
Private.ScanEvents("BigWigs_ResumeBar", text)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerResume", text)
end
if self.nextExpire == nil then
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - GetTime(), self)
elseif bar.expirationTime < self.nextExpire then
timer:CancelTimer(self.recheckTimer)
self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - GetTime(), self)
self.nextExpire = bar.expirationTime
end
end
elseif event == "BigWigs_StopBars"
or event == "BigWigs_OnBossDisable"
or event == "BigWigs_OnPluginDisable"
then
local addon = ...
for timerId, bar in pairs(self.bars) do
if bar.addon == addon then
self.bars[timerId] = nil
Private.ScanEvents("BigWigs_StopBar", timerId)
if self.isGeneric then
Private.ScanEvents("BossMod_TimerStop", timerId)
end
end
end
elseif event == "BigWigs_SetStage" then
local addon, stage = ...
self.currentStage = stage
Private.ScanEvents("BigWigs_SetStage")
if self.isGeneric then
Private.ScanEvents("BossMod_SetStage")
end
elseif event == "BigWigs_OnBossWipe" or event == "BigWigs_OnBossWin" then
self.currentStage = 0
Private.ScanEvents("BigWigs_SetStage")
if self.isGeneric then
Private.ScanEvents("BossMod_SetStage")
end
end
end,
RegisterCallback = function(self, event)
if self.registeredEvents[event] then
return
end
if BigWigsLoader then
BigWigsLoader.RegisterMessage(WeakAuras, event, function(...) self:EventCallback(...) end)
self.registeredEvents[event] = true
if event == "BigWigs_SetStage" then
-- on init of BigWigs_SetStage callback, we want to fetch currentStage in case we are already in an encounter when this is run
if BigWigs and BigWigs.IterateBossModules then
local stage = 0
for _, module in BigWigs:IterateBossModules() do
if module:IsEngaged() then
stage = math.max(stage, module:GetStage() or 1)
end
end
self.currentStage = stage
end
end
end
end,
RegisterTimer = function(self)
self:RegisterCallback("BigWigs_Timer")
self:RegisterCallback("BigWigs_TargetTimer")
self:RegisterCallback("BigWigs_StartBreak")
self:RegisterCallback("BigWigs_CastTimer")
self:RegisterCallback("BigWigs_StopBar")
self:RegisterCallback("BigWigs_StopBars")
self:RegisterCallback("BigWigs_OnBossDisable")
self:RegisterCallback("BigWigs_PauseBar")
self:RegisterCallback("BigWigs_ResumeBar")
self:RegisterCallback("BigWigs_StartPull")
end,
RegisterMessage = function(self)
self:RegisterCallback("BigWigs_Message")
end,
RegisterStage = function(self)
self:RegisterCallback("BigWigs_SetStage")
self:RegisterCallback("BigWigs_OnBossWipe")
self:RegisterCallback("BigWigs_OnBossWin")
end,
scheduled_scans = {},
DoScan = function(self, fireTime)
self.scheduled_scans[fireTime] = nil
Private.ScanEvents("BigWigs_Timer_Update")
if self.isGeneric then
Private.ScanEvents("BossMod_TimerUpdate")
end
end,
ScheduleCheck = function(self, fireTime)
if not self.scheduled_scans[fireTime] then
self.scheduled_scans[fireTime] = timer:ScheduleTimerFixed(self.DoScan, fireTime - GetTime(), self, fireTime)
end
end
}
if not WeakAuras.IsMistsOrRetail() then
Private.event_prototypes["BigWigs Stage"] = {
type = "addons",
events = {},
internal_events = {
"BigWigs_SetStage"
},
name = L["BigWigs Stage"],
init = function(trigger)
Private.ExecEnv.BossMods.BigWigs:RegisterStage()
return ""
end,
args = {
{
name = "stage",
init = "Private.ExecEnv.BossMods.BigWigs:GetStage()",
display = L["Stage"],
type = "number",
conditionType = "number",
store = true,
}
},
automaticrequired = true,
statesParameter = "one",
progressType = "none"
}
Private.category_event_prototype.addons["BigWigs Stage"] = L["BigWigs Stage"]
Private.event_prototypes["BigWigs Message"] = {
type = "addons",
events = {},
internal_events = {
"BigWigs_Message"
},
name = L["BigWigs Message"],
init = function(trigger)
Private.ExecEnv.BossMods.BigWigs:RegisterMessage();
local ret = "local use_cloneId = %s;"
return ret:format(trigger.use_cloneId and "true" or "false");
end,
statesParameter = "all",
args = {
{
name = "addon",
init = "arg",
display = L["BigWigs Addon"],
type = "string"
},
{
name = "spellId",
init = "arg",
display = L["ID"],
desc = L["The 'ID' value can be found in the BigWigs options of a specific spell"],
type = "spell",
conditionType = "string",
noValidation = true,
showExactOption = false,
negativeIsEJ = true
},
{
name = "text",
init = "arg",
display = L["Message"],
type = "longstring",
store = true,
conditionType = "string"
},
{
name = "name",
init = "text",
hidden = true,
test = "true",
store = true
},
{}, -- Importance, might be useful
{
name = "icon",
init = "arg",
hidden = true,
test = "true",
store = true
},
{
name = "cloneId",
display = L["Clone per Event"],
type = "toggle",
test = "true",
init = "use_cloneId and WeakAuras.GetUniqueCloneId() or ''"
},
},
timedrequired = true,
progressType = "timed"
}
Private.category_event_prototype.addons["BigWigs Message"] = L["BigWigs Message"]
Private.event_prototypes["BigWigs Timer"] = {
type = "addons",
events = {},
internal_events = {
"BigWigs_StartBar", "BigWigs_StopBar", "BigWigs_Timer_Update", "BigWigs_PauseBar", "BigWigs_ResumeBar"
},
force_events = "BigWigs_Timer_Force",
name = L["BigWigs Timer"],
progressType = "timed",
triggerFunction = function(trigger)
Private.ExecEnv.BossMods.BigWigs:RegisterTimer()
local ret = [=[
local triggerCounter = %q
local counter
if triggerCounter and triggerCounter ~= "" then
counter = Private.ExecEnv.CreateTriggerCounter(triggerCounter)
else
counter = Private.ExecEnv.CreateTriggerCounter()
end
return function(states, event, timerId)
local triggerSpellId = %q
local triggerText = %q
local triggerTextOperator = %q
local useClone = %s
local extendTimer = %s
local triggerUseRemaining = %s
local triggerRemaining = %s
local triggerCast = %s
local triggerIsCooldown = %s
local isBarEnabled = %s
local cloneId = useClone and timerId or ""
local state = states[cloneId]
local counter = counter
function copyOrSchedule(bar, cloneId)
local remainingTime
local changed
if bar.paused then
remainingTime = bar.remaining + extendTimer
else
remainingTime = bar.expirationTime - GetTime() + extendTimer
end
if triggerUseRemaining then
if remainingTime > 0 and remainingTime %s triggerRemaining then
Private.ExecEnv.BossMods.BigWigs:CopyBarToState(bar, states, cloneId, extendTimer)
changed = true
else
local state = states[cloneId]
if state and state.show then
state.show = false
state.changed = true
changed = true
end
end
if not bar.paused then
if extendTimer > 0 then
bar.scheduledScanExpireAt = math.max(bar.scheduledScanExpireAt or 0, bar.expirationTime + extendTimer)
end
if remainingTime >= triggerRemaining then
Private.ExecEnv.BossMods.BigWigs:ScheduleCheck(bar.expirationTime - triggerRemaining + extendTimer)
end
end
else
if not bar.paused and extendTimer > 0 then
bar.scheduledScanExpireAt = math.max(bar.scheduledScanExpireAt or 0, bar.expirationTime + extendTimer)
end
if remainingTime > 0 then
Private.ExecEnv.BossMods.BigWigs:CopyBarToState(bar, states, cloneId, extendTimer)
changed = true
end
end
return changed
end
if useClone then
if event == "BigWigs_StartBar"
or event == "BigWigs_PauseBar"
or event == "BigWigs_ResumeBar"
then
if Private.ExecEnv.BossMods.BigWigs:TimerMatches(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, triggerCast, triggerIsCooldown, isBarEnabled) then
local bar = Private.ExecEnv.BossMods.BigWigs:GetTimerById(timerId)
if bar then
return copyOrSchedule(bar, cloneId)
end
end
elseif event == "BigWigs_StopBar" and state then
local bar_remainingTime = state.expirationTime - GetTime() + (state.extend or 0)
if state.extend == 0 or bar_remainingTime <= 0 then
state.show = false
state.changed = true
return true
end
elseif event == "BigWigs_Timer_Update" then
local changed
for timerId, bar in pairs(Private.ExecEnv.BossMods.BigWigs:GetAllTimers()) do
if Private.ExecEnv.BossMods.BigWigs:TimerMatches(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, triggerCast, triggerIsCooldown, isBarEnabled) then
changed = copyOrSchedule(bar, timerId) or changed
end
end
return changed
elseif event == "BigWigs_Timer_Force" then
local changed
for _, state in pairs(states) do
state.show = false
state.changed = true
changed = true
end
for timerId, bar in pairs(Private.ExecEnv.BossMods.BigWigs:GetAllTimers()) do
if Private.ExecEnv.BossMods.BigWigs:TimerMatches(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, triggerCast, triggerIsCooldown, isBarEnabled) then
changed = copyOrSchedule(bar, timerId) or changed
end
end
return changed
end
else
if event == "BigWigs_StartBar" then
if extendTimer ~= 0 then
if Private.ExecEnv.BossMods.BigWigs:TimerMatches(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, triggerCast, triggerIsCooldown, isBarEnabled) then
local bar = Private.ExecEnv.BossMods.BigWigs:GetTimerById(timerId)
Private.ExecEnv.BossMods.BigWigs:ScheduleCheck(bar.expirationTime + extendTimer)
end
end
end
local bar = Private.ExecEnv.BossMods.BigWigs:GetTimer(triggerText, triggerTextOperator, triggerSpellId, extendTimer, counter, triggerCast, triggerIsCooldown, isBarEnabled)
if bar then
if extendTimer == 0
or not (state and state.show)
or (state and state.show and state.expirationTime > (bar.expirationTime + extendTimer))
then
return copyOrSchedule(bar, cloneId)
end
else
if state and state.show then
local bar_remainingTime = state.expirationTime - GetTime() + (state.extend or 0)
if state.extend == 0 or bar_remainingTime <= 0 then
state.show = false
state.changed = true
return true
end
end
end
end
end
]=]
return ret:format(
trigger.use_count and trigger.count or "",
trigger.use_spellId and tostring(trigger.spellId) or "",
trigger.use_text and trigger.text or "",
trigger.use_text and trigger.text_operator or "",
trigger.use_cloneId and "true" or "false",
trigger.use_extend and tonumber(trigger.extend or 0) or 0,
trigger.use_remaining and "true" or "false",
trigger.remaining and tonumber(trigger.remaining or 0) or 0,
trigger.use_cast == nil and "nil" or trigger.use_cast and "true" or "false",
trigger.use_isCooldown == nil and "nil" or trigger.use_isCooldown and "true" or "false",
trigger.use_isBarEnabled == nil and "nil" or trigger.use_isBarEnabled and "true" or "false",
trigger.remaining_operator or "<"
)
end,
statesParameter = "full",
args = {
{
name = "spellId",
display = L["ID"],
desc = L["The 'ID' value can be found in the BigWigs options of a specific spell"],
type = "spell",
conditionType = "string",
noValidation = true,
showExactOption = false,
negativeIsEJ = true
},
{
name = "text",
display = L["Message"],
type = "longstring",
store = true,
conditionType = "string"
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
},
{
name = "extend",
display = L["Offset Timer"],
type = "string",
},
{
name = "count",
display = L["Count"],
desc = L["Occurrence of the event, reset when aura is unloaded\nCan be a range of values\nCan have multiple values separated by a comma or a space\n\nExamples:\n2nd 5th and 6th events: 2, 5, 6\n2nd to 6th: 2-6\nevery 2 events: /2\nevery 3 events starting from 2nd: 2/3\nevery 3 events starting from 2nd and ending at 11th: 2-11/3\n\nOnly if BigWigs shows it on it's bar"],
type = "string",
store = true,
conditionType = "string",
},
{
name = "cast",
display = L["Cast Bar"],
desc = L["Filter messages with format <message>"],
type = "tristate",
test = "true",
init = "false",
conditionType = "bool"
},
{
name = "isCooldown",
display = L["Cooldown"],
desc = L["Cooldown bars show time before an ability is ready to be use, BigWigs prefix them with '~'"],
type = "tristate",
test = "true",
init = "false",
conditionType = "bool"
},
{
name = "isBarEnabled",
display = L["Bar enabled in BigWigs settings"],
desc = L["Test if bar is enabled in BigWigs settings"],
type = "tristate",
test = "true",
init = "false",
conditionType = "bool"
},
{
name = "cloneId",
display = L["Clone per Event"],
type = "toggle",
test = "true",
init = "false"
},
},
automaticrequired = true,
}
Private.category_event_prototype.addons["BigWigs Timer"] = L["BigWigs Timer"]
end
-- Unified
if BigWigsLoader or not DBM then
Private.ExecEnv.BossMods.Generic = Private.ExecEnv.BossMods.BigWigs
Private.ExecEnv.BossMods.BigWigs.isGeneric = true
Private.ExecEnv.BossMods.BigWigs.isInstalled = BigWigsLoader ~= nil
elseif DBM then
Private.ExecEnv.BossMods.Generic = Private.ExecEnv.BossMods.DBM
Private.ExecEnv.BossMods.DBM.isGeneric = true
Private.ExecEnv.BossMods.DBM.isInstalled = true
end
local ActiveBossModText
if Private.ExecEnv.BossMods.BigWigs.isInstalled then
ActiveBossModText = L["Active boss mod addon: |cFFffcc00BigWigs|r\n\nNote: This trigger will use BigWigs or DBM, in that order if both are installed."]
elseif Private.ExecEnv.BossMods.DBM.isInstalled then
ActiveBossModText = L["Active boss mod addon: |cFFffcc00DBM|r\n\nNote: This trigger will use BigWigs or DBM, in that order if both are installed."]
else
ActiveBossModText = L["No active boss mod addon detected.\n\nNote: This trigger will use BigWigs or DBM, in that order if both are installed."]
end
Private.event_prototypes["Boss Mod Stage"] = {
type = "addons",
events = {},
internal_events = {
"BossMod_SetStage"
},
force_events = "BossMod_SetStage",
name = L["Boss Mod Stage"],
init = function(trigger)
Private.ExecEnv.BossMods.Generic:RegisterStage()
return ""
end,
args = {
{
name = "stage",
init = "Private.ExecEnv.BossMods.Generic:GetStage()",
display = L["Stage"],
type = "number",
conditionType = "number",
store = true,
},
{
name = "note",
type = "description",
display = "",
text = ActiveBossModText
},
},
automaticrequired = true,
statesParameter = "one",
progressType = "none"
}
Private.category_event_prototype.addons["Boss Mod Stage"] = L["Boss Mod Stage"]
Private.event_prototypes["Boss Mod Stage (Event)"] = {
type = "event",
events = {
["events"] = {
"BossMod_SetStage",
}
},
name = L["Boss Mod Stage (Event)"],
init = function(trigger)
Private.ExecEnv.BossMods.Generic:RegisterStage()
return ""
end,
args = {
{
name = "stage",
init = "Private.ExecEnv.BossMods.Generic:GetStage()",
display = L["Stage"],
type = "number",
conditionType = "number",
store = true,
},
{
name = "note",
type = "description",
display = "",
text = ActiveBossModText
},
},
statesParameter = "one",
progressType = "timed",
delayEvents = true,
timedrequired = true
}
Private.category_event_prototype.addons["Boss Mod Stage (Event)"] = L["Boss Mod Stage (Event)"]
Private.event_prototypes["Boss Mod Announce"] = {
type = "addons",
events = {},
internal_events = {
"BossMod_Announce"
},
name = L["Boss Mod Announce"],
init = function(trigger)
Private.ExecEnv.BossMods.Generic:RegisterMessage();
local ret = "local use_cloneId = %s;"
return ret:format(trigger.use_cloneId and "true" or "false");
end,
statesParameter = "all",
args = {
{
name = "spellId",
init = "arg",
display = L["ID"],
store = true,
type = "spell",
conditionType = "string",
noValidation = true,
showExactOption = false,
negativeIsEJ = true
},
{
name = "message",
init = "arg",
display = L["Message"],
type = "longstring",
store = true,
conditionType = "string"
},
{
name = "name",
init = "message",
hidden = true,
test = "true",
store = true,
},
{
name = "icon",
init = "arg",
store = true,
hidden = true,
test = "true"
},
{
name = "count",
init = "arg",
display = L["Count"],
desc = L["Occurrence of the event\nCan be a range of values\nCan have multiple values separated by a comma or a space\n\nExamples:\n2nd 5th and 6th events: 2, 5, 6\n2nd to 6th: 2-6\nevery 2 events: /2\nevery 3 events starting from 2nd: 2/3\nevery 3 events starting from 2nd and ending at 11th: 2-11/3\n\nWorks only if Boss Mod addon show counter"],
type = "string",
preamble = "local counter = Private.ExecEnv.CreateTriggerCounter(%q)",
test = "counter:SetCount(tonumber(count) or 0) == nil and counter:Match()",
conditionPreamble = function(input)
return Private.ExecEnv.CreateTriggerCounter(input)
end,
conditionTest = function(state, needle, op, preamble)
preamble:SetCount(tonumber(state.count) or 0)
return preamble:Match()
end,
store = true,
conditionType = "string",
operator_types = "none"
},
{
name = "cloneId",
display = L["Clone per Event"],
type = "toggle",
test = "true",
init = "use_cloneId and WeakAuras.GetUniqueCloneId() or ''"
},
{
name = "note",
type = "description",
display = "",
text = ActiveBossModText
},
},
timedrequired = true,
progressType = "timed"
}
Private.category_event_prototype.addons["Boss Mod Announce"] = L["Boss Mod Announce"]
Private.event_prototypes["Boss Mod Timer"] = {
type = "addons",
events = {},
internal_events = {
"BossMod_TimerStart", "BossMod_TimerStop", "BossMod_TimerUpdate", "BossMod_TimerForce", "BossMod_TimerResume",
"BossMod_TimerPause", "BossMod_TimerUpdateIcon"
},
force_events = "BossMod_TimerForce",
name = L["Boss Mod Timer"],
progressType = "timed",
triggerFunction = function(trigger)
Private.ExecEnv.BossMods.Generic:RegisterTimer()
local ret = [=[
local triggerCounter = %q
local counter
if triggerCounter and triggerCounter ~= "" then
counter = Private.ExecEnv.CreateTriggerCounter(triggerCounter)
else
counter = Private.ExecEnv.CreateTriggerCounter()
end
local isBW = Private.ExecEnv.BossMods.Generic == Private.ExecEnv.BossMods.BigWigs
local isDBM = Private.ExecEnv.BossMods.Generic == Private.ExecEnv.BossMods.DBM
return function (states, event, timerId)
local triggerSpellId = %q
local triggerText = %q
local triggerTextOperator = %q
local useClone = %s
local extendTimer = %s
local triggerUseRemaining = %s
local triggerRemaining = %s
local isBarEnabled = %s
local cloneId = useClone and timerId or ""
local state = states[cloneId]
local counter = counter
function copyOrSchedule(bar, cloneId)
local remainingTime
local changed
if bar.paused then
remainingTime = bar.remaining + extendTimer
else
remainingTime = bar.expirationTime - GetTime() + extendTimer
end
if triggerUseRemaining then
if remainingTime > 0 and remainingTime %s triggerRemaining then
Private.ExecEnv.BossMods.Generic:CopyBarToState(bar, states, cloneId, extendTimer)
changed = true
else
local state = states[cloneId]
if state and state.show then
state.show = false
state.changed = true
changed = true
end
end
if not bar.paused then
if extendTimer > 0 then
bar.scheduledScanExpireAt = math.max(bar.scheduledScanExpireAt or 0, bar.expirationTime + extendTimer)
end
if remainingTime >= triggerRemaining then
Private.ExecEnv.BossMods.Generic:ScheduleCheck(bar.expirationTime - triggerRemaining + extendTimer)
end
end
else
if not bar.paused and extendTimer > 0 then
bar.scheduledScanExpireAt = math.max(bar.scheduledScanExpireAt or 0, bar.expirationTime + extendTimer)
end
if remainingTime > 0 then
Private.ExecEnv.BossMods.Generic:CopyBarToState(bar, states, cloneId, extendTimer)
changed = true
end
end
return changed
end
if useClone then
if event == "BossMod_TimerStart"
or event == "BossMod_TimerPause"
or event == "BossMod_TimerResume"
then
if Private.ExecEnv.BossMods.Generic:TimerMatchesGeneric(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, isBarEnabled) then
local bar = Private.ExecEnv.BossMods.Generic:GetTimerById(timerId)
if bar then
return copyOrSchedule(bar, cloneId)
end
end
elseif event == "BossMod_TimerStop" and state then
local bar_remainingTime = state.expirationTime - GetTime() + (state.extend or 0)
if state.extend == 0 or bar_remainingTime <= 0 then
state.show = false
state.changed = true
return true
end
elseif event == "BossMod_TimerUpdate" or event == "BossMod_TimerUpdateIcon" then
local changed
for timerId, bar in pairs(Private.ExecEnv.BossMods.Generic:GetAllTimers()) do
if Private.ExecEnv.BossMods.Generic:TimerMatchesGeneric(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, isBarEnabled) then
changed = copyOrSchedule(bar, timerId) or changed
else
local state = states[timerId]
if state then
local bar_remainingTime = state.expirationTime - GetTime() + (state.extend or 0)
if state.extend == 0 or bar_remainingTime <= 0 then
state.show = false
state.changed = true
changed = true
end
end
end
end
return changed
elseif event == "BossMod_TimerForce" then
local changed
for _, state in pairs(states) do
state.show = false
state.changed = true
changed = true
end
for timerId, bar in pairs(Private.ExecEnv.BossMods.Generic:GetAllTimers()) do
if Private.ExecEnv.BossMods.Generic:TimerMatchesGeneric(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, isBarEnabled) then
changed = copyOrSchedule(bar, timerId) or changed
end
end
return changed
end
else
if event == "BossMod_TimerStart" or event == "BossMod_TimerUpdate" then
if extendTimer ~= 0 then
if Private.ExecEnv.BossMods.Generic:TimerMatchesGeneric(timerId, triggerText, triggerTextOperator, triggerSpellId, counter, isBarEnabled) then
local bar = Private.ExecEnv.BossMods.Generic:GetTimerById(timerId)
Private.ExecEnv.BossMods.Generic:ScheduleCheck(bar.expirationTime + extendTimer)
end
end
end
local bar = Private.ExecEnv.BossMods.Generic:GetTimerGeneric(triggerText, triggerTextOperator, triggerSpellId, extendTimer, counter, isBarEnabled)
if bar then
if extendTimer == 0
or not (state and state.show)
or (state and state.show and state.expirationTime > (bar.expirationTime + extendTimer))
then
return copyOrSchedule(bar, cloneId)
end
else
if state and state.show then
local bar_remainingTime = state.expirationTime - GetTime() + (state.extend or 0)
if state.extend == 0 or bar_remainingTime <= 0 then
state.show = false
state.changed = true
return true
end
end
end
end
end
]=]
return ret:format(
trigger.use_count and trigger.count or "",
trigger.use_spellId and tostring(trigger.spellId) or "",
trigger.use_message and trigger.message or "",
trigger.use_message and trigger.message_operator or "",
trigger.use_cloneId and "true" or "false",
trigger.use_extend and tonumber(trigger.extend or 0) or 0,
trigger.use_remaining and "true" or "false",
trigger.remaining and tonumber(trigger.remaining or 0) or 0,
trigger.use_isBarEnabled == nil and "nil" or trigger.use_isBarEnabled and "true" or "false",
trigger.remaining_operator or "<"
)
end,
statesParameter = "full",
args = {
{
name = "spellId",
display = L["ID"],
store = true,
type = "spell",
conditionType = "string",
noValidation = true,
showExactOption = false,
negativeIsEJ = true
},
{
name = "message",
display = L["Message"],
type = "longstring",
store = true,
conditionType = "string"
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
},
{
name = "extend",
display = L["Offset Timer"],
type = "string",
},
{
name = "count",
display = L["Count"],
desc = L["Occurrence of the event, reset when aura is unloaded\nCan be a range of values\nCan have multiple values separated by a comma or a space\n\nExamples:\n2nd 5th and 6th events: 2, 5, 6\n2nd to 6th: 2-6\nevery 2 events: /2\nevery 3 events starting from 2nd: 2/3\nevery 3 events starting from 2nd and ending at 11th: 2-11/3\n\nOnly if DBM shows it on it's bar"],
type = "string",
conditionType = "string",
},
{
name = "isBarEnabled",
display = L["Bar enabled in Boss Mod addon settings"],
desc = L["Test if bar is enabled in Boss Mod addon settings"],
type = "tristate",
test = "true",
init = "false",
conditionType = "bool",
},
{
name = "cloneId",
display = L["Clone per Event"],
type = "toggle"
},
{
name = "note",
type = "description",
display = "",
text = ActiveBossModText
},
},
automaticrequired = true,
}
Private.category_event_prototype.addons["Boss Mod Timer"] = L["Boss Mod Timer"]