diff --git a/src/doomstat.h b/src/doomstat.h index 9dc8f4034..a31a8dc9b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -868,7 +868,6 @@ extern SINT8 spbplace; extern boolean rainbowstartavailable; extern tic_t linecrossed; extern boolean inDuel; -extern UINT8 extralaps; extern UINT8 overtimecheckpoints; extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :) diff --git a/src/g_game.c b/src/g_game.c index 226ea6d67..af8105920 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -320,7 +320,6 @@ SINT8 spbplace; // SPB exists, give the person behind better items boolean rainbowstartavailable; // Boolean, keeps track of if the rainbow start was gotten tic_t linecrossed; // For Time Attack boolean inDuel; // Boolean, keeps track of if it is a 1v1 -UINT8 extralaps; // Duel extensions! UINT8 overtimecheckpoints; // Duel overtime speedups! // Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 8918e3233..30cc7bc48 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -2997,7 +2997,7 @@ static void K_drawKartLaps(void) // I do not understand the way this system of offsets is laid out at all, // so it's probably going to be pretty bad to maintain. Sorry. - if (inDuel) + if (K_InRaceDuel()) { UINT32 flashflag = (stplyr->duelscore >= 0) ? V_BLUEMAP : V_REDMAP; if (leveltime % 2) @@ -3018,7 +3018,7 @@ static void K_drawKartLaps(void) bump = 40; } - if (numlaps != 1) + if (numlaps != 1 && !K_InRaceDuel()) { if (r_splitscreen > 1) { diff --git a/src/k_kart.c b/src/k_kart.c index 82d41dc86..43b430e8a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -119,6 +119,27 @@ boolean K_DuelItemAlwaysSpawns(mapthing_t *mt) return !!(mt->thing_args[0]); } +boolean K_InRaceDuel(void) +{ + return (inDuel && (gametyperules & GTR_CIRCUIT) && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE)); +} + +player_t *K_DuelOpponent(player_t *player) +{ + if (!K_InRaceDuel()) + return player; // ???? + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator && player - players != i) + return &players[i]; + } + } + + return player; // ???????????? +} + static void K_SpawnDuelOnlyItems(void) { mapthing_t *mt = NULL; @@ -145,7 +166,6 @@ void K_TimerReset(void) numbulbs = 1; inDuel = rainbowstartavailable = false; linecrossed = 0; - extralaps = 0; overtimecheckpoints = 0; timelimitintics = extratimeintics = secretextratime = 0; g_pointlimit = 0; @@ -275,6 +295,9 @@ void K_TimerInit(void) introtime = (108) + 5; // 108 for rotation, + 5 for white fade numbulbs += (numPlayers-2); // Extra POSITION!! time } + + if (K_InRaceDuel()) + numlaps = 200; } } @@ -4151,7 +4174,7 @@ void K_CheckpointCrossAward(player_t *player) K_AwardPlayerRings(player, (player->bot ? 20 : 10), true); // Update Duel scoring. - if (inDuel && player->position == 1) + if (K_InRaceDuel() && player->position == 1) { player->duelscore += 1; @@ -4168,10 +4191,48 @@ void K_CheckpointCrossAward(player_t *player) players[i].duelscore -= 1; } - if (player->duelscore == 3) + if (player->duelscore == DUELWINNINGSCORE) { + S_StartSound(NULL, sfx_s3k6a); P_DoPlayerExit(player, 0); P_DoAllPlayersExit(PF_NOCONTEST, 0); + + player_t *opp = K_DuelOpponent(player); + opp->position = 2; + player->position = 1; + + if (opp->distancetofinish - player->distancetofinish < 128) + { + K_StartRoundWinCamera( + player->mo, + player->angleturn + ANGLE_180, + 400*mapobjectscale, + 6*TICRATE, + FRACUNIT/16 + ); + } + else + { + K_StartRoundWinCamera( + opp->mo, + opp->angleturn + ANGLE_180, + 400*mapobjectscale, + 6*TICRATE, + FRACUNIT/16 + ); + } + + } + else + { + // Doing this here because duel exit is a weird path, and we don't want to transform for endcam. + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[(player-players)]].flags + : skins[player->skin].flags; + if (skinflags & SF_IRONMAN) + { + SetRandomFakePlayerSkin(player, true, false); + } } } @@ -10697,7 +10758,7 @@ static void K_UpdateDistanceFromFinishLine(player_t *const player) const mapheader_t *mapheader = mapheaderinfo[gamemap - 1]; if ((mapheader->levelflags & LF_SECTIONRACE) == 0U) { - const UINT8 numfulllapsleft = ((UINT8)numlaps - player->laps) / mapheader->lapspersection + extralaps; + const UINT8 numfulllapsleft = ((UINT8)numlaps - player->laps) / mapheader->lapspersection; player->distancetofinish += numfulllapsleft * K_GetCircuitLength(); } } @@ -11707,6 +11768,11 @@ void K_KartUpdatePosition(player_t *player) realplayers++; } } + else if (K_InRaceDuel() && player->exiting) + { + // Positions directly set in K_CheckpointCrossAward, don't touch. + return; + } else { for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/k_kart.h b/src/k_kart.h index 3e4995dd2..3b0b10a5b 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -75,6 +75,7 @@ Make sure this matches the actual number of states #define RINGTRANSPARENCYREGEN 3 #define DUELOVERTIME (3*60*TICRATE) +#define DUELWINNINGSCORE (1) #define MIN_WAVEDASH_CHARGE ((11*TICRATE/16)*9) @@ -94,6 +95,8 @@ angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t boolean K_IsDuelItem(mobjtype_t type); boolean K_DuelItemAlwaysSpawns(mapthing_t *mt); +boolean K_InRaceDuel(void); +player_t *K_DuelOpponent(player_t *player); void K_TimerReset(void); void K_TimerInit(void); diff --git a/src/k_tally.cpp b/src/k_tally.cpp index b095ff202..3b49c352f 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -46,6 +46,9 @@ boolean level_tally_t::UseBonuses(void) return false; } + if (K_InRaceDuel()) + return false; + // No bonuses / ranking in FREE PLAY or Time Attack return (grandprixinfo.gp == true || K_TimeAttackRules() == false); } diff --git a/src/p_saveg.c b/src/p_saveg.c index a4679ea8d..2183821c2 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6680,7 +6680,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITESINT8(save->p, spbplace); WRITEUINT8(save->p, rainbowstartavailable); WRITEUINT8(save->p, inDuel); - WRITEUINT8(save->p, extralaps); WRITEUINT8(save->p, overtimecheckpoints); WRITEUINT32(save->p, introtime); @@ -6888,7 +6887,6 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) spbplace = READSINT8(save->p); rainbowstartavailable = (boolean)READUINT8(save->p); inDuel = (boolean)READUINT8(save->p); - extralaps = (boolean)READUINT8(save->p); overtimecheckpoints = (boolean)READUINT8(save->p); introtime = READUINT32(save->p); diff --git a/src/p_spec.c b/src/p_spec.c index de2547392..0712f049f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -52,6 +52,7 @@ #include "m_easing.h" #include "music.h" #include "k_battle.h" // battleprisons +#include "k_endcam.h" // K_EndCameraIsFreezing() // Not sure if this is necessary, but it was in w_wad.c, so I'm putting it here too -Shadow Hog #include @@ -1993,11 +1994,6 @@ static void K_HandleLapIncrement(player_t *player) boolean specialduelexit = (inDuel && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE)); - if (specialduelexit) - { - extralaps += 1; - } - // finished race exit setup if (player->laps > numlaps && !specialduelexit) { @@ -2025,7 +2021,8 @@ static void K_HandleLapIncrement(player_t *player) : skins[player->skin].flags; if (skinflags & SF_IRONMAN) { - SetRandomFakePlayerSkin(player, true, false); + if (!K_InRaceDuel()) // We'll do this in K_CheckpointCrossAward if necessary. + SetRandomFakePlayerSkin(player, true, false); } // Always trust waypoints entering the first lap. @@ -2055,7 +2052,7 @@ static void K_HandleLapIncrement(player_t *player) K_SpawnDriftBoostExplosion(player, 4); K_SpawnDriftElectricSparks(player, SKINCOLOR_SILVER, false); - K_SpawnAmps(player, (inDuel) ? 20 : 50, player->mo); + K_SpawnAmps(player, (K_InRaceDuel()) ? 20 : 50, player->mo); rainbowstartavailable = false; } @@ -2077,7 +2074,9 @@ static void K_HandleLapIncrement(player_t *player) } else if (P_IsDisplayPlayer(player)) { - if (numlaps > 1 && player->laps == numlaps) // final lap + if (K_InRaceDuel()) + S_StartSound(NULL, sfx_s221); + else if (numlaps > 1 && player->laps == numlaps) // final lap S_StartSound(NULL, sfx_s3k68); else if ((player->laps > 1) && (player->laps < numlaps)) // non-final lap S_StartSound(NULL, sfx_s221); @@ -2090,7 +2089,7 @@ static void K_HandleLapIncrement(player_t *player) } else { - if ((player->laps > numlaps) && (player->position == 1)) + if ((player->laps > numlaps) && (player->position == 1) && (!K_InRaceDuel())) { // opponent finished S_StartSound(NULL, sfx_s253); @@ -4724,7 +4723,7 @@ void P_SetupSignExit(player_t *player, boolean tie) return; // SRB2Kart: FINALLY, add in an alternative if no place is found - if (player->mo && !P_MobjWasRemoved(player->mo)) + if (player->mo && !P_MobjWasRemoved(player->mo) && !K_EndCameraIsFreezing()) { thing = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->floorz, MT_SIGN); thing->angle = bestAngle; diff --git a/src/p_user.c b/src/p_user.c index c39b105bd..fc19292a6 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1368,7 +1368,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags) void P_DoAllPlayersExit(pflags_t flags, boolean trygivelife) { UINT8 i; - const boolean dofinishsound = (musiccountdown == 0); + const boolean dofinishsound = (musiccountdown == 0) && (!K_InRaceDuel()); if (grandprixinfo.gp == false || grandprixinfo.eventmode == GPEVENT_SPECIAL