Skip to content

Instantly share code, notes, and snippets.

@proglottis
Created March 17, 2013 06:26
Show Gist options
  • Save proglottis/5180379 to your computer and use it in GitHub Desktop.
Save proglottis/5180379 to your computer and use it in GitHub Desktop.
Quake 3 Log parser in AWK
#!/bin/awk -f
# Formats Quake 3 logs into HTML.
function print_header()
{
print "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>"
print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
print "<html><head>"
print "<title>Quake 3</title>"
print "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\" />"
print "<style type=\"text/css\">"
print "body { background-color:white;color:black; }"
# print "table { border:1px solid black; }"
print "td { border:1px solid black; }"
print "table.game { width:100%; }"
print "table.players { width:100%; }"
print "</style>"
print "</head><body>"
}
function print_footer()
{
print "</table>"
print "</body></html>"
}
function print_game(id, totaltime, playernames, playerscores, playerkills, playerdeaths, playerkillwith, playerdiewith)
{
print "<table summary=\"Game\" class=\"game\">"
print "<tr><td><h1>Game " id "</h1></td></tr>"
print "<tr><td>"
print "<strong>Total time:</strong> " totaltime
print "</td></tr>"
print "<tr><td>"
print "<table summary=\"Players\" class=\"players\"><tr>"
print "<td><strong>Player Name</strong></td>"
print "<td><strong>Score</strong></td>"
print "<td><strong>Kills</strong></td>"
print "<td><strong>Deaths</strong></td>"
print "<td><strong>Killed most with</strong></td>"
print "<td><strong>Died most by</strong></td>"
print "</tr>"
for(x in playernames) {
# Add zero to integers to make sure something is displayed
print "<tr>"
print "<td>" playernames[x] "</td>"
print "<td>" playerscores[x]+0 "</td>"
print "<td>" playerkills[x]+0 "</td>"
print "<td>" playerdeaths[x]+0 "</td>"
print "<td>" playerkillwith[x] "</td>"
print "<td>" playerdiewith[x] "</td>"
print "</tr>"
}
print "</td></tr></table>"
print "</td></tr></table>"
}
BEGIN {
DEATHS["0"] = "Unknown"
DEATHS["1"] = "Shotgun"
DEATHS["2"] = "Gauntlet"
DEATHS["3"] = "Machinegun"
DEATHS["4"] = "Grenade"
DEATHS["5"] = "Grenade splash"
DEATHS["6"] = "Rocket"
DEATHS["7"] = "Rocket splash"
DEATHS["8"] = "Plasma"
DEATHS["9"] = "Plasma splash"
DEATHS["10"] = "Railgun"
DEATHS["11"] = "Lightning"
DEATHS["12"] = "BFG"
DEATHS["13"] = "BFG splash"
DEATHS["14"] = "Water"
DEATHS["15"] = "Slime"
DEATHS["16"] = "Lava"
DEATHS["17"] = "Crush"
DEATHS["18"] = "Telefrag"
DEATHS["19"] = "Falling"
DEATHS["20"] = "Suiside"
DEATHS["21"] = "Target laser"
DEATHS["22"] = "Trigger hurt"
DEATHS["23"] = "Nail"
DEATHS["24"] = "Chaingun"
DEATHS["25"] = "Proximity mine"
DEATHS["26"] = "Kamikaze"
DEATHS["27"] = "Juiced"
DEATHS["28"] = "Grapple"
gameid = 0
ingame = 0
print_header()
}
END {
print_footer()
}
# End of a game
$2=="ShutdownGame:" {
ingame = 0
# Find most common kill/death method
for(x in playername) {
kmaxid = 0
kmax = 0
dmaxid = 0
dmax = 0
for(y in DEATHS) {
if(kmax<killby[x,y]) {
kmaxid = y
kmax = killby[x,y]
}
if(dmax<deathby[x,y]) {
dmaxid = y
dmax = deathby[x,y]
}
}
commonkill[x] = DEATHS[kmaxid]
commondeath[x] = DEATHS[dmaxid]
}
# Print
print_game(gameid, $1, playername, score, killcount, killedcount, commonkill, commondeath)
# Clear all arrays
for(i in playername) {
delete playername[i]
}
for(i in killcount) {
delete killcount[i]
}
for(i in killedcount) {
delete killedcount[i]
}
for(i in killby) {
delete killby[i]
}
for(i in deathby) {
delete deathby[i]
}
for(i in score) {
delete score[i]
}
}
# On player info change
ingame==1 && $2=="ClientUserinfoChanged:" {
## Real player
# 0:00 ClientUserinfoChanged: 0 n\Proglottis\t\0\model\uriel/zael\hmodel\uriel/zael\g_redteam\\g_blueteam\\c1\4\c2\5\hc\100\w\0\l\0\tt\0\tl\0
## Bot
# 0:00 ClientUserinfoChanged: 1 n\^1A^2n^3a^4r^5k^6i\t\0\model\anarki\hmodel\anarki\c1\4\c2\5\hc\70\w\0\l\0\skill\ 2.00\tt\0\tl\0
split($0, rawplayerinfo, "\\")
# TODO: Should scan for "n" which signifies that the next entry will be the name
playername[$3] = rawplayerinfo[2]
}
# On player kill
ingame==1 && $2=="Kill:" {
# 0:04 Kill: 1022 3 22: <world> killed Doom by MOD_TRIGGER_HURT
killcount[$3]++
killedcount[$4]++
# Forcing $5 to an interger by adding zero removes the colon
killby[$3, $5+0]++
deathby[$4, $5+0]++
}
# Score display lines
ingame==1 && $2=="score:" {
# 8:59 score: 1 ping: 0 client: 1 Ranger
score[$7] = $3
}
# Start of a game
$2=="InitGame:" {
# 0:00 InitGame: \capturelimit\0\g_maxGameClients\0\sv_maxclients\8\timelimit\0\fraglimit\20\dmflags\0\sv_hostname\noname\sv_punkbuster\0\sv_maxRate\0\sv_minPing\0\sv_maxPing\0\sv_floodProtect\1\version\Q3 1.32b linux-i386 Nov 14 2002\g_gametype\0\protocol\68\mapname\BGMP0\sv_privateClients\0\sv_allowDownload\0\gamename\baseq3\g_needpass\0
ingame = 1
gameid++
# The so called "world" player
playername["1022"] = "&lt;world&gt;"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment