From 316cd61d9f8567cd9a1efb4b525155193892f5f0 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 4 Jan 2022 22:41:35 +0000 Subject: [PATCH 01/19] * Fix follower colour being limited to UINT8. * Fix follower colour not being set in offline mode (based on Steel's fix but no UINT8). --- src/d_netcmd.c | 8 +++++--- src/g_demo.c | 18 ++++++++++-------- src/p_user.c | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7fa504e90..ada2302a1 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -776,10 +776,10 @@ void D_RegisterClientCommands(void) Followercolor_cons_t[i].strvalue = skincolors[i-2].name; } - Followercolor_cons_t[1].value = -1; + Followercolor_cons_t[1].value = UINT16_MAX; Followercolor_cons_t[1].strvalue = "Match"; // Add "Match" option, which will make the follower color match the player's - Followercolor_cons_t[0].value = -2; + Followercolor_cons_t[0].value = UINT16_MAX-1; Followercolor_cons_t[0].strvalue = "Opposite"; // Add "Opposite" option, ...which is like "Match", but for coloropposite. Color_cons_t[MAXSKINCOLORS].value = Followercolor_cons_t[MAXSKINCOLORS+2].value = 0; @@ -1443,6 +1443,8 @@ static void SendNameAndColor(UINT8 n) if (cv_follower[n].value >= -1 && cv_follower[n].value != player->followerskin) SetFollower(playernum, cv_follower[n].value); + player->followercolor = cv_followercolor[n].value; + if (metalrecording && n == 0) { // Starring Metal Sonic as themselves, obviously. SetPlayerSkinByNum(playernum, 5); @@ -1497,7 +1499,7 @@ static void SendNameAndColor(UINT8 n) WRITEUINT16(p, (UINT16)cv_playercolor[n].value); WRITEUINT8(p, (UINT8)cv_skin[n].value); WRITESINT8(p, (SINT8)cv_follower[n].value); - WRITEUINT16(p, (UINT8)cv_followercolor[n].value); + WRITEUINT16(p, (UINT16)cv_followercolor[n].value); SendNetXCmdForPlayer(n, XD_NAMEANDCOLOR, buf, p - buf); } diff --git a/src/g_demo.c b/src/g_demo.c index 2dd3cd277..3885ca3b0 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -299,12 +299,14 @@ void G_ReadDemoExtraData(void) // Follower's color M_Memcpy(name, demo_p, 16); demo_p += 16; - for (i = 0; i < numskincolors; i++) - if (!stricmp(skincolors[i].name, name)) // SRB2kart - { - players[p].followercolor = i; - break; - } + for (i = 0; i < numskincolors +2; i++) // +2 because of Match and Opposite + { + if (!stricmp(Followercolor_cons_t[i].strvalue, name)) + { + players[p].followercolor = i; + break; + } + } } if (extradata & DXD_PLAYSTATE) { @@ -443,7 +445,7 @@ void G_WriteDemoExtraData(void) // write follower color memset(name, 0, 16); - strncpy(name, Followercolor_cons_t[players[i].followercolor].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" + strncpy(name, Followercolor_cons_t[(UINT16)(players[i].followercolor+2)].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" M_Memcpy(demo_p,name,16); demo_p += 16; @@ -2056,7 +2058,7 @@ void G_BeginRecording(void) // Save follower's colour memset(name, 0, 16); - strncpy(name, Followercolor_cons_t[player->followercolor].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" + strncpy(name, Followercolor_cons_t[(UINT16)(player->followercolor+2)].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" M_Memcpy(demo_p, name, 16); demo_p += 16; diff --git a/src/p_user.c b/src/p_user.c index 5813d1ac4..0d2f77051 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3965,10 +3965,10 @@ static void P_HandleFollower(player_t *player) // Set follower colour switch (player->followercolor) { - case 255: // "Match" (-1) + case UINT16_MAX: // "Match" color = player->skincolor; break; - case 254: // "Opposite" (-2) + case UINT16_MAX-1: // "Opposite" color = skincolors[player->skincolor].invcolor; break; default: From a749160c6b233fbb6d3f84c1951877e4631f7b79 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 4 Jan 2022 22:43:54 +0000 Subject: [PATCH 02/19] Make followers only stretch for their movement *relative* to the player, not their movement in general. --- src/p_user.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 0d2f77051..3041178ab 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3915,7 +3915,7 @@ static void P_HandleFollower(player_t *player) follower_t fl; angle_t an; fixed_t zoffs; - fixed_t sx, sy, sz; + fixed_t sx, sy, sz, deltaz; UINT16 color; fixed_t bubble; // bubble scale (0 if no bubble) @@ -3949,6 +3949,9 @@ static void P_HandleFollower(player_t *player) sx = player->mo->x + FixedMul((player->mo->scale*fl.dist), FINECOSINE((an)>>ANGLETOFINESHIFT)); sy = player->mo->y + FixedMul((player->mo->scale*fl.dist), FINESINE((an)>>ANGLETOFINESHIFT)); + // interp info helps with stretchy fix + deltaz = (player->mo->z - player->mo->old_z); + // for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P sz = player->mo->z + FixedMul(player->mo->scale, zoffs)*P_MobjFlip(player->mo); if (player->mo->eflags & MFE_VERTICALFLIP) @@ -4032,6 +4035,7 @@ static void P_HandleFollower(player_t *player) // 02/09/2021: cast lag to int32 otherwise funny things happen since it was changed to uint32 in the struct player->follower->momx = (sx - player->follower->x)/ (INT32)fl.horzlag; player->follower->momy = (sy - player->follower->y)/ (INT32)fl.horzlag; + player->follower->z += deltaz/ (INT32)fl.vertlag; player->follower->momz = (sz - player->follower->z)/ (INT32)fl.vertlag; player->follower->angle = player->mo->angle; From 60f08f238071cf50d8d1ce5e7a0628fee74ab1a2 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 4 Jan 2022 23:02:09 +0000 Subject: [PATCH 03/19] Defines per Sal request --- src/d_netcmd.c | 4 ++-- src/p_user.c | 4 ++-- src/r_data.h | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index ada2302a1..cc8425b86 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -776,10 +776,10 @@ void D_RegisterClientCommands(void) Followercolor_cons_t[i].strvalue = skincolors[i-2].name; } - Followercolor_cons_t[1].value = UINT16_MAX; + Followercolor_cons_t[1].value = FOLLOWERCOLOR_MATCH; Followercolor_cons_t[1].strvalue = "Match"; // Add "Match" option, which will make the follower color match the player's - Followercolor_cons_t[0].value = UINT16_MAX-1; + Followercolor_cons_t[0].value = FOLLOWERCOLOR_OPPOSITE; Followercolor_cons_t[0].strvalue = "Opposite"; // Add "Opposite" option, ...which is like "Match", but for coloropposite. Color_cons_t[MAXSKINCOLORS].value = Followercolor_cons_t[MAXSKINCOLORS+2].value = 0; diff --git a/src/p_user.c b/src/p_user.c index 3041178ab..ae8a1b359 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3968,10 +3968,10 @@ static void P_HandleFollower(player_t *player) // Set follower colour switch (player->followercolor) { - case UINT16_MAX: // "Match" + case FOLLOWERCOLOR_MATCH: // "Match" color = player->skincolor; break; - case UINT16_MAX-1: // "Opposite" + case FOLLOWERCOLOR_OPPOSITE: // "Opposite" color = skincolors[player->skincolor].invcolor; break; default: diff --git a/src/r_data.h b/src/r_data.h index be92c094e..1228f2420 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -41,6 +41,8 @@ extern INT16 *hicolormaps; // remap high colors to high colors.. extern CV_PossibleValue_t Color_cons_t[]; extern CV_PossibleValue_t Followercolor_cons_t[]; // follower colours table, not a duplicate because of the "Match" option. +#define FOLLOWERCOLOR_MATCH UINT16_MAX +#define FOLLOWERCOLOR_OPPOSITE (UINT16_MAX-1) // I/O, setting up the stuff. void R_InitTextureData(void); From 6651bd404326cdb217beeff75906d1fb1d153c69 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 4 Jan 2022 23:03:51 +0000 Subject: [PATCH 04/19] Also fix bubble --- src/p_user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_user.c b/src/p_user.c index ae8a1b359..5879e4cf9 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4069,6 +4069,7 @@ static void P_HandleFollower(player_t *player) // match follower's momentums and (e)flags(2). bmobj->momx = player->follower->momx; bmobj->momy = player->follower->momy; + bmobj->z += deltaz/ (INT32)fl.vertlag; bmobj->momz = player->follower->momz; P_SetScale(bmobj, FixedMul(bubble, player->mo->scale)); From 30fe1736171272f94c3331f83e4311eb52850f8b Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 4 Jan 2022 23:21:28 +0000 Subject: [PATCH 05/19] Bracketing (fixes a weird bug with bubble) --- src/p_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 5879e4cf9..42311e4f1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4035,7 +4035,7 @@ static void P_HandleFollower(player_t *player) // 02/09/2021: cast lag to int32 otherwise funny things happen since it was changed to uint32 in the struct player->follower->momx = (sx - player->follower->x)/ (INT32)fl.horzlag; player->follower->momy = (sy - player->follower->y)/ (INT32)fl.horzlag; - player->follower->z += deltaz/ (INT32)fl.vertlag; + player->follower->z += (deltaz/ (INT32)fl.vertlag); player->follower->momz = (sz - player->follower->z)/ (INT32)fl.vertlag; player->follower->angle = player->mo->angle; @@ -4069,7 +4069,7 @@ static void P_HandleFollower(player_t *player) // match follower's momentums and (e)flags(2). bmobj->momx = player->follower->momx; bmobj->momy = player->follower->momy; - bmobj->z += deltaz/ (INT32)fl.vertlag; + bmobj->z += (deltaz/ (INT32)fl.vertlag); bmobj->momz = player->follower->momz; P_SetScale(bmobj, FixedMul(bubble, player->mo->scale)); From 8e0f02d65acdf6e43296c2a81ba2b37d2b0d616b Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 17 Jan 2022 18:53:01 -0800 Subject: [PATCH 06/19] Refactor R_SetupFrame/R_SkyboxFrame to use splitscreen number directly --- src/hardware/hw_main.c | 4 +-- src/r_main.c | 60 ++++++++++-------------------------------- src/r_main.h | 4 +-- 3 files changed, 18 insertions(+), 50 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 74f13ff0e..28bae2bb8 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6042,7 +6042,7 @@ void HWR_RenderSkyboxView(player_t *player) } // note: sets viewangle, viewx, viewy, viewz - R_SkyboxFrame(player); + R_SkyboxFrame(viewssnum); // copy view cam position for local use dup_viewx = viewx; @@ -6253,7 +6253,7 @@ void HWR_RenderPlayerView(void) } // note: sets viewangle, viewx, viewy, viewz - R_SetupFrame(player); + R_SetupFrame(viewssnum); framecount++; // timedemo // copy view cam position for local use diff --git a/src/r_main.c b/src/r_main.c index c3e044ef2..ad6e952bf 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1199,30 +1199,13 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y) // R_SetupFrame // -void R_SetupFrame(player_t *player) +void R_SetupFrame(int s) { - camera_t *thiscam = &camera[0]; - boolean chasecam = (cv_chasecam[0].value != 0); - UINT8 i = 0; + player_t *player = &players[displayplayers[s]]; + camera_t *thiscam = &camera[s]; + boolean chasecam = (cv_chasecam[s].value != 0); - for (i = 0; i <= r_splitscreen; i++) - { - if (player == &players[displayplayers[i]]) - { - thiscam = &camera[i]; - chasecam = (cv_chasecam[i].value != 0); - R_SetViewContext(VIEWCONTEXT_PLAYER1 + i); - break; - } - } - - if (i > r_splitscreen) - { - i = 0; // Shouldn't be possible, but just in case. - thiscam = &camera[0]; - chasecam = (cv_chasecam[0].value != 0); - R_SetViewContext(VIEWCONTEXT_PLAYER1); - } + R_SetViewContext(VIEWCONTEXT_PLAYER1 + s); if (player->spectator) // no spectator chasecam chasecam = false; // force chasecam off @@ -1267,8 +1250,8 @@ void R_SetupFrame(player_t *player) if (!demo.playback && player->playerstate != PST_DEAD) { - newview->angle = localangle[i]; // WARNING: camera uses this - newview->aim = localaiming[i]; + newview->angle = localangle[s]; // WARNING: camera uses this + newview->aim = localaiming[s]; } } newview->roll = R_ViewRollAngle(player); @@ -1307,27 +1290,12 @@ void R_SetupFrame(player_t *player) R_InterpolateView(rendertimefrac); } -void R_SkyboxFrame(player_t *player) +void R_SkyboxFrame(int s) { - camera_t *thiscam = &camera[0]; - UINT8 i = 0; + player_t *player = &players[displayplayers[s]]; + camera_t *thiscam = &camera[s]; - for (i = 0; i <= r_splitscreen; i++) - { - if (player == &players[displayplayers[i]]) - { - thiscam = &camera[i]; - R_SetViewContext(VIEWCONTEXT_SKY1 + i); - break; - } - } - - if (i > r_splitscreen) - { - i = 0; // Shouldn't be possible, but just in case. - thiscam = &camera[0]; - R_SetViewContext(VIEWCONTEXT_SKY1); - } + R_SetViewContext(VIEWCONTEXT_SKY1 + s); // cut-away view stuff newview->sky = true; @@ -1355,8 +1323,8 @@ void R_SkyboxFrame(player_t *player) newview->angle = player->mo->angle; if (/*!demo.playback && */player->playerstate != PST_DEAD) { - newview->angle = localangle[i]; - newview->aim = localaiming[i]; + newview->angle = localangle[s]; + newview->aim = localaiming[s]; } } newview->angle += r_viewmobj->angle; @@ -1561,7 +1529,7 @@ void R_RenderPlayerView(void) V_DrawFill(viewwidth, viewheight, viewwidth, viewheight, 31|V_NOSCALESTART); } - R_SetupFrame(player); + R_SetupFrame(viewssnum); framecount++; validcount++; diff --git a/src/r_main.h b/src/r_main.h index a2acf60d9..43bafc46c 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -134,8 +134,8 @@ void R_SetViewSize(void); // do it (sometimes explicitly called) void R_ExecuteSetViewSize(void); -void R_SetupFrame(player_t *player); -void R_SkyboxFrame(player_t *player); +void R_SetupFrame(int split); +void R_SkyboxFrame(int split); boolean R_ViewpointHasChasecam(player_t *player); boolean R_IsViewpointThirdPerson(player_t *player, boolean skybox); From eda9b36455c49cac9c6b779428b1006d97955fe7 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 17 Jan 2022 21:03:22 -0800 Subject: [PATCH 07/19] Refactor R_SetupFrame/R_SkyboxFrame to deduplicate some code --- src/r_main.c | 140 +++++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 76 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index ad6e952bf..50d77f704 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1199,6 +1199,54 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y) // R_SetupFrame // +static void +R_SetupCommonFrame +( player_t * player, + subsector_t * subsector) +{ + newview->player = player; + + newview->x += quake.x; + newview->y += quake.y; + newview->z += quake.z; + + newview->roll = R_ViewRollAngle(player); + + if (subsector) + newview->sector = subsector->sector; + else + newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; + + R_InterpolateView(rendertimefrac); +} + +static void R_SetupAimingFrame(int s) +{ + player_t *player = &players[displayplayers[s]]; + camera_t *thiscam = &camera[s]; + + if (player->awayviewtics) + { + newview->aim = player->awayviewaiming; + newview->angle = player->awayviewmobj->angle; + } + else if (thiscam && thiscam->chase) + { + newview->aim = thiscam->aiming; + newview->angle = thiscam->angle; + } + else if (!demo.playback && player->playerstate != PST_DEAD) + { + newview->aim = localaiming[s]; + newview->angle = localangle[s]; + } + else + { + newview->aim = player->aiming; + newview->angle = player->mo->angle; + } +} + void R_SetupFrame(int s) { player_t *player = &players[displayplayers[s]]; @@ -1220,74 +1268,43 @@ void R_SetupFrame(int s) newview->sky = false; + R_SetupAimingFrame(s); + if (player->awayviewtics) { // cut-away view stuff r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN I_Assert(r_viewmobj != NULL); + + newview->x = r_viewmobj->x; + newview->y = r_viewmobj->y; newview->z = r_viewmobj->z + 20*FRACUNIT; - newview->aim = player->awayviewaiming; - newview->angle = r_viewmobj->angle; + + R_SetupCommonFrame(player, r_viewmobj->subsector); } else if (!player->spectator && chasecam) // use outside cam view { r_viewmobj = NULL; + + newview->x = thiscam->x; + newview->y = thiscam->y; newview->z = thiscam->z + (thiscam->height>>1); - newview->aim = thiscam->aiming; - newview->angle = thiscam->angle; + + R_SetupCommonFrame(player, thiscam->subsector); } else // use the player's eyes view { - newview->z = player->viewz; - r_viewmobj = player->mo; I_Assert(r_viewmobj != NULL); - newview->aim = player->aiming; - newview->angle = r_viewmobj->angle; - - if (!demo.playback && player->playerstate != PST_DEAD) - { - newview->angle = localangle[s]; // WARNING: camera uses this - newview->aim = localaiming[s]; - } - } - newview->roll = R_ViewRollAngle(player); - newview->z += quake.z; - - newview->player = player; - - if (chasecam && !player->awayviewtics && !player->spectator) - { - newview->x = thiscam->x; - newview->y = thiscam->y; - newview->x += quake.x; - newview->y += quake.y; - - if (thiscam->subsector) - newview->sector = thiscam->subsector->sector; - else - newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; - } - else - { newview->x = r_viewmobj->x; newview->y = r_viewmobj->y; - newview->x += quake.x; - newview->y += quake.y; + newview->z = player->viewz; - if (r_viewmobj->subsector) - newview->sector = r_viewmobj->subsector->sector; - else - newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; + R_SetupCommonFrame(player, r_viewmobj->subsector); } - - // newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT); - // newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - - R_InterpolateView(rendertimefrac); } void R_SkyboxFrame(int s) @@ -1307,30 +1324,8 @@ void R_SkyboxFrame(int s) I_Error("R_SkyboxFrame: r_viewmobj null (player %s)", sizeu1(playeri)); } #endif - if (player->awayviewtics) - { - newview->aim = player->awayviewaiming; - newview->angle = player->awayviewmobj->angle; - } - else if (thiscam && thiscam->chase) - { - newview->aim = thiscam->aiming; - newview->angle = thiscam->angle; - } - else - { - newview->aim = player->aiming; - newview->angle = player->mo->angle; - if (/*!demo.playback && */player->playerstate != PST_DEAD) - { - newview->angle = localangle[s]; - newview->aim = localaiming[s]; - } - } - newview->angle += r_viewmobj->angle; - newview->roll = R_ViewRollAngle(player); - newview->player = player; + R_SetupAimingFrame(s); newview->x = r_viewmobj->x; newview->y = r_viewmobj->y; @@ -1407,15 +1402,8 @@ void R_SkyboxFrame(int s) newview->z += campos.z * -mh->skybox_scalez; } - if (r_viewmobj->subsector) - newview->sector = r_viewmobj->subsector->sector; - else - newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; - // newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT); - // newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - - R_InterpolateView(rendertimefrac); + R_SetupCommonFrame(player, r_viewmobj->subsector); } boolean R_ViewpointHasChasecam(player_t *player) From 8c3fad058d4caa7734b8e5a1cdb1a726e49be87f Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 23 Jan 2022 20:33:27 +0000 Subject: [PATCH 08/19] * Fix the Z_Free double-free issue (in two different ways, one ifdef'd out) that can sometimes occur on the vote screen. * Fix a technically invalid read in D_SetupVote. * If the third map on the voting screen has a different gametype, don't interact with the buffer. * Fix the inttime 0 setting, since I was in y_inter.c and testing quick map changes. --- src/d_netcmd.c | 10 +++++----- src/f_finale.c | 2 +- src/g_game.c | 34 +++++++++++++++++++++++++--------- src/g_game.h | 2 +- src/m_menu.c | 2 +- src/y_inter.c | 30 ++++++++++++++++++++++++------ 6 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7fa504e90..0358ccd58 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2408,7 +2408,7 @@ void D_SetupVote(void) UINT8 *p = buf; INT32 i; UINT8 secondgt = G_SometimesGetDifferentGametype(); - INT16 votebuffer[3] = {-1,-1,-1}; + INT16 votebuffer[4] = {-1,-1,-1, 0}; if ((cv_kartencore.value == 1) && (gametyperules & GTR_CIRCUIT)) WRITEUINT8(p, (gametype|0x80)); @@ -2421,13 +2421,13 @@ void D_SetupVote(void) { UINT16 m; if (i == 2) // sometimes a different gametype - m = G_RandMap(G_TOLFlag(secondgt), prevmap, false, 0, true, votebuffer); + m = G_RandMap(G_TOLFlag(secondgt), prevmap, ((secondgt != gametype) ? 2 : 0), 0, true, votebuffer); else if (i >= 3) // unknown-random and force-unknown MAP HELL - m = G_RandMap(G_TOLFlag(gametype), prevmap, false, (i-2), (i < 4), votebuffer); + m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, (i-2), (i < 4), votebuffer); else - m = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, true, votebuffer); + m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer); if (i < 3) - votebuffer[min(i, 2)] = m; // min() is a dumb workaround for gcc 4.4 array-bounds error + votebuffer[i] = m; // min() is a dumb workaround for gcc 4.4 array-bounds error WRITEUINT16(p, m); } diff --git a/src/f_finale.c b/src/f_finale.c index 0fc575e8e..e33a379d7 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2144,7 +2144,7 @@ void F_TitleScreenTicker(boolean run) } */ - mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, false, 0, false, NULL)+1); + mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, 0, 0, false, NULL)+1); numstaff = 1; while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR) diff --git a/src/g_game.c b/src/g_game.c index 2d927d158..f54b3e981 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -670,7 +670,7 @@ const char *G_BuildMapName(INT32 map) map = gamemap-1; else map = prevmap; - map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, false, 0, false, NULL)+1; + map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, 0, 0, false, NULL)+1; } if (map < 100) @@ -3247,20 +3247,24 @@ static UINT32 TOLMaps(UINT32 tolflags) * \author Graue */ static INT16 *okmaps = NULL; -INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer) +INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer) { - INT32 numokmaps = 0; + UINT32 numokmaps = 0; INT16 ix, bufx; UINT16 extbufsize = 0; boolean usehellmaps; // Only consider Hell maps in this pick if (!okmaps) + { + //CONS_Printf("(making okmaps)\n"); okmaps = Z_Malloc(NUMMAPS * sizeof(INT16), PU_STATIC, NULL); + } if (extbuffer != NULL) { bufx = 0; - while (extbuffer[bufx]) { + while (extbuffer[bufx]) + { extbufsize++; bufx++; } } @@ -3333,30 +3337,42 @@ tryagain: { if (randmapbuffer[3] == -1) // Is the buffer basically empty? { - ignorebuffer = true; // This will probably only help in situations where there's very few maps, but it's folly not to at least try it + ignorebuffer = 1; // This will probably only help in situations where there's very few maps, but it's folly not to at least try it + //CONS_Printf("RANDMAP - ignoring buffer\n"); goto tryagain; } for (bufx = 3; bufx < NUMMAPS; bufx++) // Let's clear all but the three most recent maps... randmapbuffer[bufx] = -1; + //CONS_Printf("RANDMAP - emptying randmapbuffer\n"); goto tryagain; } if (maphell) // Any wiggle room to loosen our restrictions here? { + //CONS_Printf("RANDMAP -maphell decrement\n"); maphell--; goto tryagain; } + //CONS_Printf("RANDMAP - defaulting to map01\n"); ix = 0; // Sorry, none match. You get MAP01. - for (bufx = 0; bufx < NUMMAPS+1; bufx++) - randmapbuffer[bufx] = -1; // if we're having trouble finding a map we should probably clear it + if (ignorebuffer == 1) + { + //CONS_Printf("(emptying randmapbuffer entirely)\n"); + for (bufx = 0; bufx < NUMMAPS; bufx++) + randmapbuffer[bufx] = -1; // if we're having trouble finding a map we should probably clear it + } } else + { + //CONS_Printf("RANDMAP - %d maps available to grab\n", numokmaps); ix = okmaps[M_RandomKey(numokmaps)]; + } if (!callagainsoon) { + //CONS_Printf("(freeing okmaps)\n"); Z_Free(okmaps); okmaps = NULL; } @@ -3366,7 +3382,7 @@ tryagain: void G_AddMapToBuffer(INT16 map) { - INT16 bufx, refreshnum = max(0, (INT32)TOLMaps(G_TOLFlag(gametype))-3); + INT16 bufx, refreshnum = max(0, TOLMaps(G_TOLFlag(gametype))-3); // Add the map to the buffer. for (bufx = NUMMAPS-1; bufx > 0; bufx--) @@ -3612,7 +3628,7 @@ static void G_DoCompleted(void) } else if (cv_advancemap.value == 2) // Go to random map. { - nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, false, NULL); + nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); } } diff --git a/src/g_game.h b/src/g_game.h index 9e4ef0159..9af1b0ffc 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -254,7 +254,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics); // Don't split up TOL handling UINT32 G_TOLFlag(INT32 pgametype); -INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer); +INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer); void G_AddMapToBuffer(INT16 map); #endif diff --git a/src/m_menu.c b/src/m_menu.c index 3a5be46a9..2b3e6553a 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8846,7 +8846,7 @@ static void M_StartServer(INT32 choice) G_StopMetalDemo(); if (!cv_nextmap.value) - CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, 0, false, NULL)+1); + CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, 0, 0, false, NULL)+1); if (cv_maxplayers.value < ssplayers+1) CV_SetValue(&cv_maxplayers, ssplayers+1); diff --git a/src/y_inter.c b/src/y_inter.c index 415672713..fd1a32231 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1066,7 +1066,7 @@ void Y_StartIntermission(void) else { if (cv_inttime.value == 0) - timer = 0; + timer = 1; else if (demo.playback && !multiplayer) // Override inttime (which is pulled from the replay anyway timer = 10*TICRATE; else @@ -1810,6 +1810,8 @@ void Y_EndVote(void) // static void Y_UnloadVoteData(void) { + UINT8 i; + voteclient.loaded = false; if (rendermode != render_soft) @@ -1825,11 +1827,27 @@ static void Y_UnloadVoteData(void) UNLOAD(randomlvl); UNLOAD(rubyicon); - UNLOAD(levelinfo[4].pic); - UNLOAD(levelinfo[3].pic); - UNLOAD(levelinfo[2].pic); - UNLOAD(levelinfo[1].pic); - UNLOAD(levelinfo[0].pic); + // to prevent double frees... + for (i = 0; i < 5; i++) + { + // I went to all the trouble of doing this, + // but literally nowhere else frees level pics. +#if 0 + UINT8 j; + + if (!levelinfo[i].pic) + continue; + + for (j = i+1; j < 5; j++) + { + if (levelinfo[j].pic == levelinfo[i].pic) + levelinfo[j].pic = NULL; + } + UNLOAD(levelinfo[i].pic); +#else + CLEANUP(levelinfo[i].pic); +#endif + } } // From 28ee38258751966c74f5de6da3e78a5e4c02e0da Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 23 Jan 2022 20:40:59 +0000 Subject: [PATCH 09/19] ok this was supposed to be here --- 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 f54b3e981..4a8a03c33 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3382,7 +3382,7 @@ tryagain: void G_AddMapToBuffer(INT16 map) { - INT16 bufx, refreshnum = max(0, TOLMaps(G_TOLFlag(gametype))-3); + INT16 bufx, refreshnum = max(0, ((INT32)TOLMaps(G_TOLFlag(gametype)))-3); // Add the map to the buffer. for (bufx = NUMMAPS-1; bufx > 0; bufx--) From 7508e0e1982e70fa42723dce07344e23a2c8f142 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 24 Jan 2022 22:03:40 +0000 Subject: [PATCH 10/19] P_IsLocalPlayer changes This is the function that controls whether a bunch of music-related function (and also whether certain error messages get printed). * P_IsLocalPlayer now supports party players (currently untested, but the code is pretty airtight). * P_IsLocalPlayer now always returns false in replays. * P_IsMachineLocalPlayer now exists for the one situation the game determines local players that actually has a net-related function (kicking illegal character changes). * Invincibility/grow sfx now operates based on whether the player is NOT local (it used to be whether it was NOT a displayplayer). * Refactored P_SpectatorJoinGame to make future team support easier, and also reset the relevant camera focus, rather than always the consoleplayer's. * Fix viewpoints on non-local players having overlapping viewpoint text. --- src/d_netcmd.c | 2 +- src/k_kart.c | 17 ++++-- src/lua_baselib.c | 4 ++ src/p_local.h | 1 + src/p_user.c | 142 ++++++++++++++++++++++++++++------------------ src/st_stuff.c | 15 +---- 6 files changed, 105 insertions(+), 76 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 416aeb86a..474306704 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1560,7 +1560,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) demo_extradata[playernum] |= DXD_COLOR; // normal player colors - if (server && !P_IsLocalPlayer(p)) + if (server && !P_IsMachineLocalPlayer(p)) { boolean kick = false; diff --git a/src/k_kart.c b/src/k_kart.c index 99f2b1cac..e2b4aa6c2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6597,7 +6597,7 @@ static void K_UpdateInvincibilitySounds(player_t *player) { INT32 sfxnum = sfx_None; - if (player->mo->health > 0 && !P_IsDisplayPlayer(player)) + if (player->mo->health > 0 && !P_IsLocalPlayer(player)) // used to be !P_IsDisplayPlayer(player) { if (cv_kartinvinsfx.value) { @@ -8989,10 +8989,16 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetScale(overlay, player->mo->scale); } player->invincibilitytimer = itemtime+(2*TICRATE); // 10 seconds - if (P_IsLocalPlayer(player)) + + if (P_IsLocalPlayer(player) == true) + { S_ChangeMusicSpecial("kinvnc"); - if (! P_IsDisplayPlayer(player)) - S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kinvnc)); + } + else //used to be "if (P_IsDisplayPlayer(player) == false)" + { + S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc)); + } + P_RestoreMusic(player); K_PlayPowerGloatSound(player->mo); player->itemamount--; @@ -9220,8 +9226,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { S_ChangeMusicSpecial("kgrow"); } - - if (P_IsDisplayPlayer(player) == false) + else //used to be "if (P_IsDisplayPlayer(player) == false)" { S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow)); } diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 596f8b158..95e5146c6 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -682,6 +682,7 @@ static int lib_pSpawnLockOn(lua_State *L) return LUA_ErrInvalid(L, "player_t"); if (state >= NUMSTATES) return luaL_error(L, "state %d out of range (0 - %d)", state, NUMSTATES-1); +#if 0 if (P_IsLocalPlayer(player)) // Only display it on your own view. { mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker @@ -689,6 +690,9 @@ static int lib_pSpawnLockOn(lua_State *L) visual->renderflags |= RF_DONTDRAW; P_SetMobjStateNF(visual, state); } +#else + CONS_Alert(CONS_WARNING, "TODO: P_SpawnLockOn is deprecated\n"); +#endif return 0; } diff --git a/src/p_local.h b/src/p_local.h index a3d5ecd74..4940daf81 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -155,6 +155,7 @@ void P_ResetPlayer(player_t *player); boolean P_PlayerCanDamage(player_t *player, mobj_t *thing); boolean P_IsLocalPlayer(player_t *player); +boolean P_IsMachineLocalPlayer(player_t *player); boolean P_IsDisplayPlayer(player_t *player); void P_SetPlayerAngle(player_t *player, angle_t angle); diff --git a/src/p_user.c b/src/p_user.c index 1e1269751..f8eb8ad38 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1070,19 +1070,16 @@ void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative) } // -// P_IsLocalPlayer +// P_IsMachineLocalPlayer // // Returns true if player is -// on the local machine. +// ACTUALLY on the local machine // -boolean P_IsLocalPlayer(player_t *player) +boolean P_IsMachineLocalPlayer(player_t *player) { UINT8 i; - if (demo.playback) - return P_IsDisplayPlayer(player); - - for (i = 0; i <= r_splitscreen; i++) // DON'T skip P1 + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[g_localplayers[i]]) return true; @@ -1091,6 +1088,35 @@ boolean P_IsLocalPlayer(player_t *player) return false; } +// +// P_IsLocalPlayer +// +// Returns true if player is +// on the local machine +// (or simulated party) +// +boolean P_IsLocalPlayer(player_t *player) +{ + UINT8 i; + + // nobody is ever local when watching something back - you're a spectator there, even if your g_localplayers might say otherwise + if (demo.playback) + return false; + + // parties - treat everyone as if it's couch co-op + if (splitscreen_partied[consoleplayer]) + { + for (i = 0; i < splitscreen_party_size[consoleplayer]; i++) + { + if (splitscreen_party[consoleplayer][i] == (player-players)) + return true; + } + return false; + } + + return P_IsMachineLocalPlayer(player); +} + // // P_IsDisplayPlayer // @@ -3539,6 +3565,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall boolean P_SpectatorJoinGame(player_t *player) { + INT32 changeto = 0; + const char *text = NULL; + // Team changing isn't allowed. if (!cv_allowteamchange.value) { @@ -3546,12 +3575,13 @@ boolean P_SpectatorJoinGame(player_t *player) CONS_Printf(M_GetText("Server does not allow team change.\n")); //player->flashing = TICRATE + 1; //to prevent message spam. } + // Team changing in Team Match and CTF // Pressing fire assigns you to a team that needs players if allowed. // Partial code reproduction from p_tick.c autobalance code. - else if (G_GametypeHasTeams()) + // a surprise tool that will help us later... + if (G_GametypeHasTeams()) { - INT32 changeto = 0; INT32 z, numplayersred = 0, numplayersblue = 0; //find a team by num players, score, or random if all else fails. @@ -3578,55 +3608,57 @@ boolean P_SpectatorJoinGame(player_t *player) if (!LUAh_TeamSwitch(player, changeto, true, false, false)) return false; - - if (player->mo) - { - P_RemoveMobj(player->mo); - player->mo = NULL; - } - player->spectator = false; - player->pflags &= ~PF_WANTSTOJOIN; - player->spectatewait = 0; - player->ctfteam = changeto; - player->playerstate = PST_REBORN; - - //Reset away view - if (P_IsLocalPlayer(player) && displayplayers[0] != consoleplayer) - { - // Call ViewpointSwitch hooks here. - // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(player, &players[consoleplayer], true); - 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'); - else if (changeto == 2) - CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x84', M_GetText("Blue team"), '\x80'); - - return true; // no more player->mo, cannot continue. } - // Joining in game from firing. - else + + // no conditions that could cause the gamejoin to fail below this line + + if (player->mo) { - if (player->mo) - { - P_RemoveMobj(player->mo); - player->mo = NULL; - } - player->spectator = false; - player->pflags &= ~PF_WANTSTOJOIN; - player->spectatewait = 0; - player->playerstate = PST_REBORN; - - //Reset away view - 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. + P_RemoveMobj(player->mo); + player->mo = NULL; } - return false; + player->spectator = false; + player->pflags &= ~PF_WANTSTOJOIN; + player->spectatewait = 0; + player->ctfteam = changeto; + player->playerstate = PST_REBORN; + + // Reset away view (some code referenced from P_IsLocalPlayer) + { + UINT8 i = 0; + if (splitscreen_partied[consoleplayer]) + { + for (i = splitscreen_party_size[consoleplayer]; i > 0; i--) + { + if (splitscreen_party[consoleplayer][i-1] == (player-players)) + break; + } + } + + if (i == 0) + for (i = r_splitscreen; i > 0; i--) + { + if (g_localplayers[i-1] == (player-players)) + break; + } + + if (i && displayplayers[i-1] != (player-players)) + { + LUAh_ViewpointSwitch(player, player, true); + displayplayers[i-1] = (player-players); + } + } + + // a surprise tool that will help us later... + if (changeto == 1) + text = va("\x82*%s switched to the %c%s%c team.\n", player_names[player-players], '\x85', "RED", '\x82'); + else if (changeto == 2) + text = va("\x82*%s switched to the %c%s%c team.\n", player_names[player-players], '\x85', "BLU", '\x82'); + else + text = va("\x82*%s entered the game.", player_names[player-players]); + + HU_AddChatText(text, false); + return true; // no more player->mo, cannot continue. } // the below is first person only, if you're curious. check out P_CalcChasePostImg in p_mobj.c for chasecam diff --git a/src/st_stuff.c b/src/st_stuff.c index 3e0788f4d..f64f5c5e7 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1074,20 +1074,7 @@ static void ST_overlayDrawer(void) { if (cv_showviewpointtext.value) { - if (!(multiplayer && demo.playback)) - { - 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]); - } - } - else if (!demo.title) + if (!demo.title && !P_IsLocalPlayer(stplyr)) { if (!r_splitscreen) { From 3f71251fd6840e5804bd366ed089f91afc57e6bb Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 24 Jan 2022 22:52:50 +0000 Subject: [PATCH 11/19] Fix a correctly timed Thunder Shield preventing you from using rings (resolves #220) --- src/k_kart.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 99f2b1cac..6fae0ca2f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9254,8 +9254,16 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { K_DoThunderShield(player); - player->itemamount--; - K_PlayAttackTaunt(player->mo); + if (player->itemamount > 0) + { + // Why is this a conditional? + // Thunder shield: the only item that allows you to + // activate a mine while you're out of its radius, + // the SAME tic it sets your itemamount to 0 + // ...:dumbestass: + player->itemamount--; + K_PlayAttackTaunt(player->mo); + } } break; case KITEM_BUBBLESHIELD: From 2e54e38607cb8c800702afc36330a33546c76c49 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 25 Jan 2022 17:02:19 +0000 Subject: [PATCH 12/19] Diagnose itemamount underflows easier (show the empty box and number if nonzero count but zero item type) --- src/k_hud.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 62253ba68..221fbf097 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1274,7 +1274,8 @@ static void K_drawKartItem(void) localpatch = kp_sadface[offset]; break; default: - return; + localpatch = kp_nodraw; // diagnose underflows + break; } if ((stplyr->pflags & PF_ITEMOUT) && !(leveltime & 1)) From 4567d9c57f0032bfa6f5badba1ea65246461ca0d Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 11 Feb 2022 00:35:11 +0000 Subject: [PATCH 13/19] Fix allowteamchange (although this code wasn't being run, it still SHOULD return early...) --- src/p_user.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index f8eb8ad38..d78cfe84b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3570,11 +3570,7 @@ boolean P_SpectatorJoinGame(player_t *player) // Team changing isn't allowed. if (!cv_allowteamchange.value) - { - if (P_IsLocalPlayer(player)) - CONS_Printf(M_GetText("Server does not allow team change.\n")); - //player->flashing = TICRATE + 1; //to prevent message spam. - } + return false; // Team changing in Team Match and CTF // Pressing fire assigns you to a team that needs players if allowed. From 03a47cfb5ae1095dc64e84d542318aaf55b5cf02 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 11 Feb 2022 01:13:38 +0000 Subject: [PATCH 14/19] Prevent using a grow while invincible resetting the invincible music timer, when that SHOULDN'T be touched and will be set to grow properly once that's over. --- src/k_kart.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index e2b4aa6c2..1f961b15b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9222,7 +9222,11 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->growshrinktimer = itemtime+(4*TICRATE); // 12 seconds - if (P_IsLocalPlayer(player) == true) + if (player->invincibilitytimer > 0) + { + ; // invincibility has priority in P_RestoreMusic, no point in starting here + } + else if (P_IsLocalPlayer(player) == true) { S_ChangeMusicSpecial("kgrow"); } From 913610b1b7bdc425c4079ec9dfe9d35c479f8076 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 11 Feb 2022 10:38:16 +0000 Subject: [PATCH 15/19] Fixed P_RestoreMusic using displayplayers instead of local players (did not use any of the functions directly and so was missed). --- src/p_user.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index d78cfe84b..30ad2b8d4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -813,6 +813,7 @@ void P_RestoreMusic(player_t *player) if (r_splitscreen) { INT32 bestlocaltimer = 1; + INT32 *localplayertable = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers); #define setbests(p) \ if (players[p].playerstate == PST_LIVE) \ @@ -822,12 +823,12 @@ void P_RestoreMusic(player_t *player) else if (players[p].growshrinktimer > bestlocaltimer) \ { wantedmus = 2; bestlocaltimer = players[p].growshrinktimer; } \ } - setbests(displayplayers[0]); - setbests(displayplayers[1]); + setbests(localplayertable[0]); + setbests(localplayertable[1]); if (r_splitscreen > 1) - setbests(displayplayers[2]); + setbests(localplayertable[2]); if (r_splitscreen > 2) - setbests(displayplayers[3]); + setbests(localplayertable[3]); #undef setbests } else From 006b6f00ac57157549c337041c466620f3b94211 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 11 Feb 2022 12:09:00 +0000 Subject: [PATCH 16/19] Rewrite the awayview reset for both Got_Teamchange and P_SpectatorJoinGame. --- src/d_netcmd.c | 19 ++++++++++++------- src/p_user.c | 28 +++++++++------------------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 474306704..2bdc8d66e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3459,15 +3459,20 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) else if (NetPacket.packet.newteam == 0) 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 || displayplayers[0] == playernum) + // Reset away view (some code referenced from P_SpectatorJoinGame) { - // Call ViewpointSwitch hooks here. - // The viewpoint was forcibly changed. - if (displayplayers[0] != consoleplayer) // You're already viewing yourself. No big deal. - LUAh_ViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); + UINT8 i = 0; + INT32 *localplayertable = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers); - displayplayers[0] = consoleplayer; + for (i = 0; i < r_splitscreen; i++) + { + if (localplayertable[i] == playernum) + { + LUAh_ViewpointSwitch(players+playernum, players+playernum, true); + displayplayers[i] = playernum; + break; + } + } } /*if (G_GametypeHasTeams()) diff --git a/src/p_user.c b/src/p_user.c index 30ad2b8d4..7a36121dd 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3620,29 +3620,19 @@ boolean P_SpectatorJoinGame(player_t *player) player->ctfteam = changeto; player->playerstate = PST_REBORN; - // Reset away view (some code referenced from P_IsLocalPlayer) + // Reset away view (some code referenced from Got_Teamchange) { UINT8 i = 0; - if (splitscreen_partied[consoleplayer]) - { - for (i = splitscreen_party_size[consoleplayer]; i > 0; i--) - { - if (splitscreen_party[consoleplayer][i-1] == (player-players)) - break; - } - } + INT32 *localplayertable = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers); - if (i == 0) - for (i = r_splitscreen; i > 0; i--) - { - if (g_localplayers[i-1] == (player-players)) - break; - } - - if (i && displayplayers[i-1] != (player-players)) + for (i = 0; i < r_splitscreen; i++) { - LUAh_ViewpointSwitch(player, player, true); - displayplayers[i-1] = (player-players); + if (localplayertable[i] == (player-players)) + { + LUAh_ViewpointSwitch(player, player, true); + displayplayers[i] = (player-players); + break; + } } } From 6d851f2bc8855d5dbd83471c95a834abd5c46d86 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 14 Feb 2022 15:43:56 +0000 Subject: [PATCH 17/19] P_LoadLevel is a mess, but attempt to fix a few things that shouldn't be happening with resyncs, including #209. Untested. --- src/p_saveg.c | 3 ++- src/p_setup.c | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index 0561d365a..0a5da687f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4496,7 +4496,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) // tell the sound code to reset the music since we're skipping what // normally sets this flag - mapmusflags |= MUSIC_RELOADRESET; + if (!reloading) + mapmusflags |= MUSIC_RELOADRESET; G_SetGamestate(READINT16(save_p)); diff --git a/src/p_setup.c b/src/p_setup.c index 1a1583a0a..b87f5014e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3943,9 +3943,12 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // will be set by player think. players[consoleplayer].viewz = 1; + // Cancel all d_main.c fadeouts (keep fade in though). + if (reloadinggamestate) + wipegamestate = gamestate; // Don't fade if reloading the gamestate // Encore mode fade to pink to white // This is handled BEFORE sounds are stopped. - if (encoremode && !prevencoremode && !demo.rewinding) + else if (encoremode && !prevencoremode && !demo.rewinding) { if (rendermode != render_none) { @@ -4007,10 +4010,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) } } - // Cancel all d_main.c fadeouts (keep fade in though). - if (reloadinggamestate) - wipegamestate = gamestate; // Don't fade if reloading the gamestate - // Special stage & record attack retry fade to white // This is handled BEFORE sounds are stopped. if (G_GetModeAttackRetryFlag()) @@ -4032,7 +4031,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Let's fade to white here // But only if we didn't do the encore startup wipe - if (!demo.rewinding) + if (!demo.rewinding && !reloadinggamestate) { // Make sure all sounds are stopped before Z_FreeTags. S_StopSounds(); @@ -4204,10 +4203,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) { P_InitCamera(); memset(localaiming, 0, sizeof(localaiming)); + K_InitDirector(); } - K_InitDirector(); - wantedcalcdelay = wantedfrequency*2; indirectitemcooldown = 0; hyubgone = 0; @@ -4237,7 +4235,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (!(netgame || multiplayer || demo.playback) && !majormods) mapvisited[gamemap-1] |= MV_VISITED; - else if (netgame || multiplayer) + else if (!demo.playback) mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently G_AddMapToBuffer(gamemap-1); @@ -4260,7 +4258,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) lastmaploaded = gamemap; // HAS to be set after saving!! } - if (grandprixinfo.gp == true) + if (reloadinggamestate) + { + CONS_Printf("Gamestate reloaded; bot infomation may be corrupted, requires further testing...\n"); + } + else if (grandprixinfo.gp == true) { if (grandprixinfo.initalize == true) { From 0b97d954ad764e423a57a4bcb6dc98df5fe49000 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 16 Feb 2022 23:23:14 +0000 Subject: [PATCH 18/19] Tested with Chengi at one point, correct a few things from that. * Fixed a few prints happening on resync that shouldn't. * Fixed OGL loading not using levelfadecol. --- src/d_clisrv.c | 27 +++++++++++++++------------ src/hardware/hw_bsp.c | 2 +- src/p_setup.c | 6 ++---- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 855056cf1..5c4dd80d4 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1292,20 +1292,23 @@ static void CL_LoadReceivedSavegame(boolean reloading) // load a base level if (P_LoadNetGame(reloading)) { - CON_LogMessage(va(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap))); - - if (strlen(mapheaderinfo[gamemap-1]->lvlttl) > 0) + if (!reloading) { - CON_LogMessage(va(": %s", mapheaderinfo[gamemap-1]->lvlttl)); - if (strlen(mapheaderinfo[gamemap-1]->zonttl) > 0) - CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->zonttl)); - else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - CON_LogMessage(M_GetText(" Zone")); - if (mapheaderinfo[gamemap-1]->actnum > 0) - CON_LogMessage(va(" %d", mapheaderinfo[gamemap-1]->actnum)); - } + CON_LogMessage(va(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap))); - CON_LogMessage("\"\n"); + if (strlen(mapheaderinfo[gamemap-1]->lvlttl) > 0) + { + CON_LogMessage(va(": %s", mapheaderinfo[gamemap-1]->lvlttl)); + if (strlen(mapheaderinfo[gamemap-1]->zonttl) > 0) + CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->zonttl)); + else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + CON_LogMessage(M_GetText(" Zone")); + if (mapheaderinfo[gamemap-1]->actnum > 0) + CON_LogMessage(va(" %d", mapheaderinfo[gamemap-1]->actnum)); + } + + CON_LogMessage("\"\n"); + } } else { diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 4db69ff8b..df0b7113e 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -589,7 +589,7 @@ static void loading_status(void) sprintf(s, "%d%%", (++ls_percent)<<1); x = BASEVIDWIDTH/2; y = BASEVIDHEIGHT/2; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Black background to match fade in effect + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); // Black background to match fade in effect //V_DrawPatchFill(W_CachePatchName("SRB2BACK",PU_CACHE)); // SRB2 background, ehhh too bright. M_DrawTextBox(x-58, y-8, 13, 1); V_DrawString(x-50, y, V_YELLOWMAP, "Loading..."); diff --git a/src/p_setup.c b/src/p_setup.c index b87f5014e..6e77d0435 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4224,7 +4224,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_MapEnd(); // Remove the loading shit from the screen - if (rendermode != render_none && !(titlemapinaction || reloadinggamestate)) + if (rendermode != render_none && !titlemapinaction && !reloadinggamestate) F_WipeColorFill(levelfadecol); if (precache || dedicated) @@ -4259,9 +4259,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) } if (reloadinggamestate) - { - CONS_Printf("Gamestate reloaded; bot infomation may be corrupted, requires further testing...\n"); - } + ; else if (grandprixinfo.gp == true) { if (grandprixinfo.initalize == true) From b158bfe37e48a52c01f6f7428209b072612ffd0e Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 17 Feb 2022 22:41:34 +0000 Subject: [PATCH 19/19] Always stop the sounds, because we're always calling Z_FreeTags and that can lead to invalid memory. (Should fix Rai's crash) --- src/p_setup.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 6e77d0435..f5a03e628 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4029,13 +4029,14 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) } */ + // Make sure all sounds are stopped before Z_FreeTags. + S_StopSounds(); + S_ClearSfx(); + // Let's fade to white here // But only if we didn't do the encore startup wipe if (!demo.rewinding && !reloadinggamestate) { - // Make sure all sounds are stopped before Z_FreeTags. - S_StopSounds(); - S_ClearSfx(); // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug.