From b0792aed46659d8e55e1893275ca6cc5946b3504 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 14:33:38 -0600 Subject: [PATCH 001/186] Start with some strange multiplayer replay init stuff Mostly just disabling the parts of the replay that assume a single player, right now. # Conflicts: # src/g_game.c --- src/g_game.c | 131 ++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 59 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index d8022e089..ba926c57d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4481,6 +4481,7 @@ char *G_BuildMapTitle(INT32 mapnum) #define DF_NIGHTSATTACK 0x04 // This demo is from NiGHTS attack and contains its time left, score, and mares! #define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? #define DF_ATTACKSHIFT 1 +#define DF_MULTIPLAYER 0x80 // This demo contains a dynamic number of players! // For demos #define ZT_FWD 0x01 @@ -5442,7 +5443,7 @@ void G_BeginRecording(void) memset(name,0,sizeof(name)); demo_p = demobuffer; - demoflags = DF_GHOST|(modeattacking<>DF_ATTACKSHIFT; + multiplayer = !!(demoflags & DF_MULTIPLAYER); CON_ToggleOff(); hu_demotime = UINT32_MAX; @@ -5861,33 +5869,35 @@ void G_DoPlayDemo(char *defdemoname) // Random seed randseed = READUINT32(demo_p); - // Player name - M_Memcpy(player_names[0],demo_p,16); - demo_p += 16; + if (!multiplayer) { + // Player name + M_Memcpy(player_names[0],demo_p,16); + demo_p += 16; - // Skin - M_Memcpy(skin,demo_p,16); - demo_p += 16; + // Skin + M_Memcpy(skin,demo_p,16); + demo_p += 16; - // Color - M_Memcpy(color,demo_p,16); - demo_p += 16; + // Color + M_Memcpy(color,demo_p,16); + demo_p += 16; - charability = READUINT8(demo_p); - charability2 = READUINT8(demo_p); - actionspd = (fixed_t)READUINT8(demo_p)<color = players[0].skincolor; + oldghost.x = players[0].mo->x; + oldghost.y = players[0].mo->y; + oldghost.z = players[0].mo->z; } - //CV_StealthSetValue(&cv_playercolor, players[0].skincolor); -- as far as I can tell this is more trouble than it's worth - if (players[0].mo) - { - players[0].mo->color = players[0].skincolor; - oldghost.x = players[0].mo->x; - oldghost.y = players[0].mo->y; - oldghost.z = players[0].mo->z; - } - // Set saved attribute values - // No cheat checking here, because even if they ARE wrong... - // it would only break the replay if we clipped them. - players[0].charability = charability; - players[0].charability2 = charability2; - players[0].actionspd = actionspd; - players[0].mindash = mindash; - players[0].maxdash = maxdash; - // SRB2kart - players[0].kartspeed = kartspeed; - players[0].kartweight = kartweight; - // - players[0].normalspeed = normalspeed; - players[0].runspeed = runspeed; - players[0].thrustfactor = thrustfactor; - players[0].accelstart = accelstart; - players[0].acceleration = acceleration; - players[0].jumpfactor = jumpfactor; + // Set saved attribute values + // No cheat checking here, because even if they ARE wrong... + // it would only break the replay if we clipped them. + players[0].charability = charability; + players[0].charability2 = charability2; + players[0].actionspd = actionspd; + players[0].mindash = mindash; + players[0].maxdash = maxdash; + // SRB2kart + players[0].kartspeed = kartspeed; + players[0].kartweight = kartweight; + // + players[0].normalspeed = normalspeed; + players[0].runspeed = runspeed; + players[0].thrustfactor = thrustfactor; + players[0].accelstart = accelstart; + players[0].acceleration = acceleration; + players[0].jumpfactor = jumpfactor; + } demo_start = true; } From 7d881e7af1d196fb7e3038c3a91e06bb1fe8f0b9 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 12 Jan 2019 01:26:14 -0600 Subject: [PATCH 002/186] Store initial player data in net replay --- src/g_game.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index ba926c57d..20e796923 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5434,7 +5434,7 @@ void G_RecordMetal(void) void G_BeginRecording(void) { - UINT8 i; + UINT8 i, p; char name[16]; player_t *player = &players[consoleplayer]; @@ -5481,8 +5481,41 @@ void G_BeginRecording(void) WRITEUINT32(demo_p,P_GetInitSeed()); if (demoflags & DF_MULTIPLAYER) { - // Net replays don't store player info here! Just skip to the netvars and return out. + // Netvars first :) CV_SaveNetVars(&demo_p); + + // Now store a SIMPLIFIED data struct for each in-game player + for (p = 0; p < MAXPLAYERS; p++) { + if (playeringame[p] && !players[p].spectator) { + player = players[p]; + + WRITEUINT8(demo_p, p); + + // Name + memset(name, 0, 16); + strncpy(name, player_names[p], 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; + + // Skin + memset(name, 0, 16); + strncpy(name, skins[player->skin].name, 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; + + // Color + memset(name, 0, 16); + strncpy(name, COLOR_ENUMS[player->skincolor], 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; + + // Score, since Kart uses this to determine where you start on the map + WRITEUINT32(demo_p, player->score); + } + } + + WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing + return; } @@ -5738,7 +5771,7 @@ void G_DeferedPlayDemo(const char *name) #define SKIPERRORS void G_DoPlayDemo(char *defdemoname) { - UINT8 i; + UINT8 i, p; lumpnum_t l; char skin[17],color[17],*n,*pdemoname; UINT8 version,subversion,charability,charability2,kartspeed,kartweight,thrustfactor,accelstart,acceleration; @@ -5944,6 +5977,46 @@ void G_DoPlayDemo(char *defdemoname) memset(playeringame,0,sizeof(playeringame)); playeringame[0] = !multiplayer; + if (multiplayer) { + player_t *player; + + // Load players that were in-game when the map started + p = READUINT8(demo_p); + + while (p != 0xFF) + { + player = players[p]; + if (!playeringame[displayplayer]) + displayplayer = consoleplayer = p; + playeringame[p] = true; + + // Name + M_Memcpy(player_names[p],demo_p,16); + demo_p += 16; + + // Skin + M_Memcpy(skin,demo_p,16); + demo_p += 16; + SetPlayerSkin(p, skin); + + // Color + M_Memcpy(color,demo_p,16); + demo_p += 16; + for (i = 0; i < MAXSKINCOLORS; i++) + if (!stricmp(KartColor_Names[i],color)) // SRB2kart + { + players[p].skincolor = i; + break; + } + + // Score, since Kart uses this to determine where you start on the map + player->score = READUINT32(demo_p); + + // Look for the next player + p = READUINT8(demo_p); + } + } + P_SetRandSeed(randseed); G_InitNew(false, G_BuildMapName(gamemap), true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer. From 11837576a1d01ef6f2c5f730d1f2d161ad9c5163 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 12 Jan 2019 01:26:43 -0600 Subject: [PATCH 003/186] I don't wanna deal with ghosts right now --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 20e796923..c0e10f23f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5443,7 +5443,7 @@ void G_BeginRecording(void) memset(name,0,sizeof(name)); demo_p = demobuffer; - demoflags = DF_GHOST|(multiplayer ? DF_MULTIPLAYER : (modeattacking< Date: Sat, 12 Jan 2019 01:32:07 -0600 Subject: [PATCH 004/186] lol test net replay stuff --- src/d_netcmd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 41f88ab95..b9384eec5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2337,6 +2337,11 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) return; } + //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. + if (multiplayer) { + G_RecordDemo("net_replay_test"); + } + if (chmappending) chmappending--; From 61ba4ac1232be1c98438c36edcc11c72994e4c92 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 12 Jan 2019 02:06:16 -0600 Subject: [PATCH 005/186] Fix compile errors --- src/g_game.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index c0e10f23f..09c0060bd 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5487,7 +5487,7 @@ void G_BeginRecording(void) // Now store a SIMPLIFIED data struct for each in-game player for (p = 0; p < MAXPLAYERS; p++) { if (playeringame[p] && !players[p].spectator) { - player = players[p]; + player = &players[p]; WRITEUINT8(demo_p, p); @@ -5505,7 +5505,7 @@ void G_BeginRecording(void) // Color memset(name, 0, 16); - strncpy(name, COLOR_ENUMS[player->skincolor], 16); + strncpy(name, KartColor_Names[player->skincolor], 16); M_Memcpy(demo_p,name,16); demo_p += 16; @@ -5985,7 +5985,7 @@ void G_DoPlayDemo(char *defdemoname) while (p != 0xFF) { - player = players[p]; + player = &players[p]; if (!playeringame[displayplayer]) displayplayer = consoleplayer = p; playeringame[p] = true; From 2b47af32fb5694776278c11a648cdfd5b7c3d988 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 12 Jan 2019 02:06:40 -0600 Subject: [PATCH 006/186] Record all players' ticcmds in multiplayer --- src/p_tick.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/p_tick.c b/src/p_tick.c index b46b248bb..e1262a77a 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -599,9 +599,26 @@ void P_Ticker(boolean run) if (run) { if (demorecording) - G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); + { + if (!multiplayer) { + G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); + } else { + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && !players[i].spectator) + G_WriteDemoTiccmd(&players[i].cmd, i); + } + } if (demoplayback) + { + + if (!multiplayer) { G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); + } else { + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && !players[i].spectator) + G_ReadDemoTiccmd(&players[i].cmd, i); + } + } for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) From 5a6ad744b17646a1cb413e5a11a2d86546bd60a1 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 12 Jan 2019 02:06:56 -0600 Subject: [PATCH 007/186] Separate oldtic for each player --- src/g_game.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 09c0060bd..abc5857b8 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4492,7 +4492,7 @@ char *G_BuildMapTitle(INT32 mapnum) #define ZT_DRIFT 0x20 #define DEMOMARKER 0x80 // demoend -static ticcmd_t oldcmd; +static ticcmd_t oldcmd[MAXPLAYERS]; // For Metal Sonic and time attack ghosts #define GZT_XYZ 0x01 @@ -4556,26 +4556,25 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) { UINT8 ziptic; - (void)playernum; if (!demo_p || !demo_start) return; ziptic = READUINT8(demo_p); if (ziptic & ZT_FWD) - oldcmd.forwardmove = READSINT8(demo_p); + oldcmd[playernum].forwardmove = READSINT8(demo_p); if (ziptic & ZT_SIDE) - oldcmd.sidemove = READSINT8(demo_p); + oldcmd[playernum].sidemove = READSINT8(demo_p); if (ziptic & ZT_ANGLE) - oldcmd.angleturn = READINT16(demo_p); + oldcmd[playernum].angleturn = READINT16(demo_p); if (ziptic & ZT_BUTTONS) - oldcmd.buttons = (oldcmd.buttons & (BT_FORWARD|BT_BACKWARD)) | (READUINT16(demo_p) & ~(BT_FORWARD|BT_BACKWARD)); + oldcmd[playernum].buttons = (oldcmd[playernum].buttons & (BT_FORWARD|BT_BACKWARD)) | (READUINT16(demo_p) & ~(BT_FORWARD|BT_BACKWARD)); if (ziptic & ZT_AIMING) - oldcmd.aiming = READINT16(demo_p); + oldcmd[playernum].aiming = READINT16(demo_p); if (ziptic & ZT_DRIFT) - oldcmd.driftturn = READINT16(demo_p); + oldcmd[playernum].driftturn = READINT16(demo_p); - G_CopyTiccmd(cmd, &oldcmd, 1); + G_CopyTiccmd(cmd, &oldcmd[playernum], 1); // SRB2kart: Copy-pasted from ticcmd building, removes that crappy demo cam if (((players[displayplayer].mo && players[displayplayer].speed > 0) // Moving @@ -4597,51 +4596,50 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) { char ziptic = 0; UINT8 *ziptic_p; - (void)playernum; if (!demo_p) return; ziptic_p = demo_p++; // the ziptic, written at the end of this function - if (cmd->forwardmove != oldcmd.forwardmove) + if (cmd->forwardmove != oldcmd[playernum].forwardmove) { WRITEUINT8(demo_p,cmd->forwardmove); - oldcmd.forwardmove = cmd->forwardmove; + oldcmd[playernum].forwardmove = cmd->forwardmove; ziptic |= ZT_FWD; } - if (cmd->sidemove != oldcmd.sidemove) + if (cmd->sidemove != oldcmd[playernum].sidemove) { WRITEUINT8(demo_p,cmd->sidemove); - oldcmd.sidemove = cmd->sidemove; + oldcmd[playernum].sidemove = cmd->sidemove; ziptic |= ZT_SIDE; } - if (cmd->angleturn != oldcmd.angleturn) + if (cmd->angleturn != oldcmd[playernum].angleturn) { WRITEINT16(demo_p,cmd->angleturn); - oldcmd.angleturn = cmd->angleturn; + oldcmd[playernum].angleturn = cmd->angleturn; ziptic |= ZT_ANGLE; } - if (cmd->buttons != oldcmd.buttons) + if (cmd->buttons != oldcmd[playernum].buttons) { WRITEUINT16(demo_p,cmd->buttons); - oldcmd.buttons = cmd->buttons; + oldcmd[playernum].buttons = cmd->buttons; ziptic |= ZT_BUTTONS; } - if (cmd->aiming != oldcmd.aiming) + if (cmd->aiming != oldcmd[playernum].aiming) { WRITEINT16(demo_p,cmd->aiming); - oldcmd.aiming = cmd->aiming; + oldcmd[playernum].aiming = cmd->aiming; ziptic |= ZT_AIMING; } - if (cmd->driftturn != oldcmd.driftturn) + if (cmd->driftturn != oldcmd[playernum].driftturn) { WRITEINT16(demo_p,cmd->driftturn); - oldcmd.driftturn = cmd->driftturn; + oldcmd[playernum].driftturn = cmd->driftturn; ziptic |= ZT_DRIFT; } From 2ec0673af9e24746fa1e6f57cb3688e5706f27da Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 12 Jan 2019 02:48:18 -0600 Subject: [PATCH 008/186] Fix players spawning in the wrong spots when watching replays --- src/g_game.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index abc5857b8..2e8c5b481 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4364,7 +4364,7 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool players[i].marescore = 0; - if (resetplayer) // SRB2Kart + if (resetplayer && !(multiplayer && demoplayback)) // SRB2Kart { players[i].score = 0; } @@ -5983,7 +5983,6 @@ void G_DoPlayDemo(char *defdemoname) while (p != 0xFF) { - player = &players[p]; if (!playeringame[displayplayer]) displayplayer = consoleplayer = p; playeringame[p] = true; @@ -6008,7 +6007,7 @@ void G_DoPlayDemo(char *defdemoname) } // Score, since Kart uses this to determine where you start on the map - player->score = READUINT32(demo_p); + players[p].score = READUINT32(demo_p); // Look for the next player p = READUINT8(demo_p); From 28da2d2a8526569f19852fbb90ec590b7e798c0d Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 15:09:58 -0600 Subject: [PATCH 009/186] Store cmd.latency in replays --- src/g_game.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 2e8c5b481..e548399b3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4490,6 +4490,7 @@ char *G_BuildMapTitle(INT32 mapnum) #define ZT_BUTTONS 0x08 #define ZT_AIMING 0x10 #define ZT_DRIFT 0x20 +#define ZT_LATENCY 0x40 #define DEMOMARKER 0x80 // demoend static ticcmd_t oldcmd[MAXPLAYERS]; @@ -4573,6 +4574,8 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) oldcmd[playernum].aiming = READINT16(demo_p); if (ziptic & ZT_DRIFT) oldcmd[playernum].driftturn = READINT16(demo_p); + if (ziptic & ZT_LATENCY) + oldcmd[playernum].latency = READUINT8(demo_p); G_CopyTiccmd(cmd, &oldcmd[playernum], 1); @@ -4643,6 +4646,13 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) ziptic |= ZT_DRIFT; } + if (cmd->latency != oldcmd[playernum].latency) + { + WRITEUINT8(demo_p,cmd->latency); + oldcmd[playernum].latency = cmd->latency; + ziptic |= ZT_LATENCY; + } + *ziptic_p = ziptic; // attention here for the ticcmd size! @@ -5017,6 +5027,8 @@ void G_GhostTicker(void) g->p += 2; if (ziptic & ZT_DRIFT) g->p += 2; + if (ziptic & ZT_LATENCY) + g->p += 1; // Grab ghost data. ziptic = READUINT8(g->p); @@ -5404,6 +5416,8 @@ void G_RecordDemo(const char *name) { INT32 maxsize; + CONS_Printf("Recording demo %s\n", name); + strcpy(demoname, name); strcat(demoname, ".lmp"); maxsize = 1024*1024; From 5b4b5ec302a437c66fa6cba756218115a6a463cf Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 15:45:08 -0600 Subject: [PATCH 010/186] Move where multiplayer replays are started This particularly allows a server to record the first map after startup as a replay. Players joining mid-map can no longer record replays tho --- src/d_netcmd.c | 5 ----- src/p_setup.c | 7 ++++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b9384eec5..41f88ab95 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2337,11 +2337,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) return; } - //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. - if (multiplayer) { - G_RecordDemo("net_replay_test"); - } - if (chmappending) chmappending--; diff --git a/src/p_setup.c b/src/p_setup.c index 49b22184e..764ad211a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3156,6 +3156,11 @@ boolean P_SetupLevel(boolean skipprecip) ? cv_basenumlaps.value : mapheaderinfo[gamemap - 1]->numlaps); + //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. + if (!demoplayback && multiplayer) { + G_RecordDemo("net_replay_test"); + } + // =========== // landing point for netgames. netgameskip: @@ -3435,7 +3440,7 @@ boolean P_AddWadFile(const char *wadfilename) // R_AddSkins(wadnum); // faB: wadfile index in wadfiles[] - // + // // edit music defs // S_LoadMusicDefs(wadnum); From d9f134570174a8e60e3a35f7e5238afb4bc44048 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 15:45:42 -0600 Subject: [PATCH 011/186] [HACK] Save correct lap count on netreplays --- src/command.c | 16 +++++++++++++--- src/command.h | 2 +- src/d_clisrv.c | 2 +- src/g_game.c | 4 ++-- src/p_saveg.c | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/command.c b/src/command.c index bb2ea86e6..164b0988d 100644 --- a/src/command.c +++ b/src/command.c @@ -1355,7 +1355,7 @@ static void Got_NetVar(UINT8 **p, INT32 playernum) Setvalue(cvar, svalue, stealth); } -void CV_SaveNetVars(UINT8 **p) +void CV_SaveNetVars(UINT8 **p, boolean demorecording) { consvar_t *cvar; UINT8 *count_p = *p; @@ -1365,10 +1365,20 @@ void CV_SaveNetVars(UINT8 **p) // the client will reset all netvars to default before loading WRITEUINT16(*p, 0x0000); for (cvar = consvar_vars; cvar; cvar = cvar->next) - if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) + if (((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) || (demorecording && cvar->netid == cv_numlaps.netid)) { WRITEUINT16(*p, cvar->netid); - WRITESTRING(*p, cvar->string); + + // UGLY HACK: Save proper lap count in net replays + if (demorecording && cvar->netid == cv_numlaps.netid) + { + WRITESTRING(*p, cv_basenumlaps.string); + } + else + { + WRITESTRING(*p, cvar->string); + } + WRITEUINT8(*p, false); ++count; } diff --git a/src/command.h b/src/command.h index 82dfaf8aa..70bf74a93 100644 --- a/src/command.h +++ b/src/command.h @@ -160,7 +160,7 @@ void CV_AddValue(consvar_t *var, INT32 increment); void CV_SaveVariables(FILE *f); // load/save gamesate (load and save option and for network join in game) -void CV_SaveNetVars(UINT8 **p); +void CV_SaveNetVars(UINT8 **p, boolean demorecording); void CV_LoadNetVars(UINT8 **p); // reset cheat netvars after cheats is deactivated diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c84faa721..5369ff2cf 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1500,7 +1500,7 @@ static boolean SV_SendServerConfig(INT32 node) op = p = netbuffer->u.servercfg.varlengthinputs; CV_SavePlayerNames(&p); - CV_SaveNetVars(&p); + CV_SaveNetVars(&p, false); { const size_t len = sizeof (serverconfig_pak) + (size_t)(p - op); diff --git a/src/g_game.c b/src/g_game.c index e548399b3..d429ccd8d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5494,7 +5494,7 @@ void G_BeginRecording(void) if (demoflags & DF_MULTIPLAYER) { // Netvars first :) - CV_SaveNetVars(&demo_p); + CV_SaveNetVars(&demo_p, true); // Now store a SIMPLIFIED data struct for each in-game player for (p = 0; p < MAXPLAYERS; p++) { @@ -5576,7 +5576,7 @@ void G_BeginRecording(void) WRITEFIXED(demo_p, player->jumpfactor); // Save netvar data (SONICCD, etc) - CV_SaveNetVars(&demo_p); + CV_SaveNetVars(&demo_p, false); //@TODO can this be true? it's not necessary for now but would be nice for consistency memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); diff --git a/src/p_saveg.c b/src/p_saveg.c index 975a4a5d2..52a35c37c 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3447,7 +3447,7 @@ void P_SaveNetGame(void) mobj_t *mobj; INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise - CV_SaveNetVars(&save_p); + CV_SaveNetVars(&save_p, false); P_NetArchiveMisc(); // Assign the mobjnumber for pointer tracking From 30649b05746ddc3cab0d785759b15fceff8b09dc Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 16:23:34 -0600 Subject: [PATCH 012/186] broken spectator stuff? --- src/g_game.c | 16 +++++++++++++--- src/p_tick.c | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index d429ccd8d..da21d269d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4483,6 +4483,8 @@ char *G_BuildMapTitle(INT32 mapnum) #define DF_ATTACKSHIFT 1 #define DF_MULTIPLAYER 0x80 // This demo contains a dynamic number of players! +#define DEMO_SPECTATOR 0x40 + // For demos #define ZT_FWD 0x01 #define ZT_SIDE 0x02 @@ -5498,10 +5500,10 @@ void G_BeginRecording(void) // Now store a SIMPLIFIED data struct for each in-game player for (p = 0; p < MAXPLAYERS; p++) { - if (playeringame[p] && !players[p].spectator) { + if (playeringame[p]) { player = &players[p]; - WRITEUINT8(demo_p, p); + WRITEUINT8(demo_p, p | (player->spectator ? DEMO_SPECTATOR : 0)); // Name memset(name, 0, 16); @@ -5991,15 +5993,23 @@ void G_DoPlayDemo(char *defdemoname) if (multiplayer) { player_t *player; + boolean spectator; // Load players that were in-game when the map started p = READUINT8(demo_p); while (p != 0xFF) { - if (!playeringame[displayplayer]) + spectator = false; + if (p & DEMO_SPECTATOR) { + spectator = true; + p &= ~DEMO_SPECTATOR; + } + + if (!playeringame[displayplayer] || players[displayplayer].spectator) displayplayer = consoleplayer = p; playeringame[p] = true; + players[p].spectator = spectator; // Name M_Memcpy(player_names[p],demo_p,16); diff --git a/src/p_tick.c b/src/p_tick.c index e1262a77a..8814d4406 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -604,7 +604,7 @@ void P_Ticker(boolean run) G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); } else { for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && !players[i].spectator) + if (playeringame[i]) G_WriteDemoTiccmd(&players[i].cmd, i); } } @@ -615,7 +615,7 @@ void P_Ticker(boolean run) G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); } else { for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && !players[i].spectator) + if (playeringame[i]) G_ReadDemoTiccmd(&players[i].cmd, i); } } From cc5bcd16768bbcf3e38218d88d4a728a61fb7bb5 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 17:09:25 -0600 Subject: [PATCH 013/186] Reset oldcmd when recording netreplays --- src/g_game.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index da21d269d..2866624d3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5530,6 +5530,11 @@ void G_BeginRecording(void) WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing + memset(&oldcmd,0,sizeof(oldcmd)); + // Lower two lines aren't useful until ghost replays for mp are implemented, but eh + memset(&oldghost,0,sizeof(oldghost)); + memset(&ghostext,0,sizeof(ghostext)); + return; } From 08582fa7cc7c6b86a9b90063e98b5f6e99cc42f5 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 17:48:39 -0600 Subject: [PATCH 014/186] Fix spectators spawning as players in netreplays --- src/p_mobj.c | 3 ++- src/p_tick.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index f71ff2092..3eae4cae0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10889,7 +10889,8 @@ void P_SpawnPlayer(INT32 playernum) } // spawn as spectator determination - if (!G_GametypeHasSpectators()) + if (multiplayer && demoplayback); // Don't mess with spectator values since the demo setup handles them already. + else if (!G_GametypeHasSpectators()) p->spectator = false; else if (netgame && p->jointime <= 1 && pcount) { diff --git a/src/p_tick.c b/src/p_tick.c index 8814d4406..471b38ecf 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -612,7 +612,7 @@ void P_Ticker(boolean run) { if (!multiplayer) { - G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); + G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); } else { for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) From c944a524d1e4a9f17e22737e9dc3385c40b5147e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 17:58:13 -0600 Subject: [PATCH 015/186] Fix invalid numlaps value being written when set to map default --- src/command.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/command.c b/src/command.c index 164b0988d..50692c67d 100644 --- a/src/command.c +++ b/src/command.c @@ -1372,7 +1372,19 @@ void CV_SaveNetVars(UINT8 **p, boolean demorecording) // UGLY HACK: Save proper lap count in net replays if (demorecording && cvar->netid == cv_numlaps.netid) { - WRITESTRING(*p, cv_basenumlaps.string); + if (cv_basenumlaps.value && + (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) + || (mapheaderinfo[gamemap - 1]->numlaps > cv_basenumlaps.value)) + ) + { + WRITESTRING(*p, cv_basenumlaps.string); + } + else + { + char buf[9]; + sprintf(buf, "%d", mapheaderinfo[gamemap - 1]->numlaps); + WRITESTRING(*p, buf); + } } else { From 4116c111525701bb9c2f7c301d7ed17be291ce70 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 19:07:30 -0600 Subject: [PATCH 016/186] Write skin/color/name changes to replay --- src/d_netcmd.c | 2 + src/g_game.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ src/g_game.h | 13 ++++++ src/p_tick.c | 2 + src/r_things.c | 3 ++ 5 files changed, 135 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 41f88ab95..d6cf49047 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1146,6 +1146,7 @@ static void SetPlayerName(INT32 playernum, char *newname) HU_AddChatText(va("\x82*%s renamed to %s", player_names[playernum], newname), false); strcpy(player_names[playernum], newname); + demo_extradata[playernum] |= DXD_NAME; } } else @@ -1749,6 +1750,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) p->skincolor = color % MAXSKINCOLORS; if (p->mo) p->mo->color = (UINT8)p->skincolor; + demo_extradata[playernum] |= DXD_COLOR; // normal player colors if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer] diff --git a/src/g_game.c b/src/g_game.c index 2866624d3..ced20e5b2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4495,6 +4495,7 @@ char *G_BuildMapTitle(INT32 mapnum) #define ZT_LATENCY 0x40 #define DEMOMARKER 0x80 // demoend +UINT8 demo_extradata[MAXPLAYERS]; static ticcmd_t oldcmd[MAXPLAYERS]; // For Metal Sonic and time attack ghosts @@ -4556,6 +4557,119 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) return dest; } +void G_ReadDemoExtraData(void) +{ + INT32 p, extradata, i; + char name[17]; + + memset(name, '\0', 17); + + p = READUINT8(demo_p); + + while (p != 0xFF) + { + extradata = READUINT8(demo_p); + + if (extradata & DXD_RESPAWN) + { + if (players[p].mo) + P_DamageMobj(players[p].mo, NULL, NULL, 10000); // Is this how this should work..? + } + if (extradata & DXD_SKIN) + { + CONS_Printf("change skin\n"); + // Skin + M_Memcpy(name, demo_p, 16); + demo_p += 16; + SetPlayerSkin(p, name); + } + if (extradata & DXD_COLOR) + { + CONS_Printf("change color\n"); + // Color + M_Memcpy(name, demo_p, 16); + demo_p += 16; + for (i = 0; i < MAXSKINCOLORS; i++) + if (!stricmp(KartColor_Names[i], name)) // SRB2kart + { + players[p].skincolor = i; + if (players[p].mo) + players[p].mo->color = i; + break; + } + } + if (extradata & DXD_NAME) + { + // Name + M_Memcpy(player_names[p],demo_p,16); + demo_p += 16; + } + if (extradata & DXD_PLAYSTATE) + { + extradata = READUINT8(demo_p); + + // @TODO uhhhhh do something here + } + + + p = READUINT8(demo_p); + } +} + +void G_WriteDemoExtraData(void) +{ + INT32 i; + char name[16]; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (demo_extradata[i]) + { + WRITEUINT8(demo_p, i); + WRITEUINT8(demo_p, demo_extradata[i]); + + //if (demo_extradata[i] & DXD_RESPAWN) has no extra data + if (demo_extradata[i] & DXD_SKIN) + { + // Skin + memset(name, 0, 16); + strncpy(name, skins[players[i].skin].name, 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; + } + if (demo_extradata[i] & DXD_COLOR) + { + // Color + memset(name, 0, 16); + strncpy(name, KartColor_Names[players[i].skincolor], 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; + } + if (demo_extradata[i] & DXD_NAME) + { + // Name + memset(name, 0, 16); + strncpy(name, player_names[i], 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; + } + if (demo_extradata[i] & DXD_PLAYSTATE) + { + if (!playeringame[i]) + WRITEUINT8(demo_p, DXD_PST_LEFT); + else if (players[i].spectator) + WRITEUINT8(demo_p, DXD_PST_SPECTATING); + else + WRITEUINT8(demo_p, DXD_PST_PLAYING); + } + } + + demo_extradata[i] = 0; + } + + WRITEUINT8(demo_p, 0xFF); +} + void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) { UINT8 ziptic; @@ -5531,6 +5645,7 @@ void G_BeginRecording(void) WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing memset(&oldcmd,0,sizeof(oldcmd)); + memset(&demo_extradata, 0, sizeof(demo_extradata)); // Lower two lines aren't useful until ghost replays for mp are implemented, but eh memset(&oldghost,0,sizeof(oldghost)); memset(&ghostext,0,sizeof(ghostext)); diff --git a/src/g_game.h b/src/g_game.h index 6d11a4a02..f97aecd1c 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -154,7 +154,20 @@ typedef enum GHC_INVINCIBLE } ghostcolor_t; +extern UINT8 demo_extradata[MAXPLAYERS]; +#define DXD_RESPAWN 0x01 // "respawn" command in console +#define DXD_SKIN 0x02 // skin changed +#define DXD_NAME 0x04 // name changed +#define DXD_COLOR 0x08 // color changed +#define DXD_PLAYSTATE 0x10 // state changed between playing, spectating, or not in-game + +#define DXD_PST_PLAYING 0x01 +#define DXD_PST_SPECTATING 0x02 +#define DXD_PST_LEFT 0x03 + // Record/playback tics +void G_ReadDemoExtraData(void); +void G_WriteDemoExtraData(void); void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum); void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum); void G_GhostAddThok(void); diff --git a/src/p_tick.c b/src/p_tick.c index 471b38ecf..4f8829589 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -606,6 +606,7 @@ void P_Ticker(boolean run) for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) G_WriteDemoTiccmd(&players[i].cmd, i); + G_WriteDemoExtraData(); } } if (demoplayback) @@ -617,6 +618,7 @@ void P_Ticker(boolean run) for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) G_ReadDemoTiccmd(&players[i].cmd, i); + G_ReadDemoExtraData(); } } diff --git a/src/r_things.c b/src/r_things.c index d6234d4b3..0f3bf3a83 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2713,6 +2713,9 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) if (player->mo) P_SetScale(player->mo, player->mo->scale); + + demo_extradata[playernum] |= DXD_SKIN; + return; } From f1048d2b5a4ed76bff1eda6c24ad2e82a893b4df Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 19:09:29 -0600 Subject: [PATCH 017/186] Fix crashing at the end of netreplays --- src/g_game.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index ced20e5b2..40475c024 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4614,6 +4614,13 @@ void G_ReadDemoExtraData(void) p = READUINT8(demo_p); } + + if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) + { + // end of demo data stream + G_CheckDemoStatus(); + return; + } } void G_WriteDemoExtraData(void) From 5f0fc3f6816ed1fedf615fd10351233fa39c6b75 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 19:10:25 -0600 Subject: [PATCH 018/186] Write extra data before cmds This will probably nip a possible issue with player cmds getting read/wrote inconsistently if a player joins or leaves. --- src/p_tick.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_tick.c b/src/p_tick.c index 4f8829589..8b99c5aa6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -603,10 +603,10 @@ void P_Ticker(boolean run) if (!multiplayer) { G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); } else { + G_WriteDemoExtraData(); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) G_WriteDemoTiccmd(&players[i].cmd, i); - G_WriteDemoExtraData(); } } if (demoplayback) @@ -615,10 +615,10 @@ void P_Ticker(boolean run) if (!multiplayer) { G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); } else { + G_ReadDemoExtraData(); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) G_ReadDemoTiccmd(&players[i].cmd, i); - G_ReadDemoExtraData(); } } From 63dd29564ec477f141071bed89cac594bb7cc21c Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 19:30:20 -0600 Subject: [PATCH 019/186] Write respawn command usage to replays --- src/d_netcmd.c | 1 + src/g_game.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index d6cf49047..982b75d4c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2536,6 +2536,7 @@ static void Got_Respawn(UINT8 **cp, INT32 playernum) if (players[respawnplayer].mo) P_DamageMobj(players[respawnplayer].mo, NULL, NULL, 10000); + demo_extradata[playernum] |= DXD_RESPAWN; } /** Deals with an ::XD_RANDOMSEED message in a netgame. diff --git a/src/g_game.c b/src/g_game.c index 40475c024..1f43faa35 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4577,7 +4577,6 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_SKIN) { - CONS_Printf("change skin\n"); // Skin M_Memcpy(name, demo_p, 16); demo_p += 16; @@ -4585,7 +4584,6 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_COLOR) { - CONS_Printf("change color\n"); // Color M_Memcpy(name, demo_p, 16); demo_p += 16; From 8473194e8a21c5f3eaffd702fe9956be9d8d46e8 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 27 Jan 2019 20:36:13 -0600 Subject: [PATCH 020/186] Fix replay viewer discarding aim keys --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 1f43faa35..a082abe15 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4690,7 +4690,7 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) if (ziptic & ZT_ANGLE) oldcmd[playernum].angleturn = READINT16(demo_p); if (ziptic & ZT_BUTTONS) - oldcmd[playernum].buttons = (oldcmd[playernum].buttons & (BT_FORWARD|BT_BACKWARD)) | (READUINT16(demo_p) & ~(BT_FORWARD|BT_BACKWARD)); + oldcmd[playernum].buttons = READUINT16(demo_p); if (ziptic & ZT_AIMING) oldcmd[playernum].aiming = READINT16(demo_p); if (ziptic & ZT_DRIFT) From 8837fac7609f707652fffa682af0e67c41426083 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Thu, 31 Jan 2019 00:00:28 -0600 Subject: [PATCH 021/186] 4p split views test --- src/g_game.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index a082abe15..556462121 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6133,6 +6133,19 @@ void G_DoPlayDemo(char *defdemoname) if (!playeringame[displayplayer] || players[displayplayer].spectator) displayplayer = consoleplayer = p; + else if (!spectator && splitscreen < 3) { + if (splitscreen == 0) { + splitscreen = 1; + secondarydisplayplayer = p; + } else if (splitscreen == 1) { + splitscreen = 2; + thirddisplayplayer = p; + } else { + splitscreen = 3; + fourthdisplayplayer = p; + R_ExecuteSetViewSize(); + } + } playeringame[p] = true; players[p].spectator = spectator; From e1c2bc0fa939198c8311159b9657f5f11d6d796e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Thu, 31 Jan 2019 23:03:44 -0600 Subject: [PATCH 022/186] Fix replay split breaking with less than four viewpoints --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 556462121..ab4a6b8e6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6143,7 +6143,6 @@ void G_DoPlayDemo(char *defdemoname) } else { splitscreen = 3; fourthdisplayplayer = p; - R_ExecuteSetViewSize(); } } playeringame[p] = true; @@ -6174,6 +6173,7 @@ void G_DoPlayDemo(char *defdemoname) // Look for the next player p = READUINT8(demo_p); } + R_ExecuteSetViewSize(); } P_SetRandSeed(randseed); From e3e72988d407ed1c7709396192ffe98fec1c8833 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 00:44:35 -0600 Subject: [PATCH 023/186] Make joins/quits/enters/spectates sync in replays I'm not 100% sure on joins. That P_RandomByte() call looks ugly. It'll probably be a source of trouble. --- src/d_clisrv.c | 4 +++- src/d_clisrv.h | 1 + src/d_netcmd.c | 2 ++ src/g_game.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 5369ff2cf..3c8865d6f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2479,13 +2479,15 @@ void CL_ClearPlayer(INT32 playernum) // // Removes a player from the current game // -static void CL_RemovePlayer(INT32 playernum, INT32 reason) +void CL_RemovePlayer(INT32 playernum, INT32 reason) { // Sanity check: exceptional cases (i.e. c-fails) can cause multiple // kick commands to be issued for the same player. if (!playeringame[playernum]) return; + demo_extradata[playernum] |= DXD_PLAYSTATE; + if (server && !demoplayback) { INT32 node = playernode[playernum]; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 39cb8c4de..e59e44195 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -549,6 +549,7 @@ void CL_AddSplitscreenPlayer(void); void CL_RemoveSplitscreenPlayer(UINT8 p); void CL_Reset(void); void CL_ClearPlayer(INT32 playernum); +void CL_RemovePlayer(INT32 playernum, INT32 reason); void CL_UpdateServerList(boolean internetsearch, INT32 room); // Is there a game running boolean Playing(void); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 982b75d4c..7b3925e92 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3362,6 +3362,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) if (gamestate != GS_LEVEL) return; + demo_extradata[playernum] |= DXD_PLAYSTATE; + // Clear player score and rings if a spectator. if (players[playernum].spectator) { diff --git a/src/g_game.c b/src/g_game.c index ab4a6b8e6..25a70b3e1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -14,6 +14,7 @@ #include "doomdef.h" #include "console.h" #include "d_main.h" +#include "d_clisrv.h" #include "d_player.h" #include "f_finale.h" #include "p_setup.h" @@ -3032,6 +3033,8 @@ void G_AddPlayer(INT32 playernum) p->jointime = 0; p->playerstate = PST_REBORN; + + demo_extradata[playernum] |= DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN; // Set everything } void G_ExitLevel(void) @@ -3118,7 +3121,7 @@ boolean G_GametypeHasSpectators(void) #if 0 return (gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE); #else - return (netgame); //true + return (netgame || (multiplayer && demoplayback)); //true #endif } @@ -4607,6 +4610,43 @@ void G_ReadDemoExtraData(void) extradata = READUINT8(demo_p); // @TODO uhhhhh do something here + + switch (extradata) { + case DXD_PST_PLAYING: + players[p].pflags |= PF_WANTSTOJOIN; // fuck you + break; + + case DXD_PST_SPECTATING: + if (!playeringame[p]) + { + CL_ClearPlayer(p); + playeringame[p] = true; + G_AddPlayer(p); + players[p].spectator = true; + P_RandomByte(); // I'm pretty sure this ISN'T right, but it syncs my one test replay. + } + else + { + players[p].spectator = true; + if (players[p].mo) + P_DamageMobj(players[p].mo, NULL, NULL, 10000); + else + players[p].playerstate = PST_REBORN; + } + break; + + case DXD_PST_LEFT: + CL_RemovePlayer(p, 0); + break; + } + + // maybe these are necessary? + if (G_BattleGametype()) + K_CheckBumpers(); // SRB2Kart + else if (G_RaceGametype()) + P_CheckRacers(); // also SRB2Kart + + CONS_Printf("Change state @ %d\n", leveltime); } @@ -4662,7 +4702,10 @@ void G_WriteDemoExtraData(void) { if (!playeringame[i]) WRITEUINT8(demo_p, DXD_PST_LEFT); - else if (players[i].spectator) + else if ( + players[i].spectator && + !(players[i].pflags & PF_WANTSTOJOIN) // <= fuck you specifically + ) WRITEUINT8(demo_p, DXD_PST_SPECTATING); else WRITEUINT8(demo_p, DXD_PST_PLAYING); @@ -6173,6 +6216,7 @@ void G_DoPlayDemo(char *defdemoname) // Look for the next player p = READUINT8(demo_p); } + R_ExecuteSetViewSize(); } From 37b500a75d23c89a6c8f881ceed34b18e57e6a83 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 01:01:14 -0600 Subject: [PATCH 024/186] Tack on a timestamp to replay filenames --- src/p_setup.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index 764ad211a..3b5659c87 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3158,7 +3158,10 @@ boolean P_SetupLevel(boolean skipprecip) //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. if (!demoplayback && multiplayer) { - G_RecordDemo("net_replay_test"); +#include "time.h" + static char buf[256]; + sprintf(buf, "net_replay_test_%d", time(NULL)); + G_RecordDemo(buf); } // =========== From ff8e14b9974e738d75047699760b7d99418c35c4 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 01:32:35 -0600 Subject: [PATCH 025/186] wip replay viewpoint stuff heck im tired zzz good night --- src/g_game.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 25a70b3e1..9125a1317 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1227,6 +1227,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) static boolean keyboard_look, keyboard_look2, keyboard_look3, keyboard_look4; // true if lookup/down using keyboard static boolean resetdown, resetdown2, resetdown3, resetdown4; // don't cam reset every frame + if (demoplayback) return; + switch (ssplayer) { case 2: @@ -1802,7 +1804,7 @@ boolean G_Responder(event_t *ev) if (gamestate == GS_LEVEL && ev->type == ev_keydown && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) { - if (splitscreen || !netgame) + if (!demoplayback && (splitscreen || !netgame)) displayplayer = consoleplayer; else { @@ -1813,9 +1815,12 @@ boolean G_Responder(event_t *ev) if (displayplayer == MAXPLAYERS) displayplayer = 0; - if (displayplayer == consoleplayer) + if (!demoplayback && displayplayer == consoleplayer) break; // End loop + if (displayplayer == secondarydisplayplayer || displayplayer == thirddisplayplayer || displayplayer == fourthdisplayplayer) + continue; + if (!playeringame[displayplayer]) continue; @@ -1874,7 +1879,7 @@ boolean G_Responder(event_t *ev) // any other key pops up menu if in demos if (gameaction == ga_nothing && !singledemo && - ((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN)) + ((demoplayback && !modeattacking && !titledemo && !multiplayer) || gamestate == GS_TITLESCREEN)) { if (ev->type == ev_keydown && ev->data1 != 301) { From e6380ecf3efa056360e3b1ee35cb4fd71a61b3d1 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 07:50:42 -0600 Subject: [PATCH 026/186] Make the join sync hack a little more robust --- src/g_game.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 9125a1317..992a38d25 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4628,7 +4628,10 @@ void G_ReadDemoExtraData(void) playeringame[p] = true; G_AddPlayer(p); players[p].spectator = true; - P_RandomByte(); // I'm pretty sure this ISN'T right, but it syncs my one test replay. + + // There's likely an off-by-one error in timing recording or playback of joins. This hacks around it so I don't have to find out where that is. \o/ + if (oldcmd[p].forwardmove) + P_RandomByte(); } else { From 684ca46d8fef734f055d2e59b3ac2449226d53d4 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 19:28:05 -0600 Subject: [PATCH 027/186] Draw player names in netreplays --- src/st_stuff.c | 38 +++++++++++++++++++++++++++++++------- src/v_video.c | 8 +++++++- src/v_video.h | 1 + 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 8ebd21321..c49478916 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1894,15 +1894,39 @@ static void ST_overlayDrawer(void) V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, STRINGY(hudinfo[HUD_GRAVBOOTSICO].y), V_SNAPTORIGHT, gravboots); */ - if(!P_IsLocalPlayer(stplyr)) + if (!(multiplayer && demoplayback)) { - /*char name[MAXPLAYERNAME+1]; - // shorten the name if its more than twelve characters. - strlcpy(name, player_names[stplyr-players], 13);*/ + if(!P_IsLocalPlayer(stplyr)) + { + /*char name[MAXPLAYERNAME+1]; + // shorten the name if its more than twelve characters. + strlcpy(name, player_names[stplyr-players], 13);*/ - // Show name of player being displayed - V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("Viewpoint:")); - V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[stplyr-players]); + // Show name of player being displayed + V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("Viewpoint:")); + V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[stplyr-players]); + } + } + else + { + + if (!splitscreen) + { + V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Viewpoint:")); + V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_HUDTRANSHALF|V_ALLOWLOWERCASE, player_names[stplyr-players]); + } + else if (splitscreen == 1) + { + char name[MAXPLAYERNAME+12]; + sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]); + + INT32 y = (stplyr == &players[displayplayer]) ? 8 : BASEVIDHEIGHT/2-16; + V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name); + } + else if (splitscreen) + { + V_DrawCenteredThinString(BASEVIDWIDTH/4, 4, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP), player_names[stplyr-players]); + } } // This is where we draw all the fun cheese if you have the chasecam off! diff --git a/src/v_video.c b/src/v_video.c index dd95efe3d..2a16ee474 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1872,6 +1872,12 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) } } +void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string) +{ + x -= V_ThinStringWidth(string, option)/2; + V_DrawThinString(x, y, option, string); +} + void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string) { x -= V_ThinStringWidth(string, option); @@ -2305,7 +2311,7 @@ INT32 V_ThinStringWidth(const char *string, INT32 option) } } - + return w; } diff --git a/src/v_video.h b/src/v_video.h index 4a904f795..bc2549d9c 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -182,6 +182,7 @@ void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *s // draw a string using the tny_font void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string); +void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string); void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string); void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string); From 2a7bde236620c3e27755daf033e58221dc53382d Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 19:46:58 -0600 Subject: [PATCH 028/186] Refactor view changes a bit --- src/d_clisrv.c | 4 +- src/g_game.c | 158 ++++++++++++++++++++++++++++++------------------- src/g_game.h | 2 + 3 files changed, 103 insertions(+), 61 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3c8865d6f..ff15489af 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2561,8 +2561,10 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) RemoveAdminPlayer(playernum); // don't stay admin after you're gone } - if (playernum == displayplayer) + if (playernum == displayplayer && !demoplayback) displayplayer = consoleplayer; // don't look through someone's view who isn't there + else + G_ResetViews(); #ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[playernum]); diff --git a/src/g_game.c b/src/g_game.c index 992a38d25..9d3b442fc 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1808,66 +1808,8 @@ boolean G_Responder(event_t *ev) displayplayer = consoleplayer; else { - UINT8 i = 0; // spy mode - for (i = 0; i < MAXPLAYERS; i++) - { - displayplayer++; - if (displayplayer == MAXPLAYERS) - displayplayer = 0; - - if (!demoplayback && displayplayer == consoleplayer) - break; // End loop - - if (displayplayer == secondarydisplayplayer || displayplayer == thirddisplayplayer || displayplayer == fourthdisplayplayer) - continue; - - if (!playeringame[displayplayer]) - continue; - - if (players[displayplayer].spectator) - continue; - - // SRB2Kart: Only go through players who are actually playing - if (players[displayplayer].exiting) - continue; - - if (players[displayplayer].pflags & PF_TIMEOVER) - continue; - - // I don't know if we want this actually, but I'll humor the suggestion anyway - if (G_BattleGametype()) - { - if (players[displayplayer].kartstuff[k_bumper] <= 0) - continue; - } - - // SRB2Kart: we have no team-based modes, YET... - /*if (G_GametypeHasTeams()) - { - if (players[consoleplayer].ctfteam - && players[displayplayer].ctfteam != players[consoleplayer].ctfteam) - continue; - } - else if (gametype == GT_HIDEANDSEEK) - { - if (players[consoleplayer].pflags & PF_TAGIT) - continue; - } - // Other Tag-based gametypes? - else if (G_TagGametype()) - { - if (!players[consoleplayer].spectator - && (players[consoleplayer].pflags & PF_TAGIT) != (players[displayplayer].pflags & PF_TAGIT)) - continue; - } - else if (G_GametypeHasSpectators() && G_BattleGametype()) - { - if (!players[consoleplayer].spectator) - continue; - }*/ - - break; - } + displayplayer++; + G_ResetViews(); // change statusbar also if playing back demo if (singledemo) @@ -2076,6 +2018,102 @@ boolean G_Responder(event_t *ev) return false; } +static INT32 G_FindView(INT32 startview) +{ + UINT8 i = 0; // spy mode + + startview--; // Ensures view doesn't move if the current view is valid + for (i = 0; i < MAXPLAYERS; i++) + { + startview++; + if (startview == MAXPLAYERS) + startview = 0; + + if (!demoplayback && startview == consoleplayer) + break; // End loop + + if (startview == displayplayer || startview == secondarydisplayplayer || startview == thirddisplayplayer || startview == fourthdisplayplayer) + continue; + + if (!playeringame[startview]) + continue; + + if (players[startview].spectator) + continue; + + // SRB2Kart: Only go through players who are actually playing + if (players[startview].exiting) + continue; + + if (players[startview].pflags & PF_TIMEOVER) + continue; + + // I don't know if we want this actually, but I'll humor the suggestion anyway + if (G_BattleGametype()) + { + if (players[startview].kartstuff[k_bumper] <= 0) + continue; + } + + // SRB2Kart: we have no team-based modes, YET... + /*if (G_GametypeHasTeams()) + { + if (players[consoleplayer].ctfteam + && players[startview].ctfteam != players[consoleplayer].ctfteam) + continue; + } + else if (gametype == GT_HIDEANDSEEK) + { + if (players[consoleplayer].pflags & PF_TAGIT) + continue; + } + // Other Tag-based gametypes? + else if (G_TagGametype()) + { + if (!players[consoleplayer].spectator + && (players[consoleplayer].pflags & PF_TAGIT) != (players[startview].pflags & PF_TAGIT)) + continue; + } + else if (G_GametypeHasSpectators() && G_BattleGametype()) + { + if (!players[consoleplayer].spectator) + continue; + }*/ + + break; + } + + return startview; +} + +// +// G_ResetViews +// Ensures all viewpoints are valid +// +void G_ResetViews(void) +{ + INT32 tempplayer; + + tempplayer = displayplayer; + displayplayer = INT32_MAX; + displayplayer = G_FindView(tempplayer); + + tempplayer = secondarydisplayplayer; + secondarydisplayplayer = INT32_MAX; + secondarydisplayplayer = G_FindView(tempplayer); + + tempplayer = thirddisplayplayer; + thirddisplayplayer = INT32_MAX; + thirddisplayplayer = G_FindView(tempplayer); + + tempplayer = fourthdisplayplayer; + fourthdisplayplayer = INT32_MAX; + fourthdisplayplayer = G_FindView(tempplayer); + + if (demoplayback) + consoleplayer = displayplayer; +} + // // G_Ticker // Make ticcmd_ts for the players. diff --git a/src/g_game.h b/src/g_game.h index f97aecd1c..84ba6c510 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -226,6 +226,8 @@ void G_EndGame(void); // moved from y_inter.c/h and renamed void G_Ticker(boolean run); boolean G_Responder(event_t *ev); +void G_ResetViews(void); + void G_AddPlayer(INT32 playernum); void G_SetExitGameFlag(void); From 0906e02d99776d62e493c9476f703129d1537be3 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 19:53:52 -0600 Subject: [PATCH 029/186] Allow changing all players' viewpoints in replays --- src/g_game.c | 25 +++++++++++++++++++++++++ src/m_menu.c | 8 ++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 9d3b442fc..f17df4f7b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1819,6 +1819,31 @@ boolean G_Responder(event_t *ev) } } + if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demoplayback) + { + if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) + { + secondarydisplayplayer++; + G_ResetViews(); + + return true; + } + else if (ev->data1 == gamecontrol3[gc_viewpoint][0] || ev->data1 == gamecontrol3[gc_viewpoint][1]) + { + thirddisplayplayer++; + G_ResetViews(); + + return true; + } + else if (ev->data1 == gamecontrol4[gc_viewpoint][0] || ev->data1 == gamecontrol4[gc_viewpoint][1]) + { + fourthdisplayplayer++; + G_ResetViews(); + + return true; + } + } + // any other key pops up menu if in demos if (gameaction == ga_nothing && !singledemo && ((demoplayback && !modeattacking && !titledemo && !multiplayer) || gamestate == GS_TITLESCREEN)) diff --git a/src/m_menu.c b/src/m_menu.c index f0831a172..6b357cd63 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8816,7 +8816,7 @@ static void M_Setup1PControlsMenu(INT32 choice) OP_AllControlsMenu[15].status = IT_CONTROL; // Chat //OP_AllControlsMenu[16].status = IT_CONTROL; // Team-chat OP_AllControlsMenu[16].status = IT_CONTROL; // Rankings - OP_AllControlsMenu[17].status = IT_CONTROL; // Viewpoint + //OP_AllControlsMenu[17].status = IT_CONTROL; // Viewpoint // 18 is Reset Camera, 19 is Toggle Chasecam OP_AllControlsMenu[20].status = IT_CONTROL; // Pause OP_AllControlsMenu[21].status = IT_CONTROL; // Screenshot @@ -8848,7 +8848,7 @@ static void M_Setup2PControlsMenu(INT32 choice) OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint + //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint // 18 is Reset Camera, 19 is Toggle Chasecam OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot @@ -8880,7 +8880,7 @@ static void M_Setup3PControlsMenu(INT32 choice) OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint + //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint // 18 is Reset Camera, 19 is Toggle Chasecam OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot @@ -8912,7 +8912,7 @@ static void M_Setup4PControlsMenu(INT32 choice) OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint + //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint // 18 is Reset Camera, 19 is Toggle Chasecam OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot From 7d5649ad978bdffba6f2cb72f710fd3606b8941f Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 20:19:52 -0600 Subject: [PATCH 030/186] Make replays single-view by default unless requested --- src/g_game.c | 109 +++++++++++++++++++++++++++++++++++++++++---------- src/g_game.h | 2 +- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index f17df4f7b..76a799c23 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1809,7 +1809,7 @@ boolean G_Responder(event_t *ev) else { displayplayer++; - G_ResetViews(); + G_ResetViews(1); // change statusbar also if playing back demo if (singledemo) @@ -1823,22 +1823,58 @@ boolean G_Responder(event_t *ev) { if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) { + if (!splitscreen) + { + splitscreen = 1; + secondarydisplayplayer = displayplayer; + G_ResetViews(2); + + P_ResetCamera(&players[secondarydisplayplayer], &camera2); + R_ExecuteSetViewSize(); + + return true; + } + secondarydisplayplayer++; - G_ResetViews(); + G_ResetViews(2); return true; } else if (ev->data1 == gamecontrol3[gc_viewpoint][0] || ev->data1 == gamecontrol3[gc_viewpoint][1]) { + if (splitscreen == 1) + { + splitscreen = 2; + thirddisplayplayer = displayplayer; + G_ResetViews(3); + + P_ResetCamera(&players[thirddisplayplayer], &camera3); + R_ExecuteSetViewSize(); + + return true; + } + thirddisplayplayer++; - G_ResetViews(); + G_ResetViews(3); return true; } else if (ev->data1 == gamecontrol4[gc_viewpoint][0] || ev->data1 == gamecontrol4[gc_viewpoint][1]) { + if (splitscreen == 2) + { + splitscreen = 3; + fourthdisplayplayer = displayplayer; + G_ResetViews(4); + + P_ResetCamera(&players[fourthdisplayplayer], &camera4); + R_ExecuteSetViewSize(); + + return true; + } + fourthdisplayplayer++; - G_ResetViews(); + G_ResetViews(4); return true; } @@ -2057,7 +2093,16 @@ static INT32 G_FindView(INT32 startview) if (!demoplayback && startview == consoleplayer) break; // End loop - if (startview == displayplayer || startview == secondarydisplayplayer || startview == thirddisplayplayer || startview == fourthdisplayplayer) + if (startview == displayplayer) + continue; + + if (splitscreen && startview == secondarydisplayplayer) + continue; + + if (splitscreen >= 2 && startview == thirddisplayplayer) + continue; + + if (splitscreen == 3 && startview == fourthdisplayplayer) continue; if (!playeringame[startview]) @@ -2115,26 +2160,47 @@ static INT32 G_FindView(INT32 startview) // G_ResetViews // Ensures all viewpoints are valid // -void G_ResetViews(void) +void G_ResetViews(UINT8 viewnum) { INT32 tempplayer; - tempplayer = displayplayer; - displayplayer = INT32_MAX; - displayplayer = G_FindView(tempplayer); + if (!viewnum || viewnum == 1) + { + tempplayer = displayplayer; + displayplayer = INT32_MAX; + displayplayer = G_FindView(tempplayer); + } - tempplayer = secondarydisplayplayer; - secondarydisplayplayer = INT32_MAX; - secondarydisplayplayer = G_FindView(tempplayer); + if (splitscreen && demoplayback) + { - tempplayer = thirddisplayplayer; - thirddisplayplayer = INT32_MAX; - thirddisplayplayer = G_FindView(tempplayer); + if (!viewnum || viewnum == 2) + { + tempplayer = secondarydisplayplayer; + secondarydisplayplayer = INT32_MAX; + secondarydisplayplayer = G_FindView(tempplayer); + } - tempplayer = fourthdisplayplayer; - fourthdisplayplayer = INT32_MAX; - fourthdisplayplayer = G_FindView(tempplayer); + if (splitscreen >= 2) + { + if (!viewnum || viewnum == 3) + { + tempplayer = thirddisplayplayer; + thirddisplayplayer = INT32_MAX; + thirddisplayplayer = G_FindView(tempplayer); + } + if (splitscreen == 3) + { + if (!viewnum || viewnum == 4) + { + tempplayer = fourthdisplayplayer; + fourthdisplayplayer = INT32_MAX; + fourthdisplayplayer = G_FindView(tempplayer); + } + } + } + } if (demoplayback) consoleplayer = displayplayer; } @@ -6246,8 +6312,8 @@ void G_DoPlayDemo(char *defdemoname) } if (!playeringame[displayplayer] || players[displayplayer].spectator) - displayplayer = consoleplayer = p; - else if (!spectator && splitscreen < 3) { + displayplayer = consoleplayer = secondarydisplayplayer = thirddisplayplayer = fourthdisplayplayer = p; + /*else if (!spectator && splitscreen < 3) { if (splitscreen == 0) { splitscreen = 1; secondarydisplayplayer = p; @@ -6258,7 +6324,7 @@ void G_DoPlayDemo(char *defdemoname) splitscreen = 3; fourthdisplayplayer = p; } - } + }*/ playeringame[p] = true; players[p].spectator = spectator; @@ -6288,6 +6354,7 @@ void G_DoPlayDemo(char *defdemoname) p = READUINT8(demo_p); } + splitscreen = 0; R_ExecuteSetViewSize(); } diff --git a/src/g_game.h b/src/g_game.h index 84ba6c510..256dd2cff 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -226,7 +226,7 @@ void G_EndGame(void); // moved from y_inter.c/h and renamed void G_Ticker(boolean run); boolean G_Responder(event_t *ev); -void G_ResetViews(void); +void G_ResetViews(UINT8 viewnum); void G_AddPlayer(INT32 playernum); From 46c5e6f533935f566ef21d571362deec8fe57744 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 20:20:14 -0600 Subject: [PATCH 031/186] Fix P3 getting the wrong split flags in 3p splitscreen --- src/k_kart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index ee50cfdd2..0ecb60d58 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4670,7 +4670,7 @@ static void K_KartDrift(player_t *player, boolean onground) player->kartstuff[k_driftend] = 0; } - + // Incease/decrease the drift value to continue drifting in that direction if (player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_jmp] == 1 && onground && player->kartstuff[k_drift] != 0) @@ -6333,9 +6333,9 @@ INT32 K_calcSplitFlags(INT32 snapflags) } else if (splitscreen > 1) { - if (stplyr == &players[thirddisplayplayer] || stplyr == &players[fourthdisplayplayer]) + if (stplyr == &players[thirddisplayplayer] || (splitscreen == 3 && stplyr == &players[fourthdisplayplayer])) splitflags |= V_SPLITSCREEN; - if (stplyr == &players[secondarydisplayplayer] || stplyr == &players[fourthdisplayplayer]) + if (stplyr == &players[secondarydisplayplayer] || (splitscreen == 3 && stplyr == &players[fourthdisplayplayer])) splitflags |= V_HORZSCREEN; } } From c85785f29ca6d722dadd6620a2467813f73df680 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 20:50:33 -0600 Subject: [PATCH 032/186] something --- src/d_clisrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ff15489af..2e3648eef 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2564,7 +2564,7 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) if (playernum == displayplayer && !demoplayback) displayplayer = consoleplayer; // don't look through someone's view who isn't there else - G_ResetViews(); + G_ResetViews(0); #ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[playernum]); From ee35987a31ebb0882f1f595466fdd28d02433e47 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 1 Feb 2019 21:06:52 -0600 Subject: [PATCH 033/186] Play intermission after net replays --- src/d_clisrv.c | 2 +- src/g_game.c | 27 +++++++++++++++++++++------ src/y_inter.c | 13 ++++++++++--- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 2e3648eef..7806fdc21 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4919,7 +4919,7 @@ void TryRunTics(tic_t realtics) if (demoplayback) { - neededtic = gametic + (realtics * cv_playbackspeed.value); + neededtic = gametic + realtics * (gamestate == GS_LEVEL ? cv_playbackspeed.value : 1); // start a game after a demo maketic += realtics; firstticstosend = maketic; diff --git a/src/g_game.c b/src/g_game.c index 76a799c23..a6afbb147 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3589,6 +3589,8 @@ static void G_DoCompleted(void) S_StopSounds(); + if (demoplayback) goto demointermission; + prevmap = (INT16)(gamemap-1); // go to next level @@ -3693,12 +3695,15 @@ static void G_DoCompleted(void) nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, false, NULL); } + // We are committed to this map now. // We may as well allocate its header if it doesn't exist // (That is, if it's a real map) if (nextmap < NUMMAPS && !mapheaderinfo[nextmap]) P_AllocMapHeader(nextmap); +demointermission: + if (skipstats && !modeattacking) // Don't skip stats if we're in record attack G_AfterIntermission(); else @@ -3713,6 +3718,12 @@ void G_AfterIntermission(void) HU_ClearCEcho(); //G_NextLevel(); + if (demoplayback) + { + G_StopDemo(); + D_StartTitle(); + return; + } if (modeattacking) // End the run. { M_EndModeAttackRun(); @@ -4782,8 +4793,6 @@ void G_ReadDemoExtraData(void) K_CheckBumpers(); // SRB2Kart else if (G_RaceGametype()) P_CheckRacers(); // also SRB2Kart - - CONS_Printf("Change state @ %d\n", leveltime); } @@ -6892,12 +6901,18 @@ boolean G_CheckDemoStatus(void) { if (singledemo) I_Quit(); - G_StopDemo(); - if (modeattacking) - M_EndModeAttackRun(); + if (multiplayer) + G_ExitLevel(); else - D_AdvanceDemo(); + { + G_StopDemo(); + + if (modeattacking) + M_EndModeAttackRun(); + else + D_AdvanceDemo(); + } return true; } diff --git a/src/y_inter.c b/src/y_inter.c index 021519e3b..d6f89bdc8 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -360,7 +360,7 @@ void Y_IntermissionDrawer(void) else hilicol = ((intertype == int_race) ? V_SKYMAP : V_REDMAP); - if (sorttic != -1 && intertic > sorttic) + if (sorttic != -1 && intertic > sorttic && !demoplayback) { INT32 count = (intertic - sorttic); @@ -540,9 +540,16 @@ void Y_IntermissionDrawer(void) dotimer: if (timer) { + char *string; INT32 tickdown = (timer+1)/TICRATE; + + if (multiplayer && demoplayback) + string = va("Replay ends in %d", tickdown); + else + string = va("%s starts in %d", cv_advancemap.string, tickdown); + V_DrawCenteredString(BASEVIDWIDTH/2, 188, hilicol, - va("%s starts in %d", cv_advancemap.string, tickdown)); + string); } // Make it obvious that scrambling is happening next round. @@ -603,7 +610,7 @@ void Y_Ticker(void) { if (sorttic == -1) sorttic = intertic + max((cv_inttime.value/2)-2, 2)*TICRATE; // 8 second pause after match results - else + else if (!(multiplayer && demoplayback)) // Don't advance to rankings in replays { if (!data.match.rankingsmode && (intertic >= sorttic + 8)) Y_CalculateMatchData(1, Y_CompareRank); From 3440c23705885b8a505c0ccf96484fe49ce5c2e4 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 2 Feb 2019 00:24:15 -0600 Subject: [PATCH 034/186] Fix map name not showing right on replay intermission --- src/g_game.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index a6afbb147..78111f259 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3589,10 +3589,10 @@ static void G_DoCompleted(void) S_StopSounds(); - if (demoplayback) goto demointermission; - prevmap = (INT16)(gamemap-1); + if (demoplayback) goto demointermission; + // go to next level // nextmap is 0-based, unlike gamemap if (nextmapoverride != 0) From 3618de853ee883d98645cdf64ae427d79f3f1d7b Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 2 Feb 2019 10:54:24 -0600 Subject: [PATCH 035/186] Play generic intermission music after netreplays Mostly because I kept cycling to other people after the top half finished and always got the lose music as a result lol --- src/g_game.c | 2 +- src/p_user.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 78111f259..205773d74 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3581,7 +3581,7 @@ static void G_DoCompleted(void) } // play some generic music if there's no win/cool/lose music going on (for exitlevel commands) - if (G_RaceGametype() && j == splitscreen+1 && (cv_inttime.value > 0)) + if (G_RaceGametype() && ((multiplayer && demoplayback) || j == splitscreen+1) && (cv_inttime.value > 0)) S_ChangeMusicInternal("racent", true); if (automapactive) diff --git a/src/p_user.c b/src/p_user.c index d7423d803..f20c57b84 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1147,6 +1147,9 @@ boolean P_EndingMusic(player_t *player) if (!P_IsLocalPlayer(player)) // Only applies to a local player return false; + if (multiplayer && demoplayback) // Don't play this in multiplayer replays + return false; + // Event - Level Finish // Check for if this is valid or not if (splitscreen) From a7d78cf273b30056b98eaa272d0c249fa94f9417 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 3 Feb 2019 13:55:29 -0600 Subject: [PATCH 036/186] Add support for encore and battle replays --- src/g_game.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 205773d74..171f0a44a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4629,6 +4629,9 @@ char *G_BuildMapTitle(INT32 mapnum) #define DF_NIGHTSATTACK 0x04 // This demo is from NiGHTS attack and contains its time left, score, and mares! #define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? #define DF_ATTACKSHIFT 1 +#define DF_GAMETYPEMASK 0x30 +#define DF_GAMESHIFT 4 +#define DF_ENCORE 0x40 #define DF_MULTIPLAYER 0x80 // This demo contains a dynamic number of players! #define DEMO_SPECTATOR 0x40 @@ -5767,6 +5770,11 @@ void G_BeginRecording(void) demo_p = demobuffer; demoflags = multiplayer ? DF_MULTIPLAYER : (DF_GHOST|(modeattacking<>DF_ATTACKSHIFT; multiplayer = !!(demoflags & DF_MULTIPLAYER); + gametype = (demoflags & DF_GAMETYPEMASK)>>DF_GAMESHIFT; CON_ToggleOff(); hu_demotime = UINT32_MAX; @@ -6368,7 +6377,7 @@ void G_DoPlayDemo(char *defdemoname) } P_SetRandSeed(randseed); - G_InitNew(false, G_BuildMapName(gamemap), true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer. + G_InitNew(demoflags & DF_ENCORE, G_BuildMapName(gamemap), true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer. if (!multiplayer) { // Set skin From 5836b0818a4d41f4e43673bb0019cfd4f95d92be Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 3 Feb 2019 14:29:54 -0600 Subject: [PATCH 037/186] Record net replays to replay/online/ --- src/g_game.c | 2 +- src/p_setup.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 171f0a44a..63e5fb726 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5729,7 +5729,7 @@ void G_RecordDemo(const char *name) { INT32 maxsize; - CONS_Printf("Recording demo %s\n", name); + CONS_Printf("Recording demo %s.lmp\n", name); strcpy(demoname, name); strcat(demoname, ".lmp"); diff --git a/src/p_setup.c b/src/p_setup.c index 3b5659c87..a5e585cfa 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3158,9 +3158,13 @@ boolean P_SetupLevel(boolean skipprecip) //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. if (!demoplayback && multiplayer) { +// lol sorry #include "time.h" static char buf[256]; - sprintf(buf, "net_replay_test_%d", time(NULL)); + sprintf(buf, "replay"PATHSEP"online"PATHSEP"%d-%s", time(NULL), G_BuildMapName(gamemap)); + + I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); + I_mkdir(va("%s"PATHSEP"replay"PATHSEP"online", srb2home), 0755); G_RecordDemo(buf); } From 8a1c6114a7537c329ccd0bf3c9ea910bc333bb66 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 4 Feb 2019 03:09:40 -0800 Subject: [PATCH 038/186] Add support for changing viewpoint via console This isn't just a shameless console-empowerement. More precise "spying" can benefit everybody. But especially in net-replays, this is almost necessary. --- src/d_netcmd.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ src/g_game.c | 38 +++++++++----- src/g_game.h | 2 + src/p_local.h | 2 + src/p_user.c | 12 +++++ 5 files changed, 181 insertions(+), 12 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7b3925e92..9bbb73ef4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -129,6 +129,8 @@ static void Command_StopMovie_f(void); static void Command_Map_f(void); static void Command_ResetCamera_f(void); +static void Command_View_f (void); + static void Command_Addfile(void); static void Command_ListWADS_f(void); #ifdef DELFILE @@ -708,6 +710,11 @@ void D_RegisterClientCommands(void) COM_AddCommand("resetcamera", Command_ResetCamera_f); + COM_AddCommand("view", Command_View_f); + COM_AddCommand("view2", Command_View_f); + COM_AddCommand("view3", Command_View_f); + COM_AddCommand("view4", Command_View_f); + COM_AddCommand("setcontrol", Command_Setcontrol_f); COM_AddCommand("setcontrol2", Command_Setcontrol2_f); COM_AddCommand("setcontrol3", Command_Setcontrol3_f); @@ -1885,6 +1892,138 @@ static void Command_ResetCamera_f(void) P_ResetCamera(&players[displayplayer], &camera); } +static INT32 +RoundToValidPlayerNum (INT32 playernum) +{ + INT32 playernuml, playernumr; + for (playernuml = playernum; --playernuml > 0; ) + { + if (playeringame[playernuml]) + break; + } + for (playernumr = playernum ;; ) + { + if (++playernumr == MAXPLAYERS) + { + playernum = playernuml; + break; + } + if (playeringame[playernumr]) + { + if (playernum - playernuml < playernumr - playernum) + playernum = playernuml;/* "round" down */ + else + playernum = playernumr; + break; + } + } + return playernum; +} + +static INT32/* Consider replacing nametonum with this */ +LookupPlayer (const char *s) +{ + INT32 playernum; + + if (*s == '0')/* clever way to bypass atoi */ + return 0; + + if (( playernum = atoi(s) )) + { + playernum = max(min(playernum, MAXPLAYERS-1), 0);/* not out of range */ + return playernum; + } + + for (playernum = 0; playernum < MAXPLAYERS; ++playernum) + { + /* Consider strcasestr? */ + /* Match name (case-insensitively) fully, or partially the start. */ + if (playeringame[playernum]) + if (stricmp(player_names[playernum], s) == 0 || + strstr(player_names[playernum], s) == player_names[playernum] ) + { + return playernum; + } + } + return -1;/* We can't "round" a name! */ +} + +#define PRINTVIEWPOINT( pre,suf ) \ + CONS_Printf(pre"viewing \x84(%d) \x83%s\x80"suf".\n",\ + (*displayplayerp), player_names[(*displayplayerp)]); +static void +Command_View_f (void) +{ + INT32 *displayplayerp; + int viewnum; + INT32 playernum, oldplayernum; + char c; + /* easy peasy */ + c = COM_Argv(0)[strlen(COM_Argv(0))-1];/* may be digit */ + switch (c) + { + case '2': viewnum = 2; break; + case '3': viewnum = 3; break; + case '4': viewnum = 4; break; + default: viewnum = 1; + } + displayplayerp = G_GetDisplayplayerPtr(viewnum); + + if (COM_Argc() > 1)/* switch to player */ + { + if (viewnum > splitscreen+2)/* We must arrange in order. */ + { + CONS_Alert(CONS_WARNING, + "You may not change viewpoints more than " + "once ahead the current number of splits. " + "Use view%d instead.\n", splitscreen+2); + return; + } + + if (( playernum = LookupPlayer(COM_Argv(1)) ) == -1) + { + CONS_Alert(CONS_WARNING, "There is no player by that name!\n"); + return; + } + + oldplayernum = playernum; + + if (!playeringame[playernum]) + { + playernum = RoundToValidPlayerNum(playernum); + } + + if ((*displayplayerp) == playernum) + return; + + (*displayplayerp) = playernum; + G_ResetViews(viewnum); + + if ((*displayplayerp) != oldplayernum)/* differ parameter */ + { + if (playernum == oldplayernum)/* skipped some */ + { + CONS_Alert(CONS_NOTICE, + "Another viewpoint is already set to that player.\n"); + } + else + { + CONS_Alert(CONS_NOTICE, "There is no player using that slot.\n"); + } + PRINTVIEWPOINT ("Now "," instead") + } + else + PRINTVIEWPOINT ("Now ",) + } + else/* print current view */ + { + if (splitscreen < viewnum-1)/* We can't see those guys! */ + return; + PRINTVIEWPOINT ("Currently ",) + } +} +#undef PRINTVIEWPOINT + // ======================================================================== // play a demo, add .lmp for external demos diff --git a/src/g_game.c b/src/g_game.c index 63e5fb726..c6c091fca 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1825,13 +1825,9 @@ boolean G_Responder(event_t *ev) { if (!splitscreen) { - splitscreen = 1; secondarydisplayplayer = displayplayer; G_ResetViews(2); - P_ResetCamera(&players[secondarydisplayplayer], &camera2); - R_ExecuteSetViewSize(); - return true; } @@ -1844,13 +1840,9 @@ boolean G_Responder(event_t *ev) { if (splitscreen == 1) { - splitscreen = 2; thirddisplayplayer = displayplayer; G_ResetViews(3); - P_ResetCamera(&players[thirddisplayplayer], &camera3); - R_ExecuteSetViewSize(); - return true; } @@ -1863,13 +1855,9 @@ boolean G_Responder(event_t *ev) { if (splitscreen == 2) { - splitscreen = 3; fourthdisplayplayer = displayplayer; G_ResetViews(4); - P_ResetCamera(&players[fourthdisplayplayer], &camera4); - R_ExecuteSetViewSize(); - return true; } @@ -2156,6 +2144,18 @@ static INT32 G_FindView(INT32 startview) return startview; } +INT32 * +G_GetDisplayplayerPtr (UINT8 viewnum) +{ + switch (viewnum) + { + case 2: return &secondarydisplayplayer; + case 3: return &thirddisplayplayer; + case 4: return &fourthdisplayplayer; + } + return &displayplayer; +} + // // G_ResetViews // Ensures all viewpoints are valid @@ -2163,6 +2163,8 @@ static INT32 G_FindView(INT32 startview) void G_ResetViews(UINT8 viewnum) { INT32 tempplayer; + INT32 *displayplayerp; + camera_t *camerap; if (!viewnum || viewnum == 1) { @@ -2171,6 +2173,18 @@ void G_ResetViews(UINT8 viewnum) displayplayer = G_FindView(tempplayer); } + if (viewnum > 1 && multiplayer && demoplayback) + if (viewnum == splitscreen+2) + { + splitscreen = viewnum-1; + + displayplayerp = (G_GetDisplayplayerPtr(viewnum)); + camerap = (P_GetCameraPtr(viewnum)); + + P_ResetCamera(&players[(*displayplayerp)], camerap); + R_ExecuteSetViewSize(); + } + if (splitscreen && demoplayback) { diff --git a/src/g_game.h b/src/g_game.h index 256dd2cff..b64fcabb9 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -226,6 +226,8 @@ void G_EndGame(void); // moved from y_inter.c/h and renamed void G_Ticker(boolean run); boolean G_Responder(event_t *ev); +INT32 * G_GetDisplayplayerPtr (UINT8 viewnum); + void G_ResetViews(UINT8 viewnum); void G_AddPlayer(INT32 playernum); diff --git a/src/p_local.h b/src/p_local.h index cf1387fee..46afc75ea 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -126,6 +126,8 @@ extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate; extern fixed_t t_cam3_dist, t_cam3_height, t_cam3_rotate; extern fixed_t t_cam4_dist, t_cam4_height, t_cam4_rotate; +camera_t * P_GetCameraPtr (UINT8 viewnum); + fixed_t P_GetPlayerHeight(player_t *player); fixed_t P_GetPlayerSpinHeight(player_t *player); void P_AddPlayerScore(player_t *player, UINT32 amount); diff --git a/src/p_user.c b/src/p_user.c index f20c57b84..ce8e3f071 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8124,6 +8124,18 @@ fixed_t t_cam4_rotate = -42; #define MAXCAMERADIST 140*FRACUNIT // Max distance the camera can be in front of the player (2D mode) +camera_t * +P_GetCameraPtr (UINT8 viewnum) +{ + switch (viewnum) + { + case 2: return &camera2; + case 3: return &camera3; + case 4: return &camera4; + } + return &camera; +} + void P_ResetCamera(player_t *player, camera_t *thiscam) { tic_t tries = 0; From f99a7dc36b415370e0f327eb946abef1977b005d Mon Sep 17 00:00:00 2001 From: james Date: Mon, 4 Feb 2019 17:54:41 -0800 Subject: [PATCH 039/186] Shut up when our "new" viewpoint is just the same Also actually correct for new splits. --- src/d_netcmd.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9bbb73ef4..5788eb65f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1955,6 +1955,7 @@ static void Command_View_f (void) { INT32 *displayplayerp; + INT32 olddisplayplayer; int viewnum; INT32 playernum, oldplayernum; char c; @@ -1971,15 +1972,6 @@ Command_View_f (void) if (COM_Argc() > 1)/* switch to player */ { - if (viewnum > splitscreen+2)/* We must arrange in order. */ - { - CONS_Alert(CONS_WARNING, - "You may not change viewpoints more than " - "once ahead the current number of splits. " - "Use view%d instead.\n", splitscreen+2); - return; - } - if (( playernum = LookupPlayer(COM_Argv(1)) ) == -1) { CONS_Alert(CONS_WARNING, "There is no player by that name!\n"); @@ -1993,12 +1985,14 @@ Command_View_f (void) playernum = RoundToValidPlayerNum(playernum); } - if ((*displayplayerp) == playernum) - return; - + olddisplayplayer = (*displayplayerp); (*displayplayerp) = playernum; G_ResetViews(viewnum); + /* The player we wanted was corrected to who it already was. */ + if ((*displayplayerp) == olddisplayplayer) + return; + if ((*displayplayerp) != oldplayernum)/* differ parameter */ { if (playernum == oldplayernum)/* skipped some */ From b777ae0ca8abc559fb5318142481dd773253cfbe Mon Sep 17 00:00:00 2001 From: james Date: Mon, 4 Feb 2019 17:58:55 -0800 Subject: [PATCH 040/186] Automatically load splits up to new viewpoint Basically, you can start viewing your third split and the second one views another! --- src/g_game.c | 124 +++++++++++++++++++++------------------------------ 1 file changed, 52 insertions(+), 72 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index c6c091fca..8fbcec0c6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1823,14 +1823,6 @@ boolean G_Responder(event_t *ev) { if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) { - if (!splitscreen) - { - secondarydisplayplayer = displayplayer; - G_ResetViews(2); - - return true; - } - secondarydisplayplayer++; G_ResetViews(2); @@ -1838,14 +1830,6 @@ boolean G_Responder(event_t *ev) } else if (ev->data1 == gamecontrol3[gc_viewpoint][0] || ev->data1 == gamecontrol3[gc_viewpoint][1]) { - if (splitscreen == 1) - { - thirddisplayplayer = displayplayer; - G_ResetViews(3); - - return true; - } - thirddisplayplayer++; G_ResetViews(3); @@ -1853,14 +1837,6 @@ boolean G_Responder(event_t *ev) } else if (ev->data1 == gamecontrol4[gc_viewpoint][0] || ev->data1 == gamecontrol4[gc_viewpoint][1]) { - if (splitscreen == 2) - { - fourthdisplayplayer = displayplayer; - G_ResetViews(4); - - return true; - } - fourthdisplayplayer++; G_ResetViews(4); @@ -2156,65 +2132,69 @@ G_GetDisplayplayerPtr (UINT8 viewnum) return &displayplayer; } +/* Reset only one view */ +static void +G_ResetView (UINT8 viewnum) +{ + INT32 *displayplayerp; + camera_t *camerap; + + INT32 newdisplayplayer; + UINT8 viewd, splits; + + splits = splitscreen+1; + + displayplayerp = (G_GetDisplayplayerPtr(viewnum)); + newdisplayplayer = (*displayplayerp); + (*displayplayerp) = INT32_MAX; + (*displayplayerp) = G_FindView(newdisplayplayer); + + if (viewnum > splits) + { + splitscreen = viewnum-1; + + for (viewd = splits+1; viewd < viewnum; ++viewd) + { + (*(G_GetDisplayplayerPtr(viewd))) = INT32_MAX;/* ensure clean */ + } + /* Initialise views up from current splitscreen. */ + for (viewd = splits+1 ;; ) + { + displayplayerp = (G_GetDisplayplayerPtr(viewd)); + camerap = (P_GetCameraPtr(viewd)); + + P_ResetCamera(&players[(*displayplayerp)], camerap); + R_ExecuteSetViewSize(); + + if (++viewd > viewnum) + break; + + /* Correct up to but viewnum */ + (*displayplayerp) = G_FindView((*displayplayerp)); + } + } +} + // // G_ResetViews // Ensures all viewpoints are valid // void G_ResetViews(UINT8 viewnum) { - INT32 tempplayer; - INT32 *displayplayerp; - camera_t *camerap; + UINT8 splits = splitscreen+1; - if (!viewnum || viewnum == 1) + if (viewnum == 0) { - tempplayer = displayplayer; - displayplayer = INT32_MAX; - displayplayer = G_FindView(tempplayer); - } - - if (viewnum > 1 && multiplayer && demoplayback) - if (viewnum == splitscreen+2) - { - splitscreen = viewnum-1; - - displayplayerp = (G_GetDisplayplayerPtr(viewnum)); - camerap = (P_GetCameraPtr(viewnum)); - - P_ResetCamera(&players[(*displayplayerp)], camerap); - R_ExecuteSetViewSize(); - } - - if (splitscreen && demoplayback) - { - - if (!viewnum || viewnum == 2) + while (viewnum++ < splits) { - tempplayer = secondarydisplayplayer; - secondarydisplayplayer = INT32_MAX; - secondarydisplayplayer = G_FindView(tempplayer); - } - - if (splitscreen >= 2) - { - if (!viewnum || viewnum == 3) - { - tempplayer = thirddisplayplayer; - thirddisplayplayer = INT32_MAX; - thirddisplayplayer = G_FindView(tempplayer); - } - - if (splitscreen == 3) - { - if (!viewnum || viewnum == 4) - { - tempplayer = fourthdisplayplayer; - fourthdisplayplayer = INT32_MAX; - fourthdisplayplayer = G_FindView(tempplayer); - } - } + G_ResetView(viewnum); } } + else + { + G_ResetView(viewnum); + } + if (demoplayback) consoleplayer = displayplayer; } From b17607c3c3ae30e178ae44cbe86d6bdafa5ef24f Mon Sep 17 00:00:00 2001 From: james Date: Mon, 4 Feb 2019 20:09:36 -0800 Subject: [PATCH 041/186] Expose G_ResetView and amend G_ResetViews (fickle's suggestion.) --- src/d_clisrv.c | 2 +- src/d_netcmd.c | 2 +- src/g_game.c | 35 +++++++++++++++-------------------- src/g_game.h | 3 ++- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7806fdc21..72f0dd2b1 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2564,7 +2564,7 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) if (playernum == displayplayer && !demoplayback) displayplayer = consoleplayer; // don't look through someone's view who isn't there else - G_ResetViews(0); + G_ResetViews(); #ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[playernum]); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5788eb65f..84741c054 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1987,7 +1987,7 @@ Command_View_f (void) olddisplayplayer = (*displayplayerp); (*displayplayerp) = playernum; - G_ResetViews(viewnum); + G_ResetView(viewnum); /* The player we wanted was corrected to who it already was. */ if ((*displayplayerp) == olddisplayplayer) diff --git a/src/g_game.c b/src/g_game.c index 8fbcec0c6..ca003248a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1809,7 +1809,7 @@ boolean G_Responder(event_t *ev) else { displayplayer++; - G_ResetViews(1); + G_ResetView(1); // change statusbar also if playing back demo if (singledemo) @@ -1824,21 +1824,21 @@ boolean G_Responder(event_t *ev) if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) { secondarydisplayplayer++; - G_ResetViews(2); + G_ResetView(2); return true; } else if (ev->data1 == gamecontrol3[gc_viewpoint][0] || ev->data1 == gamecontrol3[gc_viewpoint][1]) { thirddisplayplayer++; - G_ResetViews(3); + G_ResetView(3); return true; } else if (ev->data1 == gamecontrol4[gc_viewpoint][0] || ev->data1 == gamecontrol4[gc_viewpoint][1]) { fourthdisplayplayer++; - G_ResetViews(4); + G_ResetView(4); return true; } @@ -2132,8 +2132,10 @@ G_GetDisplayplayerPtr (UINT8 viewnum) return &displayplayer; } -/* Reset only one view */ -static void +/* +Ensure a viewpoint is valid. +*/ +void G_ResetView (UINT8 viewnum) { INT32 *displayplayerp; @@ -2173,30 +2175,23 @@ G_ResetView (UINT8 viewnum) (*displayplayerp) = G_FindView((*displayplayerp)); } } + + if (viewnum == 1 && demoplayback) + consoleplayer = displayplayer; } // // G_ResetViews // Ensures all viewpoints are valid // -void G_ResetViews(UINT8 viewnum) +void G_ResetViews(void) { - UINT8 splits = splitscreen+1; - - if (viewnum == 0) - { - while (viewnum++ < splits) - { - G_ResetView(viewnum); - } - } - else + UINT8 viewnum = splitscreen+1; + do { G_ResetView(viewnum); } - - if (demoplayback) - consoleplayer = displayplayer; + while (--viewnum > 0) ; } // diff --git a/src/g_game.h b/src/g_game.h index b64fcabb9..a28a709e5 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -228,7 +228,8 @@ boolean G_Responder(event_t *ev); INT32 * G_GetDisplayplayerPtr (UINT8 viewnum); -void G_ResetViews(UINT8 viewnum); +void G_ResetViews(void); +void G_ResetView (UINT8 viewnum); void G_AddPlayer(INT32 playernum); From d7db80589106742172a3e885f9e9baec821eedc6 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 4 Feb 2019 20:16:54 -0800 Subject: [PATCH 042/186] Do not round player numbers in range (fickle's suggestion.) --- src/d_netcmd.c | 50 +++++++------------------------------------------- 1 file changed, 7 insertions(+), 43 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 84741c054..223537012 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1892,34 +1892,6 @@ static void Command_ResetCamera_f(void) P_ResetCamera(&players[displayplayer], &camera); } -static INT32 -RoundToValidPlayerNum (INT32 playernum) -{ - INT32 playernuml, playernumr; - for (playernuml = playernum; --playernuml > 0; ) - { - if (playeringame[playernuml]) - break; - } - for (playernumr = playernum ;; ) - { - if (++playernumr == MAXPLAYERS) - { - playernum = playernuml; - break; - } - if (playeringame[playernumr]) - { - if (playernum - playernuml < playernumr - playernum) - playernum = playernuml;/* "round" down */ - else - playernum = playernumr; - break; - } - } - return playernum; -} - static INT32/* Consider replacing nametonum with this */ LookupPlayer (const char *s) { @@ -1945,7 +1917,7 @@ LookupPlayer (const char *s) return playernum; } } - return -1;/* We can't "round" a name! */ + return -1; } #define PRINTVIEWPOINT( pre,suf ) \ @@ -1957,7 +1929,7 @@ Command_View_f (void) INT32 *displayplayerp; INT32 olddisplayplayer; int viewnum; - INT32 playernum, oldplayernum; + INT32 playernum; char c; /* easy peasy */ c = COM_Argv(0)[strlen(COM_Argv(0))-1];/* may be digit */ @@ -1977,12 +1949,10 @@ Command_View_f (void) CONS_Alert(CONS_WARNING, "There is no player by that name!\n"); return; } - - oldplayernum = playernum; - if (!playeringame[playernum]) { - playernum = RoundToValidPlayerNum(playernum); + CONS_Alert(CONS_WARNING, "There is no player using that slot!\n"); + return; } olddisplayplayer = (*displayplayerp); @@ -1995,15 +1965,9 @@ Command_View_f (void) if ((*displayplayerp) != oldplayernum)/* differ parameter */ { - if (playernum == oldplayernum)/* skipped some */ - { - CONS_Alert(CONS_NOTICE, - "Another viewpoint is already set to that player.\n"); - } - else - { - CONS_Alert(CONS_NOTICE, "There is no player using that slot.\n"); - } + /* skipped some */ + CONS_Alert(CONS_NOTICE, + "Another viewpoint is already set to that player.\n"); PRINTVIEWPOINT ("Now "," instead") } else From cd8cd10dbce50b9453a2e9adc8b59a53589ded87 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 4 Feb 2019 20:29:52 -0800 Subject: [PATCH 043/186] Bleh old stuff --- src/d_netcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 223537012..36275305b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1963,7 +1963,7 @@ Command_View_f (void) if ((*displayplayerp) == olddisplayplayer) return; - if ((*displayplayerp) != oldplayernum)/* differ parameter */ + if ((*displayplayerp) != playernum)/* differ parameter */ { /* skipped some */ CONS_Alert(CONS_NOTICE, From 3821918cb5aa49d4ddfc73489e791d788459089b Mon Sep 17 00:00:00 2001 From: james Date: Mon, 4 Feb 2019 20:48:48 -0800 Subject: [PATCH 044/186] Restrict viewn command to netreplays --- src/d_netcmd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 36275305b..ab0f4bf38 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1940,6 +1940,13 @@ Command_View_f (void) case '4': viewnum = 4; break; default: viewnum = 1; } + + if (viewnum > 1 && !( multiplayer && demoplayback )) + { + CONS_Alert(CONS_NOTICE, "You must be viewing a multiplayer replay.\n"); + return; + } + displayplayerp = G_GetDisplayplayerPtr(viewnum); if (COM_Argc() > 1)/* switch to player */ From 460bc3c4ec953b3fd640f6bb2542451313af4e05 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 4 Feb 2019 21:23:48 -0800 Subject: [PATCH 045/186] Show scores but not "Player 1" in netreplays --- src/hu_stuff.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a308dfc2b..2c5bf153c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2109,8 +2109,11 @@ UINT32 hu_demolap; static void HU_DrawDemoInfo(void) { - V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("Replay:")); - V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[0]); + if (!multiplayer)/* netreplay */ + { + V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("Replay:")); + V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[0]); + } if (modeattacking) { V_DrawRightAlignedString((BASEVIDWIDTH/2)-4, BASEVIDHEIGHT-24, V_YELLOWMAP|V_MONOSPACE, "BEST TIME:"); @@ -2227,10 +2230,7 @@ void HU_Drawer(void) if (cechotimer) HU_DrawCEcho(); - if (demoplayback && hu_showscores) - HU_DrawDemoInfo(); - - if (!Playing() + if (!( Playing() || demoplayback ) || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND @@ -2250,6 +2250,10 @@ void HU_Drawer(void) LUAh_ScoresHUD(); #endif } + if (demoplayback) + { + HU_DrawDemoInfo(); + } } if (gamestate != GS_LEVEL) From dab16409ce5fc3e11dcc536c49cf2f155d695f0c Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Feb 2019 20:25:27 -0600 Subject: [PATCH 046/186] Fix views not setting properly when adding multiple at once --- src/g_game.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index ca003248a..a69d76ee2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2166,14 +2166,14 @@ G_ResetView (UINT8 viewnum) camerap = (P_GetCameraPtr(viewd)); P_ResetCamera(&players[(*displayplayerp)], camerap); - R_ExecuteSetViewSize(); if (++viewd > viewnum) break; /* Correct up to but viewnum */ - (*displayplayerp) = G_FindView((*displayplayerp)); + (*displayplayerp) = G_FindView(displayplayer); } + R_ExecuteSetViewSize(); } if (viewnum == 1 && demoplayback) From e5cdf6d84d647d9c8a597260453e590a7c8bb150 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Feb 2019 20:25:45 -0600 Subject: [PATCH 047/186] Format for better consistency with the codebase --- src/d_netcmd.c | 7 +++---- src/g_game.c | 13 ++++++------- src/g_game.h | 4 ++-- src/p_local.h | 2 +- src/p_user.c | 3 +-- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index ab0f4bf38..6fb8aa708 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1892,8 +1892,8 @@ static void Command_ResetCamera_f(void) P_ResetCamera(&players[displayplayer], &camera); } -static INT32/* Consider replacing nametonum with this */ -LookupPlayer (const char *s) +/* Consider replacing nametonum with this */ +static INT32 LookupPlayer(const char *s) { INT32 playernum; @@ -1923,8 +1923,7 @@ LookupPlayer (const char *s) #define PRINTVIEWPOINT( pre,suf ) \ CONS_Printf(pre"viewing \x84(%d) \x83%s\x80"suf".\n",\ (*displayplayerp), player_names[(*displayplayerp)]); -static void -Command_View_f (void) +static void Command_View_f(void) { INT32 *displayplayerp; INT32 olddisplayplayer; diff --git a/src/g_game.c b/src/g_game.c index a69d76ee2..c100ce926 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2120,8 +2120,7 @@ static INT32 G_FindView(INT32 startview) return startview; } -INT32 * -G_GetDisplayplayerPtr (UINT8 viewnum) +INT32 *G_GetDisplayplayerPtr(UINT8 viewnum) { switch (viewnum) { @@ -2132,11 +2131,11 @@ G_GetDisplayplayerPtr (UINT8 viewnum) return &displayplayer; } -/* -Ensure a viewpoint is valid. -*/ -void -G_ResetView (UINT8 viewnum) +// +// G_ResetView +// Ensures a viewpoint is valid. +// +void G_ResetView(UINT8 viewnum) { INT32 *displayplayerp; camera_t *camerap; diff --git a/src/g_game.h b/src/g_game.h index a28a709e5..cf7dda09b 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -226,10 +226,10 @@ void G_EndGame(void); // moved from y_inter.c/h and renamed void G_Ticker(boolean run); boolean G_Responder(event_t *ev); -INT32 * G_GetDisplayplayerPtr (UINT8 viewnum); +INT32 *G_GetDisplayplayerPtr(UINT8 viewnum); void G_ResetViews(void); -void G_ResetView (UINT8 viewnum); +void G_ResetView(UINT8 viewnum); void G_AddPlayer(INT32 playernum); diff --git a/src/p_local.h b/src/p_local.h index 46afc75ea..12d582aa2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -126,7 +126,7 @@ extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate; extern fixed_t t_cam3_dist, t_cam3_height, t_cam3_rotate; extern fixed_t t_cam4_dist, t_cam4_height, t_cam4_rotate; -camera_t * P_GetCameraPtr (UINT8 viewnum); +camera_t *P_GetCameraPtr(UINT8 viewnum); fixed_t P_GetPlayerHeight(player_t *player); fixed_t P_GetPlayerSpinHeight(player_t *player); diff --git a/src/p_user.c b/src/p_user.c index ce8e3f071..803f1c135 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8124,8 +8124,7 @@ fixed_t t_cam4_rotate = -42; #define MAXCAMERADIST 140*FRACUNIT // Max distance the camera can be in front of the player (2D mode) -camera_t * -P_GetCameraPtr (UINT8 viewnum) +camera_t *P_GetCameraPtr(UINT8 viewnum) { switch (viewnum) { From 4f8ef7c3aa9fe062a4af2e9e74456d14dc1d68f4 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Feb 2019 21:03:05 -0600 Subject: [PATCH 048/186] Fix compile warnings --- src/g_game.c | 3 +-- src/p_setup.c | 8 +++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 2bdaaf119..8a8b021cc 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6113,7 +6113,7 @@ void G_DoPlayDemo(char *defdemoname) UINT8 i, p; lumpnum_t l; char skin[17],color[17],*n,*pdemoname; - UINT8 version,subversion,kartspeed,kartweight; + UINT8 version,subversion,kartspeed=5,kartweight=5; UINT32 randseed; char msg[1024]; #if defined(SKIPERRORS) && !defined(DEVELOP) @@ -6342,7 +6342,6 @@ void G_DoPlayDemo(char *defdemoname) playeringame[0] = !multiplayer; if (multiplayer) { - player_t *player; boolean spectator; // Load players that were in-game when the map started diff --git a/src/p_setup.c b/src/p_setup.c index ce162af61..08bcfd2f5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -65,6 +65,10 @@ #include "lua_script.h" #include "lua_hook.h" +#if !defined (UNDER_CE) +#include +#endif + #if defined (_WIN32) || defined (_WIN32_WCE) #include #include @@ -3161,10 +3165,8 @@ boolean P_SetupLevel(boolean skipprecip) //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. if (!demoplayback && multiplayer) { -// lol sorry -#include "time.h" static char buf[256]; - sprintf(buf, "replay"PATHSEP"online"PATHSEP"%d-%s", time(NULL), G_BuildMapName(gamemap)); + sprintf(buf, "replay"PATHSEP"online"PATHSEP"%d-%s", (int) (time(NULL)), G_BuildMapName(gamemap)); I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); I_mkdir(va("%s"PATHSEP"replay"PATHSEP"online", srb2home), 0755); From 011a498f4b0d6f932446c698625d2304c3755a6b Mon Sep 17 00:00:00 2001 From: james Date: Tue, 12 Feb 2019 19:16:36 -0800 Subject: [PATCH 049/186] view command: match names case-insensitively --- src/d_netcmd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 802037899..c1a92f5b9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1912,11 +1912,10 @@ static INT32 LookupPlayer(const char *s) for (playernum = 0; playernum < MAXPLAYERS; ++playernum) { - /* Consider strcasestr? */ - /* Match name (case-insensitively) fully, or partially the start. */ + /* Match name case-insensitively: fully, or partially the start. */ if (playeringame[playernum]) if (stricmp(player_names[playernum], s) == 0 || - strstr(player_names[playernum], s) == player_names[playernum] ) + strnicmp(player_names[playernum], s, strlen(s)) == 0) { return playernum; } From 0c5cc4872f499888a6cfd3e2797717c682dc4058 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 13 Feb 2019 16:17:48 -0800 Subject: [PATCH 050/186] Support splitscreen views in netreplays with less than four players The first view is also not changed if there are no players to view. --- src/d_netcmd.c | 2 +- src/g_game.c | 302 ++++++++++++++++++++++++++++++++----------------- src/g_game.h | 9 +- 3 files changed, 208 insertions(+), 105 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c1a92f5b9..54267d998 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1966,7 +1966,7 @@ static void Command_View_f(void) olddisplayplayer = (*displayplayerp); (*displayplayerp) = playernum; - G_ResetView(viewnum); + G_ResetView(viewnum, playernum); /* The player we wanted was corrected to who it already was. */ if ((*displayplayerp) == olddisplayplayer) diff --git a/src/g_game.c b/src/g_game.c index 8a8b021cc..bd1f3df9c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1831,8 +1831,7 @@ boolean G_Responder(event_t *ev) displayplayer = consoleplayer; else { - displayplayer++; - G_ResetView(1); + G_AdjustView(1, 1); // change statusbar also if playing back demo if (singledemo) @@ -1846,22 +1845,19 @@ boolean G_Responder(event_t *ev) { if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) { - secondarydisplayplayer++; - G_ResetView(2); + G_AdjustView(2, 1); return true; } else if (ev->data1 == gamecontrol3[gc_viewpoint][0] || ev->data1 == gamecontrol3[gc_viewpoint][1]) { - thirddisplayplayer++; - G_ResetView(3); + G_AdjustView(3, 1); return true; } else if (ev->data1 == gamecontrol4[gc_viewpoint][0] || ev->data1 == gamecontrol4[gc_viewpoint][1]) { - fourthdisplayplayer++; - G_ResetView(4); + G_AdjustView(4, 1); return true; } @@ -2066,81 +2062,131 @@ boolean G_Responder(event_t *ev) return false; } -static INT32 G_FindView(INT32 startview) +// +// G_CouldView +// Return whether a player could be viewed by any means. +// +boolean G_CouldView(INT32 playernum) { - UINT8 i = 0; // spy mode + player_t *player; - startview--; // Ensures view doesn't move if the current view is valid - for (i = 0; i < MAXPLAYERS; i++) + if (playernum < 0 || playernum > MAXPLAYERS-1) + return false; + + if (!playeringame[playernum]) + return false; + + player = &players[playernum]; + + if (player->spectator) + return false; + + // SRB2Kart: Only go through players who are actually playing + if (player->exiting) + return false; + if (( player->pflags & PF_TIMEOVER )) + return false; + + // I don't know if we want this actually, but I'll humor the suggestion anyway + if (G_BattleGametype()) { - startview++; - if (startview == MAXPLAYERS) - startview = 0; - - if (!demoplayback && startview == consoleplayer) - break; // End loop - - if (startview == displayplayer) - continue; - - if (splitscreen && startview == secondarydisplayplayer) - continue; - - if (splitscreen >= 2 && startview == thirddisplayplayer) - continue; - - if (splitscreen == 3 && startview == fourthdisplayplayer) - continue; - - if (!playeringame[startview]) - continue; - - if (players[startview].spectator) - continue; - - // SRB2Kart: Only go through players who are actually playing - if (players[startview].exiting) - continue; - - if (players[startview].pflags & PF_TIMEOVER) - continue; - - // I don't know if we want this actually, but I'll humor the suggestion anyway - if (G_BattleGametype()) - { - if (players[startview].kartstuff[k_bumper] <= 0) - continue; - } - - // SRB2Kart: we have no team-based modes, YET... - /*if (G_GametypeHasTeams()) - { - if (players[consoleplayer].ctfteam - && players[startview].ctfteam != players[consoleplayer].ctfteam) - continue; - } - else if (gametype == GT_HIDEANDSEEK) - { - if (players[consoleplayer].pflags & PF_TAGIT) - continue; - } - // Other Tag-based gametypes? - else if (G_TagGametype()) - { - if (!players[consoleplayer].spectator - && (players[consoleplayer].pflags & PF_TAGIT) != (players[startview].pflags & PF_TAGIT)) - continue; - } - else if (G_GametypeHasSpectators() && G_BattleGametype()) - { - if (!players[consoleplayer].spectator) - continue; - }*/ - - break; + if (player->kartstuff[k_bumper] <= 0) + return false; } - return startview; + // SRB2Kart: we have no team-based modes, YET... + /*if (G_GametypeHasTeams()) + { + if (players[consoleplayer].ctfteam + && player->ctfteam != players[consoleplayer].ctfteam) + return false; + } + else if (gametype == GT_HIDEANDSEEK) + { + if (players[consoleplayer].pflags & PF_TAGIT) + return false; + } + // Other Tag-based gametypes? + else if (G_TagGametype()) + { + if (!players[consoleplayer].spectator + && (players[consoleplayer].pflags & PF_TAGIT) != (player->pflags & PF_TAGIT)) + return false; + } + else if (G_GametypeHasSpectators() && G_BattleGametype()) + { + if (!players[consoleplayer].spectator) + return false; + }*/ + + return true; +} + +// +// G_CanView +// Return whether a player can be viewed on a particular view (splitscreen). +// +boolean G_CanView(INT32 playernum, UINT8 viewnum) +{ + UINT8 splits; + UINT8 viewd; + INT32 *displayplayerp; + + if (!G_CouldView(playernum)) + return false; + + splits = splitscreen+1; + if (viewnum > splits) + viewnum = splits; + + for (viewd = 1; viewd < viewnum; ++viewd) + { + displayplayerp = (G_GetDisplayplayerPtr(viewd)); + if ((*displayplayerp) == playernum) + return false; + } + for (viewd = viewnum + 1; viewd <= splits; ++viewd) + { + displayplayerp = (G_GetDisplayplayerPtr(viewd)); + if ((*displayplayerp) == playernum) + return false; + } + + return true; +} + +// +// G_FindView +// Return the next player that can be viewed on a view, wraps forward. +// An out of range startview is corrected. +// +INT32 G_FindView(INT32 startview, UINT8 viewnum) +{ + INT32 i; + startview = min(max(startview, 0), MAXPLAYERS); + for (i = startview; i < MAXPLAYERS; ++i) + { + if (G_CanView(i, viewnum)) + return i; + } + for (i = 0; i < startview; ++i) + { + if (G_CanView(i, viewnum)) + return i; + } + return -1; +} + +INT32 G_CountPlayersPotentiallyViewable(void) +{ + INT32 total = 0; + INT32 i; + for (i = 0; i < MAXPLAYERS; ++i) + { + if (G_CouldView(i)) + total++; + } + return total; } INT32 *G_GetDisplayplayerPtr(UINT8 viewnum) @@ -2156,64 +2202,114 @@ INT32 *G_GetDisplayplayerPtr(UINT8 viewnum) // // G_ResetView -// Ensures a viewpoint is valid. +// Correct a viewpoint to playernum or the next available, wraps forward. +// Also promotes splitscreen up to available viewable players. +// An out of range playernum is corrected. // -void G_ResetView(UINT8 viewnum) +void G_ResetView(UINT8 viewnum, INT32 playernum) { + UINT8 splits; + UINT8 viewd; + INT32 *displayplayerp; camera_t *camerap; - INT32 newdisplayplayer; - UINT8 viewd, splits; + INT32 olddisplayplayer; + INT32 playersviewable; splits = splitscreen+1; + /* Promote splits */ + if (viewnum > splits) + { + playersviewable = G_CountPlayersPotentiallyViewable(); + if (playersviewable < splits)/* do not demote */ + return; + + if (viewnum > playersviewable) + viewnum = playersviewable; + splitscreen = viewnum-1; + + /* Prepare extra views for G_FindView to pass. */ + for (viewd = splits+1; viewd < viewnum; ++viewd) + { + displayplayerp = (G_GetDisplayplayerPtr(viewd)); + (*displayplayerp) = INT32_MAX; + } + + R_ExecuteSetViewSize(); + } + + /* Focus our target view first so that we don't take its player. */ displayplayerp = (G_GetDisplayplayerPtr(viewnum)); - newdisplayplayer = (*displayplayerp); - (*displayplayerp) = INT32_MAX; - (*displayplayerp) = G_FindView(newdisplayplayer); + olddisplayplayer = (*displayplayerp); + (*displayplayerp) = G_FindView(playernum, viewnum); + if ((*displayplayerp) != olddisplayplayer) + { + camerap = (P_GetCameraPtr(viewnum)); + P_ResetCamera(&players[(*displayplayerp)], camerap); + } if (viewnum > splits) { - splitscreen = viewnum-1; - for (viewd = splits+1; viewd < viewnum; ++viewd) - { - (*(G_GetDisplayplayerPtr(viewd))) = INT32_MAX;/* ensure clean */ - } - /* Initialise views up from current splitscreen. */ - for (viewd = splits+1 ;; ) { displayplayerp = (G_GetDisplayplayerPtr(viewd)); camerap = (P_GetCameraPtr(viewd)); + (*displayplayerp) = G_FindView(0, viewd); + P_ResetCamera(&players[(*displayplayerp)], camerap); - - if (++viewd > viewnum) - break; - - /* Correct up to but viewnum */ - (*displayplayerp) = G_FindView(displayplayer); } - R_ExecuteSetViewSize(); } if (viewnum == 1 && demoplayback) consoleplayer = displayplayer; } +// +// G_AdjustView +// Increment a viewpoint by offset from the current player. A negative value +// decrements. +// +void G_AdjustView(UINT8 viewnum, INT32 offset) +{ + INT32 *displayplayerp; + displayplayerp = G_GetDisplayplayerPtr(viewnum); + G_ResetView(viewnum, ( (*displayplayerp) + offset )); +} + // // G_ResetViews // Ensures all viewpoints are valid +// Also demotes splitscreen down to one player. // void G_ResetViews(void) { - UINT8 viewnum = splitscreen+1; - do + UINT8 splits; + UINT8 viewd; + + INT32 playersviewable; + + splits = splitscreen+1; + + playersviewable = G_CountPlayersPotentiallyViewable(); + /* Demote splits */ + if (playersviewable < splits) { - G_ResetView(viewnum); + splits = playersviewable; + splitscreen = max(splits-1, 0); + R_ExecuteSetViewSize(); + } + + /* + Consider installing a method to focus the last + view elsewhere if all players spectate? + */ + for (viewd = 1; viewd <= splits; ++viewd) + { + G_AdjustView(viewd, 0); } - while (--viewnum > 0) ; } // diff --git a/src/g_game.h b/src/g_game.h index 9d9a47552..9a485ffec 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -228,8 +228,15 @@ boolean G_Responder(event_t *ev); INT32 *G_GetDisplayplayerPtr(UINT8 viewnum); +boolean G_CouldView(INT32 playernum); +boolean G_CanView(INT32 playernum, UINT8 viewnum); + +INT32 G_FindView(INT32 startview, UINT8 viewnum); +INT32 G_CountPlayersPotentiallyViewable(void); + void G_ResetViews(void); -void G_ResetView(UINT8 viewnum); +void G_ResetView(UINT8 viewnum, INT32 playernum); +void G_AdjustView(UINT8 viewnum, INT32 offset); void G_AddPlayer(INT32 playernum); From 06bda79b1b8ec2d3eb67be65c8d230d1ce88956b Mon Sep 17 00:00:00 2001 From: james Date: Wed, 13 Feb 2019 20:20:31 -0800 Subject: [PATCH 051/186] Fix "Return to title" doing NOTHING during recording --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 5e86a092f..93e7a0f3c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7113,7 +7113,7 @@ static void M_ExitGameResponse(INT32 ch) static void M_EndGame(INT32 choice) { (void)choice; - if (demoplayback || demorecording) + if (demoplayback || ( demorecording && !multiplayer ))/* hack for now */ return; if (!Playing()) From 8a0129253f8e59991336f4ff43ccf9f692ab9cec Mon Sep 17 00:00:00 2001 From: james Date: Wed, 13 Feb 2019 20:21:09 -0800 Subject: [PATCH 052/186] Wait for HU_Responder and friends to finish eating before viewpoint control --- src/g_game.c | 88 ++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 8a8b021cc..fabb66574 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1823,50 +1823,6 @@ static INT32 spectatedelay, spectatedelay2, spectatedelay3, spectatedelay4 = 0; // boolean G_Responder(event_t *ev) { - // allow spy mode changes even during the demo - if (gamestate == GS_LEVEL && ev->type == ev_keydown - && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) - { - if (!demoplayback && (splitscreen || !netgame)) - displayplayer = consoleplayer; - else - { - displayplayer++; - G_ResetView(1); - - // change statusbar also if playing back demo - if (singledemo) - ST_changeDemoView(); - - return true; - } - } - - if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demoplayback) - { - if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) - { - secondarydisplayplayer++; - G_ResetView(2); - - return true; - } - else if (ev->data1 == gamecontrol3[gc_viewpoint][0] || ev->data1 == gamecontrol3[gc_viewpoint][1]) - { - thirddisplayplayer++; - G_ResetView(3); - - return true; - } - else if (ev->data1 == gamecontrol4[gc_viewpoint][0] || ev->data1 == gamecontrol4[gc_viewpoint][1]) - { - fourthdisplayplayer++; - G_ResetView(4); - - return true; - } - } - // any other key pops up menu if in demos if (gameaction == ga_nothing && !singledemo && ((demoplayback && !modeattacking && !titledemo && !multiplayer) || gamestate == GS_TITLESCREEN)) @@ -1944,6 +1900,50 @@ boolean G_Responder(event_t *ev) if (HU_Responder(ev)) return true; // chat ate the event + // allow spy mode changes even during the demo + if (gamestate == GS_LEVEL && ev->type == ev_keydown + && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) + { + if (!demoplayback && (splitscreen || !netgame)) + displayplayer = consoleplayer; + else + { + displayplayer++; + G_ResetView(1); + + // change statusbar also if playing back demo + if (singledemo) + ST_changeDemoView(); + + return true; + } + } + + if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demoplayback) + { + if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) + { + secondarydisplayplayer++; + G_ResetView(2); + + return true; + } + else if (ev->data1 == gamecontrol3[gc_viewpoint][0] || ev->data1 == gamecontrol3[gc_viewpoint][1]) + { + thirddisplayplayer++; + G_ResetView(3); + + return true; + } + else if (ev->data1 == gamecontrol4[gc_viewpoint][0] || ev->data1 == gamecontrol4[gc_viewpoint][1]) + { + fourthdisplayplayer++; + G_ResetView(4); + + return true; + } + } + // update keys current state G_MapEventsToControls(ev); From da428a7150b8038c3c9fbf2b5e3d561dc10e3467 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 14 Feb 2019 00:17:29 -0800 Subject: [PATCH 053/186] Add support for an optional file list embeded in demos Ghosts are also supported. The playback function can read demos without this file list--it is a flag. --- src/g_game.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 8a8b021cc..731354af6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4634,6 +4634,7 @@ char *G_BuildMapTitle(INT32 mapnum) #define DF_NIGHTSATTACK 0x04 // This demo is from NiGHTS attack and contains its time left, score, and mares! #define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? #define DF_ATTACKSHIFT 1 +#define DF_FILELIST 0x08 // This demo contains an extra files list #define DF_GAMETYPEMASK 0x30 #define DF_GAMESHIFT 4 #define DF_ENCORE 0x40 @@ -5766,6 +5767,10 @@ void G_BeginRecording(void) char name[16]; player_t *player = &players[consoleplayer]; + char *filename; + UINT8 totalfiles; + UINT8 *m; + if (demo_p) return; memset(name,0,sizeof(name)); @@ -5775,6 +5780,8 @@ void G_BeginRecording(void) demoflags |= gametype<filename)) + { + nameonly(( filename = va("%s", wadfiles[i]->filename) )); + /* FIXME: maximum size? */ + WRITESTRING(demo_p, filename); + WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); + + totalfiles++; + } + + WRITEUINT8(m, totalfiles); + switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 @@ -5970,6 +5996,81 @@ void G_SetDemoTime(UINT32 ptime, UINT32 plap) }*/ } +static void G_LoadDemoExtraFiles(UINT8 **pp) +{ + UINT8 totalfiles; + char filename[MAX_WADPATH]; + UINT8 md5sum[16]; + filestatus_t ncs; + boolean toomany = false; + boolean alreadyloaded; + UINT8 i, j; + + totalfiles = READUINT8((*pp)); + for (i = 0; i < totalfiles; ++i) + { + if (toomany) + SKIPSTRING((*pp)); + else + { + strlcpy(filename, (char *)(*pp), sizeof filename); + SKIPSTRING((*pp)); + } + READMEM((*pp), md5sum, 16); + + if (!toomany) + { + alreadyloaded = false; + + for (j = 0; j < numwadfiles; ++j) + { + if (memcmp(md5sum, wadfiles[j]->md5sum, 16) == 0) + { + alreadyloaded = true; + break; + } + } + + if (alreadyloaded) + continue; + + if (numwadfiles >= MAX_WADFILES) + toomany = true; + else + ncs = findfile(filename, md5sum, false); + + if (toomany || ncs != FS_FOUND) + { + if (toomany) + CONS_Printf("Too many files loaded\n"); + else if (ncs == FS_NOTFOUND) + CONS_Printf("You do not have a copy of %s\n", filename); + else if (ncs == FS_MD5SUMBAD) + CONS_Printf("Checksum mismatch on %s\n", filename); + else + CONS_Printf("Unknown error finding file (%s)\n", filename); + } + else + { + P_AddWadFile(filename); + } + } + } +} + +static void G_SkipDemoExtraFiles(UINT8 **pp) +{ + UINT8 totalfiles; + UINT8 i; + + totalfiles = READUINT8((*pp)); + for (i = 0; i < totalfiles; ++i) + { + SKIPSTRING((*pp));// file name + (*pp) += 16;// md5 + } +} + // Returns bitfield: // 1 == new demo has lower time // 2 == new demo has higher score @@ -6006,6 +6107,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 2; // gamemap p += 16; // map md5 flags = READUINT8(p); // demoflags + if (flags & DF_FILELIST) // file list + { + G_SkipDemoExtraFiles(&p); + } aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK); I_Assert(aflags); @@ -6063,6 +6168,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 2; // gamemap p += 16; // mapmd5 flags = READUINT8(p); + if (flags & DF_FILELIST) // file list + { + G_SkipDemoExtraFiles(&p); + } if (!(flags & aflags)) { CONS_Alert(CONS_NOTICE, M_GetText("File '%s' not from same game mode. It will be overwritten.\n"), oldname); @@ -6213,6 +6322,11 @@ void G_DoPlayDemo(char *defdemoname) demo_p += 16; // mapmd5 demoflags = READUINT8(demo_p); + if (demoflags & DF_FILELIST) + { + G_LoadDemoExtraFiles(&demo_p); + } + modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT; multiplayer = !!(demoflags & DF_MULTIPLAYER); gametype = (demoflags & DF_GAMETYPEMASK)>>DF_GAMESHIFT; @@ -6513,6 +6627,10 @@ void G_AddGhost(char *defdemoname) p += 2; // gamemap p += 16; // mapmd5 (possibly check for consistency?) flags = READUINT8(p); + if (flags & DF_FILELIST) + { + G_LoadDemoExtraFiles(&p); + } if (!(flags & DF_GHOST)) { CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), pdemoname); @@ -6665,6 +6783,9 @@ void G_UpdateStaffGhostName(lumpnum_t l) UINT16 ghostversion; UINT8 flags; + UINT8 totalfiles; + UINT8 md5sum[16]; + buffer = p = W_CacheLumpNum(l, PU_CACHE); // read demo header @@ -6691,6 +6812,15 @@ void G_UpdateStaffGhostName(lumpnum_t l) p += 2; // gamemap p += 16; // mapmd5 (possibly check for consistency?) flags = READUINT8(p); + if (flags & DF_FILELIST) // file list + { + totalfiles = READUINT8(p); + for (; totalfiles > 0; --totalfiles) + { + SKIPSTRING(p); + READMEM(p, md5sum, 16); + } + } if (!(flags & DF_GHOST)) { goto fail; // we don't NEED to do it here, but whatever From b0ea03af2a5716e2ccdf96fd5e29bd0f4bed7cfb Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 11:52:35 -0600 Subject: [PATCH 054/186] Improve replay resyncing code Notably, it should no longer cause immediate desync warnings if a track starts on a slope. --- src/g_game.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 8a8b021cc..47bb8ac9c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5073,7 +5073,8 @@ void G_WriteGhostTic(mobj_t *ghost) // GZT_XYZ is only useful if you've moved 256 FRACUNITS or more in a single tic. if (abs(ghost->x-oldghost.x) > MAXMOM || abs(ghost->y-oldghost.y) > MAXMOM - || abs(ghost->z-oldghost.z) > MAXMOM) + || abs(ghost->z-oldghost.z) > MAXMOM + || leveltime & 255 == 1) // Hack to enable slightly nicer resyncing { oldghost.x = ghost->x; oldghost.y = ghost->y; @@ -5087,8 +5088,8 @@ void G_WriteGhostTic(mobj_t *ghost) { // For moving normally: // Store one full byte of movement, plus one byte of fractional movement. - INT16 momx = (INT16)((ghost->x-oldghost.x)>>8); - INT16 momy = (INT16)((ghost->y-oldghost.y)>>8); + INT16 momx = (INT16)((ghost->x-oldghost.x + (1<<4))>>8); + INT16 momy = (INT16)((ghost->y-oldghost.y + (1<<4))>>8); if (momx != oldghost.momx || momy != oldghost.momy) { @@ -5098,7 +5099,7 @@ void G_WriteGhostTic(mobj_t *ghost) WRITEINT16(demo_p,momx); WRITEINT16(demo_p,momy); } - momx = (INT16)((ghost->z-oldghost.z)>>8); + momx = (INT16)((ghost->z-oldghost.z + (1<<4))>>8); if (momx != oldghost.momz) { oldghost.momz = momx; @@ -5202,8 +5203,9 @@ void G_WriteGhostTic(mobj_t *ghost) void G_ConsGhostTic(void) { UINT8 ziptic; - UINT16 px,py,pz,gx,gy,gz; + UINT32 px,py,pz,gx,gy,gz; mobj_t *testmo; + UINT32 syncleeway; boolean nightsfail = false; if (!demo_p || !demo_start) @@ -5220,6 +5222,7 @@ void G_ConsGhostTic(void) oldghost.x = READFIXED(demo_p); oldghost.y = READFIXED(demo_p); oldghost.z = READFIXED(demo_p); + syncleeway = 0; } else { @@ -5233,6 +5236,7 @@ void G_ConsGhostTic(void) oldghost.x += oldghost.momx; oldghost.y += oldghost.momy; oldghost.z += oldghost.momz; + syncleeway = FRACUNIT; } if (ziptic & GZT_ANGLE) demo_p++; @@ -5298,14 +5302,14 @@ void G_ConsGhostTic(void) } // Re-synchronise - px = testmo->x>>FRACBITS; - py = testmo->y>>FRACBITS; - pz = testmo->z>>FRACBITS; - gx = oldghost.x>>FRACBITS; - gy = oldghost.y>>FRACBITS; - gz = oldghost.z>>FRACBITS; + px = testmo->x; + py = testmo->y; + pz = testmo->z; + gx = oldghost.x; + gy = oldghost.y; + gz = oldghost.z; - if (nightsfail || px != gx || py != gy || pz != gz) + if (nightsfail || abs(px-gx) > syncleeway || abs(py-gy) > syncleeway || abs(pz-gz) > syncleeway) { if (demosynced) CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); From 0bbff7f6d42addc546d892645106e7f3eb547bb7 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 12:42:24 -0600 Subject: [PATCH 055/186] [WIP, CRASHES] Save ghost data in netreplays --- src/g_game.c | 249 +++++++++++++++++++++++++------------------------- src/g_game.h | 18 ++-- src/p_enemy.c | 2 +- src/p_inter.c | 6 +- src/p_mobj.c | 4 +- src/p_user.c | 20 ++-- 6 files changed, 152 insertions(+), 147 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 47bb8ac9c..0f5c832f7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -320,7 +320,7 @@ static struct { // EZT_HIT UINT16 hits; mobj_t **hitlist; -} ghostext; +} ghostext[MAXPLAYERS]; // Your naming conventions are stupid and useless. // There is no conflict here. @@ -4675,7 +4675,7 @@ static ticcmd_t oldcmd[MAXPLAYERS]; #define EZT_HIT 0x20 // Damaged a mobj #define EZT_SPRITE 0x40 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) -static mobj_t oldmetal, oldghost; +static mobj_t oldmetal, oldghost[MAXPLAYERS]; void G_SaveMetal(UINT8 **buffer) { @@ -4737,6 +4737,7 @@ void G_ReadDemoExtraData(void) M_Memcpy(name, demo_p, 16); demo_p += 16; SetPlayerSkin(p, name); + CONS_Printf("new skin %d %d\n", players[p].kartspeed, players[p].kartweight); } if (extradata & DXD_COLOR) { @@ -4761,6 +4762,7 @@ void G_ReadDemoExtraData(void) if (extradata & DXD_PLAYSTATE) { extradata = READUINT8(demo_p); + CONS_Printf("player state %d %d\n", p, extradata); // @TODO uhhhhh do something here @@ -4982,71 +4984,71 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) } } -void G_GhostAddThok(void) +void G_GhostAddThok(INT32 playernum) { if (!demorecording || !(demoflags & DF_GHOST)) return; - ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_THOK; + ghostext[playernum].flags = (ghostext[playernum].flags & ~EZT_THOKMASK) | EZT_THOK; } -void G_GhostAddSpin(void) +void G_GhostAddSpin(INT32 playernum) { if (!demorecording || !(demoflags & DF_GHOST)) return; - ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_SPIN; + ghostext[playernum].flags = (ghostext[playernum].flags & ~EZT_THOKMASK) | EZT_SPIN; } -void G_GhostAddRev(void) +void G_GhostAddRev(INT32 playernum) { if (!demorecording || !(demoflags & DF_GHOST)) return; - ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_REV; + ghostext[playernum].flags = (ghostext[playernum].flags & ~EZT_THOKMASK) | EZT_REV; } -void G_GhostAddFlip(void) +void G_GhostAddFlip(INT32 playernum) { if (!demorecording || !(demoflags & DF_GHOST)) return; - ghostext.flags |= EZT_FLIP; + ghostext[playernum].flags |= EZT_FLIP; } -void G_GhostAddColor(ghostcolor_t color) +void G_GhostAddColor(INT32 playernum, ghostcolor_t color) { if (!demorecording || !(demoflags & DF_GHOST)) return; - if (ghostext.lastcolor == (UINT8)color) + if (ghostext[playernum].lastcolor == (UINT8)color) { - ghostext.flags &= ~EZT_COLOR; + ghostext[playernum].flags &= ~EZT_COLOR; return; } - ghostext.flags |= EZT_COLOR; - ghostext.color = (UINT8)color; + ghostext[playernum].flags |= EZT_COLOR; + ghostext[playernum].color = (UINT8)color; } -void G_GhostAddScale(fixed_t scale) +void G_GhostAddScale(INT32 playernum, fixed_t scale) { if (!demorecording || !(demoflags & DF_GHOST)) return; - if (ghostext.lastscale == scale) + if (ghostext[playernum].lastscale == scale) { - ghostext.flags &= ~EZT_SCALE; + ghostext[playernum].flags &= ~EZT_SCALE; return; } - ghostext.flags |= EZT_SCALE; - ghostext.scale = scale; + ghostext[playernum].flags |= EZT_SCALE; + ghostext[playernum].scale = scale; } -void G_GhostAddHit(mobj_t *victim) +void G_GhostAddHit(INT32 playernum, mobj_t *victim) { if (!demorecording || !(demoflags & DF_GHOST)) return; - ghostext.flags |= EZT_HIT; - ghostext.hits++; - ghostext.hitlist = Z_Realloc(ghostext.hitlist, ghostext.hits * sizeof(mobj_t *), PU_LEVEL, NULL); - ghostext.hitlist[ghostext.hits-1] = victim; + 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[ghostext[playernum].hits-1] = victim; } -void G_WriteGhostTic(mobj_t *ghost) +void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) { char ziptic = 0; UINT8 *ziptic_p; @@ -5071,38 +5073,38 @@ void G_WriteGhostTic(mobj_t *ghost) #define MAXMOM (0xFFFF<<8) // GZT_XYZ is only useful if you've moved 256 FRACUNITS or more in a single tic. - if (abs(ghost->x-oldghost.x) > MAXMOM - || abs(ghost->y-oldghost.y) > MAXMOM - || abs(ghost->z-oldghost.z) > MAXMOM - || leveltime & 255 == 1) // Hack to enable slightly nicer resyncing + if (abs(ghost->x-oldghost[playernum].x) > MAXMOM + || abs(ghost->y-oldghost[playernum].y) > MAXMOM + || abs(ghost->z-oldghost[playernum].z) > MAXMOM + || (leveltime & 255) == 1) // Hack to enable slightly nicer resyncing { - oldghost.x = ghost->x; - oldghost.y = ghost->y; - oldghost.z = ghost->z; + oldghost[playernum].x = ghost->x; + oldghost[playernum].y = ghost->y; + oldghost[playernum].z = ghost->z; ziptic |= GZT_XYZ; - WRITEFIXED(demo_p,oldghost.x); - WRITEFIXED(demo_p,oldghost.y); - WRITEFIXED(demo_p,oldghost.z); + WRITEFIXED(demo_p,oldghost[playernum].x); + WRITEFIXED(demo_p,oldghost[playernum].y); + WRITEFIXED(demo_p,oldghost[playernum].z); } else { // For moving normally: // Store one full byte of movement, plus one byte of fractional movement. - INT16 momx = (INT16)((ghost->x-oldghost.x + (1<<4))>>8); - INT16 momy = (INT16)((ghost->y-oldghost.y + (1<<4))>>8); - if (momx != oldghost.momx - || momy != oldghost.momy) + INT16 momx = (INT16)((ghost->x-oldghost[playernum].x + (1<<4))>>8); + INT16 momy = (INT16)((ghost->y-oldghost[playernum].y + (1<<4))>>8); + if (momx != oldghost[playernum].momx + || momy != oldghost[playernum].momy) { - oldghost.momx = momx; - oldghost.momy = momy; + oldghost[playernum].momx = momx; + oldghost[playernum].momy = momy; ziptic |= GZT_MOMXY; WRITEINT16(demo_p,momx); WRITEINT16(demo_p,momy); } - momx = (INT16)((ghost->z-oldghost.z + (1<<4))>>8); - if (momx != oldghost.momz) + momx = (INT16)((ghost->z-oldghost[playernum].z + (1<<4))>>8); + if (momx != oldghost[playernum].momz) { - oldghost.momz = momx; + oldghost[playernum].momz = momx; ziptic |= GZT_MOMZ; WRITEINT16(demo_p,momx); } @@ -5110,9 +5112,9 @@ void G_WriteGhostTic(mobj_t *ghost) // This SHOULD set oldghost.x/y/z to match ghost->x/y/z // but it keeps the fractional loss of one byte, // so it will hopefully be made up for in future tics. - oldghost.x += oldghost.momx<<8; - oldghost.y += oldghost.momy<<8; - oldghost.z += oldghost.momz<<8; + oldghost[playernum].x += oldghost[playernum].momx<<8; + oldghost[playernum].y += oldghost[playernum].momy<<8; + oldghost[playernum].z += oldghost[playernum].momz<<8; } #undef MAXMOM @@ -5120,56 +5122,56 @@ void G_WriteGhostTic(mobj_t *ghost) // Only store the 8 most relevant bits of angle // because exact values aren't too easy to discern to begin with when only 8 angles have different sprites // and it does not affect this mode of movement at all anyway. - if (ghost->angle>>24 != oldghost.angle) + if (ghost->angle>>24 != oldghost[playernum].angle) { - oldghost.angle = ghost->angle>>24; + oldghost[playernum].angle = ghost->angle>>24; ziptic |= GZT_ANGLE; - WRITEUINT8(demo_p,oldghost.angle); + WRITEUINT8(demo_p,oldghost[playernum].angle); } // Store the sprite frame. frame = ghost->frame & 0xFF; - if (frame != oldghost.frame) + if (frame != oldghost[playernum].frame) { - oldghost.frame = frame; + oldghost[playernum].frame = frame; ziptic |= GZT_SPRITE; - WRITEUINT8(demo_p,oldghost.frame); + WRITEUINT8(demo_p,oldghost[playernum].frame); } // Check for sprite set changes sprite = ghost->sprite; - if (sprite != oldghost.sprite) + if (sprite != oldghost[playernum].sprite) { - oldghost.sprite = sprite; - ghostext.flags |= EZT_SPRITE; + oldghost[playernum].sprite = sprite; + ghostext[playernum].flags |= EZT_SPRITE; } - if (ghostext.flags) + if (ghostext[playernum].color == ghostext[playernum].lastcolor) + ghostext[playernum].flags &= ~EZT_COLOR; + if (ghostext[playernum].scale == ghostext[playernum].lastscale) + ghostext[playernum].flags &= ~EZT_SCALE; + + if (ghostext[playernum].flags) { ziptic |= GZT_EXTRA; + WRITEUINT8(demo_p,ghostext[playernum].flags); - if (ghostext.color == ghostext.lastcolor) - ghostext.flags &= ~EZT_COLOR; - if (ghostext.scale == ghostext.lastscale) - ghostext.flags &= ~EZT_SCALE; - - WRITEUINT8(demo_p,ghostext.flags); - if (ghostext.flags & EZT_COLOR) + if (ghostext[playernum].flags & EZT_COLOR) { - WRITEUINT8(demo_p,ghostext.color); - ghostext.lastcolor = ghostext.color; + WRITEUINT8(demo_p,ghostext[playernum].color); + ghostext[playernum].lastcolor = ghostext[playernum].color; } - if (ghostext.flags & EZT_SCALE) + if (ghostext[playernum].flags & EZT_SCALE) { - WRITEFIXED(demo_p,ghostext.scale); - ghostext.lastscale = ghostext.scale; + WRITEFIXED(demo_p,ghostext[playernum].scale); + ghostext[playernum].lastscale = ghostext[playernum].scale; } - if (ghostext.flags & EZT_HIT) + if (ghostext[playernum].flags & EZT_HIT) { - WRITEUINT16(demo_p,ghostext.hits); - for (i = 0; i < ghostext.hits; i++) + WRITEUINT16(demo_p,ghostext[playernum].hits); + for (i = 0; i < ghostext[playernum].hits; i++) { - mobj_t *mo = ghostext.hitlist[i]; + mobj_t *mo = ghostext[playernum].hitlist[i]; WRITEUINT32(demo_p,UINT32_MAX); // reserved for some method of determining exactly which mobj this is. (mobjnum doesn't work here.) WRITEUINT32(demo_p,mo->type); WRITEUINT16(demo_p,(UINT16)mo->health); @@ -5178,13 +5180,13 @@ void G_WriteGhostTic(mobj_t *ghost) WRITEFIXED(demo_p,mo->z); WRITEANGLE(demo_p,mo->angle); } - Z_Free(ghostext.hitlist); - ghostext.hits = 0; - ghostext.hitlist = NULL; + Z_Free(ghostext[playernum].hitlist); + ghostext[playernum].hits = 0; + ghostext[playernum].hitlist = NULL; } - if (ghostext.flags & EZT_SPRITE) + if (ghostext[playernum].flags & EZT_SPRITE) WRITEUINT8(demo_p,sprite); - ghostext.flags = 0; + ghostext[playernum].flags = 0; } *ziptic_p = ziptic; @@ -5200,7 +5202,7 @@ void G_WriteGhostTic(mobj_t *ghost) // Uses ghost data to do consistency checks on your position. // This fixes desynchronising demos when fighting eggman. -void G_ConsGhostTic(void) +void G_ConsGhostTic(INT32 playernum) { UINT8 ziptic; UINT32 px,py,pz,gx,gy,gz; @@ -5213,29 +5215,29 @@ void G_ConsGhostTic(void) if (!(demoflags & DF_GHOST)) return; // No ghost data to use. - testmo = players[0].mo; + testmo = players[playernum].mo; // Grab ghost data. ziptic = READUINT8(demo_p); if (ziptic & GZT_XYZ) { - oldghost.x = READFIXED(demo_p); - oldghost.y = READFIXED(demo_p); - oldghost.z = READFIXED(demo_p); + oldghost[playernum].x = READFIXED(demo_p); + oldghost[playernum].y = READFIXED(demo_p); + oldghost[playernum].z = READFIXED(demo_p); syncleeway = 0; } else { if (ziptic & GZT_MOMXY) { - oldghost.momx = READINT16(demo_p)<<8; - oldghost.momy = READINT16(demo_p)<<8; + oldghost[playernum].momx = READINT16(demo_p)<<8; + oldghost[playernum].momy = READINT16(demo_p)<<8; } if (ziptic & GZT_MOMZ) - oldghost.momz = READINT16(demo_p)<<8; - oldghost.x += oldghost.momx; - oldghost.y += oldghost.momy; - oldghost.z += oldghost.momz; + oldghost[playernum].momz = READINT16(demo_p)<<8; + oldghost[playernum].x += oldghost[playernum].momx; + oldghost[playernum].y += oldghost[playernum].momy; + oldghost[playernum].z += oldghost[playernum].momz; syncleeway = FRACUNIT; } if (ziptic & GZT_ANGLE) @@ -5305,21 +5307,21 @@ void G_ConsGhostTic(void) px = testmo->x; py = testmo->y; pz = testmo->z; - gx = oldghost.x; - gy = oldghost.y; - gz = oldghost.z; + gx = oldghost[playernum].x; + gy = oldghost[playernum].y; + gz = oldghost[playernum].z; if (nightsfail || abs(px-gx) > syncleeway || abs(py-gy) > syncleeway || abs(pz-gz) > syncleeway) { if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced! %d>%d %d>%d %d>%d\n"), px, gx, py, gy, pz, gz); demosynced = false; P_UnsetThingPosition(testmo); - testmo->x = oldghost.x; - testmo->y = oldghost.y; + testmo->x = oldghost[playernum].x; + testmo->y = oldghost[playernum].y; P_SetThingPosition(testmo); - testmo->z = oldghost.z; + testmo->z = oldghost[playernum].z; } if (*demo_p == DEMOMARKER) @@ -5775,7 +5777,7 @@ void G_BeginRecording(void) memset(name,0,sizeof(name)); demo_p = demobuffer; - demoflags = multiplayer ? DF_MULTIPLAYER : (DF_GHOST|(modeattacking<mo) + for (i = 0; i < MAXPLAYERS; i++) { - oldghost.x = player->mo->x; - oldghost.y = player->mo->y; - oldghost.z = player->mo->z; - oldghost.angle = player->mo->angle; + ghostext[i].lastcolor = ghostext[i].color = GHC_NORMAL; + ghostext[i].lastscale = ghostext[i].scale = FRACUNIT; - // preticker started us gravity flipped - if (player->mo->eflags & MFE_VERTICALFLIP) - ghostext.flags |= EZT_FLIP; + if (players[i].mo) + { + oldghost[i].x = players[i].mo->x; + oldghost[i].y = players[i].mo->y; + oldghost[i].z = players[i].mo->z; + oldghost[i].angle = players[i].mo->angle; + + // preticker started us gravity flipped + if (players[i].mo->eflags & MFE_VERTICALFLIP) + ghostext[i].flags |= EZT_FLIP; + } } } @@ -6409,15 +6410,19 @@ void G_DoPlayDemo(char *defdemoname) P_SetRandSeed(randseed); G_InitNew(demoflags & DF_ENCORE, G_BuildMapName(gamemap), true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer. + for (i = 0; i < MAXPLAYERS; i++) + { + if (players[i].mo) + { + players[i].mo->color = players[i].skincolor; + oldghost[i].x = players[i].mo->x; + oldghost[i].y = players[i].mo->y; + oldghost[i].z = players[i].mo->z; + } + } + if (!multiplayer) { //CV_StealthSetValue(&cv_playercolor, players[0].skincolor); -- as far as I can tell this is more trouble than it's worth - if (players[0].mo) - { - players[0].mo->color = players[0].skincolor; - oldghost.x = players[0].mo->x; - oldghost.y = players[0].mo->y; - oldghost.z = players[0].mo->z; - } // Set saved attribute values // No cheat checking here, because even if they ARE wrong... diff --git a/src/g_game.h b/src/g_game.h index 9d9a47552..6e4f6408e 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -170,15 +170,15 @@ void G_ReadDemoExtraData(void); void G_WriteDemoExtraData(void); void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum); void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum); -void G_GhostAddThok(void); -void G_GhostAddSpin(void); -void G_GhostAddRev(void); -void G_GhostAddColor(ghostcolor_t color); -void G_GhostAddFlip(void); -void G_GhostAddScale(fixed_t scale); -void G_GhostAddHit(mobj_t *victim); -void G_WriteGhostTic(mobj_t *ghost); -void G_ConsGhostTic(void); +void G_GhostAddThok(INT32 playernum); +void G_GhostAddSpin(INT32 playernum); +void G_GhostAddRev(INT32 playernum); +void G_GhostAddColor(INT32 playernum, ghostcolor_t color); +void G_GhostAddFlip(INT32 playernum); +void G_GhostAddScale(INT32 playernum, fixed_t scale); +void G_GhostAddHit(INT32 playernum, mobj_t *victim); +void G_WriteGhostTic(mobj_t *ghost, INT32 playernum); +void G_ConsGhostTic(INT32 playernum); void G_GhostTicker(void); void G_ReadMetalTic(mobj_t *metal); void G_WriteMetalTic(mobj_t *metal); diff --git a/src/p_enemy.c b/src/p_enemy.c index 9d3aa9519..b01f9be67 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3079,7 +3079,7 @@ void A_Invincibility(mobj_t *actor) { S_StopMusic(); if (mariomode) - G_GhostAddColor(GHC_INVINCIBLE); + G_GhostAddColor((INT32) (player - players), GHC_INVINCIBLE); S_ChangeMusicInternal((mariomode) ? "minvnc" : "invinc", false); } } diff --git a/src/p_inter.c b/src/p_inter.c index dd27858fc..425461d56 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1424,7 +1424,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; player->powers[pw_shield] |= SH_FIREFLOWER; toucher->color = SKINCOLOR_WHITE; - G_GhostAddColor(GHC_FIREFLOWER); + G_GhostAddColor(player - players, GHC_FIREFLOWER); break; // *************** // @@ -3028,7 +3028,7 @@ void P_RemoveShield(player_t *player) if (!player->powers[pw_super]) { player->mo->color = player->skincolor; - G_GhostAddColor(GHC_NORMAL); + G_GhostAddColor((INT32) (player - players), GHC_NORMAL); } } else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB) // Give them what's coming to them! @@ -3459,7 +3459,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da target->health -= damage; if (source && source->player && target) - G_GhostAddHit(target); + G_GhostAddHit((INT32) (source->player - players), target); if (target->health <= 0) { diff --git a/src/p_mobj.c b/src/p_mobj.c index 302f50a1e..4be4afd9f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1220,7 +1220,7 @@ static void P_PlayerFlip(mobj_t *mo) if (!mo->player) return; - G_GhostAddFlip(); + G_GhostAddFlip((INT32) (mo->player - players)); // Flip aiming to match! if (mo->player->pflags & PF_NIGHTSMODE) // NiGHTS doesn't use flipcam @@ -6010,7 +6010,7 @@ void P_SetScale(mobj_t *mobj, fixed_t newscale) if (player) { - G_GhostAddScale(newscale); + G_GhostAddScale((INT32) (player - players), newscale); player->viewheight = FixedMul(FixedDiv(player->viewheight, oldscale), newscale); // Nonono don't calculate viewheight elsewhere, this is the best place for it! player->dashspeed = FixedMul(FixedDiv(player->dashspeed, oldscale), newscale); // Prevents the player from having to re-charge up spindash if the player grew in size } diff --git a/src/p_user.c b/src/p_user.c index 0c1fb11a3..73caa2111 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1708,7 +1708,7 @@ void P_SpawnThokMobj(player_t *player) P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do if (demorecording) - G_GhostAddThok(); + G_GhostAddThok((INT32) (player - players)); } // @@ -2416,12 +2416,12 @@ static void P_CheckInvincibilityTimer(player_t *player) //if (player->powers[pw_shield] & SH_FIREFLOWER) //{ // player->mo->color = SKINCOLOR_WHITE; - // G_GhostAddColor(GHC_FIREFLOWER); + // G_GhostAddColor((INT32) (player - players), GHC_FIREFLOWER); //} //else { player->mo->color = player->skincolor; - G_GhostAddColor(GHC_NORMAL); + G_GhostAddColor((INT32) (player - players), GHC_NORMAL); } } @@ -3673,12 +3673,12 @@ static void P_DoSuperStuff(player_t *player) if (player->powers[pw_shield] & SH_FIREFLOWER) { player->mo->color = SKINCOLOR_WHITE; - G_GhostAddColor(GHC_FIREFLOWER); + G_GhostAddColor((INT32) (player - players), GHC_FIREFLOWER); } else { player->mo->color = player->skincolor; - G_GhostAddColor(GHC_NORMAL); + G_GhostAddColor((INT32) (player - players), GHC_NORMAL); } if (gametype != GT_COOP) @@ -3714,7 +3714,7 @@ static void P_DoSuperStuff(player_t *player) P_SetScale(spark, player->mo->scale); } - G_GhostAddColor(GHC_SUPER); + G_GhostAddColor((INT32) (player - players), GHC_SUPER); // Ran out of rings while super! if (player->health <= 1 || player->exiting) @@ -3728,12 +3728,12 @@ static void P_DoSuperStuff(player_t *player) if (player->powers[pw_shield] & SH_FIREFLOWER) { player->mo->color = SKINCOLOR_WHITE; - G_GhostAddColor(GHC_FIREFLOWER); + G_GhostAddColor((INT32) (player - players), GHC_FIREFLOWER); } else { player->mo->color = player->skincolor; - G_GhostAddColor(GHC_NORMAL); + G_GhostAddColor((INT32) (player - players), GHC_NORMAL); } if (gametype != GT_COOP) @@ -4035,7 +4035,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) // SRB2kart - unused. // Now spawn the color thok circle. P_SpawnSpinMobj(player, player->revitem); if (demorecording) - G_GhostAddRev(); + G_GhostAddRev((INT32) (player - players)); } } // If not moving up or down, and travelling faster than a speed of four while not holding @@ -7017,7 +7017,7 @@ static void P_MovePlayer(player_t *player) { P_SpawnSpinMobj(player, player->spinitem); if (demorecording) - G_GhostAddSpin(); + G_GhostAddSpin((INT32) (player - players)); } */ From 73639b650408a56db2d248b8f7783e65a091fba1 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 13:10:58 -0600 Subject: [PATCH 056/186] ??? --- src/p_tick.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/p_tick.c b/src/p_tick.c index 8b99c5aa6..7e048af59 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -722,10 +722,43 @@ void P_Ticker(boolean run) G_ReadMetalTic(metalplayback); if (metalrecording) G_WriteMetalTic(players[consoleplayer].mo); - if (demorecording) - G_WriteGhostTic(players[consoleplayer].mo); - if (demoplayback) // Use Ghost data for consistency checks. - G_ConsGhostTic(); + + if (multiplayer) + { + if (demorecording) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo) + continue; + + G_WriteGhostTic(players[i].mo, i); + } + } + if (demoplayback) // Use Ghost data for consistency checks. + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo) + continue; + + G_ConsGhostTic(i); + } + } + } + else + { + if (demorecording) + G_WriteGhostTic(players[consoleplayer].mo, consoleplayer); + if (demoplayback) // Use Ghost data for consistency checks. + G_ConsGhostTic(0); + } if (modeattacking) G_GhostTicker(); From 7c0290795e7f6f6f3648421949c4fc04ac523291 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 13:42:21 -0600 Subject: [PATCH 057/186] Resync items and bumpers in replays --- src/g_game.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 0f5c832f7..cf40d5685 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -317,6 +317,9 @@ static struct { // EZT_SCALE fixed_t scale, lastscale; + // EZT_KART + INT32 kartitem, kartamount, kartbumpers; + // EZT_HIT UINT16 hits; mobj_t **hitlist; @@ -4674,6 +4677,7 @@ static ticcmd_t oldcmd[MAXPLAYERS]; #define EZT_SCALE 0x10 // Changed size #define EZT_HIT 0x20 // Damaged a mobj #define EZT_SPRITE 0x40 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) +#define EZT_KART 0x80 // SRB2Kart: Changed current held item/quantity and bumpers for battle static mobj_t oldmetal, oldghost[MAXPLAYERS]; @@ -5146,6 +5150,22 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) ghostext[playernum].flags |= EZT_SPRITE; } + if (ghost->player) + { + if ( + ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] || + ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] || + ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper] + ) + { + ghostext[playernum].flags |= EZT_KART; + ghostext[playernum].kartitem = ghost->player->kartstuff[k_itemtype]; + ghostext[playernum].kartamount = ghost->player->kartstuff[k_itemamount]; + ghostext[playernum].kartbumpers = ghost->player->kartstuff[k_bumper]; + + } + } + if (ghostext[playernum].color == ghostext[playernum].lastcolor) ghostext[playernum].flags &= ~EZT_COLOR; if (ghostext[playernum].scale == ghostext[playernum].lastscale) @@ -5186,6 +5206,12 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) } if (ghostext[playernum].flags & EZT_SPRITE) WRITEUINT8(demo_p,sprite); + if (ghostext[playernum].flags & EZT_KART) + { + WRITEINT32(demo_p, ghostext[playernum].kartitem); + WRITEINT32(demo_p, ghostext[playernum].kartamount); + WRITEINT32(demo_p, ghostext[playernum].kartbumpers); + } ghostext[playernum].flags = 0; } @@ -5301,6 +5327,12 @@ void G_ConsGhostTic(INT32 playernum) } if (ziptic & EZT_SPRITE) demo_p++; + if (ziptic & EZT_KART) + { + ghostext[playernum].kartitem = READINT32(demo_p); + ghostext[playernum].kartamount = READINT32(demo_p); + ghostext[playernum].kartbumpers = READINT32(demo_p); + } } // Re-synchronise @@ -5314,7 +5346,7 @@ void G_ConsGhostTic(INT32 playernum) if (nightsfail || abs(px-gx) > syncleeway || abs(py-gy) > syncleeway || abs(pz-gz) > syncleeway) { if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced! %d>%d %d>%d %d>%d\n"), px, gx, py, gy, pz, gz); + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); demosynced = false; P_UnsetThingPosition(testmo); @@ -5324,6 +5356,21 @@ void G_ConsGhostTic(INT32 playernum) testmo->z = oldghost[playernum].z; } + if ( + players[playernum].kartstuff[k_itemtype] != ghostext[playernum].kartitem || + players[playernum].kartstuff[k_itemamount] != ghostext[playernum].kartamount || + players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers + ) + { + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + demosynced = false; + + players[playernum].kartstuff[k_itemtype] = ghostext[playernum].kartitem; + players[playernum].kartstuff[k_itemamount] = ghostext[playernum].kartamount; + players[playernum].kartstuff[k_bumper] = ghostext[playernum].kartbumpers; + } + if (*demo_p == DEMOMARKER) { // end of demo data stream @@ -5493,6 +5540,8 @@ void G_GhostTicker(void) } if (ziptic & EZT_SPRITE) g->mo->sprite = READUINT8(g->p); + if (ziptic & EZT_KART) + g->p += 12; // kartitem, kartamount, kartbumpers } // Tick ghost colors (Super and Mario Invincibility flashing) @@ -6321,6 +6370,7 @@ void G_DoPlayDemo(char *defdemoname) memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); + memset(&ghostext,0,sizeof(ghostext)); #if defined(SKIPERRORS) && !defined(DEVELOP) if ((VERSION != version || SUBVERSION != subversion) && !skiperrors) From 82b8590fbc1b3ee084d3d13146144c6684c69b01 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 13:49:31 -0600 Subject: [PATCH 058/186] Backwards compat for old replays --- src/g_game.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index cf40d5685..e0f9e7fb4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -319,6 +319,7 @@ static struct { // EZT_KART INT32 kartitem, kartamount, kartbumpers; + boolean kartresync; //@TODO backwards compat with old replays. remove eventually // EZT_HIT UINT16 hits; @@ -5332,6 +5333,7 @@ void G_ConsGhostTic(INT32 playernum) ghostext[playernum].kartitem = READINT32(demo_p); ghostext[playernum].kartamount = READINT32(demo_p); ghostext[playernum].kartbumpers = READINT32(demo_p); + ghostext[playernum].kartresync = true; } } @@ -5357,9 +5359,10 @@ void G_ConsGhostTic(INT32 playernum) } if ( + ghostext[playernum].kartresync && ( players[playernum].kartstuff[k_itemtype] != ghostext[playernum].kartitem || players[playernum].kartstuff[k_itemamount] != ghostext[playernum].kartamount || - players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers + players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers) ) { if (demosynced) From bceebf7e3ea2818d1a9129722afd3fe9ec97ba21 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 13:58:32 -0600 Subject: [PATCH 059/186] Remove debug-related code --- src/g_game.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index e0f9e7fb4..063e9a60d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4742,7 +4742,6 @@ void G_ReadDemoExtraData(void) M_Memcpy(name, demo_p, 16); demo_p += 16; SetPlayerSkin(p, name); - CONS_Printf("new skin %d %d\n", players[p].kartspeed, players[p].kartweight); } if (extradata & DXD_COLOR) { @@ -4767,9 +4766,6 @@ void G_ReadDemoExtraData(void) if (extradata & DXD_PLAYSTATE) { extradata = READUINT8(demo_p); - CONS_Printf("player state %d %d\n", p, extradata); - - // @TODO uhhhhh do something here switch (extradata) { case DXD_PST_PLAYING: From 7c6226ee9189f2c00e3de1521b141593fd151b63 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 14:24:00 -0600 Subject: [PATCH 060/186] Try to keep the RNG seed in sync --- src/g_game.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- src/g_game.h | 1 + src/lua_baselib.c | 7 +++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 063e9a60d..c455b3c97 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4656,8 +4656,14 @@ char *G_BuildMapTitle(INT32 mapnum) #define DEMOMARKER 0x80 // demoend UINT8 demo_extradata[MAXPLAYERS]; +UINT8 demo_writerng; // 0=no, 1=yes, 2=yes but on a timeout static ticcmd_t oldcmd[MAXPLAYERS]; +#define DW_END 0xFF // End of extradata block +#define DW_RNG 0xFE // Check RNG seed! + +#define DW_EXTRASTUFF 0xFE // Numbers below this are reserved for writing player slot data + // For Metal Sonic and time attack ghosts #define GZT_XYZ 0x01 #define GZT_MOMXY 0x02 @@ -4727,7 +4733,7 @@ void G_ReadDemoExtraData(void) p = READUINT8(demo_p); - while (p != 0xFF) + while (p < DW_EXTRASTUFF) { extradata = READUINT8(demo_p); @@ -4810,6 +4816,24 @@ void G_ReadDemoExtraData(void) p = READUINT8(demo_p); } + while (p != DW_END) + { + INT32 rng; + + switch (p) + { + case DW_RNG: + rng = READUINT32(demo_p); + if (P_GetRandSeed() != rng) + { + P_SetRandSeed(rng); + CONS_Alert(CONS_WARNING, "Random seed has desynced!\n"); + } + } + + p = READUINT8(demo_p); + } + if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) { // end of demo data stream @@ -4857,6 +4881,7 @@ void G_WriteDemoExtraData(void) } if (demo_extradata[i] & DXD_PLAYSTATE) { + demo_writerng = 1; if (!playeringame[i]) WRITEUINT8(demo_p, DXD_PST_LEFT); else if ( @@ -4872,7 +4897,25 @@ void G_WriteDemoExtraData(void) demo_extradata[i] = 0; } - WRITEUINT8(demo_p, 0xFF); + // May not be necessary, but might as well play it safe... + if ((leveltime & 255) == 128) + demo_writerng = 1; + + { + static UINT8 timeout = 0; + + if (timeout) timeout--; + + if (demo_writerng == 1 || (demo_writerng == 2 && timeout == 0)) + { + demo_writerng = 0; + timeout = 16; + WRITEUINT8(demo_p, DW_RNG); + WRITEUINT32(demo_p, P_GetRandSeed()); + } + } + + WRITEUINT8(demo_p, DW_END); } void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) diff --git a/src/g_game.h b/src/g_game.h index 6e4f6408e..73dcb1ce0 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -155,6 +155,7 @@ typedef enum } ghostcolor_t; extern UINT8 demo_extradata[MAXPLAYERS]; +extern UINT8 demo_writerng; #define DXD_RESPAWN 0x01 // "respawn" command in console #define DXD_SKIN 0x02 // skin changed #define DXD_NAME 0x04 // name changed diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 78f972f87..36becc56c 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -163,6 +163,7 @@ static int lib_pRandomFixed(lua_State *L) { NOHUD lua_pushfixed(L, P_RandomFixed()); + demo_writerng = 2; return 1; } @@ -170,6 +171,7 @@ static int lib_pRandomByte(lua_State *L) { NOHUD lua_pushinteger(L, P_RandomByte()); + demo_writerng = 2; return 1; } @@ -181,6 +183,7 @@ static int lib_pRandomKey(lua_State *L) if (a > 65536) LUA_UsageWarning(L, "P_RandomKey: range > 65536 is undefined behavior"); lua_pushinteger(L, P_RandomKey(a)); + demo_writerng = 2; return 1; } @@ -198,6 +201,7 @@ static int lib_pRandomRange(lua_State *L) if ((b-a+1) > 65536) LUA_UsageWarning(L, "P_RandomRange: range > 65536 is undefined behavior"); lua_pushinteger(L, P_RandomRange(a, b)); + demo_writerng = 2; return 1; } @@ -207,6 +211,7 @@ static int lib_pRandom(lua_State *L) NOHUD LUA_Deprecated(L, "P_Random", "P_RandomByte"); lua_pushinteger(L, P_RandomByte()); + demo_writerng = 2; return 1; } @@ -214,6 +219,7 @@ static int lib_pSignedRandom(lua_State *L) { NOHUD lua_pushinteger(L, P_SignedRandom()); + demo_writerng = 2; return 1; } @@ -222,6 +228,7 @@ static int lib_pRandomChance(lua_State *L) fixed_t p = luaL_checkfixed(L, 1); NOHUD lua_pushboolean(L, P_RandomChance(p)); + demo_writerng = 2; return 1; } From 712bdfd4b639898c648f198c2082e6a106362d71 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 15:49:54 -0600 Subject: [PATCH 061/186] Double default replay size --- src/g_game.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index c455b3c97..434be94eb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5833,7 +5833,8 @@ void G_RecordDemo(const char *name) strcpy(demoname, name); strcat(demoname, ".lmp"); - maxsize = 1024*1024; + //@TODO make a maxdemosize cvar + maxsize = 1024*1024*2; if (M_CheckParm("-maxdemo") && M_IsNextParm()) maxsize = atoi(M_GetNextParm()) * 1024; // if (demobuffer) From d7d029eb9e085cb44b4ba31d9df7624e38d026eb Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 16:16:35 -0600 Subject: [PATCH 062/186] Don't prevent exiting games while recording at all --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 93e7a0f3c..59274e858 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7113,7 +7113,7 @@ static void M_ExitGameResponse(INT32 ch) static void M_EndGame(INT32 choice) { (void)choice; - if (demoplayback || ( demorecording && !multiplayer ))/* hack for now */ + if (demoplayback) return; if (!Playing()) From d2b34a0e200271b1cc23d8d32c29f8b50f62757d Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 18:29:51 -0600 Subject: [PATCH 063/186] Add cvar for netreplay saving options --- src/d_netcmd.c | 4 ++++ src/g_game.c | 62 +++++++++++++++++++++++++++++--------------------- src/g_game.h | 5 +++- src/p_tick.c | 4 ++++ src/p_user.c | 3 +++ src/y_inter.c | 11 +++++++++ 6 files changed, 62 insertions(+), 27 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 802037899..71adfdf08 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -793,6 +793,8 @@ void D_RegisterClientCommands(void) COM_AddCommand("displayplayer", Command_Displayplayer_f); + CV_RegisterVar(&cv_recordmultiplayerdemos); + // FIXME: not to be here.. but needs be done for config loading CV_RegisterVar(&cv_usegamma); @@ -2502,6 +2504,8 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) LUAh_MapChange(mapnumber); #endif*/ + demosaved = demodefersave = false; + demosavebutton = 0; G_InitNew(pencoremode, mapname, resetplayer, skipprecutscene); if (demoplayback && !timingdemo) precache = true; diff --git a/src/g_game.c b/src/g_game.c index 864c7f43b..84b5f1ca6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -288,8 +288,8 @@ UINT32 timesBeatenWithEmeralds; //UINT32 timesBeatenUltimate; static char demoname[64]; -boolean demorecording; -boolean demoplayback; +boolean demorecording, demosaved, demodefersave, demoplayback; +tic_t demosavebutton; boolean titledemo; // Title Screen demo can be cancelled by any key boolean fromtitledemo; // SRB2Kart: Don't stop the music static UINT8 *demobuffer = NULL; @@ -334,6 +334,9 @@ boolean precache = true; // if true, load all graphics at start INT16 prevmap, nextmap; +static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{0, "Disabled"}, {1, "Manual Save"}, {2, "Auto Save"}, {0, NULL}}; +consvar_t cv_recordmultiplayerdemos = {"recordmultiplayerdemos", "Manual Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + static UINT8 *savebuffer; // Analog Control @@ -3206,6 +3209,9 @@ void G_ExitLevel(void) // Remove CEcho text on round end. HU_ClearCEcho(); + + if (multiplayer && demorecording && cv_recordmultiplayerdemos.value == 2) + G_SaveDemo(); } } @@ -6990,8 +6996,6 @@ void G_StopDemo(void) boolean G_CheckDemoStatus(void) { - boolean saved; - while (ghosts) { demoghost *next = ghosts->next; @@ -7040,35 +7044,41 @@ boolean G_CheckDemoStatus(void) return true; } - if (demorecording) + if (demorecording && (!multiplayer || cv_recordmultiplayerdemos.value == 2)) { - UINT8 *p = demobuffer+16; // checksum position -#ifdef NOMD5 - UINT8 i; - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - for (i = 0; i < 16; i++, p++) - *p = P_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. -#else - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. -#endif - saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. - free(demobuffer); - demorecording = false; - - if (modeattacking != ATTACKING_RECORD) - { - if (saved) - CONS_Printf(M_GetText("Demo %s recorded\n"), demoname); - else - CONS_Alert(CONS_WARNING, M_GetText("Demo %s not saved\n"), demoname); - } + G_SaveDemo(); return true; } + demorecording = false; return false; } +void G_SaveDemo(void) +{ + UINT8 *p = demobuffer+16; // checksum position +#ifdef NOMD5 + UINT8 i; + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + for (i = 0; i < 16; i++, p++) + *p = P_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. +#else + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. +#endif + demosaved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. + free(demobuffer); + demorecording = false; + + if (modeattacking != ATTACKING_RECORD) + { + if (demosaved) + CONS_Printf(M_GetText("Demo %s recorded\n"), demoname); + else + CONS_Alert(CONS_WARNING, M_GetText("Demo %s not saved\n"), demoname); + } +} + // // G_SetGamestate // diff --git a/src/g_game.h b/src/g_game.h index 73dcb1ce0..458f166b7 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -36,7 +36,9 @@ extern boolean playeringame[MAXPLAYERS]; // ====================================== // demoplaying back and demo recording -extern boolean demoplayback, titledemo, fromtitledemo, demorecording, timingdemo; +extern boolean demoplayback, titledemo, fromtitledemo, demorecording, timingdemo, demosaved, demodefersave; +extern tic_t demosavebutton; +extern consvar_t cv_recordmultiplayerdemos; // Quit after playing a demo from cmdline. extern boolean singledemo; @@ -207,6 +209,7 @@ void G_StopMetalDemo(void); ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(void); void G_StopDemo(void); boolean G_CheckDemoStatus(void); +void G_SaveDemo(void); boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); diff --git a/src/p_tick.c b/src/p_tick.c index 7e048af59..f5d5d5b20 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -13,6 +13,7 @@ #include "doomstat.h" #include "g_game.h" +#include "g_input.h" #include "p_local.h" #include "z_zone.h" #include "s_sound.h" @@ -737,6 +738,9 @@ void P_Ticker(boolean run) G_WriteGhostTic(players[i].mo, i); } + + if (demosavebutton && demosavebutton + 3*TICRATE < leveltime && InputDown(gc_lookback, 1)) + demodefersave = true; } if (demoplayback) // Use Ghost data for consistency checks. { diff --git a/src/p_user.c b/src/p_user.c index 73caa2111..d51c18af1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1835,6 +1835,9 @@ void P_DoPlayerExit(player_t *player) player->powers[pw_spacetime] = 0; player->kartstuff[k_cardanimation] = 0; // srb2kart: reset battle animation + if (player == &players[consoleplayer]) + demosavebutton = leveltime; + /*if (playeringame[player-players] && netgame && !circuitmap) CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);*/ } diff --git a/src/y_inter.c b/src/y_inter.c index 0ca175078..995cddfe1 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -562,6 +562,11 @@ dotimer: string); } + if (demorecording && cv_recordmultiplayerdemos.value == 1) + V_DrawCenteredString(BASEVIDWIDTH/2, 178, V_ALLOWLOWERCASE|hilicol, "Press Look Backward to save the replay"); + else if (demosaved) + V_DrawCenteredString(BASEVIDWIDTH/2, 178, V_ALLOWLOWERCASE|hilicol, "Replay saved!"); + // Make it obvious that scrambling is happening next round. if (cv_scrambleonchange.value && cv_teamscramble.value && (intertic/TICRATE % 2 == 0)) V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, hilicol, M_GetText("Teams will be scrambled next round!")); @@ -577,6 +582,12 @@ void Y_Ticker(void) if (intertype == int_none) return; + if (demorecording && cv_recordmultiplayerdemos.value == 1 && (demodefersave || InputDown(gc_lookback, 1))) + { + demodefersave = false; + G_SaveDemo(); + } + // Check for pause or menu up in single player if (paused || P_AutoPause()) return; From 68266a7250cc8ccc22584c9dcb8357e6cf9897ef Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 20:53:15 -0600 Subject: [PATCH 064/186] Fuck you --- src/g_game.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_game.c b/src/g_game.c index 5d854beab..bdc149f0b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4881,6 +4881,7 @@ void G_ReadDemoExtraData(void) break; case DXD_PST_SPECTATING: + players[p].pflags &= ~PF_WANTSTOJOIN; // double-fuck you if (!playeringame[p]) { CL_ClearPlayer(p); From d68e3efc729e64d8ba2e030472e69d4095342597 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 21:07:11 -0600 Subject: [PATCH 065/186] Reset views away from spectators --- src/g_game.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_game.c b/src/g_game.c index bdc149f0b..7dccdaf26 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4908,6 +4908,7 @@ void G_ReadDemoExtraData(void) break; } + G_ResetViews(); // maybe these are necessary? if (G_BattleGametype()) K_CheckBumpers(); // SRB2Kart From 5a5264e5dd76b72e0da653d0f4a6dbd4a8bcc558 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 21:55:08 -0600 Subject: [PATCH 066/186] Fix multiplayer ghosts crashing the game sometimes --- src/g_game.c | 95 ++++++++++++++++++++++++++++++++++------------------ src/g_game.h | 2 ++ src/p_tick.c | 22 ++---------- 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 7dccdaf26..d7b2c4d51 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5196,6 +5196,23 @@ void G_GhostAddHit(INT32 playernum, mobj_t *victim) ghostext[playernum].hitlist[ghostext[playernum].hits-1] = victim; } +void G_WriteAllGhostTics(void) +{ + INT32 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo) + continue; + + WRITEUINT8(demo_p, i); + G_WriteGhostTic(players[i].mo, i); + } + WRITEUINT8(demo_p, 0xFF); +} + void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) { char ziptic = 0; @@ -5370,6 +5387,17 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) } } +void G_ConsAllGhostTics(void) +{ + UINT8 p = READUINT8(demo_p); + + while (p != 0xFF) + { + G_ConsGhostTic(p); + p = READUINT8(demo_p); + } +} + // Uses ghost data to do consistency checks on your position. // This fixes desynchronising demos when fighting eggman. void G_ConsGhostTic(INT32 playernum) @@ -5415,7 +5443,7 @@ void G_ConsGhostTic(INT32 playernum) if (ziptic & GZT_SPRITE) demo_p++; if(ziptic & GZT_NIGHTS) { - if (!testmo->player || !(testmo->player->pflags & PF_NIGHTSMODE) || !testmo->tracer) + if (!testmo || !testmo->player || !(testmo->player->pflags & PF_NIGHTSMODE) || !testmo->tracer) nightsfail = true; else testmo = testmo->tracer; @@ -5480,41 +5508,44 @@ void G_ConsGhostTic(INT32 playernum) } } - // Re-synchronise - px = testmo->x; - py = testmo->y; - pz = testmo->z; - gx = oldghost[playernum].x; - gy = oldghost[playernum].y; - gz = oldghost[playernum].z; - - if (nightsfail || abs(px-gx) > syncleeway || abs(py-gy) > syncleeway || abs(pz-gz) > syncleeway) + if (testmo) { - if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); - demosynced = false; + // Re-synchronise + px = testmo->x; + py = testmo->y; + pz = testmo->z; + gx = oldghost[playernum].x; + gy = oldghost[playernum].y; + gz = oldghost[playernum].z; - P_UnsetThingPosition(testmo); - testmo->x = oldghost[playernum].x; - testmo->y = oldghost[playernum].y; - P_SetThingPosition(testmo); - testmo->z = oldghost[playernum].z; - } + if (nightsfail || abs(px-gx) > syncleeway || abs(py-gy) > syncleeway || abs(pz-gz) > syncleeway) + { + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + demosynced = false; - if ( - ghostext[playernum].kartresync && ( - players[playernum].kartstuff[k_itemtype] != ghostext[playernum].kartitem || - players[playernum].kartstuff[k_itemamount] != ghostext[playernum].kartamount || - players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers) - ) - { - if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); - demosynced = false; + P_UnsetThingPosition(testmo); + testmo->x = oldghost[playernum].x; + testmo->y = oldghost[playernum].y; + P_SetThingPosition(testmo); + testmo->z = oldghost[playernum].z; + } - players[playernum].kartstuff[k_itemtype] = ghostext[playernum].kartitem; - players[playernum].kartstuff[k_itemamount] = ghostext[playernum].kartamount; - players[playernum].kartstuff[k_bumper] = ghostext[playernum].kartbumpers; + if ( + ghostext[playernum].kartresync && ( + players[playernum].kartstuff[k_itemtype] != ghostext[playernum].kartitem || + players[playernum].kartstuff[k_itemamount] != ghostext[playernum].kartamount || + players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers) + ) + { + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + demosynced = false; + + players[playernum].kartstuff[k_itemtype] = ghostext[playernum].kartitem; + players[playernum].kartstuff[k_itemamount] = ghostext[playernum].kartamount; + players[playernum].kartstuff[k_bumper] = ghostext[playernum].kartbumpers; + } } if (*demo_p == DEMOMARKER) diff --git a/src/g_game.h b/src/g_game.h index 32c314ff5..10a0280bc 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -180,7 +180,9 @@ void G_GhostAddColor(INT32 playernum, ghostcolor_t color); void G_GhostAddFlip(INT32 playernum); void G_GhostAddScale(INT32 playernum, fixed_t scale); void G_GhostAddHit(INT32 playernum, mobj_t *victim); +void G_WriteAllGhostTics(void); void G_WriteGhostTic(mobj_t *ghost, INT32 playernum); +void G_ConsAllGhostTics(void); void G_ConsGhostTic(INT32 playernum); void G_GhostTicker(void); void G_ReadMetalTic(mobj_t *metal); diff --git a/src/p_tick.c b/src/p_tick.c index f5d5d5b20..b422e9d2c 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -728,32 +728,14 @@ void P_Ticker(boolean run) { if (demorecording) { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo) - continue; - - G_WriteGhostTic(players[i].mo, i); - } + G_WriteAllGhostTics(); if (demosavebutton && demosavebutton + 3*TICRATE < leveltime && InputDown(gc_lookback, 1)) demodefersave = true; } if (demoplayback) // Use Ghost data for consistency checks. { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo) - continue; - - G_ConsGhostTic(i); - } + G_ConsAllGhostTics(); } } else From 53fa9299c1193f73b56ca158717d92179eee858c Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 22:06:47 -0600 Subject: [PATCH 067/186] Fix views getting automatically changed in netreplays --- src/g_game.c | 42 ++++++++++++++++++++++++------------------ src/g_game.h | 8 ++++---- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index d7b2c4d51..490b55bd0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1915,7 +1915,7 @@ boolean G_Responder(event_t *ev) displayplayer = consoleplayer; else { - G_AdjustView(1, 1); + G_AdjustView(1, 1, true); // change statusbar also if playing back demo if (singledemo) @@ -1929,19 +1929,19 @@ boolean G_Responder(event_t *ev) { if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) { - G_AdjustView(2, 1); + G_AdjustView(2, 1, true); return true; } else if (ev->data1 == gamecontrol3[gc_viewpoint][0] || ev->data1 == gamecontrol3[gc_viewpoint][1]) { - G_AdjustView(3, 1); + G_AdjustView(3, 1, true); return true; } else if (ev->data1 == gamecontrol4[gc_viewpoint][0] || ev->data1 == gamecontrol4[gc_viewpoint][1]) { - G_AdjustView(4, 1); + G_AdjustView(4, 1, true); return true; } @@ -2167,30 +2167,30 @@ boolean G_CanView(INT32 playernum, UINT8 viewnum) // Return the next player that can be viewed on a view, wraps forward. // An out of range startview is corrected. // -INT32 G_FindView(INT32 startview, UINT8 viewnum) +INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive) { INT32 i; startview = min(max(startview, 0), MAXPLAYERS); for (i = startview; i < MAXPLAYERS; ++i) { - if (G_CanView(i, viewnum)) + if (onlyactive ? G_CanView(i, viewnum) : (playeringame[i] && !players[i].spectator)) return i; } for (i = 0; i < startview; ++i) { - if (G_CanView(i, viewnum)) + if (onlyactive ? G_CanView(i, viewnum) : (playeringame[i] && !players[i].spectator)) return i; } return -1; } -INT32 G_CountPlayersPotentiallyViewable(void) +INT32 G_CountPlayersPotentiallyViewable(boolean active) { INT32 total = 0; INT32 i; for (i = 0; i < MAXPLAYERS; ++i) { - if (G_CouldView(i)) + if (active ? G_CouldView(i) : (playeringame[i] && !players[i].spectator)) total++; } return total; @@ -2213,7 +2213,7 @@ INT32 *G_GetDisplayplayerPtr(UINT8 viewnum) // Also promotes splitscreen up to available viewable players. // An out of range playernum is corrected. // -void G_ResetView(UINT8 viewnum, INT32 playernum) +void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) { UINT8 splits; UINT8 viewd; @@ -2229,7 +2229,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum) /* Promote splits */ if (viewnum > splits) { - playersviewable = G_CountPlayersPotentiallyViewable(); + playersviewable = G_CountPlayersPotentiallyViewable(onlyactive); if (playersviewable < splits)/* do not demote */ return; @@ -2250,7 +2250,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum) /* Focus our target view first so that we don't take its player. */ displayplayerp = (G_GetDisplayplayerPtr(viewnum)); olddisplayplayer = (*displayplayerp); - (*displayplayerp) = G_FindView(playernum, viewnum); + (*displayplayerp) = G_FindView(playernum, viewnum, onlyactive); if ((*displayplayerp) != olddisplayplayer) { camerap = (P_GetCameraPtr(viewnum)); @@ -2264,7 +2264,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum) displayplayerp = (G_GetDisplayplayerPtr(viewd)); camerap = (P_GetCameraPtr(viewd)); - (*displayplayerp) = G_FindView(0, viewd); + (*displayplayerp) = G_FindView(0, viewd, onlyactive); P_ResetCamera(&players[(*displayplayerp)], camerap); } @@ -2279,11 +2279,16 @@ void G_ResetView(UINT8 viewnum, INT32 playernum) // Increment a viewpoint by offset from the current player. A negative value // decrements. // -void G_AdjustView(UINT8 viewnum, INT32 offset) +void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive) { - INT32 *displayplayerp; + INT32 *displayplayerp, oldview; displayplayerp = G_GetDisplayplayerPtr(viewnum); - G_ResetView(viewnum, ( (*displayplayerp) + offset )); + oldview = (*displayplayerp); + G_ResetView(viewnum, ( (*displayplayerp) + offset ), onlyactive); + + // If no other view could be found, go back to what we had. + if ((*displayplayerp) == -1) + (*displayplayerp) = oldview; } // @@ -2300,7 +2305,7 @@ void G_ResetViews(void) splits = splitscreen+1; - playersviewable = G_CountPlayersPotentiallyViewable(); + playersviewable = G_CountPlayersPotentiallyViewable(false); /* Demote splits */ if (playersviewable < splits) { @@ -2315,7 +2320,7 @@ void G_ResetViews(void) */ for (viewd = 1; viewd <= splits; ++viewd) { - G_AdjustView(viewd, 0); + G_AdjustView(viewd, 0, false); } } @@ -4909,6 +4914,7 @@ void G_ReadDemoExtraData(void) } G_ResetViews(); + // maybe these are necessary? if (G_BattleGametype()) K_CheckBumpers(); // SRB2Kart diff --git a/src/g_game.h b/src/g_game.h index 10a0280bc..20edb3333 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -237,12 +237,12 @@ INT32 *G_GetDisplayplayerPtr(UINT8 viewnum); boolean G_CouldView(INT32 playernum); boolean G_CanView(INT32 playernum, UINT8 viewnum); -INT32 G_FindView(INT32 startview, UINT8 viewnum); -INT32 G_CountPlayersPotentiallyViewable(void); +INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive); +INT32 G_CountPlayersPotentiallyViewable(boolean active); void G_ResetViews(void); -void G_ResetView(UINT8 viewnum, INT32 playernum); -void G_AdjustView(UINT8 viewnum, INT32 offset); +void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive); +void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive); void G_AddPlayer(INT32 playernum); From fb8ca7c7601ac276133a4c19ab5acadf536d1757 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 22:19:05 -0600 Subject: [PATCH 068/186] Fix replays crashing upon completion --- src/g_game.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 490b55bd0..6dca67fb7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5402,6 +5402,13 @@ void G_ConsAllGhostTics(void) G_ConsGhostTic(p); p = READUINT8(demo_p); } + + if (*demo_p == DEMOMARKER) + { + // end of demo data stream + G_CheckDemoStatus(); + return; + } } // Uses ghost data to do consistency checks on your position. From 15f6e3de48c8769f340d2b656da3fb4d71d48b91 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 22:19:17 -0600 Subject: [PATCH 069/186] Remove unnecessary ResetViews call --- src/d_clisrv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 8ed33d52a..8d8bfca6e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2563,8 +2563,6 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) if (playernum == displayplayer && !demoplayback) displayplayer = consoleplayer; // don't look through someone's view who isn't there - else - G_ResetViews(); #ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[playernum]); From 63d07acc38e74a645ea1827e87beecfa8f819017 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 16 Feb 2019 22:24:37 -0600 Subject: [PATCH 070/186] Fix duplicated player views from ResetViews --- src/g_game.c | 8 ++++---- src/g_game.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 6dca67fb7..7a81aea59 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2133,13 +2133,13 @@ boolean G_CouldView(INT32 playernum) // G_CanView // Return whether a player can be viewed on a particular view (splitscreen). // -boolean G_CanView(INT32 playernum, UINT8 viewnum) +boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive) { UINT8 splits; UINT8 viewd; INT32 *displayplayerp; - if (!G_CouldView(playernum)) + if (!(onlyactive ? G_CouldView(playernum) : (playeringame[playernum] && !players[playernum].spectator))) return false; splits = splitscreen+1; @@ -2173,12 +2173,12 @@ INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive) startview = min(max(startview, 0), MAXPLAYERS); for (i = startview; i < MAXPLAYERS; ++i) { - if (onlyactive ? G_CanView(i, viewnum) : (playeringame[i] && !players[i].spectator)) + if (G_CanView(i, viewnum, onlyactive)) return i; } for (i = 0; i < startview; ++i) { - if (onlyactive ? G_CanView(i, viewnum) : (playeringame[i] && !players[i].spectator)) + if (G_CanView(i, viewnum, onlyactive)) return i; } return -1; diff --git a/src/g_game.h b/src/g_game.h index 20edb3333..0042e4bf1 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -235,7 +235,7 @@ boolean G_Responder(event_t *ev); INT32 *G_GetDisplayplayerPtr(UINT8 viewnum); boolean G_CouldView(INT32 playernum); -boolean G_CanView(INT32 playernum, UINT8 viewnum); +boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive); INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive); INT32 G_CountPlayersPotentiallyViewable(boolean active); From c00fcfe2ea81e0bdd0b97165d16b1659dac147d5 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 17 Feb 2019 10:03:34 -0600 Subject: [PATCH 071/186] Missed a ResetView line --- src/d_netcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 6d7817240..65e3c0363 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1968,7 +1968,7 @@ static void Command_View_f(void) olddisplayplayer = (*displayplayerp); (*displayplayerp) = playernum; - G_ResetView(viewnum, playernum); + G_ResetView(viewnum, playernum, false); /* The player we wanted was corrected to who it already was. */ if ((*displayplayerp) == olddisplayplayer) From ed16a35795a8913c9581af26bbd6e5220ffc3921 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 17 Feb 2019 10:04:48 -0600 Subject: [PATCH 072/186] Don't force loading files for replays --- src/d_netcmd.c | 5 +- src/f_finale.c | 2 + src/g_game.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++-- src/g_game.h | 2 +- src/m_menu.c | 2 + 5 files changed, 152 insertions(+), 8 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 65e3c0363..7376bc8c8 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2003,7 +2003,7 @@ static void Command_Playdemo_f(void) { char name[256]; - if (COM_Argc() != 2) + if (COM_Argc() < 2) { CONS_Printf(M_GetText("playdemo : playback a demo\n")); return; @@ -2027,6 +2027,9 @@ static void Command_Playdemo_f(void) CONS_Printf(M_GetText("Playing back demo '%s'.\n"), name); + demo_loadfiles = strcmp(COM_Argv(2), "-addfiles") == 0; + demo_ignorefiles = strcmp(COM_Argv(2), "-force") == 0; + // Internal if no extension, external if one exists // If external, convert the file name to a path in SRB2's home directory if (FIL_CheckExtension(name)) diff --git a/src/f_finale.c b/src/f_finale.c index b863ea74b..45f9dc1a4 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1080,6 +1080,8 @@ void F_TitleScreenTicker(boolean run) }*/ titledemo = fromtitledemo = true; + demo_ignorefiles = true; + demo_loadfiles = false; G_DoPlayDemo(dname); } } diff --git a/src/g_game.c b/src/g_game.c index c31514aed..4cbf4360e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -287,8 +287,10 @@ UINT32 timesBeaten; UINT32 timesBeatenWithEmeralds; //UINT32 timesBeatenUltimate; +//@TODO put these all in a struct for namespacing purposes? static char demoname[64]; boolean demorecording, demosaved, demodefersave, demoplayback; +boolean demo_loadfiles, demo_ignorefiles; // Demo file loading options tic_t demosavebutton; boolean titledemo; // Title Screen demo can be cancelled by any key boolean fromtitledemo; // SRB2Kart: Don't stop the music @@ -6053,11 +6055,10 @@ void G_BeginRecording(void) totalfiles = 0; for (i = mainwads; ++i < numwadfiles; ) - if (!W_VerifyNMUSlumps(wadfiles[i]->filename)) + if (!wadfiles[i]->important) { nameonly(( filename = va("%s", wadfiles[i]->filename) )); - /* FIXME: maximum size? */ - WRITESTRING(demo_p, filename); + WRITESTRINGN(demo_p, filename, 64); WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); totalfiles++; @@ -6316,6 +6317,87 @@ static void G_SkipDemoExtraFiles(UINT8 **pp) } } +// G_CheckDemoExtraFiles: checks if our loaded WAD list matches the demo's. +#define DFILE_ERROR_NOTLOADED 0x01 // Files are not loaded, but can be without a restart. +#define DFILE_ERROR_OUTOFORDER 0x02 // Files are loaded, but out of order. +#define DFILE_ERROR_INCOMPLETEOUTOFORDER 0x03 // Some files are loaded out of order, but others are not. +#define DFILE_ERROR_CANNOTLOAD 0x04 // Files are missing and cannot be loaded. +#define DFILE_ERROR_EXTRAFILES 0x05 // Extra files outside of the replay's file list are loaded. +static UINT8 G_CheckDemoExtraFiles(UINT8 **pp) +{ + UINT8 totalfiles, filesloaded, nmusfilecount; + char filename[MAX_WADPATH]; + UINT8 md5sum[16]; + boolean toomany = false; + boolean alreadyloaded; + UINT8 i, j; + UINT8 error = 0; + + totalfiles = READUINT8((*pp)); + filesloaded = 0; + for (i = 0; i < totalfiles; ++i) + { + if (toomany) + SKIPSTRING((*pp)); + else + { + strlcpy(filename, (char *)(*pp), sizeof filename); + SKIPSTRING((*pp)); + } + READMEM((*pp), md5sum, 16); + + if (!toomany) + { + alreadyloaded = false; + nmusfilecount = 0; + + for (j = 0; j < numwadfiles; ++j) + { + if (wadfiles[j]->important && j > mainwads) + nmusfilecount++; + else + continue; + + if (memcmp(md5sum, wadfiles[j]->md5sum, 16) == 0) + { + alreadyloaded = true; + + if (i != nmusfilecount-1 && error < DFILE_ERROR_OUTOFORDER) + error |= DFILE_ERROR_OUTOFORDER; + + break; + } + } + + if (alreadyloaded) + { + filesloaded++; + continue; + } + + if (numwadfiles >= MAX_WADFILES) + error = DFILE_ERROR_CANNOTLOAD; + else if (findfile(filename, md5sum, false) != FS_FOUND) + error = DFILE_ERROR_CANNOTLOAD; + else if (error < DFILE_ERROR_INCOMPLETEOUTOFORDER) + error |= DFILE_ERROR_NOTLOADED; + } else + error = DFILE_ERROR_CANNOTLOAD; + } + + // Get final file count + nmusfilecount = 0; + + for (j = 0; j < numwadfiles; ++j) + if (wadfiles[j]->important && j > mainwads) + nmusfilecount++; + + if (!error && filesloaded < nmusfilecount) + error = DFILE_ERROR_EXTRAFILES; + + return error; +} + // Returns bitfield: // 1 == new demo has lower time // 2 == new demo has higher score @@ -6455,7 +6537,7 @@ void G_DeferedPlayDemo(const char *name) { COM_BufAddText("playdemo \""); COM_BufAddText(name); - COM_BufAddText("\"\n"); + COM_BufAddText("\" -addfiles\n"); } // @@ -6569,7 +6651,61 @@ void G_DoPlayDemo(char *defdemoname) demoflags = READUINT8(demo_p); if (demoflags & DF_FILELIST) { - G_LoadDemoExtraFiles(&demo_p); + if (titledemo) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. + G_SkipDemoExtraFiles(&demo_p); + if (demo_loadfiles) + G_LoadDemoExtraFiles(&demo_p); + else if (demo_ignorefiles) + G_SkipDemoExtraFiles(&demo_p); + else + { + UINT8 error = G_CheckDemoExtraFiles(&demo_p); + + if (error) + { + switch (error) + { + case DFILE_ERROR_NOTLOADED: + snprintf(msg, 1024, + M_GetText("Required files for this demo are not loaded.\n\nUse\n\"playdemo %s -addfiles\"\nto load them and play the demo.\n"), + pdemoname); + break; + + case DFILE_ERROR_OUTOFORDER: + snprintf(msg, 1024, + M_GetText("Required files for this demo are loaded out of order.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; + + case DFILE_ERROR_INCOMPLETEOUTOFORDER: + snprintf(msg, 1024, + M_GetText("Required files for this demo are not loaded, and some are out of order.\n\nUse\n\"playdemo %s -addfiles\"\nto load needed files and play the demo.\n"), + pdemoname); + break; + + case DFILE_ERROR_CANNOTLOAD: + snprintf(msg, 1024, + M_GetText("Required files for this demo cannot be loaded.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; + + case DFILE_ERROR_EXTRAFILES: + snprintf(msg, 1024, + M_GetText("You have additional files loaded beyond the demo's file list.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; + } + + CONS_Alert(CONS_ERROR, "%s", msg); + if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out. + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + } } modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT; @@ -6879,7 +7015,7 @@ void G_AddGhost(char *defdemoname) flags = READUINT8(p); if (flags & DF_FILELIST) { - G_LoadDemoExtraFiles(&p); + G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts. } if (!(flags & DF_GHOST)) { @@ -6959,6 +7095,7 @@ void G_AddGhost(char *defdemoname) if (i == numskins) { + //@TODO nah this should fallback CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid character.\n"), pdemoname); Z_Free(pdemoname); Z_Free(buffer); diff --git a/src/g_game.h b/src/g_game.h index 0042e4bf1..4549044b0 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -36,7 +36,7 @@ extern boolean playeringame[MAXPLAYERS]; // ====================================== // demoplaying back and demo recording -extern boolean demoplayback, titledemo, fromtitledemo, demorecording, timingdemo, demosaved, demodefersave; +extern boolean demoplayback, titledemo, fromtitledemo, demorecording, timingdemo, demosaved, demodefersave, demo_loadfiles, demo_ignorefiles; extern tic_t demosavebutton; extern consvar_t cv_recordmultiplayerdemos; diff --git a/src/m_menu.c b/src/m_menu.c index 59274e858..9776b2f57 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6897,6 +6897,7 @@ static void M_HandleStaffReplay(INT32 choice) break; M_ClearMenus(true); modeattacking = ATTACKING_RECORD; + demo_loadfiles = false; demo_ignorefiles = true; // Just assume that record attack replays have the files needed G_DoPlayDemo(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); break; default: @@ -6917,6 +6918,7 @@ static void M_ReplayTimeAttack(INT32 choice) const char *which; M_ClearMenus(true); modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows + demo_loadfiles = false; demo_ignorefiles = true; // Just assume that record attack replays have the files needed if (currentMenu == &SP_ReplayDef) { From 786e8875ae975ce95ff5a0f2a5cb2eb1ffa045be Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 17 Feb 2019 11:52:23 -0600 Subject: [PATCH 073/186] Whoops, saving the wrong file list --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 4cbf4360e..efea06056 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6055,7 +6055,7 @@ void G_BeginRecording(void) totalfiles = 0; for (i = mainwads; ++i < numwadfiles; ) - if (!wadfiles[i]->important) + if (wadfiles[i]->important) { nameonly(( filename = va("%s", wadfiles[i]->filename) )); WRITESTRINGN(demo_p, filename, 64); From 0b927432443c4506548f162f5257757bd2516b98 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 17 Feb 2019 13:13:45 -0600 Subject: [PATCH 074/186] Support netreplays in titledemos TDEMO###, where ### is a number from 1 to 255. --- src/doomdef.h | 4 +-- src/f_finale.c | 18 ++++++++++++++ src/g_game.c | 17 +++++++++++-- src/k_kart.c | 66 +++++++++++++++++++++++++++++--------------------- src/st_stuff.c | 2 +- 5 files changed, 75 insertions(+), 32 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index ab863c6f6..3126a7cae 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -151,8 +151,8 @@ extern FILE *logstream; #else #define VERSION 100 // Game version #define SUBVERSION 3 // more precise version number -#define VERSIONSTRING "v1.0.3" -#define VERSIONSTRINGW L"v1.0.3" +#define VERSIONSTRING "v1.0.3 Netreplays" +#define VERSIONSTRINGW L"v1.0.3 Netreplays" // Hey! If you change this, add 1 to the MODVERSION below! // Otherwise we can't force updates! #endif diff --git a/src/f_finale.c b/src/f_finale.c index 45f9dc1a4..9872fa455 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1024,11 +1024,28 @@ void F_TitleScreenTicker(boolean run) // is it time? if (!(--demoIdleLeft)) { + static boolean use_netreplay = false; + char dname[9]; lumpnum_t l; const char *mapname; UINT8 numstaff; + if ((use_netreplay = !use_netreplay)) + { + numstaff = 1; + while ((l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR) + numstaff++; + numstaff--; + + if (numstaff) + { + numstaff = M_RandomKey(numstaff)+1; + snprintf(dname, 9, "TDEMO%03u", numstaff); + goto loadreplay; + } + } + // prevent console spam if failed demoIdleLeft = demoIdleTime; @@ -1079,6 +1096,7 @@ void F_TitleScreenTicker(boolean run) return; }*/ +loadreplay: titledemo = fromtitledemo = true; demo_ignorefiles = true; demo_loadfiles = false; diff --git a/src/g_game.c b/src/g_game.c index efea06056..fe6df0918 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6653,7 +6653,7 @@ void G_DoPlayDemo(char *defdemoname) { if (titledemo) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. G_SkipDemoExtraFiles(&demo_p); - if (demo_loadfiles) + else if (demo_loadfiles) G_LoadDemoExtraFiles(&demo_p); else if (demo_ignorefiles) G_SkipDemoExtraFiles(&demo_p); @@ -6839,6 +6839,7 @@ void G_DoPlayDemo(char *defdemoname) if (multiplayer) { boolean spectator; + UINT8 slots[MAXPLAYERS], numslots = 0; // Load players that were in-game when the map started p = READUINT8(demo_p); @@ -6850,6 +6851,7 @@ void G_DoPlayDemo(char *defdemoname) spectator = true; p &= ~DEMO_SPECTATOR; } + slots[numslots] = p; numslots++; if (!playeringame[displayplayer] || players[displayplayer].spectator) displayplayer = consoleplayer = secondarydisplayplayer = thirddisplayplayer = fourthdisplayplayer = p; @@ -6895,6 +6897,17 @@ void G_DoPlayDemo(char *defdemoname) } splitscreen = 0; + + if (titledemo) + { + splitscreen = min(min(3, numslots-1), max(0, M_RandomKey(6)-1)); // Bias toward 1p and 4p views + + for (p = 0; p <= splitscreen; p++) + G_ResetView(p+1, slots[M_RandomKey(numslots)], false); + + CONS_Printf("%d - %d %d %d %d\n", splitscreen, displayplayer, secondarydisplayplayer, thirddisplayplayer, fourthdisplayplayer); + } + R_ExecuteSetViewSize(); } @@ -7438,7 +7451,7 @@ boolean G_CheckDemoStatus(void) if (singledemo) I_Quit(); - if (multiplayer) + if (multiplayer && !titledemo) G_ExitLevel(); else { diff --git a/src/k_kart.c b/src/k_kart.c index e5cbc9c58..5d99d3144 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8107,19 +8107,12 @@ static void K_drawInput(void) if (timeinmap < 113) { INT32 count = ((INT32)(timeinmap) - 105); - offs = (titledemo ? 128 : 64); + offs = 64; while (count-- > 0) offs >>= 1; x += offs; } - if (titledemo) - { - V_DrawTinyScaledPatch(x-54, 128, splitflags, W_CachePatchName("TTKBANNR", PU_CACHE)); - V_DrawTinyScaledPatch(x-54, 128+25, splitflags, W_CachePatchName("TTKART", PU_CACHE)); - return; - } - #define BUTTW 8 #define BUTTH 11 @@ -8413,7 +8406,7 @@ void K_drawKartHUD(void) && comeback && stplyr->playerstate == PST_LIVE))); - if (!battlefullscreen || splitscreen) + if (!titledemo && (!battlefullscreen || splitscreen)) { // Draw the CHECK indicator before the other items, so it's overlapped by everything else if (cv_kartcheck.value && !splitscreen && !players[displayplayer].exiting) @@ -8428,7 +8421,7 @@ void K_drawKartHUD(void) K_drawKartWanted(); } - if (cv_kartminimap.value && !titledemo) + if (cv_kartminimap.value) { #ifdef HAVE_BLUA if (LUA_HudEnabled(hud_minimap)) @@ -8469,26 +8462,45 @@ void K_drawKartHUD(void) } if (!stplyr->spectator) // Bottom of the screen elements, don't need in spectate mode - { - if (G_RaceGametype()) // Race-only elements - { - if (!titledemo) - { - // Draw the lap counter -#ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_gametypeinfo)) -#endif - K_drawKartLaps(); + { + if (titledemo) // Draw title logo instead in titledemos + { + INT32 x = BASEVIDWIDTH - 32, y = 128, offs; + + if (splitscreen == 3) + { + x = BASEVIDWIDTH/2 + 10; + y = BASEVIDHEIGHT/2 - 30; + } - if (!splitscreen) - { - // Draw the speedometer - // TODO: Make a better speedometer. + if (timeinmap < 113) + { + INT32 count = ((INT32)(timeinmap) - 104); + offs = 256; + while (count-- > 0) + offs >>= 1; + x += offs; + } + + V_DrawTinyScaledPatch(x-54, y, 0, W_CachePatchName("TTKBANNR", PU_CACHE)); + V_DrawTinyScaledPatch(x-54, y+25, 0, W_CachePatchName("TTKART", PU_CACHE)); + } + else if (G_RaceGametype()) // Race-only elements + { + // Draw the lap counter #ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_speedometer)) + if (LUA_HudEnabled(hud_gametypeinfo)) #endif - K_drawKartSpeedometer(); - } + K_drawKartLaps(); + + if (!splitscreen) + { + // Draw the speedometer + // TODO: Make a better speedometer. +#ifdef HAVE_BLUA + if (LUA_HudEnabled(hud_speedometer)) +#endif + K_drawKartSpeedometer(); } if (isfreeplay) diff --git a/src/st_stuff.c b/src/st_stuff.c index ef40fae23..73700e1a0 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1907,7 +1907,7 @@ static void ST_overlayDrawer(void) V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[stplyr-players]); } } - else + else if (!titledemo) { if (!splitscreen) From 97a663745ac04d5796305ec46b6f371a79224b08 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 18 Feb 2019 20:51:02 -0600 Subject: [PATCH 075/186] Use generic resync message for RNG desyncs --- src/g_game.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index fe6df0918..e65b65711 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4940,7 +4940,10 @@ void G_ReadDemoExtraData(void) if (P_GetRandSeed() != rng) { P_SetRandSeed(rng); - CONS_Alert(CONS_WARNING, "Random seed has desynced!\n"); + + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + demosynced = false; } } From bca918cdbff88c68e8f1dffa6261a7474d909362 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 18 Feb 2019 20:51:28 -0600 Subject: [PATCH 076/186] Let titledemos play while game is unfocused --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index d51c18af1..6b23f67f5 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -169,7 +169,7 @@ fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move) boolean P_AutoPause(void) { // Don't pause even on menu-up or focus-lost in netgames or record attack - if (netgame || modeattacking) + if (netgame || modeattacking || titledemo) return false; return (menuactive || window_notinfocus); From b176ca27b3ba50e66865e41f07da73909cbd9a3c Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 18 Feb 2019 20:52:21 -0600 Subject: [PATCH 077/186] For now, only use netreplays on the title if available --- src/f_finale.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 9872fa455..1426e50d2 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1024,14 +1024,15 @@ void F_TitleScreenTicker(boolean run) // is it time? if (!(--demoIdleLeft)) { - static boolean use_netreplay = false; + //static boolean use_netreplay = false; char dname[9]; lumpnum_t l; const char *mapname; UINT8 numstaff; - if ((use_netreplay = !use_netreplay)) + //@TODO uncomment this when this goes into vanilla + /*if ((use_netreplay = !use_netreplay))*/ { numstaff = 1; while ((l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR) From b731e63d76c925fa2486f8b438ef68f1ca9f7d55 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 18 Feb 2019 20:54:37 -0600 Subject: [PATCH 078/186] Remove debug print --- src/g_game.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index e65b65711..19c40a19f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6907,8 +6907,6 @@ void G_DoPlayDemo(char *defdemoname) for (p = 0; p <= splitscreen; p++) G_ResetView(p+1, slots[M_RandomKey(numslots)], false); - - CONS_Printf("%d - %d %d %d %d\n", splitscreen, displayplayer, secondarydisplayplayer, thirddisplayplayer, fourthdisplayplayer); } R_ExecuteSetViewSize(); From 35148c48c049a466a6f9708cb0ff8ad23aa62e58 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 18 Feb 2019 21:08:11 -0600 Subject: [PATCH 079/186] Crash fix I think (CHERRY PICK INTO BASE) --- src/r_things.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_things.c b/src/r_things.c index c1a847a13..84ca4a1a5 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -651,7 +651,7 @@ void R_DrawMaskedColumn(column_t *column) basetexturemid = dc_texturemid; - for (; column->topdelta != 0xff ;) + for (; column && column->topdelta != 0xff ;) { // calculate unclipped screen coordinates // for post From ae3348e24db4e6970d921f26a357c171e75fa87e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 18 Feb 2019 21:23:05 -0600 Subject: [PATCH 080/186] Allow viewing karma bombs during replays --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 19c40a19f..22daab231 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2097,7 +2097,7 @@ boolean G_CouldView(INT32 playernum) return false; // I don't know if we want this actually, but I'll humor the suggestion anyway - if (G_BattleGametype()) + if (G_BattleGametype() && !demoplayback) { if (player->kartstuff[k_bumper] <= 0) return false; From 5e6b3a650c035db73553911f6d93334bf30740e7 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 18 Feb 2019 21:33:15 -0600 Subject: [PATCH 081/186] Force intermission to 10 seconds on replays --- src/y_inter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/y_inter.c b/src/y_inter.c index 995cddfe1..24c4f93e1 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -780,6 +780,8 @@ void Y_StartIntermission(void) { if (cv_inttime.value == 0 && gametype == GT_COOP) timer = 0; + else if (demoplayback) // Override inttime (which is pulled from the replay anyway + timer = 10*TICRATE; else { timer = cv_inttime.value*TICRATE; From a5a98eec2ff1febbc45db27a88dc3a88d7d8eac2 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 19 Feb 2019 17:33:02 -0600 Subject: [PATCH 082/186] Fix count limiter not always working right for titledemo netreplays --- src/g_game.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 22daab231..452c55056 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6903,7 +6903,8 @@ void G_DoPlayDemo(char *defdemoname) if (titledemo) { - splitscreen = min(min(3, numslots-1), max(0, M_RandomKey(6)-1)); // Bias toward 1p and 4p views + splitscreen = M_RandomKey(6)-1; + splitscreen = min(min(3, numslots-1), max(0, splitscreen)); // Bias toward 1p and 4p views for (p = 0; p <= splitscreen; p++) G_ResetView(p+1, slots[M_RandomKey(numslots)], false); From 030428fc9e5637730f219e31fc7e37f6526a2d64 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 19 Feb 2019 19:26:32 -0600 Subject: [PATCH 083/186] Maybe this is a better way to work around the DrawMasked crash... --- src/r_things.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/r_things.c b/src/r_things.c index 84ca4a1a5..9816ca22f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -651,7 +651,7 @@ void R_DrawMaskedColumn(column_t *column) basetexturemid = dc_texturemid; - for (; column && column->topdelta != 0xff ;) + for (; column->topdelta != 0xff ;) { // calculate unclipped screen coordinates // for post @@ -925,6 +925,13 @@ static void R_DrawVisSprite(vissprite_t *vis) if (vis->x2 >= vid.width) vis->x2 = vid.width-1; +#if 1 + // Something is occasionally setting 1px-wide sprites whose frac is exactly the width of the sprite, causing crashes due to + // accessing invalid column info. Until the cause is found, let's try to correct those manually... + while (frac + vis->xiscale*(vis->x2-vis->x1) > SHORT(patch->width)<x2 >= vis->x1) + vis->x2--; +#endif + for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) { if (vis->scalestep) // currently papersprites only From a991af5c6ac18af4c2fa38e052d816f75ed1eab6 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 20 Feb 2019 18:58:17 -0800 Subject: [PATCH 084/186] Remove jitters in view command --- src/d_netcmd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7376bc8c8..c18379aa9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1967,7 +1967,6 @@ static void Command_View_f(void) } olddisplayplayer = (*displayplayerp); - (*displayplayerp) = playernum; G_ResetView(viewnum, playernum, false); /* The player we wanted was corrected to who it already was. */ From a3c2c97a7561179baf1d342ac88dd70c9ce8ed02 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 13 Feb 2019 16:33:45 -0800 Subject: [PATCH 085/186] Add setviews command --- src/d_netcmd.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7376bc8c8..bb10afd9f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -130,6 +130,7 @@ static void Command_Map_f(void); static void Command_ResetCamera_f(void); static void Command_View_f (void); +static void Command_SetViews_f(void); static void Command_Addfile(void); static void Command_ListWADS_f(void); @@ -719,6 +720,8 @@ void D_RegisterClientCommands(void) COM_AddCommand("view3", Command_View_f); COM_AddCommand("view4", Command_View_f); + COM_AddCommand("setviews", Command_SetViews_f); + COM_AddCommand("setcontrol", Command_Setcontrol_f); COM_AddCommand("setcontrol2", Command_Setcontrol2_f); COM_AddCommand("setcontrol3", Command_Setcontrol3_f); @@ -1993,6 +1996,37 @@ static void Command_View_f(void) } #undef PRINTVIEWPOINT +static void Command_SetViews_f(void) +{ + UINT8 splits; + UINT8 newsplits; + + if (!( demoplayback && multiplayer )) + { + CONS_Alert(CONS_NOTICE, + "You must be viewing a multiplayer replay to use this.\n"); + return; + } + + if (COM_Argc() != 2) + { + CONS_Printf("setviews : set the number of split screens\n"); + return; + } + + splits = splitscreen+1; + + newsplits = atoi(COM_Argv(1)); + newsplits = min(max(newsplits, 1), 4); + if (newsplits > splits) + G_AdjustView(newsplits, 0); + else + { + splitscreen = newsplits-1; + R_ExecuteSetViewSize(); + } +} + // ======================================================================== // play a demo, add .lmp for external demos From 5c041126d6b8b73365ee99a3cff3f08919b7f684 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 13 Feb 2019 16:30:50 -0800 Subject: [PATCH 086/186] Add race placement criteria to view command --- src/d_netcmd.c | 85 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 9 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c18379aa9..cc75822d3 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1925,6 +1925,44 @@ static INT32 LookupPlayer(const char *s) return -1; } +static INT32 FindPlayerByPlace(INT32 place) +{ + INT32 playernum; + for (playernum = 0; playernum < MAXPLAYERS; ++playernum) + if (playeringame[playernum]) + { + if (players[playernum].kartstuff[k_position] == place) + { + return playernum; + } + } + return -1; +} + +// +// GetViewablePlayerPlaceRange +// Return in first and last, that player available to view, sorted by placement +// in the race. +// +static void GetViewablePlayerPlaceRange(INT32 *first, INT32 *last) +{ + INT32 i; + INT32 place; + + (*first) = MAXPLAYERS; + (*last) = 0; + + for (i = 0; i < MAXPLAYERS; ++i) + if (G_CouldView(i)) + { + place = players[i].kartstuff[k_position]; + if (place < (*first)) + (*first) = place; + if (place > (*last)) + (*last) = place; + } +} + #define PRINTVIEWPOINT( pre,suf ) \ CONS_Printf(pre"viewing \x84(%d) \x83%s\x80"suf".\n",\ (*displayplayerp), player_names[(*displayplayerp)]); @@ -1933,7 +1971,10 @@ static void Command_View_f(void) INT32 *displayplayerp; INT32 olddisplayplayer; int viewnum; + const char *playerparam; + INT32 placenum; INT32 playernum; + INT32 firstplace, lastplace; char c; /* easy peasy */ c = COM_Argv(0)[strlen(COM_Argv(0))-1];/* may be digit */ @@ -1947,7 +1988,8 @@ static void Command_View_f(void) if (viewnum > 1 && !( multiplayer && demoplayback )) { - CONS_Alert(CONS_NOTICE, "You must be viewing a multiplayer replay.\n"); + CONS_Alert(CONS_NOTICE, + "You must be viewing a multiplayer replay to use this.\n"); return; } @@ -1955,15 +1997,41 @@ static void Command_View_f(void) if (COM_Argc() > 1)/* switch to player */ { - if (( playernum = LookupPlayer(COM_Argv(1)) ) == -1) + playerparam = COM_Argv(1); + if (playerparam[0] == '#')/* search by placement */ { - CONS_Alert(CONS_WARNING, "There is no player by that name!\n"); - return; + placenum = atoi(&playerparam[1]); + playernum = FindPlayerByPlace(placenum); + if (playernum == -1 || !G_CouldView(playernum)) + { + GetViewablePlayerPlaceRange(&firstplace, &lastplace); + if (playernum == -1) + { + CONS_Alert(CONS_WARNING, "There is no player in that place! "); + } + else + { + CONS_Alert(CONS_WARNING, + "That player cannot be viewed currently! " + "The first player that you can view is \x82#%d\x80; ", + firstplace); + } + CONS_Printf("Last place is \x82#%d\x80.\n", lastplace); + return; + } } - if (!playeringame[playernum]) + else { - CONS_Alert(CONS_WARNING, "There is no player using that slot!\n"); - return; + if (( playernum = LookupPlayer(COM_Argv(1)) ) == -1) + { + CONS_Alert(CONS_WARNING, "There is no player by that name!\n"); + return; + } + if (!playeringame[playernum]) + { + CONS_Alert(CONS_WARNING, "There is no player using that slot!\n"); + return; + } } olddisplayplayer = (*displayplayerp); @@ -1976,8 +2044,7 @@ static void Command_View_f(void) if ((*displayplayerp) != playernum)/* differ parameter */ { /* skipped some */ - CONS_Alert(CONS_NOTICE, - "Another viewpoint is already set to that player.\n"); + CONS_Alert(CONS_NOTICE, "That player cannot be viewed currently.\n"); PRINTVIEWPOINT ("Now "," instead") } else From e984c3d86801c38ac1adbe430d3c92a60e2cec67 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 20 Feb 2019 19:25:56 -0800 Subject: [PATCH 087/186] Document the playdemo command --- src/d_netcmd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7376bc8c8..7ec02edaa 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2005,7 +2005,12 @@ static void Command_Playdemo_f(void) if (COM_Argc() < 2) { - CONS_Printf(M_GetText("playdemo : playback a demo\n")); + CONS_Printf("playdemo [-addfiles / -force]:\n"); + CONS_Printf(M_GetText( + "Play back a demo file. The full path from your Kart directory must be given.\n\n" + + "* With \"-addfiles\", any required files are added from a list contained within the demo file.\n" + "* With \"-force\", the demo is played even if the necessary files have not been added.\n")); return; } From 1124c06220c23f7e469be2fdccd4f815569854ba Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 21 Feb 2019 22:54:09 -0800 Subject: [PATCH 088/186] I am pretty dumb --- src/d_netcmd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7376bc8c8..4bfb6f2e6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1916,8 +1916,7 @@ static INT32 LookupPlayer(const char *s) { /* Match name case-insensitively: fully, or partially the start. */ if (playeringame[playernum]) - if (stricmp(player_names[playernum], s) == 0 || - strnicmp(player_names[playernum], s, strlen(s)) == 0) + if (strnicmp(player_names[playernum], s, strlen(s)) == 0) { return playernum; } From bfcb6cc67ea9cf4367a2dd9d037b0899bf2c59e5 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 24 Feb 2019 17:47:33 -0800 Subject: [PATCH 089/186] Try to fix compiler errors --- src/command.c | 6 +++--- src/command.h | 2 +- src/g_game.c | 2 +- src/st_stuff.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/command.c b/src/command.c index 50692c67d..886fc85f4 100644 --- a/src/command.c +++ b/src/command.c @@ -1355,7 +1355,7 @@ static void Got_NetVar(UINT8 **p, INT32 playernum) Setvalue(cvar, svalue, stealth); } -void CV_SaveNetVars(UINT8 **p, boolean demorecording) +void CV_SaveNetVars(UINT8 **p, boolean isdemorecording) { consvar_t *cvar; UINT8 *count_p = *p; @@ -1365,12 +1365,12 @@ void CV_SaveNetVars(UINT8 **p, boolean demorecording) // the client will reset all netvars to default before loading WRITEUINT16(*p, 0x0000); for (cvar = consvar_vars; cvar; cvar = cvar->next) - if (((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) || (demorecording && cvar->netid == cv_numlaps.netid)) + if (((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) || (isdemorecording && cvar->netid == cv_numlaps.netid)) { WRITEUINT16(*p, cvar->netid); // UGLY HACK: Save proper lap count in net replays - if (demorecording && cvar->netid == cv_numlaps.netid) + if (isdemorecording && cvar->netid == cv_numlaps.netid) { if (cv_basenumlaps.value && (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) diff --git a/src/command.h b/src/command.h index 70bf74a93..71cef9d94 100644 --- a/src/command.h +++ b/src/command.h @@ -160,7 +160,7 @@ void CV_AddValue(consvar_t *var, INT32 increment); void CV_SaveVariables(FILE *f); // load/save gamesate (load and save option and for network join in game) -void CV_SaveNetVars(UINT8 **p, boolean demorecording); +void CV_SaveNetVars(UINT8 **p, boolean isdemorecording); void CV_LoadNetVars(UINT8 **p); // reset cheat netvars after cheats is deactivated diff --git a/src/g_game.c b/src/g_game.c index 47bb8ac9c..24804458d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5074,7 +5074,7 @@ void G_WriteGhostTic(mobj_t *ghost) if (abs(ghost->x-oldghost.x) > MAXMOM || abs(ghost->y-oldghost.y) > MAXMOM || abs(ghost->z-oldghost.z) > MAXMOM - || leveltime & 255 == 1) // Hack to enable slightly nicer resyncing + || ( leveltime & 255 == 1 )) // Hack to enable slightly nicer resyncing { oldghost.x = ghost->x; oldghost.y = ghost->y; diff --git a/src/st_stuff.c b/src/st_stuff.c index 53a1506ec..b9046abda 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1918,9 +1918,9 @@ static void ST_overlayDrawer(void) else if (splitscreen == 1) { char name[MAXPLAYERNAME+12]; - sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]); INT32 y = (stplyr == &players[displayplayer]) ? 8 : BASEVIDHEIGHT/2-16; + sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]); V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name); } else if (splitscreen) From 64508edabc5c7c2c91dd61f4ac625bdaa01025a3 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 24 Feb 2019 17:59:13 -0800 Subject: [PATCH 090/186] d'oh --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 24804458d..53a48a9b7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5074,7 +5074,7 @@ void G_WriteGhostTic(mobj_t *ghost) if (abs(ghost->x-oldghost.x) > MAXMOM || abs(ghost->y-oldghost.y) > MAXMOM || abs(ghost->z-oldghost.z) > MAXMOM - || ( leveltime & 255 == 1 )) // Hack to enable slightly nicer resyncing + || ( leveltime & 255 ) == 1) // Hack to enable slightly nicer resyncing { oldghost.x = ghost->x; oldghost.y = ghost->y; From fcbe62bbe2e70ee47710099b416515b011ad8bbc Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 3 Mar 2019 20:24:35 -0600 Subject: [PATCH 091/186] Assign a server player in replays for Lua purposes Unfortunately this doesn't seem to help sync much. It at least prevents constant Lua errors I guess.... --- src/dehacked.c | 2 +- src/g_game.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 11aed24d0..4c3b35a3e 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9812,7 +9812,7 @@ static inline int lib_getenum(lua_State *L) lua_pushinteger(L, mapmusflags); return 1; } else if (fastcmp(word,"server")) { - if ((!multiplayer || !netgame) && !playeringame[serverplayer]) + if ((!multiplayer || !(netgame || demoplayback)) && !playeringame[serverplayer]) return 0; LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); return 1; diff --git a/src/g_game.c b/src/g_game.c index 452c55056..219bc8157 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6847,6 +6847,8 @@ void G_DoPlayDemo(char *defdemoname) // Load players that were in-game when the map started p = READUINT8(demo_p); + secondarydisplayplayer = thirddisplayplayer = fourthdisplayplayer = INT32_MAX; + while (p != 0xFF) { spectator = false; @@ -6857,7 +6859,7 @@ void G_DoPlayDemo(char *defdemoname) slots[numslots] = p; numslots++; if (!playeringame[displayplayer] || players[displayplayer].spectator) - displayplayer = consoleplayer = secondarydisplayplayer = thirddisplayplayer = fourthdisplayplayer = p; + displayplayer = consoleplayer = serverplayer = p; /*else if (!spectator && splitscreen < 3) { if (splitscreen == 0) { splitscreen = 1; From 2cecd2faf390d0e680228adfa443c2865aeda385 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 3 Mar 2019 20:25:22 -0600 Subject: [PATCH 092/186] Cleanup :3c --- src/g_game.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 219bc8157..d1252d58f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6860,18 +6860,7 @@ void G_DoPlayDemo(char *defdemoname) if (!playeringame[displayplayer] || players[displayplayer].spectator) displayplayer = consoleplayer = serverplayer = p; - /*else if (!spectator && splitscreen < 3) { - if (splitscreen == 0) { - splitscreen = 1; - secondarydisplayplayer = p; - } else if (splitscreen == 1) { - splitscreen = 2; - thirddisplayplayer = p; - } else { - splitscreen = 3; - fourthdisplayplayer = p; - } - }*/ + playeringame[p] = true; players[p].spectator = spectator; From 3918d5e1778b2b95cf23292c3008177dd4a69979 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 3 Mar 2019 20:33:59 -0600 Subject: [PATCH 093/186] Fix missing argument in G_AdjustView call --- src/d_netcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 84f4b5894..80d1fcea4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2084,7 +2084,7 @@ static void Command_SetViews_f(void) newsplits = atoi(COM_Argv(1)); newsplits = min(max(newsplits, 1), 4); if (newsplits > splits) - G_AdjustView(newsplits, 0); + G_AdjustView(newsplits, 0, true); else { splitscreen = newsplits-1; From 8d6c6823f3bf44c8eb8f3199799a413ee713aca4 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 3 Mar 2019 20:41:20 -0600 Subject: [PATCH 094/186] Maintain compat for record attack replays --- src/g_game.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index d1252d58f..10774621f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6031,7 +6031,10 @@ void G_BeginRecording(void) demoflags |= gametype<important) + if (demoflags & DF_FILELIST) { - nameonly(( filename = va("%s", wadfiles[i]->filename) )); - WRITESTRINGN(demo_p, filename, 64); - WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); + // file list + m = demo_p;/* file count */ + demo_p += 1; - totalfiles++; + totalfiles = 0; + for (i = mainwads; ++i < numwadfiles; ) + if (wadfiles[i]->important) + { + nameonly(( filename = va("%s", wadfiles[i]->filename) )); + WRITESTRINGN(demo_p, filename, 64); + WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); + + totalfiles++; + } + + WRITEUINT8(m, totalfiles); } - WRITEUINT8(m, totalfiles); - switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 From cb12da81c1ec80df1d2276bdf7a22d20eec94be5 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Mar 2019 20:02:49 -0800 Subject: [PATCH 095/186] Use correct signedness in comparison --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 10774621f..29a598ac6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4931,7 +4931,7 @@ void G_ReadDemoExtraData(void) while (p != DW_END) { - INT32 rng; + UINT32 rng; switch (p) { From 45236434af8916c34981459194b76ccabf4caab6 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Mar 2019 20:08:28 -0800 Subject: [PATCH 096/186] Remove always true expression --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 29a598ac6..048978961 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6901,7 +6901,7 @@ void G_DoPlayDemo(char *defdemoname) if (titledemo) { splitscreen = M_RandomKey(6)-1; - splitscreen = min(min(3, numslots-1), max(0, splitscreen)); // Bias toward 1p and 4p views + splitscreen = min(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); From e93a721ca1fd4dc8b860c56823bd5ab17fe9ee7e Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Mon, 4 Mar 2019 19:07:34 -0500 Subject: [PATCH 097/186] Fixup unsigned mess --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 10774621f..29a598ac6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4931,7 +4931,7 @@ void G_ReadDemoExtraData(void) while (p != DW_END) { - INT32 rng; + UINT32 rng; switch (p) { From bcebe2fcc2d30972863efbce90681ec38feffa64 Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Mon, 4 Mar 2019 19:10:43 -0500 Subject: [PATCH 098/186] Fixup max() mess --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 29a598ac6..048978961 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6901,7 +6901,7 @@ void G_DoPlayDemo(char *defdemoname) if (titledemo) { splitscreen = M_RandomKey(6)-1; - splitscreen = min(min(3, numslots-1), max(0, splitscreen)); // Bias toward 1p and 4p views + splitscreen = min(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); From 55d07235a496225cc2954c4b1bf0aa9ef6c39a8f Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Mon, 4 Mar 2019 19:16:46 -0500 Subject: [PATCH 099/186] do not overshadow demorecording --- src/command.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/command.c b/src/command.c index 50692c67d..886fc85f4 100644 --- a/src/command.c +++ b/src/command.c @@ -1355,7 +1355,7 @@ static void Got_NetVar(UINT8 **p, INT32 playernum) Setvalue(cvar, svalue, stealth); } -void CV_SaveNetVars(UINT8 **p, boolean demorecording) +void CV_SaveNetVars(UINT8 **p, boolean isdemorecording) { consvar_t *cvar; UINT8 *count_p = *p; @@ -1365,12 +1365,12 @@ void CV_SaveNetVars(UINT8 **p, boolean demorecording) // the client will reset all netvars to default before loading WRITEUINT16(*p, 0x0000); for (cvar = consvar_vars; cvar; cvar = cvar->next) - if (((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) || (demorecording && cvar->netid == cv_numlaps.netid)) + if (((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) || (isdemorecording && cvar->netid == cv_numlaps.netid)) { WRITEUINT16(*p, cvar->netid); // UGLY HACK: Save proper lap count in net replays - if (demorecording && cvar->netid == cv_numlaps.netid) + if (isdemorecording && cvar->netid == cv_numlaps.netid) { if (cv_basenumlaps.value && (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) From c68cfbdda01b64fd50c09815fd65090066ccc8bf Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Mon, 4 Mar 2019 20:09:20 -0500 Subject: [PATCH 100/186] =?UTF-8?q?Avoid=20=E2=80=98ncs=E2=80=99=20being?= =?UTF-8?q?=20used=20uninitialized?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/g_game.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 048978961..e3a1f3cd7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6294,11 +6294,13 @@ static void G_LoadDemoExtraFiles(UINT8 **pp) else ncs = findfile(filename, md5sum, false); - if (toomany || ncs != FS_FOUND) + if (toomany) { - if (toomany) - CONS_Printf("Too many files loaded\n"); - else if (ncs == FS_NOTFOUND) + CONS_Printf("Too many files loaded\n"); + } + else if (ncs != FS_FOUND) + { + if (ncs == FS_NOTFOUND) CONS_Printf("You do not have a copy of %s\n", filename); else if (ncs == FS_MD5SUMBAD) CONS_Printf("Checksum mismatch on %s\n", filename); From c209e211aea3936e949916b2d3264b60c7205feb Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Mon, 4 Mar 2019 20:26:44 -0500 Subject: [PATCH 101/186] Fixed comparing unsigned/signed mess --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index e3a1f3cd7..62bc4d8d3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5422,7 +5422,7 @@ void G_ConsAllGhostTics(void) void G_ConsGhostTic(INT32 playernum) { UINT8 ziptic; - UINT32 px,py,pz,gx,gy,gz; + fixed_t px,py,pz,gx,gy,gz; mobj_t *testmo; UINT32 syncleeway; boolean nightsfail = false; From 8b5f25caa08e5bc5a895f487eb370f484f7f01aa Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Mon, 4 Mar 2019 20:27:01 -0500 Subject: [PATCH 102/186] the READ/WRITE marcos do not need ; --- src/g_game.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 62bc4d8d3..4671b4dab 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -7218,8 +7218,8 @@ void G_UpdateStaffGhostName(lumpnum_t l) totalfiles = READUINT8(p); for (; totalfiles > 0; --totalfiles) { - SKIPSTRING(p); - READMEM(p, md5sum, 16); + SKIPSTRING(p) + READMEM(p, md5sum, 16) } } if (!(flags & DF_GHOST)) From 95c2967f358a12a0863ada3c46990f06962161f0 Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Mon, 4 Mar 2019 20:35:13 -0500 Subject: [PATCH 103/186] more unsigned mess --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 4671b4dab..19b062da0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5424,7 +5424,7 @@ void G_ConsGhostTic(INT32 playernum) UINT8 ziptic; fixed_t px,py,pz,gx,gy,gz; mobj_t *testmo; - UINT32 syncleeway; + fixed_t syncleeway; boolean nightsfail = false; if (!demo_p || !demo_start) From 6949781ca2c5ac722208c9c8b6ccb51cf722f726 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 4 Mar 2019 22:26:05 -0800 Subject: [PATCH 104/186] Do not record replays when dedicated --- src/p_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index de250b1fa..0c9ea8c7b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3164,7 +3164,7 @@ boolean P_SetupLevel(boolean skipprecip) : mapheaderinfo[gamemap - 1]->numlaps); //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. - if (!demoplayback && multiplayer) { + if (!demoplayback && multiplayer && !dedicated) { static char buf[256]; sprintf(buf, "replay"PATHSEP"online"PATHSEP"%d-%s", (int) (time(NULL)), G_BuildMapName(gamemap)); From 03783a589dfcb63ab83495c738030e410a902de0 Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Tue, 5 Mar 2019 11:29:00 -0500 Subject: [PATCH 105/186] fix EOL in k_kart.c --- src/k_kart.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 1732f69c9..7a5b77872 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6397,9 +6397,9 @@ INT32 K_calcSplitFlags(INT32 snapflags) splitflags |= V_SPLITSCREEN; } else if (splitscreen > 1) - { - if (stplyr == &players[thirddisplayplayer] || (splitscreen == 3 && stplyr == &players[fourthdisplayplayer])) - splitflags |= V_SPLITSCREEN; + { + if (stplyr == &players[thirddisplayplayer] || (splitscreen == 3 && stplyr == &players[fourthdisplayplayer])) + splitflags |= V_SPLITSCREEN; if (stplyr == &players[secondarydisplayplayer] || (splitscreen == 3 && stplyr == &players[fourthdisplayplayer])) splitflags |= V_HORZSCREEN; } @@ -8468,16 +8468,16 @@ void K_drawKartHUD(void) } if (!stplyr->spectator) // Bottom of the screen elements, don't need in spectate mode - { - if (titledemo) // Draw title logo instead in titledemos - { - INT32 x = BASEVIDWIDTH - 32, y = 128, offs; - - if (splitscreen == 3) - { - x = BASEVIDWIDTH/2 + 10; - y = BASEVIDHEIGHT/2 - 30; - } + { + if (titledemo) // Draw title logo instead in titledemos + { + INT32 x = BASEVIDWIDTH - 32, y = 128, offs; + + if (splitscreen == 3) + { + x = BASEVIDWIDTH/2 + 10; + y = BASEVIDHEIGHT/2 - 30; + } if (timeinmap < 113) { @@ -8487,10 +8487,10 @@ void K_drawKartHUD(void) offs >>= 1; x += offs; } - + V_DrawTinyScaledPatch(x-54, y, 0, W_CachePatchName("TTKBANNR", PU_CACHE)); V_DrawTinyScaledPatch(x-54, y+25, 0, W_CachePatchName("TTKART", PU_CACHE)); - } + } else if (G_RaceGametype()) // Race-only elements { // Draw the lap counter From 92d463d4227a5afa74c00190d99f9ffecb11feb4 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 6 Mar 2019 18:06:16 -0800 Subject: [PATCH 106/186] Check that G_FindView actually found a view --- src/g_game.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 19b062da0..828003467 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2249,10 +2249,13 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) R_ExecuteSetViewSize(); } + /* Check if anyone is available to view. */ + if (( playernum = G_FindView(playernum, viewnum, onlyactive) ) == -1) + return; /* Focus our target view first so that we don't take its player. */ displayplayerp = (G_GetDisplayplayerPtr(viewnum)); olddisplayplayer = (*displayplayerp); - (*displayplayerp) = G_FindView(playernum, viewnum, onlyactive); + (*displayplayerp) = playernum; if ((*displayplayerp) != olddisplayplayer) { camerap = (P_GetCameraPtr(viewnum)); From 4be82dc30f5a078f89a7941881b50ef8144d1668 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 19 Mar 2019 22:59:27 -0500 Subject: [PATCH 107/186] Don't resync position until off for two tics in a row This patches over a few trouble spots, like Misty Maze, causing consistent resyncs and screwing up playback. --- src/g_game.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 313156d31..02f703167 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -323,6 +323,8 @@ static struct { INT32 kartitem, kartamount, kartbumpers; boolean kartresync; //@TODO backwards compat with old replays. remove eventually + UINT8 desyncframes; // Don't try to resync unless we've been off for two frames, to monkeypatch a few trouble spots + // EZT_HIT UINT16 hits; mobj_t **hitlist; @@ -5548,16 +5550,25 @@ void G_ConsGhostTic(INT32 playernum) if (nightsfail || abs(px-gx) > syncleeway || abs(py-gy) > syncleeway || abs(pz-gz) > syncleeway) { - if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); - demosynced = false; + ghostext[playernum].desyncframes++; - P_UnsetThingPosition(testmo); - testmo->x = oldghost[playernum].x; - testmo->y = oldghost[playernum].y; - P_SetThingPosition(testmo); - testmo->z = oldghost[playernum].z; + if (ghostext[playernum].desyncframes >= 2) + { + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + demosynced = false; + + P_UnsetThingPosition(testmo); + testmo->x = oldghost[playernum].x; + testmo->y = oldghost[playernum].y; + P_SetThingPosition(testmo); + testmo->z = oldghost[playernum].z; + + ghostext[playernum].desyncframes = 2; + } } + else + ghostext[playernum].desyncframes = 0; if ( ghostext[playernum].kartresync && ( From d6167ef35ae75e24b171d2c6c027907d45fe419e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 19 Mar 2019 23:02:17 -0500 Subject: [PATCH 108/186] Keep record attack replays base-game-compatible for now --- src/g_game.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 02f703167..54cd3f0c9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5337,9 +5337,11 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) if (ghost->player) { if ( - ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] || - ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] || - ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper] + !modeattacking && ( //@TODO: This is a temporary check to keep netreplays EXE record attack replays compatible with base Kart. + ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] || + ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] || + ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper] + ) ) { ghostext[playernum].flags |= EZT_KART; From 3a96ee70af3e3763ad55b56006f053b3134f9059 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 19 Mar 2019 23:08:32 -0500 Subject: [PATCH 109/186] Rename recordmultiplayerdemos to netdemo_record Begins the process of namespacing demo recording commands. --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 54cd3f0c9..916b6ce1a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -339,7 +339,7 @@ boolean precache = true; // if true, load all graphics at start INT16 prevmap, nextmap; static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{0, "Disabled"}, {1, "Manual Save"}, {2, "Auto Save"}, {0, NULL}}; -consvar_t cv_recordmultiplayerdemos = {"recordmultiplayerdemos", "Manual Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_recordmultiplayerdemos = {"netdemo_record", "Manual Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static UINT8 *savebuffer; From 62281de40a8177f9c2cf728a5ae70743996216b3 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 19 Mar 2019 23:38:26 -0500 Subject: [PATCH 110/186] Fix MAXMOM being above the max value GZT_MOM* could store This caused a lot of """desyncs""" when players were moving between 128-255 FU/T, which was exacerbated by this next commit... --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 916b6ce1a..0b52c5280 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5258,7 +5258,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) ziptic_p = demo_p++; // the ziptic, written at the end of this function - #define MAXMOM (0xFFFF<<8) + #define MAXMOM (0x7FFF<<8) // GZT_XYZ is only useful if you've moved 256 FRACUNITS or more in a single tic. if (abs(ghost->x-oldghost[playernum].x) > MAXMOM From fa28feb8dbf23f8303e9602596d49b7f2258d392 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 19 Mar 2019 23:39:04 -0500 Subject: [PATCH 111/186] Add command to lower netreplay sync frequency This makes for smaller replay files while keeping sync checks in place! --- src/d_netcmd.c | 1 + src/g_game.c | 12 ++++++++++-- src/g_game.h | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 0522fd715..b13df51ec 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -811,6 +811,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("displayplayer", Command_Displayplayer_f); CV_RegisterVar(&cv_recordmultiplayerdemos); + CV_RegisterVar(&cv_netdemosyncquality); // FIXME: not to be here.. but needs be done for config loading CV_RegisterVar(&cv_usegamma); diff --git a/src/g_game.c b/src/g_game.c index 0b52c5280..7335939c2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -341,6 +341,9 @@ INT16 prevmap, nextmap; static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{0, "Disabled"}, {1, "Manual Save"}, {2, "Auto Save"}, {0, NULL}}; consvar_t cv_recordmultiplayerdemos = {"netdemo_record", "Manual Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t netdemosyncquality_cons_t[] = {{1, "MIN"}, {35, "MAX"}, {0, NULL}}; +consvar_t cv_netdemosyncquality = {"netdemo_syncquality", "1", CV_SAVE, netdemosyncquality_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + static UINT8 *savebuffer; // Analog Control @@ -5221,7 +5224,7 @@ void G_GhostAddHit(INT32 playernum, mobj_t *victim) void G_WriteAllGhostTics(void) { - INT32 i; + INT32 i, counter = leveltime; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) @@ -5230,6 +5233,11 @@ void G_WriteAllGhostTics(void) if (!players[i].mo) continue; + counter++; + + if (counter % cv_netdemosyncquality.value != 0) // Only write 1 in this many ghost datas per tic to cut down on multiplayer replay size. + continue; + WRITEUINT8(demo_p, i); G_WriteGhostTic(players[i].mo, i); } @@ -5264,7 +5272,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) if (abs(ghost->x-oldghost[playernum].x) > MAXMOM || abs(ghost->y-oldghost[playernum].y) > MAXMOM || abs(ghost->z-oldghost[playernum].z) > MAXMOM - || (leveltime & 255) == 1) // Hack to enable slightly nicer resyncing + || ((UINT8)(leveltime & 255) > 0 && (UINT8)(leveltime & 255) <= (UINT8)cv_netdemosyncquality.value)) // Hack to enable slightly nicer resyncing { oldghost[playernum].x = ghost->x; oldghost[playernum].y = ghost->y; diff --git a/src/g_game.h b/src/g_game.h index e5f947936..f78a06d06 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -38,7 +38,7 @@ extern boolean playeringame[MAXPLAYERS]; // demoplaying back and demo recording extern boolean demoplayback, titledemo, fromtitledemo, demorecording, timingdemo, demosaved, demodefersave, demo_loadfiles, demo_ignorefiles; extern tic_t demosavebutton; -extern consvar_t cv_recordmultiplayerdemos; +extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality; // Quit after playing a demo from cmdline. extern boolean singledemo; From ab0bb33d6ece9cac7b45df2440bb1bbce550e4fe Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 19 Mar 2019 23:45:45 -0500 Subject: [PATCH 112/186] Self-reminder... --- src/p_setup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_setup.c b/src/p_setup.c index b891bc76c..07a72e7f7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3164,6 +3164,7 @@ boolean P_SetupLevel(boolean skipprecip) : mapheaderinfo[gamemap - 1]->numlaps); //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. + //@TODO I'd like to fix dedis crashing when recording replays for the future too... if (!demoplayback && multiplayer && !dedicated) { static char buf[256]; sprintf(buf, "replay"PATHSEP"online"PATHSEP"%d-%s", (int) (time(NULL)), G_BuildMapName(gamemap)); From d13134bae276ea4f8e65f18539e7879e66f7a5ee Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 17:47:24 -0500 Subject: [PATCH 113/186] Prepare for a demo format upgrade! --- src/doomdef.h | 3 +++ src/g_game.c | 22 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/doomdef.h b/src/doomdef.h index a4a8ff224..793537f82 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -157,6 +157,9 @@ extern FILE *logstream; // Otherwise we can't force updates! #endif +// Maintain compatibility with 1.0.x record attack replays? +#define DEMO_COMPAT_100 + // Does this version require an added patch file? // Comment or uncomment this as necessary. //#define USE_PATCH_DTA diff --git a/src/g_game.c b/src/g_game.c index 5ea653e40..f4110b2a9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4756,7 +4756,7 @@ char *G_BuildMapTitle(INT32 mapnum) // DEMO RECORDING // -#define DEMOVERSION 0x0001 +#define DEMOVERSION 0x0002 #define DEMOHEADER "\xF0" "KartReplay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! @@ -6522,6 +6522,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) { case DEMOVERSION: // latest always supported break; +#ifdef DEMO_COMPAT_100 + case 0x0001: + I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); +#endif // too old, cannot support. default: CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); @@ -6664,6 +6668,10 @@ void G_DoPlayDemo(char *defdemoname) { case DEMOVERSION: // latest always supported break; +#ifdef DEMO_COMPAT_100 + case 0x0001: + I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); +#endif // too old, cannot support. default: snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname); @@ -7033,6 +7041,10 @@ void G_AddGhost(char *defdemoname) { case DEMOVERSION: // latest always supported break; +#ifdef DEMO_COMPAT_100 + case 0x0001: + I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); +#endif // too old, cannot support. default: CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname); @@ -7233,6 +7245,10 @@ void G_UpdateStaffGhostName(lumpnum_t l) { case DEMOVERSION: // latest always supported break; +#ifdef DEMO_COMPAT_100 + case 0x0001: + I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); +#endif // too old, cannot support. default: goto fail; @@ -7344,6 +7360,10 @@ void G_DoPlayMetal(void) { case DEMOVERSION: // latest always supported break; +#ifdef DEMO_COMPAT_100 + case 0x0001: + I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); +#endif // too old, cannot support. default: CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n")); From 0c6c401d888a1f835f54f34f3460bc0821e2048b Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 18:48:14 -0500 Subject: [PATCH 114/186] Add title to netreplays and do some format cleanup --- src/d_clisrv.c | 4 ++ src/d_clisrv.h | 1 + src/doomstat.h | 2 + src/g_game.c | 175 +++++++++++++++++++++++++++---------------------- src/hu_stuff.c | 5 ++ 5 files changed, 107 insertions(+), 80 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 79ed85d72..8e5fad287 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -140,6 +140,7 @@ static UINT8 localtextcmd3[MAXTEXTCMD]; // splitscreen == 2 static UINT8 localtextcmd4[MAXTEXTCMD]; // splitscreen == 3 static tic_t neededtic; SINT8 servernode = 0; // the number of the server node +char connectedservername[MAXSERVERNAME]; /// \brief do we accept new players? /// \todo WORK! boolean acceptnewnode = true; @@ -2320,6 +2321,9 @@ static void CL_ConnectToServer(boolean viams) { INT32 j; const char *gametypestr = NULL; + + strncpy(connectedservername, serverlist[i].info.servername, MAXSERVERNAME); + CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); for (j = 0; gametype_cons_t[j].strvalue; j++) { diff --git a/src/d_clisrv.h b/src/d_clisrv.h index f195fcc9d..2387754a1 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -532,6 +532,7 @@ extern boolean dedicated; // For dedicated server extern UINT16 software_MAXPACKETLENGTH; extern boolean acceptnewnode; extern SINT8 servernode; +extern char connectedservername[MAXSERVERNAME]; void Command_Ping_f(void); extern tic_t connectiontimeout; diff --git a/src/doomstat.h b/src/doomstat.h index 834b3a7cf..c2da75c88 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -487,6 +487,8 @@ extern UINT32 timesBeaten; // # of times the game has been beaten. extern UINT32 timesBeatenWithEmeralds; //extern UINT32 timesBeatenUltimate; +extern char demotitle[65]; + // =========================== // Internal parameters, fixed. // =========================== diff --git a/src/g_game.c b/src/g_game.c index f4110b2a9..13027e5db 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -289,6 +289,7 @@ UINT32 timesBeatenWithEmeralds; //@TODO put these all in a struct for namespacing purposes? static char demoname[64]; +char demotitle[65]; boolean demorecording, demosaved, demodefersave, demoplayback; boolean demo_loadfiles, demo_ignorefiles; // Demo file loading options tic_t demosavebutton; @@ -6061,13 +6062,6 @@ void G_BeginRecording(void) demo_p = demobuffer; demoflags = DF_GHOST|(multiplayer ? DF_MULTIPLAYER : (modeattacking<important) { - // file list - m = demo_p;/* file count */ - demo_p += 1; + nameonly(( filename = va("%s", wadfiles[i]->filename) )); + WRITESTRINGN(demo_p, filename, 64); + WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); - totalfiles = 0; - for (i = mainwads; ++i < numwadfiles; ) - if (wadfiles[i]->important) - { - nameonly(( filename = va("%s", wadfiles[i]->filename) )); - WRITESTRINGN(demo_p, filename, 64); - WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); - - totalfiles++; - } - - WRITEUINT8(m, totalfiles); + totalfiles++; } + WRITEUINT8(m, totalfiles); + switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 @@ -6471,6 +6467,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) I_Assert(c == SUBVERSION); s = READUINT16(p); I_Assert(s == DEMOVERSION); + p += 64; // full demo title p += 16; // demo checksum I_Assert(!memcmp(p, "PLAY", 4)); p += 4; // PLAY @@ -6521,10 +6518,11 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) switch(oldversion) // demoversion { case DEMOVERSION: // latest always supported + p += 64; // full demo title break; #ifdef DEMO_COMPAT_100 case 0x0001: - I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); + I_Error("You need to implement demo compat here, doofus! %s:%d", __FILE__, __LINE__); #endif // too old, cannot support. default: @@ -6667,10 +6665,15 @@ void G_DoPlayDemo(char *defdemoname) switch(demoversion) { case DEMOVERSION: // latest always supported + // demo title + M_Memcpy(demotitle, demo_p, 64); + CONS_Printf("Demo title: %s\n", demotitle); + demo_p += 64; + break; #ifdef DEMO_COMPAT_100 case 0x0001: - I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); + I_Error("You need to implement demo compat here, doofus! %s:%d", __FILE__, __LINE__); #endif // too old, cannot support. default: @@ -6700,68 +6703,73 @@ void G_DoPlayDemo(char *defdemoname) demo_p += 16; // mapmd5 demoflags = READUINT8(demo_p); - if (demoflags & DF_FILELIST) +#ifdef DEMO_COMPAT_100 + if (demoversion != 0x0001) { - if (titledemo) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. - G_SkipDemoExtraFiles(&demo_p); - else if (demo_loadfiles) - G_LoadDemoExtraFiles(&demo_p); - else if (demo_ignorefiles) - G_SkipDemoExtraFiles(&demo_p); - else +#endif + gametype = READUINT8(demo_p); + + if (titledemo) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. + G_SkipDemoExtraFiles(&demo_p); + else if (demo_loadfiles) + G_LoadDemoExtraFiles(&demo_p); + else if (demo_ignorefiles) + G_SkipDemoExtraFiles(&demo_p); + else + { + UINT8 error = G_CheckDemoExtraFiles(&demo_p); + + if (error) { - UINT8 error = G_CheckDemoExtraFiles(&demo_p); - - if (error) + switch (error) { - switch (error) - { - case DFILE_ERROR_NOTLOADED: - snprintf(msg, 1024, - M_GetText("Required files for this demo are not loaded.\n\nUse\n\"playdemo %s -addfiles\"\nto load them and play the demo.\n"), - pdemoname); - break; + case DFILE_ERROR_NOTLOADED: + snprintf(msg, 1024, + M_GetText("Required files for this demo are not loaded.\n\nUse\n\"playdemo %s -addfiles\"\nto load them and play the demo.\n"), + pdemoname); + break; - case DFILE_ERROR_OUTOFORDER: - snprintf(msg, 1024, - M_GetText("Required files for this demo are loaded out of order.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), - pdemoname); - break; + case DFILE_ERROR_OUTOFORDER: + snprintf(msg, 1024, + M_GetText("Required files for this demo are loaded out of order.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; - case DFILE_ERROR_INCOMPLETEOUTOFORDER: - snprintf(msg, 1024, - M_GetText("Required files for this demo are not loaded, and some are out of order.\n\nUse\n\"playdemo %s -addfiles\"\nto load needed files and play the demo.\n"), - pdemoname); - break; + case DFILE_ERROR_INCOMPLETEOUTOFORDER: + snprintf(msg, 1024, + M_GetText("Required files for this demo are not loaded, and some are out of order.\n\nUse\n\"playdemo %s -addfiles\"\nto load needed files and play the demo.\n"), + pdemoname); + break; - case DFILE_ERROR_CANNOTLOAD: - snprintf(msg, 1024, - M_GetText("Required files for this demo cannot be loaded.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), - pdemoname); - break; + case DFILE_ERROR_CANNOTLOAD: + snprintf(msg, 1024, + M_GetText("Required files for this demo cannot be loaded.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; - case DFILE_ERROR_EXTRAFILES: - snprintf(msg, 1024, - M_GetText("You have additional files loaded beyond the demo's file list.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), - pdemoname); - break; - } - - CONS_Alert(CONS_ERROR, "%s", msg); - if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out. - M_StartMessage(msg, NULL, MM_NOTHING); - Z_Free(pdemoname); - Z_Free(demobuffer); - demoplayback = false; - titledemo = false; - return; + case DFILE_ERROR_EXTRAFILES: + snprintf(msg, 1024, + M_GetText("You have additional files loaded beyond the demo's file list.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; } + + CONS_Alert(CONS_ERROR, "%s", msg); + if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out. + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; } } +#ifdef DEMO_COMPAT_100 + } +#endif modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT; multiplayer = !!(demoflags & DF_MULTIPLAYER); - gametype = (demoflags & DF_GAMETYPEMASK)>>DF_GAMESHIFT; CON_ToggleOff(); hu_demotime = UINT32_MAX; @@ -7043,7 +7051,7 @@ void G_AddGhost(char *defdemoname) break; #ifdef DEMO_COMPAT_100 case 0x0001: - I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); + I_Error("You need to implement demo compat here, doofus! %s:%d", __FILE__, __LINE__); #endif // too old, cannot support. default: @@ -7244,10 +7252,11 @@ void G_UpdateStaffGhostName(lumpnum_t l) switch(ghostversion) { case DEMOVERSION: // latest always supported + p += 64; // full demo title break; #ifdef DEMO_COMPAT_100 case 0x0001: - I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); + CONS_Printf("You need to implement demo compat here, doofus! %s:%d\n", __FILE__, __LINE__); #endif // too old, cannot support. default: @@ -7362,7 +7371,7 @@ void G_DoPlayMetal(void) break; #ifdef DEMO_COMPAT_100 case 0x0001: - I_Error("You need to implement demo compat here, doofus! %s:%s", __FILE__, __LINE__); + I_Error("You need to implement demo compat here, doofus! %s:%d", __FILE__, __LINE__); #endif // too old, cannot support. default: @@ -7534,13 +7543,19 @@ void G_SaveDemo(void) UINT8 *p = demobuffer+16; // checksum position #ifdef NOMD5 UINT8 i; +#endif + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + M_Memcpy(p, demotitle, 64); // Write demo title here + p += 64; + +#ifdef NOMD5 for (i = 0; i < 16; i++, p++) - *p = P_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. + *p = M_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. #else - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. #endif + demosaved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. free(demobuffer); demorecording = false; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 12633ed4d..a8cf35eb8 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2204,6 +2204,11 @@ static void HU_DrawDemoInfo(void) V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("Replay:")); V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[0]); } + else + { + V_DrawRightAlignedThinString(BASEVIDWIDTH-2, BASEVIDHEIGHT-10, V_ALLOWLOWERCASE, demotitle); + } + if (modeattacking) { V_DrawRightAlignedString((BASEVIDWIDTH/2)-4, BASEVIDHEIGHT-24, V_YELLOWMAP|V_MONOSPACE, "BEST TIME:"); From 77aea850ba9d98107a0bfa19c2c22146263e9c66 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 19:14:34 -0500 Subject: [PATCH 115/186] Clean up demo header read/write code --- src/g_game.c | 287 +++++++++++++++++++++++++-------------------------- 1 file changed, 142 insertions(+), 145 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 13027e5db..c82c368ec 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4765,11 +4765,14 @@ char *G_BuildMapTitle(INT32 mapnum) #define DF_NIGHTSATTACK 0x04 // This demo is from NiGHTS attack and contains its time left, score, and mares! #define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? #define DF_ATTACKSHIFT 1 +#define DF_ENCORE 0x40 +#define DF_MULTIPLAYER 0x80 // This demo was recorded in multiplayer mode! + +#ifdef DEMO_COMPAT_100 #define DF_FILELIST 0x08 // This demo contains an extra files list #define DF_GAMETYPEMASK 0x30 #define DF_GAMESHIFT 4 -#define DF_ENCORE 0x40 -#define DF_MULTIPLAYER 0x80 // This demo contains a dynamic number of players! +#endif #define DEMO_SPECTATOR 0x40 @@ -6123,93 +6126,45 @@ void G_BeginRecording(void) WRITEUINT32(demo_p,P_GetInitSeed()); - if (demoflags & DF_MULTIPLAYER) { - // Netvars first :) - CV_SaveNetVars(&demo_p, true); + // Save netvars + CV_SaveNetVars(&demo_p, true); - // Now store a SIMPLIFIED data struct for each in-game player - for (p = 0; p < MAXPLAYERS; p++) { - if (playeringame[p]) { - player = &players[p]; + // Now store some info for each in-game player + for (p = 0; p < MAXPLAYERS; p++) { + if (playeringame[p]) { + player = &players[p]; - WRITEUINT8(demo_p, p | (player->spectator ? DEMO_SPECTATOR : 0)); + WRITEUINT8(demo_p, p | (player->spectator ? DEMO_SPECTATOR : 0)); - // Name - memset(name, 0, 16); - strncpy(name, player_names[p], 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; + // Name + memset(name, 0, 16); + strncpy(name, player_names[p], 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; - // Skin - memset(name, 0, 16); - strncpy(name, skins[player->skin].name, 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; + // Skin + memset(name, 0, 16); + strncpy(name, skins[player->skin].name, 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; - // Color - memset(name, 0, 16); - strncpy(name, KartColor_Names[player->skincolor], 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; + // Color + memset(name, 0, 16); + strncpy(name, KartColor_Names[player->skincolor], 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; - // Score, since Kart uses this to determine where you start on the map - WRITEUINT32(demo_p, player->score); - } + // Score, since Kart uses this to determine where you start on the map + WRITEUINT32(demo_p, player->score); + + // Kart speed and weight + WRITEUINT8(demo_p, skins[player->skin].kartspeed); + WRITEUINT8(demo_p, skins[player->skin].kartweight); } - - WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing - - goto initcmdandghost; } - // Name - for (i = 0; i < 16 && cv_playername.string[i]; i++) - name[i] = cv_playername.string[i]; - for (; i < 16; i++) - name[i] = '\0'; - M_Memcpy(demo_p,name,16); - demo_p += 16; + WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing - // Skin - for (i = 0; i < 16 && cv_skin.string[i]; i++) - name[i] = cv_skin.string[i]; - for (; i < 16; i++) - name[i] = '\0'; - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Color - for (i = 0; i < 16 && cv_playercolor.string[i]; i++) - name[i] = cv_playercolor.string[i]; - for (; i < 16; i++) - name[i] = '\0'; - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Stats - WRITEUINT8(demo_p,player->charability); - WRITEUINT8(demo_p,player->charability2); - WRITEUINT8(demo_p,player->actionspd>>FRACBITS); - WRITEUINT8(demo_p,player->mindash>>FRACBITS); - WRITEUINT8(demo_p,player->maxdash>>FRACBITS); - // SRB2kart - WRITEUINT8(demo_p,player->kartspeed); - WRITEUINT8(demo_p,player->kartweight); - // - WRITEUINT8(demo_p,player->normalspeed>>FRACBITS); - WRITEUINT8(demo_p,player->runspeed>>FRACBITS); - WRITEUINT8(demo_p,player->thrustfactor); - WRITEUINT8(demo_p,player->accelstart); - WRITEUINT8(demo_p,player->acceleration); - - // Trying to convert it back to % causes demo desync due to precision loss. - // Don't do it. - WRITEFIXED(demo_p, player->jumpfactor); - - // Save netvar data (SONICCD, etc) - CV_SaveNetVars(&demo_p, false); //@TODO can this be true? it's not necessary for now but would be nice for consistency - -initcmdandghost: memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); memset(&ghostext,0,sizeof(ghostext)); @@ -6594,12 +6549,14 @@ void G_DoPlayDemo(char *defdemoname) UINT8 i, p; lumpnum_t l; char skin[17],color[17],*n,*pdemoname; - UINT8 version,subversion,kartspeed=5,kartweight=5; + UINT8 version,subversion; UINT32 randseed; char msg[1024]; #if defined(SKIPERRORS) && !defined(DEVELOP) boolean skiperrors = false; #endif + boolean spectator; + UINT8 slots[MAXPLAYERS], kartspeed[MAXPLAYERS], kartweight[MAXPLAYERS], numslots = 0; skin[16] = '\0'; color[16] = '\0'; @@ -6795,7 +6752,8 @@ void G_DoPlayDemo(char *defdemoname) // Random seed randseed = READUINT32(demo_p); - if (!multiplayer) { +#ifdef DEMO_COMPAT_100 + if (demoversion == 0x0001) { // Player name M_Memcpy(player_names[0],demo_p,16); demo_p += 16; @@ -6810,8 +6768,8 @@ void G_DoPlayDemo(char *defdemoname) demo_p += 5; // Backwards compat - some stats // SRB2kart - kartspeed = READUINT8(demo_p); - kartweight = READUINT8(demo_p); + kartspeed[0] = READUINT8(demo_p); + kartweight[0] = READUINT8(demo_p); // demo_p += 9; // Backwards compat - more stats @@ -6848,7 +6806,48 @@ void G_DoPlayDemo(char *defdemoname) players[0].skincolor = i; break; } + + // net var data + CV_LoadNetVars(&demo_p); + + // Sigh ... it's an empty demo. + if (*demo_p == DEMOMARKER) + { + snprintf(msg, 1024, M_GetText("%s contains no data to be played.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + + Z_Free(pdemoname); + + memset(&oldcmd,0,sizeof(oldcmd)); + memset(&oldghost,0,sizeof(oldghost)); + memset(&ghostext,0,sizeof(ghostext)); + + CONS_Alert(CONS_WARNING, M_GetText("Demo version does not match game version. Desyncs may occur.\n")); + + // console warning messages +#if defined(SKIPERRORS) && !defined(DEVELOP) + demosynced = (!skiperrors); +#else + demosynced = true; +#endif + + // didn't start recording right away. + demo_start = false; + + displayplayer = consoleplayer = 0; + memset(playeringame, 0, sizeof(playeringame)); + playeringame[0] = true; + + goto post_compat; } +#endif // net var data CV_LoadNetVars(&demo_p); @@ -6894,72 +6893,74 @@ void G_DoPlayDemo(char *defdemoname) #endif*/ displayplayer = consoleplayer = 0; memset(playeringame,0,sizeof(playeringame)); - playeringame[0] = !multiplayer; - if (multiplayer) { - boolean spectator; - UINT8 slots[MAXPLAYERS], numslots = 0; + // Load players that were in-game when the map started + p = READUINT8(demo_p); - // Load players that were in-game when the map started - p = READUINT8(demo_p); + secondarydisplayplayer = thirddisplayplayer = fourthdisplayplayer = INT32_MAX; - secondarydisplayplayer = thirddisplayplayer = fourthdisplayplayer = INT32_MAX; + while (p != 0xFF) + { + spectator = false; + if (p & DEMO_SPECTATOR) { + spectator = true; + p &= ~DEMO_SPECTATOR; + } + slots[numslots] = p; numslots++; - while (p != 0xFF) - { - spectator = false; - if (p & DEMO_SPECTATOR) { - spectator = true; - p &= ~DEMO_SPECTATOR; + if (!playeringame[displayplayer] || players[displayplayer].spectator) + displayplayer = consoleplayer = serverplayer = p; + + playeringame[p] = true; + players[p].spectator = spectator; + + // Name + M_Memcpy(player_names[p],demo_p,16); + demo_p += 16; + + // Skin + M_Memcpy(skin,demo_p,16); + demo_p += 16; + SetPlayerSkin(p, skin); + + // Color + M_Memcpy(color,demo_p,16); + demo_p += 16; + for (i = 0; i < MAXSKINCOLORS; i++) + if (!stricmp(KartColor_Names[i],color)) // SRB2kart + { + players[p].skincolor = i; + break; } - slots[numslots] = p; numslots++; - if (!playeringame[displayplayer] || players[displayplayer].spectator) - displayplayer = consoleplayer = serverplayer = p; + // Score, since Kart uses this to determine where you start on the map + players[p].score = READUINT32(demo_p); - playeringame[p] = true; - players[p].spectator = spectator; + // Kart stats, temporarily + kartspeed[p] = READUINT8(demo_p); + kartweight[p] = READUINT8(demo_p); - // Name - M_Memcpy(player_names[p],demo_p,16); - demo_p += 16; - - // Skin - M_Memcpy(skin,demo_p,16); - demo_p += 16; - SetPlayerSkin(p, skin); - - // Color - M_Memcpy(color,demo_p,16); - demo_p += 16; - for (i = 0; i < MAXSKINCOLORS; i++) - if (!stricmp(KartColor_Names[i],color)) // SRB2kart - { - players[p].skincolor = i; - break; - } - - // Score, since Kart uses this to determine where you start on the map - players[p].score = READUINT32(demo_p); - - // Look for the next player - p = READUINT8(demo_p); - } - - splitscreen = 0; - - if (titledemo) - { - splitscreen = M_RandomKey(6)-1; - splitscreen = min(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); - } - - R_ExecuteSetViewSize(); + // Look for the next player + p = READUINT8(demo_p); } + splitscreen = 0; + + if (titledemo) + { + splitscreen = M_RandomKey(6)-1; + splitscreen = min(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); + } + + R_ExecuteSetViewSize(); + +#ifdef DEMO_COMPAT_100 +post_compat: +#endif + P_SetRandSeed(randseed); G_InitNew(demoflags & DF_ENCORE, G_BuildMapName(gamemap), true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer. @@ -6972,16 +6973,12 @@ void G_DoPlayDemo(char *defdemoname) oldghost[i].y = players[i].mo->y; oldghost[i].z = players[i].mo->z; } - } - - if (!multiplayer) { - //CV_StealthSetValue(&cv_playercolor, players[0].skincolor); -- as far as I can tell this is more trouble than it's worth // Set saved attribute values // No cheat checking here, because even if they ARE wrong... // it would only break the replay if we clipped them. - players[0].kartspeed = kartspeed; - players[0].kartweight = kartweight; + players[i].kartspeed = kartspeed[i]; + players[i].kartweight = kartweight[i]; } demo_start = true; From b922c2289e95d82fc1b90d50441866913bbb17e9 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 19:19:57 -0500 Subject: [PATCH 116/186] Add some checks against invalid replays --- src/g_game.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index c82c368ec..608ab33ab 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6630,7 +6630,8 @@ void G_DoPlayDemo(char *defdemoname) break; #ifdef DEMO_COMPAT_100 case 0x0001: - I_Error("You need to implement demo compat here, doofus! %s:%d", __FILE__, __LINE__); + CONS_Printf("You need to implement demo compat here, doofus! %s:%d\n", __FILE__, __LINE__); + break; #endif // too old, cannot support. default: @@ -6661,7 +6662,21 @@ void G_DoPlayDemo(char *defdemoname) demoflags = READUINT8(demo_p); #ifdef DEMO_COMPAT_100 - if (demoversion != 0x0001) + if (demoversion == 0x0001) + { + if (demoflags & DF_MULTIPLAYER) + { + snprintf(msg, 1024, M_GetText("%s is an alpha multiplayer replay and cannot be played.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + } + else { #endif gametype = READUINT8(demo_p); @@ -6902,12 +6917,38 @@ void G_DoPlayDemo(char *defdemoname) while (p != 0xFF) { spectator = false; - if (p & DEMO_SPECTATOR) { + if (p & DEMO_SPECTATOR) + { spectator = true; p &= ~DEMO_SPECTATOR; + + if (modeattacking) + { + snprintf(msg, 1024, M_GetText("%s is a record attack replay with spectators, and is thus invalid.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } } slots[numslots] = p; numslots++; + + if (modeattacking && numslots > 1) + { + snprintf(msg, 1024, M_GetText("%s is a record attack replay with multiple players, and is thus invalid.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + if (!playeringame[displayplayer] || players[displayplayer].spectator) displayplayer = consoleplayer = serverplayer = p; From 1941ba09b0c6ffa53861e9f1aef6972a083a6bf3 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 19:41:25 -0500 Subject: [PATCH 117/186] Use skin with closest stats if the expected one wasn't found This allows people to watch replays without the characters loaded, without making everyone be Sonic. --- src/g_game.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 608ab33ab..319c4a00b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4855,6 +4855,26 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) return dest; } +// Finds a skin with the closest stats if the expected skin doesn't exist. +static void FindClosestSkinForStats(UINT32 p, UINT8 kartspeed, UINT8 kartweight) +{ + INT32 i, closest_skin = 0; + UINT8 closest_stats = UINT8_MAX, stat_diff; + + for (i = 0; i < numskins; i++) + { + stat_diff = abs(skins[i].kartspeed - kartspeed) + abs(skins[i].kartweight - kartweight); + if (stat_diff < closest_stats) + { + closest_stats = stat_diff; + closest_skin = i; + } + } + + CONS_Printf("Using %s instead...\n", skins[closest_skin].name); + SetPlayerSkinByNum(p, closest_skin); +} + void G_ReadDemoExtraData(void) { INT32 p, extradata, i; @@ -4875,10 +4895,22 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_SKIN) { + UINT8 kartspeed, kartweight; + // Skin M_Memcpy(name, demo_p, 16); demo_p += 16; SetPlayerSkin(p, name); + + kartspeed = READUINT8(demo_p); + kartweight = READUINT8(demo_p); + + + if (stricmp(skins[players[p].skin].name, name) != 0) + FindClosestSkinForStats(p, kartspeed, kartweight); + + players[p].kartspeed = kartspeed; + players[p].kartweight = kartweight; } if (extradata & DXD_COLOR) { @@ -4999,6 +5031,9 @@ void G_WriteDemoExtraData(void) strncpy(name, skins[players[i].skin].name, 16); M_Memcpy(demo_p,name,16); demo_p += 16; + + WRITEUINT8(demo_p, skins[players[i].skin].kartspeed); + WRITEUINT8(demo_p, skins[players[i].skin].kartweight); } if (demo_extradata[i] & DXD_COLOR) { @@ -6981,6 +7016,9 @@ void G_DoPlayDemo(char *defdemoname) kartspeed[p] = READUINT8(demo_p); kartweight[p] = READUINT8(demo_p); + if (stricmp(skins[players[p].skin].name, skin) != 0) + FindClosestSkinForStats(p, kartspeed[p], kartweight[p]); + // Look for the next player p = READUINT8(demo_p); } From 557ac6f0d3fc8db7db5a41e2e392043e8e404997 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 19:57:11 -0500 Subject: [PATCH 118/186] Move save replay prompt into the upper-right corner --- src/st_stuff.c | 4 ++-- src/y_inter.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 3899864fd..d87a805d7 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2018,9 +2018,9 @@ static void ST_overlayDrawer(void) if (demorecording && multiplayer && demosavebutton && demosavebutton + 3*TICRATE < leveltime) { if (demodefersave || cv_recordmultiplayerdemos.value == 2) - V_DrawCenteredString(BASEVIDWIDTH/2, 178, V_HUDTRANSHALF|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved."); + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved."); else - V_DrawCenteredString(BASEVIDWIDTH/2, 178, V_HUDTRANSHALF|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Press Look Backward to save the replay"); + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Look Backward: Save replay"); } ST_drawDebugInfo(); diff --git a/src/y_inter.c b/src/y_inter.c index 24c4f93e1..778ab5ad3 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -563,9 +563,9 @@ dotimer: } if (demorecording && cv_recordmultiplayerdemos.value == 1) - V_DrawCenteredString(BASEVIDWIDTH/2, 178, V_ALLOWLOWERCASE|hilicol, "Press Look Backward to save the replay"); - else if (demosaved) - V_DrawCenteredString(BASEVIDWIDTH/2, 178, V_ALLOWLOWERCASE|hilicol, "Replay saved!"); + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Look Backward: Save replay"); + else if (demosaved && !demoplayback) + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Replay saved!"); // Make it obvious that scrambling is happening next round. if (cv_scrambleonchange.value && cv_teamscramble.value && (intertic/TICRATE % 2 == 0)) From f162dc0270f4f007620eef40ffa67597eb2a352d Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 20:36:22 -0500 Subject: [PATCH 119/186] Use demo title as filename for multiplayer replays --- src/d_main.c | 2 ++ src/g_game.c | 41 ++++++++++++++++++++++++++++++++++++++++- src/m_menu.c | 2 ++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index 84d5a6f32..674cf365d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1529,6 +1529,8 @@ void D_SRB2Main(void) // as having been modified for the first game. M_PushSpecialParameters(); // push all "+" parameter at the command buffer + strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); + if (M_CheckParm("-gametype") && M_IsNextParm()) { // from Command_Map_f diff --git a/src/g_game.c b/src/g_game.c index 319c4a00b..8e58c975c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -288,7 +288,7 @@ UINT32 timesBeatenWithEmeralds; //UINT32 timesBeatenUltimate; //@TODO put these all in a struct for namespacing purposes? -static char demoname[64]; +static char demoname[128]; char demotitle[65]; boolean demorecording, demosaved, demodefersave, demoplayback; boolean demo_loadfiles, demo_ignorefiles; // Demo file loading options @@ -7625,6 +7625,45 @@ void G_SaveDemo(void) M_Memcpy(p, demotitle, 64); // Write demo title here p += 64; + if (multiplayer) + { + // Change the demo's name to be a slug of the title + char demo_slug[128]; + char *writepoint; + size_t i, strindex = 0; + boolean dash = true; + + for (i = 0; demotitle[i] && i < 127; i++) + { + if ((demotitle[i] >= 'a' && demotitle[i] <= 'z') || (demotitle[i] >= '0' && demotitle[i] <= '9')) + { + demo_slug[strindex] = demotitle[i]; + strindex++; + dash = false; + } + else if (demotitle[i] >= 'A' && demotitle[i] <= 'Z') + { + demo_slug[strindex] = demotitle[i] + 'a' - 'A'; + strindex++; + dash = false; + } + else if (!dash) + { + demo_slug[strindex] = '-'; + strindex++; + dash = true; + } + } + + demo_slug[strindex] = 0; + if (dash) demo_slug[strindex-1] = 0; + CONS_Printf("%s\n%s\n", demotitle, demo_slug); + + writepoint = strstr(demoname, "-") + 1; + demo_slug[128 - (writepoint - demoname) - 4] = 0; + sprintf(writepoint, "%s.lmp", demo_slug); + } + #ifdef NOMD5 for (i = 0; i < 16; i++, p++) *p = M_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. diff --git a/src/m_menu.c b/src/m_menu.c index 0fc622330..fa88d601b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7579,6 +7579,8 @@ static void M_StartServer(INT32 choice) multiplayer = true; + strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); + // Still need to reset devmode cv_debug = 0; From f60e92aa70fbedb740f583f1eca01211b8c7f06f Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 21:32:15 -0500 Subject: [PATCH 120/186] Move public demo vars to a single struct --- src/d_clisrv.c | 18 ++--- src/d_main.c | 2 +- src/d_netcmd.c | 30 ++++---- src/dehacked.c | 2 +- src/doomstat.h | 2 - src/f_finale.c | 10 +-- src/g_game.c | 180 +++++++++++++++++++++----------------------- src/g_game.h | 28 +++++-- src/hu_stuff.c | 10 +-- src/k_kart.c | 10 +-- src/m_cheat.c | 2 +- src/m_menu.c | 12 +-- src/p_inter.c | 2 +- src/p_map.c | 4 +- src/p_mobj.c | 2 +- src/p_setup.c | 10 +-- src/p_spec.c | 4 +- src/p_tick.c | 16 ++-- src/p_user.c | 18 ++--- src/r_data.c | 2 +- src/r_main.c | 6 +- src/r_things.c | 2 +- src/s_sound.c | 4 +- src/sdl/i_system.c | 4 +- src/st_stuff.c | 6 +- src/win32/win_sys.c | 4 +- src/y_inter.c | 18 ++--- 27 files changed, 209 insertions(+), 199 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 8e5fad287..d8ce0f963 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1742,8 +1742,8 @@ static void CL_LoadReceivedSavegame(void) } paused = false; - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; automapactive = false; // load a base level @@ -2541,7 +2541,7 @@ static void Command_connect(void) return; } - if (Playing() || titledemo) + if (Playing() || demo.title) { CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); return; @@ -2642,7 +2642,7 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) demo_extradata[playernum] |= DXD_PLAYSTATE; - if (server && !demoplayback) + if (server && !demo.playback) { INT32 node = playernode[playernum]; //playerpernode[node] = 0; // It'd be better to remove them all at once, but ghosting happened, so continue to let CL_RemovePlayer do it one-by-one @@ -2717,7 +2717,7 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) RemoveAdminPlayer(playernum); // don't stay admin after you're gone } - if (playernum == displayplayer && !demoplayback) + if (playernum == displayplayer && !demo.playback) displayplayer = consoleplayer; // don't look through someone's view who isn't there #ifdef HAVE_BLUA @@ -2738,7 +2738,7 @@ void CL_Reset(void) G_StopMetalRecording(); if (metalplayback) G_StopMetalDemo(); - if (demorecording) + if (demo.recording) G_CheckDemoStatus(); // reset client/server code @@ -3657,7 +3657,7 @@ boolean Playing(void) boolean SV_SpawnServer(void) { - if (demoplayback) + if (demo.playback) G_StopDemo(); // reset engine parameter if (metalplayback) G_StopMetalDemo(); @@ -5245,7 +5245,7 @@ void TryRunTics(tic_t realtics) NetUpdate(); - if (demoplayback) + if (demo.playback) { neededtic = gametic + realtics * (gamestate == GS_LEVEL ? cv_playbackspeed.value : 1); // start a game after a demo @@ -5508,7 +5508,7 @@ FILESTAMP } else { - if (!demoplayback) + if (!demo.playback) { INT32 counts; diff --git a/src/d_main.c b/src/d_main.c index 674cf365d..6edb1cf44 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1502,7 +1502,7 @@ void D_SRB2Main(void) if (M_CheckParm("-playdemo")) { - singledemo = true; // quit after one demo + demo.quitafterplaying = true; // quit after one demo G_DeferedPlayDemo(tmp); } else diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b13df51ec..d4ffe27a8 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2005,7 +2005,7 @@ static void Command_View_f(void) default: viewnum = 1; } - if (viewnum > 1 && !( multiplayer && demoplayback )) + if (viewnum > 1 && !( multiplayer && demo.playback )) { CONS_Alert(CONS_NOTICE, "You must be viewing a multiplayer replay to use this.\n"); @@ -2083,7 +2083,7 @@ static void Command_SetViews_f(void) UINT8 splits; UINT8 newsplits; - if (!( demoplayback && multiplayer )) + if (!( demo.playback && multiplayer )) { CONS_Alert(CONS_NOTICE, "You must be viewing a multiplayer replay to use this.\n"); @@ -2137,7 +2137,7 @@ static void Command_Playdemo_f(void) } // disconnect from server here? - if (demoplayback) + if (demo.playback) G_StopDemo(); if (metalplayback) G_StopMetalDemo(); @@ -2148,8 +2148,8 @@ static void Command_Playdemo_f(void) CONS_Printf(M_GetText("Playing back demo '%s'.\n"), name); - demo_loadfiles = strcmp(COM_Argv(2), "-addfiles") == 0; - demo_ignorefiles = strcmp(COM_Argv(2), "-force") == 0; + demo.loadfiles = strcmp(COM_Argv(2), "-addfiles") == 0; + demo.ignorefiles = strcmp(COM_Argv(2), "-force") == 0; // Internal if no extension, external if one exists // If external, convert the file name to a path in SRB2's home directory @@ -2176,7 +2176,7 @@ static void Command_Timedemo_f(void) } // disconnect from server here? - if (demoplayback) + if (demo.playback) G_StopDemo(); if (metalplayback) G_StopMetalDemo(); @@ -2610,7 +2610,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) CON_ToggleOff(); CON_ClearHUD(); - if (demoplayback && !timingdemo) + if (demo.playback && !demo.timing) precache = false; if (resetplayer) @@ -2628,18 +2628,18 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) #endif*/ demosaved = demodefersave = false; - demosavebutton = 0; + demo.savebutton = 0; G_InitNew(pencoremode, mapname, resetplayer, skipprecutscene); - if (demoplayback && !timingdemo) + if (demo.playback && !demo.timing) precache = true; - if (timingdemo) + if (demo.timing) G_DoneLevelLoad(); if (metalrecording) G_BeginMetal(); - if (demorecording) // Okay, level loaded, character spawned and skinned, + if (demo.recording) // Okay, level loaded, character spawned and skinned, G_BeginRecording(); // I AM NOW READY TO RECORD. - demo_start = true; + demo.deferstart = true; } static void Command_Pause(void) @@ -2695,7 +2695,7 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) paused = READUINT8(*cp); dedicatedpause = READUINT8(*cp); - if (!demoplayback) + if (!demo.playback) { if (netgame) { @@ -4668,7 +4668,7 @@ static void PointLimit_OnChange(void) static void NumLaps_OnChange(void) { - if (!G_RaceGametype() || (modeattacking || demoplayback)) + if (!G_RaceGametype() || (modeattacking || demo.playback)) return; if (server && Playing() @@ -5108,7 +5108,7 @@ static void Command_ExitLevel_f(void) CONS_Printf(M_GetText("This only works in a netgame.\n")); else if (!(server || (IsPlayerAdmin(consoleplayer)))) CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); - else if (gamestate != GS_LEVEL || demoplayback) + else if (gamestate != GS_LEVEL || demo.playback) CONS_Printf(M_GetText("You must be in a level to use this.\n")); else SendNetXCmd(XD_EXITLEVEL, NULL, 0); diff --git a/src/dehacked.c b/src/dehacked.c index 4f41ac0cd..20c2964b7 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9873,7 +9873,7 @@ static inline int lib_getenum(lua_State *L) lua_pushinteger(L, mapmusflags); return 1; } else if (fastcmp(word,"server")) { - if ((!multiplayer || !(netgame || demoplayback)) && !playeringame[serverplayer]) + if ((!multiplayer || !(netgame || demo.playback)) && !playeringame[serverplayer]) return 0; LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); return 1; diff --git a/src/doomstat.h b/src/doomstat.h index c2da75c88..834b3a7cf 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -487,8 +487,6 @@ extern UINT32 timesBeaten; // # of times the game has been beaten. extern UINT32 timesBeatenWithEmeralds; //extern UINT32 timesBeatenUltimate; -extern char demotitle[65]; - // =========================== // Internal parameters, fixed. // =========================== diff --git a/src/f_finale.c b/src/f_finale.c index cdde54f3c..d184a2833 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -909,9 +909,9 @@ void F_StartTitleScreen(void) // IWAD dependent stuff. // music is started in the ticker - if (!fromtitledemo) // SRB2Kart: Don't reset music if the right track is already playing + if (!demo.fromtitle) // SRB2Kart: Don't reset music if the right track is already playing S_StopMusic(); - fromtitledemo = false; + demo.fromtitle = false; animtimer = 0; @@ -1098,9 +1098,9 @@ void F_TitleScreenTicker(boolean run) }*/ loadreplay: - titledemo = fromtitledemo = true; - demo_ignorefiles = true; - demo_loadfiles = false; + demo.title = demo.fromtitle = true; + demo.ignorefiles = true; + demo.loadfiles = false; G_DoPlayDemo(dname); } } diff --git a/src/g_game.c b/src/g_game.c index 8e58c975c..ef8a41968 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -101,7 +101,6 @@ UINT8 numDemos = 0; //3; -- i'm FED UP of losing my skincolour to a broken UINT32 demoDelayTime = 15*TICRATE; UINT32 demoIdleTime = 3*TICRATE; -boolean timingdemo; // if true, exit with report on completion boolean nodrawers; // for comparative timing purposes boolean noblit; // for comparative timing purposes static tic_t demostarttime; // for comparative timing purposes @@ -289,21 +288,16 @@ UINT32 timesBeatenWithEmeralds; //@TODO put these all in a struct for namespacing purposes? static char demoname[128]; -char demotitle[65]; -boolean demorecording, demosaved, demodefersave, demoplayback; -boolean demo_loadfiles, demo_ignorefiles; // Demo file loading options -tic_t demosavebutton; -boolean titledemo; // Title Screen demo can be cancelled by any key -boolean fromtitledemo; // SRB2Kart: Don't stop the music +boolean demosaved, demodefersave; static UINT8 *demobuffer = NULL; static UINT8 *demo_p, *demotime_p; static UINT8 *demoend; static UINT8 demoflags; static UINT16 demoversion; -boolean singledemo; // quit after playing a demo from cmdline -boolean demo_start; // don't start playing demo right away static boolean demosynced = true; // console warning message +struct demovars_s demo; + boolean metalrecording; // recording as metal sonic mobj_t *metalplayback; static UINT8 *metalbuffer = NULL; @@ -1252,7 +1246,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) static boolean keyboard_look, keyboard_look2, keyboard_look3, keyboard_look4; // true if lookup/down using keyboard static boolean resetdown, resetdown2, resetdown3, resetdown4; // don't cam reset every frame - if (demoplayback) return; + if (demo.playback) return; switch (ssplayer) { @@ -1842,8 +1836,8 @@ static INT32 spectatedelay, spectatedelay2, spectatedelay3, spectatedelay4 = 0; boolean G_Responder(event_t *ev) { // any other key pops up menu if in demos - if (gameaction == ga_nothing && !singledemo && - ((demoplayback && !modeattacking && !titledemo && !multiplayer) || gamestate == GS_TITLESCREEN)) + if (gameaction == ga_nothing && !demo.quitafterplaying && + ((demo.playback && !modeattacking && !demo.title && !multiplayer) || gamestate == GS_TITLESCREEN)) { if (ev->type == ev_keydown && ev->data1 != 301) { @@ -1852,7 +1846,7 @@ boolean G_Responder(event_t *ev) } return false; } - else if (demoplayback && titledemo) + else if (demo.playback && demo.title) { // Title demo uses intro responder if (F_IntroResponder(ev)) @@ -1922,21 +1916,21 @@ boolean G_Responder(event_t *ev) if (gamestate == GS_LEVEL && ev->type == ev_keydown && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) { - if (!demoplayback && (splitscreen || !netgame)) + if (!demo.playback && (splitscreen || !netgame)) displayplayer = consoleplayer; else { G_AdjustView(1, 1, true); // change statusbar also if playing back demo - if (singledemo) + if (demo.quitafterplaying) ST_changeDemoView(); return true; } } - if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demoplayback) + if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demo.playback) { if (ev->data1 == gamecontrolbis[gc_viewpoint][0] || ev->data1 == gamecontrolbis[gc_viewpoint][1]) { @@ -2106,7 +2100,7 @@ boolean G_CouldView(INT32 playernum) return false; // I don't know if we want this actually, but I'll humor the suggestion anyway - if (G_BattleGametype() && !demoplayback) + if (G_BattleGametype() && !demo.playback) { if (player->kartstuff[k_bumper] <= 0) return false; @@ -2284,7 +2278,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) } } - if (viewnum == 1 && demoplayback) + if (viewnum == 1 && demo.playback) consoleplayer = displayplayer; } @@ -2415,7 +2409,7 @@ void G_Ticker(boolean run) switch (gamestate) { case GS_LEVEL: - if (titledemo) + if (demo.title) F_TitleDemoTicker(); P_Ticker(run); // tic the game ST_Ticker(); @@ -2545,7 +2539,7 @@ static inline void G_PlayerFinishLevel(INT32 player) // SRB2kart: Increment the "matches played" counter. if (player == consoleplayer) { - if (legitimateexit && !demoplayback && !mapreset) // (yes you're allowed to unlock stuff this way when the game is modified) + if (legitimateexit && !demo.playback && !mapreset) // (yes you're allowed to unlock stuff this way when the game is modified) { matchesplayed++; if (M_UpdateUnlockablesAndExtraEmblems(true)) @@ -3331,7 +3325,7 @@ void G_ExitLevel(void) // Remove CEcho text on round end. HU_ClearCEcho(); - if (multiplayer && demorecording && cv_recordmultiplayerdemos.value == 2) + if (multiplayer && demo.recording && cv_recordmultiplayerdemos.value == 2) G_SaveDemo(); } } @@ -3397,7 +3391,7 @@ boolean G_GametypeHasSpectators(void) #if 0 return (gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE); #else - return (netgame || (multiplayer && demoplayback)); //true + return (netgame || (multiplayer && demo.playback)); //true #endif } @@ -3723,7 +3717,7 @@ static void G_DoCompleted(void) } // play some generic music if there's no win/cool/lose music going on (for exitlevel commands) - if (G_RaceGametype() && ((multiplayer && demoplayback) || j == splitscreen+1) && (cv_inttime.value > 0)) + if (G_RaceGametype() && ((multiplayer && demo.playback) || j == splitscreen+1) && (cv_inttime.value > 0)) S_ChangeMusicInternal("racent", true); if (automapactive) @@ -3733,7 +3727,7 @@ static void G_DoCompleted(void) prevmap = (INT16)(gamemap-1); - if (demoplayback) goto demointermission; + if (demo.playback) goto demointermission; // go to next level // nextmap is 0-based, unlike gamemap @@ -3860,7 +3854,7 @@ void G_AfterIntermission(void) HU_ClearCEcho(); //G_NextLevel(); - if (demoplayback) + if (demo.playback) { G_StopDemo(); D_StartTitle(); @@ -4441,7 +4435,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) } save_p += VERSIONSIZE; - if (demoplayback) // reset game engine + if (demo.playback) // reset game engine G_StopDemo(); // paused = false; @@ -4540,7 +4534,7 @@ void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar UINT8 color = 0; paused = false; - if (demoplayback) + if (demo.playback) COM_BufAddText("stopdemo\n"); while (ghosts) @@ -4602,7 +4596,7 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool legitimateexit = false; // SRB2Kart comebackshowninfo = false; - if (!demoplayback && !netgame) // Netgame sets random seed elsewhere, demo playback sets seed just before us! + if (!demo.playback && !netgame) // Netgame sets random seed elsewhere, demo playback sets seed just before us! P_SetRandSeed(M_RandomizedSeed()); // Use a more "Random" random seed //SRB2Kart - Score is literally the only thing you SHOULDN'T reset at all times @@ -4648,7 +4642,7 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool players[i].marescore = 0; - if (resetplayer && !(multiplayer && demoplayback)) // SRB2Kart + if (resetplayer && !(multiplayer && demo.playback)) // SRB2Kart { players[i].score = 0; } @@ -5094,7 +5088,7 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) { UINT8 ziptic; - if (!demo_p || !demo_start) + if (!demo_p || !demo.deferstart) return; ziptic = READUINT8(demo_p); @@ -5202,35 +5196,35 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) void G_GhostAddThok(INT32 playernum) { - if (!demorecording || !(demoflags & DF_GHOST)) + if (!demo.recording || !(demoflags & DF_GHOST)) return; ghostext[playernum].flags = (ghostext[playernum].flags & ~EZT_THOKMASK) | EZT_THOK; } void G_GhostAddSpin(INT32 playernum) { - if (!demorecording || !(demoflags & DF_GHOST)) + if (!demo.recording || !(demoflags & DF_GHOST)) return; ghostext[playernum].flags = (ghostext[playernum].flags & ~EZT_THOKMASK) | EZT_SPIN; } void G_GhostAddRev(INT32 playernum) { - if (!demorecording || !(demoflags & DF_GHOST)) + if (!demo.recording || !(demoflags & DF_GHOST)) return; ghostext[playernum].flags = (ghostext[playernum].flags & ~EZT_THOKMASK) | EZT_REV; } void G_GhostAddFlip(INT32 playernum) { - if (!demorecording || !(demoflags & DF_GHOST)) + if (!demo.recording || !(demoflags & DF_GHOST)) return; ghostext[playernum].flags |= EZT_FLIP; } void G_GhostAddColor(INT32 playernum, ghostcolor_t color) { - if (!demorecording || !(demoflags & DF_GHOST)) + if (!demo.recording || !(demoflags & DF_GHOST)) return; if (ghostext[playernum].lastcolor == (UINT8)color) { @@ -5243,7 +5237,7 @@ void G_GhostAddColor(INT32 playernum, ghostcolor_t color) void G_GhostAddScale(INT32 playernum, fixed_t scale) { - if (!demorecording || !(demoflags & DF_GHOST)) + if (!demo.recording || !(demoflags & DF_GHOST)) return; if (ghostext[playernum].lastscale == scale) { @@ -5256,7 +5250,7 @@ void G_GhostAddScale(INT32 playernum, fixed_t scale) void G_GhostAddHit(INT32 playernum, mobj_t *victim) { - if (!demorecording || !(demoflags & DF_GHOST)) + if (!demo.recording || !(demoflags & DF_GHOST)) return; ghostext[playernum].flags |= EZT_HIT; ghostext[playernum].hits++; @@ -5490,7 +5484,7 @@ void G_ConsGhostTic(INT32 playernum) fixed_t syncleeway; boolean nightsfail = false; - if (!demo_p || !demo_start) + if (!demo_p || !demo.deferstart) return; if (!(demoflags & DF_GHOST)) return; // No ghost data to use. @@ -6068,7 +6062,7 @@ void G_RecordDemo(const char *name) demobuffer = malloc(maxsize); demoend = demobuffer + maxsize; - demorecording = true; + demo.recording = true; } void G_RecordMetal(void) @@ -6111,7 +6105,7 @@ void G_BeginRecording(void) // Full replay title demo_p += 64; - snprintf(demotitle, 64, "%s - %s", G_BuildMapTitle(gamemap), modeattacking ? "Record Attack" : connectedservername); + snprintf(demo.titlename, 64, "%s - %s", G_BuildMapTitle(gamemap), modeattacking ? "Record Attack" : connectedservername); // demo checksum demo_p += 16; @@ -6253,7 +6247,7 @@ void G_BeginMetal(void) void G_SetDemoTime(UINT32 ptime, UINT32 plap) { - if (!demorecording || !demotime_p) + if (!demo.recording || !demotime_p) return; if (demoflags & DF_RECORDATTACK) { @@ -6637,7 +6631,7 @@ void G_DoPlayDemo(char *defdemoname) // read demo header gameaction = ga_nothing; - demoplayback = true; + demo.playback = true; if (memcmp(demo_p, DEMOHEADER, 12)) { snprintf(msg, 1024, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemoname); @@ -6645,8 +6639,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } demo_p += 12; // DEMOHEADER @@ -6658,8 +6652,8 @@ void G_DoPlayDemo(char *defdemoname) { case DEMOVERSION: // latest always supported // demo title - M_Memcpy(demotitle, demo_p, 64); - CONS_Printf("Demo title: %s\n", demotitle); + M_Memcpy(demo.titlename, demo_p, 64); + CONS_Printf("Demo title: %s\n", demo.titlename); demo_p += 64; break; @@ -6675,8 +6669,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } demo_p += 16; // demo checksum @@ -6687,8 +6681,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } demo_p += 4; // "PLAY" @@ -6706,8 +6700,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } } @@ -6716,11 +6710,11 @@ void G_DoPlayDemo(char *defdemoname) #endif gametype = READUINT8(demo_p); - if (titledemo) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. + if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. G_SkipDemoExtraFiles(&demo_p); - else if (demo_loadfiles) + else if (demo.loadfiles) G_LoadDemoExtraFiles(&demo_p); - else if (demo_ignorefiles) + else if (demo.ignorefiles) G_SkipDemoExtraFiles(&demo_p); else { @@ -6766,8 +6760,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } } @@ -6831,8 +6825,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } @@ -6844,8 +6838,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } @@ -6868,8 +6862,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } @@ -6889,7 +6883,7 @@ void G_DoPlayDemo(char *defdemoname) #endif // didn't start recording right away. - demo_start = false; + demo.deferstart = false; displayplayer = consoleplayer = 0; memset(playeringame, 0, sizeof(playeringame)); @@ -6910,8 +6904,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } @@ -6936,7 +6930,7 @@ void G_DoPlayDemo(char *defdemoname) #endif // didn't start recording right away. - demo_start = false; + demo.deferstart = false; /*#ifdef HAVE_BLUA LUAh_MapChange(gamemap); @@ -6964,8 +6958,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } } @@ -6979,8 +6973,8 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); Z_Free(demobuffer); - demoplayback = false; - titledemo = false; + demo.playback = false; + demo.title = false; return; } @@ -7025,7 +7019,7 @@ void G_DoPlayDemo(char *defdemoname) splitscreen = 0; - if (titledemo) + if (demo.title) { splitscreen = M_RandomKey(6)-1; splitscreen = min(min(3, numslots-1), splitscreen); // Bias toward 1p and 4p views @@ -7060,7 +7054,7 @@ post_compat: players[i].kartweight = kartweight[i]; } - demo_start = true; + demo.deferstart = true; } #undef SKIPERRORS @@ -7397,7 +7391,7 @@ void G_TimeDemo(const char *name) restorecv_vidwait = cv_vidwait.value; if (cv_vidwait.value) CV_Set(&cv_vidwait, "0"); - timingdemo = true; + demo.timing = true; singletics = true; framecount = 0; demostarttime = I_GetTime(); @@ -7531,11 +7525,11 @@ void G_StopDemo(void) { Z_Free(demobuffer); demobuffer = NULL; - demoplayback = false; - if (titledemo) + demo.playback = false; + if (demo.title) modeattacking = false; - titledemo = false; - timingdemo = false; + demo.title = false; + demo.timing = false; singletics = false; if (gamestate == GS_LEVEL && rendermode != render_none) @@ -7566,7 +7560,7 @@ boolean G_CheckDemoStatus(void) // DO NOT end metal sonic demos here - if (timingdemo) + if (demo.timing) { INT32 demotime; double f1, f2; @@ -7574,7 +7568,7 @@ boolean G_CheckDemoStatus(void) if (!demotime) return true; G_StopDemo(); - timingdemo = false; + demo.timing = false; f1 = (double)demotime; f2 = (double)framecount*TICRATE; CONS_Printf(M_GetText("timed %u gametics in %d realtics\n%f seconds, %f avg fps\n"), leveltime,demotime,f1/TICRATE,f2/f1); @@ -7584,12 +7578,12 @@ boolean G_CheckDemoStatus(void) return true; } - if (demoplayback) + if (demo.playback) { - if (singledemo) + if (demo.quitafterplaying) I_Quit(); - if (multiplayer && !titledemo) + if (multiplayer && !demo.title) G_ExitLevel(); else { @@ -7604,12 +7598,12 @@ boolean G_CheckDemoStatus(void) return true; } - if (demorecording && (!multiplayer || cv_recordmultiplayerdemos.value == 2)) + if (demo.recording && (!multiplayer || cv_recordmultiplayerdemos.value == 2)) { G_SaveDemo(); return true; } - demorecording = false; + demo.recording = false; return false; } @@ -7622,7 +7616,7 @@ void G_SaveDemo(void) #endif WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - M_Memcpy(p, demotitle, 64); // Write demo title here + M_Memcpy(p, demo.titlename, 64); // Write demo title here p += 64; if (multiplayer) @@ -7633,17 +7627,18 @@ void G_SaveDemo(void) size_t i, strindex = 0; boolean dash = true; - for (i = 0; demotitle[i] && i < 127; i++) + for (i = 0; demo.titlename[i] && i < 127; i++) { - if ((demotitle[i] >= 'a' && demotitle[i] <= 'z') || (demotitle[i] >= '0' && demotitle[i] <= '9')) + if ((demo.titlename[i] >= 'a' && demo.titlename[i] <= 'z') || + (demo.titlename[i] >= '0' && demo.titlename[i] <= '9')) { - demo_slug[strindex] = demotitle[i]; + demo_slug[strindex] = demo.titlename[i]; strindex++; dash = false; } - else if (demotitle[i] >= 'A' && demotitle[i] <= 'Z') + else if (demo.titlename[i] >= 'A' && demo.titlename[i] <= 'Z') { - demo_slug[strindex] = demotitle[i] + 'a' - 'A'; + demo_slug[strindex] = demo.titlename[i] + 'a' - 'A'; strindex++; dash = false; } @@ -7657,7 +7652,6 @@ void G_SaveDemo(void) demo_slug[strindex] = 0; if (dash) demo_slug[strindex-1] = 0; - CONS_Printf("%s\n%s\n", demotitle, demo_slug); writepoint = strstr(demoname, "-") + 1; demo_slug[128 - (writepoint - demoname) - 4] = 0; @@ -7673,7 +7667,7 @@ void G_SaveDemo(void) demosaved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. free(demobuffer); - demorecording = false; + demo.recording = false; if (modeattacking != ATTACKING_RECORD) { diff --git a/src/g_game.h b/src/g_game.h index f78a06d06..ffe98d739 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -36,13 +36,31 @@ extern boolean playeringame[MAXPLAYERS]; // ====================================== // demoplaying back and demo recording -extern boolean demoplayback, titledemo, fromtitledemo, demorecording, timingdemo, demosaved, demodefersave, demo_loadfiles, demo_ignorefiles; -extern tic_t demosavebutton; +extern boolean demosaved, demodefersave; extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality; -// Quit after playing a demo from cmdline. -extern boolean singledemo; -extern boolean demo_start; +// Publicly-accessible demo vars +struct demovars_s { + char titlename[65]; + boolean recording, playback, timing; + boolean title; // Title Screen demo can be cancelled by any key + + boolean loadfiles, ignorefiles; // Demo file loading options + boolean fromtitle; // SRB2Kart: Don't stop the music + boolean quitafterplaying; // quit after playing a demo from cmdline + boolean deferstart; // don't start playing demo right away + + tic_t savebutton; // Used to determine when the local player can choose to save the replay while the race is still going + enum { + DSM_NOTSAVING, + DSM_WILLAUTOSAVE, + DSM_TITLEENTRY, + DSM_WILLSAVE, + DSM_SAVED + } savemode; +}; + +extern struct demovars_s demo; extern mobj_t *metalplayback; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a8cf35eb8..9affc72f6 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2206,7 +2206,7 @@ static void HU_DrawDemoInfo(void) } else { - V_DrawRightAlignedThinString(BASEVIDWIDTH-2, BASEVIDHEIGHT-10, V_ALLOWLOWERCASE, demotitle); + V_DrawRightAlignedThinString(BASEVIDWIDTH-2, BASEVIDHEIGHT-10, V_ALLOWLOWERCASE, demo.titlename); } if (modeattacking) @@ -2326,7 +2326,7 @@ void HU_Drawer(void) if (cechotimer) HU_DrawCEcho(); - if (!( Playing() || demoplayback ) + if (!( Playing() || demo.playback ) || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND @@ -2346,7 +2346,7 @@ void HU_Drawer(void) LUAh_ScoresHUD(); #endif } - if (demoplayback) + if (demo.playback) { HU_DrawDemoInfo(); } @@ -2356,7 +2356,7 @@ void HU_Drawer(void) return; // draw the crosshair, not when viewing demos nor with chasecam - /*if (!automapactive && !demoplayback) + /*if (!automapactive && !demo.playback) { if (cv_crosshair.value && !camera.chase && !players[displayplayer].spectator) HU_DrawCrosshair(); @@ -3009,7 +3009,7 @@ static void HU_DrawRankings(void) // When you play, you quickly see your score because your name is displayed in white. // When playing back a demo, you quickly see who's the view. if (!splitscreen) - whiteplayer = demoplayback ? displayplayer : consoleplayer; + whiteplayer = demo.playback ? displayplayer : consoleplayer; scorelines = 0; memset(completed, 0, sizeof (completed)); diff --git a/src/k_kart.c b/src/k_kart.c index 8a68cafe5..3918e8f94 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7115,7 +7115,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI else if ((drawtime/TICRATE) & 1) V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99")); - if (emblemmap && (modeattacking || (mode == 1)) && !demoplayback) // emblem time! + if (emblemmap && (modeattacking || (mode == 1)) && !demo.playback) // emblem time! { INT32 workx = TX + 96, worky = TY+18; SINT8 curemb = 0; @@ -8731,7 +8731,7 @@ void K_drawKartHUD(void) && comeback && stplyr->playerstate == PST_LIVE))); - if (!titledemo && (!battlefullscreen || splitscreen)) + if (!demo.title && (!battlefullscreen || splitscreen)) { // Draw the CHECK indicator before the other items, so it's overlapped by everything else if (cv_kartcheck.value && !splitscreen && !players[displayplayer].exiting) @@ -8768,7 +8768,7 @@ void K_drawKartHUD(void) K_drawKartItem(); // If not splitscreen, draw... - if (!splitscreen && !titledemo) + if (!splitscreen && !demo.title) { // Draw the timestamp #ifdef HAVE_BLUA @@ -8788,7 +8788,7 @@ void K_drawKartHUD(void) if (!stplyr->spectator) // Bottom of the screen elements, don't need in spectate mode { - if (titledemo) // Draw title logo instead in titledemos + if (demo.title) // Draw title logo instead in demo.titles { INT32 x = BASEVIDWIDTH - 32, y = 128, offs; @@ -8838,7 +8838,7 @@ void K_drawKartHUD(void) #endif K_DrawKartPositionNum(stplyr->kartstuff[k_position]); } - else //if (!(demoplayback && hu_showscores)) + else //if (!(demo.playback && hu_showscores)) { // Draw the input UI #ifdef HAVE_BLUA diff --git a/src/m_cheat.c b/src/m_cheat.c index 2fc2e85c9..e7e877ada 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -273,7 +273,7 @@ boolean cht_Responder(event_t *ev) #define REQUIRE_OBJECTPLACE if (!objectplacing)\ { CONS_Printf(M_GetText("OBJECTPLACE must be enabled.\n")); return; } -#define REQUIRE_INLEVEL if (gamestate != GS_LEVEL || demoplayback)\ +#define REQUIRE_INLEVEL if (gamestate != GS_LEVEL || demo.playback)\ { CONS_Printf(M_GetText("You must be in a level to use this.\n")); return; } #define REQUIRE_SINGLEPLAYER if (netgame || multiplayer)\ diff --git a/src/m_menu.c b/src/m_menu.c index fa88d601b..392310348 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2445,7 +2445,7 @@ boolean M_Responder(event_t *ev) static INT32 lastx = 0, lasty = 0; void (*routine)(INT32 choice); // for some casting problem - if (dedicated || (demoplayback && titledemo) + if (dedicated || (demo.playback && demo.title) || gamestate == GS_INTRO || gamestate == GS_CUTSCENE || gamestate == GS_GAMEEND || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) return false; @@ -2917,7 +2917,7 @@ void M_Drawer(void) void M_StartControlPanel(void) { // time attack HACK - if (modeattacking && demoplayback) + if (modeattacking && demo.playback) { G_CheckDemoStatus(); S_ChangeMusicInternal("racent", true); @@ -6946,7 +6946,7 @@ static void M_HandleStaffReplay(INT32 choice) break; M_ClearMenus(true); modeattacking = ATTACKING_RECORD; - demo_loadfiles = false; demo_ignorefiles = true; // Just assume that record attack replays have the files needed + demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed G_DoPlayDemo(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); break; default: @@ -6967,7 +6967,7 @@ static void M_ReplayTimeAttack(INT32 choice) const char *which; M_ClearMenus(true); modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows - demo_loadfiles = false; demo_ignorefiles = true; // Just assume that record attack replays have the files needed + demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed if (currentMenu == &SP_ReplayDef) { @@ -7164,7 +7164,7 @@ static void M_ExitGameResponse(INT32 ch) static void M_EndGame(INT32 choice) { (void)choice; - if (demoplayback) + if (demo.playback) return; if (!Playing()) @@ -7589,7 +7589,7 @@ static void M_StartServer(INT32 choice) else joinpasswordset = false; - if (demoplayback) + if (demo.playback) G_StopDemo(); if (metalrecording) G_StopMetalDemo(); diff --git a/src/p_inter.c b/src/p_inter.c index 90e7a06f5..f70bcf3ee 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -851,7 +851,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Secret emblem thingy case MT_EMBLEM: { - if (demoplayback || player->bot) + if (demo.playback || player->bot) return; emblemlocations[special->health-1].collected = true; diff --git a/src/p_map.c b/src/p_map.c index 256c9cef1..9b0db658b 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -212,7 +212,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) { object->angle = spring->angle; - if (!demoplayback || P_AnalogMove(object->player)) + if (!demo.playback || P_AnalogMove(object->player)) { if (object->player == &players[consoleplayer]) localangle = spring->angle; @@ -1264,7 +1264,7 @@ static boolean PIT_CheckThing(mobj_t *thing) thing->angle = tmthing->angle; - if (!demoplayback || P_AnalogMove(thing->player)) + if (!demo.playback || P_AnalogMove(thing->player)) { if (thing->player == &players[consoleplayer]) localangle = thing->angle; diff --git a/src/p_mobj.c b/src/p_mobj.c index 484d34fbd..f31075f36 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10789,7 +10789,7 @@ void P_SpawnPlayer(INT32 playernum) } // spawn as spectator determination - if (multiplayer && demoplayback); // Don't mess with spectator values since the demo setup handles them already. + if (multiplayer && demo.playback); // Don't mess with spectator values since the demo setup handles them already. else if (!G_GametypeHasSpectators()) p->spectator = false; else if (netgame && p->jointime <= 1 && pcount) diff --git a/src/p_setup.c b/src/p_setup.c index 07a72e7f7..f73aef99c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2729,7 +2729,7 @@ static boolean P_CanSave(void) if ((cursaveslot < 0) // Playing without saving || (modifiedgame && !savemoddata) // Game is modified || (netgame || multiplayer) // Not in single-player - || (demoplayback || demorecording || metalrecording) // Currently in demo + || (demo.playback || demo.recording || metalrecording) // Currently in demo || (players[consoleplayer].lives <= 0) // Completely dead || (modeattacking || ultimatemode || G_IsSpecialStage(gamemap))) // Specialized instances return false; @@ -3113,9 +3113,9 @@ boolean P_SetupLevel(boolean skipprecip) } } - if (modeattacking == ATTACKING_RECORD && !demoplayback) + if (modeattacking == ATTACKING_RECORD && !demo.playback) P_LoadRecordGhosts(); - /*else if (modeattacking == ATTACKING_NIGHTS && !demoplayback) + /*else if (modeattacking == ATTACKING_NIGHTS && !demo.playback) P_LoadNightsGhosts();*/ if (G_TagGametype()) @@ -3163,9 +3163,9 @@ boolean P_SetupLevel(boolean skipprecip) ? cv_basenumlaps.value : mapheaderinfo[gamemap - 1]->numlaps); - //@TODO NET REPLAYS NEED BETTER FILE NAMING STUFF. ALSO OPTIONS. FUCK. + // Start recording replay in multiplayer with a temp filename //@TODO I'd like to fix dedis crashing when recording replays for the future too... - if (!demoplayback && multiplayer && !dedicated) { + if (!demo.playback && multiplayer && !dedicated) { static char buf[256]; sprintf(buf, "replay"PATHSEP"online"PATHSEP"%d-%s", (int) (time(NULL)), G_BuildMapName(gamemap)); diff --git a/src/p_spec.c b/src/p_spec.c index 67bb74720..6b5f09f6d 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3834,7 +3834,7 @@ DoneSection2: if (player->mo->scale > mapobjectscale) linespeed = FixedMul(linespeed, mapobjectscale + (player->mo->scale - mapobjectscale)); - if (!demoplayback || P_AnalogMove(player)) + if (!demo.playback || P_AnalogMove(player)) { if (player == &players[consoleplayer]) localangle = player->mo->angle; @@ -7841,7 +7841,7 @@ void T_Pusher(pusher_t *p) thing->player->pflags |= PF_SLIDING; thing->angle = R_PointToAngle2 (0, 0, xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR)); - if (!demoplayback || P_AnalogMove(thing->player)) + if (!demo.playback || P_AnalogMove(thing->player)) { if (thing->player == &players[consoleplayer]) { diff --git a/src/p_tick.c b/src/p_tick.c index 6fd2e09f0..a9f786623 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -599,7 +599,7 @@ void P_Ticker(boolean run) if (run) { - if (demorecording) + if (demo.recording) { if (!multiplayer) { G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); @@ -610,7 +610,7 @@ void P_Ticker(boolean run) G_WriteDemoTiccmd(&players[i].cmd, i); } } - if (demoplayback) + if (demo.playback) { if (!multiplayer) { @@ -629,7 +629,7 @@ void P_Ticker(boolean run) } // Keep track of how long they've been playing! - if (!demoplayback) // Don't increment if a demo is playing. + if (!demo.playback) // Don't increment if a demo is playing. totalplaytime++; /*if (!useNightsSS && G_IsSpecialStage(gamemap)) @@ -728,23 +728,23 @@ void P_Ticker(boolean run) if (multiplayer) { - if (demorecording) + if (demo.recording) { G_WriteAllGhostTics(); - if (demosavebutton && demosavebutton + 3*TICRATE < leveltime && InputDown(gc_lookback, 1)) + if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime && InputDown(gc_lookback, 1)) demodefersave = true; } - if (demoplayback) // Use Ghost data for consistency checks. + if (demo.playback) // Use Ghost data for consistency checks. { G_ConsAllGhostTics(); } } else { - if (demorecording) + if (demo.recording) G_WriteGhostTic(players[consoleplayer].mo, consoleplayer); - if (demoplayback) // Use Ghost data for consistency checks. + if (demo.playback) // Use Ghost data for consistency checks. G_ConsGhostTic(0); } if (modeattacking) diff --git a/src/p_user.c b/src/p_user.c index 72949c929..18b14f426 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -169,7 +169,7 @@ fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move) boolean P_AutoPause(void) { // Don't pause even on menu-up or focus-lost in netgames or record attack - if (netgame || modeattacking || titledemo) + if (netgame || modeattacking || demo.title) return false; return (menuactive || ( window_notinfocus && cv_pauseifunfocused.value )); @@ -1147,7 +1147,7 @@ boolean P_EndingMusic(player_t *player) if (!P_IsLocalPlayer(player)) // Only applies to a local player return false; - if (multiplayer && demoplayback) // Don't play this in multiplayer replays + if (multiplayer && demo.playback) // Don't play this in multiplayer replays return false; // Event - Level Finish @@ -1707,7 +1707,7 @@ void P_SpawnThokMobj(player_t *player) } P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do - if (demorecording) + if (demo.recording) G_GhostAddThok((INT32) (player - players)); } @@ -1776,7 +1776,7 @@ void P_DoPlayerExit(player_t *player) || (splitscreen && player == &players[secondarydisplayplayer]) || (splitscreen > 1 && player == &players[thirddisplayplayer]) || (splitscreen > 2 && player == &players[fourthdisplayplayer])) - && (!player->spectator && !demoplayback)) + && (!player->spectator && !demo.playback)) legitimateexit = true; if (G_RaceGametype()) // If in Race Mode, allow @@ -1836,7 +1836,7 @@ void P_DoPlayerExit(player_t *player) player->kartstuff[k_cardanimation] = 0; // srb2kart: reset battle animation if (player == &players[consoleplayer]) - demosavebutton = leveltime; + demo.savebutton = leveltime; /*if (playeringame[player-players] && netgame && !circuitmap) CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);*/ @@ -3878,7 +3878,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) // SRB2kart - unused. // Now spawn the color thok circle. P_SpawnSpinMobj(player, player->revitem); - if (demorecording) + if (demo.recording) G_GhostAddRev((INT32) (player - players)); } } @@ -6767,7 +6767,7 @@ static void P_MovePlayer(player_t *player) if (player->pflags & PF_SPINNING && player->speed > FixedMul(15<mo->scale) && !(player->pflags & PF_JUMPED)) { P_SpawnSpinMobj(player, player->spinitem); - if (demorecording) + if (demo.recording) G_GhostAddSpin((INT32) (player - players)); } */ @@ -7958,7 +7958,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall // if (leveltime > 0 && timeinmap <= 0) // return true; - if (demoplayback) + if (demo.playback) { focusangle = mo->angle; focusaiming = 0; @@ -8670,7 +8670,7 @@ void P_DoTimeOver(player_t *player) || (splitscreen && player == &players[secondarydisplayplayer]) || (splitscreen > 1 && player == &players[thirddisplayplayer]) || (splitscreen > 2 && player == &players[fourthdisplayplayer])) - && !demoplayback) + && !demo.playback) legitimateexit = true; // SRB2kart: losing a race is still seeing it through to the end :p if (player->mo) diff --git a/src/r_data.c b/src/r_data.c index 1a74f7336..7fb11855f 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1600,7 +1600,7 @@ void R_PrecacheLevel(void) thinker_t *th; spriteframe_t *sf; - if (demoplayback) + if (demo.playback) return; // do not flush the memory, Z_Malloc twice with same user will cause error in Z_CheckHeap() diff --git a/src/r_main.c b/src/r_main.c index 36182d0e8..b4dcd9183 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -193,7 +193,7 @@ void SplitScreen_OnChange(void) // recompute screen size R_ExecuteSetViewSize(); - if (!demoplayback && !botingame) + if (!demo.playback && !botingame) { for (i = 1; i < 3; i++) { @@ -879,7 +879,7 @@ void R_SkyboxFrame(player_t *player) { aimingangle = player->aiming; viewangle = player->mo->angle; - if (/*!demoplayback && */player->playerstate != PST_DEAD) + if (/*!demo.playback && */player->playerstate != PST_DEAD) { if (player == &players[consoleplayer]) { @@ -1141,7 +1141,7 @@ void R_SetupFrame(player_t *player, boolean skybox) aimingangle = player->aiming; viewangle = viewmobj->angle; - if (/*!demoplayback && */player->playerstate != PST_DEAD) + if (/*!demo.playback && */player->playerstate != PST_DEAD) { if (player == &players[consoleplayer]) { diff --git a/src/r_things.c b/src/r_things.c index baba42116..efc5dd466 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2660,7 +2660,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->kartspeed = skin->kartspeed; player->kartweight = skin->kartweight; - /*if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback || modeattacking)) + /*if (!(cv_debug || devparm) && !(netgame || multiplayer || demo.playback || modeattacking)) { if (playernum == consoleplayer) CV_StealthSetValue(&cv_playercolor, skin->prefcolor); diff --git a/src/s_sound.c b/src/s_sound.c index 2ddffa3f5..9653d8ff6 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1920,7 +1920,7 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) #endif if (S_MusicDisabled() - || titledemo) // SRB2Kart: Demos don't interrupt title screen music + || demo.title) // SRB2Kart: Demos don't interrupt title screen music return; // No Music (empty string) @@ -1955,7 +1955,7 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) void S_StopMusic(void) { if (!I_SongPlaying() - || titledemo) // SRB2Kart: Demos don't interrupt title screen music + || demo.title) // SRB2Kart: Demos don't interrupt title screen music return; if (I_SongPaused()) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index f92f1f14a..c0fca64da 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -3061,7 +3061,7 @@ void I_Quit(void) //added:16-02-98: when recording a demo, should exit using 'q' key, // but sometimes we forget and use 'F10'.. so save here too. - if (demorecording) + if (demo.recording) G_CheckDemoStatus(); if (metalrecording) G_StopMetalRecording(); @@ -3179,7 +3179,7 @@ void I_Error(const char *error, ...) G_SaveGameData(false); // Tails 12-08-2002 // Shutdown. Here might be other errors. - if (demorecording) + if (demo.recording) G_CheckDemoStatus(); if (metalrecording) G_StopMetalRecording(); diff --git a/src/st_stuff.c b/src/st_stuff.c index d87a805d7..2dd045c17 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1894,7 +1894,7 @@ static void ST_overlayDrawer(void) V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, STRINGY(hudinfo[HUD_GRAVBOOTSICO].y), V_SNAPTORIGHT, gravboots); */ - if (!(multiplayer && demoplayback)) + if (!(multiplayer && demo.playback)) { if(!P_IsLocalPlayer(stplyr)) { @@ -1907,7 +1907,7 @@ static void ST_overlayDrawer(void) V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[stplyr-players]); } } - else if (!titledemo) + else if (!demo.title) { if (!splitscreen) @@ -2015,7 +2015,7 @@ static void ST_overlayDrawer(void) } // Replay manual-save stuff - if (demorecording && multiplayer && demosavebutton && demosavebutton + 3*TICRATE < leveltime) + if (demo.recording && multiplayer && demo.savebutton && demo.savebutton + 3*TICRATE < leveltime) { if (demodefersave || cv_recordmultiplayerdemos.value == 2) V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved."); diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 472503341..a98aa8615 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -644,7 +644,7 @@ void I_Error(const char *error, ...) // save demo, could be useful for debug // NOTE: demos are normally not saved here. - if (demorecording) + if (demo.recording) G_CheckDemoStatus(); if (metalrecording) G_StopMetalRecording(); @@ -730,7 +730,7 @@ void I_Quit(void) DWORD mode; // when recording a demo, should exit using 'q', // but sometimes we forget and use Alt+F4, so save here too. - if (demorecording) + if (demo.recording) G_CheckDemoStatus(); if (metalrecording) G_StopMetalRecording(); diff --git a/src/y_inter.c b/src/y_inter.c index 778ab5ad3..5a8791d4a 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -351,7 +351,7 @@ void Y_IntermissionDrawer(void) V_DrawFadeScreen(0xFF00, 22); if (!splitscreen) - whiteplayer = demoplayback ? displayplayer : consoleplayer; + whiteplayer = demo.playback ? displayplayer : consoleplayer; if (cons_menuhighlight.value) hilicol = cons_menuhighlight.value; @@ -360,7 +360,7 @@ void Y_IntermissionDrawer(void) else hilicol = ((intertype == int_race) ? V_SKYMAP : V_REDMAP); - if (sorttic != -1 && intertic > sorttic && !demoplayback) + if (sorttic != -1 && intertic > sorttic && !demo.playback) { INT32 count = (intertic - sorttic); @@ -553,7 +553,7 @@ dotimer: char *string; INT32 tickdown = (timer+1)/TICRATE; - if (multiplayer && demoplayback) + if (multiplayer && demo.playback) string = va("Replay ends in %d", tickdown); else string = va("%s starts in %d", cv_advancemap.string, tickdown); @@ -562,9 +562,9 @@ dotimer: string); } - if (demorecording && cv_recordmultiplayerdemos.value == 1) + if (demo.recording && cv_recordmultiplayerdemos.value == 1) V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Look Backward: Save replay"); - else if (demosaved && !demoplayback) + else if (demosaved && !demo.playback) V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Replay saved!"); // Make it obvious that scrambling is happening next round. @@ -582,7 +582,7 @@ void Y_Ticker(void) if (intertype == int_none) return; - if (demorecording && cv_recordmultiplayerdemos.value == 1 && (demodefersave || InputDown(gc_lookback, 1))) + if (demo.recording && cv_recordmultiplayerdemos.value == 1 && (demodefersave || InputDown(gc_lookback, 1))) { demodefersave = false; G_SaveDemo(); @@ -631,7 +631,7 @@ void Y_Ticker(void) { if (sorttic == -1) sorttic = intertic + max((cv_inttime.value/2)-2, 2)*TICRATE; // 8 second pause after match results - else if (!(multiplayer && demoplayback)) // Don't advance to rankings in replays + else if (!(multiplayer && demo.playback)) // Don't advance to rankings in replays { if (!data.match.rankingsmode && (intertic >= sorttic + 8)) Y_CalculateMatchData(1, Y_CompareRank); @@ -780,7 +780,7 @@ void Y_StartIntermission(void) { if (cv_inttime.value == 0 && gametype == GT_COOP) timer = 0; - else if (demoplayback) // Override inttime (which is pulled from the replay anyway + else if (demo.playback) // Override inttime (which is pulled from the replay anyway timer = 10*TICRATE; else { @@ -816,7 +816,7 @@ void Y_StartIntermission(void) } case int_race: // (time-only race) { - if (!majormods && !multiplayer && !demoplayback) // remove this once we have a proper time attack screen + if (!majormods && !multiplayer && !demo.playback) // remove this once we have a proper time attack screen { // Update visitation flags mapvisited[gamemap-1] |= MV_BEATEN; From 8d9462d4aa7ae3fbd413eba2ef01f82a197ac89d Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 21:55:08 -0500 Subject: [PATCH 121/186] Refactor replay saving handler for later use --- src/d_netcmd.c | 2 +- src/g_game.c | 14 ++++++++++---- src/g_game.h | 1 - src/p_tick.c | 2 +- src/st_stuff.c | 19 ++++++++++++++++--- src/y_inter.c | 27 ++++++++++++++++++++------- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index d4ffe27a8..50f0a2e8f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2627,7 +2627,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) LUAh_MapChange(mapnumber); #endif*/ - demosaved = demodefersave = false; + demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING; demo.savebutton = 0; G_InitNew(pencoremode, mapname, resetplayer, skipprecutscene); if (demo.playback && !demo.timing) diff --git a/src/g_game.c b/src/g_game.c index ef8a41968..fc6365377 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -288,7 +288,6 @@ UINT32 timesBeatenWithEmeralds; //@TODO put these all in a struct for namespacing purposes? static char demoname[128]; -boolean demosaved, demodefersave; static UINT8 *demobuffer = NULL; static UINT8 *demo_p, *demotime_p; static UINT8 *demoend; @@ -3325,7 +3324,7 @@ void G_ExitLevel(void) // Remove CEcho text on round end. HU_ClearCEcho(); - if (multiplayer && demo.recording && cv_recordmultiplayerdemos.value == 2) + if (multiplayer && demo.recording && (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE)) G_SaveDemo(); } } @@ -3860,6 +3859,9 @@ void G_AfterIntermission(void) D_StartTitle(); return; } + else if (demo.recording && demo.savemode != DSM_NOTSAVING) + G_SaveDemo(); + if (modeattacking) // End the run. { M_EndModeAttackRun(); @@ -4004,6 +4006,9 @@ static void G_DoContinued(void) // when something new is added. void G_EndGame(void) { + if (demo.recording && demo.savemode != DSM_NOTSAVING) + G_SaveDemo(); + // Only do evaluation and credits in coop games. if (gametype == GT_COOP) { @@ -7665,13 +7670,14 @@ void G_SaveDemo(void) md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. #endif - demosaved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. + if (FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer)) // finally output the file. + demo.savemode = DSM_SAVED; free(demobuffer); demo.recording = false; if (modeattacking != ATTACKING_RECORD) { - if (demosaved) + if (demo.savemode == DSM_SAVED) CONS_Printf(M_GetText("Demo %s recorded\n"), demoname); else CONS_Alert(CONS_WARNING, M_GetText("Demo %s not saved\n"), demoname); diff --git a/src/g_game.h b/src/g_game.h index ffe98d739..c9bcaf01b 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -36,7 +36,6 @@ extern boolean playeringame[MAXPLAYERS]; // ====================================== // demoplaying back and demo recording -extern boolean demosaved, demodefersave; extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality; // Publicly-accessible demo vars diff --git a/src/p_tick.c b/src/p_tick.c index a9f786623..03ce05c3e 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -733,7 +733,7 @@ void P_Ticker(boolean run) G_WriteAllGhostTics(); if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime && InputDown(gc_lookback, 1)) - demodefersave = true; + demo.savemode = DSM_WILLSAVE; // DSM_TITLEENTRY } if (demo.playback) // Use Ghost data for consistency checks. { diff --git a/src/st_stuff.c b/src/st_stuff.c index 2dd045c17..dec7ee0cf 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2017,10 +2017,23 @@ static void ST_overlayDrawer(void) // Replay manual-save stuff if (demo.recording && multiplayer && demo.savebutton && demo.savebutton + 3*TICRATE < leveltime) { - if (demodefersave || cv_recordmultiplayerdemos.value == 2) - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved."); - else + switch (demo.savemode) + { + case DSM_NOTSAVING: V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Look Backward: Save replay"); + break; + + case DSM_WILLAUTOSAVE: + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved." /*" (Look Backward: Change title)"*/); + break; + + case DSM_WILLSAVE: + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved."); + break; + + default: // Don't render anything + break; + } } ST_drawDebugInfo(); diff --git a/src/y_inter.c b/src/y_inter.c index 5a8791d4a..1e6d945c4 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -562,10 +562,20 @@ dotimer: string); } - if (demo.recording && cv_recordmultiplayerdemos.value == 1) - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Look Backward: Save replay"); - else if (demosaved && !demo.playback) - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Replay saved!"); + if ((demo.recording || demo.savemode == DSM_SAVED) && !demo.playback) + switch (demo.savemode) + { + case DSM_NOTSAVING: + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Look Backward: Save replay"); + break; + + case DSM_SAVED: + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Replay saved!"); + break; + + default: // Don't render any text here + break; + } // Make it obvious that scrambling is happening next round. if (cv_scrambleonchange.value && cv_teamscramble.value && (intertic/TICRATE % 2 == 0)) @@ -582,10 +592,13 @@ void Y_Ticker(void) if (intertype == int_none) return; - if (demo.recording && cv_recordmultiplayerdemos.value == 1 && (demodefersave || InputDown(gc_lookback, 1))) + if (demo.recording) { - demodefersave = false; - G_SaveDemo(); + if (demo.savemode == DSM_NOTSAVING && InputDown(gc_lookback, 1)) + demo.savemode = DSM_WILLSAVE; // DSM_TITLEENTRY + + if (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE) + G_SaveDemo(); } // Check for pause or menu up in single player From 91868fc3a4187c144b559434a5d5c2367b8ba027 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 24 Mar 2019 22:40:52 -0500 Subject: [PATCH 122/186] Allow entering a title for replays on save --- src/d_main.c | 6 ++++++ src/g_game.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- src/g_game.h | 1 + src/p_tick.c | 2 +- src/st_stuff.c | 36 ++++++++++++++++++++++++++++++++++- src/st_stuff.h | 3 +++ src/y_inter.c | 6 +++++- 7 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 6edb1cf44..16a70519f 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -248,6 +248,12 @@ void D_ProcessEvents(void) continue; } + if (demo.savemode == DSM_TITLEENTRY) + { + if (G_DemoTitleResponder(ev)) + continue; + } + // Menu input if (M_Responder(ev)) continue; // menu ate the event diff --git a/src/g_game.c b/src/g_game.c index fc6365377..ca2f02080 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -7603,7 +7603,7 @@ boolean G_CheckDemoStatus(void) return true; } - if (demo.recording && (!multiplayer || cv_recordmultiplayerdemos.value == 2)) + if (demo.recording && demo.savemode != DSM_NOTSAVING) { G_SaveDemo(); return true; @@ -7684,6 +7684,55 @@ void G_SaveDemo(void) } } +boolean G_DemoTitleResponder(event_t *ev) +{ + size_t len; + INT32 ch; + + if (ev->type != ev_keydown) + return false; + + ch = (INT32)ev->data1; + + // Only ESC and non-keyboard keys abort connection + if (ch == KEY_ESCAPE) + { + demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING; + return true; + } + + if (ch == KEY_ENTER || ch >= KEY_MOUSE1) + { + demo.savemode = DSM_WILLSAVE; + return true; + } + + if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) + || ch == ' ') // Allow spaces, of course + { + len = strlen(demo.titlename); + if (len < 64) + { + demo.titlename[len+1] = 0; + demo.titlename[len] = CON_ShiftChar(ch); + } + } + else if (ch == KEY_BACKSPACE) + { + if (shiftdown) + memset(demo.titlename, 0, sizeof(demo.titlename)); + else + { + len = strlen(demo.titlename); + + if (len > 0) + demo.titlename[len-1] = 0; + } + } + + return true; +} + // // G_SetGamestate // diff --git a/src/g_game.h b/src/g_game.h index c9bcaf01b..d97752b26 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -230,6 +230,7 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(void); void G_StopDemo(void); boolean G_CheckDemoStatus(void); void G_SaveDemo(void); +boolean G_DemoTitleResponder(event_t *ev); boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); diff --git a/src/p_tick.c b/src/p_tick.c index 03ce05c3e..177f3b657 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -733,7 +733,7 @@ void P_Ticker(boolean run) G_WriteAllGhostTics(); if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime && InputDown(gc_lookback, 1)) - demo.savemode = DSM_WILLSAVE; // DSM_TITLEENTRY + demo.savemode = DSM_TITLEENTRY; } if (demo.playback) // Use Ghost data for consistency checks. { diff --git a/src/st_stuff.c b/src/st_stuff.c index dec7ee0cf..acb01fb69 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2024,13 +2024,17 @@ static void ST_overlayDrawer(void) break; case DSM_WILLAUTOSAVE: - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved." /*" (Look Backward: Change title)"*/); + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved. (Look Backward: Change title)"); break; case DSM_WILLSAVE: V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved."); break; + case DSM_TITLEENTRY: + ST_DrawDemoTitleEntry(); + break; + default: // Don't render anything break; } @@ -2039,6 +2043,36 @@ static void ST_overlayDrawer(void) ST_drawDebugInfo(); } +void ST_DrawDemoTitleEntry(void) +{ + static UINT8 skullAnimCounter = 0; + char *nametodraw; + + skullAnimCounter++; + skullAnimCounter %= 8; + + nametodraw = demo.titlename; + while (V_StringWidth(nametodraw, 0) > MAXSTRINGLENGTH*8 - 8) + nametodraw++; + +#define x (BASEVIDWIDTH/2 - 139) +#define y (BASEVIDHEIGHT/2) + M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); + V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, nametodraw); + if (skullAnimCounter < 4) + V_DrawCharacter(x + 8 + V_StringWidth(nametodraw, 0), y + 12, + '_' | 0x80, false); + + M_DrawTextBox(x + 30, y - 24, 26, 1); + V_DrawString(x + 38, y - 16, V_ALLOWLOWERCASE, "Enter the name of the replay."); + + M_DrawTextBox(x + 50, y + 20, 20, 1); + V_DrawThinString(x + 58, y + 28, V_ALLOWLOWERCASE, "Escape - Cancel"); + V_DrawRightAlignedThinString(x + 220, y + 28, V_ALLOWLOWERCASE, "Enter - Confirm"); +#undef x +#undef y +} + // MayonakaStatic: draw Midnight Channel's TV-like borders static void ST_MayonakaStatic(void) { diff --git a/src/st_stuff.h b/src/st_stuff.h index f96aee938..16f7b8811 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -26,6 +26,9 @@ // Called by main loop. void ST_Ticker(void); +// Called when naming a replay. +void ST_DrawDemoTitleEntry(void); + // Called by main loop. void ST_Drawer(void); diff --git a/src/y_inter.c b/src/y_inter.c index 1e6d945c4..256a8566a 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -573,6 +573,10 @@ dotimer: V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Replay saved!"); break; + case DSM_TITLEENTRY: + ST_DrawDemoTitleEntry(); + break; + default: // Don't render any text here break; } @@ -595,7 +599,7 @@ void Y_Ticker(void) if (demo.recording) { if (demo.savemode == DSM_NOTSAVING && InputDown(gc_lookback, 1)) - demo.savemode = DSM_WILLSAVE; // DSM_TITLEENTRY + demo.savemode = DSM_TITLEENTRY; if (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE) G_SaveDemo(); From 93e07ae745689857c9ca1b5a2868144e8a03d06e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 30 Mar 2019 17:25:54 -0500 Subject: [PATCH 123/186] Move menu options around 1 Player now goes directly to Time Attack, and Extras is now a submenu with Unlockables, Statistics, and a currently-dummied option for Replay Hut. --- src/m_menu.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 392310348..18bf0d41c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -233,7 +233,9 @@ static char *M_GetConditionString(condition_t cond); menu_t SR_MainDef, SR_UnlockChecklistDef; // Misc. Main Menu +#if 0 // Bring this back when we have actual single-player static void M_SinglePlayerMenu(INT32 choice); +#endif static void M_Options(INT32 choice); static void M_Manual(INT32 choice); static void M_SelectableClearMenus(INT32 choice); @@ -500,12 +502,13 @@ static consvar_t cv_dummystaff = {"dummystaff", "0", CV_HIDEN|CV_CALL, dummystaf // --------- static menuitem_t MainMenu[] = { - {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_UnlockChecklistDef, 76}, - {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, - {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, - {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, - {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, - {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, + {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_MainDef, 76}, + //{IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, + {IT_CALL |IT_STRING, NULL, "Time Attack", M_TimeAttack, 84}, + {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, + {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, + {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, + {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, }; typedef enum @@ -695,7 +698,9 @@ static menuitem_t SR_PandorasBox[] = // Sky Room Custom Unlocks static menuitem_t SR_MainMenu[] = { - {IT_STRING|IT_SUBMENU,NULL, "Secrets Checklist", &SR_UnlockChecklistDef, 0}, + {IT_STRING|IT_SUBMENU, NULL, "Unlockables", &SR_UnlockChecklistDef, 0}, + {IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 10}, + {IT_CALL|IT_STRING, NULL, "Replay Hut", M_Statistics, 20}, {IT_DISABLED, NULL, "", NULL, 0}, // Custom1 {IT_DISABLED, NULL, "", NULL, 0}, // Custom2 {IT_DISABLED, NULL, "", NULL, 0}, // Custom3 @@ -1681,7 +1686,8 @@ menu_t SR_MainDef = sizeof (SR_MainMenu)/sizeof (menuitem_t), &MainDef, SR_MainMenu, - M_DrawSkyRoom, + M_DrawGenericMenu, + //M_DrawSkyRoom, 60, 40, 0, NULL @@ -1693,7 +1699,7 @@ menu_t SR_UnlockChecklistDef = { NULL, 1, - &MainDef, //&SR_MainDef + &SR_MainDef, SR_UnlockChecklistMenu, M_DrawChecklist, 280, 185, @@ -1731,7 +1737,7 @@ menu_t SP_LevelStatsDef = { "M_STATS", 1, - &SP_MainDef, + &SR_MainDef, SP_LevelStatsMenu, M_DrawLevelStats, 280, 185, @@ -5619,6 +5625,7 @@ static void M_Credits(INT32 choice) // SINGLE PLAYER MENU // ================== +#if 0 // Bring this back when we have actual single-player static void M_SinglePlayerMenu(INT32 choice) { (void)choice; @@ -5629,6 +5636,7 @@ static void M_SinglePlayerMenu(INT32 choice) M_SetupNextMenu(&SP_MainDef); } +#endif /*static void M_LoadGameLevelSelect(INT32 choice) { From a54a7de02d3c8b49c2dab59d0b57761495b79d6d Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 30 Mar 2019 20:57:53 -0500 Subject: [PATCH 124/186] Start on the replay hut menu! --- src/filesrch.c | 75 +++++++++++++++++++------------- src/filesrch.h | 2 +- src/m_menu.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 154 insertions(+), 38 deletions(-) diff --git a/src/filesrch.c b/src/filesrch.c index 0276e1c90..69a6c5c73 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -368,9 +368,10 @@ void searchfilemenu(char *tempname) return; } -boolean preparefilemenu(boolean samedepth) +boolean preparefilemenu(boolean samedepth, boolean replayhut) { (void)samedepth; + (void)replayhut; return false; } @@ -437,9 +438,10 @@ void searchfilemenu(char *tempname) return; } -boolean preparefilemenu(boolean samedepth) +boolean preparefilemenu(boolean samedepth, boolean replayhut) { (void)samedepth; + (void)replayhut; return false; } @@ -710,7 +712,7 @@ void searchfilemenu(char *tempname) } } -boolean preparefilemenu(boolean samedepth) +boolean preparefilemenu(boolean samedepth, boolean replayhut) { DIR *dirhandle; struct dirent *dent; @@ -759,9 +761,13 @@ boolean preparefilemenu(boolean samedepth) { if (!S_ISDIR(fsstat.st_mode)) // file { - if (!cv_addons_showall.value) + size_t len = strlen(dent->d_name)+1; + if (replayhut) + { + if (strcasecmp(".lmp", dent->d_name+len-5)) continue; // Not a replay + } + else if (!cv_addons_showall.value) { - size_t len = strlen(dent->d_name)+1; UINT8 ext; for (ext = 0; ext < NUM_EXT_TABLE; ext++) if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison @@ -829,40 +835,49 @@ boolean preparefilemenu(boolean samedepth) if (!S_ISDIR(fsstat.st_mode)) // file { if (!((numfolders+pos) < sizecoredirmenu)) continue; // crash prevention - for (; ext < NUM_EXT_TABLE; ext++) - if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison - if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file - ext += EXT_START; // moving to be appropriate position - if (ext >= EXT_LOADSTART) + if (replayhut) { - size_t i; - for (i = 0; i < numwadfiles; i++) + if (strcasecmp(".lmp", dent->d_name+len-5)) continue; // Not a replay + ext = EXT_TXT; // This isn't used anywhere but better safe than sorry for messing with this... + } + else + { + for (; ext < NUM_EXT_TABLE; ext++) + if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison + if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file + ext += EXT_START; // moving to be appropriate position + + if (ext >= EXT_LOADSTART) { - if (!filenamebuf[i][0]) + size_t i; + for (i = 0; i < numwadfiles; i++) { - strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH); - filenamebuf[i][MAX_WADPATH - 1] = '\0'; - nameonly(filenamebuf[i]); + if (!filenamebuf[i][0]) + { + strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH); + filenamebuf[i][MAX_WADPATH - 1] = '\0'; + nameonly(filenamebuf[i]); + } + + if (strcmp(dent->d_name, filenamebuf[i])) + continue; + if (cv_addons_md5.value && !checkfilemd5(menupath, wadfiles[i]->md5sum)) + continue; + + ext |= EXT_LOADED; } - - if (strcmp(dent->d_name, filenamebuf[i])) - continue; - if (cv_addons_md5.value && !checkfilemd5(menupath, wadfiles[i]->md5sum)) - continue; - - ext |= EXT_LOADED; } - } - else if (ext == EXT_TXT) - { - if (!strcmp(dent->d_name, "log.txt") || !strcmp(dent->d_name, "errorlog.txt")) + else if (ext == EXT_TXT) + { + if (!strcmp(dent->d_name, "log.txt") || !strcmp(dent->d_name, "errorlog.txt")) + ext |= EXT_LOADED; + } + + if (!strcmp(dent->d_name, configfile)) ext |= EXT_LOADED; } - if (!strcmp(dent->d_name, configfile)) - ext |= EXT_LOADED; - folder = 0; } else // directory diff --git a/src/filesrch.h b/src/filesrch.h index 01a528482..dbcc5fc37 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -94,6 +94,6 @@ typedef enum void closefilemenu(boolean validsize); void searchfilemenu(char *tempname); -boolean preparefilemenu(boolean samedepth); +boolean preparefilemenu(boolean samedepth, boolean replayhut); #endif // __FILESRCH_H__ diff --git a/src/m_menu.c b/src/m_menu.c index 18bf0d41c..a6957f3a6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -336,6 +336,10 @@ static patch_t *addonsp[NUM_EXT+5]; #define numaddonsshown 4 +// Replay hut +static void M_ReplayHut(INT32 choice); +static void M_DrawReplayHut(void); + // Drawing functions static void M_DrawGenericMenu(void); static void M_DrawCenteredMenu(void); @@ -526,6 +530,13 @@ static menuitem_t MISC_AddonsMenu[] = {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleAddons, 0}, // dummy menuitem for the control func }; +static menuitem_t MISC_ReplayHutMenu[] = +{ + {IT_SUBMENU |IT_STRING, NULL, "Replay Options...", NULL, 0}, + + {IT_KEYHANDLER|IT_NOTHING, NULL, "", NULL, 20}, // Dummy menuitem for the replay list +}; + // --------------------------------- // Pause Menu Mode Attacking Edition // --------------------------------- @@ -700,7 +711,7 @@ static menuitem_t SR_MainMenu[] = { {IT_STRING|IT_SUBMENU, NULL, "Unlockables", &SR_UnlockChecklistDef, 0}, {IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 10}, - {IT_CALL|IT_STRING, NULL, "Replay Hut", M_Statistics, 20}, + {IT_CALL|IT_STRING, NULL, "Replay Hut", M_ReplayHut, 20}, {IT_DISABLED, NULL, "", NULL, 0}, // Custom1 {IT_DISABLED, NULL, "", NULL, 0}, // Custom2 {IT_DISABLED, NULL, "", NULL, 0}, // Custom3 @@ -1583,6 +1594,18 @@ menu_t MISC_AddonsDef = NULL }; +menu_t MISC_ReplayHutDef = +{ + "M_REPLAY", + sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t), + &MainDef, + MISC_ReplayHutMenu, + M_DrawReplayHut, + 30, 80, + 0, + NULL +}; + menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); @@ -4471,7 +4494,7 @@ static void M_Addons(INT32 choice) else --menupathindex[menudepthleft]; - if (!preparefilemenu(false)) + if (!preparefilemenu(false, false)) { M_StartMessage(va("No files/folders found.\n\n%s\n\n(Press a key)\n", (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)),NULL,MM_NOTHING); return; @@ -4595,7 +4618,7 @@ static void M_AddonsClearName(INT32 choice) // returns whether to do message draw static boolean M_AddonsRefresh(void) { - if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true)) + if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true, false)) { UNEXIST; if (refreshdirname) @@ -4844,7 +4867,7 @@ static void M_HandleAddons(INT32 choice) if (dirmenu && dirmenu[dir_on[menudepthleft]]) tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL #if 0 // much slower - if (!preparefilemenu(true)) + if (!preparefilemenu(true, false)) { UNEXIST; return; @@ -4898,13 +4921,13 @@ static void M_HandleAddons(INT32 choice) menupathindex[--menudepthleft] = strlen(menupath); menupath[menupathindex[menudepthleft]] = 0; - if (!preparefilemenu(false)) + if (!preparefilemenu(false, false)) { S_StartSound(NULL, sfx_s224); M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); menupath[menupathindex[++menudepthleft]] = 0; - if (!preparefilemenu(true)) + if (!preparefilemenu(true, false)) { UNEXIST; return; @@ -4927,7 +4950,7 @@ static void M_HandleAddons(INT32 choice) case EXT_UP: S_StartSound(NULL, sfx_menu1); menupath[menupathindex[++menudepthleft]] = 0; - if (!preparefilemenu(false)) + if (!preparefilemenu(false, false)) { UNEXIST; return; @@ -4984,6 +5007,84 @@ static void M_HandleAddons(INT32 choice) } } +// ---- REPLAY HUT ----- + +static INT16 replayOn = 0; + +static void M_ReplayHut(INT32 choice) +{ + (void)choice; + + snprintf(menupath, 1024, "%s"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home); + menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath); + + if (!preparefilemenu(false, true)) + { + M_StartMessage("No replays found.\n\n(Press a key)\n", NULL, MM_NOTHING); + return; + } + else + dir_on[menudepthleft] = 0; + + M_SetupNextMenu(&MISC_ReplayHutDef); + G_SetGamestate(GS_TIMEATTACK); + + S_ChangeMusicInternal("replst", true); +} + +static void M_DrawReplayHut(void) +{ + INT32 x, y, cursory = 0; + INT16 i; + + (void)cursory; + + V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + M_DrawMenuTitle(); + + // Draw menu choices + x = currentMenu->x; + y = currentMenu->y; + + if (itemOn == currentMenu->numitems-1) + { + INT32 maxy; + // Scroll menu items if needed + cursory = y + currentMenu->menuitems[currentMenu->numitems-1].alphaKey + replayOn*10; + maxy = y + currentMenu->menuitems[currentMenu->numitems-1].alphaKey + sizedirmenu*10; + + if (cursory > maxy - 70) + cursory = maxy - 70; + + if (cursory > 130) + y -= (cursory-130); + } + + // Draw static menu items + for (i = 0; i < currentMenu->numitems-1; i++) + { + if (i == itemOn) + cursory = y; + + if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) + V_DrawString(x, y + currentMenu->menuitems[i].alphaKey, 0, currentMenu->menuitems[i].text); + else + V_DrawString(x, y + currentMenu->menuitems[i].alphaKey, highlightflags, currentMenu->menuitems[i].text); + } + + y += currentMenu->menuitems[currentMenu->numitems-1].alphaKey; + + for (i = 0; i < (INT16)sizedirmenu; i++) + { + V_DrawString(x, y+i*10, V_ALLOWLOWERCASE, dirmenu[i]+DIR_STRING); + } + + // Draw the cursor + V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, + W_CachePatchName("M_CURSOR", PU_CACHE)); + V_DrawString(currentMenu->x, cursory, highlightflags, currentMenu->menuitems[itemOn].text); +} + static void M_PandorasBox(INT32 choice) { (void)choice; From 29a80e01eb645c93cb953b46e9df5c96943270bf Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 01:22:41 -0500 Subject: [PATCH 125/186] List demos by title in the replay hut --- src/filesrch.c | 2 + src/g_game.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ src/g_game.h | 20 ++++++++ src/m_menu.c | 113 +++++++++++++++++++++++++++++++++++++++------ 4 files changed, 243 insertions(+), 14 deletions(-) diff --git a/src/filesrch.c b/src/filesrch.c index 69a6c5c73..6827dc57e 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -896,6 +896,8 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut) strcpy(temp+len, PATHSEP); coredirmenu[folderpos++] = temp; } + else if (replayhut) // Reverse-alphabetical on just the files; acts as a fake "most recent first" with the current filename format + coredirmenu[sizecoredirmenu - 1 - pos++] = temp; else coredirmenu[numfolders + pos++] = temp; } diff --git a/src/g_game.c b/src/g_game.c index ca2f02080..09a3db52d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6564,6 +6564,128 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) return c; } +void G_LoadDemoInfo(menudemo_t *pdemo) +{ + UINT8 *infobuffer, *info_p; + UINT8 version, subversion, pdemoflags; + UINT16 pdemoversion, cvarcount; + + if (!FIL_ReadFile(pdemo->filepath, &infobuffer)) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), pdemo->filepath); + pdemo->type = MD_INVALID; + sprintf(pdemo->title, "INVALID REPLAY"); + + return; + } + + info_p = infobuffer; + + if (memcmp(info_p, DEMOHEADER, 12)) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemo->filepath); + pdemo->type = MD_INVALID; + sprintf(pdemo->title, "INVALID REPLAY"); + Z_Free(infobuffer); + return; + } + + pdemo->type = MD_LOADED; + + info_p += 12; // DEMOHEADER + + version = READUINT8(info_p); + subversion = READUINT8(info_p); + pdemoversion = READUINT16(info_p); + + switch(pdemoversion) + { + case DEMOVERSION: // latest always supported + // demo title + M_Memcpy(pdemo->title, info_p, 64); + info_p += 64; + + break; +#ifdef DEMO_COMPAT_100 + case 0x0001: + pdemo->type = MD_OUTDATED; + sprintf(pdemo->title, "Legacy Replay"); + break; +#endif + // too old, cannot support. + default: + CONS_Alert(CONS_ERROR, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemo->filepath); + pdemo->type = MD_INVALID; + sprintf(pdemo->title, "INVALID REPLAY"); + Z_Free(infobuffer); + return; + } + + if (version != VERSION || subversion != SUBVERSION) + pdemo->type = MD_OUTDATED; + + info_p += 16; // demo checksum + if (memcmp(info_p, "PLAY", 4)) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is the wrong type of recording and cannot be played.\n"), pdemo->filepath); + pdemo->type = MD_INVALID; + sprintf(pdemo->title, "INVALID REPLAY"); + Z_Free(infobuffer); + return; + } + demo_p += 4; // "PLAY" + pdemo->map = READINT16(info_p); + demo_p += 16; // mapmd5 + + pdemoflags = READUINT8(info_p); + + // temp? + if (!(pdemoflags & DF_MULTIPLAYER)) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is not a multiplayer replay and can't be listed on this menu fully yet.\n"), pdemo->filepath); + Z_Free(infobuffer); + return; + } + + pdemo->gametype = READUINT8(info_p); + + G_SkipDemoExtraFiles(&info_p); //@TODO see if this information is useful for display? + demo_p += 4; // RNG seed + + // Pared down version of CV_LoadNetVars to find the kart speed + cvarcount = READUINT16(info_p); + while (cvarcount--) + { + UINT16 netid; + char *svalue; + + netid = READUINT16(info_p); + svalue = (char *)info_p; + SKIPSTRING(info_p); + info_p++; // stealth + + if (netid == cv_kartspeed.netid) + { + for (cvarcount = 0; kartspeed_cons_t[cvarcount].value; cvarcount++) + { + if (!strcasecmp(kartspeed_cons_t[cvarcount].strvalue, svalue)) + { + pdemo->kartspeed = kartspeed_cons_t[cvarcount].value; + break; + } + } + + break; + } + } + + if (pdemoflags & DF_ENCORE) + pdemo->kartspeed |= DF_ENCORE; + + // I think that's everything we need? + free(infobuffer); +} + // // G_PlayDemo // diff --git a/src/g_game.h b/src/g_game.h index d97752b26..5b07d053c 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -61,6 +61,25 @@ struct demovars_s { extern struct demovars_s demo; +typedef enum { + MD_NOTLOADED, + MD_LOADED, + MD_SUBDIR, + MD_OUTDATED, + MD_INVALID +} menudemotype_e; + +typedef struct menudemo_s { + char filepath[256]; + menudemotype_e type; + + char title[65]; // Null-terminated for string prints + UINT16 map; + UINT8 gametype; + UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk +} menudemo_t; + + extern mobj_t *metalplayback; // gametic at level start @@ -147,6 +166,7 @@ void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar UINT8 ssplayers, boolean FLS); void G_DoLoadLevel(boolean resetplayer); +void G_LoadDemoInfo(menudemo_t *pdemo); void G_DeferedPlayDemo(const char *demo); // Can be called by the startup code or M_Responder, calls P_SetupLevel. diff --git a/src/m_menu.c b/src/m_menu.c index a6957f3a6..a5f51f2a9 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -338,6 +338,7 @@ static patch_t *addonsp[NUM_EXT+5]; // Replay hut static void M_ReplayHut(INT32 choice); +static void M_HandleReplayHutList(INT32 choice); static void M_DrawReplayHut(void); // Drawing functions @@ -532,9 +533,10 @@ static menuitem_t MISC_AddonsMenu[] = static menuitem_t MISC_ReplayHutMenu[] = { - {IT_SUBMENU |IT_STRING, NULL, "Replay Options...", NULL, 0}, + {IT_SUBMENU |IT_STRING, NULL, "Replay Options...", NULL, 0}, - {IT_KEYHANDLER|IT_NOTHING, NULL, "", NULL, 20}, // Dummy menuitem for the replay list + {IT_KEYHANDLER|IT_NOTHING, NULL, "", M_HandleReplayHutList, 20}, // Dummy menuitem for the replay list + {IT_NOTHING, NULL, "", NULL, 20}, // Dummy for handling wrapping to the top of the menu.. }; // --------------------------------- @@ -1602,7 +1604,7 @@ menu_t MISC_ReplayHutDef = MISC_ReplayHutMenu, M_DrawReplayHut, 30, 80, - 0, + (sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t)) - 2, // Start on the replay list NULL }; @@ -5008,9 +5010,35 @@ static void M_HandleAddons(INT32 choice) } // ---- REPLAY HUT ----- +menudemo_t *demolist; static INT16 replayOn = 0; +static void PrepReplayList(void) +{ + size_t i; + + if (demolist) + Z_Free(demolist); + + demolist = Z_Calloc(sizeof(menudemo_t) * sizedirmenu, PU_STATIC, NULL); + + for (i = 0; i < sizedirmenu; i++) + { + if (dirmenu[i][DIR_TYPE] == EXT_FOLDER) + { + demolist[i].type = MD_SUBDIR; + strncpy(demolist[i].title, dirmenu[i] + DIR_STRING, 64); + } + else + { + demolist[i].type = MD_NOTLOADED; + snprintf(demolist[i].filepath, 255, "%s%s", menupath, dirmenu[i] + DIR_STRING); + sprintf(demolist[i].title, "....."); + } + } +} + static void M_ReplayHut(INT32 choice) { (void)choice; @@ -5026,18 +5054,46 @@ static void M_ReplayHut(INT32 choice) else dir_on[menudepthleft] = 0; + PrepReplayList(); + M_SetupNextMenu(&MISC_ReplayHutDef); G_SetGamestate(GS_TIMEATTACK); S_ChangeMusicInternal("replst", true); } +static void M_HandleReplayHutList(INT32 choice) +{ + switch (choice) + { + case KEY_UPARROW: + if (replayOn) + replayOn--; + else + M_PrevOpt(); + + S_StartSound(NULL, sfx_menu1); + break; + + case KEY_DOWNARROW: + if (replayOn < (INT16)sizedirmenu-1) + replayOn++; + else + itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item + + S_StartSound(NULL, sfx_menu1); + break; + } +} + static void M_DrawReplayHut(void) { INT32 x, y, cursory = 0; INT16 i; + INT16 replaylistitem = currentMenu->numitems-2; + boolean processed_one_this_frame = false; - (void)cursory; + static UINT16 replayhutmenuy = 0; V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); M_DrawMenuTitle(); @@ -5046,25 +5102,41 @@ static void M_DrawReplayHut(void) x = currentMenu->x; y = currentMenu->y; - if (itemOn == currentMenu->numitems-1) + if (itemOn > replaylistitem) + { + itemOn = replaylistitem; + replayOn = sizedirmenu-1; + } + else if (itemOn < replaylistitem) + { + replayOn = 0; + } + + if (itemOn == replaylistitem) { INT32 maxy; // Scroll menu items if needed - cursory = y + currentMenu->menuitems[currentMenu->numitems-1].alphaKey + replayOn*10; - maxy = y + currentMenu->menuitems[currentMenu->numitems-1].alphaKey + sizedirmenu*10; + cursory = y + currentMenu->menuitems[replaylistitem].alphaKey + replayOn*10; + maxy = y + currentMenu->menuitems[replaylistitem].alphaKey + sizedirmenu*10; - if (cursory > maxy - 70) - cursory = maxy - 70; + if (cursory > maxy - 20) + cursory = maxy - 20; - if (cursory > 130) - y -= (cursory-130); + if (cursory - replayhutmenuy > 150) + replayhutmenuy += (cursory-150-replayhutmenuy)/2; + else if (cursory - replayhutmenuy < 110) + replayhutmenuy += (max(0, cursory-110)-replayhutmenuy)/2; } + else + replayhutmenuy /= 2; + + y -= replayhutmenuy; // Draw static menu items - for (i = 0; i < currentMenu->numitems-1; i++) + for (i = 0; i < replaylistitem; i++) { if (i == itemOn) - cursory = y; + cursory = y + currentMenu->menuitems[i].alphaKey; if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) V_DrawString(x, y + currentMenu->menuitems[i].alphaKey, 0, currentMenu->menuitems[i].text); @@ -5076,7 +5148,20 @@ static void M_DrawReplayHut(void) for (i = 0; i < (INT16)sizedirmenu; i++) { - V_DrawString(x, y+i*10, V_ALLOWLOWERCASE, dirmenu[i]+DIR_STRING); + INT32 localy = y+i*10; + if (localy >= 0 && localy < 200 && demolist[i].type == MD_NOTLOADED && !processed_one_this_frame) + { + processed_one_this_frame = true; + G_LoadDemoInfo(&demolist[i]); + } + + if (itemOn == replaylistitem && i == replayOn) + { + cursory = localy; + V_DrawString(x, localy, highlightflags|V_ALLOWLOWERCASE, demolist[i].title); + } + else + V_DrawString(x, localy, V_ALLOWLOWERCASE, demolist[i].title); } // Draw the cursor From f00f9c9a0a4c92fd3d438a5f0bcc04ee86fb5266 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 02:54:09 -0500 Subject: [PATCH 126/186] Display infobox for the currently-selected replay --- src/g_game.c | 30 ++++++------ src/g_game.h | 12 +++++ src/m_menu.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 155 insertions(+), 19 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 09a3db52d..94f8bd8d1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6346,12 +6346,8 @@ static void G_SkipDemoExtraFiles(UINT8 **pp) } // G_CheckDemoExtraFiles: checks if our loaded WAD list matches the demo's. -#define DFILE_ERROR_NOTLOADED 0x01 // Files are not loaded, but can be without a restart. -#define DFILE_ERROR_OUTOFORDER 0x02 // Files are loaded, but out of order. -#define DFILE_ERROR_INCOMPLETEOUTOFORDER 0x03 // Some files are loaded out of order, but others are not. -#define DFILE_ERROR_CANNOTLOAD 0x04 // Files are missing and cannot be loaded. -#define DFILE_ERROR_EXTRAFILES 0x05 // Extra files outside of the replay's file list are loaded. -static UINT8 G_CheckDemoExtraFiles(UINT8 **pp) +// Enabling quick prevents filesystem checks to see if needed files are available to load. +static UINT8 G_CheckDemoExtraFiles(UINT8 **pp, boolean quick) { UINT8 totalfiles, filesloaded, nmusfilecount; char filename[MAX_WADPATH]; @@ -6405,7 +6401,7 @@ static UINT8 G_CheckDemoExtraFiles(UINT8 **pp) if (numwadfiles >= MAX_WADFILES) error = DFILE_ERROR_CANNOTLOAD; - else if (findfile(filename, md5sum, false) != FS_FOUND) + else if (!quick && findfile(filename, md5sum, false) != FS_FOUND) error = DFILE_ERROR_CANNOTLOAD; else if (error < DFILE_ERROR_INCOMPLETEOUTOFORDER) error |= DFILE_ERROR_NOTLOADED; @@ -6633,9 +6629,9 @@ void G_LoadDemoInfo(menudemo_t *pdemo) Z_Free(infobuffer); return; } - demo_p += 4; // "PLAY" + info_p += 4; // "PLAY" pdemo->map = READINT16(info_p); - demo_p += 16; // mapmd5 + info_p += 16; // mapmd5 pdemoflags = READUINT8(info_p); @@ -6649,8 +6645,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo) pdemo->gametype = READUINT8(info_p); - G_SkipDemoExtraFiles(&info_p); //@TODO see if this information is useful for display? - demo_p += 4; // RNG seed + pdemo->addonstatus = G_CheckDemoExtraFiles(&info_p, true); + info_p += 4; // RNG seed // Pared down version of CV_LoadNetVars to find the kart speed cvarcount = READUINT16(info_p); @@ -6666,9 +6662,9 @@ void G_LoadDemoInfo(menudemo_t *pdemo) if (netid == cv_kartspeed.netid) { - for (cvarcount = 0; kartspeed_cons_t[cvarcount].value; cvarcount++) + for (cvarcount = 0; kartspeed_cons_t[cvarcount].strvalue; cvarcount++) { - if (!strcasecmp(kartspeed_cons_t[cvarcount].strvalue, svalue)) + if (!stricmp(kartspeed_cons_t[cvarcount].strvalue, svalue)) { pdemo->kartspeed = kartspeed_cons_t[cvarcount].value; break; @@ -6682,6 +6678,12 @@ void G_LoadDemoInfo(menudemo_t *pdemo) if (pdemoflags & DF_ENCORE) pdemo->kartspeed |= DF_ENCORE; + // Temporary info until this is actually present in replays. + sprintf(pdemo->winnername, "transrights420"); + pdemo->winnerskin = 1; + pdemo->winnercolor = SKINCOLOR_MOONSLAM; + pdemo->winnertime = 6666; + // I think that's everything we need? free(infobuffer); } @@ -6845,7 +6847,7 @@ void G_DoPlayDemo(char *defdemoname) G_SkipDemoExtraFiles(&demo_p); else { - UINT8 error = G_CheckDemoExtraFiles(&demo_p); + UINT8 error = G_CheckDemoExtraFiles(&demo_p, false); if (error) { diff --git a/src/g_game.h b/src/g_game.h index 5b07d053c..af85bd029 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -75,8 +75,13 @@ typedef struct menudemo_s { char title[65]; // Null-terminated for string prints UINT16 map; + UINT8 addonstatus; // What do we need to do addon-wise to play this demo? UINT8 gametype; UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk + + char winnername[17]; + UINT8 winnerskin, winnercolor; + UINT32 winnertime; } menudemo_t; @@ -239,6 +244,13 @@ typedef struct demoghost { } demoghost; extern demoghost *ghosts; +// G_CheckDemoExtraFiles: checks if our loaded WAD list matches the demo's. +#define DFILE_ERROR_NOTLOADED 0x01 // Files are not loaded, but can be without a restart. +#define DFILE_ERROR_OUTOFORDER 0x02 // Files are loaded, but out of order. +#define DFILE_ERROR_INCOMPLETEOUTOFORDER 0x03 // Some files are loaded out of order, but others are not. +#define DFILE_ERROR_CANNOTLOAD 0x04 // Files are missing and cannot be loaded. +#define DFILE_ERROR_EXTRAFILES 0x05 // Extra files outside of the replay's file list are loaded. + void G_DoPlayDemo(char *defdemoname); void G_TimeDemo(const char *name); void G_AddGhost(char *defdemoname); diff --git a/src/m_menu.c b/src/m_menu.c index a5f51f2a9..db31a4a54 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5012,7 +5012,10 @@ static void M_HandleAddons(INT32 choice) // ---- REPLAY HUT ----- menudemo_t *demolist; +#define DF_ENCORE 0x40 static INT16 replayOn = 0; +static INT16 replayScrollTitle = 0; +static INT8 replayScrollDelay = TICRATE, replayScrollDir = 1; static void PrepReplayList(void) { @@ -5073,6 +5076,7 @@ static void M_HandleReplayHutList(INT32 choice) M_PrevOpt(); S_StartSound(NULL, sfx_menu1); + replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; break; case KEY_DOWNARROW: @@ -5082,6 +5086,7 @@ static void M_HandleReplayHutList(INT32 choice) itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item S_StartSound(NULL, sfx_menu1); + replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; break; } } @@ -5096,7 +5101,6 @@ static void M_DrawReplayHut(void) static UINT16 replayhutmenuy = 0; V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - M_DrawMenuTitle(); // Draw menu choices x = currentMenu->x; @@ -5106,10 +5110,12 @@ static void M_DrawReplayHut(void) { itemOn = replaylistitem; replayOn = sizedirmenu-1; + replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; } else if (itemOn < replaylistitem) { replayOn = 0; + replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; } if (itemOn == replaylistitem) @@ -5123,9 +5129,9 @@ static void M_DrawReplayHut(void) cursory = maxy - 20; if (cursory - replayhutmenuy > 150) - replayhutmenuy += (cursory-150-replayhutmenuy)/2; + replayhutmenuy += (cursory-150-replayhutmenuy + 1)/2; else if (cursory - replayhutmenuy < 110) - replayhutmenuy += (max(0, cursory-110)-replayhutmenuy)/2; + replayhutmenuy += (max(0, cursory-110)-replayhutmenuy - 1)/2; } else replayhutmenuy /= 2; @@ -5149,7 +5155,13 @@ static void M_DrawReplayHut(void) for (i = 0; i < (INT16)sizedirmenu; i++) { INT32 localy = y+i*10; - if (localy >= 0 && localy < 200 && demolist[i].type == MD_NOTLOADED && !processed_one_this_frame) + + if (localy < 65) + continue; + if (localy >= 200) + break; + + if (demolist[i].type == MD_NOTLOADED && !processed_one_this_frame) { processed_one_this_frame = true; G_LoadDemoInfo(&demolist[i]); @@ -5158,7 +5170,31 @@ static void M_DrawReplayHut(void) if (itemOn == replaylistitem && i == replayOn) { cursory = localy; - V_DrawString(x, localy, highlightflags|V_ALLOWLOWERCASE, demolist[i].title); + + if (replayScrollDelay) + replayScrollDelay--; + else if (replayScrollDir > 0) + { + if (replayScrollTitle < (V_StringWidth(demolist[i].title, 0) - (BASEVIDWIDTH - (x<<1)))<<1) + replayScrollTitle++; + else + { + replayScrollDelay = TICRATE; + replayScrollDir = -1; + } + } + else + { + if (replayScrollTitle > 0) + replayScrollTitle--; + else + { + replayScrollDelay = TICRATE; + replayScrollDir = 1; + } + } + + V_DrawString(x - (replayScrollTitle>>1), localy, highlightflags|V_ALLOWLOWERCASE, demolist[i].title); } else V_DrawString(x, localy, V_ALLOWLOWERCASE, demolist[i].title); @@ -5168,6 +5204,92 @@ static void M_DrawReplayHut(void) V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); V_DrawString(currentMenu->x, cursory, highlightflags, currentMenu->menuitems[itemOn].text); + + // Now draw some replay info! + V_DrawFill(10, 10, 300, 60, 239); + + if (itemOn == replaylistitem) + { + switch (demolist[replayOn].type) + { + case MD_NOTLOADED: + V_DrawCenteredString(160, 40, 0, "Loading replay information..."); + break; + + case MD_INVALID: + V_DrawCenteredString(160, 40, warningflags, "This replay cannot be played."); + break; + + case MD_SUBDIR: + break; // Can't think of anything to draw here right now + + case MD_OUTDATED: + V_DrawThinString(17, 60, V_ALLOWLOWERCASE|V_TRANSLUCENT|highlightflags, "Recorded on an outdated version."); + /*fallthru*/ + default: + { // Draw level stuff + lumpnum_t lumpnum; + patch_t *PictureOfLevel; + INT32 w, h; + x = 15; y = 15; + //INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; + + // A 160x100 image of the level as entry MAPxxP + CONS_Printf("%d %s\n", demolist[replayOn].map, G_BuildMapName(demolist[replayOn].map)); + lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[replayOn].map))); + if (lumpnum != LUMPERROR) + PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + else + PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + + if (!(demolist[replayOn].kartspeed & DF_ENCORE)) + V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); + else + { + w = SHORT(PictureOfLevel->width); + h = SHORT(PictureOfLevel->height); + V_DrawFixedPatch((x+w)<>ANGLETOFINESHIFT); + V_DrawFixedPatch((x+w/2)<width), y+20, 0, facewantprefix[demolist[replayOn].winnerskin], colormap); + } + } + + break; + } + } } static void M_PandorasBox(INT32 choice) From c21072ec291d14632418dbd470248627e829194b Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 12:49:42 -0500 Subject: [PATCH 127/186] Show music credit for credits --- src/f_finale.c | 5 +++++ src/hu_stuff.c | 2 +- src/hu_stuff.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index d184a2833..5d57d34a9 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -584,6 +584,7 @@ void F_StartCredits(void) S_StopMusic(); S_ChangeMusicInternal("credit", false); + S_ShowMusicCredit(); finalecount = 0; animtimer = 0; @@ -644,6 +645,10 @@ void F_CreditDrawer(void) break; } + // draw song credits + if (cv_songcredits.value) + HU_DrawSongCredits(); + if (!credits[i] && y <= 120< Date: Sun, 31 Mar 2019 13:50:20 -0500 Subject: [PATCH 128/186] Enable exiting and playing demos from replay hut properly --- src/m_menu.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index db31a4a54..203531ea8 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -340,6 +340,7 @@ static patch_t *addonsp[NUM_EXT+5]; static void M_ReplayHut(INT32 choice); static void M_HandleReplayHutList(INT32 choice); static void M_DrawReplayHut(void); +static boolean M_QuitReplayHut(void); // Drawing functions static void M_DrawGenericMenu(void); @@ -1598,14 +1599,14 @@ menu_t MISC_AddonsDef = menu_t MISC_ReplayHutDef = { - "M_REPLAY", + NULL, sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t), - &MainDef, + NULL, MISC_ReplayHutMenu, M_DrawReplayHut, 30, 80, (sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t)) - 2, // Start on the replay list - NULL + M_QuitReplayHut }; menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); @@ -5016,6 +5017,7 @@ menudemo_t *demolist; static INT16 replayOn = 0; static INT16 replayScrollTitle = 0; static INT8 replayScrollDelay = TICRATE, replayScrollDir = 1; +static boolean inreplayhut = false; static void PrepReplayList(void) { @@ -5046,8 +5048,12 @@ static void M_ReplayHut(INT32 choice) { (void)choice; - snprintf(menupath, 1024, "%s"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home); - menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath); + if (!inreplayhut) + { + snprintf(menupath, 1024, "%s"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home); + menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath); + } + inreplayhut = true; if (!preparefilemenu(false, true)) { @@ -5088,6 +5094,17 @@ static void M_HandleReplayHutList(INT32 choice) S_StartSound(NULL, sfx_menu1); replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; break; + + case KEY_ESCAPE: + M_QuitReplayHut(); + break; + + case KEY_ENTER: + M_ClearMenus(false); + demo.loadfiles = true; demo.ignorefiles = false; //@TODO prompt + + G_DoPlayDemo(demolist[replayOn].filepath); + break; } } @@ -5292,6 +5309,21 @@ static void M_DrawReplayHut(void) } } +static boolean M_QuitReplayHut(void) +{ + // D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate. + menuactive = false; + D_StartTitle(); + + if (demolist) + Z_Free(demolist); + demolist = NULL; + + inreplayhut = false; + + return true; +} + static void M_PandorasBox(INT32 choice) { (void)choice; From 17b30c0e3e1b983824bd40d0ee7fd3e99964a9c0 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 13:50:29 -0500 Subject: [PATCH 129/186] Add replay options screen --- src/m_menu.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 203531ea8..d6436ffa8 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -341,9 +341,11 @@ static void M_ReplayHut(INT32 choice); static void M_HandleReplayHutList(INT32 choice); static void M_DrawReplayHut(void); static boolean M_QuitReplayHut(void); +static void M_EnterReplayOptions(INT32 choice); // Drawing functions static void M_DrawGenericMenu(void); +static void M_DrawGenericBackgroundMenu(void); static void M_DrawCenteredMenu(void); static void M_DrawAddons(void); static void M_DrawSkyRoom(void); @@ -534,12 +536,18 @@ static menuitem_t MISC_AddonsMenu[] = static menuitem_t MISC_ReplayHutMenu[] = { - {IT_SUBMENU |IT_STRING, NULL, "Replay Options...", NULL, 0}, + {IT_CALL |IT_STRING, NULL, "Replay Options...", M_EnterReplayOptions, 0}, {IT_KEYHANDLER|IT_NOTHING, NULL, "", M_HandleReplayHutList, 20}, // Dummy menuitem for the replay list {IT_NOTHING, NULL, "", NULL, 20}, // Dummy for handling wrapping to the top of the menu.. }; +static menuitem_t MISC_ReplayOptionsMenu[] = +{ + {IT_CVAR|IT_STRING, NULL, "Record Replays", &cv_recordmultiplayerdemos, 0}, + {IT_CVAR|IT_STRING, NULL, "Sync Check Interval", &cv_netdemosyncquality, 10}, +}; + // --------------------------------- // Pause Menu Mode Attacking Edition // --------------------------------- @@ -1608,6 +1616,17 @@ menu_t MISC_ReplayHutDef = (sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t)) - 2, // Start on the replay list M_QuitReplayHut }; +menu_t MISC_ReplayOptionsDef = +{ + NULL, + sizeof (MISC_ReplayOptionsMenu)/sizeof (menuitem_t), + &MISC_ReplayHutDef, + MISC_ReplayOptionsMenu, + M_DrawGenericBackgroundMenu, + 27, 40, + 0, + NULL +}; menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); @@ -3713,6 +3732,12 @@ static void M_DrawGenericMenu(void) } } +static void M_DrawGenericBackgroundMenu(void) +{ + V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + M_DrawGenericMenu(); +} + static void M_DrawPauseMenu(void) { #if 0 @@ -5324,6 +5349,15 @@ static boolean M_QuitReplayHut(void) return true; } +static void M_EnterReplayOptions(INT32 choice) +{ + (void)choice; + + // We can't just use M_SetupNextMenu because that'll boot us back to the title screen! + currentMenu = &MISC_ReplayOptionsDef; + itemOn = currentMenu->lastOn; +} + static void M_PandorasBox(INT32 choice) { (void)choice; From 03af8595352c274e03228aeb6738faccfbd66767 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 16:28:18 -0500 Subject: [PATCH 130/186] Support directory navigation properly --- src/g_game.c | 10 +++++ src/m_menu.c | 123 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 102 insertions(+), 31 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 94f8bd8d1..e56362b66 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6642,6 +6642,16 @@ void G_LoadDemoInfo(menudemo_t *pdemo) Z_Free(infobuffer); return; } +#ifdef DEMO_COMPAT_100 + else if (pdemoversion == 0x0001) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is a legacy multiplayer replay and cannot be played.\n"), pdemo->filepath); + pdemo->type = MD_INVALID; + sprintf(pdemo->title, "INVALID REPLAY"); + Z_Free(infobuffer); + return; + } +#endif pdemo->gametype = READUINT8(info_p); diff --git a/src/m_menu.c b/src/m_menu.c index d6436ffa8..013eb354d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5039,7 +5039,6 @@ static void M_HandleAddons(INT32 choice) menudemo_t *demolist; #define DF_ENCORE 0x40 -static INT16 replayOn = 0; static INT16 replayScrollTitle = 0; static INT8 replayScrollDelay = TICRATE, replayScrollDir = 1; static boolean inreplayhut = false; @@ -5055,7 +5054,12 @@ static void PrepReplayList(void) for (i = 0; i < sizedirmenu; i++) { - if (dirmenu[i][DIR_TYPE] == EXT_FOLDER) + if (dirmenu[i][DIR_TYPE] == EXT_UP) + { + demolist[i].type = MD_SUBDIR; + sprintf(demolist[i].title, "UP"); + } + else if (dirmenu[i][DIR_TYPE] == EXT_FOLDER) { demolist[i].type = MD_SUBDIR; strncpy(demolist[i].title, dirmenu[i] + DIR_STRING, 64); @@ -5078,15 +5082,14 @@ static void M_ReplayHut(INT32 choice) snprintf(menupath, 1024, "%s"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home); menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath); } - inreplayhut = true; - if (!preparefilemenu(false, true)) { M_StartMessage("No replays found.\n\n(Press a key)\n", NULL, MM_NOTHING); return; } - else + else if (!inreplayhut) dir_on[menudepthleft] = 0; + inreplayhut = true; PrepReplayList(); @@ -5101,8 +5104,8 @@ static void M_HandleReplayHutList(INT32 choice) switch (choice) { case KEY_UPARROW: - if (replayOn) - replayOn--; + if (dir_on[menudepthleft]) + dir_on[menudepthleft]--; else M_PrevOpt(); @@ -5111,8 +5114,8 @@ static void M_HandleReplayHutList(INT32 choice) break; case KEY_DOWNARROW: - if (replayOn < (INT16)sizedirmenu-1) - replayOn++; + if (dir_on[menudepthleft] < sizedirmenu-1) + dir_on[menudepthleft]++; else itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item @@ -5125,10 +5128,59 @@ static void M_HandleReplayHutList(INT32 choice) break; case KEY_ENTER: - M_ClearMenus(false); - demo.loadfiles = true; demo.ignorefiles = false; //@TODO prompt + switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE]) + { + case EXT_FOLDER: + strcpy(&menupath[menupathindex[menudepthleft]],dirmenu[dir_on[menudepthleft]]+DIR_STRING); + if (menudepthleft) + { + menupathindex[--menudepthleft] = strlen(menupath); + menupath[menupathindex[menudepthleft]] = 0; + + if (!preparefilemenu(false, true)) + { + S_StartSound(NULL, sfx_s224); + M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); + menupath[menupathindex[++menudepthleft]] = 0; + + if (!preparefilemenu(true, true)) + { + M_QuitReplayHut(); + return; + } + } + else + { + S_StartSound(NULL, sfx_menu1); + dir_on[menudepthleft] = 1; + PrepReplayList(); + } + } + else + { + S_StartSound(NULL, sfx_s26d); + M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); + menupath[menupathindex[menudepthleft]] = 0; + } + break; + case EXT_UP: + S_StartSound(NULL, sfx_menu1); + menupath[menupathindex[++menudepthleft]] = 0; + if (!preparefilemenu(false, true)) + { + M_QuitReplayHut(); + return; + } + PrepReplayList(); + break; + default: + currentMenu->lastOn = itemOn; + M_ClearMenus(false); + demo.loadfiles = true; demo.ignorefiles = false; //@TODO prompt + + G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath); + } - G_DoPlayDemo(demolist[replayOn].filepath); break; } } @@ -5151,12 +5203,12 @@ static void M_DrawReplayHut(void) if (itemOn > replaylistitem) { itemOn = replaylistitem; - replayOn = sizedirmenu-1; + dir_on[menudepthleft] = sizedirmenu-1; replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; } else if (itemOn < replaylistitem) { - replayOn = 0; + dir_on[menudepthleft] = 0; replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; } @@ -5164,7 +5216,7 @@ static void M_DrawReplayHut(void) { INT32 maxy; // Scroll menu items if needed - cursory = y + currentMenu->menuitems[replaylistitem].alphaKey + replayOn*10; + cursory = y + currentMenu->menuitems[replaylistitem].alphaKey + dir_on[menudepthleft]*10; maxy = y + currentMenu->menuitems[replaylistitem].alphaKey + sizedirmenu*10; if (cursory > maxy - 20) @@ -5209,7 +5261,7 @@ static void M_DrawReplayHut(void) G_LoadDemoInfo(&demolist[i]); } - if (itemOn == replaylistitem && i == replayOn) + if (itemOn == replaylistitem && i == (INT16)dir_on[menudepthleft]) { cursory = localy; @@ -5252,7 +5304,7 @@ static void M_DrawReplayHut(void) if (itemOn == replaylistitem) { - switch (demolist[replayOn].type) + switch (demolist[dir_on[menudepthleft]].type) { case MD_NOTLOADED: V_DrawCenteredString(160, 40, 0, "Loading replay information..."); @@ -5277,14 +5329,14 @@ static void M_DrawReplayHut(void) //INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; // A 160x100 image of the level as entry MAPxxP - CONS_Printf("%d %s\n", demolist[replayOn].map, G_BuildMapName(demolist[replayOn].map)); - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[replayOn].map))); + //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); + lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map))); if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); - if (!(demolist[replayOn].kartspeed & DF_ENCORE)) + if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); else { @@ -5302,30 +5354,39 @@ static void M_DrawReplayHut(void) x += 85; - if (mapheaderinfo[demolist[replayOn].map-1]) - V_DrawString(x, y, 0, G_BuildMapTitle(demolist[replayOn].map)); + if (mapheaderinfo[demolist[dir_on[menudepthleft]].map-1]) + V_DrawString(x, y, 0, G_BuildMapTitle(demolist[dir_on[menudepthleft]].map)); else V_DrawString(x, y, V_ALLOWLOWERCASE|V_TRANSLUCENT, "Level is not loaded."); - V_DrawString(x, y+20, V_ALLOWLOWERCASE, demolist[replayOn].gametype == GT_RACE ? - va("Race (%s speed)", kartspeed_cons_t[demolist[replayOn].kartspeed & ~DF_ENCORE].strvalue) : + V_DrawString(x, y+20, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].gametype == GT_RACE ? + va("Race (%s speed)", kartspeed_cons_t[demolist[dir_on[menudepthleft]].kartspeed & ~DF_ENCORE].strvalue) : "Battle Mode"); V_DrawThinString(x, y+29, highlightflags, "WINNER"); - V_DrawString(x+38, y+30, V_ALLOWLOWERCASE, demolist[replayOn].winnername); + V_DrawString(x+38, y+30, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].winnername); V_DrawThinString(x, y+39, highlightflags, "TIME"); V_DrawString(x+28, y+40, 0, va("%2d'%02d\"%02d", - G_TicsToMinutes(demolist[replayOn].winnertime, true), - G_TicsToSeconds(demolist[replayOn].winnertime), - G_TicsToCentiseconds(demolist[replayOn].winnertime) + G_TicsToMinutes(demolist[dir_on[menudepthleft]].winnertime, true), + G_TicsToSeconds(demolist[dir_on[menudepthleft]].winnertime), + G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].winnertime) )); // Character face! - if (W_CheckNumForName(skins[demolist[replayOn].winnerskin].facewant) != LUMPERROR) + if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].winnerskin].facewant) != LUMPERROR) { - UINT8 *colormap = R_GetTranslationColormap(demolist[replayOn].winnerskin, demolist[replayOn].winnercolor, GTC_MENUCACHE); - V_DrawMappedPatch(BASEVIDWIDTH-15 - SHORT(facewantprefix[demolist[replayOn].winnerskin]->width), y+20, 0, facewantprefix[demolist[replayOn].winnerskin], colormap); + UINT8 *colormap = R_GetTranslationColormap( + demolist[dir_on[menudepthleft]].winnerskin, + demolist[dir_on[menudepthleft]].winnercolor, + GTC_MENUCACHE); + V_DrawMappedPatch( + BASEVIDWIDTH-15 - SHORT(facewantprefix[demolist[dir_on[menudepthleft]].winnerskin]->width), + y+20, + 0, + facewantprefix[demolist[dir_on[menudepthleft]].winnerskin], + colormap + ); } } From 0ae4c905ad9d7f9ee9d81a6a52be2f247fec8e7b Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 16:28:29 -0500 Subject: [PATCH 131/186] Don't pause while the menu's up during replays --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 18b14f426..509cc4d76 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -172,7 +172,7 @@ boolean P_AutoPause(void) if (netgame || modeattacking || demo.title) return false; - return (menuactive || ( window_notinfocus && cv_pauseifunfocused.value )); + return ((menuactive && !demo.playback) || ( window_notinfocus && cv_pauseifunfocused.value )); } // From e93927b911d0fe728ffada5f0fc9325f909fdc92 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 17:29:41 -0500 Subject: [PATCH 132/186] Add subscreen to confirm replay watching This will have other goodies on it later! --- src/m_menu.c | 294 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 203 insertions(+), 91 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 013eb354d..7e8c36387 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -337,11 +337,14 @@ static patch_t *addonsp[NUM_EXT+5]; #define numaddonsshown 4 // Replay hut +menu_t MISC_ReplayHutDef; static void M_ReplayHut(INT32 choice); static void M_HandleReplayHutList(INT32 choice); static void M_DrawReplayHut(void); +static void M_DrawReplayStartMenu(void); static boolean M_QuitReplayHut(void); static void M_EnterReplayOptions(INT32 choice); +static void M_HutStartReplay(INT32 choice); // Drawing functions static void M_DrawGenericMenu(void); @@ -542,6 +545,14 @@ static menuitem_t MISC_ReplayHutMenu[] = {IT_NOTHING, NULL, "", NULL, 20}, // Dummy for handling wrapping to the top of the menu.. }; +static menuitem_t MISC_ReplayStartMenu[] = +{ + {IT_CALL |IT_STRING, NULL, "Load Addons and Watch", M_HutStartReplay, 0}, + {IT_CALL |IT_STRING, NULL, "Watch Without Addons", M_HutStartReplay, 10}, + {IT_CALL |IT_STRING, NULL, "Watch Replay", M_HutStartReplay, 10}, + {IT_SUBMENU |IT_STRING, NULL, "Back", &MISC_ReplayHutDef, 30}, +}; + static menuitem_t MISC_ReplayOptionsMenu[] = { {IT_CVAR|IT_STRING, NULL, "Record Replays", &cv_recordmultiplayerdemos, 0}, @@ -1616,6 +1627,7 @@ menu_t MISC_ReplayHutDef = (sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t)) - 2, // Start on the replay list M_QuitReplayHut }; + menu_t MISC_ReplayOptionsDef = { NULL, @@ -1628,6 +1640,18 @@ menu_t MISC_ReplayOptionsDef = NULL }; +menu_t MISC_ReplayStartDef = +{ + NULL, + sizeof (MISC_ReplayStartMenu)/sizeof (menuitem_t), + &MISC_ReplayHutDef, + MISC_ReplayStartMenu, + M_DrawReplayStartMenu, + 30, 90, + 0, + NULL +}; + menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); @@ -5174,11 +5198,137 @@ static void M_HandleReplayHutList(INT32 choice) PrepReplayList(); break; default: + // We can't just use M_SetupNextMenu because that'll run ReplayDef's quitroutine and boot us back to the title screen! currentMenu->lastOn = itemOn; - M_ClearMenus(false); - demo.loadfiles = true; demo.ignorefiles = false; //@TODO prompt + currentMenu = &MISC_ReplayStartDef; - G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath); + switch (demolist[dir_on[menudepthleft]].addonstatus) + { + case DFILE_ERROR_CANNOTLOAD: + // Only show "Watch Replay Without Addons" + MISC_ReplayStartMenu[0].status = IT_DISABLED; + MISC_ReplayStartMenu[1].status = IT_CALL|IT_STRING; + //MISC_ReplayStartMenu[1].alphaKey = 0; + MISC_ReplayStartMenu[2].status = IT_DISABLED; + itemOn = 1; + break; + + case DFILE_ERROR_NOTLOADED: + case DFILE_ERROR_INCOMPLETEOUTOFORDER: + // Show "Load Addons and Watch Replay" and "Watch Replay Without Addons" + MISC_ReplayStartMenu[0].status = IT_CALL|IT_STRING; + MISC_ReplayStartMenu[1].status = IT_CALL|IT_STRING; + //MISC_ReplayStartMenu[1].alphaKey = 10; + MISC_ReplayStartMenu[2].status = IT_DISABLED; + itemOn = 0; + break; + + case DFILE_ERROR_EXTRAFILES: + case DFILE_ERROR_OUTOFORDER: + default: + // Show "Watch Replay" + MISC_ReplayStartMenu[0].status = IT_DISABLED; + MISC_ReplayStartMenu[1].status = IT_DISABLED; + MISC_ReplayStartMenu[2].status = IT_CALL|IT_STRING; + //MISC_ReplayStartMenu[2].alphaKey = 0; + itemOn = 2; + break; + } + + /*demo.loadfiles = true; demo.ignorefiles = false; //@TODO prompt + + G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath);*/ + } + + break; + } +} + +static void DrawReplayHutReplayInfo(void) +{ + lumpnum_t lumpnum; + patch_t *PictureOfLevel; + INT32 x, y, w, h; + + switch (demolist[dir_on[menudepthleft]].type) + { + case MD_NOTLOADED: + V_DrawCenteredString(160, 40, 0, "Loading replay information..."); + break; + + case MD_INVALID: + V_DrawCenteredString(160, 40, warningflags, "This replay cannot be played."); + break; + + case MD_SUBDIR: + break; // Can't think of anything to draw here right now + + case MD_OUTDATED: + V_DrawThinString(17, 64, V_ALLOWLOWERCASE|V_TRANSLUCENT|highlightflags, "Recorded on an outdated version."); + /*fallthru*/ + default: + // Draw level stuff + x = 15; y = 15; + + // A 160x100 image of the level as entry MAPxxP + //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); + lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map))); + if (lumpnum != LUMPERROR) + PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + else + PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + + if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) + V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); + else + { + w = SHORT(PictureOfLevel->width); + h = SHORT(PictureOfLevel->height); + V_DrawFixedPatch((x+w)<>ANGLETOFINESHIFT); + V_DrawFixedPatch((x+w/2)<width), + y+20, + 0, + facewantprefix[demolist[dir_on[menudepthleft]].winnerskin], + colormap + ); } break; @@ -5304,97 +5454,47 @@ static void M_DrawReplayHut(void) if (itemOn == replaylistitem) { - switch (demolist[dir_on[menudepthleft]].type) - { - case MD_NOTLOADED: - V_DrawCenteredString(160, 40, 0, "Loading replay information..."); - break; - - case MD_INVALID: - V_DrawCenteredString(160, 40, warningflags, "This replay cannot be played."); - break; - - case MD_SUBDIR: - break; // Can't think of anything to draw here right now - - case MD_OUTDATED: - V_DrawThinString(17, 60, V_ALLOWLOWERCASE|V_TRANSLUCENT|highlightflags, "Recorded on an outdated version."); - /*fallthru*/ - default: - { // Draw level stuff - lumpnum_t lumpnum; - patch_t *PictureOfLevel; - INT32 w, h; - x = 15; y = 15; - //INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; - - // A 160x100 image of the level as entry MAPxxP - //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map))); - if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); - else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); - - if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) - V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); - else - { - w = SHORT(PictureOfLevel->width); - h = SHORT(PictureOfLevel->height); - V_DrawFixedPatch((x+w)<>ANGLETOFINESHIFT); - V_DrawFixedPatch((x+w/2)<width), - y+20, - 0, - facewantprefix[demolist[dir_on[menudepthleft]].winnerskin], - colormap - ); - } - } - - break; - } + DrawReplayHutReplayInfo(); } } +static void M_DrawReplayStartMenu(void) +{ + const char *warning; + + M_DrawGenericBackgroundMenu(); + V_DrawFill(10, 10, 300, 60, 239); + DrawReplayHutReplayInfo(); + + V_DrawString(10, 72, highlightflags|V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].title); + + // Draw a warning prompt if needed + switch (demolist[dir_on[menudepthleft]].addonstatus) + { + case DFILE_ERROR_CANNOTLOAD: + warning = "Some addons in this replay cannot be loaded.\nYou can watch anyway, but desyncs may occur."; + break; + + case DFILE_ERROR_NOTLOADED: + case DFILE_ERROR_INCOMPLETEOUTOFORDER: + warning = "Loading addons will mark your game as modified, and record attack may be unavailable.\nYou can watch without loading addons, but desyncs may occur."; + break; + + case DFILE_ERROR_EXTRAFILES: + warning = "You have addons loaded that were not present in this replay.\nYou can watch anyway, but desyncs may occur."; + break; + + case DFILE_ERROR_OUTOFORDER: + warning = "You have this replay's addons loaded, but they are out of order.\nYou can watch anyway, but desyncs may occur."; + break; + + default: + return; + } + + V_DrawSmallString(4, BASEVIDHEIGHT-14, V_ALLOWLOWERCASE, warning); +} + static boolean M_QuitReplayHut(void) { // D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate. @@ -5419,6 +5519,18 @@ static void M_EnterReplayOptions(INT32 choice) itemOn = currentMenu->lastOn; } +static void M_HutStartReplay(INT32 choice) +{ + (void)choice; + + M_ClearMenus(false); + demo.loadfiles = (itemOn == 0); + demo.ignorefiles = (itemOn != 0); + + G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath); +} + + static void M_PandorasBox(INT32 choice) { (void)choice; From 3dd4e4aac751c7ef5223096ec1dbad589e9838cb Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 19:26:53 -0500 Subject: [PATCH 133/186] Return to replay hut after watching a replay --- src/g_game.c | 7 ++++++- src/g_game.h | 1 + src/m_menu.c | 13 ++++++------- src/m_menu.h | 2 ++ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index e56362b66..bf28425cd 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3856,7 +3856,12 @@ void G_AfterIntermission(void) if (demo.playback) { G_StopDemo(); - D_StartTitle(); + + if (demo.inreplayhut) + M_ReplayHut(0); + else + D_StartTitle(); + return; } else if (demo.recording && demo.savemode != DSM_NOTSAVING) diff --git a/src/g_game.h b/src/g_game.h index af85bd029..324af06bb 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -46,6 +46,7 @@ struct demovars_s { boolean loadfiles, ignorefiles; // Demo file loading options boolean fromtitle; // SRB2Kart: Don't stop the music + boolean inreplayhut; // Go back to replayhut after demos boolean quitafterplaying; // quit after playing a demo from cmdline boolean deferstart; // don't start playing demo right away diff --git a/src/m_menu.c b/src/m_menu.c index 7e8c36387..0942f1ee5 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -338,7 +338,6 @@ static patch_t *addonsp[NUM_EXT+5]; // Replay hut menu_t MISC_ReplayHutDef; -static void M_ReplayHut(INT32 choice); static void M_HandleReplayHutList(INT32 choice); static void M_DrawReplayHut(void); static void M_DrawReplayStartMenu(void); @@ -5065,7 +5064,6 @@ menudemo_t *demolist; #define DF_ENCORE 0x40 static INT16 replayScrollTitle = 0; static INT8 replayScrollDelay = TICRATE, replayScrollDir = 1; -static boolean inreplayhut = false; static void PrepReplayList(void) { @@ -5097,11 +5095,11 @@ static void PrepReplayList(void) } } -static void M_ReplayHut(INT32 choice) +void M_ReplayHut(INT32 choice) { (void)choice; - if (!inreplayhut) + if (!demo.inreplayhut) { snprintf(menupath, 1024, "%s"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home); menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath); @@ -5111,12 +5109,13 @@ static void M_ReplayHut(INT32 choice) M_StartMessage("No replays found.\n\n(Press a key)\n", NULL, MM_NOTHING); return; } - else if (!inreplayhut) + else if (!demo.inreplayhut) dir_on[menudepthleft] = 0; - inreplayhut = true; + demo.inreplayhut = true; PrepReplayList(); + menuactive = true; M_SetupNextMenu(&MISC_ReplayHutDef); G_SetGamestate(GS_TIMEATTACK); @@ -5505,7 +5504,7 @@ static boolean M_QuitReplayHut(void) Z_Free(demolist); demolist = NULL; - inreplayhut = false; + demo.inreplayhut = false; return true; } diff --git a/src/m_menu.h b/src/m_menu.h index 33dc1e407..f49c6ca64 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -235,6 +235,8 @@ void Screenshot_option_Onchange(void); // Addons menu updating void Addons_option_Onchange(void); +void M_ReplayHut(INT32 choice); + INT32 HU_GetHighlightColor(void); // These defines make it a little easier to make menus From 746f13a999b054355f7bf879742b883850bcf0db Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 31 Mar 2019 19:29:05 -0500 Subject: [PATCH 134/186] Don't draw options menu entry above replay infobox --- src/m_menu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 0942f1ee5..551a5c89a 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5384,13 +5384,18 @@ static void M_DrawReplayHut(void) // Draw static menu items for (i = 0; i < replaylistitem; i++) { + INT32 localy = y + currentMenu->menuitems[i].alphaKey; + + if (localy < 65) + continue; + if (i == itemOn) - cursory = y + currentMenu->menuitems[i].alphaKey; + cursory = localy; if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) - V_DrawString(x, y + currentMenu->menuitems[i].alphaKey, 0, currentMenu->menuitems[i].text); + V_DrawString(x, localy, 0, currentMenu->menuitems[i].text); else - V_DrawString(x, y + currentMenu->menuitems[i].alphaKey, highlightflags, currentMenu->menuitems[i].text); + V_DrawString(x, localy, highlightflags, currentMenu->menuitems[i].text); } y += currentMenu->menuitems[currentMenu->numitems-1].alphaKey; From e8260f9f361bde68920aade2840e5ef0c72ecdf2 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 12:25:12 -0500 Subject: [PATCH 135/186] Draw icons for directories --- src/m_menu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 551a5c89a..5d4e0731f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5403,6 +5403,7 @@ static void M_DrawReplayHut(void) for (i = 0; i < (INT16)sizedirmenu; i++) { INT32 localy = y+i*10; + INT32 localx = x; if (localy < 65) continue; @@ -5415,6 +5416,12 @@ static void M_DrawReplayHut(void) G_LoadDemoInfo(&demolist[i]); } + if (demolist[i].type == MD_SUBDIR) + { + localx += 8; + V_DrawFixedPatch(x<>1), localy, highlightflags|V_ALLOWLOWERCASE, demolist[i].title); + V_DrawString(localx - (replayScrollTitle>>1), localy, highlightflags|V_ALLOWLOWERCASE, demolist[i].title); } else - V_DrawString(x, localy, V_ALLOWLOWERCASE, demolist[i].title); + V_DrawString(localx, localy, V_ALLOWLOWERCASE, demolist[i].title); } // Draw the cursor From 733d8c1f7be2beaa8076e4bd63e1ca0e5d64158f Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 12:28:01 -0500 Subject: [PATCH 136/186] Fix normal speed replays showing as easy speed --- src/g_game.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_game.c b/src/g_game.c index bf28425cd..ca27ec5af 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6664,6 +6664,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) info_p += 4; // RNG seed // Pared down version of CV_LoadNetVars to find the kart speed + pdemo->kartspeed = 1; // Default to normal speed cvarcount = READUINT16(info_p); while (cvarcount--) { From aa1546a533e05d3e2c920465a9c9c2e40e185287 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 12:56:23 -0500 Subject: [PATCH 137/186] Show non-default lap count on replay screen too --- src/g_game.c | 9 ++------- src/g_game.h | 1 + src/m_menu.c | 3 +++ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index ca27ec5af..723d2b5ee 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6679,16 +6679,11 @@ void G_LoadDemoInfo(menudemo_t *pdemo) if (netid == cv_kartspeed.netid) { for (cvarcount = 0; kartspeed_cons_t[cvarcount].strvalue; cvarcount++) - { if (!stricmp(kartspeed_cons_t[cvarcount].strvalue, svalue)) - { pdemo->kartspeed = kartspeed_cons_t[cvarcount].value; - break; - } - } - - break; } + else if (netid == cv_basenumlaps.netid && pdemo->gametype == GT_RACE) + pdemo->numlaps = atoi(svalue); } if (pdemoflags & DF_ENCORE) diff --git a/src/g_game.h b/src/g_game.h index 324af06bb..aa20dee49 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -79,6 +79,7 @@ typedef struct menudemo_s { UINT8 addonstatus; // What do we need to do addon-wise to play this demo? UINT8 gametype; UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk + UINT8 numlaps; char winnername[17]; UINT8 winnerskin, winnercolor; diff --git a/src/m_menu.c b/src/m_menu.c index 5d4e0731f..379023109 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5300,6 +5300,9 @@ static void DrawReplayHutReplayInfo(void) else V_DrawString(x, y, V_ALLOWLOWERCASE|V_TRANSLUCENT, "Level is not loaded."); + if (demolist[dir_on[menudepthleft]].numlaps) + V_DrawThinString(x, y+9, V_ALLOWLOWERCASE, va("(%d laps)", demolist[dir_on[menudepthleft]].numlaps)); + V_DrawString(x, y+20, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].gametype == GT_RACE ? va("Race (%s speed)", kartspeed_cons_t[demolist[dir_on[menudepthleft]].kartspeed & ~DF_ENCORE].strvalue) : "Battle Mode"); From f753e8edee9fb567217902aa8328e66ff0b63095 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 13:10:35 -0500 Subject: [PATCH 138/186] [FORMAT CHANGE] Add space for extrainfo pointer --- src/g_game.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 723d2b5ee..f2463832d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -289,7 +289,7 @@ UINT32 timesBeatenWithEmeralds; //@TODO put these all in a struct for namespacing purposes? static char demoname[128]; static UINT8 *demobuffer = NULL; -static UINT8 *demo_p, *demotime_p; +static UINT8 *demo_p, *demotime_p, *demoinfo_p; static UINT8 *demoend; static UINT8 demoflags; static UINT16 demoversion; @@ -6165,6 +6165,10 @@ void G_BeginRecording(void) WRITEUINT32(demo_p,P_GetInitSeed()); + // Reserved for extrainfo location from start of file + demoinfo_p = demo_p; + WRITEUINT32(demo_p, 0); + // Save netvars CV_SaveNetVars(&demo_p, true); @@ -6567,7 +6571,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) void G_LoadDemoInfo(menudemo_t *pdemo) { - UINT8 *infobuffer, *info_p; + UINT8 *infobuffer, *info_p, *extrainfo_p; UINT8 version, subversion, pdemoflags; UINT16 pdemoversion, cvarcount; @@ -6663,6 +6667,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo) pdemo->addonstatus = G_CheckDemoExtraFiles(&info_p, true); info_p += 4; // RNG seed + extrainfo_p = infobuffer + READUINT32(info_p); + // Pared down version of CV_LoadNetVars to find the kart speed pdemo->kartspeed = 1; // Default to normal speed cvarcount = READUINT16(info_p); @@ -6690,6 +6696,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) pdemo->kartspeed |= DF_ENCORE; // Temporary info until this is actually present in replays. + (void)extrainfo_p; sprintf(pdemo->winnername, "transrights420"); pdemo->winnerskin = 1; pdemo->winnercolor = SKINCOLOR_MOONSLAM; @@ -6935,6 +6942,7 @@ void G_DoPlayDemo(char *defdemoname) // Random seed randseed = READUINT32(demo_p); + demo_p += 4; // Extrainfo location #ifdef DEMO_COMPAT_100 if (demoversion == 0x0001) { From b8ef18e983a90b9a6c53f410ce0c8c12c66f7158 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 15:07:27 -0500 Subject: [PATCH 139/186] Read and write standings to replays --- src/g_game.c | 112 ++++++++++++++++++++++++++++++++++++++++++++------ src/g_game.h | 10 +++-- src/m_menu.c | 104 ++++++++++++++++++++++++++++++++++++++-------- src/y_inter.c | 9 ++++ 4 files changed, 203 insertions(+), 32 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index f2463832d..0a20b1040 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3324,8 +3324,7 @@ void G_ExitLevel(void) // Remove CEcho text on round end. HU_ClearCEcho(); - if (multiplayer && demo.recording && (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE)) - G_SaveDemo(); + // Don't save demos immediately here! Let standings write first } } @@ -4799,6 +4798,9 @@ static ticcmd_t oldcmd[MAXPLAYERS]; #define DW_EXTRASTUFF 0xFE // Numbers below this are reserved for writing player slot data +// Below consts are only used for demo extrainfo sections +#define DW_STANDING 0x00 + // For Metal Sonic and time attack ghosts #define GZT_XYZ 0x01 #define GZT_MOMXY 0x02 @@ -6259,6 +6261,41 @@ void G_BeginMetal(void) oldmetal.angle = mo->angle; } +void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT8 color, UINT32 val) +{ + char temp[16]; + + if (demoinfo_p && (UINT32)(*demoinfo_p) == 0) + { + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + WRITEUINT32(demoinfo_p, demo_p - demobuffer); + } + + WRITEUINT8(demo_p, DW_STANDING); + WRITEUINT8(demo_p, ranking); + + // Name + memset(temp, 0, 16); + strncpy(temp, name, 16); + M_Memcpy(demo_p,temp,16); + demo_p += 16; + + // Skin + memset(temp, 0, 16); + strncpy(temp, skins[skinnum].name, 16); + M_Memcpy(demo_p,temp,16); + demo_p += 16; + + // Color + memset(temp, 0, 16); + strncpy(temp, KartColor_Names[color], 16); + M_Memcpy(demo_p,temp,16); + demo_p += 16; + + // Score/time/whatever + WRITEUINT32(demo_p, val); +} + void G_SetDemoTime(UINT32 ptime, UINT32 plap) { if (!demo.recording || !demotime_p) @@ -6573,7 +6610,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) { UINT8 *infobuffer, *info_p, *extrainfo_p; UINT8 version, subversion, pdemoflags; - UINT16 pdemoversion, cvarcount; + UINT16 pdemoversion, count; if (!FIL_ReadFile(pdemo->filepath, &infobuffer)) { @@ -6671,8 +6708,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo) // Pared down version of CV_LoadNetVars to find the kart speed pdemo->kartspeed = 1; // Default to normal speed - cvarcount = READUINT16(info_p); - while (cvarcount--) + count = READUINT16(info_p); + while (count--) { UINT16 netid; char *svalue; @@ -6684,9 +6721,10 @@ void G_LoadDemoInfo(menudemo_t *pdemo) if (netid == cv_kartspeed.netid) { - for (cvarcount = 0; kartspeed_cons_t[cvarcount].strvalue; cvarcount++) - if (!stricmp(kartspeed_cons_t[cvarcount].strvalue, svalue)) - pdemo->kartspeed = kartspeed_cons_t[cvarcount].value; + UINT8 j; + for (j = 0; kartspeed_cons_t[j].strvalue; j++) + if (!stricmp(kartspeed_cons_t[j].strvalue, svalue)) + pdemo->kartspeed = kartspeed_cons_t[j].value; } else if (netid == cv_basenumlaps.netid && pdemo->gametype == GT_RACE) pdemo->numlaps = atoi(svalue); @@ -6695,12 +6733,53 @@ void G_LoadDemoInfo(menudemo_t *pdemo) if (pdemoflags & DF_ENCORE) pdemo->kartspeed |= DF_ENCORE; - // Temporary info until this is actually present in replays. + /*// Temporary info until this is actually present in replays. (void)extrainfo_p; sprintf(pdemo->winnername, "transrights420"); pdemo->winnerskin = 1; pdemo->winnercolor = SKINCOLOR_MOONSLAM; - pdemo->winnertime = 6666; + pdemo->winnertime = 6666;*/ + + // Read standings! + count = 0; + + while (READUINT8(extrainfo_p) == DW_STANDING) // Assume standings are always first in the extrainfo + { + INT32 i; + char temp[16]; + + pdemo->standings[count].ranking = READUINT8(extrainfo_p); + + // Name + M_Memcpy(pdemo->standings[count].name, extrainfo_p, 16); + extrainfo_p += 16; + + // Skin + M_Memcpy(temp,extrainfo_p,16); + extrainfo_p += 16; + pdemo->standings[count].skin = UINT8_MAX; + for (i = 0; i < numskins; i++) + if (stricmp(skins[i].name, temp) == 0) + { + pdemo->standings[count].skin = i; + break; + } + + // Color + M_Memcpy(temp,extrainfo_p,16); + extrainfo_p += 16; + for (i = 0; i < MAXSKINCOLORS; i++) + if (!stricmp(KartColor_Names[i],temp)) // SRB2kart + { + pdemo->standings[count].color = i; + break; + } + + // Score/time/whatever + pdemo->standings[count].timeorscore = READUINT32(extrainfo_p); + + count++; + } // I think that's everything we need? free(infobuffer); @@ -7763,7 +7842,14 @@ void G_SaveDemo(void) UINT8 i; #endif - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + // Ensure extrainfo pointer is always available, even if no info is present. + if (demoinfo_p && (UINT32)(*demoinfo_p) == 0) + { + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + WRITEUINT32(demoinfo_p, (UINT32)(demo_p - demobuffer)); + } + WRITEUINT8(demo_p, DW_END); // Mark end of demo extra data. + M_Memcpy(p, demo.titlename, 64); // Write demo title here p += 64; @@ -7810,9 +7896,11 @@ void G_SaveDemo(void) for (i = 0; i < 16; i++, p++) *p = M_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. #else - md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. + // Make a checksum of everything after the checksum in the file up to the end of the standard data. Extrainfo is freely modifiable. + md5_buffer((char *)p+16, (demobuffer + (UINT32)*demoinfo_p) - (p+16), p); #endif + if (FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer)) // finally output the file. demo.savemode = DSM_SAVED; free(demobuffer); diff --git a/src/g_game.h b/src/g_game.h index aa20dee49..c44691e8c 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -81,9 +81,12 @@ typedef struct menudemo_s { UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk UINT8 numlaps; - char winnername[17]; - UINT8 winnerskin, winnercolor; - UINT32 winnertime; + struct { + UINT8 ranking; + char name[17]; + UINT8 skin, color; + UINT32 timeorscore; + } standings[MAXPLAYERS]; } menudemo_t; @@ -190,6 +193,7 @@ void G_BeginRecording(void); void G_BeginMetal(void); // Only called by shutdown code. +void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT8 color, UINT32 val); void G_SetDemoTime(UINT32 ptime, UINT32 plap); UINT8 G_CmpDemoTime(char *oldname, char *newname); diff --git a/src/m_menu.c b/src/m_menu.c index 379023109..4d334a47d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5113,6 +5113,8 @@ void M_ReplayHut(INT32 choice) dir_on[menudepthleft] = 0; demo.inreplayhut = true; + replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; + PrepReplayList(); menuactive = true; @@ -5201,6 +5203,8 @@ static void M_HandleReplayHutList(INT32 choice) currentMenu->lastOn = itemOn; currentMenu = &MISC_ReplayStartDef; + replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; + switch (demolist[dir_on[menudepthleft]].addonstatus) { case DFILE_ERROR_CANNOTLOAD: @@ -5233,10 +5237,6 @@ static void M_HandleReplayHutList(INT32 choice) itemOn = 2; break; } - - /*demo.loadfiles = true; demo.ignorefiles = false; //@TODO prompt - - G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath);*/ } break; @@ -5308,27 +5308,35 @@ static void DrawReplayHutReplayInfo(void) "Battle Mode"); V_DrawThinString(x, y+29, highlightflags, "WINNER"); - V_DrawString(x+38, y+30, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].winnername); + V_DrawString(x+38, y+30, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[0].name); - V_DrawThinString(x, y+39, highlightflags, "TIME"); - V_DrawString(x+28, y+40, 0, va("%2d'%02d\"%02d", - G_TicsToMinutes(demolist[dir_on[menudepthleft]].winnertime, true), - G_TicsToSeconds(demolist[dir_on[menudepthleft]].winnertime), - G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].winnertime) - )); + if (demolist[dir_on[menudepthleft]].gametype == GT_RACE) + { + V_DrawThinString(x, y+39, highlightflags, "TIME"); + V_DrawRightAlignedString(x+84, y+40, 0, va("%d'%02d\"%02d", + G_TicsToMinutes(demolist[dir_on[menudepthleft]].standings[0].timeorscore, true), + G_TicsToSeconds(demolist[dir_on[menudepthleft]].standings[0].timeorscore), + G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].standings[0].timeorscore) + )); + } + else + { + V_DrawThinString(x, y+39, highlightflags, "SCORE"); + V_DrawString(x+32, y+40, 0, va("%d", demolist[dir_on[menudepthleft]].standings[0].timeorscore)); + } // Character face! - if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].winnerskin].facewant) != LUMPERROR) + if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[0].skin].facewant) != LUMPERROR) { UINT8 *colormap = R_GetTranslationColormap( - demolist[dir_on[menudepthleft]].winnerskin, - demolist[dir_on[menudepthleft]].winnercolor, + demolist[dir_on[menudepthleft]].standings[0].skin, + demolist[dir_on[menudepthleft]].standings[0].color, GTC_MENUCACHE); V_DrawMappedPatch( - BASEVIDWIDTH-15 - SHORT(facewantprefix[demolist[dir_on[menudepthleft]].winnerskin]->width), + BASEVIDWIDTH-15 - SHORT(facewantprefix[demolist[dir_on[menudepthleft]].standings[0].skin]->width), y+20, 0, - facewantprefix[demolist[dir_on[menudepthleft]].winnerskin], + facewantprefix[demolist[dir_on[menudepthleft]].standings[0].skin], colormap ); } @@ -5422,7 +5430,7 @@ static void M_DrawReplayHut(void) if (demolist[i].type == MD_SUBDIR) { localx += 8; - V_DrawFixedPatch(x<>1) + // Draw rankings beyond first + for (i = 1; i < MAXPLAYERS && demolist[dir_on[menudepthleft]].standings[i].ranking; i++) + { + V_DrawRightAlignedString(BASEVIDWIDTH-100, STARTY + i*20, highlightflags, va("%2d", demolist[dir_on[menudepthleft]].standings[i].ranking)); + V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[i].name); + + if (demolist[dir_on[menudepthleft]].standings[i].timeorscore == UINT32_MAX-1) + V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20 + 9, 0, "NO CONTEST"); + else if (demolist[dir_on[menudepthleft]].gametype == GT_RACE) + V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, 0, va("%d'%02d\"%02d", + G_TicsToMinutes(demolist[dir_on[menudepthleft]].standings[i].timeorscore, true), + G_TicsToSeconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore), + G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore) + )); + else + V_DrawString(BASEVIDWIDTH-96, STARTY + i*20 + 9, 0, va("%d", demolist[dir_on[menudepthleft]].standings[i].timeorscore)); + + // Character face! + if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[i].skin].facerank) != LUMPERROR) + { + UINT8 *colormap = R_GetTranslationColormap( + demolist[dir_on[menudepthleft]].standings[i].skin, + demolist[dir_on[menudepthleft]].standings[i].color, + GTC_MENUCACHE); + V_DrawMappedPatch( + BASEVIDWIDTH-5 - SHORT(facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin]->width), + STARTY + i*20, + 0, + facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin], + colormap + ); + } + } +#undef STARTY + + // Handle scrolling rankings + if (replayScrollDelay) + replayScrollDelay--; + else if (replayScrollDir > 0) + { + if (replayScrollTitle < (i*20 - 100)<<1) + replayScrollTitle++; + else + { + replayScrollDelay = TICRATE; + replayScrollDir = -1; + } + } + else + { + if (replayScrollTitle > 0) + replayScrollTitle--; + else + { + replayScrollDelay = TICRATE; + replayScrollDir = 1; + } + } + V_DrawFill(10, 10, 300, 60, 239); DrawReplayHutReplayInfo(); diff --git a/src/y_inter.c b/src/y_inter.c index 256a8566a..4fce58cc2 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -304,6 +304,15 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) players[i].score += data.match.increase[i]; } + if (demo.recording) + G_WriteStanding( + data.match.pos[data.match.numplayers], + data.match.name[data.match.numplayers], + *data.match.character[data.match.numplayers], + *data.match.color[data.match.numplayers], + data.match.val[data.match.numplayers] + ); + data.match.numplayers++; } } From c5e166f25912a81da7bcee4a5608e8b1d72a8a1f Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 17:14:45 -0500 Subject: [PATCH 140/186] Fix old replays not loading --- src/g_game.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 0a20b1040..5aa28a070 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -7021,6 +7021,9 @@ void G_DoPlayDemo(char *defdemoname) // Random seed randseed = READUINT32(demo_p); +#ifdef DEMO_COMPAT_100 + if (demoversion != 0x0001) +#endif demo_p += 4; // Extrainfo location #ifdef DEMO_COMPAT_100 From 4d3542d421053d951db7b6f4a4f9efc8b5b0f60c Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 20:17:36 -0500 Subject: [PATCH 141/186] Fix encore stage rendering on replay hut --- src/m_menu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 4d334a47d..5e18e7e84 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5283,12 +5283,12 @@ static void DrawReplayHutReplayInfo(void) { w = SHORT(PictureOfLevel->width); h = SHORT(PictureOfLevel->height); - V_DrawFixedPatch((x+w)<>1), y, V_FLIP, PictureOfLevel); { static angle_t rubyfloattime = 0; const fixed_t rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT); - V_DrawFixedPatch((x+w/2)<>2))<>2))< Date: Mon, 1 Apr 2019 20:30:24 -0500 Subject: [PATCH 142/186] Draw placeholder when no standings are available --- src/m_menu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/m_menu.c b/src/m_menu.c index 5e18e7e84..7a9f83b54 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5307,6 +5307,15 @@ static void DrawReplayHutReplayInfo(void) va("Race (%s speed)", kartspeed_cons_t[demolist[dir_on[menudepthleft]].kartspeed & ~DF_ENCORE].strvalue) : "Battle Mode"); + if (!demolist[dir_on[menudepthleft]].standings[0].ranking) + { + // No standings were loaded! + V_DrawString(x, y+39, V_ALLOWLOWERCASE|V_TRANSLUCENT, "No standings available."); + + + break; + } + V_DrawThinString(x, y+29, highlightflags, "WINNER"); V_DrawString(x+38, y+30, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[0].name); From d633ba9421e3d1cd5c87f18686196f4550984a64 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 23:34:53 -0500 Subject: [PATCH 143/186] something something character placeholders im tired --- src/m_menu.c | 83 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 7a9f83b54..c841d50e0 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5246,7 +5246,8 @@ static void M_HandleReplayHutList(INT32 choice) static void DrawReplayHutReplayInfo(void) { lumpnum_t lumpnum; - patch_t *PictureOfLevel; + patch_t *patch; + UINT8 *colormap; INT32 x, y, w, h; switch (demolist[dir_on[menudepthleft]].type) @@ -5273,17 +5274,17 @@ static void DrawReplayHutReplayInfo(void) //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map))); if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + patch = W_CachePatchNum(lumpnum, PU_CACHE); else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + patch = W_CachePatchName("BLANKLVL", PU_CACHE); if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) - V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); + V_DrawSmallScaledPatch(x, y, 0, patch); else { - w = SHORT(PictureOfLevel->width); - h = SHORT(PictureOfLevel->height); - V_DrawSmallScaledPatch(x+(w>>1), y, V_FLIP, PictureOfLevel); + w = SHORT(patch->width); + h = SHORT(patch->height); + V_DrawSmallScaledPatch(x+(w>>1), y, V_FLIP, patch); { static angle_t rubyfloattime = 0; @@ -5337,18 +5338,22 @@ static void DrawReplayHutReplayInfo(void) // Character face! if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[0].skin].facewant) != LUMPERROR) { - UINT8 *colormap = R_GetTranslationColormap( + patch = facewantprefix[demolist[dir_on[menudepthleft]].standings[0].skin]; + colormap = R_GetTranslationColormap( demolist[dir_on[menudepthleft]].standings[0].skin, demolist[dir_on[menudepthleft]].standings[0].color, GTC_MENUCACHE); - V_DrawMappedPatch( - BASEVIDWIDTH-15 - SHORT(facewantprefix[demolist[dir_on[menudepthleft]].standings[0].skin]->width), - y+20, - 0, - facewantprefix[demolist[dir_on[menudepthleft]].standings[0].skin], - colormap - ); } + else + { + patch = W_CachePatchName("MISSINGW", PU_CACHE); + colormap = R_GetTranslationColormap( + TC_RAINBOW, + demolist[dir_on[menudepthleft]].standings[0].color, + GTC_MENUCACHE); + } + + V_DrawMappedPatch(BASEVIDWIDTH-15 - SHORT(patch->width), y+20, 0, patch, colormap); break; } @@ -5500,11 +5505,14 @@ static void M_DrawReplayStartMenu(void) // Draw rankings beyond first for (i = 1; i < MAXPLAYERS && demolist[dir_on[menudepthleft]].standings[i].ranking; i++) { + patch_t *patch; + UINT8 *colormap; + V_DrawRightAlignedString(BASEVIDWIDTH-100, STARTY + i*20, highlightflags, va("%2d", demolist[dir_on[menudepthleft]].standings[i].ranking)); V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[i].name); if (demolist[dir_on[menudepthleft]].standings[i].timeorscore == UINT32_MAX-1) - V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20 + 9, 0, "NO CONTEST"); + V_DrawThinString(BASEVIDWIDTH-92, STARTY + i*20 + 9, 0, "NO CONTEST"); else if (demolist[dir_on[menudepthleft]].gametype == GT_RACE) V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, 0, va("%d'%02d\"%02d", G_TicsToMinutes(demolist[dir_on[menudepthleft]].standings[i].timeorscore, true), @@ -5512,23 +5520,48 @@ static void M_DrawReplayStartMenu(void) G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore) )); else - V_DrawString(BASEVIDWIDTH-96, STARTY + i*20 + 9, 0, va("%d", demolist[dir_on[menudepthleft]].standings[i].timeorscore)); + V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, 0, va("%d", demolist[dir_on[menudepthleft]].standings[i].timeorscore)); +/* + // Character face! + if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[0].skin].facewant) != LUMPERROR) + { + patch = facewantprefix[demolist[dir_on[menudepthleft]].standings[0].skin]; + colormap = R_GetTranslationColormap( + demolist[dir_on[menudepthleft]].standings[0].skin, + demolist[dir_on[menudepthleft]].standings[0].color, + GTC_MENUCACHE); + } + else + { + patch = W_CachePatchName("MISSING", PU_CACHE); + colormap = R_GetTranslationColormap( + TC_RAINBOW, + demolist[dir_on[menudepthleft]].standings[0].color, + GTC_MENUCACHE); + } + + V_DrawMappedPatch(BASEVIDWIDTH-15 - SHORT(patch->width), y+20, 0, patch, colormap); +*/ // Character face! if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[i].skin].facerank) != LUMPERROR) { - UINT8 *colormap = R_GetTranslationColormap( + patch = facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin]; + colormap = R_GetTranslationColormap( demolist[dir_on[menudepthleft]].standings[i].skin, demolist[dir_on[menudepthleft]].standings[i].color, GTC_MENUCACHE); - V_DrawMappedPatch( - BASEVIDWIDTH-5 - SHORT(facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin]->width), - STARTY + i*20, - 0, - facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin], - colormap - ); } + else + { + patch = W_CachePatchName("MISSINGR", PU_CACHE); + colormap = R_GetTranslationColormap( + TC_RAINBOW, + demolist[dir_on[menudepthleft]].standings[i].color, + GTC_MENUCACHE); + } + + V_DrawMappedPatch(BASEVIDWIDTH-5 - SHORT(patch->width), STARTY + i*20, 0, patch, colormap); } #undef STARTY From c4664129022f555f1ceae26af0479ae2f4084b07 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Fri, 5 Apr 2019 02:38:48 -0500 Subject: [PATCH 144/186] Begin work on playback menu --- src/d_main.c | 2 +- src/d_netcmd.c | 2 +- src/g_game.c | 47 +++++++++--- src/g_game.h | 2 +- src/m_menu.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 232 insertions(+), 16 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 16a70519f..a86a4f97e 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -556,7 +556,7 @@ static void D_Display(void) wipegamestate = gamestate; // draw pause pic - if (paused && cv_showhud.value) + if (paused && cv_showhud.value && !demo.playback) { INT32 py; patch_t *patch; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 50f0a2e8f..21a8e2a36 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2689,7 +2689,7 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) return; } - if (modeattacking) + if (modeattacking && !demo.playback) return; paused = READUINT8(*cp); diff --git a/src/g_game.c b/src/g_game.c index 5aa28a070..df1c82355 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1949,6 +1949,33 @@ boolean G_Responder(event_t *ev) return true; } + + // Allow pausing + if ( + ev->data1 == gamecontrol[gc_pause][0] + || ev->data1 == gamecontrol[gc_pause][1] + || ev->data1 == KEY_PAUSE + ) + { + paused = !paused; + if (paused) + S_PauseAudio(); + else + S_ResumeAudio(); + + return true; + } + + // Anything else opens the menu if not already open, except for a few keys... + if (!( + // Rankings + ev->data1 == gamecontrol[gc_scores][0] || ev->data1 == gamecontrol[gc_scores][1] + )) + { + M_StartControlPanel(); + + return true; + } } // update keys current state @@ -2171,16 +2198,16 @@ boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive) // Return the next player that can be viewed on a view, wraps forward. // An out of range startview is corrected. // -INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive) +INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive, boolean reverse) { - INT32 i; + INT32 i, dir = reverse ? -1 : 1; startview = min(max(startview, 0), MAXPLAYERS); - for (i = startview; i < MAXPLAYERS; ++i) + for (i = startview; i < MAXPLAYERS && i >= 0; i += dir) { if (G_CanView(i, viewnum, onlyactive)) return i; } - for (i = 0; i < startview; ++i) + for (i = (reverse ? MAXPLAYERS-1 : 0); i != startview; i += dir) { if (G_CanView(i, viewnum, onlyactive)) return i; @@ -2251,12 +2278,14 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) R_ExecuteSetViewSize(); } - /* Check if anyone is available to view. */ - if (( playernum = G_FindView(playernum, viewnum, onlyactive) ) == -1) - return; - /* Focus our target view first so that we don't take its player. */ displayplayerp = (G_GetDisplayplayerPtr(viewnum)); olddisplayplayer = (*displayplayerp); + + /* Check if anyone is available to view. */ + if (( playernum = G_FindView(playernum, viewnum, onlyactive, playernum < olddisplayplayer) ) == -1) + return; + + /* Focus our target view first so that we don't take its player. */ (*displayplayerp) = playernum; if ((*displayplayerp) != olddisplayplayer) { @@ -2271,7 +2300,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) displayplayerp = (G_GetDisplayplayerPtr(viewd)); camerap = (P_GetCameraPtr(viewd)); - (*displayplayerp) = G_FindView(0, viewd, onlyactive); + (*displayplayerp) = G_FindView(0, viewd, onlyactive, false); P_ResetCamera(&players[(*displayplayerp)], camerap); } diff --git a/src/g_game.h b/src/g_game.h index c44691e8c..42623dfac 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -294,7 +294,7 @@ INT32 *G_GetDisplayplayerPtr(UINT8 viewnum); boolean G_CouldView(INT32 playernum); boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive); -INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive); +INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive, boolean reverse); INT32 G_CountPlayersPotentiallyViewable(boolean active); void G_ResetViews(void); diff --git a/src/m_menu.c b/src/m_menu.c index c841d50e0..96e4075d9 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -345,6 +345,13 @@ static boolean M_QuitReplayHut(void); static void M_EnterReplayOptions(INT32 choice); static void M_HutStartReplay(INT32 choice); +static void M_DrawPlaybackMenu(void); +static void M_PlaybackPause(INT32 choice); +static void M_PlaybackFastForward(INT32 choice); +static void M_PlaybackAdvance(INT32 choice); +static void M_PlaybackSetViews(INT32 choice); +static void M_PlaybackAdjustView(INT32 choice); + // Drawing functions static void M_DrawGenericMenu(void); static void M_DrawGenericBackgroundMenu(void); @@ -558,6 +565,43 @@ static menuitem_t MISC_ReplayOptionsMenu[] = {IT_CVAR|IT_STRING, NULL, "Sync Check Interval", &cv_netdemosyncquality, 10}, }; +static menuitem_t PlaybackMenu[] = +{ + {IT_CALL | IT_STRING, NULL, "Hide Menu", M_SelectableClearMenus, 0}, + + {IT_CALL | IT_STRING, NULL, "Rewind", M_SelectableClearMenus, 24}, + {IT_CALL | IT_STRING, NULL, "Pause", M_PlaybackPause, 40}, + {IT_CALL | IT_STRING, NULL, "Resume", M_PlaybackPause, 40}, + {IT_CALL | IT_STRING, NULL, "Fast-Foward", M_PlaybackFastForward, 56}, + {IT_CALL | IT_STRING, NULL, "Advance Frame", M_PlaybackAdvance, 56}, + + {IT_ARROWS | IT_STRING, NULL, "View Count", M_PlaybackSetViews, 80}, + {IT_ARROWS | IT_STRING, NULL, "Viewpoint", M_PlaybackAdjustView, 96}, + {IT_ARROWS | IT_STRING, NULL, "Viewpoint 2", M_PlaybackAdjustView, 112}, + {IT_ARROWS | IT_STRING, NULL, "Viewpoint 3", M_PlaybackAdjustView, 128}, + {IT_ARROWS | IT_STRING, NULL, "Viewpoint 4", M_PlaybackAdjustView, 144}, + + + {IT_CALL | IT_STRING, NULL, "More Options...", M_ReplayHut, 168}, + {IT_CALL | IT_STRING, NULL, "Stop Playback", M_ReplayHut, 184}, +}; +typedef enum +{ + playback_hide, + playback_rewind, + playback_pause, + playback_resume, + playback_fastforward, + playback_advanceframe, + playback_viewcount, + playback_view1, + playback_view2, + playback_view3, + playback_view4, + playback_moreoptions, + playback_quit +} playback_e; + // --------------------------------- // Pause Menu Mode Attacking Edition // --------------------------------- @@ -1651,6 +1695,17 @@ menu_t MISC_ReplayStartDef = NULL }; +menu_t PlaybackMenuDef = { + NULL, + sizeof (PlaybackMenu)/sizeof (menuitem_t), + NULL, + PlaybackMenu, + M_DrawPlaybackMenu, + BASEVIDWIDTH/2 - 100, 2, + 0, + NULL +}; + menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); @@ -2639,8 +2694,6 @@ boolean M_Responder(event_t *ev) } } } - else if (ev->type == ev_keydown) // Preserve event for other responders - ch = ev->data1; if (ch == -1) return false; @@ -2786,6 +2839,19 @@ boolean M_Responder(event_t *ev) routine = M_ChangeCvar; } + if (currentMenu == &PlaybackMenuDef) + { + // Flip left/right with up/down for the playback menu, since it's a horizontal icon row. + switch (ch) + { + case KEY_LEFTARROW: ch = KEY_UPARROW; break; + case KEY_UPARROW: ch = KEY_RIGHTARROW; break; + case KEY_RIGHTARROW: ch = KEY_DOWNARROW; break; + case KEY_DOWNARROW: ch = KEY_LEFTARROW; break; + default: break; + } + } + // Keys usable within menu switch (ch) { @@ -2944,7 +3010,7 @@ void M_Drawer(void) if (menuactive) { // now that's more readable with a faded background (yeah like Quake...) - if (!WipeInAction) + if (!WipeInAction && currentMenu != &PlaybackMenuDef) // Replay playback has its own background V_DrawFadeScreen(0xFF00, 16); if (currentMenu->drawroutine) @@ -3007,7 +3073,11 @@ void M_StartControlPanel(void) menuactive = true; - if (!Playing()) + if (demo.playback) + { + currentMenu = &PlaybackMenuDef; + } + else if (!Playing()) { // Secret menu! //MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); @@ -5656,6 +5726,123 @@ static void M_HutStartReplay(INT32 choice) G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath); } +static void M_DrawPlaybackMenu(void) +{ + INT16 i; + patch_t *icon; + UINT8 *activemap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GOLD, GTC_MENUCACHE); + + // Toggle items + if (paused) + { + PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = IT_DISABLED; + PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = IT_CALL|IT_STRING; + } + else + { + PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = IT_CALL|IT_STRING; + PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = IT_DISABLED; + } + for (i = 0; i <= splitscreen; i++) + PlaybackMenu[playback_view1+i].status = IT_ARROWS|IT_STRING; + for (i = splitscreen+1; i < 4; i++) + PlaybackMenu[playback_view1+i].status = IT_DISABLED; + + // wip + //M_DrawTextBox(currentMenu->x-68, currentMenu->y-7, 15, 15); + //M_DrawCenteredMenu(); + + for (i = 0; i < currentMenu->numitems; i++) + { + UINT8 *inactivemap = NULL; + + if (i >= playback_view1 && i <= playback_view4) + { + if (splitscreen >= i - playback_view1) + { + INT32 ply = *G_GetDisplayplayerPtr(i - playback_view1 + 1); + + icon = facerankprefix[players[ply].skin]; + if (i != itemOn) + inactivemap = R_GetTranslationColormap(players[ply].skin, players[ply].skincolor, GTC_MENUCACHE); + } + else if (currentMenu->menuitems[i].patch && W_GetNumForName(currentMenu->menuitems[i].patch) != LUMPERROR) + icon = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); + else + icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp + } + else if (currentMenu->menuitems[i].status == IT_DISABLED) + continue; + else if (currentMenu->menuitems[i].patch && W_GetNumForName(currentMenu->menuitems[i].patch) != LUMPERROR) + icon = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); + else + icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp + + if (i == playback_fastforward && cv_playbackspeed.value > 1) + V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SILVER, GTC_MENUCACHE)); + else + V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, (i == itemOn) ? activemap : inactivemap); + + if (i == itemOn) + V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); + } +} + +static void M_PlaybackPause(INT32 choice) +{ + (void)choice; + + paused = !paused; + + if (paused) + { + itemOn = playback_resume; + S_PauseAudio(); + } + else + { + itemOn = playback_pause; + S_ResumeAudio(); + } + + CV_SetValue(&cv_playbackspeed, 1); +} + +static void M_PlaybackFastForward(INT32 choice) +{ + (void)choice; + + CV_SetValue(&cv_playbackspeed, cv_playbackspeed.value == 1 ? 4 : 1); +} + +static void M_PlaybackAdvance(INT32 choice) +{ + (void)choice; + + paused = false; + TryRunTics(1); + paused = true; +} + + +static void M_PlaybackSetViews(INT32 choice) +{ + if (choice > 0) + { + if (splitscreen < 3) + G_AdjustView(splitscreen + 2, 0, true); + } + else if (splitscreen) + { + splitscreen--; + R_ExecuteSetViewSize(); + } +} + +static void M_PlaybackAdjustView(INT32 choice) +{ + G_AdjustView(itemOn - playback_viewcount, (choice > 0) ? 1 : -1, true); +} static void M_PandorasBox(INT32 choice) { From ce7577eb3a93c3644a333a4643052b115d5ff5d8 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 6 Apr 2019 02:17:30 -0500 Subject: [PATCH 145/186] Reference graphics for menu and other stuff --- src/m_menu.c | 62 +++++++++++++++++----------------------------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 96e4075d9..730eba0df 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -567,23 +567,22 @@ static menuitem_t MISC_ReplayOptionsMenu[] = static menuitem_t PlaybackMenu[] = { - {IT_CALL | IT_STRING, NULL, "Hide Menu", M_SelectableClearMenus, 0}, + {IT_CALL | IT_STRING, "M_PHIDE", "Hide Menu", M_SelectableClearMenus, 0}, - {IT_CALL | IT_STRING, NULL, "Rewind", M_SelectableClearMenus, 24}, - {IT_CALL | IT_STRING, NULL, "Pause", M_PlaybackPause, 40}, - {IT_CALL | IT_STRING, NULL, "Resume", M_PlaybackPause, 40}, - {IT_CALL | IT_STRING, NULL, "Fast-Foward", M_PlaybackFastForward, 56}, - {IT_CALL | IT_STRING, NULL, "Advance Frame", M_PlaybackAdvance, 56}, + {IT_CALL | IT_STRING, "M_PREW", "Rewind", M_SelectableClearMenus, 24}, + {IT_CALL | IT_STRING, "M_PPAUSE", "Pause", M_PlaybackPause, 40}, + {IT_CALL | IT_STRING, "M_PRESUM", "Resume", M_PlaybackPause, 40}, + {IT_CALL | IT_STRING, "M_PFFWD", "Fast-Foward", M_PlaybackFastForward, 56}, + {IT_CALL | IT_STRING, "M_PFADV", "Advance Frame", M_PlaybackAdvance, 56}, - {IT_ARROWS | IT_STRING, NULL, "View Count", M_PlaybackSetViews, 80}, - {IT_ARROWS | IT_STRING, NULL, "Viewpoint", M_PlaybackAdjustView, 96}, - {IT_ARROWS | IT_STRING, NULL, "Viewpoint 2", M_PlaybackAdjustView, 112}, - {IT_ARROWS | IT_STRING, NULL, "Viewpoint 3", M_PlaybackAdjustView, 128}, - {IT_ARROWS | IT_STRING, NULL, "Viewpoint 4", M_PlaybackAdjustView, 144}, + {IT_ARROWS | IT_STRING, "M_PVIEWS", "View Count", M_PlaybackSetViews, 80}, + {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint", M_PlaybackAdjustView, 96}, + {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 2", M_PlaybackAdjustView, 112}, + {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 3", M_PlaybackAdjustView, 128}, + {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 4", M_PlaybackAdjustView, 144}, - - {IT_CALL | IT_STRING, NULL, "More Options...", M_ReplayHut, 168}, - {IT_CALL | IT_STRING, NULL, "Stop Playback", M_ReplayHut, 184}, + {IT_CALL | IT_STRING, "M_POPTS", "More Options...", M_ReplayHut, 168}, + {IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_ReplayHut, 184}, }; typedef enum { @@ -1673,7 +1672,7 @@ menu_t MISC_ReplayHutDef = menu_t MISC_ReplayOptionsDef = { - NULL, + "M_REPOPT", sizeof (MISC_ReplayOptionsMenu)/sizeof (menuitem_t), &MISC_ReplayHutDef, MISC_ReplayOptionsMenu, @@ -5346,7 +5345,7 @@ static void DrawReplayHutReplayInfo(void) if (lumpnum != LUMPERROR) patch = W_CachePatchNum(lumpnum, PU_CACHE); else - patch = W_CachePatchName("BLANKLVL", PU_CACHE); + patch = W_CachePatchName("M_NOLVL", PU_CACHE); if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) V_DrawSmallScaledPatch(x, y, 0, patch); @@ -5416,7 +5415,7 @@ static void DrawReplayHutReplayInfo(void) } else { - patch = W_CachePatchName("MISSINGW", PU_CACHE); + patch = W_CachePatchName("M_NOWANT", PU_CACHE); colormap = R_GetTranslationColormap( TC_RAINBOW, demolist[dir_on[menudepthleft]].standings[0].color, @@ -5514,7 +5513,7 @@ static void M_DrawReplayHut(void) if (demolist[i].type == MD_SUBDIR) { localx += 8; - V_DrawFixedPatch((x - 4)<width), y+20, 0, patch, colormap); -*/ // Character face! if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[i].skin].facerank) != LUMPERROR) { @@ -5624,7 +5602,7 @@ static void M_DrawReplayStartMenu(void) } else { - patch = W_CachePatchName("MISSINGR", PU_CACHE); + patch = W_CachePatchName("M_NORANK", PU_CACHE); colormap = R_GetTranslationColormap( TC_RAINBOW, demolist[dir_on[menudepthleft]].standings[i].color, @@ -5766,14 +5744,14 @@ static void M_DrawPlaybackMenu(void) if (i != itemOn) inactivemap = R_GetTranslationColormap(players[ply].skin, players[ply].skincolor, GTC_MENUCACHE); } - else if (currentMenu->menuitems[i].patch && W_GetNumForName(currentMenu->menuitems[i].patch) != LUMPERROR) + else if (currentMenu->menuitems[i].patch && W_CheckNumForName(currentMenu->menuitems[i].patch) != LUMPERROR) icon = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); else icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp } else if (currentMenu->menuitems[i].status == IT_DISABLED) continue; - else if (currentMenu->menuitems[i].patch && W_GetNumForName(currentMenu->menuitems[i].patch) != LUMPERROR) + else if (currentMenu->menuitems[i].patch && W_CheckNumForName(currentMenu->menuitems[i].patch) != LUMPERROR) icon = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); else icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp From c7125c862c4abcbe4d44f4139571de237df96314 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 6 Apr 2019 11:16:19 -0500 Subject: [PATCH 146/186] Support non-green resolutions in the replay hut --- src/m_menu.c | 82 ++++++++++++++++++++++++++------------------------- src/v_video.c | 7 +++-- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 730eba0df..a9c917247 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5312,6 +5312,8 @@ static void M_HandleReplayHutList(INT32 choice) } } +#define SCALEDVIEWWIDTH (vid.width/vid.dupx) +#define SCALEDVIEWHEIGHT (vid.height/vid.dupy) static void DrawReplayHutReplayInfo(void) { lumpnum_t lumpnum; @@ -5322,18 +5324,18 @@ static void DrawReplayHutReplayInfo(void) switch (demolist[dir_on[menudepthleft]].type) { case MD_NOTLOADED: - V_DrawCenteredString(160, 40, 0, "Loading replay information..."); + V_DrawCenteredString(160, 40, V_SNAPTOTOP, "Loading replay information..."); break; case MD_INVALID: - V_DrawCenteredString(160, 40, warningflags, "This replay cannot be played."); + V_DrawCenteredString(160, 40, V_SNAPTOTOP|warningflags, "This replay cannot be played."); break; case MD_SUBDIR: break; // Can't think of anything to draw here right now case MD_OUTDATED: - V_DrawThinString(17, 64, V_ALLOWLOWERCASE|V_TRANSLUCENT|highlightflags, "Recorded on an outdated version."); + V_DrawThinString(17, 64, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT|highlightflags, "Recorded on an outdated version."); /*fallthru*/ default: // Draw level stuff @@ -5348,17 +5350,17 @@ static void DrawReplayHutReplayInfo(void) patch = W_CachePatchName("M_NOLVL", PU_CACHE); if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) - V_DrawSmallScaledPatch(x, y, 0, patch); + V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch); else { w = SHORT(patch->width); h = SHORT(patch->height); - V_DrawSmallScaledPatch(x+(w>>1), y, V_FLIP, patch); + V_DrawSmallScaledPatch(x+(w>>1), y, V_SNAPTOTOP|V_FLIP, patch); { static angle_t rubyfloattime = 0; const fixed_t rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT); - V_DrawFixedPatch((x+(w>>2))<>2))<>2))<>2))<width), y+20, 0, patch, colormap); + V_DrawMappedPatch(BASEVIDWIDTH-15 - SHORT(patch->width), y+20, V_SNAPTOTOP, patch, colormap); break; } @@ -5465,8 +5467,8 @@ static void M_DrawReplayHut(void) if (cursory > maxy - 20) cursory = maxy - 20; - if (cursory - replayhutmenuy > 150) - replayhutmenuy += (cursory-150-replayhutmenuy + 1)/2; + if (cursory - replayhutmenuy > SCALEDVIEWHEIGHT-50) + replayhutmenuy += (cursory-SCALEDVIEWHEIGHT-replayhutmenuy + 51)/2; else if (cursory - replayhutmenuy < 110) replayhutmenuy += (max(0, cursory-110)-replayhutmenuy - 1)/2; } @@ -5487,9 +5489,9 @@ static void M_DrawReplayHut(void) cursory = localy; if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) - V_DrawString(x, localy, 0, currentMenu->menuitems[i].text); + V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT, currentMenu->menuitems[i].text); else - V_DrawString(x, localy, highlightflags, currentMenu->menuitems[i].text); + V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[i].text); } y += currentMenu->menuitems[currentMenu->numitems-1].alphaKey; @@ -5501,7 +5503,7 @@ static void M_DrawReplayHut(void) if (localy < 65) continue; - if (localy >= 200) + if (localy >= SCALEDVIEWHEIGHT) break; if (demolist[i].type == MD_NOTLOADED && !processed_one_this_frame) @@ -5513,7 +5515,7 @@ static void M_DrawReplayHut(void) if (demolist[i].type == MD_SUBDIR) { localx += 8; - V_DrawScaledPatch(x - 4, localy, 0, W_CachePatchName(dirmenu[i][DIR_TYPE] == EXT_UP ? "M_RBACK" : "M_RFLDR", PU_CACHE)); + V_DrawScaledPatch(x - 4, localy, V_SNAPTOTOP|V_SNAPTOLEFT, W_CachePatchName(dirmenu[i][DIR_TYPE] == EXT_UP ? "M_RBACK" : "M_RFLDR", PU_CACHE)); } if (itemOn == replaylistitem && i == (INT16)dir_on[menudepthleft]) @@ -5524,7 +5526,7 @@ static void M_DrawReplayHut(void) replayScrollDelay--; else if (replayScrollDir > 0) { - if (replayScrollTitle < (V_StringWidth(demolist[i].title, 0) - (BASEVIDWIDTH - (x<<1)))<<1) + if (replayScrollTitle < (V_StringWidth(demolist[i].title, 0) - (SCALEDVIEWWIDTH - (x<<1)))<<1) replayScrollTitle++; else { @@ -5543,19 +5545,19 @@ static void M_DrawReplayHut(void) } } - V_DrawString(localx - (replayScrollTitle>>1), localy, highlightflags|V_ALLOWLOWERCASE, demolist[i].title); + V_DrawString(localx - (replayScrollTitle>>1), localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags|V_ALLOWLOWERCASE, demolist[i].title); } else - V_DrawString(localx, localy, V_ALLOWLOWERCASE, demolist[i].title); + V_DrawString(localx, localy, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, demolist[i].title); } // Draw the cursor - V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, + V_DrawScaledPatch(currentMenu->x - 24, cursory, V_SNAPTOTOP|V_SNAPTOLEFT, W_CachePatchName("M_CURSOR", PU_CACHE)); - V_DrawString(currentMenu->x, cursory, highlightflags, currentMenu->menuitems[itemOn].text); + V_DrawString(currentMenu->x, cursory, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[itemOn].text); // Now draw some replay info! - V_DrawFill(10, 10, 300, 60, 239); + V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|239); if (itemOn == replaylistitem) { @@ -5577,19 +5579,19 @@ static void M_DrawReplayStartMenu(void) patch_t *patch; UINT8 *colormap; - V_DrawRightAlignedString(BASEVIDWIDTH-100, STARTY + i*20, highlightflags, va("%2d", demolist[dir_on[menudepthleft]].standings[i].ranking)); - V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[i].name); + V_DrawRightAlignedString(BASEVIDWIDTH-100, STARTY + i*20, V_SNAPTOTOP|highlightflags, va("%2d", demolist[dir_on[menudepthleft]].standings[i].ranking)); + V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20, V_SNAPTOTOP|V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[i].name); if (demolist[dir_on[menudepthleft]].standings[i].timeorscore == UINT32_MAX-1) - V_DrawThinString(BASEVIDWIDTH-92, STARTY + i*20 + 9, 0, "NO CONTEST"); + V_DrawThinString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, "NO CONTEST"); else if (demolist[dir_on[menudepthleft]].gametype == GT_RACE) - V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, 0, va("%d'%02d\"%02d", + V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d'%02d\"%02d", G_TicsToMinutes(demolist[dir_on[menudepthleft]].standings[i].timeorscore, true), G_TicsToSeconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore), G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore) )); else - V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, 0, va("%d", demolist[dir_on[menudepthleft]].standings[i].timeorscore)); + V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d", demolist[dir_on[menudepthleft]].standings[i].timeorscore)); // Character face! if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[i].skin].facerank) != LUMPERROR) @@ -5609,7 +5611,7 @@ static void M_DrawReplayStartMenu(void) GTC_MENUCACHE); } - V_DrawMappedPatch(BASEVIDWIDTH-5 - SHORT(patch->width), STARTY + i*20, 0, patch, colormap); + V_DrawMappedPatch(BASEVIDWIDTH-5 - SHORT(patch->width), STARTY + i*20, V_SNAPTOTOP, patch, colormap); } #undef STARTY @@ -5618,7 +5620,7 @@ static void M_DrawReplayStartMenu(void) replayScrollDelay--; else if (replayScrollDir > 0) { - if (replayScrollTitle < (i*20 - 100)<<1) + if (replayScrollTitle < (i*20 - SCALEDVIEWHEIGHT + 100)<<1) replayScrollTitle++; else { @@ -5637,10 +5639,10 @@ static void M_DrawReplayStartMenu(void) } } - V_DrawFill(10, 10, 300, 60, 239); + V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|239); DrawReplayHutReplayInfo(); - V_DrawString(10, 72, highlightflags|V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].title); + V_DrawString(10, 72, V_SNAPTOTOP|highlightflags|V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].title); // Draw a warning prompt if needed switch (demolist[dir_on[menudepthleft]].addonstatus) @@ -5666,7 +5668,7 @@ static void M_DrawReplayStartMenu(void) return; } - V_DrawSmallString(4, BASEVIDHEIGHT-14, V_ALLOWLOWERCASE, warning); + V_DrawSmallString(4, BASEVIDHEIGHT-14, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, warning); } static boolean M_QuitReplayHut(void) diff --git a/src/v_video.c b/src/v_video.c index 1f5020dd7..29acc12b5 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1460,8 +1460,11 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) { dupx = dupy = 1; scrwidth = vid.width/vid.dupx; - left = (scrwidth - BASEVIDWIDTH)/2; - scrwidth -= left; + if (!(option & V_SNAPTOLEFT)) + { + left = (scrwidth - BASEVIDWIDTH)/2; + scrwidth -= left; + } } charflags = (option & V_CHARCOLORMASK); From 25ff05fdd0768b577018557aaf89ba94ccdffb62 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 6 Apr 2019 14:51:00 -0500 Subject: [PATCH 147/186] Add demo rewinding Preview is fairly basic, and only shows players rewinding. Full state is restored via reloading the replay and jumping to the timestamp once the rewind is done. --- src/d_main.c | 3 + src/g_game.c | 229 ++++++++++++++++++++++++++++++++++++++++++++------ src/g_game.h | 7 ++ src/m_menu.c | 40 +++++++-- src/p_setup.c | 4 +- src/p_tick.c | 11 +++ src/s_sound.c | 4 +- src/v_video.c | 9 +- 8 files changed, 266 insertions(+), 41 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index a86a4f97e..d1a820c8f 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -568,6 +568,9 @@ static void D_Display(void) V_DrawScaledPatch(viewwindowx + (BASEVIDWIDTH - SHORT(patch->width))/2, py, 0, patch); } + if (demo.rewinding) + V_DrawFadeScreen(TC_RAINBOW, (leveltime & 0x20) ? SKINCOLOR_PASTEL : SKINCOLOR_MOONSLAM); + // vid size change is now finished if it was on... vid.recalc = 0; diff --git a/src/g_game.c b/src/g_game.c index df1c82355..d3f8d7987 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5875,6 +5875,168 @@ void G_GhostTicker(void) } } +// Demo rewinding functions +typedef struct rewindinfo_s { + tic_t leveltime; + + struct { + boolean ingame; + player_t player; + mobj_t mobj; + } playerinfo[MAXPLAYERS]; + + struct rewindinfo_s *prev; +} rewindinfo_t; + +static tic_t currentrewindnum; +static rewindinfo_t *rewindhead = NULL; // Reverse chronological order + +void G_InitDemoRewind(void) +{ + while (rewindhead) + { + rewindinfo_t *p = rewindhead->prev; + Z_Free(rewindhead); + rewindhead = p; + } + + currentrewindnum = 0; +} + +void G_StoreRewindInfo(void) +{ + static UINT8 timetolog = 8; + rewindinfo_t *info; + size_t i; + + if (timetolog-- > 0) + return; + timetolog = 8; + + info = Z_Calloc(sizeof(rewindinfo_t), PU_STATIC, NULL); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + { + info->playerinfo[i].ingame = false; + continue; + } + + info->playerinfo[i].ingame = true; + memcpy(&info->playerinfo[i].player, &players[i], sizeof(player_t)); + if (players[i].mo) + memcpy(&info->playerinfo[i].mobj, players[i].mo, sizeof(mobj_t)); + } + + info->leveltime = leveltime; + info->prev = rewindhead; + rewindhead = info; +} + +void G_PreviewRewind(tic_t previewtime) +{ + size_t i, j; + fixed_t tweenvalue = 0; + rewindinfo_t *info = rewindhead, *next_info = rewindhead; + while (info->leveltime > previewtime && info->prev) + { + next_info = info; + info = info->prev; + } + if (info != next_info) + tweenvalue = FixedDiv(previewtime - info->leveltime, next_info->leveltime - info->leveltime); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + { + if (info->playerinfo[i].player.mo) + { + //@TODO spawn temp object to act as a player display + } + + continue; + } + + if (!info->playerinfo[i].ingame || !info->playerinfo[i].player.mo) + { + if (players[i].mo) + players[i].mo->flags2 |= MF2_DONTDRAW; + + continue; + } + + if (!players[i].mo) + continue; //@TODO spawn temp object to act as a player display + + players[i].mo->flags2 &= ~MF2_DONTDRAW; + + P_UnsetThingPosition(players[i].mo); +#define TWEEN(pr) info->playerinfo[i].mobj.pr + FixedMul((INT32) (next_info->playerinfo[i].mobj.pr - info->playerinfo[i].mobj.pr), tweenvalue) + players[i].mo->x = TWEEN(x); + players[i].mo->y = TWEEN(y); + players[i].mo->z = TWEEN(z); + players[i].mo->angle = TWEEN(angle); +#undef TWEEN + P_SetThingPosition(players[i].mo); + + players[i].frameangle = info->playerinfo[i].player.frameangle + FixedMul((INT32) (next_info->playerinfo[i].player.frameangle - info->playerinfo[i].player.frameangle), tweenvalue); + + players[i].mo->sprite = info->playerinfo[i].mobj.sprite; + players[i].mo->frame = info->playerinfo[i].mobj.frame; + + players[i].realtime = info->playerinfo[i].player.realtime; + for (j = 0; j < NUMKARTSTUFF; j++) + players[i].kartstuff[j] = info->playerinfo[i].player.kartstuff[j]; + } + + for (i = splitscreen+1; i > 0; i--) + P_ResetCamera(&players[(*G_GetDisplayplayerPtr(i))], P_GetCameraPtr(i)); +} + +void G_ConfirmRewind(tic_t rewindtime) +{ + tic_t i; + boolean oldmenuactive = menuactive, oldsounddisabled = sound_disabled, olddigitaldisabled = digital_disabled; + + INT32 olddp1 = displayplayer, olddp2 = secondarydisplayplayer, olddp3 = thirddisplayplayer, olddp4 = fourthdisplayplayer; + UINT8 oldss = splitscreen; + + cv_renderview.value = 0; + + menuactive = false; // Prevent loops + sound_disabled = /*digital_disabled =*/ true; // Prevent sound spam + demo.rewinding = true; // may not need later + G_DoPlayDemo(NULL); // Restart the current demo + + for (i = 0; i < rewindtime && leveltime < rewindtime; i++) + { + //TryRunTics(1); + G_Ticker((i % NEWTICRATERATIO) == 0); + } + + demo.rewinding = false; + menuactive = oldmenuactive; // Bring the menu back up + sound_disabled = oldsounddisabled; // Re-enable SFX + digital_disabled = olddigitaldisabled; + + wipegamestate = gamestate; // No fading back in! + + cv_renderview.value = 1; + + splitscreen = oldss; + displayplayer = olddp1; + secondarydisplayplayer = olddp2; + thirddisplayplayer = olddp3; + fourthdisplayplayer = olddp4; + R_ExecuteSetViewSize(); + G_ResetViews(); + + for (i = splitscreen+1; i > 0; i--) + P_ResetCamera(&players[(*G_GetDisplayplayerPtr(i))], P_GetCameraPtr(i)); +} + void G_ReadMetalTic(mobj_t *metal) { UINT8 ziptic; @@ -6842,46 +7004,57 @@ void G_DoPlayDemo(char *defdemoname) boolean spectator; UINT8 slots[MAXPLAYERS], kartspeed[MAXPLAYERS], kartweight[MAXPLAYERS], numslots = 0; + G_InitDemoRewind(); + skin[16] = '\0'; color[16] = '\0'; - n = defdemoname+strlen(defdemoname); - while (*n != '/' && *n != '\\' && n != defdemoname) - n--; - if (n != defdemoname) - n++; - pdemoname = ZZ_Alloc(strlen(n)+1); - strcpy(pdemoname,n); - - // Internal if no extension, external if one exists - if (FIL_CheckExtension(defdemoname)) + // No demo name means we're restarting the current demo + if (defdemoname == NULL) { - //FIL_DefaultExtension(defdemoname, ".lmp"); - if (!FIL_ReadFile(defdemoname, &demobuffer)) + demo_p = demobuffer; + pdemoname = ZZ_Alloc(1); // Easier than adding checks for this everywhere it's freed + } + else + { + n = defdemoname+strlen(defdemoname); + while (*n != '/' && *n != '\\' && n != defdemoname) + n--; + if (n != defdemoname) + n++; + pdemoname = ZZ_Alloc(strlen(n)+1); + strcpy(pdemoname,n); + + // Internal if no extension, external if one exists + if (FIL_CheckExtension(defdemoname)) { - snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname); + //FIL_DefaultExtension(defdemoname, ".lmp"); + if (!FIL_ReadFile(defdemoname, &demobuffer)) + { + snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + demo_p = demobuffer; + } + // load demo resource from WAD + else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); CONS_Alert(CONS_ERROR, "%s", msg); gameaction = ga_nothing; M_StartMessage(msg, NULL, MM_NOTHING); return; } - demo_p = demobuffer; - } - // load demo resource from WAD - else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) - { - snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - gameaction = ga_nothing; - M_StartMessage(msg, NULL, MM_NOTHING); - return; - } - else // it's an internal demo - { - demobuffer = demo_p = W_CacheLumpNum(l, PU_STATIC); + else // it's an internal demo + { + demobuffer = demo_p = W_CacheLumpNum(l, PU_STATIC); #if defined(SKIPERRORS) && !defined(DEVELOP) - skiperrors = true; // SRB2Kart: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... + skiperrors = true; // SRB2Kart: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... #endif + } } // read demo header diff --git a/src/g_game.h b/src/g_game.h index 42623dfac..190608099 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -43,6 +43,7 @@ struct demovars_s { char titlename[65]; boolean recording, playback, timing; boolean title; // Title Screen demo can be cancelled by any key + boolean rewinding; // Rewind in progress boolean loadfiles, ignorefiles; // Demo file loading options boolean fromtitle; // SRB2Kart: Don't stop the music @@ -234,6 +235,12 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum); void G_ConsAllGhostTics(void); void G_ConsGhostTic(INT32 playernum); void G_GhostTicker(void); + +void G_InitDemoRewind(void); +void G_StoreRewindInfo(void); +void G_PreviewRewind(tic_t previewtime); +void G_ConfirmRewind(tic_t rewindtime); + void G_ReadMetalTic(mobj_t *metal); void G_WriteMetalTic(mobj_t *metal); void G_SaveMetal(UINT8 **buffer); diff --git a/src/m_menu.c b/src/m_menu.c index a9c917247..0213847d7 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -346,6 +346,7 @@ static void M_EnterReplayOptions(INT32 choice); static void M_HutStartReplay(INT32 choice); static void M_DrawPlaybackMenu(void); +static void M_PlaybackRewind(INT32 choice); static void M_PlaybackPause(INT32 choice); static void M_PlaybackFastForward(INT32 choice); static void M_PlaybackAdvance(INT32 choice); @@ -569,11 +570,11 @@ static menuitem_t PlaybackMenu[] = { {IT_CALL | IT_STRING, "M_PHIDE", "Hide Menu", M_SelectableClearMenus, 0}, - {IT_CALL | IT_STRING, "M_PREW", "Rewind", M_SelectableClearMenus, 24}, - {IT_CALL | IT_STRING, "M_PPAUSE", "Pause", M_PlaybackPause, 40}, - {IT_CALL | IT_STRING, "M_PRESUM", "Resume", M_PlaybackPause, 40}, - {IT_CALL | IT_STRING, "M_PFFWD", "Fast-Foward", M_PlaybackFastForward, 56}, - {IT_CALL | IT_STRING, "M_PFADV", "Advance Frame", M_PlaybackAdvance, 56}, + {IT_CALL | IT_STRING, "M_PREW", "Rewind", M_PlaybackRewind, 24}, + {IT_CALL | IT_STRING, "M_PPAUSE", "Pause", M_PlaybackPause, 40}, + {IT_CALL | IT_STRING, "M_PRESUM", "Resume", M_PlaybackPause, 40}, + {IT_CALL | IT_STRING, "M_PFFWD", "Fast-Foward", M_PlaybackFastForward, 56}, + {IT_CALL | IT_STRING, "M_PFADV", "Advance Frame", M_PlaybackAdvance, 56}, {IT_ARROWS | IT_STRING, "M_PVIEWS", "View Count", M_PlaybackSetViews, 80}, {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint", M_PlaybackAdjustView, 96}, @@ -5713,7 +5714,7 @@ static void M_DrawPlaybackMenu(void) UINT8 *activemap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GOLD, GTC_MENUCACHE); // Toggle items - if (paused) + if (paused && !demo.rewinding) { PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = IT_DISABLED; PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = IT_CALL|IT_STRING; @@ -5768,13 +5769,32 @@ static void M_DrawPlaybackMenu(void) } } +static void M_PlaybackRewind(INT32 choice) +{ + (void)choice; + + if (!demo.rewinding) + demo.rewinding = paused = true; + else + G_ConfirmRewind(leveltime); + + // temp + //G_ConfirmRewind(starttime + 90*TICRATE); +} + static void M_PlaybackPause(INT32 choice) { (void)choice; paused = !paused; - if (paused) + if (demo.rewinding) + { + G_ConfirmRewind(leveltime); + paused = true; + S_PauseAudio(); + } + else if (paused) { itemOn = playback_resume; S_PauseAudio(); @@ -5792,6 +5812,12 @@ static void M_PlaybackFastForward(INT32 choice) { (void)choice; + if (demo.rewinding) + { + G_ConfirmRewind(leveltime); + paused = false; + S_ResumeAudio(); + } CV_SetValue(&cv_playbackspeed, cv_playbackspeed.value == 1 ? 4 : 1); } diff --git a/src/p_setup.c b/src/p_setup.c index f73aef99c..8c1c9ae72 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2829,7 +2829,7 @@ boolean P_SetupLevel(boolean skipprecip) // Encore mode fade to pink to white // This is handled BEFORE sounds are stopped. - if (rendermode != render_none && encoremode && !prevencoremode) + if (rendermode != render_none && encoremode && !prevencoremode && !demo.rewinding) { tic_t locstarttime, endtime, nowtime; @@ -2881,7 +2881,7 @@ boolean P_SetupLevel(boolean skipprecip) // Let's fade to white here // But only if we didn't do the encore startup wipe - if (rendermode != render_none && !ranspecialwipe) + if (rendermode != render_none && !ranspecialwipe && !demo.rewinding) { F_WipeStartScreen(); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); diff --git a/src/p_tick.c b/src/p_tick.c index 177f3b657..9b4f7a214 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -591,7 +591,15 @@ void P_Ticker(boolean run) // Check for pause or menu up in single player if (paused || P_AutoPause()) + { + if (demo.rewinding && leveltime > 0) + { + leveltime = (leveltime-1) & ~3; + G_PreviewRewind(leveltime); + } + return; + } postimgtype = postimgtype2 = postimgtype3 = postimgtype4 = postimg_none; @@ -768,6 +776,9 @@ void P_Ticker(boolean run) P_MapEnd(); + if (demo.playback) + G_StoreRewindInfo(); + // Z_CheckMemCleanup(); } diff --git a/src/s_sound.c b/src/s_sound.c index 9653d8ff6..1585753f9 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1733,7 +1733,7 @@ void S_ShowMusicCredit(void) { musicdef_t *def = musicdefstart; - if (!cv_songcredits.value) + if (!cv_songcredits.value || demo.rewinding) return; if (!def) // No definitions @@ -1920,6 +1920,7 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) #endif if (S_MusicDisabled() + || demo.rewinding // Don't mess with music while rewinding! || demo.title) // SRB2Kart: Demos don't interrupt title screen music return; @@ -1955,6 +1956,7 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) void S_StopMusic(void) { if (!I_SongPlaying() + || demo.rewinding // Don't mess with music while rewinding! || demo.title) // SRB2Kart: Demos don't interrupt title screen music return; diff --git a/src/v_video.c b/src/v_video.c index 29acc12b5..dfad4c3a4 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1234,9 +1234,12 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) #endif { - const UINT8 *fadetable = ((color & 0xFF00) // Color is not palette index? - ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. - : ((UINT8 *)transtables + ((9-strength)< 0xFFF0) // Grab a specific colormap palette? + ? R_GetTranslationColormap(color | 0xFFFF0000, strength, GTC_CACHE) + : ((color & 0xFF00) // Color is not palette index? + ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. + : ((UINT8 *)transtables + ((9-strength)< Date: Sat, 6 Apr 2019 15:36:53 -0500 Subject: [PATCH 148/186] Allow backwards frame advance while paused --- src/m_menu.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 0213847d7..915643acd 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5774,7 +5774,16 @@ static void M_PlaybackRewind(INT32 choice) (void)choice; if (!demo.rewinding) - demo.rewinding = paused = true; + { + if (paused) + { + G_ConfirmRewind(leveltime-1); + paused = true; + S_PauseAudio(); + } + else + demo.rewinding = paused = true; + } else G_ConfirmRewind(leveltime); @@ -5792,6 +5801,7 @@ static void M_PlaybackPause(INT32 choice) { G_ConfirmRewind(leveltime); paused = true; + itemOn = playback_resume; S_PauseAudio(); } else if (paused) From d9e061d999311636cc980b0c7351e959ff9d445b Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 6 Apr 2019 18:06:02 -0500 Subject: [PATCH 149/186] Various fixes and tweaks to rewinds --- src/g_game.c | 25 ++++++++++++++++++------- src/m_menu.c | 12 ++++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index d3f8d7987..701f06738 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5939,6 +5939,10 @@ void G_PreviewRewind(tic_t previewtime) size_t i, j; fixed_t tweenvalue = 0; rewindinfo_t *info = rewindhead, *next_info = rewindhead; + + if (!info) + return; + while (info->leveltime > previewtime && info->prev) { next_info = info; @@ -5947,6 +5951,7 @@ void G_PreviewRewind(tic_t previewtime) if (info != next_info) tweenvalue = FixedDiv(previewtime - info->leveltime, next_info->leveltime - info->leveltime); + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) @@ -5998,16 +6003,23 @@ void G_PreviewRewind(tic_t previewtime) void G_ConfirmRewind(tic_t rewindtime) { tic_t i; - boolean oldmenuactive = menuactive, oldsounddisabled = sound_disabled, olddigitaldisabled = digital_disabled; + boolean oldmenuactive = menuactive, oldsounddisabled = sound_disabled; INT32 olddp1 = displayplayer, olddp2 = secondarydisplayplayer, olddp3 = thirddisplayplayer, olddp4 = fourthdisplayplayer; UINT8 oldss = splitscreen; - cv_renderview.value = 0; - menuactive = false; // Prevent loops - sound_disabled = /*digital_disabled =*/ true; // Prevent sound spam - demo.rewinding = true; // may not need later + + CV_StealthSetValue(&cv_renderview, 0); + + if (rewindtime > starttime) + { + sound_disabled = true; // Prevent sound spam + demo.rewinding = true; + } + else + demo.rewinding = false; + G_DoPlayDemo(NULL); // Restart the current demo for (i = 0; i < rewindtime && leveltime < rewindtime; i++) @@ -6019,11 +6031,10 @@ void G_ConfirmRewind(tic_t rewindtime) demo.rewinding = false; menuactive = oldmenuactive; // Bring the menu back up sound_disabled = oldsounddisabled; // Re-enable SFX - digital_disabled = olddigitaldisabled; wipegamestate = gamestate; // No fading back in! - cv_renderview.value = 1; + COM_BufInsertText("renderview on\n"); splitscreen = oldss; displayplayer = olddp1; diff --git a/src/m_menu.c b/src/m_menu.c index 915643acd..c3d2397fb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5759,7 +5759,7 @@ static void M_DrawPlaybackMenu(void) else icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp - if (i == playback_fastforward && cv_playbackspeed.value > 1) + if ((i == playback_fastforward && cv_playbackspeed.value > 1) || (i == playback_rewind && demo.rewinding)) V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SILVER, GTC_MENUCACHE)); else V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, (i == itemOn) ? activemap : inactivemap); @@ -5771,6 +5771,8 @@ static void M_DrawPlaybackMenu(void) static void M_PlaybackRewind(INT32 choice) { + static tic_t lastconfirmtime; + (void)choice; if (!demo.rewinding) @@ -5784,11 +5786,13 @@ static void M_PlaybackRewind(INT32 choice) else demo.rewinding = paused = true; } - else + else if (lastconfirmtime + TICRATE/2 < I_GetTime()) + { + lastconfirmtime = I_GetTime(); G_ConfirmRewind(leveltime); + } - // temp - //G_ConfirmRewind(starttime + 90*TICRATE); + CV_SetValue(&cv_playbackspeed, 1); } static void M_PlaybackPause(INT32 choice) From 3787e9078117c1677270093f9743bab89f4439bd Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 6 Apr 2019 18:17:56 -0500 Subject: [PATCH 150/186] Fix title menu not working if you leave a replay early --- src/m_menu.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index c3d2397fb..7c82bc316 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -352,6 +352,7 @@ static void M_PlaybackFastForward(INT32 choice); static void M_PlaybackAdvance(INT32 choice); static void M_PlaybackSetViews(INT32 choice); static void M_PlaybackAdjustView(INT32 choice); +static void M_PlaybackQuit(INT32 choice); // Drawing functions static void M_DrawGenericMenu(void); @@ -583,7 +584,7 @@ static menuitem_t PlaybackMenu[] = {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 4", M_PlaybackAdjustView, 144}, {IT_CALL | IT_STRING, "M_POPTS", "More Options...", M_ReplayHut, 168}, - {IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_ReplayHut, 184}, + {IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_PlaybackQuit, 184}, }; typedef enum { @@ -5864,6 +5865,19 @@ static void M_PlaybackAdjustView(INT32 choice) G_AdjustView(itemOn - playback_viewcount, (choice > 0) ? 1 : -1, true); } +static void M_PlaybackQuit(INT32 choice) +{ + (void)choice; + G_StopDemo(); + + if (demo.inreplayhut) + M_ReplayHut(choice); + else if (modeattacking) + S_ChangeMusicInternal("racent", true); // ??? + else + D_StartTitle(); +} + static void M_PandorasBox(INT32 choice) { (void)choice; From 77c71ca94455c2e0ca9bfd14807b6fba4d678190 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 6 Apr 2019 18:59:11 -0500 Subject: [PATCH 151/186] Support playback menu for record attack replays too --- src/g_game.c | 2 ++ src/m_menu.c | 73 +++++++++++++++++++++++++++++++++------------------- src/m_menu.h | 1 + 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 701f06738..f7f0457a8 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -7036,6 +7036,8 @@ void G_DoPlayDemo(char *defdemoname) pdemoname = ZZ_Alloc(strlen(n)+1); strcpy(pdemoname,n); + M_SetPlaybackMenuPointer(); + // Internal if no extension, external if one exists if (FIL_CheckExtension(defdemoname)) { diff --git a/src/m_menu.c b/src/m_menu.c index 7c82bc316..d8d8f4a13 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -571,20 +571,20 @@ static menuitem_t PlaybackMenu[] = { {IT_CALL | IT_STRING, "M_PHIDE", "Hide Menu", M_SelectableClearMenus, 0}, - {IT_CALL | IT_STRING, "M_PREW", "Rewind", M_PlaybackRewind, 24}, - {IT_CALL | IT_STRING, "M_PPAUSE", "Pause", M_PlaybackPause, 40}, - {IT_CALL | IT_STRING, "M_PRESUM", "Resume", M_PlaybackPause, 40}, - {IT_CALL | IT_STRING, "M_PFFWD", "Fast-Foward", M_PlaybackFastForward, 56}, - {IT_CALL | IT_STRING, "M_PFADV", "Advance Frame", M_PlaybackAdvance, 56}, + {IT_CALL | IT_STRING, "M_PREW", "Rewind", M_PlaybackRewind, 20}, + {IT_CALL | IT_STRING, "M_PPAUSE", "Pause", M_PlaybackPause, 36}, + {IT_CALL | IT_STRING, "M_PRESUM", "Resume", M_PlaybackPause, 36}, + {IT_CALL | IT_STRING, "M_PFFWD", "Fast-Foward", M_PlaybackFastForward, 52}, + {IT_CALL | IT_STRING, "M_PFADV", "Advance Frame", M_PlaybackAdvance, 52}, - {IT_ARROWS | IT_STRING, "M_PVIEWS", "View Count", M_PlaybackSetViews, 80}, - {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint", M_PlaybackAdjustView, 96}, - {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 2", M_PlaybackAdjustView, 112}, - {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 3", M_PlaybackAdjustView, 128}, - {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 4", M_PlaybackAdjustView, 144}, + {IT_ARROWS | IT_STRING, "M_PVIEWS", "View Count", M_PlaybackSetViews, 72}, + {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint", M_PlaybackAdjustView, 88}, + {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 2", M_PlaybackAdjustView, 104}, + {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 3", M_PlaybackAdjustView, 120}, + {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 4", M_PlaybackAdjustView, 136}, - {IT_CALL | IT_STRING, "M_POPTS", "More Options...", M_ReplayHut, 168}, - {IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_PlaybackQuit, 184}, + {IT_CALL | IT_STRING, "M_POPTS", "More Options...", M_ReplayHut, 156}, + {IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_PlaybackQuit, 172}, }; typedef enum { @@ -1702,7 +1702,7 @@ menu_t PlaybackMenuDef = { NULL, PlaybackMenu, M_DrawPlaybackMenu, - BASEVIDWIDTH/2 - 100, 2, + BASEVIDWIDTH/2 - 94, 2, 0, NULL }; @@ -3057,14 +3057,6 @@ void M_Drawer(void) // void M_StartControlPanel(void) { - // time attack HACK - if (modeattacking && demo.playback) - { - G_CheckDemoStatus(); - S_ChangeMusicInternal("racent", true); - return; - } - // intro might call this repeatedly if (menuactive) { @@ -5708,6 +5700,11 @@ static void M_HutStartReplay(INT32 choice) G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath); } +void M_SetPlaybackMenuPointer(void) +{ + itemOn = playback_pause; +} + static void M_DrawPlaybackMenu(void) { INT16 i; @@ -5725,10 +5722,29 @@ static void M_DrawPlaybackMenu(void) PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = IT_CALL|IT_STRING; PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = IT_DISABLED; } - for (i = 0; i <= splitscreen; i++) - PlaybackMenu[playback_view1+i].status = IT_ARROWS|IT_STRING; - for (i = splitscreen+1; i < 4; i++) - PlaybackMenu[playback_view1+i].status = IT_DISABLED; + + if (modeattacking) + { + for (i = playback_viewcount; i <= playback_view4; i++) + PlaybackMenu[i].status = IT_DISABLED; + + PlaybackMenu[playback_moreoptions].alphaKey = 72; + PlaybackMenu[playback_quit].alphaKey = 88; + + currentMenu->x = BASEVIDWIDTH/2 - 52; + } + else + { + for (i = 0; i <= splitscreen; i++) + PlaybackMenu[playback_view1+i].status = IT_ARROWS|IT_STRING; + for (i = splitscreen+1; i < 4; i++) + PlaybackMenu[playback_view1+i].status = IT_DISABLED; + + PlaybackMenu[playback_moreoptions].alphaKey = 156; + PlaybackMenu[playback_quit].alphaKey = 172; + + currentMenu->x = BASEVIDWIDTH/2 - 94; + } // wip //M_DrawTextBox(currentMenu->x-68, currentMenu->y-7, 15, 15); @@ -5740,6 +5756,8 @@ static void M_DrawPlaybackMenu(void) if (i >= playback_view1 && i <= playback_view4) { + if (modeattacking) continue; + if (splitscreen >= i - playback_view1) { INT32 ply = *G_GetDisplayplayerPtr(i - playback_view1 + 1); @@ -5873,7 +5891,10 @@ static void M_PlaybackQuit(INT32 choice) if (demo.inreplayhut) M_ReplayHut(choice); else if (modeattacking) - S_ChangeMusicInternal("racent", true); // ??? + { + M_EndModeAttackRun(); + S_ChangeMusicInternal("racent", true); + } else D_StartTitle(); } diff --git a/src/m_menu.h b/src/m_menu.h index f49c6ca64..ef0381d11 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -236,6 +236,7 @@ void Screenshot_option_Onchange(void); void Addons_option_Onchange(void); void M_ReplayHut(INT32 choice); +void M_SetPlaybackMenuPointer(void); INT32 HU_GetHighlightColor(void); From fb3d5ec7f0b81dfca04847a1e657f9a66c51ef2e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 7 Apr 2019 17:59:32 -0500 Subject: [PATCH 152/186] Record demos consistently and also other stuff --- src/g_game.c | 39 ++++++++++++++++++++------------------- src/g_game.h | 1 + src/p_tick.c | 46 +++++++++++++++++++++++----------------------- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index f7f0457a8..2f4f8531f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -292,7 +292,6 @@ static UINT8 *demobuffer = NULL; static UINT8 *demo_p, *demotime_p, *demoinfo_p; static UINT8 *demoend; static UINT8 demoflags; -static UINT16 demoversion; static boolean demosynced = true; // console warning message struct demovars_s demo; @@ -315,7 +314,6 @@ static struct { // EZT_KART INT32 kartitem, kartamount, kartbumpers; - boolean kartresync; //@TODO backwards compat with old replays. remove eventually UINT8 desyncframes; // Don't try to resync unless we've been off for two frames, to monkeypatch a few trouble spots @@ -5422,11 +5420,9 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) if (ghost->player) { if ( - !modeattacking && ( //@TODO: This is a temporary check to keep netreplays EXE record attack replays compatible with base Kart. - ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] || - ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] || - ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper] - ) + ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] || + ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] || + ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper] ) { ghostext[playernum].flags |= EZT_KART; @@ -5621,7 +5617,6 @@ void G_ConsGhostTic(INT32 playernum) ghostext[playernum].kartitem = READINT32(demo_p); ghostext[playernum].kartamount = READINT32(demo_p); ghostext[playernum].kartbumpers = READINT32(demo_p); - ghostext[playernum].kartresync = true; } } @@ -5651,6 +5646,9 @@ void G_ConsGhostTic(INT32 playernum) P_SetThingPosition(testmo); testmo->z = oldghost[playernum].z; + if (abs(testmo->z - testmo->floorz) < 4*FRACUNIT) + testmo->z = testmo->floorz; // Sync players to the ground when they're likely supposed to be there... + ghostext[playernum].desyncframes = 2; } } @@ -5658,10 +5656,14 @@ void G_ConsGhostTic(INT32 playernum) ghostext[playernum].desyncframes = 0; if ( - ghostext[playernum].kartresync && ( - players[playernum].kartstuff[k_itemtype] != ghostext[playernum].kartitem || - players[playernum].kartstuff[k_itemamount] != ghostext[playernum].kartamount || - players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers) +#ifdef DEMO_COMPAT_100 + demo.version != 0x0001 && +#endif + ( + players[playernum].kartstuff[k_itemtype] != ghostext[playernum].kartitem || + players[playernum].kartstuff[k_itemamount] != ghostext[playernum].kartamount || + players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers + ) ) { if (demosynced) @@ -7088,19 +7090,17 @@ void G_DoPlayDemo(char *defdemoname) version = READUINT8(demo_p); subversion = READUINT8(demo_p); - demoversion = READUINT16(demo_p); - switch(demoversion) + demo.version = READUINT16(demo_p); + switch(demo.version) { case DEMOVERSION: // latest always supported // demo title M_Memcpy(demo.titlename, demo_p, 64); - CONS_Printf("Demo title: %s\n", demo.titlename); demo_p += 64; break; #ifdef DEMO_COMPAT_100 case 0x0001: - CONS_Printf("You need to implement demo compat here, doofus! %s:%d\n", __FILE__, __LINE__); break; #endif // too old, cannot support. @@ -7132,7 +7132,7 @@ void G_DoPlayDemo(char *defdemoname) demoflags = READUINT8(demo_p); #ifdef DEMO_COMPAT_100 - if (demoversion == 0x0001) + if (demo.version == 0x0001) { if (demoflags & DF_MULTIPLAYER) { @@ -7237,12 +7237,13 @@ void G_DoPlayDemo(char *defdemoname) // Random seed randseed = READUINT32(demo_p); #ifdef DEMO_COMPAT_100 - if (demoversion != 0x0001) + if (demo.version != 0x0001) #endif demo_p += 4; // Extrainfo location #ifdef DEMO_COMPAT_100 - if (demoversion == 0x0001) { + if (demo.version == 0x0001) + { // Player name M_Memcpy(player_names[0],demo_p,16); demo_p += 16; diff --git a/src/g_game.h b/src/g_game.h index 190608099..148a5e52b 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -42,6 +42,7 @@ extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality; struct demovars_s { char titlename[65]; boolean recording, playback, timing; + UINT16 version; // Current file format of the demo being played boolean title; // Title Screen demo can be cancelled by any key boolean rewinding; // Rewind in progress diff --git a/src/p_tick.c b/src/p_tick.c index 9b4f7a214..a5f6313b3 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -609,26 +609,29 @@ void P_Ticker(boolean run) { if (demo.recording) { - if (!multiplayer) { - G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); - } else { - G_WriteDemoExtraData(); - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - G_WriteDemoTiccmd(&players[i].cmd, i); - } + G_WriteDemoExtraData(); + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + G_WriteDemoTiccmd(&players[i].cmd, i); } if (demo.playback) { - if (!multiplayer) { +#ifdef DEMO_COMPAT_100 + if (demo.version == 0x0001) + { G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); - } else { + } + else + { +#endif G_ReadDemoExtraData(); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) G_ReadDemoTiccmd(&players[i].cmd, i); +#ifdef DEMO_COMPAT_100 } +#endif } for (i = 0; i < MAXPLAYERS; i++) @@ -734,27 +737,24 @@ void P_Ticker(boolean run) if (metalrecording) G_WriteMetalTic(players[consoleplayer].mo); - if (multiplayer) + if (demo.recording) { - if (demo.recording) - { - G_WriteAllGhostTics(); + G_WriteAllGhostTics(); + if (cv_recordmultiplayerdemos.value && (demo.savemode == DSM_NOTSAVING || demo.savemode == DSM_WILLAUTOSAVE)) if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime && InputDown(gc_lookback, 1)) demo.savemode = DSM_TITLEENTRY; - } - if (demo.playback) // Use Ghost data for consistency checks. - { - G_ConsAllGhostTics(); - } } - else + else if (demo.playback) // Use Ghost data for consistency checks. { - if (demo.recording) - G_WriteGhostTic(players[consoleplayer].mo, consoleplayer); - if (demo.playback) // Use Ghost data for consistency checks. +#ifdef DEMO_COMPAT_100 + if (demo.version == 0x0001) G_ConsGhostTic(0); + else +#endif + G_ConsAllGhostTics(); } + if (modeattacking) G_GhostTicker(); From bea8f51253c466b8e78208d3890d114e4a3bec99 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 7 Apr 2019 18:51:42 -0500 Subject: [PATCH 153/186] Fix record attack not recording + staff names load for all replay types --- src/g_game.c | 73 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 2f4f8531f..2bf89a9e4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3890,7 +3890,7 @@ void G_AfterIntermission(void) return; } - else if (demo.recording && demo.savemode != DSM_NOTSAVING) + else if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING)) G_SaveDemo(); if (modeattacking) // End the run. @@ -4037,7 +4037,7 @@ static void G_DoContinued(void) // when something new is added. void G_EndGame(void) { - if (demo.recording && demo.savemode != DSM_NOTSAVING) + if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING)) G_SaveDemo(); // Only do evaluation and credits in coop games. @@ -7411,7 +7411,6 @@ void G_DoPlayDemo(char *defdemoname) } slots[numslots] = p; numslots++; - if (modeattacking && numslots > 1) { snprintf(msg, 1024, M_GetText("%s is a record attack replay with multiple players, and is thus invalid.\n"), pdemoname); @@ -7752,53 +7751,62 @@ void G_UpdateStaffGhostName(lumpnum_t l) UINT16 ghostversion; UINT8 flags; - UINT8 totalfiles; - UINT8 md5sum[16]; - buffer = p = W_CacheLumpNum(l, PU_CACHE); // read demo header if (memcmp(p, DEMOHEADER, 12)) { goto fail; - } p += 12; // DEMOHEADER + } + + p += 12; // DEMOHEADER p++; // VERSION p++; // SUBVERSION + ghostversion = READUINT16(p); switch(ghostversion) { case DEMOVERSION: // latest always supported p += 64; // full demo title break; + #ifdef DEMO_COMPAT_100 case 0x0001: - CONS_Printf("You need to implement demo compat here, doofus! %s:%d\n", __FILE__, __LINE__); + break; #endif + // too old, cannot support. default: goto fail; } + p += 16; // demo checksum + if (memcmp(p, "PLAY", 4)) { goto fail; - } p += 4; // "PLAY" + } + + p += 4; // "PLAY" p += 2; // gamemap p += 16; // mapmd5 (possibly check for consistency?) + flags = READUINT8(p); - if (flags & DF_FILELIST) // file list - { - totalfiles = READUINT8(p); - for (; totalfiles > 0; --totalfiles) - { - SKIPSTRING(p) - READMEM(p, md5sum, 16) - } - } if (!(flags & DF_GHOST)) { goto fail; // we don't NEED to do it here, but whatever } + +#ifdef DEMO_COMPAT_100 + if (ghostversion != 0x0001) +#endif + p++; // Gametype + +#ifdef DEMO_COMPAT_100 + if (ghostversion != 0x0001) +#endif + G_SkipDemoExtraFiles(&p); + switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 @@ -7812,9 +7820,34 @@ void G_UpdateStaffGhostName(lumpnum_t l) default: // 3 break; } + p += 4; // random seed - // Player name + +#ifdef DEMO_COMPAT_100 + if (ghostversion == 0x0001) + { + // Player name + M_Memcpy(dummystaffname, p,16); + dummystaffname[16] = '\0'; + goto fail; // Not really a failure but whatever + } +#endif + + p += 4; // Extrainfo location marker + + // Ehhhh don't need ghostversion here (?) so I'll reuse the var here + ghostversion = READUINT16(p); + while (ghostversion--) + { + p += 2; + SKIPSTRING(p); + p++; // stealth + } + + // Assert first player is in and then read name + if (READUINT8(p) != 0) + goto fail; M_Memcpy(dummystaffname, p,16); dummystaffname[16] = '\0'; @@ -8044,7 +8077,7 @@ boolean G_CheckDemoStatus(void) return true; } - if (demo.recording && demo.savemode != DSM_NOTSAVING) + if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING)) { G_SaveDemo(); return true; From 73153b7db9372d607ff80a39074b34a7215c2b3e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 8 Apr 2019 00:30:04 -0500 Subject: [PATCH 154/186] Support new-format ghosts or some bullshit like that maybe future fickle will add support for multiple ghosts from one replay for some sick memery but idgaf right now --- src/g_game.c | 202 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 164 insertions(+), 38 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 2bf89a9e4..6233fb99a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4889,7 +4889,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) } // Finds a skin with the closest stats if the expected skin doesn't exist. -static void FindClosestSkinForStats(UINT32 p, UINT8 kartspeed, UINT8 kartweight) +static INT32 GetSkinNumClosestToStats(UINT8 kartspeed, UINT8 kartweight) { INT32 i, closest_skin = 0; UINT8 closest_stats = UINT8_MAX, stat_diff; @@ -4904,6 +4904,13 @@ static void FindClosestSkinForStats(UINT32 p, UINT8 kartspeed, UINT8 kartweight) } } + return closest_skin; +} + +static void FindClosestSkinForStats(UINT32 p, UINT8 kartspeed, UINT8 kartweight) +{ + INT32 closest_skin = GetSkinNumClosestToStats(kartspeed, kartweight); + CONS_Printf("Using %s instead...\n", skins[closest_skin].name); SetPlayerSkinByNum(p, closest_skin); } @@ -5691,6 +5698,38 @@ void G_GhostTicker(void) { // Skip normal demo data. UINT8 ziptic = READUINT8(g->p); + +#ifdef DEMO_COMPAT_100 + if (g->version != 0x0001) + { +#endif + while (ziptic != DW_END) // Get rid of extradata stuff + { + if (ziptic == 0) // Only support player 0 info for now + { + ziptic = READUINT8(g->p); + if (ziptic & DXD_SKIN) + g->p += 18; // We _could_ read this info, but it shouldn't change anything in record attack... + if (ziptic & DXD_COLOR) + g->p += 16; // Same tbh + if (ziptic & DXD_NAME) + g->p += 16; // yea + if (ziptic & DXD_PLAYSTATE && READUINT8(g->p) != DXD_PST_PLAYING) + I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this + } + else if (ziptic == DW_RNG) + g->p += 4; // RNG seed + else + I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this + + ziptic = READUINT8(g->p); + } + + ziptic = READUINT8(g->p); // Back to actual ziptic stuff +#ifdef DEMO_COMPAT_100 + } +#endif + if (ziptic & ZT_FWD) g->p++; if (ziptic & ZT_SIDE) @@ -5708,6 +5747,19 @@ void G_GhostTicker(void) // Grab ghost data. ziptic = READUINT8(g->p); + +#ifdef DEMO_COMPAT_100 + if (g->version != 0x0001) + { +#endif + if (ziptic == 0xFF) + goto skippedghosttic; // Didn't write ghost info this frame + else if (ziptic != 0) + I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this + ziptic = READUINT8(g->p); +#ifdef DEMO_COMPAT_100 + } +#endif if (ziptic & GZT_XYZ) { g->oldmo.x = READFIXED(g->p); @@ -5848,6 +5900,17 @@ void G_GhostTicker(void) g->p += 12; // kartitem, kartamount, kartbumpers } +#ifdef DEMO_COMPAT_100 + if (g->version != 0x0001) + { +#endif + if (READUINT8(g->p) != 0xFF) // Make sure there isn't other ghost data here. + I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this +#ifdef DEMO_COMPAT_100 + } +#endif + +skippedghosttic: // Tick ghost colors (Super and Mario Invincibility flashing) switch(g->color) { @@ -7514,6 +7577,7 @@ void G_AddGhost(char *defdemoname) mapthing_t *mthing; UINT16 count, ghostversion; skin_t *ghskin = &skins[0]; + UINT8 kartspeed = UINT8_MAX, kartweight = UINT8_MAX; name[16] = '\0'; skin[16] = '\0'; @@ -7556,17 +7620,21 @@ void G_AddGhost(char *defdemoname) Z_Free(pdemoname); Z_Free(buffer); return; - } p += 12; // DEMOHEADER + } + + p += 12; // DEMOHEADER p++; // VERSION p++; // SUBVERSION + ghostversion = READUINT16(p); switch(ghostversion) { case DEMOVERSION: // latest always supported + p += 64; // title break; #ifdef DEMO_COMPAT_100 case 0x0001: - I_Error("You need to implement demo compat here, doofus! %s:%d", __FILE__, __LINE__); + break; #endif // too old, cannot support. default: @@ -7575,6 +7643,7 @@ void G_AddGhost(char *defdemoname) Z_Free(buffer); return; } + M_Memcpy(md5, p, 16); p += 16; // demo checksum for (gh = ghosts; gh; gh = gh->next) if (!memcmp(md5, gh->checksum, 16)) // another ghost in the game already has this checksum? @@ -7584,20 +7653,21 @@ void G_AddGhost(char *defdemoname) Z_Free(buffer); return; } + if (memcmp(p, "PLAY", 4)) { CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), pdemoname); Z_Free(pdemoname); Z_Free(buffer); return; - } p += 4; // "PLAY" + } + + p += 4; // "PLAY" p += 2; // gamemap p += 16; // mapmd5 (possibly check for consistency?) + flags = READUINT8(p); - if (flags & DF_FILELIST) - { - G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts. - } + if (!(flags & DF_GHOST)) { CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), pdemoname); @@ -7605,6 +7675,16 @@ void G_AddGhost(char *defdemoname) Z_Free(buffer); return; } + +#ifdef DEMO_COMPAT_100 + if (ghostversion != 0x0001) +#endif + p++; // gametype + +#ifdef DEMO_COMPAT_100 + if (ghostversion != 0x0001) +#endif + G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts. switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 @@ -7621,34 +7701,41 @@ void G_AddGhost(char *defdemoname) p += 4; // random seed - // Player name (TODO: Display this somehow if it doesn't match cv_playername!) - M_Memcpy(name, p,16); - p += 16; +#ifdef DEMO_COMPAT_100 + if (ghostversion == 0x0001) + { + // Player name (TODO: Display this somehow if it doesn't match cv_playername!) + M_Memcpy(name, p,16); + p += 16; - // Skin - M_Memcpy(skin, p,16); - p += 16; + // Skin + M_Memcpy(skin, p,16); + p += 16; - // Color - M_Memcpy(color, p,16); - p += 16; + // Color + M_Memcpy(color, p,16); + p += 16; - // Ghosts do not have a player structure to put this in. - p++; // charability - p++; // charability2 - p++; // actionspd - p++; // mindash - p++; // maxdash - // SRB2kart - p++; // kartspeed - p++; // kartweight - // - p++; // normalspeed - p++; // runspeed - p++; // thrustfactor - p++; // accelstart - p++; // acceleration - p += 4; // jumpfactor + // Ghosts do not have a player structure to put this in. + p++; // charability + p++; // charability2 + p++; // actionspd + p++; // mindash + p++; // maxdash + // SRB2kart + p++; // kartspeed + p++; // kartweight + // + p++; // normalspeed + p++; // runspeed + p++; // thrustfactor + p++; // accelstart + p++; // acceleration + p += 4; // jumpfactor + } + else +#endif + p += 4; // Extra data location reference // net var data count = READUINT16(p); @@ -7667,6 +7754,46 @@ void G_AddGhost(char *defdemoname) return; } +#ifdef DEMO_COMPAT_100 + if (ghostversion != 0x0001) + { +#endif + if (READUINT8(p) != 0) + { + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + + // Player name (TODO: Display this somehow if it doesn't match cv_playername!) + M_Memcpy(name, p, 16); + p += 16; + + // Skin + M_Memcpy(skin, p, 16); + p += 16; + + // Color + M_Memcpy(color, p, 16); + p += 16; + + p += 4; // score + + kartspeed = READUINT8(p); + kartweight = READUINT8(p); + + if (READUINT8(p) != 0xFF) + { + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } +#ifdef DEMO_COMPAT_100 + } +#endif + for (i = 0; i < numskins; i++) if (!stricmp(skins[i].name,skin)) { @@ -7676,11 +7803,10 @@ void G_AddGhost(char *defdemoname) if (i == numskins) { - //@TODO nah this should fallback - CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid character.\n"), pdemoname); - Z_Free(pdemoname); - Z_Free(buffer); - return; + if (kartspeed != UINT8_MAX && kartweight != UINT8_MAX) + ghskin = &skins[GetSkinNumClosestToStats(kartspeed, kartweight)]; + + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Invalid character. Falling back to %s.\n"), pdemoname, ghskin->name); } gh = Z_Calloc(sizeof(demoghost), PU_LEVEL, NULL); From f573e4089d2ca318a4f1a50d86bae07ba06a8db2 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 8 Apr 2019 00:45:19 -0500 Subject: [PATCH 155/186] Support RA time comparisons in new format I don't care enough about supporting old replays, and they're old anyway. Force-overwrite them. :) --- src/g_game.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 6233fb99a..6284ea663 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6772,10 +6772,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 2; // gamemap p += 16; // map md5 flags = READUINT8(p); // demoflags - if (flags & DF_FILELIST) // file list - { - G_SkipDemoExtraFiles(&p); - } + p++; // gametype + G_SkipDemoExtraFiles(&p); aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK); I_Assert(aflags); @@ -6820,7 +6818,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) break; #ifdef DEMO_COMPAT_100 case 0x0001: - I_Error("You need to implement demo compat here, doofus! %s:%d", __FILE__, __LINE__); + // Old replays gotta go :] + CONS_Alert(CONS_NOTICE, M_GetText("File '%s' outdated version. It will be overwritten. Nyeheheh.\n"), oldname); + Z_Free(buffer); + return UINT8_MAX; #endif // too old, cannot support. default: @@ -6838,10 +6839,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 2; // gamemap p += 16; // mapmd5 flags = READUINT8(p); - if (flags & DF_FILELIST) // file list - { - G_SkipDemoExtraFiles(&p); - } + p++; // gametype + G_SkipDemoExtraFiles(&p); if (!(flags & aflags)) { CONS_Alert(CONS_NOTICE, M_GetText("File '%s' not from same game mode. It will be overwritten.\n"), oldname); From 25f55b63515c33f273c5f30ee4e3faa468a69e4f Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 8 Apr 2019 23:21:11 -0500 Subject: [PATCH 156/186] Add VHS pause/rewind effect --- src/d_main.c | 6 +++++ src/d_netcmd.c | 2 ++ src/screen.c | 4 ++++ src/screen.h | 2 +- src/v_video.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/v_video.h | 3 +++ 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index d1a820c8f..6feedb18e 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -571,6 +571,9 @@ static void D_Display(void) if (demo.rewinding) V_DrawFadeScreen(TC_RAINBOW, (leveltime & 0x20) ? SKINCOLOR_PASTEL : SKINCOLOR_MOONSLAM); + if (cv_vhseffect.value && (paused || (demo.playback && cv_playbackspeed.value > 1))) + V_DrawVhsEffect(demo.rewinding); + // vid size change is now finished if it was on... vid.recalc = 0; @@ -628,6 +631,9 @@ static void D_Display(void) V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-10, V_YELLOWMAP, s); } + if (cv_shittyscreen.value) + V_DrawVhsEffect(cv_shittyscreen.value == 2); + I_FinishUpdate(); // page flip or blit buffer } } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 21a8e2a36..36774a80f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -932,6 +932,8 @@ void D_RegisterClientCommands(void) // screen.c CV_RegisterVar(&cv_fullscreen); CV_RegisterVar(&cv_renderview); + CV_RegisterVar(&cv_vhseffect); + CV_RegisterVar(&cv_shittyscreen); CV_RegisterVar(&cv_scr_depth); CV_RegisterVar(&cv_scr_width); CV_RegisterVar(&cv_scr_height); diff --git a/src/screen.c b/src/screen.c index 4de2abd05..4cb8bac5d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -59,6 +59,8 @@ INT32 setmodeneeded; //video mode change needed if > 0 (the mode number to set + static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, {24, "24 bits"}, {32, "32 bits"}, {0, NULL}}; +static CV_PossibleValue_t shittyscreen_cons_t[] = {{0, "Okay"}, {1, "Shitty"}, {2, "Extra Shitty"}, {0, NULL}}; + //added : 03-02-98: default screen mode, as loaded/saved in config #ifdef WII consvar_t cv_scr_width = {"scr_width", "640", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -70,6 +72,8 @@ consvar_t cv_scr_height = {"scr_height", "800", CV_SAVE, CV_Unsigned, NULL, 0, N consvar_t cv_scr_depth = {"scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_vhseffect = {"vhspause", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_shittyscreen = {"televisionsignal", "Okay", CV_NOSHOWHELP, shittyscreen_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static void SCR_ChangeFullscreen (void); diff --git a/src/screen.h b/src/screen.h index 5b4a8e583..2e4d29b95 100644 --- a/src/screen.h +++ b/src/screen.h @@ -158,7 +158,7 @@ extern INT32 setmodeneeded; // mode number to set if needed, or 0 extern INT32 scr_bpp; extern UINT8 *scr_borderpatch; // patch used to fill the view borders -extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_fullscreen; +extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_fullscreen, cv_vhseffect, cv_shittyscreen; // wait for page flipping to end or not extern consvar_t cv_vidwait; diff --git a/src/v_video.c b/src/v_video.c index dfad4c3a4..16d784f44 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1214,6 +1214,65 @@ void V_DrawPatchFill(patch_t *pat) } } +void V_DrawVhsEffect(boolean rewind) +{ + static fixed_t upbary = 100, downbary = 150; + + UINT8 *buf = screens[0], *tmp = screens[4]; + UINT16 x, y; + UINT32 pos = 0; + + UINT8 *normalmapstart = ((UINT8 *)transtables + (8<>1; + + if (rewind) + V_DrawVhsEffect(false); // experimentation + + upbary -= vid.dupy * (rewind ? 3 : 1.8f); + downbary += vid.dupy * (rewind ? 2 : 1); + if (upbary < -barsize) upbary = vid.height; + if (downbary > vid.height) downbary = -barsize; + + for (y = 0; y < vid.height; y++) + { + randommask = 0x0700; + thismapstart = normalmapstart; + offs = 0; + + if (y >= upbary && y < upbary+barsize) + { + //randommask = 0x0300; + thismapstart -= (2<= downbary && y < downbary+barsize) + { + //randommask = 0x0300; + //thismapstart = barmapstart; + thismapstart -= (2< 0) offs = 0; + + for (x = 0; x < vid.rowbytes; x++, pos++) + tmp[pos] = thismapstart[/*(M_RandomFixed()&randommask)|*/buf[pos+offs]]; + } + (void)randommask; + + memcpy(buf, tmp, vid.rowbytes*vid.height); +} + // // Fade all the screen buffer, so that the menu is more readable, // especially now that we use the small hufont in the menus... diff --git a/src/v_video.h b/src/v_video.h index c48c7a118..c8485c179 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -153,6 +153,9 @@ void V_DrawDiag(INT32 x, INT32 y, INT32 wh, INT32 c); // fill a box with a flat as a pattern void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum); +// draw wobbly VHS pause stuff +void V_DrawVhsEffect(boolean rewind); + // fade down the screen buffer before drawing the menu over void V_DrawFadeScreen(UINT16 color, UINT8 strength); From b98639e8520067bd64daa71added876ee129f9fb Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 9 Apr 2019 01:09:13 -0500 Subject: [PATCH 157/186] Potentially apply VHS distortion semi-transparently? Pros: fuckin SMOOTH effect especially for 256-color sw Cons: might lose the intended color distortion, maybe not a great idea for FPS Conclusion: put it behind an ifdef for now --- src/v_video.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index 16d784f44..646e60159 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1223,7 +1223,9 @@ void V_DrawVhsEffect(boolean rewind) UINT32 pos = 0; UINT8 *normalmapstart = ((UINT8 *)transtables + (8<= upbary && y < upbary+barsize) { - //randommask = 0x0300; thismapstart -= (2<= downbary && y < downbary+barsize) { - //randommask = 0x0300; - //thismapstart = barmapstart; thismapstart -= (2< 0) offs = 0; for (x = 0; x < vid.rowbytes; x++, pos++) - tmp[pos] = thismapstart[/*(M_RandomFixed()&randommask)|*/buf[pos+offs]]; + { + tmp[pos] = thismapstart[buf[pos+offs]]; +#ifdef HQ_VHS + tmp[pos] = tmapstart[buf[pos]<<8 | tmp[pos]]; +#endif + } } - (void)randommask; memcpy(buf, tmp, vid.rowbytes*vid.height); } From 5535f8936f3db29d3545a57a08bd096e6d716c0e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 9 Apr 2019 01:18:10 -0500 Subject: [PATCH 158/186] Unused var --- src/v_video.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index 646e60159..83bfff730 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1227,7 +1227,6 @@ void V_DrawVhsEffect(boolean rewind) UINT8 *tmapstart = ((UINT8 *)transtables + (6< Date: Tue, 9 Apr 2019 19:34:34 +0100 Subject: [PATCH 159/186] Turn the INT8's into SINT8's --- src/m_menu.c | 2 +- src/v_video.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index d8d8f4a13..c74614267 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5126,7 +5126,7 @@ menudemo_t *demolist; #define DF_ENCORE 0x40 static INT16 replayScrollTitle = 0; -static INT8 replayScrollDelay = TICRATE, replayScrollDir = 1; +static SINT8 replayScrollDelay = TICRATE, replayScrollDir = 1; static void PrepReplayList(void) { diff --git a/src/v_video.c b/src/v_video.c index 83bfff730..2d8ca8120 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1227,7 +1227,7 @@ void V_DrawVhsEffect(boolean rewind) UINT8 *tmapstart = ((UINT8 *)transtables + (6< Date: Tue, 9 Apr 2019 20:15:35 +0100 Subject: [PATCH 160/186] Z_Free not free. --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 6284ea663..37aa4a5e6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -7048,7 +7048,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) } // I think that's everything we need? - free(infobuffer); + Z_Free(infobuffer); } // From c4ee58cfab4b61ac0c87b9136903c1f05e703aee Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 9 Apr 2019 23:00:39 -0500 Subject: [PATCH 161/186] Only calculate vfx every other row to try to improve performance --- src/v_video.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index 83bfff730..59522cb38 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1219,8 +1219,8 @@ void V_DrawVhsEffect(boolean rewind) static fixed_t upbary = 100, downbary = 150; UINT8 *buf = screens[0], *tmp = screens[4]; - UINT16 x, y; - UINT32 pos = 0; + UINT16 y; + UINT32 x, pos = 0; UINT8 *normalmapstart = ((UINT8 *)transtables + (8< vid.height) downbary = -barsize; - for (y = 0; y < vid.height; y++) + for (y = 0; y < vid.height; y+=2) { thismapstart = normalmapstart; offs = 0; @@ -1260,9 +1260,9 @@ void V_DrawVhsEffect(boolean rewind) // lazy way to avoid crashes if (y == 0 && offs < 0) offs = 0; - else if (y == vid.height-1 && offs > 0) offs = 0; + else if (y >= vid.height-2 && offs > 0) offs = 0; - for (x = 0; x < vid.rowbytes; x++, pos++) + for (x = pos+vid.rowbytes*2; pos < x; pos++) { tmp[pos] = thismapstart[buf[pos+offs]]; #ifdef HQ_VHS From 273db8f5c18b2bb0eabad406e2df64c211b56788 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 9 Apr 2019 23:55:25 -0500 Subject: [PATCH 162/186] Fix thrown items desyncing during frame advance --- src/g_game.c | 10 +++++++--- src/p_tick.c | 11 +++++++++++ src/p_user.c | 13 +++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 37aa4a5e6..0dd24ecb2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2407,6 +2407,7 @@ void G_Ticker(boolean run) buf = gametic % BACKUPTICS; + if (!demo.playback) // read/write demo and check turbo cheat for (i = 0; i < MAXPLAYERS; i++) { @@ -2414,15 +2415,18 @@ void G_Ticker(boolean run) if (playeringame[i]) { + //@TODO all this throwdir stuff shouldn't be here! But it stays for now to maintain 1.0.4 compat... + // Remove for 1.1! + // SRB2kart // Save the dir the player is holding // to allow items to be thrown forward or backward. if (cmd->buttons & BT_FORWARD) - players[i].kartstuff[k_throwdir] = 1; + players[i].kartstuff[k_throwdir] = 1; else if (cmd->buttons & BT_BACKWARD) - players[i].kartstuff[k_throwdir] = -1; + players[i].kartstuff[k_throwdir] = -1; else - players[i].kartstuff[k_throwdir] = 0; + players[i].kartstuff[k_throwdir] = 0; G_CopyTiccmd(cmd, &netcmds[buf][i], 1); diff --git a/src/p_tick.c b/src/p_tick.c index a5f6313b3..038d00a2a 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -628,7 +628,18 @@ void P_Ticker(boolean run) G_ReadDemoExtraData(); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) + { + //@TODO all this throwdir stuff shouldn't be here! But it's added to maintain 1.0.4 compat for now... + // Remove for 1.1! + if (players[i].cmd.buttons & BT_FORWARD) + players[i].kartstuff[k_throwdir] = 1; + else if (players[i].cmd.buttons & BT_BACKWARD) + players[i].kartstuff[k_throwdir] = -1; + else + players[i].kartstuff[k_throwdir] = 0; + G_ReadDemoTiccmd(&players[i].cmd, i); + } #ifdef DEMO_COMPAT_100 } #endif diff --git a/src/p_user.c b/src/p_user.c index 509cc4d76..26ee9f8c4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8779,6 +8779,19 @@ void P_PlayerThink(player_t *player) cmd = &player->cmd; + //@TODO This fixes a one-tic latency on direction handling, AND makes behavior consistent while paused, but is not BC with 1.0.4. Do this for 1.1! +#if 0 + // SRB2kart + // Save the dir the player is holding + // to allow items to be thrown forward or backward. + if (cmd->buttons & BT_FORWARD) + player->kartstuff[k_throwdir] = 1; + else if (cmd->buttons & BT_BACKWARD) + player->kartstuff[k_throwdir] = -1; + else + player->kartstuff[k_throwdir] = 0; +#endif + // Add some extra randomization. if (cmd->forwardmove) P_RandomFixed(); From 65e272f89287ff94fb3805edcb31da8c08786dde Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 10 Apr 2019 09:10:09 -0500 Subject: [PATCH 163/186] Proposal: VHS effect over the replay hut background? --- src/m_menu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/m_menu.c b/src/m_menu.c index c74614267..7a4ea6786 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5435,6 +5435,9 @@ static void M_DrawReplayHut(void) V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + if (cv_vhseffect.value) + V_DrawVhsEffect(false); + // Draw menu choices x = currentMenu->x; y = currentMenu->y; From 1ba5412bfedc0a91e652751ca4359f4141bfab4e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 13 Apr 2019 14:22:48 -0500 Subject: [PATCH 164/186] Fix being able to carry rewind state where it shouldn't be --- src/g_game.c | 9 ++++++++- src/m_menu.c | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 0dd24ecb2..539392136 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1956,7 +1956,14 @@ boolean G_Responder(event_t *ev) ) { paused = !paused; - if (paused) + + if (demo.rewinding) + { + G_ConfirmRewind(leveltime); + paused = true; + S_PauseAudio(); + } + else if (paused) S_PauseAudio(); else S_ResumeAudio(); diff --git a/src/m_menu.c b/src/m_menu.c index 7a4ea6786..cbbff403b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5184,6 +5184,8 @@ void M_ReplayHut(INT32 choice) M_SetupNextMenu(&MISC_ReplayHutDef); G_SetGamestate(GS_TIMEATTACK); + demo.rewinding = false; + S_ChangeMusicInternal("replst", true); } From 830b608a1573bba75d864dcb3c7fb682a5657453 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 13 Apr 2019 14:42:15 -0500 Subject: [PATCH 165/186] Playback menu improvements --- src/m_menu.c | 70 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index cbbff403b..970630a50 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -573,8 +573,9 @@ static menuitem_t PlaybackMenu[] = {IT_CALL | IT_STRING, "M_PREW", "Rewind", M_PlaybackRewind, 20}, {IT_CALL | IT_STRING, "M_PPAUSE", "Pause", M_PlaybackPause, 36}, - {IT_CALL | IT_STRING, "M_PRESUM", "Resume", M_PlaybackPause, 36}, {IT_CALL | IT_STRING, "M_PFFWD", "Fast-Foward", M_PlaybackFastForward, 52}, + {IT_CALL | IT_STRING, "M_PSTEPB", "Backup Frame", M_PlaybackRewind, 20}, + {IT_CALL | IT_STRING, "M_PRESUM", "Resume", M_PlaybackPause, 36}, {IT_CALL | IT_STRING, "M_PFADV", "Advance Frame", M_PlaybackAdvance, 52}, {IT_ARROWS | IT_STRING, "M_PVIEWS", "View Count", M_PlaybackSetViews, 72}, @@ -591,8 +592,9 @@ typedef enum playback_hide, playback_rewind, playback_pause, - playback_resume, playback_fastforward, + playback_backframe, + playback_resume, playback_advanceframe, playback_viewcount, playback_view1, @@ -5719,13 +5721,19 @@ static void M_DrawPlaybackMenu(void) // Toggle items if (paused && !demo.rewinding) { - PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = IT_DISABLED; - PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = IT_CALL|IT_STRING; + PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = PlaybackMenu[playback_rewind].status = IT_DISABLED; + PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = PlaybackMenu[playback_backframe].status = IT_CALL|IT_STRING; + + if (itemOn >= playback_rewind && itemOn <= playback_fastforward) + itemOn += playback_backframe - playback_rewind; } else { - PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = IT_CALL|IT_STRING; - PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = IT_DISABLED; + PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = PlaybackMenu[playback_rewind].status = IT_CALL|IT_STRING; + PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = PlaybackMenu[playback_backframe].status = IT_DISABLED; + + if (itemOn >= playback_backframe && itemOn <= playback_advanceframe) + itemOn -= playback_backframe - playback_rewind; } if (modeattacking) @@ -5789,7 +5797,50 @@ static void M_DrawPlaybackMenu(void) V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, (i == itemOn) ? activemap : inactivemap); if (i == itemOn) + { V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); + + if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS) + { + char *str; + + if (!(i == playback_viewcount && splitscreen == 3)) + V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 28 - (skullAnimCounter/5), + '\x1A' | highlightflags, false); // up arrow + + if (!(i == playback_viewcount && splitscreen == 0)) + V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 48 + (skullAnimCounter/5), + '\x1B' | highlightflags, false); // down arrow + + switch (i) + { + case playback_viewcount: + str = va("%d", splitscreen+1); + break; + + case playback_view1: + str = player_names[displayplayer]; + break; + + case playback_view2: + str = player_names[secondarydisplayplayer]; + break; + + case playback_view3: + str = player_names[thirddisplayplayer]; + break; + + case playback_view4: + str = player_names[fourthdisplayplayer]; + break; + + default: // shouldn't ever be reached but whatever + continue; + } + + V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 38, V_ALLOWLOWERCASE|highlightflags, str); + } + } } } @@ -5829,19 +5880,12 @@ static void M_PlaybackPause(INT32 choice) { G_ConfirmRewind(leveltime); paused = true; - itemOn = playback_resume; S_PauseAudio(); } else if (paused) - { - itemOn = playback_resume; S_PauseAudio(); - } else - { - itemOn = playback_pause; S_ResumeAudio(); - } CV_SetValue(&cv_playbackspeed, 1); } From 5e703807eb543536cfc52e53c4eb353d998441f6 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 13 Apr 2019 15:23:23 -0500 Subject: [PATCH 166/186] Change color of active playback items --- src/m_menu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 970630a50..484c653cb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5792,12 +5792,15 @@ static void M_DrawPlaybackMenu(void) icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp if ((i == playback_fastforward && cv_playbackspeed.value > 1) || (i == playback_rewind && demo.rewinding)) - V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SILVER, GTC_MENUCACHE)); + V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JAWZ, GTC_MENUCACHE)); else V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, (i == itemOn) ? activemap : inactivemap); if (i == itemOn) { + V_DrawCharacter(currentMenu->x + currentMenu->menuitems[i].alphaKey + 4, currentMenu->y + 14, + '\x1A' | highlightflags, false); + V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS) From 5b1c3efb863fdb9f52188cc3ad416207d1d9c4db Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 13 Apr 2019 15:23:31 -0500 Subject: [PATCH 167/186] Temporarily disable Extra Options menu --- src/m_menu.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 484c653cb..c6a93bc41 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -584,8 +584,9 @@ static menuitem_t PlaybackMenu[] = {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 3", M_PlaybackAdjustView, 120}, {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 4", M_PlaybackAdjustView, 136}, - {IT_CALL | IT_STRING, "M_POPTS", "More Options...", M_ReplayHut, 156}, - {IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_PlaybackQuit, 172}, + //{IT_CALL | IT_STRING, "M_POPTS", "More Options...", M_ReplayHut, 156}, + //{IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_PlaybackQuit, 172}, + {IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_PlaybackQuit, 156}, }; typedef enum { @@ -601,7 +602,7 @@ typedef enum playback_view2, playback_view3, playback_view4, - playback_moreoptions, + //playback_moreoptions, playback_quit } playback_e; @@ -1704,7 +1705,8 @@ menu_t PlaybackMenuDef = { NULL, PlaybackMenu, M_DrawPlaybackMenu, - BASEVIDWIDTH/2 - 94, 2, + //BASEVIDWIDTH/2 - 94, 2, + BASEVIDWIDTH/2 - 88, 2, 0, NULL }; @@ -5741,10 +5743,12 @@ static void M_DrawPlaybackMenu(void) for (i = playback_viewcount; i <= playback_view4; i++) PlaybackMenu[i].status = IT_DISABLED; - PlaybackMenu[playback_moreoptions].alphaKey = 72; - PlaybackMenu[playback_quit].alphaKey = 88; + //PlaybackMenu[playback_moreoptions].alphaKey = 72; + //PlaybackMenu[playback_quit].alphaKey = 88; + PlaybackMenu[playback_quit].alphaKey = 72; - currentMenu->x = BASEVIDWIDTH/2 - 52; + //currentMenu->x = BASEVIDWIDTH/2 - 52; + currentMenu->x = BASEVIDWIDTH/2 - 44; } else { @@ -5753,10 +5757,12 @@ static void M_DrawPlaybackMenu(void) for (i = splitscreen+1; i < 4; i++) PlaybackMenu[playback_view1+i].status = IT_DISABLED; - PlaybackMenu[playback_moreoptions].alphaKey = 156; - PlaybackMenu[playback_quit].alphaKey = 172; + //PlaybackMenu[playback_moreoptions].alphaKey = 156; + //PlaybackMenu[playback_quit].alphaKey = 172; + PlaybackMenu[playback_quit].alphaKey = 156; - currentMenu->x = BASEVIDWIDTH/2 - 94; + //currentMenu->x = BASEVIDWIDTH/2 - 94; + currentMenu->x = BASEVIDWIDTH/2 - 88; } // wip From 7c75397b6755af418338c165325578a0ef9aa1e8 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 14 Apr 2019 17:08:04 -0500 Subject: [PATCH 168/186] Fix writing corrupt standings that break replay hut --- src/g_game.c | 3 +++ src/y_inter.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 539392136..85077c7bf 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -7056,6 +7056,9 @@ void G_LoadDemoInfo(menudemo_t *pdemo) pdemo->standings[count].timeorscore = READUINT32(extrainfo_p); count++; + + if (count >= MAXPLAYERS) + break; //@TODO still cycle through the rest of these if extra demo data is ever used } // I think that's everything we need? diff --git a/src/y_inter.c b/src/y_inter.c index 4fce58cc2..f37084282 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -304,7 +304,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) players[i].score += data.match.increase[i]; } - if (demo.recording) + if (demo.recording && !rankingsmode) G_WriteStanding( data.match.pos[data.match.numplayers], data.match.name[data.match.numplayers], From 7911558ebac4d111ed6a3a727e8edcb53c685ee9 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 14 Apr 2019 23:17:12 -0500 Subject: [PATCH 169/186] Add scroll bar to replay hut --- src/m_menu.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index c6a93bc41..6d9ccaf15 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5497,7 +5497,7 @@ static void M_DrawReplayHut(void) V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[i].text); } - y += currentMenu->menuitems[currentMenu->numitems-1].alphaKey; + y += currentMenu->menuitems[replaylistitem].alphaKey; for (i = 0; i < (INT16)sizedirmenu; i++) { @@ -5554,6 +5554,14 @@ static void M_DrawReplayHut(void) V_DrawString(localx, localy, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, demolist[i].title); } + // Draw scrollbar + y = sizedirmenu*10 + currentMenu->menuitems[replaylistitem].alphaKey + 30; + if (y > SCALEDVIEWHEIGHT-80) + { + V_DrawFill(BASEVIDWIDTH-4, 75, 4, SCALEDVIEWHEIGHT-80, V_SNAPTOTOP|V_SNAPTORIGHT|239); + V_DrawFill(BASEVIDWIDTH-3, 76 + (SCALEDVIEWHEIGHT-80) * replayhutmenuy / y, 2, (((SCALEDVIEWHEIGHT-80) * (SCALEDVIEWHEIGHT-80))-1) / y - 1, V_SNAPTOTOP|V_SNAPTORIGHT|229); + } + // Draw the cursor V_DrawScaledPatch(currentMenu->x - 24, cursory, V_SNAPTOTOP|V_SNAPTOLEFT, W_CachePatchName("M_CURSOR", PU_CACHE)); From a6879cca69bf56f6a67b618405e9375345103945 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 14 Apr 2019 23:22:24 -0500 Subject: [PATCH 170/186] Keep playback menu bar on the top in non-green reses --- src/m_menu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 6d9ccaf15..4eb184462 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5806,16 +5806,16 @@ static void M_DrawPlaybackMenu(void) icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp if ((i == playback_fastforward && cv_playbackspeed.value > 1) || (i == playback_rewind && demo.rewinding)) - V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JAWZ, GTC_MENUCACHE)); + V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, V_SNAPTOTOP, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JAWZ, GTC_MENUCACHE)); else - V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, 0, icon, (i == itemOn) ? activemap : inactivemap); + V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, V_SNAPTOTOP, icon, (i == itemOn) ? activemap : inactivemap); if (i == itemOn) { V_DrawCharacter(currentMenu->x + currentMenu->menuitems[i].alphaKey + 4, currentMenu->y + 14, - '\x1A' | highlightflags, false); + '\x1A' | V_SNAPTOTOP|highlightflags, false); - V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); + V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, V_SNAPTOTOP|V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS) { @@ -5823,11 +5823,11 @@ static void M_DrawPlaybackMenu(void) if (!(i == playback_viewcount && splitscreen == 3)) V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 28 - (skullAnimCounter/5), - '\x1A' | highlightflags, false); // up arrow + '\x1A' | V_SNAPTOTOP|highlightflags, false); // up arrow if (!(i == playback_viewcount && splitscreen == 0)) V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 48 + (skullAnimCounter/5), - '\x1B' | highlightflags, false); // down arrow + '\x1B' | V_SNAPTOTOP|highlightflags, false); // down arrow switch (i) { @@ -5855,7 +5855,7 @@ static void M_DrawPlaybackMenu(void) continue; } - V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 38, V_ALLOWLOWERCASE|highlightflags, str); + V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 38, V_SNAPTOTOP|V_ALLOWLOWERCASE|highlightflags, str); } } } From fcc188ec0b184529d97abe8efdf0e5b7c6071eaa Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 14 Apr 2019 23:52:03 -0500 Subject: [PATCH 171/186] Show player names on the bottom in 4p Also adjust margins to better match other HUD stuff --- src/st_stuff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index acb01fb69..bbfa4c047 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1919,13 +1919,13 @@ static void ST_overlayDrawer(void) { char name[MAXPLAYERNAME+12]; - INT32 y = (stplyr == &players[displayplayer]) ? 8 : BASEVIDHEIGHT/2-16; + INT32 y = (stplyr == &players[displayplayer]) ? 4 : BASEVIDHEIGHT/2-12; sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]); V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name); } else if (splitscreen) { - V_DrawCenteredThinString(BASEVIDWIDTH/4, 4, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP), player_names[stplyr-players]); + V_DrawCenteredThinString((vid.width/vid.dupx)/4, BASEVIDHEIGHT/2 - 12, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT), player_names[stplyr-players]); } } From 089be795a21af12d9466658fbe046f96f728159f Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 18 Apr 2019 03:08:11 -0400 Subject: [PATCH 172/186] Huge splitscreen refactor Did not get to finish all refactoring or even compile this, I'll continue later --- src/d_clisrv.c | 36 ++-- src/d_main.c | 154 ++++++---------- src/d_netcmd.c | 160 ++++++++-------- src/dehacked.c | 2 +- src/doomstat.h | 15 +- src/g_game.c | 297 ++++++++++++------------------ src/g_game.h | 8 +- src/hu_stuff.c | 20 +- src/k_kart.c | 160 +++++++--------- src/lua_consolelib.c | 4 +- src/lua_hudlib.c | 14 +- src/lua_mobjlib.c | 14 +- src/lua_playerlib.c | 14 +- src/m_menu.c | 25 +-- src/m_misc.c | 10 +- src/p_enemy.c | 10 +- src/p_floor.c | 16 +- src/p_inter.c | 52 +++--- src/p_local.h | 4 +- src/p_map.c | 79 ++++---- src/p_maputl.c | 16 +- src/p_mobj.c | 186 ++++++++----------- src/p_polyobj.c | 14 +- src/p_saveg.c | 14 +- src/p_setup.c | 51 +++--- src/p_spec.c | 99 +++++----- src/p_telept.c | 69 +++---- src/p_tick.c | 21 +-- src/p_user.c | 428 ++++++++++++++++++++++--------------------- src/r_bsp.c | 33 ++-- src/r_bsp.h | 2 +- src/r_main.c | 197 ++++++++++---------- src/r_plane.c | 8 +- src/r_state.h | 3 +- src/r_things.c | 8 +- src/r_things.h | 2 +- src/s_sound.c | 175 +++++++++--------- src/st_stuff.c | 54 +++--- src/y_inter.c | 21 +-- 39 files changed, 1144 insertions(+), 1351 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d8ce0f963..b79d2ba0b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2369,7 +2369,7 @@ static void CL_ConnectToServer(boolean viams) #endif DEBFILE(va("Synchronisation Finished\n")); - displayplayer = consoleplayer; + displayplayers[0] = consoleplayer; } #ifndef NONET @@ -2717,8 +2717,8 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) RemoveAdminPlayer(playernum); // don't stay admin after you're gone } - if (playernum == displayplayer && !demo.playback) - displayplayer = consoleplayer; // don't look through someone's view who isn't there + if (playernum == displayplayers[0] && !demo.playback) + displayplayers[0] = consoleplayer; // don't look through someone's view who isn't there #ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[playernum]); @@ -3448,6 +3448,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) { INT16 node, newplayernum; UINT8 splitscreenplayer = 0; + UINT8 i; if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -3481,34 +3482,19 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (node == mynode) { playernode[newplayernum] = 0; // for information only + if (splitscreenplayer) { - if (splitscreenplayer == 1) - { - secondarydisplayplayer = newplayernum; - DEBFILE("spawning my brother\n"); - if (botingame) - players[newplayernum].bot = 1; - // Same goes for player 2 when relevant - } - else if (splitscreenplayer == 2) - { - thirddisplayplayer = newplayernum; - DEBFILE("spawning my sister\n"); - } - else if (splitscreenplayer == 3) - { - fourthdisplayplayer = newplayernum; - DEBFILE("spawning my trusty pet dog\n"); - } + displayplayers[splitscreenplayer] = newplayernum; + DEBFILE(va("spawning one of my sister number %d\n", splitscreenplayer)); + if (splitscreenplayer == 1 && botingame) + players[newplayernum].bot = 1; } else { consoleplayer = newplayernum; - displayplayer = newplayernum; - secondarydisplayplayer = newplayernum; - thirddisplayplayer = newplayernum; - fourthdisplayplayer = newplayernum; + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + displayplayers[i] = newplayernum; DEBFILE("spawning me\n"); } D_SendPlayerConfig(); diff --git a/src/d_main.c b/src/d_main.c index 6feedb18e..b3ae0adea 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -118,14 +118,8 @@ boolean devparm = false; // started game with -devparm boolean singletics = false; // timedemo boolean lastdraw = false; -postimg_t postimgtype = postimg_none; -INT32 postimgparam; -postimg_t postimgtype2 = postimg_none; -INT32 postimgparam2; -postimg_t postimgtype3 = postimg_none; -INT32 postimgparam3; -postimg_t postimgtype4 = postimg_none; -INT32 postimgparam4; +postimg_t postimgtype[MAXSPLITSCREENPLAYERS]; +INT32 postimgparam[MAXSPLITSCREENPLAYERS]; // These variables are only true if // whether the respective sound system is disabled @@ -280,6 +274,7 @@ static void D_Display(void) boolean forcerefresh = false; static boolean wipe = false; INT32 wipedefindex = 0; + UINT8 i; if (dedicated) return; @@ -428,109 +423,75 @@ static void D_Display(void) // draw the view directly if (cv_renderview.value && !automapactive) { - if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) + for (i = 0; i <= splitscreen; i++) { - viewwindowy = 0; - viewwindowx = 0; - - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; - objectsdrawn = 0; -#ifdef HWRENDER - if (rendermode != render_soft) - HWR_RenderPlayerView(0, &players[displayplayer]); - else -#endif - if (rendermode != render_none) - R_RenderPlayerView(&players[displayplayer]); - } - - // render the second screen - if (splitscreen && players[secondarydisplayplayer].mo) - { -#ifdef HWRENDER - if (rendermode != render_soft) - HWR_RenderPlayerView(1, &players[secondarydisplayplayer]); - else -#endif - if (rendermode != render_none) + if (players[displayplayers[i]].mo || players[displayplayers[i]].playerstate == PST_DEAD) { - if (splitscreen > 1) + if (i == 0) // Initialize for P1 { - viewwindowx = viewwidth; viewwindowy = 0; - } - else - { viewwindowx = 0; - viewwindowy = viewheight; + + topleft = screens[0] + viewwindowy*vid.width + viewwindowx; + objectsdrawn = 0; } - M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0])); - - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; - - R_RenderPlayerView(&players[secondarydisplayplayer]); - - viewwindowy = 0; - M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); - } - } - - // render the third screen - if (splitscreen > 1 && players[thirddisplayplayer].mo) - { #ifdef HWRENDER - if (rendermode != render_soft) - HWR_RenderPlayerView(2, &players[thirddisplayplayer]); - else + if (rendermode != render_soft) + HWR_RenderPlayerView(i, &players[displayplayers[i]]); + else #endif - if (rendermode != render_none) - { - viewwindowx = 0; - viewwindowy = viewheight; - M_Memcpy(ylookup, ylookup3, viewheight*sizeof (ylookup[0])); + if (rendermode != render_none) + { + if (i > 0) // Splitscreen-specific + { + switch (i) + { + case 1: + if (splitscreen > 1) + { + viewwindowx = viewwidth; + viewwindowy = 0; + } + else + { + viewwindowx = 0; + viewwindowy = viewheight; + } + M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0])); + break; + case 2: + viewwindowx = 0; + viewwindowy = viewheight; + M_Memcpy(ylookup, ylookup3, viewheight*sizeof (ylookup[0])); + break; + case 3: + viewwindowx = viewwidth; + viewwindowy = viewheight; + M_Memcpy(ylookup, ylookup4, viewheight*sizeof (ylookup[0])); + default: + break; + } - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; + + topleft = screens[0] + viewwindowy*vid.width + viewwindowx; + } - R_RenderPlayerView(&players[thirddisplayplayer]); + R_RenderPlayerView(&players[displayplayers[i]]); - viewwindowy = 0; - M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); - } - } - - if (splitscreen > 2 && players[fourthdisplayplayer].mo) // render the fourth screen - { -#ifdef HWRENDER - if (rendermode != render_soft) - HWR_RenderPlayerView(3, &players[fourthdisplayplayer]); - else -#endif - if (rendermode != render_none) - { - viewwindowx = viewwidth; - viewwindowy = viewheight; - M_Memcpy(ylookup, ylookup4, viewheight*sizeof (ylookup[0])); - - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; - - R_RenderPlayerView(&players[fourthdisplayplayer]); - - viewwindowy = 0; - M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); + if (i > 0) + M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); + } } } if (rendermode == render_soft) { - if (postimgtype) - V_DoPostProcessor(0, postimgtype, postimgparam); - if (postimgtype2) - V_DoPostProcessor(1, postimgtype2, postimgparam2); - if (postimgtype3) - V_DoPostProcessor(2, postimgtype3, postimgparam3); - if (postimgtype4) - V_DoPostProcessor(3, postimgtype4, postimgparam4); + for (i = 0; i <= splitscreen; i++) + { + if (postimgtype[i]) + V_DoPostProcessor(i, postimgtype[i], postimgparam[i]); + } } } @@ -750,7 +711,7 @@ void D_SRB2Loop(void) M_DoScreenShot(); } - // consoleplayer -> displayplayer (hear sounds from viewpoint) + // consoleplayer -> displayplayers (hear sounds from viewpoint) S_UpdateSounds(); // move positional sounds // check for media change, loop music.. @@ -829,7 +790,8 @@ void D_StartTitle(void) maptol = 0; gameaction = ga_nothing; - displayplayer = consoleplayer = 0; + memset(displayplayers, 0, sizeof(displayplayers)); + consoleplayer = 0; //demosequence = -1; gametype = GT_RACE; // SRB2kart paused = false; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 36774a80f..76f72dd94 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1145,11 +1145,11 @@ static void CleanupPlayerName(INT32 playernum, const char *newname) // spaces may have been removed if (playernum == consoleplayer) CV_StealthSet(&cv_playername, tmpname); - else if (playernum == secondarydisplayplayer || (!netgame && playernum == 1)) + else if (playernum == displayplayers[1] || (!netgame && playernum == 1)) CV_StealthSet(&cv_playername2, tmpname); - else if (playernum == thirddisplayplayer || (!netgame && playernum == 2)) + else if (playernum == displayplayers[2] || (!netgame && playernum == 2)) CV_StealthSet(&cv_playername3, tmpname); - else if (playernum == fourthdisplayplayer || (!netgame && playernum == 3)) + else if (playernum == displayplayers[3] || (!netgame && playernum == 3)) CV_StealthSet(&cv_playername4, tmpname); else I_Assert(((void)"CleanupPlayerName used on non-local player", 0)); @@ -1257,11 +1257,11 @@ static void ForceAllSkins(INT32 forcedskin) { if (i == consoleplayer) CV_StealthSet(&cv_skin, skins[forcedskin].name); - else if (i == secondarydisplayplayer) + else if (i == displayplayers[1]) CV_StealthSet(&cv_skin2, skins[forcedskin].name); - else if (i == thirddisplayplayer) + else if (i == displayplayers[2]) CV_StealthSet(&cv_skin3, skins[forcedskin].name); - else if (i == fourthdisplayplayer) + else if (i == displayplayers[3]) CV_StealthSet(&cv_skin4, skins[forcedskin].name); } } @@ -1396,8 +1396,8 @@ static void SendNameAndColor2(void) if (splitscreen < 1 && !botingame) return; // can happen if skin2/color2/name2 changed - if (secondarydisplayplayer != consoleplayer) - secondplaya = secondarydisplayplayer; + if (displayplayers[1] != consoleplayer) + secondplaya = displayplayers[1]; else if (!netgame) // HACK secondplaya = 1; @@ -1446,7 +1446,7 @@ static void SendNameAndColor2(void) CleanupPlayerName(secondplaya, cv_playername2.zstring); strcpy(player_names[secondplaya], cv_playername2.zstring); - // don't use secondarydisplayplayer: the second player must be 1 + // don't use displayplayers[1]: the second player must be 1 players[secondplaya].skincolor = cv_playercolor2.value; if (players[secondplaya].mo) players[secondplaya].mo->color = players[secondplaya].skincolor; @@ -1485,14 +1485,14 @@ static void SendNameAndColor2(void) snac2pending++; // Don't change name if muted - if (cv_mute.value && !(server || IsPlayerAdmin(secondarydisplayplayer))) - CV_StealthSet(&cv_playername2, player_names[secondarydisplayplayer]); + if (cv_mute.value && !(server || IsPlayerAdmin(displayplayers[1]))) + CV_StealthSet(&cv_playername2, player_names[displayplayers[1]]); else // Cleanup name if changing it - CleanupPlayerName(secondarydisplayplayer, cv_playername2.zstring); + CleanupPlayerName(displayplayers[1], cv_playername2.zstring); // Don't change skin if the server doesn't want you to. - if (!CanChangeSkin(secondarydisplayplayer)) - CV_StealthSet(&cv_skin2, skins[players[secondarydisplayplayer].skin].name); + if (!CanChangeSkin(displayplayers[1])) + CV_StealthSet(&cv_skin2, skins[players[displayplayers[1]].skin].name); // check if player has the skin loaded (cv_skin2 may have // the name of a skin that was available in the previous game) @@ -1519,8 +1519,8 @@ static void SendNameAndColor3(void) if (splitscreen < 2) return; // can happen if skin3/color3/name3 changed - if (thirddisplayplayer != consoleplayer) - thirdplaya = thirddisplayplayer; + if (displayplayers[2] != consoleplayer) + thirdplaya = displayplayers[2]; else if (!netgame) // HACK thirdplaya = 2; @@ -1561,7 +1561,7 @@ static void SendNameAndColor3(void) CleanupPlayerName(thirdplaya, cv_playername3.zstring); strcpy(player_names[thirdplaya], cv_playername3.zstring); - // don't use thirddisplayplayer: the third player must be 2 + // don't use displayplayers[2]: the third player must be 2 players[thirdplaya].skincolor = cv_playercolor3.value; if (players[thirdplaya].mo) players[thirdplaya].mo->color = players[thirdplaya].skincolor; @@ -1600,14 +1600,14 @@ static void SendNameAndColor3(void) snac3pending++; // Don't change name if muted - if (cv_mute.value && !(server || IsPlayerAdmin(thirddisplayplayer))) - CV_StealthSet(&cv_playername3, player_names[thirddisplayplayer]); + if (cv_mute.value && !(server || IsPlayerAdmin(displayplayers[2]))) + CV_StealthSet(&cv_playername3, player_names[displayplayers[2]]); else // Cleanup name if changing it - CleanupPlayerName(thirddisplayplayer, cv_playername3.zstring); + CleanupPlayerName(displayplayers[2], cv_playername3.zstring); // Don't change skin if the server doesn't want you to. - if (!CanChangeSkin(thirddisplayplayer)) - CV_StealthSet(&cv_skin3, skins[players[thirddisplayplayer].skin].name); + if (!CanChangeSkin(displayplayers[2])) + CV_StealthSet(&cv_skin3, skins[players[displayplayers[2]].skin].name); // check if player has the skin loaded (cv_skin3 may have // the name of a skin that was available in the previous game) @@ -1634,8 +1634,8 @@ static void SendNameAndColor4(void) if (splitscreen < 3) return; // can happen if skin4/color4/name4 changed - if (fourthdisplayplayer != consoleplayer) - fourthplaya = fourthdisplayplayer; + if (displayplayers[3] != consoleplayer) + fourthplaya = displayplayers[3]; else if (!netgame) // HACK fourthplaya = 3; @@ -1684,7 +1684,7 @@ static void SendNameAndColor4(void) CleanupPlayerName(fourthplaya, cv_playername4.zstring); strcpy(player_names[fourthplaya], cv_playername4.zstring); - // don't use fourthdisplayplayer: the second player must be 4 + // don't use displayplayers[3]: the second player must be 4 players[fourthplaya].skincolor = cv_playercolor4.value; if (players[fourthplaya].mo) players[fourthplaya].mo->color = players[fourthplaya].skincolor; @@ -1723,14 +1723,14 @@ static void SendNameAndColor4(void) snac4pending++; // Don't change name if muted - if (cv_mute.value && !(server || IsPlayerAdmin(fourthdisplayplayer))) - CV_StealthSet(&cv_playername4, player_names[fourthdisplayplayer]); + if (cv_mute.value && !(server || IsPlayerAdmin(displayplayers[3]))) + CV_StealthSet(&cv_playername4, player_names[displayplayers[3]]); else // Cleanup name if changing it - CleanupPlayerName(fourthdisplayplayer, cv_playername4.zstring); + CleanupPlayerName(displayplayers[3], cv_playername4.zstring); // Don't change skin if the server doesn't want you to. - if (!CanChangeSkin(fourthdisplayplayer)) - CV_StealthSet(&cv_skin4, skins[players[fourthdisplayplayer].skin].name); + if (!CanChangeSkin(displayplayers[3])) + CV_StealthSet(&cv_skin4, skins[players[displayplayers[3]].skin].name); // check if player has the skin loaded (cv_skin4 may have // the name of a skin that was available in the previous game) @@ -1760,12 +1760,12 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) #endif if (playernum == consoleplayer) - snacpending--; - else if (playernum == secondarydisplayplayer) + snacpending--; // TODO: make snacpending an array instead of 4 separate vars? + else if (playernum == displayplayers[1]) snac2pending--; - else if (playernum == thirddisplayplayer) + else if (playernum == displayplayers[2]) snac3pending--; - else if (playernum == fourthdisplayplayer) + else if (playernum == displayplayers[3]) snac4pending--; #ifdef PARANOIA @@ -1788,8 +1788,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) demo_extradata[playernum] |= DXD_COLOR; // normal player colors - if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer] - && p != &players[thirddisplayplayer] && p != &players[fourthdisplayplayer])) + if (server && (p != &players[consoleplayer] && p != &players[displayplayers[1]] + && p != &players[displayplayers[2]] && p != &players[displayplayers[3]])) { boolean kick = false; @@ -1826,11 +1826,11 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) if (playernum == consoleplayer) CV_StealthSet(&cv_skin, skins[forcedskin].name); - else if (playernum == secondarydisplayplayer) + else if (playernum == displayplayers[1]) CV_StealthSet(&cv_skin2, skins[forcedskin].name); - else if (playernum == thirddisplayplayer) + else if (playernum == displayplayers[2]) CV_StealthSet(&cv_skin3, skins[forcedskin].name); - else if (playernum == fourthdisplayplayer) + else if (playernum == displayplayers[3]) CV_StealthSet(&cv_skin4, skins[forcedskin].name); } else @@ -1917,7 +1917,7 @@ void D_SendPlayerConfig(void) // Only works for displayplayer, sorry! static void Command_ResetCamera_f(void) { - P_ResetCamera(&players[displayplayer], &camera); + P_ResetCamera(&players[displayplayers[0]], &camera[0]); } /* Consider replacing nametonum with this */ @@ -2014,7 +2014,7 @@ static void Command_View_f(void) return; } - displayplayerp = G_GetDisplayplayerPtr(viewnum); + displayplayerp = &displayplayers[viewnum]; if (COM_Argc() > 1)/* switch to player */ { @@ -2302,7 +2302,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r { //CL_AddSplitscreenPlayer(); botingame = true; - secondarydisplayplayer = 1; + displayplayers[1] = 1; playeringame[1] = true; players[1].bot = 1; SendNameAndColor2(); @@ -2354,12 +2354,8 @@ void D_ModifyClientVote(SINT8 voted, UINT8 splitplayer) char *p = buf; UINT8 player = consoleplayer; - if (splitplayer == 1) - player = secondarydisplayplayer; - else if (splitplayer == 2) - player = thirddisplayplayer; - else if (splitplayer == 3) - player = fourthdisplayplayer; + if (splitplayer > 0) + player = displayplayers[splitplayer]; WRITESINT8(p, voted); WRITEUINT8(p, player); @@ -3006,11 +3002,11 @@ static void Command_Teamchange2_f(void) return; } - if (players[secondarydisplayplayer].spectator) - error = !(NetPacket.packet.newteam || (players[secondarydisplayplayer].pflags & PF_WANTSTOJOIN)); + if (players[displayplayers[1]].spectator) + error = !(NetPacket.packet.newteam || (players[displayplayers[1]].pflags & PF_WANTSTOJOIN)); else if (G_GametypeHasTeams()) - error = (NetPacket.packet.newteam == (unsigned)players[secondarydisplayplayer].ctfteam); - else if (G_GametypeHasSpectators() && !players[secondarydisplayplayer].spectator) + error = (NetPacket.packet.newteam == (unsigned)players[displayplayers[1]].ctfteam); + else if (G_GametypeHasSpectators() && !players[displayplayers[1]].spectator) error = (NetPacket.packet.newteam == 3); #ifdef PARANOIA else @@ -3097,11 +3093,11 @@ static void Command_Teamchange3_f(void) return; } - if (players[thirddisplayplayer].spectator) - error = !(NetPacket.packet.newteam || (players[thirddisplayplayer].pflags & PF_WANTSTOJOIN)); + if (players[displayplayers[2]].spectator) + error = !(NetPacket.packet.newteam || (players[displayplayers[2]].pflags & PF_WANTSTOJOIN)); else if (G_GametypeHasTeams()) - error = (NetPacket.packet.newteam == (unsigned)players[thirddisplayplayer].ctfteam); - else if (G_GametypeHasSpectators() && !players[thirddisplayplayer].spectator) + error = (NetPacket.packet.newteam == (unsigned)players[displayplayers[2]].ctfteam); + else if (G_GametypeHasSpectators() && !players[displayplayers[2]].spectator) error = (NetPacket.packet.newteam == 3); #ifdef PARANOIA else @@ -3188,11 +3184,11 @@ static void Command_Teamchange4_f(void) return; } - if (players[fourthdisplayplayer].spectator) - error = !(NetPacket.packet.newteam || (players[fourthdisplayplayer].pflags & PF_WANTSTOJOIN)); + if (players[displayplayers[3]].spectator) + error = !(NetPacket.packet.newteam || (players[displayplayers[3]].pflags & PF_WANTSTOJOIN)); else if (G_GametypeHasTeams()) - error = (NetPacket.packet.newteam == (unsigned)players[fourthdisplayplayer].ctfteam); - else if (G_GametypeHasSpectators() && !players[fourthdisplayplayer].spectator) + error = (NetPacket.packet.newteam == (unsigned)players[displayplayers[3]].ctfteam); + else if (G_GametypeHasSpectators() && !players[displayplayers[3]].spectator) error = (NetPacket.packet.newteam == 3); #ifdef PARANOIA else @@ -3589,8 +3585,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false); // "entered the game" text was moved to P_SpectatorJoinGame //reset view if you are changed, or viewing someone who was changed. - if (playernum == consoleplayer || displayplayer == playernum) - displayplayer = consoleplayer; + if (playernum == consoleplayer || displayplayers[0] == playernum) + displayplayers[0] = consoleplayer; if (G_GametypeHasTeams()) { @@ -3598,11 +3594,11 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) { if (playernum == consoleplayer) //CTF and Team Match colors. CV_SetValue(&cv_playercolor, NetPacket.packet.newteam + 5); - else if (playernum == secondarydisplayplayer) + else if (playernum == displayplayers[1]) CV_SetValue(&cv_playercolor2, NetPacket.packet.newteam + 5); - else if (playernum == thirddisplayplayer) + else if (playernum == displayplayers[2]) CV_SetValue(&cv_playercolor3, NetPacket.packet.newteam + 5); - else if (playernum == fourthdisplayplayer) + else if (playernum == displayplayers[3]) CV_SetValue(&cv_playercolor4, NetPacket.packet.newteam + 5); } } @@ -5208,13 +5204,13 @@ static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) Y_SetupVoteFinish(pick, level); } -/** Prints the number of the displayplayer. +/** Prints the number of displayplayers[0]. * * \todo Possibly remove this; it was useful for debugging at one point. */ static void Command_Displayplayer_f(void) { - CONS_Printf(M_GetText("Displayplayer is %d\n"), displayplayer); + CONS_Printf(M_GetText("Displayplayer is %d\n"), displayplayers[0]); } /** Quits a game and returns to the title screen. @@ -5425,7 +5421,7 @@ static void Name2_OnChange(void) if (cv_mute.value) //Secondary player can't be admin. { CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername2, player_names[secondarydisplayplayer]); + CV_StealthSet(&cv_playername2, player_names[displayplayers[1]]); } else SendNameAndColor2(); @@ -5436,7 +5432,7 @@ static void Name3_OnChange(void) if (cv_mute.value) //Third player can't be admin. { CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername3, player_names[thirddisplayplayer]); + CV_StealthSet(&cv_playername3, player_names[displayplayers[2]]); } else SendNameAndColor3(); @@ -5447,7 +5443,7 @@ static void Name4_OnChange(void) if (cv_mute.value) //Secondary player can't be admin. { CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername4, player_names[fourthdisplayplayer]); + CV_StealthSet(&cv_playername4, player_names[displayplayers[3]]); } else SendNameAndColor4(); @@ -5488,12 +5484,12 @@ static void Skin2_OnChange(void) if (!Playing() || !splitscreen) return; // do whatever you want - if (CanChangeSkin(secondarydisplayplayer) && !P_PlayerMoving(secondarydisplayplayer)) + if (CanChangeSkin(displayplayers[1]) && !P_PlayerMoving(displayplayers[1])) SendNameAndColor2(); else { CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin2, skins[players[secondarydisplayplayer].skin].name); + CV_StealthSet(&cv_skin2, skins[players[displayplayers[1]].skin].name); } } @@ -5502,12 +5498,12 @@ static void Skin3_OnChange(void) if (!Playing() || splitscreen < 2) return; // do whatever you want - if (CanChangeSkin(thirddisplayplayer) && !P_PlayerMoving(thirddisplayplayer)) + if (CanChangeSkin(displayplayers[2]) && !P_PlayerMoving(displayplayers[2])) SendNameAndColor3(); else { CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin3, skins[players[thirddisplayplayer].skin].name); + CV_StealthSet(&cv_skin3, skins[players[displayplayers[2]].skin].name); } } @@ -5516,12 +5512,12 @@ static void Skin4_OnChange(void) if (!Playing() || splitscreen < 3) return; // do whatever you want - if (CanChangeSkin(fourthdisplayplayer) && !P_PlayerMoving(fourthdisplayplayer)) + if (CanChangeSkin(displayplayers[3]) && !P_PlayerMoving(displayplayers[3])) SendNameAndColor4(); else { CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin4, skins[players[fourthdisplayplayer].skin].name); + CV_StealthSet(&cv_skin4, skins[players[displayplayers[3]].skin].name); } } @@ -5562,7 +5558,7 @@ static void Color2_OnChange(void) if (!Playing() || !splitscreen) return; // do whatever you want - if (!P_PlayerMoving(secondarydisplayplayer)) + if (!P_PlayerMoving(displayplayers[1])) { // Color change menu scrolling fix is no longer necessary SendNameAndColor2(); @@ -5570,7 +5566,7 @@ static void Color2_OnChange(void) else { CV_StealthSetValue(&cv_playercolor2, - players[secondarydisplayplayer].skincolor); + players[displayplayers[1]].skincolor); } } @@ -5579,7 +5575,7 @@ static void Color3_OnChange(void) if (!Playing() || splitscreen < 2) return; // do whatever you want - if (!P_PlayerMoving(thirddisplayplayer)) + if (!P_PlayerMoving(displayplayers[2])) { // Color change menu scrolling fix is no longer necessary SendNameAndColor3(); @@ -5587,7 +5583,7 @@ static void Color3_OnChange(void) else { CV_StealthSetValue(&cv_playercolor3, - players[thirddisplayplayer].skincolor); + players[displayplayers[2]].skincolor); } } @@ -5596,7 +5592,7 @@ static void Color4_OnChange(void) if (!Playing() || splitscreen < 3) return; // do whatever you want - if (!P_PlayerMoving(fourthdisplayplayer)) + if (!P_PlayerMoving(displayplayers[3])) { // Color change menu scrolling fix is no longer necessary SendNameAndColor4(); @@ -5604,7 +5600,7 @@ static void Color4_OnChange(void) else { CV_StealthSetValue(&cv_playercolor4, - players[fourthdisplayplayer].skincolor); + players[displayplayers[3]].skincolor); } } diff --git a/src/dehacked.c b/src/dehacked.c index 20c2964b7..b0052c6c6 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9799,7 +9799,7 @@ static inline int lib_getenum(lua_State *L) // DYNAMIC variables too!! // Try not to add anything that would break netgames or timeattack replays here. - // You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime. + // You know, like consoleplayer, displayplayers, or gametime. if (fastcmp(word,"gamemap")) { lua_pushinteger(L, gamemap); return 1; diff --git a/src/doomstat.h b/src/doomstat.h index 834b3a7cf..4c4270bec 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -106,14 +106,8 @@ extern UINT8 window_notinfocus; // are we in focus? (backend independant -- hand extern boolean nodrawers; extern boolean noblit; extern boolean lastdraw; -extern postimg_t postimgtype; -extern INT32 postimgparam; -extern postimg_t postimgtype2; -extern INT32 postimgparam2; -extern postimg_t postimgtype3; -extern INT32 postimgparam3; -extern postimg_t postimgtype4; -extern INT32 postimgparam4; +extern postimg_t postimgtype[MAXSPLITSCREENPLAYERS]; +extern INT32 postimgparam[MAXSPLITSCREENPLAYERS]; extern INT32 viewwindowx, viewwindowy; extern INT32 viewwidth, scaledviewwidth; @@ -122,10 +116,7 @@ extern boolean gamedataloaded; // Player taking events, and displaying. extern INT32 consoleplayer; -extern INT32 displayplayer; -extern INT32 secondarydisplayplayer; // for splitscreen -extern INT32 thirddisplayplayer; -extern INT32 fourthdisplayplayer; +extern INT32 displayplayers[MAXSPLITSCREENPLAYERS]; // Maps of special importance extern INT16 spstage_start; diff --git a/src/g_game.c b/src/g_game.c index 85077c7bf..109c2baa5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -112,10 +112,7 @@ boolean addedtogame; player_t players[MAXPLAYERS]; INT32 consoleplayer; // player taking events and displaying -INT32 displayplayer; // view being displayed -INT32 secondarydisplayplayer; // for splitscreen -INT32 thirddisplayplayer; -INT32 fourthdisplayplayer; +INT32 displayplayers[MAXSPLITSCREENPLAYERS]; // view being displayed tic_t gametic; tic_t levelstarttic; // gametic at level start @@ -1220,9 +1217,9 @@ INT32 JoyAxis(axis_input_e axissel, UINT8 p) // // set secondaryplayer true to build player 2's ticcmd in splitscreen mode // -INT32 localaiming, localaiming2, localaiming3, localaiming4; -angle_t localangle, localangle2, localangle3, localangle4; -boolean camspin, camspin2, camspin3, camspin4; +INT32 localaiming[MAXSPLITSCREENPLAYERS]; // TODO: convert these 3 into MAXSPLITSCREENPLAYERS arrays +angle_t localangle[MAXSPLITSCREENPLAYERS]; +boolean camspin[MAXSPLITSCREENPLAYERS]; static fixed_t forwardmove[2] = {25<>16, 50<>16}; static fixed_t sidemove[2] = {2<>16, 4<>16}; @@ -1239,53 +1236,36 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) camera_t *thiscam; angle_t lang; - static INT32 turnheld, turnheld2, turnheld3, turnheld4; // for accelerative turning - static boolean keyboard_look, keyboard_look2, keyboard_look3, keyboard_look4; // true if lookup/down using keyboard - static boolean resetdown, resetdown2, resetdown3, resetdown4; // don't cam reset every frame + static INT32 turnheld[MAXSPLITSCREENPLAYERS]; // for accelerative turning + static boolean keyboard_look[MAXSPLITSCREENPLAYERS]; // true if lookup/down using keyboard + static boolean resetdown[MAXSPLITSCREENPLAYERS]; // don't cam reset every frame if (demo.playback) return; + player = &players[displayplayers[ssplayer-1]]; + if (ssplayer == 2) + thiscam = (player->bot == 2 ? &camera[0] : &camera[ssplayer-1]); + else + thiscam = &camera[ssplayer-1]; + lang = localangle[ssplayer-1]; + laim = localaiming[ssplayer-1]; + th = turnheld[ssplayer-1]; + kbl = keyboard_look[ssplayer-1]; + rd = resetdown[ssplayer-1]; + switch (ssplayer) { case 2: - player = &players[secondarydisplayplayer]; - thiscam = (player->bot == 2 ? &camera : &camera2); - lang = localangle2; - laim = localaiming2; - th = turnheld2; - kbl = keyboard_look2; - rd = resetdown2; G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); break; case 3: - player = &players[thirddisplayplayer]; - thiscam = &camera3; - lang = localangle3; - laim = localaiming3; - th = turnheld3; - kbl = keyboard_look3; - rd = resetdown3; G_CopyTiccmd(cmd, I_BaseTiccmd3(), 1); break; case 4: - player = &players[fourthdisplayplayer]; - thiscam = &camera4; - lang = localangle4; - laim = localaiming4; - th = turnheld4; - kbl = keyboard_look4; - rd = resetdown4; G_CopyTiccmd(cmd, I_BaseTiccmd4(), 1); break; case 1: default: - player = &players[consoleplayer]; - thiscam = &camera; - lang = localangle; - laim = localaiming; - th = turnheld; - kbl = keyboard_look; - rd = resetdown; G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver break; } @@ -1576,42 +1556,12 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (!hu_stopped) { - switch (ssplayer) - { - case 2: - localangle2 = lang; - localaiming2 = laim; - keyboard_look2 = kbl; - turnheld2 = th; - resetdown2 = rd; - camspin2 = InputDown(gc_lookback, ssplayer); - break; - case 3: - localangle3 = lang; - localaiming3 = laim; - keyboard_look3 = kbl; - turnheld3 = th; - resetdown3 = rd; - camspin3 = InputDown(gc_lookback, ssplayer); - break; - case 4: - localangle4 = lang; - localaiming4 = laim; - keyboard_look4 = kbl; - turnheld4 = th; - resetdown4 = rd; - camspin4 = InputDown(gc_lookback, ssplayer); - break; - case 1: - default: - localangle = lang; - localaiming = laim; - keyboard_look = kbl; - turnheld = th; - resetdown = rd; - camspin = InputDown(gc_lookback, ssplayer); - break; - } + localangle[ssplayer-1] = lang; + localaiming[ssplayer-1] = laim; + keyboard_look[ssplayer-1] = kbl; + turnheld[ssplayer-1] = th; + resetdown[ssplayer-1] = rd; + camspin[ssplayer-1] = InputDown(gc_lookback, ssplayer); } /* Lua: Allow this hook to overwrite ticcmd. @@ -1631,8 +1581,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) //Reset away view if a command is given. if ((cmd->forwardmove || cmd->sidemove || cmd->buttons) - && displayplayer != consoleplayer && ssplayer == 1) - displayplayer = consoleplayer; + && displayplayers[0] != consoleplayer && ssplayer == 1) + displayplayers[0] = consoleplayer; } @@ -1784,27 +1734,24 @@ void G_DoLoadLevel(boolean resetplayer) if (!resetplayer) P_FindEmerald(); - displayplayer = consoleplayer; // view the guy you are playing - if (!splitscreen && !botingame) - secondarydisplayplayer = consoleplayer; - if (splitscreen < 2) - thirddisplayplayer = consoleplayer; - if (splitscreen < 3) - fourthdisplayplayer = consoleplayer; + displayplayers[0] = consoleplayer; // view the guy you are playing + + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + { + if (i > 0 && !(i == 1 && botingame) && splitscreen < i) + displayplayers[i] = consoleplayer; + } gameaction = ga_nothing; #ifdef PARANOIA Z_CheckHeap(-2); #endif - if (camera.chase) - P_ResetCamera(&players[displayplayer], &camera); - if (camera2.chase && splitscreen) - P_ResetCamera(&players[secondarydisplayplayer], &camera2); - if (camera3.chase && splitscreen > 1) - P_ResetCamera(&players[thirddisplayplayer], &camera3); - if (camera4.chase && splitscreen > 2) - P_ResetCamera(&players[fourthdisplayplayer], &camera4); + for (i = 0; i <= splitscreen; i++) + { + if (camera[i].chase) + P_ResetCamera(&players[displayplayers[i]], &camera[i]); + } // clear cmd building stuff memset(gamekeydown, 0, sizeof (gamekeydown)); @@ -1914,7 +1861,7 @@ boolean G_Responder(event_t *ev) && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) { if (!demo.playback && (splitscreen || !netgame)) - displayplayer = consoleplayer; + displayplayers[0] = consoleplayer; else { G_AdjustView(1, 1, true); @@ -2184,13 +2131,13 @@ boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive) for (viewd = 1; viewd < viewnum; ++viewd) { - displayplayerp = (G_GetDisplayplayerPtr(viewd)); + displayplayerp = (&displayplayers[viewd-1]); if ((*displayplayerp) == playernum) return false; } for (viewd = viewnum + 1; viewd <= splits; ++viewd) { - displayplayerp = (G_GetDisplayplayerPtr(viewd)); + displayplayerp = (&displayplayers[viewd-1]); if ((*displayplayerp) == playernum) return false; } @@ -2232,17 +2179,6 @@ INT32 G_CountPlayersPotentiallyViewable(boolean active) return total; } -INT32 *G_GetDisplayplayerPtr(UINT8 viewnum) -{ - switch (viewnum) - { - case 2: return &secondarydisplayplayer; - case 3: return &thirddisplayplayer; - case 4: return &fourthdisplayplayer; - } - return &displayplayer; -} - // // G_ResetView // Correct a viewpoint to playernum or the next available, wraps forward. @@ -2276,14 +2212,14 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) /* Prepare extra views for G_FindView to pass. */ for (viewd = splits+1; viewd < viewnum; ++viewd) { - displayplayerp = (G_GetDisplayplayerPtr(viewd)); + displayplayerp = (&displayplayers[viewd-1]); (*displayplayerp) = INT32_MAX; } R_ExecuteSetViewSize(); } - displayplayerp = (G_GetDisplayplayerPtr(viewnum)); + displayplayerp = (&displayplayers[viewnum-1]); olddisplayplayer = (*displayplayerp); /* Check if anyone is available to view. */ @@ -2294,7 +2230,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) (*displayplayerp) = playernum; if ((*displayplayerp) != olddisplayplayer) { - camerap = (P_GetCameraPtr(viewnum)); + camerap = &camera[viewnum-1]; P_ResetCamera(&players[(*displayplayerp)], camerap); } @@ -2302,8 +2238,8 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) { for (viewd = splits+1; viewd < viewnum; ++viewd) { - displayplayerp = (G_GetDisplayplayerPtr(viewd)); - camerap = (P_GetCameraPtr(viewd)); + displayplayerp = (&displayplayers[viewd-1]); + camerap = &camera[viewd]; (*displayplayerp) = G_FindView(0, viewd, onlyactive, false); @@ -2312,7 +2248,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) } if (viewnum == 1 && demo.playback) - consoleplayer = displayplayer; + consoleplayer = displayplayers[0]; } // @@ -2323,7 +2259,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive) { INT32 *displayplayerp, oldview; - displayplayerp = G_GetDisplayplayerPtr(viewnum); + displayplayerp = &displayplayers[viewnum-1]; oldview = (*displayplayerp); G_ResetView(viewnum, ( (*displayplayerp) + offset ), onlyactive); @@ -2864,22 +2800,22 @@ void G_PlayerReborn(INT32 player) { if (p == &players[consoleplayer]) CV_SetValue(&cv_playercolor, skincolor_redteam); - else if (p == &players[secondarydisplayplayer]) + else if (p == &players[displayplayers[1]]) CV_SetValue(&cv_playercolor2, skincolor_redteam); - else if (p == &players[thirddisplayplayer]) + else if (p == &players[displayplayers[2]]) CV_SetValue(&cv_playercolor3, skincolor_redteam); - else if (p == &players[fourthdisplayplayer]) + else if (p == &players[displayplayers[3]]) CV_SetValue(&cv_playercolor4, skincolor_redteam); } else if (p->ctfteam == 2 && p->skincolor != skincolor_blueteam) { if (p == &players[consoleplayer]) CV_SetValue(&cv_playercolor, skincolor_blueteam); - else if (p == &players[secondarydisplayplayer]) + else if (p == &players[displayplayers[1]]) CV_SetValue(&cv_playercolor2, skincolor_blueteam); - else if (p == &players[thirddisplayplayer]) + else if (p == &players[displayplayers[2]]) CV_SetValue(&cv_playercolor3, skincolor_blueteam); - else if (p == &players[fourthdisplayplayer]) + else if (p == &players[displayplayers[3]]) CV_SetValue(&cv_playercolor4, skincolor_blueteam); } }*/ @@ -2984,18 +2920,18 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) if (nummapthings) { if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n")); spawnpoint = &mapthings[0]; } else { if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n")); //P_MovePlayerToSpawn handles this fine if the spawnpoint is NULL. } @@ -3015,9 +2951,9 @@ mapthing_t *G_FindCTFStart(INT32 playernum) if (!numredctfstarts && !numbluectfstarts) //why even bother, eh? { if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("No CTF starts in this map!\n")); return NULL; } @@ -3027,9 +2963,9 @@ mapthing_t *G_FindCTFStart(INT32 playernum) if (!numredctfstarts) { if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("No Red Team starts in this map!\n")); return NULL; } @@ -3042,9 +2978,9 @@ mapthing_t *G_FindCTFStart(INT32 playernum) } if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Red Team starts!\n")); return NULL; } @@ -3053,9 +2989,9 @@ mapthing_t *G_FindCTFStart(INT32 playernum) if (!numbluectfstarts) { if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("No Blue Team starts in this map!\n")); return NULL; } @@ -3067,9 +3003,9 @@ mapthing_t *G_FindCTFStart(INT32 playernum) return bluectfstarts[i]; } if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Blue Team starts!\n")); return NULL; } @@ -3090,17 +3026,17 @@ mapthing_t *G_FindMatchStart(INT32 playernum) return deathmatchstarts[i]; } if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n")); return NULL; } if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("No Deathmatch starts in this map!\n")); return NULL; } @@ -3166,17 +3102,17 @@ mapthing_t *G_FindRaceStart(INT32 playernum) //return playerstarts[0]; if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Race starts!\n")); return NULL; } if (playernum == consoleplayer - || (splitscreen && playernum == secondarydisplayplayer) - || (splitscreen > 1 && playernum == thirddisplayplayer) - || (splitscreen > 2 && playernum == fourthdisplayplayer)) + || (splitscreen && playernum == displayplayers[1]) + || (splitscreen > 1 && playernum == displayplayers[2]) + || (splitscreen > 2 && playernum == displayplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("No Race starts in this map!\n")); return NULL; } @@ -3268,14 +3204,11 @@ void G_DoReborn(INT32 playernum) if (player->starpostnum) // SRB2kart starpost = true; - if (camera.chase) - P_ResetCamera(&players[displayplayer], &camera); - if (camera2.chase && splitscreen > 0) - P_ResetCamera(&players[secondarydisplayplayer], &camera2); - if (camera3.chase && splitscreen > 1) - P_ResetCamera(&players[thirddisplayplayer], &camera3); - if (camera4.chase && splitscreen > 2) - P_ResetCamera(&players[fourthdisplayplayer], &camera4); + for (i = 0; i <= splitscreen; i++) + { + if (camera[i].chase) + P_ResetCamera(&players[displayplayers[i]], &camera[i]); + } // clear cmd building stuff memset(gamekeydown, 0, sizeof (gamekeydown)); @@ -3297,8 +3230,8 @@ void G_DoReborn(INT32 playernum) if (botingame) { // Bots respawn next to their master. - players[secondarydisplayplayer].playerstate = PST_REBORN; - G_SpawnPlayer(secondarydisplayplayer, false); + players[displayplayers[1]].playerstate = PST_REBORN; + G_SpawnPlayer(displayplayers[1], false); } } else @@ -4418,7 +4351,7 @@ static void M_ForceLoadGameResponse(INT32 ch) //set cursaveslot to -1 so nothing gets saved. cursaveslot = -1; - displayplayer = consoleplayer; + displayplayers[0] = consoleplayer; multiplayer = false; splitscreen = 0; SplitScreen_OnChange(); // not needed? @@ -4508,7 +4441,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) // gameaction = ga_nothing; // G_SetGamestate(GS_LEVEL); - displayplayer = consoleplayer; + displayplayers[0] = consoleplayer; multiplayer = false; splitscreen = 0; SplitScreen_OnChange(); // not needed? @@ -4573,7 +4506,7 @@ void G_SaveGame(UINT32 savegameslot) // // G_DeferedInitNew // Can be called by the startup code or the menu task, -// consoleplayer, displayplayer, playeringame[] should be set. +// consoleplayer, displayplayers[], playeringame[] should be set. // void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar, UINT8 ssplayers, boolean FLS) { @@ -5167,12 +5100,12 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) G_CopyTiccmd(cmd, &oldcmd[playernum], 1); // SRB2kart: Copy-pasted from ticcmd building, removes that crappy demo cam - if (((players[displayplayer].mo && players[displayplayer].speed > 0) // Moving + if (((players[displayplayers[0]].mo && players[displayplayers[0]].speed > 0) // Moving || (leveltime > starttime && (cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE)) // Rubber-burn turn - || (players[displayplayer].kartstuff[k_respawn]) // Respawning - || (players[displayplayer].spectator || objectplacing)) // Not a physical player - && !(players[displayplayer].kartstuff[k_spinouttimer] && players[displayplayer].kartstuff[k_sneakertimer])) // Spinning and boosting cancels out spinout - localangle += (cmd->angleturn<<16); + || (players[displayplayers[0]].kartstuff[k_respawn]) // Respawning + || (players[displayplayers[0]].spectator || objectplacing)) // Not a physical player + && !(players[displayplayers[0]].kartstuff[k_spinouttimer] && players[displayplayers[0]].kartstuff[k_sneakertimer])) // Spinning and boosting cancels out spinout + localangle[0] += (cmd->angleturn<<16); if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) { @@ -6073,7 +6006,7 @@ void G_PreviewRewind(tic_t previewtime) } for (i = splitscreen+1; i > 0; i--) - P_ResetCamera(&players[(*G_GetDisplayplayerPtr(i))], P_GetCameraPtr(i)); + P_ResetCamera(&players[displayplayers[i]], &camera[i]); } void G_ConfirmRewind(tic_t rewindtime) @@ -6081,7 +6014,7 @@ void G_ConfirmRewind(tic_t rewindtime) tic_t i; boolean oldmenuactive = menuactive, oldsounddisabled = sound_disabled; - INT32 olddp1 = displayplayer, olddp2 = secondarydisplayplayer, olddp3 = thirddisplayplayer, olddp4 = fourthdisplayplayer; + INT32 olddp1 = displayplayers[0], olddp2 = displayplayers[1], olddp3 = displayplayers[2], olddp4 = displayplayers[3]; UINT8 oldss = splitscreen; menuactive = false; // Prevent loops @@ -6113,15 +6046,15 @@ void G_ConfirmRewind(tic_t rewindtime) COM_BufInsertText("renderview on\n"); splitscreen = oldss; - displayplayer = olddp1; - secondarydisplayplayer = olddp2; - thirddisplayplayer = olddp3; - fourthdisplayplayer = olddp4; + displayplayers[0] = olddp1; + displayplayers[1] = olddp2; + displayplayers[2] = olddp3; + displayplayers[3] = olddp4; R_ExecuteSetViewSize(); G_ResetViews(); for (i = splitscreen+1; i > 0; i--) - P_ResetCamera(&players[(*G_GetDisplayplayerPtr(i))], P_GetCameraPtr(i)); + P_ResetCamera(&players[displayplayers[i]], &camera[i]); } void G_ReadMetalTic(mobj_t *metal) @@ -7407,7 +7340,8 @@ void G_DoPlayDemo(char *defdemoname) // didn't start recording right away. demo.deferstart = false; - displayplayer = consoleplayer = 0; + consoleplayer = 0; + memset(displayplayers, 0, sizeof(displayplayers)); memset(playeringame, 0, sizeof(playeringame)); playeringame[0] = true; @@ -7457,13 +7391,14 @@ void G_DoPlayDemo(char *defdemoname) /*#ifdef HAVE_BLUA LUAh_MapChange(gamemap); #endif*/ - displayplayer = consoleplayer = 0; + displayplayers[0] = consoleplayer = 0; memset(playeringame,0,sizeof(playeringame)); // Load players that were in-game when the map started p = READUINT8(demo_p); - secondarydisplayplayer = thirddisplayplayer = fourthdisplayplayer = INT32_MAX; + for (i = 1; i < MAXSPLITSCREENPLAYERS; i++); + displayplayers[i] = INT32_MAX; while (p != 0xFF) { @@ -7499,8 +7434,8 @@ void G_DoPlayDemo(char *defdemoname) return; } - if (!playeringame[displayplayer] || players[displayplayer].spectator) - displayplayer = consoleplayer = serverplayer = p; + if (!playeringame[displayplayers[0]] || players[displayplayers[0]].spectator) + displayplayers[0] = consoleplayer = serverplayer = p; playeringame[p] = true; players[p].spectator = spectator; diff --git a/src/g_game.h b/src/g_game.h index 148a5e52b..dd6eefca3 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -152,9 +152,9 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming); boolean InputDown(INT32 gc, UINT8 p); INT32 JoyAxis(axis_input_e axissel, UINT8 p); -extern angle_t localangle, localangle2, localangle3, localangle4; -extern INT32 localaiming, localaiming2, localaiming3, localaiming4; // should be an angle_t but signed -extern boolean camspin, camspin2, camspin3, camspin4; // SRB2Kart +extern angle_t localangle[MAXSPLITSCREENPLAYERS]; +extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed +extern boolean camspin[MAXSPLITSCREENPLAYERS]; // SRB2Kart // // GAME @@ -297,8 +297,6 @@ void G_EndGame(void); // moved from y_inter.c/h and renamed void G_Ticker(boolean run); boolean G_Responder(event_t *ev); -INT32 *G_GetDisplayplayerPtr(UINT8 viewnum); - boolean G_CouldView(INT32 playernum); boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index d7020e8c6..2368d1f21 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -39,7 +39,7 @@ #include "am_map.h" #include "d_main.h" -#include "p_local.h" // camera, camera2, camera3, camera4 +#include "p_local.h" // camera[] #include "p_tick.h" #ifdef HWRENDER @@ -1987,7 +1987,7 @@ static void HU_DrawChat_Old(void) if (!i) return; - if ((netgame || multiplayer) && players[displayplayer].spectator) + if ((netgame || multiplayer) && players[displayplayers[0]].spectator) return; #ifdef HWRENDER @@ -2014,7 +2014,7 @@ static inline void HU_DrawCrosshair2(void) if (!i) return; - if ((netgame || multiplayer) && players[secondarydisplayplayer].spectator) + if ((netgame || multiplayer) && players[displayplayers[1]].spectator) return; #ifdef HWRENDER @@ -2061,7 +2061,7 @@ static inline void HU_DrawCrosshair3(void) if (!i) return; - if ((netgame || multiplayer) && players[thirddisplayplayer].spectator) + if ((netgame || multiplayer) && players[displayplayers[2]].spectator) return; #ifdef HWRENDER @@ -2098,7 +2098,7 @@ static inline void HU_DrawCrosshair4(void) if (!i) return; - if ((netgame || multiplayer) && players[fourthdisplayplayer].spectator) + if ((netgame || multiplayer) && players[displayplayers[3]].spectator) return; #ifdef HWRENDER @@ -2358,16 +2358,16 @@ void HU_Drawer(void) // draw the crosshair, not when viewing demos nor with chasecam /*if (!automapactive && !demo.playback) { - if (cv_crosshair.value && !camera.chase && !players[displayplayer].spectator) + if (cv_crosshair.value && !camera[0].chase && !players[displayplayers[0]].spectator) HU_DrawCrosshair(); - if (cv_crosshair2.value && !camera2.chase && !players[secondarydisplayplayer].spectator) + if (cv_crosshair2.value && !camera[1].chase && !players[displayplayers[1]].spectator) HU_DrawCrosshair2(); - if (cv_crosshair3.value && !camera3.chase && !players[thirddisplayplayer].spectator) + if (cv_crosshair3.value && !camera[2].chase && !players[displayplayers[2]].spectator) HU_DrawCrosshair3(); - if (cv_crosshair4.value && !camera4.chase && !players[fourthdisplayplayer].spectator) + if (cv_crosshair4.value && !camera[3].chase && !players[displayplayers[3]].spectator) HU_DrawCrosshair4(); }*/ @@ -3009,7 +3009,7 @@ static void HU_DrawRankings(void) // When you play, you quickly see your score because your name is displayed in white. // When playing back a demo, you quickly see who's the view. if (!splitscreen) - whiteplayer = demo.playback ? displayplayer : consoleplayer; + whiteplayer = demo.playback ? displayplayers[0] : consoleplayer; scorelines = 0; memset(completed, 0, sizeof (completed)); diff --git a/src/k_kart.c b/src/k_kart.c index 3918e8f94..1237a5920 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1027,34 +1027,14 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } // This makes the roulette produce the random noises. - if ((player->kartstuff[k_itemroulette] % 3) == 1 && P_IsLocalPlayer(player)) + if ((player->kartstuff[k_itemroulette] % 3) == 1 && P_IsDisplayPlayer(player)) { -#define PLAYROULETTESND S_StartSound(NULL, sfx_itrol1 + ((player->kartstuff[k_itemroulette] / 3) % 8)); - if (splitscreen) +#define PLAYROULETTESND S_StartSound(NULL, sfx_itrol1 + ((player->kartstuff[k_itemroulette] / 3) % 8)) + for (i = 0; i <= splitscreen; i++) { - if (players[displayplayer].kartstuff[k_itemroulette]) - { - if (player == &players[displayplayer]) - PLAYROULETTESND; - } - else if (players[secondarydisplayplayer].kartstuff[k_itemroulette]) - { - if (player == &players[secondarydisplayplayer]) - PLAYROULETTESND; - } - else if (players[thirddisplayplayer].kartstuff[k_itemroulette] && splitscreen > 1) - { - if (player == &players[thirddisplayplayer]) - PLAYROULETTESND; - } - else if (players[fourthdisplayplayer].kartstuff[k_itemroulette] && splitscreen > 2) - { - if (player == &players[fourthdisplayplayer]) - PLAYROULETTESND; - } + if (player == &players[displayplayers[i]] && players[displayplayers[i]].kartstuff[k_itemroulette]) + PLAYROULETTESND; } - else - PLAYROULETTESND; #undef PLAYROULETTESND } @@ -1081,7 +1061,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) //player->kartstuff[k_itemblinkmode] = 1; player->kartstuff[k_itemroulette] = 0; player->kartstuff[k_roulettetype] = 0; - if (P_IsLocalPlayer(player)) + if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrole); return; } @@ -1094,7 +1074,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) player->kartstuff[k_itemblinkmode] = 2; player->kartstuff[k_itemroulette] = 0; player->kartstuff[k_roulettetype] = 0; - if (P_IsLocalPlayer(player)) + if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_dbgsal); return; } @@ -1126,7 +1106,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) player->kartstuff[k_itemamount] = 1; } - if (P_IsLocalPlayer(player)) + if (P_IsDisplayPlayer(player)) S_StartSound(NULL, ((player->kartstuff[k_roulettetype] == 1) ? sfx_itrolk : (mashed ? sfx_itrolm : sfx_itrolf))); player->kartstuff[k_itemblink] = TICRATE; @@ -4331,10 +4311,7 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) if (!playeringame[i] || !players[i].mo || players[i].spectator || players[i].exiting) continue; - if ((i == displayplayer) - || (i == secondarydisplayplayer && splitscreen) - || (i == thirddisplayplayer && splitscreen > 1) - || (i == fourthdisplayplayer && splitscreen > 2)) + if (P_IsDisplayPlayer(&players[i])) { volumedampen += FRACUNIT; // We already know what this is gonna be, let's not waste our time. continue; @@ -5691,13 +5668,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_hyudorotimer] >= (1*TICRATE/2) && player->kartstuff[k_hyudorotimer] <= hyudorotime-(1*TICRATE/2)) { - if (player == &players[secondarydisplayplayer]) + if (player == &players[displayplayers[1]]) player->mo->eflags |= MFE_DRAWONLYFORP2; - else if (player == &players[thirddisplayplayer] && splitscreen > 1) + else if (player == &players[displayplayers[2]] && splitscreen > 1) player->mo->eflags |= MFE_DRAWONLYFORP3; - else if (player == &players[fourthdisplayplayer] && splitscreen > 2) + else if (player == &players[displayplayers[3]] && splitscreen > 2) player->mo->eflags |= MFE_DRAWONLYFORP4; - else if (player == &players[consoleplayer]) + else if (player == &players[displayplayers[0]]) player->mo->eflags |= MFE_DRAWONLYFORP1; else player->mo->flags2 |= MF2_DONTDRAW; @@ -5707,8 +5684,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else { - if (player == &players[displayplayer] - || (player != &players[displayplayer] && (player->kartstuff[k_hyudorotimer] < (1*TICRATE/2) || player->kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2)))) + if (P_IsDisplayPlayer(player) + || (!P_IsDisplayPlayer(player) && (player->kartstuff[k_hyudorotimer] < (1*TICRATE/2) || player->kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2)))) { if (leveltime & 1) player->mo->flags2 |= MF2_DONTDRAW; @@ -5808,7 +5785,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } // Play the starting countdown sounds - if (player == &players[displayplayer]) // Don't play louder in splitscreen + if (player == &players[displayplayers[0]]) // Don't play louder in splitscreen { if ((leveltime == starttime-(3*TICRATE)) || (leveltime == starttime-(2*TICRATE)) || (leveltime == starttime-TICRATE)) S_StartSound(NULL, sfx_s3ka7); @@ -6693,17 +6670,17 @@ INT32 K_calcSplitFlags(INT32 snapflags) if (splitscreen == 0) return snapflags; - if (stplyr != &players[displayplayer]) + if (stplyr != &players[displayplayers[0]]) { - if (splitscreen == 1 && stplyr == &players[secondarydisplayplayer]) + if (splitscreen == 1 && stplyr == &players[displayplayers[1]]) { splitflags |= V_SPLITSCREEN; } else if (splitscreen > 1) { - if (stplyr == &players[thirddisplayplayer] || (splitscreen == 3 && stplyr == &players[fourthdisplayplayer])) + if (stplyr == &players[displayplayers[2]] || (splitscreen == 3 && stplyr == &players[displayplayers[3]])) splitflags |= V_SPLITSCREEN; - if (stplyr == &players[secondarydisplayplayer] || (splitscreen == 3 && stplyr == &players[fourthdisplayplayer])) + if (stplyr == &players[displayplayers[1]] || (splitscreen == 3 && stplyr == &players[displayplayers[3]])) splitflags |= V_HORZSCREEN; } } @@ -6965,25 +6942,25 @@ static void K_drawKartItem(void) } // pain and suffering defined below - if (splitscreen < 2) // don't change shit for THIS splitscreen. + if (splitscreen < 2) // don't change shit for THIS splitscreen. { fx = ITEM_X; fy = ITEM_Y; fflags = K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOLEFT); } - else // now we're having a fun game. + else // now we're having a fun game. { - if (stplyr == &players[displayplayer] || stplyr == &players[thirddisplayplayer]) // If we are P1 or P3... + if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... { fx = ITEM_X; fy = ITEM_Y; - fflags = V_SNAPTOLEFT|((stplyr == &players[thirddisplayplayer]) ? V_SPLITSCREEN : V_SNAPTOTOP); // flip P3 to the bottom. + fflags = V_SNAPTOLEFT|((stplyr == &players[displayplayers[2]]) ? V_SPLITSCREEN : V_SNAPTOTOP); // flip P3 to the bottom. } else // else, that means we're P2 or P4. { fx = ITEM2_X; fy = ITEM2_Y; - fflags = V_SNAPTORIGHT|((stplyr == &players[fourthdisplayplayer]) ? V_SPLITSCREEN : V_SNAPTOTOP); // flip P4 to the bottom + fflags = V_SNAPTORIGHT|((stplyr == &players[displayplayers[3]]) ? V_SPLITSCREEN : V_SNAPTOTOP); // flip P4 to the bottom flipamount = true; } } @@ -6996,10 +6973,10 @@ static void K_drawKartItem(void) // Then, the numbers: if (stplyr->kartstuff[k_itemamount] >= numberdisplaymin && !stplyr->kartstuff[k_itemroulette]) { - V_DrawScaledPatch(fx + (flipamount ? 48 : 0), fy, V_HUDTRANS|fflags|(flipamount ? V_FLIP : 0), kp_itemmulsticker[offset]); // flip this graphic for p2 and p4 in split and shift it. + V_DrawScaledPatch(fx + (flipamount ? 48 : 0), fy, V_HUDTRANS|fflags|(flipamount ? V_FLIP : 0), kp_itemmulsticker[offset]); // flip this graphic for p2 and p4 in split and shift it. V_DrawFixedPatch(fx<kartstuff[k_itemamount])); else V_DrawString(fx+24, fy+31, V_ALLOWLOWERCASE|V_HUDTRANS|fflags, va("x%d", stplyr->kartstuff[k_itemamount])); @@ -7226,7 +7203,7 @@ static void K_DrawKartPositionNum(INT32 num) else if (splitscreen == 1) // for this splitscreen, we'll use case by case because it's a bit different. { fx = POSI_X; - if (stplyr == &players[displayplayer]) // for player 1: display this at the top right, above the minimap. + if (stplyr == &players[displayplayers[0]]) // for player 1: display this at the top right, above the minimap. { fy = 30; fflags = V_SNAPTOTOP|V_SNAPTORIGHT; @@ -7241,11 +7218,11 @@ static void K_DrawKartPositionNum(INT32 num) } else { - if (stplyr == &players[displayplayer] || stplyr == &players[thirddisplayplayer]) // If we are P1 or P3... + if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... { fx = POSI_X; fy = POSI_Y; - fflags = V_SNAPTOLEFT|((stplyr == &players[thirddisplayplayer]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. + fflags = V_SNAPTOLEFT|((stplyr == &players[displayplayers[2]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. flipdraw = true; if (num && num >= 10) fx += W; // this seems dumb, but we need to do this in order for positions above 10 going off screen. @@ -7254,7 +7231,7 @@ static void K_DrawKartPositionNum(INT32 num) { fx = POSI2_X; fy = POSI2_Y; - fflags = V_SNAPTORIGHT|((stplyr == &players[fourthdisplayplayer]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom + fflags = V_SNAPTORIGHT|((stplyr == &players[displayplayers[3]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom } } @@ -7580,17 +7557,17 @@ static void K_drawKartLaps(void) } else { - if (stplyr == &players[displayplayer] || stplyr == &players[thirddisplayplayer]) // If we are P1 or P3... + if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... { fx = LAPS_X; fy = LAPS_Y; - fflags = V_SNAPTOLEFT|((stplyr == &players[thirddisplayplayer]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. + fflags = V_SNAPTOLEFT|((stplyr == &players[displayplayers[2]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. } else // else, that means we're P2 or P4. { fx = LAPS2_X; fy = LAPS2_Y; - fflags = V_SNAPTORIGHT|((stplyr == &players[fourthdisplayplayer]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom + fflags = V_SNAPTORIGHT|((stplyr == &players[displayplayers[3]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom flipstring = true; // make the string right aligned and other shit } } @@ -7662,17 +7639,17 @@ static void K_drawKartBumpersOrKarma(void) // we will reuse lap coords here since it's essentially the same shit. - if (stplyr == &players[displayplayer] || stplyr == &players[thirddisplayplayer]) // If we are P1 or P3... + if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... { fx = LAPS_X; fy = LAPS_Y; - fflags = V_SNAPTOLEFT|((stplyr == &players[thirddisplayplayer]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. + fflags = V_SNAPTOLEFT|((stplyr == &players[displayplayers[2]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. } else // else, that means we're P2 or P4. { fx = LAPS2_X; fy = LAPS2_Y; - fflags = V_SNAPTORIGHT|((stplyr == &players[fourthdisplayplayer]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom + fflags = V_SNAPTORIGHT|((stplyr == &players[displayplayers[3]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom flipstring = true; } @@ -7749,7 +7726,7 @@ static void K_drawKartWanted(void) UINT8 *colormap = NULL; INT32 basex = 0, basey = 0; - if (stplyr != &players[displayplayer]) + if (stplyr != &players[displayplayers[0]]) return; for (i = 0; i < 4; i++) @@ -7829,7 +7806,7 @@ static void K_drawKartPlayerCheck(void) if (stplyr->awayviewtics) return; - if (camspin) + if (camspin[0]) return; for (i = 0; i < MAXPLAYERS; i++) @@ -7975,7 +7952,7 @@ static void K_drawKartMinimap(void) if (gamestate != GS_LEVEL) return; - if (stplyr != &players[displayplayer]) + if (stplyr != &players[displayplayers[0]]) return; lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(gamemap))); @@ -8049,7 +8026,7 @@ static void K_drawKartMinimap(void) if (!players[i].mo || players[i].spectator) continue; - if (i != displayplayer || splitscreen) + if (i != displayplayers[0] || splitscreen) { if (G_BattleGametype() && players[i].kartstuff[k_bumper] <= 0) continue; @@ -8063,7 +8040,7 @@ static void K_drawKartMinimap(void) } } - if (i == displayplayer || i == secondarydisplayplayer || i == thirddisplayplayer || i == fourthdisplayplayer) + if (P_IsDisplayPlayer(&players[i])) { // Draw display players on top of everything else localplayers[numlocalplayers] = i; @@ -8133,7 +8110,7 @@ static void K_drawKartFinish(void) xval = (SHORT(kp_racefinish[pnum]->width)<kartstuff[k_cardanimation])*(xval > x ? xval : x))/TICRATE; - if (splitscreen && stplyr == &players[secondarydisplayplayer]) + if (splitscreen && stplyr == &players[displayplayers[1]]) x = -x; V_DrawFixedPatch(x + (STCD_X<>1), @@ -8152,9 +8129,9 @@ static void K_drawBattleFullscreen(void) if (splitscreen) { - if ((splitscreen == 1 && stplyr == &players[secondarydisplayplayer]) - || (splitscreen > 1 && (stplyr == &players[thirddisplayplayer] - || (stplyr == &players[fourthdisplayplayer] && splitscreen > 2)))) + if ((splitscreen == 1 && stplyr == &players[displayplayers[1]]) + || (splitscreen > 1 && (stplyr == &players[displayplayers[2]] + || (stplyr == &players[displayplayers[3]] && splitscreen > 2)))) { y = 232-(stplyr->kartstuff[k_cardanimation]/2); splitflags = V_SNAPTOBOTTOM; @@ -8166,8 +8143,8 @@ static void K_drawBattleFullscreen(void) { scale /= 2; - if (stplyr == &players[secondarydisplayplayer] - || (stplyr == &players[fourthdisplayplayer] && splitscreen > 2)) + if (stplyr == &players[displayplayers[1]] + || (stplyr == &players[displayplayers[3]] && splitscreen > 2)) x = 3*BASEVIDWIDTH/4; else x = BASEVIDWIDTH/4; @@ -8176,7 +8153,7 @@ static void K_drawBattleFullscreen(void) { if (stplyr->exiting) { - if (stplyr == &players[secondarydisplayplayer]) + if (stplyr == &players[displayplayers[1]]) x = BASEVIDWIDTH-96; else x = 96; @@ -8188,7 +8165,7 @@ static void K_drawBattleFullscreen(void) if (stplyr->exiting) { - if (stplyr == &players[displayplayer]) + if (stplyr == &players[displayplayers[0]]) V_DrawFadeScreen(0xFF00, 16); if (stplyr->exiting < 6*TICRATE && !stplyr->spectator) { @@ -8218,9 +8195,9 @@ static void K_drawBattleFullscreen(void) { if (splitscreen > 1) ty = (BASEVIDHEIGHT/4)+33; - if ((splitscreen == 1 && stplyr == &players[secondarydisplayplayer]) - || (stplyr == &players[thirddisplayplayer] && splitscreen > 1) - || (stplyr == &players[fourthdisplayplayer] && splitscreen > 2)) + if ((splitscreen == 1 && stplyr == &players[displayplayers[1]]) + || (stplyr == &players[displayplayers[2]] && splitscreen > 1) + || (stplyr == &players[displayplayers[3]] && splitscreen > 2)) ty += (BASEVIDHEIGHT/2); } else @@ -8273,11 +8250,11 @@ static void K_drawKartFirstPerson(void) if (stplyr->spectator || !stplyr->mo || (stplyr->mo->flags2 & MF2_DONTDRAW)) return; - if (stplyr == &players[secondarydisplayplayer] && splitscreen) + if (stplyr == &players[displayplayers[1]] && splitscreen) { pn = pnum[1]; tn = turn[1]; dr = drift[1]; } - else if (stplyr == &players[thirddisplayplayer] && splitscreen > 1) + else if (stplyr == &players[displayplayers[2]] && splitscreen > 1) { pn = pnum[2]; tn = turn[2]; dr = drift[2]; } - else if (stplyr == &players[fourthdisplayplayer] && splitscreen > 2) + else if (stplyr == &players[displayplayers[3]] && splitscreen > 2) { pn = pnum[3]; tn = turn[3]; dr = drift[3]; } else { pn = pnum[0]; tn = turn[0]; dr = drift[0]; } @@ -8402,11 +8379,11 @@ static void K_drawKartFirstPerson(void) V_DrawFixedPatch(x, y, scale, splitflags, kp_fpview[target], colmap); - if (stplyr == &players[secondarydisplayplayer] && splitscreen) + if (stplyr == &players[displayplayers[1]] && splitscreen) { pnum[1] = pn; turn[1] = tn; drift[1] = dr; } - else if (stplyr == &players[thirddisplayplayer] && splitscreen > 1) + else if (stplyr == &players[displayplayers[2]] && splitscreen > 1) { pnum[2] = pn; turn[2] = tn; drift[2] = dr; } - else if (stplyr == &players[fourthdisplayplayer] && splitscreen > 2) + else if (stplyr == &players[displayplayers[3]] && splitscreen > 2) { pnum[3] = pn; turn[3] = tn; drift[3] = dr; } else { pnum[0] = pn; turn[0] = tn; drift[0] = dr; } @@ -8627,7 +8604,7 @@ static void K_drawDistributionDebugger(void) boolean dontforcespb = false; boolean spbrush = false; - if (stplyr != &players[displayplayer]) // only for p1 + if (stplyr != &players[displayplayers[0]]) // only for p1 return; // The only code duplication from the Kart, just to avoid the actual item function from calculating pingame twice @@ -8691,7 +8668,7 @@ static void K_drawDistributionDebugger(void) static void K_drawCheckpointDebugger(void) { - if (stplyr != &players[displayplayer]) // only for p1 + if (stplyr != &players[displayplayers[0]]) // only for p1 return; if (stplyr->starpostnum >= (numstarposts - (numstarposts/2))) @@ -8705,20 +8682,21 @@ void K_drawKartHUD(void) { boolean isfreeplay = false; boolean battlefullscreen = false; + UINT8 i; // Define the X and Y for each drawn object // This is handled by console/menu values K_initKartHUD(); // Draw that fun first person HUD! Drawn ASAP so it looks more "real". - if ((stplyr == &players[displayplayer] && !camera.chase) - || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase) - || ((splitscreen > 1 && stplyr == &players[thirddisplayplayer]) && !camera3.chase) - || ((splitscreen > 2 && stplyr == &players[fourthdisplayplayer]) && !camera4.chase)) - K_drawKartFirstPerson(); + for (i = 0; i <= splitscreen; i++) + { + if (stplyr == &players[displayplayers[i]] && !camera[i].chase) + K_drawKartFirstPerson(); + } // Draw full screen stuff that turns off the rest of the HUD - if (mapreset && stplyr == &players[displayplayer]) + if (mapreset && stplyr == &players[displayplayers[0]]) { K_drawChallengerScreen(); return; @@ -8734,7 +8712,7 @@ void K_drawKartHUD(void) if (!demo.title && (!battlefullscreen || splitscreen)) { // Draw the CHECK indicator before the other items, so it's overlapped by everything else - if (cv_kartcheck.value && !splitscreen && !players[displayplayer].exiting) + if (cv_kartcheck.value && !splitscreen && !players[displayplayers[0]].exiting) K_drawKartPlayerCheck(); // Draw WANTED status diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 0ea0c8097..299870e00 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -118,14 +118,14 @@ void COM_Lua_f(void) flags = (UINT8)lua_tointeger(gL, -1); lua_pop(gL, 1); // pop flags - if (flags & 2) // flag 2: splitscreen player command. + if (flags & 2) // flag 2: splitscreen player command. TODO: support 4P { if (!splitscreen) { lua_pop(gL, 1); // pop command info table return; // can't execute splitscreen command without player 2! } - playernum = secondarydisplayplayer; + playernum = displayplayers[1]; } if (netgame) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index fb6814b25..31beecf09 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -797,24 +797,24 @@ void LUAh_GameHUD(player_t *stplayr) lua_remove(gL, -3); // pop HUD LUA_PushUserdata(gL, stplayr, META_PLAYER); - if (splitscreen > 2 && stplayr == &players[fourthdisplayplayer]) + if (splitscreen > 2 && stplayr == &players[displayplayers[3]]) { - LUA_PushUserdata(gL, &camera4, META_CAMERA); + LUA_PushUserdata(gL, &camera[3], META_CAMERA); camnum = 4; } - else if (splitscreen > 1 && stplayr == &players[thirddisplayplayer]) + else if (splitscreen > 1 && stplayr == &players[displayplayers[2]]) { - LUA_PushUserdata(gL, &camera3, META_CAMERA); + LUA_PushUserdata(gL, &camera[2], META_CAMERA); camnum = 3; } - else if (splitscreen && stplayr == &players[secondarydisplayplayer]) + else if (splitscreen && stplayr == &players[displayplayers[1]]) { - LUA_PushUserdata(gL, &camera2, META_CAMERA); + LUA_PushUserdata(gL, &camera[1], META_CAMERA); camnum = 2; } else { - LUA_PushUserdata(gL, &camera, META_CAMERA); + LUA_PushUserdata(gL, &camera[0], META_CAMERA); camnum = 1; } diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index b56538d0f..dfb344e34 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -421,13 +421,13 @@ static int mobj_set(lua_State *L) case mobj_angle: mo->angle = luaL_checkangle(L, 3); if (mo->player == &players[consoleplayer]) - localangle = mo->angle; - else if (mo->player == &players[secondarydisplayplayer]) - localangle2 = mo->angle; - else if (mo->player == &players[thirddisplayplayer]) - localangle3 = mo->angle; - else if (mo->player == &players[fourthdisplayplayer]) - localangle4 = mo->angle; + localangle[0] = mo->angle; + else if (mo->player == &players[displayplayers[1]]) + localangle[1] = mo->angle; + else if (mo->player == &players[displayplayers[2]]) + localangle[2] = mo->angle; + else if (mo->player == &players[displayplayers[3]]) + localangle[3] = mo->angle; break; case mobj_sprite: mo->sprite = luaL_checkinteger(L, 3); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 73d5ecbc0..4921ba7a4 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -382,13 +382,13 @@ static int player_set(lua_State *L) else if (fastcmp(field,"aiming")) { plr->aiming = luaL_checkangle(L, 3); if (plr == &players[consoleplayer]) - localaiming = plr->aiming; - else if (plr == &players[secondarydisplayplayer]) - localaiming2 = plr->aiming; - else if (plr == &players[thirddisplayplayer]) - localaiming3 = plr->aiming; - else if (plr == &players[fourthdisplayplayer]) - localaiming4 = plr->aiming; + localaiming[0] = plr->aiming; + else if (plr == &players[displayplayers[1]]) + localaiming[1] = plr->aiming; + else if (plr == &players[displayplayers[2]]) + localaiming[2] = plr->aiming; + else if (plr == &players[displayplayers[3]]) + localaiming[3] = plr->aiming; } else if (fastcmp(field,"health")) plr->health = (INT32)luaL_checkinteger(L, 3); diff --git a/src/m_menu.c b/src/m_menu.c index 4eb184462..cb62738ad 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5787,7 +5787,7 @@ static void M_DrawPlaybackMenu(void) if (splitscreen >= i - playback_view1) { - INT32 ply = *G_GetDisplayplayerPtr(i - playback_view1 + 1); + INT32 ply = displayplayers[i - playback_view1 + 1]; icon = facerankprefix[players[ply].skin]; if (i != itemOn) @@ -5836,19 +5836,10 @@ static void M_DrawPlaybackMenu(void) break; case playback_view1: - str = player_names[displayplayer]; - break; - case playback_view2: - str = player_names[secondarydisplayplayer]; - break; - case playback_view3: - str = player_names[thirddisplayplayer]; - break; - case playback_view4: - str = player_names[fourthdisplayplayer]; + str = player_names[displayplayers[i - playback_view1]]; // 0 to 3 break; default: // shouldn't ever be reached but whatever @@ -9472,7 +9463,7 @@ static void M_SetupMultiPlayer2(INT32 choice) strcpy (setupm_name, cv_playername2.string); // set for splitscreen secondary player - setupm_player = &players[secondarydisplayplayer]; + setupm_player = &players[displayplayers[1]]; setupm_cvskin = &cv_skin2; setupm_cvcolor = &cv_playercolor2; setupm_cvname = &cv_playername2; @@ -9484,7 +9475,7 @@ static void M_SetupMultiPlayer2(INT32 choice) setupm_fakecolor = setupm_cvcolor->value; // disable skin changes if we can't actually change skins - if (splitscreen && !CanChangeSkin(secondarydisplayplayer)) + if (splitscreen && !CanChangeSkin(displayplayers[1])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); @@ -9503,7 +9494,7 @@ static void M_SetupMultiPlayer3(INT32 choice) strcpy(setupm_name, cv_playername3.string); // set for splitscreen third player - setupm_player = &players[thirddisplayplayer]; + setupm_player = &players[displayplayers[2]]; setupm_cvskin = &cv_skin3; setupm_cvcolor = &cv_playercolor3; setupm_cvname = &cv_playername3; @@ -9515,7 +9506,7 @@ static void M_SetupMultiPlayer3(INT32 choice) setupm_fakecolor = setupm_cvcolor->value; // disable skin changes if we can't actually change skins - if (splitscreen > 1 && !CanChangeSkin(thirddisplayplayer)) + if (splitscreen > 1 && !CanChangeSkin(displayplayers[2])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); @@ -9534,7 +9525,7 @@ static void M_SetupMultiPlayer4(INT32 choice) strcpy(setupm_name, cv_playername4.string); // set for splitscreen fourth player - setupm_player = &players[fourthdisplayplayer]; + setupm_player = &players[displayplayers[3]]; setupm_cvskin = &cv_skin4; setupm_cvcolor = &cv_playercolor4; setupm_cvname = &cv_playername4; @@ -9546,7 +9537,7 @@ static void M_SetupMultiPlayer4(INT32 choice) setupm_fakecolor = setupm_cvcolor->value; // disable skin changes if we can't actually change skins - if (splitscreen > 2 && !CanChangeSkin(fourthdisplayplayer)) + if (splitscreen > 2 && !CanChangeSkin(displayplayers[3])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); diff --git a/src/m_misc.c b/src/m_misc.c index c95aa392c..f4a4ec291 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -743,12 +743,12 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png else snprintf(lvlttltext, 48, "Unknown"); - if (gamestate == GS_LEVEL && &players[displayplayer] && players[displayplayer].mo) + if (gamestate == GS_LEVEL && &players[displayplayers[0]] && players[displayplayers[0]].mo) snprintf(locationtxt, 40, "X:%d Y:%d Z:%d A:%d", - players[displayplayer].mo->x>>FRACBITS, - players[displayplayer].mo->y>>FRACBITS, - players[displayplayer].mo->z>>FRACBITS, - FixedInt(AngleFixed(players[displayplayer].mo->angle))); + players[displayplayers[0]].mo->x>>FRACBITS, + players[displayplayers[0]].mo->y>>FRACBITS, + players[displayplayers[0]].mo->z>>FRACBITS, + FixedInt(AngleFixed(players[displayplayers[0]].mo->angle))); else snprintf(locationtxt, 40, "Unknown"); diff --git a/src/p_enemy.c b/src/p_enemy.c index 6d5137c43..f5073deab 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4174,12 +4174,12 @@ void A_OverlayThink(mobj_t *actor) { angle_t viewingangle; - if (players[displayplayer].awayviewtics) - viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); - else if (!camera.chase && players[displayplayer].mo) - viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y); + if (players[displayplayers[0]].awayviewtics) + viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y); + else if (!camera[0].chase && players[displayplayers[0]].mo) + viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y); else - viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, camera.x, camera.y); + viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, camera[0].x, camera[0].y); destx = actor->target->x + P_ReturnThrustX(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale)); desty = actor->target->y + P_ReturnThrustY(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale)); diff --git a/src/p_floor.c b/src/p_floor.c index e11fe4030..ccbfd6eae 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2536,9 +2536,9 @@ void T_CameraScanner(elevator_t *elevator) lastleveltime = leveltime; } - if (players[displayplayer].mo) + if (players[displayplayers[0]].mo) { - if (players[displayplayer].mo->subsector->sector == elevator->actionsector) + if (players[displayplayers[0]].mo->subsector->sector == elevator->actionsector) { if (t_cam_dist == -42) t_cam_dist = cv_cam_dist.value; @@ -2564,9 +2564,9 @@ void T_CameraScanner(elevator_t *elevator) } } - if (splitscreen && players[secondarydisplayplayer].mo) + if (splitscreen && players[displayplayers[1]].mo) { - if (players[secondarydisplayplayer].mo->subsector->sector == elevator->actionsector) + if (players[displayplayers[1]].mo->subsector->sector == elevator->actionsector) { if (t_cam2_rotate == -42) t_cam2_dist = cv_cam2_dist.value; @@ -2592,9 +2592,9 @@ void T_CameraScanner(elevator_t *elevator) } } - if (splitscreen > 1 && players[thirddisplayplayer].mo) + if (splitscreen > 1 && players[displayplayers[2]].mo) { - if (players[thirddisplayplayer].mo->subsector->sector == elevator->actionsector) + if (players[displayplayers[2]].mo->subsector->sector == elevator->actionsector) { if (t_cam3_rotate == -42) t_cam3_dist = cv_cam3_dist.value; @@ -2620,9 +2620,9 @@ void T_CameraScanner(elevator_t *elevator) } } - if (splitscreen > 2 && players[fourthdisplayplayer].mo) + if (splitscreen > 2 && players[displayplayers[3]].mo) { - if (players[fourthdisplayplayer].mo->subsector->sector == elevator->actionsector) + if (players[displayplayers[3]].mo->subsector->sector == elevator->actionsector) { if (t_cam4_rotate == -42) t_cam4_dist = cv_cam4_dist.value; diff --git a/src/p_inter.c b/src/p_inter.c index f70bcf3ee..e6cb19993 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -62,11 +62,11 @@ void P_ForceConstant(const BasicFF_t *FFInfo) ConstantQuake.Magnitude = FFInfo->Magnitude; if (FFInfo->player == &players[consoleplayer]) I_Tactile(ConstantForce, &ConstantQuake); - else if (splitscreen && FFInfo->player == &players[secondarydisplayplayer]) + else if (splitscreen && FFInfo->player == &players[displayplayers[1]]) I_Tactile2(ConstantForce, &ConstantQuake); - else if (splitscreen > 1 && FFInfo->player == &players[thirddisplayplayer]) + else if (splitscreen > 1 && FFInfo->player == &players[displayplayers[2]]) I_Tactile3(ConstantForce, &ConstantQuake); - else if (splitscreen > 2 && FFInfo->player == &players[fourthdisplayplayer]) + else if (splitscreen > 2 && FFInfo->player == &players[displayplayers[3]]) I_Tactile4(ConstantForce, &ConstantQuake); } void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End) @@ -83,11 +83,11 @@ void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End) RampQuake.End = End; if (FFInfo->player == &players[consoleplayer]) I_Tactile(ConstantForce, &RampQuake); - else if (splitscreen && FFInfo->player == &players[secondarydisplayplayer]) + else if (splitscreen && FFInfo->player == &players[displayplayers[1]]) I_Tactile2(ConstantForce, &RampQuake); - else if (splitscreen > 1 && FFInfo->player == &players[thirddisplayplayer]) + else if (splitscreen > 1 && FFInfo->player == &players[displayplayers[2]]) I_Tactile3(ConstantForce, &RampQuake); - else if (splitscreen > 2 && FFInfo->player == &players[fourthdisplayplayer]) + else if (splitscreen > 2 && FFInfo->player == &players[displayplayers[3]]) I_Tactile4(ConstantForce, &RampQuake); } @@ -218,7 +218,7 @@ void P_DoNightsScore(player_t *player) dummymo->fuse = 3*TICRATE; // What?! NO, don't use the camera! Scale up instead! - //P_InstaThrust(dummymo, R_PointToAngle2(dummymo->x, dummymo->y, camera.x, camera.y), 3*FRACUNIT); + //P_InstaThrust(dummymo, R_PointToAngle2(dummymo->x, dummymo->y, camera[0].x, camera[0].y), 3*FRACUNIT); dummymo->scalespeed = FRACUNIT/25; dummymo->destscale = 2*FRACUNIT; } @@ -1180,13 +1180,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) toucher->angle = special->angle; if (player == &players[consoleplayer]) - localangle = toucher->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = toucher->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = toucher->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = toucher->angle; + localangle[0] = toucher->angle; + else if (player == &players[displayplayers[1]]) + localangle[1] = toucher->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = toucher->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = toucher->angle; P_ResetPlayer(player); @@ -1209,7 +1209,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } // CECHO showing you what this item is - if (player == &players[displayplayer] || G_IsSpecialStage(gamemap)) + if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) { HU_SetCEchoFlags(V_AUTOFADEOUT); HU_SetCEchoDuration(4); @@ -1231,7 +1231,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } // CECHO showing you what this item is - if (player == &players[displayplayer] || G_IsSpecialStage(gamemap)) + if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) { HU_SetCEchoFlags(V_AUTOFADEOUT); HU_SetCEchoDuration(4); @@ -1263,7 +1263,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } // CECHO showing you what this item is - if (player == &players[displayplayer] || G_IsSpecialStage(gamemap)) + if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) { HU_SetCEchoFlags(V_AUTOFADEOUT); HU_SetCEchoDuration(4); @@ -1293,7 +1293,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } // CECHO showing you what this item is - if (player == &players[displayplayer] || G_IsSpecialStage(gamemap)) + if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) { HU_SetCEchoFlags(V_AUTOFADEOUT); HU_SetCEchoDuration(4); @@ -1321,7 +1321,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } // CECHO showing you what this item is - if (player == &players[displayplayer] || G_IsSpecialStage(gamemap)) + if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) { HU_SetCEchoFlags(V_AUTOFADEOUT); HU_SetCEchoDuration(4); @@ -2324,17 +2324,17 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) AM_Stop(); //added : 22-02-98: recenter view for next life... - localaiming = 0; + localaiming[0] = 0; } - if (target->player == &players[secondarydisplayplayer]) + if (target->player == &players[displayplayers[1]]) { // added : 22-02-98: recenter view for next life... - localaiming2 = 0; + localaiming[1] = 0; } - if (target->player == &players[thirddisplayplayer]) - localaiming3 = 0; - if (target->player == &players[fourthdisplayplayer]) - localaiming4 = 0; + if (target->player == &players[displayplayers[2]]) + localaiming[2] = 0; + if (target->player == &players[displayplayers[3]]) + localaiming[3] = 0; //tag deaths handled differently in suicide cases. Don't count spectators! /*if (G_TagGametype() diff --git a/src/p_local.h b/src/p_local.h index 21fb3ddbe..5f7c4ef98 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -108,7 +108,7 @@ typedef struct camera_s fixed_t pan; } camera_t; -extern camera_t camera, camera2, camera3, camera4; +extern camera_t camera[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_dist, cv_cam_still, cv_cam_height; extern consvar_t cv_cam_speed, cv_cam_rotate, cv_cam_rotspeed; @@ -126,8 +126,6 @@ extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate; extern fixed_t t_cam3_dist, t_cam3_height, t_cam3_rotate; extern fixed_t t_cam4_dist, t_cam4_height, t_cam4_rotate; -camera_t *P_GetCameraPtr(UINT8 viewnum); - fixed_t P_GetPlayerHeight(player_t *player); fixed_t P_GetPlayerSpinHeight(player_t *player); void P_AddPlayerScore(player_t *player, UINT32 amount); diff --git a/src/p_map.c b/src/p_map.c index 9b0db658b..3c2aad441 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -215,13 +215,13 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (!demo.playback || P_AnalogMove(object->player)) { if (object->player == &players[consoleplayer]) - localangle = spring->angle; - else if (object->player == &players[secondarydisplayplayer]) - localangle2 = spring->angle; - else if (object->player == &players[thirddisplayplayer]) - localangle3 = spring->angle; - else if (object->player == &players[fourthdisplayplayer]) - localangle4 = spring->angle; + localangle[0] = spring->angle; + else if (object->player == &players[displayplayers[1]]) + localangle[1] = spring->angle; + else if (object->player == &players[displayplayers[2]]) + localangle[2] = spring->angle; + else if (object->player == &players[displayplayers[3]]) + localangle[3] = spring->angle; } } @@ -1267,13 +1267,13 @@ static boolean PIT_CheckThing(mobj_t *thing) if (!demo.playback || P_AnalogMove(thing->player)) { if (thing->player == &players[consoleplayer]) - localangle = thing->angle; - else if (thing->player == &players[secondarydisplayplayer]) - localangle2 = thing->angle; - else if (thing->player == &players[thirddisplayplayer]) - localangle3 = thing->angle; - else if (thing->player == &players[fourthdisplayplayer]) - localangle4 = thing->angle; + localangle[0] = thing->angle; + else if (thing->player == &players[displayplayers[1]]) + localangle[1] = thing->angle; + else if (thing->player == &players[displayplayers[2]]) + localangle[2] = thing->angle; + else if (thing->player == &players[displayplayers[3]]) + localangle[3] = thing->angle; } return true; @@ -2504,41 +2504,46 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) subsector_t *s = R_PointInSubsector(x, y); boolean retval = true; boolean itsatwodlevel = false; + UINT8 i; floatok = false; - if (twodlevel - || (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera3 && players[thirddisplayplayer].mo && (players[thirddisplayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera4 && players[fourthdisplayplayer].mo && (players[fourthdisplayplayer].mo->flags2 & MF2_TWOD))) + if (twodlevel) itsatwodlevel = true; + else + { + for (i = 0; i <= splitscreen; i++) + { + if (thiscam == &camera[i] && players[displayplayers[i]].mo + && (players[displayplayers[i]].mo->flags2 & MF2_TWOD)) + { + itsatwodlevel = true; + break; + } + } + } - if (!itsatwodlevel && players[displayplayer].mo) + if (!itsatwodlevel && players[displayplayers[0]].mo) { fixed_t tryx = thiscam->x; fixed_t tryy = thiscam->y; + for (i = 0; i <= splitscreen; i++) + { #ifndef NOCLIPCAM - if ((thiscam == &camera && (players[displayplayer].pflags & PF_NOCLIP)) - || (thiscam == &camera2 && (players[secondarydisplayplayer].pflags & PF_NOCLIP)) - || (thiscam == &camera3 && (players[thirddisplayplayer].pflags & PF_NOCLIP)) - || (thiscam == &camera4 && (players[fourthdisplayplayer].pflags & PF_NOCLIP)) - || (leveltime < introtime)) + if ((thiscam == &camera[i] && (players[displayplayers[i]].pflags & PF_NOCLIP)) || (leveltime < introtime)) // Noclipping player camera noclips too!! #else - if ((thiscam == &camera && !(players[displayplayer].pflags & PF_TIMEOVER)) - || (thiscam == &camera2 && !(players[secondarydisplayplayer].pflags & PF_TIMEOVER)) - || (thiscam == &camera3 && !(players[thirddisplayplayer].pflags & PF_TIMEOVER)) - || (thiscam == &camera4 && !(players[fourthdisplayplayer].pflags & PF_TIMEOVER))) + if (thiscam == &camera[i] && !(players[displayplayers[i]].pflags & PF_TIMEOVER)) // Time Over should not clip through walls #endif - { // Noclipping player camera noclips too!! - floatok = true; - thiscam->floorz = thiscam->z; - thiscam->ceilingz = thiscam->z + thiscam->height; - thiscam->x = x; - thiscam->y = y; - thiscam->subsector = s; - return true; + { + floatok = true; + thiscam->floorz = thiscam->z; + thiscam->ceilingz = thiscam->z + thiscam->height; + thiscam->x = x; + thiscam->y = y; + thiscam->subsector = s; + return true; + } } do { diff --git a/src/p_maputl.c b/src/p_maputl.c index c5a593d3e..355c58db8 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -339,9 +339,9 @@ void P_CameraLineOpening(line_t *linedef) frontceiling = sectors[front->camsec].ceilingheight; #ifdef ESLOPE if (sectors[front->camsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetZAt(sectors[front->camsec].f_slope, camera.x, camera.y); + frontfloor = P_GetZAt(sectors[front->camsec].f_slope, camera[0].x, camera[0].y); if (sectors[front->camsec].c_slope) - frontceiling = P_GetZAt(sectors[front->camsec].c_slope, camera.x, camera.y); + frontceiling = P_GetZAt(sectors[front->camsec].c_slope, camera[0].x, camera[0].y); #endif } @@ -351,9 +351,9 @@ void P_CameraLineOpening(line_t *linedef) frontceiling = sectors[front->heightsec].ceilingheight; #ifdef ESLOPE if (sectors[front->heightsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetZAt(sectors[front->heightsec].f_slope, camera.x, camera.y); + frontfloor = P_GetZAt(sectors[front->heightsec].f_slope, camera[0].x, camera[0].y); if (sectors[front->heightsec].c_slope) - frontceiling = P_GetZAt(sectors[front->heightsec].c_slope, camera.x, camera.y); + frontceiling = P_GetZAt(sectors[front->heightsec].c_slope, camera[0].x, camera[0].y); #endif } else @@ -367,9 +367,9 @@ void P_CameraLineOpening(line_t *linedef) backceiling = sectors[back->camsec].ceilingheight; #ifdef ESLOPE if (sectors[back->camsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetZAt(sectors[back->camsec].f_slope, camera.x, camera.y); + frontfloor = P_GetZAt(sectors[back->camsec].f_slope, camera[0].x, camera[0].y); if (sectors[back->camsec].c_slope) - frontceiling = P_GetZAt(sectors[back->camsec].c_slope, camera.x, camera.y); + frontceiling = P_GetZAt(sectors[back->camsec].c_slope, camera[0].x, camera[0].y); #endif } else if (back->heightsec >= 0) @@ -378,9 +378,9 @@ void P_CameraLineOpening(line_t *linedef) backceiling = sectors[back->heightsec].ceilingheight; #ifdef ESLOPE if (sectors[back->heightsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetZAt(sectors[back->heightsec].f_slope, camera.x, camera.y); + frontfloor = P_GetZAt(sectors[back->heightsec].f_slope, camera[0].x, camera[0].y); if (sectors[back->heightsec].c_slope) - frontceiling = P_GetZAt(sectors[back->heightsec].c_slope, camera.x, camera.y); + frontceiling = P_GetZAt(sectors[back->heightsec].c_slope, camera[0].x, camera[0].y); #endif } else diff --git a/src/p_mobj.c b/src/p_mobj.c index f31075f36..102af9dca 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1136,44 +1136,18 @@ static void P_PlayerFlip(mobj_t *mo) else if (mo->player->pflags & PF_FLIPCAM) { mo->player->aiming = InvAngle(mo->player->aiming); - if (mo->player-players == displayplayer) + + for (i = 0; i <= splitscreen; i++) { - localaiming = mo->player->aiming; - if (camera.chase) { - camera.aiming = InvAngle(camera.aiming); - camera.z = mo->z - camera.z + mo->z; - if (mo->eflags & MFE_VERTICALFLIP) - camera.z += FixedMul(20*FRACUNIT, mo->scale); - } - } - else if (mo->player-players == secondarydisplayplayer) - { - localaiming2 = mo->player->aiming; - if (camera2.chase) { - camera2.aiming = InvAngle(camera2.aiming); - camera2.z = mo->z - camera2.z + mo->z; - if (mo->eflags & MFE_VERTICALFLIP) - camera2.z += FixedMul(20*FRACUNIT, mo->scale); - } - } - else if (mo->player-players == thirddisplayplayer) - { - localaiming3 = mo->player->aiming; - if (camera3.chase) { - camera3.aiming = InvAngle(camera3.aiming); - camera3.z = mo->z - camera3.z + mo->z; - if (mo->eflags & MFE_VERTICALFLIP) - camera3.z += FixedMul(20*FRACUNIT, mo->scale); - } - } - else if (mo->player-players == fourthdisplayplayer) - { - localaiming4 = mo->player->aiming; - if (camera4.chase) { - camera4.aiming = InvAngle(camera4.aiming); - camera4.z = mo->z - camera4.z + mo->z; - if (mo->eflags & MFE_VERTICALFLIP) - camera4.z += FixedMul(20*FRACUNIT, mo->scale); + if (mo->player-players == displayplayers[i]) + { + localaiming[i] = mo->player->aiming; + if (camera[i].chase) { + camera[i].aiming = InvAngle(camera[i].aiming); + camera[i].z = mo->z - camera[i].z + mo->z; + if (mo->eflags & MFE_VERTICALFLIP) + camera[i].z += FixedMul(20*FRACUNIT, mo->scale); + } } } } @@ -3546,17 +3520,26 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled { boolean itsatwodlevel = false; postimg_t postimg = postimg_none; + UINT8 i; // This can happen when joining if (thiscam->subsector == NULL || thiscam->subsector->sector == NULL) return true; - if (twodlevel - || (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera3 && players[thirddisplayplayer].mo && (players[thirddisplayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera4 && players[fourthdisplayplayer].mo && (players[fourthdisplayplayer].mo->flags2 & MF2_TWOD))) + if (twodlevel) itsatwodlevel = true; + else + { + for (i = 0; i <= splitscreen; i++) + { + if (thiscam == &camera[i] && players[displayplayers[i]].mo + && (players[displayplayers[i]].mo->flags2 & MF2_TWOD)) + { + itsatwodlevel = true; + break; + } + } + } if (encoremode) postimg = postimg_mirror; @@ -3588,14 +3571,11 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled if (postimg != postimg_none) { - if (splitscreen && player == &players[secondarydisplayplayer]) - postimgtype2 = postimg; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - postimgtype3 = postimg; - else if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - postimgtype4 = postimg; - else - postimgtype = postimg; + for (i = 0; i <= splitscreen; i++) + { + if (player == &players[displayplayers[i]]) + postimgtype[i] = postimg; + } } if (thiscam->momx || thiscam->momy) @@ -3641,11 +3621,11 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled fixed_t cam_height = cv_cam_height.value; thiscam->z = thiscam->floorz; - if (player == &players[secondarydisplayplayer]) + if (player == &players[displayplayers[1]]) cam_height = cv_cam2_height.value; - if (player == &players[thirddisplayplayer]) + if (player == &players[displayplayers[2]]) cam_height = cv_cam3_height.value; - if (player == &players[fourthdisplayplayer]) + if (player == &players[displayplayers[3]]) cam_height = cv_cam4_height.value; if (thiscam->z > player->mo->z + player->mo->height + FixedMul(cam_height*FRACUNIT + 16*FRACUNIT, player->mo->scale)) { @@ -6101,12 +6081,12 @@ void P_RunOverlays(void) { angle_t viewingangle; - if (players[displayplayer].awayviewtics) - viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); - else if (!camera.chase && players[displayplayer].mo) - viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y); + if (players[displayplayers[0]].awayviewtics) + viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y); + else if (!camera[0].chase && players[displayplayers[0]].mo) + viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y); else - viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, camera.x, camera.y); + viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, camera[0].x, camera[0].y); if (!(mo->state->frame & FF_ANIMATE) && mo->state->var1) viewingangle += ANGLE_180; @@ -6680,7 +6660,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target && mobj->target->health && mobj->target->player && !mobj->target->player->spectator && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD - /*&& players[displayplayer].mo && !players[displayplayer].spectator*/) + /*&& players[displayplayers[0]].mo && !players[displayplayers[0]].spectator*/) { fixed_t scale = 3*mobj->target->scale; mobj->color = mobj->target->color; @@ -6688,7 +6668,7 @@ void P_MobjThinker(mobj_t *mobj) if ((G_RaceGametype() || mobj->target->player->kartstuff[k_bumper] <= 0) #if 1 // Set to 0 to test without needing to host - || ((mobj->target->player == &players[displayplayer]) || P_IsLocalPlayer(mobj->target->player)) + || ((mobj->target->player == &players[displayplayers[0]]) || P_IsLocalPlayer(mobj->target->player)) #endif ) mobj->flags2 |= MF2_DONTDRAW; @@ -6699,10 +6679,10 @@ void P_MobjThinker(mobj_t *mobj) mobj->angle = R_PointToAngle(mobj->x, mobj->y) + ANGLE_90; // literally only happened because i wanted to ^L^R the SPR_ITEM's - if (!splitscreen && players[displayplayer].mo) + if (!splitscreen && players[displayplayers[0]].mo) { - scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayer].mo->x-mobj->target->x, - players[displayplayer].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); + scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, + players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); if (scale > 16*mobj->target->scale) scale = 16*mobj->target->scale; } @@ -6887,7 +6867,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target && mobj->target->health && mobj->tracer && mobj->target->player && !mobj->target->player->spectator && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD - && players[displayplayer].mo && !players[displayplayer].spectator) + && players[displayplayers[0]].mo && !players[displayplayers[0]].spectator) { fixed_t scale = 3*mobj->target->scale; @@ -6909,8 +6889,8 @@ void P_MobjThinker(mobj_t *mobj) if (!splitscreen) { - scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayer].mo->x-mobj->target->x, - players[displayplayer].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); + scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, + players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); if (scale > 16*mobj->target->scale) scale = 16*mobj->target->scale; } @@ -8296,12 +8276,12 @@ void P_MobjThinker(mobj_t *mobj) angle_t viewingangle; statenum_t curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); - if (players[displayplayer].awayviewtics) - viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); - else if (!camera.chase && players[displayplayer].mo) - viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y); + if (players[displayplayers[0]].awayviewtics) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y); + else if (!camera[0].chase && players[displayplayers[0]].mo) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y); else - viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera.x, camera.y); + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera[0].x, camera[0].y); if (curstate > S_THUNDERSHIELD15) viewingangle += ANGLE_180; @@ -10562,13 +10542,13 @@ void P_PrecipitationEffects(void) // Local effects from here on out! // If we're not in game fully yet, we don't worry about them. - if (!playeringame[displayplayer] || !players[displayplayer].mo) + if (!playeringame[displayplayers[0]] || !players[displayplayers[0]].mo) return; if (sound_disabled) return; // Sound off? D'aw, no fun. - if (players[displayplayer].mo->subsector->sector->ceilingpic == skyflatnum) + if (players[displayplayers[0]].mo->subsector->sector->ceilingpic == skyflatnum) volume = 255; // Sky above? We get it full blast. else { @@ -10576,17 +10556,17 @@ void P_PrecipitationEffects(void) fixed_t closedist, newdist; // Essentially check in a 1024 unit radius of the player for an outdoor area. - yl = players[displayplayer].mo->y - 1024*FRACUNIT; - yh = players[displayplayer].mo->y + 1024*FRACUNIT; - xl = players[displayplayer].mo->x - 1024*FRACUNIT; - xh = players[displayplayer].mo->x + 1024*FRACUNIT; + yl = players[displayplayers[0]].mo->y - 1024*FRACUNIT; + yh = players[displayplayers[0]].mo->y + 1024*FRACUNIT; + xl = players[displayplayers[0]].mo->x - 1024*FRACUNIT; + xh = players[displayplayers[0]].mo->x + 1024*FRACUNIT; closedist = 2048*FRACUNIT; for (y = yl; y <= yh; y += FRACUNIT*64) for (x = xl; x <= xh; x += FRACUNIT*64) { if (R_PointInSubsector(x, y)->sector->ceilingpic == skyflatnum) // Found the outdoors! { - newdist = S_CalculateSoundDistance(players[displayplayer].mo->x, players[displayplayer].mo->y, 0, x, y, 0); + newdist = S_CalculateSoundDistance(players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y, 0, x, y, 0); if (newdist < closedist) closedist = newdist; } @@ -10601,7 +10581,7 @@ void P_PrecipitationEffects(void) volume = 255; if (sounds_rain && (!leveltime || leveltime % 80 == 1)) - S_StartSoundAtVolume(players[displayplayer].mo, sfx_rainin, volume); + S_StartSoundAtVolume(players[displayplayers[0]].mo, sfx_rainin, volume); if (!sounds_thunder) return; @@ -10609,7 +10589,7 @@ void P_PrecipitationEffects(void) if (effects_lightning && lightningStrike && volume) { // Large, close thunder sounds to go with our lightning. - S_StartSoundAtVolume(players[displayplayer].mo, sfx_litng1 + M_RandomKey(4), volume); + S_StartSoundAtVolume(players[displayplayers[0]].mo, sfx_litng1 + M_RandomKey(4), volume); } else if (thunderchance < 20) { @@ -10617,7 +10597,7 @@ void P_PrecipitationEffects(void) if (volume < 80) volume = 80; - S_StartSoundAtVolume(players[displayplayer].mo, sfx_athun1 + M_RandomKey(2), volume); + S_StartSoundAtVolume(players[displayplayers[0]].mo, sfx_athun1 + M_RandomKey(2), volume); } } @@ -10924,15 +10904,21 @@ void P_AfterPlayerSpawn(INT32 playernum) { player_t *p = &players[playernum]; mobj_t *mobj = p->mo; + UINT8 i; if (playernum == consoleplayer) - localangle = mobj->angle; - else if (playernum == secondarydisplayplayer) - localangle2 = mobj->angle; - else if (playernum == thirddisplayplayer) - localangle3 = mobj->angle; - else if (playernum == fourthdisplayplayer) - localangle4 = mobj->angle; + localangle[0] = mobj->angle; + else if (splitscreen) + { + for (i = 1; i <= splitscreen; i++) + { + if (playernum == displayplayers[i]) + { + localangle[i] = mobj->angle; + break; + } + } + } p->viewheight = 32<x, mobj->y, mobj->angle); - if (camera.chase) + for (i = 0; i <= splitscreen; i++) { - if (displayplayer == playernum) - P_ResetCamera(p, &camera); - } - if (camera2.chase && splitscreen) - { - if (secondarydisplayplayer == playernum) - P_ResetCamera(p, &camera2); - } - if (camera3.chase && splitscreen > 1) - { - if (thirddisplayplayer == playernum) - P_ResetCamera(p, &camera3); - } - if (camera4.chase && splitscreen > 2) - { - if (fourthdisplayplayer == playernum) - P_ResetCamera(p, &camera4); + if (camera[i].chase) + { + if (displayplayers[i] == playernum) + P_ResetCamera(p, &camera[i]); + } } if (CheckForReverseGravity) diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 34402f1ac..9967969d3 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1336,13 +1336,13 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta, if (turnthings == 2 || (turnthings == 1 && !mo->player)) { mo->angle += delta; if (mo->player == &players[consoleplayer]) - localangle = mo->angle; - else if (mo->player == &players[secondarydisplayplayer]) - localangle2 = mo->angle; - else if (mo->player == &players[thirddisplayplayer]) - localangle3 = mo->angle; - else if (mo->player == &players[fourthdisplayplayer]) - localangle4 = mo->angle; + localangle[0] = mo->angle; + else if (mo->player == &players[displayplayers[1]]) + localangle[1] = mo->angle; + else if (mo->player == &players[displayplayers[2]]) + localangle[2] = mo->angle; + else if (mo->player == &players[displayplayers[3]]) + localangle[3] = mo->angle; } } } diff --git a/src/p_saveg.c b/src/p_saveg.c index c1a34b2a4..2eb0d7edb 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2106,13 +2106,13 @@ static void LoadMobjThinker(actionf_p1 thinker) mobj->player->mo = mobj; // added for angle prediction if (consoleplayer == i) - localangle = mobj->angle; - if (secondarydisplayplayer == i) - localangle2 = mobj->angle; - if (thirddisplayplayer == i) - localangle3 = mobj->angle; - if (fourthdisplayplayer == i) - localangle4 = mobj->angle; + localangle[0] = mobj->angle; + if (displayplayers[1] == i) + localangle[1] = mobj->angle; + if (displayplayers[2] == i) + localangle[2] = mobj->angle; + if (displayplayers[3] == i) + localangle[3] = mobj->angle; } if (diff & MD_MOVEDIR) mobj->movedir = READANGLE(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 8c1c9ae72..c85e95307 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2269,7 +2269,7 @@ static void P_LevelInitStuff(void) leveltime = 0; - localaiming = localaiming2 = localaiming3 = localaiming4 = 0; + memset(localaiming, 0, sizeof(localaiming)); // map object scale mapobjectscale = mapheaderinfo[gamemap-1]->mobj_scale; @@ -2536,29 +2536,29 @@ static void P_ForceCharacter(const char *forcecharskin) { if (splitscreen) { - SetPlayerSkin(secondarydisplayplayer, forcecharskin); - if ((unsigned)cv_playercolor2.value != skins[players[secondarydisplayplayer].skin].prefcolor && !modeattacking) + SetPlayerSkin(displayplayers[1], forcecharskin); + if ((unsigned)cv_playercolor2.value != skins[players[displayplayers[1]].skin].prefcolor && !modeattacking) { - CV_StealthSetValue(&cv_playercolor2, skins[players[secondarydisplayplayer].skin].prefcolor); - players[secondarydisplayplayer].skincolor = skins[players[secondarydisplayplayer].skin].prefcolor; + CV_StealthSetValue(&cv_playercolor2, skins[players[displayplayers[1]].skin].prefcolor); + players[displayplayers[1]].skincolor = skins[players[displayplayers[1]].skin].prefcolor; } if (splitscreen > 1) { - SetPlayerSkin(thirddisplayplayer, forcecharskin); - if ((unsigned)cv_playercolor3.value != skins[players[thirddisplayplayer].skin].prefcolor && !modeattacking) + SetPlayerSkin(displayplayers[2], forcecharskin); + if ((unsigned)cv_playercolor3.value != skins[players[displayplayers[2]].skin].prefcolor && !modeattacking) { - CV_StealthSetValue(&cv_playercolor3, skins[players[thirddisplayplayer].skin].prefcolor); - players[thirddisplayplayer].skincolor = skins[players[thirddisplayplayer].skin].prefcolor; + CV_StealthSetValue(&cv_playercolor3, skins[players[displayplayers[2]].skin].prefcolor); + players[displayplayers[2]].skincolor = skins[players[displayplayers[2]].skin].prefcolor; } if (splitscreen > 2) { - SetPlayerSkin(fourthdisplayplayer, forcecharskin); - if ((unsigned)cv_playercolor4.value != skins[players[fourthdisplayplayer].skin].prefcolor && !modeattacking) + SetPlayerSkin(displayplayers[3], forcecharskin); + if ((unsigned)cv_playercolor4.value != skins[players[displayplayers[3]].skin].prefcolor && !modeattacking) { - CV_StealthSetValue(&cv_playercolor4, skins[players[fourthdisplayplayer].skin].prefcolor); - players[fourthdisplayplayer].skincolor = skins[players[fourthdisplayplayer].skin].prefcolor; + CV_StealthSetValue(&cv_playercolor4, skins[players[displayplayers[3]].skin].prefcolor); + players[displayplayers[3]].skincolor = skins[players[displayplayers[3]].skin].prefcolor; } } } @@ -2793,7 +2793,8 @@ boolean P_SetupLevel(boolean skipprecip) P_LevelInitStuff(); - postimgtype = postimgtype2 = postimgtype3 = postimgtype4 = postimg_none; + for (i = 0; i <= splitscreen; i++) + postimgtype[i] = postimg_none; if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0' && atoi(mapheaderinfo[gamemap-1]->forcecharacter) != 255) @@ -3180,19 +3181,8 @@ boolean P_SetupLevel(boolean skipprecip) if (!dedicated) { - P_SetupCamera(displayplayer, &camera); - if (splitscreen) - { - P_SetupCamera(secondarydisplayplayer, &camera2); - if (splitscreen > 1) - { - P_SetupCamera(thirddisplayplayer, &camera3); - if (splitscreen > 2) - { - P_SetupCamera(fourthdisplayplayer, &camera4); - } - } - } + for (i = 0; i <= splitscreen; i++) + P_SetupCamera(displayplayers[i], &camera[i]); // Salt: CV_ClearChangedFlags() messes with your settings :( /*if (!cv_cam_height.changed) @@ -3233,7 +3223,7 @@ boolean P_SetupLevel(boolean skipprecip) /*if (rendermode != render_none) CV_Set(&cv_fov, cv_fov.defaultvalue);*/ - displayplayer = consoleplayer; // Start with your OWN view, please! + displayplayers[0] = consoleplayer; // Start with your OWN view, please! } /*if (cv_useranalog.value) @@ -3312,7 +3302,10 @@ boolean P_SetupLevel(boolean skipprecip) savedata.lives = 0; } - skyVisible = skyVisible1 = skyVisible2 = skyVisible3 = skyVisible4 = true; // assume the skybox is visible on level load. + // assume the skybox is visible on level load. + skyVisible = true; + memset(skyVisiblePerPlayer, true, sizeof(skyVisiblePerPlayer)); + if (loadprecip) // uglier hack { // to make a newly loaded level start on the second frame. INT32 buf = gametic % BACKUPTICS; diff --git a/src/p_spec.c b/src/p_spec.c index 6b5f09f6d..eaa7fa3d6 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2243,7 +2243,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) I_Assert(!mo || !P_MobjWasRemoved(mo)); // If mo is there, mo must be valid! if (mo && mo->player && botingame) - bot = players[secondarydisplayplayer].mo; + bot = players[displayplayers[1]].mo; // note: only commands with linedef types >= 400 && < 500 can be used switch (line->special) @@ -2383,33 +2383,17 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { if (bot) // This might put poor Tails in a wall if he's too far behind! D: But okay, whatever! >:3 P_TeleportMove(bot, bot->x + x, bot->y + y, bot->z + z); - if (splitscreen > 2 && mo->player == &players[fourthdisplayplayer] && camera4.chase) + + for (i = 0; i <= splitscreen; i++) { - camera4.x += x; - camera4.y += y; - camera4.z += z; - camera4.subsector = R_PointInSubsector(camera4.x, camera4.y); - } - else if (splitscreen > 1 && mo->player == &players[thirddisplayplayer] && camera3.chase) - { - camera3.x += x; - camera3.y += y; - camera3.z += z; - camera3.subsector = R_PointInSubsector(camera3.x, camera3.y); - } - else if (splitscreen && mo->player == &players[secondarydisplayplayer] && camera2.chase) - { - camera2.x += x; - camera2.y += y; - camera2.z += z; - camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); - } - else if (camera.chase && mo->player == &players[displayplayer]) - { - camera.x += x; - camera.y += y; - camera.z += z; - camera.subsector = R_PointInSubsector(camera.x, camera.y); + if (mo->player == &players[displayplayers[i]] && camera[i].chase) + { + camera[i].x += x; + camera[i].y += y; + camera[i].z += z; + camera[i].subsector = R_PointInSubsector(camera[i].x, camera[i].y); + break; + } } } } @@ -2515,8 +2499,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (line->flags & ML_NOCLIMB) { // play the sound from nowhere, but only if display player triggered it - if (mo && mo->player && (mo->player == &players[displayplayer] || mo->player == &players[secondarydisplayplayer] - || mo->player == &players[thirddisplayplayer] || mo->player == &players[fourthdisplayplayer])) + if (mo && mo->player && P_IsDisplayPlayer(mo->player)) S_StartSound(NULL, sfxnum); } else if (line->flags & ML_EFFECT4) @@ -3837,13 +3820,13 @@ DoneSection2: if (!demo.playback || P_AnalogMove(player)) { if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; } if (!(lines[i].flags & ML_EFFECT4)) @@ -7845,40 +7828,40 @@ void T_Pusher(pusher_t *p) { if (thing->player == &players[consoleplayer]) { - if (thing->angle - localangle > ANGLE_180) - localangle -= (localangle - thing->angle) / 8; + if (thing->angle - localangle[0] > ANGLE_180) + localangle[0] -= (localangle[0] - thing->angle) / 8; else - localangle += (thing->angle - localangle) / 8; + localangle[0] += (thing->angle - localangle[0]) / 8; } - else if (thing->player == &players[secondarydisplayplayer]) + else if (thing->player == &players[displayplayers[1]]) { - if (thing->angle - localangle2 > ANGLE_180) - localangle2 -= (localangle2 - thing->angle) / 8; + if (thing->angle - localangle[1] > ANGLE_180) + localangle[1] -= (localangle[1] - thing->angle) / 8; else - localangle2 += (thing->angle - localangle2) / 8; + localangle[1] += (thing->angle - localangle[1]) / 8; } - else if (thing->player == &players[thirddisplayplayer]) + else if (thing->player == &players[displayplayers[2]]) { - if (thing->angle - localangle3 > ANGLE_180) - localangle3 -= (localangle3 - thing->angle) / 8; + if (thing->angle - localangle[2] > ANGLE_180) + localangle[2] -= (localangle[2] - thing->angle) / 8; else - localangle3 += (thing->angle - localangle3) / 8; + localangle[2] += (thing->angle - localangle[2]) / 8; } - else if (thing->player == &players[fourthdisplayplayer]) + else if (thing->player == &players[displayplayers[3]]) { - if (thing->angle - localangle4 > ANGLE_180) - localangle4 -= (localangle4 - thing->angle) / 8; + if (thing->angle - localangle[3] > ANGLE_180) + localangle[3] -= (localangle[3] - thing->angle) / 8; else - localangle4 += (thing->angle - localangle4) / 8; + localangle[3] += (thing->angle - localangle[3]) / 8; } /*if (thing->player == &players[consoleplayer]) - localangle = thing->angle; - else if (thing->player == &players[secondarydisplayplayer]) - localangle2 = thing->angle; - else if (thing->player == &players[thirddisplayplayer]) - localangle3 = thing->angle; - else if (thing->player == &players[fourthdisplayplayer]) - localangle4 = thing->angle;*/ + localangle[0] = thing->angle; + else if (thing->player == &players[displayplayers[1]]) + localangle[1] = thing->angle; + else if (thing->player == &players[displayplayers[2]]) + localangle[2] = thing->angle; + else if (thing->player == &players[displayplayers[3]]) + localangle[3] = thing->angle;*/ } } diff --git a/src/p_telept.c b/src/p_telept.c index 24e201fc1..74f9d462c 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -36,6 +36,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, INT32 flags2) { const INT32 takeflags2 = MF2_TWOD|MF2_OBJECTFLIP; + UINT8 i; // the move is ok, // so link the thing into its new position @@ -64,23 +65,25 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, // absolute angle position if (thing == players[consoleplayer].mo) - localangle = angle; - if (thing == players[secondarydisplayplayer].mo) - localangle2 = angle; - if (thing == players[thirddisplayplayer].mo) - localangle3 = angle; - if (thing == players[fourthdisplayplayer].mo) - localangle4 = angle; + localangle[0] = angle; + else if (splitscreen) + { + for (i = 1; i <= splitscreen; i++) + { + if (thing == players[displayplayers[i]].mo) + { + localangle[i] = angle; + break; + } + } + } // move chasecam at new player location - if (splitscreen > 2 && camera4.chase && thing->player == &players[fourthdisplayplayer]) - P_ResetCamera(thing->player, &camera4); - else if (splitscreen > 1 && camera3.chase && thing->player == &players[thirddisplayplayer]) - P_ResetCamera(thing->player, &camera3); - else if (splitscreen && camera2.chase && thing->player == &players[secondarydisplayplayer]) - P_ResetCamera(thing->player, &camera2); - else if (camera.chase && thing->player == &players[displayplayer]) - P_ResetCamera(thing->player, &camera); + for (i = 0; i <= splitscreen; i++) + { + if (thing->player == &players[displayplayers[i]] && camera[i].chase) + P_ResetCamera(thing->player, &camera[i]); + } // don't run in place after a teleport thing->player->cmomx = thing->player->cmomy = 0; @@ -123,6 +126,8 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, */ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, boolean flash, boolean dontstopmove) { + UINT8 i; + if (!P_TeleportMove(thing, x, y, z)) return false; @@ -144,24 +149,26 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle thing->reactiontime = TICRATE/2; // don't move for about half a second // absolute angle position - if (thing->player == &players[consoleplayer]) - localangle = angle; - if (thing->player == &players[secondarydisplayplayer]) - localangle2 = angle; - if (thing->player == &players[thirddisplayplayer]) - localangle3 = angle; - if (thing->player == &players[fourthdisplayplayer]) - localangle4 = angle; + if (thing == players[consoleplayer].mo) + localangle[0] = angle; + else if (splitscreen) + { + for (i = 1; i <= splitscreen; i++) + { + if (thing == players[displayplayers[i]].mo) + { + localangle[i] = angle; + break; + } + } + } // move chasecam at new player location - if (splitscreen > 2 && camera4.chase && thing->player == &players[fourthdisplayplayer]) - P_ResetCamera(thing->player, &camera4); - else if (splitscreen > 1 && camera3.chase && thing->player == &players[thirddisplayplayer]) - P_ResetCamera(thing->player, &camera3); - else if (splitscreen && camera2.chase && thing->player == &players[secondarydisplayplayer]) - P_ResetCamera(thing->player, &camera2); - else if (camera.chase && thing->player == &players[displayplayer]) - P_ResetCamera(thing->player, &camera); + for (i = 0; i <= splitscreen; i++) + { + if (thing->player == &players[displayplayers[i]] && camera[i].chase) + P_ResetCamera(thing->player, &camera[i]); + } // don't run in place after a teleport if (!dontstopmove) diff --git a/src/p_tick.c b/src/p_tick.c index 038d00a2a..2502c7213 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -583,7 +583,7 @@ void P_Ticker(boolean run) { P_MapStart(); OP_ObjectplaceMovement(&players[0]); - P_MoveChaseCamera(&players[0], &camera, false); + P_MoveChaseCamera(&players[0], &camera[0], false); P_MapEnd(); return; } @@ -601,7 +601,8 @@ void P_Ticker(boolean run) return; } - postimgtype = postimgtype2 = postimgtype3 = postimgtype4 = postimg_none; + for (i = 0; i <= splitscreen; i++) + postimgtype[i] = postimg_none; P_MapStart(); @@ -776,14 +777,11 @@ void P_Ticker(boolean run) } // Always move the camera. - if (camera.chase) - P_MoveChaseCamera(&players[displayplayer], &camera, false); - if (splitscreen && camera2.chase) - P_MoveChaseCamera(&players[secondarydisplayplayer], &camera2, false); - if (splitscreen > 1 && camera3.chase) - P_MoveChaseCamera(&players[thirddisplayplayer], &camera3, false); - if (splitscreen > 2 && camera4.chase) - P_MoveChaseCamera(&players[fourthdisplayplayer], &camera4, false); + for (i = 0; i <= splitscreen; i++) + { + if (camera[i].chase) + P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false); + } P_MapEnd(); @@ -799,7 +797,8 @@ void P_PreTicker(INT32 frames) INT32 i,framecnt; ticcmd_t temptic; - postimgtype = postimgtype2 = postimgtype3 = postimgtype4 = postimg_none; + for (i = 0; i <= splitscreen; i++) + postimgtype[i] = postimg_none; for (framecnt = 0; framecnt < frames; ++framecnt) { diff --git a/src/p_user.c b/src/p_user.c index 26ee9f8c4..8d8400264 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -654,13 +654,13 @@ static void P_DeNightserizePlayer(player_t *player) // Restore aiming angle if (player == &players[consoleplayer]) - localaiming = 0; - else if (player == &players[secondarydisplayplayer]) - localaiming2 = 0; - else if (player == &players[thirddisplayplayer]) - localaiming3 = 0; - else if (player == &players[fourthdisplayplayer]) - localaiming4 = 0; + localaiming[0] = 0; + else if (player == &players[displayplayers[1]]) + localaiming[1] = 0; + else if (player == &players[displayplayers[2]]) + localaiming[2] = 0; + else if (player == &players[displayplayers[3]]) + localaiming[3] = 0; if (player->mo->tracer) P_RemoveMobj(player->mo->tracer); @@ -1154,25 +1154,25 @@ boolean P_EndingMusic(player_t *player) // Check for if this is valid or not if (splitscreen) { - if (!((players[displayplayer].exiting || (players[displayplayer].pflags & PF_TIMEOVER)) - || (players[secondarydisplayplayer].exiting || (players[secondarydisplayplayer].pflags & PF_TIMEOVER)) - || ((splitscreen < 2) && (players[thirddisplayplayer].exiting || (players[thirddisplayplayer].pflags & PF_TIMEOVER))) - || ((splitscreen < 3) && (players[fourthdisplayplayer].exiting || (players[fourthdisplayplayer].pflags & PF_TIMEOVER))))) + if (!((players[displayplayers[0]].exiting || (players[displayplayers[0]].pflags & PF_TIMEOVER)) + || (players[displayplayers[1]].exiting || (players[displayplayers[1]].pflags & PF_TIMEOVER)) + || ((splitscreen < 2) && (players[displayplayers[2]].exiting || (players[displayplayers[2]].pflags & PF_TIMEOVER))) + || ((splitscreen < 3) && (players[displayplayers[3]].exiting || (players[displayplayers[3]].pflags & PF_TIMEOVER))))) return false; - bestlocalplayer = &players[displayplayer]; - bestlocalpos = ((players[displayplayer].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[displayplayer].kartstuff[k_position]); + bestlocalplayer = &players[displayplayers[0]]; + bestlocalpos = ((players[displayplayers[0]].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[displayplayers[0]].kartstuff[k_position]); #define setbests(p) \ if (((players[p].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[p].kartstuff[k_position]) < bestlocalpos) \ { \ bestlocalplayer = &players[p]; \ bestlocalpos = ((players[p].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[p].kartstuff[k_position]); \ } - setbests(secondarydisplayplayer); + setbests(displayplayers[1]); if (splitscreen > 1) - setbests(thirddisplayplayer); + setbests(displayplayers[2]); if (splitscreen > 2) - setbests(fourthdisplayplayer); + setbests(displayplayers[3]); #undef setbests } else @@ -1253,12 +1253,12 @@ void P_RestoreMusic(player_t *player) else if (players[p].kartstuff[k_invincibilitytimer] > bestlocaltimer) \ { wantedmus = 1; bestlocaltimer = players[p].kartstuff[k_invincibilitytimer]; } \ } - setbests(displayplayer); - setbests(secondarydisplayplayer); + setbests(displayplayers[0]); + setbests(displayplayers[1]); if (splitscreen > 1) - setbests(thirddisplayplayer); + setbests(displayplayers[2]); if (splitscreen > 2) - setbests(fourthdisplayplayer); + setbests(displayplayers[3]); #undef setbests } else @@ -1516,10 +1516,39 @@ fixed_t P_GetPlayerSpinHeight(player_t *player) // boolean P_IsLocalPlayer(player_t *player) { - return ((splitscreen > 2 && player == &players[fourthdisplayplayer]) - || (splitscreen > 1 && player == &players[thirddisplayplayer]) - || (splitscreen && player == &players[secondarydisplayplayer]) - || player == &players[consoleplayer]); + UINT8 i; + + if (player == &players[consoleplayer]) + return true; + else if (splitscreen) + { + for (i = 1; i <= splitscreen; i++) // Skip P1 + { + if (player == &players[displayplayers[i]]) + return true; + } + } + + return false; +} + +// +// P_IsDisplayPlayer +// +// Returns true if player is +// currently being watched. +// +boolean P_IsDisplayPlayer(player_t *player) +{ + UINT8 i; + + for (i = 0; i <= splitscreen; i++) // DON'T skip P1 + { + if (player == &players[displayplayers[i]]) + return true; + } + + return false; } // @@ -1772,11 +1801,7 @@ void P_DoPlayerExit(player_t *player) if (player->exiting || mapreset) return; - if ((player == &players[consoleplayer] - || (splitscreen && player == &players[secondarydisplayplayer]) - || (splitscreen > 1 && player == &players[thirddisplayplayer]) - || (splitscreen > 2 && player == &players[fourthdisplayplayer])) - && (!player->spectator && !demo.playback)) + if (P_IsLocalPlayer(player) && (!player->spectator && !demo.playback)) legitimateexit = true; if (G_RaceGametype()) // If in Race Mode, allow @@ -2515,8 +2540,7 @@ static void P_DoPlayerHeadSigns(player_t *player) // If you're "IT", show a big "IT" over your head for others to see. if (player->pflags & PF_TAGIT) { - if (!(player == &players[consoleplayer] || player == &players[displayplayer] || player == &players[secondarydisplayplayer] - || player == &players[thirddisplayplayer] || player == &players[fourthdisplayplayer])) // Don't display it on your own view. + if (!P_IsDisplayPlayer(player)) // Don't display it on your own view. { if (!(player->mo->eflags & MFE_VERTICALFLIP)) P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height, MT_TAG); @@ -3004,13 +3028,13 @@ static void P_DoClimbing(player_t *player) // SRB2kart - unused } if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; if (player->climbing == 0) P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); @@ -3675,13 +3699,13 @@ void P_DoJump(player_t *player, boolean soundandstate) player->mo->angle = player->mo->angle - ANGLE_180; // Turn around from the wall you were climbing. if (player == &players[consoleplayer]) - localangle = player->mo->angle; // Adjust the local control angle. - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; // Adjust the local control angle. + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; player->climbing = 0; // Stop climbing, duh! P_InstaThrust(player->mo, player->mo->angle, FixedMul(6*FRACUNIT, player->mo->scale)); // Jump off the wall. @@ -4365,14 +4389,14 @@ boolean P_AnalogMove(player_t *player) fixed_t tempx = 0, tempy = 0; angle_t tempangle, origtempangle; - if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - thiscam = &camera4; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - thiscam = &camera3; - else if (splitscreen && player == &players[secondarydisplayplayer]) - thiscam = &camera2; + if (splitscreen > 2 && player == &players[displayplayers[3]]) + thiscam = &camera[3]; + else if (splitscreen > 1 && player == &players[displayplayers[2]]) + thiscam = &camera[2]; + else if (splitscreen && player == &players[displayplayers[1]]) + thiscam = &camera[1]; else - thiscam = &camera; + thiscam = &camera[0]; if (!cmd->forwardmove && !cmd->sidemove) return 0; @@ -4513,13 +4537,13 @@ static void P_2dMovement(player_t *player) } if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; if (player->pflags & PF_GLIDING) movepushangle = player->mo->angle; @@ -6049,13 +6073,13 @@ static void P_NiGHTSMovement(player_t *player) P_SetMobjStateNF(player->mo->tracer, leveltime & 1 ? flystate : flystate+1); if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; if (still) { @@ -6082,13 +6106,13 @@ static void P_NiGHTSMovement(player_t *player) movingangle = InvAngle(movingangle); if (player == &players[consoleplayer]) - localaiming = movingangle; - else if (player == &players[secondarydisplayplayer]) - localaiming2 = movingangle; - else if (player == &players[thirddisplayplayer]) - localaiming3 = movingangle; - else if (player == &players[fourthdisplayplayer]) - localaiming4 = movingangle; + localaiming[0] = movingangle; + else if (player == &players[displayplayers[1]]) + localaiming[1] = movingangle; + else if (player == &players[displayplayers[2]]) + localaiming[2] = movingangle; + else if (player == &players[displayplayers[3]]) + localaiming[3] = movingangle; player->mo->tracer->angle = player->mo->angle; @@ -6352,7 +6376,7 @@ static void P_MovePlayer(player_t *player) { if (G_IsSpecialStage(gamemap)) { - if (player == &players[displayplayer]) // only play the sound for yourself landing + if (player == &players[displayplayers[0]]) // only play the sound for yourself landing S_StartSound(NULL, sfx_s3k6a); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) @@ -6865,13 +6889,13 @@ static void P_MovePlayer(player_t *player) // Update the local angle control. if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; } #endif @@ -7193,13 +7217,13 @@ static void P_DoZoomTube(player_t *player) player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->tracer->x, player->mo->tracer->y); if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; } #if 0 if (player->mo->state != &states[S_KART_SPIN]) @@ -7589,13 +7613,13 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target if (source->player) { if (source->player == &players[consoleplayer]) - localangle = source->angle; - else if (source->player == &players[secondarydisplayplayer]) - localangle2 = source->angle; - else if (source->player == &players[thirddisplayplayer]) - localangle3 = source->angle; - else if (source->player == &players[fourthdisplayplayer]) - localangle4 = source->angle; + localangle[0] = source->angle; + else if (source->player == &players[displayplayers[1]]) + localangle[1] = source->angle; + else if (source->player == &players[displayplayers[2]]) + localangle[2] = source->angle; + else if (source->player == &players[displayplayers[3]]) + localangle[3] = source->angle; } // change slope @@ -7728,7 +7752,7 @@ notrealplayer: // P_MoveCamera: make sure the camera is not outside the world and looks at the player avatar // -camera_t camera, camera2, camera3, camera4; // Four cameras, three for splitscreen +camera_t camera[MAXSPLITSCREENPLAYERS]; // Four cameras, three for splitscreen static void CV_CamRotate_OnChange(void) { @@ -7809,17 +7833,6 @@ fixed_t t_cam4_rotate = -42; #define MAXCAMERADIST 140*FRACUNIT // Max distance the camera can be in front of the player (2D mode) -camera_t *P_GetCameraPtr(UINT8 viewnum) -{ - switch (viewnum) - { - case 2: return &camera2; - case 3: return &camera3; - case 4: return &camera4; - } - return &camera; -} - void P_ResetCamera(player_t *player, camera_t *thiscam) { tic_t tries = 0; @@ -7844,10 +7857,10 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) thiscam->y = y; thiscam->z = z; - if (!(thiscam == &camera && (cv_cam_still.value || cv_analog.value)) - && !(thiscam == &camera2 && (cv_cam2_still.value || cv_analog2.value)) - && !(thiscam == &camera3 && (cv_cam3_still.value || cv_analog3.value)) - && !(thiscam == &camera4 && (cv_cam4_still.value || cv_analog4.value))) + if (!(thiscam == &camera[0] && (cv_cam_still.value || cv_analog.value)) + && !(thiscam == &camera[1] && (cv_cam2_still.value || cv_analog2.value)) + && !(thiscam == &camera[2] && (cv_cam3_still.value || cv_analog3.value)) + && !(thiscam == &camera[3] && (cv_cam4_still.value || cv_analog4.value))) { thiscam->angle = player->mo->angle; thiscam->aiming = 0; @@ -7905,31 +7918,32 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (player->spectator) // force cam off for spectators return true; - if (!cv_chasecam.value && thiscam == &camera) + if (!cv_chasecam.value && thiscam == &camera[0]) return true; - if (!cv_chasecam2.value && thiscam == &camera2) + if (!cv_chasecam2.value && thiscam == &camera[1]) return true; - if (!cv_chasecam3.value && thiscam == &camera3) + if (!cv_chasecam3.value && thiscam == &camera[2]) return true; - if (!cv_chasecam4.value && thiscam == &camera4) + if (!cv_chasecam4.value && thiscam == &camera[3]) return true; } if (!thiscam->chase && !resetcalled) { if (player == &players[consoleplayer]) - focusangle = localangle; - else if (player == &players[secondarydisplayplayer]) - focusangle = localangle2; - else if (player == &players[thirddisplayplayer]) - focusangle = localangle3; - else if (player == &players[fourthdisplayplayer]) - focusangle = localangle4; + focusangle = localangle[0]; + else if (player == &players[displayplayers[1]]) + focusangle = localangle[1]; + else if (player == &players[displayplayers[2]]) + focusangle = localangle[2]; + else if (player == &players[displayplayers[3]]) + focusangle = localangle[3]; else focusangle = mo->angle; + if (thiscam == &camera) camrotate = cv_cam_rotate.value; else if (thiscam == &camera2) @@ -7940,11 +7954,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camrotate = cv_cam4_rotate.value; else camrotate = 0; + if (leveltime < introtime) // Whoooshy camera! { const INT32 introcam = (introtime - leveltime); camrotate += introcam*5; } + thiscam->angle = focusangle + FixedAngle(camrotate*FRACUNIT); P_ResetCamera(player, thiscam); return true; @@ -7965,23 +7981,23 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } else if (player == &players[consoleplayer]) { - focusangle = localangle; - focusaiming = localaiming; + focusangle = localangle[0]; + focusaiming = localaiming[0]; } - else if (player == &players[secondarydisplayplayer]) + else if (player == &players[displayplayers[1]]) { - focusangle = localangle2; - focusaiming = localaiming2; + focusangle = localangle[1]; + focusaiming = localaiming[1]; } - else if (player == &players[thirddisplayplayer]) + else if (player == &players[displayplayers[2]]) { - focusangle = localangle3; - focusaiming = localaiming3; + focusangle = localangle[2]; + focusaiming = localaiming[2]; } - else if (player == &players[fourthdisplayplayer]) + else if (player == &players[displayplayers[3]]) { - focusangle = localangle4; - focusaiming = localaiming4; + focusangle = localangle[3]; + focusaiming = localaiming[3]; } else { @@ -7992,17 +8008,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (P_CameraThinker(player, thiscam, resetcalled)) return true; - if (thiscam == &camera) - { - num = 0; - camspeed = cv_cam_speed.value; - camstill = cv_cam_still.value; - camrotate = cv_cam_rotate.value; - camdist = FixedMul(cv_cam_dist.value, mapobjectscale); - camheight = FixedMul(cv_cam_height.value, mapobjectscale); - lookback = camspin; - } - else if (thiscam == &camera2) // Camera 2 + + if (thiscam == &camera[1]) // Camera 2 { num = 1; camspeed = cv_cam2_speed.value; @@ -8010,9 +8017,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camrotate = cv_cam2_rotate.value; camdist = FixedMul(cv_cam2_dist.value, mapobjectscale); camheight = FixedMul(cv_cam2_height.value, mapobjectscale); - lookback = camspin2; + lookback = camspin[1]; } - else if (thiscam == &camera3) // Camera 3 + else if (thiscam == &camera[2]) // Camera 3 { num = 2; camspeed = cv_cam3_speed.value; @@ -8020,9 +8027,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camrotate = cv_cam3_rotate.value; camdist = FixedMul(cv_cam3_dist.value, mapobjectscale); camheight = FixedMul(cv_cam3_height.value, mapobjectscale); - lookback = camspin3; + lookback = camspin[2]; } - else // Camera 4 + else if (thiscam == &camera[3]) // Camera 4 { num = 3; camspeed = cv_cam4_speed.value; @@ -8030,7 +8037,17 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camrotate = cv_cam4_rotate.value; camdist = FixedMul(cv_cam4_dist.value, mapobjectscale); camheight = FixedMul(cv_cam4_height.value, mapobjectscale); - lookback = camspin4; + lookback = camspin[3]; + } + else // Camera 1 + { + num = 0; + camspeed = cv_cam_speed.value; + camstill = cv_cam_still.value; + camrotate = cv_cam_rotate.value; + camdist = FixedMul(cv_cam_dist.value, mapobjectscale); + camheight = FixedMul(cv_cam_height.value, mapobjectscale); + lookback = camspin[0]; } if (timeover) @@ -8091,10 +8108,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } if (!resetcalled && (leveltime > starttime && timeover != 2) - && ((thiscam == &camera && t_cam_rotate != -42) - || (thiscam == &camera2 && t_cam2_rotate != -42) - || (thiscam == &camera3 && t_cam3_rotate != -42) - || (thiscam == &camera4 && t_cam4_rotate != -42))) + && ((thiscam == &camera[0] && t_cam_rotate != -42) + || (thiscam == &camera[1] && t_cam2_rotate != -42) + || (thiscam == &camera[2] && t_cam3_rotate != -42) + || (thiscam == &camera[3] && t_cam4_rotate != -42))) { angle = FixedAngle(camrotate*FRACUNIT); thiscam->angle = angle; @@ -8489,8 +8506,8 @@ boolean P_SpectatorJoinGame(player_t *player) player->playerstate = PST_REBORN; //Reset away view - if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) - displayplayer = consoleplayer; + if (P_IsLocalPlayer(player) && displayplayers[0] != consoleplayer) + displayplayers[0] = consoleplayer; if (changeto == 1) CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x85', M_GetText("Red team"), '\x80'); @@ -8513,8 +8530,8 @@ boolean P_SpectatorJoinGame(player_t *player) player->playerstate = PST_REBORN; //Reset away view - if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) - displayplayer = consoleplayer; + if (P_IsLocalPlayer(player) && displayplayers[0] != consoleplayer) + displayplayers[0] = consoleplayer; HU_AddChatText(va(M_GetText("\x82*%s entered the game."), player_names[player-players]), false); return true; // no more player->mo, cannot continue. @@ -8528,6 +8545,7 @@ static void P_CalcPostImg(player_t *player) postimg_t *type; INT32 *param; fixed_t pviewheight; + UINT8 i; if (player->mo->eflags & MFE_VERTICALFLIP) pviewheight = player->mo->z + player->mo->height - player->viewheight; @@ -8540,25 +8558,14 @@ static void P_CalcPostImg(player_t *player) pviewheight = player->awayviewmobj->z + 20*FRACUNIT; } - if (splitscreen > 2 && player == &players[fourthdisplayplayer]) + for (i = 0; i <= splitscreen; i++) { - type = &postimgtype4; - param = &postimgparam4; - } - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - { - type = &postimgtype3; - param = &postimgparam3; - } - else if (splitscreen && player == &players[secondarydisplayplayer]) - { - type = &postimgtype2; - param = &postimgparam2; - } - else - { - type = &postimgtype; - param = &postimgparam; + if (player == &players[displayplayers[i]]) + { + type = &postimgtype[i]; + param = &postimgparam[i]; + break; + } } // see if we are in heat (no, not THAT kind of heat...) @@ -8666,11 +8673,7 @@ void P_DoTimeOver(player_t *player) player->pflags |= PF_TIMEOVER; - if ((player == &players[consoleplayer] - || (splitscreen && player == &players[secondarydisplayplayer]) - || (splitscreen > 1 && player == &players[thirddisplayplayer]) - || (splitscreen > 2 && player == &players[fourthdisplayplayer])) - && !demo.playback) + if (P_IsLocalPlayer(player) && !demo.playback) legitimateexit = true; // SRB2kart: losing a race is still seeing it through to the end :p if (player->mo) @@ -8717,7 +8720,7 @@ void P_PlayerThink(player_t *player) } #ifdef SEENAMES - if (netgame && player == &players[displayplayer] && !(leveltime % (TICRATE/5)) && !splitscreen) + if (netgame && player == &players[displayplayers[0]] && !(leveltime % (TICRATE/5)) && !splitscreen) { seenplayer = NULL; @@ -9064,7 +9067,9 @@ void P_PlayerThink(player_t *player) || player->kartstuff[k_driftboost] || player->kartstuff[k_sneakertimer] || player->kartstuff[k_startboost]) && !player->kartstuff[k_invincibilitytimer] // SRB2kart && (player->speed + abs(player->mo->momz)) > FixedMul(20*FRACUNIT,player->mo->scale)) { + UINT8 i; mobj_t *gmobj = P_SpawnGhostMobj(player->mo); + gmobj->fuse = 2; if (leveltime & 1) { @@ -9072,15 +9077,17 @@ void P_PlayerThink(player_t *player) gmobj->frame |= tr_trans70< 1 && player == &players[thirddisplayplayer] && !camera3.chase) - || (splitscreen > 2 && player == &players[fourthdisplayplayer] && !camera4.chase)) - gmobj->flags2 |= MF2_DONTDRAW; + for (i = 0; i <= splitscreen; i++) + { + if (player == &players[displayplayers[i]] && !camera[i].chase) + { + gmobj->flags2 |= MF2_DONTDRAW; + break; + } + } } #endif @@ -9280,6 +9287,7 @@ void P_PlayerAfterThink(player_t *player) ticcmd_t *cmd; //INT32 oldweapon = player->currentweapon; // SRB2kart - unused camera_t *thiscam = NULL; // if not one of the displayed players, just don't bother + UINT8 i; #ifdef PARANOIA if (!player->mo) @@ -9302,14 +9310,14 @@ void P_PlayerAfterThink(player_t *player) P_PlayerInSpecialSector(player); #endif - if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - thiscam = &camera4; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - thiscam = &camera3; - else if (splitscreen && player == &players[secondarydisplayplayer]) - thiscam = &camera2; - else if (player == &players[displayplayer]) - thiscam = &camera; + for (i = 0; i <= splitscreen; i++) + { + if (player == &players[displayplayers[i]]) + { + thiscam = &camera[i]; + break; + } + } if (player->playerstate == PST_DEAD) { @@ -9494,13 +9502,13 @@ void P_PlayerAfterThink(player_t *player) player->mo->angle = player->mo->tracer->angle; if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; } if (P_AproxDistance(player->mo->x - player->mo->tracer->x, player->mo->y - player->mo->tracer->y) > player->mo->radius) @@ -9568,13 +9576,13 @@ void P_PlayerAfterThink(player_t *player) player->mo->angle += cmd->sidemove< ANGLE_MAX if (player == &players[consoleplayer]) - localangle = player->mo->angle; // Adjust the local control angle. - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - else if (player == &players[thirddisplayplayer]) - localangle3 = player->mo->angle; - else if (player == &players[fourthdisplayplayer]) - localangle4 = player->mo->angle; + localangle[0] = player->mo->angle; // Adjust the local control angle. + else if (player == &players[displayplayers[1]]) + localangle[1] = player->mo->angle; + else if (player == &players[displayplayers[2]]) + localangle[2] = player->mo->angle; + else if (player == &players[displayplayers[3]]) + localangle[3] = player->mo->angle; } } diff --git a/src/r_bsp.c b/src/r_bsp.c index b819735e1..296cbbe87 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -252,20 +252,23 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, mobj_t *viewmobj = viewplayer->mo; INT32 heightsec; boolean underwater; + UINT8 i; - if (splitscreen > 2 && viewplayer == &players[fourthdisplayplayer] && camera4.chase) - heightsec = R_PointInSubsector(camera4.x, camera4.y)->sector->heightsec; - else if (splitscreen > 1 && viewplayer == &players[thirddisplayplayer] && camera3.chase) - heightsec = R_PointInSubsector(camera3.x, camera3.y)->sector->heightsec; - else if (splitscreen && viewplayer == &players[secondarydisplayplayer] && camera2.chase) - heightsec = R_PointInSubsector(camera2.x, camera2.y)->sector->heightsec; - else if (camera.chase && viewplayer == &players[displayplayer]) - heightsec = R_PointInSubsector(camera.x, camera.y)->sector->heightsec; - else if (viewmobj) + for (i = 0; i <= splitscreen; i++) + { + if (viewplayer == &players[displayplayers[i]] && camera[i].chase) + { + heightsec = R_PointInSubsector(camera[i].x, camera[i].y)->sector->heightsec; + break; + } + } + + if (i > splitscreen && viewmobj) heightsec = R_PointInSubsector(viewmobj->x, viewmobj->y)->sector->heightsec; else return sec; - underwater = heightsec != -1 && viewz <= sectors[heightsec].floorheight; + + underwater = (heightsec != -1 && viewz <= sectors[heightsec].floorheight); // Replace sector being drawn, with a copy to be hacked *tempsec = *sec; @@ -827,7 +830,7 @@ static void R_AddPolyObjects(subsector_t *sub) drawseg_t *firstseg; -static void R_Subsector(size_t num, UINT8 viewnumber) +static void R_Subsector(size_t num) { INT32 count, floorlightlevel, ceilinglightlevel, light; seg_t *line; @@ -1149,7 +1152,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) // Either you must pass the fake sector and handle validcount here, on the // real sector, or you must account for the lighting in some other way, // like passing it as an argument. - R_AddSprites(sub->sector, (floorlightlevel+ceilinglightlevel)/2, viewnumber); + R_AddSprites(sub->sector, (floorlightlevel+ceilinglightlevel)/2); firstseg = NULL; @@ -1355,7 +1358,7 @@ INT32 R_GetPlaneLight(sector_t *sector, fixed_t planeheight, boolean underside) // // killough 5/2/98: reformatted, removed tail recursion -void R_RenderBSPNode(INT32 bspnum, UINT8 viewnumber) +void R_RenderBSPNode(INT32 bspnum) { node_t *bsp; INT32 side; @@ -1366,7 +1369,7 @@ void R_RenderBSPNode(INT32 bspnum, UINT8 viewnumber) // Decide which side the view point is on. side = R_PointOnSide(viewx, viewy, bsp); // Recursively divide front space. - R_RenderBSPNode(bsp->children[side], viewnumber); + R_RenderBSPNode(bsp->children[side]); // Possibly divide back space. @@ -1384,5 +1387,5 @@ void R_RenderBSPNode(INT32 bspnum, UINT8 viewnumber) portalcullsector = NULL; } - R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR, viewnumber); + R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); } diff --git a/src/r_bsp.h b/src/r_bsp.h index 7810c9b5c..e3662e2e6 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -37,7 +37,7 @@ extern INT32 doorclosed; void R_ClearClipSegs(void); void R_PortalClearClipSegs(INT32 start, INT32 end); void R_ClearDrawSegs(void); -void R_RenderBSPNode(INT32 bspnum, UINT8 viewnumber); +void R_RenderBSPNode(INT32 bspnum); void R_AddPortal(INT32 line1, INT32 line2, INT32 x1, INT32 x2); #ifdef POLYOBJECTS diff --git a/src/r_main.c b/src/r_main.c index b4dcd9183..122062431 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -65,9 +65,10 @@ size_t loopcount; fixed_t viewx, viewy, viewz; angle_t viewangle, aimingangle; +UINT8 viewnumber; fixed_t viewcos, viewsin; boolean viewsky, skyVisible; -boolean skyVisible1, skyVisible2, skyVisible3, skyVisible4; // saved values of skyVisible for P1/P2/P3/P4, for splitscreen +boolean skyVisiblePerPlayer[MAXSPLITSCREENPLAYERS]; // saved values of skyVisible for each splitscreen player sector_t *viewsector; player_t *viewplayer; @@ -195,17 +196,10 @@ void SplitScreen_OnChange(void) if (!demo.playback && !botingame) { - for (i = 1; i < 3; i++) + for (i = 1; i < MAXSPLITSCREENPLAYERS; i++) { if (i > splitscreen) - { - if (i == 1) - CL_RemoveSplitscreenPlayer(secondarydisplayplayer); - else if (i == 2) - CL_RemoveSplitscreenPlayer(thirddisplayplayer); - else if (i == 3) - CL_RemoveSplitscreenPlayer(fourthdisplayplayer); - } + CL_RemoveSplitscreenPlayer(displayplayers[i]); else CL_AddSplitscreenPlayer(); } @@ -215,21 +209,27 @@ void SplitScreen_OnChange(void) } else { - secondarydisplayplayer = consoleplayer; - thirddisplayplayer = consoleplayer; - fourthdisplayplayer = consoleplayer; + for (i = 1; i < MAXSPLITSCREENPLAYERS; i++) + displayplayers[i] = consoleplayer; + for (i = 0; i < MAXPLAYERS; i++) + { if (playeringame[i] && i != consoleplayer) { - if (secondarydisplayplayer == consoleplayer) - secondarydisplayplayer = i; - else if (thirddisplayplayer == consoleplayer) - thirddisplayplayer = i; - else if (fourthdisplayplayer == consoleplayer) - fourthdisplayplayer = i; - else + UINT8 j; + for (j = 1; j < MAXSPLITSCREENPLAYERS; j++) + { + if (displayplayers[j] == consoleplayer) + { + displayplayers[j] = i; + break; + } + } + + if (j == MAXSPLITSCREENPLAYERS) break; } + } } } static void Fov_OnChange(void) @@ -844,16 +844,20 @@ static void R_SetupFreelook(void) void R_SkyboxFrame(player_t *player) { - camera_t *thiscam; + camera_t *thiscam = &camera[0]; + UINT8 i; - if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - thiscam = &camera4; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - thiscam = &camera3; - else if (splitscreen && player == &players[secondarydisplayplayer]) - thiscam = &camera2; - else - thiscam = &camera; + if (splitscreen) + { + for (i = 1; i <= splitscreen; i++) + { + if (player == &players[i]) + { + thiscam = &camera[i]; + break; + } + } + } // cut-away view stuff viewsky = true; @@ -883,23 +887,20 @@ void R_SkyboxFrame(player_t *player) { if (player == &players[consoleplayer]) { - viewangle = localangle; // WARNING: camera uses this - aimingangle = localaiming; + viewangle = localangle[0]; // WARNING: camera uses this + aimingangle = localaiming[0]; } - else if (player == &players[secondarydisplayplayer]) + else if (splitscreen) { - viewangle = localangle2; - aimingangle = localaiming2; - } - else if (player == &players[thirddisplayplayer]) - { - viewangle = localangle3; - aimingangle = localaiming3; - } - else if (player == &players[fourthdisplayplayer]) - { - viewangle = localangle4; - aimingangle = localaiming4; + for (i = 1; i <= splitscreen; i++) + { + if (player == &players[displayplayers[i]]) + { + viewangle = localangle[i]; + aimingangle = localaiming[i]; + break; + } + } } } } @@ -1078,24 +1079,24 @@ void R_SetupFrame(player_t *player, boolean skybox) camera_t *thiscam; boolean chasecam = false; - if (splitscreen > 2 && player == &players[fourthdisplayplayer]) + if (splitscreen > 2 && player == &players[displayplayers[3]]) { - thiscam = &camera4; + thiscam = &camera[3]; chasecam = (cv_chasecam4.value != 0); } - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) + else if (splitscreen > 1 && player == &players[displayplayers[2]]) { - thiscam = &camera3; + thiscam = &camera[2]; chasecam = (cv_chasecam3.value != 0); } - else if (splitscreen && player == &players[secondarydisplayplayer]) + else if (splitscreen && player == &players[displayplayers[1]]) { - thiscam = &camera2; + thiscam = &camera[1]; chasecam = (cv_chasecam2.value != 0); } else { - thiscam = &camera; + thiscam = &camera[0]; chasecam = (cv_chasecam.value != 0); } @@ -1145,23 +1146,20 @@ void R_SetupFrame(player_t *player, boolean skybox) { if (player == &players[consoleplayer]) { - viewangle = localangle; // WARNING: camera uses this - aimingangle = localaiming; + viewangle = localangle[0]; // WARNING: camera uses this + aimingangle = localaiming[0]; } - else if (player == &players[secondarydisplayplayer]) + else if (splitscreen) { - viewangle = localangle2; - aimingangle = localaiming2; - } - else if (player == &players[thirddisplayplayer]) - { - viewangle = localangle3; - aimingangle = localaiming3; - } - else if (player == &players[fourthdisplayplayer]) - { - viewangle = localangle4; - aimingangle = localaiming4; + for (i = 1; i <= splitscreen; i++) + { + if (player == &players[displayplayers[i]]) + { + viewangle = localangle[i]; + aimingangle = localaiming[i]; + break; + } + } } } } @@ -1323,19 +1321,24 @@ void R_RenderPlayerView(player_t *player) { portal_pair *portal; const boolean skybox = (skyboxmo[0] && cv_skybox.value); - UINT8 viewnumber; + UINT8 i; - if (player == &players[secondarydisplayplayer] && splitscreen) - viewnumber = 1; - else if (player == &players[thirddisplayplayer] && splitscreen > 1) - viewnumber = 2; - else if (player == &players[fourthdisplayplayer] && splitscreen > 2) - viewnumber = 3; - else - viewnumber = 0; + viewnumber = 0; // default + + if (splitscreen) + { + for (i = 1; i <= splitscreen; i++) + { + if (player == &players[i]) + { + viewnumber = i; + break; + } + } + } // if this is display player 1 - if (cv_homremoval.value && player == &players[displayplayer]) + if (cv_homremoval.value && player == &players[displayplayers[0]]) { if (cv_homremoval.value == 1) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // No HOM effect! @@ -1343,7 +1346,7 @@ void R_RenderPlayerView(player_t *player) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 128+(timeinmap&15)); } // Draw over the fourth screen so you don't have to stare at a HOM :V - else if (splitscreen == 2 && player == &players[thirddisplayplayer]) + else if (splitscreen == 2 && player == &players[displayplayers[2]]) #if 1 { // V_DrawPatchFill, but for the fourth screen only @@ -1362,14 +1365,14 @@ void R_RenderPlayerView(player_t *player) #endif // load previous saved value of skyVisible for the player - if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - skyVisible = skyVisible4; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - skyVisible = skyVisible3; - else if (splitscreen && player == &players[secondarydisplayplayer]) - skyVisible = skyVisible2; - else - skyVisible = skyVisible1; + for (i = 0; i <= splitscreen; i++) + { + if (player == &players[displayplayers[i]] + { + skyVisible = skyVisiblePerPlayer[i]; + break; + } + } portalrender = 0; portal_base = portal_cap = NULL; @@ -1386,7 +1389,7 @@ void R_RenderPlayerView(player_t *player) R_ClearVisibleFloorSplats(); #endif - R_RenderBSPNode((INT32)numnodes - 1, viewnumber); + R_RenderBSPNode((INT32)numnodes - 1); R_ClipSprites(); R_DrawPlanes(); #ifdef FLOORSPLATS @@ -1419,7 +1422,7 @@ void R_RenderPlayerView(player_t *player) mytotal = 0; ProfZeroTimer(); #endif - R_RenderBSPNode((INT32)numnodes - 1, viewnumber); + R_RenderBSPNode((INT32)numnodes - 1); R_ClipSprites(); #ifdef TIMING RDMSR(0x10, &mycount); @@ -1444,7 +1447,7 @@ void R_RenderPlayerView(player_t *player) validcount++; - R_RenderBSPNode((INT32)numnodes - 1, viewnumber); + R_RenderBSPNode((INT32)numnodes - 1); R_ClipSprites(); //R_DrawPlanes(); //R_DrawMasked(); @@ -1470,16 +1473,16 @@ void R_RenderPlayerView(player_t *player) // Check for new console commands. NetUpdate(); - // save value to skyVisible1 or skyVisible2 + // save value to skyVisiblePerPlayer // this is so that P1 can't affect whether P2 can see a skybox or not, or vice versa - if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - skyVisible4 = skyVisible; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - skyVisible3 = skyVisible; - else if (splitscreen && player == &players[secondarydisplayplayer]) - skyVisible2 = skyVisible; - else - skyVisible1 = skyVisible; + for (i = 0; i <= splitscreen; i++) + { + if (player == &players[displayplayers[i]]) + { + skyVisiblePerPlayer[i] = skyVisible; + break; + } + } } // ========================================================================= diff --git a/src/r_plane.c b/src/r_plane.c index 0ff97fcc3..db5bfbda2 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -883,12 +883,12 @@ void R_DrawSinglePlane(visplane_t *pl) if (bottom > vid.height) bottom = vid.height; - if (splitscreen > 2 && viewplayer == &players[fourthdisplayplayer]) // Only copy the part of the screen we need + if (splitscreen > 2 && viewplayer == &players[displayplayers[3]]) // Only copy the part of the screen we need scr = (screens[0] + (top+(viewheight))*vid.width + viewwidth); - else if ((splitscreen == 1 && viewplayer == &players[secondarydisplayplayer]) - || (splitscreen > 1 && viewplayer == &players[thirddisplayplayer])) + else if ((splitscreen == 1 && viewplayer == &players[displayplayers[1]]) + || (splitscreen > 1 && viewplayer == &players[displayplayers[2]])) scr = (screens[0] + (top+(viewheight))*vid.width); - else if (splitscreen > 1 && viewplayer == &players[secondarydisplayplayer]) + else if (splitscreen > 1 && viewplayer == &players[displayplayers[1]]) scr = (screens[0] + ((top)*vid.width) + viewwidth); else scr = (screens[0] + ((top)*vid.width)); diff --git a/src/r_state.h b/src/r_state.h index d6d123e99..6e21e4477 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -88,8 +88,9 @@ extern side_t *sides; // extern fixed_t viewx, viewy, viewz; extern angle_t viewangle, aimingangle; +extern UINT8 viewnumber; // splitscreen view number extern boolean viewsky, skyVisible; -extern boolean skyVisible1, skyVisible2, skyVisible3, skyVisible4; // saved values of skyVisible for P1 and P2, for splitscreen +extern boolean skyVisiblePerPlayer[MAXSPLITSCREENPLAYERS]; // saved values of skyVisible of each splitscreen player extern sector_t *viewsector; extern player_t *viewplayer; extern UINT8 portalrender; diff --git a/src/r_things.c b/src/r_things.c index efc5dd466..71957bb54 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1702,7 +1702,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // R_AddSprites // During BSP traversal, this adds sprites by sector. // -void R_AddSprites(sector_t *sec, INT32 lightlevel, UINT8 viewnumber) +void R_AddSprites(sector_t *sec, INT32 lightlevel) { mobj_t *thing; precipmobj_t *precipthing; // Tails 08-25-2002 @@ -2664,11 +2664,11 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) { if (playernum == consoleplayer) CV_StealthSetValue(&cv_playercolor, skin->prefcolor); - else if (playernum == secondarydisplayplayer) + else if (playernum == displayplayers[1]) CV_StealthSetValue(&cv_playercolor2, skin->prefcolor); - else if (playernum == thirddisplayplayer) + else if (playernum == displayplayers[2]) CV_StealthSetValue(&cv_playercolor3, skin->prefcolor); - else if (playernum == fourthdisplayplayer) + else if (playernum == displayplayers[3]) CV_StealthSetValue(&cv_playercolor4, skin->prefcolor); player->skincolor = skin->prefcolor; if (player->mo) diff --git a/src/r_things.h b/src/r_things.h index 6f48cc5bf..499d80413 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -55,7 +55,7 @@ void R_DelSpriteDefs(UINT16 wadnum); #endif //SoM: 6/5/2000: Light sprites correctly! -void R_AddSprites(sector_t *sec, INT32 lightlevel, UINT8 viewnumber); +void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); void R_ClearSprites(void); void R_ClipSprites(void); diff --git a/src/s_sound.c b/src/s_sound.c index 1585753f9..8e649d08c 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -438,7 +438,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) listener_t listener3 = {0,0,0,0}; listener_t listener4 = {0,0,0,0}; - mobj_t *listenmobj = players[displayplayer].mo; + mobj_t *listenmobj = players[displayplayers[0]].mo; mobj_t *listenmobj2 = NULL; mobj_t *listenmobj3 = NULL; mobj_t *listenmobj4 = NULL; @@ -450,26 +450,26 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) if (sfx_id == sfx_None) return; - if (players[displayplayer].awayviewtics) - listenmobj = players[displayplayer].awayviewmobj; + if (players[displayplayers[0]].awayviewtics) + listenmobj = players[displayplayers[0]].awayviewmobj; if (splitscreen) { - listenmobj2 = players[secondarydisplayplayer].mo; - if (players[secondarydisplayplayer].awayviewtics) - listenmobj2 = players[secondarydisplayplayer].awayviewmobj; + listenmobj2 = players[displayplayers[1]].mo; + if (players[displayplayers[1]].awayviewtics) + listenmobj2 = players[displayplayers[1]].awayviewmobj; if (splitscreen > 1) { - listenmobj3 = players[thirddisplayplayer].mo; - if (players[thirddisplayplayer].awayviewtics) - listenmobj3 = players[thirddisplayplayer].awayviewmobj; + listenmobj3 = players[displayplayers[2]].mo; + if (players[displayplayers[2]].awayviewtics) + listenmobj3 = players[displayplayers[2]].awayviewmobj; if (splitscreen > 2) { - listenmobj4 = players[fourthdisplayplayer].mo; - if (players[fourthdisplayplayer].awayviewtics) - listenmobj4 = players[fourthdisplayplayer].awayviewmobj; + listenmobj4 = players[displayplayers[3]].mo; + if (players[displayplayers[3]].awayviewtics) + listenmobj4 = players[displayplayers[3]].awayviewmobj; } } } @@ -482,12 +482,12 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) }; #endif - if (camera.chase && !players[displayplayer].awayviewtics) + if (camera[0].chase && !players[displayplayers[0]].awayviewtics) { - listener.x = camera.x; - listener.y = camera.y; - listener.z = camera.z; - listener.angle = camera.angle; + listener.x = camera[0].x; + listener.y = camera[0].y; + listener.z = camera[0].z; + listener.angle = camera[0].angle; } else if (listenmobj) { @@ -501,12 +501,12 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) if (listenmobj2) { - if (camera2.chase && !players[secondarydisplayplayer].awayviewtics) + if (camera[1].chase && !players[displayplayers[1]].awayviewtics) { - listener2.x = camera2.x; - listener2.y = camera2.y; - listener2.z = camera2.z; - listener2.angle = camera2.angle; + listener2.x = camera[1].x; + listener2.y = camera[1].y; + listener2.z = camera[1].z; + listener2.angle = camera[1].angle; } else { @@ -519,12 +519,12 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) if (listenmobj3) { - if (camera3.chase && !players[thirddisplayplayer].awayviewtics) + if (camera[2].chase && !players[displayplayers[2]].awayviewtics) { - listener3.x = camera3.x; - listener3.y = camera3.y; - listener3.z = camera3.z; - listener3.angle = camera3.angle; + listener3.x = camera[2].x; + listener3.y = camera[2].y; + listener3.z = camera[2].z; + listener3.angle = camera[2].angle; } else { @@ -537,12 +537,12 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) if (listenmobj4) { - if (camera4.chase && !players[fourthdisplayplayer].awayviewtics) + if (camera[3].chase && !players[displayplayers[3]].awayviewtics) { - listener4.x = camera4.x; - listener4.y = camera4.y; - listener4.z = camera4.z; - listener4.angle = camera4.angle; + listener4.x = camera[3].x; + listener4.y = camera[3].y; + listener4.z = camera[3].z; + listener4.angle = camera[3].angle; } else { @@ -899,7 +899,7 @@ void S_UpdateSounds(void) listener_t listener3; listener_t listener4; - mobj_t *listenmobj = players[displayplayer].mo; + mobj_t *listenmobj = players[displayplayers[0]].mo; mobj_t *listenmobj2 = NULL; mobj_t *listenmobj3 = NULL; mobj_t *listenmobj4 = NULL; @@ -940,31 +940,31 @@ void S_UpdateSounds(void) if (splitscreen) { - listenmobj2 = players[secondarydisplayplayer].mo; - if (players[secondarydisplayplayer].awayviewtics) - listenmobj2 = players[secondarydisplayplayer].awayviewmobj; + listenmobj2 = players[displayplayers[1]].mo; + if (players[displayplayers[1]].awayviewtics) + listenmobj2 = players[displayplayers[1]].awayviewmobj; if (splitscreen > 1) { - listenmobj3 = players[thirddisplayplayer].mo; - if (players[thirddisplayplayer].awayviewtics) - listenmobj3 = players[thirddisplayplayer].awayviewmobj; + listenmobj3 = players[displayplayers[2]].mo; + if (players[displayplayers[2]].awayviewtics) + listenmobj3 = players[displayplayers[2]].awayviewmobj; if (splitscreen > 2) { - listenmobj4 = players[fourthdisplayplayer].mo; - if (players[fourthdisplayplayer].awayviewtics) - listenmobj4 = players[fourthdisplayplayer].awayviewmobj; + listenmobj4 = players[displayplayers[3]].mo; + if (players[displayplayers[3]].awayviewtics) + listenmobj4 = players[displayplayers[3]].awayviewmobj; } } } - if (camera.chase && !players[displayplayer].awayviewtics) + if (camera[0].chase && !players[displayplayers[0]].awayviewtics) { - listener.x = camera.x; - listener.y = camera.y; - listener.z = camera.z; - listener.angle = camera.angle; + listener.x = camera[0].x; + listener.y = camera[0].y; + listener.z = camera[0].z; + listener.angle = camera[0].angle; } else if (listenmobj) { @@ -989,12 +989,12 @@ void S_UpdateSounds(void) if (listenmobj2) { - if (camera2.chase && !players[secondarydisplayplayer].awayviewtics) + if (camera[1].chase && !players[displayplayers[1]].awayviewtics) { - listener2.x = camera2.x; - listener2.y = camera2.y; - listener2.z = camera2.z; - listener2.angle = camera2.angle; + listener2.x = camera[1].x; + listener2.y = camera[1].y; + listener2.z = camera[1].z; + listener2.angle = camera[1].angle; } else { @@ -1007,12 +1007,12 @@ void S_UpdateSounds(void) if (listenmobj3) { - if (camera3.chase && !players[thirddisplayplayer].awayviewtics) + if (camera[2].chase && !players[displayplayers[2]].awayviewtics) { - listener3.x = camera3.x; - listener3.y = camera3.y; - listener3.z = camera3.z; - listener3.angle = camera3.angle; + listener3.x = camera[2].x; + listener3.y = camera[2].y; + listener3.z = camera[2].z; + listener3.angle = camera[2].angle; } else { @@ -1025,12 +1025,12 @@ void S_UpdateSounds(void) if (listenmobj4) { - if (camera4.chase && !players[fourthdisplayplayer].awayviewtics) + if (camera[3].chase && !players[displayplayers[3]].awayviewtics) { - listener4.x = camera4.x; - listener4.y = camera4.y; - listener4.z = camera4.z; - listener4.angle = camera4.angle; + listener4.x = camera[3].x; + listener4.y = camera[3].y; + listener4.z = camera[3].z; + listener4.angle = camera[3].angle; } else { @@ -1060,9 +1060,9 @@ void S_UpdateSounds(void) // check non-local sounds for distance clipping // or modify their params if (c->origin && ((c->origin != players[consoleplayer].mo) - || (splitscreen && c->origin != players[secondarydisplayplayer].mo) - || (splitscreen > 1 && c->origin != players[thirddisplayplayer].mo) - || (splitscreen > 2 && c->origin != players[fourthdisplayplayer].mo))) + || (splitscreen && c->origin != players[displayplayers[1]].mo) + || (splitscreen > 1 && c->origin != players[displayplayers[2]].mo) + || (splitscreen > 2 && c->origin != players[displayplayers[3]].mo))) { // Whomever is closer gets the sound, but only in splitscreen. if (splitscreen) @@ -1071,13 +1071,10 @@ void S_UpdateSounds(void) fixed_t recdist = -1; INT32 i, p = -1; - for (i = 0; i < 4; i++) + for (i = 0; i <= splitscreen; i++) { fixed_t thisdist = -1; - if (i > splitscreen) - break; - if (i == 0 && listenmobj) thisdist = P_AproxDistance(listener.x-soundmobj->x, listener.y-soundmobj->y); else if (i == 1 && listenmobj2) @@ -1250,33 +1247,33 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v if (!listener) return false; - if (listener == players[displayplayer].mo && camera.chase) + if (listener == players[displayplayers[0]].mo && camera[0].chase) { - listensource.x = camera.x; - listensource.y = camera.y; - listensource.z = camera.z; - listensource.angle = camera.angle; + listensource.x = camera[0].x; + listensource.y = camera[0].y; + listensource.z = camera[0].z; + listensource.angle = camera[0].angle; } - else if (splitscreen && listener == players[secondarydisplayplayer].mo && camera2.chase) + else if (splitscreen && listener == players[displayplayers[1]].mo && camera[1].chase) { - listensource.x = camera2.x; - listensource.y = camera2.y; - listensource.z = camera2.z; - listensource.angle = camera2.angle; + listensource.x = camera[1].x; + listensource.y = camera[1].y; + listensource.z = camera[1].z; + listensource.angle = camera[1].angle; } - else if (splitscreen > 1 && listener == players[thirddisplayplayer].mo && camera3.chase) + else if (splitscreen > 1 && listener == players[displayplayers[2]].mo && camera[2].chase) { - listensource.x = camera3.x; - listensource.y = camera3.y; - listensource.z = camera3.z; - listensource.angle = camera3.angle; + listensource.x = camera[2].x; + listensource.y = camera[2].y; + listensource.z = camera[2].z; + listensource.angle = camera[2].angle; } - else if (splitscreen > 2 && listener == players[fourthdisplayplayer].mo && camera4.chase) + else if (splitscreen > 2 && listener == players[displayplayers[3]].mo && camera[3].chase) { - listensource.x = camera4.x; - listensource.y = camera4.y; - listensource.z = camera4.z; - listensource.angle = camera4.angle; + listensource.x = camera[3].x; + listensource.y = camera[3].y; + listensource.z = camera[3].z; + listensource.angle = camera[3].angle; } else { diff --git a/src/st_stuff.c b/src/st_stuff.c index bbfa4c047..3b35907b7 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -372,7 +372,7 @@ static inline void ST_InitData(void) // 'link' the statusbar display to a player, which could be // another player than consoleplayer, for example, when you // change the view in a multiplayer demo with F12. - stplyr = &players[displayplayer]; + stplyr = &players[displayplayers[0]]; st_palette = -1; } @@ -442,7 +442,7 @@ static INT32 SCY(INT32 y) if (splitscreen) { y >>= 1; - if (stplyr != &players[displayplayer]) + if (stplyr != &players[displayplayers[0]]) y += vid.height / 2; } return y; @@ -458,7 +458,7 @@ static INT32 STRINGY(INT32 y) if (splitscreen) { y >>= 1; - if (stplyr != &players[displayplayer]) + if (stplyr != &players[displayplayers[0]]) y += BASEVIDHEIGHT / 2; } return y; @@ -471,7 +471,7 @@ static INT32 SPLITFLAGS(INT32 f) // Pass this V_SNAPTO(TOP|BOTTOM) and it'll trim them to account for splitscreen! -Red if (splitscreen) { - if (stplyr != &players[displayplayer]) + if (stplyr != &players[displayplayers[0]]) f &= ~V_SNAPTOTOP; else f &= ~V_SNAPTOBOTTOM; @@ -498,7 +498,7 @@ static INT32 SCR(INT32 r) if (splitscreen) { y >>= 1; - if (stplyr != &players[displayplayer]) + if (stplyr != &players[displayplayers[0]]) y += vid.height / 2; } return FixedInt(FixedDiv(y, vid.fdupy)); @@ -701,7 +701,7 @@ static inline void ST_drawRings(void) // SRB2kart - unused. /* static void ST_drawLives(void) // SRB2kart - unused. { - const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayer] ? V_SPLITSCREEN : 0); + const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayers[0]] ? V_SPLITSCREEN : 0); if (!stplyr->skincolor) return; // Just joined a server, skin isn't loaded yet! @@ -1019,7 +1019,7 @@ static void ST_drawNiGHTSHUD(void) // SRB2kart - unused. if (G_IsSpecialStage(gamemap)) { // Since special stages share score, time, rings, etc. // disable splitscreen mode for its HUD. - if (stplyr != &players[displayplayer]) + if (stplyr != &players[displayplayers[0]]) return; nosshack = splitscreen; splitscreen = 0; @@ -1124,7 +1124,7 @@ static void ST_drawNiGHTSHUD(void) // SRB2kart - unused. V_DrawScaledPatch(locx, STRINGY(locy)-3, V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), V_HUDTRANS, drillfill[fillpatch]); - stplyr = &players[secondarydisplayplayer]; + stplyr = &players[displayplayers[1]]; if (stplyr->pflags & PF_DRILLING) fillpatch = (stplyr->drillmeter & 1) + 1; else @@ -1132,7 +1132,7 @@ static void ST_drawNiGHTSHUD(void) // SRB2kart - unused. V_DrawScaledPatch(locx, STRINGY(locy-3), V_SNAPTOBOTTOM|V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]); - stplyr = &players[displayplayer]; + stplyr = &players[displayplayers[0]]; splitscreen = 0; } else @@ -1881,7 +1881,7 @@ static void ST_overlayDrawer(void) ST_drawTeamName(); // Special Stage HUD - if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayer]) + if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayers[0]]) ST_drawSpecialStageHUD(); // Emerald Hunt Indicators @@ -1919,7 +1919,7 @@ static void ST_overlayDrawer(void) { char name[MAXPLAYERNAME+12]; - INT32 y = (stplyr == &players[displayplayer]) ? 4 : BASEVIDHEIGHT/2-12; + INT32 y = (stplyr == &players[displayplayers[0]]) ? 4 : BASEVIDHEIGHT/2-12; sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]); V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name); } @@ -1930,10 +1930,10 @@ static void ST_overlayDrawer(void) } // This is where we draw all the fun cheese if you have the chasecam off! - /*if ((stplyr == &players[displayplayer] && !camera.chase) - || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase) - || ((splitscreen > 1 && stplyr == &players[thirddisplayplayer]) && !camera3.chase) - || ((splitscreen > 2 && stplyr == &players[fourthdisplayplayer]) && !camera4.chase)) + /*if ((stplyr == &players[displayplayers[0]] && !camera[0].chase) + || ((splitscreen && stplyr == &players[displayplayers[1]]) && !camera[1].chase) + || ((splitscreen > 1 && stplyr == &players[displayplayers[2]]) && !camera[2].chase) + || ((splitscreen > 2 && stplyr == &players[displayplayers[3]]) && !camera[3].chase)) { ST_drawFirstPersonHUD(); }*/ @@ -2086,8 +2086,10 @@ static void ST_MayonakaStatic(void) void ST_Drawer(void) { + UINT8 i; + #ifdef SEENAMES - if (cv_seenames.value && cv_allowseenames.value && displayplayer == consoleplayer && seenplayer && seenplayer->mo && !mapreset) + if (cv_seenames.value && cv_allowseenames.value && displayplayers[0] == consoleplayer && seenplayer && seenplayer->mo && !mapreset) { if (cv_seenames.value == 1) V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF, player_names[seenplayer-players]); @@ -2121,26 +2123,12 @@ void ST_Drawer(void) if (st_overlay) { // No deadview! - stplyr = &players[displayplayer]; - ST_overlayDrawer(); - - if (splitscreen) + for (i = 0; i <= splitscreen; i++) { - stplyr = &players[secondarydisplayplayer]; + stplyr = &players[displayplayers[i]]; ST_overlayDrawer(); - - if (splitscreen > 1) - { - stplyr = &players[thirddisplayplayer]; - ST_overlayDrawer(); - - if (splitscreen > 2) - { - stplyr = &players[fourthdisplayplayer]; - ST_overlayDrawer(); - } - } } + // draw Midnight Channel's overlay ontop if (mapheaderinfo[gamemap-1]->typeoflevel & TOL_TV) // Very specific Midnight Channel stuff. ST_MayonakaStatic(); diff --git a/src/y_inter.c b/src/y_inter.c index f37084282..f7f4845bb 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -360,7 +360,7 @@ void Y_IntermissionDrawer(void) V_DrawFadeScreen(0xFF00, 22); if (!splitscreen) - whiteplayer = demo.playback ? displayplayer : consoleplayer; + whiteplayer = demo.playback ? displayplayers[0] : consoleplayer; if (cons_menuhighlight.value) hilicol = cons_menuhighlight.value; @@ -1051,19 +1051,19 @@ void Y_VoteDrawer(void) { case 1: thiscurs = cursor2; - p = secondarydisplayplayer; + p = displayplayers[1]; break; case 2: thiscurs = cursor3; - p = thirddisplayplayer; + p = displayplayers[2]; break; case 3: thiscurs = cursor4; - p = fourthdisplayplayer; + p = displayplayers[3]; break; default: thiscurs = cursor1; - p = displayplayer; + p = displayplayers[0]; break; } @@ -1218,10 +1218,7 @@ static void Y_VoteStops(SINT8 pick, SINT8 level) S_StartSound(NULL, sfx_noooo2); // gasp else if (mapheaderinfo[nextmap] && (mapheaderinfo[nextmap]->menuflags & LF2_HIDEINMENU)) S_StartSound(NULL, sfx_noooo1); // this is bad - else if (netgame && (pick == consoleplayer - || pick == secondarydisplayplayer - || pick == thirddisplayplayer - || pick == fourthdisplayplayer)) + else if (netgame && P_IsLocalPlayer(&players[pick])) S_StartSound(NULL, sfx_yeeeah); // yeeeah! else S_StartSound(NULL, sfx_kc48); // just a cool sound @@ -1354,13 +1351,13 @@ void Y_VoteTicker(void) switch (i) { case 1: - p = secondarydisplayplayer; + p = displayplayers[1]; break; case 2: - p = thirddisplayplayer; + p = displayplayers[2]; break; case 3: - p = fourthdisplayplayer; + p = displayplayers[3]; break; default: p = consoleplayer; From a3d2b4832922fd26e7937fa733ac258a1a75702a Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 18 Apr 2019 12:20:13 -0400 Subject: [PATCH 173/186] Fix up more stuff Now in a mergable state --- src/d_main.c | 2 + src/d_net.h | 1 - src/doomstat.h | 3 + src/g_game.c | 2 +- src/hardware/hw3sound.c | 10 +-- src/hardware/hw_main.c | 167 ++++++++++++++-------------------------- src/k_kart.c | 2 +- src/p_local.h | 2 + src/p_mobj.c | 2 + src/p_spec.c | 2 + src/p_user.c | 10 +-- src/r_main.c | 20 +---- src/r_state.h | 3 +- src/r_things.c | 16 ++-- src/s_sound.c | 4 +- 15 files changed, 98 insertions(+), 148 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index b3ae0adea..313980397 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -436,6 +436,8 @@ static void D_Display(void) objectsdrawn = 0; } + viewssnum = i; + #ifdef HWRENDER if (rendermode != render_soft) HWR_RenderPlayerView(i, &players[displayplayers[i]]); diff --git a/src/d_net.h b/src/d_net.h index 8e518e404..eb657eec1 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -21,7 +21,6 @@ // Max computers in a game #define MAXNETNODES (MAXPLAYERS+4) #define BROADCASTADDR MAXNETNODES -#define MAXSPLITSCREENPLAYERS 4 // Max number of players on a single computer #define NETSPLITSCREEN // Kart's splitscreen netgame feature #define STATLENGTH (TICRATE*2) diff --git a/src/doomstat.h b/src/doomstat.h index 4c4270bec..f80efe631 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -77,7 +77,10 @@ extern boolean addedtogame; // true after the server has added you extern boolean multiplayer; extern INT16 gametype; + +#define MAXSPLITSCREENPLAYERS 4 // Max number of players on a single computer extern UINT8 splitscreen; + extern boolean circuitmap; // Does this level have 'circuit mode'? extern boolean fromlevelselect; extern boolean forceresetplayers, deferencoremode; diff --git a/src/g_game.c b/src/g_game.c index 109c2baa5..f9c8f401c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -7397,7 +7397,7 @@ void G_DoPlayDemo(char *defdemoname) // Load players that were in-game when the map started p = READUINT8(demo_p); - for (i = 1; i < MAXSPLITSCREENPLAYERS; i++); + for (i = 1; i < MAXSPLITSCREENPLAYERS; i++) displayplayers[i] = INT32_MAX; while (p != 0xFF) diff --git a/src/hardware/hw3sound.c b/src/hardware/hw3sound.c index f7c6e1da0..2594a5df9 100644 --- a/src/hardware/hw3sound.c +++ b/src/hardware/hw3sound.c @@ -296,7 +296,7 @@ static void HW3S_FillSourceParameters data->max_distance = MAX_DISTANCE; data->min_distance = MIN_DISTANCE; - if (origin && origin != players[displayplayer].mo) + if (origin && origin != players[displayplayers[0]].mo) { data->head_relative = false; @@ -356,10 +356,10 @@ INT32 HW3S_I_StartSound(const void *origin_p, source3D_data_t *source_parm, chan source3D_data_t source3d_data; INT32 s_num = 0; source_t *source = NULL; - mobj_t *listenmobj = players[displayplayer].mo; + mobj_t *listenmobj = players[displayplayers[0]].mo; // TODO: Kart 4P does not support sounds properly here mobj_t *listenmobj2 = NULL; - if (splitscreen) listenmobj2 = players[secondarydisplayplayer].mo; + if (splitscreen) listenmobj2 = players[displayplayers[1]].mo; if (sound_disabled) return -1; @@ -876,12 +876,12 @@ static void HW3S_Update3DSource(source_t *src) void HW3S_UpdateSources(void) { - mobj_t *listener = players[displayplayer].mo; + mobj_t *listener = players[displayplayers[0]].mo; mobj_t *listener2 = NULL; source_t *src; INT32 audible, snum, volume, sep, pitch; - if (splitscreen) listener2 = players[secondarydisplayplayer].mo; + if (splitscreen) listener2 = players[displayplayers[1]].mo; HW3S_UpdateListener2(listener2); HW3S_UpdateListener(listener); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4fcef218a..54395ab45 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -63,7 +63,7 @@ struct hwdriver_s hwdriver; // ========================================================================== -static void HWR_AddSprites(sector_t *sec, UINT8 ssplayer); +static void HWR_AddSprites(sector_t *sec); static void HWR_ProjectSprite(mobj_t *thing); #ifdef HWPRECIP static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); @@ -3389,7 +3389,7 @@ static void HWR_AddPolyObjectPlanes(void) // : Draw one or more line segments. // Notes : Sets gr_cursectorlight to the light of the parent sector, to modulate wall textures // -----------------+ -static void HWR_Subsector(size_t num, UINT8 ssplayer) +static void HWR_Subsector(size_t num) { INT16 count; seg_t *line; @@ -3754,7 +3754,7 @@ static void HWR_Subsector(size_t num, UINT8 ssplayer) { // draw sprites first, coz they are clipped to the solidsegs of // subsectors more 'in front' - HWR_AddSprites(gr_frontsector, ssplayer); + HWR_AddSprites(gr_frontsector); //Hurdler: at this point validcount must be the same, but is not because // gr_frontsector doesn't point anymore to sub->sector due to @@ -3806,7 +3806,7 @@ static boolean HWR_CheckHackBBox(fixed_t *bb) // BP: big hack for a test in lighning ref : 1249753487AB fixed_t *hwbbox; -static void HWR_RenderBSPNode(INT32 bspnum, UINT8 ssplayer) +static void HWR_RenderBSPNode(INT32 bspnum) { /*//GZDoom code if(bspnum == -1) @@ -3846,12 +3846,12 @@ static void HWR_RenderBSPNode(INT32 bspnum, UINT8 ssplayer) if (bspnum == -1) { //*(gr_drawsubsector_p++) = 0; - HWR_Subsector(0, ssplayer); + HWR_Subsector(0); } else { //*(gr_drawsubsector_p++) = bspnum&(~NF_SUBSECTOR); - HWR_Subsector(bspnum&(~NF_SUBSECTOR), ssplayer); + HWR_Subsector(bspnum&(~NF_SUBSECTOR)); } return; } @@ -3863,14 +3863,14 @@ static void HWR_RenderBSPNode(INT32 bspnum, UINT8 ssplayer) hwbbox = bsp->bbox[side]; // Recursively divide front space. - HWR_RenderBSPNode(bsp->children[side], ssplayer); + HWR_RenderBSPNode(bsp->children[side]); // Possibly divide back space. if (HWR_CheckBBox(bsp->bbox[side^1])) { // BP: big hack for a test in lighning ref : 1249753487AB hwbbox = bsp->bbox[side^1]; - HWR_RenderBSPNode(bsp->children[side^1], ssplayer); + HWR_RenderBSPNode(bsp->children[side^1]); } } @@ -4097,14 +4097,14 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t angle_t shadowdir; // Set direction - if (splitscreen && stplyr == &players[secondarydisplayplayer]) - shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value); - else if (splitscreen > 1 && stplyr == &players[thirddisplayplayer]) - shadowdir = localangle3 + FixedAngle(cv_cam3_rotate.value); - else if (splitscreen > 2 && stplyr == &players[fourthdisplayplayer]) - shadowdir = localangle4 + FixedAngle(cv_cam4_rotate.value); + if (splitscreen && stplyr == &players[displayplayers[1]]) + shadowdir = localangle[1] + FixedAngle(cv_cam2_rotate.value); + else if (splitscreen > 1 && stplyr == &players[displayplayers[2]]) + shadowdir = localangle[2] + FixedAngle(cv_cam3_rotate.value); + else if (splitscreen > 2 && stplyr == &players[displayplayers[3]]) + shadowdir = localangle[3] + FixedAngle(cv_cam4_rotate.value); else - shadowdir = localangle + FixedAngle(cv_cam_rotate.value); + shadowdir = localangle[0] + FixedAngle(cv_cam_rotate.value); // Find floorheight floorheight = HWR_OpaqueFloorAtPos( @@ -5283,7 +5283,7 @@ static void HWR_DrawSprites(void) // During BSP traversal, this adds sprites by sector. // -------------------------------------------------------------------------- static UINT8 sectorlight; -static void HWR_AddSprites(sector_t *sec, UINT8 ssplayer) +static void HWR_AddSprites(sector_t *sec) { mobj_t *thing; #ifdef HWPRECIP @@ -5316,19 +5316,19 @@ static void HWR_AddSprites(sector_t *sec, UINT8 ssplayer) if (splitscreen) { if (thing->eflags & MFE_DRAWONLYFORP1) - if (ssplayer != 1) + if (viewssnum != 0) continue; if (thing->eflags & MFE_DRAWONLYFORP2) - if (ssplayer != 2) + if (viewssnum != 1) continue; if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) - if (ssplayer != 3) + if (viewssnum != 2) continue; if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) - if (ssplayer != 4) + if (viewssnum != 3) continue; } @@ -5351,19 +5351,19 @@ static void HWR_AddSprites(sector_t *sec, UINT8 ssplayer) if (splitscreen) { if (thing->eflags & MFE_DRAWONLYFORP1) - if (ssplayer != 1) + if (viewssnum != 0) continue; if (thing->eflags & MFE_DRAWONLYFORP2) - if (ssplayer != 2) + if (viewssnum != 1) continue; if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) - if (ssplayer != 3) + if (viewssnum != 2) continue; if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) - if (ssplayer != 4) + if (viewssnum != 3) continue; } @@ -5906,33 +5906,8 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) { const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd); postimg_t *type; - UINT8 ssplayer = 0; - if (splitscreen) - { - if (player == &players[secondarydisplayplayer]) - { - type = &postimgtype2; - ssplayer = 2; - } - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - { - type = &postimgtype3; - ssplayer = 3; - } - else if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - { - type = &postimgtype4; - ssplayer = 4; - } - else - { - type = &postimgtype; - ssplayer = 1; - } - } - else - type = &postimgtype; + type = &postimgtype[viewnumber]; { // do we really need to save player (is it not the same)? @@ -6056,36 +6031,36 @@ if (0) validcount++; - HWR_RenderBSPNode((INT32)numnodes-1, ssplayer); + HWR_RenderBSPNode((INT32)numnodes-1); #ifndef NEWCLIP // Make a viewangle int so we can render things based on mouselook if (player == &players[consoleplayer]) - viewangle = localaiming; - else if (splitscreen && player == &players[secondarydisplayplayer]) - viewangle = localaiming2; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - viewangle = localaiming3; - else if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - viewangle = localaiming4; + viewangle = localaiming[0]; + else if (splitscreen && player == &players[displayplayers[1]]) + viewangle = localaiming[1]; + else if (splitscreen > 1 && player == &players[displayplayers[2]]) + viewangle = localaiming[2]; + else if (splitscreen > 2 && player == &players[displayplayers[3]]) + viewangle = localaiming[3]; // Handle stuff when you are looking farther up or down. if ((aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT)) { dup_viewangle += ANGLE_90; HWR_ClearClipSegs(); - HWR_RenderBSPNode((INT32)numnodes-1, ssplayer); //left + HWR_RenderBSPNode((INT32)numnodes-1); //left dup_viewangle += ANGLE_90; if (((INT32)aimingangle > ANGLE_45 || (INT32)aimingangle<-ANGLE_45)) { HWR_ClearClipSegs(); - HWR_RenderBSPNode((INT32)numnodes-1, ssplayer); //back + HWR_RenderBSPNode((INT32)numnodes-1); //back } dup_viewangle += ANGLE_90; HWR_ClearClipSegs(); - HWR_RenderBSPNode((INT32)numnodes-1, ssplayer); //right + HWR_RenderBSPNode((INT32)numnodes-1); //right dup_viewangle += ANGLE_90; } @@ -6149,38 +6124,13 @@ if (0) void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) { const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd); - postimg_t *type; - UINT8 ssplayer = 0; + postimg_t *type = &postimgtype[viewnumber]; const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on FRGBAFloat ClearColor; - if (splitscreen) - { - if (player == &players[secondarydisplayplayer]) - { - type = &postimgtype2; - ssplayer = 2; - } - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - { - type = &postimgtype3; - ssplayer = 3; - } - else if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - { - type = &postimgtype4; - ssplayer = 4; - } - else - { - type = &postimgtype; - ssplayer = 1; - } - } - else - type = &postimgtype; + type = &postimgtype[viewnumber]; ClearColor.red = 0.0f; ClearColor.green = 0.0f; @@ -6315,36 +6265,36 @@ if (0) validcount++; - HWR_RenderBSPNode((INT32)numnodes-1, ssplayer); + HWR_RenderBSPNode((INT32)numnodes-1); #ifndef NEWCLIP // Make a viewangle int so we can render things based on mouselook if (player == &players[consoleplayer]) - viewangle = localaiming; - else if (splitscreen && player == &players[secondarydisplayplayer]) - viewangle = localaiming2; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - viewangle = localaiming3; - else if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - viewangle = localaiming4; + viewangle = localaiming[0]; + else if (splitscreen && player == &players[displayplayers[1]]) + viewangle = localaiming[1]; + else if (splitscreen > 1 && player == &players[displayplayers[2]]) + viewangle = localaiming[2]; + else if (splitscreen > 2 && player == &players[displayplayers[3]]) + viewangle = localaiming[3]; // Handle stuff when you are looking farther up or down. if ((aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT)) { dup_viewangle += ANGLE_90; HWR_ClearClipSegs(); - HWR_RenderBSPNode((INT32)numnodes-1, ssplayer); //left + HWR_RenderBSPNode((INT32)numnodes-1); //left dup_viewangle += ANGLE_90; if (((INT32)aimingangle > ANGLE_45 || (INT32)aimingangle<-ANGLE_45)) { HWR_ClearClipSegs(); - HWR_RenderBSPNode((INT32)numnodes-1, ssplayer); //back + HWR_RenderBSPNode((INT32)numnodes-1); //back } dup_viewangle += ANGLE_90; HWR_ClearClipSegs(); - HWR_RenderBSPNode((INT32)numnodes-1, ssplayer); //right + HWR_RenderBSPNode((INT32)numnodes-1); //right dup_viewangle += ANGLE_90; } @@ -6807,16 +6757,17 @@ INT32 HWR_GetTextureUsed(void) void HWR_DoPostProcessor(player_t *player) { - postimg_t *type; + postimg_t *type = &postimgtype[0]; + UINT8 i; - if (splitscreen > 2 && player == &players[fourthdisplayplayer]) - type = &postimgtype4; - else if (splitscreen > 1 && player == &players[thirddisplayplayer]) - type = &postimgtype3; - else if (splitscreen && player == &players[secondarydisplayplayer]) - type = &postimgtype2; - else - type = &postimgtype; + for (i = splitscreen; i > 0; i--) + { + if (player == &players[displayplayers[i]]) + { + type = &postimgtype[i]; + break; + } + } // Armageddon Blast Flash! // Could this even be considered postprocessor? diff --git a/src/k_kart.c b/src/k_kart.c index 1237a5920..17885b71a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8224,7 +8224,7 @@ static void K_drawBattleFullscreen(void) // check to see if there's anyone else at all for (i = 0; i < MAXPLAYERS; i++) { - if (i == displayplayer) + if (i == displayplayers[0]) continue; if (playeringame[i] && !stplyr->spectator) return; diff --git a/src/p_local.h b/src/p_local.h index 5f7c4ef98..bfb78cef5 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -22,6 +22,7 @@ #include "p_tick.h" #include "r_defs.h" #include "p_maputl.h" +#include "doomstat.h" // MAXSPLITSCREENPLAYERS #define FLOATSPEED (FRACUNIT*4) @@ -137,6 +138,7 @@ boolean P_PlayerInPain(player_t *player); void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor); void P_ResetPlayer(player_t *player); boolean P_IsLocalPlayer(player_t *player); +boolean P_IsDisplayPlayer(player_t *player); boolean P_SpectatorJoinGame(player_t *player); boolean P_IsObjectInGoop(mobj_t *mo); diff --git a/src/p_mobj.c b/src/p_mobj.c index 102af9dca..9d583d131 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1135,6 +1135,8 @@ static void P_PlayerFlip(mobj_t *mo) } else if (mo->player->pflags & PF_FLIPCAM) { + UINT8 i; + mo->player->aiming = InvAngle(mo->player->aiming); for (i = 0; i <= splitscreen; i++) diff --git a/src/p_spec.c b/src/p_spec.c index eaa7fa3d6..9ed17eaa7 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2381,6 +2381,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (mo->player) { + UINT8 i; + if (bot) // This might put poor Tails in a wall if he's too far behind! D: But okay, whatever! >:3 P_TeleportMove(bot, bot->x + x, bot->y + y, bot->z + z); diff --git a/src/p_user.c b/src/p_user.c index 8d8400264..df93eaac3 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -7944,13 +7944,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall else focusangle = mo->angle; - if (thiscam == &camera) + if (thiscam == &camera[0]) camrotate = cv_cam_rotate.value; - else if (thiscam == &camera2) + else if (thiscam == &camera[1]) camrotate = cv_cam2_rotate.value; - else if (thiscam == &camera3) + else if (thiscam == &camera[2]) camrotate = cv_cam3_rotate.value; - else if (thiscam == &camera4) + else if (thiscam == &camera[3]) camrotate = cv_cam4_rotate.value; else camrotate = 0; @@ -8542,7 +8542,7 @@ boolean P_SpectatorJoinGame(player_t *player) static void P_CalcPostImg(player_t *player) { sector_t *sector = player->mo->subsector->sector; - postimg_t *type; + postimg_t *type = postimg_none; INT32 *param; fixed_t pviewheight; UINT8 i; diff --git a/src/r_main.c b/src/r_main.c index 122062431..2a7d2be96 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -30,6 +30,7 @@ #include "p_spec.h" // skyboxmo #include "z_zone.h" #include "m_random.h" // quake camera shake +#include "doomstat.h" // MAXSPLITSCREENPLAYERS #ifdef HWRENDER #include "hardware/hw_main.h" @@ -65,7 +66,7 @@ size_t loopcount; fixed_t viewx, viewy, viewz; angle_t viewangle, aimingangle; -UINT8 viewnumber; +UINT8 viewssnum; fixed_t viewcos, viewsin; boolean viewsky, skyVisible; boolean skyVisiblePerPlayer[MAXSPLITSCREENPLAYERS]; // saved values of skyVisible for each splitscreen player @@ -1151,6 +1152,7 @@ void R_SetupFrame(player_t *player, boolean skybox) } else if (splitscreen) { + UINT8 i; for (i = 1; i <= splitscreen; i++) { if (player == &players[displayplayers[i]]) @@ -1323,20 +1325,6 @@ void R_RenderPlayerView(player_t *player) const boolean skybox = (skyboxmo[0] && cv_skybox.value); UINT8 i; - viewnumber = 0; // default - - if (splitscreen) - { - for (i = 1; i <= splitscreen; i++) - { - if (player == &players[i]) - { - viewnumber = i; - break; - } - } - } - // if this is display player 1 if (cv_homremoval.value && player == &players[displayplayers[0]]) { @@ -1367,7 +1355,7 @@ void R_RenderPlayerView(player_t *player) // load previous saved value of skyVisible for the player for (i = 0; i <= splitscreen; i++) { - if (player == &players[displayplayers[i]] + if (player == &players[displayplayers[i]]) { skyVisible = skyVisiblePerPlayer[i]; break; diff --git a/src/r_state.h b/src/r_state.h index 6e21e4477..e37bdf52e 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -17,6 +17,7 @@ // Need data structure definitions. #include "d_player.h" #include "r_data.h" +#include "doomstat.h" // MAXSPLITSCREENPLAYERS #ifdef __GNUG__ #pragma interface @@ -88,7 +89,7 @@ extern side_t *sides; // extern fixed_t viewx, viewy, viewz; extern angle_t viewangle, aimingangle; -extern UINT8 viewnumber; // splitscreen view number +extern UINT8 viewssnum; // splitscreen view number extern boolean viewsky, skyVisible; extern boolean skyVisiblePerPlayer[MAXSPLITSCREENPLAYERS]; // saved values of skyVisible of each splitscreen player extern sector_t *viewsector; diff --git a/src/r_things.c b/src/r_things.c index 71957bb54..6af423101 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1748,19 +1748,19 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) if (splitscreen) { if (thing->eflags & MFE_DRAWONLYFORP1) - if (viewnumber != 0) + if (viewssnum != 0) continue; if (thing->eflags & MFE_DRAWONLYFORP2) - if (viewnumber != 1) + if (viewssnum != 1) continue; if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) - if (viewnumber != 2) + if (viewssnum != 2) continue; if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) - if (viewnumber != 3) + if (viewssnum != 3) continue; } @@ -1783,19 +1783,19 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) if (splitscreen) { if (thing->eflags & MFE_DRAWONLYFORP1) - if (viewnumber != 0) + if (viewssnum != 0) continue; if (thing->eflags & MFE_DRAWONLYFORP2) - if (viewnumber != 1) + if (viewssnum != 1) continue; if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) - if (viewnumber != 2) + if (viewssnum != 2) continue; if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) - if (viewnumber != 3) + if (viewssnum != 3) continue; } diff --git a/src/s_sound.c b/src/s_sound.c index 8e649d08c..a89946a54 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -935,8 +935,8 @@ void S_UpdateSounds(void) if (dedicated || sound_disabled) return; - if (players[displayplayer].awayviewtics) - listenmobj = players[displayplayer].awayviewmobj; + if (players[displayplayers[0]].awayviewtics) + listenmobj = players[displayplayers[0]].awayviewmobj; if (splitscreen) { From 804cde886110819a7a8df5213564d8a75f2de009 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 00:48:01 -0400 Subject: [PATCH 174/186] Fix polyobj angle delta --- src/p_polyobj.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 9967969d3..03fb10d0f 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1336,13 +1336,13 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta, if (turnthings == 2 || (turnthings == 1 && !mo->player)) { mo->angle += delta; if (mo->player == &players[consoleplayer]) - localangle[0] = mo->angle; + localangle[0] += delta; else if (mo->player == &players[displayplayers[1]]) - localangle[1] = mo->angle; + localangle[1] += delta; else if (mo->player == &players[displayplayers[2]]) - localangle[2] = mo->angle; + localangle[2] += delta; else if (mo->player == &players[displayplayers[3]]) - localangle[3] = mo->angle; + localangle[3] += delta; } } } From 8a1ff31d1db6dffd65c7b9f360f5427f7eba9dfc Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 00:49:05 -0400 Subject: [PATCH 175/186] Remove bad +1 --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index cb62738ad..b2e27f89b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5787,7 +5787,7 @@ static void M_DrawPlaybackMenu(void) if (splitscreen >= i - playback_view1) { - INT32 ply = displayplayers[i - playback_view1 + 1]; + INT32 ply = displayplayers[i - playback_view1]; icon = facerankprefix[players[ply].skin]; if (i != itemOn) From 5a1fc6f9f4f85dafcd3680b58e547933443acbf6 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 00:49:36 -0400 Subject: [PATCH 176/186] Remove outdated comment --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index f9c8f401c..7d673f66d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1217,7 +1217,7 @@ INT32 JoyAxis(axis_input_e axissel, UINT8 p) // // set secondaryplayer true to build player 2's ticcmd in splitscreen mode // -INT32 localaiming[MAXSPLITSCREENPLAYERS]; // TODO: convert these 3 into MAXSPLITSCREENPLAYERS arrays +INT32 localaiming[MAXSPLITSCREENPLAYERS]; angle_t localangle[MAXSPLITSCREENPLAYERS]; boolean camspin[MAXSPLITSCREENPLAYERS]; From fe28094c0c4ce26b517cb89ee2a929bb15eb23bf Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 01:33:11 -0400 Subject: [PATCH 177/186] Menu fix-up - Use center menu style for the tiny extras menu - Move Screenshot Options, Add-on Options, Replay Options, and Erase Data into Data Options again --- src/m_menu.c | 83 +++++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 53 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index b2e27f89b..3d407ec45 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -319,7 +319,7 @@ menu_t OP_SoundOptionsDef; //static void M_RestartAudio(void); //Misc -menu_t /*OP_DataOptionsDef,*/ OP_ScreenshotOptionsDef, OP_EraseDataDef; +menu_t OP_DataOptionsDef, OP_ScreenshotOptionsDef, OP_EraseDataDef; menu_t OP_HUDOptionsDef, OP_ChatOptionsDef; menu_t OP_GameOptionsDef, OP_ServerOptionsDef; #ifndef NONET @@ -338,11 +338,11 @@ static patch_t *addonsp[NUM_EXT+5]; // Replay hut menu_t MISC_ReplayHutDef; +menu_t MISC_ReplayOptionsDef; static void M_HandleReplayHutList(INT32 choice); static void M_DrawReplayHut(void); static void M_DrawReplayStartMenu(void); static boolean M_QuitReplayHut(void); -static void M_EnterReplayOptions(INT32 choice); static void M_HutStartReplay(INT32 choice); static void M_DrawPlaybackMenu(void); @@ -547,10 +547,8 @@ static menuitem_t MISC_AddonsMenu[] = static menuitem_t MISC_ReplayHutMenu[] = { - {IT_CALL |IT_STRING, NULL, "Replay Options...", M_EnterReplayOptions, 0}, - - {IT_KEYHANDLER|IT_NOTHING, NULL, "", M_HandleReplayHutList, 20}, // Dummy menuitem for the replay list - {IT_NOTHING, NULL, "", NULL, 20}, // Dummy for handling wrapping to the top of the menu.. + {IT_KEYHANDLER|IT_NOTHING, NULL, "", M_HandleReplayHutList, 0}, // Dummy menuitem for the replay list + {IT_NOTHING, NULL, "", NULL, 0}, // Dummy for handling wrapping to the top of the menu.. }; static menuitem_t MISC_ReplayStartMenu[] = @@ -778,9 +776,9 @@ static menuitem_t SR_PandorasBox[] = // Sky Room Custom Unlocks static menuitem_t SR_MainMenu[] = { - {IT_STRING|IT_SUBMENU, NULL, "Unlockables", &SR_UnlockChecklistDef, 0}, - {IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 10}, - {IT_CALL|IT_STRING, NULL, "Replay Hut", M_ReplayHut, 20}, + {IT_STRING|IT_SUBMENU, NULL, "Unlockables", &SR_UnlockChecklistDef, 100}, + {IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 108}, + {IT_CALL|IT_STRING, NULL, "Replay Hut", M_ReplayHut, 116}, {IT_DISABLED, NULL, "", NULL, 0}, // Custom1 {IT_DISABLED, NULL, "", NULL, 0}, // Custom2 {IT_DISABLED, NULL, "", NULL, 0}, // Custom3 @@ -1129,15 +1127,13 @@ static menuitem_t OP_MainMenu[] = {IT_SUBMENU|IT_STRING, NULL, "Sound Options...", &OP_SoundOptionsDef, 40}, {IT_SUBMENU|IT_STRING, NULL, "HUD Options...", &OP_HUDOptionsDef, 60}, - {IT_STRING|IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 70}, + {IT_SUBMENU|IT_STRING, NULL, "Gameplay Options...", &OP_GameOptionsDef, 70}, + {IT_SUBMENU|IT_STRING, NULL, "Server Options...", &OP_ServerOptionsDef, 80}, - {IT_SUBMENU|IT_STRING, NULL, "Gameplay Options...", &OP_GameOptionsDef, 90}, - {IT_SUBMENU|IT_STRING, NULL, "Server Options...", &OP_ServerOptionsDef, 100}, - {IT_STRING|IT_CALL, NULL, "Add-on Options...", M_AddonsOptions, 110}, + {IT_SUBMENU|IT_STRING, NULL, "Data Options...", &OP_DataOptionsDef, 100}, - {IT_CALL|IT_STRING, NULL, "Tricks & Secrets (F1)", M_Manual, 130}, - {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 140}, - {IT_SUBMENU|IT_STRING, NULL, "Erase Data...", &OP_EraseDataDef, 150}, + {IT_CALL|IT_STRING, NULL, "Tricks & Secrets (F1)", M_Manual, 120}, + {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 130}, }; static menuitem_t OP_ControlsMenu[] = @@ -1409,12 +1405,14 @@ static menuitem_t OP_SoundOptionsMenu[] = {IT_STRING|IT_CVAR, NULL, "Play SFX While Unfocused", &cv_playsoundifunfocused, 135}, }; -/*static menuitem_t OP_DataOptionsMenu[] = +static menuitem_t OP_DataOptionsMenu[] = { - {IT_STRING | IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 10}, + {IT_STRING | IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 10}, + {IT_STRING | IT_CALL, NULL, "Add-on Options...", M_AddonsOptions, 20}, + {IT_STRING | IT_SUBMENU, NULL, "Replay Options...", &MISC_ReplayOptionsDef, 30}, - {IT_STRING | IT_SUBMENU, NULL, "Erase Data...", &OP_EraseDataDef, 30}, -};*/ + {IT_STRING | IT_SUBMENU, NULL, "Erase Data...", &OP_EraseDataDef, 50}, +}; static menuitem_t OP_ScreenshotOptionsMenu[] = { @@ -1655,7 +1653,7 @@ menu_t MISC_AddonsDef = { NULL, sizeof (MISC_AddonsMenu)/sizeof (menuitem_t), - &MainDef, + &OP_DataOptionsDef, MISC_AddonsMenu, M_DrawAddons, 50, 28, @@ -1671,7 +1669,7 @@ menu_t MISC_ReplayHutDef = MISC_ReplayHutMenu, M_DrawReplayHut, 30, 80, - (sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t)) - 2, // Start on the replay list + 0, M_QuitReplayHut }; @@ -1679,9 +1677,9 @@ menu_t MISC_ReplayOptionsDef = { "M_REPOPT", sizeof (MISC_ReplayOptionsMenu)/sizeof (menuitem_t), - &MISC_ReplayHutDef, + &OP_DataOptionsDef, MISC_ReplayOptionsMenu, - M_DrawGenericBackgroundMenu, + M_DrawGenericMenu, 27, 40, 0, NULL @@ -1808,18 +1806,7 @@ menu_t SR_PandoraDef = 0, M_ExitPandorasBox }; -menu_t SR_MainDef = -{ - "M_SECRET", - sizeof (SR_MainMenu)/sizeof (menuitem_t), - &MainDef, - SR_MainMenu, - M_DrawGenericMenu, - //M_DrawSkyRoom, - 60, 40, - 0, - NULL -}; +menu_t SR_MainDef = CENTERMENUSTYLE(NULL, SR_MainMenu, &MainDef, 72); //menu_t SR_LevelSelectDef = MAPICONMENUSTYLE(NULL, SR_LevelSelectMenu, &SR_MainDef); @@ -2163,10 +2150,10 @@ menu_t OP_OpenGLColorDef = NULL }; #endif -//menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); -menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_MainDef, 30, 30); -menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_MainDef, 30, 30); -menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_MainDef, 30, 30); +menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); +menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_DataOptionsDef, 30, 30); +menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30); +menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 30, 30); // ========================================================================== // CVAR ONCHANGE EVENTS GO HERE @@ -5697,15 +5684,6 @@ static boolean M_QuitReplayHut(void) return true; } -static void M_EnterReplayOptions(INT32 choice) -{ - (void)choice; - - // We can't just use M_SetupNextMenu because that'll boot us back to the title screen! - currentMenu = &MISC_ReplayOptionsDef; - itemOn = currentMenu->lastOn; -} - static void M_HutStartReplay(INT32 choice) { (void)choice; @@ -6088,11 +6066,10 @@ static void M_Options(INT32 choice) (void)choice; // if the player is not admin or server, disable gameplay & server options - OP_MainMenu[5].status = OP_MainMenu[6].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + OP_MainMenu[4].status = OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); - // if the player is playing _at all_, disable the erase data & credits options - OP_MainMenu[9].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); - OP_MainMenu[10].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // Play credits + OP_DataOptionsMenu[3].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // Erase data OP_GameOptionsMenu[3].status = (M_SecretUnlocked(SECRET_ENCORE)) ? (IT_CVAR|IT_STRING) : IT_SECRET; // cv_kartencore From 032a755ef771bd12abf0b337d8039ac80b3cb67a Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 01:34:25 -0400 Subject: [PATCH 178/186] Remove unique version number --- src/doomdef.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index 793537f82..8db114fb5 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -151,8 +151,8 @@ extern FILE *logstream; #else #define VERSION 100 // Game version #define SUBVERSION 4 // more precise version number -#define VERSIONSTRING "v1.0.4 Netreplays" -#define VERSIONSTRINGW L"v1.0.4 Netreplays" +#define VERSIONSTRING "v1.0.4" +#define VERSIONSTRINGW L"v1.0.4" // Hey! If you change this, add 1 to the MODVERSION below! // Otherwise we can't force updates! #endif From 3fdd51736b54406651827bfa764fab42736457ad Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 12:00:51 -0400 Subject: [PATCH 179/186] HORRID HACK around holding enter in the playback menu having awful, crash-causing side-effects --- src/m_menu.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index b516c8ec4..144b671eb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -354,6 +354,8 @@ static void M_PlaybackSetViews(INT32 choice); static void M_PlaybackAdjustView(INT32 choice); static void M_PlaybackQuit(INT32 choice); +static UINT8 playback_enterheld = 0; // horrid hack to prevent holding the button from being extremely fucked + // Drawing functions static void M_DrawGenericMenu(void); static void M_DrawGenericBackgroundMenu(void); @@ -2837,11 +2839,11 @@ boolean M_Responder(event_t *ev) // Flip left/right with up/down for the playback menu, since it's a horizontal icon row. switch (ch) { - case KEY_LEFTARROW: ch = KEY_UPARROW; break; - case KEY_UPARROW: ch = KEY_RIGHTARROW; break; - case KEY_RIGHTARROW: ch = KEY_DOWNARROW; break; - case KEY_DOWNARROW: ch = KEY_LEFTARROW; break; - default: break; + case KEY_LEFTARROW: ch = KEY_UPARROW; break; + case KEY_UPARROW: ch = KEY_RIGHTARROW; break; + case KEY_RIGHTARROW: ch = KEY_DOWNARROW; break; + case KEY_DOWNARROW: ch = KEY_LEFTARROW; break; + default: break; } } @@ -2891,6 +2893,15 @@ boolean M_Responder(event_t *ev) case KEY_ENTER: noFurtherInput = true; currentMenu->lastOn = itemOn; + + if (currentMenu == &PlaybackMenuDef) + { + boolean held = (boolean)playback_enterheld; + playback_enterheld = TICRATE/7; + if (held) + return true; + } + if (routine) { if (((currentMenu->menuitems[itemOn].status & IT_TYPE)==IT_CALL @@ -3294,6 +3305,14 @@ void M_Ticker(void) if (--skullAnimCounter <= 0) skullAnimCounter = 8; + if (currentMenu == &PlaybackMenuDef) + { + if (playback_enterheld > 0) + playback_enterheld--; + } + else + playback_enterheld = 0; + //added : 30-01-98 : test mode for five seconds if (vidm_testingmode > 0) { @@ -4349,7 +4368,6 @@ void M_StartMessage(const char *string, void *routine, M_StartControlPanel(); // can't put menuactive to true if (currentMenu == &MessageDef) // Prevent recursion - MessageDef.prevMenu = &MainDef; else MessageDef.prevMenu = currentMenu; From 00a3ea58ee2db2193fcfd96bad5473c37525f5bb Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 12:03:50 -0400 Subject: [PATCH 180/186] Add message boxes for file add errors --- src/g_game.c | 13 +++++++++---- src/m_menu.c | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 7d673f66d..d29da5ba0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -6570,16 +6570,21 @@ static void G_LoadDemoExtraFiles(UINT8 **pp) if (toomany) { - CONS_Printf("Too many files loaded\n"); + CONS_Alert(CONS_WARNING, M_GetText("Too many files loaded to add anymore for demo playback\n")); + if (!CON_Ready()) + M_StartMessage(M_GetText("There are too many files loaded to add this demo's add-ons.\n\nDemo playback may desync.\n\nPress ESC\n"), NULL, MM_NOTHING); } else if (ncs != FS_FOUND) { if (ncs == FS_NOTFOUND) - CONS_Printf("You do not have a copy of %s\n", filename); + CONS_Alert(CONS_NOTICE, M_GetText("You do not have a copy of %s\n"), filename); else if (ncs == FS_MD5SUMBAD) - CONS_Printf("Checksum mismatch on %s\n", filename); + CONS_Alert(CONS_NOTICE, M_GetText("Checksum mismatch on %s\n"), filename); else - CONS_Printf("Unknown error finding file (%s)\n", filename); + CONS_Alert(CONS_NOTICE, M_GetText("Unknown error finding file %s\n"), filename); + + if (!CON_Ready()) + M_StartMessage(M_GetText("There were errors trying to add this demo's add-ons. Check the console for more information.\n\nDemo playback may desync.\n\nPress ESC\n"), NULL, MM_NOTHING); } else { diff --git a/src/m_menu.c b/src/m_menu.c index 144b671eb..ed034f93c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4368,6 +4368,7 @@ void M_StartMessage(const char *string, void *routine, M_StartControlPanel(); // can't put menuactive to true if (currentMenu == &MessageDef) // Prevent recursion + MessageDef.prevMenu = ((demo.playback) ? &PlaybackMenuDef : &MainDef); else MessageDef.prevMenu = currentMenu; From 50be0cdbee730bf3ca4db2c61939e80412d62174 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 12:31:50 -0400 Subject: [PATCH 181/186] Don't keep fast-forward enabled between demos --- src/g_game.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index d29da5ba0..13fb3d61a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -8090,6 +8090,8 @@ void G_StopDemo(void) demo.timing = false; singletics = false; + CV_SetValue(&cv_playbackspeed, 1); + if (gamestate == GS_LEVEL && rendermode != render_none) { V_SetPaletteLump("PLAYPAL"); // Reset the palette From 3fed6b69956a80d5275c364475009b9300014ef0 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 12:36:11 -0400 Subject: [PATCH 182/186] Disable rewind between demos, too. --- src/g_game.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_game.c b/src/g_game.c index 13fb3d61a..a5a623841 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -8091,6 +8091,7 @@ void G_StopDemo(void) singletics = false; CV_SetValue(&cv_playbackspeed, 1); + demo.rewinding = false; if (gamestate == GS_LEVEL && rendermode != render_none) { From 2c49feeb9c4a6f002e64c957e27d2d5742140de8 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 12:42:29 -0400 Subject: [PATCH 183/186] ENSURE viewcount slider is present for multiplayer demos --- src/m_menu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/m_menu.c b/src/m_menu.c index ed034f93c..7fb2a1ec4 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5758,6 +5758,8 @@ static void M_DrawPlaybackMenu(void) } else { + PlaybackMenu[playback_viewcount].status = IT_ARROWS|IT_STRING; + for (i = 0; i <= splitscreen; i++) PlaybackMenu[playback_view1+i].status = IT_ARROWS|IT_STRING; for (i = splitscreen+1; i < 4; i++) From b679cfe5c5539c87a929b47c05ce38f32757030d Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 12:50:05 -0400 Subject: [PATCH 184/186] Hide this debug message --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index a5a623841..6e9a60681 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4855,7 +4855,7 @@ static void FindClosestSkinForStats(UINT32 p, UINT8 kartspeed, UINT8 kartweight) { INT32 closest_skin = GetSkinNumClosestToStats(kartspeed, kartweight); - CONS_Printf("Using %s instead...\n", skins[closest_skin].name); + //CONS_Printf("Using %s instead...\n", skins[closest_skin].name); SetPlayerSkinByNum(p, closest_skin); } From 9a1ae859bdb4422c3041e30e25a05c64bea7b07c Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 2 May 2019 12:58:02 -0400 Subject: [PATCH 185/186] Don't allow custom gamedata to overwrite kart gamedata or replay folders --- src/dehacked.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index b0052c6c6..972fe9591 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2142,11 +2142,12 @@ static boolean GoodDataFileName(const char *s) p = s + strlen(s) - strlen(tail); if (p <= s) return false; // too short if (!fasticmp(p, tail)) return false; // doesn't end in .dat -#ifdef DELFILE - if (fasticmp(s, "gamedata.dat") && !disableundo) return false; -#else - if (fasticmp(s, "gamedata.dat")) return false; -#endif + + if (fasticmp(s, "gamedata.dat")) return false; // Vanilla SRB2 gamedata + if (fasticmp(s, "main.dat")) return false; // Vanilla SRB2 time attack replay folder + if (fasticmp(s, "kartdata.dat")) return false; // SRB2Kart gamedata + if (fasticmp(s, "kart.dat")) return false; // SRB2Kart time attack replay folder + if (fasticmp(s, "online.dat")) return false; // SRB2Kart online replay folder return true; } From 0958617ecbd5a343b491d0fd17e4bce824f050ee Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Mon, 6 May 2019 21:17:32 -0400 Subject: [PATCH 186/186] Fix skybox bug --- src/r_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_main.c b/src/r_main.c index 4d825eef8..b2f511dee 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -852,7 +852,7 @@ void R_SkyboxFrame(player_t *player) { for (i = 1; i <= splitscreen; i++) { - if (player == &players[i]) + if (player == &players[displayplayers[i]]) { thiscam = &camera[i]; break;