From c4fd7d74dd56e2e03b17a992b35ddd3e7ba8cdda Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 4 Nov 2022 16:11:50 +0000 Subject: [PATCH 01/56] 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 02/56] 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 03/56] 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 04/56] 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 05/56] 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 06/56] 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 07/56] 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 08/56] 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 09/56] 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 10/56] 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 11/56] 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 12/56] 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 13/56] 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 14/56] 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 368a45c6742ac765aa0c0fde1b76aa49dd19dbf8 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 22:15:08 +0000 Subject: [PATCH 15/56] 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 16/56] 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 17/56] 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 18/56] 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 19/56] 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 20/56] 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 21/56] 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 22/56] 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 492c068cdddafb3d22c1ad1c3959bf757b862eed Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 12 Nov 2022 09:48:59 -0500 Subject: [PATCH 23/56] 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 24/56] 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 25/56] 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 26/56] 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 27/56] 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 28/56] 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 29/56] 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 30/56] 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 31/56] 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 32/56] 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 33/56] 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 34/56] 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 35/56] 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 36/56] 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 37/56] 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 38/56] 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 39/56] 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 40/56] 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 41/56] 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 42/56] 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 43/56] 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 44/56] 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 45/56] 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 46/56] 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 47/56] 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 48/56] 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 49/56] 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 50/56] 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 51/56] 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 52/56] 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 53/56] 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 54/56] 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 55/56] 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 56/56] 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 }