initial commit
This commit is contained in:
2814
Modules/RaidTimeline/RaidTimeline.lua
Normal file
2814
Modules/RaidTimeline/RaidTimeline.lua
Normal file
File diff suppressed because it is too large
Load Diff
202
Modules/RaidTimeline/RaidTimelineBigWigs.lua
Normal file
202
Modules/RaidTimeline/RaidTimelineBigWigs.lua
Normal file
@@ -0,0 +1,202 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME)
|
||||
if not HMGT then return end
|
||||
|
||||
local RT = HMGT.RaidTimeline
|
||||
if not RT then return end
|
||||
|
||||
local function TrimText(value)
|
||||
local text = tostring(value or "")
|
||||
text = string.gsub(text, "^%s+", "")
|
||||
text = string.gsub(text, "%s+$", "")
|
||||
return text
|
||||
end
|
||||
|
||||
local function StripBarDisplayText(value)
|
||||
local text = tostring(value or "")
|
||||
text = string.gsub(text, "|T.-|t", "")
|
||||
text = string.gsub(text, "|c%x%x%x%x%x%x%x%x", "")
|
||||
text = string.gsub(text, "|r", "")
|
||||
return TrimText(text)
|
||||
end
|
||||
|
||||
local function NormalizeBossAbilityBarName(value)
|
||||
local text = TrimText(value)
|
||||
if text == "" then
|
||||
return ""
|
||||
end
|
||||
text = string.gsub(text, "%s*%(%d+%)%s*$", "")
|
||||
text = string.gsub(text, "%s*%([Cc]ount%)%s*$", "")
|
||||
text = string.gsub(text, "^%s*%[([A-Za-z])%]%s*", "%1 ")
|
||||
text = string.gsub(text, "%s*%[([A-Za-z])%]%s*$", " (%1)")
|
||||
text = string.gsub(text, "%s*%(([A-Za-z])%)%s*$", " (%1)")
|
||||
text = string.lower(text)
|
||||
return TrimText(text)
|
||||
end
|
||||
|
||||
local function EnsureBigWigsBridge()
|
||||
if RT._bigWigsBridgeRegistered == true then
|
||||
return true
|
||||
end
|
||||
if type(BigWigsLoader) ~= "table" or type(BigWigsLoader.RegisterMessage) ~= "function" then
|
||||
return false
|
||||
end
|
||||
|
||||
RT._bigWigsObservedBars = RT._bigWigsObservedBars or setmetatable({}, { __mode = "k" })
|
||||
RT._bigWigsReceiver = RT._bigWigsReceiver or {}
|
||||
|
||||
function RT._bigWigsReceiver:OnBigWigsBarCreated(_, plugin, bar, module, key, text, time)
|
||||
RT._bigWigsObservedBars[bar] = {
|
||||
plugin = plugin,
|
||||
module = module,
|
||||
key = key,
|
||||
createdText = tostring(text or ""),
|
||||
duration = tonumber(time) or 0,
|
||||
}
|
||||
end
|
||||
|
||||
function RT._bigWigsReceiver:OnBigWigsStopBar(_, plugin, module, text)
|
||||
local targetText = StripBarDisplayText(text)
|
||||
for bar, info in pairs(RT._bigWigsObservedBars) do
|
||||
local currentText = ""
|
||||
if type(bar) == "table" and type(bar.GetText) == "function" then
|
||||
currentText = StripBarDisplayText(bar:GetText())
|
||||
end
|
||||
if (info and info.plugin == plugin or not info or not info.plugin)
|
||||
and (currentText == targetText or StripBarDisplayText(info and info.createdText) == targetText) then
|
||||
RT._bigWigsObservedBars[bar] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BigWigsLoader.RegisterMessage(RT._bigWigsReceiver, "BigWigs_BarCreated", "OnBigWigsBarCreated")
|
||||
BigWigsLoader.RegisterMessage(RT._bigWigsReceiver, "BigWigs_StopBar", "OnBigWigsStopBar")
|
||||
RT._bigWigsBridgeRegistered = true
|
||||
return true
|
||||
end
|
||||
|
||||
function RT:GetObservedBigWigsBars()
|
||||
local observed = {}
|
||||
if not EnsureBigWigsBridge() then
|
||||
return observed
|
||||
end
|
||||
|
||||
for bar, info in pairs(self._bigWigsObservedBars or {}) do
|
||||
local rawText = nil
|
||||
if type(bar) == "table" and type(bar.GetText) == "function" then
|
||||
rawText = bar:GetText()
|
||||
end
|
||||
rawText = StripBarDisplayText(rawText or (info and info.createdText) or "")
|
||||
local remaining = math.max(0, tonumber(bar and bar.remaining) or 0)
|
||||
if rawText ~= "" and remaining > 0 then
|
||||
observed[#observed + 1] = {
|
||||
rawText = rawText,
|
||||
normalizedName = NormalizeBossAbilityBarName(rawText),
|
||||
count = tonumber(string.match(rawText, "%((%d+)%)%s*$")) or 1,
|
||||
seconds = remaining,
|
||||
key = info and info.key or nil,
|
||||
}
|
||||
else
|
||||
self._bigWigsObservedBars[bar] = nil
|
||||
end
|
||||
end
|
||||
|
||||
return observed
|
||||
end
|
||||
|
||||
function RT:ProbeBossAbilityEntry(entryIndex, entry)
|
||||
if not self:IsLocalEditor() or not self.activeEncounterId or self:GetTriggerType(entry) ~= "bossAbility" then
|
||||
return
|
||||
end
|
||||
|
||||
local desiredRawName = TrimText(entry and entry.bossAbilityBarName or "")
|
||||
local desiredName = NormalizeBossAbilityBarName(desiredRawName)
|
||||
local desiredSelector = self:NormalizeCastCountSelector(entry and entry.castCount)
|
||||
local desiredSelectorText = self:FormatCastCountSelector(desiredSelector)
|
||||
if desiredName == "" then
|
||||
self:LogBossAbilityProbe(
|
||||
entryIndex,
|
||||
entry,
|
||||
"missing-bar-name",
|
||||
"RaidTimeline BigWigs probe encounter=%s slot=%s skipped=missing-bar-name",
|
||||
tostring(self.activeEncounterId),
|
||||
tostring(entryIndex)
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
local bars = self:GetObservedBigWigsBars()
|
||||
if #bars == 0 then
|
||||
self:LogBossAbilityProbe(
|
||||
entryIndex,
|
||||
entry,
|
||||
"no-bars",
|
||||
"RaidTimeline BigWigs probe encounter=%s slot=%s target=%s normalized=%s selector=%s foundBar=false bars=0",
|
||||
tostring(self.activeEncounterId),
|
||||
tostring(entryIndex),
|
||||
tostring(desiredRawName),
|
||||
tostring(desiredName),
|
||||
tostring(desiredSelectorText)
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
local seenNames = {}
|
||||
local foundName = false
|
||||
for _, observed in ipairs(bars) do
|
||||
seenNames[#seenNames + 1] = string.format("%s{key=%s}[%d]=%.1fs", tostring(observed.rawText), tostring(observed.key), tonumber(observed.count) or 1, tonumber(observed.seconds) or 0)
|
||||
if observed.normalizedName == desiredName then
|
||||
foundName = true
|
||||
if self:DoesCastCountSelectorMatch(desiredSelector, observed.count) then
|
||||
self:LogBossAbilityProbe(
|
||||
entryIndex,
|
||||
entry,
|
||||
string.format("match:%s:%s:%d", desiredName, tostring(desiredSelector), tonumber(observed.count) or 1),
|
||||
"RaidTimeline BigWigs probe encounter=%s slot=%s target=%s normalized=%s selector=%s foundBar=true countMatch=true observed=%s key=%s observedCount=%d remaining=%.1f",
|
||||
tostring(self.activeEncounterId),
|
||||
tostring(entryIndex),
|
||||
tostring(desiredRawName),
|
||||
tostring(desiredName),
|
||||
tostring(desiredSelectorText),
|
||||
tostring(observed.rawText),
|
||||
tostring(observed.key),
|
||||
tonumber(observed.count) or 1,
|
||||
tonumber(observed.seconds) or 0
|
||||
)
|
||||
self:TryDispatchBossAbilityEntry(entryIndex, entry, observed.count, observed.seconds)
|
||||
return
|
||||
end
|
||||
|
||||
self:LogBossAbilityProbe(
|
||||
entryIndex,
|
||||
entry,
|
||||
string.format("count-mismatch:%s:%d", desiredName, observed.count),
|
||||
"RaidTimeline BigWigs probe encounter=%s slot=%s target=%s normalized=%s selector=%s foundBar=true countMatch=false observed=%s key=%s observedCount=%d remaining=%.1f",
|
||||
tostring(self.activeEncounterId),
|
||||
tostring(entryIndex),
|
||||
tostring(desiredRawName),
|
||||
tostring(desiredName),
|
||||
tostring(desiredSelectorText),
|
||||
tostring(observed.rawText),
|
||||
tostring(observed.key),
|
||||
tonumber(observed.count) or 1,
|
||||
tonumber(observed.seconds) or 0
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
if not foundName then
|
||||
self:LogBossAbilityProbe(
|
||||
entryIndex,
|
||||
entry,
|
||||
string.format("name-miss:%s", desiredName),
|
||||
"RaidTimeline BigWigs probe encounter=%s slot=%s target=%s normalized=%s selector=%s foundBar=false bars=%s",
|
||||
tostring(self.activeEncounterId),
|
||||
tostring(entryIndex),
|
||||
tostring(desiredRawName),
|
||||
tostring(desiredName),
|
||||
tostring(desiredSelectorText),
|
||||
table.concat(seenNames, ", ")
|
||||
)
|
||||
end
|
||||
end
|
||||
52
Modules/RaidTimeline/RaidTimelineBossAbilityData.lua
Normal file
52
Modules/RaidTimeline/RaidTimelineBossAbilityData.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME)
|
||||
if not HMGT then return end
|
||||
|
||||
HMGT.RaidTimelineBossAbilityData = HMGT.RaidTimelineBossAbilityData or {
|
||||
raids = {
|
||||
--[[
|
||||
{
|
||||
name = "Void Spire",
|
||||
journalInstanceId = 1307,
|
||||
bosses = {
|
||||
[3176] = {
|
||||
name = "Imperator Averzian",
|
||||
abilities = {
|
||||
{
|
||||
key = "gloom",
|
||||
name = "Gloom",
|
||||
spellId = 123456,
|
||||
icon = 1234567,
|
||||
difficulties = {
|
||||
lfr = false,
|
||||
normal = true,
|
||||
heroic = true,
|
||||
mythic = true,
|
||||
},
|
||||
triggers = {
|
||||
bigwigs = { 123456, "gloom" },
|
||||
dbm = { 123456 },
|
||||
},
|
||||
},
|
||||
{
|
||||
key = "mythic_gloom",
|
||||
name = "Mythic Gloom",
|
||||
spellId = 123457,
|
||||
difficulties = {
|
||||
lfr = false,
|
||||
normal = false,
|
||||
heroic = false,
|
||||
mythic = true,
|
||||
},
|
||||
triggers = {
|
||||
bigwigs = { 123457 },
|
||||
dbm = { 123457 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]]
|
||||
},
|
||||
}
|
||||
8
Modules/RaidTimeline/RaidTimelineDBM.lua
Normal file
8
Modules/RaidTimeline/RaidTimelineDBM.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME)
|
||||
if not HMGT then return end
|
||||
|
||||
local RT = HMGT.RaidTimeline
|
||||
if not RT then return end
|
||||
|
||||
-- Placeholder for later DBM-specific raid timeline integration.
|
||||
799
Modules/RaidTimeline/RaidTimelineOptions.lua
Normal file
799
Modules/RaidTimeline/RaidTimelineOptions.lua
Normal file
@@ -0,0 +1,799 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME)
|
||||
if not HMGT then return end
|
||||
|
||||
local RT = HMGT.RaidTimeline
|
||||
if not RT then return end
|
||||
if not HMGT_Config or not HMGT_Config.RegisterOptionsProvider then return end
|
||||
|
||||
local L = LibStub("AceLocale-3.0"):GetLocale(ADDON_NAME, true) or {}
|
||||
local AceConfigRegistry = LibStub("AceConfigRegistry-3.0")
|
||||
local LSM = LibStub("LibSharedMedia-3.0", true)
|
||||
|
||||
local FONT_OUTLINE_VALUES = {
|
||||
NONE = NONE or "None",
|
||||
OUTLINE = "Outline",
|
||||
THICKOUTLINE = "Thick Outline",
|
||||
MONOCHROME = "Monochrome",
|
||||
["OUTLINE,MONOCHROME"] = "Outline Monochrome",
|
||||
}
|
||||
|
||||
local DIFFICULTY_KEYS = { "lfr", "normal", "heroic", "mythic" }
|
||||
local MAX_ENTRY_ROWS = 24
|
||||
local raidTimelineOptionsGroup
|
||||
local raidCooldownSpellValuesCache
|
||||
local bossAbilityValuesCache = {}
|
||||
|
||||
local function ClearOptionCaches()
|
||||
raidCooldownSpellValuesCache = nil
|
||||
bossAbilityValuesCache = {}
|
||||
end
|
||||
|
||||
local function Notify(rebuild)
|
||||
if rebuild then
|
||||
ClearOptionCaches()
|
||||
end
|
||||
if rebuild and raidTimelineOptionsGroup then
|
||||
local fresh = RT:GetOptionsGroup()
|
||||
raidTimelineOptionsGroup.name = fresh.name
|
||||
raidTimelineOptionsGroup.order = fresh.order
|
||||
raidTimelineOptionsGroup.childGroups = fresh.childGroups
|
||||
raidTimelineOptionsGroup.args = fresh.args
|
||||
end
|
||||
AceConfigRegistry:NotifyChange(ADDON_NAME)
|
||||
end
|
||||
|
||||
local function GetDrafts()
|
||||
HMGT._raidTimelineDraft = HMGT._raidTimelineDraft or {
|
||||
addEncounterId = "",
|
||||
addEncounterName = "",
|
||||
entries = {},
|
||||
}
|
||||
HMGT._raidTimelineDraft.entries = HMGT._raidTimelineDraft.entries or {}
|
||||
return HMGT._raidTimelineDraft
|
||||
end
|
||||
|
||||
local function TrimText(value)
|
||||
return tostring(value or ""):gsub("^%s+", ""):gsub("%s+$", "")
|
||||
end
|
||||
|
||||
local function GetEncounterDraft(encounterId)
|
||||
local drafts = GetDrafts()
|
||||
local key = tostring(tonumber(encounterId) or encounterId or "")
|
||||
drafts.entries[key] = drafts.entries[key] or {
|
||||
time = "",
|
||||
spellId = 0,
|
||||
alertText = "",
|
||||
playerName = "",
|
||||
entryType = "spell",
|
||||
triggerType = "time",
|
||||
actionType = "raidCooldown",
|
||||
targetSpec = "",
|
||||
bossAbilityId = "",
|
||||
bossAbilityBarName = "",
|
||||
castCount = "1",
|
||||
}
|
||||
return drafts.entries[key]
|
||||
end
|
||||
|
||||
local function GetTriggerTypeValues()
|
||||
return (RT.GetTriggerTypeValues and RT:GetTriggerTypeValues()) or {
|
||||
time = L["OPT_RT_TRIGGER_TIME"] or "Time",
|
||||
bossAbility = L["OPT_RT_TRIGGER_BOSS_ABILITY"] or "Boss ability",
|
||||
}
|
||||
end
|
||||
|
||||
local function GetActionTypeValues()
|
||||
return (RT.GetActionTypeValues and RT:GetActionTypeValues()) or {
|
||||
text = L["OPT_RT_ACTION_TEXT"] or "Text",
|
||||
raidCooldown = L["OPT_RT_ACTION_RAID_COOLDOWN"] or "Raid Cooldown",
|
||||
}
|
||||
end
|
||||
|
||||
local function GetEncounterEntry(encounterId, row)
|
||||
local encounter = encounterId and RT:GetEncounter(encounterId)
|
||||
return encounter and encounter.entries and encounter.entries[row] or nil
|
||||
end
|
||||
|
||||
local function GetTargetFieldLabel(kind, isAddRow)
|
||||
return (isAddRow and (L["OPT_RT_ADD_PLAYER"] or "Target")) or (L["OPT_RT_ENTRY_PLAYER"] or "Target")
|
||||
end
|
||||
|
||||
local function GetTargetFieldDesc(kind)
|
||||
return L["OPT_RT_ADD_PLAYER_DESC"] or "Optional. Comma-separated player names or variables like Group1, Group8, GroupEven, GroupOdd."
|
||||
end
|
||||
|
||||
local function FormatEntryTime(value)
|
||||
return RT.FormatTimelineClock and RT:FormatTimelineClock(value) or tostring(value or "")
|
||||
end
|
||||
|
||||
local function GetBossAbilityValues(encounterId)
|
||||
local encounterKey = tostring(tonumber(encounterId) or encounterId or 0)
|
||||
if bossAbilityValuesCache[encounterKey] then
|
||||
return bossAbilityValuesCache[encounterKey]
|
||||
end
|
||||
local values = RT.GetBossAbilityValues and RT:GetBossAbilityValues(encounterId) or { [""] = L["OPT_RT_NO_BOSS_ABILITY"] or "No boss ability" }
|
||||
bossAbilityValuesCache[encounterKey] = values
|
||||
return values
|
||||
end
|
||||
|
||||
local function GetDraftTriggerType(encounterId)
|
||||
local draft = GetEncounterDraft(encounterId)
|
||||
draft.triggerType = tostring(draft.triggerType or "time")
|
||||
return draft.triggerType == "bossAbility" and "bossAbility" or "time"
|
||||
end
|
||||
|
||||
local function GetDraftActionType(encounterId)
|
||||
local draft = GetEncounterDraft(encounterId)
|
||||
draft.actionType = tostring(draft.actionType or "raidCooldown")
|
||||
return draft.actionType == "text" and "text" or "raidCooldown"
|
||||
end
|
||||
|
||||
local function GetSpellName(spellId)
|
||||
local sid = tonumber(spellId)
|
||||
if not sid or sid <= 0 then return nil end
|
||||
if C_Spell and type(C_Spell.GetSpellName) == "function" then
|
||||
local name = C_Spell.GetSpellName(sid)
|
||||
if type(name) == "string" and name ~= "" then
|
||||
return name
|
||||
end
|
||||
end
|
||||
if type(GetSpellInfo) == "function" then
|
||||
local name = GetSpellInfo(sid)
|
||||
if type(name) == "string" and name ~= "" then
|
||||
return name
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function GetSpellIcon(spellId)
|
||||
local sid = tonumber(spellId)
|
||||
if not sid or sid <= 0 then return nil end
|
||||
if HMGT_SpellData and type(HMGT_SpellData.GetSpellIcon) == "function" then
|
||||
local icon = HMGT_SpellData.GetSpellIcon(sid)
|
||||
if icon and icon ~= "" then
|
||||
return icon
|
||||
end
|
||||
end
|
||||
if C_Spell and type(C_Spell.GetSpellTexture) == "function" then
|
||||
local icon = C_Spell.GetSpellTexture(sid)
|
||||
if icon and icon ~= "" then
|
||||
return icon
|
||||
end
|
||||
end
|
||||
local _, _, icon = GetSpellInfo(sid)
|
||||
return icon
|
||||
end
|
||||
|
||||
local function GetRaidCooldownSpellValues()
|
||||
if raidCooldownSpellValuesCache then
|
||||
return raidCooldownSpellValuesCache
|
||||
end
|
||||
local values = { [0] = L["OPT_RT_NO_SPELL"] or "No spell" }
|
||||
local seen = { [0] = true }
|
||||
for _, entry in ipairs(HMGT_SpellData and HMGT_SpellData.RaidCooldowns or {}) do
|
||||
local spellId = tonumber(entry and entry.spellId)
|
||||
if spellId and spellId > 0 and not seen[spellId] then
|
||||
seen[spellId] = true
|
||||
local spellName = GetSpellName(spellId) or tostring(entry.name or ("Spell " .. spellId))
|
||||
local icon = GetSpellIcon(spellId)
|
||||
values[spellId] = icon and icon ~= ""
|
||||
and string.format("|T%s:16:16:0:0|t %s (%d)", tostring(icon), spellName, spellId)
|
||||
or string.format("%s (%d)", spellName, spellId)
|
||||
end
|
||||
end
|
||||
raidCooldownSpellValuesCache = values
|
||||
return values
|
||||
end
|
||||
|
||||
local function GetDifficultyLabel(key)
|
||||
if key == "lfr" then return L["OPT_RT_DIFF_LFR"] or "LFR" end
|
||||
if key == "heroic" then return L["OPT_RT_DIFF_HEROIC"] or "HC" end
|
||||
if key == "mythic" then return L["OPT_RT_DIFF_MYTHIC"] or "Mythic" end
|
||||
return L["OPT_RT_DIFF_NORMAL"] or "Normal"
|
||||
end
|
||||
|
||||
local function GetEncounterLabel(encounterId)
|
||||
local encounter = RT:GetEncounter(encounterId)
|
||||
local name = TrimText(encounter and encounter.name or "")
|
||||
if name == "" then
|
||||
name = L["OPT_RT_ENCOUNTER"] or "Encounter"
|
||||
end
|
||||
return string.format("%s (%d)", name, tonumber(encounterId) or 0)
|
||||
end
|
||||
|
||||
local function GetBossTreeLabel(encounterId)
|
||||
local encounter = RT:GetEncounter(encounterId)
|
||||
local name = TrimText(encounter and encounter.name or "")
|
||||
if name == "" then
|
||||
name = L["OPT_RT_ENCOUNTER"] or "Encounter"
|
||||
end
|
||||
return string.format("%s (%d)", name, #(encounter and encounter.entries or {}))
|
||||
end
|
||||
|
||||
local function GetRaidBuckets()
|
||||
local buckets, raidNames = {}, {}
|
||||
for _, encounterId in ipairs(RT:GetEncounterIds()) do
|
||||
local encounter = RT:GetEncounter(encounterId)
|
||||
if encounter then
|
||||
local journalInstanceId, instanceName = RT:GetEncounterInstanceInfo(encounterId)
|
||||
local raidName = tostring(encounter.instanceName or instanceName or (L["OPT_RT_RAID_DEFAULT"] or "Encounter"))
|
||||
if not buckets[raidName] then
|
||||
buckets[raidName] = {
|
||||
key = tostring(journalInstanceId or raidName),
|
||||
ids = {},
|
||||
difficulties = { lfr = {}, normal = {}, heroic = {}, mythic = {} },
|
||||
}
|
||||
table.insert(raidNames, raidName)
|
||||
end
|
||||
table.insert(buckets[raidName].ids, encounterId)
|
||||
for _, difficultyKey in ipairs(DIFFICULTY_KEYS) do
|
||||
if encounter.difficulties and encounter.difficulties[difficultyKey] == true then
|
||||
table.insert(buckets[raidName].difficulties[difficultyKey], encounterId)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(raidNames)
|
||||
for _, raidName in ipairs(raidNames) do
|
||||
table.sort(buckets[raidName].ids)
|
||||
for _, difficultyKey in ipairs(DIFFICULTY_KEYS) do
|
||||
table.sort(buckets[raidName].difficulties[difficultyKey])
|
||||
end
|
||||
end
|
||||
return raidNames, buckets
|
||||
end
|
||||
|
||||
local function BuildEntryEditorArgs(encounterId)
|
||||
local args = {
|
||||
entriesHeader = {
|
||||
type = "header",
|
||||
order = 20,
|
||||
name = L["OPT_RT_ENCOUNTERS_HEADER"] or "Encounter timelines",
|
||||
},
|
||||
addTime = {
|
||||
type = "input", order = 21, width = 0.7, name = L["OPT_RT_ADD_TIME"] or "Time (MM:SS)",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
get = function() return tostring(GetEncounterDraft(encounterId).time or "") end,
|
||||
set = function(_, val) GetEncounterDraft(encounterId).time = val end,
|
||||
hidden = function() return GetDraftTriggerType(encounterId) == "bossAbility" end,
|
||||
},
|
||||
addTriggerType = {
|
||||
type = "select", order = 22, width = 0.8, name = L["OPT_RT_TRIGGER"] or "Trigger",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
values = GetTriggerTypeValues,
|
||||
get = function() return GetDraftTriggerType(encounterId) end,
|
||||
set = function(_, val)
|
||||
local draft = GetEncounterDraft(encounterId)
|
||||
draft.triggerType = (tostring(val or "") == "bossAbility") and "bossAbility" or "time"
|
||||
if draft.triggerType == "time" then
|
||||
draft.bossAbilityId = ""
|
||||
draft.bossAbilityBarName = ""
|
||||
draft.castCount = "1"
|
||||
end
|
||||
Notify(false)
|
||||
end,
|
||||
},
|
||||
addActionType = {
|
||||
type = "select", order = 22.1, width = 1.0, name = L["OPT_RT_ACTION"] or "Action",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
values = GetActionTypeValues,
|
||||
get = function() return GetDraftActionType(encounterId) end,
|
||||
set = function(_, val)
|
||||
local draft = GetEncounterDraft(encounterId)
|
||||
draft.actionType = (tostring(val or "") == "text") and "text" or "raidCooldown"
|
||||
if draft.actionType == "text" then
|
||||
draft.spellId = 0
|
||||
end
|
||||
Notify(false)
|
||||
end,
|
||||
},
|
||||
addSpellId = {
|
||||
type = "select", order = 23, width = 1.2, name = L["OPT_RT_ADD_SPELL"] or "Spell",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
values = GetRaidCooldownSpellValues,
|
||||
get = function() return math.max(0, tonumber(GetEncounterDraft(encounterId).spellId) or 0) end,
|
||||
set = function(_, val) GetEncounterDraft(encounterId).spellId = math.max(0, tonumber(val) or 0) end,
|
||||
hidden = function() return GetDraftActionType(encounterId) ~= "raidCooldown" end,
|
||||
},
|
||||
addCastCount = {
|
||||
type = "input", order = 23.1, width = 0.7, name = L["OPT_RT_CAST_COUNT"] or "Cast count",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
desc = L["OPT_RT_CAST_COUNT_DESC"] or "Use a number, All, Odd, or Even.",
|
||||
get = function() return RT:FormatCastCountSelector(GetEncounterDraft(encounterId).castCount or "1") end,
|
||||
set = function(_, val) GetEncounterDraft(encounterId).castCount = RT:NormalizeCastCountSelector(val) end,
|
||||
hidden = function() return GetDraftTriggerType(encounterId) ~= "bossAbility" end,
|
||||
},
|
||||
addBossAbilityBarName = {
|
||||
type = "input", order = 23.2, width = 1.2, name = L["OPT_RT_BOSS_BAR_NAME"] or "Bossmod bar name",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
get = function() return tostring(GetEncounterDraft(encounterId).bossAbilityBarName or "") end,
|
||||
set = function(_, val) GetEncounterDraft(encounterId).bossAbilityBarName = tostring(val or "") end,
|
||||
hidden = function() return GetDraftTriggerType(encounterId) ~= "bossAbility" end,
|
||||
},
|
||||
addAlertText = {
|
||||
type = "input", order = 24, width = 1.2, name = L["OPT_RT_ADD_TEXT"] or "Custom text",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
get = function() return tostring(GetEncounterDraft(encounterId).alertText or "") end,
|
||||
set = function(_, val) GetEncounterDraft(encounterId).alertText = tostring(val or "") end,
|
||||
hidden = function()
|
||||
return GetDraftActionType(encounterId) ~= "text"
|
||||
end,
|
||||
},
|
||||
addPlayerName = {
|
||||
type = "input", order = 25, width = 1.2,
|
||||
name = function() return GetTargetFieldLabel(GetDraftActionType(encounterId), true) end,
|
||||
desc = function() return GetTargetFieldDesc(GetDraftActionType(encounterId)) end,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
get = function()
|
||||
local draft = GetEncounterDraft(encounterId)
|
||||
return tostring(draft.playerName or draft.targetSpec or "")
|
||||
end,
|
||||
set = function(_, val)
|
||||
local draft = GetEncounterDraft(encounterId)
|
||||
draft.playerName = tostring(val or "")
|
||||
draft.targetSpec = tostring(val or "")
|
||||
end,
|
||||
},
|
||||
addEntry = {
|
||||
type = "execute", order = 26, width = "full", name = L["OPT_RT_ADD_ENTRY"] or "Add entry",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
func = function()
|
||||
local draft = GetEncounterDraft(encounterId)
|
||||
local ok = RT:AddDetailedEntry(encounterId, draft)
|
||||
if ok then
|
||||
draft.time, draft.spellId, draft.alertText, draft.playerName, draft.entryType, draft.triggerType, draft.actionType, draft.targetSpec, draft.bossAbilityId, draft.bossAbilityBarName, draft.castCount = "", 0, "", "", "spell", "time", "raidCooldown", "", "", "", "1"
|
||||
Notify(true)
|
||||
else
|
||||
HMGT:Print(L["OPT_RT_ADD_ENTRY_INVALID"] or "HMGT: invalid raid timeline entry")
|
||||
end
|
||||
end,
|
||||
},
|
||||
addBreak = { type = "description", order = 27, width = "full", name = " " },
|
||||
}
|
||||
|
||||
for entryRow = 1, MAX_ENTRY_ROWS do
|
||||
local order = 40 + (entryRow * 10)
|
||||
args["entryTime_" .. entryRow] = {
|
||||
type = "input", order = order, width = 0.7,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
name = function() return entryRow == 1 and (L["OPT_RT_ENTRY_TIME"] or "Time") or "" end,
|
||||
get = function() local entry = GetEncounterEntry(encounterId, entryRow); return entry and FormatEntryTime(entry.time or 0) or "" end,
|
||||
set = function(_, val)
|
||||
if not RT:SetEntryField(encounterId, entryRow, "time", val) then
|
||||
HMGT:Print(L["OPT_RT_INVALID_TIME"] or "HMGT: invalid time")
|
||||
end
|
||||
Notify(false)
|
||||
end,
|
||||
hidden = function()
|
||||
local entry = GetEncounterEntry(encounterId, entryRow)
|
||||
return not entry or RT:GetTriggerType(entry) == "bossAbility"
|
||||
end,
|
||||
}
|
||||
args["entryTriggerType_" .. entryRow] = {
|
||||
type = "select", order = order + 1, width = 0.8,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
name = function() return entryRow == 1 and (L["OPT_RT_TRIGGER"] or "Trigger") or "" end,
|
||||
values = GetTriggerTypeValues,
|
||||
get = function() local entry = GetEncounterEntry(encounterId, entryRow); return entry and RT:GetTriggerType(entry) or "time" end,
|
||||
set = function(_, val) RT:SetEntryField(encounterId, entryRow, "triggerType", val); Notify(false) end,
|
||||
hidden = function() return GetEncounterEntry(encounterId, entryRow) == nil end,
|
||||
}
|
||||
args["entryActionType_" .. entryRow] = {
|
||||
type = "select", order = order + 1.1, width = 1.0,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
name = function() return entryRow == 1 and (L["OPT_RT_ACTION"] or "Action") or "" end,
|
||||
values = GetActionTypeValues,
|
||||
get = function() local entry = GetEncounterEntry(encounterId, entryRow); return entry and RT:GetActionType(entry) or "raidCooldown" end,
|
||||
set = function(_, val) RT:SetEntryField(encounterId, entryRow, "actionType", val); Notify(false) end,
|
||||
hidden = function() return GetEncounterEntry(encounterId, entryRow) == nil end,
|
||||
}
|
||||
args["entrySpell_" .. entryRow] = {
|
||||
type = "select", order = order + 2, width = 1.2,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
name = function() return entryRow == 1 and (L["OPT_RT_ENTRY_SPELL"] or "Spell") or "" end,
|
||||
values = GetRaidCooldownSpellValues,
|
||||
get = function() local entry = GetEncounterEntry(encounterId, entryRow); return entry and math.max(0, tonumber(entry.spellId) or 0) or 0 end,
|
||||
set = function(_, val)
|
||||
if not RT:SetEntryField(encounterId, entryRow, "spellId", math.max(0, tonumber(val) or 0)) then
|
||||
HMGT:Print(L["OPT_RT_INVALID_SPELL"] or "HMGT: invalid spell ID")
|
||||
end
|
||||
Notify(false)
|
||||
end,
|
||||
hidden = function() local entry = GetEncounterEntry(encounterId, entryRow); return not entry or RT:GetActionType(entry) ~= "raidCooldown" end,
|
||||
}
|
||||
args["entryCastCount_" .. entryRow] = {
|
||||
type = "input", order = order + 2.1, width = 0.7,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
name = function() return entryRow == 1 and (L["OPT_RT_CAST_COUNT"] or "Cast count") or "" end,
|
||||
desc = L["OPT_RT_CAST_COUNT_DESC"] or "Use a number, All, Odd, or Even.",
|
||||
get = function() local entry = GetEncounterEntry(encounterId, entryRow); return entry and RT:FormatCastCountSelector(entry.castCount) or "1" end,
|
||||
set = function(_, val) RT:SetEntryField(encounterId, entryRow, "castCount", val); Notify(false) end,
|
||||
hidden = function() local entry = GetEncounterEntry(encounterId, entryRow); return not entry or RT:GetTriggerType(entry) ~= "bossAbility" end,
|
||||
}
|
||||
args["entryBossAbilityBarName_" .. entryRow] = {
|
||||
type = "input", order = order + 2.2, width = 1.2,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
name = function() return entryRow == 1 and (L["OPT_RT_BOSS_BAR_NAME"] or "Bossmod bar name") or "" end,
|
||||
get = function() local entry = GetEncounterEntry(encounterId, entryRow); return entry and tostring(entry.bossAbilityBarName or "") or "" end,
|
||||
set = function(_, val) RT:SetEntryField(encounterId, entryRow, "bossAbilityBarName", val); Notify(false) end,
|
||||
hidden = function() local entry = GetEncounterEntry(encounterId, entryRow); return not entry or RT:GetTriggerType(entry) ~= "bossAbility" end,
|
||||
}
|
||||
args["entryText_" .. entryRow] = {
|
||||
type = "input", order = order + 3, width = 1.2,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
name = function() return entryRow == 1 and (L["OPT_RT_ENTRY_TEXT"] or "Custom text") or "" end,
|
||||
get = function() local entry = GetEncounterEntry(encounterId, entryRow); return entry and tostring(entry.alertText or "") or "" end,
|
||||
set = function(_, val) RT:SetEntryField(encounterId, entryRow, "alertText", val); Notify(false) end,
|
||||
hidden = function()
|
||||
local entry = GetEncounterEntry(encounterId, entryRow)
|
||||
if not entry then
|
||||
return true
|
||||
end
|
||||
return RT:GetActionType(entry) ~= "text"
|
||||
end,
|
||||
}
|
||||
args["entryPlayer_" .. entryRow] = {
|
||||
type = "input", order = order + 4, width = 1.1,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
name = function()
|
||||
local entry = GetEncounterEntry(encounterId, entryRow)
|
||||
return entryRow == 1 and GetTargetFieldLabel(entry and RT:GetActionType(entry) or "raidCooldown", false) or ""
|
||||
end,
|
||||
desc = function()
|
||||
local entry = GetEncounterEntry(encounterId, entryRow)
|
||||
return GetTargetFieldDesc(entry and RT:GetActionType(entry) or "raidCooldown")
|
||||
end,
|
||||
get = function()
|
||||
local entry = GetEncounterEntry(encounterId, entryRow)
|
||||
if not entry then return "" end
|
||||
return tostring(entry.playerName or entry.targetSpec or "")
|
||||
end,
|
||||
set = function(_, val)
|
||||
local entry = GetEncounterEntry(encounterId, entryRow)
|
||||
if entry then
|
||||
RT:SetEntryField(encounterId, entryRow, "playerName", val)
|
||||
RT:SetEntryField(encounterId, entryRow, "targetSpec", val)
|
||||
Notify(false)
|
||||
end
|
||||
end,
|
||||
hidden = function() return GetEncounterEntry(encounterId, entryRow) == nil end,
|
||||
}
|
||||
args["entryDelete_" .. entryRow] = {
|
||||
type = "execute", order = order + 5, width = 0.6, name = REMOVE or "Remove",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
func = function() RT:RemoveEntry(encounterId, entryRow); Notify(true) end,
|
||||
hidden = function() return GetEncounterEntry(encounterId, entryRow) == nil end,
|
||||
}
|
||||
args["entryBreak_" .. entryRow] = {
|
||||
type = "description", order = order + 6, width = "full", name = " ",
|
||||
hidden = function() return GetEncounterEntry(encounterId, entryRow) == nil end,
|
||||
}
|
||||
end
|
||||
return args
|
||||
end
|
||||
|
||||
local function BuildEncounterDetailGroup(encounterId)
|
||||
local encounter = RT:GetEncounter(encounterId)
|
||||
if not encounter then return nil end
|
||||
|
||||
local args = {
|
||||
header = { type = "header", order = 1, name = GetEncounterLabel(encounterId) },
|
||||
encounterId = {
|
||||
type = "description", order = 2, width = "full",
|
||||
name = string.format("|cffffd100%s|r: %d", L["OPT_RT_ADD_ENCOUNTER_ID"] or "Encounter ID", tonumber(encounterId) or 0),
|
||||
},
|
||||
raidName = {
|
||||
type = "description", order = 3, width = "full",
|
||||
name = function()
|
||||
local _, instanceName = RT:GetEncounterInstanceInfo(encounterId)
|
||||
local current = RT:GetEncounter(encounterId)
|
||||
return string.format("|cffffd100%s|r: %s", L["OPT_RT_RAID_NAME"] or "Raid", tostring((current and current.instanceName) or instanceName or (L["OPT_RT_RAID_DEFAULT"] or "Encounter")))
|
||||
end,
|
||||
},
|
||||
encounterName = {
|
||||
type = "input", order = 4, width = "full", name = L["OPT_RT_ENCOUNTER_NAME"] or "Name",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
get = function() local current = RT:GetEncounter(encounterId); return current and tostring(current.name or "") or "" end,
|
||||
set = function(_, val) local current = RT:GetEncounter(encounterId); if current then current.name = tostring(val or ""); Notify(true) end end,
|
||||
},
|
||||
difficultyHeader = { type = "header", order = 5, name = L["OPT_RT_DIFFICULTY_HEADER"] or "Difficulties" },
|
||||
}
|
||||
|
||||
local diffOrder = 6
|
||||
for _, difficultyKey in ipairs(DIFFICULTY_KEYS) do
|
||||
args["difficulty_" .. difficultyKey] = {
|
||||
type = "toggle", order = diffOrder, width = 0.75, name = GetDifficultyLabel(difficultyKey),
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
get = function()
|
||||
local current = RT:GetEncounter(encounterId)
|
||||
local difficulties = current and current.difficulties or nil
|
||||
return difficulties and difficulties[difficultyKey] ~= false or false
|
||||
end,
|
||||
set = function(_, val)
|
||||
local current = RT:GetEncounter(encounterId)
|
||||
if current then
|
||||
current.difficulties = current.difficulties or {}
|
||||
current.difficulties[difficultyKey] = val and true or false
|
||||
Notify(true)
|
||||
end
|
||||
end,
|
||||
}
|
||||
diffOrder = diffOrder + 0.01
|
||||
end
|
||||
|
||||
args.openTimelineEditor = {
|
||||
type = "execute", order = 7, width = "full", name = L["OPT_RT_OPEN_EDITOR"] or "Open timeline",
|
||||
func = function() if RT.OpenTimelineEditor then RT:OpenTimelineEditor(encounterId) end end,
|
||||
}
|
||||
args.runTest = {
|
||||
type = "execute",
|
||||
order = 7.5,
|
||||
width = "full",
|
||||
name = function()
|
||||
if RT:IsTestRunning(encounterId) then
|
||||
return L["OPT_RT_STOP_TEST"] or "Stop test"
|
||||
end
|
||||
return L["OPT_RT_START_TEST"] or "Start timeline test"
|
||||
end,
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
func = function()
|
||||
if RT:IsTestRunning(encounterId) then
|
||||
RT:StopEncounterTest()
|
||||
else
|
||||
RT:StartEncounterTest(encounterId)
|
||||
end
|
||||
Notify()
|
||||
end,
|
||||
}
|
||||
args.testHint = {
|
||||
type = "description",
|
||||
order = 7.6,
|
||||
width = "full",
|
||||
name = L["OPT_RT_TEST_HINT"] or "Runs the encounter timeline outside of combat so you can verify assignments, whispers and debug output.",
|
||||
}
|
||||
args.editorHint = {
|
||||
type = "description", order = 8, width = "full",
|
||||
name = L["OPT_RT_TIMELINE_HINT"] or "Click the bar to add a cooldown. Drag markers horizontally to change the time. Mousewheel scrolls, Ctrl+Mousewheel zooms.",
|
||||
}
|
||||
args.encounterDelete = {
|
||||
type = "execute", order = 9, width = "full", name = DELETE or "Delete",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
confirm = function() return string.format(L["OPT_RT_DELETE_ENCOUNTER_CONFIRM"] or "Delete raid timeline for encounter %d?", tonumber(encounterId) or 0) end,
|
||||
func = function() RT:RemoveEncounter(encounterId); Notify(true) end,
|
||||
}
|
||||
args.entryBreak = { type = "description", order = 10, width = "full", name = " " }
|
||||
|
||||
for key, value in pairs(BuildEntryEditorArgs(encounterId)) do
|
||||
args[key] = value
|
||||
end
|
||||
|
||||
return { type = "group", name = GetBossTreeLabel(encounterId), args = args }
|
||||
end
|
||||
|
||||
local function BuildRaidTreeArgs()
|
||||
local args = {}
|
||||
local raidNames, buckets = GetRaidBuckets()
|
||||
|
||||
for raidIndex, raidName in ipairs(raidNames) do
|
||||
local raidKey = tostring(buckets[raidName].key or raidIndex)
|
||||
args["raid_" .. raidKey] = {
|
||||
type = "group",
|
||||
order = 100 + raidIndex,
|
||||
name = raidName,
|
||||
childGroups = "tree",
|
||||
args = {
|
||||
description = {
|
||||
type = "description",
|
||||
order = 1,
|
||||
width = "full",
|
||||
name = string.format("|cffffd100%s|r: %s", L["OPT_RT_RAID_NAME"] or "Raid", raidName),
|
||||
},
|
||||
raidId = {
|
||||
type = "description",
|
||||
order = 2,
|
||||
width = "full",
|
||||
name = string.format("|cffffd100%s|r: %s", L["OPT_RT_RAID_ID"] or "Raid ID", tostring(buckets[raidName].key or raidIndex)),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local addedEncounterIds = {}
|
||||
local bossOrder = 10
|
||||
for _, difficultyKey in ipairs(DIFFICULTY_KEYS) do
|
||||
local encounterIds = buckets[raidName].difficulties[difficultyKey] or {}
|
||||
for _, encounterId in ipairs(encounterIds) do
|
||||
if not addedEncounterIds[encounterId] then
|
||||
local encounterGroup = BuildEncounterDetailGroup(encounterId)
|
||||
if encounterGroup then
|
||||
encounterGroup.order = bossOrder
|
||||
args["raid_" .. raidKey].args["boss_" .. tostring(encounterId)] = encounterGroup
|
||||
bossOrder = bossOrder + 1
|
||||
addedEncounterIds[encounterId] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return args, #raidNames
|
||||
end
|
||||
|
||||
function RT:GetOptionsGroup()
|
||||
local drafts = GetDrafts()
|
||||
local raidTreeArgs, raidCount = BuildRaidTreeArgs()
|
||||
|
||||
local group = {
|
||||
type = "group",
|
||||
name = L["OPT_RT_NAME"] or "Raid Timeline",
|
||||
order = 4,
|
||||
childGroups = "tree",
|
||||
args = {
|
||||
general = {
|
||||
type = "group",
|
||||
order = 1,
|
||||
name = L["OPT_RT_SECTION_GENERAL"] or "General",
|
||||
args = {
|
||||
enabled = {
|
||||
type = "toggle",
|
||||
order = 1,
|
||||
width = "full",
|
||||
name = L["OPT_RT_ENABLED"] or "Enable Raid Timeline",
|
||||
get = function() return RT:GetSettings().enabled == true end,
|
||||
set = function(_, val)
|
||||
RT:GetSettings().enabled = val and true or false
|
||||
if val then RT:Enable() else RT:Disable() end
|
||||
end,
|
||||
},
|
||||
leadTime = {
|
||||
type = "range",
|
||||
order = 2,
|
||||
min = 1,
|
||||
max = 15,
|
||||
step = 1,
|
||||
name = L["OPT_RT_LEAD_TIME"] or "Warning lead time",
|
||||
get = function() return tonumber(RT:GetSettings().leadTime) or 5 end,
|
||||
set = function(_, val) RT:GetSettings().leadTime = math.floor((tonumber(val) or 5) + 0.5) end,
|
||||
},
|
||||
assignmentLeadTime = {
|
||||
type = "range",
|
||||
order = 2.1,
|
||||
min = 0,
|
||||
max = 60,
|
||||
step = 1,
|
||||
name = L["OPT_RT_ASSIGNMENT_LEAD_TIME"] or "Assignment lead time",
|
||||
desc = L["OPT_RT_ASSIGNMENT_LEAD_TIME_DESC"] or "How many seconds before the planned use the assigned player should be selected.",
|
||||
get = function()
|
||||
local settings = RT:GetSettings()
|
||||
return tonumber(settings.assignmentLeadTime) or tonumber(settings.leadTime) or 5
|
||||
end,
|
||||
set = function(_, val)
|
||||
RT:GetSettings().assignmentLeadTime = math.floor((tonumber(val) or 5) + 0.5)
|
||||
end,
|
||||
},
|
||||
header = { type = "header", order = 3, name = L["OPT_RT_ALERT_HEADER"] or "Alert frame" },
|
||||
unlocked = {
|
||||
type = "toggle", order = 4, width = "double", name = L["OPT_RT_UNLOCK"] or "Unlock alert frame",
|
||||
get = function() return RT:GetSettings().unlocked == true end,
|
||||
set = function(_, val)
|
||||
RT:GetSettings().unlocked = val and true or false
|
||||
RT:ApplyAlertStyle()
|
||||
if val then RT:ShowPreview() end
|
||||
end,
|
||||
},
|
||||
preview = {
|
||||
type = "toggle", order = 5, width = "double", name = L["OPT_RT_PREVIEW"] or "Preview alert",
|
||||
get = function() return RT.previewAlertActive == true end,
|
||||
set = function(_, val) if val then RT:ShowPreview() else RT:HideAlert() end end,
|
||||
},
|
||||
alertFont = {
|
||||
type = "select", order = 6, width = 1.4, name = L["OPT_FONT"] or "Typeface",
|
||||
dialogControl = "LSM30_Font",
|
||||
values = AceGUIWidgetLSMlists and AceGUIWidgetLSMlists.font or (LSM and LSM:HashTable("font")) or {},
|
||||
get = function() return RT:GetSettings().alertFont or "Friz Quadrata TT" end,
|
||||
set = function(_, val) RT:GetSettings().alertFont = val; RT:ApplyAlertStyle() end,
|
||||
},
|
||||
alertFontSize = {
|
||||
type = "range", order = 7, min = 10, max = 72, step = 1, width = 1.0, name = L["OPT_FONT_SIZE"] or "Font size",
|
||||
get = function() return tonumber(RT:GetSettings().alertFontSize) or 30 end,
|
||||
set = function(_, val) RT:GetSettings().alertFontSize = math.floor((tonumber(val) or 30) + 0.5); RT:ApplyAlertStyle() end,
|
||||
},
|
||||
alertFontOutline = {
|
||||
type = "select", order = 8, width = 1.0, name = L["OPT_FONT_OUTLINE"] or "Font outline",
|
||||
values = FONT_OUTLINE_VALUES,
|
||||
get = function() return RT:GetSettings().alertFontOutline or "OUTLINE" end,
|
||||
set = function(_, val) RT:GetSettings().alertFontOutline = val; RT:ApplyAlertStyle() end,
|
||||
},
|
||||
alertColor = {
|
||||
type = "color", order = 9, width = 0.8, name = L["OPT_RT_ALERT_COLOR"] or "Text colour", hasAlpha = true,
|
||||
get = function()
|
||||
local color = RT:GetSettings().alertColor or {}
|
||||
return color.r or 1, color.g or 0.82, color.b or 0.15, color.a or 1
|
||||
end,
|
||||
set = function(_, r, g, b, a)
|
||||
local color = RT:GetSettings().alertColor
|
||||
color.r, color.g, color.b, color.a = r, g, b, a
|
||||
RT:ApplyAlertStyle()
|
||||
end,
|
||||
},
|
||||
desc = {
|
||||
type = "description", order = 10, width = "full",
|
||||
name = L["OPT_RT_DESC"] or "Create encounter timelines here and open the interactive Ace3 timeline editor for visual planning.",
|
||||
},
|
||||
},
|
||||
},
|
||||
manage = {
|
||||
type = "group",
|
||||
order = 2,
|
||||
name = L["OPT_RT_SECTION_MANAGE"] or "Manage encounters",
|
||||
args = {
|
||||
header = { type = "header", order = 1, name = L["OPT_RT_ENCOUNTERS_HEADER"] or "Encounter timelines" },
|
||||
addEncounterId = {
|
||||
type = "input", order = 2, width = 0.8, name = L["OPT_RT_ADD_ENCOUNTER_ID"] or "Encounter ID",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
get = function() return tostring(drafts.addEncounterId or "") end,
|
||||
set = function(_, val) drafts.addEncounterId = val end,
|
||||
},
|
||||
addEncounterName = {
|
||||
type = "input", order = 3, width = 1.2, name = L["OPT_RT_ADD_ENCOUNTER_NAME"] or "Encounter name",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
get = function() return tostring(drafts.addEncounterName or "") end,
|
||||
set = function(_, val) drafts.addEncounterName = val end,
|
||||
},
|
||||
addEncounter = {
|
||||
type = "execute", order = 5, width = "full", name = L["OPT_RT_ADD_ENCOUNTER"] or "Add encounter",
|
||||
disabled = function() return not RT:IsLocalEditor() end,
|
||||
func = function()
|
||||
if RT:AddEncounter(drafts.addEncounterId, drafts.addEncounterName) then
|
||||
drafts.addEncounterId, drafts.addEncounterName = "", ""
|
||||
Notify(true)
|
||||
else
|
||||
HMGT:Print(L["OPT_RT_INVALID_ENCOUNTER"] or "HMGT: invalid encounter ID")
|
||||
end
|
||||
end,
|
||||
},
|
||||
summary = {
|
||||
type = "description", order = 6, width = "full",
|
||||
name = function()
|
||||
if raidCount == 0 then return L["OPT_RT_EMPTY"] or "No encounter timelines configured yet." end
|
||||
return string.format("|cffffd100%s|r: %d", L["OPT_RT_ENCOUNTERS_HEADER"] or "Encounter timelines", #RT:GetEncounterIds())
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if raidCount == 0 then
|
||||
group.args.empty = {
|
||||
type = "group",
|
||||
order = 50,
|
||||
name = L["OPT_RT_EMPTY"] or "No encounter timelines configured yet.",
|
||||
args = {
|
||||
description = { type = "description", order = 1, width = "full", name = L["OPT_RT_EMPTY"] or "No encounter timelines configured yet." },
|
||||
},
|
||||
}
|
||||
else
|
||||
for key, value in pairs(raidTreeArgs) do
|
||||
group.args[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
return group
|
||||
end
|
||||
|
||||
HMGT_Config:RegisterOptionsProvider("raidTimeline", function()
|
||||
raidTimelineOptionsGroup = raidTimelineOptionsGroup or RT:GetOptionsGroup()
|
||||
ClearOptionCaches()
|
||||
local fresh = RT:GetOptionsGroup()
|
||||
raidTimelineOptionsGroup.name = fresh.name
|
||||
raidTimelineOptionsGroup.order = fresh.order
|
||||
raidTimelineOptionsGroup.childGroups = fresh.childGroups
|
||||
raidTimelineOptionsGroup.args = fresh.args
|
||||
return {
|
||||
path = "raidTimeline",
|
||||
order = 4,
|
||||
group = raidTimelineOptionsGroup,
|
||||
}
|
||||
end)
|
||||
Reference in New Issue
Block a user