From 97c8d201eb66b033d9b9223b757b9e8833b225c4 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Feb 2023 15:28:31 +0000 Subject: [PATCH 1/8] Command_Map_f: Respect value of splitplayers cvar Permits testing multiple players in GP by your lonesome without having to manipulate multiple controllers at once. --- src/d_netcmd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 8ca9286d1..818d8eb89 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2970,8 +2970,21 @@ static void Command_Map_f(void) if (!Playing()) { + UINT8 ssplayers = cv_splitplayers.value-1; + multiplayer = true; restoreMenu = NULL; + + strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); + + if (cv_maxconnections.value < ssplayers+1) + CV_SetValue(&cv_maxconnections, ssplayers+1); + + if (splitscreen != ssplayers) + { + splitscreen = ssplayers; + SplitScreen_OnChange(); + } } } From e3eb3ed9f8ea372ff55d8ec8a0f6cfdcfeb965ec Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Feb 2023 15:31:25 +0000 Subject: [PATCH 2/8] Command_Map_f: Guess gametype of map in offline GP, as well as from titlescreen/menu --- 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 818d8eb89..a3f28a3ba 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2846,7 +2846,7 @@ static void Command_Map_f(void) return; } } - else if (!Playing()) + else if (!Playing() || (netgame == false && grandprixinfo.gp == true)) { newresetplayers = true; if (mapheaderinfo[newmapnum-1]) From 1b2be7b6c99745198317ab3cedf08f20ea1fca25 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Feb 2023 16:35:52 +0000 Subject: [PATCH 3/8] K_CheckBumpers, K_HandleBumperChanges: Make 2P behaviour in battle capsules mode function - Only exit Capsules/Versus round if number of players with no bumpers is equal to number of players in game. - Apply Eliminated flags in relevant context, to prevent griefing. --- src/k_battle.c | 29 ++++++++--------------------- src/k_kart.c | 4 ++-- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index 765df4966..5cc3794fe 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -17,6 +17,7 @@ #include "m_random.h" #include "r_sky.h" // skyflatnum #include "k_grandprix.h" // K_CanChangeRules +#include "k_boss.h" // bossinfo.valid #include "p_spec.h" #include "k_objects.h" @@ -92,7 +93,7 @@ void K_CheckBumpers(void) UINT8 numingame = 0; SINT8 winnernum = -1; UINT32 winnerscoreadd = 0, maxroundscore = 0; - boolean nobumpers = false; + UINT8 nobumpers = 0; if (!(gametyperules & GTR_BUMPERS)) return; @@ -118,7 +119,7 @@ void K_CheckBumpers(void) if (players[i].bumpers <= 0) // if you don't have any bumpers, you're probably not a winner { - nobumpers = true; + nobumpers++; continue; } else if (winnernum != -1) // TWO winners? that's dumb :V @@ -128,9 +129,9 @@ void K_CheckBumpers(void) winnerscoreadd -= players[i].roundscore; } - if (K_CanChangeRules(true) == false) + if (battlecapsules || bossinfo.valid) { - if (nobumpers) + if (nobumpers > 0 && nobumpers >= numingame) { for (i = 0; i < MAXPLAYERS; i++) { @@ -144,29 +145,15 @@ void K_CheckBumpers(void) } return; } - else if (numingame <= 1) + + if (numingame <= 1) { - if ((gametyperules & GTR_CAPSULES) && !battlecapsules) + if ((gametyperules & GTR_CAPSULES) && (K_CanChangeRules(true) == true)) { // Reset map to turn on battle capsules if (server) D_MapChange(gamemap, gametype, encoremode, true, 0, false, false); } - else - { - if (nobumpers) - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - if (players[i].spectator) - continue; - players[i].pflags |= PF_NOCONTEST; - P_DoPlayerExit(&players[i]); - } - } - } return; } diff --git a/src/k_kart.c b/src/k_kart.c index 081b1b124..5705fa339 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4192,9 +4192,9 @@ void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers) player->karmadelay = comebacktime; - if (gametyperules & GTR_BOSS) + if (battlecapsules || bossinfo.valid) { - P_DoTimeOver(player); + player->pflags |= (PF_NOCONTEST|PF_ELIMINATED); } else if (netgame) { From fa3b361e2f79e0c7aa9107b88c0babe92a28fe7a Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Feb 2023 16:36:32 +0000 Subject: [PATCH 4/8] K_drawStartCountdown: Only show "DUEL" text if you're actually inDuel. --- src/k_hud.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 951c2456b..5c1bec0a6 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4302,7 +4302,7 @@ static void K_drawKartStartCountdown(void) break; } - if (numplayers == 2) + if (inDuel == true) { pnum++; // DUEL } From 472d7bf25c69f6dfbdcd2f91bcf89e0d35a440c2 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Feb 2023 17:04:59 +0000 Subject: [PATCH 5/8] Match old behaviour of GTR_BOSS: DMG_TIMEOVER a player that has lost all their bumpers --- src/k_kart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/k_kart.c b/src/k_kart.c index 5705fa339..ccbeb62c6 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4195,6 +4195,7 @@ void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers) if (battlecapsules || bossinfo.valid) { player->pflags |= (PF_NOCONTEST|PF_ELIMINATED); + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER); } else if (netgame) { From ae30a24a717a7b3eabe6b517b47ab0c00c8f1eca Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Feb 2023 17:09:13 +0000 Subject: [PATCH 6/8] K_MoveExitBeam: PF_NOCONTEST and P_DoPlayerExit to match other special stage failures. Not a currently accessible codepath, but in-advance fix.: P_DoTimeOver sets exitcountdown effectively unconditionally, which means it can only be used in situations where *every* remaining player is about to explode. --- src/k_specialstage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_specialstage.c b/src/k_specialstage.c index b0defccb9..7aca01e4a 100644 --- a/src/k_specialstage.c +++ b/src/k_specialstage.c @@ -102,7 +102,8 @@ static void K_MoveExitBeam(void) if (player->distancetofinish > specialstageinfo.beamDist) { - P_DoTimeOver(player); + player->pflags |= PF_NOCONTEST; + P_DoPlayerExit(player); } } } From d2aed2d49ee0c42ab265ae7612215d788679e3fe Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Feb 2023 18:14:31 +0000 Subject: [PATCH 7/8] V_AdjustXYWithSnap: Support top/bottom slides if not V_SPLITSCREEN, V_SNAPTORIGHT, or V_SNAPTOLEFT, but do have V_SLIDEIN --- src/v_video.cpp | 58 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index 3a5983167..779a3a6c6 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -603,31 +603,49 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du if (timer < length) { - boolean slidefromright = false; - - const INT32 offsetAmount = (screenwidth * FRACUNIT/2) / length; - fixed_t offset = (screenwidth * FRACUNIT/2) - (timer * offsetAmount); - - offset += FixedMul(offsetAmount, renderdeltatics); - offset /= FRACUNIT; - - if (r_splitscreen > 1) + if ((options & (V_SNAPTORIGHT|V_SNAPTOLEFT|V_SPLITSCREEN)) != 0) { - if (stplyr == &players[displayplayers[1]] || stplyr == &players[displayplayers[3]]) + boolean slidefromright = false; + + const INT32 offsetAmount = (screenwidth * FRACUNIT/2) / length; + fixed_t offset = (screenwidth * FRACUNIT/2) - (timer * offsetAmount); + + offset += FixedMul(offsetAmount, renderdeltatics); + offset /= FRACUNIT; + + if (r_splitscreen > 1) + { + if (stplyr == &players[displayplayers[1]] || stplyr == &players[displayplayers[3]]) + slidefromright = true; + } + + if (options & V_SNAPTORIGHT) slidefromright = true; + else if (options & V_SNAPTOLEFT) + slidefromright = false; + + if (slidefromright == true) + { + offset = -offset; + } + + *x -= offset; } - - if (options & V_SNAPTORIGHT) - slidefromright = true; - else if (options & V_SNAPTOLEFT) - slidefromright = false; - - if (slidefromright == true) + else { - offset = -offset; - } + const INT32 offsetAmount = (screenheight * FRACUNIT/2) / length; + fixed_t offset = (screenheight * FRACUNIT/2) - (timer * offsetAmount); - *x -= offset; + offset += FixedMul(offsetAmount, renderdeltatics); + offset /= FRACUNIT; + + if (options & V_SNAPTOBOTTOM) + { + offset = -offset; + } + + *y -= offset; + } } } } From a8ae2f035ec0d8dd50f06c94c29053d90ca9ee88 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Feb 2023 18:23:10 +0000 Subject: [PATCH 8/8] K_drawKartTimestamp: Draw in splitscreen if gametype has timelimit. - 2p: In 1p position (slides from right) - 3p/4p: In top-middle of screen (slides from top) - Uses time from the display with the highest time, which covers exiting, no contest, etc - Exposes V_ flags in the function signature --- src/k_hud.c | 46 ++++++++++++++++++++++++++++++++++------------ src/k_hud.h | 2 +- src/k_menudraw.c | 4 ++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 5c1bec0a6..668de1d52 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1466,7 +1466,7 @@ static void K_drawKartItem(void) } } -void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode) +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode) { // TIME_X = BASEVIDWIDTH-124; // 196 // TIME_Y = 6; // 6 @@ -1474,11 +1474,8 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode) tic_t worktime; INT32 jitter = 0; - INT32 splitflags = 0; if (!mode) { - splitflags = V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|V_SNAPTORIGHT|V_SPLITSCREEN; - if (timelimitintics > 0) { if (drawtime >= timelimitintics) @@ -4971,17 +4968,15 @@ void K_drawKartHUD(void) boolean battlefullscreen = false; boolean freecam = demo.freecam; //disable some hud elements w/ freecam UINT8 i; + UINT8 viewnum = R_GetViewNumber(); // 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". - for (i = 0; i <= r_splitscreen; i++) - { - if (stplyr == &players[displayplayers[i]] && !camera[i].chase && !freecam) - K_drawKartFirstPerson(); - } + if (!camera[viewnum].chase && !freecam) + K_drawKartFirstPerson(); // Draw full screen stuff that turns off the rest of the HUD if (mapreset && stplyr == &players[displayplayers[0]]) @@ -5032,15 +5027,42 @@ void K_drawKartHUD(void) if (LUA_HudEnabled(hud_item) && !freecam) K_drawKartItem(); - // If not splitscreen, draw... - if (!r_splitscreen && !demo.title) + if (demo.title) + ; + else if (!r_splitscreen) { // Draw the timestamp if (LUA_HudEnabled(hud_time)) - K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, 0); + K_drawKartTimestamp(stplyr->realtime, + TIME_X, + TIME_Y, + V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|V_SNAPTORIGHT, + 0); islonesome = K_drawKartPositionFaces(); } + else if (viewnum == r_splitscreen + && (gametyperules & GTR_TIMELIMIT) + && timelimitintics > 0) + { + tic_t highestrealtime = players[displayplayers[1]].realtime; + + // Uses the highest time across all players (handles paused timer on exiting) + for (i = 1; i <= r_splitscreen; i++) + { + if (players[displayplayers[i]].realtime <= highestrealtime) + continue; + highestrealtime = players[displayplayers[i]].realtime; + } + + // Draw the timestamp (mostly) CENTERED + if (LUA_HudEnabled(hud_time)) + K_drawKartTimestamp(highestrealtime, + (r_splitscreen == 1 ? TIME_X : ((BASEVIDWIDTH/2) - 69)), + TIME_Y, + V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|(r_splitscreen == 1 ? V_SNAPTORIGHT : 0), + 0); + } if (!stplyr->spectator && !demo.freecam) // Bottom of the screen elements, don't need in spectate mode { diff --git a/src/k_hud.h b/src/k_hud.h index 982cc76f5..9b783f710 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -40,7 +40,7 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny); void K_LoadKartHUDGraphics(void); void K_drawKartHUD(void); void K_drawKartFreePlay(void); -void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode); +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode); void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol); void K_DrawMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, UINT16 map, UINT8 *colormap); void K_DrawLikeMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, patch_t *patch, UINT8 *colormap); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 0963909b7..e09bc5873 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2266,7 +2266,7 @@ void M_DrawTimeAttack(void) && (mapheaderinfo[map]->numlaps != 1)) { V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:"); - K_drawKartTimestamp(laprec, 162+t, timeheight+6, 2); + K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2); timeheight += 30; } else @@ -2275,7 +2275,7 @@ void M_DrawTimeAttack(void) } V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:"); - K_drawKartTimestamp(timerec, 162+t, timeheight+6, 1); + K_drawKartTimestamp(timerec, 162+t, timeheight+6, 0, 1); } else opty = 80;