Mercurial > wow > ouroloot
comparison core.lua @ 25:cb9635999171
- Reassigning loot, and marking loot as disenchanted/vault, will update the
history entries also.
- Tooltip help on dropdown menus appears at mouse now, instead of depending
on Blizzard's "Beginner Tooltips" setting.
- Forum BBcode output includes an option for MMO-Champion/Wowstead formatting.
- Smarter cleanup functions for expiring caches.
- Properly prefer locally-generated loot events, even when other users can
see and rebroadcast the events back to you faster than you see them.
author | Farmbuyer of US-Kilrogg <farmbuyer@gmail.com> |
---|---|
date | Wed, 05 Oct 2011 02:14:07 +0000 |
parents | 61d932f0e8f2 |
children | 68d7b903ee17 |
comparison
equal
deleted
inserted
replaced
24:61d932f0e8f2 | 25:cb9635999171 |
---|---|
57 ['snarky_boss'] = true, | 57 ['snarky_boss'] = true, |
58 ['keybinding'] = false, | 58 ['keybinding'] = false, |
59 ['bossmod'] = "DBM", | 59 ['bossmod'] = "DBM", |
60 ['keybinding_text'] = 'CTRL-SHIFT-O', | 60 ['keybinding_text'] = 'CTRL-SHIFT-O', |
61 ['forum'] = { | 61 ['forum'] = { |
62 ['[url]'] = '[url=http://www.wowhead.com/?item=$I]$N[/url]$X - $T', | 62 ['[url] Wowhead'] = '[url=http://www.wowhead.com/?item=$I]$N[/url]$X - $T', |
63 ['[url] MMO/Wowstead'] = '[http://db.mmo-champion.com/i/$I]$X - $T', | |
63 ['[item] by name'] = '[item]$N[/item]$X - $T', | 64 ['[item] by name'] = '[item]$N[/item]$X - $T', |
64 ['[item] by ID'] = '[item]$I[/item]$X - $T', | 65 ['[item] by ID'] = '[item]$I[/item]$X - $T', |
65 ['Custom...'] = '', | 66 ['Custom...'] = '', |
66 }, | 67 }, |
67 ['forum_current'] = '[item] by name', | 68 ['forum_current'] = '[item] by name', |
259 foo:add("blah") | 260 foo:add("blah") |
260 foo:test("blah") -- returns true | 261 foo:test("blah") -- returns true |
261 ]] | 262 ]] |
262 do | 263 do |
263 local caches = {} | 264 local caches = {} |
264 local cleanup_group = AnimTimerFrame:CreateAnimationGroup() | 265 local cleanup_group = _G.AnimTimerFrame:CreateAnimationGroup() |
265 local time = _G.time | 266 local time = _G.time |
266 cleanup_group:SetLooping("REPEAT") | 267 cleanup_group:SetLooping("REPEAT") |
267 cleanup_group:SetScript("OnLoop", function(cg) | 268 cleanup_group:SetScript("OnLoop", function(cg) |
268 addon.dprint('cache',"OnLoop firing") | 269 addon.dprint('cache',"OnLoop firing") |
269 local now = time() | 270 local now = time() |
270 local alldone = true | 271 local alldone = true |
271 -- this is ass-ugly | 272 -- this is ass-ugly |
272 for _,c in ipairs(caches) do | 273 for name,c in pairs(caches) do |
273 while (#c > 0) and (now - c[1].t > c.ttl) do | 274 local fifo = c.fifo |
274 addon.dprint('cache', c.name, "cache removing",c[1].t, c[1].m) | 275 local active = #fifo > 0 |
275 tremove(c,1) | 276 while (#fifo > 0) and (now - fifo[1].t > c.ttl) do |
276 end | 277 addon.dprint('cache', name, "cache removing",fifo[1].t, fifo[1].m) |
277 alldone = alldone and (#c == 0) | 278 tremove(fifo,1) |
279 end | |
280 if active and #fifo == 0 and c.func then | |
281 addon.dprint('cache', name, "empty, firing cleanup") | |
282 c:func() | |
283 end | |
284 alldone = alldone and (#fifo == 0) | |
278 end | 285 end |
279 if alldone then | 286 if alldone then |
280 addon.dprint('cache',"OnLoop finishing animation group") | 287 addon.dprint('cache',"OnLoop finishing animation group") |
281 cleanup_group:Finish() | 288 cleanup_group:Finish() |
282 for _,c in ipairs(caches) do | |
283 if c.func then c:func() end | |
284 end | |
285 end | 289 end |
286 addon.dprint('cache',"OnLoop done") | 290 addon.dprint('cache',"OnLoop done") |
287 end) | 291 end) |
288 | 292 |
289 local function _add (cache, x) | 293 local function _add (cache, x) |
290 tinsert(cache, {t=time(),m=x}) | 294 local datum = { t=time(), m=x } |
295 cache.hash[x] = datum | |
296 tinsert (cache.fifo, datum) | |
291 if not cleanup_group:IsPlaying() then | 297 if not cleanup_group:IsPlaying() then |
292 addon.dprint('cache', cache.name, "STARTING animation group") | 298 addon.dprint('cache', cache.name, "STARTING animation group") |
293 cache.cleanup:SetDuration(2) -- hmmm | 299 cache.cleanup:SetDuration(2) -- hmmm |
294 cleanup_group:Play() | 300 cleanup_group:Play() |
295 end | 301 end |
296 end | 302 end |
297 local function _test (cache, x) | 303 local function _test (cache, x) |
298 for _,v in ipairs(cache) do | 304 return cache.hash[x] ~= nil |
305 --[[for _,v in ipairs(cache) do | |
299 if v.m == x then return true end | 306 if v.m == x then return true end |
300 end | 307 end]] |
301 end | 308 end |
309 | |
302 function create_new_cache (name, ttl, on_alldone) | 310 function create_new_cache (name, ttl, on_alldone) |
311 -- setting OnFinished for cleanup fires at the end of each inner loop, | |
312 -- with no 'requested' argument to distinguish cases. thus, on_alldone. | |
303 local c = { | 313 local c = { |
304 ttl = ttl, | 314 ttl = ttl, |
305 name = name, | 315 name = name, |
306 add = _add, | 316 add = _add, |
307 test = _test, | 317 test = _test, |
308 cleanup = cleanup_group:CreateAnimation("Animation"), | 318 cleanup = cleanup_group:CreateAnimation("Animation"), |
309 func = on_alldone, | 319 func = on_alldone, |
320 fifo = {}, | |
321 hash = setmetatable({}, {__mode='kv'}), | |
310 } | 322 } |
311 c.cleanup:SetOrder(1) | 323 c.cleanup:SetOrder(1) |
312 -- setting OnFinished for cleanup fires at the end of each inner loop, | 324 caches[name] = c |
313 -- with no 'requested' argument to distinguish cases. thus, on_alldone. | |
314 tinsert (caches, c) | |
315 return c | 325 return c |
316 end | 326 end |
317 end | 327 end |
318 | 328 |
319 | 329 |
335 for opt,default in pairs(option_defaults) do | 345 for opt,default in pairs(option_defaults) do |
336 if opts[opt] == nil then | 346 if opts[opt] == nil then |
337 opts[opt] = default | 347 opts[opt] = default |
338 end | 348 end |
339 end | 349 end |
350 -- transition&remove old options | |
351 opts['forum_use_itemid'] = nil | |
352 if opts['forum_format'] then | |
353 opts.forum['Custom...'] = opts['forum_format'] | |
354 opts['forum_format'] = nil | |
355 end | |
356 if opts.forum['[url]'] then | |
357 opts.forum['[url] Wowhead'] = opts.forum['[url]'] | |
358 opts.forum['[url]'] = nil | |
359 opts.forum['[url] MMO/Wowstead'] = option_defaults.forum['[url] MMO/Wowstead'] | |
360 if opts['forum_current'] == '[url]' then | |
361 opts['forum_current'] = '[url] Wowhead' | |
362 end | |
363 end | |
340 option_defaults = nil | 364 option_defaults = nil |
341 -- transition&remove old options | |
342 opts["forum_use_itemid"] = nil | |
343 if opts["forum_format"] then | |
344 opts.forum["Custom..."] = opts["forum_format"] | |
345 opts["forum_format"] = nil | |
346 end | |
347 if OuroLootSV then -- may not be the same as testing g_restore_p soon | 365 if OuroLootSV then -- may not be the same as testing g_restore_p soon |
348 if OuroLootSV.saved then | 366 if OuroLootSV.saved then |
349 OuroLootSV_saved = OuroLootSV.saved; OuroLootSV.saved = nil | 367 OuroLootSV_saved = OuroLootSV.saved; OuroLootSV.saved = nil |
350 end | 368 end |
351 if OuroLootSV.threshold then | 369 if OuroLootSV.threshold then |
615 end | 633 end |
616 | 634 |
617 -- helper for CHAT_MSG_LOOT handler | 635 -- helper for CHAT_MSG_LOOT handler |
618 do | 636 do |
619 -- Recent loot cache | 637 -- Recent loot cache |
620 addon.recent_loot = create_new_cache ('loot', comm_cleanup_ttl) | 638 local candidates = {} |
639 local function prefer_local_loots (cache) | |
640 -- The function name is a bit of a misnomer, as local entries overwrite | |
641 -- remote entries as the candidate table is populated. This routine is | |
642 -- to extract the results once the cache timers have expired. | |
643 for i,sig in ipairs(candidates) do | |
644 addon.dprint('loot', "processing candidate entry", i, sig) | |
645 local loot = candidates[sig] | |
646 if loot then | |
647 addon.dprint('loot', i, "was found") | |
648 candidates[sig] = nil | |
649 local looti = addon._addLootEntry(loot) | |
650 if (loot.disposition ~= 'shard') | |
651 and (loot.disposition ~= 'gvault') | |
652 and (not addon.history_suppress) | |
653 then | |
654 addon:_addHistoryEntry(looti) | |
655 end | |
656 end | |
657 end | |
658 | |
659 if addon.display then | |
660 addon:redisplay() | |
661 end | |
662 table.wipe(candidates) | |
663 end | |
664 addon.recent_loot = create_new_cache ('loot', comm_cleanup_ttl, prefer_local_loots) | |
621 | 665 |
622 local GetItemInfo, GetItemIcon = GetItemInfo, GetItemIcon | 666 local GetItemInfo, GetItemIcon = GetItemInfo, GetItemIcon |
623 | 667 |
624 -- 'from' and onwards only present if this is triggered by a broadcast | 668 -- 'from' and onwards only present if this is triggered by a broadcast |
625 function addon:_do_loot (local_override, recipient, itemid, count, from, extratext) | 669 function addon:_do_loot (local_override, recipient, itemid, count, from, extratext) |
632 UNKNOWN..': '..itemid, 'item:6948', ITEM_QUALITY_COMMON, [[ICONS\INV_Misc_QuestionMark]] | 676 UNKNOWN..': '..itemid, 'item:6948', ITEM_QUALITY_COMMON, [[ICONS\INV_Misc_QuestionMark]] |
633 end | 677 end |
634 self.dprint('loot',">>_do_loot, R:", recipient, "I:", itemid, "C:", count, "frm:", from, "ex:", extratext, "q:", iquality) | 678 self.dprint('loot',">>_do_loot, R:", recipient, "I:", itemid, "C:", count, "frm:", from, "ex:", extratext, "q:", iquality) |
635 | 679 |
636 itemid = tonumber(ilink:match("item:(%d+)") or 0) | 680 itemid = tonumber(ilink:match("item:(%d+)") or 0) |
637 if local_override or ((iquality >= self.threshold) and not opts.itemfilter[itemid]) then | 681 -- This is only a loop to make jumping out of it easy, and still do cleanup below. |
682 while local_override or ((iquality >= self.threshold) and not opts.itemfilter[itemid]) do | |
638 if (self.rebroadcast and (not from)) and not local_override then | 683 if (self.rebroadcast and (not from)) and not local_override then |
639 self:broadcast('loot', recipient, itemid, count) | 684 self:broadcast('loot', recipient, itemid, count) |
640 end | 685 end |
641 if self.enabled or local_override then | 686 if (not self.enabled) and (not local_override) then break end |
642 local signature = recipient .. iname .. (count or "") | 687 local signature = recipient .. iname .. (count or "") |
643 if self.recent_loot:test(signature) then | 688 if from and self.recent_loot:test(signature) then |
644 self.dprint('cache', "loot <",signature,"> already in cache, skipping") | 689 self.dprint('cache', "loot <",signature,"> already in cache, skipping") |
645 else | 690 else |
646 self.recent_loot:add(signature) | 691 self.recent_loot:add(signature) |
647 i = self._addLootEntry{ -- There is some redundancy here... | 692 -- There is some redundancy in all this, in the interests of ease-of-coding |
648 kind = 'loot', | 693 i = { |
649 person = recipient, | 694 kind = 'loot', |
650 person_class= select(2,UnitClass(recipient)), | 695 person = recipient, |
651 cache_miss = i and true or nil, | 696 person_class= select(2,UnitClass(recipient)), |
652 quality = iquality, | 697 cache_miss = i and true or nil, |
653 itemname = iname, | 698 quality = iquality, |
654 id = itemid, | 699 itemname = iname, |
655 itemlink = ilink, | 700 id = itemid, |
656 itexture = itexture, | 701 itemlink = ilink, |
657 disposition = (recipient == self.sharder) and 'shard' or nil, | 702 itexture = itexture, |
658 count = count, | 703 disposition = (recipient == self.sharder) and 'shard' or nil, |
659 bcast_from = from, | 704 count = count, |
660 extratext = extratext, | 705 bcast_from = from, |
661 is_heroic = self:is_heroic_item(ilink), | 706 extratext = extratext, |
662 } | 707 is_heroic = self:is_heroic_item(ilink), |
663 self.dprint('loot', "added loot entry", i) | 708 } |
664 if not self.history_suppress then | 709 candidates[signature] = i |
665 self:_addHistoryEntry(i) | 710 tinsert (candidates, signature) |
666 end | 711 self.dprint('cache', "loot <",signature,"> added to cache, candidate", #candidates) |
667 if self.display then | 712 end |
668 self:redisplay() | 713 break |
669 --[[ | |
670 local st = self.display:GetUserData("eoiST") | |
671 if st and st.frame:IsVisible() then | |
672 st:OuroLoot_Refresh() | |
673 end | |
674 ]] | |
675 end | |
676 end | |
677 end | |
678 end | 714 end |
679 self.dprint('loot',"<<_do_loot out") | 715 self.dprint('loot',"<<_do_loot out") |
680 return i | 716 return i |
681 end | 717 end |
682 | 718 |
1065 _G.OL = self | 1101 _G.OL = self |
1066 _G.Oloot = g_loot | 1102 _G.Oloot = g_loot |
1067 end | 1103 end |
1068 end | 1104 end |
1069 | 1105 |
1070 -- Tie-ins with Deadly Boss Mods | 1106 -- Tie-in with Deadly Boss Mods (or other such addons) |
1071 do | 1107 do |
1072 local candidates, location | 1108 local candidates = {} |
1109 local location | |
1073 local function fixup_durations (cache) | 1110 local function fixup_durations (cache) |
1074 if candidates == nil then return end -- this is called for *all* cache expirations, including non-boss | |
1075 local boss, bossi | 1111 local boss, bossi |
1076 boss = candidates[1] | 1112 boss = candidates[1] |
1077 if #candidates == 1 then | 1113 if #candidates == 1 then |
1078 -- (1) or (2) | 1114 -- (1) or (2) |
1079 boss.duration = boss.duration or 0 | 1115 boss.duration = boss.duration or 0 |
1106 addon:_mark_boss_kill (bossi) | 1142 addon:_mark_boss_kill (bossi) |
1107 if opts.chatty_on_kill then | 1143 if opts.chatty_on_kill then |
1108 addon:Print("Registered kill for '%s' in %s!", boss.bosskill, boss.instance) | 1144 addon:Print("Registered kill for '%s' in %s!", boss.bosskill, boss.instance) |
1109 end | 1145 end |
1110 end | 1146 end |
1111 candidates = nil | 1147 table.wipe(candidates) |
1112 end | 1148 end |
1113 addon.recent_boss = create_new_cache ('boss', 10, fixup_durations) | 1149 addon.recent_boss = create_new_cache ('boss', 10, fixup_durations) |
1114 | 1150 |
1115 -- Similar to _do_loot, but duration+ parms only present when locally generated. | 1151 -- Similar to _do_loot, but duration+ parms only present when locally generated. |
1116 local function _do_boss (self, reason, bossname, intag, duration, raiders) | 1152 local function _do_boss (self, reason, bossname, intag, duration, raiders) |
1143 reason = reason, | 1179 reason = reason, |
1144 instance = intag, | 1180 instance = intag, |
1145 duration = duration, -- these two deliberately may be nil | 1181 duration = duration, -- these two deliberately may be nil |
1146 raiderlist = raiders and table.concat(raiders, ", ") | 1182 raiderlist = raiders and table.concat(raiders, ", ") |
1147 } | 1183 } |
1148 candidates = candidates or {} | |
1149 tinsert(candidates,c) | 1184 tinsert(candidates,c) |
1150 end | 1185 end |
1151 break | 1186 break |
1152 end | 1187 end |
1153 self.dprint('loot',"<<_do_boss out") | 1188 self.dprint('loot',"<<_do_boss out") |
1529 function addon:_addHistoryEntry (lootindex) | 1564 function addon:_addHistoryEntry (lootindex) |
1530 local e = g_loot[lootindex] | 1565 local e = g_loot[lootindex] |
1531 if e.kind ~= 'loot' then return end | 1566 if e.kind ~= 'loot' then return end |
1532 | 1567 |
1533 local i,h = self:get_loot_history(e.person) | 1568 local i,h = self:get_loot_history(e.person) |
1569 -- If any of these change, update the end of history_handle_disposition. | |
1534 local n = { | 1570 local n = { |
1535 id = e.id, | 1571 id = e.id, |
1536 when = self:format_timestamp (g_today, e), | 1572 when = self:format_timestamp (g_today, e), |
1537 count = e.count, | 1573 count = e.count, |
1538 } | 1574 } |
1572 tremove (h) | 1608 tremove (h) |
1573 end | 1609 end |
1574 end | 1610 end |
1575 end | 1611 end |
1576 | 1612 |
1577 function addon:reassign_loot (index, name_to) | 1613 -- Given an entry in a g_loot table, looks up the corresponding history |
1578 local e = assert(g_loot[index], "trying to reassign nonexistant entry") | 1614 -- entry. Returns the player's index and history table (as in get_loot_history) |
1579 assert(e.kind=='loot', "trying to reassign something that isn't loot") | 1615 -- and the index into that table of the loot entry. On failure, returns nil |
1580 assert(type(name_to)=='string' and name_to:len()>0) | 1616 -- and an error message ready to be formatted with the loot's name/itemlink. |
1581 | 1617 function addon:_history_by_loot_id (loot, operation_text) |
1582 local name_from = e.person | 1618 -- Using assert() here would be concatenating error strings that probably |
1583 local tag = e.history_unique | 1619 -- wouldn't be used. Do more verbose testing instead. |
1620 if type(loot) ~= 'table' then | |
1621 error("trying to "..operation_text.." nonexistant entry") | |
1622 end | |
1623 if loot.kind ~= 'loot' then | |
1624 error("trying to "..operation_text.." something that isn't loot") | |
1625 end | |
1626 | |
1627 local player = loot.person | |
1628 local tag = loot.history_unique | |
1584 local errtxt | 1629 local errtxt |
1630 local player_i, player_h, hist_i | |
1585 | 1631 |
1586 if not tag then | 1632 if not tag then |
1587 errtxt = "Entry for %s is missing a history tag!" | 1633 errtxt = "Entry for %s is missing a history tag!" |
1588 else | 1634 else |
1589 local from_i,from_h = self:get_loot_history(name_from) | 1635 player_i,player_h = self:get_loot_history(player) |
1590 local to_i,to_h = self:get_loot_history(name_to) | 1636 for i,h in ipairs(player_h) do |
1591 | |
1592 local hi | |
1593 for i,h in ipairs(from_h) do | |
1594 local unique = h.id .. ' ' .. h.when | 1637 local unique = h.id .. ' ' .. h.when |
1595 if unique == tag then | 1638 if unique == tag then |
1596 hi = i | 1639 hist_i = i |
1597 break | 1640 break |
1598 end | 1641 end |
1599 end | 1642 end |
1600 if not hi then | 1643 if not hist_i then |
1601 -- 1) loot an item, 2) clear old history, 3) reassign from current loot | 1644 -- 1) loot an item, 2) clear old history, 3) reassign from current loot |
1602 -- Bah. Anybody that tricky is already recoding the tables directly anyhow. | 1645 -- Bah. Anybody that tricky is already recoding the tables directly anyhow. |
1603 errtxt = "There is no record of %s ever having been assigned!" | 1646 errtxt = "There is no record of %s ever having been assigned!" |
1647 end | |
1648 end | |
1649 | |
1650 if errtxt then | |
1651 return nil, errtxt | |
1652 end | |
1653 return player_i, player_h, hist_i | |
1654 end | |
1655 | |
1656 function addon:reassign_loot (index, to_name) | |
1657 assert(type(to_name)=='string' and to_name:len()>0) | |
1658 local e = g_loot[index] | |
1659 local from_i, from_h, hist_i = self:_history_by_loot_id (e, "reassign") | |
1660 local from_name = e.person | |
1661 local to_i,to_h = self:get_loot_history(to_name) | |
1662 | |
1663 if not from_i then | |
1664 -- from_h is the formatted error text | |
1665 self:Print(from_h .. " Loot will be reassigned, but history will NOT be updated.", e.itemlink) | |
1666 else | |
1667 local hist_h = tremove (from_h, hist_i) | |
1668 tinsert (to_h, 1, hist_h) | |
1669 tsort (from_h, comp) | |
1670 tsort (to_h, comp) | |
1671 end | |
1672 e.person = to_name | |
1673 e.person_class = select(2,UnitClass(to_name)) | |
1674 self.hist_clean = nil | |
1675 | |
1676 self:Print("Reassigned entry %d/%s from '%s' to '%s'.", index, e.itemlink, from_name, to_name) | |
1677 end | |
1678 | |
1679 -- Any extra work for the "Mark as <x>" dropdown actions. The | |
1680 -- corresponding <x> will already have been assigned in the loot entry. | |
1681 local deleted_cache = {} --setmetatable({}, {__mode='k'}) | |
1682 function addon:history_handle_disposition (index, olddisp) | |
1683 local e = g_loot[index] | |
1684 -- Standard disposition has a nil entry, but that's tedious in debug | |
1685 -- output, so force to a string instead. | |
1686 olddisp = olddisp or 'normal' | |
1687 local newdisp = e.disposition or 'normal' | |
1688 -- Ignore misclicks and the like | |
1689 if olddisp == newdisp then return end | |
1690 | |
1691 local name = e.person | |
1692 | |
1693 if (newdisp == 'shard' or newdisp == 'gvault') then | |
1694 local name_i, name_h, hist_i = self:_history_by_loot_id (e, "mark") | |
1695 -- remove history entry | |
1696 if hist_i then | |
1697 local hist_h = tremove (name_h, hist_i) | |
1698 deleted_cache[e.history_unique] = hist_h | |
1699 self.hist_clean = nil | |
1700 elseif (olddisp == 'shard' or olddisp == 'gvault') then | |
1701 -- Sharding a vault item, or giving the auto-sharder something to bank, | |
1702 -- etc, wouldn't necessarily have had a history entry to begin with. | |
1604 else | 1703 else |
1605 hi = tremove (from_h, hi) | 1704 self:Print(name_h .. " Loot has been marked, but history will NOT be updated.", e.itemlink) |
1606 tinsert (to_h, 1, hi) | 1705 end |
1607 tsort (from_h, comp) | 1706 return |
1608 tsort (to_h, comp) | 1707 end |
1609 end | 1708 |
1610 end | 1709 if (olddisp == 'shard' or olddisp == 'gvault') |
1611 | 1710 and (newdisp == 'normal' or newdisp == 'offspec') |
1612 if errtxt then | 1711 then |
1613 self:Print(errtxt .. " Loot will be reassigned but history will NOT be updated.", e.itemlink) | 1712 local name_i, name_h = self:get_loot_history(name) |
1614 end | 1713 |
1615 e.person = name_to | 1714 -- Must create a new history entry. Could call '_addHistoryEntry(index)' |
1616 e.person_class = select(2,UnitClass(name_to)) | 1715 -- but that would duplicate a lot of effort. To start with, check the |
1617 | 1716 -- cache of stuff we've already deleted; if it's not there then just do |
1618 self:Print("Reassigned entry %d from '%s' to '%s'.", index, name_from, name_to) | 1717 -- the same steps as _addHistoryEntry. |
1718 local entry | |
1719 if e.history_unique and deleted_cache[e.history_unique] then | |
1720 entry = deleted_cache[e.history_unique] | |
1721 deleted_cache[e.history_unique] = nil | |
1722 end | |
1723 local when = g_today and self:format_timestamp (g_today, e) or tostring(e.stamp) | |
1724 entry = entry or { | |
1725 id = e.id, | |
1726 when = when, | |
1727 count = e.count, | |
1728 } | |
1729 tinsert (name_h, 1, entry) | |
1730 e.history_unique = e.history_unique or (entry.id .. ' ' .. entry.when) | |
1731 self.hist_clean = nil | |
1732 return | |
1733 end | |
1619 end | 1734 end |
1620 end | 1735 end |
1621 | 1736 |
1622 | 1737 |
1623 ------ Player communication | 1738 ------ Player communication |