diff mleqdkp.lua @ 10:67b8537e8432

More work on ML/EQDKP generator and its spawned subprojects.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Tue, 28 Jun 2011 07:36:26 +0000
parents 822b6ca3ef89
children 40ff9c63badc
line wrap: on
line diff
--- a/mleqdkp.lua	Fri Jun 17 20:30:46 2011 +0000
+++ b/mleqdkp.lua	Tue Jun 28 07:36:26 2011 +0000
@@ -1,5 +1,14 @@
-if UnitName"player" ~= "Farmbuyer" then return end
+-- This file is one gigantic exercise in abusing the garbage collector via
+-- string manipulation.  A real XML-handling library would be cleaner, alas,
+-- we can't load third-party .so/.dll inside the WoW client.  Life is hard.
+
 local addon = select(2,...)
+local pairs, ipairs, tinsert, tremove, tconcat = pairs, ipairs, table.insert, table.remove, table.concat
+local tostring, tonumber = tostring, tonumber
+
+local banner_formatted = "Formatted version (scroll down for unformatted):"
+local banner_unformatted = "Unformatted version:"
+local banner_sep = "==========================="
 
 -- We keep some local state bundled up rather than trying to pass it around
 -- as paramters (which would have entailed creating a ton of closures).
@@ -9,7 +18,7 @@
 
 
 --[[
-This is taken from CT_RaidTracker 1.7.32, reconstructing the output from
+This is based on CT_RaidTracker 1.7.32, reconstructing the output from
 code inspection.  No official format documents are available on the web
 without downloading and installing the EQDKP webserver package.  Bah.
 
@@ -31,22 +40,32 @@
 <key>$TIMESTAMP</key>
 <realm>$REALM</realm>
 <start>$TIMESTAMP</start>   {Same as the key, apparently?}
-<end>$ENDTIME</end>    {Set by the "end the raid" command in the raid tracker, here just the final entry time}
+<end>$ENDTIME</end>    {Set by the "end the raid" command in CTRT, here it is just the final entry time}
 <zone>$ZONE</zone>   {may be optional.  first one on the list in case of multiple zones?}
 {<difficulty>$DIFFICULTY</difficulty>   {this scales badly in places like ICC.  may be optional?}}
 
-{<PlayerInfos>... {guh.}}
+<PlayerInfos>
+  $PLAYER_INFOS
+</PlayerInfos>
 
 <BossKills>
   $BOSS_KILLS
 </BossKills>
 
-{<Wipes>  bleh}
-{<NextBoss>Baron Steamroller</NextBoss>  {only one "next boss" for the whole raid event?  huh?}}
+<Wipes>
+  $WIPES
+</Wipes>
+{<NextBoss>Baron Steamroller</NextBoss>  {only one "next boss" for the whole
+                          raid event? presumably where to pick up next time?}}
 
 <note><![CDATA[$RAIDNOTE - Zone: $ZONE]]></note>
 
-{<Join>...</Join><Leave>...</Leave>   {specific timestamps per player. meh.}}
+<Join>
+  $JOINS
+</Join>
+<Leave>
+  $LEAVES
+</Leave>
 
 <Loot>
   $PHAT_LEWTS
@@ -54,7 +73,7 @@
 </RaidInfo>]====]):gsub('%b{}', "")
 
 --[[
-See the loot markup, next block.
+See the loot markup below.
 ]]
 local boss_kills_xml = ([====[
   <key$N>
@@ -78,9 +97,52 @@
 end
 
 --[[
+Handles the PlayerInfo, Join, and Leave tags.
+]]
+local joinleave_xml
+local player_info_xml = ([====[
+  <key$N>
+$PLAYER_GRUNTWORK
+  </key$N>
+]====]):gsub('%b{}', "")
+
+local function player_info_tag_lookup (tag)
+	if tag == 'N' then
+		return tostring(state.key)
+	elseif tag == 'NAME' then
+		return state.index
+	elseif tag == 'TIME' then
+		return state.time
+	end
+	local ltag = tag:lower()
+	if state.entry[ltag] then
+		-- handles race, guild, sex, class, level
+		return state.entry[ltag]
+	end
+	return "?"
+end
+
+do
+	local pi_xml_save = player_info_xml
+	local gruntwork_tags = {
+		"name", "race", "guild", "sex", "class", "level"
+	}
+	for i,tag in ipairs(gruntwork_tags) do
+		gruntwork_tags[i] = ("    <%s>$%s</%s>"):format(tag,tag:upper(),tag)
+	end
+	player_info_xml = player_info_xml:gsub('$PLAYER_GRUNTWORK', table.concat(gruntwork_tags,'\n'))
+
+	-- The join/leave blocks use "player" instead of "name".  They don't have a
+	-- guild tag, but they do have a time tag.
+	gruntwork_tags[1] = "    <player>$NAME</player>"
+	gruntwork_tags[3] = "    <time>$TIME</time>"
+	joinleave_xml = pi_xml_save:gsub('$PLAYER_GRUNTWORK', table.concat(gruntwork_tags,'\n'))
+end
+
+--[[
 $N                  1-based loop variable for key element
-$ITEMNAME           Without The Brackets
-$ITEMID             Not the ID, actually a full itemstring without the leading "item:"
+$ITEMNAME           Without The Square Brackets of the Whale
+$ITEMID             Not the numeric ID, actually a full itemstring without the leading "item:"
 $ICON               Last component of texture path?
 $CLASS,$SUBCLASS    ItemType
 $COLOR              GetItemQualityColor, full 8-digit string
@@ -169,7 +231,7 @@
 		return e.count and e.count:sub(2) or "1"   -- skip the leading "x"
 	end
 
--- maybe combine these next two
+-- should combine these next two
 tag_lookup_handlers.BOSS =
 	function (i, e)
 		while i > 0 and state.loot[i].kind ~= 'boss' do
@@ -224,6 +286,7 @@
 	end
 end
 
+
 local function generator (ttype, loot, last_printed, generated, cache)
 	-- Because it's XML, generated text is "grown" by shoving more crap into
 	-- the middle instead of appending to the end.  Only easy way of doing that
@@ -280,25 +343,49 @@
 			state.key = state.key + 1
 		end
 
-		text = text:gsub('$PHAT_LEWTS', table.concat(all_lewts, '\n'))
+		text = text:gsub('$PHAT_LEWTS', tconcat(all_lewts, '\n'))
 	end
 
-	-- Bosses
+	-- Player info, join times, leave times
 	do
-		local all_bosses = {}
+		local all_players, all_joins, all_leaves = {}, {}, {}
+		local player_template, joinleave_template = player_info_xml, joinleave_xml
+		local date = date
+
+		state.key = 1
+		if type(loot.raiders) == 'table' then for name,r in pairs(loot.raiders) do
+			state.index, state.entry = name, r
+			all_players[#all_players+1] = player_template:gsub('%$([%w_]+)', player_info_tag_lookup)
+			state.time = date ("%m/%d/%y %H:%M:00", r.join)
+			all_joins[#all_joins+1] = joinleave_template:gsub('%$([%w_]+)', player_info_tag_lookup)
+			state.time = date ("%m/%d/%y %H:%M:00", r.leave)
+			all_leaves[#all_leaves+1] = joinleave_template:gsub('%$([%w_]+)', player_info_tag_lookup)
+			state.key = state.key + 1
+		end end
+		text = text:gsub('$PLAYER_INFOS', tconcat(all_players, '\n'))
+		           :gsub('$JOINS', tconcat(all_joins, '\n'))
+		           :gsub('$LEAVES', tconcat(all_leaves, '\n'))
+	end
+
+	-- Bosses and wipes (does anybody really use the latter?)
+	do
+		local all_bosses, all_wipes = {}, {}
 		local boss_template = boss_kills_xml
 
 		state.key = 1
 		for i,e in addon:filtered_loot_iter('boss') do
-			if e.reason == 'kill' then  -- oh, for a 'continue' statement...
+			if e.reason == 'kill' then
 				state.index, state.entry = i, e
 				all_bosses[#all_bosses+1] = boss_template:gsub('%$([%w_]+)',
 					boss_kills_tag_lookup)
 				state.key = state.key + 1
+			elseif e.reason == 'wipe' then
+				all_wipes[#all_wipes+1] = ('<Wipe>%d</Wipe>'):format(e.stamp)
 			end
 		end
 
-		text = text:gsub('$BOSS_KILLS', table.concat(all_bosses, '\n'))
+		text = text:gsub('$BOSS_KILLS', tconcat(all_bosses, '\n'))
+		           :gsub('$WIPES', tconcat(all_wipes, '\n'))
 	end
 
 	-- In addition to doing the top-level zone, this will also catch any
@@ -316,13 +403,13 @@
 	--text = text:gsub('$DIFFICULTY', )
 	text = text:gsub('$RAIDNOTE', "")
 
-	cache[#cache+1] = "Formatted version (scroll down for unformatted):"
-	cache[#cache+1] = "==========================="
+	cache[#cache+1] = banner_formatted
+	cache[#cache+1] = banner_sep
 	cache[#cache+1] = text
 	cache[#cache+1] = '\n'
 
-	cache[#cache+1] = "Unformatted version:"
-	cache[#cache+1] = "==========================="
+	cache[#cache+1] = banner_unformatted
+	cache[#cache+1] = banner_sep
 	text = text:gsub('>%s+<', "><")
 	cache[#cache+1] = text
 	cache[#cache+1] = '\n'
@@ -332,17 +419,41 @@
 end
 
 local function specials (_, editbox, container, mkbutton)
-	local hl = mkbutton("Highlight",
+	local b = mkbutton("Highlight",
 		[[Highlight the unformatted copy for copy-and-pasting.]])
-	hl:SetFullWidth(true)
-	hl:SetCallback("OnClick", function(_hl)
+	b:SetFullWidth(true)
+	b:SetCallback("OnClick", function(_b)
+		local _,start,finish
 		local txt = editbox:GetText()
-		local _,start = txt:find("Unformatted version:\n=+\n")
-		local _,finish = txt:find("</RaidInfo>", start)
+		_,start = txt:find(banner_unformatted..'\n'..banner_sep..'\n')
+		_,finish = txt:find("</RaidInfo>", start)
 		editbox.editBox:HighlightText(start,finish)
 		editbox.editBox:SetCursorPosition(start)
 	end)
-	container:AddChild(hl)
+	container:AddChild(b)
+
+	local b = mkbutton("Re-Unformat",
+		[[Regenerate only the unformatted copy at the bottom <*from*> the formatted copy at the top.]])
+	b:SetFullWidth(true)
+	b:SetCallback("OnClick", function(_b)
+		local _,start,finish
+		local txt = editbox:GetText()
+		_,start = txt:find(banner_formatted..'\n'..banner_sep..'\n', --[[init=]]1, --[[plain=]]true)
+		_,finish = txt:find("</RaidInfo>", start, true)
+		txt = txt:sub(start+1,finish)
+		txt = banner_formatted .. '\n'
+			.. banner_sep .. '\n'
+			.. txt .. '\n\n\n'
+			.. banner_unformatted .. '\n'
+			.. banner_sep .. '\n'
+			.. txt:gsub('>%s+<', "><") .. '\n'
+		-- This would normally screw up the cached version, but we're regenerating
+		-- everything on each new display for this tab anyhow.
+		editbox.editBox:SetText(txt)
+		_,start = txt:find(banner_unformatted..'\n'..banner_sep..'\n', --[[init=]]1, --[[plain=]]true)
+		editbox.editBox:SetCursorPosition(start)
+	end)
+	container:AddChild(b)
 end
 
 addon:register_text_generator ("mleqdkp", [[ML/EQ-DKP]], [[MLdkp 1.1 EQDKP format]], generator, specials)