diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b6825d3e3..a4629b4cc 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,226 @@ 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; + boolean immediatelyprefix = false; + 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) + { + //if (lastID != cn->id && validSoFar) + //CONS_Printf("\x87""Condition%d good\n", lastID); + if (lastID != cn->id) + { + 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 (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 (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; + } + + lastID = cn->id; + + lastRequiresPlaying = requiresPlaying; + requiresPlaying = (cn->type >= UCRP_REQUIRESPLAYING); + + if (!firstpass && 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; + + 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++; + } + } + } + + { + 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", errors); + else + CONS_Printf("\x83""No errors detected! Good job\n"); +} + // ========================================================================= // MISC. COMMANDS // ========================================================================= diff --git a/src/deh_soc.c b/src/deh_soc.c index 9c0a8feab..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); @@ -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); 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) diff --git a/src/k_menu.h b/src/k_menu.h index a34d0a94b..2e08260e9 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -771,6 +771,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 3a9b1d332..e8df09c5d 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2272,7 +2272,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) { @@ -6622,7 +6622,7 @@ challengedesc: ) ) { - V_DrawCenteredString(BASEVIDWIDTH/2, 120 + 32, 0, challengesmenu.unlockcondition); + V_DrawCenteredThinString(BASEVIDWIDTH/2, 120 + 32, 0, challengesmenu.unlockcondition); } } 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..e170f8fe6 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; } @@ -1607,7 +1613,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 +1631,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: @@ -1811,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) @@ -2514,7 +2530,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; } @@ -2700,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) @@ -2880,7 +2896,7 @@ char *M_BuildConditionSetString(UINT16 unlockid) DESCRIPTIONWIDTH << FRACBITS, FRACUNIT, FRACUNIT, FRACUNIT, 0, - HU_FONT, + TINY_FONT, message ); } @@ -2989,7 +3005,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/menus/play-char-select.c b/src/menus/play-char-select.c index 6c71e871a..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,50 +1024,67 @@ 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 { - 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); } 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); } 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 @@ -1114,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); @@ -1163,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)) @@ -1194,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; @@ -1256,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); } 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; 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) { 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; }