From d3af5db8743bfc4ca84e04d3f9b78a5b1188d1cc Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 23 Dec 2023 21:38:23 +0000 Subject: [PATCH 01/15] readcondition: Fix AllChaos/AllSuper/AllEmeralds difficulty restriction --- src/deh_soc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 9c0a8feab..56c36604f 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2773,9 +2773,9 @@ static void readcondition(UINT16 set, UINT32 id, char *word2) if (fastcmp(params[1], "NORMAL")) ; else if (fastcmp(params[1], "HARD")) - x1 = KARTSPEED_HARD; + re = KARTSPEED_HARD; else if (fastcmp(params[1], "MASTER")) - x1 = KARTGP_MASTER; + re = KARTGP_MASTER; else { deh_warning("gamespeed requirement \"%s\" invalid for condition ID %d", params[1], id+1); From 64922460ac03a07fcaabd7ce214e4ed423507ca4 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 23 Dec 2023 22:12:00 +0000 Subject: [PATCH 02/15] Handle Podium unlocks during mapload, not when finishing the ceremony Solves mid-podium crashes not granting second page material --- src/k_podium.cpp | 19 ++++++++++--------- src/m_cond.c | 8 ++++---- src/p_setup.c | 8 +++++++- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/k_podium.cpp b/src/k_podium.cpp index 072a4e075..fab819594 100644 --- a/src/k_podium.cpp +++ b/src/k_podium.cpp @@ -864,7 +864,11 @@ void K_InitializePodiumWaypoint(player_t *const player) { if ((player != NULL) && (player->mo != NULL)) { - player->position = K_GetPodiumPosition(player); + if (player->position == 0) + { + // Just in case a netgame scenario with a late joiner ocurrs. + player->position = K_GetPodiumPosition(player); + } if (player->position > 0 && player->position <= MAXPLAYERS) { @@ -989,12 +993,6 @@ void K_FinishCeremony(void) } g_podiumData.ranking = true; - - // Play the noise now (via G_UpdateVisited's concluding challenge check) - prevmap = gamemap-1; - G_UpdateVisited(); - if (gamedata->deferredsave) - G_SaveGameData(); } /*-------------------------------------------------- @@ -1084,8 +1082,11 @@ void K_ResetCeremony(void) } } - // Save before playing the noise - G_SaveGameData(); + // Update visitation. + prevmap = gamemap-1; + G_UpdateVisited(); + + // will subsequently save in P_LoadLevel } /*-------------------------------------------------- diff --git a/src/m_cond.c b/src/m_cond.c index b9664d46e..bd5231128 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1607,7 +1607,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) return (grandprixinfo.gamespeed >= cn->requirement); case UCRP_PODIUMCUP: - if (grandprixinfo.gp == false || K_PodiumRanking() == false) + if (grandprixinfo.gp == false || K_PodiumSequence() == false) return false; if (grandprixinfo.cup == NULL || ( @@ -1625,11 +1625,11 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) case UCRP_PODIUMEMERALD: case UCRP_PODIUMPRIZE: return (grandprixinfo.gp == true - && K_PodiumRanking() == true + && K_PodiumSequence() == true && grandprixinfo.rank.specialWon == true); case UCRP_PODIUMNOCONTINUES: return (grandprixinfo.gp == true - && K_PodiumRanking() == true + && K_PodiumSequence() == true && grandprixinfo.rank.continuesUsed == 0); case UCRP_FINISHCOOL: @@ -2989,7 +2989,7 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall) } } - if (!demo.playback && Playing() && (gamestate == GS_LEVEL || K_PodiumRanking() == true)) + if (!demo.playback && Playing() && (gamestate == GS_LEVEL || K_PodiumSequence() == true)) { for (i = 0; i <= splitscreen; i++) { diff --git a/src/p_setup.c b/src/p_setup.c index 2fdb86d54..40e1d0f3c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7600,7 +7600,13 @@ static void P_InitLevelSettings(void) if (K_PodiumSequence() == true) { - ; // NOP + // Okay, now that everything preceding is handled, set the position. + for (i = 0; i < MAXPLAYERS; i++) + { + players[i].position = K_GetPodiumPosition(&players[i]); + } + + // We don't touch the gamespeed, though! } else if (grandprixinfo.gp == true) { From 9fc49acec647613c4db6d14c53f2479f8fbd1aa9 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 23 Dec 2023 22:59:42 +0000 Subject: [PATCH 03/15] M_PrecacheLevelLocks: Better diagnostic information --- src/m_cond.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index bd5231128..2d10b639d 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1034,7 +1034,7 @@ static void M_PrecacheLevelLocks(void) && mapheaderinfo[map]) { if (mapheaderinfo[map]->cache_maplock != MAXUNLOCKABLES) - CONS_Alert(CONS_ERROR, "Unlockable %u: Too many SECRET_MAPs associated with Level %s\n", i, mapheaderinfo[map]->lumpname); + CONS_Alert(CONS_ERROR, "Unlockable %u: Too many SECRET_MAPs associated with Level %s\n", i+1, mapheaderinfo[map]->lumpname); mapheaderinfo[map]->cache_maplock = i; } break; @@ -1115,11 +1115,17 @@ static void M_PrecacheLevelLocks(void) break; } if (j == mapheaderinfo[map]->musname_size) - CONS_Alert(CONS_ERROR, "Unlockable %u: Too many SECRET_ALTMUSICs associated with Level %s\n", i, mapheaderinfo[map]->lumpname); + CONS_Alert(CONS_ERROR, "Unlockable %u: Too many SECRET_ALTMUSICs associated with Level %s\n", i+1, mapheaderinfo[map]->lumpname); + } + else + { + CONS_Alert(CONS_ERROR, "Unlockable %u: Invalid levelname %s for SECRET_ALTMUSIC\n", i+1, unlockables[i].stringVar); } if (tempstr == NULL) - tempstr = va("INVALID MUSIC UNLOCK %u", i); + { + tempstr = va("INVALID MUSIC UNLOCK %u", i+1); + } strlcpy(unlockables[i].name, tempstr, sizeof (unlockables[i].name)); @@ -1132,7 +1138,7 @@ static void M_PrecacheLevelLocks(void) if (cup) { if (cup->cache_cuplock != MAXUNLOCKABLES) - CONS_Alert(CONS_ERROR, "Unlockable %u: Too many SECRET_CUPs associated with Cup %s\n", i, cup->name); + CONS_Alert(CONS_ERROR, "Unlockable %u: Too many SECRET_CUPs associated with Cup %s\n", i+1, cup->name); cup->cache_cuplock = i; break; } From 286c6d12a2857337b81b87d2676318738e574ecb Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 23 Dec 2023 23:12:25 +0000 Subject: [PATCH 04/15] Add "cxdiag" console command Challenge eXception Diagnostic for development purposes --- src/d_netcmd.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b6825d3e3..bdd15831e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -134,6 +134,7 @@ static void Command_LeaveParty_f(void); static void Command_Addfile(void); static void Command_ListWADS_f(void); static void Command_ListDoomednums_f(void); +static void Command_cxdiag_f(void); static void Command_RunSOC(void); static void Command_Pause(void); @@ -396,6 +397,7 @@ void D_RegisterServerCommands(void) COM_AddCommand("addfile", Command_Addfile); COM_AddDebugCommand("listwad", Command_ListWADS_f); COM_AddDebugCommand("listmapthings", Command_ListDoomednums_f); + COM_AddDebugCommand("cxdiag", Command_cxdiag_f); COM_AddCommand("runsoc", Command_RunSOC); COM_AddCommand("pause", Command_Pause); @@ -4704,6 +4706,94 @@ static void Command_ListDoomednums_f(void) #undef MAXDOOMEDNUM +static void Command_cxdiag_f(void) +{ + UINT16 i, j, errors = 0; + + CONS_Printf("\x82""Welcome to the Challenge eXception Diagnostic.\n"); + + { + conditionset_t *c; + condition_t *cn; + + CONS_Printf("\x82""Evaluating ConditionSets...\n"); + + for (i = 0; i < MAXCONDITIONSETS; i++) + { + c = &conditionSets[i]; + if (!c->numconditions) + continue; + + UINT32 lastID = 0; + boolean validSoFar = true; + boolean requiresPlaying = false; + boolean lastRequiresPlaying = false; + boolean lastrequiredplayingvalid = false; + for (j = 0; j < c->numconditions; ++j) + { + cn = &c->condition[j]; + + if (lastID) + { + //if (lastID != cn->id && validSoFar) + //CONS_Printf("\x87""Condition%d good\n", lastID); + if (lastID != cn->id) + { + lastrequiredplayingvalid = false; + validSoFar = true; + } + else if (!validSoFar) + continue; + } + + if (cn->type == UC_AND || cn->type == UC_COMMA || cn->type == UC_DESCRIPTIONOVERRIDE) + continue; + + lastID = cn->id; + + lastRequiresPlaying = requiresPlaying; + requiresPlaying = (cn->type >= UCRP_REQUIRESPLAYING); + + if (lastrequiredplayingvalid) + { + if (lastRequiresPlaying != requiresPlaying) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) combines Playing condition and Statistics condition - will never be achieved\n", i+1, j+1, lastID); + validSoFar = false; + errors++; + } + } + lastrequiredplayingvalid = true; + } + } + } + + { + unlockable_t *un; + + CONS_Printf("\x82""Evaluating Challenges...\n"); + + for (i = 0; i < MAXUNLOCKABLES; i++) + { + un = &unlockables[i]; + j = un->conditionset; + if (!j) + continue; + + if (!conditionSets[j-1].numconditions) + { + CONS_Printf("\x87"" Unlockable %u has ConditionSet %u, which has no Conditions successfully set - will never be unlocked?\n", i+1, j); + errors++; + } + } + } + + if (errors) + CONS_Printf("\x85""%u errors detected.\n", i+1, j); + else + CONS_Printf("\x83""No errors detected! Good job\n", i+1, j); +} + // ========================================================================= // MISC. COMMANDS // ========================================================================= From b88372c85da23e96f3e86c88266e1a049bd5ad77 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 24 Dec 2023 16:30:53 +0000 Subject: [PATCH 05/15] PodiumCup challenge description: Correctly use extrainfo1 instead of requirement for Grade --- src/m_cond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index 2d10b639d..88cfdc8eb 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -2520,7 +2520,7 @@ static const char *M_GetConditionString(condition_t *cn) if (cn->extrainfo2) { - switch (cn->requirement) + switch (cn->extrainfo1) { case GRADE_E: { completetype = "get grade E"; break; } case GRADE_D: { completetype = "get grade D"; break; } From 798e016aa1e47119fc41504320706c662c10003f Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Dec 2023 15:47:32 +0000 Subject: [PATCH 06/15] Fix compilation error for cxdiag --- src/d_netcmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index bdd15831e..5de549a59 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4789,9 +4789,9 @@ static void Command_cxdiag_f(void) } if (errors) - CONS_Printf("\x85""%u errors detected.\n", i+1, j); + CONS_Printf("\x85""%u errors detected.\n", errors); else - CONS_Printf("\x83""No errors detected! Good job\n", i+1, j); + CONS_Printf("\x83""No errors detected! Good job\n"); } // ========================================================================= From 43880b4a4b8f1a3a7cf566c9b86e9afa133ce46d Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Dec 2023 15:52:22 +0000 Subject: [PATCH 07/15] G_LoadGamedata: Add a sanity check when imbibing pendingkeyroundoffset Should solve Laz's infinite key increment hell --- src/g_game.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 316280198..ea287f975 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4691,6 +4691,16 @@ void G_LoadGameData(void) gamedata->keyspending = READUINT16(save.p); } + // Sanity check. + if (gamedata->pendingkeyroundoffset >= GDCONVERT_ROUNDSTOKEY) + { + gamedata->pendingkeyrounds += + (gamedata->pendingkeyroundoffset + - (GDCONVERT_ROUNDSTOKEY-1)); + gamedata->pendingkeyroundoffset = (GDCONVERT_ROUNDSTOKEY-1); + gamedata->keyspending = 0; // safe to nuke - will be recalc'd if the offset still permits + } + gamedata->chaokeys = READUINT16(save.p); if (versionMinor >= 4) From 920201621f0dff30fb3f6562dfe243475527ef01 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Dec 2023 16:56:55 +0000 Subject: [PATCH 08/15] Count PF_VOID as FAULTing during POSITION for the purpose of Challenges --- src/p_spec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index d11810b11..2ce654adc 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1926,6 +1926,13 @@ static void K_HandleLapIncrement(player_t *player) ClearFakePlayerSkin(player); S_StartSound(player->mo, sfx_s3k8a); P_MoveOrigin(player->mo, player->mo->old_x, player->mo->old_y, player->mo->z); + + if (player->roundconditions.faulted == false) + { + player->roundconditions.faulted = true; + player->roundconditions.checkthisframe = true; + } + return; } From 49e48c267ab771128fa3769d668c4ffda8ac5780 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Dec 2023 17:02:11 +0000 Subject: [PATCH 09/15] Use thin font for Challenge descriptions --- src/k_menudraw.c | 2 +- src/m_cond.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 923c0423b..5a684f9be 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6596,7 +6596,7 @@ challengedesc: ) ) { - V_DrawCenteredString(BASEVIDWIDTH/2, 120 + 32, 0, challengesmenu.unlockcondition); + V_DrawCenteredThinString(BASEVIDWIDTH/2, 120 + 32, 0, challengesmenu.unlockcondition); } } diff --git a/src/m_cond.c b/src/m_cond.c index 88cfdc8eb..c61c028b0 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -2886,7 +2886,7 @@ char *M_BuildConditionSetString(UINT16 unlockid) DESCRIPTIONWIDTH << FRACBITS, FRACUNIT, FRACUNIT, FRACUNIT, 0, - HU_FONT, + TINY_FONT, message ); } From 122ede8de949406b7b1cb36886059578c2ff83fb Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Dec 2023 17:23:17 +0000 Subject: [PATCH 10/15] More cxdiag Challenge condition minor error identification --- src/d_netcmd.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5de549a59..71d32613e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4729,6 +4729,7 @@ static void Command_cxdiag_f(void) boolean requiresPlaying = false; boolean lastRequiresPlaying = false; boolean lastrequiredplayingvalid = false; + boolean immediatelyprefix = false; for (j = 0; j < c->numconditions; ++j) { cn = &c->condition[j]; @@ -4746,8 +4747,27 @@ static void Command_cxdiag_f(void) continue; } - if (cn->type == UC_AND || cn->type == UC_COMMA || cn->type == UC_DESCRIPTIONOVERRIDE) + if (cn->type == UC_DESCRIPTIONOVERRIDE) + { + if (!cn->stringvar) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) - Description override has no description!?\n", i+1, j+1, cn->id); + } + else if (cn->stringvar[0] != tolower(cn->stringvar[0])) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) - Description override begins with capital letter, which isn't necessary and can sometimes look weird in generated descriptions\n", i+1, j+1, cn->id); + } continue; + } + + if (cn->type == UC_AND || cn->type == UC_COMMA) + { + if (immediatelyprefix || lastID != cn->id) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) - Conjunction immediately follows %s - this just looks plain weird!\n", i+1, j+1, cn->id, immediatelyprefix ? "Prefix type" : "start"); + } + continue; + } lastID = cn->id; @@ -4764,6 +4784,8 @@ static void Command_cxdiag_f(void) } } lastrequiredplayingvalid = true; + + immediatelyprefix = (cn->type >= UCRP_PREFIX_GRANDPRIX && cn->type <= UCRP_PREFIX_ISMAP); } } } From bfa52b695ecdab9a67eec21541a3f1e1f0a3e9d4 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Dec 2023 22:13:05 +0000 Subject: [PATCH 11/15] Character select: Fix mismatch between ground truth and unlock-dependent followercategory Resolves Fyrus' follower select bug --- src/menus/play-char-select.c | 47 +++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index 6c71e871a..ad8333536 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -1016,26 +1016,30 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num) } else { - if (p->followern < 0 || followers[p->followern].category != p->followercategory) + if (p->followern < 0 + || followers[p->followern].category != setup_followercategories[p->followercategory][1]) { p->followern = 0; - while (p->followern < numfollowers - && (followers[p->followern].category != setup_followercategories[p->followercategory][1] - || !K_FollowerUsable(p->followern))) + while (p->followern < numfollowers) + { + if (followers[p->followern].category == setup_followercategories[p->followercategory][1] + && K_FollowerUsable(p->followern)) + break; p->followern++; + } } - if (p->followern >= numfollowers) - { - p->followern = -1; - S_StartSound(NULL, sfx_s3kb2); - } - else + if (p->followern < numfollowers) { M_GetFollowerState(p); p->mdepth = CSSTEP_FOLLOWER; S_StartSound(NULL, sfx_s3k63); } + else + { + p->followern = -1; + S_StartSound(NULL, sfx_s3kb2); + } } M_SetMenuDelay(num); @@ -1049,10 +1053,25 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num) } else if (M_MenuExtraPressed(num)) { - 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; + INT16 i = -1; + if (p->followercategory < 0 + && p->followern >= 0 + && p->followern < numfollowers + && followers[p->followern].category < numfollowercategories) + { + for (i = 0; i < setup_numfollowercategories; i++) + { + if (followers[p->followern].category != setup_followercategories[i][1]) + continue; + + break; + } + + if (i >= setup_numfollowercategories) + i = -1; + } + + p->followercategory = i; p->rotate = CSROTATETICS; p->hitlag = true; S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s From a07aeef0498a3cb4f558eef203f81e0498da7ef7 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Dec 2023 23:00:09 +0000 Subject: [PATCH 12/15] play-char-select.c: Reduce copypasted hell Instead of manually handling every single transition, only simple transitions are unique. Helper functions are used for the complicated transitions - Color selection if there's more than 1 colour, Follower selection if you have any followers unlocked, and the choice of Alts versus Character when going back. Fixes a whole class of issues where, for example, you'd skip over setting your skincolor if you went through the Alts submenu, but not if there's only one character on that statblock. --- src/k_menu.h | 1 + src/k_menudraw.c | 2 +- src/menus/play-char-select.c | 172 ++++++++++++++++++----------------- 3 files changed, 92 insertions(+), 83 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index e750146cd..059c7528f 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -765,6 +765,7 @@ extern consvar_t *setup_playercvars[MAXSPLITSCREENPLAYERS][SPLITCV_MAX]; void M_CharacterSelectInit(void); void M_CharacterSelect(INT32 choice); void M_SetupReadyExplosions(boolean charsel, UINT16 basex, UINT16 basey, UINT16 color); +boolean M_CharacterSelectForceInAction(void); boolean M_CharacterSelectHandler(INT32 choice); void M_CharacterSelectTick(void); boolean M_CharacterSelectQuit(void); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 5a684f9be..903dc772f 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2246,7 +2246,7 @@ void M_DrawCharacterSelect(void) INT16 quadx, quady; INT16 skin; INT32 basex = optionsmenu.profile ? (64 + (menutransition.tics*32)) : 0; - boolean forceskin = (Playing() && K_CanChangeRules(true) == true) && (cv_forceskin.value != -1); + boolean forceskin = M_CharacterSelectForceInAction(); if (setup_numplayers > 0) { diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index ad8333536..58fbf3a56 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -630,9 +630,17 @@ static boolean M_HandleCSelectProfile(setup_player_t *p, UINT8 num) } +static void M_HandlePlayerFinalise(setup_player_t *p) +{ + p->mdepth = CSSTEP_READY; + p->delay = TICRATE; + M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); + S_StartSound(NULL, sfx_s3k4e); +} + + static void M_HandleCharAskChange(setup_player_t *p, UINT8 num) { - if (cv_splitdevice.value) num = 0; @@ -658,11 +666,7 @@ static void M_HandleCharAskChange(setup_player_t *p, UINT8 num) { // no changes M_GetFollowerState(p); - p->mdepth = CSSTEP_READY; - p->delay = TICRATE; - - S_StartSound(NULL, sfx_s3k4e); - M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); + M_HandlePlayerFinalise(p); } else { @@ -675,11 +679,70 @@ static void M_HandleCharAskChange(setup_player_t *p, UINT8 num) } } +boolean M_CharacterSelectForceInAction(void) +{ + if (!Playing()) + return false; + + if (K_CanChangeRules(true) == false) + return false; + + return (cv_forceskin.value != -1); +} + +static void M_HandleBackToChars(setup_player_t *p) +{ + boolean forceskin = M_CharacterSelectForceInAction(); + + if (forceskin + || setup_chargrid[p->gridx][p->gridy].numskins == 1) + { + p->mdepth = CSSTEP_CHARS; // Skip clones menu + } + else + { + p->mdepth = CSSTEP_ALTS; + } +} + +static boolean M_HandleBeginningColors(setup_player_t *p) +{ + p->mdepth = CSSTEP_COLORS; + M_NewPlayerColors(p); + if (p->colors.listLen != 1) + return true; + + p->color = p->colors.list[0]; + return false; +} + +static void M_HandleBeginningFollowers(setup_player_t *p) +{ + if (setup_numfollowercategories == 0) + { + p->followern = -1; + M_HandlePlayerFinalise(p); + } + else + { + p->mdepth = CSSTEP_FOLLOWERCATEGORY; + S_StartSound(NULL, sfx_s3k63); + } +} + +static void M_HandleBeginningColorsOrFollowers(setup_player_t *p) +{ + if (M_HandleBeginningColors(p)) + S_StartSound(NULL, sfx_s3k63); + else + M_HandleBeginningFollowers(p); +} + static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num) { UINT8 numclones; INT32 skin; - boolean forceskin = (Playing() && K_CanChangeRules(true) == true) && (cv_forceskin.value != -1); + boolean forceskin = M_CharacterSelectForceInAction(); if (cv_splitdevice.value) num = 0; @@ -748,9 +811,7 @@ static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num) } else { - p->mdepth = CSSTEP_COLORS; - M_NewPlayerColors(p); - S_StartSound(NULL, sfx_s3k63); + M_HandleBeginningColorsOrFollowers(p); } } else @@ -764,15 +825,13 @@ static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num) { if (setup_page+1 == setup_chargrid[p->gridx][p->gridy].numskins) { - p->mdepth = CSSTEP_COLORS; // Skip clones menu if there are none on this page. - M_NewPlayerColors(p); + M_HandleBeginningColorsOrFollowers(p); } else { p->mdepth = CSSTEP_ALTS; + S_StartSound(NULL, sfx_s3k63); } - - S_StartSound(NULL, sfx_s3k63); } } @@ -840,33 +899,10 @@ static void M_HandleCharRotate(setup_player_t *p, UINT8 num) S_StartSound(NULL, sfx_s3kc3s); } - if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) + if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) { - p->mdepth = CSSTEP_COLORS; - M_NewPlayerColors(p); - if (p->colors.listLen == 1) - { - p->color = p->colors.list[0]; - if (setup_numfollowercategories == 0) - { - p->followern = -1; - p->mdepth = CSSTEP_READY; - p->delay = TICRATE; - M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); - S_StartSound(NULL, sfx_s3k4e); - } - else - { - p->mdepth = CSSTEP_FOLLOWERCATEGORY; - S_StartSound(NULL, sfx_s3k63); - M_SetMenuDelay(num); - } - } - else - { - S_StartSound(NULL, sfx_s3k63); - M_SetMenuDelay(num); - } + M_HandleBeginningColorsOrFollowers(p); + M_SetMenuDelay(num); } else if (M_MenuBackPressed(num)) { @@ -886,8 +922,6 @@ static void M_HandleCharRotate(setup_player_t *p, UINT8 num) static void M_HandleColorRotate(setup_player_t *p, UINT8 num) { - boolean forceskin = (Playing() && K_CanChangeRules(true) == true) && (cv_forceskin.value != -1); - if (cv_splitdevice.value) num = 0; @@ -908,32 +942,13 @@ static void M_HandleColorRotate(setup_player_t *p, UINT8 num) if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) { - if (setup_numfollowercategories == 0) - { - p->followern = -1; - p->mdepth = CSSTEP_READY; - p->delay = TICRATE; - M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); - S_StartSound(NULL, sfx_s3k4e); - } - else - { - p->mdepth = CSSTEP_FOLLOWERCATEGORY; - S_StartSound(NULL, sfx_s3k63); - M_SetMenuDelay(num); - } + M_HandleBeginningFollowers(p); + M_SetMenuDelay(num); } else if (M_MenuBackPressed(num)) { - if (forceskin - || setup_chargrid[p->gridx][p->gridy].numskins == 1) - { - p->mdepth = CSSTEP_CHARS; // Skip clones menu - } - else - { - p->mdepth = CSSTEP_ALTS; - } + M_HandleBackToChars(p); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } @@ -1009,10 +1024,7 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num) if (p->followercategory < 0) { p->followern = -1; - p->mdepth = CSSTEP_READY; - p->delay = TICRATE; - M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); - S_StartSound(NULL, sfx_s3k4e); + M_HandlePlayerFinalise(p); } else { @@ -1046,8 +1058,9 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num) } else if (M_MenuBackPressed(num)) { - p->mdepth = CSSTEP_COLORS; - M_NewPlayerColors(p); + if (!M_HandleBeginningColors(p)) + M_HandleBackToChars(p); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } @@ -1133,10 +1146,7 @@ static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num) } else { - p->mdepth = CSSTEP_READY; - p->delay = TICRATE; - M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); - S_StartSound(NULL, sfx_s3k4e); + M_HandlePlayerFinalise(p); } M_SetMenuDelay(num); @@ -1182,10 +1192,7 @@ static void M_HandleFollowerColorRotate(setup_player_t *p, UINT8 num) if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) { - p->mdepth = CSSTEP_READY; - p->delay = TICRATE; - M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); - S_StartSound(NULL, sfx_s3k4e); + M_HandlePlayerFinalise(p); M_SetMenuDelay(num); } else if (M_MenuBackPressed(num)) @@ -1213,7 +1220,7 @@ static void M_HandleFollowerColorRotate(setup_player_t *p, UINT8 num) boolean M_CharacterSelectHandler(INT32 choice) { INT32 i; - boolean forceskin = (Playing() && K_CanChangeRules(true) == true) && (cv_forceskin.value != -1); + boolean forceskin = M_CharacterSelectForceInAction(); (void)choice; @@ -1275,8 +1282,9 @@ boolean M_CharacterSelectHandler(INT32 choice) default: // Unready if (M_MenuBackPressed(i)) { - p->mdepth = CSSTEP_COLORS; - M_NewPlayerColors(p); + if (!M_HandleBeginningColors(p)) + M_HandleBackToChars(p); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(i); } From a15f6280d7fbde4cd3056dac75f06674e3b9ed9a Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 27 Dec 2023 15:16:03 +0000 Subject: [PATCH 13/15] UCRP_TRACKHAZARD fixes - describe as "course hazard", not "track hazard", to match updated player-facing lingo - Add rudimentary handling to allow achievement in Prison Break, Versus --- src/m_cond.c | 12 +++++++++++- src/p_inter.c | 4 +++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index c61c028b0..e170f8fe6 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1817,6 +1817,16 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) case UCRP_TRACKHAZARD: { + if (!(gametyperules & GTR_CIRCUIT)) + { + // Prison Break/Versus + + if (!player->exiting && cn->requirement == 0) + return false; + + return (((player->roundconditions.hittrackhazard[0] & 1) == 1) == (cn->requirement == 1)); + } + INT16 requiredlap = cn->extrainfo1; if (requiredlap < 0) @@ -2706,7 +2716,7 @@ static const char *M_GetConditionString(condition_t *cn) case UCRP_TRACKHAZARD: { - work = (cn->requirement == 1) ? "touch a track hazard" : "don't touch any track hazards"; + work = (cn->requirement == 1) ? "touch a course hazard" : "don't touch any course hazards"; if (cn->extrainfo1 == -1) return va("%s%s", work, (cn->requirement == 1) ? " on every lap" : ""); if (cn->extrainfo1 == -2) diff --git a/src/p_inter.c b/src/p_inter.c index b8645c76a..d8512e194 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2986,10 +2986,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } } else if (!(inflictor && inflictor->player) - && player->laps <= numlaps + && !(player->exiting || player->laps > numlaps) && damagetype != DMG_DEATHPIT) { + // laps will never increment outside of GTR_CIRCUIT, so this is still fine const UINT8 requiredbit = 1<<(player->laps & 7); + if (!(player->roundconditions.hittrackhazard[player->laps/8] & requiredbit)) { player->roundconditions.hittrackhazard[player->laps/8] |= requiredbit; From 80e519e442744af337052efba552758f6bbc3f2d Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 27 Dec 2023 15:28:19 +0000 Subject: [PATCH 14/15] mapheader_t destroyforchallenge: Actually read supplied mobjtypes past the first one Fixes Joypolis chairs not being counted --- src/deh_soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 56c36604f..2e11d2ba2 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1408,7 +1408,7 @@ void readlevelheader(MYFILE *f, char * name) do { if (j >= MAXDESTRUCTIBLES) break; - mapheaderinfo[num]->destroyforchallenge[j] = get_mobjtype(word2); + mapheaderinfo[num]->destroyforchallenge[j] = get_mobjtype(tmp); j++; } while ((tmp = strtok(NULL,",")) != NULL); From 76916299036722928ad290ad6876e7fc021f534e Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 27 Dec 2023 16:34:23 +0000 Subject: [PATCH 15/15] Further cxdiag faff - Loop over each set of conditions twice - first to determine relevant level/gametype - secondly to evaluate everything else in that context - Pick up called events which are invalid for the relevant gametype - Pick up multiple levels per single condition --- src/d_netcmd.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 71d32613e..a4629b4cc 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4730,8 +4730,22 @@ static void Command_cxdiag_f(void) boolean lastRequiresPlaying = false; boolean lastrequiredplayingvalid = false; boolean immediatelyprefix = false; - for (j = 0; j < c->numconditions; ++j) + INT32 relevantlevelgt = -1; + UINT8 lastj = j = 0; + while (true) //for (j = 0; j < c->numconditions; ++j) { + if (j >= c->numconditions) + { + if (j == lastj) + break; + UINT8 swap = j; + j = lastj; + lastj = swap; + + lastrequiredplayingvalid = false; + validSoFar = true; + } + cn = &c->condition[j]; if (lastID) @@ -4742,30 +4756,54 @@ static void Command_cxdiag_f(void) { lastrequiredplayingvalid = false; validSoFar = true; + if (j != lastj) + { + UINT8 swap = j; + j = lastj; + lastj = swap; + continue; + } + relevantlevelgt = -1; } else if (!validSoFar) + { + j++; continue; + } } + const boolean firstpass = (lastj <= j); + if (cn->type == UC_DESCRIPTIONOVERRIDE) { - if (!cn->stringvar) + if (firstpass) + ; + else if (!cn->stringvar) { CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) - Description override has no description!?\n", i+1, j+1, cn->id); + errors++; } else if (cn->stringvar[0] != tolower(cn->stringvar[0])) { CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) - Description override begins with capital letter, which isn't necessary and can sometimes look weird in generated descriptions\n", i+1, j+1, cn->id); + errors++; } + lastID = cn->id; + j++; continue; } if (cn->type == UC_AND || cn->type == UC_COMMA) { - if (immediatelyprefix || lastID != cn->id) + if (firstpass) + ; + else if (immediatelyprefix || lastID != cn->id) { CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) - Conjunction immediately follows %s - this just looks plain weird!\n", i+1, j+1, cn->id, immediatelyprefix ? "Prefix type" : "start"); + errors++; } + lastID = cn->id; + j++; continue; } @@ -4774,7 +4812,7 @@ static void Command_cxdiag_f(void) lastRequiresPlaying = requiresPlaying; requiresPlaying = (cn->type >= UCRP_REQUIRESPLAYING); - if (lastrequiredplayingvalid) + if (!firstpass && lastrequiredplayingvalid) { if (lastRequiresPlaying != requiresPlaying) { @@ -4786,6 +4824,78 @@ static void Command_cxdiag_f(void) lastrequiredplayingvalid = true; immediatelyprefix = (cn->type >= UCRP_PREFIX_GRANDPRIX && cn->type <= UCRP_PREFIX_ISMAP); + + if (cn->type == UCRP_PREFIX_ISMAP || cn->type == UCRP_ISMAP) + { + if (firstpass && relevantlevelgt != -1) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) has multiple courses specified\n", i+1, j+1, lastID); + validSoFar = false; + errors++; + } + if (cn->requirement == 0) + relevantlevelgt = 0; + else if (cn->requirement > 0 && cn->requirement < basenummapheaders) + relevantlevelgt = G_GuessGametypeByTOL(mapheaderinfo[cn->requirement]->typeoflevel); + else + relevantlevelgt = -1; + } + else if (firstpass || relevantlevelgt == -1) + ; + else if (cn->type >= UCRP_PODIUMCUP && cn->type <= UCRP_PODIUMNOCONTINUES) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) is Podium state when specific course in Cup already requested\n", i+1, j+1, lastID); + validSoFar = false; + errors++; + } + else if (cn->type == UCRP_FINISHALLPRISONS || cn->type == UCRP_PREFIX_PRISONBREAK) + { + if (!(gametypes[relevantlevelgt]->rules & GTR_PRISONS)) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) is Prison Break-based, but with %s course\n", i+1, j+1, lastID, gametypes[relevantlevelgt]->name); + validSoFar = false; + errors++; + } + } + else if (cn->type == UCRP_SMASHUFO || cn->type == UCRP_PREFIX_SEALEDSTAR) + { + if (!(gametypes[relevantlevelgt]->rules & GTR_CATCHER)) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) is Sealed Star-based, but with %s course\n", i+1, j+1, lastID, gametypes[relevantlevelgt]->name); + validSoFar = false; + errors++; + } + } + else if (cn->type == UCRP_RINGS || cn->type == UCRP_RINGSEXACT || cn->type == UCRP_RINGDEBT) + { + if ((gametypes[relevantlevelgt]->rules & GTR_SPHERES)) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) is Rings-based, but with %s course\n", i+1, j+1, lastID, gametypes[relevantlevelgt]->name); + validSoFar = false; + errors++; + } + } + else if (cn->type == UCRP_GROWCONSECUTIVEBEAMS || cn->type == UCRP_FAULTED || cn->type == UCRP_FINISHPERFECT) + { + if (!(gametypes[relevantlevelgt]->rules & GTR_CIRCUIT)) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) is circuit-based, but with %s course\n", i+1, j+1, lastID, gametypes[relevantlevelgt]->name); + validSoFar = false; + errors++; + } + } + else if (cn->type == UCRP_FINISHTIMELEFT) + { + if (!(gametypes[relevantlevelgt]->rules & GTR_TIMELIMIT)) + { + CONS_Printf("\x87"" ConditionSet %u entry %u (Condition%u) is timelimit-based, but with %s course\n", i+1, j+1, lastID, gametypes[relevantlevelgt]->name); + validSoFar = false; + errors++; + } + } + + + j++; } } }