This repository has been archived by the owner on Aug 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathChallenge.lua
361 lines (333 loc) · 11.2 KB
/
Challenge.lua
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
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
--[[--
@module MyDungeonsBook
]]
--[[--
Challenge
@section Challenge
]]
local L = LibStub("AceLocale-3.0"):GetLocale("MyDungeonsBook");
local LGIST = LibStub:GetLibrary("LibGroupInSpecT-1.1");
--[[--
Check if player is in challenge mode.
@return[type=bool]
]]
function MyDungeonsBook:IsInChallengeMode()
local _, _, difficulty, _, _, _, _, _ = GetInstanceInfo();
local _, elapsedTime = GetWorldElapsedTime(1);
return C_ChallengeMode.IsChallengeModeActive() and difficulty == 8 and elapsedTime >= 0;
end
--[[--
Create a skeleton for a new dungeon challenge
@param[type=number] id identifier for new dungeon challenge
]]
function MyDungeonsBook:InitNewDungeonChallenge(id)
self.db.char.challenges[id] = {
id = id,
challengeInfo = {},
gameInfo = {},
encounters = {},
players = {
player = {},
party1 = {},
party2 = {},
party3 = {},
party4 = {}
},
mechanics = {},
misc = {
isFavorite = false,
loot = {}
}
};
self:DebugPrint(string.format("New challenge is init with id %s", id));
end
function MyDungeonsBook:GetUnitTalents(unitId)
local talents = {};
local exportStream = ExportUtil.MakeExportDataStream();
local specID = GetInspectSpecialization(unitId);
local configID = unitId == "player" and C_ClassTalents.GetActiveConfigID() or -1;
local configInfo = C_Traits.GetConfigInfo(configID);
if (not configInfo) then
return "", {};
end
local treeID = configInfo.treeIDs[1];
local treeInfo = C_Traits.GetTreeInfo(configID, treeID);
local treeHash = C_Traits.GetTreeHash(treeInfo.ID);
local serializationVersion = (C_Traits.GetLoadoutSerializationVersion ~= nil and C_Traits.GetLoadoutSerializationVersion()) or 1;
local function GetActiveEntryIndex(treeNode)
for i, entryID in ipairs(treeNode.entryIDs) do
if(entryID == treeNode.activeEntry.entryID) then
return i;
end
end
return 0;
end
local bitWidthHeaderVersion = 8;
local bitWidthSpecID = 16;
local bitWidthRanksPurchased = 6;
-- HEADER
exportStream:AddValue(bitWidthHeaderVersion, serializationVersion);
exportStream:AddValue(bitWidthSpecID, specID);
for i, hashVal in ipairs(treeHash) do
exportStream:AddValue(8, hashVal);
end
-- CONTENT
local treeNodes = C_Traits.GetTreeNodes(treeID);
for i, treeNodeID in ipairs(treeNodes) do
local treeNode = C_Traits.GetNodeInfo(configID, treeNodeID);
local isNodeSelected = treeNode.ranksPurchased > 0 or treeNode.activeRank > 0;
local isPartiallyRanked = treeNode.ranksPurchased ~= treeNode.maxRanks;
local isChoiceNode = treeNode.type == Enum.TraitNodeType.Selection;
exportStream:AddValue(1, isNodeSelected and 1 or 0);
if(isNodeSelected) then
exportStream:AddValue(1, isPartiallyRanked and 1 or 0);
if(isPartiallyRanked) then
exportStream:AddValue(bitWidthRanksPurchased, treeNode.ranksPurchased);
end
local entryId = treeNode.activeEntry.entryID;
local entry = C_Traits.GetEntryInfo(configID, entryId);
if (entry) then
local definitionInfo = C_Traits.GetDefinitionInfo(entry.definitionID);
if (definitionInfo) then
local spellId = definitionInfo.spellID;
if (spellId) then
tinsert(talents, {
spellId = spellId;
maxRanks = treeNode.maxRanks;
activeRank = treeNode.activeRank;
displayType = entry.type;
group = treeNode.posX > 10000 and "spec" or "class";
});
end
end
end
exportStream:AddValue(1, isChoiceNode and 1 or 0);
if(isChoiceNode) then
local entryIndex = GetActiveEntryIndex(treeNode);
if(entryIndex <= 0 or entryIndex > 4) then
error("Error exporting tree node " .. treeNode.ID .. ". The active choice node entry index (" .. entryIndex .. ") is out of bounds. ");
end
-- store entry index as zero-index
exportStream:AddValue(2, entryIndex - 1);
end
end
end
local exportString = exportStream:GetExportString();
return exportString, talents;
end
--[[--
Parse info about player or any other party member (`unit`).
@param[type=unitId] unitId
]]
function MyDungeonsBook:ParseUnitInfoWithWowApi(unitId)
if (not UnitExists(unitId)) then
return {};
end
local unitInfoFromLGI = LGIST:GetCachedInfo(UnitGUID(unitId));
local _, _, class = UnitClass(unitId);
local name, realm = UnitFullName(unitId);
local _, race = UnitRace(unitId);
local spec = GetInspectSpecialization(unitId);
if (spec == 0) then
spec = nil;
end
local role = UnitGroupRolesAssigned(unitId);
if (not realm) then
local _, myRealm = UnitFullName("player");
realm = myRealm;
end
local items = {};
for i = 1, 17 do
local itemLink = GetInventoryItemLink(unitId, i);
items[i] = itemLink;
end
local talentsStr, talents = self:GetUnitTalents();
local unitInfo = {
name = name,
role = role,
race = race,
class = class,
spec = spec,
realm = realm,
items = items,
gender = unitInfoFromLGI.gender,
talents = talents,
talentsStr = talentsStr,
misc = {},
covenant = {}
};
if (unitId == "player") then
local covenantId = C_Covenants.GetActiveCovenantID();
local activeSoulbindId = C_Soulbinds.GetActiveSoulbindID();
local activeSoulbindData = C_Soulbinds.GetSoulbindData(activeSoulbindId);
local conduits = {};
for _, conduit in pairs(activeSoulbindData.tree.nodes) do
if (conduit.failureRenownRequirement == nil and conduit.state == 3) then
tinsert(conduits, conduit);
end
end
unitInfo.covenant.id = covenantId;
unitInfo.covenant.soulbind = {
id = activeSoulbindId,
name = activeSoulbindData.name,
textureKit = activeSoulbindData.textureKit,
conduits = conduits
};
end
return unitInfo;
end
--[[--
@param[type=GUID] guid
]]
function MyDungeonsBook:UpdateUnitInfo(guid)
local id = self.db.char.activeChallengeId;
if (not id) then
return false;
end
local unit = self:GetPartyUnitByGuid(guid);
if (not unit) then
self:DebugPrint(string.format("Unit with guid %s not found", guid));
return false;
end
local unitInfo = self:ParseUnitInfoWithWowApi(unit);
if (unitInfo and unitInfo.talents and #unitInfo.talents > 0 and self.db.char.challenges[id].players[unit] and self.db.char.challenges[id].players[unit].talents and #self.db.char.challenges[id].players[unit].talents > 0) then
wipe(self.db.char.challenges[id].players[unit].talents);
end
self.db.char.challenges[id].players[unit] = self:MergeTables(self.db.char.challenges[id].players[unit], unitInfo);
self:DebugPrint(string.format("Info about %s is stored", unit));
return true;
end
--[[--
Delete info about challenge from local DB
@param[type=number] challengeId
]]
function MyDungeonsBook:Challenge_Delete(challengeId)
local challenge = self.db.char.challenges[challengeId];
if (challenge) then
if (self.activeChallengeId == challengeId) then
self.activeChallengeId = nil;
self.challengeDetailsFrame.frame:Hide();
end
wipe(self.db.char.challenges[challengeId]);
self.db.char.challenges[challengeId] = nil;
if (self.challengesTable) then
self.challengesTable:SetData(self:ChallengesFrame_GetDataForTable());
end
self:LogPrint(string.format(L["Challenge #%s is deleted successfully"], challengeId));
end
end
--[[--
@param[type=number] id
@return[type=?table]
]]
function MyDungeonsBook:Challenge_GetById(id)
if (not id) then
id = self.db.char.activeChallengeId;
end
return self.db.char.challenges[id];
end
--[[--
@param[type=number] challengeId
@param[type=string] mechanicKey
@return[type=?table]
]]
function MyDungeonsBook:Challenge_Mechanic_GetById(challengeId, mechanicKey)
local challenge = self:Challenge_GetById(challengeId);
if (not challenge) then
return nil;
end
if (challengeId == self.activeChallengeId) then
if (not self.activeChallengeMechanics) then
self.activeChallengeMechanics = challenge.mechanics;
if (type(challenge.mechanics) ~= "table") then
self.activeChallengeMechanics = select(2, self:Decompress(challenge.mechanics));
end
end
if (not self.activeChallengeMechanics[mechanicKey]) then
return nil;
end
if (type(self.activeChallengeMechanics[mechanicKey]) ~= "table") then
self.activeChallengeMechanics[mechanicKey] = select(2, self:Decompress(self.activeChallengeMechanics[mechanicKey]));
end
return self.activeChallengeMechanics[mechanicKey];
end
local mechanics = challenge.mechanics;
if (type(challenge.mechanics) ~= "table") then
mechanics = select(2, self:Decompress(challenge.mechanics));
end
if (not mechanics[mechanicKey]) then
return nil;
end
if (type(mechanics[mechanicKey]) ~= "table") then
mechanics[mechanicKey] = select(2, self:Decompress(mechanics[mechanicKey]));
end
return mechanics[mechanicKey];
end
--[[--
@param[type=number] challengeId
@param[type=string] msg
@param[type=unitId] unitId
]]
function MyDungeonsBook:UpdatePartyMemberAnimaPowers(challengeId, msg, unitId)
if (not self.db.char.challenges[challengeId].players[unitId]) then
return;
end
self.db.char.challenges[challengeId].players[unitId].misc.animaPowers = self.db.char.challenges[challengeId].players[unitId].misc.animaPowers or {
ids = {},
powers = {}
};
for i = 1, 5 do
local _, icon, count, _, _, _, _, _, _, spellId = UnitAura(unitId, i, "MAW");
if (icon) then
local powerInfo = {icon = icon, count = count, slot = i, spellId = spellId};
if (self.db.char.challenges[challengeId].players[unitId].misc.animaPowers.ids[spellId]) then
local inserted = false;
for _, power in pairs(self.db.char.challenges[challengeId].players[unitId].misc.animaPowers.powers) do
if (power.spellId == spellId) then
if (power.count ~= count) then
power.count = count;
if (not inserted) then
tinsert(self.db.char.challenges[challengeId].players[unitId].misc.animaPowers.powers, powerInfo);
inserted = true;
end
end
end
end
else
self.db.char.challenges[challengeId].players[unitId].misc.animaPowers.ids[spellId] = true;
tinsert(self.db.char.challenges[challengeId].players[unitId].misc.animaPowers.powers, powerInfo);
end
end
end
end
--[[--
@return[type=?number]
]]
function MyDungeonsBook:GetLastChallengeId()
local id = nil;
local startTime = 0;
for _, challenge in pairs(self.db.char.challenges) do
if (challenge.challengeInfo ~= nil and challenge.challengeInfo.startTime ~= nil and challenge.challengeInfo.startTime > startTime) then
startTime = challenge.challengeInfo.startTime;
id = challenge.id;
end
end
return id or "";
end
function MyDungeonsBook:CleanupOlderChallenges()
local cleanupOlder = self.db.profile.performance.cleanupOlder;
if (cleanupOlder == nil or cleanupOlder == -1) then
return;
end
local currentTime = time();
local sum = 0;
for _, challenge in pairs(self.db.char.challenges) do
if (challenge.challengeInfo ~= nil and challenge.challengeInfo.startTime ~= nil and currentTime - challenge.challengeInfo.startTime > cleanupOlder and not challenge.misc.isFavorite) then
self:Challenge_Delete(challenge.id);
sum = sum + 1;
end
end
if (sum ~= 0) then
self:LogPrint(string.format(L["%s challenge(s) are deleted"], sum));
end
end