From ce7fe894b81b02bd90c17a3a85d116e317b16f8c Mon Sep 17 00:00:00 2001 From: Ashnal Date: Mon, 29 Aug 2022 16:58:33 -0400 Subject: [PATCH 01/81] Should fix the dedicated server player node takeover that completely destroys servers # Conflicts: # src/d_clisrv.c --- src/d_clisrv.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 417fbade4..aa692c3bc 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3935,6 +3935,11 @@ static void HandleConnect(SINT8 node) // If a server filled out, then it'd overwrite the host and turn everyone into weird husks..... // It's too much effort to legimately fix right now. Just prevent it from reaching that state. UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value); + UINT8 connectedplayers = 0; + + for (UINT8 i = dedicated ? 1 : 0; i < MAXPLAYERS; i++) + if (playernode[i] != UINT8_MAX) // We use this to count players because it is affected by SV_AddWaitingPlayers when more than one client joins on the same tic, unlike playeringame and D_NumPlayers. UINT8_MAX denotes no node for that player + connectedplayers++; if (bannednode && bannednode[node].banid != SIZE_MAX) { @@ -3992,7 +3997,7 @@ static void HandleConnect(SINT8 node) { SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment.")); } - else if (D_NumPlayers() >= maxplayers) + else if (connectedplayers >= maxplayers) { SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), maxplayers)); } @@ -4000,7 +4005,7 @@ static void HandleConnect(SINT8 node) { SV_SendRefuse(node, M_GetText("Too many players from\nthis node.")); } - else if (netgame && D_NumPlayers() + netbuffer->u.clientcfg.localplayers > maxplayers) + else if (netgame && connectedplayers + netbuffer->u.clientcfg.localplayers > maxplayers) { SV_SendRefuse(node, va(M_GetText("Number of local players\nwould exceed maximum: %d"), maxplayers)); } From 8742a55077faee7975881082e196e03ae1448516 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 3 Nov 2022 05:44:33 -0700 Subject: [PATCH 02/81] Add cv_palette and cv_palettenum Cheats; override the current palette --- src/d_netcmd.c | 3 +++ src/p_setup.c | 2 +- src/v_video.c | 54 +++++++++++++++++++++++++++++++++++++------------- src/v_video.h | 3 ++- 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 51d205931..a3213489b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -986,6 +986,9 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_bsaturation); CV_RegisterVar(&cv_msaturation); + CV_RegisterVar(&cv_palette); + CV_RegisterVar(&cv_palettenum); + // k_menu.c //CV_RegisterVar(&cv_compactscoreboard); CV_RegisterVar(&cv_chatheight); diff --git a/src/p_setup.c b/src/p_setup.c index 3de23a0d1..5bbdb53ab 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7350,7 +7350,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Reset the palette now all fades have been done if (rendermode != render_none) - V_SetPaletteLump(GetPalette()); // Set the level palette + V_ReloadPalette(); // Set the level palette if (!(reloadinggamestate || titlemapinaction)) { diff --git a/src/v_video.c b/src/v_video.c index 0e85bf2fa..2636b9a6e 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -86,11 +86,16 @@ static CV_PossibleValue_t constextsize_cons_t[] = { static void CV_constextsize_OnChange(void); consvar_t cv_constextsize = CVAR_INIT ("con_textsize", "Medium", CV_SAVE|CV_CALL, constextsize_cons_t, CV_constextsize_OnChange); +consvar_t cv_palette = CVAR_INIT ("palette", "", CV_CHEAT|CV_CALL|CV_NOINIT, NULL, CV_palette_OnChange); +consvar_t cv_palettenum = CVAR_INIT ("palettenum", "0", CV_CHEAT|CV_CALL|CV_NOINIT, CV_Unsigned, CV_palette_OnChange); + // local copy of the palette for V_GetColor() RGBA_t *pLocalPalette = NULL; RGBA_t *pMasterPalette = NULL; RGBA_t *pGammaCorrectedPalette = NULL; +static size_t currentPaletteSize; + /* The following was an extremely helpful resource when developing my Colour Cube LUT. http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter24.html @@ -311,9 +316,12 @@ UINT32 V_GammaCorrect(UINT32 input, double power) static void LoadPalette(const char *lumpname) { lumpnum_t lumpnum = W_GetNumForName(lumpname); - size_t i, palsize = W_LumpLength(lumpnum)/3; + size_t i, palsize; UINT8 *pal; + currentPaletteSize = W_LumpLength(lumpnum); + palsize = currentPaletteSize / 3; + Cubeapply = InitCube(); if (pLocalPalette != pMasterPalette) @@ -400,8 +408,24 @@ const char *R_GetPalname(UINT16 num) const char *GetPalette(void) { + const char *user = cv_palette.string; + + if (user && user[0]) + { + if (W_CheckNumForName(user) == LUMPERROR) + { + CONS_Alert(CONS_WARNING, + "cv_palette %s lump does not exist\n", user); + } + else + { + return cv_palette.string; + } + } + if (gamestate == GS_LEVEL) return R_GetPalname((encoremode ? mapheaderinfo[gamemap-1]->encorepal : mapheaderinfo[gamemap-1]->palette)); + return "PLAYPAL"; } @@ -419,6 +443,19 @@ void V_SetPalette(INT32 palettenum) if (!pLocalPalette) V_ReloadPalette(); + if (palettenum == 0) + { + palettenum = cv_palettenum.value; + + if (palettenum * 256U > currentPaletteSize - 256) + { + CONS_Alert(CONS_WARNING, + "cv_palettenum %d out of range\n", + palettenum); + palettenum = 0; + } + } + #ifdef HWRENDER if (rendermode == render_opengl) HWR_SetPalette(&pLocalPalette[palettenum*256]); @@ -433,23 +470,12 @@ void V_SetPalette(INT32 palettenum) void V_SetPaletteLump(const char *pal) { LoadPalette(pal); -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_SetPalette(pLocalPalette); -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) - else -#endif -#endif - if (rendermode != render_none) - I_SetPalette(pLocalPalette); -#ifdef HASINVERT - R_MakeInvertmap(); -#endif + V_SetPalette(0); } static void CV_palette_OnChange(void) { - // reload palette + // recalculate Color Cube V_ReloadPalette(); V_SetPalette(0); } diff --git a/src/v_video.h b/src/v_video.h index 35be68b2f..34800e7b4 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -34,7 +34,8 @@ extern consvar_t cv_ticrate, cv_constextsize, cv_globalgamma, cv_globalsaturation, cv_rhue, cv_yhue, cv_ghue, cv_chue, cv_bhue, cv_mhue, cv_rgamma, cv_ygamma, cv_ggamma, cv_cgamma, cv_bgamma, cv_mgamma, -cv_rsaturation, cv_ysaturation, cv_gsaturation, cv_csaturation, cv_bsaturation, cv_msaturation; +cv_rsaturation, cv_ysaturation, cv_gsaturation, cv_csaturation, cv_bsaturation, cv_msaturation, +cv_palette, cv_palettenum; // Allocates buffer screens, call before R_Init. void V_Init(void); From a6e87ae82cdcb23ce604545cd4e3b7f045cb76ad Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 3 Nov 2022 05:46:22 -0700 Subject: [PATCH 03/81] Let toggle command multiple choice mode work on cvars lacking PossibleValue array --- src/command.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/command.c b/src/command.c index a66522186..eb1204108 100644 --- a/src/command.c +++ b/src/command.c @@ -1080,9 +1080,10 @@ static void COM_Toggle_f(void) for (i = 2; i < COM_Argc() - 1; ++i) { const char *str = COM_Argv(i); - INT32 val; + INT32 val = 0; - if (CV_CompleteValue(cvar, &str, &val)) + if (!cvar->PossibleValue || + CV_CompleteValue(cvar, &str, &val)) { if (str ? !stricmp(cvar->string, str) : cvar->value == val) From 7b2918ae634fd74be426dafe028e31a2691d6e76 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 3 Nov 2022 05:51:39 -0700 Subject: [PATCH 04/81] Add grayscale command, toggles GRAYPAL palette override --- src/d_netcmd.c | 1 + src/m_cheat.c | 7 +++++++ src/m_cheat.h | 1 + 3 files changed, 9 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a3213489b..f19c0f2fc 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1092,6 +1092,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("rteleport", Command_RTeleport_f); COM_AddCommand("skynum", Command_Skynum_f); COM_AddCommand("weather", Command_Weather_f); + COM_AddCommand("grayscale", Command_Grayscale_f); #ifdef _DEBUG COM_AddCommand("causecfail", Command_CauseCfail_f); #endif diff --git a/src/m_cheat.c b/src/m_cheat.c index 9614c9b60..be4f231e1 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -762,6 +762,13 @@ void Command_Setlives_f(void) D_Cheat(consoleplayer, CHEAT_LIVES, atoi(COM_Argv(1))); } +void Command_Grayscale_f(void) +{ + REQUIRE_CHEATS; + + COM_ImmedExecute("toggle palette \"\" GRAYPAL"); +} + // // OBJECTPLACE (and related variables) // diff --git a/src/m_cheat.h b/src/m_cheat.h index 4d97cb8d9..c952721c3 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -75,6 +75,7 @@ void Command_Teleport_f(void); void Command_RTeleport_f(void); void Command_Skynum_f(void); void Command_Weather_f(void); +void Command_Grayscale_f(void); #ifdef _DEBUG void Command_CauseCfail_f(void); #endif From 16300bee840c3c6176a2bb9fe6938769df86df53 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sat, 10 Sep 2022 13:29:18 -0400 Subject: [PATCH 05/81] Attempt to fix use after free bug with precipitation mobjs on netgame load # Conflicts: # src/p_saveg.c --- src/p_mobj.c | 28 +++++++++++++++++++++------- src/p_saveg.c | 15 ++++++++++++++- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index bdf0064f0..b5fafd89e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10769,20 +10769,34 @@ void P_RemovePrecipMobj(precipmobj_t *mobj) void P_RemoveSavegameMobj(mobj_t *mobj) { // unlink from sector and block lists - P_UnsetThingPosition(mobj); - - // Remove touching_sectorlist from mobj. - if (sector_list) + if (((thinker_t *)mobj)->function.acp1 == (actionf_p1)P_NullPrecipThinker) { - P_DelSeclist(sector_list); - sector_list = NULL; + P_UnsetPrecipThingPosition((precipmobj_t *)mobj); + + if (precipsector_list) + { + P_DelPrecipSeclist(precipsector_list); + precipsector_list = NULL; + } + } + else + { + // unlink from sector and block lists + P_UnsetThingPosition(mobj); + + // Remove touching_sectorlist from mobj. + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } } // stop any playing sound S_StopSound(mobj); // free block - P_RemoveThinker((thinker_t *)mobj); + P_RemoveThinkerDelayed((thinker_t *)mobj); // Call directly here since we are calling P_InitThinkers R_RemoveMobjInterpolator(mobj); } diff --git a/src/p_saveg.c b/src/p_saveg.c index e35fa823f..6e143962f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3341,6 +3341,19 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight; } + if (mobj->type == MT_SKYBOX) + { + mtag_t = mobj->movedir; + if (tag < 0 || tag > 15) + { + CONS_Debug(DBG_GAMELOGIC, "LoadMobjThinker: Skybox ID %d of netloaded object is not between 0 and 15!\n", tag); + } + else if (mobj->flags2 & MF2_AMBUSH) + skyboxcenterpnts[tag] = mobj; + else + skyboxviewpnts[tag] = mobj; + } + if (diff2 & MD2_WAYPOINTCAP) P_SetTarget(&waypointcap, mobj); @@ -3968,7 +3981,7 @@ static void P_NetUnArchiveThinkers(void) { next = currentthinker->next; - if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) + if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker || currentthinker->function.acp1 == (actionf_p1)P_NullPrecipThinker) P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it else Z_Free(currentthinker); From fb4cf4c3bad9aa59fad2eb812bc8595532aeaeb6 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Thu, 29 Sep 2022 15:43:50 -0400 Subject: [PATCH 06/81] Remove usage of currentthinker from direct removal It's designed to be referenced from P_RunTHinkers, whjich we aren't doing --- src/p_mobj.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index b5fafd89e..ee09ad8e1 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10794,10 +10794,17 @@ void P_RemoveSavegameMobj(mobj_t *mobj) // stop any playing sound S_StopSound(mobj); + R_RemoveMobjInterpolator(mobj); // free block - P_RemoveThinkerDelayed((thinker_t *)mobj); // Call directly here since we are calling P_InitThinkers - R_RemoveMobjInterpolator(mobj); + // Here we use the same code as R_RemoveThinkerDelayed, but without reference counting (we're removing everything so it shouldn't matter) and without touching currentthinker since we aren't in P_RunThinkers + { + thinker_t *thinker = (thinker_t *)mobj; + thinker_t *next = thinker->next; + (next->prev = thinker->prev)->next = next; + R_DestroyLevelInterpolators(thinker); + Z_Free(thinker); + } } static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; From 1e9b844e88a36172d968821ecae0caecc2f0bc48 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Thu, 29 Sep 2022 19:22:53 -0400 Subject: [PATCH 07/81] Unlink non-mobj and non-precip thinkers when loading and freeing Move globalweather to before P_SpawnSpecials so that specials can properly change weather and have it communicated in savegames # Conflicts: # src/p_saveg.c # src/p_setup.c --- src/p_mobj.c | 1 - src/p_saveg.c | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index ee09ad8e1..b6a50f7f6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10802,7 +10802,6 @@ void P_RemoveSavegameMobj(mobj_t *mobj) thinker_t *thinker = (thinker_t *)mobj; thinker_t *next = thinker->next; (next->prev = thinker->prev)->next = next; - R_DestroyLevelInterpolators(thinker); Z_Free(thinker); } } diff --git a/src/p_saveg.c b/src/p_saveg.c index 6e143962f..a03dbe677 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3984,7 +3984,11 @@ static void P_NetUnArchiveThinkers(void) if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker || currentthinker->function.acp1 == (actionf_p1)P_NullPrecipThinker) P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it else + { + (next->prev = currentthinker->prev)->next = next; + R_DestroyLevelInterpolators(currentthinker); Z_Free(currentthinker); + } } } From d7e2c60d73e7aa3d564cc3d270b9c2a5355ed337 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 13:35:51 +0000 Subject: [PATCH 08/81] 1.6 replay hut graphical fixes -- obviously redoing the whole thing later but important to get reasonable foundation to build off --- src/k_menudraw.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 92e47cb2f..ab9ed8b5e 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -3896,6 +3896,17 @@ static void M_DrawReplayHutReplayInfo(menudemo_t *demoref) if (demoref->gametype == GT_RACE) { V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "TIME"); + } + else + { + V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "SCORE"); + } + + if (demoref->standings[0].timeorscore == (UINT32_MAX-1)) + { + V_DrawThinString(x+32, y+39, V_SNAPTOTOP, "NO CONTEST"); + } + else if (demoref->gametype == GT_RACE) V_DrawRightAlignedString(x+84, y+40, V_SNAPTOTOP, va("%d'%02d\"%02d", G_TicsToMinutes(demoref->standings[0].timeorscore, true), G_TicsToSeconds(demoref->standings[0].timeorscore), @@ -3904,7 +3915,6 @@ static void M_DrawReplayHutReplayInfo(menudemo_t *demoref) } else { - V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "SCORE"); V_DrawString(x+32, y+40, V_SNAPTOTOP, va("%d", demoref->standings[0].timeorscore)); } @@ -3913,7 +3923,7 @@ static void M_DrawReplayHutReplayInfo(menudemo_t *demoref) // Lat: 08/06/2020: For some reason missing skins have their value set to 255 (don't even ask me why I didn't write this) // and for an even STRANGER reason this passes the first check below, so we're going to make sure that the skin here ISN'T 255 before we do anything stupid. - if (demoref->standings[0].skin != 0xFF) + if (demoref->standings[0].skin < numskins) { patch = faceprefix[demoref->standings[0].skin][FACE_WANTED]; colormap = R_GetTranslationColormap( @@ -4114,7 +4124,7 @@ void M_DrawReplayStartMenu(void) // Lat: 08/06/2020: For some reason missing skins have their value set to 255 (don't even ask me why I didn't write this) // and for an even STRANGER reason this passes the first check below, so we're going to make sure that the skin here ISN'T 255 before we do anything stupid. - if (demoref->standings[i].skin != 0xFF) + if (demoref->standings[i].skin < numskins) { patch = faceprefix[demoref->standings[i].skin][FACE_RANK]; colormap = R_GetTranslationColormap( From 92db1aa6341690de9c38a483f34e7c923891f349 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 13:49:27 +0000 Subject: [PATCH 09/81] Make all the join/leave sound effects have a `singularity` of `true` so that they don't stack super loud during major net interruption or multiple splitscreen player joins. --- src/sounds.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sounds.c b/src/sounds.c index 5abb9504b..9c77ba9f1 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1089,10 +1089,10 @@ sfxinfo_t S_sfx[NUMSFX] = {"bhurry", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // v1.0.2 Battle overtime {"bsnipe", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Banana sniping {"sploss", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Down to yellow sparks - {"join", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Player joined server - {"leave", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Player left server - {"requst", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Got a Discord join request - {"syfail", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Funny sync failure + {"join", true, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Player joined server + {"leave", true, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Player left server + {"requst", true, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Got a Discord join request + {"syfail", true, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Funny sync failure {"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // :shitsfree: {"dbgsal", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Debug notification {"cock", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Hammer cocks, bang bang From 1b55c73a3c945d19698a74599b4b6052dd4657f5 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 13:52:05 +0000 Subject: [PATCH 10/81] Fix undesired interpolation for regular teleport --- src/p_telept.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_telept.c b/src/p_telept.c index c3e36f3c7..8586a08cf 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -73,8 +73,12 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, // move chasecam at new player location for (i = 0; i <= r_splitscreen; i++) { - if (thing->player == &players[displayplayers[i]] && camera[i].chase) + if (thing->player != &players[displayplayers[i]]) + continue; + if (camera[i].chase) P_ResetCamera(thing->player, &camera[i]); + R_ResetViewInterpolation(i + 1); + break; } // don't run in place after a teleport From e5d1b39e30c8be0acc753a1b50d8c9e701b8a588 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 27 Oct 2022 13:38:13 +0100 Subject: [PATCH 11/81] Add R_RelativeTeleportViewInterpolation Adjusts pview_old for relative teleport to attempt a contigious motion --- src/p_spec.c | 1 + src/r_fps.c | 8 ++++++++ src/r_fps.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index 25d75f3ff..91b958e31 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2387,6 +2387,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) camera[i].y += y; camera[i].z += z; camera[i].subsector = R_PointInSubsector(camera[i].x, camera[i].y); + R_RelativeTeleportViewInterpolation(i, x, y, z, 0); break; } } diff --git a/src/r_fps.c b/src/r_fps.c index 2c01cc571..8f870abf2 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -216,6 +216,14 @@ void R_ResetViewInterpolation(UINT8 p) } } +void R_RelativeTeleportViewInterpolation(UINT8 p, fixed_t xdiff, fixed_t ydiff, fixed_t zdiff, angle_t angdiff) +{ + pview_old[p].x += xdiff; + pview_old[p].y += ydiff; + pview_old[p].z += zdiff; + pview_old[p].angle += angdiff; +} + void R_SetViewContext(enum viewcontext_e _viewcontext) { UINT8 i = 0; diff --git a/src/r_fps.h b/src/r_fps.h index 41fc65af0..c2bc05699 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -126,6 +126,8 @@ void R_InterpolateViewRollAngle(fixed_t frac); void R_UpdateViewInterpolation(void); // Reset the view states (e.g. after level load) so R_InterpolateView doesn't interpolate invalid data void R_ResetViewInterpolation(UINT8 p); +// Update old view for seamless relative teleport +void R_RelativeTeleportViewInterpolation(UINT8 p, fixed_t xdiff, fixed_t ydiff, fixed_t zdiff, angle_t angdiff); // Set the current view context (the viewvars pointed to by newview) void R_SetViewContext(enum viewcontext_e _viewcontext); From 7216b56e2e46574d17d433d6eb28673e71d1afac Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 13:58:57 +0000 Subject: [PATCH 12/81] More consistent netreplay wadfile list writing Fixes crashes for newly-written demos that have files with absurdly long names attached --- src/g_demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index 103a60a41..f7282e263 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2006,7 +2006,7 @@ void G_BeginRecording(void) if (wadfiles[i]->important) { nameonly(( filename = va("%s", wadfiles[i]->filename) )); - WRITESTRINGN(demo_p, filename, 64); + WRITESTRINGL(demo_p, filename, MAX_WADPATH); WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); totalfiles++; From b0af04eeebf0d400b2d73532012b9bfbdb536d57 Mon Sep 17 00:00:00 2001 From: "X.organic" Date: Sat, 20 Aug 2022 21:45:22 +0200 Subject: [PATCH 13/81] Bring the maximum WAD file count up to 255 Per @TehRealSalt's recommendation. # Conflicts: # src/w_wad.h --- src/w_wad.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/w_wad.h b/src/w_wad.h index 361ee4e50..ec3013af7 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -99,9 +99,10 @@ void* vres_GetPatch(virtlump_t *vlump, INT32 tag); // ========================================================================= #define MAX_WADPATH 512 -#define MAX_WADFILES 127 // maximum of wad files used at the same time -// Replay code relies on it being an UINT8 and, just to be safe, in case some wad counter somewhere is a SINT8, you should NOT go above 127 here if you're lazy like me. -// Besides, are there truly 127 wads worth your interrest? +#define MAX_WADFILES 255 // maximum of wad files used at the same time +// Replay code relies on it being an UINT8. There are no SINT8s handling WAD indices, though. +// Can be set all the way up to 255 but not 256, +// because an UINT8 will never be >= 256, probably breaking some conditionals. #define lumpcache_t void * From e027cc2a0681583491aedca4de4e22edfef05496 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 14:23:30 +0000 Subject: [PATCH 14/81] Error checking for running out of freeslots --- src/deh_soc.c | 24 +++++++++++++++++++++--- src/sounds.c | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 70f1305c6..4ae9927f4 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -224,7 +224,10 @@ void readfreeslots(MYFILE *f) // TODO: Out-of-slots warnings/errors. // TODO: Name too long (truncated) warnings. if (fastcmp(type, "SFX")) + { + CONS_Printf("Sound sfx_%s allocated.\n",word); S_AddSoundFx(word, false, 0, false); + } else if (fastcmp(type, "SPR")) { for (i = SPR_FIRSTFREESLOT; i <= SPR_LASTFREESLOT; i++) @@ -238,39 +241,54 @@ void readfreeslots(MYFILE *f) // Found a free slot! strncpy(sprnames[i],word,4); //sprnames[i][4] = 0; + CONS_Printf("Sprite SPR_%s allocated.\n",word); used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now. break; } + if (i > SPR_LASTFREESLOT) + I_Error("Out of Sprite Freeslots while allocating \"%s\"\nLoad less addons to fix this.", word); + } else if (fastcmp(type, "S")) { for (i = 0; i < NUMSTATEFREESLOTS; i++) if (!FREE_STATES[i]) { + CONS_Printf("State S_%s allocated.\n",word); FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_STATES[i],word); freeslotusage[0][0]++; break; } + if (i == NUMSTATEFREESLOTS) + I_Error("Out of State Freeslots while allocating \"%s\"\nLoad less addons to fix this.", word); + } else if (fastcmp(type, "MT")) { for (i = 0; i < NUMMOBJFREESLOTS; i++) if (!FREE_MOBJS[i]) { + CONS_Printf("MobjType MT_%s allocated.\n",word); FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_MOBJS[i],word); freeslotusage[1][0]++; break; } + if (i == NUMMOBJFREESLOTS) + I_Error("Out of Mobj Freeslots while allocating \"%s\"\nLoad less addons to fix this.", word); + } else if (fastcmp(type, "SKINCOLOR")) { for (i = 0; i < NUMCOLORFREESLOTS; i++) if (!FREE_SKINCOLORS[i]) { + CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word); FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_SKINCOLORS[i],word); M_AddMenuColor(numskincolors++); break; } + if (i == NUMCOLORFREESLOTS) + I_Error("Out of Skincolor Freeslots while allocating \"%s\"\nLoad less addons to fix this.", word); } else if (fastcmp(type, "SPR2")) { @@ -287,7 +305,7 @@ void readfreeslots(MYFILE *f) spr2defaults[free_spr2] = 0; spr2names[free_spr2++][4] = 0; } else - deh_warning("Ran out of free SPR2 slots!\n"); + I_Error("Out of SPR2 Freeslots while allocating \"%s\"\nLoad less addons to fix this.", word); } else if (fastcmp(type, "TOL")) { @@ -302,7 +320,7 @@ void readfreeslots(MYFILE *f) // We don't, so freeslot it. if (lastcustomtol == (UINT32)MAXTOL) // Unless you have way too many, since they're flags. - deh_warning("Ran out of free typeoflevel slots!\n"); + I_Error("Out of Typeoflevel Freeslots while allocating \"%s\"\nLoad less addons to fix this.", word); else { G_AddTOL(lastcustomtol, word); @@ -326,7 +344,7 @@ void readfreeslots(MYFILE *f) precipprops[i].name = Z_StrDup(word); precip_freeslot++; } else - deh_warning("Ran out of free PRECIP slots!\n"); + I_Error("Out of Precipitation Freeslots while allocating \"%s\"\nLoad less addons to fix this.", word); } else deh_warning("Freeslots: unknown enum class '%s' for '%s_%s'", type, type, word); diff --git a/src/sounds.c b/src/sounds.c index 9c77ba9f1..e10adc82c 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1353,7 +1353,7 @@ sfxenum_t S_AddSoundFx(const char *name, boolean singular, INT32 flags, boolean return i; } - CONS_Alert(CONS_WARNING, M_GetText("No more free sound slots\n")); + I_Error("Out of Sound Freeslots while allocating \"%s\"\nLoad less addons to fix this.", name); return 0; } From c5a3d362a12801e94d7362715d457fa16d0c4e64 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 14:28:19 +0000 Subject: [PATCH 15/81] Shadowed declaration fix for d_clisrv anti-bodysnatch fix --- 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 aa692c3bc..84fcb5d4b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3937,7 +3937,7 @@ static void HandleConnect(SINT8 node) UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value); UINT8 connectedplayers = 0; - for (UINT8 i = dedicated ? 1 : 0; i < MAXPLAYERS; i++) + for (i = dedicated ? 1 : 0; i < MAXPLAYERS; i++) if (playernode[i] != UINT8_MAX) // We use this to count players because it is affected by SV_AddWaitingPlayers when more than one client joins on the same tic, unlike playeringame and D_NumPlayers. UINT8_MAX denotes no node for that player connectedplayers++; From e7c700a64ff85f60b3d7d9f9820a9422855e710f Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 14:32:40 +0000 Subject: [PATCH 16/81] Compilation errors from corrupted cherry-pick/porting --- src/k_menudraw.c | 1 + src/p_saveg.c | 2 +- src/p_telept.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index ab9ed8b5e..a66680b5d 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -3907,6 +3907,7 @@ static void M_DrawReplayHutReplayInfo(menudemo_t *demoref) V_DrawThinString(x+32, y+39, V_SNAPTOTOP, "NO CONTEST"); } else if (demoref->gametype == GT_RACE) + { V_DrawRightAlignedString(x+84, y+40, V_SNAPTOTOP, va("%d'%02d\"%02d", G_TicsToMinutes(demoref->standings[0].timeorscore, true), G_TicsToSeconds(demoref->standings[0].timeorscore), diff --git a/src/p_saveg.c b/src/p_saveg.c index a03dbe677..c9ede8b78 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3343,7 +3343,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) if (mobj->type == MT_SKYBOX) { - mtag_t = mobj->movedir; + mtag_t tag = mobj->movedir; if (tag < 0 || tag > 15) { CONS_Debug(DBG_GAMELOGIC, "LoadMobjThinker: Skybox ID %d of netloaded object is not between 0 and 15!\n", tag); diff --git a/src/p_telept.c b/src/p_telept.c index 8586a08cf..9d3f792a3 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -17,6 +17,7 @@ #include "r_state.h" #include "s_sound.h" #include "r_main.h" +#include "r_fps.h" /** \brief The P_MixUp function From 0230b57aa8971c8e5448d3065348ac5cd24267b5 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 14:45:36 +0000 Subject: [PATCH 17/81] Remove advancedemo Just a weird, meaningless footgun waiting in the wings for someone to catch themselves on --- src/d_clisrv.c | 8 -------- src/d_main.c | 11 ----------- src/d_main.h | 3 --- src/g_demo.c | 12 +++++++++--- 4 files changed, 9 insertions(+), 25 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 84fcb5d4b..e6e6987e3 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5488,14 +5488,6 @@ boolean TryRunTics(tic_t realtics) if (ticking) { - if (advancedemo) - { - if (timedemo_quit) - COM_ImmedExecute("quit"); - else - D_StartTitle(); - } - else { // run the count * tics while (neededtic > gametic) diff --git a/src/d_main.c b/src/d_main.c index 7f1a40ca6..330290fe2 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -131,7 +131,6 @@ INT32 postimgparam[MAXSPLITSCREENPLAYERS]; boolean sound_disabled = false; boolean digital_disabled = false; -boolean advancedemo; #ifdef DEBUGFILE INT32 debugload = 0; #endif @@ -913,15 +912,6 @@ void D_SRB2Loop(void) } } -// -// D_AdvanceDemo -// Called after each demo or intro demosequence finishes -// -void D_AdvanceDemo(void) -{ - advancedemo = true; -} - // ========================================================================= // D_SRB2Main // ========================================================================= @@ -997,7 +987,6 @@ void D_StartTitle(void) //demosequence = -1; G_SetGametype(GT_RACE); // SRB2kart paused = false; - advancedemo = false; F_StartTitleScreen(); // Reset the palette diff --git a/src/d_main.h b/src/d_main.h index f01f9227f..c8e803521 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -18,8 +18,6 @@ #include "d_event.h" #include "w_wad.h" // for MAX_WADFILES -extern boolean advancedemo; - // make sure not to write back the config until it's been correctly loaded extern tic_t rendergametic; @@ -52,7 +50,6 @@ const char *D_Home(void); // // BASE LEVEL // -void D_AdvanceDemo(void); void D_StartTitle(void); #endif //__D_MAIN__ diff --git a/src/g_demo.c b/src/g_demo.c index f7282e263..0fbd920c6 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3727,7 +3727,11 @@ static void G_StopTimingDemo(void) if (restorecv_vidwait != cv_vidwait.value) CV_SetValue(&cv_vidwait, restorecv_vidwait); - D_AdvanceDemo(); + + if (timedemo_quit) + COM_ImmedExecute("quit"); + else + D_StartTitle(); } // reset engine variable set for the demos @@ -3786,10 +3790,12 @@ boolean G_CheckDemoStatus(void) { G_StopDemo(); - if (modeattacking) + if (timedemo_quit) + COM_ImmedExecute("quit"); + else if (modeattacking) M_EndModeAttackRun(); else - D_AdvanceDemo(); + D_StartTitle(); } return true; From ea0bf216c59e7b18740ff9851f29d5f7784a7e4c Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 14:50:29 +0000 Subject: [PATCH 18/81] Newview hack crash fixes - Renderer should exist - Player mo should exist --- src/p_tick.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/p_tick.c b/src/p_tick.c index a7f53b003..f2aab3aef 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -787,15 +787,20 @@ void P_Ticker(boolean run) // Hack: ensure newview is assigned every tic. // Ensures view interpolation is T-1 to T in poor network conditions // We need a better way to assign view state decoupled from game logic - for (i = 0; i <= r_splitscreen; i++) + if (rendermode != render_none) { - player_t *player = &players[displayplayers[i]]; - const boolean skybox = (player->skybox.viewpoint && cv_skybox.value); // True if there's a skybox object and skyboxes are on - if (skybox) + for (i = 0; i <= r_splitscreen; i++) { - R_SkyboxFrame(i); + player_t *player = &players[displayplayers[i]]; + if (!player->mo) + continue; + const boolean skybox = (player->skybox.viewpoint && cv_skybox.value); // True if there's a skybox object and skyboxes are on + if (skybox) + { + R_SkyboxFrame(i); + } + R_SetupFrame(i); } - R_SetupFrame(i); } } From ed10cd102f2473dffc423a0dd48d774e1f1b52c4 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 3 Nov 2022 14:57:27 +0000 Subject: [PATCH 19/81] Missing header reference --- src/p_tick.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_tick.c b/src/p_tick.c index f2aab3aef..7cf1748b5 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -24,6 +24,7 @@ #include "lua_hook.h" #include "m_perfstats.h" #include "i_system.h" // I_GetPreciseTime +#include "i_video.h" // rendermode #include "r_main.h" #include "r_fps.h" From 8dbac697cad072b0d62a60068a737ec055dd2b95 Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 3 Nov 2022 22:07:09 -0400 Subject: [PATCH 20/81] Add backdrop for paper items Capsules are unaffected as it has it's own object that shares the sprite of the items. --- src/deh_tables.c | 1 + src/info.c | 2 ++ src/info.h | 2 ++ src/k_kart.c | 7 ++++++- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 2f68edf2c..383823833 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3271,6 +3271,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_ITEM_DEBRIS_CLOUD_SPAWNER2", "S_ITEMICON", + "S_ITEMBACKDROP", // Item capsules "S_ITEMCAPSULE", diff --git a/src/info.c b/src/info.c index b1f4bc1be..266787230 100644 --- a/src/info.c +++ b/src/info.c @@ -531,6 +531,7 @@ char sprnames[NUMSPRITES + 1][5] = "SBOX", // Sphere Box (for Battle) "RPOP", // Random Item Box Pop "ITRI", // Item Box Debris + "ITPA", // Paper item backdrop "SGNS", // Signpost sparkle "FAST", // Speed boost trail "DSHR", // Speed boost dust release @@ -3879,6 +3880,7 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 7, {A_SpawnItemDebrisCloud}, 20, 0, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER2 {SPR_NULL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMICON + {SPR_ITPA, FF_FULLBRIGHT, -1, {NULL}, 1, 0, S_NULL}, // S_ITEMBACKDROP {SPR_ICAP, FF_ADD|0, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE {SPR_ICAP, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_TOP_SIDE diff --git a/src/info.h b/src/info.h index 176705a41..408d85832 100644 --- a/src/info.h +++ b/src/info.h @@ -1077,6 +1077,7 @@ typedef enum sprite SPR_SBOX, // Sphere Box (for Battle) SPR_RPOP, // Random Item Box Pop SPR_ITRI, // Item Box Debris + SPR_ITPA, // Paper item backdrop SPR_SGNS, // Signpost sparkle SPR_FAST, // Speed boost trail SPR_DSHR, // Speed boost dust release @@ -4282,6 +4283,7 @@ typedef enum state S_ITEM_DEBRIS_CLOUD_SPAWNER2, S_ITEMICON, + S_ITEMBACKDROP, // Item capsules S_ITEMCAPSULE, diff --git a/src/k_kart.c b/src/k_kart.c index dff8c406a..d41851144 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6924,9 +6924,14 @@ void K_DropHnextList(player_t *player, boolean keepshields) mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount) { mobj_t *drop = P_SpawnMobj(x, y, z, MT_FLOATINGITEM); + mobj_t *backdrop = P_SpawnMobjFromMobj(drop, 0, 0, 0, MT_OVERLAY); + + P_SetTarget(&backdrop->target, drop); + P_SetMobjState(backdrop, S_ITEMBACKDROP); + P_SetScale(drop, drop->scale>>4); drop->destscale = (3*drop->destscale)/2; - + drop->angle = angle; P_Thrust(drop, FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle, From 701b345f3981d957596d89c0267e4c4d198eb4cf Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 3 Nov 2022 23:11:51 -0400 Subject: [PATCH 21/81] Fix sprite clipping in OpenGL --- src/k_kart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index d41851144..583639b9c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7007,6 +7007,9 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 } drop->flags |= MF_NOCLIPTHING; + backdrop->dispoffset = 1; + P_SetTarget(&backdrop->tracer, drop); + backdrop->flags2 |= MF2_LINKDRAW; return drop; } From 8f628ccd7d66ca871844d29b8ca655c670bab02a Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 22:01:11 -0700 Subject: [PATCH 22/81] Fix invinc, scale difference, and hyu not blocking explosions --- src/p_inter.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index da54636fb..8f439ff89 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1997,9 +1997,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Check if the player is allowed to be damaged! // If not, then spawn the instashield effect instead. - // NB: "allowcombo", "hardhit" and related checks are here to disallow HITLAG COMBOS, not loss-of-control combos - // DMG_EXPLODE bypasses this check to prevent blocking eggbox/SPB with spinout flashtics - if (!force && (type != DMG_EXPLODE)) + if (!force) { if (gametyperules & GTR_BUMPERS) { @@ -2039,7 +2037,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da allowcombo = false; } - if ((target->hitlag == 0 || allowcombo == false) && player->flashing > 0) + // DMG_EXPLODE excluded from flashtic checks to prevent dodging eggbox/SPB with weak spinout + if ((target->hitlag == 0 || allowcombo == false) && player->flashing > 0 && type != DMG_EXPLODE) { // Post-hit invincibility K_DoInstashield(player); From 84a5e28302529de30be4fc242f0dc7135280f28e Mon Sep 17 00:00:00 2001 From: SteelT Date: Fri, 4 Nov 2022 11:19:27 -0400 Subject: [PATCH 23/81] Don't match slope pitch and roll for MT_FLOATINGITEM (per VC discussion) --- src/p_mobj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index bdf0064f0..76c1de31a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6786,6 +6786,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) break; case MT_FLOATINGITEM: { + mobj->pitch = mobj->roll = 0; if (mobj->flags & MF_NOCLIPTHING) { if (P_CheckDeathPitCollide(mobj)) From c4fd7d74dd56e2e03b17a992b35ddd3e7ba8cdda Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 4 Nov 2022 16:11:50 +0000 Subject: [PATCH 24/81] P_AddWadFile partial stages port from SRB2Kart 1.6 Originally written by x.organic, flattened rewrite due to massive changes between RR and SRB2Kart codebase Notable changes: - p_adding_file has been reworked into partadd_earliestfile to allow for final setup to use - much like the public version required removing TEXTURE SOCs, this one required removing Flats support from ANIMDEFS --- src/d_clisrv.c | 16 ++++- src/d_main.c | 8 +-- src/d_netfil.c | 2 +- src/hu_stuff.c | 18 +++-- src/p_setup.c | 176 +++++++++++++++++++++++++++++++++++-------------- src/p_setup.h | 22 ++++++- src/p_spec.c | 63 ++++-------------- 7 files changed, 190 insertions(+), 115 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1387c80e4..f35428c95 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -533,6 +533,7 @@ typedef enum CL_DOWNLOADFILES, CL_ASKJOIN, CL_LOADFILES, + CL_SETUPFILES, CL_WAITJOINRESPONSE, CL_DOWNLOADSAVEGAME, CL_CONNECTED, @@ -617,6 +618,9 @@ static inline void CL_DrawConnectionStatus(void) case CL_CONFIRMCONNECT: cltext = ""; break; + case CL_SETUPFILES: + cltext = M_GetText("Configuring addons..."); + break; case CL_ASKJOIN: case CL_WAITJOINRESPONSE: if (serverisfull) @@ -1851,7 +1855,12 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic cl_mode = CL_LOADFILES; break; case CL_LOADFILES: - if (CL_LoadServerFiles()) + if (CL_LoadServerFiles()) + cl_mode = CL_SETUPFILES; + + break; + case CL_SETUPFILES: + if (P_PartialAddGetStage() < 0 || P_MultiSetupWadFiles(false)) { *asksent = 0; //This ensure the first join ask is right away firstconnectattempttime = I_GetTime(); @@ -2079,7 +2088,12 @@ static void CL_ConnectToServer(void) { // If the connection was aborted for some reason, leave if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent)) + { + if (P_PartialAddGetStage() >= 0) + P_MultiSetupWadFiles(true); // in case any partial adds were done + return; + } if (server) { diff --git a/src/d_main.c b/src/d_main.c index 7fb82482e..947350a08 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1203,8 +1203,6 @@ void D_SRB2Main(void) { INT32 i, p; - INT32 numbasemapheaders; - INT32 pstartmap = 1; boolean autostart = false; @@ -1461,9 +1459,7 @@ void D_SRB2Main(void) // // search for mainwad maps // - P_InitMapData(0); - - numbasemapheaders = nummapheaders; + P_InitMapData(false); CON_SetLoadingProgress(LOADED_IWAD); @@ -1474,7 +1470,7 @@ void D_SRB2Main(void) // // search for pwad maps // - P_InitMapData(numbasemapheaders); + P_InitMapData(true); CON_SetLoadingProgress(LOADED_PWAD); diff --git a/src/d_netfil.c b/src/d_netfil.c index 3de3a0030..ffd2c546b 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -552,7 +552,7 @@ boolean CL_LoadServerFiles(void) continue; // Already loaded else if (fileneeded[i].status == FS_FOUND) { - P_AddWadFile(fileneeded[i].filename); + P_PartialAddWadFile(fileneeded[i].filename); G_SetGameModified(true, false); fileneeded[i].status = FS_OPEN; return false; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 63d093ae1..d33a88daf 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -326,22 +326,30 @@ patch_t *HU_UpdateOrBlankPatch(patch_t **user, boolean required, const char *for va_list ap; char buffer[9]; - lumpnum_t lump; + lumpnum_t lump = INT16_MAX; patch_t *patch; va_start (ap, format); vsnprintf(buffer, sizeof buffer, format, ap); va_end (ap); - if (user && p_adding_file != INT16_MAX) + if (user && partadd_earliestfile != UINT16_MAX) { - lump = W_CheckNumForNamePwad(buffer, p_adding_file, 0); + UINT16 fileref = numwadfiles; + lump = INT16_MAX; + + while ((lump == INT16_MAX) && ((--fileref) >= partadd_earliestfile)) + { + lump = W_CheckNumForNamePwad(buffer, fileref, 0); + } /* no update in this wad */ - if (lump == INT16_MAX) + if (fileref < partadd_earliestfile) return *user; - lump |= (p_adding_file << 16); + CONS_Printf("pe = %d, fr = %d\n", partadd_earliestfile, fileref); + + lump |= (fileref << 16); } else { diff --git a/src/p_setup.c b/src/p_setup.c index 3de23a0d1..b08e75f01 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -170,6 +170,13 @@ mapthing_t *playerstarts[MAXPLAYERS]; mapthing_t *bluectfstarts[MAXPLAYERS]; mapthing_t *redctfstarts[MAXPLAYERS]; +// Global state for PartialAddWadFile/MultiSetupWadFiles +// Might be replacable with parameters, but non-trivial when the functions are called on separate tics +static SINT8 partadd_stage = -1; +static boolean partadd_important = false; +UINT16 partadd_earliestfile = UINT16_MAX; + + // Maintain *ZOOM TUBE* waypoints // Renamed because SRB2Kart owns real waypoints. mobj_t *tubewaypoints[NUMTUBEWAYPOINTSEQUENCES][TUBEWAYPOINTSEQUENCESIZE]; @@ -7745,7 +7752,7 @@ lumpnum_t wadnamelump = LUMPERROR; INT16 wadnamemap = 0; // gamemap based // Initialising map data (and catching replacements)... -UINT8 P_InitMapData(INT32 numexistingmapheaders) +UINT8 P_InitMapData(boolean existingmapheaders) { UINT8 ret = 0; INT32 i; @@ -7763,7 +7770,7 @@ UINT8 P_InitMapData(INT32 numexistingmapheaders) if (maplump == INT16_MAX) { #ifndef DEVELOP - if (!numexistingmapheaders) + if (!existingmapheaders) { I_Error("P_InitMapData: Base map %s has a header but no level\n", name); } @@ -7816,7 +7823,7 @@ UINT8 P_InitMapData(INT32 numexistingmapheaders) ret |= MAPRET_ADDED; CONS_Printf("%s\n", name); - if (numexistingmapheaders && mapheaderinfo[i]->lumpnum != LUMPERROR) + if (existingmapheaders && mapheaderinfo[i]->lumpnum != LUMPERROR) { G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you @@ -7866,23 +7873,32 @@ UINT8 P_InitMapData(INT32 numexistingmapheaders) return ret; } -UINT16 p_adding_file = INT16_MAX; - // // Add a wadfile to the active wad files, // replace sounds, musics, patches, textures, sprites and maps // boolean P_AddWadFile(const char *wadfilename) +{ + UINT16 wadnum; + + if ((wadnum = P_PartialAddWadFile(wadfilename)) == UINT16_MAX) + return false; + + P_MultiSetupWadFiles(true); + return true; +} + +// +// Add a WAD file and do the per-WAD setup stages. +// Call P_MultiSetupWadFiles as soon as possible after any number of these. +// +UINT16 P_PartialAddWadFile(const char *wadfilename) { size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0; - INT32 numexistingmapheaders = nummapheaders; UINT16 numlumps, wadnum; char *name; lumpinfo_t *lumpinfo; - //boolean texturechange = false; ///\todo Useless; broken when back-frontporting PK3 changes? - UINT8 mapsadded = 0; - // Vars to help us with the position start and amount of each resource type. // Useful for PK3s since they use folders. // WADs use markers for some resources, but others such as sounds are checked lump-by-lump anyway. @@ -7902,10 +7918,19 @@ boolean P_AddWadFile(const char *wadfilename) refreshdirmenu |= REFRESHDIR_NOTLOADED; return false; } - else - wadnum = (UINT16)(numwadfiles-1); - p_adding_file = wadnum; + wadnum = (UINT16)(numwadfiles-1); + + // Init partadd. + if (wadfiles[wadnum]->important) + { + partadd_important = true; + } + if (partadd_stage != 0) + { + partadd_earliestfile = wadnum; + } + partadd_stage = 0; switch(wadfiles[wadnum]->type) { @@ -7939,8 +7964,6 @@ boolean P_AddWadFile(const char *wadfilename) // R_LoadSpritsRange(wadnum, sprPos, sprNum); // if (texNum) // Textures. TODO: R_LoadTextures() does the folder positioning once again. New function maybe? // R_LoadTextures(); -// if (mapNum) // Maps. TODO: Actually implement the map WAD loading code, lulz. -// P_LoadWadMapRange(wadnum, mapPos, mapNum); break; default: lumpinfo = wadfiles[wadnum]->lumpinfo; @@ -8005,23 +8028,14 @@ boolean P_AddWadFile(const char *wadfilename) // TEXTURES/etc. list. R_LoadTexturesPwad(wadnum); // numtexture changes - // Reload ANIMDEFS - P_InitPicAnims(); - // Reload BRIGHT K_InitBrightmapsPwad(wadnum); - // Flush and reload HUD graphics - //ST_UnloadGraphics(); - HU_LoadGraphics(); - ST_LoadGraphics(); - // // look for skins // R_AddSkins(wadnum); // faB: wadfile index in wadfiles[] R_PatchSkins(wadnum); // toast: PATCH PATCH - ST_ReloadSkinFaceGraphics(); // // edit music defs @@ -8029,37 +8043,99 @@ boolean P_AddWadFile(const char *wadfilename) S_LoadMusicDefs(wadnum); // - // search for maps + // extra sprite/skin data // - mapsadded = P_InitMapData(numexistingmapheaders); - - if (!mapsadded) - CONS_Printf(M_GetText("No maps added\n")); - R_LoadSpriteInfoLumps(wadnum, numlumps); -#ifdef HWRENDER - HWR_ReloadModels(); -#endif + // For anything that has to be done over every wadfile at once, see P_MultiSetupWadFiles. - // reload status bar (warning should have valid player!) - if (gamestate == GS_LEVEL) - ST_Start(); - - // Prevent savefile cheating - if (cursaveslot > 0) - cursaveslot = 0; - - if ((mapsadded & MAPRET_CURRENTREPLACED) && gamestate == GS_LEVEL && (netgame || multiplayer)) - { - CONS_Printf(M_GetText("Current map %d replaced by added file, ending the level to ensure consistency.\n"), gamemap); - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); - } - - refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_GAMEDATA to disappear the next frame, but it's a bit too dangerous for that... - - p_adding_file = INT16_MAX; + refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_ flags to disappear the next frame, but this one's a bit too dangerous for that... return true; } + +// Only exists to make sure there's no way to overwrite partadd_stage externally +// unless you really push yourself. +SINT8 P_PartialAddGetStage(void) +{ + return partadd_stage; +} + +// +// Set up a series of partially added WAD files. +// Setup functions that iterate over every loaded WAD go here. +// If fullsetup false, only do one stage per call. +// +boolean P_MultiSetupWadFiles(boolean fullsetup) +{ + if (partadd_stage < 0) + I_Error(M_GetText("P_MultiSetupWadFiles: Post-load addon setup attempted without loading any addons first")); + + if (partadd_stage == 0) + { + // Flush and reload HUD graphics + //ST_UnloadGraphics(); + HU_LoadGraphics(); + ST_LoadGraphics(); + ST_ReloadSkinFaceGraphics(); + + if (!partadd_important) + partadd_stage = -1; // everything done + else if (fullsetup) + partadd_stage++; + } + + if (partadd_stage == 1) + { + // Prevent savefile cheating + if (cursaveslot >= 0) + cursaveslot = 0; + + // Reload ANIMATED / ANIMDEFS + P_InitPicAnims(); + + // reload status bar (warning should have valid player!) + if (gamestate == GS_LEVEL) + ST_Start(); + +#ifdef HWRENDER + HWR_ReloadModels(); +#endif + + if (fullsetup) + partadd_stage++; + } + + if (partadd_stage == 2) + { + UINT8 mapsadded = P_InitMapData(true); + + if (!mapsadded) + CONS_Printf(M_GetText("No maps added\n")); + + if ((mapsadded & MAPRET_CURRENTREPLACED) + && (gamestate == GS_LEVEL) + && (netgame || multiplayer)) + { + CONS_Printf(M_GetText("Current map %d replaced by added file, ending the level to ensure consistency.\n"), gamemap); + if (server) + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + } + + //if (fullsetup) + //partadd_stage++; + partadd_stage = -1; + } + + I_Assert(!fullsetup || partadd_stage < 0); + + if (partadd_stage < 0) + { + partadd_important = false; + partadd_earliestfile = UINT16_MAX; + return true; + } + + partadd_stage++; + return false; +} diff --git a/src/p_setup.h b/src/p_setup.h index d5d3aa7d0..04a3233e0 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -96,8 +96,6 @@ INT32 P_CheckLevelFlat(const char *flatname); extern size_t nummapthings; extern mapthing_t *mapthings; -extern UINT16 p_adding_file; - void P_SetupLevelSky(const char *skytexname, boolean global); void P_RespawnThings(void); boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); @@ -108,11 +106,29 @@ boolean P_AddWadFile(const char *wadfilename); #define MAPRET_ADDED (1) #define MAPRET_CURRENTREPLACED (1<<1) -UINT8 P_InitMapData(INT32 numexistingmapheaders); +UINT8 P_InitMapData(boolean existingmapheaders); extern lumpnum_t wadnamelump; extern INT16 wadnamemap; #define WADNAMECHECK(name) (!strncmp(name, "WADNAME", 7)) +// WARNING: The following functions should be grouped as follows: +// any amount of PartialAdds followed by MultiSetups until returned true, +// as soon as possible. +UINT16 P_PartialAddWadFile(const char *wadfilename); +// Run a single stage of multisetup, or all of them if fullsetup set. +// fullsetup true: run everything +// otherwise multiple stages +// returns true if setup finished on this call, false otherwise (always true on fullsetup) +// throws I_Error if called without any partial adds started as a safeguard +boolean P_MultiSetupWadFiles(boolean fullsetup); +// Get the current setup stage. +// if negative, no PartialAdds done since last MultiSetup +// if 0, partial adds done but MultiSetup not called yet +// if positive, setup's partway done +SINT8 P_PartialAddGetStage(void); +extern UINT16 partadd_earliestfile; + + boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); diff --git a/src/p_spec.c b/src/p_spec.c index 91b958e31..31af5b0e6 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -148,7 +148,7 @@ static void GrowAnimDefs(void) // A prototype; here instead of p_spec.h, so they're "private" void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum); -void P_ParseAnimationDefintion(SINT8 istexture); +void P_ParseAnimationDefintion(void); /** Sets up texture and flat animations. * @@ -161,8 +161,6 @@ void P_ParseAnimationDefintion(SINT8 istexture); * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs), JTE (had to rewrite it to handle multiple WADs _correctly_) */ -static boolean animdeftempflats = false; // only until ANIMDEFS flats are removed - void P_InitPicAnims(void) { // Init animation @@ -182,7 +180,6 @@ void P_InitPicAnims(void) while (animdefsLumpNum != INT16_MAX) { - animdeftempflats = ((p_adding_file == INT16_MAX) || p_adding_file == w); P_ParseANIMDEFSLump(w, animdefsLumpNum); animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", (UINT16)w, animdefsLumpNum + 1); } @@ -204,31 +201,14 @@ void P_InitPicAnims(void) lastanim = anims; for (i = 0; animdefs[i].istexture != -1; i++) { - if (animdefs[i].istexture == 1) - { - if (R_CheckTextureNumForName(animdefs[i].startname) == -1) - continue; - - lastanim->picnum = R_TextureNumForName(animdefs[i].endname); - lastanim->basepic = R_TextureNumForName(animdefs[i].startname); - } - else - { - if (animdefs[i].istexture == 2) - { - CONS_Alert(CONS_WARNING, "ANIMDEFS flats are disabled; flat support in general will be removed soon! (%s, %s)\n", animdefs[i].startname, animdefs[i].endname); - } + if (animdefs[i].istexture != 1) continue; - } -#if 0 - { - if ((W_CheckNumForName(animdefs[i].startname)) == LUMPERROR) - continue; - lastanim->picnum = R_GetFlatNumForName(animdefs[i].endname); - lastanim->basepic = R_GetFlatNumForName(animdefs[i].startname); - } -#endif + if (R_CheckTextureNumForName(animdefs[i].startname) == -1) + continue; + + lastanim->picnum = R_TextureNumForName(animdefs[i].endname); + lastanim->basepic = R_TextureNumForName(animdefs[i].startname); lastanim->istexture = animdefs[i].istexture; lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; @@ -285,21 +265,20 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum) if (stricmp(animdefsToken, "TEXTURE") == 0) { Z_Free(animdefsToken); - P_ParseAnimationDefintion(1); + P_ParseAnimationDefintion(); } else if (stricmp(animdefsToken, "FLAT") == 0) { - Z_Free(animdefsToken); - P_ParseAnimationDefintion(0); + I_Error("Error parsing ANIMDEFS lump: FLats are no longer supported by Ring Racers"); } else if (stricmp(animdefsToken, "OSCILLATE") == 0) { // This probably came off the tail of an earlier definition. It's technically legal syntax, but we don't support it. - I_Error("Error parsing ANIMDEFS lump: Animation definitions utilizing \"OSCILLATE\" (the animation plays in reverse when it reaches the end) are not supported by SRB2"); + I_Error("Error parsing ANIMDEFS lump: Animation definitions utilizing \"OSCILLATE\" (the animation plays in reverse when it reaches the end) are not supported by Ring Racers"); } else { - I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken); + I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\", got \"%s\"",animdefsToken); } // parse next line while (*p != '\0' && *p != '\n') ++p; @@ -310,7 +289,7 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum) Z_Free((void *)animdefsText); } -void P_ParseAnimationDefintion(SINT8 istexture) +void P_ParseAnimationDefintion(void) { char *animdefsToken; size_t animdefsTokenLength; @@ -353,8 +332,7 @@ void P_ParseAnimationDefintion(SINT8 istexture) // Search for existing animdef for (i = 0; i < maxanims; i++) - if (animdefs[i].istexture == istexture // Check if it's the same type! - && stricmp(animdefsToken, animdefs[i].startname) == 0) + if (stricmp(animdefsToken, animdefs[i].startname) == 0) { //CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken); @@ -376,10 +354,7 @@ void P_ParseAnimationDefintion(SINT8 istexture) Z_Free(animdefsToken); // set texture type - if (istexture) - animdefs[i].istexture = 1; - else - animdefs[i].istexture = (animdeftempflats ? 2 : 0); + animdefs[i].istexture = 1; // "RANGE" animdefsToken = M_GetToken(NULL); @@ -457,16 +432,6 @@ void P_ParseAnimationDefintion(SINT8 istexture) } animdefs[i].speed = animSpeed; Z_Free(animdefsToken); - -#ifdef WALLFLATS - // hehe... uhh..... - if (!istexture) - { - GrowAnimDefs(); - M_Memcpy(&animdefs[maxanims-1], &animdefs[i], sizeof(animdef_t)); - animdefs[maxanims-1].istexture = 1; - } -#endif } /** Checks for flats in levelflats that are part of a flat animation sequence From bac58847fec9ea9876c35a65e9008a42a0566ddc Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 4 Nov 2022 16:50:37 +0000 Subject: [PATCH 25/81] Make P_InitMapData/dependents use partadd_earliestfile --- src/p_setup.c | 25 +++++++++++++------------ src/w_wad.c | 3 ++- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index b08e75f01..94530ccc5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7766,20 +7766,9 @@ UINT8 P_InitMapData(boolean existingmapheaders) name = mapheaderinfo[i]->lumpname; maplump = W_CheckNumForMap(name); - // Doesn't exist? - if (maplump == INT16_MAX) - { -#ifndef DEVELOP - if (!existingmapheaders) - { - I_Error("P_InitMapData: Base map %s has a header but no level\n", name); - } -#endif - continue; - } - // Always check for cup cache reassociations. // (The core assumption is that cups < headers.) + if (maplump != LUMPERROR || mapheaderinfo[i]->lumpnum != LUMPERROR) { cupheader_t *cup = kartcupheaders; INT32 j; @@ -7814,6 +7803,18 @@ UINT8 P_InitMapData(boolean existingmapheaders) } } + // Doesn't exist in this set of files? + if (maplump == LUMPERROR) + { +#ifndef DEVELOP + if (!existingmapheaders) + { + I_Error("P_InitMapData: Base map %s has a header but no level\n", name); + } +#endif + continue; + } + // No change? if (mapheaderinfo[i]->lumpnum == maplump) continue; diff --git a/src/w_wad.c b/src/w_wad.c index 8edbe74b6..e81879114 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1324,6 +1324,7 @@ lumpnum_t W_CheckNumForMap(const char *name) lumpnum_t check = INT16_MAX; UINT32 uhash, hash = quickncasehash(name, LUMPNUMCACHENAME); INT32 i; + UINT16 firstfile = (partadd_earliestfile == UINT16_MAX) ? 0 : partadd_earliestfile; // Check the lumpnumcache first. Loop backwards so that we check // most recent entries first @@ -1339,7 +1340,7 @@ lumpnum_t W_CheckNumForMap(const char *name) uhash = quickncasehash(name, 8); // Not a mistake, legacy system for short lumpnames - for (i = numwadfiles - 1; i >= 0; i--) + for (i = numwadfiles - 1; i >= firstfile; i--) { check = W_CheckNumForMapPwad(name, uhash, (UINT16)i, 0); From 9ce87671c7db2f261e12378c1d38449d8faa137f Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 4 Nov 2022 16:54:07 +0000 Subject: [PATCH 26/81] Use Partial Addfile for G_LoadDemoExtraFiles as well Still cope compared to the MP addfile codepath, but not the n^2 time cope of before. --- src/g_demo.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index 0fbd920c6..f602e2752 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2294,10 +2294,13 @@ static void G_LoadDemoExtraFiles(UINT8 **pp) } else { - P_AddWadFile(filename); + P_PartialAddWadFile(filename); } } } + + if (P_PartialAddGetStage() >= 0) + P_MultiSetupWadFiles(true); // in case any partial adds were done } static void G_SkipDemoExtraFiles(UINT8 **pp) From 923c69889814125ad2b1a07e53115f3262399d4b Mon Sep 17 00:00:00 2001 From: SteelT Date: Tue, 1 Nov 2022 18:15:13 -0400 Subject: [PATCH 27/81] Add MD5 checking to HTTP downloading In cases of where the file mismatches from what the server expects, it will fall back to direct downloading of the file. --- src/d_netfil.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/d_netfil.c b/src/d_netfil.c index ffd2c546b..c71fb39b7 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1750,6 +1750,7 @@ void CURLGetFile(void) int msgs_left; /* how many messages are left */ const char *easy_handle_error; long response_code = 0; + static char *filename; if (curl_runninghandles) { @@ -1774,6 +1775,8 @@ void CURLGetFile(void) { e = m->easy_handle; easyres = m->data.result; + filename = Z_StrDup(curl_realname); + nameonly(filename); if (easyres != CURLE_OK) { if (easyres == CURLE_HTTP_RETURNED_ERROR) @@ -1786,21 +1789,29 @@ void CURLGetFile(void) curl_failedwebdownload = true; fclose(curl_curfile->file); remove(curl_curfile->filename); - curl_curfile->file = NULL; - //nameonly(curl_curfile->filename); - nameonly(curl_realname); - CONS_Printf(M_GetText("Failed to download %s (%s)\n"), curl_realname, easy_handle_error); + CONS_Printf(M_GetText("Failed to download %s (%s)\n"), filename, easy_handle_error); } else { - nameonly(curl_realname); - CONS_Printf(M_GetText("Finished downloading %s\n"), curl_realname); - downloadcompletednum++; - downloadcompletedsize += curl_curfile->totalsize; - curl_curfile->status = FS_FOUND; fclose(curl_curfile->file); + + if (checkfilemd5(curl_curfile->filename, curl_curfile->md5sum) == FS_MD5SUMBAD) + { + CONS_Alert(CONS_ERROR, M_GetText("HTTP Download of %s finished but is corrupt or has been modified\n"), filename); + curl_curfile->status = FS_FALLBACK; + } + else + { + CONS_Printf(M_GetText("Finished HTTP download of %s\n"), filename); + downloadcompletednum++; + downloadcompletedsize += curl_curfile->totalsize; + curl_curfile->status = FS_FOUND; + } } + + Z_Free(filename); + curl_curfile->file = NULL; curl_running = false; curl_transfers--; curl_multi_remove_handle(multi_handle, e); From 7c528ead8079171e5546c094be19dbd7446e9a1d Mon Sep 17 00:00:00 2001 From: SteelT Date: Tue, 1 Nov 2022 18:49:42 -0400 Subject: [PATCH 28/81] Set curl_failedwebdownload to true for corrupt or modified HTTP downloads. So that it actually falls back to direct downloading --- src/d_netfil.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_netfil.c b/src/d_netfil.c index c71fb39b7..f50e37bdb 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1799,6 +1799,7 @@ void CURLGetFile(void) { CONS_Alert(CONS_ERROR, M_GetText("HTTP Download of %s finished but is corrupt or has been modified\n"), filename); curl_curfile->status = FS_FALLBACK; + curl_failedwebdownload = true; } else { From 893cc0fd9b99a7a7564a7095f04928ce0833a9e0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 5 Nov 2022 12:44:51 +0000 Subject: [PATCH 29/81] Remove debug print --- src/hu_stuff.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index d33a88daf..4fcfc3614 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -347,8 +347,6 @@ patch_t *HU_UpdateOrBlankPatch(patch_t **user, boolean required, const char *for if (fileref < partadd_earliestfile) return *user; - CONS_Printf("pe = %d, fr = %d\n", partadd_earliestfile, fileref); - lump |= (fileref << 16); } else From c445b0b26afb4a0ffde379fd22431eddb97279d2 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 5 Nov 2022 13:53:04 +0000 Subject: [PATCH 30/81] Direct file downloader changes ported from 1.6 Flattened due to changes between the code base including renamed functions. Also renames CL_LEGACYREQUESTFAILED to the more specific CL_DOWNLOADFAILED. --- src/d_clisrv.c | 29 ++++++++++- src/d_netfil.c | 132 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 143 insertions(+), 18 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f35428c95..e432580c5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -531,6 +531,7 @@ typedef enum CL_SEARCHING, CL_CHECKFILES, CL_DOWNLOADFILES, + CL_DOWNLOADFAILED, CL_ASKJOIN, CL_LOADFILES, CL_SETUPFILES, @@ -616,6 +617,7 @@ static inline void CL_DrawConnectionStatus(void) break; case CL_ASKFULLFILELIST: case CL_CONFIRMCONNECT: + case CL_DOWNLOADFAILED: cltext = ""; break; case CL_SETUPFILES: @@ -723,8 +725,10 @@ static inline void CL_DrawConnectionStatus(void) strncpy(tempname, filename, sizeof(tempname)-1); } + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-30, 0, + va(M_GetText("%s downloading"), ((cl_mode == CL_DOWNLOADHTTPFILES) ? "\x82""HTTP" : "\x85""Direct"))); V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-22, V_YELLOWMAP, - va(M_GetText("Downloading \"%s\""), tempname)); + va(M_GetText("\"%s\""), tempname)); V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE, va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10)); V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE, @@ -1501,6 +1505,10 @@ static void M_ConfirmConnect(void) { cl_mode = CL_DOWNLOADFILES; } + else + { + cl_mode = CL_DOWNLOADFAILED; + } } #ifdef HAVE_CURL else @@ -1649,6 +1657,10 @@ static boolean CL_FinishedFileList(void) { cl_mode = CL_DOWNLOADFILES; } + else + { + cl_mode = CL_DOWNLOADFAILED; + } } #endif } @@ -1854,6 +1866,21 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic cl_mode = CL_LOADFILES; break; + case CL_DOWNLOADFAILED: + { + CONS_Printf(M_GetText("Legacy downloader request packet failed.\n")); + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "The direct download encountered an error.\n" + "See the logfile for more info.\n" + "\n" + "Press (B)\n" + ), NULL, MM_NOTHING); + return false; + } case CL_LOADFILES: if (CL_LoadServerFiles()) cl_mode = CL_SETUPFILES; diff --git a/src/d_netfil.c b/src/d_netfil.c index f50e37bdb..246567c72 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -354,6 +354,9 @@ void CL_AbortDownloadResume(void) pauseddownload = NULL; } +// The following was written and, against all odds, works. +#define MORELEGACYDOWNLOADER + /** Sends requests for files in the ::fileneeded table with a status of * ::FS_NOTFOUND. * @@ -366,42 +369,135 @@ boolean CL_SendFileRequest(void) char *p; INT32 i; INT64 totalfreespaceneeded = 0, availablefreespace; + INT32 skippedafile = -1; +#ifdef MORELEGACYDOWNLOADER + boolean firstloop = true; +#endif #ifdef PARANOIA if (M_CheckParm("-nodownload")) - I_Error("Attempted to download files in -nodownload mode"); + { + CONS_Printf("Direct download - Attempted to download files in -nodownload mode"); + return false; + } +#endif for (i = 0; i < fileneedednum; i++) + { +#ifdef PARANOIA if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) { - I_Error("Attempted to download files that were not sendable"); + CONS_Printf("Direct download - attempted to download files that were not sendable\n"); + return false; } #endif + if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK)) + { + // Error check for the first time around. + totalfreespaceneeded += fileneeded[i].totalsize; + } + } + + I_GetDiskFreeSpace(&availablefreespace); + if (totalfreespaceneeded > availablefreespace) + { + CONS_Printf("Direct download -\n" + " To play on this server you must download %s KB,\n" + " but you have only %s KB free space on this drive\n", + sizeu1((size_t)(totalfreespaceneeded>>10)), sizeu2((size_t)(availablefreespace>>10))); + return false; + } + +#ifdef MORELEGACYDOWNLOADER +tryagain: + skippedafile = -1; +#endif + +#ifdef VERBOSEREQUESTFILE + CONS_Printf("Preparing packet\n"); +#endif netbuffer->packettype = PT_REQUESTFILE; p = (char *)netbuffer->u.textcmd; + for (i = 0; i < fileneedednum; i++) + { if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK)) { - totalfreespaceneeded += fileneeded[i].totalsize; + // Pre-prepare. + size_t checklen; nameonly(fileneeded[i].filename); + + // Figure out if we'd overrun our buffer. + checklen = strlen(fileneeded[i].filename)+2; // plus the fileid (and terminator, in case this is last) + if ((UINT8 *)(p + checklen) >= netbuffer->u.textcmd + MAXTEXTCMD) + { + skippedafile = i; + // we might have a shorter file that can fit in the remaining space, and file ID permits out-of-order data + continue; + } + + // Now write. WRITEUINT8(p, i); // fileid WRITESTRINGN(p, fileneeded[i].filename, MAX_WADPATH); + +#ifdef VERBOSEREQUESTFILE + CONS_Printf(" file \"%s\" (id %d)\n", i, fileneeded[i].filename); +#endif + // put it in download dir strcatbf(fileneeded[i].filename, downloaddir, "/"); fileneeded[i].status = FS_REQUESTED; } - WRITEUINT8(p, 0xFF); - I_GetDiskFreeSpace(&availablefreespace); - if (totalfreespaceneeded > availablefreespace) - I_Error("To play on this server you must download %s KB,\n" - "but you have only %s KB free space on this drive\n", - sizeu1((size_t)(totalfreespaceneeded>>10)), sizeu2((size_t)(availablefreespace>>10))); + } - // prepare to download - I_mkdir(downloaddir, 0755); - return HSendPacket(servernode, true, 0, p - (char *)netbuffer->u.textcmd); +#ifdef MORELEGACYDOWNLOADER + if (firstloop) +#else + // If we're not trying extralong legacy download requests, gotta bail. + if (skippedafile != -1) + { + CONS_Printf("Direct download - missing files are as follows:\n"); + for (i = 0; i < fileneedednum; i++) + { + if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK || fileneeded[i].status == FS_REQUESTED)) // FS_REQUESTED added + CONS_Printf(" %s\n", fileneeded[i].filename); + } + return false; + } +#endif + I_mkdir(downloaddir, 0755); + +#ifdef PARANOIA + // Couldn't fit a single one in? + if (p == (char *)netbuffer->u.textcmd) + { + CONS_Printf("Direct download - fileneeded name for %s (fileneeded[%d]) too long??\n", (skippedafile != -1 ? fileneeded[skippedafile].filename : NULL), skippedafile); + return false; + } +#endif + + WRITEUINT8(p, 0xFF); // terminator + if (!HSendPacket(servernode, true, 0, p - (char *)netbuffer->u.textcmd)) + { + CONS_Printf("Direct download - unable to send packet.\n"); + return false; + } + +#ifdef MORELEGACYDOWNLOADER + if (skippedafile != -1) + { + firstloop = false; + goto tryagain; + } +#endif + +#ifdef VERBOSEREQUESTFILE + CONS_Printf("Returning true\n"); +#endif + + return true; } // get request filepak and put it on the send queue @@ -411,16 +507,18 @@ boolean PT_RequestFile(INT32 node) char wad[MAX_WADPATH+1]; UINT8 *p = netbuffer->u.textcmd; UINT8 id; - while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow + while (p < netbuffer->u.textcmd + MAXTEXTCMD) // Don't allow hacked client to overflow { id = READUINT8(p); if (id == 0xFF) break; READSTRINGN(p, wad, MAX_WADPATH); - if (!AddFileToSendQueue(node, wad, id)) + if (p >= netbuffer->u.textcmd + MAXTEXTCMD || !AddFileToSendQueue(node, wad, id)) { + if (cv_noticedownload.value) + CONS_Printf("Bad PT_REQUESTFILE from node %d!\n", node); SV_AbortSendFiles(node); - return false; // don't read the rest of the files + return false; // don't read any more } } return true; // no problems with any files @@ -798,7 +896,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid char wadfilename[MAX_WADPATH]; if (cv_noticedownload.value) - CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node)); + CONS_Printf("Sending file \"%s\" (id %d) to node %d (%s)\n", filename, fileid, node, I_GetNodeAddress(node)); // Find the last file in the list and set a pointer to its "next" field q = &transfer[node].txlist; @@ -972,7 +1070,7 @@ static void SV_EndFileSend(INT32 node) { case SF_FILE: // It's a file, close it and free its filename if (cv_noticedownload.value) - CONS_Printf("Ending file transfer for node %d\n", node); + CONS_Printf("Ending file transfer (id %d) for node %d\n", p->fileid, node); if (transfer[node].currentfile) fclose(transfer[node].currentfile); free(p->id.filename); From 6cbbb0b286e73ec8e6bdd876d343748f07c2a4d0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 5 Nov 2022 14:03:38 +0000 Subject: [PATCH 31/81] All download meters ported from v1 now use the 2.2 palette --- src/d_clisrv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e432580c5..f8eaf2bca 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -661,8 +661,8 @@ static inline void CL_DrawConnectionStatus(void) V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, "Checking server addons..."); totalfileslength = (INT32)((checkednum/(double)(fileneedednum)) * 256); M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 160); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 96); V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, va(" %2u/%2u Files",checkednum,fileneedednum)); } @@ -683,8 +683,8 @@ static inline void CL_DrawConnectionStatus(void) V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, "Loading server addons..."); totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256); M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 160); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 96); V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, va(" %2u/%2u Files",loadcompletednum,fileneedednum)); } @@ -744,8 +744,8 @@ static inline void CL_DrawConnectionStatus(void) V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-14, V_YELLOWMAP, "Overall Download Progress"); totalfileslength = (INT32)((totaldldsize/(double)totalfilesrequestedsize) * 256); M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 160); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 96); if (totalfilesrequestedsize>>20 >= 10) //display in MB if over 10MB V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, From 990e342b12917de6ffa4788779f72404ae04b73c Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 6 Nov 2022 06:20:28 -0800 Subject: [PATCH 32/81] Fix KITEM DEH list not defined with KITEM_ prefix --- src/deh_tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 383823833..7cb97c82a 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6756,7 +6756,7 @@ struct int_const_s const INT_CONST[] = { // SRB2Kart // kartitems_t -#define FOREACH( name, n ) { #name, KITEM_ ## name } +#define FOREACH( name, n ) { TOSTR (KITEM_ ## name), KITEM_ ## name } KART_ITEM_ITERATOR, // Actual items (can be set for k_itemtype) #undef FOREACH {"NUMKARTITEMS",NUMKARTITEMS}, From f5eadd331e65c473b021772dda8a074d01996f4c Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 14:01:00 +0000 Subject: [PATCH 33/81] Fix follower colour handling in replays --- src/g_demo.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 0fbd920c6..551477d2e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -313,11 +313,11 @@ void G_ReadDemoExtraData(void) demo_p += 16; 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 (!stricmp(Followercolor_cons_t[i].strvalue, name)) + { + players[p].followercolor = Followercolor_cons_t[i].value; + break; + } } } if (extradata & DXD_PLAYSTATE) @@ -407,7 +407,7 @@ void G_ReadDemoExtraData(void) void G_WriteDemoExtraData(void) { - INT32 i; + INT32 i, j; char name[16]; for (i = 0; i < MAXPLAYERS; i++) @@ -459,7 +459,12 @@ void G_WriteDemoExtraData(void) // write follower color memset(name, 0, 16); - strncpy(name, Followercolor_cons_t[(UINT16)(players[i].followercolor+2)].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" + for (j = (numskincolors+2)-1; j > 0; j--) + { + if (Followercolor_cons_t[j].value == players[i].followercolor) + break; + } + strncpy(name, Followercolor_cons_t[j].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" M_Memcpy(demo_p,name,16); demo_p += 16; @@ -1951,7 +1956,7 @@ void G_RecordMetal(void) void G_BeginRecording(void) { - UINT8 i, p; + UINT8 i, j, p; char name[MAXCOLORNAME+1]; player_t *player = &players[consoleplayer]; @@ -2097,7 +2102,12 @@ void G_BeginRecording(void) // Save follower's colour memset(name, 0, 16); - strncpy(name, Followercolor_cons_t[(UINT16)(player->followercolor+2)].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" + for (j = (numskincolors+2)-1; j > 0; j--) + { + if (Followercolor_cons_t[j].value == players[i].followercolor) + break; + } + strncpy(name, Followercolor_cons_t[j].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" M_Memcpy(demo_p, name, 16); demo_p += 16; @@ -3070,11 +3080,11 @@ void G_DoPlayDemo(char *defdemoname) demo_p += 16; for (i = 0; i < numskincolors +2; i++) // +2 because of Match and Opposite { - if (!stricmp(Followercolor_cons_t[i].strvalue, color)) - { - players[p].followercolor = i; - break; - } + if (!stricmp(Followercolor_cons_t[i].strvalue, color)) + { + players[p].followercolor = Followercolor_cons_t[i].value; + break; + } } // Score, since Kart uses this to determine where you start on the map From ca3525a81a65f1de8fb5dc5d88d4f8753756e97e Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 14:52:37 +0000 Subject: [PATCH 34/81] Fixing going back in the follower list on the Character Select --- src/k_menufunc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 4babf145b..8cd8ef7cc 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -2787,6 +2787,8 @@ static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num) if (p->followern < -1) p->followern = numfollowers-1; + M_GetFollowerState(p); + p->rotate = -CSROTATETICS; p->delay = CSROTATETICS; S_StartSound(NULL, sfx_s3kc3s); From 1cae2e1502551e0f24df116a83b91b4ea3093263 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 15:21:22 +0000 Subject: [PATCH 35/81] Fix loading follower default colour Also corrects an issue where the last two skincolours were not being copied to the followercolor table --- src/d_netcmd.c | 21 --------------------- src/deh_soc.c | 24 +++++++++++++++--------- src/g_game.c | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 51d205931..b62840e45 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -831,27 +831,6 @@ void D_RegisterClientCommands(void) { INT32 i; - for (i = 0; i < MAXSKINCOLORS; i++) - { - Color_cons_t[i].value = i; - Color_cons_t[i].strvalue = skincolors[i].name; - } - - for (i = 2; i < MAXSKINCOLORS; i++) - { - Followercolor_cons_t[i].value = i-2; - Followercolor_cons_t[i].strvalue = skincolors[i-2].name; - } - - 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 = 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; - Color_cons_t[MAXSKINCOLORS].strvalue = Followercolor_cons_t[MAXSKINCOLORS+2].strvalue = NULL; - // Set default player names // Monster Iestyn (12/08/19): not sure where else I could have actually put this, but oh well for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/deh_soc.c b/src/deh_soc.c index 4ae9927f4..c19db90ae 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3161,7 +3161,7 @@ void readfollower(MYFILE *f) followers[numfollowers].bobspeed = TICRATE*2; followers[numfollowers].bobamp = 4*FRACUNIT; followers[numfollowers].hitconfirmtime = TICRATE; - followers[numfollowers].defaultcolor = SKINCOLOR_GREEN; + followers[numfollowers].defaultcolor = FOLLOWERCOLOR_MATCH; strcpy(followers[numfollowers].icon, "M_NORANK"); do @@ -3215,7 +3215,20 @@ void readfollower(MYFILE *f) } else if (fastcmp(word, "DEFAULTCOLOR")) { - followers[numfollowers].defaultcolor = get_number(word2); + INT32 j; + for (j = 0; j < numskincolors +2; j++) // +2 because of Match and Opposite + { + if (!stricmp(Followercolor_cons_t[j].strvalue, word2)) + { + followers[numfollowers].defaultcolor = Followercolor_cons_t[j].value; + break; + } + } + + if (j == numskincolors+2) + { + deh_warning("Follower %d: unknown follower color '%s'", numfollowers, word2); + } } else if (fastcmp(word, "SCALE")) { @@ -3373,13 +3386,6 @@ if ((signed)followers[numfollowers].field < threshold) \ #undef FALLBACK - // Special case for color I suppose - if (followers[numfollowers].defaultcolor > (unsigned)(numskincolors-1)) - { - followers[numfollowers].defaultcolor = SKINCOLOR_GREEN; - deh_warning("Follower \'%s\': Value for 'color' should be between 1 and %d.\n", dname, numskincolors-1); - } - // also check if we forgot states. If we did, we will set any missing state to the follower's idlestate. // Print a warning in case we don't have a fallback and set the state to S_INVISIBLE (rather than S_NULL) if unavailable. diff --git a/src/g_game.c b/src/g_game.c index 8db8fac2c..db838ab91 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4263,8 +4263,26 @@ void G_EndGame(void) // Sets a tad of default info we need. void G_LoadGameSettings(void) { + INT32 i; + // initialize free sfx slots for skin sounds S_InitRuntimeSounds(); + + // Prepare skincolor material. + for (i = 0; i < MAXSKINCOLORS; i++) + { + Color_cons_t[i].value = Followercolor_cons_t[i+2].value = i; + Color_cons_t[i].strvalue = Followercolor_cons_t[i+2].strvalue = skincolors[i].name; + } + + 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 = 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; + Color_cons_t[MAXSKINCOLORS].strvalue = Followercolor_cons_t[MAXSKINCOLORS+2].strvalue = NULL; } #define GD_VERSIONCHECK 0xBA5ED444 // Change every major version, as usual From 44f869e5e65d4945ab6611618bf487d6a5dff36b Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 16:53:57 +0000 Subject: [PATCH 36/81] Adjust followers (and players) drawing on character select - Use default colours for followers when not select(ing/ed) follower colour, to match character selection - Adjust offsets in general, including a rework bobbing handling, so there isn't a huge variance in follower position on-screen - Move followers to draw in front of several elements, including the "A/B/C/D PLAYER" text and the rotatey wheel so you can actually see them - Also applies to player: Don't mirror between sides of the screen - instead, rotate the virtual player object, so asymmetrical details aren't lost! - Player-specific: Animate when READY !! to simlate starting your engine. --- src/k_menudraw.c | 134 +++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 69 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 84393be4b..9ecb857e0 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1082,7 +1082,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) patch = W_CachePatchName(fl->icon, PU_CACHE); colormap = R_GetTranslationColormap(TC_DEFAULT, - K_GetEffectiveFollowerColor(p->followercolor, p->color), + K_GetEffectiveFollowerColor(fl->defaultcolor, p->color), GTC_MENUCACHE ); } @@ -1154,41 +1154,40 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) } // returns false if the character couldn't be rendered -static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, INT32 addflags, UINT8 *colormap) +static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, boolean charflip, boolean animate, INT32 addflags, UINT8 *colormap) { UINT8 spr; spritedef_t *sprdef; spriteframe_t *sprframe; patch_t *sprpatch; + UINT8 rotation = (charflip ? 1 : 7); + UINT32 frame = animate ? setup_animcounter : 0; - UINT32 flags = 0; - UINT32 frame; - - spr = P_GetSkinSprite2(&skins[skin], SPR2_FSTN, NULL); + spr = P_GetSkinSprite2(&skins[skin], SPR2_STIN, NULL); sprdef = &skins[skin].sprites[spr]; if (!sprdef->numframes) // No frames ?? return false; // Can't render! - frame = states[S_KART_FAST].frame & FF_FRAMEMASK; - if (frame >= sprdef->numframes) // Walking animation missing - frame = 0; // Try to use standing frame + frame %= sprdef->numframes; sprframe = &sprdef->spriteframes[frame]; - sprpatch = W_CachePatchNum(sprframe->lumppat[1], PU_CACHE); + sprpatch = W_CachePatchNum(sprframe->lumppat[rotation], PU_CACHE); - if (sprframe->flip & 1) // Only for first sprite - flags |= V_FLIP; // This sprite is left/right flipped! + if (sprframe->flip & (1<followern; @@ -1238,14 +1238,11 @@ static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, INT32 addflags, useframe = 0; // frame doesn't exist, we went beyond it... what? sprframe = &sprdef->spriteframes[useframe]; - patch = W_CachePatchNum(sprframe->lumppat[1], PU_CACHE); + patch = W_CachePatchNum(sprframe->lumppat[rotation], PU_CACHE); - if (sprframe->flip & 2) // Only for first sprite + if (sprframe->flip & (1<follower_timer)>>ANGLETOFINESHIFT) & FINEMASK)); - color = K_GetEffectiveFollowerColor(p->followercolor, p->color); + color = K_GetEffectiveFollowerColor( + (p->mdepth < CSSTEP_FOLLOWERCOLORS) ? fl.defaultcolor : p->followercolor, + p->color); } colormap = R_GetTranslationColormap(TC_DEFAULT, color, GTC_MENUCACHE); - V_DrawFixedPatch((x)*FRACUNIT, ((y-12)*FRACUNIT) + sine - fl.zoffs, fl.scale, addflags, patch, colormap); + V_DrawFixedPatch((x*FRACUNIT), ((y-12)*FRACUNIT) + sine, fl.scale, addflags, patch, colormap); return true; } -static void M_DrawCharSelectSprite(UINT8 num, INT16 x, INT16 y) +static void M_DrawCharSelectSprite(UINT8 num, INT16 x, INT16 y, boolean charflip) { setup_player_t *p = &setup_player[num]; UINT8 cnum = p->clonenum; + INT16 skin; + UINT8 color; + UINT8 *colormap; // for p1 alone don't try to preview things on pages that don't exist lol. if (p->mdepth == CSSTEP_CHARS && setup_numplayers == 1) cnum = setup_page; - INT16 skin = setup_chargrid[p->gridx][p->gridy].skinlist[cnum]; - UINT8 color = p->color; - UINT8 *colormap = R_GetTranslationColormap(skin, color, GTC_MENUCACHE); - INT32 flags = 0; - - // Flip for left-side players - if (!(num & 1)) - flags ^= V_FLIP; + skin = setup_chargrid[p->gridx][p->gridy].skinlist[cnum]; + color = p->color; + colormap = R_GetTranslationColormap(skin, color, GTC_MENUCACHE); if (skin >= 0) - M_DrawCharacterSprite(x, y, skin, flags, colormap); + M_DrawCharacterSprite(x, y, skin, charflip, (p->mdepth == CSSTEP_READY), 0, colormap); } static void M_DrawCharSelectPreview(UINT8 num) @@ -1289,6 +1286,7 @@ static void M_DrawCharSelectPreview(UINT8 num) INT16 x = 11, y = 5; char letter = 'A' + num; setup_player_t *p = &setup_player[num]; + boolean charflip = !!(num & 1); if (num & 1) x += 233; @@ -1300,28 +1298,10 @@ static void M_DrawCharSelectPreview(UINT8 num) if (p->mdepth >= CSSTEP_CHARS) { - M_DrawCharSelectSprite(num, x+32, y+75); - - if (p->mdepth >= CSSTEP_FOLLOWER) - { - M_DrawFollowerSprite(x+16, y+75, -1, !(num & 1) ? V_FLIP : 0, 0, p); - } - + M_DrawCharSelectSprite(num, x+32, y+75, charflip); M_DrawCharSelectCircle(p, x+32, y+64); } - if ((setup_animcounter/10) & 1 && gamestate == GS_MENU) // Not drawn outside of GS_MENU. - { - if (p->mdepth == CSSTEP_NONE && num == setup_numplayers) - { - V_DrawScaledPatch(x+1, y+36, 0, W_CachePatchName("4PSTART", PU_CACHE)); - } - else if (p->mdepth >= CSSTEP_READY) - { - V_DrawScaledPatch(x+1, y+36, 0, W_CachePatchName("4PREADY", PU_CACHE)); - } - } - V_DrawScaledPatch(x+9, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE)); V_DrawScaledPatch(x, y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE)); if (p->mdepth > CSSTEP_PROFILE) @@ -1334,6 +1314,23 @@ static void M_DrawCharSelectPreview(UINT8 num) V_DrawFileString(x+16, y+2, 0, "PLAYER"); } + if (p->mdepth >= CSSTEP_FOLLOWER) + { + M_DrawFollowerSprite(x+32+((charflip ? 1 : -1)*16), y+75, -1, charflip, 0, 0, p); + } + + if ((setup_animcounter/10) & 1 && gamestate == GS_MENU) // Not drawn outside of GS_MENU. + { + if (p->mdepth == CSSTEP_NONE && num == setup_numplayers) + { + V_DrawScaledPatch(x+1, y+36, 0, W_CachePatchName("4PSTART", PU_CACHE)); + } + else if (p->mdepth >= CSSTEP_READY) + { + V_DrawScaledPatch(x+1, y+36, 0, W_CachePatchName("4PREADY", PU_CACHE)); + } + } + // Profile selection if (p->mdepth == CSSTEP_PROFILE) { @@ -1549,39 +1546,38 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p) // check what setup_player is doing in priority. if (sp->mdepth >= CSSTEP_CHARS) { - skinnum = setup_chargrid[sp->gridx][sp->gridy].skinlist[sp->clonenum]; if (skinnum >= 0) { - if (M_DrawCharacterSprite(x-22, y+119, skinnum, V_FLIP, colormap)) + if (M_DrawCharacterSprite(x-22, y+119, skinnum, false, false, 0, colormap)) V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], colormap); - - if (sp->mdepth >= CSSTEP_FOLLOWER) - { - if (M_DrawFollowerSprite(x-44 +12, y+119, 0, V_FLIP, 0, sp)) - { - UINT16 col = K_GetEffectiveFollowerColor(sp->followercolor, sp->color);; - patch_t *ico = W_CachePatchName(followers[sp->followern].icon, PU_CACHE); - UINT8 *fcolormap; - - fcolormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); - V_DrawMappedPatch(x+14+18, y+66, 0, ico, fcolormap); - } - } } M_DrawCharSelectCircle(sp, x-22, y+104); + + if (sp->mdepth >= CSSTEP_FOLLOWER) + { + if (M_DrawFollowerSprite(x-22 - 16, y+119, 0, false, 0, 0, sp)) + { + UINT16 col = K_GetEffectiveFollowerColor(sp->followercolor, sp->color);; + patch_t *ico = W_CachePatchName(followers[sp->followern].icon, PU_CACHE); + UINT8 *fcolormap; + + fcolormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); + V_DrawMappedPatch(x+14+18, y+66, 0, ico, fcolormap); + } + } } else if (skinnum > -1) // otherwise, read from profile. { UINT16 col = K_GetEffectiveFollowerColor(p->followercolor, p->color);; UINT8 fln = K_FollowerAvailable(p->follower); - if (M_DrawCharacterSprite(x-22, y+119, skinnum, V_FLIP, colormap)) + if (M_DrawCharacterSprite(x-22, y+119, skinnum, false, false, 0, colormap)) V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], colormap); - if (M_DrawFollowerSprite(x-44 +12, y+119, fln, V_FLIP, col, NULL)) + if (M_DrawFollowerSprite(x-22 - 16, y+119, fln, false, 0, col, NULL)) { patch_t *ico = W_CachePatchName(followers[fln].icon, PU_CACHE); UINT8 *fcolormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); From 59cd7bfc11fd1ca914e2f66ee82c13d3e2209a68 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 17:06:29 +0000 Subject: [PATCH 37/81] Use character's prefcolour before color selection for that player --- src/k_menudraw.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 9ecb857e0..a7baafe14 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1274,7 +1274,10 @@ static void M_DrawCharSelectSprite(UINT8 num, INT16 x, INT16 y, boolean charflip cnum = setup_page; skin = setup_chargrid[p->gridx][p->gridy].skinlist[cnum]; - color = p->color; + if (p->mdepth < CSSTEP_COLORS) + color = skins[skin].prefcolor; + else + color = p->color; colormap = R_GetTranslationColormap(skin, color, GTC_MENUCACHE); if (skin >= 0) From 9a009cab1855a292f8fe033afa65ca915ec5676a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 6 Nov 2022 15:23:18 -0500 Subject: [PATCH 38/81] Overlays use dispoffset instead of position hack --- src/p_mobj.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index c1de9d6ce..366be896d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5257,27 +5257,8 @@ void P_RunOverlays(void) continue; } - if (!r_splitscreen /*&& rendermode != render_soft*/) - { - angle_t viewingangle; - - 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[0].x, camera[0].y); - - if (!(mo->state->frame & FF_ANIMATE) && mo->state->var1) - viewingangle += ANGLE_180; - destx = mo->target->x + P_ReturnThrustX(mo->target, viewingangle, FixedMul(FRACUNIT/4, mo->scale)); - desty = mo->target->y + P_ReturnThrustY(mo->target, viewingangle, FixedMul(FRACUNIT/4, mo->scale)); - } - else - { - destx = mo->target->x; - desty = mo->target->y; - } + destx = mo->target->x; + desty = mo->target->y; mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP) | (mo->target->eflags & MFE_VERTICALFLIP); mo->scale = mo->destscale = FixedMul(mo->target->scale, mo->movefactor); @@ -5289,12 +5270,27 @@ void P_RunOverlays(void) if ((mo->flags & MF_DONTENCOREMAP) != (mo->target->flags & MF_DONTENCOREMAP)) mo->flags ^= MF_DONTENCOREMAP; + mo->dispoffset = mo->target->dispoffset + mo->info->dispoffset; + if (!(mo->state->frame & FF_ANIMATE)) + { zoffs = FixedMul(((signed)mo->state->var2)*FRACUNIT, mo->scale); - // if you're using FF_ANIMATE on an overlay, - // then you're on your own. + + if (mo->state->var1) + { + mo->dispoffset--; + } + else + { + mo->dispoffset++; + } + } else + { + // if you're using FF_ANIMATE on an overlay, + // then you're on your own. zoffs = 0; + } P_UnsetThingPosition(mo); mo->x = destx; From 368a45c6742ac765aa0c0fde1b76aa49dd19dbf8 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 22:15:08 +0000 Subject: [PATCH 39/81] Change default followercolor to "Match" (from "1") --- src/d_netcmd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b62840e45..1c527b1a5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -295,10 +295,10 @@ consvar_t cv_follower[MAXSPLITSCREENPLAYERS] = { // player's follower colors... Also saved... consvar_t cv_followercolor[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("followercolor", "1", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor_OnChange), - CVAR_INIT ("followercolor2", "1", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor2_OnChange), - CVAR_INIT ("followercolor3", "1", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor3_OnChange), - CVAR_INIT ("followercolor4", "1", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor4_OnChange) + CVAR_INIT ("followercolor", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor_OnChange), + CVAR_INIT ("followercolor2", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor2_OnChange), + CVAR_INIT ("followercolor3", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor3_OnChange), + CVAR_INIT ("followercolor4", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor4_OnChange) }; // last selected profile, unaccessible cvar only set internally but is saved. From 8aeaf9738d3a013352e16c4cb8d4537c694f037c Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 22:53:12 +0000 Subject: [PATCH 40/81] Major changes to follower selection - Followers now have categories, definable in SOC - New character select step: Follower category - "None" is a category, just skips straight to Follower None - Select a category to go to the previous regular follower selection step - Press the C/Extra button to reset a character select step to its "default" - Character: Center the character in the engine class (goes from [0,1] to [1,1], etc) - Character alts: Centers the "primary" alt (prefers Eggman over Eggrobo) - Skincolor: Centers the character's prefcolour - Follower category: Centers on the "None" option - Follower: [CURRENTLY NO BEHAVIOUR] - Followercolor: Cycles between follower's defaultcolour, "Match", and "Opposite" --- src/deh_soc.c | 97 +++++++++++++++++++++++++++-- src/deh_soc.h | 1 + src/dehacked.c | 6 ++ src/k_follower.c | 3 + src/k_follower.h | 14 +++++ src/k_menu.h | 5 +- src/k_menudraw.c | 108 ++++++++++++++++++++++++++------- src/k_menufunc.c | 155 ++++++++++++++++++++++++++++++++++++++++++++--- 8 files changed, 354 insertions(+), 35 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index c19db90ae..1d806322e 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3139,10 +3139,9 @@ void readfollower(MYFILE *f) INT32 res; INT32 i; - if (numfollowers > MAXSKINS) + if (numfollowers >= MAXSKINS) { - deh_warning("Error: Too many followers, cannot add anymore.\n"); - return; + I_Error("Out of Followers\nLoad less addons to fix this."); } s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -3162,7 +3161,8 @@ void readfollower(MYFILE *f) followers[numfollowers].bobamp = 4*FRACUNIT; followers[numfollowers].hitconfirmtime = TICRATE; followers[numfollowers].defaultcolor = FOLLOWERCOLOR_MATCH; - strcpy(followers[numfollowers].icon, "M_NORANK"); + followers[numfollowers].category = UINT8_MAX; + strcpy(followers[numfollowers].icon, "MISSING"); do { @@ -3201,6 +3201,23 @@ void readfollower(MYFILE *f) strcpy(followers[numfollowers].icon, word2); nameset = true; } + else if (fastcmp(word, "CATEGORY")) + { + INT32 j; + for (j = 0; j < numfollowercategories; j++) + { + if (!stricmp(followercategories[j].name, word2)) + { + followers[numfollowers].category = j; + break; + } + } + + if (j == numfollowercategories) + { + deh_warning("Follower %d: unknown follower category '%s'", numfollowers, word2); + } + } else if (fastcmp(word, "MODE")) { if (word2) @@ -3406,10 +3423,82 @@ if (!followers[numfollowers].field) \ #undef NOSTATE CONS_Printf("Added follower '%s'\n", dname); + if (followers[numfollowers].category < numfollowercategories) + followercategories[followers[numfollowers].category].numincategory++; numfollowers++; // add 1 follower Z_Free(s); } +void readfollowercategory(MYFILE *f) +{ + char *s; + char *word, *word2; + char *tmp; + + boolean nameset; + + if (numfollowercategories == MAXFOLLOWERCATEGORIES) + { + I_Error("Out of Follower categories\nLoad less addons to fix this."); + } + + s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + + // Ready the default variables for followers. We will overwrite them as we go! We won't set the name or states RIGHT HERE as this is handled down instead. + strcpy(followercategories[numfollowercategories].icon, "MISSING"); + followercategories[numfollowercategories].numincategory = 0; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + word2 = strtok(NULL, " = "); + + if (!word2) + break; + + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + + if (fastcmp(word, "NAME")) + { + strcpy(followercategories[numfollowercategories].name, word2); + nameset = true; + } + else if (fastcmp(word, "ICON")) + { + strcpy(followercategories[numfollowercategories].icon, word2); + nameset = true; + } + } + } while (!myfeof(f)); // finish when the line is empty + + if (!nameset) + { + // well this is problematic. + strcpy(followercategories[numfollowercategories].name, va("Followercategory%d", numfollowercategories)); // this is lazy, so what + } + + CONS_Printf("Added follower category '%s'\n", followercategories[numfollowercategories].name); + numfollowercategories++; // add 1 follower + Z_Free(s); +} + void readweather(MYFILE *f, INT32 num) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); diff --git a/src/deh_soc.h b/src/deh_soc.h index 161422783..0d9beccab 100644 --- a/src/deh_soc.h +++ b/src/deh_soc.h @@ -82,6 +82,7 @@ void clear_conditionsets(void); void readcupheader(MYFILE *f, cupheader_t *cup); void readfollower(MYFILE *f); +void readfollowercategory(MYFILE *f); preciptype_t get_precip(const char *word); void readweather(MYFILE *f, INT32 num); diff --git a/src/dehacked.c b/src/dehacked.c index 690a49dbc..99ee7b0e8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -235,6 +235,12 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) readfollower(f); continue; } + else if (fastcmp(word, "FOLLOWERCATEGORY")) + { + // This is not a major mod. + readfollowercategory(f); + continue; + } word2 = strtok(NULL, " "); if (word2) { diff --git a/src/k_follower.c b/src/k_follower.c index 63ebda167..c6a9e97eb 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -15,6 +15,9 @@ INT32 numfollowers = 0; follower_t followers[MAXSKINS]; +INT32 numfollowercategories; +followercategory_t followercategories[MAXFOLLOWERCATEGORIES]; + CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+3]; // +3 to account for "Match", "Opposite" & NULL /*-------------------------------------------------- diff --git a/src/k_follower.h b/src/k_follower.h index f9a16c971..4bf39dbc0 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -49,6 +49,8 @@ typedef struct follower_s char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this. char icon[8+1]; // Lump names are only 8 characters. (+1 for \0) + UINT8 category; // Category + skincolornum_t defaultcolor; // default color for menus. followermode_t mode; // Follower behavior modifier. @@ -85,6 +87,18 @@ typedef struct follower_s extern INT32 numfollowers; extern follower_t followers[MAXSKINS]; +#define MAXFOLLOWERCATEGORIES 32 + +typedef struct followercategory_s +{ + char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this. + char icon[8+1]; // Lump names are only 8 characters. (+1 for \0) + UINT8 numincategory; +} followercategory_t; + +extern INT32 numfollowercategories; +extern followercategory_t followercategories[MAXFOLLOWERCATEGORIES]; + /*-------------------------------------------------- INT32 K_FollowerAvailable(const char *name) diff --git a/src/k_menu.h b/src/k_menu.h index ba4458bcc..c64ff4d2d 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -599,6 +599,7 @@ typedef enum CSSTEP_CHARS, CSSTEP_ALTS, CSSTEP_COLORS, + CSSTEP_FOLLOWERCATEGORY, CSSTEP_FOLLOWER, CSSTEP_FOLLOWERCOLORS, CSSTEP_READY @@ -614,6 +615,7 @@ typedef struct setup_player_s UINT8 delay; UINT16 color; UINT8 mdepth; + boolean hitlag; // Hack, save player 1's original device even if they init charsel with keyboard. // If they play ALONE, allow them to retain that original device, otherwise, ignore this. @@ -622,7 +624,8 @@ typedef struct setup_player_s UINT8 changeselect; - INT32 followern; + INT16 followercategory; + INT16 followern; UINT16 followercolor; tic_t follower_tics; tic_t follower_timer; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index a7baafe14..d757ea799 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -969,7 +969,8 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) { angle_t angamt = ANGLE_MAX; UINT16 i, numoptions = 0; - UINT16 l = 0, r = 0; + INT16 l = 0, r = 0; + INT16 subtractcheck; switch (p->mdepth) { @@ -979,8 +980,11 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) case CSSTEP_COLORS: numoptions = nummenucolors; break; + case CSSTEP_FOLLOWERCATEGORY: + numoptions = numfollowercategories+1; + break; case CSSTEP_FOLLOWER: - numoptions = numfollowers+1; + numoptions = followercategories[p->followercategory].numincategory; break; case CSSTEP_FOLLOWERCOLORS: numoptions = nummenucolors+2; @@ -994,17 +998,19 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) return; } + subtractcheck = 1 ^ (numoptions & 1); + angamt /= numoptions; for (i = 0; i < numoptions; i++) { fixed_t cx = x << FRACBITS, cy = y << FRACBITS; - boolean subtract = (i & 1); + boolean subtract = (i & 1) == subtractcheck; angle_t ang = ((i+1)/2) * angamt; patch_t *patch = NULL; UINT8 *colormap = NULL; fixed_t radius = 28<mdepth) { @@ -1017,7 +1023,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) n -= ((i+1)/2); else n += ((i+1)/2); - n %= numoptions; + n = (n + numoptions) % numoptions; skin = setup_chargrid[p->gridx][p->gridy].skinlist[n]; patch = faceprefix[skin][FACE_RANK]; @@ -1061,16 +1067,16 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) break; } - case CSSTEP_FOLLOWER: + case CSSTEP_FOLLOWERCATEGORY: { - follower_t *fl = NULL; + followercategory_t *fc = NULL; - n = (p->followern + 1) + numoptions/2; + n = (p->followercategory + 1) + numoptions/2; if (subtract) n -= ((i+1)/2); else n += ((i+1)/2); - n %= numoptions; + n = (n + numoptions) % numoptions; if (n == 0) { @@ -1078,7 +1084,67 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) } else { - fl = &followers[n - 1]; + fc = &followercategories[n - 1]; + patch = W_CachePatchName(fc->icon, PU_CACHE); + } + + radius = 24<width) << FRACBITS) >> 1; + cy -= (SHORT(patch->height) << FRACBITS) >> 1; + break; + } + + case CSSTEP_FOLLOWER: + { + follower_t *fl = NULL; + INT16 startfollowern = p->followern; + + if (i == 0) + { + n = p->followern; + r = (numoptions+1)/2; + while (r) + { + n--; + if (n < 0) + n = numfollowers-1; + if (n == startfollowern) + break; + if (followers[n].category == p->followercategory) + r--; + } + l = r = n; + } + else if (subtract) + { + do + { + l--; + if (l < 0) + l = numfollowers-1; + if (l == startfollowern) + break; + } + while (followers[l].category != p->followercategory); + n = l; + } + else + { + do + { + r++; + if (r >= numfollowers) + r = 0; + if (r == startfollowern) + break; + } + while (followers[r].category != p->followercategory); + n = r; + } + + { + fl = &followers[n]; patch = W_CachePatchName(fl->icon, PU_CACHE); colormap = R_GetTranslationColormap(TC_DEFAULT, @@ -1142,7 +1208,12 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) ang = (signed)(ang - (angamt/2)); if (p->rotate) - ang = (signed)(ang + ((angamt / CSROTATETICS) * p->rotate)); + { + SINT8 rotate = p->rotate; + if ((p->hitlag == true) && (setup_animcounter & 1)) + rotate = -rotate; + ang = (signed)(ang + ((angamt / CSROTATETICS) * rotate)); + } cx += FixedMul(radius, FINECOSINE(ang >> ANGLETOFINESHIFT)); cy -= FixedMul(radius, FINESINE(ang >> ANGLETOFINESHIFT)) / 3; @@ -1264,24 +1335,19 @@ static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charfli static void M_DrawCharSelectSprite(UINT8 num, INT16 x, INT16 y, boolean charflip) { setup_player_t *p = &setup_player[num]; - UINT8 cnum = p->clonenum; - INT16 skin; UINT8 color; UINT8 *colormap; - // for p1 alone don't try to preview things on pages that don't exist lol. - if (p->mdepth == CSSTEP_CHARS && setup_numplayers == 1) - cnum = setup_page; + if (p->skin < 0) + return; - skin = setup_chargrid[p->gridx][p->gridy].skinlist[cnum]; if (p->mdepth < CSSTEP_COLORS) - color = skins[skin].prefcolor; + color = skins[p->skin].prefcolor; else color = p->color; - colormap = R_GetTranslationColormap(skin, color, GTC_MENUCACHE); + colormap = R_GetTranslationColormap(p->skin, color, GTC_MENUCACHE); - if (skin >= 0) - M_DrawCharacterSprite(x, y, skin, charflip, (p->mdepth == CSSTEP_READY), 0, colormap); + M_DrawCharacterSprite(x, y, p->skin, charflip, (p->mdepth == CSSTEP_READY), 0, colormap); } static void M_DrawCharSelectPreview(UINT8 num) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 8cd8ef7cc..f3d482eaa 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -2150,6 +2150,7 @@ void M_CharacterSelectInit(void) { // Default to no follower / match colour. setup_player[i].followern = -1; + setup_player[i].followercategory = -1; setup_player[i].followercolor = FOLLOWERCOLOR_MATCH; // Set default selected profile to the last used profile for each player: @@ -2578,6 +2579,15 @@ static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num) S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } + else if (M_MenuExtraPressed(num)) + { + p->gridx /= 3; + p->gridx = (3*p->gridx) + 1; + p->gridy /= 3; + p->gridy = (3*p->gridy) + 1; + S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s + M_SetMenuDelay(num); + } // try to set the clone num to the page # if possible. p->clonenum = setup_page; @@ -2692,6 +2702,14 @@ static void M_HandleCharRotate(setup_player_t *p, UINT8 num) S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } + else if (M_MenuExtraPressed(num)) + { + p->clonenum = 0; + p->rotate = CSROTATETICS; + p->hitlag = true; + S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s + M_SetMenuDelay(num); + } } static void M_HandleColorRotate(setup_player_t *p, UINT8 num) @@ -2716,8 +2734,7 @@ static void M_HandleColorRotate(setup_player_t *p, UINT8 num) if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) { - p->mdepth = CSSTEP_FOLLOWER; - M_GetFollowerState(p); + p->mdepth = CSSTEP_FOLLOWERCATEGORY; S_StartSound(NULL, sfx_s3k63); M_SetMenuDelay(num); } @@ -2734,6 +2751,17 @@ static void M_HandleColorRotate(setup_player_t *p, UINT8 num) S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } + else if (M_MenuExtraPressed(num)) + { + if (p->skin >= 0) + { + p->color = skins[p->skin].prefcolor; + p->rotate = CSROTATETICS; + p->hitlag = true; + S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s + M_SetMenuDelay(num); + } + } } static void M_AnimateFollower(setup_player_t *p) @@ -2764,16 +2792,100 @@ static void M_AnimateFollower(setup_player_t *p) p->follower_timer++; } -static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num) +static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num) { if (cv_splitdevice.value) num = 0; if (menucmd[num].dpad_lr > 0) { - p->followern++; - if (p->followern >= numfollowers) + p->followercategory++; + if (p->followercategory >= numfollowercategories) + p->followercategory = -1; + + p->rotate = CSROTATETICS; + p->delay = CSROTATETICS; + S_StartSound(NULL, sfx_s3kc3s); + } + else if (menucmd[num].dpad_lr < 0) + { + p->followercategory--; + if (p->followercategory < -1) + p->followercategory = numfollowercategories-1; + + p->rotate = -CSROTATETICS; + p->delay = CSROTATETICS; + S_StartSound(NULL, sfx_s3kc3s); + } + + if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) + { + if (p->followercategory < 0) + { p->followern = -1; + p->mdepth = CSSTEP_READY; + p->delay = TICRATE; + M_SetupReadyExplosions(p); + S_StartSound(NULL, sfx_s3k4e); + } + else + { + if (p->followern < 0 || followers[p->followern].category != p->followercategory) + { + p->followern = 0; + while (p->followern < numfollowers && followers[p->followern].category != p->followercategory) + p->followern++; + } + + if (p->followern >= numfollowers) + { + p->followern = -1; + S_StartSound(NULL, sfx_s3kb2); + } + else + { + M_GetFollowerState(p); + p->mdepth = CSSTEP_FOLLOWER; + S_StartSound(NULL, sfx_s3k63); + } + } + + M_SetMenuDelay(num); + } + else if (M_MenuBackPressed(num)) + { + p->mdepth = CSSTEP_COLORS; + S_StartSound(NULL, sfx_s3k5b); + M_SetMenuDelay(num); + } + else if (M_MenuExtraPressed(num)) + { + p->followercategory = -1; + p->rotate = CSROTATETICS; + p->hitlag = true; + S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s + M_SetMenuDelay(num); + } +} + +static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num) +{ + INT16 startfollowern = p->followern; + + if (cv_splitdevice.value) + num = 0; + + if (menucmd[num].dpad_lr > 0) + { + do + { + p->followern++; + if (p->followern >= numfollowers) + p->followern = 0; + if (p->followern == startfollowern) + break; + } + while (followers[p->followern].category != p->followercategory); M_GetFollowerState(p); @@ -2783,9 +2895,15 @@ static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num) } else if (menucmd[num].dpad_lr < 0) { - p->followern--; - if (p->followern < -1) - p->followern = numfollowers-1; + do + { + p->followern--; + if (p->followern < 0) + p->followern = numfollowers-1; + if (p->followern == startfollowern) + break; + } + while (followers[p->followern].category != p->followercategory); M_GetFollowerState(p); @@ -2813,7 +2931,7 @@ static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num) } else if (M_MenuBackPressed(num)) { - p->mdepth = CSSTEP_COLORS; + p->mdepth = CSSTEP_FOLLOWERCATEGORY; S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } @@ -2851,10 +2969,24 @@ static void M_HandleFollowerColorRotate(setup_player_t *p, UINT8 num) } else if (M_MenuBackPressed(num)) { + M_GetFollowerState(p); p->mdepth = CSSTEP_FOLLOWER; S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } + else if (M_MenuExtraPressed(num)) + { + if (p->followercolor == FOLLOWERCOLOR_MATCH) + p->followercolor = FOLLOWERCOLOR_OPPOSITE; + else if (p->followercolor == followers[p->followern].defaultcolor) + p->followercolor = FOLLOWERCOLOR_MATCH; + else + p->followercolor = followers[p->followern].defaultcolor; + p->rotate = CSROTATETICS; + p->hitlag = true; + S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s + M_SetMenuDelay(num); + } } boolean M_CharacterSelectHandler(INT32 choice) @@ -2903,6 +3035,9 @@ boolean M_CharacterSelectHandler(INT32 choice) case CSSTEP_COLORS: // Select color M_HandleColorRotate(p, i); break; + case CSSTEP_FOLLOWERCATEGORY: + M_HandleFollowerCategoryRotate(p, i); + break; case CSSTEP_FOLLOWER: M_HandleFollowerRotate(p, i); break; @@ -3006,6 +3141,8 @@ void M_CharacterSelectTick(void) setup_player[i].rotate--; else if (setup_player[i].rotate < 0) setup_player[i].rotate++; + else + setup_player[i].hitlag = false; if (i >= setup_numplayers) continue; From fa5aa408be4ca09d5b12ddfe96d6e75317fc14cb Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Nov 2022 00:58:55 +0000 Subject: [PATCH 41/81] WIP: Catch a few places which could be going wrong with followers on joining servers. Definitely better than it was, but current status: sometimes when joining a server cv_follower[n].value is 0 and I don't know why. --- src/d_netcmd.c | 12 ++++++----- src/k_follower.c | 56 +++++++++++++++++++++++++++--------------------- src/k_follower.h | 14 ++++++++++++ 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1c527b1a5..f5df01d7a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1468,7 +1468,7 @@ static void SendNameAndColor(UINT8 n) const INT32 playernum = g_localplayers[n]; player_t *player = &players[playernum]; - char buf[MAXPLAYERNAME+9]; + char buf[MAXPLAYERNAME+12]; char *p; if (splitscreen < n) @@ -1501,7 +1501,7 @@ static void SendNameAndColor(UINT8 n) // so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game: if (cv_follower[n].value >= numfollowers || cv_follower[n].value < -1) - CV_StealthSet(&cv_follower[n], "-1"); + CV_StealthSet(&cv_follower[n], "None"); if (!strcmp(cv_playername[n].string, player_names[playernum]) && cv_playercolor[n].value == player->skincolor @@ -1587,7 +1587,8 @@ static void SendNameAndColor(UINT8 n) WRITEUINT32(p, (UINT32)player->availabilities); WRITEUINT16(p, (UINT16)cv_playercolor[n].value); WRITEUINT8(p, (UINT8)cv_skin[n].value); - WRITESINT8(p, (SINT8)cv_follower[n].value); + WRITEINT16(p, (INT16)cv_follower[n].value); + //CONS_Printf("Sending follower id %d\n", (INT16)cv_follower[n].value); WRITEUINT16(p, (UINT16)cv_followercolor[n].value); SendNetXCmdForPlayer(n, XD_NAMEANDCOLOR, buf, p - buf); @@ -1599,7 +1600,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) char name[MAXPLAYERNAME+1]; UINT16 color, followercolor; UINT8 skin; - SINT8 follower; + INT16 follower; SINT8 localplayer = -1; UINT8 i; @@ -1628,7 +1629,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) p->availabilities = READUINT32(*cp); color = READUINT16(*cp); skin = READUINT8(*cp); - follower = READSINT8(*cp); + follower = READINT16(*cp); + //CONS_Printf("Recieved follower id %d\n", follower); followercolor = READUINT16(*cp); // set name diff --git a/src/k_follower.c b/src/k_follower.c index c6a9e97eb..b21f56595 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -77,6 +77,31 @@ boolean K_SetFollowerByName(INT32 playernum, const char *skinname) return false; } +/*-------------------------------------------------- + void K_RemoveFollower(player_t *player) + + See header file for description. +--------------------------------------------------*/ +void K_RemoveFollower(player_t *player) +{ + mobj_t *bub, *tmp; + if (player->follower && !P_MobjWasRemoved(player->follower)) // this is also called when we change colour so don't respawn the follower unless we changed skins + { + // Remove follower's possible hnext list (bubble) + bub = player->follower->hnext; + + while (bub && !P_MobjWasRemoved(bub)) + { + tmp = bub->hnext; + P_RemoveMobj(bub); + bub = tmp; + } + + P_RemoveMobj(player->follower); + P_SetTarget(&player->follower, NULL); + } +} + /*-------------------------------------------------- void K_SetFollowerByNum(INT32 playernum, INT32 skinnum) @@ -85,8 +110,6 @@ boolean K_SetFollowerByName(INT32 playernum, const char *skinname) void K_SetFollowerByNum(INT32 playernum, INT32 skinnum) { player_t *player = &players[playernum]; - mobj_t *bub; - mobj_t *tmp; player->followerready = true; // we are ready to perform follower related actions in the player thinker, now. @@ -97,21 +120,8 @@ void K_SetFollowerByNum(INT32 playernum, INT32 skinnum) However, we will despawn it right here if there's any to make it easy for the player thinker to replace it or delete it. */ - if (player->follower && skinnum != player->followerskin) // this is also called when we change colour so don't respawn the follower unless we changed skins - { - // Remove follower's possible hnext list (bubble) - bub = player->follower->hnext; - - while (bub && !P_MobjWasRemoved(bub)) - { - tmp = bub->hnext; - P_RemoveMobj(bub); - bub = tmp; - } - - P_RemoveMobj(player->follower); - P_SetTarget(&player->follower, NULL); - } + if (skinnum != player->followerskin) + K_RemoveFollower(player); player->followerskin = skinnum; @@ -256,18 +266,16 @@ void K_HandleFollower(player_t *player) { //CONS_Printf("Follower skin invlaid. Setting to -1.\n"); player->followerskin = -1; - return; } // don't do anything if we can't have a follower to begin with. // (It gets removed under those conditions) - if (player->spectator) - { - return; - } - - if (player->followerskin < 0) + if (player->spectator || player->followerskin < 0) { + if (player->follower) + { + K_RemoveFollower(player); + } return; } diff --git a/src/k_follower.h b/src/k_follower.h index 4bf39dbc0..e0eddccd1 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -182,5 +182,19 @@ UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor); void K_HandleFollower(player_t *player); +/*-------------------------------------------------- + void K_RemoveFollower(player_t *player) + + Removes Follower object + + Input Arguments:- + player - The player who we want to remove the follower of. + + Return:- + None +--------------------------------------------------*/ + +void K_RemoveFollower(player_t *player); + #endif // __K_FOLLOWER__ From 35a3a9db4ac66b1bc363194953dd5eca36207b54 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Nov 2022 16:42:22 +0000 Subject: [PATCH 42/81] Remove follower on player departure --- src/d_clisrv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1387c80e4..fc6612821 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2487,6 +2487,11 @@ void CL_ClearPlayer(INT32 playernum) { int i; + if (players[playernum].follower) + { + K_RemoveFollower(&players[playernum]); + } + if (players[playernum].mo) { P_RemoveMobj(players[playernum].mo); From 2e750126450246b3a7be5274ecd429527bfe7412 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Nov 2022 18:11:06 +0000 Subject: [PATCH 43/81] Clean up follower setting to handle strings and values just like player->skin - Fixes defaulting to follower id 0 (previously chao, currently hot robo) when joining a server without going through the menu flow - No need to store TWO names for a follower, so save a little memory - Should make it easier to add unlockable followers later --- src/d_netcmd.c | 215 ++++++++--------------------------------------- src/deh_soc.c | 17 ++-- src/g_demo.c | 4 +- src/k_follower.c | 4 +- src/k_follower.h | 3 +- src/k_menufunc.c | 19 +++-- 6 files changed, 56 insertions(+), 206 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index f5df01d7a..9a60a7a0a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1528,31 +1528,28 @@ static void SendNameAndColor(UINT8 n) K_KartResetPlayerColor(player); - // Update follower for local games: - if (cv_follower[n].value >= -1 && cv_follower[n].value != player->followerskin) - K_SetFollowerByNum(playernum, cv_follower[n].value); - - player->followercolor = cv_followercolor[n].value; - - if (metalrecording && n == 0) - { // Starring Metal Sonic as themselves, obviously. - SetPlayerSkinByNum(playernum, 5); - CV_StealthSet(&cv_skin[n], skins[5].name); - } - else if ((foundskin = R_SkinAvailable(cv_skin[n].string)) != -1 && R_SkinUsable(playernum, foundskin)) + if ((foundskin = R_SkinAvailable(cv_skin[n].string)) != -1 && R_SkinUsable(playernum, foundskin)) { - cv_skin[n].value = foundskin; SetPlayerSkin(playernum, cv_skin[n].string); - CV_StealthSet(&cv_skin[n], skins[cv_skin[n].value].name); + CV_StealthSet(&cv_skin[n], skins[foundskin].name); + cv_skin[n].value = foundskin; } else { - cv_skin[n].value = players[playernum].skin; CV_StealthSet(&cv_skin[n], skins[player->skin].name); + cv_skin[n].value = player->skin; // will always be same as current SetPlayerSkin(playernum, cv_skin[n].string); } + player->followercolor = cv_followercolor[n].value; + + // Update follower for local games: + foundskin = K_FollowerAvailable(cv_follower[n].string); + CV_StealthSet(&cv_follower[n], (foundskin == -1) ? "None" : followers[foundskin].name); + cv_follower[n].value = foundskin; + K_SetFollowerByNum(playernum, foundskin); + return; } @@ -1582,6 +1579,13 @@ static void SendNameAndColor(UINT8 n) cv_skin[n].value = 0; } + cv_follower[n].value = K_FollowerAvailable(cv_follower[n].string); + if (cv_follower[n].value < 0) + { + CV_StealthSet(&cv_follower[n], "None"); + cv_follower[n].value = -1; + } + // Finally write out the complete packet and send it off. WRITESTRINGN(p, cv_playername[n].zstring, MAXPLAYERNAME); WRITEUINT32(p, (UINT32)player->availabilities); @@ -6096,207 +6100,56 @@ static void Name4_OnChange(void) } // sends the follower change for players -static void Follower_OnChange(void) +static void FollowerAny_OnChange(UINT8 pnum) { - char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1]; - INT32 num; - - // there is a slight chance that we will actually use a string instead so... - // let's investigate the string... - strcpy(str, cv_follower[0].string); - strcpy(cpy, cv_follower[0].string); - strlwr(str); - if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright... - { - if (stricmp(cpy, "None") == 0) - { - CV_StealthSet(&cv_follower[0], "-1"); - - if (!Playing()) - return; // don't send anything there. - - SendNameAndColor(0); - return; - } - - num = K_FollowerAvailable(str); - - if (num == -1) // that's an error. - CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str); - - CV_StealthSet(&cv_follower[0], str); - cv_follower[0].value = num; - } - if (!Playing()) return; // don't send anything there. - SendNameAndColor(0); + SendNameAndColor(pnum); +} + +// sends the follower change for players +static void Follower_OnChange(void) +{ + FollowerAny_OnChange(0); } // About the same as Color_OnChange but for followers. static void Followercolor_OnChange(void) { - if (!Playing()) - return; // do whatever you want if you aren't in the game or don't have a follower. - - if (!P_PlayerMoving(consoleplayer)) - { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor(0); - } + FollowerAny_OnChange(0); } // repeat for the 3 other players static void Follower2_OnChange(void) { - char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1]; - INT32 num; - - // there is a slight chance that we will actually use a string instead so... - // let's investigate the string... - strcpy(str, cv_follower[1].string); - strcpy(cpy, cv_follower[1].string); - strlwr(str); - if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright... - { - if (stricmp(cpy, "None") == 0) - { - CV_StealthSet(&cv_follower[1], "-1"); - - if (!Playing()) - return; // don't send anything there. - - SendNameAndColor(1); - return; - } - - num = K_FollowerAvailable(str); - - if (num == -1) // that's an error. - CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str); - - CV_StealthSet(&cv_follower[1], str); - cv_follower[1].value = num; - } - - if (!Playing()) - return; // don't send anything there. - - SendNameAndColor(1); + FollowerAny_OnChange(1); } static void Followercolor2_OnChange(void) { - if (!Playing()) - return; // do whatever you want if you aren't in the game or don't have a follower. - - if (!P_PlayerMoving(g_localplayers[1])) - { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor(1); - } + FollowerAny_OnChange(1); } static void Follower3_OnChange(void) { - char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1]; - INT32 num; - - // there is a slight chance that we will actually use a string instead so... - // let's investigate the string... - strcpy(str, cv_follower[2].string); - strcpy(cpy, cv_follower[2].string); - strlwr(str); - if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright... - { - if (stricmp(cpy, "None") == 0) - { - CV_StealthSet(&cv_follower[2], "-1"); - - if (!Playing()) - return; // don't send anything there. - - SendNameAndColor(2); - return; - } - - num = K_FollowerAvailable(str); - - if (num == -1) // that's an error. - CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str); - - CV_StealthSet(&cv_follower[2], str); - cv_follower[2].value = num; - } - - if (!Playing()) - return; // don't send anything there. - - SendNameAndColor(2); + FollowerAny_OnChange(2); } static void Followercolor3_OnChange(void) { - if (!Playing()) - return; // do whatever you want if you aren't in the game or don't have a follower. - - if (!P_PlayerMoving(g_localplayers[2])) - { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor(2); - } + FollowerAny_OnChange(2); } static void Follower4_OnChange(void) { - char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1]; - INT32 num; - - // there is a slight chance that we will actually use a string instead so... - // let's investigate the string... - strcpy(str, cv_follower[3].string); - strcpy(cpy, cv_follower[3].string); - strlwr(str); - if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright... - { - if (stricmp(cpy, "None") == 0) - { - CV_StealthSet(&cv_follower[3], "-1"); - - if (!Playing()) - return; // don't send anything there. - - SendNameAndColor(3); - return; - } - - num = K_FollowerAvailable(str); - - if (num == -1) // that's an error. - CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str); - - CV_StealthSet(&cv_follower[3], str); - cv_follower[3].value = num; - } - - if (!Playing()) - return; // don't send anything there. - - SendNameAndColor(3); + FollowerAny_OnChange(3); } static void Followercolor4_OnChange(void) { - if (!Playing()) - return; // do whatever you want if you aren't in the game or don't have a follower. - - if (!P_PlayerMoving(g_localplayers[3])) - { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor(3); - } + FollowerAny_OnChange(3); } /** Sends a skin change for the console player, unless that player is moving. Also forces them to spectate if the change is done during gameplay diff --git a/src/deh_soc.c b/src/deh_soc.c index 1d806322e..1455f0641 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3130,7 +3130,7 @@ void readcupheader(MYFILE *f, cupheader_t *cup) void readfollower(MYFILE *f) { char *s; - char *word, *word2, dname[SKINNAMESIZE+1]; + char *word, *word2; char *tmp; char testname[SKINNAMESIZE+1]; @@ -3348,10 +3348,6 @@ void readfollower(MYFILE *f) // set skin name (this is just the follower's name in lowercases): // but before we do, let's... actually check if another follower isn't doing the same shit... - strcpy(testname, followers[numfollowers].name); - - // lower testname for skin checks... - strlwr(testname); res = K_FollowerAvailable(testname); if (res > -1) // yikes, someone else has stolen our name already { @@ -3363,8 +3359,7 @@ void readfollower(MYFILE *f) // in that case, we'll be very lazy and copy numfollowers to the end of our skin name. } - strcpy(followers[numfollowers].skinname, testname); - strcpy(dname, followers[numfollowers].skinname); // display name, just used for printing succesful stuff or errors later down the line. + strcpy(testname, followers[numfollowers].name); // now that the skin name is ready, post process the actual name to turn the underscores into spaces! for (i = 0; followers[numfollowers].name[i]; i++) @@ -3379,14 +3374,14 @@ void readfollower(MYFILE *f) if (followers[numfollowers].mode < FOLLOWERMODE_FLOAT || followers[numfollowers].mode >= FOLLOWERMODE__MAX) { followers[numfollowers].mode = FOLLOWERMODE_FLOAT; - deh_warning("Follower '%s': Value for 'mode' should be between %d and %d.", dname, FOLLOWERMODE_FLOAT, FOLLOWERMODE__MAX-1); + deh_warning("Follower '%s': Value for 'mode' should be between %d and %d.", testname, FOLLOWERMODE_FLOAT, FOLLOWERMODE__MAX-1); } #define FALLBACK(field, field2, threshold, set) \ if ((signed)followers[numfollowers].field < threshold) \ { \ followers[numfollowers].field = set; \ - deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", dname, field2, threshold, set); \ + deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", testname, field2, threshold, set); \ } \ FALLBACK(dist, "DIST", 0, 0); @@ -3411,7 +3406,7 @@ if (!followers[numfollowers].field) \ { \ followers[numfollowers].field = fallbackstate ? fallbackstate : S_INVISIBLE; \ if (!fallbackstate) \ - deh_warning("Follower '%s' is missing state definition for '%s', no idlestate fallback was found", dname, field2); \ + deh_warning("Follower '%s' is missing state definition for '%s', no idlestate fallback was found", testname, field2); \ } \ NOSTATE(idlestate, "IDLESTATE"); @@ -3422,7 +3417,7 @@ if (!followers[numfollowers].field) \ NOSTATE(hitconfirmstate, "HITCONFIRMSTATE"); #undef NOSTATE - CONS_Printf("Added follower '%s'\n", dname); + CONS_Printf("Added follower '%s'\n", testname); if (followers[numfollowers].category < numfollowercategories) followercategories[followers[numfollowers].category].numincategory++; numfollowers++; // add 1 follower diff --git a/src/g_demo.c b/src/g_demo.c index 551477d2e..bc461d84a 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -453,7 +453,7 @@ void G_WriteDemoExtraData(void) if (players[i].followerskin == -1) strncpy(name, "None", 16); else - strncpy(name, followers[players[i].followerskin].skinname, 16); + strncpy(name, followers[players[i].followerskin].name, 16); M_Memcpy(demo_p, name, 16); demo_p += 16; @@ -2093,7 +2093,7 @@ void G_BeginRecording(void) memset(name, 0, 16); if (player->follower) - strncpy(name, followers[player->followerskin].skinname, 16); + strncpy(name, followers[player->followerskin].name, 16); else strncpy(name, "None", 16); // Say we don't have one, then. diff --git a/src/k_follower.c b/src/k_follower.c index b21f56595..636620ec8 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -31,7 +31,7 @@ INT32 K_FollowerAvailable(const char *name) for (i = 0; i < numfollowers; i++) { - if (stricmp(followers[i].skinname, name) == 0) + if (stricmp(followers[i].name, name) == 0) return i; } @@ -57,7 +57,7 @@ boolean K_SetFollowerByName(INT32 playernum, const char *skinname) for (i = 0; i < numfollowers; i++) { // search in the skin list - if (stricmp(followers[i].skinname, skinname) == 0) + if (stricmp(followers[i].name, skinname) == 0) { K_SetFollowerByNum(playernum, i); return true; diff --git a/src/k_follower.h b/src/k_follower.h index e0eddccd1..3c1e2a7d1 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -45,8 +45,7 @@ typedef enum // typedef struct follower_s { - char skinname[SKINNAMESIZE+1]; // Skin Name. This is what to refer to when asking the commands anything. - char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this. + char name[SKINNAMESIZE+1]; // Skin Name. This is what to refer to when asking the commands anything.. char icon[8+1]; // Lump names are only 8 characters. (+1 for \0) UINT8 category; // Category diff --git a/src/k_menufunc.c b/src/k_menufunc.c index f3d482eaa..4c3b6c5c1 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3093,9 +3093,6 @@ static void M_MPConfirmCharacterSelection(void) UINT8 i; INT16 col; - char commandnames[][MAXSTRINGLENGTH] = { "skin ", "skin2 ", "skin3 ", "skin4 "}; - // ^ laziness 100 (we append a space directly so that we don't have to do it later too!!!!) - for (i = 0; i < splitscreen +1; i++) { char cmd[MAXSTRINGLENGTH]; @@ -3106,7 +3103,10 @@ static void M_MPConfirmCharacterSelection(void) CV_StealthSetValue(&cv_playercolor[i], col); // follower - CV_StealthSetValue(&cv_follower[i], setup_player[i].followern); + if (setup_player[i].followern < 0) + CV_StealthSet(&cv_follower[i], "None"); + else + CV_StealthSet(&cv_follower[i], followers[setup_player[i].followern].name); // follower color CV_StealthSetValue(&cv_followercolor[i], setup_player[i].followercolor); @@ -3117,8 +3117,8 @@ static void M_MPConfirmCharacterSelection(void) // This is a hack to make sure we call Skin[x]_OnChange afterwards CV_StealthSetValue(&cv_skin[i], -1); - strcpy(cmd, commandnames[i]); - strcat(cmd, skins[setup_player[i].skin].name); + strcpy(cmd, cv_skin[i].name); + strcat(cmd, va(" %s", skins[setup_player[i].skin].name)); COM_ImmedExecute(cmd); } @@ -3173,7 +3173,7 @@ void M_CharacterSelectTick(void) optionsmenu.profile->color = setup_player[0].color; // save follower - strcpy(optionsmenu.profile->follower, followers[setup_player[0].followern].skinname); + strcpy(optionsmenu.profile->follower, followers[setup_player[0].followern].name); optionsmenu.profile->followercolor = setup_player[0].followercolor; // reset setup_player @@ -3190,7 +3190,10 @@ void M_CharacterSelectTick(void) CV_StealthSet(&cv_skin[i], skins[setup_player[i].skin].name); CV_StealthSetValue(&cv_playercolor[i], setup_player[i].color); - CV_StealthSetValue(&cv_follower[i], setup_player[i].followern); + if (setup_player[i].followern < 0) + CV_StealthSet(&cv_follower[i], "None"); + else + CV_StealthSet(&cv_follower[i], followers[setup_player[i].followern].name); CV_StealthSetValue(&cv_followercolor[i], setup_player[i].followercolor); } From 2304ef28a55f4ba843f47771a30f43f5e5493750 Mon Sep 17 00:00:00 2001 From: SteelT Date: Mon, 7 Nov 2022 14:32:13 -0500 Subject: [PATCH 44/81] Set vsync on screen update or resolution change in software mode Similar to what the OGL code does, fixes vsync not being properly applied on game startup --- src/sdl/i_video.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index a1948f2f1..6bb131777 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -106,10 +106,9 @@ rendermode_t chosenrendermode = render_none; // set by command line arguments boolean highcolor = false; -static void Impl_SetVsync(void); // synchronize page flipping with screen refresh -consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, Impl_SetVsync); +consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL); static consvar_t cv_stretch = CVAR_INIT ("stretch", "Off", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL); static consvar_t cv_alwaysgrabmouse = CVAR_INIT ("alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL); @@ -185,6 +184,18 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen); //static void Impl_SetWindowName(const char *title); static void Impl_SetWindowIcon(void); +static void Impl_SetSoftwareVsync(int vsync) +{ + static int oldvsync = 0; +#if SDL_VERSION_ATLEAST(2,0,18) + if (oldvsync != vsync) + { + SDL_RenderSetVSync(renderer, vsync); + } + oldvsync = vsync; +#endif +} + static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool reposition) { static SDL_bool wasfullscreen = SDL_FALSE; @@ -277,6 +288,7 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool } SDL_PixelFormatEnumToMasks(sw_texture_format, &bpp, &rmask, &gmask, &bmask, &amask); vidSurface = SDL_CreateRGBSurface(0, width, height, bpp, rmask, gmask, bmask, amask); + Impl_SetSoftwareVsync(cv_vidwait.value); } } @@ -1254,6 +1266,7 @@ void I_FinishUpdate(void) SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, &src_rect, NULL); SDL_RenderPresent(renderer); + Impl_SetSoftwareVsync(cv_vidwait.value); } #ifdef HWRENDER else if (rendermode == render_opengl) @@ -1478,15 +1491,6 @@ static SDL_bool Impl_CreateContext(void) int flags = 0; // Use this to set SDL_RENDERER_* flags now if (usesdl2soft) flags |= SDL_RENDERER_SOFTWARE; -#if 0 - // This shit is BROKEN. - // - The version of SDL we're using cannot toggle VSync at runtime. We'll need a new SDL version implemented to have this work properly. - // - cv_vidwait is initialized before config is loaded, so it's forced to default value at runtime, and forced off when switching. The config loading code would need restructured. - // - With both this & frame interpolation on, I_FinishUpdate takes x10 longer. At this point, it is simpler to use a standard FPS cap. - // So you can probably guess why I'm kinda over this, I'm just disabling it. - else if (cv_vidwait.value) - flags |= SDL_RENDERER_PRESENTVSYNC; -#endif // 3 August 2022 // Possibly a Windows 11 issue; the default @@ -2006,11 +2010,3 @@ UINT32 I_GetRefreshRate(void) // trouble querying mode over and over again. return refresh_rate; } - -static void Impl_SetVsync(void) -{ -#if SDL_VERSION_ATLEAST(2,0,18) - if (renderer) - SDL_RenderSetVSync(renderer, cv_vidwait.value); -#endif -} From e086b520551e6365c4f4ae29a0439b0d6563134b Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Nov 2022 20:16:53 +0000 Subject: [PATCH 45/81] Fix the MP character select being completely busted and sending infinite changenameandcolor packets Still has weird inappropriate conditions for changing skin, but gets the feature at least WORKING for now. --- src/d_netcmd.c | 12 ++++++------ src/k_menufunc.c | 17 +++++++---------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9a60a7a0a..247b3e151 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1499,14 +1499,11 @@ static void SendNameAndColor(UINT8 n) if (!cv_followercolor[n].value) CV_StealthSet(&cv_followercolor[n], "Match"); // set it to "Match". I don't care about your stupidity! - // so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game: - if (cv_follower[n].value >= numfollowers || cv_follower[n].value < -1) - CV_StealthSet(&cv_follower[n], "None"); - if (!strcmp(cv_playername[n].string, player_names[playernum]) && cv_playercolor[n].value == player->skincolor - && !strcmp(cv_skin[n].string, skins[player->skin].name) - && cv_follower[n].value == player->followerskin + && !stricmp(cv_skin[n].string, skins[player->skin].name) + && !stricmp(cv_follower[n].string, + (player->followerskin < 0 ? "None" : followers[player->followerskin].name)) && cv_followercolor[n].value == player->followercolor) return; @@ -6060,6 +6057,7 @@ static void Name_OnChange(void) { CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); CV_StealthSet(&cv_playername[0], player_names[consoleplayer]); + return; } else SendNameAndColor(0); @@ -6169,7 +6167,9 @@ static void Skin_OnChange(void) } if (CanChangeSkinWhilePlaying(consoleplayer)) + { SendNameAndColor(0); + } else { CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 4c3b6c5c1..74135465d 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -1583,6 +1583,9 @@ void M_Ticker(void) { INT32 i; + if (!menuactive) + return; + if (menutransition.tics != 0 || menutransition.dest != 0) { noFurtherInput = true; @@ -3095,8 +3098,6 @@ static void M_MPConfirmCharacterSelection(void) for (i = 0; i < splitscreen +1; i++) { - char cmd[MAXSTRINGLENGTH]; - // colour // (convert the number that's saved to a string we can use) col = setup_player[i].color; @@ -3108,18 +3109,14 @@ static void M_MPConfirmCharacterSelection(void) else CV_StealthSet(&cv_follower[i], followers[setup_player[i].followern].name); - // follower color - CV_StealthSetValue(&cv_followercolor[i], setup_player[i].followercolor); - // finally, call the skin[x] console command. // This will call SendNameAndColor which will synch everything we sent here and apply the changes! - // This is a hack to make sure we call Skin[x]_OnChange afterwards - CV_StealthSetValue(&cv_skin[i], -1); + CV_StealthSet(&cv_skin[i], skins[setup_player[i].skin].name); - strcpy(cmd, cv_skin[i].name); - strcat(cmd, va(" %s", skins[setup_player[i].skin].name)); - COM_ImmedExecute(cmd); + // ...actually, let's do this last - Skin_OnChange has some return-early occasions + // follower color + CV_SetValue(&cv_followercolor[i], setup_player[i].followercolor); } M_ClearMenus(true); From 6eda325561e768b20a13c2a50723a2260e940c10 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Nov 2022 20:57:02 +0000 Subject: [PATCH 46/81] More character select quality of life - When selecting follower category, initial follower category is now the category of your last used follower (or None) - More C/Extra button functionality: - Profile selection: Toggle between your last used profile and guest - Follower category: Toggle between category of your last selected follower and None - Follower: Return to category selection and hover over None (flows seamlessly into above option) --- src/k_menufunc.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 74135465d..4d5d401af 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -2066,6 +2066,12 @@ static void M_SetupProfileGridPos(setup_player_t *p) // While we're here, read follower values. p->followern = K_FollowerAvailable(pr->follower); + + if (p->followern < 0 || p->followern >= numfollowers || followers[p->followern].category >= numfollowercategories) + p->followercategory = -1; + else + p->followercategory = followers[p->followern].category; + p->followercolor = pr->followercolor; // Now position the grid for skin @@ -2490,6 +2496,16 @@ static boolean M_HandleCSelectProfile(setup_player_t *p, UINT8 num) S_StartSound(NULL, sfx_s3k63); } + else if (M_MenuExtraPressed(num)) + { + UINT8 yourprofile = min(cv_lastprofile[realnum].value, PR_GetNumProfiles()); + if (p->profilen == yourprofile) + p->profilen = PROFILE_GUEST; + else + p->profilen = yourprofile; + S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s + M_SetMenuDelay(num); + } return false; @@ -2863,7 +2879,10 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num) } else if (M_MenuExtraPressed(num)) { - p->followercategory = -1; + if (p->followercategory >= 0 || p->followern < 0 || p->followern >= numfollowers || followers[p->followern].category >= numfollowercategories) + p->followercategory = -1; + else + p->followercategory = followers[p->followern].category; p->rotate = CSROTATETICS; p->hitlag = true; S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s @@ -2938,6 +2957,15 @@ static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num) S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } + else if (M_MenuExtraPressed(num)) + { + p->mdepth = CSSTEP_FOLLOWERCATEGORY; + p->followercategory = -1; + p->rotate = CSROTATETICS; + p->hitlag = true; + S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s + M_SetMenuDelay(num); + } } static void M_HandleFollowerColorRotate(setup_player_t *p, UINT8 num) From c216cc6988386d31262c569696fd7394a5a0623d Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 7 Nov 2022 20:30:14 -0800 Subject: [PATCH 47/81] Fix buffer overflow when pasting into chat --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 63d093ae1..5d73ecda6 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1251,7 +1251,7 @@ boolean HU_Responder(event_t *ev) if (chatlen+pastelen > HU_MAXMSGLEN) return true; // we can't paste this!! - memmove(&w_chat[c_input + pastelen], &w_chat[c_input], pastelen); + memmove(&w_chat[c_input + pastelen], &w_chat[c_input], (chatlen - c_input) + 1); // +1 for '\0' memcpy(&w_chat[c_input], paste, pastelen); // copy all of that. c_input += pastelen; return true; From 492c068cdddafb3d22c1ad1c3959bf757b862eed Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 12 Nov 2022 09:48:59 -0500 Subject: [PATCH 48/81] Try some things to reduce rng biases - Don't clamp all RNG calls to [0, FRACUNIT-1]. Only does this for P_RandomFixed now. - Use rejection sampling for any clamped RNG calls, to remove modulo bias. - Because of this, P_RandomRange ranges >= FRACUNIT are no longer undefined behavior. - Added P_Random/M_Random to grab RNG output directly. - Shuffle M_Random's RNG as well, since OS rand can be [0,INT32_MAX] instead of [0,UINT32_MAX]. --- src/lua_baselib.c | 9 +--- src/m_random.c | 126 +++++++++++++++++++++++++++++++++++----------- src/m_random.h | 16 +++--- src/st_stuff.c | 4 +- 4 files changed, 110 insertions(+), 45 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index d73e7b073..fcdf86624 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -402,10 +402,7 @@ static int lib_pRandomByte(lua_State *L) static int lib_pRandomKey(lua_State *L) { INT32 a = (INT32)luaL_checkinteger(L, 1); - NOHUD - if (a > 65536) - LUA_UsageWarning(L, "P_RandomKey: range > 65536 is undefined behavior"); lua_pushinteger(L, P_RandomKey(PR_UNDEFINED, a)); demo_writerng = 2; return 1; @@ -415,15 +412,13 @@ static int lib_pRandomRange(lua_State *L) { INT32 a = (INT32)luaL_checkinteger(L, 1); INT32 b = (INT32)luaL_checkinteger(L, 2); - NOHUD - if (b < a) { + if (b < a) + { INT32 c = a; a = b; b = c; } - if ((b-a+1) > 65536) - LUA_UsageWarning(L, "P_RandomRange: range > 65536 is undefined behavior"); lua_pushinteger(L, P_RandomRange(PR_UNDEFINED, a, b)); demo_writerng = 2; return 1; diff --git a/src/m_random.c b/src/m_random.c index 166c6bf2e..6d8beeaa3 100644 --- a/src/m_random.c +++ b/src/m_random.c @@ -25,20 +25,56 @@ // RNG functions (not synched) // --------------------------- +ATTRINLINE static UINT32 FUNCINLINE __external_prng__(void) +{ + UINT32 rnd = rand(); + +#if RAND_MAX < 65535 + // Compensate for especially bad randomness. + UINT32 rndv = (rand() & 1) << 15; + rnd ^= rndv; +#endif + + // Shuffle like we do for our own PRNG, since RAND_MAX + // tends to be [0, INT32_MAX] instead of [0, UINT32_MAX]. + rnd ^= rnd >> 13; + rnd ^= rnd >> 11; + rnd ^= rnd << 21; + return (rnd * 36548569); +} + +ATTRINLINE static UINT32 FUNCINLINE __external_prng_bound__(UINT32 bound) +{ + // Do rejection sampling to remove the modulo bias. + UINT32 threshold = -bound % bound; + for (;;) + { + UINT32 r = __external_prng__(); + if (r >= threshold) + { + return r % bound; + } + } +} + +/** Provides a random 32-bit number. Distribution is uniform. + * As with all M_Random functions, not synched in netgames. + * + * \return A random 32-bit number. + */ +UINT32 M_Random(void) +{ + return __external_prng__(); +} + /** Provides a random fixed point number. Distribution is uniform. * As with all M_Random functions, not synched in netgames. * - * \return A random fixed point number from [0,1). + * \return A random fixed point number from [0,1]. */ fixed_t M_RandomFixed(void) { -#if RAND_MAX < 65535 - // Compensate for insufficient randomness. - fixed_t rndv = (rand()&1)<<15; - return rand()^rndv; -#else - return (rand() & 0xFFFF); -#endif + return (fixed_t)(__external_prng_bound__(FRACUNIT)); } /** Provides a random byte. Distribution is uniform. @@ -48,7 +84,7 @@ fixed_t M_RandomFixed(void) */ UINT8 M_RandomByte(void) { - return (rand() & 0xFF); + return (UINT8)(__external_prng_bound__(UINT8_MAX)); } /** Provides a random integer for picking random elements from an array. @@ -58,9 +94,9 @@ UINT8 M_RandomByte(void) * \param a Number of items in array. * \return A random integer from [0,a). */ -INT32 M_RandomKey(INT32 a) +UINT32 M_RandomKey(UINT32 a) { - return (INT32)((rand()/((unsigned)RAND_MAX+1.0f))*a); + return __external_prng_bound__(a); } /** Provides a random integer in a given range. @@ -73,7 +109,7 @@ INT32 M_RandomKey(INT32 a) */ INT32 M_RandomRange(INT32 a, INT32 b) { - return (INT32)((rand()/((unsigned)RAND_MAX+1.0f))*(b-a+1))+a; + return (INT32)(__external_prng_bound__((b - a) + 1)) + a; } @@ -92,23 +128,56 @@ typedef struct static rng_t rng; // The entire PRNG state -/** Provides a random fixed point number. +/** Provides a random 32 bit integer. * This is a variant of an xorshift PRNG; state fits in a 32 bit integer structure. * - * \return A random fixed point number from [0,1). + * \return A random, uniformly distributed number from [0,UINT32_MAX]. */ -ATTRINLINE static fixed_t FUNCINLINE __internal_prng__(pr_class_t pr_class) +ATTRINLINE static UINT32 FUNCINLINE __internal_prng__(pr_class_t pr_class) { rng.seed[pr_class] ^= rng.seed[pr_class] >> 13; rng.seed[pr_class] ^= rng.seed[pr_class] >> 11; rng.seed[pr_class] ^= rng.seed[pr_class] << 21; - return ( (rng.seed[pr_class] * 36548569) >> 4) & (FRACUNIT-1); + return (rng.seed[pr_class] * 36548569); +} + +/** Provides a random number within a specified range. + * + * \return A random, uniformly distributed number from [0,bound]. + */ +ATTRINLINE static UINT32 FUNCINLINE __internal_prng_bound__(pr_class_t pr_class, UINT32 bound) +{ + // Do rejection sampling to remove the modulo bias. + UINT32 threshold = -bound % bound; + for (;;) + { + UINT32 r = __internal_prng__(pr_class); + if (r >= threshold) + { + return r % bound; + } + } } /** Provides a random fixed point number. Distribution is uniform. * Literally a wrapper for the internal PRNG function. * - * \return A random fixed point number from [0,1). + * \return A random fixed point number from [0,UINT32_MAX]. + */ +#ifndef DEBUGRANDOM +UINT32 P_Random(pr_class_t pr_class) +{ +#else +UINT32 P_RandomD(const char *rfile, INT32 rline, pr_class_t pr_class) +{ + CONS_Printf("P_Random(%u) at: %sp %d\n", pr_class, rfile, rline); +#endif + return __internal_prng__(pr_class); +} + +/** Provides a random fixed point number. Distribution is uniform. + * + * \return A random fixed point number from [0,1]. */ #ifndef DEBUGRANDOM fixed_t P_RandomFixed(pr_class_t pr_class) @@ -118,14 +187,14 @@ fixed_t P_RandomFixedD(const char *rfile, INT32 rline, pr_class_t pr_class) { CONS_Printf("P_RandomFixed(%u) at: %sp %d\n", pr_class, rfile, rline); #endif - return __internal_prng__(pr_class); + return (fixed_t)(__internal_prng_bound__(pr_class, FRACUNIT)); } /** Provides a random byte. Distribution is uniform. * If you're curious, (&0xFF00) >> 8 gives the same result * as a fixed point multiplication by 256. * - * \return Random integer from [0, 255]. + * \return Random integer from [0,255]. * \sa __internal_prng__ */ #ifndef DEBUGRANDOM @@ -136,7 +205,7 @@ UINT8 P_RandomByteD(const char *rfile, INT32 rline, pr_class_t pr_class) { CONS_Printf("P_RandomByte(%u) at: %sp %d\n", pr_class, rfile, rline); #endif - return (UINT8)((__internal_prng__(pr_class) & 0xFF00) >> 8); + return (UINT8)(__internal_prng_bound__(pr_class, UINT8_MAX)); } /** Provides a random integer for picking random elements from an array. @@ -144,23 +213,22 @@ UINT8 P_RandomByteD(const char *rfile, INT32 rline, pr_class_t pr_class) * NOTE: Maximum range is 65536. * * \param a Number of items in array. - * \return A random integer from [0,a). + * \return A random integer from [0,a]. * \sa __internal_prng__ */ #ifndef DEBUGRANDOM -INT32 P_RandomKey(pr_class_t pr_class, INT32 a) +UINT32 P_RandomKey(pr_class_t pr_class, UINT32 a) { #else -INT32 P_RandomKeyD(const char *rfile, INT32 rline, pr_class_t pr_class, INT32 a) +UINT32 P_RandomKeyD(const char *rfile, INT32 rline, pr_class_t pr_class, UINT32 a) { CONS_Printf("P_RandomKey(%u) at: %sp %d\n", pr_class, rfile, rline); #endif - return (INT32)(((INT64)__internal_prng__(pr_class) * a) >> FRACBITS); + return __internal_prng_bound__(pr_class, a); } /** Provides a random integer in a given range. * Distribution is uniform. - * NOTE: Maximum range is 65536. * * \param a Lower bound. * \param b Upper bound. @@ -175,7 +243,7 @@ INT32 P_RandomRangeD(const char *rfile, INT32 rline, pr_class_t pr_class, INT32 { CONS_Printf("P_RandomRange(%u) at: %sp %d\n", pr_class, rfile, rline); #endif - return (INT32)(((INT64)__internal_prng__(pr_class) * (b - a + 1)) >> FRACBITS) + a; + return (INT32)(__internal_prng_bound__(pr_class, (b - a) + 1)) + a; } @@ -187,13 +255,13 @@ INT32 P_RandomRangeD(const char *rfile, INT32 rline, pr_class_t pr_class, INT32 /** Peeks to see what the next result from the PRNG will be. * Used for debugging. * - * \return A 'random' fixed point number from [0,1). + * \return A 'random' number from [0,UINT32_MAX] * \sa __internal_prng__ */ -fixed_t P_RandomPeek(pr_class_t pr_class) +UINT32 P_RandomPeek(pr_class_t pr_class) { UINT32 r = rng.seed[pr_class]; - fixed_t ret = __internal_prng__(pr_class); + UINT32 ret = __internal_prng__(pr_class); rng.seed[pr_class] = r; return ret; } diff --git a/src/m_random.h b/src/m_random.h index c08e32993..5bb5d4435 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -69,37 +69,41 @@ typedef enum // P_Random functions pulls random bytes from a PRNG that is network synced. // RNG functions +UINT32 M_Random(void); fixed_t M_RandomFixed(void); UINT8 M_RandomByte(void); -INT32 M_RandomKey(INT32 a); +UINT32 M_RandomKey(UINT32 a); INT32 M_RandomRange(INT32 a, INT32 b); // PRNG functions #ifdef DEBUGRANDOM +#define P_Random(c) P_RandomD(__FILE__, __LINE__, c) #define P_RandomFixed(c) P_RandomFixedD(__FILE__, __LINE__, c) #define P_RandomByte(c) P_RandomByteD(__FILE__, __LINE__, c) #define P_RandomKey(c, d) P_RandomKeyD(__FILE__, __LINE__, c, d) #define P_RandomRange(c, d, e) P_RandomRangeD(__FILE__, __LINE__, c, d, e) +UINT32 P_RandomD(const char *rfile, INT32 rline, pr_class_t pr_class); fixed_t P_RandomFixedD(const char *rfile, INT32 rline, pr_class_t pr_class); UINT8 P_RandomByteD(const char *rfile, INT32 rline, pr_class_t pr_class); -INT32 P_RandomKeyD(const char *rfile, INT32 rline, pr_class_t pr_class, INT32 a); +UINT32 P_RandomKeyD(const char *rfile, INT32 rline, pr_class_t pr_class, UINT32 a); INT32 P_RandomRangeD(const char *rfile, INT32 rline, pr_class_t pr_class, INT32 a, INT32 b); #else +UINT32 P_Random(pr_class_t pr_class); fixed_t P_RandomFixed(pr_class_t pr_class); UINT8 P_RandomByte(pr_class_t pr_class); -INT32 P_RandomKey(pr_class_t pr_class, INT32 a); +UINT32 P_RandomKey(pr_class_t pr_class, UINT32 a); INT32 P_RandomRange(pr_class_t pr_class, INT32 a, INT32 b); #endif // Macros for other functions -#define M_SignedRandom() ((INT32)M_RandomByte() - 128) // [-128, 127] signed byte, originally a -#define P_SignedRandom(pr) ((INT32)P_RandomByte(pr) - 128) // function of its own, moved to a macro +#define M_SignedRandom() ((INT32)M_RandomByte() + INT8_MIN) // [-128, 127] signed byte, originally a +#define P_SignedRandom(pr) ((INT32)P_RandomByte(pr) + INT8_MIN) // function of its own, moved to a macro #define M_RandomChance(p) (M_RandomFixed() < p) // given fixed point probability, p, between 0 (0%) #define P_RandomChance(pr, p) (P_RandomFixed(pr) < p) // and FRACUNIT (100%), returns true p% of the time // Debugging -fixed_t P_RandomPeek(pr_class_t pr_class); +UINT32 P_RandomPeek(pr_class_t pr_class); // Working with the seed for PRNG #ifdef DEBUGRANDOM diff --git a/src/st_stuff.c b/src/st_stuff.c index 676c3992a..5c2def212 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -411,12 +411,10 @@ static void ST_drawDebugInfo(void) // Figure out some other way to display all of the RNG classes. fixed_t peekres = P_RandomPeek(PR_UNDEFINED); - peekres *= 10000; // Change from fixed point - peekres >>= FRACBITS; // to displayable decimal V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Init: %08x", P_GetInitSeed(PR_UNDEFINED))); V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Seed: %08x", P_GetRandSeed(PR_UNDEFINED))); - V_DrawRightAlignedString(320, height, V_MONOSPACE, va("== : .%04d", peekres)); + V_DrawRightAlignedString(320, height, V_MONOSPACE, va("== : %08x", peekres)); height -= 32; } From f87366de04ebcc69bb9164a62fbaedae302b442a Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 16 Nov 2022 20:03:36 +0000 Subject: [PATCH 49/81] Make menu-created button prompts consistent with d_clisrv.c button prompts --- src/k_menufunc.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 4d5d401af..3a2706b9d 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -357,7 +357,7 @@ static void M_EraseDataResponse(INT32 ch) void M_EraseData(INT32 choice) { - const char *eschoice, *esstr = M_GetText("Are you sure you want to erase\n%s?\n\n(Press A to confirm)\n"); + const char *eschoice, *esstr = M_GetText("Are you sure you want to erase\n%s?\n\nPress (A) to confirm or (B) to cancel\n"); optionsmenu.erasecontext = (UINT8)choice; @@ -1517,7 +1517,7 @@ static void M_HandleMenuInput(void) { if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && majormods) { - M_StartMessage(M_GetText("This cannot be done with complex addons\nor in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("This cannot be done with complex addons\nor in a cheated game.\n\nPress (B)\n"), NULL, MM_NOTHING); return; } } @@ -2038,7 +2038,7 @@ void M_QuitSRB2(INT32 choice) // We pick index 0 which is language sensitive, or one at random, // between 1 and maximum number. (void)choice; - M_StartMessage("Are you sure you want to quit playing?\n\n(Press A to exit)", FUNCPTRCAST(M_QuitResponse), MM_YESNO); + M_StartMessage("Are you sure you want to quit playing?\n\nPress (A) to confirm or (B) to cancel", FUNCPTRCAST(M_QuitResponse), MM_YESNO); } // ========= @@ -4942,7 +4942,7 @@ void M_HandleProfileSelect(INT32 ch) #if 0 if (optionsmenu.profilen == 0) { - M_StartMessage(M_GetText("Are you sure you wish\nto use the Guest Profile?\nThis profile cannot be customised.\nIt is recommended to create\na new Profile instead.\n\n(Press A to confirm)"), FUNCPTRCAST(M_FirstPickProfile), MM_YESNO); + M_StartMessage(M_GetText("Are you sure you wish\nto use the Guest Profile?\nThis profile cannot be customised.\nIt is recommended to create\na new Profile instead.\n\nPress (A) to confirm or (B) to cancel"), FUNCPTRCAST(M_FirstPickProfile), MM_YESNO); return; } #endif @@ -5084,7 +5084,7 @@ void M_ConfirmProfile(INT32 choice) } else { - M_StartMessage(M_GetText("Are you sure you wish to\nselect this profile?\n\n(Press A to confirm)"), FUNCPTRCAST(M_FirstPickProfile), MM_YESNO); + M_StartMessage(M_GetText("Are you sure you wish to\nselect this profile?\n\nPress (A) to confirm or (B) to cancel"), FUNCPTRCAST(M_FirstPickProfile), MM_YESNO); M_SetMenuDelay(pid); } } @@ -5290,7 +5290,7 @@ void M_ProfileControlsConfirm(INT32 choice) { (void)choice; - //M_StartMessage(M_GetText("Exiting will save the control changes\nfor this Profile.\nIs this okay?\n\n(Press A to confirm)"), FUNCPTRCAST(M_ProfileControlSaveResponse), MM_YESNO); + //M_StartMessage(M_GetText("Exiting will save the control changes\nfor this Profile.\nIs this okay?\n\nPress (A) to confirm or (B) to cancel"), FUNCPTRCAST(M_ProfileControlSaveResponse), MM_YESNO); // TODO: Add a graphic for controls saving, instead of obnoxious prompt. M_ProfileControlSaveResponse(MA_YES); @@ -5667,7 +5667,7 @@ void M_CheckProfileData(INT32 choice) if (np < 2) { S_StartSound(NULL, sfx_s3k7b); - M_StartMessage("There are no custom profiles.\n\n(Press any button)", NULL, MM_NOTHING); + M_StartMessage("There are no custom profiles.\n\nPress (B)", NULL, MM_NOTHING); return; } @@ -5731,9 +5731,9 @@ void M_HandleProfileErase(INT32 choice) else if (M_MenuConfirmPressed(pid)) { if (optionsmenu.eraseprofilen == cv_currprofile.value) - M_StartMessage("Your ""\x85""current profile""\x80"" will be erased.\nAre you sure you want to proceed?\nDeleting this profile will also\nreturn you to the title screen.\n\n(Press A to confirm)", FUNCPTRCAST(M_EraseProfileResponse), MM_YESNO); + M_StartMessage("Your ""\x85""current profile""\x80"" will be erased.\nAre you sure you want to proceed?\nDeleting this profile will also\nreturn you to the title screen.\n\nPress (A) to confirm or (B) to cancel", FUNCPTRCAST(M_EraseProfileResponse), MM_YESNO); else - M_StartMessage("This profile will be erased.\nAre you sure you want to proceed?\n\n(Press A to confirm)", FUNCPTRCAST(M_EraseProfileResponse), MM_YESNO); + M_StartMessage("This profile will be erased.\nAre you sure you want to proceed?\n\nPress (A) to confirm or (B) to cancel", FUNCPTRCAST(M_EraseProfileResponse), MM_YESNO); M_SetMenuDelay(pid); } @@ -5995,7 +5995,7 @@ void M_ConfirmEnterGame(INT32 choice) (void)choice; if (!cv_allowteamchange.value) { - M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\n\nPress (B)\n"), NULL, MM_NOTHING); return; } M_QuitPauseMenu(-1); @@ -6027,7 +6027,7 @@ void M_EndGame(INT32 choice) if (!Playing()) return; - M_StartMessage(M_GetText("Are you sure you want to return\nto the title screen?\n(Press A to confirm)\n"), FUNCPTRCAST(M_ExitGameResponse), MM_YESNO); + M_StartMessage(M_GetText("Are you sure you want to return\nto the title screen?\nPress (A) to confirm or (B) to cancel\n"), FUNCPTRCAST(M_ExitGameResponse), MM_YESNO); } @@ -6209,7 +6209,7 @@ void M_ReplayHut(INT32 choice) } if (!preparefilemenu(false, true)) { - M_StartMessage("No replays found.\n\n(Press a key)\n", NULL, MM_NOTHING); + M_StartMessage("No replays found.\n\nPress (B)\n", NULL, MM_NOTHING); return; } else if (!demo.inreplayhut) @@ -6285,7 +6285,7 @@ void M_HandleReplayHutList(INT32 choice) 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); + M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\nPress (B)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); menupath[menupathindex[++menudepthleft]] = 0; if (!preparefilemenu(true, true)) @@ -6304,7 +6304,7 @@ void M_HandleReplayHutList(INT32 choice) 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); + M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\nPress (B)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); menupath[menupathindex[menudepthleft]] = 0; } break; @@ -6431,7 +6431,7 @@ void M_Addons(INT32 choice) if (!preparefilemenu(false, false)) { - M_StartMessage(va("No files/folders found.\n\n%s\n\n(Press a key)\n", LOCATIONSTRING1),NULL,MM_NOTHING); + M_StartMessage(va("No files/folders found.\n\n%s\n\nPress (B)\n", LOCATIONSTRING1),NULL,MM_NOTHING); return; } else @@ -6464,7 +6464,7 @@ char *M_AddonsHeaderPath(void) #define UNEXIST S_StartSound(NULL, sfx_s26d);\ M_SetupNextMenu(MISC_AddonsDef.prevMenu, false);\ - M_StartMessage(va("\x82%s\x80\nThis folder no longer exists!\nAborting to main menu.\n\n(Press a key)\n", M_AddonsHeaderPath()),NULL,MM_NOTHING) + M_StartMessage(va("\x82%s\x80\nThis folder no longer exists!\nAborting to main menu.\n\nPress (B)\n", M_AddonsHeaderPath()),NULL,MM_NOTHING) #define CLEARNAME Z_Free(refreshdirname);\ refreshdirname = NULL @@ -6508,19 +6508,19 @@ void M_AddonsRefresh(void) { S_StartSound(NULL, sfx_s26d); if (refreshdirmenu & REFRESHDIR_MAX) - message = va("%c%s\x80\nMaximum number of addons reached.\nA file could not be loaded.\nIf you wish to play with this addon, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + message = va("%c%s\x80\nMaximum number of addons reached.\nA file could not be loaded.\nIf you wish to play with this addon, restart the game to clear existing ones.\n\nPress (B)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); else - message = va("%c%s\x80\nA file was not loaded.\nCheck the console log for more info.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + message = va("%c%s\x80\nA file was not loaded.\nCheck the console log for more info.\n\nPress (B)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); } else if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR)) { S_StartSound(NULL, sfx_s224); - message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more info.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")); + message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more info.\n\nPress (B)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")); } else if (majormods && !prevmajormods) { S_StartSound(NULL, sfx_s221); - message = va("%c%s\x80\nYou've loaded a gameplay-modifying addon.\n\nRecord Attack has been disabled, but you\ncan still play alone in local Multiplayer.\n\nIf you wish to play Record Attack mode, restart the game to disable loaded addons.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + message = va("%c%s\x80\nYou've loaded a gameplay-modifying addon.\n\nRecord Attack has been disabled, but you\ncan still play alone in local Multiplayer.\n\nIf you wish to play Record Attack mode, restart the game to disable loaded addons.\n\nPress (B)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); prevmajormods = majormods; } @@ -6639,7 +6639,7 @@ void M_HandleAddons(INT32 choice) 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); + M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\nPress (B)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); menupath[menupathindex[++menudepthleft]] = 0; if (!preparefilemenu(true, false)) @@ -6658,7 +6658,7 @@ void M_HandleAddons(INT32 choice) 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); + M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\nPress (B)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); menupath[menupathindex[menudepthleft]] = 0; } break; @@ -6674,11 +6674,11 @@ void M_HandleAddons(INT32 choice) break; case EXT_TXT: - M_StartMessage(va("%c%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\n(Press A to confirm)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),FUNCPTRCAST(M_AddonExec),MM_YESNO); + M_StartMessage(va("%c%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\nPress (A) to confirm or (B) to cancel\n\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),FUNCPTRCAST(M_AddonExec),MM_YESNO); break; case EXT_CFG: - M_StartMessage(va("%c%s\x80\nThis file may modify your settings.\nAttempt to run anyways? \n\n(Press A to confirm)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),FUNCPTRCAST(M_AddonExec),MM_YESNO); + M_StartMessage(va("%c%s\x80\nThis file may modify your settings.\nAttempt to run anyways? \n\nPress (A) to confirm or (B) to cancel\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),FUNCPTRCAST(M_AddonExec),MM_YESNO); break; case EXT_LUA: From 1242e9256e27ec1d578a8d64a7bd841722769b31 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 17 Nov 2022 16:37:09 +0000 Subject: [PATCH 50/81] Clear menus on returning to title screen --- src/d_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_main.c b/src/d_main.c index 947350a08..78741c437 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -993,6 +993,7 @@ void D_StartTitle(void) memset(deviceResponding, false, sizeof (deviceResponding)); F_StartTitleScreen(); + M_ClearMenus(false); // Reset the palette if (rendermode != render_none) From 0c8c3df6a334a9bf266a2f2cb396dc48dcf5f303 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 17 Nov 2022 16:42:05 +0000 Subject: [PATCH 51/81] Fix menus sometimes getting stuck closed The problem here is that the menuactive check I added in the followers branch prevented noFurtherInput from being unset. It now can no longer be set while the menu is closed. --- src/k_menufunc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 3a2706b9d..0463c261a 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -1584,7 +1584,10 @@ void M_Ticker(void) INT32 i; if (!menuactive) + { + noFurtherInput = false; return; + } if (menutransition.tics != 0 || menutransition.dest != 0) { From 962393f7b9bf628f1dcc2516adbe9c4ace47a93e Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 17 Nov 2022 16:45:07 +0000 Subject: [PATCH 52/81] Restart Map/Try Again pause menu entry Closer to parity with pre-newmenus behaviour. - Clinical term for server admins, colloquial for SP contexts (GP/modeattacking) - Won't show up in GP if you're out of lives - Also fixes lives going negative in K_PlayerLoseLife --- src/k_grandprix.c | 2 +- src/k_menu.h | 4 ++++ src/k_menudef.c | 6 +++++ src/k_menudraw.c | 20 ++++++++++++----- src/k_menufunc.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 497909dc8..6149434c7 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -676,7 +676,7 @@ void K_PlayerLoseLife(player_t *player) return; } - if (player->spectator || player->exiting || player->bot || (player->pflags & PF_LOSTLIFE)) + if (player->spectator || player->exiting || player->bot || player->lives <= 0 || (player->pflags & PF_LOSTLIFE)) { return; } diff --git a/src/k_menu.h b/src/k_menu.h index c64ff4d2d..588542002 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -410,6 +410,8 @@ typedef enum { mpause_addons = 0, mpause_switchmap, + mpause_restartmap, + mpause_tryagain, #ifdef HAVE_DISCORDRPC mpause_discordrequests, #endif @@ -978,6 +980,8 @@ extern consvar_t cv_dummymenuplayer; extern consvar_t cv_dummyspectator; // Bunch of funny functions for the pause menu...~ +void M_RestartMap(INT32 choice); // Restart level (MP) +void M_TryAgain(INT32 choice); // Try again (SP) void M_ConfirmSpectate(INT32 choice); // Spectate confirm when you're alone void M_ConfirmEnterGame(INT32 choice); // Enter game confirm when you're alone void M_ConfirmSpectateChange(INT32 choice); // Splitscreen spectate/play menu func diff --git a/src/k_menudef.c b/src/k_menudef.c index 66be81efb..4d278eeab 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -1594,6 +1594,12 @@ menuitem_t PAUSE_Main[] = {IT_STRING | IT_SUBMENU, "CHANGE MAP", "M_ICOMAP", NULL, {.submenu = &PAUSE_GamemodesDef}, 0, 0}, + {IT_STRING | IT_CALL, "RESTART MAP", "M_ICORE", + NULL, {.routine = M_RestartMap}, 0, 0}, + + {IT_STRING | IT_CALL, "TRY AGAIN", "M_ICORE", + NULL, {.routine = M_TryAgain}, 0, 0}, + #ifdef HAVE_DISCORDRPC {IT_STRING | IT_CALL, "DISCORD REQUESTS", "M_ICODIS", NULL, {NULL}, 0, 0}, diff --git a/src/k_menudraw.c b/src/k_menudraw.c index d757ea799..cfd52a459 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -3659,19 +3659,29 @@ void M_DrawPause(void) { case IT_STRING: { - - char iconame[9]; // 8 chars + \0 patch_t *pp; if (i == itemOn) { - strcpy(iconame, currentMenu->menuitems[i].tooltip); - iconame[7] = '2'; // Yes this is a stupid hack. Replace the last character with a 2 when we're selecting this graphic. + if (i == mpause_restartmap || i == mpause_tryagain) + { + pp = W_CachePatchName( + va("M_ICOR2%c", ('A'+(pausemenu.ticker & 1))), + PU_CACHE); + } + else + { + char iconame[9]; // 8 chars + \0 + strcpy(iconame, currentMenu->menuitems[i].tooltip); + iconame[7] = '2'; // Yes this is a stupid hack. Replace the last character with a 2 when we're selecting this graphic. - pp = W_CachePatchName(iconame, PU_CACHE); + pp = W_CachePatchName(iconame, PU_CACHE); + } } else + { pp = W_CachePatchName(currentMenu->menuitems[i].tooltip, PU_CACHE); + } // 294 - 261 = 33 // We need to move 33 px in 50 tics which means we move 33/50 = 0.66 px every tic = 2/3 of the offset. diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 0463c261a..d05eb20cc 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -5870,6 +5870,8 @@ struct pausemenu_s pausemenu; // Pause menu! void M_OpenPauseMenu(void) { + INT32 i = 0; + currentMenu = &PAUSE_MainDef; // Ready the variables @@ -5886,6 +5888,8 @@ void M_OpenPauseMenu(void) PAUSE_Main[mpause_addons].status = IT_DISABLED; PAUSE_Main[mpause_switchmap].status = IT_DISABLED; + PAUSE_Main[mpause_restartmap].status = IT_DISABLED; + PAUSE_Main[mpause_tryagain].status = IT_DISABLED; #ifdef HAVE_DISCORDRPC PAUSE_Main[mpause_discordrequests].status = IT_DISABLED; #endif @@ -5905,9 +5909,29 @@ void M_OpenPauseMenu(void) if (server || IsPlayerAdmin(consoleplayer)) { PAUSE_Main[mpause_switchmap].status = IT_STRING | IT_SUBMENU; + PAUSE_Main[mpause_restartmap].status = IT_STRING | IT_CALL; PAUSE_Main[mpause_addons].status = IT_STRING | IT_CALL; } } + else if (!netgame && !demo.playback) + { + boolean retryallowed = (modeattacking != ATTACKING_NONE); + if (G_GametypeUsesLives()) + { + for (i = 0; i <= splitscreen; i++) + { + if (players[g_localplayers[i]].lives <= 1) + continue; + retryallowed = true; + break; + } + } + + if (retryallowed) + { + PAUSE_Main[mpause_tryagain].status = IT_STRING | IT_CALL; + } + } if (G_GametypeHasSpectators()) { @@ -5936,6 +5960,7 @@ void M_QuitPauseMenu(INT32 choice) void M_PauseTick(void) { pausemenu.offset /= 2; + pausemenu.ticker++; if (pausemenu.closing) { @@ -5984,6 +6009,37 @@ boolean M_PauseInputs(INT32 ch) return false; } +// Restart map +void M_RestartMap(INT32 choice) +{ + (void)choice; + M_ClearMenus(false); + COM_ImmedExecute("restartlevel"); +} + +// Try again +void M_TryAgain(INT32 choice) +{ + (void)choice; + if (demo.playback) + return; + + if (netgame || !Playing()) // Should never happen! + return; + + M_ClearMenus(false); + + if (modeattacking != ATTACKING_NONE) + { + G_CheckDemoStatus(); // Cancel recording + M_StartTimeAttack(-1); + } + else + { + G_SetRetryFlag(); + } +} + // Pause spectate / join functions void M_ConfirmSpectate(INT32 choice) { From 372854f8d3aa27518350f4ce06374605ea2ee7d5 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 17 Nov 2022 17:28:18 +0000 Subject: [PATCH 53/81] Do SOME attempt to add quality of life changes to the admin Change Map flow, rather than just bypassing it entirely. - Pre-select the current gametype when showing what gamemodes are available. - Pre-select the current map's cup when opening up the cup view. --- src/k_menufunc.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index d05eb20cc..73eeb4aef 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3430,7 +3430,7 @@ static void M_LevelListFromGametype(INT16 gt) if (levellist.newgametype == GT_RACE) { cupheader_t *cup = kartcupheaders; - UINT8 highestid = 0; + UINT8 highestid = 0, count = 0; // Make sure there's valid cups before going to this menu. if (cup == NULL) @@ -3439,7 +3439,16 @@ static void M_LevelListFromGametype(INT16 gt) while (cup) { if (cup->unlockrequired == -1 || unlockables[cup->unlockrequired].unlocked) + { highestid = cup->id; + if (Playing() && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == cup) + { + cupgrid.x = count % CUPMENU_COLUMNS; + cupgrid.y = (count / CUPMENU_COLUMNS) % CUPMENU_ROWS; + cupgrid.pageno = count / (CUPMENU_COLUMNS * CUPMENU_ROWS); + } + count++; + } cup = cup->next; } @@ -5909,6 +5918,13 @@ void M_OpenPauseMenu(void) if (server || IsPlayerAdmin(consoleplayer)) { PAUSE_Main[mpause_switchmap].status = IT_STRING | IT_SUBMENU; + for (i = 0; i < PAUSE_GamemodesDef.numitems; i++) + { + if (PAUSE_GamemodesMenu[i].mvar2 != gametype) + continue; + PAUSE_GamemodesDef.lastOn = i; + break; + } PAUSE_Main[mpause_restartmap].status = IT_STRING | IT_CALL; PAUSE_Main[mpause_addons].status = IT_STRING | IT_CALL; } From f01bb3e793fadc55ce441c2748dd5b4688ce2755 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 17 Nov 2022 18:30:55 +0000 Subject: [PATCH 54/81] Make the second page of cups accessible by up/down input at the limit, rather than left/right input --- src/k_menufunc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 73eeb4aef..7c06c3ecd 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3528,12 +3528,7 @@ void M_CupSelectHandler(INT32 choice) { cupgrid.x++; if (cupgrid.x >= CUPMENU_COLUMNS) - { cupgrid.x = 0; - cupgrid.pageno++; - if (cupgrid.pageno >= cupgrid.numpages) - cupgrid.pageno = 0; - } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -3541,12 +3536,7 @@ void M_CupSelectHandler(INT32 choice) { cupgrid.x--; if (cupgrid.x < 0) - { cupgrid.x = CUPMENU_COLUMNS-1; - cupgrid.pageno--; - if (cupgrid.pageno < 0) - cupgrid.pageno = cupgrid.numpages-1; - } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -3555,7 +3545,12 @@ void M_CupSelectHandler(INT32 choice) { cupgrid.y++; if (cupgrid.y >= CUPMENU_ROWS) + { cupgrid.y = 0; + cupgrid.pageno--; + if (cupgrid.pageno < 0) + cupgrid.pageno = cupgrid.numpages-1; + } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -3563,7 +3558,12 @@ void M_CupSelectHandler(INT32 choice) { cupgrid.y--; if (cupgrid.y < 0) + { cupgrid.y = CUPMENU_ROWS-1; + cupgrid.pageno++; + if (cupgrid.pageno >= cupgrid.numpages) + cupgrid.pageno = 0; + } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } From 0233c263864c311f188085ee01c1d08a087f93ed Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 6 Nov 2022 13:00:09 -0500 Subject: [PATCH 55/81] Chengi's new position numbers --- src/d_player.h | 2 +- src/doomdef.h | 13 +++ src/info.c | 16 ++- src/k_hud.c | 270 +++++++++++++++++++++++++++---------------------- src/k_kart.c | 4 +- 5 files changed, 179 insertions(+), 126 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index d61360ded..d3a41ad39 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -412,7 +412,7 @@ typedef struct player_s // Basic gameplay things UINT8 position; // Used for Kart positions, mostly for deterministic stuff UINT8 oldposition; // Used for taunting when you pass someone - UINT8 positiondelay; // Used for position number, so it can grow when passing/being passed + UINT8 positiondelay; // Used for position number, so it can grow when passing UINT32 distancetofinish; waypoint_t *nextwaypoint; respawnvars_t respawn; // Respawn info diff --git a/src/doomdef.h b/src/doomdef.h index 0c462c8ee..8271a4ae2 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -398,6 +398,19 @@ typedef enum SKINCOLOR_CHAOSEMERALD7, SKINCOLOR_INVINCFLASH, + SKINCOLOR_POSNUM, + SKINCOLOR_POSNUM_WIN1, + SKINCOLOR_POSNUM_WIN2, + SKINCOLOR_POSNUM_WIN3, + SKINCOLOR_POSNUM_LOSE1, + SKINCOLOR_POSNUM_LOSE2, + SKINCOLOR_POSNUM_LOSE3, + SKINCOLOR_POSNUM_BEST1, + SKINCOLOR_POSNUM_BEST2, + SKINCOLOR_POSNUM_BEST3, + SKINCOLOR_POSNUM_BEST4, + SKINCOLOR_POSNUM_BEST5, + SKINCOLOR_POSNUM_BEST6, SKINCOLOR_FIRSTFREESLOT, SKINCOLOR_LASTFREESLOT = SKINCOLOR_FIRSTFREESLOT + NUMCOLORFREESLOTS - 1, diff --git a/src/info.c b/src/info.c index 266787230..6e0e46267 100644 --- a/src/info.c +++ b/src/info.c @@ -29126,7 +29126,21 @@ skincolor_t skincolors[MAXSKINCOLORS] = { {"Chaos Emerald 6", { 0, 208, 50, 32, 34, 37, 40, 44, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD6 {"Chaos Emerald 7", { 0, 120, 121, 140, 133, 135, 149, 156, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD7 - {"Invinc Flash", { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, SKINCOLOR_NONE, 0, 0, false} // SKINCOLOR_INVINCFLASH + {"Invinc Flash", { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_INVINCFLASH + + {"Position", { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM + {"Position Win 1", {152, 152, 153, 154, 155, 156, 157, 157, 158, 158, 159, 159, 253, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN1 + {"Position Win 2", {135, 135, 135, 136, 136, 136, 137, 137, 137, 138, 138, 139, 139, 254, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN2 + {"Position Win 3", {255, 255, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN3 + {"Position Lose 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 47, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE1 + {"Position Lose 2", { 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 44, 45, 71, 46, 47, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE2 + {"Position Lose 3", { 73, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79, 236, 237, 238, 239, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE3 + {"Position Best 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 47, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST1 + {"Position Best 2", { 73, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79, 236, 237, 238, 239, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST2 + {"Position Best 3", {112, 112, 113, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 110, 111, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST3 + {"Position Best 4", {255, 255, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST4 + {"Position Best 5", {152, 152, 153, 154, 155, 156, 157, 157, 158, 158, 159, 159, 253, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST5 + {"Position Best 6", {181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 29, 30}, SKINCOLOR_NONE, 0, 0, false} // SKINCOLOR_POSNUM_BEST6 }; /** Patches the mobjinfo, state, and skincolor tables. diff --git a/src/k_hud.c b/src/k_hud.c index d4127e131..39b08623c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -37,10 +37,6 @@ #include "r_fps.h" #include "m_random.h" -#define NUMPOSNUMS 10 -#define NUMPOSFRAMES 7 // White, three blues, three reds -#define NUMWINFRAMES 6 // Red, yellow, green, cyan, blue, purple - //{ Patch Definitions static patch_t *kp_nodraw; @@ -70,8 +66,7 @@ static patch_t *kp_startcountdown[20]; static patch_t *kp_racefault[6]; static patch_t *kp_racefinish[6]; -static patch_t *kp_positionnum[NUMPOSNUMS][NUMPOSFRAMES]; -static patch_t *kp_winnernum[NUMPOSFRAMES]; +static patch_t *kp_positionnum[10][2][2]; // number, overlay or underlay, splitscreen static patch_t *kp_facenum[MAXPLAYERS+1]; static patch_t *kp_facehighlight[8]; @@ -179,7 +174,7 @@ static patch_t *kp_trickcool[2]; void K_LoadKartHUDGraphics(void) { - INT32 i, j; + INT32 i, j, k; char buffer[9]; // Null Stuff @@ -280,23 +275,29 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_racefinish[5], "K_2PFINB"); // Position numbers - sprintf(buffer, "K_POSNxx"); - for (i = 0; i < NUMPOSNUMS; i++) + sprintf(buffer, "KRNKxyz"); + for (i = 0; i < 10; i++) { buffer[6] = '0'+i; - for (j = 0; j < NUMPOSFRAMES; j++) - { - //sprintf(buffer, "K_POSN%d%d", i, j); - buffer[7] = '0'+j; - HU_UpdatePatch(&kp_positionnum[i][j], "%s", buffer); - } - } - sprintf(buffer, "K_POSNWx"); - for (i = 0; i < NUMWINFRAMES; i++) - { - buffer[7] = '0'+i; - HU_UpdatePatch(&kp_winnernum[i], "%s", buffer); + for (j = 0; j < 2; j++) + { + buffer[5] = 'A'+j; + + for (k = 0; k < 2; k++) + { + if (k > 0) + { + buffer[4] = 'S'; + } + else + { + buffer[4] = 'B'; + } + + HU_UpdatePatch(&kp_positionnum[i][j][k], "%s", buffer); + } + } } sprintf(buffer, "OPPRNKxx"); @@ -1545,146 +1546,169 @@ bademblem: } } -static void K_DrawKartPositionNum(INT32 num) +static fixed_t K_DrawKartPositionNumPatch(UINT8 num, UINT8 *color, fixed_t x, fixed_t y, fixed_t scale, INT32 flags) { - // POSI_X = BASEVIDWIDTH - 51; // 269 - // POSI_Y = BASEVIDHEIGHT- 64; // 136 + UINT8 splitIndex = (r_splitscreen > 0) ? 1 : 0; + fixed_t w = FRACUNIT; + fixed_t h = FRACUNIT; + INT32 overlayFlags[2]; + INT32 i; - boolean win = (stplyr->exiting && num == 1); - //INT32 X = POSI_X; - INT32 W = SHORT(kp_positionnum[0][0]->width); - fixed_t scale = FRACUNIT; - patch_t *localpatch = kp_positionnum[0][0]; - INT32 fx = 0, fy = 0, fflags = 0; - INT32 addOrSub = V_ADD; - boolean flipdraw = false; // flip the order we draw it in for MORE splitscreen bs. fun. - boolean flipvdraw = false; // used only for 2p splitscreen so overtaking doesn't make 1P's position fly off the screen. - boolean overtake = false; + if (num >= 10) + { + return x; // invalid input + } if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SUBTRACTNUM) == LF_SUBTRACTNUM) { - addOrSub = V_SUBTRACT; + overlayFlags[0] = V_SUBTRACT; + overlayFlags[1] = V_ADD; } + else + { + overlayFlags[0] = V_ADD; + overlayFlags[1] = V_SUBTRACT; + } + + w = kp_positionnum[num][0][splitIndex]->width * scale; + h = kp_positionnum[num][0][splitIndex]->height * scale; + + if (flags & V_SNAPTORIGHT) + { + x -= w; + } + + if (flags & V_SNAPTOBOTTOM) + { + y -= h; + } + + for (i = 1; i >= 0; i--) + { + V_DrawFixedPatch( + x, y, scale, + flags | overlayFlags[i], + kp_positionnum[num][i][splitIndex], + color + ); + } + + return (x - w); +} + +static void K_DrawKartPositionNum(INT32 num) +{ + const tic_t counter = (leveltime / 3); // Alternate colors every three frames + fixed_t scale = FRACUNIT; + fixed_t fx = 0, fy = 0; + INT32 fflags = 0; + UINT8 *color = NULL; if (stplyr->positiondelay || stplyr->exiting) { scale *= 2; - overtake = true; // this is used for splitscreen stuff in conjunction with flipdraw. } - if (r_splitscreen) - { - scale /= 2; - } - - W = FixedMul(W<>FRACBITS; - // pain and suffering defined below if (!r_splitscreen) { - fx = POSI_X; - fy = BASEVIDHEIGHT - 8; - fflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN; + fx = BASEVIDWIDTH << FRACBITS; + fy = BASEVIDHEIGHT << FRACBITS; + fflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT; } else if (r_splitscreen == 1) // for this splitscreen, we'll use case by case because it's a bit different. { - fx = POSI_X; - if (stplyr == &players[displayplayers[0]]) // for player 1: display this at the top right, above the minimap. + fx = BASEVIDWIDTH << FRACBITS; + + if (stplyr == &players[displayplayers[0]]) { - fy = 30; - fflags = V_SNAPTOTOP|V_SNAPTORIGHT|V_SPLITSCREEN; - if (overtake) - flipvdraw = true; // make sure overtaking doesn't explode us + // for player 1: display this at the top right, above the minimap. + fy = 0; + fflags = V_SNAPTOTOP|V_SNAPTORIGHT; } - else // if we're not p1, that means we're p2. display this at the bottom right, below the minimap. + else { - fy = (BASEVIDHEIGHT/2) - 8; - fflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN; + // if we're not p1, that means we're p2. display this at the bottom right, below the minimap. + fy = BASEVIDHEIGHT << FRACBITS; + fflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } + + fy >>= 1; + } + else + { + fy = BASEVIDHEIGHT << FRACBITS; + + if (stplyr == &players[displayplayers[0]] + || stplyr == &players[displayplayers[2]]) + { + // If we are P1 or P3... + fx = 0; + fflags = V_SNAPTOLEFT|V_SNAPTOBOTTOM; + } + else + { + // else, that means we're P2 or P4. + fx = BASEVIDWIDTH << FRACBITS; + fflags = V_SNAPTORIGHT|V_SNAPTOBOTTOM; + } + + fx >>= 1; + fy >>= 1; + } + + if (stplyr->exiting && num == 1) + { + // 1st place winner? You get rainbows!! + color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_BEST1 + (counter % 6), GTC_CACHE); + } + else if (stplyr->laps >= numlaps || stplyr->exiting) + { + // On the final lap, or already won. + boolean useRedNums = K_IsPlayerLosing(stplyr); + + if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SUBTRACTNUM) == LF_SUBTRACTNUM) + { + // Subtracting RED will look BLUE, and vice versa. + useRedNums = !useRedNums; + } + + if (useRedNums == true) + { + color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_LOSE1 + (counter % 3), GTC_CACHE); + } + else + { + color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_WIN1 + (counter % 3), GTC_CACHE); } } else { - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... - { - fx = POSI_X; - fy = POSI_Y; - fflags = V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_SPLITSCREEN; - 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. - } - else // else, that means we're P2 or P4. - { - fx = POSI2_X; - fy = POSI2_Y; - fflags = V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_SPLITSCREEN; - } + color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM, GTC_CACHE); } // Special case for 0 if (num <= 0) { - V_DrawFixedPatch(fx<laps >= numlaps || stplyr->exiting) // Check for the final lap, or won - { - boolean useRedNums = K_IsPlayerLosing(stplyr); + /* + + */ - if (addOrSub == V_SUBTRACT) - { - // Subtracting RED will look BLUE, and vice versa. - useRedNums = !useRedNums; - } - - // Alternate frame every three frames - switch ((leveltime % 9) / 3) - { - case 0: - if (useRedNums == true) - localpatch = kp_positionnum[num % 10][4]; - else - localpatch = kp_positionnum[num % 10][1]; - break; - case 1: - if (useRedNums == true) - localpatch = kp_positionnum[num % 10][5]; - else - localpatch = kp_positionnum[num % 10][2]; - break; - case 2: - if (useRedNums == true) - localpatch = kp_positionnum[num % 10][6]; - else - localpatch = kp_positionnum[num % 10][3]; - break; - default: - localpatch = kp_positionnum[num % 10][0]; - break; - } - } - else - { - localpatch = kp_positionnum[num % 10][0]; - } - - V_DrawFixedPatch( - (fx<width)*scale/2) : 0), - (fy<height)*scale/2) : 0), - scale, addOrSub|V_SLIDEIN|fflags, localpatch, NULL + fx = K_DrawKartPositionNumPatch( + (num % 10), color, + fx, fy, scale, V_SLIDEIN|V_SPLITSCREEN|fflags ); - // ^ if we overtake as p1 or p3 in splitscren, we shift it so that it doesn't go off screen. - // ^ if we overtake as p1 in 2p splits, shift vertically so that this doesn't happen either. - - fx -= W; num /= 10; } } diff --git a/src/k_kart.c b/src/k_kart.c index 583639b9c..c1536cfb4 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9865,8 +9865,10 @@ void K_KartUpdatePosition(player_t *player) if (leveltime < starttime || oldposition == 0) oldposition = position; - if (oldposition != position) // Changed places? + if (position < oldposition) // Changed places? + { player->positiondelay = 10; // Position number growth + } /* except in FREE PLAY */ if (player->curshield == KSHIELD_TOP && From e456eaed6d702c39796ed869c7c30b77027e9fe6 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 6 Nov 2022 14:58:31 -0500 Subject: [PATCH 56/81] SubtractNum also makes tripwire subtractive --- src/p_setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index 8e9eed1a5..efadfedd9 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2631,6 +2631,7 @@ static void P_ProcessLinedefsAfterSidedefs(void) { size_t i = numlines; register line_t *ld = lines; + const boolean subtractTripwire = ((mapheaderinfo[gamemap - 1]->levelflags & LF_SUBTRACTNUM) == LF_SUBTRACTNUM); for (; i--; ld++) { @@ -2645,7 +2646,7 @@ static void P_ProcessLinedefsAfterSidedefs(void) if (ld->tripwire) { - ld->blendmode = AST_ADD; + ld->blendmode = (subtractTripwire ? AST_SUBTRACT : AST_ADD); ld->alpha = 0xff; } From 0d5d1c7a09d867091a8254d3c41dbd9b61da51a9 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Nov 2022 18:50:25 -0800 Subject: [PATCH 57/81] Invert yaw diff in reverse HUD tracking This fixes the player CHECK moving in the opposite direction of what it should across the screen. --- src/k_hud.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/k_hud.c b/src/k_hud.c index d4127e131..a08be833f 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -950,6 +950,11 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean revers h = R_PointToDist2(point->x, point->y, viewx, viewy); da = AngleDeltaSigned(viewpointAngle, R_PointToAngle2(point->x, point->y, viewx, viewy)); + if (reverse) + { + da = -(da); + } + // Set results relative to top left! result->x = FixedMul(NEWTAN(da), fg); result->y = FixedMul((NEWTAN(viewpointAiming) - FixedDiv((viewz - point->z), 1 + FixedMul(NEWCOS(da), h))), fg); From 31046f039021f35ae3675d40ebbd9c66f00a2d7f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 17 Nov 2022 22:25:55 -0500 Subject: [PATCH 58/81] Gamma correct the colors used by the position nums My case for why I hate the gamma correction: took me 30 minutes tops to insert all of these colors originally, but took me an hour to reverse the proper gamma correction to the handful that needed it. --- src/info.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/info.c b/src/info.c index 6e0e46267..e2e902b65 100644 --- a/src/info.c +++ b/src/info.c @@ -29128,18 +29128,18 @@ skincolor_t skincolors[MAXSKINCOLORS] = { {"Invinc Flash", { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_INVINCFLASH - {"Position", { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM - {"Position Win 1", {152, 152, 153, 154, 155, 156, 157, 157, 158, 158, 159, 159, 253, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN1 - {"Position Win 2", {135, 135, 135, 136, 136, 136, 137, 137, 137, 138, 138, 139, 139, 254, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN2 - {"Position Win 3", {255, 255, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN3 - {"Position Lose 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 47, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE1 - {"Position Lose 2", { 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 44, 45, 71, 46, 47, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE2 + {"Position", { 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, 24, 26, 27, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM + {"Position Win 1", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN1 + {"Position Win 2", {134, 134, 135, 135, 135, 136, 136, 136, 137, 137, 138, 138, 139, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN2 + {"Position Win 3", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN3 + {"Position Lose 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE1 + {"Position Lose 2", { 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 63, 44, 45, 46, 47, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE2 {"Position Lose 3", { 73, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79, 236, 237, 238, 239, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE3 - {"Position Best 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 47, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST1 + {"Position Best 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST1 {"Position Best 2", { 73, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79, 236, 237, 238, 239, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST2 {"Position Best 3", {112, 112, 113, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 110, 111, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST3 - {"Position Best 4", {255, 255, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST4 - {"Position Best 5", {152, 152, 153, 154, 155, 156, 157, 157, 158, 158, 159, 159, 253, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST5 + {"Position Best 4", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST4 + {"Position Best 5", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST5 {"Position Best 6", {181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 29, 30}, SKINCOLOR_NONE, 0, 0, false} // SKINCOLOR_POSNUM_BEST6 }; From 5f20d5a3ac901e679ef4e2262aa8e34f7d87f8bf Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 17 Nov 2022 22:46:26 -0500 Subject: [PATCH 59/81] Smooth scale-up --- src/k_hud.c | 3 ++- src/k_hud.h | 2 ++ src/k_kart.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 39b08623c..141fe5bce 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1606,7 +1606,8 @@ static void K_DrawKartPositionNum(INT32 num) if (stplyr->positiondelay || stplyr->exiting) { - scale *= 2; + UINT8 delay = (stplyr->exiting) ? POS_DELAY_TIME : stplyr->positiondelay; + scale += min((scale * (delay * delay)) / (POS_DELAY_TIME * POS_DELAY_TIME), scale); } // pain and suffering defined below diff --git a/src/k_hud.h b/src/k_hud.h index 683425e8a..4f84f9dd3 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -19,6 +19,8 @@ #define RINGANIM_NUMFRAMES 10 #define RINGANIM_DELAYMAX 5 +#define POS_DELAY_TIME 10 + void K_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 dupy); typedef struct trackingResult_s diff --git a/src/k_kart.c b/src/k_kart.c index c1536cfb4..fa0b72eeb 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9867,7 +9867,7 @@ void K_KartUpdatePosition(player_t *player) if (position < oldposition) // Changed places? { - player->positiondelay = 10; // Position number growth + player->positiondelay = POS_DELAY_TIME + 4; // Position number growth } /* except in FREE PLAY */ From 2d200c1361818be1d5cc9e69713605997a6a675e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 17 Nov 2022 23:02:44 -0500 Subject: [PATCH 60/81] Fade-in position number after GO --- src/k_hud.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/k_hud.c b/src/k_hud.c index 141fe5bce..25f38dc72 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1601,9 +1601,20 @@ static void K_DrawKartPositionNum(INT32 num) const tic_t counter = (leveltime / 3); // Alternate colors every three frames fixed_t scale = FRACUNIT; fixed_t fx = 0, fy = 0; + transnum_t trans = 0; INT32 fflags = 0; UINT8 *color = NULL; + if (leveltime < (starttime + NUMTRANSMAPS)) + { + trans = max(0, (starttime + NUMTRANSMAPS) - leveltime); + } + + if (trans >= NUMTRANSMAPS) + { + return; + } + if (stplyr->positiondelay || stplyr->exiting) { UINT8 delay = (stplyr->exiting) ? POS_DELAY_TIME : stplyr->positiondelay; @@ -1658,6 +1669,11 @@ static void K_DrawKartPositionNum(INT32 num) fy >>= 1; } + if (trans > 0) + { + fflags |= (trans << V_ALPHASHIFT); + } + if (stplyr->exiting && num == 1) { // 1st place winner? You get rainbows!! From 895a5e34e0485f99f019510c26a05913a60521ae Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 17 Nov 2022 23:09:19 -0500 Subject: [PATCH 61/81] Go back to old growth behavior --- src/k_kart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index fa0b72eeb..683796437 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9865,10 +9865,8 @@ void K_KartUpdatePosition(player_t *player) if (leveltime < starttime || oldposition == 0) oldposition = position; - if (position < oldposition) // Changed places? - { - player->positiondelay = POS_DELAY_TIME + 4; // Position number growth - } + // Changed places? + player->positiondelay = POS_DELAY_TIME + 4; // Position number growth /* except in FREE PLAY */ if (player->curshield == KSHIELD_TOP && From 98f5f4bfcb7f0f22fe1469b6c8956cde7f72547e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 17 Nov 2022 23:09:19 -0500 Subject: [PATCH 62/81] Go back to old growth behavior --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index fa0b72eeb..45f2b906f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9865,7 +9865,7 @@ void K_KartUpdatePosition(player_t *player) if (leveltime < starttime || oldposition == 0) oldposition = position; - if (position < oldposition) // Changed places? + if (position != oldposition) // Changed places? { player->positiondelay = POS_DELAY_TIME + 4; // Position number growth } From 651b75e80255efb31defd8e602083144946f0992 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 17 Nov 2022 23:45:56 -0500 Subject: [PATCH 63/81] Sound when passing --- src/k_kart.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 45f2b906f..cc8c044d9 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9867,6 +9867,12 @@ void K_KartUpdatePosition(player_t *player) if (position != oldposition) // Changed places? { + if (position < oldposition && P_IsDisplayPlayer(player) == true) + { + // Play sound when getting closer to 1st. + S_StartSound(player->mo, sfx_mbs41); + } + player->positiondelay = POS_DELAY_TIME + 4; // Position number growth } From d0a3e4704de3f4488d3b889397c309cc2a26dab6 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 17 Nov 2022 23:48:06 -0500 Subject: [PATCH 64/81] Make position number scale vary - Before: always x2 - With "normal screen" (1P, 3P, 4P): x1.75 - With "wide splitscreen" (2P): x2.5 --- src/k_hud.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 25f38dc72..b4f868491 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1617,8 +1617,9 @@ static void K_DrawKartPositionNum(INT32 num) if (stplyr->positiondelay || stplyr->exiting) { - UINT8 delay = (stplyr->exiting) ? POS_DELAY_TIME : stplyr->positiondelay; - scale += min((scale * (delay * delay)) / (POS_DELAY_TIME * POS_DELAY_TIME), scale); + const UINT8 delay = (stplyr->exiting) ? POS_DELAY_TIME : stplyr->positiondelay; + const fixed_t add = (scale * 3) >> ((r_splitscreen == 1) ? 1 : 2); + scale += min((add * (delay * delay)) / (POS_DELAY_TIME * POS_DELAY_TIME), add); } // pain and suffering defined below From 88d1f1d1473a13ca3acf04c2ebf1412d89283e3f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 18 Nov 2022 00:37:53 -0500 Subject: [PATCH 65/81] Fix bananas not maintaining angle when dropped --- src/k_kart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 583639b9c..97238f65f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6247,6 +6247,8 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, if (player->mo->eflags & MFE_VERTICALFLIP) mo->eflags |= MFE_VERTICALFLIP; + mo->angle = newangle; + if (mapthing == MT_SSMINE) mo->extravalue1 = 49; // Pads the start-up length from 21 frames to a full 2 seconds else if (mapthing == MT_BUBBLESHIELDTRAP) From 1688325c67e04477b27e2d5b5d6bd7c296f996ca Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 18 Nov 2022 01:05:01 -0500 Subject: [PATCH 66/81] Banana angle crazy mode - Randomize banana angles when thrown - Spin bananas when mid-air - Add MF_SLOPE flag to control whenever or not pitch/roll are set for an object (replaces MF_BOXICON) --- src/deh_tables.c | 2 +- src/info.c | 66 ++++++++++++++++++++++++------------------------ src/k_kart.c | 18 ++++++++----- src/p_mobj.c | 43 +++++++++++++++---------------- src/p_mobj.h | 6 ++--- 5 files changed, 70 insertions(+), 65 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 383823833..6affca2b7 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5628,7 +5628,7 @@ const char *const MOBJFLAG_LIST[] = { "SLIDEME", "NOCLIP", "FLOAT", - "BOXICON", + "SLOPE", "MISSILE", "SPRING", "MONITOR", diff --git a/src/info.c b/src/info.c index 266787230..0f48c82ac 100644 --- a/src/info.c +++ b/src/info.c @@ -5289,7 +5289,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass MT_THOK, // damage sfx_None, // activesound - MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags (statenum_t)MT_THOK // raisestate }, @@ -5316,7 +5316,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SOLID|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -9986,7 +9986,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10013,7 +10013,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10040,7 +10040,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10067,7 +10067,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10094,7 +10094,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10121,7 +10121,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10148,7 +10148,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10175,7 +10175,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10202,7 +10202,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10229,7 +10229,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10256,7 +10256,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10283,7 +10283,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10310,7 +10310,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10337,7 +10337,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10364,7 +10364,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10391,7 +10391,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10418,7 +10418,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10445,7 +10445,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10472,7 +10472,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 62*FRACUNIT, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -23090,7 +23090,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_peel, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23117,7 +23117,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23144,7 +23144,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k96, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23171,7 +23171,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23198,7 +23198,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3kc0s, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23225,7 +23225,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23279,7 +23279,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k5c, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23306,7 +23306,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23414,7 +23414,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_s3k5c, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23441,7 +23441,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k96, // activesound - MF_SPECIAL|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SPECIAL|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -23468,7 +23468,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SPECIAL|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_SPECIAL|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, @@ -24089,7 +24089,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags S_NULL // raisestate }, diff --git a/src/k_kart.c b/src/k_kart.c index 97238f65f..546f48328 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6133,6 +6133,7 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, { // Shoot forward mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, mapthing); + mo->angle = player->mo->angle; // These are really weird so let's make it a very specific case to make SURE it works... if (player->mo->eflags & MFE_VERTICALFLIP) @@ -6147,7 +6148,6 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, S_StartSound(player->mo, mo->info->seesound); - if (mo) { angle_t fa = player->mo->angle>>ANGLETOFINESHIFT; fixed_t HEIGHT = ((20 + (dir*10)) * FRACUNIT) + (FixedDiv(player->mo->momz, mapobjectscale)*P_MobjFlip(player->mo)); // Also intentionally not player scale @@ -6155,14 +6155,20 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, P_SetObjectMomZ(mo, HEIGHT, false); mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), PROJSPEED*dir); mo->momy = player->mo->momy + FixedMul(FINESINE(fa), PROJSPEED*dir); + } - mo->extravalue2 = dir; + mo->extravalue2 = dir; - if (mo->eflags & MFE_UNDERWATER) - mo->momz = (117 * mo->momz) / 200; + if (mo->eflags & MFE_UNDERWATER) + mo->momz = (117 * mo->momz) / 200; - P_SetScale(mo, finalscale); - mo->destscale = finalscale; + P_SetScale(mo, finalscale); + mo->destscale = finalscale; + + if (mapthing == MT_BANANA) + { + mo->angle = FixedAngle(P_RandomRange(PR_DECORATION, -180, 180) << FRACBITS); + mo->rollangle = FixedAngle(P_RandomRange(PR_DECORATION, -180, 180) << FRACBITS); } // this is the small graphic effect that plops in you when you throw an item: diff --git a/src/p_mobj.c b/src/p_mobj.c index 366be896d..80c49017c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1261,6 +1261,11 @@ void P_CheckGravity(mobj_t *mo, boolean affect) // void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope) { + if (!(mo->flags & MF_SLOPE)) + { + return; + } + if (slope) { fixed_t tempz = slope->normal.z; @@ -6927,11 +6932,23 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } } - if (P_IsObjectOnGround(mobj) && mobj->health > 1) + if (P_IsObjectOnGround(mobj)) { - S_StartSound(mobj, mobj->info->activesound); - mobj->momx = mobj->momy = 0; - mobj->health = 1; + //mobj->rollangle = 0; + + if (mobj->health > 1) + { + S_StartSound(mobj, mobj->info->activesound); + mobj->momx = mobj->momy = 0; + mobj->health = 1; + } + } + else + { + // tilt n tumble + angle_t spin = FixedMul(FixedDiv(mobj->momz, 8 * mobj->scale), ANGLE_67h); + mobj->angle += spin; + mobj->rollangle -= spin; } if (mobj->threshold > 0) @@ -9700,24 +9717,6 @@ void P_PushableThinker(mobj_t *mobj) // Quick, optimized function for scenery void P_SceneryThinker(mobj_t *mobj) { - if (mobj->flags & MF_BOXICON) - { - if (!(mobj->eflags & MFE_VERTICALFLIP)) - { - if (mobj->z < mobj->floorz + FixedMul(mobj->info->damage, mobj->scale)) - mobj->momz = FixedMul(mobj->info->speed, mobj->scale); - else - mobj->momz = 0; - } - else - { - if (mobj->z + FixedMul(mobj->info->height, mobj->scale) > mobj->ceilingz - FixedMul(mobj->info->damage, mobj->scale)) - mobj->momz = -FixedMul(mobj->info->speed, mobj->scale); - else - mobj->momz = 0; - } - } - // momentum movement if (mobj->momx || mobj->momy) { diff --git a/src/p_mobj.h b/src/p_mobj.h index 923fc7f80..b725f2bf0 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -126,8 +126,8 @@ typedef enum MF_NOCLIP = 1<<12, // Allow moves to any height, no gravity. For active floaters. MF_FLOAT = 1<<13, - // Monitor powerup icon. These rise a bit. - MF_BOXICON = 1<<14, + // Change pitch/roll when touching slopes. + MF_SLOPE = 1<<14, // Don't hit same species, explode on block. // Player missiles as well as fireballs of various kinds. MF_MISSILE = 1<<15, @@ -163,7 +163,7 @@ typedef enum MF_NOSQUISH = 1<<30, // Disable hitlag for this object MF_NOHITLAGFORME = (INT32)(1U<<31), - // no more free slots, next up I suppose we can get rid of shit like MF_BOXICON? + // no more free slots, gotta get rid of more crusty base SRB2 flags } mobjflag_t; typedef enum From 32c477e61994fb3c42d313d855ab7883739e2746 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 18 Nov 2022 01:56:45 -0500 Subject: [PATCH 67/81] Bananas use proper death frame --- src/info.c | 2 +- src/k_collide.c | 8 +-- src/k_kart.c | 4 +- src/objects/orbinaut.c | 4 +- src/p_mobj.c | 122 +++++++++++++++++++++++------------------ 5 files changed, 77 insertions(+), 63 deletions(-) diff --git a/src/info.c b/src/info.c index 0f48c82ac..b39ee8f10 100644 --- a/src/info.c +++ b/src/info.c @@ -4077,7 +4077,7 @@ state_t states[NUMSTATES] = {SPR_FITM, 24|FF_FULLBRIGHT, 175, {NULL}, 0, 0, S_NULL}, // S_EGGMANITEM_DEAD {SPR_BANA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BANANA - {SPR_BANA, 0, 175, {NULL}, 0, 0, S_NULL}, // S_BANANA_DEAD + {SPR_BANA, 1, 175, {NULL}, 0, 0, S_NULL}, // S_BANANA_DEAD {SPR_ORBN, 0, 1, {NULL}, 0, 0, S_ORBINAUT2}, // S_ORBINAUT1 {SPR_ORBN, 1, 1, {NULL}, 0, 0, S_ORBINAUT3}, // S_ORBINAUT2 diff --git a/src/k_collide.c b/src/k_collide.c index b03cdfdec..d3b9bc60c 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -94,7 +94,7 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); - P_SetObjectMomZ(t2, 8*FRACUNIT, false); + P_SetObjectMomZ(t2, 24*FRACUNIT, false); P_InstaThrust(t2, bounceangle, 16*FRACUNIT); P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH); @@ -122,7 +122,7 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) S_StartSound(t1, t1->info->deathsound); P_KillMobj(t1, t2, t2, DMG_NORMAL); - P_SetObjectMomZ(t1, 8*FRACUNIT, false); + P_SetObjectMomZ(t1, 24*FRACUNIT, false); P_InstaThrust(t1, bounceangle, 16*FRACUNIT); } @@ -351,7 +351,7 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); - P_SetObjectMomZ(t2, 8*FRACUNIT, false); + P_SetObjectMomZ(t2, 24*FRACUNIT, false); P_InstaThrust(t2, bounceangle, 16*FRACUNIT); } else if (t2->flags & MF_SHOOTABLE) @@ -414,7 +414,7 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); - P_SetObjectMomZ(t2, 8*FRACUNIT, false); + P_SetObjectMomZ(t2, 24*FRACUNIT, false); P_InstaThrust(t2, bounceangle, 16*FRACUNIT); P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH); diff --git a/src/k_kart.c b/src/k_kart.c index 546f48328..448c802e2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6670,7 +6670,7 @@ killnext: S_StartSound(banana, banana->info->deathsound); P_KillMobj(banana, inflictor, source, DMG_NORMAL); - P_SetObjectMomZ(banana, 8*FRACUNIT, false); + P_SetObjectMomZ(banana, 24*FRACUNIT, false); if (inflictor) P_InstaThrust(banana, R_PointToAngle2(inflictor->x, inflictor->y, banana->x, banana->y)+ANGLE_90, 16*FRACUNIT); } @@ -7071,7 +7071,7 @@ void K_DropRocketSneaker(player_t *player) flingangle = ANG60; S_StartSound(shoe, shoe->info->deathsound); - P_SetObjectMomZ(shoe, 8*FRACUNIT, false); + P_SetObjectMomZ(shoe, 24*FRACUNIT, false); P_InstaThrust(shoe, R_PointToAngle2(shoe->target->x, shoe->target->y, shoe->x, shoe->y)+flingangle, 16*FRACUNIT); shoe->momx += shoe->target->momx; shoe->momy += shoe->target->momy; diff --git a/src/objects/orbinaut.c b/src/objects/orbinaut.c index 4d5738e00..ee6e72ed5 100644 --- a/src/objects/orbinaut.c +++ b/src/objects/orbinaut.c @@ -217,7 +217,7 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); - P_SetObjectMomZ(t2, 8*FRACUNIT, false); + P_SetObjectMomZ(t2, 24*FRACUNIT, false); P_InstaThrust(t2, bounceangle, 16*FRACUNIT); P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH); @@ -254,7 +254,7 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) S_StartSound(t1, t1->info->deathsound); P_KillMobj(t1, t2, t2, DMG_NORMAL); - P_SetObjectMomZ(t1, 8*FRACUNIT, false); + P_SetObjectMomZ(t1, 24*FRACUNIT, false); P_InstaThrust(t1, bounceangle, 16*FRACUNIT); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 80c49017c..04462afb5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1158,66 +1158,68 @@ fixed_t P_GetMobjGravity(mobj_t *mo) gravityadd = -gravityadd; } } - else //Otherwise, sort through the other exceptions. + + // Sort through the other exceptions. + switch (mo->type) { - switch (mo->type) - { - case MT_FLINGRING: - case MT_FLINGCOIN: - case MT_FLINGBLUESPHERE: - case MT_FLINGNIGHTSCHIP: - case MT_BOUNCERING: - case MT_RAILRING: - case MT_INFINITYRING: - case MT_AUTOMATICRING: - case MT_EXPLOSIONRING: - case MT_SCATTERRING: - case MT_GRENADERING: - case MT_BOUNCEPICKUP: - case MT_RAILPICKUP: - case MT_AUTOPICKUP: - case MT_EXPLODEPICKUP: - case MT_SCATTERPICKUP: - case MT_GRENADEPICKUP: - case MT_REDFLAG: - case MT_BLUEFLAG: - if (mo->target) + case MT_FLINGRING: + case MT_FLINGCOIN: + case MT_FLINGBLUESPHERE: + case MT_FLINGNIGHTSCHIP: + case MT_BOUNCERING: + case MT_RAILRING: + case MT_INFINITYRING: + case MT_AUTOMATICRING: + case MT_EXPLOSIONRING: + case MT_SCATTERRING: + case MT_GRENADERING: + case MT_BOUNCEPICKUP: + case MT_RAILPICKUP: + case MT_AUTOPICKUP: + case MT_EXPLODEPICKUP: + case MT_SCATTERPICKUP: + case MT_GRENADEPICKUP: + case MT_REDFLAG: + case MT_BLUEFLAG: + if (mo->target) + { + // Flung items copy the gravity of their tosser. + if ((mo->target->eflags & MFE_VERTICALFLIP) && !(mo->eflags & MFE_VERTICALFLIP)) { - // Flung items copy the gravity of their tosser. - if ((mo->target->eflags & MFE_VERTICALFLIP) && !(mo->eflags & MFE_VERTICALFLIP)) - { - gravityadd = -gravityadd; - mo->eflags |= MFE_VERTICALFLIP; - } + gravityadd = -gravityadd; + mo->eflags |= MFE_VERTICALFLIP; } - break; - case MT_WATERDROP: - case MT_BATTLEBUMPER: - gravityadd /= 2; - break; - case MT_BANANA: - case MT_EGGMANITEM: - case MT_SSMINE: - case MT_LANDMINE: - case MT_DROPTARGET: - case MT_SINK: - case MT_EMERALD: + } + break; + case MT_WATERDROP: + case MT_BATTLEBUMPER: + gravityadd /= 2; + break; + case MT_BANANA: + case MT_EGGMANITEM: + case MT_SSMINE: + case MT_LANDMINE: + case MT_DROPTARGET: + case MT_SINK: + case MT_EMERALD: + if (mo->health > 0) + { if (mo->extravalue2 > 0) { gravityadd *= mo->extravalue2; } gravityadd = (5*gravityadd)/2; - break; - case MT_KARMAFIREWORK: - gravityadd /= 3; - break; - case MT_ITEM_DEBRIS: - gravityadd *= 6; - break; - default: - break; - } + } + break; + case MT_KARMAFIREWORK: + gravityadd /= 3; + break; + case MT_ITEM_DEBRIS: + gravityadd *= 6; + break; + default: + break; } } @@ -1769,7 +1771,7 @@ void P_XYMovement(mobj_t *mo) S_StartSound(mo, mo->info->deathsound); P_KillMobj(mo, NULL, NULL, DMG_NORMAL); - P_SetObjectMomZ(mo, 8*FRACUNIT, false); + P_SetObjectMomZ(mo, 24*FRACUNIT, false); P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT); } break; @@ -6491,8 +6493,20 @@ static boolean P_MobjDeadThink(mobj_t *mobj) P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true); } break; - case MT_ORBINAUT: case MT_BANANA: + { + angle_t spin = FixedMul(FixedDiv(mobj->momz, 8 * mobj->scale), ANGLE_67h); + mobj->angle -= spin; + mobj->rollangle += spin; + + if (P_IsObjectOnGround(mobj) && mobj->momz * P_MobjFlip(mobj) <= 0) + { + P_RemoveMobj(mobj); + return false; + } + } + break; + case MT_ORBINAUT: case MT_EGGMANITEM: case MT_LANDMINE: //case MT_DROPTARGET: @@ -9490,7 +9504,7 @@ void P_MobjThinker(mobj_t *mobj) S_StartSound(mobj, mobj->info->deathsound); P_KillMobj(mobj, NULL, NULL, DMG_NORMAL); - P_SetObjectMomZ(mobj, 8*FRACUNIT, false); + P_SetObjectMomZ(mobj, 24*FRACUNIT, false); P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy) + ANGLE_90, 16*FRACUNIT); } From d0cd25328ebfa8566e4ce71489142a2b055c650a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 18 Nov 2022 02:34:59 -0500 Subject: [PATCH 68/81] Remove decabanana --- src/d_netcmd.c | 1 - src/d_netcmd.h | 1 - src/d_player.h | 1 - src/deh_tables.c | 1 - src/k_hud.c | 2 -- src/k_kart.c | 12 +----------- src/k_menudef.c | 1 - 7 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1f09000f4..44480910a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -386,7 +386,6 @@ consvar_t cv_gardentop = CVAR_INIT ("gardentop", "On", CV_NETVAR, CV_OnOff, consvar_t cv_dualsneaker = CVAR_INIT ("dualsneaker", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_triplesneaker = CVAR_INIT ("triplesneaker", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_triplebanana = CVAR_INIT ("triplebanana", "On", CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_decabanana = CVAR_INIT ("decabanana", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_tripleorbinaut = CVAR_INIT ("tripleorbinaut", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_quadorbinaut = CVAR_INIT ("quadorbinaut", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_dualjawz = CVAR_INIT ("dualjawz", "On", CV_NETVAR, CV_OnOff, NULL); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 266d73395..f3ace5cd9 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -100,7 +100,6 @@ extern consvar_t cv_dualsneaker, cv_triplesneaker, cv_triplebanana, - cv_decabanana, cv_tripleorbinaut, cv_quadorbinaut, cv_dualjawz; diff --git a/src/d_player.h b/src/d_player.h index d61360ded..4f59579b0 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -168,7 +168,6 @@ typedef enum KRITEM_DUALSNEAKER = NUMKARTITEMS, KRITEM_TRIPLESNEAKER, KRITEM_TRIPLEBANANA, - KRITEM_TENFOLDBANANA, KRITEM_TRIPLEORBINAUT, KRITEM_QUADORBINAUT, KRITEM_DUALJAWZ, diff --git a/src/deh_tables.c b/src/deh_tables.c index 6affca2b7..17242ba29 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6763,7 +6763,6 @@ struct int_const_s const INT_CONST[] = { {"KRITEM_DUALSNEAKER",KRITEM_DUALSNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch) {"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER}, {"KRITEM_TRIPLEBANANA",KRITEM_TRIPLEBANANA}, - {"KRITEM_TENFOLDBANANA",KRITEM_TENFOLDBANANA}, {"KRITEM_TRIPLEORBINAUT",KRITEM_TRIPLEORBINAUT}, {"KRITEM_QUADORBINAUT",KRITEM_QUADORBINAUT}, {"KRITEM_DUALJAWZ",KRITEM_DUALJAWZ}, diff --git a/src/k_hud.c b/src/k_hud.c index d4127e131..a32a1b195 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -659,7 +659,6 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISINV1" : "K_ITINV1"); case KITEM_BANANA: case KRITEM_TRIPLEBANANA: - case KRITEM_TENFOLDBANANA: return (tiny ? "K_ISBANA" : "K_ITBANA"); case KITEM_EGGMAN: return (tiny ? "K_ISEGGM" : "K_ITEGGM"); @@ -4494,7 +4493,6 @@ static void K_drawDistributionDebugger(void) kp_sneaker[1], kp_sneaker[1], kp_banana[1], - kp_banana[1], kp_orbinaut[4], kp_orbinaut[4], kp_jawz[1] diff --git a/src/k_kart.c b/src/k_kart.c index 448c802e2..ff75d755c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -305,7 +305,6 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_dualsneaker); CV_RegisterVar(&cv_triplesneaker); CV_RegisterVar(&cv_triplebanana); - CV_RegisterVar(&cv_decabanana); CV_RegisterVar(&cv_tripleorbinaut); CV_RegisterVar(&cv_quadorbinaut); CV_RegisterVar(&cv_dualjawz); @@ -409,7 +408,6 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = &cv_dualsneaker, &cv_triplesneaker, &cv_triplebanana, - &cv_decabanana, &cv_tripleorbinaut, &cv_quadorbinaut, &cv_dualjawz @@ -428,7 +426,7 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor { 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut { 0, 4, 2, 1, 0, 0, 0, 0 }, // Jawz - { 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine + { 0, 3, 3, 2, 0, 0, 0, 0 }, // Mine { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb @@ -446,7 +444,6 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2 { 0, 0, 0, 0, 4, 4, 4, 0 }, // Sneaker x3 { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 - { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10 { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 { 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4 { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2 @@ -480,7 +477,6 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = { 0, 0 }, // Sneaker x2 { 0, 1 }, // Sneaker x3 { 0, 0 }, // Banana x3 - { 1, 1 }, // Banana x10 { 2, 0 }, // Orbinaut x3 { 1, 1 }, // Orbinaut x4 { 5, 1 } // Jawz x2 @@ -516,7 +512,6 @@ static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] = { 0, 1, 1, 0 }, // Sneaker x2 { 0, 0, 1, 1 }, // Sneaker x3 { 0, 0, 0, 0 }, // Banana x3 - { 0, 0, 0, 0 }, // Banana x10 { 0, 1, 1, 0 }, // Orbinaut x3 { 0, 0, 1, 1 }, // Orbinaut x4 { 0, 0, 1, 1 } // Jawz x2 @@ -577,7 +572,6 @@ SINT8 K_ItemResultToType(SINT8 getitem) return KITEM_SNEAKER; case KRITEM_TRIPLEBANANA: - case KRITEM_TENFOLDBANANA: return KITEM_BANANA; case KRITEM_TRIPLEORBINAUT: @@ -615,9 +609,6 @@ UINT8 K_ItemResultToAmount(SINT8 getitem) case KITEM_BALLHOG: // Not a special result, but has a special amount return 5; - case KRITEM_TENFOLDBANANA: - return 10; - default: return 1; } @@ -891,7 +882,6 @@ INT32 K_KartGetItemOdds( break; case KRITEM_TRIPLEBANANA: - case KRITEM_TENFOLDBANANA: powerItem = true; notNearEnd = true; break; diff --git a/src/k_menudef.c b/src/k_menudef.c index 66be81efb..55d1f30ad 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -1071,7 +1071,6 @@ menuitem_t OPTIONS_GameplayItems[] = {IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas", NULL, {.routine = M_HandleItemToggles}, KITEM_BANANA, 0}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEBANANA, 0}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas x10", NULL, {.routine = M_HandleItemToggles}, KRITEM_TENFOLDBANANA, 0}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Proximity Mines", NULL, {.routine = M_HandleItemToggles}, KITEM_MINE, 0}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts", NULL, {.routine = M_HandleItemToggles}, KITEM_ORBINAUT, 0}, From 3174e0cc3d8af6edd576ca9dc018d341933c0f54 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 18 Nov 2022 12:50:24 +0000 Subject: [PATCH 69/81] Tryx, tryy for P_GetThingStepUp in increment_move instead of destination x, y --- src/p_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index e235cb9a4..677954b43 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2618,7 +2618,7 @@ increment_move if (!(thing->flags & MF_NOCLIP)) { //All things are affected by their scale. - fixed_t maxstep = P_GetThingStepUp(thing, x, y); + fixed_t maxstep = P_GetThingStepUp(thing, tryx, tryy); if (tmceilingz - tmfloorz < thing->height) { From 3422efb2fded9e0794f0605e597768b135a54c20 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 18 Nov 2022 13:41:50 +0000 Subject: [PATCH 70/81] Reduce restriction for water skiing slope differences Only prohibit if slope surface is TOO different along the direction of movement, rather than even slightly different across any axis. Fixes MK's indev Mirage Saloon --- src/p_mobj.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 366be896d..c010e98e2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3127,8 +3127,9 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) boolean doifit = false; pslope_t *waterSlope = NULL; - angle_t ourZAng = 0; - angle_t waterZAng = 0; + angle_t moveDir = 0; + fixed_t ourZAng = 0; + fixed_t waterZAng = 0; if (rover == NULL) { @@ -3162,20 +3163,36 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) return false; } - if (mobj->standingslope != NULL) + moveDir = K_MomentumAngle(mobj); + + if (mobj->standingslope != NULL && mobj->standingslope->zangle != 0) { - ourZAng = mobj->standingslope->zangle; + angle_t dir = mobj->standingslope->xydirection; + angle_t workang = mobj->standingslope->zangle; + if (workang >= ANGLE_180) + { + workang = InvAngle(workang); + dir = InvAngle(dir); + } + ourZAng = P_ReturnThrustX(mobj, dir - moveDir, AngleFixed(workang)); } waterSlope = (flip ? *rover->b_slope : *rover->t_slope); - if (waterSlope != NULL) + if (waterSlope != NULL && waterSlope->zangle != 0) { - waterZAng = waterSlope->zangle; + angle_t dir = waterSlope->xydirection; + angle_t workang = waterSlope->zangle; + if (workang >= ANGLE_180) + { + workang = InvAngle(workang); + dir = InvAngle(dir); + } + waterZAng = P_ReturnThrustX(mobj, dir - moveDir, AngleFixed(workang)); } - if (ourZAng != waterZAng) + if (abs(ourZAng - waterZAng) > 11*FRACUNIT) { - // The surface slopes are different. + // The surface slopes are too different. return false; } From a558c4f5c0f3bfa52994cdc7cc92d0d536c146bc Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 18 Nov 2022 19:39:56 +0000 Subject: [PATCH 71/81] Waterskiing stepdown improvement Only prohibits when there's a valid stepdown if the object is on a sloping surface. Fixes Mega Aqua Lake without breaking Water Palace or a modified Nova Shore (after addition of an extra downward slope) --- src/p_mobj.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index c010e98e2..a7bb2fb32 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3119,9 +3119,6 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) fixed_t surfaceheight = INT32_MAX; fixed_t surfDiff = INT32_MAX; - fixed_t floorheight = INT32_MAX; - fixed_t floorDiff = INT32_MAX; - fixed_t mobjbottom = INT32_MAX; fixed_t maxStep = INT32_MAX; boolean doifit = false; @@ -3210,16 +3207,20 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) maxStep = P_GetThingStepUp(mobj, mobj->x, mobj->y); surfDiff = flip ? (surfaceheight - mobjbottom) : (mobjbottom - surfaceheight); + + // We start water run IF we can step onto it! if (surfDiff <= maxStep && surfDiff >= 0) { - // We start water run IF we can step-down! - floorheight = flip ? P_GetSectorCeilingZAt(mobj->subsector->sector, mobj->x, mobj->y) : P_GetSectorFloorZAt(mobj->subsector->sector, mobj->x, mobj->y); - floorDiff = flip ? (floorheight - mobjbottom) : (mobjbottom - floorheight); - if (floorDiff <= maxStep && floorDiff >= 0) + if (ourZAng < 0) { - // ... but NOT if real floor is in range. - // FIXME: Count solid FOFs in this check - return false; + fixed_t floorheight = flip ? P_GetSectorCeilingZAt(mobj->subsector->sector, mobj->x, mobj->y) : P_GetSectorFloorZAt(mobj->subsector->sector, mobj->x, mobj->y); + fixed_t floorDiff = flip ? (floorheight - mobjbottom) : (mobjbottom - floorheight); + if (floorDiff <= maxStep && floorDiff >= -maxStep) + { + // ... but NOT if going down and real floor is in range. + // FIXME: Count solid FOFs in this check + return false; + } } return true; From 70d83da50717bfde20b2b7d158ffad36a4775f95 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 18 Nov 2022 19:59:15 +0000 Subject: [PATCH 72/81] More lenient waterskip per VC discussion --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 583639b9c..24f560e2c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3430,7 +3430,7 @@ boolean K_TripwirePass(player_t *player) boolean K_MovingHorizontally(mobj_t *mobj) { - return (P_AproxDistance(mobj->momx, mobj->momy) / 5 > abs(mobj->momz)); + return (P_AproxDistance(mobj->momx, mobj->momy) / 4 > abs(mobj->momz)); } boolean K_WaterRun(mobj_t *mobj) From 4235798d8acf1bf9736b1d00cc78d3391c5212a5 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 18 Nov 2022 20:05:09 +0000 Subject: [PATCH 73/81] Revert "Make the second page of cups accessible by up/down input at the limit, rather than left/right input" This reverts commit f01bb3e793fadc55ce441c2748dd5b4688ce2755. --- src/k_menufunc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 7c06c3ecd..73eeb4aef 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3528,7 +3528,12 @@ void M_CupSelectHandler(INT32 choice) { cupgrid.x++; if (cupgrid.x >= CUPMENU_COLUMNS) + { cupgrid.x = 0; + cupgrid.pageno++; + if (cupgrid.pageno >= cupgrid.numpages) + cupgrid.pageno = 0; + } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -3536,7 +3541,12 @@ void M_CupSelectHandler(INT32 choice) { cupgrid.x--; if (cupgrid.x < 0) + { cupgrid.x = CUPMENU_COLUMNS-1; + cupgrid.pageno--; + if (cupgrid.pageno < 0) + cupgrid.pageno = cupgrid.numpages-1; + } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -3545,12 +3555,7 @@ void M_CupSelectHandler(INT32 choice) { cupgrid.y++; if (cupgrid.y >= CUPMENU_ROWS) - { cupgrid.y = 0; - cupgrid.pageno--; - if (cupgrid.pageno < 0) - cupgrid.pageno = cupgrid.numpages-1; - } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -3558,12 +3563,7 @@ void M_CupSelectHandler(INT32 choice) { cupgrid.y--; if (cupgrid.y < 0) - { cupgrid.y = CUPMENU_ROWS-1; - cupgrid.pageno++; - if (cupgrid.pageno >= cupgrid.numpages) - cupgrid.pageno = 0; - } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } From 3ef98fd80d2d9fe53f5cef7c1386acc4db1c6323 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 18 Nov 2022 20:08:52 +0000 Subject: [PATCH 74/81] Don't use a seperate count, I literally forgot id is useful for this --- src/k_menufunc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 73eeb4aef..ab43217ff 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3430,7 +3430,7 @@ static void M_LevelListFromGametype(INT16 gt) if (levellist.newgametype == GT_RACE) { cupheader_t *cup = kartcupheaders; - UINT8 highestid = 0, count = 0; + UINT8 highestid = 0; // Make sure there's valid cups before going to this menu. if (cup == NULL) @@ -3443,11 +3443,10 @@ static void M_LevelListFromGametype(INT16 gt) highestid = cup->id; if (Playing() && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == cup) { - cupgrid.x = count % CUPMENU_COLUMNS; - cupgrid.y = (count / CUPMENU_COLUMNS) % CUPMENU_ROWS; - cupgrid.pageno = count / (CUPMENU_COLUMNS * CUPMENU_ROWS); + cupgrid.x = cup->id % CUPMENU_COLUMNS; + cupgrid.y = (cup->id / CUPMENU_COLUMNS) % CUPMENU_ROWS; + cupgrid.pageno = cup->id / (CUPMENU_COLUMNS * CUPMENU_ROWS); } - count++; } cup = cup->next; } From d0b86ee7ed95a54f85c44112418062d9c8a399fc Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 18 Nov 2022 15:55:47 -0500 Subject: [PATCH 75/81] Add banana death particles --- src/deh_tables.c | 6 ++++++ src/info.c | 33 +++++++++++++++++++++++++++++++++ src/info.h | 7 +++++++ src/p_inter.c | 26 ++++++++++++++++++++++++++ src/p_mobj.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 17242ba29..82bd0b0be 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3488,6 +3488,11 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_BANANA", "S_BANANA_DEAD", + "S_BANANA_SPARK", + "S_BANANA_SPARK2", + "S_BANANA_SPARK3", + "S_BANANA_SPARK4", + //{ Orbinaut "S_ORBINAUT1", "S_ORBINAUT2", @@ -5311,6 +5316,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BANANA", // Banana Stuff "MT_BANANA_SHIELD", + "MT_BANANA_SPARK", "MT_ORBINAUT", // Orbinaut stuff "MT_ORBINAUT_SHIELD", diff --git a/src/info.c b/src/info.c index b39ee8f10..bbda140f6 100644 --- a/src/info.c +++ b/src/info.c @@ -557,6 +557,7 @@ char sprnames[NUMSPRITES + 1][5] = "RSHE", // Rocket sneaker "FITM", // Eggman Monitor "BANA", // Banana Peel + "BAND", // Banana Peel death particles "ORBN", // Orbinaut "JAWZ", // Jawz "SSMN", // SS Mine @@ -4079,6 +4080,11 @@ state_t states[NUMSTATES] = {SPR_BANA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BANANA {SPR_BANA, 1, 175, {NULL}, 0, 0, S_NULL}, // S_BANANA_DEAD + {SPR_BAND, 0, -1, {NULL}, 0, 0, S_BANANA_SPARK2}, // S_BANANA_SPARK + {SPR_BAND, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BANANA_SPARK3}, // S_BANANA_SPARK2 + {SPR_BAND, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BANANA_SPARK4}, // S_BANANA_SPARK3 + {SPR_BAND, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BANANA_SPARK4 + {SPR_ORBN, 0, 1, {NULL}, 0, 0, S_ORBINAUT2}, // S_ORBINAUT1 {SPR_ORBN, 1, 1, {NULL}, 0, 0, S_ORBINAUT3}, // S_ORBINAUT2 {SPR_ORBN, 2, 1, {NULL}, 0, 0, S_ORBINAUT4}, // S_ORBINAUT3 @@ -23121,6 +23127,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BANANA_SPARK + -1, // doomednum + S_BANANA_SPARK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BANANA_SPARK2,// deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 4*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_DONTENCOREMAP|MF_NOCLIPTHING|MF_NOSQUISH, // flags + S_NULL // raisestate + }, + { // MT_ORBINAUT -1, // doomednum S_ORBINAUT1, // spawnstate diff --git a/src/info.h b/src/info.h index 408d85832..78fc6e2db 100644 --- a/src/info.h +++ b/src/info.h @@ -1103,6 +1103,7 @@ typedef enum sprite SPR_RSHE, // Rocket sneaker SPR_FITM, // Eggman Monitor SPR_BANA, // Banana Peel + SPR_BAND, // Banana Peel death particles SPR_ORBN, // Orbinaut SPR_JAWZ, // Jawz SPR_SSMN, // SS Mine @@ -4500,6 +4501,11 @@ typedef enum state S_BANANA, S_BANANA_DEAD, + S_BANANA_SPARK, + S_BANANA_SPARK2, + S_BANANA_SPARK3, + S_BANANA_SPARK4, + //{ Orbinaut S_ORBINAUT1, S_ORBINAUT2, @@ -6359,6 +6365,7 @@ typedef enum mobj_type MT_BANANA, // Banana Stuff MT_BANANA_SHIELD, + MT_BANANA_SPARK, MT_ORBINAUT, // Orbinaut stuff MT_ORBINAUT_SHIELD, diff --git a/src/p_inter.c b/src/p_inter.c index 8f439ff89..494844360 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1585,6 +1585,32 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->fuse = 1; break; + case MT_BANANA: + case MT_BANANA_SHIELD: + { + const UINT8 numParticles = 8; + const angle_t diff = ANGLE_MAX / numParticles; + UINT8 i; + + for (i = 0; i < numParticles; i++) + { + mobj_t *spark = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_BANANA_SPARK); + spark->angle = (diff * i) - (diff / 2); + + if (inflictor != NULL && P_MobjWasRemoved(inflictor) == false) + { + spark->angle += K_MomentumAngle(inflictor); + spark->momx += inflictor->momx / 2; + spark->momy += inflictor->momy / 2; + spark->momz += inflictor->momz / 2; + } + + P_SetObjectMomZ(spark, (12 + P_RandomRange(PR_DECORATION, -4, 4)) * FRACUNIT, true); + P_Thrust(spark, spark->angle, (12 + P_RandomRange(PR_DECORATION, -4, 4)) * spark->scale); + } + break; + } + default: break; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 04462afb5..794e3a0be 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6495,7 +6495,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj) break; case MT_BANANA: { - angle_t spin = FixedMul(FixedDiv(mobj->momz, 8 * mobj->scale), ANGLE_67h); + angle_t spin = FixedMul(FixedDiv(abs(mobj->momz), 8 * mobj->scale), ANGLE_67h); mobj->angle -= spin; mobj->rollangle += spin; @@ -6506,6 +6506,12 @@ static boolean P_MobjDeadThink(mobj_t *mobj) } } break; + case MT_BANANA_SPARK: + { + angle_t spin = FixedMul(FixedDiv(abs(mobj->momz), 8 * mobj->scale), ANGLE_22h); + mobj->rollangle += spin; + } + break; case MT_ORBINAUT: case MT_EGGMANITEM: case MT_LANDMINE: @@ -6960,7 +6966,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) else { // tilt n tumble - angle_t spin = FixedMul(FixedDiv(mobj->momz, 8 * mobj->scale), ANGLE_67h); + angle_t spin = FixedMul(FixedDiv(abs(mobj->momz), 8 * mobj->scale), ANGLE_67h); mobj->angle += spin; mobj->rollangle -= spin; } @@ -6968,6 +6974,39 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->threshold > 0) mobj->threshold--; break; + case MT_BANANA_SPARK: + { + if (leveltime & 1) + { + mobj->spritexscale = mobj->spriteyscale = FRACUNIT; + } + else + { + if ((leveltime / 2) & 1) + { + mobj->spriteyscale = 3*FRACUNIT/2; + } + else + { + mobj->spritexscale = 3*FRACUNIT/2; + } + } + + if (P_IsObjectOnGround(mobj) == true && mobj->momz * P_MobjFlip(mobj) <= 0) + { + P_SetObjectMomZ(mobj, 8*FRACUNIT, false); + + if (mobj->health > 0) + { + mobj->tics = 1; + mobj->destscale = 0; + mobj->spritexscale = mobj->spriteyscale = FRACUNIT; + mobj->health = 0; + } + } + + break; + } case MT_SPB: { Obj_SPBThink(mobj); @@ -13694,6 +13733,8 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo if (!newmobj) return NULL; + newmobj->hitlag = mobj->hitlag; + newmobj->destscale = P_ScaleFromMap(mobj->destscale, newmobj->destscale); P_SetScale(newmobj, P_ScaleFromMap(mobj->scale, newmobj->scale)); From cf49a0df6ad40288ea9ee0bc43f7691cc353af7c Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Nov 2022 00:32:52 +0000 Subject: [PATCH 76/81] Flung rings from grow/shrunk players are now at mapobjectscale rather than player scale This is a HUGE pet peeve of mine considering how ring scale is otherwise very, very consistent and uncoupled --- src/p_inter.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_inter.c b/src/p_inter.c index 8f439ff89..2f2f95d56 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2256,6 +2256,9 @@ static void P_FlingBurst mo->fuse = objFuse; P_SetTarget(&mo->target, player->mo); + // We want everything from P_SpawnMobjFromMobj except scale. + objScale = FixedMul(objScale, FixedDiv(mapobjectscale, player->mo->scale)); + if (objScale != FRACUNIT) { P_SetScale(mo, FixedMul(objScale, mo->scale)); From 73cc93a76f222e005052ec02a994243c081a4587 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Nov 2022 00:36:27 +0000 Subject: [PATCH 77/81] WIP: Attempt to make shrink/grow tricks consistent with mapobjectscale tricks. Now the opposite problem - slightly too high momentum for shrink, slightly low momentum for grow. Some other factor I haven't considered..? Would VERY much appreciate an assist. --- src/k_kart.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 583639b9c..f64ce421b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6568,6 +6568,7 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) mo->player->tricktime = 0; // Reset post-hitlag timer // Setup the boost for potential upwards trick, at worse, make it your regular max speed. (boost = curr speed*1.25) mo->player->trickboostpower = max(FixedDiv(mo->player->speed, K_GetKartSpeed(mo->player, false, false)) - FRACUNIT, 0)*125/100; + mo->player->trickboostpower = FixedMul(mo->player->trickboostpower, FixedDiv(mapobjectscale, mo->scale)); //CONS_Printf("Got boost: %d%\n", mo->player->trickboostpower*100 / FRACUNIT); } @@ -11361,9 +11362,10 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { const angle_t lr = ANGLE_45; fixed_t momz = FixedDiv(player->mo->momz, mapobjectscale); // bring momz back to scale... + fixed_t invertscale = FixedDiv(mapobjectscale, player->mo->scale); fixed_t speedmult = max(0, FRACUNIT - abs(momz)/TRICKMOMZRAMP); // TRICKMOMZRAMP momz is minimum speed (Should be 20) - fixed_t basespeed = K_GetKartSpeed(player, false, false); // at WORSE, keep your normal speed when tricking. - fixed_t speed = FixedMul(speedmult, P_AproxDistance(player->mo->momx, player->mo->momy)); + fixed_t basespeed = FixedMul(invertscale, K_GetKartSpeed(player, false, false)); // at WORSE, keep your normal speed when tricking. + fixed_t speed = FixedMul(invertscale, FixedMul(speedmult, P_AproxDistance(player->mo->momx, player->mo->momy))); K_trickPanelTimingVisual(player, momz); @@ -11466,7 +11468,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->trickboostdecay = min(TICRATE*3/4, abs(momz/FRACUNIT)); //CONS_Printf("decay: %d\n", player->trickboostdecay); - P_SetObjectMomZ(player->mo, 48*FRACUNIT, relative); + P_SetObjectMomZ(player->mo, 48*invertscale, relative); player->trickpanel = 4; } } From ea74a219e51dda0bb46fa3296abc8807dc3c2894 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Nov 2022 00:48:50 +0000 Subject: [PATCH 78/81] Use K_GrowShrinkSpeedMul instead of custom-built scale inversion (THANKYOUSAL!!!!!!!!!!!) --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index f64ce421b..a2a114057 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6568,7 +6568,7 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) mo->player->tricktime = 0; // Reset post-hitlag timer // Setup the boost for potential upwards trick, at worse, make it your regular max speed. (boost = curr speed*1.25) mo->player->trickboostpower = max(FixedDiv(mo->player->speed, K_GetKartSpeed(mo->player, false, false)) - FRACUNIT, 0)*125/100; - mo->player->trickboostpower = FixedMul(mo->player->trickboostpower, FixedDiv(mapobjectscale, mo->scale)); + mo->player->trickboostpower = FixedDiv(mo->player->trickboostpower, K_GrowShrinkSpeedMul(mo->player)); //CONS_Printf("Got boost: %d%\n", mo->player->trickboostpower*100 / FRACUNIT); } @@ -11362,7 +11362,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { const angle_t lr = ANGLE_45; fixed_t momz = FixedDiv(player->mo->momz, mapobjectscale); // bring momz back to scale... - fixed_t invertscale = FixedDiv(mapobjectscale, player->mo->scale); + fixed_t invertscale = FixedDiv(FRACUNIT, K_GrowShrinkSpeedMul(player)); fixed_t speedmult = max(0, FRACUNIT - abs(momz)/TRICKMOMZRAMP); // TRICKMOMZRAMP momz is minimum speed (Should be 20) fixed_t basespeed = FixedMul(invertscale, K_GetKartSpeed(player, false, false)); // at WORSE, keep your normal speed when tricking. fixed_t speed = FixedMul(invertscale, FixedMul(speedmult, P_AproxDistance(player->mo->momx, player->mo->momy))); From 1c8e5b3418d69c6ef7b78d8060ec22db224c4eab Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Nov 2022 01:01:10 +0000 Subject: [PATCH 79/81] Make momz always base-scale handled, to match how gravity works --- src/k_kart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index a2a114057..0fd3f723b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -11452,14 +11452,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else if (cmd->throwdir < 0) { - boolean relative = true; - player->mo->momx /= 3; player->mo->momy /= 3; if (player->mo->momz * P_MobjFlip(player->mo) <= 0) { - relative = false; + player->mo->momz = 0; // relative = false; } // Calculate speed boost decay: @@ -11468,7 +11466,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->trickboostdecay = min(TICRATE*3/4, abs(momz/FRACUNIT)); //CONS_Printf("decay: %d\n", player->trickboostdecay); - P_SetObjectMomZ(player->mo, 48*invertscale, relative); + player->mo->momz += P_MobjFlip(player->mo)*48*mapobjectscale; player->trickpanel = 4; } } From 4316169d99eda3542961b421c8c78af5ce2de449 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Nov 2022 01:37:12 -0800 Subject: [PATCH 80/81] Fix -Wtype-limits This subtraction cannot yield a negative value, even if the type were signed, so the max is useless. --- 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 a1cb40085..4a5644442 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1611,7 +1611,7 @@ static void K_DrawKartPositionNum(INT32 num) if (leveltime < (starttime + NUMTRANSMAPS)) { - trans = max(0, (starttime + NUMTRANSMAPS) - leveltime); + trans = (starttime + NUMTRANSMAPS) - leveltime; } if (trans >= NUMTRANSMAPS) From ad464817dda7e4bce4366e29d7bbfd0cdb3323c6 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Nov 2022 01:39:51 -0800 Subject: [PATCH 81/81] Fix -Wunused-variable and -Wunused-parameter blame 2304ef28a5 --- src/sdl/i_video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 6bb131777..5e97694ad 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -186,13 +186,15 @@ static void Impl_SetWindowIcon(void); static void Impl_SetSoftwareVsync(int vsync) { - static int oldvsync = 0; #if SDL_VERSION_ATLEAST(2,0,18) + static int oldvsync = 0; if (oldvsync != vsync) { SDL_RenderSetVSync(renderer, vsync); } oldvsync = vsync; +#else + (void)vsync; #endif }