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.

337 lines
12 KiB

3 years ago
local ADDON_NAME, Internal = ...
local External = _G[ADDON_NAME]
local L = Internal.L
local DEFAULT_COMPLETED_FUNCTION = "return self:IsFlaggedCompleted()"
local DEFAULT_TEXT_FUNCTION = [[return self:IsCompleted() and Images.COMPLETE or "-"]]
local DEFAULT_CLICK_FUNCTION = [[self:SetFlaggedCompleted(not self:IsFlaggedCompleted())]]
-- DST doesnt effect daily/weekly/halfweekly resets so these should always be accurate
local SECONDS_PER_HOUR = 60 * 60
local SECONDS_PER_WEEK = 60 * 60 * 24 * 7
local SECONDS_PER_HALF_WEEK = 60 * 60 * 24 * 3.5
local function GetNextWeeklyResetTimestamp()
return math.floor((GetServerTime() + C_DateAndTime.GetSecondsUntilWeeklyReset()) / SECONDS_PER_HOUR + 0.5) * SECONDS_PER_HOUR
end
local function GetNextDailyResetTimestamp()
return math.floor((GetServerTime() + C_DateAndTime.GetSecondsUntilDailyReset()) / SECONDS_PER_HOUR + 0.5) * SECONDS_PER_HOUR
end
Internal.GetNextWeeklyResetTimestamp = GetNextWeeklyResetTimestamp
Internal.GetNextDailyResetTimestamp = GetNextDailyResetTimestamp
local function ADDON_LOADED(event, addon)
if addon == ADDON_NAME then
BtWTodoData = BtWTodoData or {}
BtWTodoCategories = BtWTodoCategories or {}
BtWTodoCharacters = BtWTodoCharacters or {}
BtWTodoCache = BtWTodoCache or {}
BtWTodoCache.quests = BtWTodoCache.quests or {}
BtWTodoCache.currencies = BtWTodoCache.currencies or {}
BtWTodoCache.factions = BtWTodoCache.factions or {}
BtWTodoCache.callings = BtWTodoCache.callings or {[1] = {}, [2] = {}, [3] = {}, [4] = {}}
BtWTodoCache.resets = BtWTodoCache.resets or {}
Internal.UnregisterEvent("ADDON_LOADED", ADDON_LOADED)
end
end
Internal.RegisterEvent("ADDON_LOADED", ADDON_LOADED, -10)
local function HandleResets()
local season = C_MythicPlus.GetCurrentSeason()
local nextDailyReset = GetNextDailyResetTimestamp()
local nextWeeklyReset = GetNextWeeklyResetTimestamp()
local nextHalfWeeklyReset = nextWeeklyReset - SECONDS_PER_HALF_WEEK
if season == -1 then -- During login it isnt available
C_Timer.After(5, HandleResets)
elseif season ~= BtWTodoCache.resets.season then
-- print("SEASON_RESET", season, BtWTodoCache.resets.season)
External.TriggerEvent("SEASON_RESET")
BtWTodoCache.resets.season = season
end
-- We do +10 for each of these as the reset times can fluctuate, most I've seen
-- is 1 second more but no harm in doing 10 since it should jump by 1 week/3.5 days/1 day
if nextWeeklyReset > (BtWTodoCache.resets.weekly or 0) + 10 then
-- print("WEEKLY_RESET", nextWeeklyReset, (BtWTodoCache.resets.weekly or 0))
External.TriggerEvent("WEEKLY_RESET")
External.TriggerEvent("HALF_WEEKLY_RESET", true)
External.TriggerEvent("DAILY_RESET", true)
BtWTodoCache.resets.weekly = nextWeeklyReset
BtWTodoCache.resets.halfweekly = nextHalfWeeklyReset
BtWTodoCache.resets.daily = nextDailyReset
elseif nextHalfWeeklyReset > (BtWTodoCache.resets.halfweekly or 0) + 10 then
-- print("HALF_WEEKLY_RESET", nextHalfWeeklyReset, (BtWTodoCache.resets.halfweekly or 0))
External.TriggerEvent("HALF_WEEKLY_RESET", false)
BtWTodoCache.resets.halfweekly = nextHalfWeeklyReset
elseif nextDailyReset > (BtWTodoCache.resets.daily or 0) + 10 then
-- print("DAILY_RESET", nextDailyReset, (BtWTodoCache.resets.daily or 0))
External.TriggerEvent("DAILY_RESET", false)
BtWTodoCache.resets.daily = nextDailyReset
end
end
Internal.RegisterEvent("PLAYER_LOGIN", HandleResets)
Internal.RegisterEvent("CHAT_MSG_SYSTEM", function (event, ...)
if ... == DAILY_QUESTS_RESET then
-- This should happen as the C_DateAndTime.GetSecondsUntilDailyReset() timer rolls over
-- but may happen slightly early and since its annoying to test that we are just gonna
-- deal with that possibility
local dailyReset = C_DateAndTime.GetSecondsUntilDailyReset()
if dailyReset > 10 then
dailyReset = 1
end
C_Timer.After(dailyReset, HandleResets)
end
end)
local function HalfWeeklyResetTimer(runReset)
local timer = C_DateAndTime.GetSecondsUntilWeeklyReset() - SECONDS_PER_HALF_WEEK
if timer >= 0 then
C_Timer.After(timer, function () HalfWeeklyResetTimer(true) end)
end
if runReset then
HandleResets()
end
end
HalfWeeklyResetTimer()
local registeredTodos = {}
function External.RegisterTodo(todo)
if type(todo) ~= "table" then
error("External.RegisterTodo(todo): todo must be a table")
elseif todo.id == nil then
error("External.RegisterTodo(todo): todo.id is required")
elseif type(todo.id) ~= "string" then
error("External.RegisterTodo(todo): todo.id must be string")
elseif registeredTodos[todo.id] then
error("External.RegisterTodo(todo): " .. todo.id .. " is already registered")
elseif todo.name == nil then
error("External.RegisterTodo(todo): todo.name is required")
end
todo.registered = true
registeredTodos[todo.id] = todo
end
function External.RegisterTodos(todos)
for _,todo in ipairs(todos) do
External.RegisterTodo(todo)
end
end
function Internal.GetTodo(id)
return BtWTodoData[id] or registeredTodos[id]
end
function Internal.GetTodoByUUID(uuid)
local todo = BtWTodoData[uuid] or registeredTodos[uuid]
if todo then
return todo
end
for i=1,#BtWTodoData do
local todo = BtWTodoData[i]
if todo and todo.uuid == uuid then
return todo
end
end
end
-- Used for reverting todos to their registered version
function Internal.GetRegisteredTodo(id)
return registeredTodos[id]
end
function Internal.CheckTodoForUpdate(id, current)
local current, new = current, current
if not current and BtWTodoData[id] then
local data = BtWTodoData[id]
current, new = data.version or 0, data.version or 0
end
if registeredTodos[id] then
local data = registeredTodos[id]
current, new = current or data.version or 0, data.version or 0
end
return current ~= new, current, new
end
function Internal.GetTodoChangeLog(id, start)
if not registeredTodos[id] then
return
end
local result = {}
local source = registeredTodos[id].changeLog
if source then
for i=start or 1,#source do
local item = source[i]
if type(item) == "table" then
for _,line in ipairs(item) do
result[#result+1] = line
end
else
result[#result+1] = item
end
end
end
return result
end
local registeredCategories = {}
function External.RegisterCategory(category)
if type(category) ~= "table" then
error("External.RegisterCategory(category): category must be a table")
elseif category.id == nil then
error("External.RegisterCategory(category): category.id is required")
elseif type(category.id) ~= "string" then
error("External.RegisterCategory(category): category.id must be string")
elseif registeredCategories[category.id] then
error("External.RegisterCategory(category): " .. category.id .. " is already registered")
elseif category.name == nil then
error("External.RegisterCategory(category): category.name is required")
elseif category.color == nil then
error("External.RegisterCategory(category): category.color is required")
end
registeredCategories[category.id] = category
end
function External.RegisterCategories(items)
for _,item in ipairs(items) do
External.RegisterCategory(item)
end
end
function External.GetCategory(id)
local saved, registered = BtWTodoCategories[id], registeredCategories[id]
if type(saved) ~= "table" and type(registered) ~= "table" then
error("External.GetCategory(category): unknown category " .. tostring(id))
end
-- Clone the color, the config ui edits this color return from here, if we return the color
-- stored without cloning then when saving the color it'll always be considered the same
-- as the original registered color and not be saved
local color
if saved and saved.color then
color = CreateColor(unpack(saved.color))
else
color = CreateColor(registered.color:GetRGB())
end
return { id = id, name = saved and saved.name or registered.name, color = color }
end
function External.UpdateCategory(id, name, color)
local category = BtWTodoCategories[id]
if not category then
category = {}
BtWTodoCategories[id] = category
end
category.name = name or category.name
category.color = color and {color:GetRGBA()} or category.color
local registered = registeredCategories[id]
if registered then
if registered.name == category.name then
category.name = nil
end
if registered.color.r == category.color[1] and registered.color.g == category.color[2] and registered.color.b == category.color[3] then
category.color = nil
end
if next(category) == nil then
BtWTodoCategories[id] = nil
end
end
end
function External.ResetCategory(id)
BtWTodoCategories[id] = nil
end
function Internal.IterateCategories()
local tbl = {}
for id in pairs(BtWTodoCategories) do
tbl[id] = External.GetCategory(id)
end
for id in pairs(registeredCategories) do
if not tbl[id] then
tbl[id] = External.GetCategory(id)
end
end
return next, tbl, nil
end
function External.GetCategoryByName(name)
for id,category in pairs(registeredCategories) do
if category.name == name then
return id
end
end
end
function External.GetTodoName(id, dontError)
local tbl
if BtWTodoData[id] then
tbl = BtWTodoData[id]
else
tbl = registeredTodos[id]
end
if tbl == nil then
if not dontError then
error("External.GetTodoName(id): unknown todo " .. tostring(id))
else
return
end
end
return tbl.name
end
function Internal.IterateTodos()
local tbl = {}
for id,todo in pairs(BtWTodoData) do
tbl[id] = todo
end
for id,todo in pairs(registeredTodos) do
if not tbl[id] then
tbl[id] = todo
end
end
return next, tbl, nil
end
function External.CreateTodoByID(id)
local tbl
if BtWTodoData[id] then
tbl = BtWTodoData[id]
else
tbl = registeredTodos[id]
end
if tbl == nil then
error("External.CreateTodoByID(id): unknown todo " .. tostring(id))
end
local id, name, states, completed, text, click, tooltip = tbl.id, tbl.name, tbl.states, tbl.completed or DEFAULT_COMPLETED_FUNCTION, tbl.text or DEFAULT_TEXT_FUNCTION, tbl.click, tbl.tooltip
return Internal.CreateStateDriver(id, name, states, completed, text, click, tooltip)
end
function Internal.CompareTodos(a, b) -- Compare everything except id, and version data
if a.name ~= b.name then
return false
end
if #a.states ~= #b.states then
return false
end
for i=1,#a.states do
local aState, bState = a.states[i], b.states[i]
if aState.type ~= bState.type or aState.id ~= bState.id or type(aState.values) ~= type(bState.values) or (type(aState.values) == "table" and not tCompare(a.values, b.values, 3)) then
return false
end
end
if a.completed ~= b.completed or a.text ~= b.text or a.tooltip ~= b.tooltip or a.click ~= b.click then
return false
end
return true
end
function Internal.SaveTodo(tbl)
local id = tbl.id
if registeredTodos[id] and Internal.CompareTodos(tbl, registeredTodos[id]) then
BtWTodoData[id] = nil
else
BtWTodoData[id] = tbl
end
end