This commit is contained in:
Not 2022-03-28 13:08:08 +02:00
parent 9cfb1689b3
commit 8f8dd18c6b
1 changed files with 243 additions and 47 deletions

View File

@ -6,37 +6,92 @@ local timeFinished = 0
local disable = true
local prevLap = 0
local splits = {}
local PATCH = {
["FACERANK"]={}
}
local PATCH = nil
local Flags = 0
-- SPB flags with the least significance first
local F_SPBATK = 0x1
local F_SPBJUS = 0x2
local F_SPBBIG = 0x4
local F_SPBEXP = 0x8
local clearcheats = false
local startTime = 6 * TICRATE + (3 * TICRATE / 4)
-- patch caching function
local cachePatches
local function lbID(map, flags)
local id = tostring(map)
if flags & F_SPBATK then
id = id + "S"
end
return id
end
local function score_t(map, name, skin, color, time, splits, flags)
return {
["map"] = map,
["name"] = name,
["skin"] = skin,
["color"] = color,
["time"] = time,
["splits"] = splits,
["flags"] = flags
}
end
-- Read the leaderboard
local f = io.open(FILENAME, "r")
if f then
for l in f:lines() do
-- Leaderboard is stored in the following tab separated format
-- name, skin, color, time, splits, flags
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]] = {}
local flags = 0
if t[7] != nil then
flags = tonumber(t[7])
end
local lbt = lb[lbID(t[1], flags)]
if lbt == nil then
lbt = {}
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})
table.insert(
lbt,
score_t(
t[1],
t[2],
t[3],
t[4],
tonumber(t[5]),
spl,
flags
)
)
lb[lbID(t[1], flags)] = lbt
end
f:close()
else
print("Failed to open file: ", FILENAME)
end
local function initLeaderboard()
local function initLeaderboard(player)
local ingame = 0
for p in players.iterate do
if p.valid and not p.spectator then
@ -55,15 +110,28 @@ addHook("PlayerSpawn", initLeaderboard)
local function retry(player, ...)
if disable or player.spectator then
print("How dare you")
CONS_Printf(player, "How dare you")
return
end
G_SetCustomExitVars(gamemap, 2)
G_ExitLevel()
COM_BufInsertText(server, "map " + G_BuildMapName(gamemap))
end
COM_AddCommand("retry", retry)
local function exitlevel(player, ...)
if disable or player.spectator then
CONS_Printf(player, "How dare you")
return
end
G_ExitLevel()
end
COM_AddCommand("exit", exitlevel)
COM_AddCommand("spba_clearcheats", function(player)
clearcheats = true
CONS_Printf(player, "SPB Attack cheats will be cleared on next round")
end
)
--DEBUGGING
--local function printTable(tb)
@ -71,7 +139,16 @@ COM_AddCommand("retry", retry)
-- 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], ","))
-- print(
-- v[i]["name"],
-- v[i]["skin"],
-- v[i]["color"],
-- v[i]["time"],
-- table.concat(v[i]["splits"]),
-- v[i]["flags"],
-- ","
-- )
--
-- end
-- end
-- end
@ -81,6 +158,7 @@ addHook("MapLoad", function()
timeFinished = 0
splits = {}
prevLap = 0
--printTable(lb)
end
)
@ -93,6 +171,19 @@ local function ticsToTime(tics)
)
end
-- Item patches have the amazing property of being displaced 12x 13y pixels
local iXoffset = 13 * FRACUNIT
local iYoffset = 12 * FRACUNIT
local function drawitem(v, x, y, scale, itempatch, vflags)
v.drawScaled(
x * FRACUNIT - FixedMul(iXoffset, scale),
y * FRACUNIT - FixedMul(iYoffset, scale),
scale,
itempatch,
vflags
)
end
local bodium = {V_YELLOWMAP, V_GRAYMAP, V_BROWNMAP, 0}
local splitColor = {[true]=V_SKYMAP, [false]=V_REDMAP}
local splitSymbol = {[true]="-", [false]="+"}
@ -100,45 +191,74 @@ local splitSymbol = {[true]="-", [false]="+"}
local showSplit = 0
local function drawScoreboard(v, player)
if disable then return end
if player != displayplayers[0] then return end
-- PATCH CACHE
if not PATCH["CHILI"] then
PATCH["CHILI"] = {}
for i = 1, 8 do
PATCH["CHILI"][i-1] = v.cachePatch("K_CHILI" + i)
end
end
for skin in skins.iterate do
if PATCH["FACERANK"][skin.name] then
continue
end
PATCH["FACERANK"][skin.name] = v.cachePatch(skin.facerank)
end
cachePatches(v)
local m = lb[tostring(gamemap)]
local m = lb[lbID(gamemap, Flags)]
if m == nil then
return
end
for i = 1, #m do
local score = m[i]
local name = score[1]
local skin = skins[score[2]]
for i, score in ipairs(m) do
local name = score["name"]
local skin = skins[score["skin"]]
if skin == nil then
skin = skins["sonic"]
end
local skinPatch = PATCH["FACERANK"][skin.name]
-- | OFFSET | + | PADDING | * |INDEX|
-- | OFFSET | + | PADDING | * |INDEX|
local h = ((200 / 4) + 4) + (skinPatch.height + 4) * (i - 1)
v.draw(4, h, skinPatch, V_HUDTRANS, v.getColormap("sonic", score[3]))
v.draw(4, h, skinPatch, V_HUDTRANS, v.getColormap("sonic", score["color"]))
if player.name == name then
v.draw(4, h, PATCH["CHILI"][(leveltime / 4) % 8], V_HUDTRANS)
end
-- SPB
if score["flags"] & F_SPBATK then
local scale = FRACUNIT / 4
drawitem(
v,
4 - 2,
h - 2,
scale,
PATCH["SPB"],
V_HUDTRANS
)
if score["flags"] & F_SPBEXP then
drawitem(
v,
skinPatch.width,
h - 2,
scale,
PATCH["INV"][(leveltime / 4) % 6],
V_HUDTRANS
)
end
if score["flags"] & F_SPBBIG then
drawitem(
v,
4 - 2,
h + skinPatch.height - 4,
scale,
PATCH["BIG"],
V_HUDTRANS
)
end
if score["flags"] & F_SPBJUS then
drawitem(
v,
skinPatch.width,
h + skinPatch.height - 4,
scale,
PATCH["HYUD"],
V_HUDTRANS
)
end
end
-- Shorten long names
local stralign = "left"
local MAXWIDTH = 70
@ -159,30 +279,69 @@ local function drawScoreboard(v, player)
v.drawString(px + skinPatch.width, h + py, name, V_HUDTRANSHALF | V_ALLOWLOWERCASE, stralign)
-- Draw splits
if showSplit > 0 and score[5][prevLap] != nil then
local split = splits[prevLap] - score[5][prevLap]
if showSplit > 0 and score["splits"][prevLap] != nil then
local split = splits[prevLap] - score["splits"][prevLap]
v.drawString(px + skinPatch.width, h + 8, splitSymbol[split < 0] + ticsToTime(abs(split)), V_HUDTRANSHALF | splitColor[split < 0])
else
v.drawString(px + skinPatch.width, h + 8, ticsToTime(score[4]), V_HUDTRANSHALF | bodium[min(i, 4)])
v.drawString(px + skinPatch.width, h + 8, ticsToTime(score["time"]), V_HUDTRANSHALF | bodium[min(i, 4)])
end
end
end
hud.add(drawScoreboard, "game")
function cachePatches(v)
if PATCH == nil then
PATCH = {}
PATCH["CHILI"] = {}
for i = 1, 8 do
PATCH["CHILI"][i-1] = v.cachePatch("K_CHILI" + i)
end
PATCH["FACERANK"] = {}
for skin in skins.iterate do
PATCH["FACERANK"][skin.name] = v.cachePatch(skin.facerank)
end
PATCH["SPB"] = v.cachePatch("K_ISSPB")
PATCH["INV"] = {}
for i = 1, 6 do
PATCH["INV"][i - 1] = v.cachePatch("K_ISINV" + i)
end
PATCH["BIG"] = v.cachePatch("K_ISGROW")
PATCH["HYUD"] = v.cachePatch("K_ISHYUD")
end
end
-- True if a is better than b
local function lbComp(a, b)
return a[4] < b[4]
-- Calculates the difficulty, harder has higher priority
-- if s is positive then a is harder
-- if s is negative then b is harder
-- if s is 0 then compare time
local s = (a["flags"] & (F_SPBEXP | F_SPBBIG)) - (b["flags"] & (F_SPBEXP | F_SPBBIG))
return s > 0 or not(s < 0 or a["time"] > b["time"])
end
local function saveTime(player)
-- Check if you beat your previous best
local m = lb[tostring(gamemap)]
local m = lb[lbID(gamemap, Flags)]
if m == nil then
m = {}
end
local newscore = score_t(
gamemap,
player.name,
player.mo.skin,
player.mo.color,
timeFinished,
splits,
Flags
)
-- Check if you beat your previous best
for i = 1, #m do
if m[i][1] == player.name then
if m[i][4] > timeFinished then
if m[i]["name"] == player.name then
if lbComp(newscore, m[i]) then
table.remove(m, i)
S_StartSound(nil, 130)
break
@ -195,14 +354,17 @@ local function saveTime(player)
end
print("Saving score")
table.insert(m, {player.name, player.mo.skin, player.mo.color, timeFinished, splits})
table.insert(
m,
newscore
)
table.sort(m, lbComp)
while #m > 5 do
table.remove(m)
end
lb[tostring(gamemap)] = m
lb[lbID(gamemap, Flags)] = m
local f = assert(io.open(FILENAME, "w"))
if f == nil then
@ -213,7 +375,15 @@ local function saveTime(player)
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")
f:write(
s["map"], "\t",
s["name"], "\t",
s["skin"], "\t",
s["color"], "\t",
s["time"], "\t",
table.concat(s["splits"], " "), "\t",
s["flags"], "\n"
)
end
end
@ -236,7 +406,7 @@ local function regLap(player)
end
end
local function captureFinish()
local function think()
if disable then
return
end
@ -244,6 +414,32 @@ local function captureFinish()
showSplit = showSplit - 1
end
if leveltime < startTime then
Flags = $ & !(F_SPBATK | F_SPBEXP | F_SPBBIG | F_SPBJUS)
if server.SPBArunning then
Flags = $ | F_SPBATK
if server.SPBAexpert then
Flags = $ | F_SPBEXP
end
if clearcheats then
clearcheats = false
for p in players.iterate do
p.SPBAKARTBIG = false
p.SPBAjustice = false
p.SPBAshutup = false
end
end
for p in players.iterate do
if p.SPBAKARTBIG then
Flags = $ | F_SPBBIG
end
if p.SPBAjustice then
Flags = $ | F_SPBJUS
end
end
end
end
for p in players.iterate do
if p.laps >= mapheaderinfo[gamemap].numlaps and timeFinished == 0 then
timeFinished = p.realtime
@ -252,7 +448,7 @@ local function captureFinish()
regLap(p)
end
end
addHook("ThinkFrame", captureFinish)
addHook("ThinkFrame", think)
local function netvars(net)
lb = net($)