srb2k-leaderboard/browser.lua

499 lines
9.9 KiB
Lua
Raw Normal View History

local MapRecords
2022-08-29 06:08:53 +02:00
local maps
local mapIndex = 1
2022-08-31 02:18:21 +02:00
local scrollPos = 1
2022-08-29 06:08:53 +02:00
local modes = nil
local mode = 1
2022-08-31 04:33:14 +02:00
local prefMode = nil
local ModeSep
---- Imported functions ----
2022-08-29 06:08:53 +02:00
2022-09-02 23:03:09 +02:00
-- lb_common.lua
local ZoneAct = lb_ZoneAct
local TicsToTime = lb_TicsToTime
2022-11-18 01:35:59 +01:00
local mapChecksum = lb_map_checksum
-- lb_store.lua
local GetMapRecords = lb_get_map_records
2022-09-02 23:03:09 +02:00
-----------------------------
2022-09-01 16:57:01 +02:00
2022-09-04 18:00:02 +02:00
local cv_kartencore
2022-08-29 06:08:53 +02:00
local function mapIndexOffset(n)
return (mapIndex + n + #maps - 1) % #maps + 1
end
2022-08-31 04:33:14 +02:00
local function getMap(offset)
return maps[mapIndexOffset(offset or 0)]
end
local function updateModes()
-- set available modes for this map
modes = {}
for mode, _ in pairs(MapRecords) do
table.insert(modes, mode)
2022-08-31 04:33:14 +02:00
end
table.sort(modes)
2022-08-29 06:08:53 +02:00
mode = 1
2022-08-31 04:33:14 +02:00
-- select pref mode
for i, m in ipairs(modes) do
if m == prefMode then
mode = i
break
end
end
2022-08-29 06:08:53 +02:00
end
2022-08-31 04:33:14 +02:00
local function updateMapIndex(n)
mapIndex = mapIndexOffset(n)
scrollPos = 1
2022-11-18 01:35:59 +01:00
MapRecords = GetMapRecords(maps[mapIndex], mapChecksum(maps[mapIndex]), ModeSep)
2022-08-31 04:33:14 +02:00
updateModes()
2022-08-29 06:08:53 +02:00
end
local scalar = 2
local hlfScrnWdth = 320 / 2
local mappY = 26
local ttlY = mappY + FixedMul(30, FRACUNIT / scalar)
local scoresY = ttlY + 16
2022-09-04 18:00:02 +02:00
local sin = sin
2022-08-29 06:08:53 +02:00
local function drawMapPatch(v, offset)
local scale = FRACUNIT / (abs(offset) + scalar)
local mapName = G_BuildMapName(getMap(offset))
2022-08-31 02:51:55 +02:00
local patchName = mapName.."P"
local mapp = v.patchExists(patchName) and v.cachePatch(patchName) or v.cachePatch("BLANKLVL")
2022-08-29 06:08:53 +02:00
local scaledWidth = FixedMul(mapp.width, scale)
local scaledHeight = FixedMul(mapp.height, scale)
v.drawScaled(
(hlfScrnWdth + offset * scaledWidth - scaledWidth / 2) * FRACUNIT,
(mappY - scaledHeight / 2) * FRACUNIT,
scale,
mapp
)
2022-09-04 18:00:02 +02:00
end
local function drawEncore(v)
if not cv_kartencore then
cv_kartencore = CV_FindVar("kartencore")
end
if not cv_kartencore.value then
return
end
local rubyp = v.cachePatch("RUBYICON")
local bob = sin(leveltime * ANG10) * 2
v.drawScaled(
hlfScrnWdth * FRACUNIT,
mappY * FRACUNIT + bob,
FRACUNIT,
rubyp
)
2022-08-29 06:08:53 +02:00
end
local colors = {
[0] = 0,
[1] = 215
}
local function drawMapBorder(v)
local mapWidth = FixedMul(160, FRACUNIT / scalar)
local mapHeight = FixedMul(100, FRACUNIT / scalar)
v.drawFill(
hlfScrnWdth - mapWidth / 2 - 1,
mappY - mapHeight / 2 -1,
mapWidth + 2,
mapHeight + 2,
colors[leveltime / 4 % 2]
)
end
local function drawMapStrings(v)
local map = mapheaderinfo[getMap()]
local titleWidth = v.stringWidth(map.lvlttl)
-- title
v.drawString(
hlfScrnWdth,
ttlY,
map.lvlttl,
V_SKYMAP,
"center"
)
-- zone/act
2022-09-01 16:57:01 +02:00
local zone = ZoneAct(map)
2022-08-29 06:08:53 +02:00
local zoneWidth = v.stringWidth(zone)
v.drawString(
hlfScrnWdth + titleWidth / 2,
ttlY + 8,
zone,
V_SKYMAP,
"right"
)
-- subtitle
v.drawString(
hlfScrnWdth + titleWidth / 2 - zoneWidth,
ttlY + 8,
map.subttl,
V_MAGENTAMAP,
"small-right"
)
2022-09-02 23:53:42 +02:00
-- hell
if map.menuflags & LF2_HIDEINMENU then
v.drawString(
300,
ttlY + 16,
"HELL",
V_REDMAP,
"right"
)
end
2022-08-29 06:08:53 +02:00
end
local F_SPBATK = 0x1
local F_SPBJUS = 0x2
local F_SPBBIG = 0x4
local F_SPBEXP = 0x8
2022-08-31 00:41:05 +02:00
local F_ENCORE = 0x80
2022-08-29 06:08:53 +02:00
local function drawGamemode(v)
local m = modes[mode] or 0
local modeX = 20
local modeY = scoresY
local scale = FRACUNIT / 2
if m == 0 then
local clockp = v.cachePatch("K_LAPE02")
v.drawScaled(
modeX * FRACUNIT,
modeY * FRACUNIT,
scale,
clockp
)
v.drawString(
modeX,
modeY,
"Time Attack!"
)
elseif m & F_SPBATK then
local scaledHalf = FixedMul(50 * FRACUNIT, scale) / 2
local xoff = 0
if m & F_SPBBIG then
xoff = $ + scaledHalf
end
if m & F_SPBEXP then
xoff = $ + scaledHalf
end
if m & F_SPBBIG then
local growp = v.cachePatch("K_ITGROW")
v.drawScaled(
modeX * FRACUNIT - scaledHalf + xoff,
modeY * FRACUNIT - scaledHalf,
scale,
growp
)
xoff = $ - scaledHalf
end
if m & F_SPBEXP then
2022-09-04 18:32:41 +02:00
local invp = v.cachePatch("K_ITINV"..(leveltime / 3 % 7 + 1))
2022-08-29 06:08:53 +02:00
v.drawScaled(
modeX * FRACUNIT - scaledHalf + xoff,
modeY * FRACUNIT - scaledHalf,
scale,
invp
)
end
local spbp = v.cachePatch("K_ITSPB")
v.drawScaled(
modeX * FRACUNIT - scaledHalf,
modeY * FRACUNIT - scaledHalf,
scale,
spbp
)
v.drawString(
modeX,
modeY,
"SPB Attack!"
)
end
end
2022-08-31 00:41:05 +02:00
local function drawFlags(v, x, y, flags)
local nx = x * FRACUNIT
2022-08-31 02:18:21 +02:00
local ny = y * FRACUNIT + 2 * FRACUNIT
2022-08-31 00:41:05 +02:00
local margin = 4 * FRACUNIT
if flags & F_ENCORE then
local encp = v.cachePatch("RUBYICON")
v.drawScaled(
2022-08-31 02:18:21 +02:00
nx,
ny + 2 * FRACUNIT,
FRACUNIT / 5,
2022-08-31 00:41:05 +02:00
encp
)
nx = $ + margin
end
if flags & F_SPBATK then
2022-08-31 02:18:21 +02:00
local scale = FRACUNIT / 3
2022-08-31 00:41:05 +02:00
local shift = 6 * FRACUNIT
nx = $ - shift
ny = $ - shift
if flags & F_SPBJUS then
local hyup = v.cachePatch("K_ISHYUD")
v.drawScaled(nx, ny, scale, hyup)
nx = $ + margin
end
if flags & F_SPBBIG then
local growp = v.cachePatch("K_ISGROW")
2022-08-31 02:18:21 +02:00
v.drawScaled(nx - FRACUNIT / 2, ny, scale, growp)
2022-08-31 00:41:05 +02:00
nx = $ + margin
end
if flags & F_SPBEXP then
2022-09-04 18:32:41 +02:00
local invp = v.cachePatch("K_ISINV"..(leveltime / 3 % 6 + 1))
2022-08-31 00:41:05 +02:00
v.drawScaled(nx, ny, scale, invp)
2022-08-31 02:18:21 +02:00
nx = $ + margin
2022-08-31 00:41:05 +02:00
end
end
end
2022-09-15 01:06:23 +02:00
local MSK_SPEED = 0xF0
local MSK_WEIGHT = 0xF
2022-08-31 00:41:05 +02:00
local function drawStats(v, x, y, skin, stats)
local s = skins[skin]
2022-09-15 01:06:23 +02:00
if stats
and not (s
and s.kartspeed == (stats & MSK_SPEED) >> 4
and s.kartweight == stats & MSK_WEIGHT
) then
v.drawString(x-2, y-2, (stats & MSK_SPEED) >> 4, V_ALLOWLOWERCASE, "thin")
v.drawString(x + 13, y + 9, stats & MSK_WEIGHT, V_ALLOWLOWERCASE, "thin")
2022-08-31 00:41:05 +02:00
end
end
2022-08-29 06:08:53 +02:00
-- draw in columns
-- pos, facerank, name, time, flags
-- ______________________________________________
-- | 3|[O]|InsertNameHere | 01:02:03 | EXB |
-- ----------------------------------------------
2022-08-31 02:18:21 +02:00
-- defined are widths of each column, x value is calculated below
2022-08-29 06:08:53 +02:00
local column = {
2022-08-31 02:18:21 +02:00
[1] = 18, -- facerank, pos, drawNum is right aligned
[2] = 170, -- name
[3] = 60, -- time
[4] = 0 -- flags
}
do
local w = 32 -- starting offset
local t
for i = 1, #column do
t = column[i]
column[i] = w
w = $ + t
end
end
local colorFlags = {
[0] = V_SKYMAP,
[1] = 0
2022-08-29 06:08:53 +02:00
}
2022-09-06 09:52:51 +02:00
local function drawScore(v, i, pos, score, highlight)
2022-08-29 06:08:53 +02:00
local y = scoresY + i * 18
2022-08-31 02:18:21 +02:00
local textFlag = colorFlags[pos%2]
2022-08-29 06:08:53 +02:00
-- position
2022-08-31 02:18:21 +02:00
v.drawNum(column[1], y, pos)
2022-08-29 06:08:53 +02:00
2022-08-31 02:18:21 +02:00
-- facerank
2022-08-29 06:08:53 +02:00
local skin = skins[score["skin"]]
local facerank = skin and v.cachePatch(skin.facerank) or v.cachePatch("M_NORANK")
v.draw(column[1], y, facerank, 0, v.getColormap("sonic", score["color"]))
2022-08-31 02:18:21 +02:00
2022-09-06 09:52:51 +02:00
-- chili
if highlight then
local chilip = v.cachePatch("K_CHILI"..leveltime/4%8+1)
v.draw(column[1], y, chilip)
textFlag = V_YELLOWMAP
end
2022-08-31 02:18:21 +02:00
-- stats
2022-08-31 00:41:05 +02:00
drawStats(v, column[1], y, score["skin"], score["stat"])
2022-08-31 02:18:21 +02:00
-- name
v.drawString(column[2], y, score["name"], V_ALLOWLOWERCASE | textFlag)
-- time
2022-09-01 16:57:01 +02:00
v.drawString(column[3], y, TicsToTime(score["time"]), textFlag)
2022-08-31 02:18:21 +02:00
-- flags
2022-08-31 00:41:05 +02:00
drawFlags(v, column[4], y, score["flags"])
2022-08-29 06:08:53 +02:00
end
2022-09-06 09:52:51 +02:00
local function drawBrowser(v, player)
if not MapRecords then return end
2022-08-29 06:08:53 +02:00
v.fadeScreen(0xFF00, 16)
-- previous, next maps
for i = 5, 1, -1 do
drawMapPatch(v, -i)
drawMapPatch(v, i)
end
-- draw map border
drawMapBorder(v)
-- current map
drawMapPatch(v, 0)
2022-09-04 18:00:02 +02:00
drawEncore(v)
2022-08-29 06:08:53 +02:00
drawMapStrings(v)
drawGamemode(v)
if not modes then return end
local records = MapRecords[modes[mode]]
if not records then return end
2022-08-29 06:08:53 +02:00
local record_count = #records
scrollPos = max(min(scrollPos, record_count - 3), 1)
local endi = min(scrollPos + 7, record_count)
2022-08-31 02:18:21 +02:00
for i = scrollPos, endi do
drawScore(v, i - scrollPos + 1, i, records[i], records[i].name == player.name)
2022-08-29 06:08:53 +02:00
end
end
rawset(_G, "DrawBrowser", drawBrowser)
local function initBrowser(modeSep)
ModeSep = modeSep
2022-08-31 04:33:14 +02:00
2022-08-29 06:08:53 +02:00
-- set mapIndex to current map
for i, m in ipairs(maps) do
if m == gamemap then
mapIndex = i
break
end
end
-- initialize MapRecords
2022-11-18 01:35:59 +01:00
MapRecords = GetMapRecords(gamemap, mapChecksum(gamemap), ModeSep)
2022-08-31 04:36:31 +02:00
scrollPos = 1
2022-08-31 04:33:14 +02:00
updateModes()
2022-08-29 06:08:53 +02:00
end
rawset(_G, "InitBrowser", initBrowser)
-- initialize maps with racemaps only
local function loadMaps()
maps = {}
2022-09-03 00:12:57 +02:00
local hell = {}
2022-08-29 06:08:53 +02:00
for i = 0, #mapheaderinfo do
local map = mapheaderinfo[i]
if map and map.typeoflevel & TOL_RACE then
2022-09-03 00:12:57 +02:00
if map.menuflags & LF2_HIDEINMENU then
table.insert(hell, i)
else
table.insert(maps, i)
end
2022-08-29 06:08:53 +02:00
end
end
2022-09-03 00:12:57 +02:00
-- append hell maps
for _, map in ipairs(hell) do
table.insert(maps, map)
end
2022-08-29 06:08:53 +02:00
end
addHook("MapLoad", loadMaps)
local repeatCount = 0
local keyRepeat = 0
local function updateKeyRepeat()
S_StartSound(nil, 143)
if repeatCount < 1 then
keyRepeat = TICRATE / 4
else
keyRepeat = TICRATE / 15
end
repeatCount = $ + 1
end
local function resetKeyRepeat()
keyRepeat = 0
repeatCount = 0
end
2022-09-04 18:00:02 +02:00
local ValidButtons = BT_ACCELERATE | BT_BRAKE | BT_FORWARD | BT_BACKWARD | BT_DRIFT | BT_ATTACK
2022-08-29 06:08:53 +02:00
-- return value indicates we want to exit the browser
local function controller(player)
keyRepeat = max(0, $ - 1)
if not (player.cmd.driftturn or player.cmd.buttons) then
resetKeyRepeat()
end
2022-08-31 02:18:21 +02:00
local cmd = player.cmd
2022-08-29 06:08:53 +02:00
if not keyRepeat then
2022-09-04 17:23:32 +02:00
if not (cmd.buttons & ValidButtons or cmd.driftturn) then
return
end
updateKeyRepeat()
if cmd.buttons & BT_BRAKE then
S_StartSound(nil, 115)
return true
elseif cmd.buttons & BT_ACCELERATE then
COM_BufInsertText(player, "changelevel "..G_BuildMapName(maps[mapIndex]))
return true
2022-09-04 18:00:02 +02:00
elseif cmd.buttons & BT_ATTACK then
COM_BufInsertText(player, "encore")
2022-09-04 17:23:32 +02:00
elseif cmd.driftturn then
local dir = cmd.driftturn > 0 and -1 or 1
if encoremode then
updateMapIndex(-dir)
else
updateMapIndex(dir)
end
2022-08-31 02:18:21 +02:00
elseif cmd.buttons & BT_FORWARD then
scrollPos = $ - 1
elseif cmd.buttons & BT_BACKWARD then
scrollPos = $ + 1
elseif cmd.buttons & BT_DRIFT then
2022-08-31 04:33:14 +02:00
scrollPos = 1
2022-09-02 22:49:00 +02:00
if modes and #modes then
2022-08-29 06:08:53 +02:00
mode = $ % #modes + 1
2022-08-31 04:33:14 +02:00
prefMode = modes[mode]
2022-08-29 06:08:53 +02:00
end
end
end
end
rawset(_G, "BrowserController", controller)
local function netvars(net)
maps = net($)
mapIndex = net($)
modes = net($)
mode = net($)
2022-08-31 04:33:14 +02:00
prefMode = net($)
2022-08-31 02:18:21 +02:00
scrollPos = net($)
MapRecords = net($)
2022-10-07 17:16:37 +02:00
ModeSep = net($)
2022-08-29 06:08:53 +02:00
end
addHook("NetVars", netvars)