comparison core.lua @ 16:5ee4edd24c13

- new blizz methods for editboxes in dialog popups - initial code for dropdowns in history (not active yet) - hovering and shift-clicking to link out of history - proper confirmations for history rewriting - options checkboxes more grid-like - saved texts get a scrollbar instead of expanding indefinitely (duh) - rearranged savedvars a bit (and added transition code) - stores raider join/leave times and "demographic" info, all for MLEQDKP - minor bugfixes and tweaks
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Thu, 25 Aug 2011 00:45:31 +0000
parents d8fee518ce5d
children d929c40cdb09
comparison
equal deleted inserted replaced
15:d8fee518ce5d 16:5ee4edd24c13
3 --[==[ 3 --[==[
4 g_loot's numeric indices are loot entries (including titles, separators, 4 g_loot's numeric indices are loot entries (including titles, separators,
5 etc); its named indices are: 5 etc); its named indices are:
6 - forum: saved text from forum markup window, default nil 6 - forum: saved text from forum markup window, default nil
7 - attend: saved text from raid attendence window, default nil 7 - attend: saved text from raid attendence window, default nil
8 - printed.FOO: last index formatted into text window FOO, default 0 8 - printed.FOO: last loot index formatted into text window FOO, default 0
9 - saved: table of copies of saved texts, default nil; keys are numeric
10 indices of tables, subkeys of those are name/forum/attend/date
11 - autoshard: optional name of disenchanting player, default nil
12 - threshold: optional loot threshold, default nil
13 9
14 Functions arranged like this, with these lables (for jumping to). As a 10 Functions arranged like this, with these lables (for jumping to). As a
15 rule, member functions with UpperCamelCase names are called directly by 11 rule, member functions with UpperCamelCase names are called directly by
16 user-facing code, ones with lowercase names are "one step removed", and 12 user-facing code, ones with lowercase names are "one step removed", and
17 names with leading underscores are strictly internal helper functions. 13 names with leading underscores are strictly internal helper functions.
31 27
32 This started off as part of a raid addon package written by somebody else. 28 This started off as part of a raid addon package written by somebody else.
33 After he retired, I began modifying the code. Eventually I set aside the 29 After he retired, I began modifying the code. Eventually I set aside the
34 entire package and rewrote the loot tracker module from scratch. Many of the 30 entire package and rewrote the loot tracker module from scratch. Many of the
35 variable/function naming conventions (sv_*, g_*, and family) stayed across the 31 variable/function naming conventions (sv_*, g_*, and family) stayed across the
36 rewrite. Some variables are needlessly initialized to nil just to look uniform. 32 rewrite.
33
34 Some variables are needlessly initialized to nil just to look uniform.
37 35
38 ]==] 36 ]==]
39 37
40 ------ Saved variables 38 ------ Saved variables
41 OuroLootSV = nil -- possible copy of g_loot 39 OuroLootSV = nil -- possible copy of g_loot
42 OuroLootSV_opts = nil -- same as option_defaults until changed 40 OuroLootSV_saved = nil -- table of copies of saved texts, default nil; keys
43 OuroLootSV_hist = nil 41 -- are numeric indices of tables, subkeys of those
42 -- are name/forum/attend/date
43 OuroLootSV_opts = nil -- same as option_defaults until changed
44 -- autoshard: optional name of disenchanting player, default nil
45 -- threshold: optional loot threshold, default nil
46 OuroLootSV_hist = nil
44 47
45 48
46 ------ Constants 49 ------ Constants
47 local option_defaults = { 50 local option_defaults = {
48 ['popup_on_join'] = true, 51 ['popup_on_join'] = true,
147 150
148 151
149 ------ Globals 152 ------ Globals
150 local g_loot = nil 153 local g_loot = nil
151 local g_restore_p = nil 154 local g_restore_p = nil
152 local g_saved_tmp = nil -- restoring across a clear
153 local g_wafer_thin = nil -- for prompting for additional rebroadcasters 155 local g_wafer_thin = nil -- for prompting for additional rebroadcasters
154 local g_today = nil -- "today" entry in g_loot 156 local g_today = nil -- "today" entry in g_loot
157 local g_boss_signpost = nil
155 local opts = nil 158 local opts = nil
156 159
157 local pairs, ipairs, tinsert, tremove, tonumber = pairs, ipairs, table.insert, table.remove, tonumber 160 local pairs, ipairs, tinsert, tremove, tonumber = pairs, ipairs, table.insert, table.remove, tonumber
158 local pprint, tabledump = addon.pprint, flib.tabledump 161 local pprint, tabledump = addon.pprint, flib.tabledump
159 local GetNumRaidMembers = GetNumRaidMembers 162 local GetNumRaidMembers = GetNumRaidMembers
327 opts["forum_use_itemid"] = nil 330 opts["forum_use_itemid"] = nil
328 if opts["forum_format"] then 331 if opts["forum_format"] then
329 opts.forum["Custom..."] = opts["forum_format"] 332 opts.forum["Custom..."] = opts["forum_format"]
330 opts["forum_format"] = nil 333 opts["forum_format"] = nil
331 end 334 end
335 if OuroLootSV then -- may not be the same as testing g_restore_p soon
336 if OuroLootSV.saved then
337 OuroLootSV_saved = OuroLootSV.saved; OuroLootSV.saved = nil
338 end
339 if OuroLootSV.threshold then
340 opts.threshold = OuroLootSV.threshold; OuroLootSV.threshold = nil
341 end
342 if OuroLootSV.autoshard then
343 opts.autoshard = OuroLootSV.autoshard; OuroLootSV.autoshard = nil
344 end
345 end
332 -- get item filter table if needed 346 -- get item filter table if needed
333 if opts.itemfilter == nil then 347 if opts.itemfilter == nil then
334 opts.itemfilter = addon.default_itemfilter 348 opts.itemfilter = addon.default_itemfilter
335 end 349 end
336 addon.default_itemfilter = nil 350 addon.default_itemfilter = nil
396 410
397 ------ Event handlers 411 ------ Event handlers
398 function addon:_clear_SVs() 412 function addon:_clear_SVs()
399 g_loot = {} -- not saved, just fooling PLAYER_LOGOUT tests 413 g_loot = {} -- not saved, just fooling PLAYER_LOGOUT tests
400 OuroLootSV = nil 414 OuroLootSV = nil
415 OuroLootSV_saved = nil
401 OuroLootSV_opts = nil 416 OuroLootSV_opts = nil
402 OuroLootSV_hist = nil 417 OuroLootSV_hist = nil
403 ReloadUI() 418 ReloadUI()
404 end 419 end
405 function addon:PLAYER_LOGOUT() 420 function addon:PLAYER_LOGOUT()
406 if (#g_loot > 0) or g_loot.saved 421 self:UnregisterEvent("RAID_ROSTER_UPDATE")
407 -- someday make this smarter 422 self:UnregisterEvent("PLAYER_ENTERING_WORLD")
408 or (g_loot.forum and g_loot.forum ~= "") 423
409 or (g_loot.attend and g_loot.attend ~= "") 424 local worth_saving = #g_loot > 0 or next(g_loot.raiders)
410 then 425 if not worth_saving then for text in self:registered_textgen_iter() do
411 g_loot.autoshard = self.sharder 426 worth_saving = worth_saving or g_loot.printed[text] > 0
412 g_loot.threshold = self.threshold 427 end end
428 if worth_saving then
429 opts.autoshard = self.sharder
430 opts.threshold = self.threshold
413 for i,e in ipairs(g_loot) do 431 for i,e in ipairs(g_loot) do
414 e.cols = nil 432 e.cols = nil
415 end 433 end
416 OuroLootSV = g_loot 434 OuroLootSV = g_loot
417 end 435 else
436 OuroLootSV = nil
437 end
438
418 for r,t in pairs(self.history_all) do if type(t) == 'table' then 439 for r,t in pairs(self.history_all) do if type(t) == 'table' then
419 if #t == 0 then 440 if #t == 0 then
420 self.history_all[r] = nil 441 self.history_all[r] = nil
421 else 442 else
422 t.realm = nil 443 t.realm = nil
434 UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo 455 UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo
435 local time, difftime = time, difftime 456 local time, difftime = time, difftime
436 local R_ACTIVE, R_OFFLINE, R_LEFT = 1, 2, 3 457 local R_ACTIVE, R_OFFLINE, R_LEFT = 1, 2, 3
437 458
438 local lastevent, now = 0, 0 459 local lastevent, now = 0, 0
439 local timer_handle 460 local redo_count = 0
461 local redo, timer_handle
440 462
441 function addon:CheckRoster (leaving_p, now_a) 463 function addon:CheckRoster (leaving_p, now_a)
442 if not g_loot.raiders then return end -- bad transition 464 if not g_loot.raiders then return end -- bad transition
443 465
444 now = now_a or time() 466 now = now_a or time()
445 467
446 if leaving_p then 468 if leaving_p then
469 if timer_handle then
470 self:CancelTimer(timer_handle)
471 timer_handle = nil
472 end
447 for name,r in pairs(g_loot.raiders) do 473 for name,r in pairs(g_loot.raiders) do
448 r.leave = r.leave or now 474 r.leave = r.leave or now
449 end 475 end
450 return 476 return
451 end 477 end
455 r.online = R_LEFT 481 r.online = R_LEFT
456 r.leave = now 482 r.leave = now
457 end 483 end
458 end 484 end
459 485
460 local redo = false 486 if redo then
487 redo_count = redo_count + 1
488 end
489 redo = false
461 for i = 1, GetNumRaidMembers() do 490 for i = 1, GetNumRaidMembers() do
462 local unit = 'raid'..i 491 local unit = 'raid'..i
463 local name = UnitName(unit) 492 local name = UnitName(unit)
464 -- No, that's not my typo, it really is "uknownbeing" in Blizzard's code. 493 -- No, that's not my typo, it really is "uknownbeing" in Blizzard's code.
465 if name and name ~= UNKNOWN and name ~= UNKNOWNOBJECT and name ~= UKNOWNBEING then 494 if name and name ~= UNKNOWN and name ~= UNKNOWNOBJECT and name ~= UKNOWNBEING then
484 r.online = R_OFFLINE 513 r.online = R_OFFLINE
485 end 514 end
486 redo = redo or r.needinfo 515 redo = redo or r.needinfo
487 end 516 end
488 end 517 end
489 if redo then 518 if redo then -- XXX test redo_count here and eventually give up?
490 timer_handle = self:ScheduleRepeatingTimer("RAID_ROSTER_UPDATE", 60) 519 if not timer_handle then
491 elseif timer_handle then 520 timer_handle = self:ScheduleRepeatingTimer("RAID_ROSTER_UPDATE", 60)
492 self:CancelTimer(timer_handle) 521 end
493 timer_handle = nil 522 else
523 redo_count = 0
524 if timer_handle then
525 self:CancelTimer(timer_handle)
526 timer_handle = nil
527 end
494 end 528 end
495 end 529 end
496 530
497 function addon:RAID_ROSTER_UPDATE (event) 531 function addon:RAID_ROSTER_UPDATE (event)
498 if GetNumRaidMembers() == 0 then 532 if GetNumRaidMembers() == 0 then
533 -- Leaving a raid group.
499 -- Because of PLAYER_ENTERING_WORLD, this code also executes on load 534 -- Because of PLAYER_ENTERING_WORLD, this code also executes on load
500 -- screens while soloing and in regular groups. Take care. 535 -- screens while soloing and in regular groups. Take care.
501 if self.enabled then 536 self.dprint('flow', "GetNumRaidMembers == 0")
537 if self.enabled and not self.debug.notraid then
538 self.dprint('flow', "enabled, leaving raid")
502 self.popped = nil 539 self.popped = nil
503 self:UnregisterEvent("CHAT_MSG_LOOT") 540 self:Deactivate() -- self:UnregisterEvent("CHAT_MSG_LOOT")
504 self:CheckRoster(--[[leaving raid]]true) 541 self:CheckRoster(--[[leaving raid]]true)
505 end 542 end
506 return 543 return
507 end 544 end
508 545
519 docheck = true 556 docheck = true
520 elseif event == "RAID_ROSTER_UPDATE" then 557 elseif event == "RAID_ROSTER_UPDATE" then
521 -- hot code path, be careful 558 -- hot code path, be careful
522 559
523 -- event registration from onload, joined a raid, maybe show popup 560 -- event registration from onload, joined a raid, maybe show popup
561 self.dprint('flow', "RRU check:", self.popped, opts.popup_on_join)
524 if (not self.popped) and opts.popup_on_join then 562 if (not self.popped) and opts.popup_on_join then
525 self.popped = StaticPopup_Show "OUROL_REMIND" 563 self.popped = StaticPopup_Show "OUROL_REMIND"
526 self.popped.data = self 564 self.popped.data = self
527 return 565 return
528 end 566 end
735 end 773 end
736 774
737 775
738 ------ On/off 776 ------ On/off
739 function addon:Activate (opt_threshold, opt_bcast_only) 777 function addon:Activate (opt_threshold, opt_bcast_only)
778 self.dprint('flow', ":Activate is running")
740 self:RegisterEvent("RAID_ROSTER_UPDATE") 779 self:RegisterEvent("RAID_ROSTER_UPDATE")
741 self:RegisterEvent("PLAYER_ENTERING_WORLD","RAID_ROSTER_UPDATE") 780 self:RegisterEvent("PLAYER_ENTERING_WORLD",
781 function() self:ScheduleTimer("RAID_ROSTER_UPDATE", 5, "PLAYER_ENTERING_WORLD") end)
742 self.popped = true 782 self.popped = true
743 if GetNumRaidMembers() > 0 then 783 if GetNumRaidMembers() > 0 then
784 self.dprint('flow', ">:Activate calling RRU")
744 self:RAID_ROSTER_UPDATE("Activate") 785 self:RAID_ROSTER_UPDATE("Activate")
745 elseif self.debug.notraid then 786 elseif self.debug.notraid then
787 self.dprint('flow', ">:Activate registering loot and bossmods")
746 self:RegisterEvent("CHAT_MSG_LOOT") 788 self:RegisterEvent("CHAT_MSG_LOOT")
747 _register_bossmod(self) 789 _register_bossmod(self)
748 elseif g_restore_p then 790 elseif g_restore_p then
749 g_restore_p = nil 791 g_restore_p = nil
750 if #g_loot == 0 then return end -- only saved texts, not worth verbage 792 self.popped = nil -- get the reminder if later joining a raid
793 if #g_loot == 0 then
794 -- only generated text and raider join/leave data, not worth verbage
795 self.dprint('flow', ">:Activate restored generated texts, un-popping")
796 return
797 end
751 self:Print("Ouro Raid Loot restored previous data, but not in a raid", 798 self:Print("Ouro Raid Loot restored previous data, but not in a raid",
752 "and 5-person mode not active. |cffff0505NOT tracking loot|r;", 799 "and 5-person mode not active. |cffff0505NOT tracking loot|r;",
753 "use 'enable' to activate loot tracking, or 'clear' to erase", 800 "use 'enable' to activate loot tracking, or 'clear' to erase",
754 "previous data, or 'help' to read about saved-texts commands.") 801 "previous data, or 'help' to read about saved-texts commands.")
755 self.popped = nil -- get the reminder if later joining a raid
756 return 802 return
757 end 803 end
758 self.rebroadcast = true -- hardcode to true; this used to be more complicated 804 self.rebroadcast = true -- hardcode to true; this used to be more complicated
759 self.enabled = not opt_bcast_only 805 self.enabled = not opt_bcast_only
760 if opt_threshold then 806 if opt_threshold then
788 self.display:Hide() 834 self.display:Hide()
789 end 835 end
790 g_restore_p = nil 836 g_restore_p = nil
791 OuroLootSV = nil 837 OuroLootSV = nil
792 self:_reset_timestamps() 838 self:_reset_timestamps()
793 g_saved_tmp = g_loot.saved
794 if verbose_p then 839 if verbose_p then
795 if (g_saved_tmp and #g_saved_tmp>0) then 840 if (OuroLootSV_saved and #OuroLootSV_saved>0) then
796 self:Print("Current loot data cleared, %d saved sets remaining.", #g_saved_tmp) 841 self:Print("Current loot data cleared, %d saved sets remaining.", #OuroLootSV_saved)
797 else 842 else
798 self:Print("Current loot data cleared.") 843 self:Print("Current loot data cleared.")
799 end 844 end
800 end 845 end
801 _init(self,st) 846 _init(self,st)
898 return (t == ITEM_HEROIC) or nil 943 return (t == ITEM_HEROIC) or nil
899 end 944 end
900 end 945 end
901 946
902 -- Called when first loading up, and then also when a 'clear' is being 947 -- Called when first loading up, and then also when a 'clear' is being
903 -- performed. If SV's are present then restore_p will be true. 948 -- performed. If SV's are present then g_restore_p will be true.
904 function _init (self, possible_st) 949 function _init (self, possible_st)
905 self.dprint('flow',"_init running") 950 self.dprint('flow',"_init running")
906 self.loot_clean = nil 951 self.loot_clean = nil
907 self.hist_clean = nil 952 self.hist_clean = nil
908 if g_restore_p then 953 if g_restore_p then
909 g_loot = OuroLootSV 954 g_loot = OuroLootSV
910 self.popped = true 955 self.popped = #g_loot > 0
911 self.dprint('flow', "restoring", #g_loot, "entries") 956 self.dprint('flow', "restoring", #g_loot, "entries")
912 self:ScheduleTimer("Activate", 12, g_loot.threshold) 957 self:ScheduleTimer("Activate", 12, opts.threshold)
913 -- FIXME printed could be too large if entries were deleted, how much do we care? 958 -- FIXME printed could be too large if entries were deleted, how much do we care?
914 self.sharder = g_loot.autoshard 959 self.sharder = opts.autoshard
915 else 960 else
916 g_loot = { printed = {}, raiders = {} } 961 g_loot = { printed = {}, raiders = {} }
917 g_loot.saved = g_saved_tmp; g_saved_tmp = nil -- potentially restore across a clear 962 end
918 end 963
919 964 self.threshold = opts.threshold or self.threshold -- in the case of restoring but not tracking
920 self.threshold = g_loot.threshold or self.threshold -- in the case of restoring but not tracking
921 self:gui_init(g_loot) 965 self:gui_init(g_loot)
966 opts.autoshard = nil
967 opts.threshold = nil
922 968
923 if g_restore_p then 969 if g_restore_p then
924 self:zero_printed_fenceposts() -- g_loot.printed.* = previous/safe values 970 self:zero_printed_fenceposts() -- g_loot.printed.* = previous/safe values
925 else 971 else
926 self:zero_printed_fenceposts(0) -- g_loot.printed.* = 0 972 self:zero_printed_fenceposts(0) -- g_loot.printed.* = 0
968 break 1014 break
969 end 1015 end
970 end 1016 end
971 end 1017 end
972 bossi = addon._addLootEntry(boss) 1018 bossi = addon._addLootEntry(boss)
1019 --
1020 bossi = addon._adjustBossOrder (bossi, g_boss_signpost)
1021 g_boss_signpost = nil
973 addon.dprint('loot', "added entry", bossi) 1022 addon.dprint('loot', "added entry", bossi)
974 if boss.reason == 'kill' then 1023 if boss.reason == 'kill' then
975 addon:_mark_boss_kill (bossi) 1024 addon:_mark_boss_kill (bossi)
976 if opts.chatty_on_kill then 1025 if opts.chatty_on_kill then
977 addon:Print("Registered kill for '%s' in %s!", boss.bosskill, boss.instance) 1026 addon:Print("Registered kill for '%s' in %s!", boss.bosskill, boss.instance)
996 local signature = bossname .. reason 1045 local signature = bossname .. reason
997 if not_from_local and self.recent_boss:test(signature) then 1046 if not_from_local and self.recent_boss:test(signature) then
998 self.dprint('cache', "boss <",signature,"> already in cache, skipping") 1047 self.dprint('cache', "boss <",signature,"> already in cache, skipping")
999 else 1048 else
1000 self.recent_boss:add(signature) 1049 self.recent_boss:add(signature)
1050 g_boss_signpost = #g_loot + 1
1001 -- Possible scenarios: (1) we don't see a boss event at all (e.g., we're 1051 -- Possible scenarios: (1) we don't see a boss event at all (e.g., we're
1002 -- outside the instance) and so this only happens once as a non-local event, 1052 -- outside the instance) and so this only happens once as a non-local event,
1003 -- (2) we see a local event first and all non-local events are filtered 1053 -- (2) we see a local event first and all non-local events are filtered
1004 -- by the cache, (3) we happen to get some non-local events before doing 1054 -- by the cache, (3) we happen to get some non-local events before doing
1005 -- our local event (not because of network weirdness but because our local 1055 -- our local event (not because of network weirdness but because our local
1023 addon.on_boss_broadcast = _do_boss 1073 addon.on_boss_broadcast = _do_boss
1024 1074
1025 function addon:_mark_boss_kill (index) 1075 function addon:_mark_boss_kill (index)
1026 local e = g_loot[index] 1076 local e = g_loot[index]
1027 if not e.bosskill then 1077 if not e.bosskill then
1028 return self:Print("Something horribly wrong;", index, "is not a boss entry!") 1078 self:Print("Something horribly wrong;", index, "is not a boss entry!")
1079 return
1029 end 1080 end
1030 if e.reason ~= 'wipe' then 1081 if e.reason ~= 'wipe' then
1031 -- enh, bail 1082 -- enh, bail
1032 self.loot_clean = index-1 1083 self.loot_clean = index-1
1033 end 1084 end
1194 e.stamp = time_t --localuptime 1245 e.stamp = time_t --localuptime
1195 local index = #g_loot + 1 1246 local index = #g_loot + 1
1196 g_loot[index] = e 1247 g_loot[index] = e
1197 return index 1248 return index
1198 end 1249 end
1250
1251 -- Problem: (1) boss kill happens, (2) fast looting happens, (3) boss
1252 -- cache cleanup fires. Result: loot shows up before boss kill entry.
1253 -- Solution: We need to shuffle the boss entry above any of the loot
1254 -- from that boss.
1255 function addon._adjustBossOrder (is, should_be)
1256 --pprint('loot', is, should_be)
1257 if is == should_be then --pprint('loot', "equal, yay")
1258 return
1259 end
1260 if is < should_be then --pprint('loot', "...the hell? bailing")
1261 return
1262 end
1263 if g_loot[should_be].kind == 'time' then
1264 should_be = should_be + 1
1265 if is == should_be then
1266 --pprint('loot', "needed to mark day entry, otherwise equal, yay")
1267 return
1268 end
1269 end
1270
1271 assert(g_loot[is].kind == 'boss')
1272 local boss = tremove (g_loot, is)
1273 --pprint('loot', "MOVING", boss.bosskill)
1274 tinsert (g_loot, should_be, boss)
1275 return should_be
1276 end
1199 end 1277 end
1200 1278
1201 1279
1202 ------ Saved texts 1280 ------ Saved texts
1203 function addon:check_saved_table(silent_p) 1281 function addon:check_saved_table(silent_p)
1204 local s = g_loot.saved 1282 local s = OuroLootSV_saved
1205 if s and (#s > 0) then return s end 1283 if s and (#s > 0) then return s end
1206 g_loot.saved = nil 1284 OuroLootSV_saved = nil
1207 if not silent_p then self:Print("There are no saved loot texts.") end 1285 if not silent_p then self:Print("There are no saved loot texts.") end
1208 end 1286 end
1209 1287
1210 function addon:save_list() 1288 function addon:save_list()
1211 local s = self:check_saved_table(); if not s then return end; 1289 local s = self:check_saved_table(); if not s then return end;
1213 self:Print("#%d %s %d entries %s", i, t.date, t.count, t.name) 1291 self:Print("#%d %s %d entries %s", i, t.date, t.count, t.name)
1214 end 1292 end
1215 end 1293 end
1216 1294
1217 function addon:save_saveas(name) 1295 function addon:save_saveas(name)
1218 g_loot.saved = g_loot.saved or {} 1296 OuroLootSV_saved = OuroLootSV_saved or {}
1219 local n = #(g_loot.saved) + 1 1297 local SV = OuroLootSV_saved
1298 local n = #SV + 1
1220 local save = { 1299 local save = {
1221 name = name, 1300 name = name,
1222 date = makedate(), 1301 date = makedate(),
1223 count = #g_loot, 1302 count = #g_loot,
1224 } 1303 }
1225 for text in self:registered_textgen_iter() do 1304 for text in self:registered_textgen_iter() do
1226 save[text] = g_loot[text] 1305 save[text] = g_loot[text]
1227 end 1306 end
1228 self:Print("Saving current loot texts to #%d '%s'", n, name) 1307 self:Print("Saving current loot texts to #%d '%s'", n, name)
1229 g_loot.saved[n] = save 1308 SV[n] = save
1230 return self:save_list() 1309 return self:save_list()
1231 end 1310 end
1232 1311
1233 function addon:save_restore(num) 1312 function addon:save_restore(num)
1234 local s = self:check_saved_table(); if not s then return end; 1313 local s = self:check_saved_table(); if not s then return end;