farmbuyer@1
|
1 if UnitName"player" ~= "Farmbuyer" then return end
|
farmbuyer@1
|
2 local addon = select(2,...)
|
farmbuyer@1
|
3
|
farmbuyer@1
|
4 -- We keep some local state bundled up rather than trying to pass it around
|
farmbuyer@1
|
5 -- as paramters (which would have entailed creating a ton of closures).
|
farmbuyer@1
|
6 local state = {}
|
farmbuyer@1
|
7 local tag_lookup_handlers = {}
|
farmbuyer@1
|
8 local do_tag_lookup_handler
|
farmbuyer@1
|
9
|
farmbuyer@1
|
10
|
farmbuyer@1
|
11 --[[
|
farmbuyer@1
|
12 This is taken from CT_RaidTracker 1.7.32, reconstructing the output from
|
farmbuyer@1
|
13 code inspection. No official format documents are available on the web
|
farmbuyer@1
|
14 without downloading and installing the EQDKP webserver package. Bah.
|
farmbuyer@1
|
15
|
farmbuyer@1
|
16 Case of tag names shouldn't matter, but is preserved here from CT_RaidTracker
|
farmbuyer@1
|
17 code for comparison of generated output.
|
farmbuyer@1
|
18
|
farmbuyer@1
|
19 There is some waste adding newlines between elements here only to strip them
|
farmbuyer@1
|
20 out later, but it's worth the extra cycles for debugging and verification.
|
farmbuyer@1
|
21
|
farmbuyer@1
|
22 $TIMESTAMP,$ENDTIME MM/DD/YY HH:mm:ss except we don't have seconds available
|
farmbuyer@1
|
23 $REALM GetRealmName()
|
farmbuyer@1
|
24 $ZONE raw name, not snarky
|
farmbuyer@1
|
25 $RAIDNOTE arbitrary text for the raid event
|
farmbuyer@1
|
26 $PHAT_LEWTS all accumulated loot entries
|
farmbuyer@1
|
27 ]]
|
farmbuyer@1
|
28 local XML = ([====[
|
farmbuyer@1
|
29 <RaidInfo>
|
farmbuyer@1
|
30 <Version>1.4</Version> {In live output, this is missing due to scoping bug in ct_raidtracker.lua:3471}
|
farmbuyer@1
|
31 <key>$TIMESTAMP</key>
|
farmbuyer@1
|
32 <realm>$REALM</realm>
|
farmbuyer@1
|
33 <start>$TIMESTAMP</start> {Same as the key, apparently?}
|
farmbuyer@1
|
34 <end>$ENDTIME</end> {Set by the "end the raid" command in the raid tracker, here just the final entry time}
|
farmbuyer@1
|
35 <zone>$ZONE</zone> {may be optional. first one on the list in case of multiple zones?}
|
farmbuyer@1
|
36 {<difficulty>$DIFFICULTY</difficulty> {this scales badly in places like ICC. may be optional?}}
|
farmbuyer@1
|
37
|
farmbuyer@1
|
38 {<PlayerInfos>... {guh.}}
|
farmbuyer@1
|
39
|
farmbuyer@1
|
40 <BossKills>
|
farmbuyer@1
|
41 $BOSS_KILLS
|
farmbuyer@1
|
42 </BossKills>
|
farmbuyer@1
|
43
|
farmbuyer@1
|
44 {<Wipes> bleh}
|
farmbuyer@1
|
45 {<NextBoss>Baron Steamroller</NextBoss> {only one "next boss" for the whole raid event? huh?}}
|
farmbuyer@1
|
46
|
farmbuyer@1
|
47 <note><![CDATA[$RAIDNOTE - Zone: $ZONE]]></note>
|
farmbuyer@1
|
48
|
farmbuyer@1
|
49 {<Join>...</Join><Leave>...</Leave> {specific timestamps per player. meh.}}
|
farmbuyer@1
|
50
|
farmbuyer@1
|
51 <Loot>
|
farmbuyer@1
|
52 $PHAT_LEWTS
|
farmbuyer@1
|
53 </Loot>
|
farmbuyer@1
|
54 </RaidInfo>]====]):gsub('%b{}', "")
|
farmbuyer@1
|
55
|
farmbuyer@1
|
56 --[[
|
farmbuyer@1
|
57 See the loot markup, next block.
|
farmbuyer@1
|
58 ]]
|
farmbuyer@1
|
59 local boss_kills_xml = ([====[
|
farmbuyer@1
|
60 <key$N>
|
farmbuyer@1
|
61 <name>$BOSS_NAME</name>
|
farmbuyer@1
|
62 <time>$BOSS_TIME</time>
|
farmbuyer@1
|
63 <attendees></attendees> {this is actually empty in the working example...}
|
farmbuyer@1
|
64 <difficulty>$DIFFICULTY</difficulty>
|
farmbuyer@1
|
65 </key$N>
|
farmbuyer@1
|
66 ]====]):gsub('%b{}', "")
|
farmbuyer@1
|
67
|
farmbuyer@1
|
68 local function boss_kills_tag_lookup (tag)
|
farmbuyer@1
|
69 if tag == 'N' then
|
farmbuyer@1
|
70 return tostring(state.key)
|
farmbuyer@1
|
71 elseif tag == 'BOSS_NAME' then
|
farmbuyer@1
|
72 return state.entry.bosskill
|
farmbuyer@1
|
73 elseif tag == 'BOSS_TIME' then
|
farmbuyer@1
|
74 return do_tag_lookup_handler (state.index, state.entry, 'TIME')
|
farmbuyer@1
|
75 else
|
farmbuyer@1
|
76 return do_tag_lookup_handler (state.index, state.entry, tag) or 'NYI'
|
farmbuyer@1
|
77 end
|
farmbuyer@1
|
78 end
|
farmbuyer@1
|
79
|
farmbuyer@1
|
80 --[[
|
farmbuyer@1
|
81 $N 1-based loop variable for key element
|
farmbuyer@1
|
82 $ITEMNAME Without The Brackets
|
farmbuyer@1
|
83 $ITEMID Not the ID, actually a full itemstring without the leading "item:"
|
farmbuyer@1
|
84 $ICON Last component of texture path?
|
farmbuyer@1
|
85 $CLASS,$SUBCLASS ItemType
|
farmbuyer@1
|
86 $COLOR GetItemQualityColor, full 8-digit string
|
farmbuyer@1
|
87 $COUNT,$BOSS,$ZONE,
|
farmbuyer@1
|
88 $PLAYER all self-explanatory
|
farmbuyer@1
|
89 $COSTS in DKP points... hmmm
|
farmbuyer@1
|
90 $ITEMNOTE take the notes field for this one
|
farmbuyer@1
|
91 $TIME another formatted timestamp
|
farmbuyer@1
|
92 ]]
|
farmbuyer@1
|
93 local phat_lewt_xml = ([====[
|
farmbuyer@1
|
94 <key$N>
|
farmbuyer@1
|
95 $LEWT_GRUNTWORK
|
farmbuyer@1
|
96 <zone>$ZONE</zone> {may be optional}
|
farmbuyer@1
|
97 <difficulty>$DIFFICULTY</difficulty> {this scales badly in places like ICC. may be optional?}
|
farmbuyer@1
|
98 <Note><![CDATA[$ITEMNOTE - Zone: $ZONE - Boss: $BOSS - $COSTS DKP]]></Note> {zone can be followed by difficulty}
|
farmbuyer@1
|
99 </key$N>
|
farmbuyer@1
|
100 ]====]):gsub('%b{}', "")
|
farmbuyer@1
|
101
|
farmbuyer@1
|
102 local function phat_lewt_tag_lookup (tag)
|
farmbuyer@1
|
103 if tag == 'N' then
|
farmbuyer@1
|
104 return tostring(state.key)
|
farmbuyer@1
|
105 elseif tag == 'COSTS'
|
farmbuyer@1
|
106 then return '1'
|
farmbuyer@1
|
107 else
|
farmbuyer@1
|
108 return do_tag_lookup_handler (state.index, state.entry, tag) or 'NYI'
|
farmbuyer@1
|
109 end
|
farmbuyer@1
|
110 end
|
farmbuyer@1
|
111
|
farmbuyer@1
|
112 do
|
farmbuyer@1
|
113 local gruntwork_tags = {
|
farmbuyer@1
|
114 "ItemName", "ItemID", "Icon", "Class", "SubClass", "Color", "Count",
|
farmbuyer@1
|
115 "Player", "Costs", "Boss", "Time",
|
farmbuyer@1
|
116 }
|
farmbuyer@1
|
117 for i,tag in ipairs(gruntwork_tags) do
|
farmbuyer@1
|
118 gruntwork_tags[i] = (" <%s>$%s</%s>"):format(tag,tag:upper(),tag)
|
farmbuyer@1
|
119 end
|
farmbuyer@1
|
120 phat_lewt_xml = phat_lewt_xml:gsub('$LEWT_GRUNTWORK', table.concat(gruntwork_tags,'\n'))
|
farmbuyer@1
|
121 end
|
farmbuyer@1
|
122
|
farmbuyer@1
|
123
|
farmbuyer@1
|
124 local function format_EQDKP_timestamp (day_entry, time_entry)
|
farmbuyer@1
|
125 --assert(day_entry.kind == 'time', day_entry.kind .. " passed to MLEQDKP timestamp")
|
farmbuyer@1
|
126 return addon:format_timestamp ("$M/$D/$Y $h:$m:00", day_entry, time_entry)
|
farmbuyer@1
|
127 end
|
farmbuyer@1
|
128
|
farmbuyer@1
|
129
|
farmbuyer@1
|
130 -- Look up tag strings for a particular item, given index and entry table.
|
farmbuyer@1
|
131 tag_lookup_handlers.ITEMNAME =
|
farmbuyer@1
|
132 function (i, e)
|
farmbuyer@1
|
133 return e.itemname
|
farmbuyer@1
|
134 end
|
farmbuyer@1
|
135
|
farmbuyer@1
|
136 tag_lookup_handlers.ITEMID =
|
farmbuyer@1
|
137 function (i, e)
|
farmbuyer@1
|
138 return e.itemlink:match("^|c%x+|H(item[%d:]+)|h%[")
|
farmbuyer@1
|
139 end
|
farmbuyer@1
|
140
|
farmbuyer@1
|
141 tag_lookup_handlers.ICON =
|
farmbuyer@1
|
142 function (i, e)
|
farmbuyer@1
|
143 local str = e.itexture
|
farmbuyer@1
|
144 repeat
|
farmbuyer@1
|
145 local s = str:find('\\')
|
farmbuyer@1
|
146 if s then str = str:sub(s+1) end
|
farmbuyer@1
|
147 until not s
|
farmbuyer@1
|
148 return str
|
farmbuyer@1
|
149 end
|
farmbuyer@1
|
150
|
farmbuyer@1
|
151 tag_lookup_handlers.CLASS =
|
farmbuyer@1
|
152 function (i, e)
|
farmbuyer@1
|
153 return state.class
|
farmbuyer@1
|
154 end
|
farmbuyer@1
|
155
|
farmbuyer@1
|
156 tag_lookup_handlers.SUBCLASS =
|
farmbuyer@1
|
157 function (i, e)
|
farmbuyer@1
|
158 return state.subclass
|
farmbuyer@1
|
159 end
|
farmbuyer@1
|
160
|
farmbuyer@1
|
161 tag_lookup_handlers.COLOR =
|
farmbuyer@1
|
162 function (i, e)
|
farmbuyer@1
|
163 local q = select(4, GetItemQualityColor(e.quality))
|
farmbuyer@1
|
164 return q:sub(3) -- skip leading |c
|
farmbuyer@1
|
165 end
|
farmbuyer@1
|
166
|
farmbuyer@1
|
167 tag_lookup_handlers.COUNT =
|
farmbuyer@1
|
168 function (i, e)
|
farmbuyer@1
|
169 return e.count and e.count:sub(2) or "1" -- skip the leading "x"
|
farmbuyer@1
|
170 end
|
farmbuyer@1
|
171
|
farmbuyer@1
|
172 -- maybe combine these next two
|
farmbuyer@1
|
173 tag_lookup_handlers.BOSS =
|
farmbuyer@1
|
174 function (i, e)
|
farmbuyer@1
|
175 while i > 0 and state.loot[i].kind ~= 'boss' do
|
farmbuyer@1
|
176 i = i - 1
|
farmbuyer@1
|
177 end
|
farmbuyer@1
|
178 if i == 0 then return "No Boss Entry Found, Unknown Boss" end
|
farmbuyer@1
|
179 return state.loot[i].bosskill
|
farmbuyer@1
|
180 end
|
farmbuyer@1
|
181
|
farmbuyer@1
|
182 tag_lookup_handlers.ZONE =
|
farmbuyer@1
|
183 function (i, e)
|
farmbuyer@1
|
184 while i > 0 and state.loot[i].kind ~= 'boss' do
|
farmbuyer@1
|
185 i = i - 1
|
farmbuyer@1
|
186 end
|
farmbuyer@1
|
187 if i == 0 then return "No Boss Entry Found, Unknown Zone" end
|
farmbuyer@1
|
188 return state.loot[i].instance
|
farmbuyer@1
|
189 end
|
farmbuyer@1
|
190
|
farmbuyer@1
|
191 tag_lookup_handlers.DIFFICULTY =
|
farmbuyer@1
|
192 function (i, e)
|
farmbuyer@1
|
193 local tag = tag_lookup_handlers.ZONE(i,e)
|
farmbuyer@1
|
194 local N,h = tag:match("%((%d+)(h?)%)")
|
farmbuyer@1
|
195 if not N then return "1" end -- maybe signal an error instead?
|
farmbuyer@1
|
196 N = tonumber(N)
|
farmbuyer@1
|
197 N = ( (N==10) and 1 or 2 ) + ( (h=='h') and 2 or 0 )
|
farmbuyer@1
|
198 return tostring(N)
|
farmbuyer@1
|
199 end
|
farmbuyer@1
|
200
|
farmbuyer@1
|
201 tag_lookup_handlers.PLAYER =
|
farmbuyer@1
|
202 function (i, e)
|
farmbuyer@1
|
203 return state.player
|
farmbuyer@1
|
204 end
|
farmbuyer@1
|
205
|
farmbuyer@1
|
206 tag_lookup_handlers.ITEMNOTE =
|
farmbuyer@1
|
207 function (i, e)
|
farmbuyer@1
|
208 return state.itemnote
|
farmbuyer@1
|
209 end
|
farmbuyer@1
|
210
|
farmbuyer@1
|
211 tag_lookup_handlers.TIME =
|
farmbuyer@1
|
212 function (i, e)
|
farmbuyer@1
|
213 local ti,tl = addon:find_previous_time_entry(i)
|
farmbuyer@1
|
214 return format_EQDKP_timestamp(tl,e)
|
farmbuyer@1
|
215 end
|
farmbuyer@1
|
216
|
farmbuyer@1
|
217
|
farmbuyer@1
|
218 function do_tag_lookup_handler (index, entry, tag)
|
farmbuyer@1
|
219 local h = tag_lookup_handlers[tag]
|
farmbuyer@1
|
220 if h then
|
farmbuyer@1
|
221 return h(index,entry)
|
farmbuyer@1
|
222 else
|
farmbuyer@1
|
223 error(("MLDKP tag lookup (index %d) on tag %s with no handler"):format(index,tag))
|
farmbuyer@1
|
224 end
|
farmbuyer@1
|
225 end
|
farmbuyer@1
|
226
|
farmbuyer@1
|
227 local function generator (ttype, loot, last_printed, generated, cache)
|
farmbuyer@1
|
228 -- Because it's XML, generated text is "grown" by shoving more crap into
|
farmbuyer@1
|
229 -- the middle instead of appending to the end. Only easy way of doing that
|
farmbuyer@1
|
230 -- here is regenerating it from scratch each time.
|
farmbuyer@1
|
231 generated[ttype] = nil
|
farmbuyer@1
|
232
|
farmbuyer@1
|
233 local _
|
farmbuyer@1
|
234 local text = XML
|
farmbuyer@1
|
235 state.loot = loot
|
farmbuyer@1
|
236
|
farmbuyer@1
|
237 -- TIMESTAMPs
|
farmbuyer@1
|
238 do
|
farmbuyer@1
|
239 local f,l -- first and last timestamps in the table
|
farmbuyer@1
|
240 for i = 1, #loot do
|
farmbuyer@1
|
241 if loot[i].kind == 'time' then
|
farmbuyer@1
|
242 f = format_EQDKP_timestamp(loot[i])
|
farmbuyer@1
|
243 break
|
farmbuyer@1
|
244 end
|
farmbuyer@1
|
245 end
|
farmbuyer@1
|
246 _,l = addon:find_previous_time_entry(#loot) -- latest timestamp
|
farmbuyer@1
|
247 l = format_EQDKP_timestamp(l,loot[#loot])
|
farmbuyer@1
|
248 text = text:gsub('$TIMESTAMP', f):gsub('$ENDTIME', l)
|
farmbuyer@1
|
249 end
|
farmbuyer@1
|
250
|
farmbuyer@1
|
251 -- Loot
|
farmbuyer@1
|
252 do
|
farmbuyer@1
|
253 local all_lewts = {}
|
farmbuyer@1
|
254 local lewt_template = phat_lewt_xml
|
farmbuyer@1
|
255
|
farmbuyer@1
|
256 state.key = 1
|
farmbuyer@1
|
257 for i,e in addon:filtered_loot_iter('loot') do
|
farmbuyer@1
|
258 state.index, state.entry = i, e
|
farmbuyer@1
|
259 -- no sense doing repeated getiteminfo calls
|
farmbuyer@1
|
260 state.class, state.subclass = select(6, GetItemInfo(e.id))
|
farmbuyer@1
|
261
|
farmbuyer@1
|
262 -- similar logic as text_tabs.lua:
|
farmbuyer@1
|
263 -- assuming nobody names a toon "offspec" or "gvault"
|
farmbuyer@1
|
264 local P, N
|
farmbuyer@1
|
265 local disp = e.disposition or e.person
|
farmbuyer@1
|
266 if disp == 'offspec' then
|
farmbuyer@1
|
267 P,N = e.person, "offspec"
|
farmbuyer@1
|
268 elseif disp == 'gvault' then
|
farmbuyer@1
|
269 P,N = "guild vault", e.person
|
farmbuyer@1
|
270 else
|
farmbuyer@1
|
271 P,N = disp, ""
|
farmbuyer@1
|
272 end
|
farmbuyer@1
|
273 if e.extratext_byhand then
|
farmbuyer@1
|
274 N = N .. " -- " .. e.extratext
|
farmbuyer@1
|
275 end
|
farmbuyer@1
|
276 state.player, state.itemnote = P, N
|
farmbuyer@1
|
277
|
farmbuyer@1
|
278 all_lewts[#all_lewts+1] = lewt_template:gsub('%$([%w_]+)',
|
farmbuyer@1
|
279 phat_lewt_tag_lookup)
|
farmbuyer@1
|
280 state.key = state.key + 1
|
farmbuyer@1
|
281 end
|
farmbuyer@1
|
282
|
farmbuyer@1
|
283 text = text:gsub('$PHAT_LEWTS', table.concat(all_lewts, '\n'))
|
farmbuyer@1
|
284 end
|
farmbuyer@1
|
285
|
farmbuyer@1
|
286 -- Bosses
|
farmbuyer@1
|
287 do
|
farmbuyer@1
|
288 local all_bosses = {}
|
farmbuyer@1
|
289 local boss_template = boss_kills_xml
|
farmbuyer@1
|
290
|
farmbuyer@1
|
291 state.key = 1
|
farmbuyer@1
|
292 for i,e in addon:filtered_loot_iter('boss') do
|
farmbuyer@1
|
293 if e.reason == 'kill' then -- oh, for a 'continue' statement...
|
farmbuyer@1
|
294 state.index, state.entry = i, e
|
farmbuyer@1
|
295 all_bosses[#all_bosses+1] = boss_template:gsub('%$([%w_]+)',
|
farmbuyer@1
|
296 boss_kills_tag_lookup)
|
farmbuyer@1
|
297 state.key = state.key + 1
|
farmbuyer@1
|
298 end
|
farmbuyer@1
|
299 end
|
farmbuyer@1
|
300
|
farmbuyer@1
|
301 text = text:gsub('$BOSS_KILLS', table.concat(all_bosses, '\n'))
|
farmbuyer@1
|
302 end
|
farmbuyer@1
|
303
|
farmbuyer@1
|
304 -- In addition to doing the top-level zone, this will also catch any
|
farmbuyer@1
|
305 -- leftover $ZONE tags. There could be multiple places in the raid, so
|
farmbuyer@1
|
306 -- we default to the first one we saw.
|
farmbuyer@1
|
307 do
|
farmbuyer@1
|
308 local iter = addon:filtered_loot_iter() -- HACK
|
farmbuyer@1
|
309 local first_boss = iter('boss',0)
|
farmbuyer@1
|
310 local zone = first_boss and loot[first_boss].instance or "Unknown"
|
farmbuyer@1
|
311 text = text:gsub('$ZONE', zone)
|
farmbuyer@1
|
312 end
|
farmbuyer@1
|
313
|
farmbuyer@1
|
314 -- Misc
|
farmbuyer@1
|
315 text = text:gsub('$REALM', (GetRealmName()))
|
farmbuyer@1
|
316 --text = text:gsub('$DIFFICULTY', )
|
farmbuyer@1
|
317 text = text:gsub('$RAIDNOTE', "")
|
farmbuyer@1
|
318
|
farmbuyer@1
|
319 cache[#cache+1] = "Formatted version (scroll down for unformatted):"
|
farmbuyer@1
|
320 cache[#cache+1] = "==========================="
|
farmbuyer@1
|
321 cache[#cache+1] = text
|
farmbuyer@1
|
322 cache[#cache+1] = '\n'
|
farmbuyer@1
|
323
|
farmbuyer@1
|
324 cache[#cache+1] = "Unformatted version:"
|
farmbuyer@1
|
325 cache[#cache+1] = "==========================="
|
farmbuyer@1
|
326 text = text:gsub('>%s+<', "><")
|
farmbuyer@1
|
327 cache[#cache+1] = text
|
farmbuyer@1
|
328 cache[#cache+1] = '\n'
|
farmbuyer@1
|
329
|
farmbuyer@1
|
330 wipe(state)
|
farmbuyer@1
|
331 return true
|
farmbuyer@1
|
332 end
|
farmbuyer@1
|
333
|
farmbuyer@1
|
334 local function specials (_, editbox, container, mkbutton)
|
farmbuyer@1
|
335 local hl = mkbutton("Highlight",
|
farmbuyer@1
|
336 [[Highlight the unformatted copy for copy-and-pasting.]])
|
farmbuyer@1
|
337 hl:SetFullWidth(true)
|
farmbuyer@1
|
338 hl:SetCallback("OnClick", function(_hl)
|
farmbuyer@1
|
339 local txt = editbox:GetText()
|
farmbuyer@1
|
340 local _,start = txt:find("Unformatted version:\n=+\n")
|
farmbuyer@1
|
341 local _,finish = txt:find("</RaidInfo>", start)
|
farmbuyer@1
|
342 editbox.editBox:HighlightText(start,finish)
|
farmbuyer@1
|
343 editbox.editBox:SetCursorPosition(start)
|
farmbuyer@1
|
344 end)
|
farmbuyer@1
|
345 container:AddChild(hl)
|
farmbuyer@1
|
346 end
|
farmbuyer@1
|
347
|
farmbuyer@1
|
348 addon:register_text_generator ("mleqdkp", [[ML/EQ-DKP]], [[MLdkp 1.1 EQDKP format]], generator, specials)
|
farmbuyer@1
|
349
|
farmbuyer@1
|
350 -- vim:noet
|