farmbuyer@1: if UnitName"player" ~= "Farmbuyer" then return end
farmbuyer@1: local addon = select(2,...)
farmbuyer@1:
farmbuyer@1: -- We keep some local state bundled up rather than trying to pass it around
farmbuyer@1: -- as paramters (which would have entailed creating a ton of closures).
farmbuyer@1: local state = {}
farmbuyer@1: local tag_lookup_handlers = {}
farmbuyer@1: local do_tag_lookup_handler
farmbuyer@1:
farmbuyer@1:
farmbuyer@1: --[[
farmbuyer@1: This is taken from CT_RaidTracker 1.7.32, reconstructing the output from
farmbuyer@1: code inspection. No official format documents are available on the web
farmbuyer@1: without downloading and installing the EQDKP webserver package. Bah.
farmbuyer@1:
farmbuyer@1: Case of tag names shouldn't matter, but is preserved here from CT_RaidTracker
farmbuyer@1: code for comparison of generated output.
farmbuyer@1:
farmbuyer@1: There is some waste adding newlines between elements here only to strip them
farmbuyer@1: out later, but it's worth the extra cycles for debugging and verification.
farmbuyer@1:
farmbuyer@1: $TIMESTAMP,$ENDTIME MM/DD/YY HH:mm:ss except we don't have seconds available
farmbuyer@1: $REALM GetRealmName()
farmbuyer@1: $ZONE raw name, not snarky
farmbuyer@1: $RAIDNOTE arbitrary text for the raid event
farmbuyer@1: $PHAT_LEWTS all accumulated loot entries
farmbuyer@1: ]]
farmbuyer@1: local XML = ([====[
farmbuyer@1:
farmbuyer@1: 1.4 {In live output, this is missing due to scoping bug in ct_raidtracker.lua:3471}
farmbuyer@1: $TIMESTAMP
farmbuyer@1: $REALM
farmbuyer@1: $TIMESTAMP {Same as the key, apparently?}
farmbuyer@1: $ENDTIME {Set by the "end the raid" command in the raid tracker, here just the final entry time}
farmbuyer@1: $ZONE {may be optional. first one on the list in case of multiple zones?}
farmbuyer@1: {$DIFFICULTY {this scales badly in places like ICC. may be optional?}}
farmbuyer@1:
farmbuyer@1: {... {guh.}}
farmbuyer@1:
farmbuyer@1:
farmbuyer@1: $BOSS_KILLS
farmbuyer@1:
farmbuyer@1:
farmbuyer@1: { bleh}
farmbuyer@1: {Baron Steamroller {only one "next boss" for the whole raid event? huh?}}
farmbuyer@1:
farmbuyer@1:
farmbuyer@1:
farmbuyer@1: {...... {specific timestamps per player. meh.}}
farmbuyer@1:
farmbuyer@1:
farmbuyer@1: $PHAT_LEWTS
farmbuyer@1:
farmbuyer@1: ]====]):gsub('%b{}', "")
farmbuyer@1:
farmbuyer@1: --[[
farmbuyer@1: See the loot markup, next block.
farmbuyer@1: ]]
farmbuyer@1: local boss_kills_xml = ([====[
farmbuyer@1:
farmbuyer@1: $BOSS_NAME
farmbuyer@1:
farmbuyer@1: {this is actually empty in the working example...}
farmbuyer@1: $DIFFICULTY
farmbuyer@1:
farmbuyer@1: ]====]):gsub('%b{}', "")
farmbuyer@1:
farmbuyer@1: local function boss_kills_tag_lookup (tag)
farmbuyer@1: if tag == 'N' then
farmbuyer@1: return tostring(state.key)
farmbuyer@1: elseif tag == 'BOSS_NAME' then
farmbuyer@1: return state.entry.bosskill
farmbuyer@1: elseif tag == 'BOSS_TIME' then
farmbuyer@1: return do_tag_lookup_handler (state.index, state.entry, 'TIME')
farmbuyer@1: else
farmbuyer@1: return do_tag_lookup_handler (state.index, state.entry, tag) or 'NYI'
farmbuyer@1: end
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: --[[
farmbuyer@1: $N 1-based loop variable for key element
farmbuyer@1: $ITEMNAME Without The Brackets
farmbuyer@1: $ITEMID Not the ID, actually a full itemstring without the leading "item:"
farmbuyer@1: $ICON Last component of texture path?
farmbuyer@1: $CLASS,$SUBCLASS ItemType
farmbuyer@1: $COLOR GetItemQualityColor, full 8-digit string
farmbuyer@1: $COUNT,$BOSS,$ZONE,
farmbuyer@1: $PLAYER all self-explanatory
farmbuyer@1: $COSTS in DKP points... hmmm
farmbuyer@1: $ITEMNOTE take the notes field for this one
farmbuyer@1: $TIME another formatted timestamp
farmbuyer@1: ]]
farmbuyer@1: local phat_lewt_xml = ([====[
farmbuyer@1:
farmbuyer@1: $LEWT_GRUNTWORK
farmbuyer@1: $ZONE {may be optional}
farmbuyer@1: $DIFFICULTY {this scales badly in places like ICC. may be optional?}
farmbuyer@1: {zone can be followed by difficulty}
farmbuyer@1:
farmbuyer@1: ]====]):gsub('%b{}', "")
farmbuyer@1:
farmbuyer@1: local function phat_lewt_tag_lookup (tag)
farmbuyer@1: if tag == 'N' then
farmbuyer@1: return tostring(state.key)
farmbuyer@1: elseif tag == 'COSTS'
farmbuyer@1: then return '1'
farmbuyer@1: else
farmbuyer@1: return do_tag_lookup_handler (state.index, state.entry, tag) or 'NYI'
farmbuyer@1: end
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: do
farmbuyer@1: local gruntwork_tags = {
farmbuyer@1: "ItemName", "ItemID", "Icon", "Class", "SubClass", "Color", "Count",
farmbuyer@1: "Player", "Costs", "Boss", "Time",
farmbuyer@1: }
farmbuyer@1: for i,tag in ipairs(gruntwork_tags) do
farmbuyer@1: gruntwork_tags[i] = (" <%s>$%s%s>"):format(tag,tag:upper(),tag)
farmbuyer@1: end
farmbuyer@1: phat_lewt_xml = phat_lewt_xml:gsub('$LEWT_GRUNTWORK', table.concat(gruntwork_tags,'\n'))
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1:
farmbuyer@1: local function format_EQDKP_timestamp (day_entry, time_entry)
farmbuyer@1: --assert(day_entry.kind == 'time', day_entry.kind .. " passed to MLEQDKP timestamp")
farmbuyer@1: return addon:format_timestamp ("$M/$D/$Y $h:$m:00", day_entry, time_entry)
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1:
farmbuyer@1: -- Look up tag strings for a particular item, given index and entry table.
farmbuyer@1: tag_lookup_handlers.ITEMNAME =
farmbuyer@1: function (i, e)
farmbuyer@1: return e.itemname
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.ITEMID =
farmbuyer@1: function (i, e)
farmbuyer@1: return e.itemlink:match("^|c%x+|H(item[%d:]+)|h%[")
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.ICON =
farmbuyer@1: function (i, e)
farmbuyer@1: local str = e.itexture
farmbuyer@1: repeat
farmbuyer@1: local s = str:find('\\')
farmbuyer@1: if s then str = str:sub(s+1) end
farmbuyer@1: until not s
farmbuyer@1: return str
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.CLASS =
farmbuyer@1: function (i, e)
farmbuyer@1: return state.class
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.SUBCLASS =
farmbuyer@1: function (i, e)
farmbuyer@1: return state.subclass
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.COLOR =
farmbuyer@1: function (i, e)
farmbuyer@1: local q = select(4, GetItemQualityColor(e.quality))
farmbuyer@1: return q:sub(3) -- skip leading |c
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.COUNT =
farmbuyer@1: function (i, e)
farmbuyer@1: return e.count and e.count:sub(2) or "1" -- skip the leading "x"
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: -- maybe combine these next two
farmbuyer@1: tag_lookup_handlers.BOSS =
farmbuyer@1: function (i, e)
farmbuyer@1: while i > 0 and state.loot[i].kind ~= 'boss' do
farmbuyer@1: i = i - 1
farmbuyer@1: end
farmbuyer@1: if i == 0 then return "No Boss Entry Found, Unknown Boss" end
farmbuyer@1: return state.loot[i].bosskill
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.ZONE =
farmbuyer@1: function (i, e)
farmbuyer@1: while i > 0 and state.loot[i].kind ~= 'boss' do
farmbuyer@1: i = i - 1
farmbuyer@1: end
farmbuyer@1: if i == 0 then return "No Boss Entry Found, Unknown Zone" end
farmbuyer@1: return state.loot[i].instance
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.DIFFICULTY =
farmbuyer@1: function (i, e)
farmbuyer@1: local tag = tag_lookup_handlers.ZONE(i,e)
farmbuyer@1: local N,h = tag:match("%((%d+)(h?)%)")
farmbuyer@1: if not N then return "1" end -- maybe signal an error instead?
farmbuyer@1: N = tonumber(N)
farmbuyer@1: N = ( (N==10) and 1 or 2 ) + ( (h=='h') and 2 or 0 )
farmbuyer@1: return tostring(N)
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.PLAYER =
farmbuyer@1: function (i, e)
farmbuyer@1: return state.player
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.ITEMNOTE =
farmbuyer@1: function (i, e)
farmbuyer@1: return state.itemnote
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: tag_lookup_handlers.TIME =
farmbuyer@1: function (i, e)
farmbuyer@1: local ti,tl = addon:find_previous_time_entry(i)
farmbuyer@1: return format_EQDKP_timestamp(tl,e)
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1:
farmbuyer@1: function do_tag_lookup_handler (index, entry, tag)
farmbuyer@1: local h = tag_lookup_handlers[tag]
farmbuyer@1: if h then
farmbuyer@1: return h(index,entry)
farmbuyer@1: else
farmbuyer@1: error(("MLDKP tag lookup (index %d) on tag %s with no handler"):format(index,tag))
farmbuyer@1: end
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: local function generator (ttype, loot, last_printed, generated, cache)
farmbuyer@1: -- Because it's XML, generated text is "grown" by shoving more crap into
farmbuyer@1: -- the middle instead of appending to the end. Only easy way of doing that
farmbuyer@1: -- here is regenerating it from scratch each time.
farmbuyer@1: generated[ttype] = nil
farmbuyer@1:
farmbuyer@1: local _
farmbuyer@1: local text = XML
farmbuyer@1: state.loot = loot
farmbuyer@1:
farmbuyer@1: -- TIMESTAMPs
farmbuyer@1: do
farmbuyer@1: local f,l -- first and last timestamps in the table
farmbuyer@1: for i = 1, #loot do
farmbuyer@1: if loot[i].kind == 'time' then
farmbuyer@1: f = format_EQDKP_timestamp(loot[i])
farmbuyer@1: break
farmbuyer@1: end
farmbuyer@1: end
farmbuyer@1: _,l = addon:find_previous_time_entry(#loot) -- latest timestamp
farmbuyer@1: l = format_EQDKP_timestamp(l,loot[#loot])
farmbuyer@1: text = text:gsub('$TIMESTAMP', f):gsub('$ENDTIME', l)
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: -- Loot
farmbuyer@1: do
farmbuyer@1: local all_lewts = {}
farmbuyer@1: local lewt_template = phat_lewt_xml
farmbuyer@1:
farmbuyer@1: state.key = 1
farmbuyer@1: for i,e in addon:filtered_loot_iter('loot') do
farmbuyer@1: state.index, state.entry = i, e
farmbuyer@1: -- no sense doing repeated getiteminfo calls
farmbuyer@1: state.class, state.subclass = select(6, GetItemInfo(e.id))
farmbuyer@1:
farmbuyer@1: -- similar logic as text_tabs.lua:
farmbuyer@1: -- assuming nobody names a toon "offspec" or "gvault"
farmbuyer@1: local P, N
farmbuyer@1: local disp = e.disposition or e.person
farmbuyer@1: if disp == 'offspec' then
farmbuyer@1: P,N = e.person, "offspec"
farmbuyer@1: elseif disp == 'gvault' then
farmbuyer@1: P,N = "guild vault", e.person
farmbuyer@1: else
farmbuyer@1: P,N = disp, ""
farmbuyer@1: end
farmbuyer@1: if e.extratext_byhand then
farmbuyer@1: N = N .. " -- " .. e.extratext
farmbuyer@1: end
farmbuyer@1: state.player, state.itemnote = P, N
farmbuyer@1:
farmbuyer@1: all_lewts[#all_lewts+1] = lewt_template:gsub('%$([%w_]+)',
farmbuyer@1: phat_lewt_tag_lookup)
farmbuyer@1: state.key = state.key + 1
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: text = text:gsub('$PHAT_LEWTS', table.concat(all_lewts, '\n'))
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: -- Bosses
farmbuyer@1: do
farmbuyer@1: local all_bosses = {}
farmbuyer@1: local boss_template = boss_kills_xml
farmbuyer@1:
farmbuyer@1: state.key = 1
farmbuyer@1: for i,e in addon:filtered_loot_iter('boss') do
farmbuyer@1: if e.reason == 'kill' then -- oh, for a 'continue' statement...
farmbuyer@1: state.index, state.entry = i, e
farmbuyer@1: all_bosses[#all_bosses+1] = boss_template:gsub('%$([%w_]+)',
farmbuyer@1: boss_kills_tag_lookup)
farmbuyer@1: state.key = state.key + 1
farmbuyer@1: end
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: text = text:gsub('$BOSS_KILLS', table.concat(all_bosses, '\n'))
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: -- In addition to doing the top-level zone, this will also catch any
farmbuyer@1: -- leftover $ZONE tags. There could be multiple places in the raid, so
farmbuyer@1: -- we default to the first one we saw.
farmbuyer@1: do
farmbuyer@1: local iter = addon:filtered_loot_iter() -- HACK
farmbuyer@1: local first_boss = iter('boss',0)
farmbuyer@1: local zone = first_boss and loot[first_boss].instance or "Unknown"
farmbuyer@1: text = text:gsub('$ZONE', zone)
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: -- Misc
farmbuyer@1: text = text:gsub('$REALM', (GetRealmName()))
farmbuyer@1: --text = text:gsub('$DIFFICULTY', )
farmbuyer@1: text = text:gsub('$RAIDNOTE', "")
farmbuyer@1:
farmbuyer@1: cache[#cache+1] = "Formatted version (scroll down for unformatted):"
farmbuyer@1: cache[#cache+1] = "==========================="
farmbuyer@1: cache[#cache+1] = text
farmbuyer@1: cache[#cache+1] = '\n'
farmbuyer@1:
farmbuyer@1: cache[#cache+1] = "Unformatted version:"
farmbuyer@1: cache[#cache+1] = "==========================="
farmbuyer@1: text = text:gsub('>%s+<', "><")
farmbuyer@1: cache[#cache+1] = text
farmbuyer@1: cache[#cache+1] = '\n'
farmbuyer@1:
farmbuyer@1: wipe(state)
farmbuyer@1: return true
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: local function specials (_, editbox, container, mkbutton)
farmbuyer@1: local hl = mkbutton("Highlight",
farmbuyer@1: [[Highlight the unformatted copy for copy-and-pasting.]])
farmbuyer@1: hl:SetFullWidth(true)
farmbuyer@1: hl:SetCallback("OnClick", function(_hl)
farmbuyer@1: local txt = editbox:GetText()
farmbuyer@1: local _,start = txt:find("Unformatted version:\n=+\n")
farmbuyer@1: local _,finish = txt:find("", start)
farmbuyer@1: editbox.editBox:HighlightText(start,finish)
farmbuyer@1: editbox.editBox:SetCursorPosition(start)
farmbuyer@1: end)
farmbuyer@1: container:AddChild(hl)
farmbuyer@1: end
farmbuyer@1:
farmbuyer@1: addon:register_text_generator ("mleqdkp", [[ML/EQ-DKP]], [[MLdkp 1.1 EQDKP format]], generator, specials)
farmbuyer@1:
farmbuyer@1: -- vim:noet