diff 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
line wrap: on
line diff
--- a/core.lua	Sun Jul 17 17:40:00 2011 +0000
+++ b/core.lua	Thu Aug 25 00:45:31 2011 +0000
@@ -5,11 +5,7 @@
 etc); its named indices are:
 - forum:		saved text from forum markup window, default nil
 - attend:		saved text from raid attendence window, default nil
-- printed.FOO:	last index formatted into text window FOO, default 0
-- saved:		table of copies of saved texts, default nil; keys are numeric
-				indices of tables, subkeys of those are name/forum/attend/date
-- autoshard:	optional name of disenchanting player, default nil
-- threshold:	optional loot threshold, default nil
+- printed.FOO:	last loot index formatted into text window FOO, default 0
 
 Functions arranged like this, with these lables (for jumping to).  As a
 rule, member functions with UpperCamelCase names are called directly by
@@ -33,14 +29,21 @@
 After he retired, I began modifying the code.  Eventually I set aside the
 entire package and rewrote the loot tracker module from scratch.  Many of the
 variable/function naming conventions (sv_*, g_*, and family) stayed across the
-rewrite.  Some variables are needlessly initialized to nil just to look uniform.
+rewrite.
+
+Some variables are needlessly initialized to nil just to look uniform.
 
 ]==]
 
 ------ Saved variables
-OuroLootSV		= nil   -- possible copy of g_loot
-OuroLootSV_opts	= nil   -- same as option_defaults until changed
-OuroLootSV_hist	= nil
+OuroLootSV       = nil   -- possible copy of g_loot
+OuroLootSV_saved = nil   -- table of copies of saved texts, default nil; keys
+                         -- are numeric indices of tables, subkeys of those
+						 -- are name/forum/attend/date
+OuroLootSV_opts  = nil   -- same as option_defaults until changed
+                         -- autoshard:  optional name of disenchanting player, default nil
+                         -- threshold:  optional loot threshold, default nil
+OuroLootSV_hist  = nil
 
 
 ------ Constants
@@ -149,9 +152,9 @@
 ------ Globals
 local g_loot			= nil
 local g_restore_p		= nil
-local g_saved_tmp		= nil   -- restoring across a clear
 local g_wafer_thin		= nil   -- for prompting for additional rebroadcasters
 local g_today			= nil   -- "today" entry in g_loot
+local g_boss_signpost	= nil
 local opts				= nil
 
 local pairs, ipairs, tinsert, tremove, tonumber = pairs, ipairs, table.insert, table.remove, tonumber
@@ -329,6 +332,17 @@
 		opts.forum["Custom..."] = opts["forum_format"]
 		opts["forum_format"] = nil
 	end
+	if OuroLootSV then  -- may not be the same as testing g_restore_p soon
+		if OuroLootSV.saved then
+			OuroLootSV_saved = OuroLootSV.saved; OuroLootSV.saved = nil
+		end
+		if OuroLootSV.threshold then
+			opts.threshold = OuroLootSV.threshold; OuroLootSV.threshold = nil
+		end
+		if OuroLootSV.autoshard then
+			opts.autoshard = OuroLootSV.autoshard; OuroLootSV.autoshard = nil
+		end
+	end
 	-- get item filter table if needed
 	if opts.itemfilter == nil then
 		opts.itemfilter = addon.default_itemfilter
@@ -398,23 +412,30 @@
 function addon:_clear_SVs()
 	g_loot = {}  -- not saved, just fooling PLAYER_LOGOUT tests
 	OuroLootSV = nil
+	OuroLootSV_saved = nil
 	OuroLootSV_opts = nil
 	OuroLootSV_hist = nil
 	ReloadUI()
 end
 function addon:PLAYER_LOGOUT()
-	if (#g_loot > 0) or g_loot.saved
-		-- someday make this smarter
-	   or (g_loot.forum and g_loot.forum ~= "")
-	   or (g_loot.attend and g_loot.attend ~= "")
-	then
-		g_loot.autoshard = self.sharder
-		g_loot.threshold = self.threshold
+	self:UnregisterEvent("RAID_ROSTER_UPDATE")
+	self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+
+	local worth_saving = #g_loot > 0 or next(g_loot.raiders)
+	if not worth_saving then for text in self:registered_textgen_iter() do
+		worth_saving = worth_saving or g_loot.printed[text] > 0
+	end end
+	if worth_saving then
+		opts.autoshard = self.sharder
+		opts.threshold = self.threshold
 		for i,e in ipairs(g_loot) do
 			e.cols = nil
 		end
 		OuroLootSV = g_loot
+	else
+		OuroLootSV = nil
 	end
+
 	for r,t in pairs(self.history_all) do if type(t) == 'table' then
 		if #t == 0 then
 			self.history_all[r] = nil
@@ -436,7 +457,8 @@
 	local R_ACTIVE, R_OFFLINE, R_LEFT = 1, 2, 3
 
 	local lastevent, now = 0, 0
-	local timer_handle
+	local redo_count = 0
+	local redo, timer_handle
 
 	function addon:CheckRoster (leaving_p, now_a)
 		if not g_loot.raiders then return end -- bad transition
@@ -444,6 +466,10 @@
 		now = now_a or time()
 
 		if leaving_p then
+			if timer_handle then
+				self:CancelTimer(timer_handle)
+				timer_handle = nil
+			end
 			for name,r in pairs(g_loot.raiders) do
 				r.leave = r.leave or now
 			end
@@ -457,7 +483,10 @@
 			end
 		end
 
-		local redo = false
+		if redo then
+			redo_count = redo_count + 1
+		end
+		redo = false
 		for i = 1, GetNumRaidMembers() do
 			local unit = 'raid'..i
 			local name = UnitName(unit)
@@ -486,21 +515,29 @@
 				redo = redo or r.needinfo
 			end
 		end
-		if redo then
-			timer_handle = self:ScheduleRepeatingTimer("RAID_ROSTER_UPDATE", 60)
-		elseif timer_handle then
-			self:CancelTimer(timer_handle)
-			timer_handle = nil
+		if redo then  -- XXX test redo_count here and eventually give up?
+			if not timer_handle then
+				timer_handle = self:ScheduleRepeatingTimer("RAID_ROSTER_UPDATE", 60)
+			end
+		else
+			redo_count = 0
+			if timer_handle then
+				self:CancelTimer(timer_handle)
+				timer_handle = nil
+			end
 		end
 	end
 
 	function addon:RAID_ROSTER_UPDATE (event)
 		if GetNumRaidMembers() == 0 then
+			-- Leaving a raid group.
 			-- Because of PLAYER_ENTERING_WORLD, this code also executes on load
 			-- screens while soloing and in regular groups.  Take care.
-			if self.enabled then
+			self.dprint('flow', "GetNumRaidMembers == 0")
+			if self.enabled and not self.debug.notraid then
+				self.dprint('flow', "enabled, leaving raid")
 				self.popped = nil
-				self:UnregisterEvent("CHAT_MSG_LOOT")
+				self:Deactivate()  -- self:UnregisterEvent("CHAT_MSG_LOOT")
 				self:CheckRoster(--[[leaving raid]]true)
 			end
 			return
@@ -521,6 +558,7 @@
 			-- hot code path, be careful
 
 			-- event registration from onload, joined a raid, maybe show popup
+			self.dprint('flow', "RRU check:", self.popped, opts.popup_on_join)
 			if (not self.popped) and opts.popup_on_join then
 				self.popped = StaticPopup_Show "OUROL_REMIND"
 				self.popped.data = self
@@ -737,22 +775,30 @@
 
 ------ On/off
 function addon:Activate (opt_threshold, opt_bcast_only)
+	self.dprint('flow', ":Activate is running")
 	self:RegisterEvent("RAID_ROSTER_UPDATE")
-	self:RegisterEvent("PLAYER_ENTERING_WORLD","RAID_ROSTER_UPDATE")
+	self:RegisterEvent("PLAYER_ENTERING_WORLD",
+		function() self:ScheduleTimer("RAID_ROSTER_UPDATE", 5, "PLAYER_ENTERING_WORLD") end)
 	self.popped = true
 	if GetNumRaidMembers() > 0 then
+		self.dprint('flow', ">:Activate calling RRU")
 		self:RAID_ROSTER_UPDATE("Activate")
 	elseif self.debug.notraid then
+		self.dprint('flow', ">:Activate registering loot and bossmods")
 		self:RegisterEvent("CHAT_MSG_LOOT")
 		_register_bossmod(self)
 	elseif g_restore_p then
 		g_restore_p = nil
-		if #g_loot == 0 then return end -- only saved texts, not worth verbage
+		self.popped = nil  -- get the reminder if later joining a raid
+		if #g_loot == 0 then
+			-- only generated text and raider join/leave data, not worth verbage
+			self.dprint('flow', ">:Activate restored generated texts, un-popping")
+			return
+		end
 		self:Print("Ouro Raid Loot restored previous data, but not in a raid",
 				"and 5-person mode not active.  |cffff0505NOT tracking loot|r;",
 				"use 'enable' to activate loot tracking, or 'clear' to erase",
 				"previous data, or 'help' to read about saved-texts commands.")
-		self.popped = nil  -- get the reminder if later joining a raid
 		return
 	end
 	self.rebroadcast = true  -- hardcode to true; this used to be more complicated
@@ -790,10 +836,9 @@
 	g_restore_p = nil
 	OuroLootSV = nil
 	self:_reset_timestamps()
-	g_saved_tmp = g_loot.saved
 	if verbose_p then
-		if (g_saved_tmp and #g_saved_tmp>0) then
-			self:Print("Current loot data cleared, %d saved sets remaining.", #g_saved_tmp)
+		if (OuroLootSV_saved and #OuroLootSV_saved>0) then
+			self:Print("Current loot data cleared, %d saved sets remaining.", #OuroLootSV_saved)
 		else
 			self:Print("Current loot data cleared.")
 		end
@@ -900,25 +945,26 @@
 end
 
 -- Called when first loading up, and then also when a 'clear' is being
--- performed.  If SV's are present then restore_p will be true.
+-- performed.  If SV's are present then g_restore_p will be true.
 function _init (self, possible_st)
 	self.dprint('flow',"_init running")
 	self.loot_clean = nil
 	self.hist_clean = nil
 	if g_restore_p then
 		g_loot = OuroLootSV
-		self.popped = true
+		self.popped = #g_loot > 0
 		self.dprint('flow', "restoring", #g_loot, "entries")
-		self:ScheduleTimer("Activate", 12, g_loot.threshold)
+		self:ScheduleTimer("Activate", 12, opts.threshold)
 		-- FIXME printed could be too large if entries were deleted, how much do we care?
-		self.sharder = g_loot.autoshard
+		self.sharder = opts.autoshard
 	else
 		g_loot = { printed = {}, raiders = {} }
-		g_loot.saved = g_saved_tmp; g_saved_tmp = nil	-- potentially restore across a clear
 	end
 
-	self.threshold = g_loot.threshold or self.threshold -- in the case of restoring but not tracking
+	self.threshold = opts.threshold or self.threshold -- in the case of restoring but not tracking
 	self:gui_init(g_loot)
+	opts.autoshard = nil
+	opts.threshold = nil
 
 	if g_restore_p then
 		self:zero_printed_fenceposts()                  -- g_loot.printed.* = previous/safe values
@@ -970,6 +1016,9 @@
 			end
 		end
 		bossi = addon._addLootEntry(boss)
+		--
+		bossi = addon._adjustBossOrder (bossi, g_boss_signpost)
+		g_boss_signpost = nil
 		addon.dprint('loot', "added entry", bossi)
 		if boss.reason == 'kill' then
 			addon:_mark_boss_kill (bossi)
@@ -998,6 +1047,7 @@
 				self.dprint('cache', "boss <",signature,"> already in cache, skipping")
 			else
 				self.recent_boss:add(signature)
+				g_boss_signpost = #g_loot + 1
 				-- Possible scenarios:  (1) we don't see a boss event at all (e.g., we're
 				-- outside the instance) and so this only happens once as a non-local event,
 				-- (2) we see a local event first and all non-local events are filtered
@@ -1025,7 +1075,8 @@
 	function addon:_mark_boss_kill (index)
 		local e = g_loot[index]
 		if not e.bosskill then
-			return self:Print("Something horribly wrong;", index, "is not a boss entry!")
+			self:Print("Something horribly wrong;", index, "is not a boss entry!")
+			return
 		end
 		if e.reason ~= 'wipe' then
 			-- enh, bail
@@ -1196,14 +1247,41 @@
 		g_loot[index] = e
 		return index
 	end
+
+	-- Problem:  (1) boss kill happens, (2) fast looting happens, (3) boss
+	-- cache cleanup fires.  Result:  loot shows up before boss kill entry.
+	-- Solution:  We need to shuffle the boss entry above any of the loot
+	-- from that boss.
+	function addon._adjustBossOrder (is, should_be)
+		--pprint('loot', is, should_be)
+		if is == should_be then --pprint('loot', "equal, yay")
+			return
+		end
+		if is < should_be then --pprint('loot', "...the hell? bailing")
+			return
+		end
+		if g_loot[should_be].kind == 'time' then
+			should_be = should_be + 1
+			if is == should_be then
+				--pprint('loot', "needed to mark day entry, otherwise equal, yay")
+				return
+			end
+		end
+
+		assert(g_loot[is].kind == 'boss')
+		local boss = tremove (g_loot, is)
+		--pprint('loot', "MOVING", boss.bosskill)
+		tinsert (g_loot, should_be, boss)
+		return should_be
+	end
 end
 
 
 ------ Saved texts
 function addon:check_saved_table(silent_p)
-	local s = g_loot.saved
+	local s = OuroLootSV_saved
 	if s and (#s > 0) then return s end
-	g_loot.saved = nil
+	OuroLootSV_saved = nil
 	if not silent_p then self:Print("There are no saved loot texts.") end
 end
 
@@ -1215,8 +1293,9 @@
 end
 
 function addon:save_saveas(name)
-	g_loot.saved = g_loot.saved or {}
-	local n = #(g_loot.saved) + 1
+	OuroLootSV_saved = OuroLootSV_saved or {}
+	local SV = OuroLootSV_saved
+	local n = #SV + 1
 	local save = {
 		name = name,
 		date = makedate(),
@@ -1226,7 +1305,7 @@
 		save[text] = g_loot[text]
 	end
 	self:Print("Saving current loot texts to #%d '%s'", n, name)
-	g_loot.saved[n] = save
+	SV[n] = save
 	return self:save_list()
 end