diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9740bdff0..88b49cd74 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2891,6 +2891,10 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r { pencoremode = bossinfo.encore; } + else if (specialStage.active == true) + { + pencoremode = specialStage.encore; + } else if (grandprixinfo.gp == true) { pencoremode = grandprixinfo.encore; diff --git a/src/g_game.c b/src/g_game.c index 2559cb707..72ad99903 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -59,6 +59,7 @@ #include "k_color.h" #include "k_grandprix.h" #include "k_boss.h" +#include "k_specialstage.h" #include "k_bot.h" #include "k_odds.h" #include "doomstat.h" @@ -2837,7 +2838,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) starposttime = 0; prevcheck = 0; nextcheck = 0; - xtralife = 0; for (i = 0; i < LAP__MAX; i++) { @@ -4397,20 +4397,104 @@ static INT16 G_GetNextMap(boolean advancemap) } else if (grandprixinfo.gp == true) { - if (grandprixinfo.roundnum == 0 || grandprixinfo.cup == NULL) // Single session + // G: oh dear, this whole GP block has loads of side effects... + // for now, just repeat the same map for "map +" + // you're not supposed to use that in GP anyways + if (!advancemap || // ...right? + grandprixinfo.roundnum == 0 || grandprixinfo.cup == NULL) // Single session { newmap = curmap; // Same map } else { - if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map + INT32 lastgametype = gametype; + + // If we're in a GP event, don't immediately follow it up with another. + // I also suspect this will not work with online GP so I'm gonna prevent it right now. + // The server might have to communicate eventmode (alongside other GP data) in XD_MAP later. + if (netgame || grandprixinfo.eventmode != GPEVENT_NONE) + { + grandprixinfo.eventmode = GPEVENT_NONE; + + G_SetGametype(GT_RACE); + if (gametype != lastgametype) + D_GameTypeChanged(lastgametype); + + specialStage.active = false; + bossinfo.boss = false; + } + // Special stage + else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) + { + INT16 totaltotalring = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + if (players[i].spectator) + continue; + if (players[i].bot) + continue; + totaltotalring += players[i].totalring; + } + + if (totaltotalring >= 50) + { + const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_SPECIAL]; + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] + && mapheaderinfo[cupLevelNum]->typeoflevel & (TOL_SPECIAL|TOL_BOSS|TOL_BATTLE)) + { + grandprixinfo.eventmode = GPEVENT_SPECIAL; + newmap = cupLevelNum; + } + } + } + else if (grandprixinfo.roundnum == (grandprixinfo.cup->numlevels+1)/2) // 3 for a 5-map cup + { + // todo any other condition? + { + const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS]; + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] + && mapheaderinfo[cupLevelNum]->typeoflevel & (TOL_BOSS|TOL_BATTLE)) + { + grandprixinfo.eventmode = GPEVENT_BONUS; + newmap = cupLevelNum; + } + } + } + + if (grandprixinfo.eventmode != GPEVENT_NONE) + { + // nextmap is set above + const INT32 newtol = mapheaderinfo[newmap]->typeoflevel; + + if (newtol & TOL_SPECIAL) + { + specialStage.active = true; + specialStage.encore = grandprixinfo.encore; + } + else //(if newtol & (TOL_BATTLE|TOL_BOSS)) -- safe to assume?? + { + G_SetGametype(GT_BATTLE); + if (gametype != lastgametype) + D_GameTypeChanged(lastgametype); + if (newtol & TOL_BOSS) + { + K_ResetBossInfo(); + bossinfo.boss = true; + bossinfo.encore = grandprixinfo.encore; + } + } + } + else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map { newmap = NEXTMAP_CEREMONY; // ceremonymap } else { // Proceed to next map - const INT32 cupLevelNum =grandprixinfo.cup->cachedlevels[grandprixinfo.roundnum]; + const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[grandprixinfo.roundnum]; if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) { diff --git a/src/k_battle.c b/src/k_battle.c index f0a8a4e07..c95455925 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -493,7 +493,7 @@ void K_BattleInit(UINT8 numPlayers) { if (modeattacking != ATTACKING_ITEMBREAK) { - if (!cv_kartitembreaker.value) + if (K_CanChangeRules() && !cv_kartitembreaker.value) goto afteritembreaker; if (numPlayers > 1) diff --git a/src/k_hud.c b/src/k_hud.c index ab7456dd1..6ab76b78c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1642,7 +1642,15 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI else { drawtime = timelimitintics - drawtime; - if (drawtime < 5*TICRATE) + if (secretextratime) + ; + else if (extratimeintics) + { + jitter = 2; + if (leveltime & 1) + jitter = -jitter; + } + else if (drawtime < 5*TICRATE) { jitter = 1; if (drawtime & 2) diff --git a/src/p_enemy.c b/src/p_enemy.c index 36ce44d69..5f83e1748 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3284,9 +3284,12 @@ void A_AttractChase(mobj_t *actor) // Set attraction flag actor->cusval = 1; - if ((actor->tracer->player->itemtype == KITEM_THUNDERSHIELD + if ( + actor->tracer->player && actor->tracer->health + && ((gametyperules & GTR_BUMPERS) + || (actor->tracer->player->itemtype == KITEM_THUNDERSHIELD && RINGTOTAL(actor->tracer->player) < actor->tracer->player->ringmax - && !(actor->tracer->player->pflags & PF_RINGLOCK)) + && !(actor->tracer->player->pflags & PF_RINGLOCK))) //&& P_CheckSight(actor, actor->tracer) ) { diff --git a/src/p_inter.c b/src/p_inter.c index 3663e4449..30d535eb8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1004,17 +1004,37 @@ void P_CheckTimeLimit(void) { INT32 i, k; + if (exitcountdown) + return; + if (!timelimitintics) return; - if (!(multiplayer || netgame)) - return; - - if (!(gametyperules & GTR_TIMELIMIT)) - return; - - if (itembreaker) - return; + if (secretextratime) + { + secretextratime--; + timelimitintics++; + } + else if (extratimeintics) + { + timelimitintics++; + if (leveltime & 1) + ; + else + { + if (extratimeintics > 20) + { + extratimeintics -= 20; + timelimitintics += 20; + } + else + { + timelimitintics += extratimeintics; + extratimeintics = 0; + } + S_StartSound(NULL, sfx_ptally); + } + } if (leveltime < (timelimitintics + starttime)) return; @@ -1408,15 +1428,39 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (itembreaker) { + // G: uncommented this for funsies + mobj_t * ring; + angle_t dir = 0; + if (inflictor) + dir = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y); + else + dir = R_PointToAngle2(source->x, source->y, target->x, target->y); + for (UINT8 i = 0; i < 2; i++) + { + dir += (ANGLE_MAX/3); + ring = P_SpawnMobj(target->x, target->y, target->z, MT_RING); + ring->angle = dir; + P_InstaThrust(ring, dir, 16*ring->scale); + ring->momz = 8 * target->scale * P_MobjFlip(target); + P_SetTarget(&ring->tracer, source); + source->player->pickuprings++; + } + target->flags2 |= MF2_BOSSFLEE; target->flags2 |= MF2_DONTRESPAWN; K_SpawnBattlePoints(source->player, NULL, 1); + // All targets busted! if (++numtargets >= nummapboxes) { - P_DoAllPlayersExit(0, true); + P_DoAllPlayersExit(0, (grandprixinfo.gp == true)); + } + else if (timelimitintics) + { + S_StartSound(NULL, sfx_s221); + extratimeintics += 10*TICRATE; + secretextratime = TICRATE/2; } - } if (cv_itemrespawn.value && modeattacking == ATTACKING_NONE && !itembreaker) diff --git a/src/p_setup.c b/src/p_setup.c index d1ebd6ae9..e55e9a6b0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8390,22 +8390,6 @@ static void P_InitGametype(void) numlaps = K_RaceLapCount(gamemap - 1); - if ((gametyperules & GTR_TIMELIMIT) && !bossinfo.boss) - { - if (K_CanChangeRules() == false) - { - timelimitintics = timelimits[gametype] * (60*TICRATE); - } - else - { - timelimitintics = cv_timelimit.value * (60*TICRATE); - } - } - else - { - timelimitintics = 0; - } - wantedcalcdelay = wantedfrequency*2; indirectitemcooldown = 0;