mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-04-06 18:26:36 +00:00
Merge branch 'json-profiles-standings' into 'master'
JSON profiles and replay standings See merge request KartKrew/Kart!1942
This commit is contained in:
commit
2a8705a14d
8 changed files with 661 additions and 385 deletions
|
|
@ -17,7 +17,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
f_finale.c
|
||||
f_wipe.cpp
|
||||
g_build_ticcmd.cpp
|
||||
g_demo.c
|
||||
g_demo.cpp
|
||||
g_game.c
|
||||
g_gamedata.cpp
|
||||
g_input.c
|
||||
|
|
@ -30,7 +30,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
hu_stuff.c
|
||||
i_time.c
|
||||
i_video_common.cpp
|
||||
y_inter.c
|
||||
y_inter.cpp
|
||||
st_stuff.c
|
||||
m_aatree.c
|
||||
m_anigif.c
|
||||
|
|
@ -145,7 +145,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
k_terrain.c
|
||||
k_director.cpp
|
||||
k_follower.c
|
||||
k_profiles.c
|
||||
k_profiles.cpp
|
||||
k_specialstage.c
|
||||
k_roulette.c
|
||||
k_podium.cpp
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@
|
|||
/// \file g_demo.c
|
||||
/// \brief Demo recording and playback
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
#include <tcb/span.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "console.h"
|
||||
#include "d_main.h"
|
||||
|
|
@ -156,6 +162,7 @@ static ticcmd_t oldcmd[MAXPLAYERS];
|
|||
|
||||
// Below consts are only used for demo extrainfo sections
|
||||
#define DW_STANDING 0x00
|
||||
#define DW_STANDING2 0x01
|
||||
|
||||
// For time attack ghosts
|
||||
#define GZT_XYZ 0x01
|
||||
|
|
@ -266,7 +273,7 @@ void G_ReadDemoExtraData(void)
|
|||
break;
|
||||
|
||||
case DXD_PST_LEFT:
|
||||
CL_RemovePlayer(p, 0);
|
||||
CL_RemovePlayer(p, static_cast<kickreason_t>(0));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -353,9 +360,9 @@ void G_ReadDemoExtraData(void)
|
|||
{
|
||||
rng = READUINT32(demobuf.p);
|
||||
|
||||
if (P_GetRandSeed(i) != rng)
|
||||
if (P_GetRandSeed(static_cast<pr_class_t>(i)) != rng)
|
||||
{
|
||||
P_SetRandSeed(i, rng);
|
||||
P_SetRandSeed(static_cast<pr_class_t>(i), rng);
|
||||
|
||||
if (demosynced)
|
||||
CONS_Alert(CONS_WARNING, "Demo playback has desynced (RNG class %d)!\n", i);
|
||||
|
|
@ -433,7 +440,7 @@ void G_WriteDemoExtraData(void)
|
|||
{
|
||||
// Color
|
||||
memset(name, 0, 16);
|
||||
strncpy(name, skincolors[players[i].skincolor].name, 16);
|
||||
strlcpy(name, skincolors[players[i].skincolor].name, 16);
|
||||
M_Memcpy(demobuf.p,name,16);
|
||||
demobuf.p += 16;
|
||||
}
|
||||
|
|
@ -441,7 +448,7 @@ void G_WriteDemoExtraData(void)
|
|||
{
|
||||
// Name
|
||||
memset(name, 0, 16);
|
||||
strncpy(name, player_names[i], 16);
|
||||
strlcpy(name, player_names[i], 16);
|
||||
M_Memcpy(demobuf.p,name,16);
|
||||
demobuf.p += 16;
|
||||
}
|
||||
|
|
@ -452,7 +459,7 @@ void G_WriteDemoExtraData(void)
|
|||
if (players[i].followerskin == -1)
|
||||
strncpy(name, "None", 16);
|
||||
else
|
||||
strncpy(name, followers[players[i].followerskin].name, 16);
|
||||
strlcpy(name, followers[players[i].followerskin].name, 16);
|
||||
M_Memcpy(demobuf.p, name, 16);
|
||||
demobuf.p += 16;
|
||||
|
||||
|
|
@ -463,7 +470,7 @@ void G_WriteDemoExtraData(void)
|
|||
if (Followercolor_cons_t[j].value == players[i].followercolor)
|
||||
break;
|
||||
}
|
||||
strncpy(name, Followercolor_cons_t[j].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match"
|
||||
strlcpy(name, Followercolor_cons_t[j].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match"
|
||||
M_Memcpy(demobuf.p,name,16);
|
||||
demobuf.p += 16;
|
||||
|
||||
|
|
@ -494,7 +501,7 @@ void G_WriteDemoExtraData(void)
|
|||
|
||||
for (i = 0; i < PRNUMSYNCED; i++)
|
||||
{
|
||||
WRITEUINT32(demobuf.p, P_GetRandSeed(i));
|
||||
WRITEUINT32(demobuf.p, P_GetRandSeed(static_cast<pr_class_t>(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -706,7 +713,7 @@ void G_GhostAddHit(INT32 playernum, mobj_t *victim)
|
|||
return;
|
||||
ghostext[playernum].flags |= EZT_HIT;
|
||||
ghostext[playernum].hits++;
|
||||
ghostext[playernum].hitlist = Z_Realloc(ghostext[playernum].hitlist, ghostext[playernum].hits * sizeof(mobj_t *), PU_LEVEL, NULL);
|
||||
ghostext[playernum].hitlist = static_cast<mobj_t**>(Z_Realloc(ghostext[playernum].hitlist, ghostext[playernum].hits * sizeof(mobj_t *), PU_LEVEL, NULL));
|
||||
P_SetTarget(ghostext[playernum].hitlist + (ghostext[playernum].hits-1), victim);
|
||||
}
|
||||
|
||||
|
|
@ -1400,7 +1407,7 @@ readghosttic:
|
|||
}
|
||||
}
|
||||
if (xziptic & EZT_SPRITE)
|
||||
g->mo->sprite = READUINT16(g->p);
|
||||
g->mo->sprite = static_cast<spritenum_t>(READUINT16(g->p));
|
||||
if (xziptic & EZT_ITEMDATA)
|
||||
g->p += 1 + 1 + 4; // itemtype, itemamount, health
|
||||
if (xziptic & EZT_STATDATA)
|
||||
|
|
@ -1467,7 +1474,7 @@ readghosttic:
|
|||
follow->sprite2 = READUINT8(g->p);
|
||||
else
|
||||
follow->sprite2 = 0;
|
||||
follow->sprite = READUINT16(g->p);
|
||||
follow->sprite = static_cast<spritenum_t>(READUINT16(g->p));
|
||||
follow->frame = (READUINT8(g->p)) | (g->mo->frame & FF_TRANSMASK);
|
||||
follow->angle = g->mo->angle;
|
||||
follow->color = READUINT16(g->p);
|
||||
|
|
@ -1582,7 +1589,7 @@ void G_StoreRewindInfo(void)
|
|||
return;
|
||||
timetolog = 8;
|
||||
|
||||
info = Z_Calloc(sizeof(rewindinfo_t), PU_STATIC, NULL);
|
||||
info = static_cast<rewindinfo_t*>(Z_Calloc(sizeof(rewindinfo_t), PU_STATIC, NULL));
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
@ -1907,7 +1914,7 @@ static UINT8 G_CheckDemoExtraFiles(savebuffer_t *info, boolean quick)
|
|||
{
|
||||
if (!toomany)
|
||||
{
|
||||
strlcpy(filename, (char *)info->p, min(P_SaveBufferRemaining(info) + 1, sizeof filename));
|
||||
strlcpy(filename, (char *)info->p, std::min(P_SaveBufferRemaining(info) + 1, sizeof filename));
|
||||
}
|
||||
SKIPSTRINGN(info->p, P_SaveBufferRemaining(info));
|
||||
|
||||
|
|
@ -1981,7 +1988,7 @@ static void G_SaveDemoSkins(UINT8 **pp)
|
|||
{
|
||||
// Skinname, for first attempt at identification.
|
||||
memset(skin, 0, 16);
|
||||
strncpy(skin, skins[i].name, 16);
|
||||
strlcpy(skin, skins[i].name, 16);
|
||||
WRITEMEM((*pp), skin, 16);
|
||||
|
||||
// Backup information for second pass.
|
||||
|
|
@ -2011,7 +2018,7 @@ static democharlist_t *G_LoadDemoSkins(savebuffer_t *info, UINT8 *worknumskins,
|
|||
if (!(*worknumskins))
|
||||
return NULL;
|
||||
|
||||
skinlist = Z_Calloc(sizeof(democharlist_t) * (*worknumskins), PU_STATIC, NULL);
|
||||
skinlist = static_cast<democharlist_t*>(Z_Calloc(sizeof(democharlist_t) * (*worknumskins), PU_STATIC, NULL));
|
||||
if (!skinlist)
|
||||
{
|
||||
I_Error("G_LoadDemoSkins: Insufficient memory to allocate list");
|
||||
|
|
@ -2181,7 +2188,7 @@ void G_BeginRecording(void)
|
|||
|
||||
for (i = 0; i < PRNUMSYNCED; i++)
|
||||
{
|
||||
WRITEUINT32(demobuf.p, P_GetInitSeed(i));
|
||||
WRITEUINT32(demobuf.p, P_GetInitSeed(static_cast<pr_class_t>(i)));
|
||||
}
|
||||
|
||||
// Reserved for extrainfo location from start of file
|
||||
|
|
@ -2232,7 +2239,7 @@ void G_BeginRecording(void)
|
|||
|
||||
// Name
|
||||
memset(name, 0, 16);
|
||||
strncpy(name, player_names[p], 16);
|
||||
strlcpy(name, player_names[p], 16);
|
||||
M_Memcpy(demobuf.p,name,16);
|
||||
demobuf.p += 16;
|
||||
|
||||
|
|
@ -2324,36 +2331,26 @@ void G_BeginRecording(void)
|
|||
}
|
||||
}
|
||||
|
||||
void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT16 color, UINT32 val)
|
||||
void srb2::write_current_demo_standings(const srb2::StandingsJson& standings)
|
||||
{
|
||||
char temp[16];
|
||||
using namespace srb2;
|
||||
using json = nlohmann::json;
|
||||
|
||||
if (demoinfo_p && *(UINT32 *)demoinfo_p == 0)
|
||||
{
|
||||
WRITEUINT8(demobuf.p, DEMOMARKER); // add the demo end marker
|
||||
*(UINT32 *)demoinfo_p = demobuf.p - demobuf.buffer;
|
||||
}
|
||||
// TODO populate standings data
|
||||
|
||||
WRITEUINT8(demobuf.p, DW_STANDING);
|
||||
WRITEUINT8(demobuf.p, ranking);
|
||||
std::vector<uint8_t> ubjson = json::to_ubjson(standings);
|
||||
uint32_t bytes = ubjson.size();
|
||||
|
||||
// Name
|
||||
memset(temp, 0, 16);
|
||||
strncpy(temp, name, 16);
|
||||
M_Memcpy(demobuf.p,temp,16);
|
||||
demobuf.p += 16;
|
||||
WRITEUINT8(demobuf.p, DW_STANDING2);
|
||||
|
||||
// Skin
|
||||
WRITEUINT8(demobuf.p, skinnum);
|
||||
WRITEUINT32(demobuf.p, bytes);
|
||||
WRITEMEM(demobuf.p, ubjson.data(), bytes);
|
||||
}
|
||||
|
||||
// Color
|
||||
memset(temp, 0, 16);
|
||||
strncpy(temp, skincolors[color].name, 16);
|
||||
M_Memcpy(demobuf.p,temp,16);
|
||||
demobuf.p += 16;
|
||||
|
||||
// Score/time/whatever
|
||||
WRITEUINT32(demobuf.p, val);
|
||||
void srb2::write_current_demo_end_marker()
|
||||
{
|
||||
WRITEUINT8(demobuf.p, DEMOMARKER); // add the demo end marker
|
||||
*(UINT32 *)demoinfo_p = demobuf.p - demobuf.buffer;
|
||||
}
|
||||
|
||||
void G_SetDemoTime(UINT32 ptime, UINT32 plap)
|
||||
|
|
@ -2508,6 +2505,52 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
return c;
|
||||
}
|
||||
|
||||
static bool load_ubjson_standing(menudemo_t* pdemo, tcb::span<std::byte> slice, tcb::span<democharlist_t> demoskins)
|
||||
{
|
||||
using namespace srb2;
|
||||
using json = nlohmann::json;
|
||||
|
||||
StandingsJson js;
|
||||
try
|
||||
{
|
||||
js = json::from_ubjson(slice).template get<StandingsJson>();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t toread = std::min<size_t>(js.standings.size(), MAXPLAYERS);
|
||||
for (size_t i = 0; i < toread; i++)
|
||||
{
|
||||
StandingJson& jsstanding = js.standings[i];
|
||||
auto& memstanding = pdemo->standings[i];
|
||||
memstanding.ranking = jsstanding.ranking;
|
||||
strlcpy(memstanding.name, jsstanding.name.c_str(), 17);
|
||||
if (jsstanding.demoskin >= demoskins.size())
|
||||
{
|
||||
memstanding.skin = demoskins[0].mapping;
|
||||
}
|
||||
else
|
||||
{
|
||||
memstanding.skin = demoskins[jsstanding.demoskin].mapping;
|
||||
}
|
||||
memstanding.color = SKINCOLOR_NONE;
|
||||
for (size_t j = 0; j < numskincolors; j++)
|
||||
{
|
||||
skincolor_t& skincolor = skincolors[j];
|
||||
if (jsstanding.skincolor == skincolor.name)
|
||||
{
|
||||
memstanding.color = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
memstanding.timeorscore = jsstanding.timeorscore;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void G_LoadDemoInfo(menudemo_t *pdemo)
|
||||
{
|
||||
savebuffer_t info = {0};
|
||||
|
|
@ -2516,6 +2559,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
UINT16 pdemoflags;
|
||||
democharlist_t *skinlist = NULL;
|
||||
UINT16 pdemoversion, count;
|
||||
UINT16 legacystandingplayercount;
|
||||
char mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
|
||||
INT32 i;
|
||||
|
||||
|
|
@ -2584,7 +2628,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
goto badreplay;
|
||||
}
|
||||
info.p += 4; // "PLAY"
|
||||
READSTRINGN(info.p, mapname, min(P_SaveBufferRemaining(&info), sizeof(mapname)));
|
||||
READSTRINGN(info.p, mapname, std::min(P_SaveBufferRemaining(&info), sizeof(mapname)));
|
||||
pdemo->map = G_MapNumber(mapname);
|
||||
info.p += 16; // mapmd5
|
||||
|
||||
|
|
@ -2602,7 +2646,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
goto badreplay;
|
||||
}
|
||||
|
||||
READSTRINGN(info.p, gtname, min(P_SaveBufferRemaining(&info), sizeof(gtname))); // gametype
|
||||
READSTRINGN(info.p, gtname, std::min(P_SaveBufferRemaining(&info), sizeof(gtname))); // gametype
|
||||
pdemo->gametype = G_GetGametypeByName(gtname);
|
||||
|
||||
if (P_SaveBufferRemaining(&info) < 1)
|
||||
|
|
@ -2668,44 +2712,95 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
pdemo->gp = true;
|
||||
|
||||
// Read standings!
|
||||
count = 0;
|
||||
legacystandingplayercount = 0;
|
||||
|
||||
info.p = extrainfo_p;
|
||||
|
||||
while (P_SaveBufferRemaining(&info) >= 1+1+16+1+16+4 &&
|
||||
READUINT8(info.p) == DW_STANDING) // Assume standings are always first in the extrainfo
|
||||
while (P_SaveBufferRemaining(&info) > 1)
|
||||
{
|
||||
char temp[16];
|
||||
UINT8 extrainfotag = READUINT8(info.p);
|
||||
|
||||
pdemo->standings[count].ranking = READUINT8(info.p);
|
||||
|
||||
// Name
|
||||
M_Memcpy(pdemo->standings[count].name, info.p, 16);
|
||||
info.p += 16;
|
||||
|
||||
// Skin
|
||||
skinid = READUINT8(info.p);
|
||||
if (skinid > worknumskins)
|
||||
skinid = 0;
|
||||
pdemo->standings[count].skin = skinlist[skinid].mapping;
|
||||
|
||||
// Color
|
||||
M_Memcpy(temp,info.p,16);
|
||||
info.p += 16;
|
||||
for (i = 0; i < numskincolors; i++)
|
||||
if (!stricmp(skincolors[i].name,temp)) // SRB2kart
|
||||
switch (extrainfotag)
|
||||
{
|
||||
case DW_STANDING:
|
||||
{
|
||||
pdemo->standings[count].color = i;
|
||||
// This is the only extrainfo tag that is not length prefixed. All others must be.
|
||||
constexpr size_t kLegacyStandingSize = 1+16+1+16+4;
|
||||
if (P_SaveBufferRemaining(&info) < kLegacyStandingSize)
|
||||
{
|
||||
goto corrupt;
|
||||
}
|
||||
if (legacystandingplayercount >= MAXPLAYERS)
|
||||
{
|
||||
info.p += kLegacyStandingSize;
|
||||
break; // switch
|
||||
}
|
||||
char temp[16];
|
||||
|
||||
pdemo->standings[legacystandingplayercount].ranking = READUINT8(info.p);
|
||||
|
||||
// Name
|
||||
M_Memcpy(pdemo->standings[legacystandingplayercount].name, info.p, 16);
|
||||
info.p += 16;
|
||||
|
||||
// Skin
|
||||
skinid = READUINT8(info.p);
|
||||
if (skinid > worknumskins)
|
||||
skinid = 0;
|
||||
pdemo->standings[legacystandingplayercount].skin = skinlist[skinid].mapping;
|
||||
|
||||
// Color
|
||||
M_Memcpy(temp,info.p,16);
|
||||
info.p += 16;
|
||||
for (i = 0; i < numskincolors; i++)
|
||||
if (!stricmp(skincolors[i].name,temp)) // SRB2kart
|
||||
{
|
||||
pdemo->standings[legacystandingplayercount].color = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Score/time/whatever
|
||||
pdemo->standings[legacystandingplayercount].timeorscore = READUINT32(info.p);
|
||||
|
||||
legacystandingplayercount++;
|
||||
break;
|
||||
}
|
||||
|
||||
// Score/time/whatever
|
||||
pdemo->standings[count].timeorscore = READUINT32(info.p);
|
||||
|
||||
count++;
|
||||
|
||||
if (count >= MAXPLAYERS)
|
||||
break; //@TODO still cycle through the rest of these if extra demo data is ever used
|
||||
case DW_STANDING2:
|
||||
{
|
||||
if (P_SaveBufferRemaining(&info) < 4)
|
||||
{
|
||||
goto corrupt;
|
||||
}
|
||||
UINT32 size = READUINT32(info.p);
|
||||
if (P_SaveBufferRemaining(&info) < size)
|
||||
{
|
||||
goto corrupt;
|
||||
}
|
||||
tcb::span<std::byte> slice = tcb::as_writable_bytes(tcb::span(info.p, size));
|
||||
tcb::span<democharlist_t> demoskins {skinlist, worknumskins};
|
||||
info.p += size;
|
||||
if (!load_ubjson_standing(pdemo, slice, demoskins))
|
||||
{
|
||||
goto corrupt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Gracefully ignore other extrainfo tags by skipping their data
|
||||
if (P_SaveBufferRemaining(&info) < 4)
|
||||
{
|
||||
goto corrupt;
|
||||
}
|
||||
UINT32 size = READUINT32(info.p);
|
||||
if (P_SaveBufferRemaining(&info) < size)
|
||||
{
|
||||
goto corrupt;
|
||||
}
|
||||
info.p += size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (P_SaveBufferRemaining(&info) == 0)
|
||||
|
|
@ -2774,7 +2869,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
if (defdemoname == NULL)
|
||||
{
|
||||
demobuf.p = demobuf.buffer;
|
||||
pdemoname = ZZ_Alloc(1); // Easier than adding checks for this everywhere it's freed
|
||||
pdemoname = static_cast<char*>(ZZ_Alloc(1)); // Easier than adding checks for this everywhere it's freed
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2787,7 +2882,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
n--;
|
||||
if (n != defdemoname)
|
||||
n++;
|
||||
pdemoname = ZZ_Alloc(strlen(n)+1);
|
||||
pdemoname = static_cast<char*>(ZZ_Alloc(strlen(n)+1));
|
||||
strcpy(pdemoname,n);
|
||||
|
||||
M_SetPlaybackMenuPointer();
|
||||
|
|
@ -3065,7 +3160,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
grandprixinfo.gp = true;
|
||||
grandprixinfo.gamespeed = READUINT8(demobuf.p);
|
||||
grandprixinfo.masterbots = READUINT8(demobuf.p) != 0;
|
||||
grandprixinfo.eventmode = READUINT8(demobuf.p);
|
||||
grandprixinfo.eventmode = static_cast<gpEvent_e>(READUINT8(demobuf.p));
|
||||
}
|
||||
|
||||
// Sigh ... it's an empty demo.
|
||||
|
|
@ -3236,7 +3331,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
clientpowerlevels[p][gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE] = READUINT16(demobuf.p);
|
||||
|
||||
// Followitem
|
||||
players[p].followitem = READUINT32(demobuf.p);
|
||||
players[p].followitem = static_cast<mobjtype_t>(READUINT32(demobuf.p));
|
||||
|
||||
// GP
|
||||
players[p].lives = READSINT8(demobuf.p);
|
||||
|
|
@ -3262,7 +3357,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
if (demo.attract == DEMO_ATTRACT_TITLE)
|
||||
{
|
||||
splitscreen = M_RandomKey(6)-1;
|
||||
splitscreen = min(min(3, numslots-1), splitscreen); // Bias toward 1p and 4p views
|
||||
splitscreen = std::min<int>(std::min(3, numslots-1), splitscreen); // Bias toward 1p and 4p views
|
||||
|
||||
for (p = 0; p <= splitscreen; p++)
|
||||
G_ResetView(p+1, slots[M_RandomKey(numslots)], false);
|
||||
|
|
@ -3272,7 +3367,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
|
||||
for (i = 0; i < PRNUMSYNCED; i++)
|
||||
{
|
||||
P_SetRandSeed(i, randseed[i]);
|
||||
P_SetRandSeed(static_cast<pr_class_t>(i), randseed[i]);
|
||||
}
|
||||
|
||||
G_InitNew((demoflags & DF_ENCORE) != 0, gamemap, true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer.
|
||||
|
|
@ -3484,7 +3579,7 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
|
|||
}
|
||||
|
||||
|
||||
gh = Z_Calloc(sizeof(demoghost), PU_LEVEL, NULL);
|
||||
gh = static_cast<demoghost*>(Z_Calloc(sizeof(demoghost), PU_LEVEL, NULL));
|
||||
gh->next = ghosts;
|
||||
gh->buffer = buffer->buffer;
|
||||
M_Memcpy(gh->checksum, md5, 16);
|
||||
|
|
@ -3651,7 +3746,7 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
|
|||
|
||||
M_Memcpy(temp.name, p, 16);
|
||||
|
||||
ret = Z_Malloc(sizeof(staffbrief_t), PU_STATIC, NULL);
|
||||
ret = static_cast<staffbrief_t*>(Z_Malloc(sizeof(staffbrief_t), PU_STATIC, NULL));
|
||||
if (ret)
|
||||
M_Memcpy(ret, &temp, sizeof(staffbrief_t));
|
||||
|
||||
|
|
@ -3732,7 +3827,7 @@ static void G_StopTimingDemo(void)
|
|||
if (timedemo_csv)
|
||||
{
|
||||
FILE *f;
|
||||
const char *csvpath = va("%s"PATHSEP"%s", srb2home, "timedemo.csv");
|
||||
const char *csvpath = va("%s" PATHSEP "%s", srb2home, "timedemo.csv");
|
||||
const char *header = "id,demoname,seconds,avgfps,leveltime,demotime,framecount,ticrate,rendermode,vidmode,vidwidth,vidheight,procbits\n";
|
||||
const char *rowformat = "\"%s\",\"%s\",%f,%f,%u,%d,%u,%u,%u,%u,%u,%u,%u\n";
|
||||
boolean headerrow = !FIL_FileExists(csvpath);
|
||||
|
|
@ -3836,7 +3931,7 @@ boolean G_CheckDemoStatus(void)
|
|||
if (!demo.recording)
|
||||
return false;
|
||||
|
||||
if (modeattacking || demo.savemode != DSM_NOTSAVING)
|
||||
if (modeattacking || demo.savemode != demovars_s::DSM_NOTSAVING)
|
||||
{
|
||||
if (demobuf.p)
|
||||
{
|
||||
|
|
@ -3923,13 +4018,13 @@ void G_SaveDemo(void)
|
|||
#endif
|
||||
|
||||
if (FIL_WriteFile(demoname, demobuf.buffer, demobuf.p - demobuf.buffer)) // finally output the file.
|
||||
demo.savemode = DSM_SAVED;
|
||||
demo.savemode = demovars_s::DSM_SAVED;
|
||||
Z_Free(demobuf.buffer);
|
||||
demo.recording = false;
|
||||
|
||||
if (!modeattacking)
|
||||
{
|
||||
if (demo.savemode == DSM_SAVED)
|
||||
if (demo.savemode == demovars_s::DSM_SAVED)
|
||||
{
|
||||
CONS_Printf(M_GetText("Demo %s recorded\n"), demoname);
|
||||
if (gamedata->eversavedreplay == false)
|
||||
|
|
@ -3957,13 +4052,13 @@ boolean G_DemoTitleResponder(event_t *ev)
|
|||
// Only ESC and non-keyboard keys abort connection
|
||||
if (ch == KEY_ESCAPE)
|
||||
{
|
||||
demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING;
|
||||
demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? demovars_s::DSM_WILLAUTOSAVE : demovars_s::DSM_NOTSAVING;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ch == KEY_ENTER || ch >= NUMKEYS)
|
||||
{
|
||||
demo.savemode = DSM_WILLSAVE;
|
||||
demo.savemode = demovars_s::DSM_WILLSAVE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4001,7 +4096,7 @@ boolean G_CheckDemoTitleEntry(void)
|
|||
if (!G_PlayerInputDown(0, gc_b, 0) && !G_PlayerInputDown(0, gc_x, 0))
|
||||
return false;
|
||||
|
||||
demo.savemode = DSM_TITLEENTRY;
|
||||
demo.savemode = demovars_s::DSM_TITLEENTRY;
|
||||
|
||||
return true;
|
||||
}
|
||||
39
src/g_demo.h
39
src/g_demo.h
|
|
@ -19,6 +19,44 @@
|
|||
#include "d_event.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
// Modern json formats
|
||||
namespace srb2
|
||||
{
|
||||
struct StandingJson
|
||||
{
|
||||
uint8_t ranking;
|
||||
std::string name;
|
||||
uint8_t demoskin;
|
||||
std::string skincolor;
|
||||
uint32_t timeorscore;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
StandingJson,
|
||||
ranking,
|
||||
name,
|
||||
demoskin,
|
||||
skincolor,
|
||||
timeorscore
|
||||
)
|
||||
};
|
||||
struct StandingsJson
|
||||
{
|
||||
std::vector<StandingJson> standings;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(StandingsJson, standings)
|
||||
};
|
||||
|
||||
void write_current_demo_standings(const StandingsJson& standings);
|
||||
void write_current_demo_end_marker();
|
||||
|
||||
} // namespace srb2
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
|
@ -105,7 +143,6 @@ void G_RecordDemo(const char *name);
|
|||
void G_BeginRecording(void);
|
||||
|
||||
// Only called by shutdown code.
|
||||
void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT16 color, UINT32 val);
|
||||
void G_SetDemoTime(UINT32 ptime, UINT32 plap);
|
||||
UINT8 G_CmpDemoTime(char *oldname, char *newname);
|
||||
|
||||
|
|
|
|||
|
|
@ -166,3 +166,63 @@ void FileStream::close()
|
|||
|
||||
file_ = nullptr;
|
||||
}
|
||||
|
||||
static int portable_fseek64(FILE* file, int64_t offset, int origin)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _fseeki64(file, offset, origin);
|
||||
#elif __APPLE__
|
||||
return fseeko(file, offset, origin);
|
||||
#else
|
||||
return fseeko64(file, offset, origin);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t portable_ftell64(FILE* file)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _ftelli64(file);
|
||||
#elif __APPLE__
|
||||
return ftello(file);
|
||||
#else
|
||||
return ftello64(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
StreamSize FileStream::seek(SeekFrom seek_from, StreamOffset offset)
|
||||
{
|
||||
if (!file_)
|
||||
{
|
||||
throw std::domain_error("FileStream is empty");
|
||||
}
|
||||
|
||||
int origin;
|
||||
switch (seek_from)
|
||||
{
|
||||
case SeekFrom::kStart:
|
||||
origin = SEEK_SET;
|
||||
break;
|
||||
case SeekFrom::kCurrent:
|
||||
origin = SEEK_CUR;
|
||||
break;
|
||||
case SeekFrom::kEnd:
|
||||
origin = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument("invalid SeekFrom");
|
||||
}
|
||||
|
||||
if (portable_fseek64((FILE*)(file_), offset, origin) != 0)
|
||||
{
|
||||
int err = errno;
|
||||
throw make_exception_from_errno(err);
|
||||
}
|
||||
|
||||
StreamOffset newpos = portable_ftell64((FILE*)(file_));
|
||||
if (newpos < 0)
|
||||
{
|
||||
int err = errno;
|
||||
throw make_exception_from_errno(err);
|
||||
}
|
||||
return newpos;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,9 +183,9 @@ void read(uint16_t& value, I& stream, Endian endian = Endian::kLE) {
|
|||
}
|
||||
|
||||
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
|
||||
uint16_t read_uint16(I& stream) {
|
||||
uint16_t read_uint16(I& stream, Endian endian = Endian::kLE) {
|
||||
uint16_t ret;
|
||||
read(ret, stream);
|
||||
read(ret, stream, endian);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -211,9 +211,9 @@ void read(int16_t& value, I& stream, Endian endian = Endian::kLE) {
|
|||
}
|
||||
|
||||
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
|
||||
int16_t read_int16(I& stream) {
|
||||
int16_t read_int16(I& stream, Endian endian = Endian::kLE) {
|
||||
int16_t ret;
|
||||
read(ret, stream);
|
||||
read(ret, stream, endian);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -235,9 +235,9 @@ void read(uint32_t& value, I& stream, Endian endian = Endian::kLE) {
|
|||
}
|
||||
|
||||
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
|
||||
uint32_t read_uint32(I& stream) {
|
||||
uint32_t read_uint32(I& stream, Endian endian = Endian::kLE) {
|
||||
uint32_t ret;
|
||||
read(ret, stream);
|
||||
read(ret, stream, endian);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -267,9 +267,9 @@ void read(int32_t& value, I& stream, Endian endian = Endian::kLE) {
|
|||
}
|
||||
|
||||
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
|
||||
int32_t read_int32(I& stream) {
|
||||
int32_t read_int32(I& stream, Endian endian = Endian::kLE) {
|
||||
int32_t ret;
|
||||
read(ret, stream);
|
||||
read(ret, stream, endian);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -295,9 +295,9 @@ void read(uint64_t& value, I& stream, Endian endian = Endian::kLE) {
|
|||
}
|
||||
|
||||
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
|
||||
uint64_t read_uint64(I& stream) {
|
||||
uint64_t read_uint64(I& stream, Endian endian = Endian::kLE) {
|
||||
uint64_t ret;
|
||||
read(ret, stream);
|
||||
read(ret, stream, endian);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -335,9 +335,9 @@ void read(int64_t& value, I& stream, Endian endian = Endian::kLE) {
|
|||
}
|
||||
|
||||
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
|
||||
int64_t read_int64(I& stream) {
|
||||
int64_t read_int64(I& stream, Endian endian = Endian::kLE) {
|
||||
int64_t ret;
|
||||
read(ret, stream);
|
||||
read(ret, stream, endian);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -354,9 +354,9 @@ void read(float& value, I& stream, Endian endian = Endian::kLE) {
|
|||
}
|
||||
|
||||
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
|
||||
float read_float(I& stream) {
|
||||
float read_float(I& stream, Endian endian = Endian::kLE) {
|
||||
float ret;
|
||||
read(ret, stream);
|
||||
read(ret, stream, endian);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -373,9 +373,9 @@ void read(double& value, I& stream, Endian endian = Endian::kLE) {
|
|||
}
|
||||
|
||||
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
|
||||
double read_double(I& stream) {
|
||||
double read_double(I& stream, Endian endian = Endian::kLE) {
|
||||
double ret;
|
||||
read(ret, stream);
|
||||
read(ret, stream, endian);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -616,9 +616,7 @@ public:
|
|||
|
||||
StreamSize read(tcb::span<std::byte> buffer);
|
||||
StreamSize write(tcb::span<const std::byte> buffer);
|
||||
|
||||
// not bothering with seeking for now -- apparently 64-bit file positions is not available in ansi c
|
||||
// StreamSize seek(SeekFrom seek_from, StreamOffset offset);
|
||||
StreamSize seek(SeekFrom seek_from, StreamOffset offset);
|
||||
|
||||
void close();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@
|
|||
/// \file k_profiles.c
|
||||
/// \brief implements methods for profiles etc.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "io/streams.hpp"
|
||||
#include "doomtype.h"
|
||||
#include "d_main.h" // pandf
|
||||
#include "byteptr.h" // READ/WRITE macros
|
||||
|
|
@ -34,11 +39,11 @@ INT32 PR_GetNumProfiles(void)
|
|||
return numprofiles;
|
||||
}
|
||||
|
||||
static void PR_GenerateProfileKeys(profile_t *new)
|
||||
static void PR_GenerateProfileKeys(profile_t *newprofile)
|
||||
{
|
||||
static uint8_t seed[32];
|
||||
csprng(seed, 32);
|
||||
crypto_eddsa_key_pair(new->secret_key, new->public_key, seed);
|
||||
crypto_eddsa_key_pair(newprofile->secret_key, newprofile->public_key, seed);
|
||||
}
|
||||
|
||||
profile_t* PR_MakeProfile(
|
||||
|
|
@ -49,52 +54,52 @@ profile_t* PR_MakeProfile(
|
|||
INT32 controlarray[num_gamecontrols][MAXINPUTMAPPING],
|
||||
boolean guest)
|
||||
{
|
||||
profile_t *new = Z_Calloc(sizeof(profile_t), PU_STATIC, NULL);
|
||||
profile_t *newprofile = static_cast<profile_t*>(Z_Calloc(sizeof(profile_t), PU_STATIC, NULL));
|
||||
|
||||
new->version = PROFILEVER;
|
||||
newprofile->version = PROFILEVER;
|
||||
|
||||
memset(new->secret_key, 0, sizeof(new->secret_key));
|
||||
memset(new->public_key, 0, sizeof(new->public_key));
|
||||
memset(newprofile->secret_key, 0, sizeof(newprofile->secret_key));
|
||||
memset(newprofile->public_key, 0, sizeof(newprofile->public_key));
|
||||
|
||||
if (!guest)
|
||||
{
|
||||
PR_GenerateProfileKeys(new);
|
||||
PR_GenerateProfileKeys(newprofile);
|
||||
}
|
||||
|
||||
strcpy(new->profilename, prname);
|
||||
new->profilename[sizeof new->profilename - 1] = '\0';
|
||||
strcpy(newprofile->profilename, prname);
|
||||
newprofile->profilename[sizeof newprofile->profilename - 1] = '\0';
|
||||
|
||||
strcpy(new->skinname, sname);
|
||||
strcpy(new->playername, pname);
|
||||
new->color = col;
|
||||
strcpy(newprofile->skinname, sname);
|
||||
strcpy(newprofile->playername, pname);
|
||||
newprofile->color = col;
|
||||
|
||||
strcpy(new->follower, fname);
|
||||
new->followercolor = fcol;
|
||||
new->kickstartaccel = false;
|
||||
new->autoroulette = false;
|
||||
new->litesteer = true;
|
||||
new->rumble = true;
|
||||
strcpy(newprofile->follower, fname);
|
||||
newprofile->followercolor = fcol;
|
||||
newprofile->kickstartaccel = false;
|
||||
newprofile->autoroulette = false;
|
||||
newprofile->litesteer = true;
|
||||
newprofile->rumble = true;
|
||||
|
||||
// Copy from gamecontrol directly as we'll be setting controls up directly in the profile.
|
||||
memcpy(new->controls, controlarray, sizeof(new->controls));
|
||||
memcpy(newprofile->controls, controlarray, sizeof(newprofile->controls));
|
||||
|
||||
new->wins = 0;
|
||||
newprofile->wins = 0;
|
||||
|
||||
return new;
|
||||
return newprofile;
|
||||
}
|
||||
|
||||
profile_t* PR_MakeProfileFromPlayer(const char *prname, const char *pname, const char *sname, const UINT16 col, const char *fname, UINT16 fcol, UINT8 pnum)
|
||||
{
|
||||
// Generate profile using the player's gamecontrol, as we set them directly when making profiles from menus.
|
||||
profile_t *new = PR_MakeProfile(prname, pname, sname, col, fname, fcol, gamecontrol[pnum], false);
|
||||
profile_t *newprofile = PR_MakeProfile(prname, pname, sname, col, fname, fcol, gamecontrol[pnum], false);
|
||||
|
||||
// Player bound cvars:
|
||||
new->kickstartaccel = cv_kickstartaccel[pnum].value;
|
||||
new->autoroulette = cv_autoroulette[pnum].value;
|
||||
new->litesteer = cv_litesteer[pnum].value;
|
||||
new->rumble = cv_rumble[pnum].value;
|
||||
newprofile->kickstartaccel = cv_kickstartaccel[pnum].value;
|
||||
newprofile->autoroulette = cv_autoroulette[pnum].value;
|
||||
newprofile->litesteer = cv_litesteer[pnum].value;
|
||||
newprofile->rumble = cv_rumble[pnum].value;
|
||||
|
||||
return new;
|
||||
return newprofile;
|
||||
}
|
||||
|
||||
boolean PR_AddProfile(profile_t *p)
|
||||
|
|
@ -236,10 +241,10 @@ void PR_InitNewProfile(void)
|
|||
|
||||
void PR_SaveProfiles(void)
|
||||
{
|
||||
size_t length = 0;
|
||||
const size_t headerlen = strlen(PROFILEHEADER);
|
||||
UINT8 i, j, k;
|
||||
savebuffer_t save = {0};
|
||||
namespace fs = std::filesystem;
|
||||
using json = nlohmann::json;
|
||||
using namespace srb2;
|
||||
namespace io = srb2::io;
|
||||
|
||||
if (profilesList[PROFILE_GUEST] == NULL)
|
||||
{
|
||||
|
|
@ -247,65 +252,94 @@ void PR_SaveProfiles(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (P_SaveBufferAlloc(&save, sizeof(UINT32) + (numprofiles * sizeof(profile_t))) == false)
|
||||
ProfilesJson ng{};
|
||||
|
||||
for (size_t i = 1; i < numprofiles; i++)
|
||||
{
|
||||
I_Error("No more free memory for saving profiles\n");
|
||||
return;
|
||||
}
|
||||
ProfileJson jsonprof;
|
||||
profile_t* cprof = profilesList[i];
|
||||
|
||||
// Add header.
|
||||
WRITESTRINGN(save.p, PROFILEHEADER, headerlen);
|
||||
WRITEUINT8(save.p, PROFILEVER);
|
||||
WRITEUINT8(save.p, numprofiles);
|
||||
|
||||
for (i = 1; i < numprofiles; i++)
|
||||
{
|
||||
// Names and keys, all the string data up front
|
||||
WRITESTRINGN(save.p, profilesList[i]->profilename, PROFILENAMELEN);
|
||||
WRITEMEM(save.p, profilesList[i]->public_key, sizeof(((profile_t *)0)->public_key));
|
||||
WRITEMEM(save.p, profilesList[i]->secret_key, sizeof(((profile_t *)0)->secret_key));
|
||||
WRITESTRINGN(save.p, profilesList[i]->playername, MAXPLAYERNAME);
|
||||
|
||||
// Character and colour.
|
||||
WRITESTRINGN(save.p, profilesList[i]->skinname, SKINNAMESIZE);
|
||||
WRITEUINT16(save.p, profilesList[i]->color);
|
||||
|
||||
// Follower and colour.
|
||||
WRITESTRINGN(save.p, profilesList[i]->follower, SKINNAMESIZE);
|
||||
WRITEUINT16(save.p, profilesList[i]->followercolor);
|
||||
|
||||
WRITEUINT32(save.p, profilesList[i]->wins);
|
||||
|
||||
// Consvars.
|
||||
WRITEUINT8(save.p, profilesList[i]->kickstartaccel);
|
||||
WRITEUINT8(save.p, profilesList[i]->autoroulette);
|
||||
WRITEUINT8(save.p, profilesList[i]->litesteer);
|
||||
WRITEUINT8(save.p, profilesList[i]->rumble);
|
||||
|
||||
// Controls.
|
||||
for (j = 0; j < num_gamecontrols; j++)
|
||||
jsonprof.version = PROFILEVER;
|
||||
jsonprof.profilename = std::string(cprof->profilename);
|
||||
std::copy(std::begin(cprof->public_key), std::end(cprof->public_key), std::begin(jsonprof.publickey));
|
||||
std::copy(std::begin(cprof->secret_key), std::end(cprof->secret_key), std::begin(jsonprof.secretkey));
|
||||
jsonprof.playername = std::string(cprof->playername);
|
||||
jsonprof.skinname = std::string(cprof->skinname);
|
||||
jsonprof.colorname = std::string(skincolors[cprof->color].name);
|
||||
jsonprof.followername = std::string(cprof->follower);
|
||||
if (cprof->followercolor == FOLLOWERCOLOR_MATCH)
|
||||
{
|
||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
||||
jsonprof.followercolorname = "Match";
|
||||
}
|
||||
else if (cprof->followercolor == FOLLOWERCOLOR_OPPOSITE)
|
||||
{
|
||||
jsonprof.followercolorname = "Opposite";
|
||||
}
|
||||
else if (cprof->followercolor == SKINCOLOR_NONE)
|
||||
{
|
||||
jsonprof.followercolorname = "Default";
|
||||
}
|
||||
else if (cprof->followercolor >= numskincolors)
|
||||
{
|
||||
jsonprof.followercolorname = std::string();
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonprof.followercolorname = std::string(skincolors[cprof->followercolor].name);
|
||||
}
|
||||
jsonprof.records.wins = cprof->wins;
|
||||
jsonprof.preferences.kickstartaccel = cprof->kickstartaccel;
|
||||
jsonprof.preferences.autoroulette = cprof->autoroulette;
|
||||
jsonprof.preferences.litesteer = cprof->litesteer;
|
||||
jsonprof.preferences.rumble = cprof->rumble;
|
||||
|
||||
for (size_t j = 0; j < num_gamecontrols; j++)
|
||||
{
|
||||
for (size_t k = 0; k < MAXINPUTMAPPING; k++)
|
||||
{
|
||||
WRITEINT32(save.p, profilesList[i]->controls[j][k]);
|
||||
jsonprof.controls[j][k] = cprof->controls[j][k];
|
||||
}
|
||||
}
|
||||
|
||||
ng.profiles.emplace_back(std::move(jsonprof));
|
||||
}
|
||||
|
||||
length = save.p - save.buffer;
|
||||
std::vector<uint8_t> ubjson = json::to_ubjson(ng);
|
||||
|
||||
if (!FIL_WriteFile(va(pandf, srb2home, PROFILESFILE), save.buffer, length))
|
||||
std::string realpath = fmt::format("{}/{}", srb2home, PROFILESFILE);
|
||||
std::string tmppath = fmt::format("{}.tmp", realpath);
|
||||
|
||||
try
|
||||
{
|
||||
io::FileStream file {tmppath, io::FileStreamMode::kWrite};
|
||||
io::BufferedOutputStream<io::FileStream> bos {std::move(file)};
|
||||
|
||||
io::write(static_cast<uint32_t>(0x52494E47), bos, io::Endian::kBE); // "RING"
|
||||
io::write(static_cast<uint32_t>(0x5052464C), bos, io::Endian::kBE); // "PRFL"
|
||||
io::write(static_cast<uint8_t>(0), bos); // reserved1
|
||||
io::write(static_cast<uint8_t>(0), bos); // reserved2
|
||||
io::write(static_cast<uint8_t>(0), bos); // reserved3
|
||||
io::write(static_cast<uint8_t>(0), bos); // reserved4
|
||||
io::write_exact(bos, tcb::as_bytes(tcb::make_span(ubjson)));
|
||||
bos.flush();
|
||||
file = bos.stream();
|
||||
file.close();
|
||||
|
||||
fs::rename(tmppath, realpath);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
P_SaveBufferFree(&save);
|
||||
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?");
|
||||
}
|
||||
P_SaveBufferFree(&save);
|
||||
}
|
||||
|
||||
void PR_LoadProfiles(void)
|
||||
{
|
||||
const size_t headerlen = strlen(PROFILEHEADER);
|
||||
UINT8 i, j, k, version;
|
||||
namespace fs = std::filesystem;
|
||||
using namespace srb2;
|
||||
namespace io = srb2::io;
|
||||
using json = nlohmann::json;
|
||||
|
||||
profile_t *dprofile = PR_MakeProfile(
|
||||
PROFILEDEFAULTNAME,
|
||||
PROFILEDEFAULTPNAME,
|
||||
|
|
@ -314,166 +348,132 @@ void PR_LoadProfiles(void)
|
|||
gamecontroldefault,
|
||||
true
|
||||
);
|
||||
savebuffer_t save = {0};
|
||||
|
||||
if (P_SaveBufferFromFile(&save, va(pandf, srb2home, PROFILESFILE)) == false)
|
||||
std::string datapath {fmt::format("{}/{}", srb2home, PROFILESFILE)};
|
||||
|
||||
io::BufferedInputStream<io::FileStream> bis;
|
||||
try
|
||||
{
|
||||
io::FileStream file {datapath, io::FileStreamMode::kRead};
|
||||
bis = io::BufferedInputStream(std::move(file));
|
||||
}
|
||||
catch (const io::FileStreamException& ex)
|
||||
{
|
||||
// No profiles. Add the default one.
|
||||
PR_AddProfile(dprofile);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp(PROFILEHEADER, (const char *)save.buffer, headerlen))
|
||||
ProfilesJson js;
|
||||
try
|
||||
{
|
||||
const char *gdfolder = "the Ring Racers folder";
|
||||
if (strcmp(srb2home,"."))
|
||||
gdfolder = srb2home;
|
||||
uint32_t magic1;
|
||||
uint32_t magic2;
|
||||
uint8_t reserved1;
|
||||
uint8_t reserved2;
|
||||
uint8_t reserved3;
|
||||
uint8_t reserved4;
|
||||
magic1 = io::read_uint32(bis, io::Endian::kBE);
|
||||
magic2 = io::read_uint32(bis, io::Endian::kBE);
|
||||
reserved1 = io::read_uint8(bis);
|
||||
reserved2 = io::read_uint8(bis);
|
||||
reserved3 = io::read_uint8(bis);
|
||||
reserved4 = io::read_uint8(bis);
|
||||
|
||||
P_SaveBufferFree(&save);
|
||||
I_Error("Not a valid Profile file.\nDelete %s (maybe in %s) and try again.", PROFILESFILE, gdfolder);
|
||||
}
|
||||
save.p += headerlen;
|
||||
if (magic1 != 0x52494E47 || magic2 != 0x5052464C || reserved1 != 0 || reserved2 != 0 || reserved3 != 0 || reserved4 != 0)
|
||||
{
|
||||
throw std::domain_error("Header is incompatible");
|
||||
}
|
||||
|
||||
version = READUINT8(save.p);
|
||||
if (version > PROFILEVER)
|
||||
{
|
||||
P_SaveBufferFree(&save);
|
||||
I_Error("Existing %s is from the future! (expected %d, got %d)", PROFILESFILE, PROFILEVER, version);
|
||||
std::vector<std::byte> remainder = io::read_to_vec(bis);
|
||||
// safety: std::byte repr is always uint8_t 1-byte aligned
|
||||
tcb::span<uint8_t> remainder_as_u8 = tcb::span((uint8_t*)remainder.data(), remainder.size());
|
||||
json parsed = json::from_ubjson(remainder_as_u8);
|
||||
js = parsed.template get<ProfilesJson>();
|
||||
}
|
||||
else if (version < PROFILEVER)
|
||||
catch (...)
|
||||
{
|
||||
// We're converting - let'd create a backup.
|
||||
FIL_WriteFile(va("%s" PATHSEP "%s.bak", srb2home, PROFILESFILE), save.buffer, save.size);
|
||||
I_Error("Profiles file is corrupt");
|
||||
return;
|
||||
}
|
||||
|
||||
numprofiles = READUINT8(save.p);
|
||||
if (numprofiles > MAXPROFILES)
|
||||
numprofiles = MAXPROFILES;
|
||||
|
||||
for (i = 1; i < numprofiles; i++)
|
||||
numprofiles = js.profiles.size() + 1; // 1 for guest
|
||||
if (numprofiles > MAXPROFILES+1)
|
||||
{
|
||||
profilesList[i] = Z_Calloc(sizeof(profile_t), PU_STATIC, NULL);
|
||||
numprofiles = MAXPROFILES+1;
|
||||
}
|
||||
|
||||
// Version. (We always update this on successful forward step)
|
||||
profilesList[i]->version = PROFILEVER;
|
||||
for (size_t i = 1; i < numprofiles; i++)
|
||||
{
|
||||
auto& jsprof = js.profiles[i - 1];
|
||||
profile_t* newprof = static_cast<profile_t*>(Z_Calloc(sizeof(profile_t), PU_STATIC, NULL));
|
||||
profilesList[i] = newprof;
|
||||
|
||||
// Names and keys, all the identity stuff up front
|
||||
READSTRINGN(save.p, profilesList[i]->profilename, PROFILENAMELEN);
|
||||
newprof->version = jsprof.version;
|
||||
strlcpy(newprof->profilename, jsprof.profilename.c_str(), sizeof(newprof->profilename));
|
||||
memcpy(newprof->public_key, jsprof.publickey.data(), sizeof(newprof->public_key));
|
||||
memcpy(newprof->secret_key, jsprof.secretkey.data(), sizeof(newprof->secret_key));
|
||||
|
||||
// Profile update 2-->3: Add profile keys.
|
||||
if (version < 3)
|
||||
strlcpy(newprof->playername, jsprof.playername.c_str(), sizeof(newprof->playername));
|
||||
strlcpy(newprof->skinname, jsprof.skinname.c_str(), sizeof(newprof->skinname));
|
||||
newprof->color = PROFILEDEFAULTCOLOR;
|
||||
for (size_t c = 0; c < numskincolors; c++)
|
||||
{
|
||||
// Generate missing keys.
|
||||
PR_GenerateProfileKeys(profilesList[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
READMEM(save.p, profilesList[i]->public_key, sizeof(((profile_t *)0)->public_key));
|
||||
READMEM(save.p, profilesList[i]->secret_key, sizeof(((profile_t *)0)->secret_key));
|
||||
}
|
||||
|
||||
READSTRINGN(save.p, profilesList[i]->playername, MAXPLAYERNAME);
|
||||
|
||||
// Character and colour.
|
||||
READSTRINGN(save.p, profilesList[i]->skinname, SKINNAMESIZE);
|
||||
profilesList[i]->color = READUINT16(save.p);
|
||||
|
||||
if (profilesList[i]->color == SKINCOLOR_NONE)
|
||||
{
|
||||
; // Valid, even outside the bounds
|
||||
}
|
||||
else if (profilesList[i]->color >= numskincolors
|
||||
|| K_ColorUsable(profilesList[i]->color, false, false) == false)
|
||||
{
|
||||
profilesList[i]->color = PROFILEDEFAULTCOLOR;
|
||||
}
|
||||
|
||||
// Follower and colour.
|
||||
READSTRINGN(save.p, profilesList[i]->follower, SKINNAMESIZE);
|
||||
profilesList[i]->followercolor = READUINT16(save.p);
|
||||
|
||||
if (profilesList[i]->followercolor == FOLLOWERCOLOR_MATCH
|
||||
|| profilesList[i]->followercolor == FOLLOWERCOLOR_OPPOSITE
|
||||
|| profilesList[i]->followercolor == SKINCOLOR_NONE)
|
||||
{
|
||||
; // Valid, even outside the bounds
|
||||
}
|
||||
else if (profilesList[i]->followercolor >= numskincolors
|
||||
|| K_ColorUsable(profilesList[i]->followercolor, true, false) == false)
|
||||
{
|
||||
profilesList[i]->followercolor = PROFILEDEFAULTFOLLOWERCOLOR;
|
||||
}
|
||||
|
||||
// Profile update 5-->6: PWR isn't in profile data anymore.
|
||||
if (version < 6)
|
||||
{
|
||||
save.p += PWRLV_NUMTYPES*2;
|
||||
profilesList[i]->wins = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
profilesList[i]->wins = READUINT32(save.p);
|
||||
}
|
||||
|
||||
// Consvars.
|
||||
profilesList[i]->kickstartaccel = (boolean)READUINT8(save.p);
|
||||
|
||||
// 6->7, add autoroulette
|
||||
if (version < 7)
|
||||
{
|
||||
profilesList[i]->autoroulette = false;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
profilesList[i]->autoroulette = (boolean)READUINT8(save.p);
|
||||
}
|
||||
|
||||
// 7->8, add litesteer
|
||||
if (version < 8)
|
||||
{
|
||||
profilesList[i]->litesteer = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
profilesList[i]->litesteer = (boolean)READUINT8(save.p);
|
||||
}
|
||||
|
||||
if (version < 4)
|
||||
{
|
||||
profilesList[i]->rumble = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
profilesList[i]->rumble = (boolean)READUINT8(save.p);
|
||||
}
|
||||
|
||||
// Controls.
|
||||
for (j = 0; j < num_gamecontrols; j++)
|
||||
{
|
||||
#ifdef DEVELOP
|
||||
// Profile update 1-->2: Add gc_rankings.
|
||||
// Profile update 4-->5: Add gc_startlossless.
|
||||
if ((j == gc_rankings && version < 2) ||
|
||||
(j == gc_startlossless && version < 5))
|
||||
if (jsprof.colorname == skincolors[c].name && K_ColorUsable(static_cast<skincolornum_t>(c), false, false))
|
||||
{
|
||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
||||
newprof->color = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strlcpy(newprof->follower, jsprof.followername.c_str(), sizeof(newprof->follower));
|
||||
newprof->followercolor = PROFILEDEFAULTFOLLOWERCOLOR;
|
||||
if (jsprof.followercolorname == "Match")
|
||||
{
|
||||
newprof->followercolor = FOLLOWERCOLOR_MATCH;
|
||||
}
|
||||
else if (jsprof.followercolorname == "Opposite")
|
||||
{
|
||||
newprof->followercolor = FOLLOWERCOLOR_OPPOSITE;
|
||||
}
|
||||
else if (jsprof.followercolorname == "Default")
|
||||
{
|
||||
newprof->followercolor = SKINCOLOR_NONE;
|
||||
}
|
||||
else if (!jsprof.followercolorname.empty())
|
||||
{
|
||||
for (size_t c = 0; c < numskincolors; c++)
|
||||
{
|
||||
if (jsprof.followercolorname == skincolors[c].name && K_ColorUsable(static_cast<skincolornum_t>(c), false, false))
|
||||
{
|
||||
profilesList[i]->controls[j][k] = gamecontroldefault[j][k];
|
||||
newprof->followercolor = c;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
||||
newprof->wins = jsprof.records.wins;
|
||||
newprof->kickstartaccel = jsprof.preferences.kickstartaccel;
|
||||
newprof->autoroulette = jsprof.preferences.autoroulette;
|
||||
newprof->litesteer = jsprof.preferences.litesteer;
|
||||
newprof->rumble = jsprof.preferences.rumble;
|
||||
|
||||
try
|
||||
{
|
||||
for (size_t j = 0; j < num_gamecontrols; j++)
|
||||
{
|
||||
profilesList[i]->controls[j][k] = READINT32(save.p);
|
||||
for (size_t k = 0; k < MAXINPUTMAPPING; k++)
|
||||
{
|
||||
newprof->controls[j][k] = jsprof.controls.at(j).at(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::out_of_range& ex)
|
||||
{
|
||||
I_Error("Profile '%s' controls are corrupt", jsprof.playername.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the the default profile directly to avoid letting anyone tamper with it.
|
||||
profilesList[PROFILE_GUEST] = dprofile;
|
||||
}
|
||||
|
||||
|
|
@ -638,7 +638,7 @@ char *GetPrettyRRID(const unsigned char *bin, boolean brief)
|
|||
rrid_buf[i*2] = "0123456789ABCDEF"[bin[i] >> 4];
|
||||
rrid_buf[i*2+1] = "0123456789ABCDEF"[bin[i] & 0x0F];
|
||||
}
|
||||
|
||||
|
||||
rrid_buf[len*2] = '\0';
|
||||
|
||||
return rrid_buf;
|
||||
|
|
@ -23,6 +23,82 @@
|
|||
#include "k_follower.h" // followers
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace srb2
|
||||
{
|
||||
|
||||
struct ProfileRecordsJson
|
||||
{
|
||||
uint32_t wins;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfileRecordsJson, wins)
|
||||
};
|
||||
|
||||
struct ProfilePreferencesJson
|
||||
{
|
||||
bool kickstartaccel;
|
||||
bool autoroulette;
|
||||
bool litesteer;
|
||||
bool rumble;
|
||||
tm test;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
ProfilePreferencesJson,
|
||||
kickstartaccel,
|
||||
autoroulette,
|
||||
litesteer,
|
||||
rumble
|
||||
)
|
||||
};
|
||||
|
||||
struct ProfileJson
|
||||
{
|
||||
uint32_t version;
|
||||
std::string profilename;
|
||||
std::string playername;
|
||||
std::array<uint8_t, 32> publickey = {{}};
|
||||
std::array<uint8_t, 64> secretkey = {{}};
|
||||
std::string skinname;
|
||||
std::string colorname;
|
||||
std::string followername;
|
||||
std::string followercolorname;
|
||||
ProfileRecordsJson records;
|
||||
ProfilePreferencesJson preferences;
|
||||
std::array<std::array<int32_t, MAXINPUTMAPPING>, gamecontrols_e::num_gamecontrols> controls = {{{{}}}};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
ProfileJson,
|
||||
version,
|
||||
profilename,
|
||||
playername,
|
||||
publickey,
|
||||
secretkey,
|
||||
skinname,
|
||||
colorname,
|
||||
followername,
|
||||
followercolorname,
|
||||
records,
|
||||
preferences,
|
||||
controls
|
||||
)
|
||||
};
|
||||
|
||||
struct ProfilesJson
|
||||
{
|
||||
std::vector<ProfileJson> profiles;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfilesJson, profiles)
|
||||
};
|
||||
|
||||
} // namespace srb2
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
|
@ -31,7 +107,7 @@ extern "C" {
|
|||
#define SKINNAMESIZE 16
|
||||
|
||||
#define PROFILENAMELEN 6
|
||||
#define PROFILEVER 8
|
||||
#define PROFILEVER 1
|
||||
#define MAXPROFILES 16
|
||||
#define PROFILESFILE "ringprofiles.prf"
|
||||
#define PROFILE_GUEST 0
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
/// \file y_inter.c
|
||||
/// \brief Tally screens, or "Intermissions" as they were formally called in Doom
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_main.h"
|
||||
|
|
@ -194,6 +196,8 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
|||
|
||||
data.isduel = (numplayersingame <= 2);
|
||||
|
||||
srb2::StandingsJson standings {};
|
||||
|
||||
for (j = 0; j < numplayersingame; j++)
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
|
|
@ -238,13 +242,13 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
|||
|
||||
if (demo.recording)
|
||||
{
|
||||
G_WriteStanding(
|
||||
data.pos[data.numplayers],
|
||||
player_names[i],
|
||||
data.character[data.numplayers],
|
||||
data.color[data.numplayers],
|
||||
data.val[data.numplayers]
|
||||
);
|
||||
srb2::StandingJson standing {};
|
||||
standing.ranking = data.pos[data.numplayers];
|
||||
standing.name = std::string(player_names[i]);
|
||||
standing.demoskin = data.character[data.numplayers];
|
||||
standing.skincolor = std::string(skincolors[data.color[data.numplayers]].name);
|
||||
standing.timeorscore = data.val[data.numplayers];
|
||||
standings.standings.emplace_back(std::move(standing));
|
||||
}
|
||||
|
||||
if (data.val[data.numplayers] == (UINT32_MAX-1))
|
||||
|
|
@ -282,6 +286,12 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
|||
data.numplayers++;
|
||||
}
|
||||
|
||||
if (demo.recording)
|
||||
{
|
||||
srb2::write_current_demo_end_marker();
|
||||
srb2::write_current_demo_standings(standings);
|
||||
}
|
||||
|
||||
if (getmainplayer == true)
|
||||
{
|
||||
// Okay, player scores have been set now - we can calculate GP-relevant material.
|
||||
|
|
@ -308,7 +318,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
|||
data.showrank = (rankforline >= GRADE_A);
|
||||
|
||||
data.linemeter =
|
||||
(min(rankforline, GRADE_A)
|
||||
(std::min(rankforline, GRADE_A)
|
||||
* (2 * TICRATE)
|
||||
) / GRADE_A;
|
||||
|
||||
|
|
@ -465,7 +475,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
|
|||
|
||||
INT32 hilicol = highlightflags;
|
||||
|
||||
patch_t *resbar = W_CachePatchName("R_RESBAR", PU_PATCH); // Results bars for players
|
||||
patch_t *resbar = static_cast<patch_t*>(W_CachePatchName("R_RESBAR", PU_PATCH)); // Results bars for players
|
||||
|
||||
if (drawping || standings->rankingsmode != 0)
|
||||
{
|
||||
|
|
@ -550,7 +560,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
|
|||
UINT8 *charcolormap = NULL;
|
||||
if (standings->color[i] != SKINCOLOR_NONE)
|
||||
{
|
||||
charcolormap = R_GetTranslationColormap(standings->character[i], standings->color[i], GTC_CACHE);
|
||||
charcolormap = R_GetTranslationColormap(standings->character[i], static_cast<skincolornum_t>(standings->color[i]), GTC_CACHE);
|
||||
}
|
||||
|
||||
if (standings->isduel)
|
||||
|
|
@ -558,8 +568,8 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
|
|||
INT32 duelx = x + 22 + (datarightofcolumn ? inwardshim : -inwardshim);
|
||||
INT32 duely = y - 80;
|
||||
|
||||
V_DrawScaledPatch(duelx, duely, 0, W_CachePatchName("DUELGRPH", PU_CACHE));
|
||||
V_DrawScaledPatch(duelx + 8, duely + 9, V_TRANSLUCENT, W_CachePatchName("PREVBACK", PU_CACHE));
|
||||
V_DrawScaledPatch(duelx, duely, 0, static_cast<patch_t*>(W_CachePatchName("DUELGRPH", PU_CACHE)));
|
||||
V_DrawScaledPatch(duelx + 8, duely + 9, V_TRANSLUCENT, static_cast<patch_t*>(W_CachePatchName("PREVBACK", PU_CACHE)));
|
||||
|
||||
UINT8 spr2 = SPR2_STIN;
|
||||
if (standings->pos[i] == 2)
|
||||
|
|
@ -591,7 +601,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
|
|||
|
||||
if (j > splitscreen)
|
||||
{
|
||||
V_DrawScaledPatch(letterpos, duely, 0, W_CachePatchName(va("CHAR%s", (players[pnum].bot ? "CPU" : "EGGA")), PU_CACHE));
|
||||
V_DrawScaledPatch(letterpos, duely, 0, static_cast<patch_t*>(W_CachePatchName(va("CHAR%s", (players[pnum].bot ? "CPU" : "EGGA")), PU_CACHE)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -599,12 +609,12 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
|
|||
|
||||
UINT8 profilen = cv_lastprofile[j].value;
|
||||
|
||||
V_DrawScaledPatch(duelx, duely, 0, W_CachePatchName("FILEBACK", PU_CACHE));
|
||||
V_DrawScaledPatch(duelx, duely, 0, static_cast<patch_t*>(W_CachePatchName("FILEBACK", PU_CACHE)));
|
||||
|
||||
if (datarightofcolumn && j == 0)
|
||||
letterpos++; // A is one pixel thinner
|
||||
|
||||
V_DrawScaledPatch(letterpos, duely, 0, W_CachePatchName(va("CHARSEL%c", 'A' + j), PU_CACHE));
|
||||
V_DrawScaledPatch(letterpos, duely, 0, static_cast<patch_t*>(W_CachePatchName(va("CHARSEL%c", 'A' + j), PU_CACHE)));
|
||||
|
||||
profile_t *pr = PR_GetProfile(profilen);
|
||||
|
||||
|
|
@ -628,13 +638,13 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
|
|||
V_DrawMappedPatch(
|
||||
x+14, y-5,
|
||||
0,
|
||||
W_CachePatchName("MINIDEAD", PU_CACHE),
|
||||
R_GetTranslationColormap(TC_DEFAULT, standings->color[i], GTC_CACHE)
|
||||
static_cast<patch_t*>(W_CachePatchName("MINIDEAD", PU_CACHE)),
|
||||
R_GetTranslationColormap(TC_DEFAULT, static_cast<skincolornum_t>(standings->color[i]), GTC_CACHE)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
charcolormap = R_GetTranslationColormap(standings->character[i], standings->color[i], GTC_CACHE);
|
||||
charcolormap = R_GetTranslationColormap(standings->character[i], static_cast<skincolornum_t>(standings->color[i]), GTC_CACHE);
|
||||
V_DrawMappedPatch(x+14, y-5, 0, faceprefix[standings->character[i]][FACE_MINIMAP], charcolormap);
|
||||
}
|
||||
}
|
||||
|
|
@ -742,27 +752,27 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
|
|||
}
|
||||
else if (standings->grade[pnum] != GRADE_INVALID)
|
||||
{
|
||||
patch_t *gradePtc = W_CachePatchName(va("R_INRNK%c", K_GetGradeChar(standings->grade[pnum])), PU_PATCH);
|
||||
patch_t *gradePtc = static_cast<patch_t*>(W_CachePatchName(va("R_INRNK%c", K_GetGradeChar(static_cast<gp_rank_e>(standings->grade[pnum]))), PU_PATCH));
|
||||
patch_t *gradeBG = NULL;
|
||||
|
||||
UINT16 gradeColor = SKINCOLOR_NONE;
|
||||
UINT8 *gradeClm = NULL;
|
||||
|
||||
gradeColor = K_GetGradeColor(standings->grade[pnum]);
|
||||
gradeColor = K_GetGradeColor(static_cast<gp_rank_e>(standings->grade[pnum]));
|
||||
if (gradeColor != SKINCOLOR_NONE)
|
||||
{
|
||||
gradeClm = R_GetTranslationColormap(TC_DEFAULT, gradeColor, GTC_CACHE);
|
||||
gradeClm = R_GetTranslationColormap(TC_DEFAULT, static_cast<skincolornum_t>(gradeColor), GTC_CACHE);
|
||||
}
|
||||
|
||||
if (datarightofcolumn)
|
||||
{
|
||||
gradeBG = W_CachePatchName("R_INRNKR", PU_PATCH);
|
||||
gradeBG = static_cast<patch_t*>(W_CachePatchName("R_INRNKR", PU_PATCH));
|
||||
V_DrawMappedPatch(x + 118, y, 0, gradeBG, gradeClm);
|
||||
V_DrawMappedPatch(x + 118 + 4, y - 1, 0, gradePtc, gradeClm);
|
||||
}
|
||||
else
|
||||
{
|
||||
gradeBG = W_CachePatchName("R_INRNKL", PU_PATCH);
|
||||
gradeBG = static_cast<patch_t*>(W_CachePatchName("R_INRNKL", PU_PATCH));
|
||||
V_DrawMappedPatch(x - 12, y, 0, gradeBG, gradeClm);
|
||||
V_DrawMappedPatch(x - 12 + 3, y - 1, 0, gradePtc, gradeClm);
|
||||
}
|
||||
|
|
@ -828,27 +838,27 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
|
|||
INT32 bufferspace = ((vid.width/vid.dupx) - BASEVIDWIDTH) / 2;
|
||||
|
||||
// Background pieces
|
||||
patch_t *queuebg_flat = W_CachePatchName("R_RMBG1", PU_PATCH);
|
||||
patch_t *queuebg_upwa = W_CachePatchName("R_RMBG2", PU_PATCH);
|
||||
patch_t *queuebg_down = W_CachePatchName("R_RMBG3", PU_PATCH);
|
||||
patch_t *queuebg_prize = W_CachePatchName("R_RMBG4", PU_PATCH);
|
||||
patch_t *queuebg_flat = static_cast<patch_t*>(W_CachePatchName("R_RMBG1", PU_PATCH));
|
||||
patch_t *queuebg_upwa = static_cast<patch_t*>(W_CachePatchName("R_RMBG2", PU_PATCH));
|
||||
patch_t *queuebg_down = static_cast<patch_t*>(W_CachePatchName("R_RMBG3", PU_PATCH));
|
||||
patch_t *queuebg_prize = static_cast<patch_t*>(W_CachePatchName("R_RMBG4", PU_PATCH));
|
||||
|
||||
// Progression lines
|
||||
patch_t *line_upwa[BPP_MAX];
|
||||
patch_t *line_down[BPP_MAX];
|
||||
patch_t *line_flat[BPP_MAX];
|
||||
|
||||
line_upwa[BPP_AHEAD] = W_CachePatchName("R_RRMLN1", PU_PATCH);
|
||||
line_upwa[BPP_DONE] = W_CachePatchName("R_RRMLN3", PU_PATCH);
|
||||
line_upwa[BPP_SHADOW] = W_CachePatchName("R_RRMLS1", PU_PATCH);
|
||||
line_upwa[BPP_AHEAD] = static_cast<patch_t*>(W_CachePatchName("R_RRMLN1", PU_PATCH));
|
||||
line_upwa[BPP_DONE] = static_cast<patch_t*>(W_CachePatchName("R_RRMLN3", PU_PATCH));
|
||||
line_upwa[BPP_SHADOW] = static_cast<patch_t*>(W_CachePatchName("R_RRMLS1", PU_PATCH));
|
||||
|
||||
line_down[BPP_AHEAD] = W_CachePatchName("R_RRMLN2", PU_PATCH);
|
||||
line_down[BPP_DONE] = W_CachePatchName("R_RRMLN4", PU_PATCH);
|
||||
line_down[BPP_SHADOW] = W_CachePatchName("R_RRMLS2", PU_PATCH);
|
||||
line_down[BPP_AHEAD] = static_cast<patch_t*>(W_CachePatchName("R_RRMLN2", PU_PATCH));
|
||||
line_down[BPP_DONE] = static_cast<patch_t*>(W_CachePatchName("R_RRMLN4", PU_PATCH));
|
||||
line_down[BPP_SHADOW] = static_cast<patch_t*>(W_CachePatchName("R_RRMLS2", PU_PATCH));
|
||||
|
||||
line_flat[BPP_AHEAD] = W_CachePatchName("R_RRMLN5", PU_PATCH);
|
||||
line_flat[BPP_DONE] = W_CachePatchName("R_RRMLN6", PU_PATCH);
|
||||
line_flat[BPP_SHADOW] = W_CachePatchName("R_RRMLS3", PU_PATCH);
|
||||
line_flat[BPP_AHEAD] = static_cast<patch_t*>(W_CachePatchName("R_RRMLN5", PU_PATCH));
|
||||
line_flat[BPP_DONE] = static_cast<patch_t*>(W_CachePatchName("R_RRMLN6", PU_PATCH));
|
||||
line_flat[BPP_SHADOW] = static_cast<patch_t*>(W_CachePatchName("R_RRMLS3", PU_PATCH));
|
||||
|
||||
// Progress markers
|
||||
patch_t *level_dot[BPP_MAIN];
|
||||
|
|
@ -856,17 +866,17 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
|
|||
patch_t *capsu_dot[BPP_MAIN];
|
||||
patch_t *prize_dot[BPP_MAIN];
|
||||
|
||||
level_dot[BPP_AHEAD] = W_CachePatchName("R_RRMRK2", PU_PATCH);
|
||||
level_dot[BPP_DONE] = W_CachePatchName("R_RRMRK1", PU_PATCH);
|
||||
level_dot[BPP_AHEAD] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK2", PU_PATCH));
|
||||
level_dot[BPP_DONE] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK1", PU_PATCH));
|
||||
|
||||
bonus_dot[BPP_AHEAD] = W_CachePatchName("R_RRMRK7", PU_PATCH);
|
||||
bonus_dot[BPP_DONE] = W_CachePatchName("R_RRMRK8", PU_PATCH);
|
||||
bonus_dot[BPP_AHEAD] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK7", PU_PATCH));
|
||||
bonus_dot[BPP_DONE] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK8", PU_PATCH));
|
||||
|
||||
capsu_dot[BPP_AHEAD] = W_CachePatchName("R_RRMRK3", PU_PATCH);
|
||||
capsu_dot[BPP_DONE] = W_CachePatchName("R_RRMRK5", PU_PATCH);
|
||||
capsu_dot[BPP_AHEAD] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK3", PU_PATCH));
|
||||
capsu_dot[BPP_DONE] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK5", PU_PATCH));
|
||||
|
||||
prize_dot[BPP_AHEAD] = W_CachePatchName("R_RRMRK4", PU_PATCH);
|
||||
prize_dot[BPP_DONE] = W_CachePatchName("R_RRMRK6", PU_PATCH);
|
||||
prize_dot[BPP_AHEAD] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK4", PU_PATCH));
|
||||
prize_dot[BPP_DONE] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK6", PU_PATCH));
|
||||
|
||||
UINT8 *colormap = NULL, *oppositemap = NULL;
|
||||
fixed_t playerx = 0, playery = 0;
|
||||
|
|
@ -891,8 +901,8 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
|
|||
pcolor = players[standings->mainplayer].skincolor;
|
||||
}
|
||||
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, pcolor, GTC_CACHE);
|
||||
oppositemap = R_GetTranslationColormap(TC_DEFAULT, skincolors[pcolor].invcolor, GTC_CACHE);
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, static_cast<skincolornum_t>(pcolor), GTC_CACHE);
|
||||
oppositemap = R_GetTranslationColormap(TC_DEFAULT, static_cast<skincolornum_t>(skincolors[pcolor].invcolor), GTC_CACHE);
|
||||
|
||||
UINT8 workingqueuesize = roundqueue.size;
|
||||
boolean upwa = false;
|
||||
|
|
@ -924,7 +934,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
|
|||
SINT8 deferxoffs = 0;
|
||||
|
||||
const INT32 desiredx2 = (290 + bufferspace);
|
||||
spacetospecial = max(desiredx2 - widthofroundqueue - (24 - bufferspace), 16);
|
||||
spacetospecial = std::max(desiredx2 - widthofroundqueue - (24 - bufferspace), 16);
|
||||
|
||||
if (roundqueue.position == roundqueue.size)
|
||||
{
|
||||
|
|
@ -1237,7 +1247,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
|
|||
}
|
||||
else
|
||||
{
|
||||
const fixed_t fillend = min((playerx / FRACUNIT) + 2, barend);
|
||||
const fixed_t fillend = std::min((playerx / FRACUNIT) + 2, barend);
|
||||
|
||||
while (xiter < fillend)
|
||||
{
|
||||
|
|
@ -1353,8 +1363,8 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
|
|||
if (playery != 0)
|
||||
{
|
||||
patch_t *rpmark[2];
|
||||
rpmark[0] = W_CachePatchName("R_RPMARK", PU_PATCH);
|
||||
rpmark[1] = W_CachePatchName("R_R2MARK", PU_PATCH);
|
||||
rpmark[0] = static_cast<patch_t*>(W_CachePatchName("R_RPMARK", PU_PATCH));
|
||||
rpmark[1] = static_cast<patch_t*>(W_CachePatchName("R_R2MARK", PU_PATCH));
|
||||
|
||||
// Change alignment
|
||||
playerx -= (10 * FRACUNIT);
|
||||
|
|
@ -1377,7 +1387,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
|
|||
FRACUNIT,
|
||||
baseflags,
|
||||
faceprefix[pskin][FACE_RANK],
|
||||
R_GetTranslationColormap(pskin, pcolor, GTC_CACHE)
|
||||
R_GetTranslationColormap(pskin, static_cast<skincolornum_t>(pcolor), GTC_CACHE)
|
||||
);
|
||||
}
|
||||
else
|
||||
|
|
@ -1473,7 +1483,7 @@ void Y_DrawIntermissionHeader(fixed_t x, fixed_t y, boolean gotthrough, const ch
|
|||
}
|
||||
|
||||
// Header bar
|
||||
patch_t *rtpbr = W_CachePatchName((small ? "R_RTPB4" : "R_RTPBR"), PU_PATCH);
|
||||
patch_t *rtpbr = static_cast<patch_t*>(W_CachePatchName((small ? "R_RTPB4" : "R_RTPBR"), PU_PATCH));
|
||||
V_DrawFixedPatch((20 * frac) + x, (24 * frac) + y, FRACUNIT, small_flag, rtpbr, NULL);
|
||||
|
||||
fixed_t headerx, headery, headerwidth = 0;
|
||||
|
|
@ -1517,7 +1527,7 @@ void Y_DrawIntermissionHeader(fixed_t x, fixed_t y, boolean gotthrough, const ch
|
|||
if (gotthrough)
|
||||
{
|
||||
// GOT THROUGH ROUND
|
||||
patch_t *gthro = W_CachePatchName((small ? "R_GTHR4" : "R_GTHRO"), PU_PATCH);
|
||||
patch_t *gthro = static_cast<patch_t*>(W_CachePatchName((small ? "R_GTHR4" : "R_GTHRO"), PU_PATCH));
|
||||
V_DrawFixedPatch((50 * frac) + x, (42 * frac) + y, FRACUNIT, small_flag, gthro, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -1594,15 +1604,15 @@ void Y_IntermissionDrawer(void)
|
|||
fixed_t x;
|
||||
|
||||
// Checker scroll
|
||||
patch_t *rbgchk = W_CachePatchName("R_RBGCHK", PU_PATCH);
|
||||
patch_t *rbgchk = static_cast<patch_t*>(W_CachePatchName("R_RBGCHK", PU_PATCH));
|
||||
|
||||
// Scrolling marquee
|
||||
patch_t *rrmq = W_CachePatchName("R_RRMQ", PU_PATCH);
|
||||
patch_t *rrmq = static_cast<patch_t*>(W_CachePatchName("R_RRMQ", PU_PATCH));
|
||||
|
||||
fixed_t mqloop = SHORT(rrmq->width)*FRACUNIT;
|
||||
fixed_t chkloop = SHORT(rbgchk->width)*FRACUNIT;
|
||||
|
||||
UINT8 *bgcolor = R_GetTranslationColormap(TC_INTERMISSION, 0, GTC_CACHE);
|
||||
UINT8 *bgcolor = R_GetTranslationColormap(TC_INTERMISSION, static_cast<skincolornum_t>(0), GTC_CACHE);
|
||||
|
||||
// Draw the background
|
||||
K_DrawMapThumbnail(0, 0, BASEVIDWIDTH<<FRACBITS, (data.encore ? V_FLIP : 0), prevmap, bgcolor);
|
||||
|
|
@ -1681,11 +1691,11 @@ skiptallydrawer:
|
|||
|
||||
finalcounter:
|
||||
{
|
||||
if ((modeattacking == ATTACKING_NONE) && (demo.recording || demo.savemode == DSM_SAVED) && !demo.playback)
|
||||
if ((modeattacking == ATTACKING_NONE) && (demo.recording || demo.savemode == demovars_s::DSM_SAVED) && !demo.playback)
|
||||
{
|
||||
switch (demo.savemode)
|
||||
{
|
||||
case DSM_NOTSAVING:
|
||||
case demovars_s::DSM_NOTSAVING:
|
||||
{
|
||||
INT32 buttonx = BASEVIDWIDTH;
|
||||
INT32 buttony = 2;
|
||||
|
|
@ -1696,11 +1706,11 @@ finalcounter:
|
|||
V_DrawRightAlignedThinString(buttonx - 2, buttony, highlightflags, "Save replay");
|
||||
break;
|
||||
}
|
||||
case DSM_SAVED:
|
||||
case demovars_s::DSM_SAVED:
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, highlightflags, "Replay saved!");
|
||||
break;
|
||||
|
||||
case DSM_TITLEENTRY:
|
||||
case demovars_s::DSM_TITLEENTRY:
|
||||
ST_DrawDemoTitleEntry();
|
||||
break;
|
||||
|
||||
|
|
@ -1745,13 +1755,13 @@ void Y_Ticker(void)
|
|||
|
||||
if (demo.recording)
|
||||
{
|
||||
if (demo.savemode == DSM_NOTSAVING)
|
||||
if (demo.savemode == demovars_s::DSM_NOTSAVING)
|
||||
{
|
||||
replayprompttic++;
|
||||
G_CheckDemoTitleEntry();
|
||||
}
|
||||
|
||||
if (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE)
|
||||
if (demo.savemode == demovars_s::DSM_WILLSAVE || demo.savemode == demovars_s::DSM_WILLAUTOSAVE)
|
||||
G_SaveDemo();
|
||||
}
|
||||
|
||||
|
|
@ -1983,7 +1993,7 @@ void Y_DetermineIntermissionType(void)
|
|||
}
|
||||
|
||||
// set initially
|
||||
intertype = gametypes[gametype]->intermission;
|
||||
intertype = static_cast<intertype_t>(gametypes[gametype]->intermission);
|
||||
|
||||
// special cases
|
||||
if (intertype == int_scoreortimeattack)
|
||||
|
|
@ -2060,7 +2070,7 @@ void Y_StartIntermission(void)
|
|||
else
|
||||
{
|
||||
// Minimum two seconds for match results, then two second slideover approx halfway through
|
||||
sorttic = max((timer/2) - 2*TICRATE, 2*TICRATE);
|
||||
sorttic = std::max((timer/2) - 2*TICRATE, 2*TICRATE);
|
||||
}
|
||||
|
||||
// TODO: code's a mess, I'm just making it extra clear
|
||||
|
|
@ -2147,8 +2157,8 @@ void Y_StartIntermission(void)
|
|||
}
|
||||
|
||||
Automate_Run(AEV_INTERMISSIONSTART);
|
||||
bgpatch = W_CachePatchName("MENUBG", PU_STATIC);
|
||||
widebgpatch = W_CachePatchName("WEIRDRES", PU_STATIC);
|
||||
bgpatch = static_cast<patch_t*>(W_CachePatchName("MENUBG", PU_STATIC));
|
||||
widebgpatch = static_cast<patch_t*>(W_CachePatchName("WEIRDRES", PU_STATIC));
|
||||
}
|
||||
|
||||
// ======
|
||||
Loading…
Add table
Reference in a new issue