Mercurial > wow > ouroloot
comparison 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 |
comparison
equal
deleted
inserted
replaced
9:4fba9c6b5d3d | 10:67b8537e8432 |
---|---|
1 if UnitName"player" ~= "Farmbuyer" then return end | 1 -- This file is one gigantic exercise in abusing the garbage collector via |
2 -- string manipulation. A real XML-handling library would be cleaner, alas, | |
3 -- we can't load third-party .so/.dll inside the WoW client. Life is hard. | |
4 | |
2 local addon = select(2,...) | 5 local addon = select(2,...) |
6 local pairs, ipairs, tinsert, tremove, tconcat = pairs, ipairs, table.insert, table.remove, table.concat | |
7 local tostring, tonumber = tostring, tonumber | |
8 | |
9 local banner_formatted = "Formatted version (scroll down for unformatted):" | |
10 local banner_unformatted = "Unformatted version:" | |
11 local banner_sep = "===========================" | |
3 | 12 |
4 -- We keep some local state bundled up rather than trying to pass it around | 13 -- We keep some local state bundled up rather than trying to pass it around |
5 -- as paramters (which would have entailed creating a ton of closures). | 14 -- as paramters (which would have entailed creating a ton of closures). |
6 local state = {} | 15 local state = {} |
7 local tag_lookup_handlers = {} | 16 local tag_lookup_handlers = {} |
8 local do_tag_lookup_handler | 17 local do_tag_lookup_handler |
9 | 18 |
10 | 19 |
11 --[[ | 20 --[[ |
12 This is taken from CT_RaidTracker 1.7.32, reconstructing the output from | 21 This is based on CT_RaidTracker 1.7.32, reconstructing the output from |
13 code inspection. No official format documents are available on the web | 22 code inspection. No official format documents are available on the web |
14 without downloading and installing the EQDKP webserver package. Bah. | 23 without downloading and installing the EQDKP webserver package. Bah. |
15 | 24 |
16 Case of tag names shouldn't matter, but is preserved here from CT_RaidTracker | 25 Case of tag names shouldn't matter, but is preserved here from CT_RaidTracker |
17 code for comparison of generated output. | 26 code for comparison of generated output. |
29 <RaidInfo> | 38 <RaidInfo> |
30 <Version>1.4</Version> {In live output, this is missing due to scoping bug in ct_raidtracker.lua:3471} | 39 <Version>1.4</Version> {In live output, this is missing due to scoping bug in ct_raidtracker.lua:3471} |
31 <key>$TIMESTAMP</key> | 40 <key>$TIMESTAMP</key> |
32 <realm>$REALM</realm> | 41 <realm>$REALM</realm> |
33 <start>$TIMESTAMP</start> {Same as the key, apparently?} | 42 <start>$TIMESTAMP</start> {Same as the key, apparently?} |
34 <end>$ENDTIME</end> {Set by the "end the raid" command in the raid tracker, here just the final entry time} | 43 <end>$ENDTIME</end> {Set by the "end the raid" command in CTRT, here it is just the final entry time} |
35 <zone>$ZONE</zone> {may be optional. first one on the list in case of multiple zones?} | 44 <zone>$ZONE</zone> {may be optional. first one on the list in case of multiple zones?} |
36 {<difficulty>$DIFFICULTY</difficulty> {this scales badly in places like ICC. may be optional?}} | 45 {<difficulty>$DIFFICULTY</difficulty> {this scales badly in places like ICC. may be optional?}} |
37 | 46 |
38 {<PlayerInfos>... {guh.}} | 47 <PlayerInfos> |
48 $PLAYER_INFOS | |
49 </PlayerInfos> | |
39 | 50 |
40 <BossKills> | 51 <BossKills> |
41 $BOSS_KILLS | 52 $BOSS_KILLS |
42 </BossKills> | 53 </BossKills> |
43 | 54 |
44 {<Wipes> bleh} | 55 <Wipes> |
45 {<NextBoss>Baron Steamroller</NextBoss> {only one "next boss" for the whole raid event? huh?}} | 56 $WIPES |
57 </Wipes> | |
58 {<NextBoss>Baron Steamroller</NextBoss> {only one "next boss" for the whole | |
59 raid event? presumably where to pick up next time?}} | |
46 | 60 |
47 <note><![CDATA[$RAIDNOTE - Zone: $ZONE]]></note> | 61 <note><![CDATA[$RAIDNOTE - Zone: $ZONE]]></note> |
48 | 62 |
49 {<Join>...</Join><Leave>...</Leave> {specific timestamps per player. meh.}} | 63 <Join> |
64 $JOINS | |
65 </Join> | |
66 <Leave> | |
67 $LEAVES | |
68 </Leave> | |
50 | 69 |
51 <Loot> | 70 <Loot> |
52 $PHAT_LEWTS | 71 $PHAT_LEWTS |
53 </Loot> | 72 </Loot> |
54 </RaidInfo>]====]):gsub('%b{}', "") | 73 </RaidInfo>]====]):gsub('%b{}', "") |
55 | 74 |
56 --[[ | 75 --[[ |
57 See the loot markup, next block. | 76 See the loot markup below. |
58 ]] | 77 ]] |
59 local boss_kills_xml = ([====[ | 78 local boss_kills_xml = ([====[ |
60 <key$N> | 79 <key$N> |
61 <name>$BOSS_NAME</name> | 80 <name>$BOSS_NAME</name> |
62 <time>$BOSS_TIME</time> | 81 <time>$BOSS_TIME</time> |
76 return do_tag_lookup_handler (state.index, state.entry, tag) or 'NYI' | 95 return do_tag_lookup_handler (state.index, state.entry, tag) or 'NYI' |
77 end | 96 end |
78 end | 97 end |
79 | 98 |
80 --[[ | 99 --[[ |
100 Handles the PlayerInfo, Join, and Leave tags. | |
101 ]] | |
102 local joinleave_xml | |
103 local player_info_xml = ([====[ | |
104 <key$N> | |
105 $PLAYER_GRUNTWORK | |
106 </key$N> | |
107 ]====]):gsub('%b{}', "") | |
108 | |
109 local function player_info_tag_lookup (tag) | |
110 if tag == 'N' then | |
111 return tostring(state.key) | |
112 elseif tag == 'NAME' then | |
113 return state.index | |
114 elseif tag == 'TIME' then | |
115 return state.time | |
116 end | |
117 local ltag = tag:lower() | |
118 if state.entry[ltag] then | |
119 -- handles race, guild, sex, class, level | |
120 return state.entry[ltag] | |
121 end | |
122 return "?" | |
123 end | |
124 | |
125 do | |
126 local pi_xml_save = player_info_xml | |
127 local gruntwork_tags = { | |
128 "name", "race", "guild", "sex", "class", "level" | |
129 } | |
130 for i,tag in ipairs(gruntwork_tags) do | |
131 gruntwork_tags[i] = (" <%s>$%s</%s>"):format(tag,tag:upper(),tag) | |
132 end | |
133 player_info_xml = player_info_xml:gsub('$PLAYER_GRUNTWORK', table.concat(gruntwork_tags,'\n')) | |
134 | |
135 -- The join/leave blocks use "player" instead of "name". They don't have a | |
136 -- guild tag, but they do have a time tag. | |
137 gruntwork_tags[1] = " <player>$NAME</player>" | |
138 gruntwork_tags[3] = " <time>$TIME</time>" | |
139 joinleave_xml = pi_xml_save:gsub('$PLAYER_GRUNTWORK', table.concat(gruntwork_tags,'\n')) | |
140 end | |
141 | |
142 --[[ | |
81 $N 1-based loop variable for key element | 143 $N 1-based loop variable for key element |
82 $ITEMNAME Without The Brackets | 144 $ITEMNAME Without The Square Brackets of the Whale |
83 $ITEMID Not the ID, actually a full itemstring without the leading "item:" | 145 $ITEMID Not the numeric ID, actually a full itemstring without the leading "item:" |
84 $ICON Last component of texture path? | 146 $ICON Last component of texture path? |
85 $CLASS,$SUBCLASS ItemType | 147 $CLASS,$SUBCLASS ItemType |
86 $COLOR GetItemQualityColor, full 8-digit string | 148 $COLOR GetItemQualityColor, full 8-digit string |
87 $COUNT,$BOSS,$ZONE, | 149 $COUNT,$BOSS,$ZONE, |
88 $PLAYER all self-explanatory | 150 $PLAYER all self-explanatory |
167 tag_lookup_handlers.COUNT = | 229 tag_lookup_handlers.COUNT = |
168 function (i, e) | 230 function (i, e) |
169 return e.count and e.count:sub(2) or "1" -- skip the leading "x" | 231 return e.count and e.count:sub(2) or "1" -- skip the leading "x" |
170 end | 232 end |
171 | 233 |
172 -- maybe combine these next two | 234 -- should combine these next two |
173 tag_lookup_handlers.BOSS = | 235 tag_lookup_handlers.BOSS = |
174 function (i, e) | 236 function (i, e) |
175 while i > 0 and state.loot[i].kind ~= 'boss' do | 237 while i > 0 and state.loot[i].kind ~= 'boss' do |
176 i = i - 1 | 238 i = i - 1 |
177 end | 239 end |
221 return h(index,entry) | 283 return h(index,entry) |
222 else | 284 else |
223 error(("MLDKP tag lookup (index %d) on tag %s with no handler"):format(index,tag)) | 285 error(("MLDKP tag lookup (index %d) on tag %s with no handler"):format(index,tag)) |
224 end | 286 end |
225 end | 287 end |
288 | |
226 | 289 |
227 local function generator (ttype, loot, last_printed, generated, cache) | 290 local function generator (ttype, loot, last_printed, generated, cache) |
228 -- Because it's XML, generated text is "grown" by shoving more crap into | 291 -- Because it's XML, generated text is "grown" by shoving more crap into |
229 -- the middle instead of appending to the end. Only easy way of doing that | 292 -- the middle instead of appending to the end. Only easy way of doing that |
230 -- here is regenerating it from scratch each time. | 293 -- here is regenerating it from scratch each time. |
278 all_lewts[#all_lewts+1] = lewt_template:gsub('%$([%w_]+)', | 341 all_lewts[#all_lewts+1] = lewt_template:gsub('%$([%w_]+)', |
279 phat_lewt_tag_lookup) | 342 phat_lewt_tag_lookup) |
280 state.key = state.key + 1 | 343 state.key = state.key + 1 |
281 end | 344 end |
282 | 345 |
283 text = text:gsub('$PHAT_LEWTS', table.concat(all_lewts, '\n')) | 346 text = text:gsub('$PHAT_LEWTS', tconcat(all_lewts, '\n')) |
284 end | 347 end |
285 | 348 |
286 -- Bosses | 349 -- Player info, join times, leave times |
287 do | 350 do |
288 local all_bosses = {} | 351 local all_players, all_joins, all_leaves = {}, {}, {} |
352 local player_template, joinleave_template = player_info_xml, joinleave_xml | |
353 local date = date | |
354 | |
355 state.key = 1 | |
356 if type(loot.raiders) == 'table' then for name,r in pairs(loot.raiders) do | |
357 state.index, state.entry = name, r | |
358 all_players[#all_players+1] = player_template:gsub('%$([%w_]+)', player_info_tag_lookup) | |
359 state.time = date ("%m/%d/%y %H:%M:00", r.join) | |
360 all_joins[#all_joins+1] = joinleave_template:gsub('%$([%w_]+)', player_info_tag_lookup) | |
361 state.time = date ("%m/%d/%y %H:%M:00", r.leave) | |
362 all_leaves[#all_leaves+1] = joinleave_template:gsub('%$([%w_]+)', player_info_tag_lookup) | |
363 state.key = state.key + 1 | |
364 end end | |
365 text = text:gsub('$PLAYER_INFOS', tconcat(all_players, '\n')) | |
366 :gsub('$JOINS', tconcat(all_joins, '\n')) | |
367 :gsub('$LEAVES', tconcat(all_leaves, '\n')) | |
368 end | |
369 | |
370 -- Bosses and wipes (does anybody really use the latter?) | |
371 do | |
372 local all_bosses, all_wipes = {}, {} | |
289 local boss_template = boss_kills_xml | 373 local boss_template = boss_kills_xml |
290 | 374 |
291 state.key = 1 | 375 state.key = 1 |
292 for i,e in addon:filtered_loot_iter('boss') do | 376 for i,e in addon:filtered_loot_iter('boss') do |
293 if e.reason == 'kill' then -- oh, for a 'continue' statement... | 377 if e.reason == 'kill' then |
294 state.index, state.entry = i, e | 378 state.index, state.entry = i, e |
295 all_bosses[#all_bosses+1] = boss_template:gsub('%$([%w_]+)', | 379 all_bosses[#all_bosses+1] = boss_template:gsub('%$([%w_]+)', |
296 boss_kills_tag_lookup) | 380 boss_kills_tag_lookup) |
297 state.key = state.key + 1 | 381 state.key = state.key + 1 |
382 elseif e.reason == 'wipe' then | |
383 all_wipes[#all_wipes+1] = ('<Wipe>%d</Wipe>'):format(e.stamp) | |
298 end | 384 end |
299 end | 385 end |
300 | 386 |
301 text = text:gsub('$BOSS_KILLS', table.concat(all_bosses, '\n')) | 387 text = text:gsub('$BOSS_KILLS', tconcat(all_bosses, '\n')) |
388 :gsub('$WIPES', tconcat(all_wipes, '\n')) | |
302 end | 389 end |
303 | 390 |
304 -- In addition to doing the top-level zone, this will also catch any | 391 -- In addition to doing the top-level zone, this will also catch any |
305 -- leftover $ZONE tags. There could be multiple places in the raid, so | 392 -- leftover $ZONE tags. There could be multiple places in the raid, so |
306 -- we default to the first one we saw. | 393 -- we default to the first one we saw. |
314 -- Misc | 401 -- Misc |
315 text = text:gsub('$REALM', (GetRealmName())) | 402 text = text:gsub('$REALM', (GetRealmName())) |
316 --text = text:gsub('$DIFFICULTY', ) | 403 --text = text:gsub('$DIFFICULTY', ) |
317 text = text:gsub('$RAIDNOTE', "") | 404 text = text:gsub('$RAIDNOTE', "") |
318 | 405 |
319 cache[#cache+1] = "Formatted version (scroll down for unformatted):" | 406 cache[#cache+1] = banner_formatted |
320 cache[#cache+1] = "===========================" | 407 cache[#cache+1] = banner_sep |
321 cache[#cache+1] = text | 408 cache[#cache+1] = text |
322 cache[#cache+1] = '\n' | 409 cache[#cache+1] = '\n' |
323 | 410 |
324 cache[#cache+1] = "Unformatted version:" | 411 cache[#cache+1] = banner_unformatted |
325 cache[#cache+1] = "===========================" | 412 cache[#cache+1] = banner_sep |
326 text = text:gsub('>%s+<', "><") | 413 text = text:gsub('>%s+<', "><") |
327 cache[#cache+1] = text | 414 cache[#cache+1] = text |
328 cache[#cache+1] = '\n' | 415 cache[#cache+1] = '\n' |
329 | 416 |
330 wipe(state) | 417 wipe(state) |
331 return true | 418 return true |
332 end | 419 end |
333 | 420 |
334 local function specials (_, editbox, container, mkbutton) | 421 local function specials (_, editbox, container, mkbutton) |
335 local hl = mkbutton("Highlight", | 422 local b = mkbutton("Highlight", |
336 [[Highlight the unformatted copy for copy-and-pasting.]]) | 423 [[Highlight the unformatted copy for copy-and-pasting.]]) |
337 hl:SetFullWidth(true) | 424 b:SetFullWidth(true) |
338 hl:SetCallback("OnClick", function(_hl) | 425 b:SetCallback("OnClick", function(_b) |
426 local _,start,finish | |
339 local txt = editbox:GetText() | 427 local txt = editbox:GetText() |
340 local _,start = txt:find("Unformatted version:\n=+\n") | 428 _,start = txt:find(banner_unformatted..'\n'..banner_sep..'\n') |
341 local _,finish = txt:find("</RaidInfo>", start) | 429 _,finish = txt:find("</RaidInfo>", start) |
342 editbox.editBox:HighlightText(start,finish) | 430 editbox.editBox:HighlightText(start,finish) |
343 editbox.editBox:SetCursorPosition(start) | 431 editbox.editBox:SetCursorPosition(start) |
344 end) | 432 end) |
345 container:AddChild(hl) | 433 container:AddChild(b) |
434 | |
435 local b = mkbutton("Re-Unformat", | |
436 [[Regenerate only the unformatted copy at the bottom <*from*> the formatted copy at the top.]]) | |
437 b:SetFullWidth(true) | |
438 b:SetCallback("OnClick", function(_b) | |
439 local _,start,finish | |
440 local txt = editbox:GetText() | |
441 _,start = txt:find(banner_formatted..'\n'..banner_sep..'\n', --[[init=]]1, --[[plain=]]true) | |
442 _,finish = txt:find("</RaidInfo>", start, true) | |
443 txt = txt:sub(start+1,finish) | |
444 txt = banner_formatted .. '\n' | |
445 .. banner_sep .. '\n' | |
446 .. txt .. '\n\n\n' | |
447 .. banner_unformatted .. '\n' | |
448 .. banner_sep .. '\n' | |
449 .. txt:gsub('>%s+<', "><") .. '\n' | |
450 -- This would normally screw up the cached version, but we're regenerating | |
451 -- everything on each new display for this tab anyhow. | |
452 editbox.editBox:SetText(txt) | |
453 _,start = txt:find(banner_unformatted..'\n'..banner_sep..'\n', --[[init=]]1, --[[plain=]]true) | |
454 editbox.editBox:SetCursorPosition(start) | |
455 end) | |
456 container:AddChild(b) | |
346 end | 457 end |
347 | 458 |
348 addon:register_text_generator ("mleqdkp", [[ML/EQ-DKP]], [[MLdkp 1.1 EQDKP format]], generator, specials) | 459 addon:register_text_generator ("mleqdkp", [[ML/EQ-DKP]], [[MLdkp 1.1 EQDKP format]], generator, specials) |
349 | 460 |
350 -- vim:noet | 461 -- vim:noet |