--[[ Name: ParserLib Revision: $Revision: 11949 $ Author(s): rophy (rophy123@gmail.com) Website: http://www.wowace.com/index.php/ParserLib Documentation: http://www.wowace.com/index.php/ParserLib SVN: http://svn.wowace.com/root/trunk/ParserLib Description: An embedded combat log parser, which works on all localizations. Dependencies: CompostLib (optional) or Compost-2.0 (optional). ]] --------------------------------------------------------------------------- -- To Get an instance of ParserLib, call this: -- local parser = ParserLib:GetInstance(version) -- where the version is the variable 'vmajor' you see here. --------------------------------------------------------------------------- local vmajor, vminor = "1.1", tonumber(string.sub("$Revision: 11949 $", 12, -3)) local stubvarname = "TekLibStub" local libvarname = "ParserLib" -- Check to see if an update is needed -- if not then just return out now before we do anything local libobj = getglobal(libvarname) if libobj and not libobj:NeedsUpgraded(vmajor, vminor) then return end --------------------------------------------------------------------------- -- Embedded Library Registration Stub -- Written by Iriel -- Version 0.1 - 2006-03-05 -- Modified by Tekkub --------------------------------------------------------------------------- local stubobj = getglobal(stubvarname) if not stubobj then stubobj = {} setglobal(stubvarname, stubobj) -- Instance replacement method, replace contents of old with that of new function stubobj:ReplaceInstance(old, new) for k,v in pairs(old) do old[k]=nil end for k,v in pairs(new) do old[k]=v end end -- Get a new copy of the stub function stubobj:NewStub(name) local newStub = {} self:ReplaceInstance(newStub, self) newStub.libName = name newStub.lastVersion = '' newStub.versions = {} return newStub end -- Get instance version function stubobj:NeedsUpgraded(vmajor, vminor) local versionData = self.versions[vmajor] if not versionData or versionData.minor < vminor then return true end end -- Get instance version function stubobj:GetInstance(version) if not version then version = self.lastVersion end local versionData = self.versions[version] if not versionData then print(string.format("<%s> Cannot find library version: %s", self.libName, version or "")) return end return versionData.instance end -- Register new instance function stubobj:Register(newInstance) local version,minor = newInstance:GetLibraryVersion() self.lastVersion = version local versionData = self.versions[version] if not versionData then -- This one is new! versionData = { instance = newInstance, minor = minor, old = {}, } self.versions[version] = versionData newInstance:LibActivate(self) return newInstance end -- This is an update local oldInstance = versionData.instance local oldList = versionData.old versionData.instance = newInstance versionData.minor = minor local skipCopy = newInstance:LibActivate(self, oldInstance, oldList) table.insert(oldList, oldInstance) if not skipCopy then for i, old in ipairs(oldList) do self:ReplaceInstance(old, newInstance) end end return newInstance end end if not libobj then libobj = stubobj:NewStub(libvarname) setglobal(libvarname, libobj) end local lib = {} -- Return the library's current version function lib:GetLibraryVersion() return vmajor, vminor end -- Activate a new instance of this library function lib:LibActivate(stub, oldLib, oldList) local maj, min = self:GetLibraryVersion() if oldLib then local omaj, omin = oldLib:GetLibraryVersion() ---------------------------------------------------- -- ********************************************** -- -- **** Copy over any old data you need here **** -- -- ********************************************** -- ---------------------------------------------------- self.frame = oldLib.frame self:OnLoad() if omin < 11 and oldLib.clients then for event in oldLib.clients do for i in oldLib.clients[event] do if type(oldLib.clients[event][i]["func"]) == "string" then oldLib.clients[event][i]["func"] = getglobal(oldLib.clients[event][i]["func"]) end end end end self.clients = oldLib.clients else --------------------------------------------------- -- ********************************************* -- -- **** Do any initialization you need here **** -- -- ********************************************* -- --------------------------------------------------- self:OnLoad() end -- nil return makes stub do object copy end ---------------------------------------------- -- *ParserLib Public Methods* -- ---------------------------------------------- -- Register an event to ParserLib. function lib:RegisterEvent(addonID, event, handler) local eventExist for i, v in self.supportedEvents do if v == event then eventExist = true break end end if not eventExist then self:Print( string.format("Event %s is not supported. (AddOnID %s)", event, addonID), 1, 0, 0 ) return end -- self:Print(string.format("Registering %s for addon %s.", event, addonID) ); -- debug if type(handler) == "string" then handler = getglobal(handler) end -- if not handler then self:Print("nil handler from " .. addonID, 1, 0, 0) end -- debug if self.clients[event] == nil then self.clients[event] = {}; end table.insert(self.clients[event], { ["id"]=addonID, ["func"]=handler } ); self.frame:RegisterEvent(event); end -- Check if you have registered an event. function lib:IsEventRegistered(addonID, event) if self.clients[event] then for i, v in self.clients[event] do if v.id == addonID then return true end end end end -- Unregister an event. function lib:UnregisterEvent(addonID, event) local empty = true if not self.clients[event] then return end for i, v in self.clients[event] do if v.id == addonID then -- self:Print( format("Removing %s from %s", v.id, event) ) -- debug table.remove(self.clients[event], i) else empty = false end end if empty then -- self:Print("Unregistering event " .. event) -- debug self.frame:UnregisterEvent(event) self.clients[event] = nil end end -- Unregister all events. function lib:UnregisterAllEvents(addonID) local event, index, empty; for event in self.clients do empty = true; for i, v in self.clients[event] do if v.id == addonID then -- self:Print( format("Removing %s for %s", v.id, event) ) -- debug table.remove(self.clients[event], i) -- self.clients[event][index] = nil; else empty = false; end end if empty then -- self:Print("Unregistering event " .. event) -- debug self.frame:UnregisterEvent(event); self.clients[event] = nil; end end end -- Parse custom messages, check documentation.html for more info. function lib:Deformat(text, pattern) if not self.customPatterns then self.customPatterns = {} end if not self.customPatterns[pattern] then self.customPatterns[pattern] = self:Curry(pattern) end return self.customPatterns[pattern](text) end -------------------------------------------------------- -- Methods to control ParserLib behaviour -- -------------------------------------------------------- -- Use CompostLib or not? -- Not that at 1.1-23 CompostLib no longer slows down the speed of ParserLib, -- because I found out that I was calling CompostLib:Recycle too frequently, which can be avoided. function lib:UseCompost(flag) self.vars.noCompost = not flag end --------------------------------------------------- -- *End of ParserLib Public Methods* -- --------------------------------------------------- ---------------------------------------------- -- ParserLib Private Methods ---------------------------------------------- -- Constants ParserLib_SELF = 103 ParserLib_MELEE = 112 ParserLib_DAMAGESHIELD = 113 -- lib.timing = true -- timer -- Stub function called by frame.OnEvent local function ParserOnEvent() lib:OnEvent() end -- Sort the pattern so that they can be parsed in a correct sequence, will only do once for each registered event. local function PatternCompare(a, b) local pa = getglobal(a) local pb = getglobal(b) if not pa then ChatFrame1:AddMessage("|cffff0000Nil pattern: ".. a.."|r") end if not pb then ChatFrame1:AddMessage("|cffff0000Nil pattern: ".. b.."|r") end local ca=0 for _ in string.gfind(pa, "%%%d?%$?[sd]") do ca=ca+1 end local cb=0 for _ in string.gfind(pb, "%%%d?%$?[sd]") do cb=cb+1 end pa = string.gsub(pa, "%%%d?%$?[sd]", "") pb = string.gsub(pb, "%%%d?%$?[sd]", "") if string.len(pa) == string.len(pb) then return ca < cb; else return string.len(pa) > string.len(pb) end end local FindString = { [0] = function(m,p,t) return string.find(m,p), t end, [1] = function(m,p,t) _,_,t[1] = string.find(m,p) if t[1] then return true, t else return false, t end end, [2] = function(m,p,t) _,_,t[1],t[2] = string.find(m,p) if t[2] then return true, t else return false, t end end, [3] = function(m,p,t) _,_,t[1],t[2],t[3] = string.find(m,p) if t[3] then return true, t else return false, t end end, [4] = function(m,p,t) _,_,t[1],t[2],t[3],t[4] = string.find(m,p) if t[4] then return true, t else return false, t end end, [5] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5] = string.find(m,p) if t[5] then return true, t else return false, t end end, [6] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5],t[6] = string.find(m,p) if t[6] then return true, t else return false, t end end, [7] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5],t[6],t[7] = string.find(m,p) if t[7] then return true, t else return false, t end end, [8] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8] = string.find(m,p) if t[8] then return true, t else return false, t end end, [9] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9] = string.find(m,p) if t[9] then return true, t else return false, t end end, } -- Currently supported event list. lib.supportedEvents = { "CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS", "CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES", "CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS", "CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES", "CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS", "CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES", "CHAT_MSG_COMBAT_FACTION_CHANGE", "CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS", "CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES", "CHAT_MSG_COMBAT_FRIENDLY_DEATH", "CHAT_MSG_COMBAT_HONOR_GAIN", "CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS", "CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES", "CHAT_MSG_COMBAT_HOSTILE_DEATH", "CHAT_MSG_COMBAT_PARTY_HITS", "CHAT_MSG_COMBAT_PARTY_MISSES", "CHAT_MSG_COMBAT_PET_HITS", "CHAT_MSG_COMBAT_PET_MISSES", "CHAT_MSG_COMBAT_SELF_HITS", "CHAT_MSG_COMBAT_SELF_MISSES", "CHAT_MSG_COMBAT_XP_GAIN", "CHAT_MSG_SPELL_AURA_GONE_OTHER", "CHAT_MSG_SPELL_AURA_GONE_SELF", "CHAT_MSG_SPELL_AURA_GONE_PARTY", "CHAT_MSG_SPELL_BREAK_AURA", "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF", "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE", "CHAT_MSG_SPELL_CREATURE_VS_PARTY_BUFF", "CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE", "CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF", "CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE", "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS", "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF", "CHAT_MSG_SPELL_FAILED_LOCALPLAYER", "CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF", "CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE", "CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF", "CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE", "CHAT_MSG_SPELL_ITEM_ENCHANTMENTS", "CHAT_MSG_SPELL_PARTY_BUFF", "CHAT_MSG_SPELL_PARTY_DAMAGE", "CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS", "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS", "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE", "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS", "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE", "CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS", "CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE", "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS", "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE", "CHAT_MSG_SPELL_PET_BUFF", "CHAT_MSG_SPELL_PET_DAMAGE", "CHAT_MSG_SPELL_SELF_BUFF", "CHAT_MSG_SPELL_SELF_DAMAGE", "CHAT_MSG_SPELL_TRADESKILLS", } function lib:GetCompost() if self.vars.noCompost then if not self.myCompost then self.myCompost = { Recycle = function() return {} end, Acquire = function() return {} end, Reclaim = function() end, } end return self.myCompost else if not self.compost then if AceLibrary and AceLibrary:HasInstance("Compost-2.0") then self.compost = AceLibrary:GetInstance("Compost-2.0") elseif CompostLib then self.compost = CompostLib:GetInstance("compost-1") else -- Cannot find the existance of CompostLib self.vars.noCompost = true return self:GetCompost() end end return self.compost end end -- Convert "%s hits %s for %d." to "(.+) hits (.+) for (%d+)." -- Will additionaly return the sequence of tokens, for example: -- "%2$s reflects %3$d %4$s damage to %1$s." will return: -- "(.-) reflects (%+) (.-) damage to (.-)%.", 4 1 2 3. -- ( [1]=2,[2]=3,[3]=4,[4]=1 Reverting indexes and become [1]=4, [2]=[1],[3]=2,[4]=3. ) function lib:ConvertPattern(pattern, anchor) local seq -- Add % to escape all magic characters used in LUA pattern matching, except $ and % pattern = string.gsub(pattern,"([%^%(%)%.%[%]%*%+%-%?])","%%%1"); -- Do these AFTER escaping the magic characters. pattern = string.gsub(pattern,"%%s","(.-)"); -- %s to (.-) pattern = string.gsub(pattern,"%%d","(%-?%%d+)"); -- %d to (%d+) if string.find(pattern,"%$") then seq = {}; -- fills with ordered list of $s as they appear local idx = 1; -- incremental index into field[] local tmpSeq = {} for i in string.gfind(pattern,"%%(%d)%$.") do tmpSeq[idx] = tonumber(i); idx = idx + 1 end for i, j in ipairs(tmpSeq) do seq[j] = i end table.setn(seq, table.getn(tmpSeq)) pattern = string.gsub(pattern,"%%%d%$s","(.-)"); -- %1$s to (.-) pattern = string.gsub(pattern,"%%%d%$d","(%-?%%d+)"); -- %1$d to (%d+) end -- Escape $ now. pattern = string.gsub(pattern,"%$","%%$"); -- Anchor tag can improve string.find() performance by 100%. if anchor then pattern = "^"..pattern end -- If the pattern ends with (.-), replace it with (.+), or the capsule will be lost. if string.sub(pattern, -4) == "(.-)" then pattern = string.sub(pattern, 0, -5) .. "(.+)"; end if not seq then return pattern end return pattern, seq[1], seq[2], seq[3], seq[4], seq[5], seq[6], seq[7], seq[8], seq[9], seq[10] end function lib:OnLoad() -- Both table starts out empty, and load the data only when required. self.eventTable = {} self.patternTable = {} self.vars = {} if self.timing then self.timer = { ParseMessage_LoadPatternList = 0, ParseMessage_FindPattern = 0, ParseMessage_FindPattern_Regexp = 0, ParseMessage_FindPattern_Regexp_FindString = 0, ParseMessage_FindPattern_LoadPatternInfo = 0, ParseMessage_ParseInformation = 0, ParseMessage_ParseTrailers = 0, ParseMessage_ConvertTypes = 0, NotifyClients = 0, Compost_Acquire = 0, Compost_Recycle = 0, Compost_Reclaim = 0, } end if not self.clients then self.clients = {} end if not self.frame then self.frame = CreateFrame("FRAME", "ParserLibFrame") self.frame:SetScript("OnEvent", ParserOnEvent ) self.frame:Hide() end end function lib:OnEvent(e, a1) if not e then e = event end if not a1 then a1 = arg1 end -- self:Print("Event: |cff3333ff"..e.."|r") -- debug -- Titan Honor+ was changing the global events... just change it back. if e == "CHAT_MSG_HONORPLUS" then e = "CHAT_MSG_COMBAT_HONOR_GAIN" end if self:ParseMessage(a1, e) then -- local timer = GetTime() -- timer self:NotifyClients(e) -- self.timer.NotifyClients = self.timer.NotifyClients + GetTime() - timer -- timer end end function lib:NotifyClients(event) if not self.clients or not self.clients[event] then -- self:Print(event .. " has no client to notify.") -- debug return end -- Noneed to recycle the table if there is only one client. if table.getn(self.clients[event]) == 1 then -- self:Print(event .. ", calling " .. self.clients[event][1].id) -- debug self.clients[event][1].func(event, self.info) return end -- local timer = GetTime() -- timer local info = self:GetCompost():Acquire() -- self.timer.Compost_Acquire = GetTime() - timer + self.timer.Compost_Acquire -- timer for i, client in self.clients[event] do -- self:Print(event .. ", calling " .. client.id) -- debug -- I can just do a compost:Recycle() here, but I hope this can improve the performance. for j in info do if not self.info[j] then info[j] = nil end end for j, v in self.info do info[j] = v end client.func(event, info) end -- timer = GetTime() -- timer self:GetCompost():Reclaim(info) -- self.timer.reclaim = GetTime() - timer + self.timer.reclaim -- timer end function lib:Print(msg, r, g, b) ChatFrame1:AddMessage(string.format("<%s-%s-%s> %s", libvarname, vmajor, vminor, msg), r, g, b) end -- message : the arg1 in the event -- event : name says it all. -- info : the table which will store the passed result, so THIS IS THE OUTPUT. -- return : true if pattern found and parsed, nil otherwise. function lib:ParseMessage(message, event) -- -- local currTime -- timer -- currTime = GetTime() -- timer if not self.eventTable[event] then self.eventTable[event] = self:LoadPatternList(event) end local list = self.eventTable[event] -- self.timer.ParseMessage_LoadPatternList = self.timer.ParseMessage_LoadPatternList + GetTime() - currTime -- timer if not list then return end -- Get the table to store parsed results. if not self.info then -- timer = GetTime() -- timer self.info = self:GetCompost():Acquire() -- self.timer.Compost_Acquire = GetTime() - timer + self.timer.Compost_Acquire -- timer else -- timer = GetTime() -- timer self.info = self:GetCompost():Recycle(self.info) -- self.timer.Compost_Recycle = GetTime() - timer + self.timer.Compost_Recycle -- timer end -- currTime = GetTime() -- timer local pattern = self:FindPattern(message, list) -- self.timer.ParseMessage_FindPattern = GetTime() - currTime + self.timer.ParseMessage_FindPattern -- timer if not pattern then -- create "unknown" event type. self.info.type = "unknown" self.info.message = message return true end -- currTime = GetTime() -- timer self:ParseInformation(pattern) -- self.timer.ParseMessage_ParseInformation = GetTime() - currTime + self.timer.ParseMessage_ParseInformation -- timer -- currTime = GetTime() -- timer if self.info.type == "hit" or self.info.type == "environment" then self:ParseTrailers(message) end -- self.timer.ParseMessage_ParseTrailers = GetTime() - currTime + self.timer.ParseMessage_ParseTrailers -- timer -- currTime = GetTime() -- timer self:ConvertTypes(self.info) -- self.timer.ParseMessage_ConvertTypes = GetTime() - currTime + self.timer.ParseMessage_ConvertTypes -- timer return true end -- Search for pattern in 'patternList' which matches 'message', parsed tokens will be stored in table self.info function lib:FindPattern(message, patternList) local pt, timer, found for i, v in patternList do -- timer = GetTime() -- timer if not self.patternTable[v] then self.patternTable[v] = self:LoadPatternInfo(v) end -- self.timer.ParseMessage_FindPattern_LoadPatternInfo = GetTime() - timer + self.timer.ParseMessage_FindPattern_LoadPatternInfo -- timer pt = self.patternTable[v] found = false -- timer = GetTime() -- timer if self:OptimizerCheck(message, v) then -- timer = GetTime() -- timer found, self.info = FindString[pt.tc](message, pt.pattern, self.info) -- self.timer.ParseMessage_FindPattern_Regexp_FindString = GetTime() - timer + self.timer.ParseMessage_FindPattern_Regexp_FindString -- timer end -- self.timer.ParseMessage_FindPattern_Regexp = GetTime() - timer + self.timer.ParseMessage_FindPattern_Regexp -- timer if found then -- self:Print(message.." = " .. v .. ":" .. pt.pattern) -- debug return v end end end -- Parses for trailors. function lib:ParseTrailers(message) local found, amount, info info = self.info if not self.trailers then self.trailers = { CRUSHING_TRAILER = self:ConvertPattern(CRUSHING_TRAILER), GLANCING_TRAILER = self:ConvertPattern(GLANCING_TRAILER), ABSORB_TRAILER = self:ConvertPattern(ABSORB_TRAILER), BLOCK_TRAILER = self:ConvertPattern(BLOCK_TRAILER), RESIST_TRAILER = self:ConvertPattern(RESIST_TRAILER), VULNERABLE_TRAILER = self:ConvertPattern(VULNERABLE_TRAILER), } end found = string.find(message, self.trailers.CRUSHING_TRAILER) if found then info.isCrushing = true end found = string.find(message, self.trailers.GLANCING_TRAILER) if found then info.isGlancing = true end found, _, amount = string.find(message, self.trailers.ABSORB_TRAILER) if found then info.amountAbsorb = amount end found, _, amount = string.find(message, self.trailers.BLOCK_TRAILER) if found then info.amountBlock = amount end found, _, amount = string.find(message, self.trailers.RESIST_TRAILER) if found then info.amountResist = amount end found, _, amount = string.find(message, self.trailers.VULNERABLE_TRAILER) if found then info.amountVulnerable = amount end end function lib:ParseInformation(patternName) local patternInfo = self.patternTable[patternName] local info = self.info -- Create an info table from pattern table, copies everything except the pattern string. for i, v in patternInfo do if i == 1 then info.type = v elseif type(i) == "number" then if type(v) == "number" and v < 100 then info[ self:GetInfoFieldName( self.patternTable[patternName][1], i) ] = info[v] else info[ self:GetInfoFieldName( self.patternTable[patternName][1], i) ] = v end end end if info.type == "honor" and not info.amount then info.isDishonor = true elseif info.type == "durability" and not info.item then info.isAllItems = true end for i in ipairs(info) do info[i] = nil end end function lib:ConvertTypes(info) for i in info do if string.find(i, "^amount") then info[i] = tonumber(info[i]) end end end function lib:OptimizerCheck(message, patternName) --if 1 then return true end if not ParserLibOptimizer then return true end if not ParserLibOptimizer[patternName] then return true end if string.find(message, ParserLibOptimizer[patternName], 1, true) then return true end return false end -- Most of the parts were learnt from BabbleLib by chknight, so credits goes to him. function lib:Curry(pattern) local cp, tt, n, f, o local DoNothing = function(tok) return tok end tt = {} for tk in string.gfind(pattern, "%%%d?%$?([sd])") do table.insert(tt, tk) end cp = { self:ConvertPattern(pattern, true) } cp.p = cp[1] n = table.getn(cp) for i=1,n-1 do cp[i] = cp[i+1] end table.remove(cp, n) f = {} o = {} n = table.getn(tt) for i=1, n do if tt[i] == "s" then f[i] = DoNothing else f[i] = tonumber end end if not cp[1] then if n == 0 then return function() end elseif n == 1 then return function(text) _, _, o[1] = string.find(text, cp.p) if o[1] then return f[1](o[1]) end end elseif n == 2 then return function(text) _, _, o[1], o[2]= string.find(text, cp.p) if o[1] then return f[1](o[1]), f[2](o[2]) end end elseif n == 3 then return function(text) _, _, o[1], o[2], o[3] = string.find(text, cp.p) if o[1] then return f[1](o[1]), f[2](o[2]), f[3](o[3]) end end elseif n == 4 then return function(text) _, _, o[1], o[2], o[3], o[4] = string.find(text, cp.p) if o[1] then return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]) end end elseif n == 5 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5] = string.find(text, cp.p) if o[1] then return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]) end end elseif n == 6 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5], o[6] = string.find(text, cp.p) if o[1] then return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]), f[6](o[6]) end end elseif n == 7 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7] = string.find(text, cp.p) if o[1] then return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]), f[6](o[6]), f[7](o[7]) end end elseif n == 8 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8] = string.find(text, cp.p) if o[1] then return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]), f[6](o[6]), f[7](o[7]), f[8](o[8]) end end elseif n == 9 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9] = string.find(text, cp.p) if o[1] then return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]), f[6](o[6]), f[7](o[7]), f[8](o[8]), f[9](o[9]) end end end else if n == 0 then return function() end elseif n == 1 then return function(text) _, _, o[1] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]) end end elseif n == 2 then return function(text) _, _, o[1], o[2] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]) end end elseif n == 3 then return function(text) _, _, o[1], o[2], o[3] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]) end end elseif n == 4 then return function(text) _, _, o[1], o[2], o[3], o[4] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]) end end elseif n == 5 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]) end end elseif n == 6 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5], o[6] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]), f[cp[6]](o[cp[6]]) end end elseif n == 7 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]), f[cp[6]](o[cp[6]]), f[cp[7]](o[cp[7]]) end end elseif n == 8 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]), f[cp[6]](o[cp[6]]), f[cp[7]](o[cp[7]]), f[cp[8]](o[cp[8]]) end end elseif n == 9 then return function(text) _, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9] = string.find(text, cp.p) if o[1] then return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]), f[cp[6]](o[cp[6]]), f[cp[7]](o[cp[7]]), f[cp[8]](o[cp[8]]), f[cp[9]](o[cp[9]]) end end end end end function lib:PrintTable(args) for k, v in args do ChatFrame1:AddMessage(tostring(k) .. " = " .. tostring(v)); end ChatFrame1:AddMessage(""); end -- Used to test the correcteness of ParserLib on different languages. function lib:TestPatterns(sendToClients) self:LoadEverything() -- Creating the combat messages. local testNumber = 123 local message local messages = self:GetCompost():Acquire() for patternName in self.patternTable do messages[patternName] = self:GetCompost():Acquire() messages[patternName].message = getglobal(patternName) for i, v in self.patternTable[patternName] do if i ~= "tc" and type(v) == "number" and v < 100 and i~=1 then messages[patternName][v] = self:GetInfoFieldName(self.patternTable[patternName][1], i) end end for i, v in ipairs(messages[patternName]) do if string.find(v, "^amount") then messages[patternName].message = string.gsub(messages[patternName].message, "%%%d?%$?d", testNumber, 1) else messages[patternName].message = string.gsub(messages[patternName].message, "%%%d?%$?s", string.upper(v), 1) end end end -- Begin the test. local info, msg local startTime = GetTime() local startMem = gcinfo() for _, event in self.supportedEvents do for _, pattern in self:LoadPatternList(event) do msg = messages[pattern].message if sendToClients then self:OnEvent(event, msg) end if self:ParseMessage(msg, event) then info = self.info for i, v in ipairs(messages[pattern]) do if not info[v] or ( string.find(v, "^amount") and info[v] ~= testNumber ) or ( not string.find(v, "^amount") and info[v] ~= string.upper(v) ) then self:Print("Event: " .. event) self:Print("Pattern: " .. pattern) self:Print("Message: " .. msg) self:PrintTable(messages[pattern]) self:PrintTable(info) end end end end end self:Print( string.format("Test completed in %.4fs, memory cost %.2fKB.", GetTime() - startTime, gcinfo() - startMem) ) self:GetCompost():Reclaim(messages, 1) end function lib:LoadEverything() -- Load all patterns and events. for _, v in self.supportedEvents do for _, w in self:LoadPatternList(v) do if not self.patternTable[w] then self.patternTable[w] = self:LoadPatternInfo(w) end end end end function lib:PrintTimers() if not self.timer then return end local total = 0 for i in self.timer do total = total + self.timer[i] end if not self.timerIndex then self.timerIndex = {} for i in self.timer do table.insert(self.timerIndex, i) end table.sort(self.timerIndex) end DEFAULT_CHAT_FRAME:AddMessage("Time\t%\tDescription") for i, idx in self.timerIndex do DEFAULT_CHAT_FRAME:AddMessage(string.format("%.3f\t%.1f\t%s", self.timer[idx], 100*self.timer[idx]/total, idx) ) end DEFAULT_CHAT_FRAME:AddMessage(total .. "\t100\tTotal") end -- Used to load eventTable elements on demand. function lib:LoadPatternList(eventName) local list --------------- Melee Hits ---------------- if eventName == "CHAT_MSG_COMBAT_SELF_HITS" then if not self.eventTable["CHAT_MSG_COMBAT_SELF_HITS"] then self.eventTable["CHAT_MSG_COMBAT_SELF_HITS"] = self:LoadPatternCategoryTree( { "HitSelf", "EnvSelf", } ) end list = self.eventTable["CHAT_MSG_COMBAT_SELF_HITS"] elseif eventName == "CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS" or eventName == "CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS" or eventName == "CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS" or eventName == "CHAT_MSG_COMBAT_PARTY_HITS" or eventName == "CHAT_MSG_COMBAT_PET_HITS" then if not self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS"] then self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS"] = self:LoadPatternCategoryTree( { "HitOtherOther", "EnvOther", } ) end list = self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS"] elseif eventName == "CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS" or eventName == "CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS" then if not self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS"] then self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS"] = self:LoadPatternCategoryTree( { { "HitOtherOther", "HitOtherSelf", }, "EnvOther", } ) end list = self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS"] --------------- Melee Misses ---------------- elseif eventName == "CHAT_MSG_COMBAT_SELF_MISSES" then if not self.eventTable["CHAT_MSG_COMBAT_SELF_MISSES"] then self.eventTable["CHAT_MSG_COMBAT_SELF_MISSES"] = self:LoadPatternCategoryTree( { "MissSelf", } ) end list = self.eventTable["CHAT_MSG_COMBAT_SELF_MISSES"] elseif eventName == "CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES" or eventName == "CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES" or eventName == "CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES" or eventName == "CHAT_MSG_COMBAT_PARTY_MISSES" or eventName == "CHAT_MSG_COMBAT_PET_MISSES" then if not self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES"] then self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES"] = self:LoadPatternCategoryTree( { "MissOtherOther", } ) end list = self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES"] elseif eventName == "CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES" or eventName == "CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES" then if not self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES"] then self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES"] = self:LoadPatternCategoryTree( { { "MissOtherOther", "MissOtherSelf", } } ) end list = self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES"] --------------- Spell Buffs ---------------- elseif eventName == "CHAT_MSG_SPELL_SELF_BUFF" then if not self.eventTable["CHAT_MSG_SPELL_SELF_BUFF"] then if GetLocale() ~= "deDE" then self.eventTable["CHAT_MSG_SPELL_SELF_BUFF"] = self:LoadPatternCategoryTree( { "HealSelf", "EnchantSelf", "CastSelf", "PerformSelf", "DispelFailSelf", "SPELLCASTSELFSTART", "SPELLPERFORMSELFSTART", { "DrainSelf", "PowerGainSelf", "ExtraAttackSelf", }, "SPELLSPLITDAMAGESELFOTHER", { "ProcResistSelf", "SpellMissSelf", } } ) else self.eventTable["CHAT_MSG_SPELL_SELF_BUFF"] = self:LoadPatternCategoryTree( { "HealSelf", "CastSelf", "PerformSelf", "DispelFailSelf", "SPELLCASTSELFSTART", "SPELLPERFORMSELFSTART", { "DrainSelf", "PowerGainSelf", "ExtraAttackSelf", }, "SPELLSPLITDAMAGESELFOTHER", { "ProcResistSelf", "SpellMissSelf", } } ) end end list = self.eventTable["CHAT_MSG_SPELL_SELF_BUFF"] elseif eventName == "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF" or eventName == "CHAT_MSG_SPELL_CREATURE_VS_PARTY_BUFF" or eventName == "CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF" or eventName == "CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF" or eventName == "CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF" or eventName == "CHAT_MSG_SPELL_PARTY_BUFF" or eventName == "CHAT_MSG_SPELL_PET_BUFF" then if not self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"] then if GetLocale() ~= "deDE" then self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"] = self:LoadPatternCategoryTree( { { "HealOther", "PowerGainOther", "ExtraAttackOther", "DrainOther", }, "SPELLCASTOTHERSTART", { "EnchantOther", "CastOther", "PerformOther", }, "SPELLPERFORMOTHERSTART", "SpellMissOther", "ProcResistOther", "SplitDamageOther", "DispelFailOther", } ) else -- Remove "EnchantOther" from German, since it's 100% ambiguous with SIMPLECASTOTHEROTHER, which is unsolvable. self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"] = self:LoadPatternCategoryTree( { { "HealOther", "PowerGainOther", "ExtraAttackOther", "DrainOther", }, "SPELLCASTOTHERSTART", { "CastOther", "PerformOther", }, "SPELLPERFORMOTHERSTART", "SpellMissOther", "ProcResistOther", "SplitDamageOther", "DispelFailOther", } ) end end list = self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"] --------------- Spell Damages ---------------- elseif eventName == "CHAT_MSG_SPELL_SELF_DAMAGE" then if not self.eventTable["CHAT_MSG_SPELL_SELF_DAMAGE"] then self.eventTable["CHAT_MSG_SPELL_SELF_DAMAGE"] = self:LoadPatternCategoryTree( { "SpellHitSelf", { "CastSelf", "DurabilityDamageSelf", }, "PerformSelf", "SpellMissSelf", "SPELLCASTSELFSTART", "SPELLPERFORMSELFSTART", "InterruptSelf", "DispelFailSelf", "ExtraAttackSelf", "DrainSelf", } ) end list = self.eventTable["CHAT_MSG_SPELL_SELF_DAMAGE"] elseif eventName == "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE" or eventName == "CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE" or eventName == "CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE" or eventName == "CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE" or eventName == "CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE" or eventName == "CHAT_MSG_SPELL_PARTY_DAMAGE" or eventName == "CHAT_MSG_SPELL_PET_DAMAGE" then if not self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"] then self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"] = self:LoadPatternCategoryTree( { "SpellHitOther", "SPELLCASTOTHERSTART", "SPELLPERFORMOTHERSTART", "DrainOther", "SpellMissOther", { "INSTAKILLOTHER", "INSTAKILLSELF", }, { "PROCRESISTOTHEROTHER", "PROCRESISTOTHERSELF", }, "SplitDamageOther", { "CastOther", "InterruptOther", "DurabilityDamageOther", }, "PerformOther", "ExtraAttackOther", { "DISPELFAILEDOTHEROTHER", "DISPELFAILEDOTHERSELF", }, }) end list = self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"] --------------- Periodic Buffs ---------------- elseif eventName == "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS" then if not self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"] then self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"] = self:LoadPatternCategoryTree( { { "HotOther", "HotSelf", }, { "BuffSelf", "BuffOther", "PowerGainOther", "PowerGainSelf", }, "DrainSelf", "DotSelf", -- Don't think this will hapen but add it anyway. } ) end list = self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"] elseif eventName == "CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS" or eventName == "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS" or eventName == "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS" or eventName == "CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS" then if not self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"] then self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"] = self:LoadPatternCategoryTree( { { "HotOther", -- "DrainOther", -- Dont think this would happen but add it anyway. }, { "BuffOther", "PowerGainOther", "DrainOther", -- When other players use Skull of Impending Doom. }, "DotOther", -- Dont think this will happen but add anyway. "DebuffOther", -- Was fired on older WoW version. } ) end list = self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"] --------------- Periodic Damages ---------------- elseif eventName == "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE" then if not self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE"] then self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE"] = self:LoadPatternCategoryTree( { { "DotSelf", "DotOther", }, { "DebuffSelf", "DebuffOther", }, { "SPELLLOGABSORBOTHEROTHER", "SPELLLOGABSORBOTHERSELF", "SPELLLOGABSORBSELFSELF", "SPELLLOGABSORBSELFOTHER", }, "DrainSelf", } ) end list = self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE"] elseif eventName == "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE" or eventName == "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE" or eventName == "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE" or eventName == "CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE" then if not self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"] then self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"] = self:LoadPatternCategoryTree( { "DebuffOther", "DotOther", { "SPELLLOGABSORBOTHEROTHER", "SPELLLOGABSORBSELFOTHER", }, "DrainOther", { "PowerGainOther", "BuffOther", -- Was fired on older WoW version. } } ) end list = self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"] --------------- Damage Shields ---------------- elseif eventName == "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF" then if not self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] then self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] = { "SPELLRESISTOTHEROTHER", "SPELLRESISTSELFOTHER", "DAMAGESHIELDOTHEROTHER", "DAMAGESHIELDSELFOTHER", } table.sort(self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] , PatternCompare) end list = self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] elseif eventName == "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS" then if not self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] then self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] = { "SPELLRESISTOTHEROTHER", "SPELLRESISTOTHERSELF", "DAMAGESHIELDOTHEROTHER", "DAMAGESHIELDOTHERSELF", } table.sort(self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] , PatternCompare) end list = self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] --------------- Auras ---------------- elseif eventName == "CHAT_MSG_SPELL_AURA_GONE_PARTY" or eventName == "CHAT_MSG_SPELL_AURA_GONE_OTHER" then if not self.eventTable["CHAT_MSG_SPELL_AURA_GONE_OTHER"] then self.eventTable["CHAT_MSG_SPELL_AURA_GONE_OTHER"] = { "AURAREMOVEDOTHER", } table.sort(self.eventTable["CHAT_MSG_SPELL_AURA_GONE_OTHER"] , PatternCompare) end list = self.eventTable["CHAT_MSG_SPELL_AURA_GONE_OTHER"] elseif eventName == "CHAT_MSG_SPELL_AURA_GONE_SELF" then if not self.eventTable["CHAT_MSG_SPELL_AURA_GONE_SELF"] then self.eventTable["CHAT_MSG_SPELL_AURA_GONE_SELF"] = { "AURAREMOVEDOTHER", "AURAREMOVEDSELF", } table.sort(self.eventTable["CHAT_MSG_SPELL_AURA_GONE_SELF"] , PatternCompare) end list = self.eventTable["CHAT_MSG_SPELL_AURA_GONE_SELF"] elseif eventName == "CHAT_MSG_SPELL_BREAK_AURA" then if not self.eventTable["CHAT_MSG_SPELL_BREAK_AURA"] then self.eventTable["CHAT_MSG_SPELL_BREAK_AURA"] = { "AURADISPELSELF", "AURADISPELOTHER", } table.sort(self.eventTable["CHAT_MSG_SPELL_BREAK_AURA"] , PatternCompare) end list = self.eventTable["CHAT_MSG_SPELL_BREAK_AURA"] elseif eventName == "CHAT_MSG_SPELL_ITEM_ENCHANTMENTS" then if not self.eventTable["CHAT_MSG_SPELL_ITEM_ENCHANTMENTS"] then self.eventTable["CHAT_MSG_SPELL_ITEM_ENCHANTMENTS"] = { "ITEMENCHANTMENTADDSELFSELF", "ITEMENCHANTMENTADDSELFOTHER", "ITEMENCHANTMENTADDOTHEROTHER", "ITEMENCHANTMENTADDOTHERSELF", } table.sort(self.eventTable["CHAT_MSG_SPELL_ITEM_ENCHANTMENTS"] , PatternCompare) end list = self.eventTable["CHAT_MSG_SPELL_ITEM_ENCHANTMENTS"] --------------- Trade Skills ---------------- elseif eventName == "CHAT_MSG_SPELL_TRADESKILLS" then if not self.eventTable["CHAT_MSG_SPELL_TRADESKILLS"] then self.eventTable["CHAT_MSG_SPELL_TRADESKILLS"] = { "TRADESKILL_LOG_FIRSTPERSON", "TRADESKILL_LOG_THIRDPERSON", "FEEDPET_LOG_FIRSTPERSON", "FEEDPET_LOG_THIRDPERSON", } table.sort(self.eventTable["CHAT_MSG_SPELL_TRADESKILLS"], PatternCompare ) end list = self.eventTable["CHAT_MSG_SPELL_TRADESKILLS"] elseif eventName == "CHAT_MSG_SPELL_FAILED_LOCALPLAYER" then if not self.eventTable["CHAT_MSG_SPELL_FAILED_LOCALPLAYER"] then self.eventTable["CHAT_MSG_SPELL_FAILED_LOCALPLAYER"] = { "SPELLFAILPERFORMSELF", "SPELLFAILCASTSELF", } table.sort(self.eventTable["CHAT_MSG_SPELL_FAILED_LOCALPLAYER"], PatternCompare) end list = self.eventTable["CHAT_MSG_SPELL_FAILED_LOCALPLAYER"] elseif eventName == "CHAT_MSG_COMBAT_FACTION_CHANGE" then if not self.eventTable["CHAT_MSG_COMBAT_FACTION_CHANGE"] then self.eventTable["CHAT_MSG_COMBAT_FACTION_CHANGE"] = { "FACTION_STANDING_CHANGED", "FACTION_STANDING_DECREASED", "FACTION_STANDING_INCREASED", } table.sort(self.eventTable["CHAT_MSG_COMBAT_FACTION_CHANGE"] , PatternCompare) end list = self.eventTable["CHAT_MSG_COMBAT_FACTION_CHANGE"] elseif eventName == "CHAT_MSG_COMBAT_HONOR_GAIN" then if not self.eventTable["CHAT_MSG_COMBAT_HONOR_GAIN"] then self.eventTable["CHAT_MSG_COMBAT_HONOR_GAIN"] = { "COMBATLOG_HONORAWARD", "COMBATLOG_HONORGAIN", "COMBATLOG_DISHONORGAIN", } table.sort(self.eventTable["CHAT_MSG_COMBAT_HONOR_GAIN"] , PatternCompare) end list = self.eventTable["CHAT_MSG_COMBAT_HONOR_GAIN"] elseif eventName == "CHAT_MSG_COMBAT_XP_GAIN" then if not self.eventTable["CHAT_MSG_COMBAT_XP_GAIN"] then self.eventTable["CHAT_MSG_COMBAT_XP_GAIN"] = { "COMBATLOG_XPGAIN", "COMBATLOG_XPGAIN_EXHAUSTION1", "COMBATLOG_XPGAIN_EXHAUSTION1_GROUP", "COMBATLOG_XPGAIN_EXHAUSTION1_RAID", "COMBATLOG_XPGAIN_EXHAUSTION2", "COMBATLOG_XPGAIN_EXHAUSTION2_GROUP", "COMBATLOG_XPGAIN_EXHAUSTION2_RAID", "COMBATLOG_XPGAIN_EXHAUSTION4", "COMBATLOG_XPGAIN_EXHAUSTION4_GROUP", "COMBATLOG_XPGAIN_EXHAUSTION4_RAID", "COMBATLOG_XPGAIN_EXHAUSTION5", "COMBATLOG_XPGAIN_EXHAUSTION5_GROUP", "COMBATLOG_XPGAIN_EXHAUSTION5_RAID", "COMBATLOG_XPGAIN_FIRSTPERSON", "COMBATLOG_XPGAIN_FIRSTPERSON_GROUP", "COMBATLOG_XPGAIN_FIRSTPERSON_RAID", "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED", "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_GROUP", "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_RAID", "COMBATLOG_XPLOSS_FIRSTPERSON_UNNAMED", } table.sort(self.eventTable["CHAT_MSG_COMBAT_XP_GAIN"] , PatternCompare) end list = self.eventTable["CHAT_MSG_COMBAT_XP_GAIN"] elseif eventName == "CHAT_MSG_COMBAT_FRIENDLY_DEATH" or eventName == "CHAT_MSG_COMBAT_HOSTILE_DEATH" then if not self.eventTable["CHAT_MSG_COMBAT_HOSTILE_DEATH"] then self.eventTable["CHAT_MSG_COMBAT_HOSTILE_DEATH"] = { "SELFKILLOTHER", "PARTYKILLOTHER", "UNITDESTROYEDOTHER", "UNITDIESOTHER", "UNITDIESSELF", } table.sort(self.eventTable["CHAT_MSG_COMBAT_HOSTILE_DEATH"] , PatternCompare) end list = self.eventTable["CHAT_MSG_COMBAT_HOSTILE_DEATH"] end if not list then -- self:Print(string.format("Event '%s' not found.", eventName), 1, 0,0); -- debug end return list end function lib:LoadPatternCategory(category) local list if category == "AuraChange" then list = { "AURACHANGEDOTHER", "AURACHANGEDSELF", } elseif category == "AuraDispel" then list = { "AURADISPELOTHER", "AURADISPELSELF", } elseif category == "BuffOther" then list = { "AURAADDEDOTHERHELPFUL", "AURAAPPLICATIONADDEDOTHERHELPFUL", } elseif category == "BuffSelf" then list = { "AURAADDEDSELFHELPFUL", "AURAAPPLICATIONADDEDSELFHELPFUL", } elseif category == "CastOther" then list = { "SIMPLECASTOTHEROTHER", "SIMPLECASTOTHERSELF", "SPELLTERSE_OTHER", } elseif category == "CastSelf" then list = { "SIMPLECASTSELFOTHER", "SIMPLECASTSELFSELF", "SPELLTERSE_SELF", } elseif category == "DebuffOther" then list = { "AURAADDEDOTHERHARMFUL", "AURAAPPLICATIONADDEDOTHERHARMFUL", } elseif category == "DebuffSelf" then list = { "AURAADDEDSELFHARMFUL", "AURAAPPLICATIONADDEDSELFHARMFUL", } elseif category == "DispelFailOther" then list = { "DISPELFAILEDOTHEROTHER", "DISPELFAILEDOTHERSELF", } elseif category == "DispelFailSelf" then list = { "DISPELFAILEDSELFOTHER", "DISPELFAILEDSELFSELF", } elseif category == "DmgShieldOther" then list = { "DAMAGESHIELDOTHEROTHER", "DAMAGESHIELDOTHERSELF", } elseif category == "DmgShieldSelf" then list = { "DAMAGESHIELDSELFOTHER", } elseif category == "DurabilityDamageSelf" then list = { "SPELLDURABILITYDAMAGEALLSELFOTHER", "SPELLDURABILITYDAMAGESELFOTHER", } elseif category == "DurabilityDamageOther" then list = { "SPELLDURABILITYDAMAGEALLOTHEROTHER", "SPELLDURABILITYDAMAGEALLOTHERSELF", "SPELLDURABILITYDAMAGEOTHEROTHER", "SPELLDURABILITYDAMAGEOTHERSELF", } elseif category == "EnchantOther" then list = { "ITEMENCHANTMENTADDOTHEROTHER", "ITEMENCHANTMENTADDOTHERSELF", } elseif category == "EnchantSelf" then list = { "ITEMENCHANTMENTADDSELFOTHER", "ITEMENCHANTMENTADDSELFSELF", } elseif category == "ExtraAttackOther" then list = { "SPELLEXTRAATTACKSOTHER", "SPELLEXTRAATTACKSOTHER_SINGULAR", } elseif category == "ExtraAttackSelf" then list = { "SPELLEXTRAATTACKSSELF", "SPELLEXTRAATTACKSSELF_SINGULAR", } elseif category == "Fade" then list = { "AURAREMOVEDOTHER", "AURAREMOVEDSELF", } elseif category == "HealOther" then list = { "HEALEDCRITOTHEROTHER", "HEALEDCRITOTHERSELF", "HEALEDOTHEROTHER", "HEALEDOTHERSELF", } elseif category == "HealSelf" then list = { "HEALEDCRITSELFOTHER", "HEALEDCRITSELFSELF", "HEALEDSELFOTHER", "HEALEDSELFSELF", } elseif category == "HitOtherOther" then list = { "COMBATHITCRITOTHEROTHER", "COMBATHITCRITSCHOOLOTHEROTHER", "COMBATHITOTHEROTHER", "COMBATHITSCHOOLOTHEROTHER", } elseif category == "HitOtherSelf" then list = { "COMBATHITCRITOTHERSELF", "COMBATHITCRITSCHOOLOTHERSELF", "COMBATHITOTHERSELF", "COMBATHITSCHOOLOTHERSELF", } elseif category == "HitSelf" then list = { "COMBATHITSCHOOLSELFOTHER", "COMBATHITSELFOTHER", "COMBATHITCRITSCHOOLSELFOTHER", "COMBATHITCRITSELFOTHER", } elseif category == "MissOtherOther" then list = { "MISSEDOTHEROTHER", "VSABSORBOTHEROTHER", "VSBLOCKOTHEROTHER", "VSDEFLECTOTHEROTHER", "VSDODGEOTHEROTHER", "VSEVADEOTHEROTHER", "VSIMMUNEOTHEROTHER", "VSPARRYOTHEROTHER", "VSRESISTOTHEROTHER", "IMMUNEDAMAGECLASSOTHEROTHER", "IMMUNEOTHEROTHER", } elseif category == "MissOtherSelf" then list = { "MISSEDOTHERSELF", "VSABSORBOTHERSELF", "VSBLOCKOTHERSELF", "VSDEFLECTOTHERSELF", "VSDODGEOTHERSELF", "VSEVADEOTHERSELF", "VSIMMUNEOTHERSELF", "VSPARRYOTHERSELF", "VSRESISTOTHERSELF", "IMMUNEDAMAGECLASSOTHERSELF", "IMMUNEOTHERSELF", } elseif category == "MissSelf" then list = { "MISSEDSELFOTHER", "VSABSORBSELFOTHER", "VSBLOCKSELFOTHER", "VSDEFLECTSELFOTHER", "VSDODGESELFOTHER", "VSEVADESELFOTHER", "VSIMMUNESELFOTHER", "VSPARRYSELFOTHER", "VSRESISTSELFOTHER", "IMMUNEDAMAGECLASSSELFOTHER", "IMMUNESELFOTHER", "IMMUNESELFSELF", } elseif category == "PowerGainOther" then list = { "POWERGAINOTHEROTHER", "POWERGAINOTHERSELF", } elseif category == "PerformOther" then list = { "OPEN_LOCK_OTHER", "SIMPLEPERFORMOTHEROTHER", "SIMPLEPERFORMOTHERSELF", "SPELLTERSEPERFORM_OTHER", } elseif category == "PerformSelf" then list = { "OPEN_LOCK_SELF", "SIMPLEPERFORMSELFOTHER", "SIMPLEPERFORMSELFSELF", "SPELLTERSEPERFORM_SELF", } elseif category == "ProcResistOther" then list = { "PROCRESISTOTHEROTHER", "PROCRESISTOTHERSELF", } elseif category == "ProcResistSelf" then list = { "PROCRESISTSELFOTHER", "PROCRESISTSELFSELF", } elseif category == "EnvOther" then list = { "VSENVIRONMENTALDAMAGE_DROWNING_OTHER", "VSENVIRONMENTALDAMAGE_FALLING_OTHER", "VSENVIRONMENTALDAMAGE_FATIGUE_OTHER", "VSENVIRONMENTALDAMAGE_FIRE_OTHER", "VSENVIRONMENTALDAMAGE_LAVA_OTHER", "VSENVIRONMENTALDAMAGE_SLIME_OTHER", } elseif category == "EnvSelf" then list = { "VSENVIRONMENTALDAMAGE_DROWNING_SELF", "VSENVIRONMENTALDAMAGE_FALLING_SELF", "VSENVIRONMENTALDAMAGE_FATIGUE_SELF", "VSENVIRONMENTALDAMAGE_FIRE_SELF", "VSENVIRONMENTALDAMAGE_LAVA_SELF", "VSENVIRONMENTALDAMAGE_SLIME_SELF", } -- HoT effects on others. (not casted by others) elseif category == "HotOther" then list = { "PERIODICAURAHEALOTHEROTHER", "PERIODICAURAHEALSELFOTHER", } -- HoT effects on you. (not casted by you) elseif category == "HotSelf" then list = { "PERIODICAURAHEALSELFSELF", "PERIODICAURAHEALOTHERSELF", } elseif category == "PowerGainSelf" then list = { "POWERGAINSELFSELF", "POWERGAINSELFOTHER", } elseif category == "BuffOther" then list = { "AURAAPPLICATIONADDEDOTHERHELPFUL", "AURAADDEDOTHERHELPFUL", } elseif category == "BuffSelf" then list = { "AURAADDEDSELFHELPFUL", "AURAAPPLICATIONADDEDSELFHELPFUL", } elseif category == "DrainSelf" then list = { "SPELLPOWERLEECHSELFOTHER", "SPELLPOWERDRAINSELFOTHER", "SPELLPOWERDRAINSELFSELF", } elseif category == "DrainOther" then list = { "SPELLPOWERLEECHOTHEROTHER", "SPELLPOWERLEECHOTHERSELF", "SPELLPOWERDRAINOTHEROTHER", "SPELLPOWERDRAINOTHERSELF", } -- DoT effects on others (not casted by others) elseif category == "DotOther" then list = { "PERIODICAURADAMAGEOTHEROTHER", "PERIODICAURADAMAGESELFOTHER", } -- DoT effects on you (not casted by you) elseif category == "DotSelf" then list = { "PERIODICAURADAMAGEOTHERSELF", "PERIODICAURADAMAGESELFSELF", } elseif category == "SpellHitOther" then list = { "SPELLLOGCRITOTHEROTHER", "SPELLLOGCRITOTHERSELF", "SPELLLOGCRITSCHOOLOTHEROTHER", "SPELLLOGCRITSCHOOLOTHERSELF", "SPELLLOGOTHEROTHER", "SPELLLOGOTHERSELF", "SPELLLOGSCHOOLOTHEROTHER", "SPELLLOGSCHOOLOTHERSELF", } elseif category == "SpellHitSelf" then list = { "SPELLLOGCRITSELFOTHER", "SPELLLOGCRITSELFSELF", "SPELLLOGCRITSCHOOLSELFOTHER", "SPELLLOGCRITSCHOOLSELFSELF", "SPELLLOGSELFOTHER", "SPELLLOGSELFSELF", "SPELLLOGSCHOOLSELFOTHER", "SPELLLOGSCHOOLSELFSELF", } elseif category == "SpellMissSelf" then list = { "IMMUNESPELLSELFOTHER", "IMMUNESPELLSELFSELF", "SPELLBLOCKEDSELFOTHER", "SPELLDEFLECTEDSELFOTHER", "SPELLDEFLECTEDSELFSELF", "SPELLDODGEDSELFOTHER", "SPELLDODGEDSELFSELF", "SPELLEVADEDSELFOTHER", "SPELLEVADEDSELFSELF", "SPELLIMMUNESELFOTHER", "SPELLIMMUNESELFSELF", "SPELLLOGABSORBSELFOTHER", "SPELLLOGABSORBSELFSELF", "SPELLMISSSELFOTHER", "SPELLMISSSELFSELF", "SPELLPARRIEDSELFOTHER", "SPELLPARRIEDSELFSELF", "SPELLREFLECTSELFOTHER", "SPELLREFLECTSELFSELF", "SPELLRESISTSELFOTHER", "SPELLRESISTSELFSELF", } elseif category == "SpellMissOther" then list = { "IMMUNESPELLOTHEROTHER", "IMMUNESPELLOTHERSELF", "SPELLBLOCKEDOTHEROTHER", "SPELLBLOCKEDOTHERSELF", "SPELLDODGEDOTHEROTHER", "SPELLDODGEDOTHERSELF", "SPELLDEFLECTEDOTHEROTHER", "SPELLDEFLECTEDOTHERSELF", "SPELLEVADEDOTHEROTHER", "SPELLEVADEDOTHERSELF", "SPELLIMMUNEOTHEROTHER", "SPELLIMMUNEOTHERSELF", "SPELLLOGABSORBOTHEROTHER", "SPELLLOGABSORBOTHERSELF", "SPELLMISSOTHEROTHER", "SPELLMISSOTHERSELF", "SPELLPARRIEDOTHEROTHER", "SPELLPARRIEDOTHERSELF", "SPELLREFLECTOTHEROTHER", "SPELLREFLECTOTHERSELF", "SPELLRESISTOTHEROTHER", "SPELLRESISTOTHERSELF", } elseif category == "InterruptOther" then list = { "SPELLINTERRUPTOTHEROTHER", "SPELLINTERRUPTOTHERSELF", } elseif category == "InterruptSelf" then list = { "SPELLINTERRUPTSELFOTHER", } elseif category == "SplitDamageOther" then list = { "SPELLSPLITDAMAGEOTHEROTHER", "SPELLSPLITDAMAGEOTHERSELF", } else return { category } end return list end -- Load categories recursively. First layer will not be sorted. function lib:LoadPatternCategoryTree(catTree, reSort) if type(catTree) ~= "table" then return end local resultList = {} local list for i, v in catTree do if type(v) == "table" then list = self:LoadPatternCategoryTree(v, true) else -- should be string. list = self:LoadPatternCategory(v) table.sort(list, PatternCompare) end for j, w in list do table.insert(resultList, w) end end if reSort then table.sort(resultList, PatternCompare) end return resultList end -- Used to load patternTable elements on demand. function lib:LoadPatternInfo(patternName) local patternInfo if patternName == "AURAADDEDOTHERHELPFUL" then patternInfo = { "buff", 1, 2, nil, } elseif patternName == "AURAADDEDSELFHELPFUL" then patternInfo = { "buff", ParserLib_SELF, 1, nil, } elseif patternName == "AURAAPPLICATIONADDEDOTHERHELPFUL" then patternInfo = { "buff", 1, 2, 3, } elseif patternName == "AURAAPPLICATIONADDEDSELFHELPFUL" then patternInfo = { "buff", ParserLib_SELF, 1, 2, } elseif patternName == "OPEN_LOCK_OTHER" then patternInfo = { "cast", 1, 2, 3, nil, true, } elseif patternName == "OPEN_LOCK_SELF" then patternInfo = { "cast", ParserLib_SELF, 1, 2, nil, true, } elseif patternName == "SIMPLECASTOTHEROTHER" then patternInfo = { "cast", 1, 2, 3, nil, nil, } elseif patternName == "SIMPLECASTOTHERSELF" then patternInfo = { "cast", 1, 2, ParserLib_SELF, nil, nil, } elseif patternName == "SIMPLECASTSELFOTHER" then patternInfo = { "cast", ParserLib_SELF, 1, 2, nil, nil, } elseif patternName == "SIMPLECASTSELFSELF" then patternInfo = { "cast", ParserLib_SELF, 1, ParserLib_SELF, nil, nil, } elseif patternName == "SIMPLEPERFORMOTHEROTHER" then patternInfo = { "cast", 1, 2, 3, nil, true, } elseif patternName == "SIMPLEPERFORMOTHERSELF" then patternInfo = { "cast", 1, 2, ParserLib_SELF, nil, true, } elseif patternName == "SIMPLEPERFORMSELFOTHER" then patternInfo = { "cast", ParserLib_SELF, 1, 2, nil, true, } elseif patternName == "SIMPLEPERFORMSELFSELF" then patternInfo = { "cast", ParserLib_SELF, 1, ParserLib_SELF, nil, true, } elseif patternName == "SPELLCASTOTHERSTART" then patternInfo = { "cast", 1, 2, nil, true, nil, } elseif patternName == "SPELLCASTSELFSTART" then patternInfo = { "cast", ParserLib_SELF, 1, nil, true, nil, } elseif patternName == "SPELLPERFORMOTHERSTART" then patternInfo = { "cast", 1, 2, nil, true, true, } elseif patternName == "SPELLPERFORMSELFSTART" then patternInfo = { "cast", ParserLib_SELF, 1, nil, true, true, } elseif patternName == "SPELLTERSEPERFORM_OTHER" then patternInfo = { "cast", 1, 2, nil, nil, true, } elseif patternName == "SPELLTERSEPERFORM_SELF" then patternInfo = { "cast", ParserLib_SELF, 1, nil, nil, true, } elseif patternName == "SPELLTERSE_OTHER" then patternInfo = { "cast", 1, 2, nil, nil, nil, } elseif patternName == "SPELLTERSE_SELF" then patternInfo = { "cast", ParserLib_SELF, 1, nil, nil, nil, } elseif patternName == "TRADESKILL_LOG_FIRSTPERSON" then patternInfo = { "create", ParserLib_SELF, 1, } elseif patternName == "TRADESKILL_LOG_THIRDPERSON" then patternInfo = { "create", 1, 2, } elseif patternName == "PARTYKILLOTHER" then patternInfo = { "death", 1, 2, nil, nil, } elseif patternName == "SELFKILLOTHER" then patternInfo = { "death", 1, ParserLib_SELF, nil, nil, } elseif patternName == "UNITDESTROYEDOTHER" then patternInfo = { "death", 1, nil, nil, true, } elseif patternName == "UNITDIESOTHER" then patternInfo = { "death", 1, nil, nil, nil, } elseif patternName == "UNITDIESSELF" then patternInfo = { "death", ParserLib_SELF, nil, nil, nil, } elseif patternName == "INSTAKILLOTHER" then patternInfo = { "death", 1, nil, 2, nil, } elseif patternName == "INSTAKILLSELF" then patternInfo = { "death", ParserLib_SELF, nil, true, nil } elseif patternName == "AURAADDEDOTHERHARMFUL" then patternInfo = { "debuff", 1, 2, nil, } elseif patternName == "AURAADDEDSELFHARMFUL" then patternInfo = { "debuff", ParserLib_SELF, 1, nil, } elseif patternName == "AURAAPPLICATIONADDEDOTHERHARMFUL" then patternInfo = { "debuff", 1, 2, 3, } elseif patternName == "AURAAPPLICATIONADDEDSELFHARMFUL" then patternInfo = { "debuff", ParserLib_SELF, 1, 2, } elseif patternName == "AURADISPELOTHER" then patternInfo = { "dispel", 1, 2, nil, nil, } elseif patternName == "AURADISPELSELF" then patternInfo = { "dispel", ParserLib_SELF, 1, nil, nil, } elseif patternName == "DISPELFAILEDOTHEROTHER" then patternInfo = { "dispel", 2, 3, 1, true, } elseif patternName == "DISPELFAILEDOTHERSELF" then patternInfo = { "dispel", ParserLib_SELF, 2, 1, true, } elseif patternName == "DISPELFAILEDSELFOTHER" then patternInfo = { "dispel", 1, 2, ParserLib_SELF, true, } elseif patternName == "DISPELFAILEDSELFSELF" then patternInfo = { "dispel", ParserLib_SELF, 1, ParserLib_SELF, true, } elseif patternName == "SPELLPOWERDRAINOTHEROTHER" then patternInfo = { "drain", 1, 5, 2, 3, 4, } elseif patternName == "SPELLPOWERDRAINOTHERSELF" then patternInfo = { "drain", 1, ParserLib_SELF, 2, 3, 4, } elseif patternName == "SPELLPOWERDRAINSELFOTHER" then patternInfo = { "drain", ParserLib_SELF, 4, 1, 2, 3, } elseif patternName == "SPELLPOWERDRAINSELFSELF" then patternInfo = { "drain", ParserLib_SELF, ParserLib_SELF, 1, 2, 3, } elseif patternName == "SPELLDURABILITYDAMAGEALLOTHEROTHER" then patternInfo = { "durability", 1, 2, 3, nil, } elseif patternName == "SPELLDURABILITYDAMAGEALLOTHERSELF" then patternInfo = { "durability", 1, 2, ParserLib_SELF, nil, } elseif patternName == "SPELLDURABILITYDAMAGEALLSELFOTHER" then patternInfo = { "durability", ParserLib_SELF, 1, 2, nil, } elseif patternName == "SPELLDURABILITYDAMAGEOTHEROTHER" then patternInfo = { "durability", 1, 2, 3, 4, } elseif patternName == "SPELLDURABILITYDAMAGEOTHERSELF" then patternInfo = { "durability", 1, 2, ParserLib_SELF, 3, } elseif patternName == "SPELLDURABILITYDAMAGESELFOTHER" then patternInfo = { "durability", ParserLib_SELF, 1, 2, 3, } elseif patternName == "ITEMENCHANTMENTADDOTHEROTHER" then patternInfo = { "enchant", 1, 3, 2, 4, } elseif patternName == "ITEMENCHANTMENTADDOTHERSELF" then patternInfo = { "enchant", 1, ParserLib_SELF, 2, 3, } elseif patternName == "ITEMENCHANTMENTADDSELFOTHER" then patternInfo = { "enchant", ParserLib_SELF, 2, 1, 3, } elseif patternName == "ITEMENCHANTMENTADDSELFSELF" then patternInfo = { "enchant", ParserLib_SELF, ParserLib_SELF, 1, 2, } elseif patternName == "VSENVIRONMENTALDAMAGE_DROWNING_OTHER" then patternInfo = { "environment", 1, 2, "drown", } elseif patternName == "VSENVIRONMENTALDAMAGE_DROWNING_SELF" then patternInfo = { "environment", ParserLib_SELF, 1, "drown", } elseif patternName == "VSENVIRONMENTALDAMAGE_FALLING_OTHER" then patternInfo = { "environment", 1, 2, "fall", } elseif patternName == "VSENVIRONMENTALDAMAGE_FALLING_SELF" then patternInfo = { "environment", ParserLib_SELF, 1, "fall", } elseif patternName == "VSENVIRONMENTALDAMAGE_FATIGUE_OTHER" then patternInfo = { "environment", 1, 2, "exhaust", } elseif patternName == "VSENVIRONMENTALDAMAGE_FATIGUE_SELF" then patternInfo = { "environment", ParserLib_SELF, 1, "exhaust", } elseif patternName == "VSENVIRONMENTALDAMAGE_FIRE_OTHER" then patternInfo = { "environment", 1, 2, "fire", } elseif patternName == "VSENVIRONMENTALDAMAGE_FIRE_SELF" then patternInfo = { "environment", ParserLib_SELF, 1, "fire", } elseif patternName == "VSENVIRONMENTALDAMAGE_LAVA_OTHER" then patternInfo = { "environment", 1, 2, "lava", } elseif patternName == "VSENVIRONMENTALDAMAGE_LAVA_SELF" then patternInfo = { "environment", ParserLib_SELF, 1, "lava", } elseif patternName == "VSENVIRONMENTALDAMAGE_SLIME_OTHER" then patternInfo = { "environment", 1, 2, "slime", } elseif patternName == "VSENVIRONMENTALDAMAGE_SLIME_SELF" then patternInfo = { "environment", ParserLib_SELF, 1, "slime", } elseif patternName == "COMBATLOG_XPGAIN" then patternInfo = { "experience", 2, nil, nil, nil, nil, nil, nil, nil, 1, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION1" then patternInfo = { "experience", 2, 1, 3, 4, nil, nil, nil, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION1_GROUP" then patternInfo = { "experience", 2, 1, 3, 4, nil, nil, nil, 5, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION1_RAID" then patternInfo = { "experience", 2, 1, 3, 4, nil, nil, 5, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION2" then patternInfo = { "experience", 2, 1, 3, 4, nil, nil, nil, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION2_GROUP" then patternInfo = { "experience", 2, 1, 3, 4, nil, nil, nil, 5, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION2_RAID" then patternInfo = { "experience", 2, 1, 3, 4, nil, nil, 5, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION4" then patternInfo = { "experience", 2, 1, nil, nil, 3, 4, nil, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION4_GROUP" then patternInfo = { "experience", 2, 1, nil, nil, 3, 4, nil, 5, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION4_RAID" then patternInfo = { "experience", 2, 1, nil, nil, 3, 4, 5, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION5" then patternInfo = { "experience", 2, 1, nil, nil, 3, 4, nil, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION5_GROUP" then patternInfo = { "experience", 2, 1, nil, nil, 3, 4, nil, 5, nil, } elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION5_RAID" then patternInfo = { "experience", 2, 1, nil, nil, 3, 4, 5, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON" then patternInfo = { "experience", 2, 1, nil, nil, nil, nil, nil, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_GROUP" then patternInfo = { "experience", 2, 1, nil, nil, nil, nil, nil, 3, nil, } elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_RAID" then patternInfo = { "experience", 2, 1, nil, nil, nil, nil, 3, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED" then patternInfo = { "experience", 1, nil, nil, nil, nil, nil, nil, nil, nil, } elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_GROUP" then patternInfo = { "experience", 1, nil, nil, nil, nil, nil, nil, 2, nil, } elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_RAID" then patternInfo = { "experience", 1, nil, nil, nil, nil, nil, 2, nil, nil, } elseif patternName == "COMBATLOG_XPLOSS_FIRSTPERSON_UNNAMED" then patternInfo = { "experience", 1, nil, nil, nil, nil, nil, nil, nil, nil, } elseif patternName == "SPELLEXTRAATTACKSOTHER" then patternInfo = { "extraattack", 1, 3, 2, } elseif patternName == "SPELLEXTRAATTACKSOTHER_SINGULAR" then patternInfo = { "extraattack", 1, 3, 2, } elseif patternName == "SPELLEXTRAATTACKSSELF" then patternInfo = { "extraattack", ParserLib_SELF, 2, 1, } elseif patternName == "SPELLEXTRAATTACKSSELF_SINGULAR" then patternInfo = { "extraattack", ParserLib_SELF, 2, 1, } elseif patternName == "AURAREMOVEDOTHER" then patternInfo = { "fade", 2, 1, } elseif patternName == "AURAREMOVEDSELF" then patternInfo = { "fade", ParserLib_SELF, 1, } elseif patternName == "SPELLFAILCASTSELF" then patternInfo = { "fail", ParserLib_SELF, 1, 2, } elseif patternName == "SPELLFAILPERFORMSELF" then patternInfo = { "fail", ParserLib_SELF, 1, 2, } elseif patternName == "FEEDPET_LOG_FIRSTPERSON" then patternInfo = { "feedpet", ParserLib_SELF, 1, } elseif patternName == "FEEDPET_LOG_THIRDPERSON" then patternInfo = { "feedpet", 1, 2, } elseif patternName == "POWERGAINOTHEROTHER" then patternInfo = { "gain", 4, 1, 5, 2, 3, } elseif patternName == "POWERGAINOTHERSELF" then patternInfo = { "gain", 3, ParserLib_SELF, 4, 1, 2, } elseif patternName == "POWERGAINSELFOTHER" then patternInfo = { "gain", ParserLib_SELF, 1, 4, 2, 3, } elseif patternName == "POWERGAINSELFSELF" then patternInfo = { "gain", ParserLib_SELF, ParserLib_SELF, 3, 1, 2, } elseif patternName == "HEALEDCRITOTHEROTHER" then patternInfo = { "heal", 1, 3, 2, 4, true, nil, } elseif patternName == "HEALEDCRITOTHERSELF" then patternInfo = { "heal", 1, ParserLib_SELF, 2, 3, true, nil, } elseif patternName == "HEALEDCRITSELFOTHER" then patternInfo = { "heal", ParserLib_SELF, 2, 1, 3, true, nil, } elseif patternName == "HEALEDCRITSELFSELF" then patternInfo = { "heal", ParserLib_SELF, ParserLib_SELF, 1, 2, true, nil, } elseif patternName == "HEALEDOTHEROTHER" then patternInfo = { "heal", 1, 3, 2, 4, nil, nil, } elseif patternName == "HEALEDOTHERSELF" then patternInfo = { "heal", 1, ParserLib_SELF, 2, 3, nil, nil, } elseif patternName == "HEALEDSELFOTHER" then patternInfo = { "heal", ParserLib_SELF, 2, 1, 3, nil, nil, } elseif patternName == "HEALEDSELFSELF" then patternInfo = { "heal", ParserLib_SELF, ParserLib_SELF, 1, 2, nil, nil, } elseif patternName == "PERIODICAURAHEALOTHEROTHER" then patternInfo = { "heal", 3, 1, 4, 2, nil, true, } elseif patternName == "PERIODICAURAHEALOTHERSELF" then patternInfo = { "heal", 2, ParserLib_SELF, 3, 1, nil, true, } elseif patternName == "PERIODICAURAHEALSELFOTHER" then patternInfo = { "heal", ParserLib_SELF, 1, 3, 2, nil, true, } elseif patternName == "PERIODICAURAHEALSELFSELF" then patternInfo = { "heal", ParserLib_SELF, ParserLib_SELF, 2, 1, nil, true, } elseif patternName == "COMBATHITCRITOTHEROTHER" then patternInfo = { "hit", 1, 2, ParserLib_MELEE, 3, nil, true, nil, nil, } elseif patternName == "COMBATHITCRITOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_MELEE, 2, nil, true, nil, nil, } elseif patternName == "COMBATHITCRITSCHOOLOTHEROTHER" then patternInfo = { "hit", 1, 2, ParserLib_MELEE, 3, 4, true, nil, nil, } elseif patternName == "COMBATHITCRITSCHOOLOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_MELEE, 2, 3, true, nil, nil, } elseif patternName == "COMBATHITCRITSCHOOLSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 1, ParserLib_MELEE, 2, 3, true, nil, nil, } elseif patternName == "COMBATHITCRITSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 1, ParserLib_MELEE, 2, nil, true, nil, nil, } elseif patternName == "COMBATHITOTHEROTHER" then patternInfo = { "hit", 1, 2, ParserLib_MELEE, 3, nil, nil, nil, nil, } elseif patternName == "COMBATHITOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_MELEE, 2, nil, nil, nil, nil, } elseif patternName == "COMBATHITSCHOOLOTHEROTHER" then patternInfo = { "hit", 1, 2, ParserLib_MELEE, 3, 4, nil, nil, nil, } elseif patternName == "COMBATHITSCHOOLOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_MELEE, 2, 3, nil, nil, nil, } elseif patternName == "COMBATHITSCHOOLSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 1, ParserLib_MELEE, 2, 3, nil, nil, nil, } elseif patternName == "COMBATHITSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 1, ParserLib_MELEE, 2, nil, nil, nil, nil, } elseif patternName == "DAMAGESHIELDOTHEROTHER" then patternInfo = { "hit", 1, 4, ParserLib_DAMAGESHIELD, 2, 3, nil, nil, nil, } elseif patternName == "DAMAGESHIELDOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_DAMAGESHIELD, 2, 3, nil, nil, nil, } elseif patternName == "DAMAGESHIELDSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 3, ParserLib_DAMAGESHIELD, 1, 2, nil, nil, nil, } elseif patternName == "PERIODICAURADAMAGEOTHEROTHER" then patternInfo = { "hit", 4, 1, 5, 2, 3, nil, true, nil, } elseif patternName == "PERIODICAURADAMAGEOTHERSELF" then patternInfo = { "hit", 3, ParserLib_SELF, 4, 1, 2, nil, true, nil, } elseif patternName == "PERIODICAURADAMAGESELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 1, 4, 2, 3, nil, true, nil, } elseif patternName == "PERIODICAURADAMAGESELFSELF" then patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 3, 1, 2, nil, true, nil, } elseif patternName == "SPELLLOGCRITOTHEROTHER" then patternInfo = { "hit", 1, 3, 2, 4, nil, true, nil, nil, } elseif patternName == "SPELLLOGCRITOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, nil, true, nil, nil, } elseif patternName == "SPELLLOGCRITSCHOOLOTHEROTHER" then patternInfo = { "hit", 1, 3, 2, 4, 5, true, nil, nil, } elseif patternName == "SPELLLOGCRITSCHOOLOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, 4, true, nil, nil, } elseif patternName == "SPELLLOGCRITSCHOOLSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, 4, true, nil, nil, } elseif patternName == "SPELLLOGCRITSCHOOLSELFSELF" then patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 1, 2, 3, true, nil, nil, } elseif patternName == "SPELLLOGCRITSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, nil, true, nil, nil, } elseif patternName == "SPELLLOGCRITSELFSELF" then patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 1, 2, nil, true, nil, nil, } elseif patternName == "SPELLLOGOTHEROTHER" then patternInfo = { "hit", 1, 3, 2, 4, nil, nil, nil, nil, } elseif patternName == "SPELLLOGOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, nil, nil, nil, nil, } elseif patternName == "SPELLLOGSCHOOLOTHEROTHER" then patternInfo = { "hit", 1, 3, 2, 4, 5, nil, nil, nil, } elseif patternName == "SPELLLOGSCHOOLOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, 4, nil, nil, nil, } elseif patternName == "SPELLLOGSCHOOLSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, 4, nil, nil, nil, } elseif patternName == "SPELLLOGSCHOOLSELFSELF" then patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 1, 2, 3, nil, nil, nil, } elseif patternName == "SPELLLOGSELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, nil, nil, nil, nil, } elseif patternName == "SPELLLOGSELFSELF" then patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 1, 2, nil, nil, nil, nil, } elseif patternName == "SPELLSPLITDAMAGEOTHEROTHER" then patternInfo = { "hit", 1, 3, 2, 4, nil, nil, nil, true, } elseif patternName == "SPELLSPLITDAMAGEOTHERSELF" then patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, nil, nil, nil, true, } elseif patternName == "SPELLSPLITDAMAGESELFOTHER" then patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, nil, nil, nil, true, } elseif patternName == "COMBATLOG_DISHONORGAIN" then patternInfo = { "honor", nil, 1, nil, } elseif patternName == "COMBATLOG_HONORAWARD" then patternInfo = { "honor", 1, nil, nil, } elseif patternName == "COMBATLOG_HONORGAIN" then patternInfo = { "honor", 3, 1, 2, } elseif patternName == "SPELLINTERRUPTOTHEROTHER" then patternInfo = { "interrupt", 1, 2, 3, } elseif patternName == "SPELLINTERRUPTOTHERSELF" then patternInfo = { "interrupt", 1, ParserLib_SELF, 2, } elseif patternName == "SPELLINTERRUPTSELFOTHER" then patternInfo = { "interrupt", ParserLib_SELF, 1, 2, } elseif patternName == "SPELLPOWERLEECHOTHEROTHER" then patternInfo = { "leech", 1, 5, 2, 3, 4, 6, 7, 8, } elseif patternName == "SPELLPOWERLEECHOTHERSELF" then patternInfo = { "leech", 1, ParserLib_SELF, 2, 3, 4, 5, 6, 7, } elseif patternName == "SPELLPOWERLEECHSELFOTHER" then patternInfo = { "leech", ParserLib_SELF, 4, 1, 2, 3, ParserLib_SELF, 5, 6, } elseif patternName == "IMMUNEDAMAGECLASSOTHEROTHER" then patternInfo = { "miss", 2, 1, ParserLib_MELEE, "immune", } elseif patternName == "IMMUNEDAMAGECLASSOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "immune", } elseif patternName == "IMMUNEDAMAGECLASSSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "immune", } elseif patternName == "IMMUNEOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "immune", } elseif patternName == "IMMUNEOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "immune", } elseif patternName == "IMMUNESELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "immune", } elseif patternName == "IMMUNESELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, ParserLib_MELEE, "immune", } elseif patternName == "IMMUNESPELLOTHEROTHER" then patternInfo = { "miss", 2, 1, 3, "immune", } elseif patternName == "IMMUNESPELLOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "immune", } elseif patternName == "IMMUNESPELLSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, 2, "immune", } elseif patternName == "IMMUNESPELLSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "immune", } elseif patternName == "MISSEDOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "miss", } elseif patternName == "MISSEDOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "miss", } elseif patternName == "MISSEDSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "miss", } elseif patternName == "PROCRESISTOTHEROTHER" then patternInfo = { "miss", 2, 1, 3, "resist", } elseif patternName == "PROCRESISTOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "resist", } elseif patternName == "PROCRESISTSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, 2, "resist", } elseif patternName == "PROCRESISTSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "resist", } elseif patternName == "SPELLBLOCKEDOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "block", } elseif patternName == "SPELLBLOCKEDOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "block", } elseif patternName == "SPELLBLOCKEDSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "block", } elseif patternName == "SPELLDEFLECTEDOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "deflect", } elseif patternName == "SPELLDEFLECTEDOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "deflect", } elseif patternName == "SPELLDEFLECTEDSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "deflect", } elseif patternName == "SPELLDEFLECTEDSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "deflect", } elseif patternName == "SPELLDODGEDOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "dodge", } elseif patternName == "SPELLDODGEDOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "dodge", } elseif patternName == "SPELLDODGEDSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "dodge", } elseif patternName == "SPELLDODGEDSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "dodge", } elseif patternName == "SPELLEVADEDOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "evade", } elseif patternName == "SPELLEVADEDOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "evade", } elseif patternName == "SPELLEVADEDSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "evade", } elseif patternName == "SPELLEVADEDSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "evade", } elseif patternName == "SPELLIMMUNEOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "immune", } elseif patternName == "SPELLIMMUNEOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "immune", } elseif patternName == "SPELLIMMUNESELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "immune", } elseif patternName == "SPELLIMMUNESELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "immune", } elseif patternName == "SPELLLOGABSORBOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "absorb", } elseif patternName == "SPELLLOGABSORBOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "absorb", } elseif patternName == "SPELLLOGABSORBSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "absorb", } elseif patternName == "SPELLLOGABSORBSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "absorb", } elseif patternName == "SPELLMISSOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "miss", } elseif patternName == "SPELLMISSOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "miss", } elseif patternName == "SPELLMISSSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "miss", } elseif patternName == "SPELLMISSSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "miss", } elseif patternName == "SPELLPARRIEDOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "parry", } elseif patternName == "SPELLPARRIEDOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "parry", } elseif patternName == "SPELLPARRIEDSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "parry", } elseif patternName == "SPELLPARRIEDSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "parry", } elseif patternName == "SPELLREFLECTOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "reflect", } elseif patternName == "SPELLREFLECTOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "reflect", } elseif patternName == "SPELLREFLECTSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "reflect", } elseif patternName == "SPELLREFLECTSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "reflect", } elseif patternName == "SPELLRESISTOTHEROTHER" then patternInfo = { "miss", 1, 3, 2, "resist", } elseif patternName == "SPELLRESISTOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, 2, "resist", } elseif patternName == "SPELLRESISTSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 2, 1, "resist", } elseif patternName == "SPELLRESISTSELFSELF" then patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "resist", } elseif patternName == "VSABSORBOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "absorb", } elseif patternName == "VSABSORBOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "absorb", } elseif patternName == "VSABSORBSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "absorb", } elseif patternName == "VSBLOCKOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "block", } elseif patternName == "VSBLOCKOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "block", } elseif patternName == "VSBLOCKSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "block", } elseif patternName == "VSDEFLECTOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "deflect", } elseif patternName == "VSDEFLECTOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "deflect", } elseif patternName == "VSDEFLECTSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "deflect", } elseif patternName == "VSDODGEOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "dodge", } elseif patternName == "VSDODGEOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "dodge", } elseif patternName == "VSDODGESELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "dodge", } elseif patternName == "VSEVADEOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "evade", } elseif patternName == "VSEVADEOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "evade", } elseif patternName == "VSEVADESELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "evade", } elseif patternName == "VSIMMUNEOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "immune", } elseif patternName == "VSIMMUNEOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "immune", } elseif patternName == "VSIMMUNESELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "immune", } elseif patternName == "VSPARRYOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "parry", } elseif patternName == "VSPARRYOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "parry", } elseif patternName == "VSPARRYSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "parry", } elseif patternName == "VSRESISTOTHEROTHER" then patternInfo = { "miss", 1, 2, ParserLib_MELEE, "resist", } elseif patternName == "VSRESISTOTHERSELF" then patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "resist", } elseif patternName == "VSRESISTSELFOTHER" then patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "resist", } elseif patternName == "FACTION_STANDING_CHANGED" then patternInfo = { "reputation", 2, nil, 1, nil, } elseif patternName == "FACTION_STANDING_DECREASED" then patternInfo = { "reputation", 1, 2, nil, true, } elseif patternName == "FACTION_STANDING_INCREASED" then patternInfo = { "reputation", 1, 2, nil, nil, } end if not patternInfo then -- self:Print("LoadPatternInfo(): Cannot find " .. patternName ); -- debug return end local pattern = getglobal(patternName); -- Get the pattern from GlobalStrings.lua -- How many regexp tokens in this pattern? local tc = 0 for _ in string.gfind(pattern, "%%%d?%$?([sd])") do tc = tc + 1 end -- Convert string.format tokens into LUA regexp tokens. pattern = { self:ConvertPattern(pattern, true) } local n = table.getn(pattern) if n > 1 then -- Extra return values are the remapped token sequences. for j in patternInfo do if type(patternInfo[j]) == "number" and patternInfo[j] < 100 then patternInfo[j] = pattern[patternInfo[j]+1] -- Remap to correct token sequence. end end end patternInfo.tc = tc patternInfo.pattern = pattern[1] return patternInfo end -- Fields of the patternTable. lib.infoMap = { hit = { "source", "victim", "skill", "amount", "element", "isCrit", "isDOT", "isSplit" }, heal = { "source", "victim", "skill", "amount", "isCrit", "isDOT" }, miss = { "source", "victim", "skill", "missType" }, death = { "victim", "source", "skill", "isItem" }, debuff = { "victim", "skill", "amountRank" }, buff = { "victim", "skill", "amountRank" }, fade = { "victim", "skill" }, cast = { "source", "skill", "victim", "isBegin", "isPerform" }, gain = { "source", "victim", "skill", "amount", "attribute" }, drain = { "source", "victim", "skill", "amount", "attribute" }, leech = { "source", "victim", "skill", "amount", "attribute", "sourceGained", "amountGained", "attributeGained" }, dispel = { "victim", "skill", "source", "isFailed" }, extraattack = { "victim", "skill", "amount" }, environment = { "victim", "amount", "damageType" }, experience = { "amount", "source", "bonusAmount", "bonusType", "penaltyAmount", "penaltyType", "amountRaidPenalty", "amountGroupBonus", "victim" }, reputation = { "faction", "amount", "rank", "isNegative" }, feedpet = { "victim", "item" }, enchant = { "source", "victim", "skill", "item" }, fail = { "source", "skill", "reason" }, interrupt = { "source", "victim", "skill" }, create = { "source", "item" }, honor = { "amount", "source", "sourceRank" }, -- if amount == nil then isDishonor = true. durability = { "source", "skill", "victim", "item" }, -- is not item then isAllItems = true unknown = { "message" }, } function lib:GetInfoFieldName(infoType, fieldIndex) if self.infoMap[infoType] then return self.infoMap[infoType][fieldIndex-1] -- Skip the first field in patternTable which is 'type'. end end -------------------------------- -- Load this bitch! -- -------------------------------- libobj:Register(lib)