aboutsummaryrefslogtreecommitdiffstats
path: root/common/death
diff options
context:
space:
mode:
authorGravatar BanceDev 2026-02-16 16:31:54 -0500
committerGravatar BanceDev 2026-02-16 16:31:54 -0500
commitca90ebdfa8789654766c5d7969baa7afacd9ebd2 (patch)
tree9693e0c7a5af6713f4c5e39372dcf22d05844ec3 /common/death
initial commitHEADmain
Diffstat (limited to 'common/death')
-rw-r--r--common/death/death.go132
-rw-r--r--common/death/parser.go55
-rw-r--r--common/death/template.go155
3 files changed, 342 insertions, 0 deletions
diff --git a/common/death/death.go b/common/death/death.go
new file mode 100644
index 0000000..c71f862
--- /dev/null
+++ b/common/death/death.go
@@ -0,0 +1,132 @@
+package death
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+)
+
+type Weapon string
+
+const (
+ Axe Weapon = "axe"
+ Discharge Weapon = "discharge"
+ Drown Weapon = "drown"
+ Fall Weapon = "fall"
+ GrenadeLauncher Weapon = "gl"
+ Lava Weapon = "lava"
+ LightningGun Weapon = "lg"
+ Nailgun Weapon = "ng"
+ NoWeapon Weapon = "no weapon"
+ QLightningGun Weapon = "quad lg"
+ QRocketLauncher Weapon = "quad rl"
+ QShotgun Weapon = "quad sg"
+ QSuperNailgun Weapon = "quad sng"
+ QSuperShotgun Weapon = "quad ssg"
+ RocketLauncher Weapon = "rl"
+ Shotgun Weapon = "sg"
+ Slime Weapon = "slime"
+ Squish Weapon = "squish"
+ Stomp Weapon = "stomp"
+ SuperNailgun Weapon = "sng"
+ SuperShotgun Weapon = "ssg"
+ TeamKill Weapon = "tk"
+ Telefrag Weapon = "telefrag"
+ Trap Weapon = "trap"
+)
+
+type Type uint8
+
+const (
+ Unknown Type = iota
+ Death
+ Suicide
+ Kill
+ TeamKillUnknownKiller
+ TeamKillUnknownVictim
+)
+
+func (t Type) String() string {
+ names := []string{
+ "unknown",
+ "death",
+ "suicide",
+ "kill",
+ "teamkill",
+ "teamkill",
+ }
+
+ if t < 0 || int(t) >= len(names) {
+ return "type(?)"
+ }
+
+ return names[t]
+}
+
+type Obituary struct {
+ Type Type
+ Killer string
+ Victim string
+ Weapon Weapon
+}
+
+func (o Obituary) String() string {
+ hasKiller := o.Killer != ""
+ hasVictim := o.Victim != ""
+
+ switch {
+ case hasKiller && hasVictim:
+ return fmt.Sprintf("%s %s %s %s", o.Type, o.Killer, o.Weapon, o.Victim)
+ case hasKiller:
+ return fmt.Sprintf("%s %s %s", o.Type, o.Killer, o.Weapon)
+ default:
+ return fmt.Sprintf("%s %s %s", o.Type, o.Victim, o.Weapon)
+ }
+}
+
+type Parser struct {
+ templates []template
+}
+
+func init() {
+ sort.SliceStable(templates, func(i, j int) bool {
+ return templates[i].priority > templates[j].priority
+ })
+}
+
+func Parse(input string) (*Obituary, bool) {
+ s := strings.TrimSpace(input)
+
+ for _, t := range templates {
+ x, y, ok := t.parser.parse(s)
+ if !ok {
+ continue
+ }
+
+ ob := &Obituary{Weapon: t.weapon, Type: toObituaryType(t.typ)}
+
+ switch t.typ {
+ case PlayerDeath:
+ ob.Victim = x
+ case PlayerSuicide:
+ ob.Victim = x
+ case XFraggedByY:
+ ob.Victim = x
+ ob.Killer = y
+ case XFragsY:
+ ob.Killer = x
+ ob.Victim = y
+ case XTeamKilled:
+ ob.Victim = x
+ case XTeamKills:
+ ob.Killer = x
+ default:
+ ob.Victim = x
+ ob.Killer = y
+ }
+
+ return ob, true
+ }
+
+ return nil, false
+}
diff --git a/common/death/parser.go b/common/death/parser.go
new file mode 100644
index 0000000..e86cffb
--- /dev/null
+++ b/common/death/parser.go
@@ -0,0 +1,55 @@
+package death
+
+import "strings"
+
+type parser interface {
+ parse(msg string) (string, string, bool)
+}
+
+type suffixParser struct {
+ suffix string
+}
+
+func (m suffixParser) parse(msg string) (x, y string, ok bool) {
+ if !strings.HasSuffix(msg, m.suffix) {
+ return "", "", false
+ }
+
+ x = strings.TrimSpace(strings.TrimSuffix(msg, m.suffix))
+ if x == "" {
+ return "", "", false
+ }
+
+ return x, "", true
+}
+
+type infixParser struct {
+ sep string
+ suffix string
+}
+
+func (m infixParser) parse(msg string) (x, y string, ok bool) {
+ before, after, found := strings.Cut(msg, m.sep)
+ if !found {
+ return "", "", false
+ }
+
+ x = strings.TrimSpace(before)
+ if x == "" {
+ return "", "", false
+ }
+
+ if m.suffix != "" {
+ if !strings.HasSuffix(after, m.suffix) {
+ return "", "", false
+ }
+ after = strings.TrimSuffix(after, m.suffix)
+ }
+
+ y = strings.TrimSpace(after)
+ if y == "" {
+ return "", "", false
+ }
+
+ return x, y, true
+}
diff --git a/common/death/template.go b/common/death/template.go
new file mode 100644
index 0000000..3f77c5b
--- /dev/null
+++ b/common/death/template.go
@@ -0,0 +1,155 @@
+package death
+
+import "strings"
+
+type templateType uint8
+
+const (
+ PlayerDeath templateType = iota
+ PlayerSuicide
+ XFraggedByY
+ XFragsY
+ XTeamKilled
+ XTeamKills
+)
+
+func toObituaryType(t templateType) Type {
+ switch t {
+ case PlayerDeath:
+ return Death
+ case PlayerSuicide:
+ return Suicide
+ case XFraggedByY, XFragsY:
+ return Kill
+ case XTeamKilled:
+ return TeamKillUnknownKiller
+ case XTeamKills:
+ return TeamKillUnknownVictim
+ default:
+ return Unknown
+ }
+}
+
+type template struct {
+ parser parser
+ parts []string
+ priority int
+ typ templateType
+ weapon Weapon
+}
+
+func newTemplate(typ templateType, weapon Weapon, parts ...string) template {
+ prio := 0
+ for _, pr := range parts {
+ prio += len(pr)
+ }
+
+ var pa parser
+ switch typ {
+ case XFraggedByY, XFragsY:
+ pa = infixParser{
+ sep: parts[0],
+ suffix: strings.Join(parts[1:], ""),
+ }
+ default:
+ pa = suffixParser{
+ suffix: strings.Join(parts, ""),
+ }
+ }
+
+ return template{
+ parser: pa,
+ parts: parts,
+ priority: prio,
+ typ: typ,
+ weapon: weapon,
+ }
+}
+
+var templates = []template{
+ newTemplate(PlayerDeath, Drown, " sleeps with the fishes"),
+ newTemplate(PlayerDeath, Drown, " sucks it down"),
+ newTemplate(PlayerDeath, Fall, " cratered"),
+ newTemplate(PlayerDeath, Fall, " fell to her death"),
+ newTemplate(PlayerDeath, Fall, " fell to his death"),
+ newTemplate(PlayerDeath, Lava, " burst into flames"),
+ newTemplate(PlayerDeath, Lava, " turned into hot slag"),
+ newTemplate(PlayerDeath, Lava, " visits the Volcano God"),
+ newTemplate(PlayerDeath, NoWeapon, " died"),
+ newTemplate(PlayerDeath, NoWeapon, " tried to leave"),
+ newTemplate(PlayerDeath, Slime, " can't exist on slime alone"),
+ newTemplate(PlayerDeath, Slime, " gulped a load of slime"),
+ newTemplate(PlayerDeath, Squish, " was squished"),
+ newTemplate(PlayerDeath, Trap, " ate a lavaball"),
+ newTemplate(PlayerDeath, Trap, " blew up"),
+ newTemplate(PlayerDeath, Trap, " was spiked"),
+ newTemplate(PlayerDeath, Trap, " was zapped"),
+ newTemplate(PlayerSuicide, Discharge, " discharges into the lava"),
+ newTemplate(PlayerSuicide, Discharge, " discharges into the slime"),
+ newTemplate(PlayerSuicide, Discharge, " discharges into the water"),
+ newTemplate(PlayerSuicide, Discharge, " electrocutes herself"),
+ newTemplate(PlayerSuicide, Discharge, " electrocutes himself"),
+ newTemplate(PlayerSuicide, Discharge, " heats up the water"),
+ newTemplate(PlayerSuicide, Discharge, " railcutes herself"),
+ newTemplate(PlayerSuicide, Discharge, " railcutes himself"),
+ newTemplate(PlayerSuicide, GrenadeLauncher, " tries to put the pin back in"),
+ newTemplate(PlayerSuicide, NoWeapon, " suicides"),
+ newTemplate(PlayerSuicide, RocketLauncher, " becomes bored with life"),
+ newTemplate(PlayerSuicide, RocketLauncher, " discovers blast radius"),
+ newTemplate(XFraggedByY, "Axe", " was ax-murdered by "),
+ newTemplate(XFraggedByY, "Axe", " was axed to pieces by "),
+ newTemplate(XFraggedByY, QShotgun, " was lead poisoned by "),
+ newTemplate(XFraggedByY, QSuperNailgun, " was straw-cuttered by "),
+ newTemplate(XFraggedByY, Discharge, " accepts ", "' discharge"),
+ newTemplate(XFraggedByY, Discharge, " accepts ", "'s discharge"),
+ newTemplate(XFraggedByY, Discharge, " drains ", "' batteries"),
+ newTemplate(XFraggedByY, Discharge, " drains ", "'s batteries"),
+ newTemplate(XFraggedByY, GrenadeLauncher, " eats ", "' pineapple"),
+ newTemplate(XFraggedByY, GrenadeLauncher, " eats ", "'s pineapple"),
+ newTemplate(XFraggedByY, GrenadeLauncher, " was gibbed by ", "' grenade"),
+ newTemplate(XFraggedByY, GrenadeLauncher, " was gibbed by ", "'s grenade"),
+ newTemplate(XFraggedByY, LightningGun, " accepts ", "' shaft"),
+ newTemplate(XFraggedByY, LightningGun, " accepts ", "'s shaft"),
+ newTemplate(XFraggedByY, Nailgun, " was body pierced by "),
+ newTemplate(XFraggedByY, Nailgun, " was nailed by "),
+ newTemplate(XFraggedByY, QLightningGun, " gets a natural disaster from "),
+ newTemplate(XFraggedByY, QRocketLauncher, " was brutalized by ", "' quad rocket"),
+ newTemplate(XFraggedByY, QRocketLauncher, " was brutalized by ", "'s quad rocket"),
+ newTemplate(XFraggedByY, QRocketLauncher, " was smeared by ", "' quad rocket"),
+ newTemplate(XFraggedByY, QRocketLauncher, " was smeared by ", "'s quad rocket"),
+ newTemplate(XFraggedByY, QSuperShotgun, " ate 8 loads of ", "' buckshot"),
+ newTemplate(XFraggedByY, QSuperShotgun, " ate 8 loads of ", "'s buckshot"),
+ newTemplate(XFraggedByY, RocketLauncher, " rides ", "' rocket"),
+ newTemplate(XFraggedByY, RocketLauncher, " rides ", "'s rocket"),
+ newTemplate(XFraggedByY, RocketLauncher, " was gibbed by ", "' rocket"),
+ newTemplate(XFraggedByY, RocketLauncher, " was gibbed by ", "'s rocket"),
+ newTemplate(XFraggedByY, Shotgun, " chewed on ", "' boomstick"),
+ newTemplate(XFraggedByY, Shotgun, " chewed on ", "'s boomstick"),
+ newTemplate(XFraggedByY, Stomp, " softens ", "' fall"),
+ newTemplate(XFraggedByY, Stomp, " softens ", "'s fall"),
+ newTemplate(XFraggedByY, Stomp, " tried to catch "),
+ newTemplate(XFraggedByY, Stomp, " was crushed by "),
+ newTemplate(XFraggedByY, Stomp, " was jumped by "),
+ newTemplate(XFraggedByY, Stomp, " was literally stomped into particles by "),
+ newTemplate(XFraggedByY, SuperNailgun, " was perforated by "),
+ newTemplate(XFraggedByY, SuperNailgun, " was punctured by "),
+ newTemplate(XFraggedByY, SuperNailgun, " was ventilated by "),
+ newTemplate(XFraggedByY, SuperShotgun, " ate 2 loads of ", "' buckshot"),
+ newTemplate(XFraggedByY, SuperShotgun, " ate 2 loads of ", "'s buckshot"),
+ newTemplate(XFraggedByY, Telefrag, " was telefragged by "),
+ newTemplate(XFragsY, QRocketLauncher, " rips ", " a new one"),
+ newTemplate(XFragsY, Squish, " squishes "),
+ newTemplate(XFragsY, Stomp, " stomps "),
+ newTemplate(XTeamKilled, Stomp, " was crushed by her teammate"),
+ newTemplate(XTeamKilled, Stomp, " was crushed by his teammate"),
+ newTemplate(XTeamKilled, Stomp, " was jumped by her teammate"),
+ newTemplate(XTeamKilled, Stomp, " was jumped by his teammate"),
+ newTemplate(XTeamKilled, Telefrag, " was telefragged by her teammate"),
+ newTemplate(XTeamKilled, Telefrag, " was telefragged by his teammate"),
+ newTemplate(XTeamKills, Squish, " squished a teammate"),
+ newTemplate(XTeamKills, TeamKill, " checks her glasses"),
+ newTemplate(XTeamKills, TeamKill, " checks his glasses"),
+ newTemplate(XTeamKills, TeamKill, " gets a frag for the other team"),
+ newTemplate(XTeamKills, TeamKill, " loses another friend"),
+ newTemplate(XTeamKills, TeamKill, " mows down a teammate"),
+}