Files
ShaguDPS/parser-vanilla.lua
2026-10-30 16:39:13 +00:00

444 lines
16 KiB
Lua

local parser = ShaguDPS.parser
-- sanitize, cache and convert patterns into gfind compatible ones
local sanitize_cache = {}
function sanitize(pattern)
if not sanitize_cache[pattern] then
local ret = pattern
-- escape magic characters
ret = gsub(ret, "([%+%-%*%(%)%?%[%]%^])", "%%%1")
-- remove capture indexes
ret = gsub(ret, "%d%$","")
-- catch all characters
ret = gsub(ret, "(%%%a)","%(%1+%)")
-- convert all %s to .+
ret = gsub(ret, "%%s%+",".+")
-- set priority to numbers over strings
ret = gsub(ret, "%(.%+%)%(%%d%+%)","%(.-%)%(%%d%+%)")
-- cache it
sanitize_cache[pattern] = ret
end
return sanitize_cache[pattern]
end
-- find, cache and return the indexes of a regex pattern
local capture_cache = {}
function captures(pat)
local r = capture_cache
if not r[pat] then
-- set default to nil
r[pat] = { nil, nil, nil, nil, nil }
-- try to find custom capture indexes
for a, b, c, d, e in string.gfind(gsub(pat, "%((.+)%)", "%1"), gsub(pat, "%d%$", "%%(.-)$")) do
r[pat][1] = tonumber(a)
r[pat][2] = tonumber(b)
r[pat][3] = tonumber(c)
r[pat][4] = tonumber(d)
r[pat][5] = tonumber(e)
end
end
return r[pat][1], r[pat][2], r[pat][3], r[pat][4], r[pat][5]
end
-- same as string.find but aware of up to 5 capture indexes
local ra, rb, rc, rd, re, a, b, c, d, e, match, num, va, vb, vc, vd, ve
function cfind(str, pat)
-- read capture indexes
a, b, c, d, e = captures(pat)
match, num, va, vb, vc, vd, ve = string.find(str, sanitize(pat))
-- put entries into the proper return values
ra = e == 1 and ve or d == 1 and vd or c == 1 and vc or b == 1 and vb or va
rb = e == 2 and ve or d == 2 and vd or c == 2 and vc or a == 2 and va or vb
rc = e == 3 and ve or d == 3 and vd or a == 3 and va or b == 3 and vb or vc
rd = e == 4 and ve or a == 4 and va or c == 4 and vc or b == 4 and vb or vd
re = a == 5 and va or d == 5 and vd or c == 5 and vc or b == 5 and vb or ve
return match, num, ra, rb, rc, rd, re
end
-- list of possible combat log patterns that may appear on the same events
local combatlog_strings = {
-- Damage
["Hit Damage (self vs. other)"] = {
COMBATHITSELFOTHER, COMBATHITSCHOOLSELFOTHER, COMBATHITCRITSELFOTHER, COMBATHITCRITSCHOOLSELFOTHER
},
["Hit Damage (other vs. self)"] = {
COMBATHITOTHERSELF, COMBATHITCRITOTHERSELF, COMBATHITSCHOOLOTHERSELF, COMBATHITCRITSCHOOLOTHERSELF
},
["Hit Damage (other vs. other)"] = {
COMBATHITOTHEROTHER, COMBATHITCRITOTHEROTHER, COMBATHITSCHOOLOTHEROTHER, COMBATHITCRITSCHOOLOTHEROTHER
},
["Spell Damage (self vs. self/other)"] = {
SPELLLOGSCHOOLSELFSELF, SPELLLOGCRITSCHOOLSELFSELF, SPELLLOGSELFSELF, SPELLLOGCRITSELFSELF, SPELLLOGSCHOOLSELFOTHER, SPELLLOGCRITSCHOOLSELFOTHER, SPELLLOGSELFOTHER, SPELLLOGCRITSELFOTHER
},
["Spell Damage (other vs. self)"] = {
SPELLLOGSCHOOLOTHERSELF, SPELLLOGCRITSCHOOLOTHERSELF, SPELLLOGOTHERSELF, SPELLLOGCRITOTHERSELF
},
["Spell Damage (other vs. other)"] = {
SPELLLOGSCHOOLOTHEROTHER, SPELLLOGCRITSCHOOLOTHEROTHER, SPELLLOGOTHEROTHER, SPELLLOGCRITOTHEROTHER
},
["Shield Damage (self vs. other)"] = {
DAMAGESHIELDSELFOTHER
},
["Shield Damage (other vs. self/other)"] = {
DAMAGESHIELDOTHERSELF, DAMAGESHIELDOTHEROTHER
},
["Periodic Damage (self/other vs. other)"] = {
PERIODICAURADAMAGESELFOTHER, PERIODICAURADAMAGEOTHEROTHER
},
["Periodic Damage (self/other vs. self)"] = {
PERIODICAURADAMAGESELFSELF, PERIODICAURADAMAGEOTHERSELF
},
-- Heal
["Heal (self vs. self/other)"] = {
HEALEDCRITSELFSELF, HEALEDSELFSELF, HEALEDCRITSELFOTHER, HEALEDSELFOTHER
},
["Heal (other vs. self/other)"] = {
HEALEDCRITOTHERSELF, HEALEDOTHERSELF, HEALEDCRITOTHEROTHER, HEALEDOTHEROTHER
},
["Periodic Heal (self/other vs. other)"] = {
PERIODICAURAHEALSELFOTHER, PERIODICAURAHEALOTHEROTHER
},
["Periodic Heal (other vs. self/other)"] = {
PERIODICAURAHEALSELFSELF, PERIODICAURAHEALOTHERSELF
}
}
-- list of combat log events with possible patterns assigned to them
local combatlog_events = {
-- Damage
["CHAT_MSG_COMBAT_SELF_HITS"] = combatlog_strings["Hit Damage (self vs. other)"],
["CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS"] = combatlog_strings["Hit Damage (other vs. self)"],
["CHAT_MSG_COMBAT_PARTY_HITS"] = combatlog_strings["Hit Damage (other vs. other)"],
["CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS"] = combatlog_strings["Hit Damage (other vs. other)"],
["CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS"] = combatlog_strings["Hit Damage (other vs. other)"],
["CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS"] = combatlog_strings["Hit Damage (other vs. other)"],
["CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS"] = combatlog_strings["Hit Damage (other vs. other)"],
["CHAT_MSG_COMBAT_PET_HITS"] = combatlog_strings["Hit Damage (other vs. other)"],
["CHAT_MSG_SPELL_SELF_DAMAGE"] = combatlog_strings["Spell Damage (self vs. self/other)"],
["CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE"] = combatlog_strings["Spell Damage (other vs. self)"],
["CHAT_MSG_SPELL_PARTY_DAMAGE"] = combatlog_strings["Spell Damage (other vs. other)"],
["CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE"] = combatlog_strings["Spell Damage (other vs. other)"],
["CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"] = combatlog_strings["Spell Damage (other vs. other)"],
["CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE"] = combatlog_strings["Spell Damage (other vs. other)"],
["CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE"] = combatlog_strings["Spell Damage (other vs. other)"],
["CHAT_MSG_SPELL_PET_DAMAGE"] = combatlog_strings["Spell Damage (other vs. other)"],
["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] = combatlog_strings["Shield Damage (self vs. other)"],
["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] = combatlog_strings["Shield Damage (other vs. self/other)"],
["CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE"] = combatlog_strings["Periodic Damage (self/other vs. other)"],
["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"] = combatlog_strings["Periodic Damage (self/other vs. other)"],
["CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE"] = combatlog_strings["Periodic Damage (self/other vs. other)"],
["CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"] = combatlog_strings["Periodic Damage (self/other vs. other)"],
["CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE"] = combatlog_strings["Periodic Damage (self/other vs. self)"],
-- Heal
["CHAT_MSG_SPELL_SELF_BUFF"] = combatlog_strings["Heal (self vs. self/other)"],
["CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF"] = combatlog_strings["Heal (other vs. self/other)"],
["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"] = combatlog_strings["Heal (other vs. self/other)"],
["CHAT_MSG_SPELL_PARTY_BUFF"] = combatlog_strings["Heal (other vs. self/other)"],
["CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS"] = combatlog_strings["Periodic Heal (self/other vs. other)"],
["CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS"] = combatlog_strings["Periodic Heal (self/other vs. other)"],
["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"] = combatlog_strings["Periodic Heal (self/other vs. other)"],
["CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"] = combatlog_strings["Periodic Heal (other vs. self/other)"]
}
-- list of all possible patterns including the logic on how to parse them
local combatlog_parser = {
[SPELLLOGSCHOOLSELFSELF] = function(d, attack, value, school)
-- Your %s hits you for %d %s damage.
return d.source, attack, d.target, value, school, "damage"
end,
[SPELLLOGCRITSCHOOLSELFSELF] = function(d, attack, value, school)
-- Your %s crits you for %d %s damage.
return d.source, attack, d.target, value, school, "damage"
end,
[SPELLLOGSELFSELF] = function(d, attack, value)
-- Your %s hits you for %d.
return d.source, attack, d.target, value, d.school, "damage"
end,
[SPELLLOGCRITSELFSELF] = function(d, attack, value)
-- Your %s crits you for %d.
return d.source, attack, d.target, value, d.school, "damage"
end,
[PERIODICAURADAMAGESELFSELF] = function(d, value, school, attack)
-- You suffer %d %s damage from your %s.
return d.source, attack, d.target, value, school, "damage"
end,
[SPELLLOGSCHOOLSELFOTHER] = function(d, attack, target, value, school)
-- Your %s hits %s for %d %s damage.
return d.source, attack, target, value, school, "damage"
end,
[SPELLLOGCRITSCHOOLSELFOTHER] = function(d, attack, target, value, school)
-- Your %s crits %s for %d %s damage.
return d.source, attack, target, value, school, "damage"
end,
[SPELLLOGSELFOTHER] = function(d, attack, target, value)
-- Your %s hits %s for %d.
return d.source, attack, target, value, d.school, "damage"
end,
[SPELLLOGCRITSELFOTHER] = function(d, attack, target, value)
-- Your %s crits %s for %d.
return d.source, attack, target, value, d.school, "damage"
end,
[PERIODICAURADAMAGESELFOTHER] = function(d, target, value, school, attack)
-- %s suffers %d %s damage from your %s.
return d.source, attack, target, value, school, "damage"
end,
[COMBATHITSELFOTHER] = function(d, target, value)
-- You hit %s for %d.
return d.source, d.attack, target, value, d.school, "damage"
end,
[COMBATHITCRITSELFOTHER] = function(d, target, value)
-- You crit %s for %d.
return d.source, d.attack, target, value, d.school, "damage"
end,
[COMBATHITSCHOOLSELFOTHER] = function(d, target, value, school)
-- You hit %s for %d %s damage.
return d.source, d.attack, target, value, school, "damage"
end,
[COMBATHITCRITSCHOOLSELFOTHER] = function(d, target, value, school)
-- You crit %s for %d %s damage.
return d.source, d.attack, target, value, school, "damage"
end,
[DAMAGESHIELDSELFOTHER] = function(d, value, school, target)
-- You reflect %d %s damage to %s.
return d.source, "Reflect ("..school..")", target, value, school, "damage"
end,
[SPELLLOGSCHOOLOTHERSELF] = function(d, source, attack, value, school)
-- %s's %s hits you for %d %s damage.
return source, attack, d.target, value, school, "damage"
end,
[SPELLLOGCRITSCHOOLOTHERSELF] = function(d, source, attack, value, school)
-- %s's %s crits you for %d %s damage.
return source, attack, d.target, value, school, "damage"
end,
[SPELLLOGOTHERSELF] = function(d, source, attack, value)
-- %s's %s hits you for %d.
return source, attack, d.target, value, d.school, "damage"
end,
[SPELLLOGCRITOTHERSELF] = function(d, source, attack, value)
-- %s's %s crits you for %d.
return source, attack, d.target, value, d.school, "damage"
end,
[PERIODICAURADAMAGEOTHERSELF] = function(d, value, school, source, attack)
-- You suffer %d %s damage from %s's %s.
return source, attack, d.target, value, school, "damage"
end,
[COMBATHITOTHERSELF] = function(d, source, value)
-- %s hits you for %d.
return source, d.attack, d.target, value, d.school, "damage"
end,
[COMBATHITCRITOTHERSELF] = function(d, source, value)
-- %s crits you for %d.
return source, d.attack, d.target, value, d.school, "damage"
end,
[COMBATHITSCHOOLOTHERSELF] = function(d, source, value, school)
-- %s hits you for %d %s damage.
return source, d.attack, d.target, value, school, "damage"
end,
[COMBATHITCRITSCHOOLOTHERSELF] = function(d, source, value, school)
-- %s crits you for %d %s damage.
return source, d.attack, d.target, value, school, "damage"
end,
[SPELLLOGSCHOOLOTHEROTHER] = function(d, source, attack, target, value, school)
-- %s's %s hits %s for %d %s damage.
return source, attack, target, value, school, "damage"
end,
[SPELLLOGCRITSCHOOLOTHEROTHER] = function(d, source, attack, target, value, school)
-- %s's %s crits %s for %d %s damage.
return source, attack, target, value, school, "damage"
end,
[SPELLLOGOTHEROTHER] = function(d, source, attack, target, value)
-- %s's %s hits %s for %d.
return source, attack, target, value, d.school, "damage"
end,
[SPELLLOGCRITOTHEROTHER] = function(d, source, attack, target, value, school)
-- %s's %s crits %s for %d.
return source, attack, target, value, school, "damage"
end,
[PERIODICAURADAMAGEOTHEROTHER] = function(d, target, value, school, source, attack)
-- %s suffers %d %s damage from %s's %s.
return source, attack, target, value, school, "damage"
end,
[COMBATHITOTHEROTHER] = function(d, source, target, value)
-- %s hits %s for %d.
return source, d.attack, target, value, d.school, "damage"
end,
[COMBATHITCRITOTHEROTHER] = function(d, source, target, value)
-- %s crits %s for %d.
return source, d.attack, target, value, d.school, "damage"
end,
[COMBATHITSCHOOLOTHEROTHER] = function(d, source, target, value, school)
-- %s hits %s for %d %s damage.
return source, d.attack, target, value, school, "damage"
end,
[COMBATHITCRITSCHOOLOTHEROTHER] = function(d, source, target, value, school)
-- %s crits %s for %d %s damage.
return source, d.attack, target, value, school, "damage"
end,
[DAMAGESHIELDOTHERSELF] = function(d, source, value, school)
-- %s reflects %d %s damage to you.
return source, "Reflect ("..school..")", d.target, value, school, "damage"
end,
[DAMAGESHIELDOTHEROTHER] = function(d, source, value, school, target)
-- %s reflects %d %s damage to %s.
return source, "Reflect ("..school..")", target, value, school, "damage"
end,
[HEALEDCRITOTHERSELF] = function(d, source, spell, value)
-- %s's %s critically heals you for %d.
return source, spell, d.target, value, d.school, "heal"
end,
[HEALEDOTHERSELF] = function(d, source, spell, value)
-- %s's %s heals you for %d.
return source, spell, d.target, value, d.school, "heal"
end,
[PERIODICAURAHEALOTHERSELF] = function(d, value, source, spell)
-- You gain %d health from %s's %s.
return source, spell, d.target, value, d.school, "heal"
end,
[HEALEDCRITSELFSELF] = function(d, spell, value)
-- Your %s critically heals you for %d.
return d.source, spell, d.target, value, d.school, "heal"
end,
[HEALEDSELFSELF] = function(d, spell, value)
-- Your %s heals you for %d.
return d.source, spell, d.target, value, d.school, "heal"
end,
[PERIODICAURAHEALSELFSELF] = function(d, value, spell)
-- You gain %d health from %s.
return d.source, spell, d.target, value, d.school, "heal"
end,
[HEALEDCRITSELFOTHER] = function(d, spell, target, value)
-- Your %s critically heals %s for %d.
return d.source, spell, target, value, d.school, "heal"
end,
[HEALEDSELFOTHER] = function(d, spell, target, value)
-- Your %s heals %s for %d.
return d.source, spell, target, value, d.school, "heal"
end,
[PERIODICAURAHEALSELFOTHER] = function(d, target, value, spell)
-- %s gains %d health from your %s.
return d.source, spell, target, value, d.school, "heal"
end,
[HEALEDCRITOTHEROTHER] = function(d, source, spell, target, value)
-- %s's %s critically heals %s for %d.
return source, spell, target, value, d.school, "heal"
end,
[HEALEDOTHEROTHER] = function(d, source, spell, target, value)
-- %s's %s heals %s for %d.
return source, spell, target, value, d.school, "heal"
end,
[PERIODICAURAHEALOTHEROTHER] = function(d, target, value, source, spell)
-- %s gains %d health from %s's %s.
return source, spell, target, value, d.school, "heal"
end,
}
-- preload all combat log patterns
for pattern in pairs(combatlog_parser) do
sanitize(pattern)
end
-- cache default table
local defaults = { }
-- initialize absorb and resist pattern
local absorb = sanitize(ABSORB_TRAILER)
local resist = sanitize(RESIST_TRAILER)
-- scope all required variables
local _, num, pattern, result, a1, a2, a3, a4, a5
-- use same strings each time
local empty, physical, autohit = "", "physical", "Auto Hit"
local player = UnitName("player")
-- call all datasources on each event
local function OnEvent()
if not arg1 then return end
-- remove absorb and resist suffixes
arg1 = string.gsub(arg1, absorb, empty)
arg1 = string.gsub(arg1, resist, empty)
-- write default values
defaults.source = player
defaults.target = player
defaults.school = physical
defaults.attack = autohit
defaults.spell = UNKNOWN
defaults.value = 0
-- iterate over all patterns assigned to the current event
for _, pattern in pairs(combatlog_events[event]) do
result, num, a1, a2, a3, a4, a5 = cfind(arg1, pattern)
if result then
return parser:AddData(combatlog_parser[pattern](defaults, a1, a2, a3, a4, a5))
end
end
end
-- the chat combat log works on every client and is the fallback source
parser:RegisterSource("combatlog", {
available = function() return true end,
enable = function()
for event in pairs(combatlog_events) do
parser:RegisterEvent(event)
end
parser:SetScript("OnEvent", OnEvent)
end,
})