This commit is contained in:
Not 2022-03-28 12:48:16 +02:00
commit f0703eaafd
1 changed files with 218 additions and 0 deletions

218
leaderboard.lua Normal file
View File

@ -0,0 +1,218 @@
-- Leaderboards written by Not
local FILENAME = "leaderboard.txt"
local lb = {}
local timeFinished = 0
local disable = true
local prevLap = 0
local splits = {}
-- Read the leaderboard
local f = io.open(FILENAME, "r")
if f then
for l in f:lines() do
local t = {}
for word in (l+"\t"):gmatch("(.-)\t") do
table.insert(t, word)
end
--local level, name, skin, color, time, splts = l:match("(.*)\t(.*)\t(.*)\t(.*)\t(.*)\t(.*)")
if lb[t[1]] == nil then
lb[t[1]] = {}
end
local spl = {}
if t[6] != nil then
for str in t[6]:gmatch("([^ ]+)") do
table.insert(spl, tonumber(str))
end
end
table.insert(lb[t[1]], {t[2], t[3], t[4], tonumber(t[5]), spl})
end
f:close()
else
print("Failed to open file: ", FILENAME)
end
local function initLeaderboard()
local ingame = 0
for p in players.iterate do
if p.valid and not p.spectator then
ingame = ingame + 1
end
end
disable = ingame > 1
if disable then
--print("To many players in game, leaderboard has been disabled")
return
end
end
addHook("PlayerSpawn", initLeaderboard)
local function retry(player, ...)
if disable or player.spectator then
print("How dare you")
return
end
G_SetCustomExitVars(gamemap, 2)
G_ExitLevel()
end
COM_AddCommand("retry", retry)
--DEBUGGING
--local function printTable(tb)
-- for k, v in pairs(tb) do
-- for i = 1, #v do
-- print("TABLE: " + k, tb[k])
-- if v[i] != nil then
-- print(v[i][1], v[i][2], v[i][3], v[i][4], table.concat(v[i][5], ","))
-- end
-- end
-- end
--end
addHook("MapLoad", function()
timeFinished = 0
splits = {}
prevLap = 0
end
)
local function ticsToTime(tics)
return string.format(
"%d:%02d:%02d",
G_TicsToMinutes(tics),
G_TicsToSeconds(tics),
G_TicsToCentiseconds(tics)
)
end
local bodium = {V_YELLOWMAP, V_GRAYMAP, V_BROWNMAP, 0, 0}
local splitColor = {[true]=V_SKYMAP, [false]=V_REDMAP}
local splitSymbol = {[true]="-", [false]="+"}
local showSplit = 0
local function drawScoreboard(v)
if disable then return end
local m = lb[tostring(gamemap)]
if m == nil then
return
end
for i = 1, #m do
local score = m[i]
local skin = skins[score[2]]
if skin == nil then
skin = skins["sonic"]
end
local patch = v.cachePatch(skin.facerank)
-- | OFFSET | + | PADDING | * |INDEX|
local h = ((200 / 4) + 4) + (patch.height + 4) * (i - 1)
v.draw(4, h, patch, V_HUDTRANS | bodium[i], v.getColormap("sonic", score[3]))
v.drawString(8 + patch.width, h, score[1], V_HUDTRANSHALF | V_ALLOWLOWERCASE)
-- Draw splits
if showSplit > 0 and score[5][prevLap] != nil then
local split = splits[prevLap] - score[5][prevLap]
v.drawString(8 + patch.width, h + 8, splitSymbol[split < 0] + ticsToTime(abs(split)), V_HUDTRANSHALF | splitColor[split < 0])
else
v.drawString(8 + patch.width, h + 8, ticsToTime(score[4]), V_HUDTRANSHALF | bodium[i])
end
end
end
hud.add(drawScoreboard, "game")
local function lbComp(a, b)
return a[4] < b[4]
end
local function saveTime(player)
-- Check if you beat your previous best
local m = lb[tostring(gamemap)]
if m == nil then
m = {}
end
for i = 1, #m do
if m[i][1] == player.name then
if m[i][4] > timeFinished then
table.remove(m, i)
S_StartSound(nil, 130)
break
else
-- You suck lol
S_StartSound(nil, 201)
return
end
end
end
print("Saving score")
table.insert(m, {player.name, player.mo.skin, player.mo.color, timeFinished, splits})
table.sort(m, lbComp)
while #m > 5 do
table.remove(m)
end
lb[tostring(gamemap)] = m
local f = assert(io.open(FILENAME, "w"))
if f == nil then
print("Failed to open file for writing: " + FILENAME)
return
end
for k, v in pairs(lb) do
for i = 1, #v do
local s = v[i]
f:write(k, "\t", s[1], "\t", s[2], "\t", s[3], "\t", s[4], "\t", table.concat(s[5], " "), "\n")
end
end
f:close()
end
-- DEBUGGING
--local function saveLeaderboard(player, ...)
-- timeFinished = player.realtime
-- splits = {1000, 2000, 3000}
-- saveTime(player)
--end
--COM_AddCommand("save", saveLeaderboard)
local function regLap(player)
if player.laps > prevLap and timeFinished == 0 then
prevLap = player.laps
table.insert(splits, player.realtime)
showSplit = 5 * TICRATE
end
end
local function captureFinish()
if disable then
return
end
if showSplit > 0 then
showSplit = showSplit - 1
end
for p in players.iterate do
if p.laps >= mapheaderinfo[gamemap].numlaps and timeFinished == 0 then
timeFinished = p.realtime
saveTime(p)
end
regLap(p)
end
end
addHook("ThinkFrame", captureFinish)
local function netvars(net)
lb = net($)
end
addHook("NetVars", netvars)