From 5f9854e89800bba611215308b0190a44c2dfc2f8 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Dec 2022 19:10:59 +0000 Subject: [PATCH 01/28] First steps to making battle maps cup-based. * Permit a map existing in multiple cups, rather than I_Error - The reason we didn't permit this before was because of marathon plans/advancemap next. - To that end, in that progression type, a map is only considered in its first valid cup. --- src/deh_soc.c | 5 +++++ src/g_game.c | 6 ++++++ src/p_setup.c | 8 ++------ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index f23c71970..5b007d4f9 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3078,6 +3078,7 @@ void readcupheader(MYFILE *f, cupheader_t *cup) if (cup->cachedlevels[cup->numlevels] == NEXTMAP_INVALID) continue; mapheaderinfo[cup->cachedlevels[cup->numlevels]]->cup = NULL; + cup->cachedlevels[cup->numlevels] = NEXTMAP_INVALID; } tmp = strtok(word2,","); @@ -3100,6 +3101,10 @@ void readcupheader(MYFILE *f, cupheader_t *cup) cup->numbonus--; Z_Free(cup->levellist[CUPCACHE_BONUS + cup->numbonus]); cup->levellist[CUPCACHE_BONUS + cup->numbonus] = NULL; + if (cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus] == NEXTMAP_INVALID) + continue; + mapheaderinfo[cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus]]->cup = NULL; + cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus] = NEXTMAP_INVALID; } tmp = strtok(word2,","); diff --git a/src/g_game.c b/src/g_game.c index ab4b6bc9c..1bcbd5555 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3891,6 +3891,12 @@ static void G_GetNextMap(void) || (!marathonmode && M_MapLocked(cm+1))) continue; + // If the map is in multiple cups, only consider the first one valid. + if (mapheaderinfo[cm]->cup != cup) + { + continue; + } + // Grab the first valid after the map you're on if (gettingresult) { diff --git a/src/p_setup.c b/src/p_setup.c index 6a1c5c049..0130acc86 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7794,13 +7794,9 @@ UINT8 P_InitMapData(boolean existingmapheaders) if (strcasecmp(cup->levellist[j], name) != 0) continue; - // Only panic about back-reference for non-bonus material. - if (j < MAXLEVELLIST) - { - if (mapheaderinfo[i]->cup) - I_Error("P_InitMapData: Map %s cannot appear in cups multiple times! (First in %s, now in %s)", name, mapheaderinfo[i]->cup->name, cup->name); + // Have a map recognise the first cup it's a part of. + if (!mapheaderinfo[i]->cup) mapheaderinfo[i]->cup = cup; - } cup->cachedlevels[j] = i; } From 6659e78c04e8bce893249aa2668243f015806eab Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 01:08:18 +0000 Subject: [PATCH 02/28] Battle cups - The cups they're associated with for GP Bonus Round - Fixes the issue where when opening Ring Cup, Green Hills would be first in the listing because its header is defined before the rest of the cup's maps - One core set of functions that works between multiple modes Will merge conflict with Unlockables Undefeatable --- src/k_menu.h | 15 +++-- src/k_menudraw.c | 64 ++++++++++-------- src/k_menufunc.c | 167 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 175 insertions(+), 71 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index d8a966775..99120b97d 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -679,8 +679,10 @@ void M_SetupRaceMenu(INT32 choice); extern struct cupgrid_s { SINT8 x, y; - SINT8 pageno; - UINT8 numpages; + size_t pageno; + cupheader_t **builtgrid; + size_t numpages; + size_t cappages; tic_t previewanim; boolean grandprix; // Setup grand prix server after picking boolean netgame; // Start the game in an actual server @@ -693,13 +695,16 @@ extern struct levellist_s { cupheader_t *selectedcup; INT16 choosemap; UINT8 newgametype; + UINT32 typeoflevel; + boolean cupmode; boolean timeattack; // Setup time attack menu after picking boolean netgame; // Start the game in an actual server } levellist; -boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt); -INT16 M_CountLevelsToShowInList(UINT8 gt); -INT16 M_GetFirstLevelInList(UINT8 gt); +boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol); +INT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup); +INT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup); +INT16 M_GetNextLevelInList(INT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup); void M_LevelSelectInit(INT32 choice); void M_CupSelectHandler(INT32 choice); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 71f8b4242..51d1311c9 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1902,31 +1902,52 @@ void M_DrawRaceDifficulty(void) static void M_DrawCupPreview(INT16 y, cupheader_t *cup) { - UINT8 i; - const INT16 pad = ((vid.width/vid.dupx) - BASEVIDWIDTH)/2; - INT16 x = -(cupgrid.previewanim % 82) - pad; + UINT8 i = 0; + INT16 maxlevels = M_CountLevelsToShowInList(levellist.typeoflevel, cup); + INT16 x = -(cupgrid.previewanim % 82); + INT16 add; + INT16 map, start = M_GetFirstLevelInList(&i, levellist.typeoflevel, cup); + UINT8 starti = i; V_DrawFill(0, y, BASEVIDWIDTH, 54, 31); if (cup && (cup->unlockrequired == -1 || unlockables[cup->unlockrequired].unlocked)) { - i = (cupgrid.previewanim / 82) % cup->numlevels; - while (x < BASEVIDWIDTH + pad) + add = (cupgrid.previewanim / 82) % maxlevels; + map = start; + while (add > 0) + { + map = M_GetNextLevelInList(map, &i, levellist.typeoflevel, cup); + + if (map >= nummapheaders) + { + break; + } + + add--; + } + while (x < BASEVIDWIDTH) { - INT32 cupLevelNum = cup->cachedlevels[i]; patch_t *PictureOfLevel = NULL; - if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) + if (map >= nummapheaders) { - PictureOfLevel = mapheaderinfo[cupLevelNum]->thumbnailPic; + map = start; + i = starti; + } + + if (map < nummapheaders && mapheaderinfo[map]) + { + PictureOfLevel = mapheaderinfo[map]->thumbnailPic; } if (!PictureOfLevel) PictureOfLevel = blanklvl; V_DrawSmallScaledPatch(x + 1, y+2, 0, PictureOfLevel); - i = (i+1) % cup->numlevels; x += 82; + + map = M_GetNextLevelInList(map, &i, levellist.typeoflevel, cup); } } else @@ -1983,19 +2004,12 @@ void M_DrawCupSelect(void) { for (j = 0; j < CUPMENU_ROWS; j++) { - UINT8 id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS)); - cupheader_t *iconcup = kartcupheaders; + size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS)); + cupheader_t *iconcup = cupgrid.builtgrid[id]; patch_t *patch = NULL; INT16 x, y; INT16 icony = 7; - while (iconcup) - { - if (iconcup->id == id) - break; - iconcup = iconcup->next; - } - if (!iconcup) break; @@ -2167,9 +2181,9 @@ static void M_DrawLevelSelectBlock(INT16 x, INT16 y, INT16 map, boolean redblink void M_DrawLevelSelect(void) { - INT16 i; - INT16 start = M_GetFirstLevelInList(levellist.newgametype); - INT16 map = start; + INT16 i = 0; + UINT8 j = 0; + INT16 map = M_GetFirstLevelInList(&j, levellist.typeoflevel, levellist.selectedcup); INT16 t = (64*menutransition.tics), tay = 0; INT16 y = 80 - (12 * levellist.y); boolean tatransition = ((menutransition.startmenu == &PLAY_TimeAttackDef || menutransition.endmenu == &PLAY_TimeAttackDef) && menutransition.tics); @@ -2180,13 +2194,10 @@ void M_DrawLevelSelect(void) tay = t/2; } - for (i = 0; i < M_CountLevelsToShowInList(levellist.newgametype); i++) + while (true) { INT16 lvlx = t, lvly = y; - while (!M_CanShowLevelInList(map, levellist.newgametype) && map < nummapheaders) - map++; - if (map >= nummapheaders) break; @@ -2202,7 +2213,8 @@ void M_DrawLevelSelect(void) ); y += 72; - map++; + i++; + map = M_GetNextLevelInList(map, &j, levellist.typeoflevel, levellist.selectedcup); } M_DrawCupTitle(tay, levellist.selectedcup); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 384905f71..cc7475106 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3339,9 +3339,10 @@ void M_SetupDifficultySelect(INT32 choice) // Determines whether to show a given map in the various level-select lists. // Set gt = -1 to ignore gametype. // -boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) +boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol) { - UINT32 tolflag = G_TOLFlag(gt); + if (mapnum >= nummapheaders) + return false; // Does the map exist? if (!mapheaderinfo[mapnum]) @@ -3359,7 +3360,7 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) return false; // not unlocked // Check for TOL - if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag)) + if (!(mapheaderinfo[mapnum]->typeoflevel & tol)) return false; // Should the map be hidden? @@ -3370,36 +3371,93 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) if (levellist.timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK)) return false; +#if 0 if (gametypedefaultrules[gt] & GTR_CAMPAIGN && levellist.selectedcup) { if (mapheaderinfo[mapnum]->cup != levellist.selectedcup) return false; } +#else + // Don't permit cups if not cupmode + if (!levellist.cupmode && (mapheaderinfo[mapnum]->cup != NULL)) + return false; +#endif // Survived our checks. return true; } -INT16 M_CountLevelsToShowInList(UINT8 gt) +INT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup) { - INT16 mapnum, count = 0; + INT16 i, count = 0; - for (mapnum = 0; mapnum < nummapheaders; mapnum++) - if (M_CanShowLevelInList(mapnum, gt)) + if (cup) + { + for (i = 0; i < CUPCACHE_MAX; i++) + { + if (!M_CanShowLevelInList(cup->cachedlevels[i], tol)) + continue; + count++; + } + + return count; + } + + for (i = 0; i < nummapheaders; i++) + if (M_CanShowLevelInList(i, tol)) count++; return count; } -INT16 M_GetFirstLevelInList(UINT8 gt) +INT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup) { - INT16 mapnum; + INT16 mapnum = NEXTMAP_INVALID; - for (mapnum = 0; mapnum < nummapheaders; mapnum++) - if (M_CanShowLevelInList(mapnum, gt)) - return mapnum; + if (cup) + { + *i = 0; + mapnum = NEXTMAP_INVALID; + for (; *i < CUPCACHE_MAX; (*i)++) + { + if (!M_CanShowLevelInList(cup->cachedlevels[*i], tol)) + continue; + mapnum = cup->cachedlevels[*i]; + break; + } + } + else + { + for (mapnum = 0; mapnum < nummapheaders; mapnum++) + if (M_CanShowLevelInList(mapnum, tol)) + break; + } - return 0; + return mapnum; +} + +INT16 M_GetNextLevelInList(INT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup) +{ + if (cup) + { + map = NEXTMAP_INVALID; + (*i)++; + for (; *i < CUPCACHE_MAX; (*i)++) + { + if (!M_CanShowLevelInList(cup->cachedlevels[*i], tol)) + continue; + map = cup->cachedlevels[*i]; + break; + } + } + else + { + map++; + while (!M_CanShowLevelInList(map, levellist.typeoflevel) && map < nummapheaders) + map++; + } + + return map; } struct cupgrid_s cupgrid; @@ -3407,7 +3465,7 @@ struct levellist_s levellist; static void M_LevelSelectScrollDest(void) { - UINT16 m = M_CountLevelsToShowInList(levellist.newgametype)-1; + UINT16 m = M_CountLevelsToShowInList(levellist.typeoflevel, levellist.selectedcup)-1; levellist.dest = (6*levellist.cursor); @@ -3421,26 +3479,61 @@ static void M_LevelSelectScrollDest(void) // Builds the level list we'll be using from the gametype we're choosing and send us to the apropriate menu. static void M_LevelListFromGametype(INT16 gt) { - levellist.newgametype = gt; + static boolean first = true; + if (first || gt != levellist.newgametype) + { + levellist.newgametype = gt; + levellist.typeoflevel = G_TOLFlag(gt); + levellist.cupmode = true; // todo some way to choose going direct to a long consecutive list..? + levellist.selectedcup = NULL; + first = false; + } + PLAY_CupSelectDef.prevMenu = currentMenu; // Obviously go to Cup Select in gametypes that have cups. // Use a really long level select in gametypes that don't use cups. - if (levellist.newgametype == GT_RACE) + if (levellist.cupmode) { cupheader_t *cup = kartcupheaders; - UINT8 highestid = 0; + size_t currentid = 0, highestunlockedid = 0; // Make sure there's valid cups before going to this menu. if (cup == NULL) I_Error("Can you really call this a racing game, I didn't recieve any Cups on my pillow or anything"); + if (!cupgrid.builtgrid) + { + cupgrid.cappages = 2; + cupgrid.builtgrid = Z_Calloc( + sizeof(cupheader_t*) * cupgrid.cappages * (CUPMENU_COLUMNS * CUPMENU_ROWS), + PU_STATIC, NULL); + } + memset(cupgrid.builtgrid, 0, sizeof(cupheader_t*) * cupgrid.cappages * (CUPMENU_COLUMNS * CUPMENU_ROWS)); + while (cup) { + if (!M_CountLevelsToShowInList(levellist.typeoflevel, cup)) + { + // No valid maps, skip. + cup = cup->next; + continue; + } + + if (((currentid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1) >= cupgrid.cappages) + { + cupgrid.cappages *= 2; + cupgrid.builtgrid = Z_Realloc(cupgrid.builtgrid, + sizeof(cupheader_t*) * cupgrid.cappages * (CUPMENU_COLUMNS * CUPMENU_ROWS), + PU_STATIC, NULL); + } + + cupgrid.builtgrid[currentid] = cup; + if (cup->unlockrequired == -1 || unlockables[cup->unlockrequired].unlocked) { - highestid = cup->id; + highestunlockedid = currentid; if (Playing() && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == cup) { cupgrid.x = cup->id % CUPMENU_COLUMNS; @@ -3448,10 +3541,12 @@ static void M_LevelListFromGametype(INT16 gt) cupgrid.pageno = cup->id / (CUPMENU_COLUMNS * CUPMENU_ROWS); } } + + currentid++; cup = cup->next; } - cupgrid.numpages = (highestid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1; + cupgrid.numpages = (highestunlockedid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1; PLAY_LevelSelectDef.prevMenu = &PLAY_CupSelectDef; M_SetupNextMenu(&PLAY_CupSelectDef, false); @@ -3504,25 +3599,15 @@ void M_LevelSelectInit(INT32 choice) return; } - levellist.newgametype = currentMenu->menuitems[itemOn].mvar2; - - M_LevelListFromGametype(levellist.newgametype); + M_LevelListFromGametype(currentMenu->menuitems[itemOn].mvar2); } void M_CupSelectHandler(INT32 choice) { - cupheader_t *newcup = kartcupheaders; const UINT8 pid = 0; (void)choice; - while (newcup) - { - if (newcup->id == CUPMENU_CURSORID) - break; - newcup = newcup->next; - } - if (menucmd[pid].dpad_lr > 0) { cupgrid.x++; @@ -3542,9 +3627,10 @@ void M_CupSelectHandler(INT32 choice) if (cupgrid.x < 0) { cupgrid.x = CUPMENU_COLUMNS-1; - cupgrid.pageno--; - if (cupgrid.pageno < 0) + if (cupgrid.pageno == 0) cupgrid.pageno = cupgrid.numpages-1; + else + cupgrid.pageno--; } S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); @@ -3569,6 +3655,8 @@ void M_CupSelectHandler(INT32 choice) if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/) { + cupheader_t *newcup = cupgrid.builtgrid[CUPMENU_CURSORID]; + M_SetMenuDelay(pid); if ((!newcup) @@ -3640,7 +3728,7 @@ void M_CupSelectHandler(INT32 choice) else { // Keep cursor position if you select the same cup again, reset if it's a different cup - if (!levellist.selectedcup || newcup->id != levellist.selectedcup->id) + if (levellist.selectedcup != newcup) { levellist.cursor = 0; levellist.selectedcup = newcup; @@ -3671,8 +3759,7 @@ void M_CupSelectTick(void) void M_LevelSelectHandler(INT32 choice) { - INT16 start = M_GetFirstLevelInList(levellist.newgametype); - INT16 maxlevels = M_CountLevelsToShowInList(levellist.newgametype); + INT16 maxlevels = M_CountLevelsToShowInList(levellist.typeoflevel, levellist.selectedcup); const UINT8 pid = 0; (void)choice; @@ -3703,20 +3790,20 @@ void M_LevelSelectHandler(INT32 choice) if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/) { - INT16 map = start; + UINT8 i = 0; + INT16 map = M_GetFirstLevelInList(&i, levellist.typeoflevel, levellist.selectedcup); INT16 add = levellist.cursor; M_SetMenuDelay(pid); while (add > 0) { - map++; - - while (!M_CanShowLevelInList(map, levellist.newgametype) && map < nummapheaders) - map++; + map = M_GetNextLevelInList(map, &i, levellist.typeoflevel, levellist.selectedcup); if (map >= nummapheaders) + { break; + } add--; } From 12052a48de530ce9609b26253ab3aaf6af376adb Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 17 Dec 2022 20:09:23 -0800 Subject: [PATCH 03/28] Fix spring stars not spawning for upside down vertical springs --- 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 c7047bcde..9c9a71fdf 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -406,7 +406,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) K_TumbleInterrupt(object->player); P_ResetPlayer(object->player); - object->player->springstars = max(vertispeed, horizspeed) / FRACUNIT / 2; + object->player->springstars = max(abs(vertispeed), horizspeed) / FRACUNIT / 2; object->player->springcolor = starcolor; // Less friction when hitting springs From 659dc8270eeddbff17032b8281bae87a1f1972eb Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Dec 2022 01:10:34 -0500 Subject: [PATCH 04/28] Roulette speed thing - Slightly slower at start - More reasonable default --- src/k_roulette.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index ec15f4e9b..40cd68af4 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -821,7 +821,7 @@ static void K_InitRoulette(itemroulette_t *const roulette) roulette->secondToFirst = 0; roulette->elapsed = 0; - roulette->tics = roulette->speed = ROULETTE_SPEED_FASTEST; // Some default speed + roulette->tics = roulette->speed = ROULETTE_SPEED_TIMEATTACK; // Some default speed roulette->active = true; roulette->eggman = false; @@ -981,7 +981,7 @@ static void K_CalculateRouletteSpeed(itemroulette_t *const roulette) // Combine our two factors together. total = min(FRACUNIT, (frontRun / 2) + (progress / 2)); - if (leveltime < starttime + 20*TICRATE) + if (leveltime < starttime + 30*TICRATE) { // Don't impact as much at the start. // This makes it so that everyone gets to enjoy the lowest speed at the start. @@ -991,7 +991,7 @@ static void K_CalculateRouletteSpeed(itemroulette_t *const roulette) } else { - const fixed_t lerp = FixedDiv(leveltime - starttime, 20*TICRATE); + const fixed_t lerp = FixedDiv(leveltime - starttime, 30*TICRATE); total = FRACUNIT + FixedMul(lerp, total - FRACUNIT); } } From 84c571259fb41e88a765c9db095a8fc5031b1482 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Dec 2022 00:58:26 -0800 Subject: [PATCH 05/28] Don't show ebrake visuals for spectators --- src/k_kart.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 92fb5dbc5..00135cf88 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7732,7 +7732,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->tripwireState = TRIPSTATE_NONE; } - K_KartEbrakeVisuals(player); + if (player->spectator == false) + { + K_KartEbrakeVisuals(player); + } if (K_GetKartButtons(player) & BT_BRAKE && P_IsObjectOnGround(player->mo) && From 80d1b051b424ffb942dabc42889a7fd47cdeadd1 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Dec 2022 01:08:15 -0800 Subject: [PATCH 06/28] Rename patch.pk3 to scripts.pk3 --- src/d_main.c | 6 +++--- src/d_netfil.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index fe5046585..93da701ce 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1129,14 +1129,14 @@ static void IdentifyVersion(void) //// #define TEXTURESNAME "MISC_TEXTURES.pk3" #define MAPSNAME "MISC_MAPS.pk3" -#define PATCHNAME "MISC_PATCH.pk3" +#define PATCHNAME "MISC_SCRIPTS.pk3" #define MUSICNAME "MISC_MUSIC.PK3" //// #else //// #define TEXTURESNAME "textures.pk3" #define MAPSNAME "maps.pk3" -#define PATCHNAME "patch.pk3" +#define PATCHNAME "scripts.pk3" #define MUSICNAME "music.pk3" //// #endif @@ -1454,7 +1454,7 @@ void D_SRB2Main(void) mainwads++; // maps.pk3 mainwads++; // followers.pk3 #ifdef USE_PATCH_FILE - mainwads++; // patch.pk3 + mainwads++; // scripts.pk3 #endif #endif //ifndef DEVELOP diff --git a/src/d_netfil.c b/src/d_netfil.c index 246567c72..64b605d12 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1416,6 +1416,7 @@ void PT_FileFragment(void) || !strcmp(filename, "chars.pk3") || !strcmp(filename, "maps.pk3") || !strcmp(filename, "patch.pk3") + || !strcmp(filename, "scripts.pk3") || !strcmp(filename, "sounds.pk3") || !strcmp(filename, "music.pk3") ) From 134c4b7d66d376a57a088d90a5416257ef53c3ae Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Dec 2022 01:23:10 -0800 Subject: [PATCH 07/28] Buff Garden Top acceleration from 800% to 1200% --- 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 92fb5dbc5..5710bc12d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3099,9 +3099,9 @@ fixed_t K_GetKartAccel(player_t *player) if (gametype == GT_BATTLE && player->bumpers <= 0) k_accel *= 2; - // Marble Garden Top gets 800% accel + // Marble Garden Top gets 1200% accel if (player->curshield == KSHIELD_TOP) - k_accel *= 8; + k_accel *= 12; return FixedMul(k_accel, (FRACUNIT + player->accelboost) / 4); } From 6c75c9b2b1dfbb654c321c2ebe2281dae940d534 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Dec 2022 01:29:34 -0800 Subject: [PATCH 08/28] Backthrow Garden Top in look direction if on ground --- src/k_kart.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 5710bc12d..a3d8f6354 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10277,10 +10277,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { if (player->throwdir == -1) { + const angle_t angle = P_IsObjectOnGround(player->mo) ? + player->mo->angle : K_MomentumAngle(player->mo); + mobj_t *top = Obj_GardenTopDestroy(player); // Fly off the Top at high speed - P_Thrust(player->mo, K_MomentumAngle(player->mo), 80 * mapobjectscale); + P_InstaThrust(player->mo, angle, player->speed + (80 * mapobjectscale)); P_SetObjectMomZ(player->mo, player->mo->info->height / 8, true); top->momx = player->mo->momx; From 9f2a83fa0363d1084c1033eb41c70a513c76e8ed Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Dec 2022 01:42:23 -0800 Subject: [PATCH 09/28] Slightly decrease spindash charge time Also improve math precision by doing multiplication before division. --- 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 92fb5dbc5..57500df14 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2824,8 +2824,8 @@ static fixed_t K_FlameShieldDashVar(INT32 val) INT16 K_GetSpindashChargeTime(player_t *player) { // more charge time for higher speed - // Tails = 2s, Knuckles = 2.6s, Metal = 3.2s - return (player->kartspeed + 8) * (TICRATE/5); + // Tails = 1.7s, Knuckles = 2.2s, Metal = 2.7s + return ((player->kartspeed + 8) * TICRATE) / 6; } fixed_t K_GetSpindashChargeSpeed(player_t *player) From 286331b5c9c8263c8ffec2a77e6f461c200bcb9e Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 12:25:37 +0000 Subject: [PATCH 10/28] When doubling the `cupgrid.builtgrid`, memset the new region to prevent bad info --- src/k_menufunc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index cc7475106..f0278ac69 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3523,10 +3523,13 @@ static void M_LevelListFromGametype(INT16 gt) if (((currentid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1) >= cupgrid.cappages) { - cupgrid.cappages *= 2; + // Double the size of the buffer, and clear the other stuff. + size_t firstlen = sizeof(cupheader_t*) * cupgrid.cappages * (CUPMENU_COLUMNS * CUPMENU_ROWS); cupgrid.builtgrid = Z_Realloc(cupgrid.builtgrid, - sizeof(cupheader_t*) * cupgrid.cappages * (CUPMENU_COLUMNS * CUPMENU_ROWS), + firstlen * 2, PU_STATIC, NULL); + memset(cupgrid.builtgrid + firstlen, 0, firstlen); + cupgrid.cappages *= 2; } cupgrid.builtgrid[currentid] = cup; From 7ff46e31b4951c5728d2ec9c39f089d920812805 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 12:26:28 +0000 Subject: [PATCH 11/28] Fix usage of levellist.typeoflevel in M_GetNextLevelInList --- src/k_menufunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index f0278ac69..0ee5c95a3 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3453,7 +3453,7 @@ INT16 M_GetNextLevelInList(INT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup) else { map++; - while (!M_CanShowLevelInList(map, levellist.typeoflevel) && map < nummapheaders) + while (!M_CanShowLevelInList(map, tol) && map < nummapheaders) map++; } From d703a02e6cb412793f80deb856bb369a8dfd2121 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 13:12:05 +0000 Subject: [PATCH 12/28] Fix M_DrawCupSelect picking selected cup badly --- src/k_menudraw.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 51d1311c9..729f99464 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1991,14 +1991,7 @@ static void M_DrawCupTitle(INT16 y, cupheader_t *cup) void M_DrawCupSelect(void) { UINT8 i, j; - cupheader_t *cup = kartcupheaders; - - while (cup) - { - if (cup->id == CUPMENU_CURSORID) - break; - cup = cup->next; - } + cupheader_t *cup = cupgrid.builtgrid[CUPMENU_CURSORID]; for (i = 0; i < CUPMENU_COLUMNS; i++) { From ed85fb2e79130df00e0cac10c1a3bc16aa2fa922 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 13:20:50 +0000 Subject: [PATCH 13/28] Clean up cup-related conditions for M_CanShowLevelInList --- src/k_menu.h | 2 +- src/k_menufunc.c | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 99120b97d..ad76890ff 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -701,7 +701,7 @@ extern struct levellist_s { boolean netgame; // Start the game in an actual server } levellist; -boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol); +boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol, cupheader_t *cup); INT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup); INT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup); INT16 M_GetNextLevelInList(INT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 0ee5c95a3..06176cf26 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3337,9 +3337,8 @@ void M_SetupDifficultySelect(INT32 choice) // M_CanShowLevelInList // // Determines whether to show a given map in the various level-select lists. -// Set gt = -1 to ignore gametype. // -boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol) +boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol, cupheader_t *cup) { if (mapnum >= nummapheaders) return false; @@ -3371,17 +3370,9 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol) if (levellist.timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK)) return false; -#if 0 - if (gametypedefaultrules[gt] & GTR_CAMPAIGN && levellist.selectedcup) - { - if (mapheaderinfo[mapnum]->cup != levellist.selectedcup) - return false; - } -#else - // Don't permit cups if not cupmode - if (!levellist.cupmode && (mapheaderinfo[mapnum]->cup != NULL)) + // Don't permit cup when no cup requested + if (levellist.cupmode && !cup && mapheaderinfo[mapnum]->cup) return false; -#endif // Survived our checks. return true; @@ -3395,7 +3386,7 @@ INT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup) { for (i = 0; i < CUPCACHE_MAX; i++) { - if (!M_CanShowLevelInList(cup->cachedlevels[i], tol)) + if (!M_CanShowLevelInList(cup->cachedlevels[i], tol, cup)) continue; count++; } @@ -3404,7 +3395,7 @@ INT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup) } for (i = 0; i < nummapheaders; i++) - if (M_CanShowLevelInList(i, tol)) + if (M_CanShowLevelInList(i, tol, NULL)) count++; return count; @@ -3420,7 +3411,7 @@ INT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup) mapnum = NEXTMAP_INVALID; for (; *i < CUPCACHE_MAX; (*i)++) { - if (!M_CanShowLevelInList(cup->cachedlevels[*i], tol)) + if (!M_CanShowLevelInList(cup->cachedlevels[*i], tol, cup)) continue; mapnum = cup->cachedlevels[*i]; break; @@ -3429,7 +3420,7 @@ INT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup) else { for (mapnum = 0; mapnum < nummapheaders; mapnum++) - if (M_CanShowLevelInList(mapnum, tol)) + if (M_CanShowLevelInList(mapnum, tol, NULL)) break; } @@ -3444,7 +3435,7 @@ INT16 M_GetNextLevelInList(INT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup) (*i)++; for (; *i < CUPCACHE_MAX; (*i)++) { - if (!M_CanShowLevelInList(cup->cachedlevels[*i], tol)) + if (!M_CanShowLevelInList(cup->cachedlevels[*i], tol, cup)) continue; map = cup->cachedlevels[*i]; break; @@ -3453,7 +3444,7 @@ INT16 M_GetNextLevelInList(INT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup) else { map++; - while (!M_CanShowLevelInList(map, tol) && map < nummapheaders) + while (!M_CanShowLevelInList(map, tol, NULL) && map < nummapheaders) map++; } From 873b59840976d193c7b85b41682cf03c3dcae1e8 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Dec 2022 05:23:00 -0800 Subject: [PATCH 14/28] Reduce spindash top speed This was carefully adjusted so that Mecha Sonic reaches 199% top speed, barely shy of 200%. Previously, Mecha and even down to Espio could overcharge a spindash to reach Tripwire Blaster state. --- 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 57500df14..0cd6f18f0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2831,9 +2831,9 @@ INT16 K_GetSpindashChargeTime(player_t *player) fixed_t K_GetSpindashChargeSpeed(player_t *player) { // more speed for higher weight & speed - // Tails = +18.75%, Fang = +46.88%, Mighty = +46.88%, Metal = +56.25% + // Tails = +16.94%, Fang = +34.94%, Mighty = +34.94%, Metal = +43.61% // (can be higher than this value when overcharged) - const fixed_t val = ((player->kartspeed + player->kartweight) + 2) * (FRACUNIT/32); + const fixed_t val = (10*FRACUNIT/277) + (((player->kartspeed + player->kartweight) + 2) * FRACUNIT) / 45; // TODO: gametyperules return (gametype == GT_BATTLE) ? (4 * val) : val; From b9f18ffc2406ba68498cf0859d0bc424578f715c Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 13:57:39 +0000 Subject: [PATCH 15/28] More things use the menu map selection rules * G_GetFirstMapOfGametype now uses the menu functions instead of repeating the effort * GTR_NOCUPSELECT - allows gametypes to opt out of cup selection --- src/doomstat.h | 2 ++ src/g_game.c | 29 +++++++++++++---------------- src/k_menufunc.c | 2 +- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 320e29c13..ade6a4bb2 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -502,6 +502,8 @@ enum GameTypeRules GTR_LIVES = 1<<18, // Lives system, players are forced to spectate during Game Over. GTR_SPECIALBOTS = 1<<19, // Bot difficulty gets stronger between rounds, and the rival system is enabled. + GTR_NOCUPSELECT = 1<<20, // Your maps are not selected via cup. ...mutually exclusive with GTR_CAMPAIGN. + // free: to and including 1<<31 }; diff --git a/src/g_game.c b/src/g_game.c index 1bcbd5555..3371979d0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3416,29 +3416,26 @@ UINT32 G_TOLFlag(INT32 pgametype) INT16 G_GetFirstMapOfGametype(UINT8 pgametype) { + UINT8 i = 0; INT16 mapnum = NEXTMAP_INVALID; + UINT32 tol = G_TOLFlag(pgametype); - if ((gametypedefaultrules[pgametype] & GTR_CAMPAIGN) && kartcupheaders) - { - mapnum = kartcupheaders->cachedlevels[0]; - } + levellist.cupmode = (!(gametypedefaultrules[pgametype] & GTR_NOCUPSELECT)); + levellist.timeattack = false; - if (mapnum >= nummapheaders) + if (levellist.cupmode) { - UINT32 tolflag = G_TOLFlag(pgametype); - for (mapnum = 0; mapnum < nummapheaders; mapnum++) + cupheader_t *cup = kartcupheaders; + while (cup && mapnum >= nummapheaders) { - if (!mapheaderinfo[mapnum]) - continue; - if (mapheaderinfo[mapnum]->lumpnum == LUMPERROR) - continue; - if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag)) - continue; - if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU) - continue; - break; + mapnum = M_GetFirstLevelInList(&i, tol, cup); + i = 0; } } + else + { + mapnum = M_GetFirstLevelInList(&i, tol, NULL); + } return mapnum; } diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 06176cf26..18716b9b9 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3475,7 +3475,7 @@ static void M_LevelListFromGametype(INT16 gt) { levellist.newgametype = gt; levellist.typeoflevel = G_TOLFlag(gt); - levellist.cupmode = true; // todo some way to choose going direct to a long consecutive list..? + levellist.cupmode = (!(gametypedefaultrules[gt] & GTR_NOCUPSELECT)); levellist.selectedcup = NULL; first = false; } From facea912f4bf3a2f65a2e3cacfde1bd0972defca Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 13:58:39 +0000 Subject: [PATCH 16/28] Fix memory corruption in M_LevelListFromGametype --- src/k_menufunc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 18716b9b9..11be9ad1b 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3489,6 +3489,7 @@ static void M_LevelListFromGametype(INT16 gt) { cupheader_t *cup = kartcupheaders; size_t currentid = 0, highestunlockedid = 0; + const size_t unitlen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS); // Make sure there's valid cups before going to this menu. if (cup == NULL) @@ -3498,10 +3499,11 @@ static void M_LevelListFromGametype(INT16 gt) { cupgrid.cappages = 2; cupgrid.builtgrid = Z_Calloc( - sizeof(cupheader_t*) * cupgrid.cappages * (CUPMENU_COLUMNS * CUPMENU_ROWS), - PU_STATIC, NULL); + cupgrid.cappages * unitlen, + PU_STATIC, + cupgrid.builtgrid); } - memset(cupgrid.builtgrid, 0, sizeof(cupheader_t*) * cupgrid.cappages * (CUPMENU_COLUMNS * CUPMENU_ROWS)); + memset(cupgrid.builtgrid, 0, cupgrid.cappages * unitlen); while (cup) { @@ -3512,10 +3514,10 @@ static void M_LevelListFromGametype(INT16 gt) continue; } - if (((currentid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1) >= cupgrid.cappages) + if ((currentid * sizeof(cupheader_t*)) >= cupgrid.cappages * unitlen) { // Double the size of the buffer, and clear the other stuff. - size_t firstlen = sizeof(cupheader_t*) * cupgrid.cappages * (CUPMENU_COLUMNS * CUPMENU_ROWS); + const size_t firstlen = cupgrid.cappages * unitlen; cupgrid.builtgrid = Z_Realloc(cupgrid.builtgrid, firstlen * 2, PU_STATIC, NULL); From 15a733a3443928a1140552e3cd2c948d2f15452d Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 14:02:00 +0000 Subject: [PATCH 17/28] Add I_Error for inability to allocate `cuplist.builtgrid` --- src/k_menufunc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 11be9ad1b..dc292c5c1 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3502,6 +3502,11 @@ static void M_LevelListFromGametype(INT16 gt) cupgrid.cappages * unitlen, PU_STATIC, cupgrid.builtgrid); + + if (!cupgrid.builtgrid) + { + I_Error("M_LevelListFromGametype: Not enough memory to allocate builtgrid"); + } } memset(cupgrid.builtgrid, 0, cupgrid.cappages * unitlen); @@ -3521,6 +3526,12 @@ static void M_LevelListFromGametype(INT16 gt) cupgrid.builtgrid = Z_Realloc(cupgrid.builtgrid, firstlen * 2, PU_STATIC, NULL); + + if (!cupgrid.builtgrid) + { + I_Error("M_LevelListFromGametype: Not enough memory to reallocate builtgrid"); + } + memset(cupgrid.builtgrid + firstlen, 0, firstlen); cupgrid.cappages *= 2; } From ecfcc1356b7b999b21b88901ef8adafbeada0ce8 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 14:08:26 +0000 Subject: [PATCH 18/28] Don't permit duplicate maps across multiple cups in time attack. A map is only valid for its later groupings in Grand Prix and multiplayer. --- src/k_menufunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index dc292c5c1..3a57f68a1 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3370,8 +3370,8 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol, cupheader_t *cup) if (levellist.timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK)) return false; - // Don't permit cup when no cup requested - if (levellist.cupmode && !cup && mapheaderinfo[mapnum]->cup) + // Don't permit cup when no cup requested (also no dupes in time attack) + if (levellist.cupmode && (levellist.timeattack || !cup) && mapheaderinfo[mapnum]->cup != cup) return false; // Survived our checks. From f9bdfd8a50408e769ba63eae4cb15e9c53a4f38f Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 14:25:38 +0000 Subject: [PATCH 19/28] Fix typings for map index --- src/k_menu.h | 6 +++--- src/k_menufunc.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index ad76890ff..7623a19e7 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -702,9 +702,9 @@ extern struct levellist_s { } levellist; boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol, cupheader_t *cup); -INT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup); -INT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup); -INT16 M_GetNextLevelInList(INT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup); +UINT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup); +UINT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup); +UINT16 M_GetNextLevelInList(UINT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup); void M_LevelSelectInit(INT32 choice); void M_CupSelectHandler(INT32 choice); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 3a57f68a1..dfc573868 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3378,7 +3378,7 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol, cupheader_t *cup) return true; } -INT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup) +UINT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup) { INT16 i, count = 0; @@ -3401,7 +3401,7 @@ INT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup) return count; } -INT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup) +UINT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup) { INT16 mapnum = NEXTMAP_INVALID; @@ -3427,7 +3427,7 @@ INT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup) return mapnum; } -INT16 M_GetNextLevelInList(INT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup) +UINT16 M_GetNextLevelInList(UINT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup) { if (cup) { From d25e59535c603074951941ffb9fe4193a8afba8c Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 14:37:15 +0000 Subject: [PATCH 20/28] Invalidate all instances of the same map across multiple cups' `cachedlevels`, so that it DEFINITELY will be assigned to the first cup in the linked list in P_InitMapData. --- src/deh_soc.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 5b007d4f9..9f9224ae2 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3021,6 +3021,28 @@ void readwipes(MYFILE *f) // SRB2KART // +static void invalidateacrosscups(UINT16 map) +{ + cupheader_t *cup = kartcupheaders; + UINT8 i; + + if (map >= nummapheaders) + return; + + while (cup) + { + for (i = 0; i < CUPCACHE_MAX; i++) + { + if (cup->cachedlevels[i] != map) + continue; + cup->cachedlevels[i] = NEXTMAP_INVALID; + } + cup = cup->next; + } + + mapheaderinfo[map]->cup = NULL; +} + void readcupheader(MYFILE *f, cupheader_t *cup) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -3077,8 +3099,7 @@ void readcupheader(MYFILE *f, cupheader_t *cup) cup->levellist[cup->numlevels] = NULL; if (cup->cachedlevels[cup->numlevels] == NEXTMAP_INVALID) continue; - mapheaderinfo[cup->cachedlevels[cup->numlevels]]->cup = NULL; - cup->cachedlevels[cup->numlevels] = NEXTMAP_INVALID; + invalidateacrosscups(cup->cachedlevels[cup->numlevels]); } tmp = strtok(word2,","); @@ -3103,8 +3124,7 @@ void readcupheader(MYFILE *f, cupheader_t *cup) cup->levellist[CUPCACHE_BONUS + cup->numbonus] = NULL; if (cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus] == NEXTMAP_INVALID) continue; - mapheaderinfo[cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus]]->cup = NULL; - cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus] = NEXTMAP_INVALID; + invalidateacrosscups(cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus]); } tmp = strtok(word2,","); @@ -3122,6 +3142,7 @@ void readcupheader(MYFILE *f, cupheader_t *cup) } else if (fastcmp(word, "SPECIALSTAGE")) { + invalidateacrosscups(cup->cachedlevels[CUPCACHE_SPECIAL]); Z_Free(cup->levellist[CUPCACHE_SPECIAL]); cup->levellist[CUPCACHE_SPECIAL] = Z_StrDup(word2); cup->cachedlevels[CUPCACHE_SPECIAL] = NEXTMAP_INVALID; From e0412ab851ec48bc6371f2dd6d43541f014a427c Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 14:42:18 +0000 Subject: [PATCH 21/28] Fix pageno if greater than permitted --- src/k_menufunc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index dfc573868..b15fdf8ad 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3554,6 +3554,10 @@ static void M_LevelListFromGametype(INT16 gt) } cupgrid.numpages = (highestunlockedid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1; + if (cupgrid.pageno >= cupgrid.numpages) + { + cupgrid.pageno = 0; + } PLAY_LevelSelectDef.prevMenu = &PLAY_CupSelectDef; M_SetupNextMenu(&PLAY_CupSelectDef, false); From 6a5029c83b9c1d38a1b67b61fafd1bfabd844c2e Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 14:45:31 +0000 Subject: [PATCH 22/28] Use `GTR_NOCUPSELECT` as the controlling factor in `advancemap next` --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 3371979d0..819a6369e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3861,7 +3861,7 @@ static void G_GetNextMap(void) UINT32 tolflag = G_TOLFlag(gametype); register INT16 cm; - if (gametyperules & GTR_CAMPAIGN) + if (!(gametyperules & GTR_NOCUPSELECT)) { cupheader_t *cup = mapheaderinfo[gamemap-1]->cup; UINT8 gettingresult = 0; From 32e53bbd83b24150503376199946dde7a5bdf732 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Dec 2022 22:23:30 +0000 Subject: [PATCH 23/28] Remove dynamic base from CMake target link options Permits functional debugging of crash reports by preventing ASLR --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 61e5ff86f..0bcb05e22 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -134,7 +134,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows" AND NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}") # On MinGW with internal libraries, link the standard library statically - target_link_options(SRB2SDL2 PRIVATE "-static") + target_link_options(SRB2SDL2 PRIVATE "-static" "-Wl,--disable-dynamicbase") endif() target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17) From 4281adc60db90703c0d47192a4bf7c6ebe20cc0b Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 17 Dec 2022 20:30:05 -0800 Subject: [PATCH 24/28] Separate most of P_DoSpring into P_DoSpringEx --- src/p_local.h | 3 +- src/p_map.c | 161 ++++++++++++++++++++++++++++---------------------- 2 files changed, 92 insertions(+), 72 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index d9486e8b7..321ba682b 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -170,7 +170,7 @@ boolean P_IsObjectInGoop(mobj_t *mo); boolean P_IsObjectOnGround(mobj_t *mo); boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec); boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec); // SRB2Kart -#define P_IsObjectFlipped(o) ((o)->eflags & MFE_VERTICALFLIP) +#define P_IsObjectFlipped(o) (((o)->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP) boolean P_InQuicksand(mobj_t *mo); boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, angle_t oldRoll); @@ -473,6 +473,7 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); fixed_t P_CeilingzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); BlockItReturn_t PIT_PushableMoved(mobj_t *thing); +void P_DoSpringEx(mobj_t *object, fixed_t scaleVal, fixed_t vertispeed, fixed_t horizspeed, angle_t finalAngle, UINT16 starcolor); boolean P_DoSpring(mobj_t *spring, mobj_t *object); fixed_t P_GetFOFTopZAt (ffloor_t *rover, fixed_t x, fixed_t y); diff --git a/src/p_map.c b/src/p_map.c index 9c9a71fdf..8f6388452 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -268,6 +268,90 @@ static boolean P_SpecialIsLinedefCrossType(line_t *ld) return linedefcrossspecial; } +void +P_DoSpringEx +( mobj_t * object, + fixed_t scaleVal, + fixed_t vertispeed, + fixed_t horizspeed, + angle_t finalAngle, + UINT16 starcolor) +{ + object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. + object->terrain = NULL; + + object->eflags |= MFE_SPRUNG; // apply this flag asap! + + if ((vertispeed < 0) ^ P_IsObjectFlipped(object)) + vertispeed *= 2; + + if (vertispeed) + { + object->momz = FixedMul(vertispeed, scaleVal); + } + + if (horizspeed) + { + fixed_t finalSpeed = FixedMul(horizspeed, scaleVal); + fixed_t objectSpeed; + + if (object->player) + objectSpeed = object->player->speed; + else + objectSpeed = R_PointToDist2(0, 0, object->momx, object->momy); + + if (!vertispeed) + { + // Scale to gamespeed + finalSpeed = FixedMul(finalSpeed, K_GetKartGameSpeedScalar(gamespeed)); + + // Reflect your momentum angle against the surface of horizontal springs. + // This makes it a bit more interesting & unique than just being a speed boost in a pre-defined direction + if (object->momx || object->momy) + { + finalAngle = K_ReflectAngle( + R_PointToAngle2(0, 0, object->momx, object->momy), finalAngle, + objectSpeed, finalSpeed + ); + } + } + + // Horizontal speed is used as a minimum thrust, not a direct replacement + finalSpeed = max(objectSpeed, finalSpeed); + + P_InstaThrust(object, finalAngle, finalSpeed); + } + + if (object->player) + { + K_TumbleInterrupt(object->player); + P_ResetPlayer(object->player); + + object->player->springstars = max(abs(vertispeed), horizspeed) / FRACUNIT / 2; + object->player->springcolor = starcolor; + + // Less friction when hitting springs + if (!object->player->tiregrease) + { + UINT8 i; + for (i = 0; i < 2; i++) + { + mobj_t *grease; + grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE); + P_SetTarget(&grease->target, object); + grease->angle = K_MomentumAngle(object); + grease->extravalue1 = i; + K_ReduceVFX(grease, object->player); + } + } + + if (object->player->tiregrease < greasetics) + { + object->player->tiregrease = greasetics; + } + } +} + // // P_DoSpring // @@ -282,8 +366,8 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) fixed_t vertispeed = spring->info->mass; fixed_t horizspeed = spring->info->damage; UINT16 starcolor = (spring->info->painchance % numskincolors); - fixed_t savemomx = 0; - fixed_t savemomy = 0; + fixed_t savemomx = object->momx; + fixed_t savemomy = object->momy; statenum_t raisestate = spring->info->raisestate; // Object was already sprung this tic @@ -312,18 +396,11 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) return false; } - object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. - object->terrain = NULL; - - object->eflags |= MFE_SPRUNG; // apply this flag asap! spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify if (spring->eflags & MFE_VERTICALFLIP) vertispeed *= -1; - if ((spring->eflags ^ object->eflags) & MFE_VERTICALFLIP) - vertispeed *= 2; - // Vertical springs teleport you on TOP of them. if (vertispeed > 0) { @@ -355,43 +432,11 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) P_TryMove(object, spring->x + offx, spring->y + offy, true, NULL); } - if (vertispeed) - { - object->momz = FixedMul(vertispeed, scaleVal); - } + object->momx = savemomx; + object->momy = savemomy; - if (horizspeed) - { - angle_t finalAngle = spring->angle; - fixed_t finalSpeed = FixedMul(horizspeed, scaleVal); - fixed_t objectSpeed; - - if (object->player) - objectSpeed = object->player->speed; - else - objectSpeed = R_PointToDist2(0, 0, savemomx, savemomy); - - if (!vertispeed) - { - // Scale to gamespeed - finalSpeed = FixedMul(finalSpeed, K_GetKartGameSpeedScalar(gamespeed)); - - // Reflect your momentum angle against the surface of horizontal springs. - // This makes it a bit more interesting & unique than just being a speed boost in a pre-defined direction - if (savemomx || savemomy) - { - finalAngle = K_ReflectAngle( - R_PointToAngle2(0, 0, savemomx, savemomy), finalAngle, - objectSpeed, finalSpeed - ); - } - } - - // Horizontal speed is used as a minimum thrust, not a direct replacement - finalSpeed = max(objectSpeed, finalSpeed); - - P_InstaThrust(object, finalAngle, finalSpeed); - } + P_DoSpringEx(object, scaleVal, vertispeed, horizspeed, + spring->angle, starcolor); // Re-solidify spring->flags |= (spring->info->flags & (MF_SPRING|MF_SPECIAL)); @@ -403,32 +448,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) P_SetTarget(&spring->target, object); } - K_TumbleInterrupt(object->player); - P_ResetPlayer(object->player); - - object->player->springstars = max(abs(vertispeed), horizspeed) / FRACUNIT / 2; - object->player->springcolor = starcolor; - - // Less friction when hitting springs - if (!object->player->tiregrease) - { - UINT8 i; - for (i = 0; i < 2; i++) - { - mobj_t *grease; - grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE); - P_SetTarget(&grease->target, object); - grease->angle = K_MomentumAngle(object); - grease->extravalue1 = i; - K_ReduceVFX(grease, object->player); - } - } - - if (object->player->tiregrease < greasetics) - { - object->player->tiregrease = greasetics; - } - if (spring->type == MT_POGOSPRING) { if (spring->reactiontime == 0) From 8d39f0e60f092d0859f7d034c2bcfb9a094d9521 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 17 Dec 2022 23:03:35 -0800 Subject: [PATCH 25/28] Add springStrength and springStarColor to TERRAIN --- src/k_terrain.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ src/k_terrain.h | 2 ++ src/p_map.c | 6 ++++ 3 files changed, 86 insertions(+) diff --git a/src/k_terrain.c b/src/k_terrain.c index 1b1df12f1..92ca53df0 100644 --- a/src/k_terrain.c +++ b/src/k_terrain.c @@ -554,6 +554,61 @@ void K_ProcessTerrainEffect(mobj_t *mo) } } + // Spring + if (terrain->springStrength) + { + const pslope_t *slope; + angle_t angle = 0; + + fixed_t co = FRACUNIT; + fixed_t si = 0; + + // FIXME: come up with a better way to get the touched + // texture's slope to this function. At least this + // will work for 90% of scenarios... + + if (player->mo->eflags & MFE_VERTICALFLIP) + { + if (player->mo->ceilingrover != NULL) + { + slope = *player->mo->ceilingrover->b_slope; + } + else + { + slope = player->mo->subsector->sector->c_slope; + } + } + else + { + if (player->mo->floorrover != NULL) + { + slope = *player->mo->ceilingrover->t_slope; + } + else + { + slope = player->mo->subsector->sector->f_slope; + } + } + + if (slope) + { + const angle_t fa = (slope->zangle >> ANGLETOFINESHIFT); + + co = FINECOSINE(fa) * P_MobjFlip(player->mo); + si = -(FINESINE(fa)); + + angle = slope->xydirection; + } + + P_DoSpringEx(player->mo, mapobjectscale, + FixedMul(terrain->springStrength, co), + FixedMul(terrain->springStrength, si), + angle, terrain->springStarColor); + + // FIXME: this sound shouldn't move with the player + S_StartSound(player->mo, sfx_s3kb1); + } + // Bumpy floor if (terrain->flags & TRF_STAIRJANK) { @@ -1487,6 +1542,8 @@ static void K_TerrainDefaults(terrain_t *terrain) terrain->trickPanel = 0; terrain->speedPad = 0; terrain->speedPadAngle = 0; + terrain->springStrength = 0; + terrain->springStarColor = SKINCOLOR_NONE; terrain->flags = 0; } @@ -1565,6 +1622,27 @@ static void K_ParseTerrainParameter(size_t i, char *param, char *val) { terrain->speedPadAngle = FixedAngle(FLOAT_TO_FIXED(atof(val))); } + else if (stricmp(param, "springStrength") == 0) + { + const double fval = atof(val); + + if (fpclassify(fval) == FP_ZERO) + { + terrain->springStrength = 0; + } + else + { + // Springs increase in stength by 1.6 times the + // previous strength. Grey spring is 25 and + // 25/1.6 = 15.625 + terrain->springStrength = + FLOAT_TO_FIXED(15.625 * pow(1.6, fval)); + } + } + else if (stricmp(param, "springStarColor") == 0) + { + terrain->springStarColor = get_number(val); + } else if (stricmp(param, "floorClip") == 0) { terrain->floorClip = FLOAT_TO_FIXED(atof(val)); diff --git a/src/k_terrain.h b/src/k_terrain.h index 349455bed..166900036 100644 --- a/src/k_terrain.h +++ b/src/k_terrain.h @@ -116,6 +116,8 @@ struct terrain_t fixed_t trickPanel; // Trick panel strength fixed_t speedPad; // Speed pad strength angle_t speedPadAngle; // Speed pad angle + fixed_t springStrength; // Spring strength + UINT16 springStarColor; // Spring star color fixed_t floorClip; // Offset for sprites on this ground UINT32 flags; // Flag values (see: terrain_flags_t) }; diff --git a/src/p_map.c b/src/p_map.c index 8f6388452..a581d4576 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -277,6 +277,12 @@ P_DoSpringEx angle_t finalAngle, UINT16 starcolor) { + if (horizspeed < 0) + { + horizspeed = -(horizspeed); + finalAngle += ANGLE_180; + } + object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. object->terrain = NULL; From eef944bb1b37653a558699f608092ad61f356e65 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Dec 2022 21:06:41 -0800 Subject: [PATCH 26/28] Play spring TERRAIN sfx from sector --- src/k_terrain.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/k_terrain.c b/src/k_terrain.c index 92ca53df0..a702f53ad 100644 --- a/src/k_terrain.c +++ b/src/k_terrain.c @@ -557,6 +557,8 @@ void K_ProcessTerrainEffect(mobj_t *mo) // Spring if (terrain->springStrength) { + sector_t *sector = player->mo->subsector->sector; + const pslope_t *slope; angle_t angle = 0; @@ -575,7 +577,7 @@ void K_ProcessTerrainEffect(mobj_t *mo) } else { - slope = player->mo->subsector->sector->c_slope; + slope = sector->c_slope; } } else @@ -586,7 +588,7 @@ void K_ProcessTerrainEffect(mobj_t *mo) } else { - slope = player->mo->subsector->sector->f_slope; + slope = sector->f_slope; } } @@ -605,8 +607,8 @@ void K_ProcessTerrainEffect(mobj_t *mo) FixedMul(terrain->springStrength, si), angle, terrain->springStarColor); - // FIXME: this sound shouldn't move with the player - S_StartSound(player->mo, sfx_s3kb1); + sector->soundorg.z = player->mo->z; + S_StartSound(§or->soundorg, sfx_s3kb1); } // Bumpy floor From d3b8f295b8856358bf6c731990df222dcfdee311 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Dec 2022 21:10:31 -0800 Subject: [PATCH 27/28] Fix not being able to play sounds from sector->soundorg --- src/p_mobj.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/p_mobj.h b/src/p_mobj.h index 8811c0149..0f163236b 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -275,14 +275,17 @@ struct mobj_t // List: thinker links. thinker_t thinker; - mobjtype_t type; - const mobjinfo_t *info; // &mobjinfo[mobj->type] - // Info for drawing: position. fixed_t x, y, z; + // --- Please make sure you keep the fields up to this + // --- point in sync with degenmobj_t. + fixed_t old_x, old_y, old_z; // position interpolation fixed_t old_x2, old_y2, old_z2; + mobjtype_t type; + const mobjinfo_t *info; // &mobjinfo[mobj->type] + // More list: links in sector (if needed) mobj_t *snext; mobj_t **sprev; // killough 8/11/98: change to ptr-to-ptr @@ -428,14 +431,14 @@ struct precipmobj_t // List: thinker links. thinker_t thinker; - mobjtype_t type; - const mobjinfo_t *info; // &mobjinfo[mobj->type] - // Info for drawing: position. fixed_t x, y, z; fixed_t old_x, old_y, old_z; // position interpolation fixed_t old_x2, old_y2, old_z2; + mobjtype_t type; + const mobjinfo_t *info; // &mobjinfo[mobj->type] + // More list: links in sector (if needed) precipmobj_t *snext; precipmobj_t **sprev; // killough 8/11/98: change to ptr-to-ptr From a62282aa4e01ead14694769b81f50b4aa3bd6c73 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 19 Dec 2022 19:43:31 +0000 Subject: [PATCH 28/28] Make `Wl,--disable-dynamicbase` its own link option seperate from `-static` --- src/CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0bcb05e22..8d646fe0a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -132,9 +132,12 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 k_roulette.c ) -if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows" AND NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}") - # On MinGW with internal libraries, link the standard library statically - target_link_options(SRB2SDL2 PRIVATE "-static" "-Wl,--disable-dynamicbase") +if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows") + target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase") + if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}") + # On MinGW with internal libraries, link the standard library statically + target_link_options(SRB2SDL2 PRIVATE "-static") + endif() endif() target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17)