Mercurial > wow > ouroloot
changeset 56:fcc0d0ff5832
- instance_tag() also returns max instance size as a plain number, adjust
call sites
- clean up .raiders table, add some new fields, use copies of this instead
of a single string
- make sure datarev field is properly updated when it's already present
- avoid multiple GetRaidRosterInfo loops scattered throughout the addon,
instead just traverse the .raiders list, regularly updated
- make the 'loot' and 'boss' broadcasts versioned. Handle receiving older.
- new format for plaintext attendance output
author | Farmbuyer of US-Kilrogg <farmbuyer@gmail.com> |
---|---|
date | Fri, 13 Apr 2012 04:28:46 +0000 |
parents | ac57a4342812 |
children | 81d5449621f8 |
files | LibFarmbuyer.lua bossmods.lua core.lua gui.lua text_tabs.lua verbage.lua |
diffstat | 6 files changed, 205 insertions(+), 103 deletions(-) [+] |
line wrap: on
line diff
--- a/LibFarmbuyer.lua Sat Apr 07 05:40:20 2012 +0000 +++ b/LibFarmbuyer.lua Fri Apr 13 04:28:46 2012 +0000 @@ -54,7 +54,7 @@ Ditto for table recycling. ]] -local MAJOR, MINOR = "LibFarmbuyer", 15 +local MAJOR, MINOR = "LibFarmbuyer", 16 assert(LibStub,MAJOR.." requires LibStub") local lib = LibStub:NewLibrary(MAJOR, MINOR) if not lib then return end @@ -102,7 +102,7 @@ --[[ safeprint ]] -local tconcat = table.concat +local tconcat, tostring, tonumber = table.concat, tostring, tonumber local function undocontrol(c) return ("\\%.3d"):format(c:byte()) end @@ -139,7 +139,7 @@ t[i] = tostring(t[i]):gsub('\124','\124\124') :gsub('(%c)', undocontrol) end - local msg = tconcat(t,' ', i, tonumber(t.n) or #t) + local msg = tconcat(t,' ', 1, tonumber(t.n) or #t) if type(f) == 'function' then return msg,f(msg) else
--- a/bossmods.lua Sat Apr 07 05:40:20 2012 +0000 +++ b/bossmods.lua Fri Apr 13 04:28:46 2012 +0000 @@ -35,7 +35,7 @@ local tonumber = tonumber -- WoW -local GetRaidRosterInfo = GetRaidRosterInfo +--local GetRaidRosterInfo = GetRaidRosterInfo -- OL local addon_do_boss @@ -44,7 +44,7 @@ ------ Deadly Boss Mods do local DBM - local location + local location, maxsize local real_loadmod -- When zoning into a raid instance not seen this session, make sure -- we don't report a previous raid instance as current location. DBM @@ -66,7 +66,12 @@ name = "Unknown Boss" end - local it = location or self.instance_tag() + local it + if location then + it = location + else + it, maxsize = self.instance_tag() + end self.latest_instance = it location = nil @@ -75,18 +80,7 @@ duration = math.floor (GetTime() - mod.combatInfo.pull) end - -- attendance: maybe put people in groups 6,7,8 into a "backup/standby" - -- list? probably too specific to guild practices. - local raiders = {} - for i = 1, GetNumRaidMembers() do - local name = GetRaidRosterInfo(i) - if name then - tinsert (raiders, name) - end - end - table.sort(raiders) - - return addon_do_boss (self, reason, name, it, duration, raiders) + return addon_do_boss (self, reason, name, it, maxsize, duration) end local function callback(...) DBMBossCallback(addon,...) end @@ -102,7 +96,9 @@ addon_do_boss = OL_boss_worker local r = DBM:RegisterCallback("kill", callback) DBM:RegisterCallback("wipe", callback) - DBM:RegisterCallback("pull", function() location = self.instance_tag() end) + DBM:RegisterCallback("pull", function() + location, maxsize = self.instance_tag() + end) real_loadmod = DBM.LoadMod DBM.LoadMod = resetting_loadmod return r > 0
--- a/core.lua Sat Apr 07 05:40:20 2012 +0000 +++ b/core.lua Fri Apr 13 04:28:46 2012 +0000 @@ -6,6 +6,18 @@ - forum saved text from forum markup window, default nil - attend saved text from raid attendence window, default nil - printed.FOO last loot index formatted into text window FOO, default 0 +- raiders accumulating raid roster data as we see raid members; indexed + by player name with subtable fields: +- class capitalized English codename ("WARRIOR", "DEATHKNIGHT", etc) +- subgroup 1-8 +- race English codename ("BloodElf", etc) +- sex 1 = unknown/error, 2 = male, 3 = female +- level can be 0 if player was offline at the time +- guild guild name, or missing if unguilded +- online 1 = online, 2 = offline, 3 = no longer in raid + [both of these next two fields use time_t values:] +- join time player joined the raid (or first time we've seen them) +- leave time player left the raid (or time we've left the raid) Common g_loot entry indices: - kind time/boss/loot @@ -19,26 +31,29 @@ Boss specific g_loot indices: - bossname name of boss/encounter; -- may be changed if "snarky boss names" option is enabled + may be changed if "snarky boss names" option is enabled - reason wipe/kill ("pull" does not generate an entry) - instance name of instance, including size and difficulty -- duration in seconds; may be missing -- raiderlist "Able, Baker, Charlie"; may be missing +- maxsize 5/10/25, presumably also 15 and 40 could show up; can be + 0 if we're outside an instance and the player inside has + an older version +- duration in seconds; may be missing (only present if local) +- raidersnap copy of g_loot.raiders at the time of the boss event Loot specific g_loot indices: - person recipient - person_class class of recipient if available; may be missing; -- will be classID-style (e.g., DEATHKNIGHT) + will be classID-style (e.g., DEATHKNIGHT) - itemname not including square brackets - id itemID as number - itemlink full clickable link - itexture icon path (e.g., Interface\Icons\INV_Misc_Rune_01) - quality ITEM_QUALITY_* number - disposition offspec/gvault/shard; missing otherwise; can be set from -- the extratext field + the extratext field - count e.g., "x3"; missing otherwise; can be set/removed from -- extratext; triggers only for a stack of items, not "the boss -- dropped double axes today" + extratext; triggers only for a stack of items, not "the boss + dropped double axes today" - is_heroic true if item is heroic; missing otherwise - cache_miss if GetItemInfo failed; SHOULD be missing (changes other fields) - bcast_from if rebroadcast from another player; missing otherwise @@ -88,7 +103,7 @@ ------ Constants local option_defaults = { - ['datarev'] = 15, -- cheating, this isn't actually an option + ['datarev'] = 16, -- cheating, this isn't actually an option ['popup_on_join'] = true, ['register_slashloot'] = true, ['scroll_to_bottom'] = true, @@ -138,7 +153,7 @@ -- Play cute games with namespaces here just to save typing. WTB Lua 5.2 PST. do local _G = _G setfenv (1, addon) - commrev = 15 -- number + commrev = '16' revision = _G.GetAddOnMetadata(nametag,"Version") or "?" -- "x.yy.z", etc ident = "OuroLoot2" identTg = "OuroLoot2Tg" @@ -233,10 +248,10 @@ local g_boss_signpost = nil local opts = nil -local pairs, ipairs, tinsert, tremove, tonumber, wipe = - pairs, ipairs, table.insert, table.remove, tonumber, table.wipe +local pairs, ipairs, tinsert, tremove, tostring, tonumber, wipe = + pairs, ipairs, table.insert, table.remove, tostring, tonumber, table.wipe local pprint, tabledump = addon.pprint, flib.tabledump -local GetNumRaidMembers = GetNumRaidMembers +local CopyTable, GetNumRaidMembers = CopyTable, GetNumRaidMembers -- En masse forward decls of symbols defined inside local blocks local _register_bossmod, makedate, create_new_cache, _init, _log @@ -323,29 +338,30 @@ end end --- Returns an instance name or abbreviation +-- Returns an instance name or abbreviation, followed by the raid size local function instance_tag() local name, typeof, diffcode, diffstr, _, perbossheroic, isdynamic = GetInstanceInfo() - local t + local t, r name = addon.instance_abbrev[name] or name - if typeof == "none" then return name end + if typeof == "none" then return name, MAX_RAID_MEMBERS end -- diffstr is "5 Player", "10 Player (Heroic)", etc. ugh. if (GetLFGMode()) and (GetLFGModeType() == 'raid') then - t = 'LFR' + t,r = 'LFR', 25 elseif diffcode == 1 then - t = ((GetNumRaidMembers()>0) and "10" or "5") + t,r = (GetNumRaidMembers()>0) and "10",10 or "5",5 elseif diffcode == 2 then - t = ((GetNumRaidMembers()>0) and "25" or "5h") + t,r = (GetNumRaidMembers()>0) and "25",25 or "5h",5 elseif diffcode == 3 then - t = "10h" + t,r = "10h", 10 elseif diffcode == 4 then - t = "25h" + t,r = "25h", 25 end -- dynamic difficulties always return normal "codes" if isdynamic and perbossheroic == 1 then t = t .. "h" end - return name .. "(" .. t .. ")" + pprint("instance_tag final", t, r) + return name .. "(" .. t .. ")", r end addon.instance_tag = instance_tag -- grumble addon.latest_instance = nil -- spelling reminder, assigned elsewhere @@ -448,6 +464,7 @@ opts[opt] = default end end + opts.datarev = option_defaults.datarev -- transition&remove old options opts['forum_use_itemid'] = nil @@ -510,18 +527,33 @@ self.history_all.HISTFORMAT = nil -- don't keep this in live data --OuroLootSV_hist = nil - -- Handle changes to the stored data format, in stages from oldest to - -- newest. This won't look coherent until multiple stages are happening. - if stored_datarev == nil then - self:Print("Transitioning saved data format to 15...") - for i,e in ipairs(OuroLootSV) do - if e.bosskill then - e.bossname, e.bosskill = e.bosskill, nil + -- Handle changes to the stored data format in stages from oldest to newest. + if OuroLootSV then + local dirty = false + if stored_datarev == nil then + self:Print("Transitioning saved data format to 15..."); dirty = true + for i,e in ipairs(OuroLootSV) do + if e.bosskill then + e.bossname, e.bosskill = e.bosskill, nil + end end + stored_datarev = 15 end - stored_datarev = 15 + if stored_datarev == 15 then + self:Print("Transitioning saved data format to 16..."); dirty = true + for i,e in ipairs(OuroLootSV) do + if e.kind == 'boss' then + e.maxsize, e.raiderlist, e.raidersnap = 0, nil, {} + end + end + OuroLootSV.raiders = OuroLootSV.raiders or {} + for name,r in pairs(OuroLootSV.raiders) do + r.subgroup = 0 + end + stored_datarev = 16 + end + if dirty then self:Print("Saved data has been massaged into shape.") end end - --if stored_datarev == 15 then.... _init(self) self.dprint('flow', "version strings:", revision_large, self.status_text) @@ -681,9 +713,9 @@ do local IsInInstance, UnitName, UnitIsConnected, UnitClass, UnitRace, UnitSex, - UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo = + UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo, GetRaidRosterInfo = IsInInstance, UnitName, UnitIsConnected, UnitClass, UnitRace, UnitSex, - UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo + UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo, GetRaidRosterInfo local time, difftime = time, difftime local R_ACTIVE, R_OFFLINE, R_LEFT = 1, 2, 3 @@ -727,15 +759,21 @@ g_loot.raiders[name] = { needinfo=true } end local r = g_loot.raiders[name] + -- We grab a bunch of return values here, but only pay attention to + -- them under specific circumstances. + local grri_name, connected, subgroup, level, class, _ + grri_name, _, subgroup, level, _, class, connected = GetRaidRosterInfo(i) + assert(name==grri_name, "UnitName =/= grri_name of same raidindex") + r.subgroup = subgroup if r.needinfo and UnitIsVisible(unit) then r.needinfo = nil - r.class = select(2,UnitClass(unit)) + r.class = class --select(2,UnitClass(unit)) r.race = select(2,UnitRace(unit)) r.sex = UnitSex(unit) - r.level = UnitLevel(unit) + r.level = level --UnitLevel(unit) r.guild = GetGuildInfo(unit) end - local connected = UnitIsConnected(unit) + --local connected = UnitIsConnected(unit) if connected and r.online ~= R_ACTIVE then r.join = r.join or now r.online = R_ACTIVE @@ -870,7 +908,7 @@ -- This is only a 'while' to make jumping out of it easy and still do cleanup below. while local_override or ((iquality >= self.threshold) and not opts.itemfilter[itemid]) do if (self.rebroadcast and (not from)) and not local_override then - self:broadcast('loot', recipient, itemid, count) + self:vbroadcast('loot', recipient, itemid, count) end if (not self.enabled) and (not local_override) then break end local signature = recipient .. iname .. (count or "") @@ -1211,32 +1249,6 @@ addon.sender_list.namesI = byindex end --- Message sending. --- See OCR_funcs.tag at the end of this file for incoming message treatment. -do - local function assemble(...) - local msg = ... - for i = 2, select('#',...) do - msg = msg .. '\a' .. (select(i,...) or "") - end - return msg - end - - -- broadcast('tag', <stuff>) - function addon:broadcast(...) - local msg = assemble(...) - self.dprint('comm', "<broadcast>:", msg) - -- the "GUILD" here is just so that we can also pick up on it - self:SendCommMessage(self.ident, msg, self.debug.comm and "GUILD" or "RAID") - end - -- whispercast(<to>, 'tag', <stuff>) - function addon:whispercast(to,...) - local msg = assemble(...) - self.dprint('comm', "<whispercast>@", to, ":", msg) - self:SendCommMessage(self.identTg, msg, "WHISPER", to) - end -end - function addon:DoPing() self:Print("Give me a ping, Vasili. One ping only, please.") self.sender_list.active = {} @@ -1361,7 +1373,7 @@ possible_st:SetData(g_loot) end - self.status_text = ("%s communicating as ident %s commrev %d"):format(self.revision,self.ident,self.commrev) + self.status_text = ("%s communicating as ident %s commrev %s"):format(self.revision,self.ident,self.commrev) self:RegisterComm(self.ident) self:RegisterComm(self.identTg, "OnCommReceivedNocache") @@ -1418,11 +1430,11 @@ addon.recent_boss = create_new_cache ('boss', 10, fixup_durations) -- Similar to _do_loot, but duration+ parms only present when locally generated. - local function _do_boss (self, reason, bossname, intag, duration, raiders) - self.dprint('loot',">>_do_boss, R:", reason, "B:", bossname, "T:", intag, - "D:", duration, "RL:", (raiders and #raiders or 'nil')) + local function _do_boss (self, reason, bossname, intag, maxsize, duration) + self.dprint('loot',">>_do_boss, R:", reason, "B:", bossname, + "T:", intag, "MS:", maxsize, "D:", duration) if self.rebroadcast and duration then - self:broadcast('boss', reason, bossname, intag) + self:vbroadcast('boss', reason, bossname, intag, maxsize) end -- This is only a loop to make jumping out of it easy, and still do cleanup below. while self.enabled do @@ -1447,8 +1459,9 @@ bossname = bossname, reason = reason, instance = intag, - duration = duration, -- these two deliberately may be nil - raiderlist = raiders and table.concat(raiders, ", ") + duration = duration, -- deliberately may be nil + raidersnap = CopyTable(g_loot.raiders), + maxsize = maxsize, } tinsert(candidates,c) end @@ -1456,7 +1469,7 @@ end self.dprint('loot',"<<_do_boss out") end - -- No wrapping layer for now + -- This exposes the function to OCR, and can be a wrapper layer later. addon.on_boss_broadcast = _do_boss function addon:_mark_boss_kill (index) @@ -2028,6 +2041,45 @@ ------ Player communication do + local select, tconcat, strsplit = select, table.concat, strsplit + --[[ old way: repeated string concatenations, BAD + new way: new table on every call, BAD + local msg = ... + for i = 2, select('#',...) do + msg = msg .. '\a' .. (select(i,...) or "") + end + return msg + ]] + local function assemble(t,...) + if select('#',...) > 0 then + local msg = {t,...} + -- tconcat requires strings, but T is known to be one already + for i = 2, #msg do + msg[i] = tostring(msg[i]) or "" + end + return tconcat (msg, '\a') + end + return t + end + + -- broadcast('tag', <stuff>) + -- vbroadcast('tag', <stuff>) + function addon:vbroadcast(tag,...) + return self:broadcast(self.commrev..tag,...) + end + function addon:broadcast(tag,...) + local msg = assemble(tag,...) + self.dprint('comm', "<broadcast>:", msg) + -- the "GUILD" here is just so that we can also pick up on it + self:SendCommMessage(self.ident, msg, self.debug.comm and "GUILD" or "RAID") + end + -- whispercast(<to>, 'tag', <stuff>) + function addon:whispercast(to,...) + local msg = assemble(...) + self.dprint('comm', "<whispercast>@", to, ":", msg) + self:SendCommMessage(self.identTg, msg, "WHISPER", to) + end + local function adduser (name, status, active) if status then addon.sender_list.names[name] = status end if active then addon.sender_list.active[name] = active end @@ -2059,12 +2111,21 @@ adduser (sender, nil, true) addon:CHAT_MSG_LOOT ("broadcast", recip, item, count, sender, extratext) end + OCR_funcs['16loot'] = OCR_funcs.loot OCR_funcs.boss = function (sender, _, reason, bossname, instancetag) - addon.dprint('comm', "DOTboss, sender", sender, "reason", reason, "name", bossname, "it", instancetag) + addon.dprint('comm', "DOTboss, sender", sender, "reason", reason, + "name", bossname, "it", instancetag) if not addon.enabled then return end adduser (sender, nil, true) - addon:on_boss_broadcast (reason, bossname, instancetag) + addon:on_boss_broadcast (reason, bossname, instancetag, --[[maxsize=]]0) + end + OCR_funcs['16boss'] = function (sender, _, reason, bossname, instancetag, maxsize) + addon.dprint('comm', "DOTboss16, sender", sender, "reason", reason, + "name", bossname, "it", instancetag, "size", maxsize) + if not addon.enabled then return end + adduser (sender, nil, true) + addon:on_boss_broadcast (reason, bossname, instancetag, maxsize) end OCR_funcs.bcast_req = function (sender)
--- a/gui.lua Sat Apr 07 05:40:20 2012 +0000 +++ b/gui.lua Fri Apr 13 04:28:46 2012 +0000 @@ -47,7 +47,8 @@ local window_title = "Ouro Loot" local dirty_tabs = nil -local pairs, ipairs, tinsert, tremove, tonumber = pairs, ipairs, table.insert, table.remove, tonumber +local pairs, ipairs, tinsert, tremove, tostring, tonumber = + pairs, ipairs, table.insert, table.remove, tostring, tonumber local pprint, tabledump = addon.pprint, flib.tabledump local GetItemInfo, ITEM_QUALITY_COLORS = GetItemInfo, ITEM_QUALITY_COLORS @@ -164,9 +165,11 @@ _tabtexts[tabtitle] = nil tremove (_taborder, loaded_at) next_insertion_position = loaded_at + local saved_next_insertion_position = loaded_at local loaded, whynot = LoadAddOn(addon_index) if loaded then - addon:Print(tabtitle, "loaded.") + addon:Print("%s loaded. %d |4tab:tabs; added.", tabtitle, + next_insertion_position - saved_next_insertion_position) else what.disabled = true _tabtexts[tabtitle] = what -- restore this for mouseovers @@ -541,7 +544,7 @@ ["Rebroadcast this loot entry"] = function(rowi) local e = g_loot[rowi] -- This only works because GetItemInfo accepts multiple argument formats - addon:broadcast('loot', e.person, e.itemlink, e.count, e.cols[3].value) + addon:vbroadcast('loot', e.person, e.itemlink, e.count, e.cols[3].value) addon:Print("Rebroadcast entry", rowi, e.itemlink) end, @@ -553,10 +556,10 @@ repeat local e = g_loot[rowi] if e.kind == 'boss' then - addon:broadcast('boss', e.reason, e.bossname, e.instance) + addon:vbroadcast('boss', e.reason, e.bossname, e.instance) elseif e.kind == 'loot' then -- This only works because GetItemInfo accepts multiple argument formats - addon:broadcast('loot', e.person, e.itemlink, e.count, e.cols[3].value) + addon:vbroadcast('loot', e.person, e.itemlink, e.count, e.cols[3].value) end addon:Print("Rebroadcast entry", rowi, e.itemlink or e.bossname or UNKNOWN) rowi = rowi + 1 @@ -2162,7 +2165,7 @@ data.name = text local getinstance = StaticPopup_Show("OUROL_EOI_INSERT","instance") getinstance.data = data - getinstance.editBox:SetText(addon.instance_tag()) + getinstance.editBox:SetText((addon.instance_tag())) -- This suppresses auto-hide (which would case the getinstance dialog -- to go away), but only when mouse clicking. OnEnter is on its own. return true
--- a/text_tabs.lua Sat Apr 07 05:40:20 2012 +0000 +++ b/text_tabs.lua Fri Apr 13 04:28:46 2012 +0000 @@ -137,12 +137,50 @@ addon:register_text_generator ("forum", [[Forum Markup]], [[BBcode ready for Ouroboros forums]], forum, forum_specials) +local ingroups, outgroups = {}, {} +local function do_attendance (raidertable, max_group_number) + local tins, wipe, tsort, tconcat = + table.insert, table.wipe, table.sort, table.concat + + -- Assumption: everybody is packed into the first N groups. + if raidertable then for name,info in pairs(raidertable) do + if info.online ~= 3 then -- 3 == left the raid + if info.subgroup <= max_group_number then + tins (ingroups, name) + else + tins (outgroups, name) + end + end + end end + if #ingroups > 0 then + tsort(ingroups) + else + ingroups[1] = [[Nobody recorded as inside the instance.]] + end + if #outgroups > 0 then + tsort(outgroups) + else + outgroups[1] = [[Nobody recorded as outside the instance.]] + end + local i,o = tconcat(ingroups,", "), tconcat(outgroups,", ") + wipe(ingroups) + wipe(outgroups) + return i,o +end + +local saved_g_loot_pointer local function att (_, loot, last_printed, _, cache) + saved_g_loot_pointer = loot for i = last_printed+1, #loot do local e = loot[i] if e.kind == 'boss' and e.reason == 'kill' then - cache[#cache+1] = ("\n%s -- %s\n%s"):format(e.instance, e.bossname, e.raiderlist or '<none recorded>') + -- This could, concievably, be different on a per-boss basis + -- (e.g., "we're dropping to 10-man for the PvP boss") + local i,o = do_attendance (e.raidersnap, e.maxsize / MEMBERS_PER_RAID_GROUP) + + cache[#cache+1] = ("\n%s -- %s\n[+] %s\n[-] %s\n"):format(e.instance, + e.bossname, i, o) elseif e.kind == 'time' then cache[#cache+1] = e.startday.text @@ -157,13 +195,11 @@ [[Take attendance now (will continue to take attendance on each boss kill).]]) w:SetFullWidth(true) w:SetCallback("OnClick", function(_w) - local raiders = {} - for i = 1, GetNumRaidMembers() do - table.insert(raiders, (GetRaidRosterInfo(i))) - end - table.sort(raiders) + local instance, maxsize = addon.instance_tag() + local i,o = do_attendance (saved_g_loot_pointer.raiders, maxsize / MEMBERS_PER_RAID_GROUP) local h, m = GetGameTime() - local additional = ("Attendance at %.2d:%.2d:\n%s"):format(h,m,table.concat(raiders, ", ")) + + local additional = ("Attendance for %s at %.2d:%.2d:\n[+] %s\n[-] %s"):format(instance, h, m, i, o) editbox:SetText(editbox:GetText() .. '\n' .. additional) end) container:AddChild(w)
--- a/verbage.lua Sat Apr 07 05:40:20 2012 +0000 +++ b/verbage.lua Fri Apr 13 04:28:46 2012 +0000 @@ -329,7 +329,10 @@ T.texts_other = [[ So far the only other generated text is the <Attendance> tab, an alphabetized list -on a per-boss basis. +on a per-boss basis. Players who are probably inside the raid are grouped +under [:PLUS:], and the remaining players are under [-]. "Probably inside" is an +assumption that groups 1 and 2 are raiding in a 10-player instance, groups 1-5 +are raiding in a 25-player instance, and so forth. Other addons can register their own text tabs and corresponding generation functions. If you want to be able to feed text into an offline program (for @@ -523,7 +526,7 @@ wrapped = wrapped:gsub ("([^\n])\n([^\n])", "%1 %2") wrapped = wrapped:gsub ("|r\n\n", "|r\n") wrapped = wrapped:gsub ("Ouroboros", "|cffa335ee<Ouroboros>|r") - wrapped = wrapped:gsub ("%*%(", "<") :gsub("%)%*", ">") + wrapped = wrapped:gsub ("%*%(", "<") :gsub("%)%*", ">") :gsub(":PLUS:", "+") addon.helptext[funkykey] = wrapped end end -- do scope