Repository navigation
Expand file tree
/
Copy pathCore.lua
More file actions
325 lines (298 loc) · 15.8 KB
/
Copy pathCore.lua
File metadata and controls
325 lines (298 loc) · 15.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
-------------------------------------------------------------------------------
-- Core.lua -- "Gotta Queue 'Em All": saved settings, season data, slash
-- command and the settings page. The window itself lives in UI/.
--
-- /gotta, /gqea open / close the window
-- /gotta settings the settings page (Options > AddOns)
-- /gotta help these commands
-- /gotta welcome the welcome screen again
-- /gotta keystone preview of the keystone window
-- /gotta keyprobe whether key levels can be read from titles (for bug reports)
-- /gotta deserter preview of the Keystone Deserter marks (on / off)
-- /gotta rate preview of the rating window after a key
-- /gotta ratings your player ratings (list, expiry, delete)
-------------------------------------------------------------------------------
local _, ns = ...
local TITLE = "Gotta Queue 'Em All"
local issecretvalue = issecretvalue or function() return false end
local db
function ns.Print(msg)
print("|cffd2a24c" .. TITLE .. "|r " .. msg)
end
function ns.DB() return db end
-- Events the window only needs while it is open: listed here, registered
-- when it opens (ns.SetLive(true)) and dropped when it closes. Closed, the
-- addon does no work, apart from the alerts' two Group Finder events
-- (UI/Alert.lua: invites and new applicants come while it is closed).
local live = {}
function ns.Live(frame, events) live[#live + 1] = { frame, events } end
function ns.SetLive(on)
for _, l in ipairs(live) do
local frame = l[1]
for _, e in ipairs(l[2]) do
pcall(on and frame.RegisterEvent or frame.UnregisterEvent, frame, e) -- unknown events are skipped
end
end
end
-- Classes that bring Bloodlust / Heroism and a battle res.
ns.LUST_CLASS = { SHAMAN = true, MAGE = true, HUNTER = true, EVOKER = true }
ns.BREZ_CLASS = { DRUID = true, DEATHKNIGHT = true, WARLOCK = true, PALADIN = true }
-------------------------------------------------------------------------------
-- Saved settings
-------------------------------------------------------------------------------
local DEFAULTS = {
showMinimap = true,
-- Alerts (UI/Alert.lua): when you're invited, when someone applies.
alertInvite = true, alertApply = true,
inviteCard = true, -- invites answered in our card (UI/Invite.lua), not Blizzard's window
alertScreen = "glow", -- the gold edge: "glow" or "off" ("both" and "toast" from before: glow, off)
alertSound = true, alertSoundKit = "chime",
alertFlash = true, -- the taskbar icon, while WoW is in the background
markStale = true, -- "Listed a while" on old, nearly empty groups
leaderRegion = true, -- a flag for the leader's realm (UI/Region.lua)
footerVault = true, -- Great Vault and affixes in the footer
-- The keystone window at the Font of Power (UI/Keystone.lua).
keystoneWindow = true, -- ours, not Blizzard's
keystoneAutoStart = true, -- Activate: the pull timer, then the key starts at 0
keystoneReadyFirst = true, -- Activate: a ready check first (leader or assistant)
pullTimer = 10, -- seconds, the slider's last value
keystoneWide = true, -- two columns (fits any screen at full size); off: one, like the design
-- Player ratings (UI/Ratings.lua): Good / Bad for Mythic+ players, only on this PC.
ratePrompt = true, -- the rating window after a key
rateHideBad = true, -- groups of leaders rated Bad left out of the Mythic+ search
rateExpire = 6, -- months a rating counts (0: forever)
}
-- Settings of the 0.x sidebar addon, and logs of pre-release test builds;
-- nothing uses them any more.
local LEGACY = { "enabled", "width", "height", "dimPercent", "dimAlpha", "showLeaderScore", "showDungeonIcon",
"showBadges", "fitParty", "fitLust", "fitBrez", "fitNotDeclined", "presets", "createPresets",
"createLookTitle", "keyMin", "keyMax", "keyprobe", "raidprobe", "raidcreate", "raidlist", "uidebug",
"createTitlePlaystyle",
"createLust", "createBrez", "moreOpen" }
local function LoadDB()
if type(GottaQueueEmAllDB) ~= "table" then GottaQueueEmAllDB = {} end
db = GottaQueueEmAllDB
for _, k in ipairs(LEGACY) do db[k] = nil end
for k, v in pairs(DEFAULTS) do if db[k] == nil then db[k] = v end end
end
-------------------------------------------------------------------------------
-- Season dungeons and your best keys
-------------------------------------------------------------------------------
local DUNGEON_CATEGORY = GROUP_FINDER_CATEGORY_ID_DUNGEONS or 2
local challengeByInstance, challengeByName = {}, {}
local function BuildChallengeLookup()
wipe(challengeByInstance); wipe(challengeByName)
if not (C_ChallengeMode and C_ChallengeMode.GetMapTable) then return end
for _, cid in ipairs(C_ChallengeMode.GetMapTable() or {}) do
local name, _, _, _, _, instanceMapID = C_ChallengeMode.GetMapUIInfo(cid)
if name then challengeByName[name] = cid end
if instanceMapID then challengeByInstance[instanceMapID] = cid end
end
end
local function ChallengeMapForGroup(groupID, groupName)
for _, act in ipairs(C_LFGList.GetAvailableActivities(DUNGEON_CATEGORY, groupID) or {}) do
local ai = C_LFGList.GetActivityInfoTable(act)
local cid = ai and ai.mapID and challengeByInstance[ai.mapID]
if cid then return cid end
end
return challengeByName[groupName]
end
-- This season's Mythic+ dungeons: { id = activity group, name, cid = challenge map }.
function ns.SeasonGroups()
local out = {}
if not (Enum and Enum.LFGListFilter) then return out end
BuildChallengeLookup()
local flags = bit.bor(Enum.LFGListFilter.CurrentSeason, Enum.LFGListFilter.PvE)
for _, id in ipairs(C_LFGList.GetAvailableActivityGroups(DUNGEON_CATEGORY, flags) or {}) do
local name = C_LFGList.GetActivityGroupInfo(id)
if name and not issecretvalue(name) then
out[#out + 1] = { id = id, name = name, cid = ChallengeMapForGroup(id, name) }
end
end
table.sort(out, function(a, b) return a.name < b.name end)
return out
end
-- Your season best in a dungeon: level, inTime, score.
function ns.BestKey(cid)
if not (cid and C_MythicPlus and C_MythicPlus.GetSeasonBestForMap) then return end
local inTime, overTime = C_MythicPlus.GetSeasonBestForMap(cid)
local level, timed
if inTime and inTime.level then level, timed = inTime.level, true end
if overTime and overTime.level and (not level or overTime.level > level) then level, timed = overTime.level, false end
local score
if C_MythicPlus.GetSeasonBestAffixScoreInfoForMap then
local _, bonus = C_MythicPlus.GetSeasonBestAffixScoreInfoForMap(cid)
if type(bonus) == "number" and bonus > 0 then score = bonus end
end
return level, timed, score
end
-- How many levels a run would upgrade the key: +3 within 60 % of the timer,
-- +2 within 80 %, +1 in time, 0 over time (the game's thresholds; the
-- result is worked out here from the run's time, not read from the game).
function ns.Upgrades(sec, limit)
if not (sec and limit and limit > 0) then return nil end
if sec <= limit * 0.6 then return 3 end
if sec <= limit * 0.8 then return 2 end
if sec <= limit then return 1 end
return 0
end
-- Your runs in a dungeon this season, for the dungeon chips:
-- score the dungeon's points in your rating
-- limit the timer in seconds
-- inTime best timed run { level, sec, up } (nil: none)
-- over best over-time run, only when above the timed one
-- counted the run your score counts (the game's rating summary; else the
-- timed one, else the over-time one), with .timed
function ns.BestRuns(cid)
if not (cid and C_MythicPlus and C_MythicPlus.GetSeasonBestForMap) then return nil end
local t = {}
local _, _, limit = C_ChallengeMode.GetMapUIInfo(cid)
t.limit = type(limit) == "number" and limit > 0 and limit or nil
local function Run(info, timed)
if type(info) ~= "table" or type(info.level) ~= "number" or info.level <= 0 then return nil end
local sec = type(info.durationSec) == "number" and info.durationSec or nil
return { level = info.level, sec = sec, timed = timed,
up = timed and (ns.Upgrades(sec, t.limit) or 1) or 0 }
end
local ok, inTime, overTime = pcall(C_MythicPlus.GetSeasonBestForMap, cid)
if not ok then return nil end
t.inTime = Run(inTime, true)
local over = Run(overTime, false)
if over and (not t.inTime or over.level > t.inTime.level) then t.over = over end
-- Score and the counted run from the rating summary.
local sum = C_PlayerInfo and C_PlayerInfo.GetPlayerMythicPlusRatingSummary
and C_PlayerInfo.GetPlayerMythicPlusRatingSummary("player")
for _, r in ipairs(type(sum) == "table" and type(sum.runs) == "table" and sum.runs or {}) do
if r.challengeModeID == cid then
if type(r.mapScore) == "number" and r.mapScore > 0 then t.score = r.mapScore end
if type(r.bestRunLevel) == "number" and r.bestRunLevel > 0 then
local timed = r.finishedSuccess and true or false
local sec = type(r.bestRunDurationMS) == "number" and r.bestRunDurationMS / 1000 or nil
t.counted = { level = r.bestRunLevel, sec = sec, timed = timed,
up = timed and (ns.Upgrades(sec, t.limit) or 1) or 0 }
end
break
end
end
if not t.score and C_MythicPlus.GetSeasonBestAffixScoreInfoForMap then
local _, bonus = C_MythicPlus.GetSeasonBestAffixScoreInfoForMap(cid)
if type(bonus) == "number" and bonus > 0 then t.score = bonus end
end
t.counted = t.counted or t.inTime or t.over
if not t.counted then return nil end
return t
end
-------------------------------------------------------------------------------
-- Settings page (Options > AddOns > Gotta Queue 'Em All)
-------------------------------------------------------------------------------
local category
-- The settings page in the window (UI/Settings.lua): the gear, the minimap
-- button's right-click, /gotta settings.
function ns.OpenSettings()
if InCombatLockdown() then ns.Print("settings open after combat."); return end
if ns.UI and ns.UI.ShowSettings then ns.UI.ShowSettings() else ns.OpenBlizzardSettings() end
end
-- Blizzard's Options > AddOns page.
function ns.OpenBlizzardSettings()
if InCombatLockdown() then ns.Print("settings open after combat."); return end
if category and Settings and Settings.OpenToCategory then Settings.OpenToCategory(category:GetID()) end
end
local function RegisterSettings()
if not (Settings and Settings.RegisterVerticalLayoutCategory and Settings.RegisterAddOnSetting) then return end
local cat, layout = Settings.RegisterVerticalLayoutCategory(TITLE)
local function Header(text)
if layout and CreateSettingsListSectionHeaderInitializer then
layout:AddInitializer(CreateSettingsListSectionHeaderInitializer(text))
end
end
local function Button(name, text, onClick, tip)
if layout and CreateSettingsButtonInitializer then
layout:AddInitializer(CreateSettingsButtonInitializer(name, text, onClick, tip, true))
end
end
Header("Window")
Button("Window", "Open", function()
if SettingsPanel and SettingsPanel:IsShown() then HideUIPanel(SettingsPanel) end
if ns.UI and ns.UI.Toggle then ns.UI.Toggle() end
end, "Opens the Gotta Queue 'Em All window. Also: /gotta, the minimap button, or your hotkey.")
Button("Size and position", "Reset", function()
if ns.UI and ns.UI.ResetGeometry then ns.UI.ResetGeometry() end
end, "Puts the window back to its default size in the middle of the screen.")
Button("All settings", "Open in the window", function()
if SettingsPanel and SettingsPanel:IsShown() then HideUIPanel(SettingsPanel) end
ns.OpenSettings()
end, "Alerts, the group list, the footer and the window: all settings are on the window's own settings page (the gear).")
Header("Opening the window")
local var = "GottaQueueEmAll_showMinimap"
local setting = Settings.RegisterAddOnSetting(cat, var, "showMinimap", db, "boolean", "Minimap button", DEFAULTS.showMinimap)
Settings.SetOnValueChangedCallback(var, function()
if ns.UI and ns.UI.Launcher then ns.UI.Launcher.Update() end
end)
Settings.CreateCheckbox(cat, setting,
"A minimap button that opens the window. Drag it to move it around the minimap; right-click opens these settings.")
Button("Hotkey", "Key Bindings", function()
pcall(function() -- Blizzard's key bindings page, where it can be found
local kb = SettingsPanel:GetCategory(Settings.KEYBINDINGS_CATEGORY_ID)
if kb then SettingsPanel:SelectCategory(kb) end
end)
end, "Set it in the window: the Hotkey button at the top (click, then press a key). Or in Key Bindings > AddOns > Gotta Queue 'Em All.")
Settings.RegisterAddOnCategory(cat)
category = cat
end
-------------------------------------------------------------------------------
-- Boot and slash command
-------------------------------------------------------------------------------
local events = CreateFrame("Frame")
events:RegisterEvent("PLAYER_LOGIN")
events:SetScript("OnEvent", function(self)
self:UnregisterAllEvents()
LoadDB()
local ok, err = pcall(RegisterSettings)
if not ok then ns.Print("settings page unavailable (" .. tostring(err) .. ")") end
if C_MythicPlus and C_MythicPlus.RequestMapInfo then C_MythicPlus.RequestMapInfo() end
-- The Group Finder's activities: Blizzard builds its category buttons
-- (which + Create clicks) and its dungeon list from them.
if C_LFGList.RequestAvailableActivities then C_LFGList.RequestAvailableActivities() end
end)
SLASH_GOTTAQUEUEEMALL1 = "/gotta"
SLASH_GOTTAQUEUEEMALL2 = "/gqea"
local function Help()
ns.Print("commands:")
print(" /gotta - open / close the window (also /gqea)")
print(" /gotta settings - the settings page")
print(" /gotta welcome - the welcome screen again")
print(" /gotta keystone - preview the keystone window")
print(" /gotta keyprobe - check whether key levels can be read (for bug reports)")
print(" /gotta deserter - preview how Keystone Deserters are shown (on / off)")
print(" /gotta rate - preview the rating window after a key")
print(" /gotta ratings - your player ratings")
end
SlashCmdList.GOTTAQUEUEEMALL = function(msg)
if not db then return end
msg = strtrim((msg or ""):lower())
if msg == "" then
if ns.UI and ns.UI.Toggle then ns.UI.Toggle() end
elseif msg == "settings" or msg == "options" or msg == "config" then
ns.OpenSettings()
elseif msg == "welcome" and ns.UI and ns.UI.ShowWelcome then
ns.UI.ShowWelcome()
elseif msg == "keystone" and ns.UI and ns.UI.Keystone then
ns.UI.Keystone.Preview()
elseif msg == "keyprobe" and ns.UI and ns.UI.KeyProbe then
ns.UI.KeyProbe.Run()
elseif msg == "rate" and ns.UI and ns.UI.Ratings then
ns.UI.Ratings.Preview()
elseif msg == "ratings" and ns.UI and ns.UI.Ratings then
ns.OpenSettings()
ns.UI.Ratings.ShowPage()
elseif msg == "deserter" then
-- Made-up Keystone Deserters (you, some groups, some applicants) to
-- see how they look. Until switched off or the next /reload.
ns.deserterPreview = not ns.deserterPreview
ns.Print("deserter preview " .. (ns.deserterPreview and "|cffff7a9eon|r: you, every third group leader, a member of the next group and every other applicant are marked."
or "off."))
if ns.UI and ns.UI.RefreshDeserter then ns.UI.RefreshDeserter() end
else
Help()
end
end