Mercurial > wow > askmrrobot
comparison Core.lua @ 57:01b63b8ed811 v21
total rewrite to version 21
author | yellowfive |
---|---|
date | Fri, 05 Jun 2015 11:05:15 -0700 |
parents | |
children | ee701ce45354 |
comparison
equal
deleted
inserted
replaced
56:75431c084aa0 | 57:01b63b8ed811 |
---|---|
1 -- AskMrRobot | |
2 -- Does cool stuff associated with askmrrobot.com: | |
3 -- Import/Export gear and optimization solutions from/to the website | |
4 -- Improve the combat logging experience and augment it with extra data not available directly in the log file | |
5 -- Team Optimizer convenience functionality | |
6 | |
7 AskMrRobot = LibStub("AceAddon-3.0"):NewAddon("AskMrRobot", "AceEvent-3.0", "AceComm-3.0", "AceConsole-3.0", "AceSerializer-3.0") | |
8 local Amr = AskMrRobot | |
9 Amr.Serializer = LibStub("AskMrRobot-Serializer") | |
10 | |
11 Amr.ADDON_NAME = "AskMrRobot" | |
12 | |
13 -- types of inter-addon messages that we receive, used to parcel them out to the proper handlers | |
14 Amr.MessageTypes = { | |
15 Version = "_V", | |
16 VersionRequest = "_VR", | |
17 Team = "_T" | |
18 } | |
19 | |
20 local L = LibStub("AceLocale-3.0"):GetLocale("AskMrRobot", true) | |
21 local AceGUI = LibStub("AceGUI-3.0") | |
22 | |
23 -- minimap icon and LDB support | |
24 local _amrLDB = LibStub("LibDataBroker-1.1"):NewDataObject(Amr.ADDON_NAME, { | |
25 type = "launcher", | |
26 text = "Ask Mr. Robot", | |
27 icon = "Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\icon", | |
28 OnClick = function(self, button, down) | |
29 if button == "LeftButton" then | |
30 if IsControlKeyDown() then | |
31 Amr:Wipe() | |
32 else | |
33 Amr:Toggle() | |
34 end | |
35 elseif button == "RightButton" then | |
36 Amr:EquipGearSet() | |
37 end | |
38 end, | |
39 OnTooltipShow = function(tt) | |
40 tt:AddLine("Ask Mr. Robot", 1, 1, 1); | |
41 tt:AddLine(" "); | |
42 tt:AddLine(L.MinimapTooltip) | |
43 end | |
44 }) | |
45 local _icon = LibStub("LibDBIcon-1.0") | |
46 | |
47 | |
48 -- initialize the database | |
49 local function initializeDb() | |
50 | |
51 local defaults = { | |
52 char = { | |
53 FirstUse = true, -- true if this is first time use, gets cleared after seeing the export help splash window | |
54 SubSpecs = {}, -- last seen subspecs for this character, used to deal with some ambiguous specs | |
55 Equipped = {}, -- for each spec group (1 or 2), slot id to item link | |
56 BagItems = {}, -- list of item links for bag | |
57 BankItems = {}, -- list of item links for bank | |
58 VoidItems = {}, -- list of item links for void storage | |
59 BagItemsAndCounts = {}, -- used mainly for the shopping list | |
60 BankItemsAndCounts = {}, -- used mainly for the shopping list | |
61 GearSets = {}, -- imported gear sets, key by spec group (1 or 2), slot id to item object | |
62 ExtraItemData = {}, -- for each spec group (1 or 2): mainly for legacy support, item id to object with socketColor and duplicateId information | |
63 ExtraGemData = {}, -- for each spec group (1 or 2): gem enchant id to gem display information, and data used to detect identical gems (mainly for legacy support) | |
64 ExtraEnchantData = {}, -- for each spec group (1 or 2): enchant id to enchant display information and material information | |
65 Logging = { -- character logging settings | |
66 Enabled = false, -- whether logging is currently on or not | |
67 LastZone = nil, -- last zone the player was in | |
68 LastDiff = nil, -- last difficulty for the last zone the player was in | |
69 LastWipe = nil -- last time a wipe was called by this player | |
70 }, | |
71 TeamOpt = { | |
72 AllItems = {}, -- all equippable items no matter where it is, list of item unique ids, used to determine when a player gains a new equippable item | |
73 History = {}, -- history of drops since joining the current group | |
74 Rolls = {}, -- current loot choices for a loot distribution in progress | |
75 Role = nil, -- Leader or Member, changes UI to the mode most appropriate for this user | |
76 Loot = {}, -- the last loot seen by the master looter | |
77 LootGuid = nil, -- guid of the last unit looted by the master looter, will be "container" if there is no target | |
78 LootInProgress = false -- true if looting is currently in progress | |
79 } | |
80 }, | |
81 profile = { | |
82 minimap = { -- minimap hide/show and position settings | |
83 hide = false | |
84 }, | |
85 window = {}, -- main window position settings | |
86 lootWindow = {}, -- loot window position settings | |
87 shopWindow = {}, -- shopping list window position settings | |
88 options = { | |
89 autoGear = false, -- auto-equip saved gear sets when changing specs | |
90 shopAh = false -- auto-show shopping list at AH | |
91 }, | |
92 Logging = { -- global logging settings | |
93 Auto = {} -- for each instanceId, for each difficultyId, true if auto-logging enabled | |
94 } | |
95 }, | |
96 global = { | |
97 Region = nil, -- region that this user is in, all characters on the same account should be the same region | |
98 Shopping = {}, -- shopping list data stored globally for access on any character | |
99 Logging = { -- a lot of log data is stored globally for simplicity, can only be raiding with one character at a time | |
100 Wipes = {}, -- times that a wipe was called | |
101 PlayerData = {}, -- player data gathered at fight start | |
102 PlayerExtras = {} -- player extra data like auras, gathered at fight start | |
103 }, | |
104 TeamOpt = { -- this stuff is stored globally in case a player e.g. switches to an alt in a raid group | |
105 LootGear = {}, -- gear info that needs to be transmitted with the next loot | |
106 Rankings = {}, -- last rankings imported by the loot ranker | |
107 RankingString = nil -- last ranking string imported, kept around for efficient serialization | |
108 } | |
109 } | |
110 } | |
111 | |
112 -- set defaults for auto-logging | |
113 for i, instanceId in ipairs(Amr.InstanceIdsOrdered) do | |
114 local byDiff = defaults.profile.Logging.Auto[instanceId] | |
115 if not byDiff then | |
116 byDiff = {} | |
117 defaults.profile.Logging.Auto[instanceId] = byDiff | |
118 end | |
119 | |
120 for k, difficultyId in pairs(Amr.Difficulties) do | |
121 if byDiff[difficultyId] == nil then | |
122 byDiff[difficultyId] = false | |
123 end | |
124 end | |
125 end | |
126 | |
127 Amr.db = LibStub("AceDB-3.0"):New("AskMrRobotDb2", defaults) | |
128 | |
129 Amr.db.RegisterCallback(Amr, "OnProfileChanged", "RefreshConfig") | |
130 Amr.db.RegisterCallback(Amr, "OnProfileCopied", "RefreshConfig") | |
131 Amr.db.RegisterCallback(Amr, "OnProfileReset", "RefreshConfig") | |
132 end | |
133 | |
134 function Amr:OnInitialize() | |
135 | |
136 initializeDb() | |
137 | |
138 Amr:RegisterChatCommand("amr", "SlashCommand") | |
139 | |
140 _icon:Register(Amr.ADDON_NAME, _amrLDB, self.db.profile.minimap) | |
141 | |
142 -- listen for inter-addon communication | |
143 self:RegisterComm(Amr.ChatPrefix, "OnCommReceived") | |
144 end | |
145 | |
146 local _enteredWorld = false | |
147 local _pendingInit = false | |
148 | |
149 function finishInitialize() | |
150 | |
151 -- record region, the only thing that we still can't get from the log file | |
152 Amr.db.global.Region = Amr.RegionNames[GetCurrentRegion()] | |
153 | |
154 -- make sure that some initialization is deferred until after PLAYER_ENTERING_WORLD event so that data we need is available; | |
155 -- also delay this initialization for a few extra seconds to deal with some event spam that is otherwise hard to identify and ignore when a player logs in | |
156 Amr.Wait(5, function() | |
157 Amr:InitializeVersions() | |
158 Amr:InitializeGear() | |
159 Amr:InitializeExport() | |
160 Amr:InitializeCombatLog() | |
161 Amr:InitializeTeamOpt() | |
162 end) | |
163 end | |
164 | |
165 function onPlayerEnteringWorld() | |
166 | |
167 _enteredWorld = true | |
168 | |
169 if _pendingInit then | |
170 finishInitialize() | |
171 _pendingInit = false | |
172 end | |
173 end | |
174 | |
175 function Amr:OnEnable() | |
176 | |
177 -- listen for changes to the snapshot enable state, and always make sure it is enabled if using the core AskMrRobot addon | |
178 self:RegisterMessage("AMR_SNAPSHOT_STATE_CHANGED", function(eventName, isEnabled) | |
179 if not isEnabled then | |
180 -- immediately re-enable on any attempt to disable | |
181 Amr.Serializer:EnableSnapshots() | |
182 end | |
183 end) | |
184 self.Serializer:EnableSnapshots() | |
185 | |
186 -- update based on current configuration whenever enabled | |
187 self:RefreshConfig() | |
188 | |
189 -- if we have fully entered the world, do initialization; otherwise wait for PLAYER_ENTERING_WORLD to continue | |
190 if not _enteredWorld then | |
191 _pendingInit = true | |
192 else | |
193 _pendingInit = false | |
194 finishInitialize() | |
195 end | |
196 end | |
197 | |
198 function Amr:OnDisable() | |
199 -- disabling is not supported | |
200 end | |
201 | |
202 | |
203 ---------------------------------------------------------------------------------------- | |
204 -- Slash Commands | |
205 ---------------------------------------------------------------------------------------- | |
206 local _slashMethods = { | |
207 hide = "Hide", | |
208 show = "Show", | |
209 toggle = "Toggle", | |
210 equip = "EquipGearSet", -- parameter is "primary" or "secondary", or no parameter to toggle | |
211 version = "PrintVersions", | |
212 wipe = "Wipe", | |
213 undowipe = "UndoWipe", | |
214 test = "Test" | |
215 } | |
216 | |
217 function Amr:SlashCommand(input) | |
218 input = string.lower(input) | |
219 local parts = {} | |
220 for w in input:gmatch("%S+") do | |
221 table.insert(parts, w) | |
222 end | |
223 | |
224 if #parts == 0 then return end | |
225 | |
226 local func = _slashMethods[parts[1]] | |
227 if not func then return end | |
228 | |
229 local funcArgs = {} | |
230 for i = 2, #parts do | |
231 table.insert(funcArgs, parts[i]) | |
232 end | |
233 | |
234 Amr[func](Amr, unpack(funcArgs)) | |
235 end | |
236 | |
237 | |
238 ---------------------------------------------------------------------------------------- | |
239 -- Configuration | |
240 ---------------------------------------------------------------------------------------- | |
241 | |
242 -- refresh all state based on the current values of configuration options | |
243 function Amr:RefreshConfig() | |
244 | |
245 self:UpdateMinimap() | |
246 self:RefreshOptionsUi() | |
247 self:RefreshLogUi() | |
248 end | |
249 | |
250 function Amr:UpdateMinimap() | |
251 | |
252 if self.db.profile.minimap.hide or not Amr:IsEnabled() then | |
253 _icon:Hide(Amr.ADDON_NAME) | |
254 else | |
255 -- change icon color if logging | |
256 if Amr:IsLogging() then | |
257 _amrLDB.icon = 'Interface\\AddOns\\AskMrRobot\\Media\\icon_green' | |
258 else | |
259 _amrLDB.icon = 'Interface\\AddOns\\AskMrRobot\\Media\\icon' | |
260 end | |
261 | |
262 _icon:Show(Amr.ADDON_NAME) | |
263 end | |
264 end | |
265 | |
266 | |
267 ---------------------------------------------------------------------------------------- | |
268 -- Version Checking | |
269 ---------------------------------------------------------------------------------------- | |
270 | |
271 -- version of addon being run by each person in the player's raid or group | |
272 Amr.GroupVersions = {} | |
273 | |
274 local function toGroupVersionKey(realm, name) | |
275 realm = string.gsub(realm, "%s+", "") | |
276 return name .. "-" .. realm | |
277 end | |
278 | |
279 -- prune out version information for players no longer in the current raid group | |
280 local function pruneVersionInfo() | |
281 | |
282 local newVersions = {} | |
283 local units = Amr:GetGroupUnitIdentifiers() | |
284 | |
285 for i, unitId in ipairs(units) do | |
286 local realm, name = Amr:GetRealmAndName(unitId) | |
287 if realm then | |
288 local key = toGroupVersionKey(realm, name) | |
289 newVersions[key] = Amr.GroupVersions[key] | |
290 end | |
291 end | |
292 | |
293 Amr.GroupVersions = newVersions | |
294 end | |
295 | |
296 -- send version information to other people in the same raid group | |
297 local function sendVersionInfo() | |
298 | |
299 local realm = GetRealmName() | |
300 local name = UnitName("player") | |
301 local ver = GetAddOnMetadata(Amr.ADDON_NAME, "Version") | |
302 | |
303 local msg = string.format("%s\n%s\n%s\n%s", Amr.MessageTypes.Version, realm, name, ver) | |
304 Amr:SendAmrCommMessage(msg) | |
305 end | |
306 | |
307 local function onVersionInfoReceived(message) | |
308 | |
309 -- message will be of format: realm\nname\nversion | |
310 local parts = {} | |
311 for part in string.gmatch(message, "([^\n]+)") do | |
312 table.insert(parts, part) | |
313 end | |
314 | |
315 local key = toGroupVersionKey(parts[2], parts[3]) | |
316 local ver = parts[4] | |
317 | |
318 Amr.GroupVersions[key] = tonumber(ver) | |
319 | |
320 -- make sure that versions are properly pruned in case this message arrived late and the player has since been removed from the group | |
321 pruneVersionInfo() | |
322 end | |
323 | |
324 -- get the addon version another person in the player's raid/group is running, or 0 if they are not running the addon | |
325 function Amr:GetAddonVersion(realm, name) | |
326 local ver = Amr.GroupVersions[toGroupVersionKey(realm, name)] | |
327 return ver or 0 | |
328 end | |
329 | |
330 function Amr:PrintVersions() | |
331 | |
332 if not IsInGroup() and not IsInRaid() then | |
333 self:Print(L.VersionChatNotGrouped) | |
334 return | |
335 end | |
336 | |
337 local units = self:GetGroupUnitIdentifiers() | |
338 | |
339 local msg = {} | |
340 table.insert(msg, L.VersionChatTitle) | |
341 | |
342 for i, unitId in ipairs(units) do | |
343 local realm, name = self:GetRealmAndName(unitId) | |
344 if realm then | |
345 local key = toGroupVersionKey(realm, name) | |
346 local ver = Amr.GroupVersions[key] | |
347 if not ver then | |
348 table.insert(msg, key .. " |cFFFF0000" .. L.VersionChatNotInstalled .. "|r") | |
349 else | |
350 table.insert(msg, key .. " v" .. ver) | |
351 end | |
352 end | |
353 end | |
354 | |
355 msg = table.concat(msg, "\n") | |
356 print(msg) | |
357 end | |
358 | |
359 function Amr:InitializeVersions() | |
360 Amr:AddEventHandler("GROUP_ROSTER_UPDATE", pruneVersionInfo) | |
361 Amr:AddEventHandler("GROUP_ROSTER_UPDATE", sendVersionInfo) | |
362 | |
363 -- request version information from anyone in my group upon initialization | |
364 if IsInGroup() or IsInRaid() then | |
365 Amr:SendAmrCommMessage(Amr.MessageTypes.VersionRequest) | |
366 end | |
367 end | |
368 | |
369 | |
370 ---------------------------------------------------------------------------------------- | |
371 -- Generic Helpers | |
372 ---------------------------------------------------------------------------------------- | |
373 | |
374 local _waitTable = {} | |
375 local _waitFrame = nil | |
376 | |
377 -- execute the specified function after the specified delay (in seconds) | |
378 function Amr.Wait(delay, func, ...) | |
379 if not _waitFrame then | |
380 _waitFrame = CreateFrame("Frame", "AmrWaitFrame", UIParent) | |
381 _waitFrame:SetScript("OnUpdate", function (self, elapse) | |
382 local count = #_waitTable | |
383 local i = 1 | |
384 while(i <= count) do | |
385 local waitRecord = table.remove(_waitTable, i) | |
386 local d = table.remove(waitRecord, 1) | |
387 local f = table.remove(waitRecord, 1) | |
388 local p = table.remove(waitRecord, 1) | |
389 if d > elapse then | |
390 table.insert(_waitTable, i, { d-elapse, f, p }) | |
391 i = i + 1 | |
392 else | |
393 count = count - 1 | |
394 f(unpack(p)) | |
395 end | |
396 end | |
397 end) | |
398 end | |
399 table.insert(_waitTable, { delay, func, {...} }) | |
400 return true | |
401 end | |
402 | |
403 -- helper to iterate over a table in order by its keys | |
404 function Amr.spairs(t, order) | |
405 -- collect the keys | |
406 local keys = {} | |
407 for k in pairs(t) do keys[#keys+1] = k end | |
408 | |
409 -- if order function given, sort by it by passing the table and keys a, b, | |
410 -- otherwise just sort the keys | |
411 if order then | |
412 table.sort(keys, function(a,b) return order(t, a, b) end) | |
413 else | |
414 table.sort(keys) | |
415 end | |
416 | |
417 -- return the iterator function | |
418 local i = 0 | |
419 return function() | |
420 i = i + 1 | |
421 if keys[i] then | |
422 return keys[i], t[keys[i]] | |
423 end | |
424 end | |
425 end | |
426 | |
427 function Amr.StartsWith(str, prefix) | |
428 if string.len(str) < string.len(prefix) then return false end | |
429 return string.sub(str, 1, string.len(prefix)) == prefix | |
430 end | |
431 | |
432 -- helper to get the unit identifiers (e.g. to pass to GetUnitName) for all members of the player's current group/raid | |
433 function Amr:GetGroupUnitIdentifiers() | |
434 | |
435 local units = {} | |
436 if IsInRaid() then | |
437 for i = 1,40 do | |
438 table.insert(units, "raid" .. i) | |
439 end | |
440 elseif IsInGroup() then | |
441 table.insert(units, "player") | |
442 for i = 1,4 do | |
443 table.insert(units, "party" .. i) | |
444 end | |
445 else | |
446 table.insert(units, "player") | |
447 end | |
448 | |
449 return units | |
450 end | |
451 | |
452 -- helper to get the realm and name from a unitId (e.g. "player" or "raid1") | |
453 function Amr:GetRealmAndName(unitId) | |
454 | |
455 local name = GetUnitName(unitId, true) | |
456 if not name then return end | |
457 | |
458 local realm = GetRealmName() | |
459 local splitPos = string.find(name, "-") | |
460 if splitPos ~= nil then | |
461 realm = string.sub(name, splitPos + 1) | |
462 name = string.sub(name, 1, splitPos - 1) | |
463 end | |
464 | |
465 return realm, name | |
466 end | |
467 | |
468 -- find the unitid of a player given the name and realm... this comes from the server so the realm will be in english... | |
469 -- TODO: more robust handling of players with same name but different realms in the same group on non-english clients | |
470 function Amr:GetUnitId(unitRealm, unitName) | |
471 | |
472 local nameMatches = {} | |
473 | |
474 local units = Amr:GetGroupUnitIdentifiers() | |
475 for i, unitId in ipairs(units) do | |
476 local realm, name = Amr:GetRealmAndName(unitId) | |
477 if realm then | |
478 -- remove spaces to ensure proper matches | |
479 realm = string.gsub(realm, "%s+", "") | |
480 unitRealm = string.gsub(unitRealm, "%s+", "") | |
481 | |
482 if unitRealm == realm and unitName == name then return unitId end | |
483 if unitName == name then | |
484 table.insert(nameMatches, unitId) | |
485 end | |
486 end | |
487 end | |
488 | |
489 -- only one player with same name, must be the player of interest | |
490 if #nameMatches == 1 then return nameMatches[1] end | |
491 | |
492 -- could not find or ambiguous | |
493 return nil | |
494 end | |
495 | |
496 | |
497 -- scanning tooltip b/c for some odd reason the api has no way to get basic item properties... | |
498 -- so you have to generate a fake item tooltip and search for pre-defined strings in the display text | |
499 local _scanTt | |
500 function Amr:GetScanningTooltip() | |
501 if not _scanTt then | |
502 _scanTt = CreateFrame("GameTooltip", "AmrUiScanTooltip", nil, "GameTooltipTemplate") | |
503 _scanTt:SetOwner(UIParent, "ANCHOR_NONE") | |
504 end | |
505 return _scanTt | |
506 end | |
507 | |
508 local function scanTooltipHelper(txt, ...) | |
509 for i = 1, select("#", ...) do | |
510 local region = select(i, ...) | |
511 if region and region:GetObjectType() == "FontString" then | |
512 local text = region:GetText() -- string or nil | |
513 print(text) | |
514 end | |
515 end | |
516 end | |
517 | |
518 -- search the tooltip for txt, returns true if it is encountered on any line | |
519 function Amr:IsTextInTooltip(tt, txt) | |
520 local regions = { tt:GetRegions() } | |
521 for i, region in ipairs(regions) do | |
522 if region and region:GetObjectType() == "FontString" then | |
523 if region:GetText() == txt then | |
524 return true | |
525 end | |
526 end | |
527 end | |
528 return false | |
529 end | |
530 | |
531 -- helper to determine if an item in the player's bag is soulbound | |
532 function Amr:IsSoulbound(bagId, slotId) | |
533 local tt = self:GetScanningTooltip() | |
534 tt:ClearLines() | |
535 if bagId then | |
536 tt:SetBagItem(bagId, slotId) | |
537 else | |
538 tt:SetInventoryItem("player", slotId) | |
539 end | |
540 return self:IsTextInTooltip(tt, ITEM_SOULBOUND) | |
541 end | |
542 | |
543 -- helper to determine if an item has a unique constraint | |
544 function Amr:IsUnique(bagId, slotId) | |
545 local tt = self:GetScanningTooltip() | |
546 tt:ClearLines() | |
547 if bagId then | |
548 tt:SetBagItem(bagId, slotId) | |
549 else | |
550 tt:SetInventoryItem("player", slotId) | |
551 end | |
552 if self:IsTextInTooltip(tt, ITEM_UNIQUE_EQUIPPABLE) then return true end | |
553 if self:IsTextInTooltip(tt, ITEM_UNIQUE) then return true end | |
554 return false | |
555 end | |
556 | |
557 | |
558 ---------------------------------------------------------------------------------------- | |
559 -- Inter-Addon Communication | |
560 ---------------------------------------------------------------------------------------- | |
561 function Amr:SendAmrCommMessage(message, channel) | |
562 -- prepend version to all messages | |
563 local v = GetAddOnMetadata(Amr.ADDON_NAME, "Version") | |
564 message = v .. "\r" .. message | |
565 | |
566 Amr:SendCommMessage(Amr.ChatPrefix, message, channel or "RAID") | |
567 end | |
568 | |
569 function Amr:OnCommReceived(prefix, message, distribution, sender) | |
570 | |
571 local parts = {} | |
572 for part in string.gmatch(message, "([^\r]+)") do | |
573 table.insert(parts, part) | |
574 end | |
575 | |
576 local ver = parts[1] | |
577 if ver then ver = tonumber(ver) end | |
578 if ver then | |
579 -- newest versions of the addon start all messages with a version number | |
580 message = parts[2] | |
581 end | |
582 | |
583 -- we always allow version checks, even from old versions of the addon that aren't otherwise compatible | |
584 if Amr.StartsWith(message, Amr.MessageTypes.Version) then | |
585 -- version checking between group members | |
586 if Amr.StartsWith(message, Amr.MessageTypes.VersionRequest) then | |
587 sendVersionInfo() | |
588 else | |
589 onVersionInfoReceived(message) | |
590 end | |
591 | |
592 return | |
593 end | |
594 | |
595 -- any other kind of message is ignored if the version is too old | |
596 if not ver or ver < Amr.MIN_ADDON_VERSION then return end | |
597 | |
598 if Amr.StartsWith(message, Amr.MessageTypes.Team) then | |
599 -- if fully initialized, process team optimizer messages | |
600 if Amr["ProcessTeamMessage"] then | |
601 Amr:ProcessTeamMessage(message) | |
602 end | |
603 else | |
604 -- if we are fully loaded, process a player snapshot when it is received (combat logging) | |
605 if Amr["ProcessPlayerSnapshot"] then | |
606 self:ProcessPlayerSnapshot(message) | |
607 end | |
608 end | |
609 end | |
610 | |
611 | |
612 ---------------------------------------------------------------------------------------- | |
613 -- Events | |
614 ---------------------------------------------------------------------------------------- | |
615 local _eventHandlers = {} | |
616 | |
617 local function handleEvent(eventName, ...) | |
618 local list = _eventHandlers[eventName] | |
619 if list then | |
620 --print(eventName .. " handled") | |
621 for i, handler in ipairs(list) do | |
622 if type(handler) == "function" then | |
623 handler(select(1, ...)) | |
624 else | |
625 Amr[handler](Amr, select(1, ...)) | |
626 end | |
627 end | |
628 end | |
629 end | |
630 | |
631 -- WoW and Ace seem to work on a "one handler" kind of approach to events (as far as I can tell from the sparse documentation of both). | |
632 -- This is a simple wrapper to allow adding multiple handlers to the same event, thus allowing better encapsulation of code from file to file. | |
633 function Amr:AddEventHandler(eventName, methodOrName) | |
634 local list = _eventHandlers[eventName] | |
635 if not list then | |
636 list = {} | |
637 _eventHandlers[eventName] = list | |
638 Amr:RegisterEvent(eventName, handleEvent) | |
639 end | |
640 table.insert(list, methodOrName) | |
641 end | |
642 | |
643 Amr:AddEventHandler("PLAYER_ENTERING_WORLD", onPlayerEnteringWorld) | |
644 | |
645 | |
646 ---------------------------------------------------------------------------------------- | |
647 -- Debugging | |
648 ---------------------------------------------------------------------------------------- | |
649 --[[ | |
650 function Amr:Test(val1, val2, val3) | |
651 | |
652 local link = GetLootSlotLink(tonumber(val1)) | |
653 local index = Amr:TestLootIndex(link) | |
654 print("loot index: " .. index) | |
655 | |
656 if val2 then | |
657 local candidate = Amr:TestLootCandidate(link, val2, val3) | |
658 print("loot candidate: " .. candidate) | |
659 | |
660 GiveMasterLoot(index, candidate) | |
661 end | |
662 end | |
663 ]] |