From f281f47c6fdda3939c98c56612cf3364fa2df895 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 14 Oct 2022 18:34:34 +0100 Subject: [PATCH] Support alternate gameplay events during GP - Implementation details: - grandprixinfo.eventmode is the reference point - All bots have spectator applied and removed at map start depending on eventmode, and I've done my best to guard against side effects of not removing them entirely - You shouldn't turn off grandprixinfo.gp when turning on things like specialStage.active or bossinfo.boss when pursuing eventmode behaviour - Probably needs to be integrated into XD_MAP for any future netplay support, is currently disabled. - You technically don't have to assign a Capsules map to be the bonus and a Special Stage to be the special. A Capsules map can be assigned to a Special Stage too, and a Boss can be assigned to either of them. - Special Stages are still just as incomplete as they were before. - Break the Capsules has special behaviour. - Timelimit starts at 20 seconds. - Earn 10 seconds (plus a little extra cheaty time) every capsule you destroy. - WIN + extra life if you bust all the capsules, COOL if you get some but run out of time, LOSE if you lose your bumper or run out of time without breaking a single capsule. - Supposed to also give you rings, but ran into a LOT of difficulty with this and didn't want to commit half-baked stuff, so it'll be a later project. Also: - Fix a long standing bug where totalring was reset between maps, preventing the sum from adding up across GP rounds and depriving you of extra lives you were owed. - Fix an issue where Break the Capsules record attack was KARTSPEED_HARD. - Send timelimitintics in savegames, since it's handled seperately now. --- src/d_netcmd.c | 22 +++++--- src/d_netcmd.h | 2 +- src/g_game.c | 103 ++++++++++++++++++++++++++++++----- src/k_battle.c | 6 +++ src/k_bot.c | 10 +--- src/k_grandprix.c | 23 +++++--- src/k_grandprix.h | 5 ++ src/k_hud.c | 39 +++++++++----- src/k_kart.c | 30 +++++++++-- src/p_enemy.c | 7 +-- src/p_inter.c | 100 ++++++++++++++++++++++++++-------- src/p_saveg.c | 4 ++ src/p_setup.c | 26 +++------ src/p_user.c | 134 +++++++++++++++++++++++----------------------- src/st_stuff.c | 41 +++++++++++--- src/y_inter.c | 23 ++++---- 16 files changed, 398 insertions(+), 177 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index f938c0119..6b9c0e043 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2572,15 +2572,19 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r if ((netgame || multiplayer) && !((gametype == newgametype) && (gametypedefaultrules[newgametype] & GTR_CAMPAIGN))) FLS = false; - if (grandprixinfo.gp == true) - { - // Too lazy to change the input value for every instance of this function....... - pencoremode = grandprixinfo.encore; - } - else if (bossinfo.boss == true) + // Too lazy to change the input value for every instance of this function....... + if (bossinfo.boss == true) { pencoremode = bossinfo.encore; } + else if (specialStage.active == true) + { + pencoremode = specialStage.encore; + } + else if (grandprixinfo.gp == true) + { + pencoremode = grandprixinfo.encore; + } if (delay != 2) { @@ -4946,6 +4950,8 @@ Lagless_OnChange (void) } UINT32 timelimitintics = 0; +UINT32 extratimeintics = 0; +UINT32 secretextratime = 0; /** Deals with a timelimit change by printing the change to the console. * If the gametype is single player, cooperative, or race, the timelimit is @@ -5752,6 +5758,10 @@ void Command_Retry_f(void) { CONS_Printf(M_GetText("This only works in singleplayer games.\n")); } + else if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE) + { + CONS_Printf(M_GetText("You can't retry right now!\n")); + } else { M_ClearMenus(true); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index d6aa7fa5b..266d73395 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -55,7 +55,7 @@ extern consvar_t cv_itemrespawn; extern consvar_t cv_pointlimit; extern consvar_t cv_timelimit; extern consvar_t cv_numlaps; -extern UINT32 timelimitintics; +extern UINT32 timelimitintics, extratimeintics, secretextratime; extern consvar_t cv_allowexitlevel; extern consvar_t cv_autobalance; diff --git a/src/g_game.c b/src/g_game.c index d8a245ae5..ffca15ce6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -58,6 +58,7 @@ #include "k_respawn.h" #include "k_grandprix.h" #include "k_boss.h" +#include "k_specialstage.h" #include "k_bot.h" #include "doomstat.h" @@ -2297,6 +2298,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) botdiffincrease = players[player].botvars.diffincrease; botrival = players[player].botvars.rival; + totalring = players[player].totalring; + xtralife = players[player].xtralife; + pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE)); // SRB2kart @@ -2315,13 +2319,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) nocontrol = 0; laps = 0; latestlap = 0; - totalring = 0; roundscore = 0; exiting = 0; khudfinish = 0; khudcardanimation = 0; starpostnum = 0; - xtralife = 0; follower = NULL; } @@ -2358,7 +2360,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) laps = players[player].laps; latestlap = players[player].latestlap; - totalring = players[player].totalring; roundscore = players[player].roundscore; exiting = players[player].exiting; @@ -2375,8 +2376,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) starpostnum = players[player].starpostnum; - xtralife = players[player].xtralife; - follower = players[player].follower; pflags |= (players[player].pflags & (PF_STASIS|PF_ELIMINATED|PF_NOCONTEST|PF_FAULT|PF_LOSTLIFE)); @@ -2919,7 +2918,7 @@ void G_ExitLevel(void) } } } - else if (grandprixinfo.gp == true) + else if (grandprixinfo.gp == true && grandprixinfo.eventmode == GPEVENT_NONE) { youlost = (grandprixinfo.wonround != true); } @@ -3233,14 +3232,14 @@ boolean G_GametypeUsesLives(void) if (modeattacking || metalrecording) // NOT in Record Attack return false; - if (bossinfo.boss == true) // Fighting a boss? + if ((grandprixinfo.gp == true) // In Grand Prix + && (gametype == GT_RACE) // NOT in bonus round + && grandprixinfo.eventmode == GPEVENT_NONE) // NOT in bonus { return true; } - if ((grandprixinfo.gp == true) // In Grand Prix - && (gametype == GT_RACE) // NOT in bonus round - && !G_IsSpecialStage(gamemap)) // NOT in special stage + if (bossinfo.boss == true) // Fighting a boss? { return true; } @@ -3723,14 +3722,94 @@ static void G_GetNextMap(void) } 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; + nextmap = 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; + nextmap = cupLevelNum; + } + } + } + + if (grandprixinfo.eventmode != GPEVENT_NONE) + { + // nextmap is set above + const INT32 newtol = mapheaderinfo[nextmap]->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 { nextmap = 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 1a4680842..cb27d9a41 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -182,7 +182,13 @@ void K_CheckBumpers(void) K_KartUpdatePosition(&players[i]); for (i = 0; i < MAXPLAYERS; i++) // and it can't be merged with this loop because it needs to be all updated before exiting... multi-loops suck... + { + if (!playeringame[i]) + continue; + if (players[i].spectator) + continue; P_DoPlayerExit(&players[i]); + } } void K_CheckEmeralds(player_t *player) diff --git a/src/k_bot.c b/src/k_bot.c index 1b5a183b0..895fefdbe 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -1261,18 +1261,12 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) INT32 turnamt = 0; line_t *botController = NULL; - // Can't build a ticcmd if we aren't spawned... - if (!player->mo) - { - return; - } - // Remove any existing controls memset(cmd, 0, sizeof(ticcmd_t)); - if (gamestate != GS_LEVEL) + if (gamestate != GS_LEVEL || !player->mo || player->spectator) { - // Not in a level. + // Not in the level. return; } diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 0fe0e557f..af4e33e68 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -332,6 +332,16 @@ void K_UpdateGrandPrixBots(void) UINT16 newrivalscore = 0; UINT8 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || !players[i].bot) + { + continue; + } + + players[i].spectator = (grandprixinfo.eventmode != GPEVENT_NONE); + } + // Find the rival. for (i = 0; i < MAXPLAYERS; i++) { @@ -518,9 +528,11 @@ void K_RetireBots(void) UINT8 i; - if (grandprixinfo.gp == true && grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) + if (grandprixinfo.gp == true + && ((grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) + || grandprixinfo.eventmode != GPEVENT_NONE)) { - // Was last map, no replacement. + // No replacement. return; } @@ -576,18 +588,13 @@ void K_RetireBots(void) { player_t *bot = NULL; - if (!playeringame[i] || !players[i].bot) + if (!playeringame[i] || !players[i].bot || players[i].spectator) { continue; } bot = &players[i]; - if (bot->spectator) - { - continue; - } - if (bot->pflags & PF_NOCONTEST) { UINT8 skinnum = defaultbotskin; diff --git a/src/k_grandprix.h b/src/k_grandprix.h index 64085fa00..cc8527508 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -16,6 +16,10 @@ #include "doomdef.h" #include "doomstat.h" +#define GPEVENT_NONE 0 +#define GPEVENT_BONUS 1 +#define GPEVENT_SPECIAL 2 + extern struct grandprixinfo { boolean gp; ///< If true, then we are in a Grand Prix. @@ -26,6 +30,7 @@ extern struct grandprixinfo boolean masterbots; ///< If true, all bots should be max difficulty (Master Mode) boolean initalize; ///< If true, we need to initialize a new session. boolean wonround; ///< If false, then we retry the map instead of going to the next. + UINT8 eventmode; ///< See GPEVENT_ constants } grandprixinfo; diff --git a/src/k_hud.c b/src/k_hud.c index 7329d8398..ff319b89b 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -12,6 +12,7 @@ #include "k_hud.h" #include "k_kart.h" #include "k_battle.h" +#include "k_grandprix.h" #include "k_boss.h" #include "k_color.h" #include "k_director.h" @@ -1406,7 +1407,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) @@ -3904,7 +3913,7 @@ static void K_drawBattleFullscreen(void) if (K_IsPlayerLosing(stplyr)) p = kp_battlelose; - else if (stplyr->position == 1) + else if (stplyr->position == 1 && (!battlecapsules || numtargets >= maptargets)) p = kp_battlewin; V_DrawFixedPatch(x<spectator) // FREE PLAY? + // FREE PLAY? { UINT8 i; @@ -3961,11 +3970,11 @@ static void K_drawBattleFullscreen(void) { if (i == displayplayers[0]) continue; - if (playeringame[i] && !stplyr->spectator) - return; + if (playeringame[i] && !players[i].spectator) + break; } - if (LUA_HudEnabled(hud_freeplay)) + if (i != MAXPLAYERS) K_drawKartFreePlay(); } } @@ -4359,8 +4368,13 @@ static void K_drawTrickCool(void) void K_drawKartFreePlay(void) { - // no splitscreen support because it's not FREE PLAY if you have more than one player in-game - // (you fool, you can take splitscreen online. :V) + // Doesn't support splitscreens higher than 2 for real estate reasons. + + if (!LUA_HudEnabled(hud_freeplay)) + return; + + if (modeattacking || grandprixinfo.gp || bossinfo.boss || stplyr->spectator) + return; if (lt_exitticker < TICRATE/2) return; @@ -4369,7 +4383,7 @@ void K_drawKartFreePlay(void) return; V_DrawKartString((BASEVIDWIDTH - (LAPS_X+1)) - 72, // mirror the laps thingy - LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT, "FREE PLAY"); + LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, "FREE PLAY"); } static void @@ -4733,11 +4747,8 @@ void K_drawKartHUD(void) V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem); // Draw FREE PLAY. - if (islonesome && !modeattacking && !bossinfo.boss && !stplyr->spectator) - { - if (LUA_HudEnabled(hud_freeplay)) - K_drawKartFreePlay(); - } + if (islonesome) + K_drawKartFreePlay(); if (r_splitscreen == 0 && (stplyr->pflags & PF_WRONGWAY) && ((leveltime / 8) & 1)) { diff --git a/src/k_kart.c b/src/k_kart.c index 7616ee3c6..3957fa72e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -40,6 +40,7 @@ #include "k_collide.h" #include "k_follower.h" #include "k_objects.h" +#include "k_grandprix.h" #include "k_specialstage.h" // SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H: @@ -158,6 +159,29 @@ void K_TimerInit(void) // NOW you can try to spawn in the Battle capsules, if there's not enough players for a match K_BattleInit(); + timelimitintics = extratimeintics = secretextratime = 0; + if ((gametyperules & GTR_TIMELIMIT) && !bossinfo.boss) + { + if (!K_CanChangeRules()) + { + if (grandprixinfo.gp) + { + timelimitintics = (20*TICRATE); + } + else + { + timelimitintics = timelimits[gametype] * (60*TICRATE); + } + } + else +#ifndef TESTOVERTIMEINFREEPLAY + if (!battlecapsules) +#endif + { + timelimitintics = cv_timelimit.value * (60*TICRATE); + } + } + if (inDuel == true) { K_SpawnDuelOnlyItems(); @@ -331,10 +355,10 @@ boolean K_IsPlayerLosing(player_t *player) INT32 winningpos = 1; UINT8 i, pcount = 0; - if (battlecapsules && player->bumpers <= 0) - return true; // DNF in break the capsules + if (battlecapsules && numtargets == 0) + return true; // Didn't even TRY? - if (bossinfo.boss) + if (battlecapsules || bossinfo.boss) return (player->bumpers <= 0); // anything short of DNF is COOL if (player->position == 1) diff --git a/src/p_enemy.c b/src/p_enemy.c index 827e42c8e..14e17e558 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4032,9 +4032,10 @@ void A_AttractChase(mobj_t *actor) if ( actor->tracer->player && actor->tracer->health - && actor->tracer->player->itemtype == KITEM_LIGHTNINGSHIELD - && RINGTOTAL(actor->tracer->player) < 20 - && !(actor->tracer->player->pflags & PF_RINGLOCK) + && (gametyperules & GTR_SPHERES) + || (actor->tracer->player->itemtype == KITEM_LIGHTNINGSHIELD + && RINGTOTAL(actor->tracer->player) < 20 + && !(actor->tracer->player->pflags & PF_RINGLOCK)) //&& P_CheckSight(actor, actor->tracer) ) { diff --git a/src/p_inter.c b/src/p_inter.c index 838cdd25f..9d0c5de68 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -603,19 +603,37 @@ void P_CheckTimeLimit(void) { INT32 i; + if (exitcountdown) + return; + if (!timelimitintics) return; -#ifndef TESTOVERTIMEINFREEPLAY - if (battlecapsules && (grandprixinfo.gp == false)) - return; -#endif - - if (!(gametyperules & GTR_TIMELIMIT)) - return; - - if (bossinfo.boss == true) - 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; @@ -705,16 +723,19 @@ void P_CheckPointLimit(void) { INT32 i; - if (!cv_pointlimit.value) + if (exitcountdown) return; - if (!(multiplayer || netgame)) + if (!K_CanChangeRules()) + return; + + if (!cv_pointlimit.value) return; if (!(gametyperules & GTR_POINTLIMIT)) return; - if (bossinfo.boss == true) + if (battlecapsules) return; // pointlimit is nonzero, check if it's been reached by this player @@ -1422,19 +1443,21 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget case MT_BATTLECAPSULE: { + UINT8 i; mobj_t *cur; + angle_t dir = 0; - numtargets++; target->fuse = 16; target->flags |= MF_NOCLIP|MF_NOCLIPTHING; if (inflictor) { - P_Thrust(target, - R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y), - P_AproxDistance(inflictor->momx, inflictor->momy) / 12 - ); + dir = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y); + P_Thrust(target, dir, P_AproxDistance(inflictor->momx, inflictor->momy)/12); } + else if (source) + dir = R_PointToAngle2(source->x, source->y, target->x, target->y); + target->momz += 8 * target->scale * P_MobjFlip(target); target->flags &= ~MF_NOGRAVITY; @@ -1467,12 +1490,47 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget S_StartSound(target, sfx_mbs60); - // All targets busted! - if (numtargets >= maptargets) + if ((gametyperules & GTR_POINTLIMIT) && (source && source->player)) { - UINT8 i; + /*mobj_t * ring; + for (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++; + }*/ + + P_AddPlayerScore(source->player, 1); + K_SpawnBattlePoints(source->player, NULL, 1); + } + + // All targets busted! + if (++numtargets >= maptargets) + { + boolean givelife = false; for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; P_DoPlayerExit(&players[i]); + if (!grandprixinfo.gp) + continue; + P_GivePlayerLives(&players[i], 1); + givelife = true; + } + + if (givelife) + S_StartSound(NULL, sfx_cdfm73); + } + else if (timelimitintics) + { + S_StartSound(NULL, sfx_s221); + extratimeintics += 10*TICRATE; + secretextratime = TICRATE/2; } } break; diff --git a/src/p_saveg.c b/src/p_saveg.c index 3f3828051..db3d38f28 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4596,6 +4596,10 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT32(save_p, starttime); WRITEUINT8(save_p, numbulbs); + WRITEUINT32(save_p, timelimitintics); + WRITEUINT32(save_p, extratimeintics); + WRITEUINT32(save_p, secretextratime); + // Is it paused? if (paused) WRITEUINT8(save_p, 0x2f); diff --git a/src/p_setup.c b/src/p_setup.c index a8c35596f..fd80fec57 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3565,7 +3565,7 @@ static void P_InitLevelSettings(void) // SRB2Kart: map load variables if (grandprixinfo.gp == true) { - if (gametype == GT_BATTLE) + if ((gametyperules & GTR_BUMPERS)) { gamespeed = KARTSPEED_EASY; } @@ -3584,7 +3584,10 @@ static void P_InitLevelSettings(void) else if (modeattacking) { // Just play it safe and set everything - gamespeed = KARTSPEED_HARD; + if ((gametyperules & GTR_BUMPERS)) + gamespeed = KARTSPEED_EASY; + else + gamespeed = KARTSPEED_HARD; franticitems = false; } else @@ -3843,7 +3846,6 @@ static void P_InitPlayers(void) static void P_InitGametype(void) { size_t i; - boolean canchangerules = K_CanChangeRules(); spectateGriefed = 0; K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped @@ -3855,7 +3857,7 @@ static void P_InitGametype(void) if (gametyperules & GTR_CIRCUIT) { - if (canchangerules && cv_numlaps.value + if (K_CanChangeRules() && cv_numlaps.value && (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) || (mapheaderinfo[gamemap - 1]->numlaps > cv_numlaps.value))) { @@ -3875,22 +3877,6 @@ static void P_InitGametype(void) numlaps = 0; } - if ((gametyperules & GTR_TIMELIMIT) && !bossinfo.boss) - { - if (!canchangerules) - { - timelimitintics = timelimits[gametype] * (60*TICRATE); - } - else - { - timelimitintics = cv_timelimit.value * (60*TICRATE); - } - } - else - { - timelimitintics = 0; - } - wantedcalcdelay = wantedfrequency*2; for (i = 0; i < NUMKARTITEMS-1; i++) diff --git a/src/p_user.c b/src/p_user.c index 418ac6543..af117a685 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -505,7 +505,6 @@ INT32 P_GivePlayerRings(player_t *player, INT32 num_rings) num_rings -= (test+20); player->rings += num_rings; - //player->totalring += num_rings; // Used for GP lives later -- maybe you might want to move this earlier to discourage ring debt... return num_rings; } @@ -1263,75 +1262,78 @@ void P_DoPlayerExit(player_t *player) player->exiting = 1; - if ((gametyperules & GTR_CIRCUIT)) // If in Race Mode, allow + if (!player->spectator) { - K_KartUpdatePosition(player); - - if (cv_kartvoices.value) + if ((gametyperules & GTR_CIRCUIT)) // If in Race Mode, allow { - if (P_IsDisplayPlayer(player)) + K_KartUpdatePosition(player); + + if (cv_kartvoices.value) { - sfxenum_t sfx_id; - if (losing) - sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound]; - else - sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound]; - S_StartSound(NULL, sfx_id); - } - else - { - if (losing) - S_StartSound(player->mo, sfx_klose); - else - S_StartSound(player->mo, sfx_kwin); - } - } - - if (!K_CanChangeRules() || cv_inttime.value > 0) - P_EndingMusic(player); - - if (P_CheckRacers() && !exitcountdown) - exitcountdown = raceexittime+1; - } - else if ((gametyperules & GTR_BUMPERS)) // Battle Mode exiting - { - if (!exitcountdown) - exitcountdown = battleexittime+1; - P_EndingMusic(player); - } - else // Accidental death safeguard??? - { - if (!exitcountdown) - exitcountdown = raceexittime+2; - } - - if (grandprixinfo.gp == true) - { - if (player->bot) - { - // Bots are going to get harder... :) - K_IncreaseBotDifficulty(player); - } - else if (!losing) - { - const UINT8 lifethreshold = 20; - UINT8 extra = 0; - - // YOU WIN - grandprixinfo.wonround = true; - - // Increase your total rings - if (RINGTOTAL(player) > 0) - { - player->totalring += RINGTOTAL(player); - - extra = player->totalring / lifethreshold; - - if (extra > player->xtralife) + if (P_IsDisplayPlayer(player)) { - P_GivePlayerLives(player, extra - player->xtralife); - S_StartSound(NULL, sfx_cdfm73); - player->xtralife = extra; + sfxenum_t sfx_id; + if (losing) + sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound]; + else + sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound]; + S_StartSound(NULL, sfx_id); + } + else + { + if (losing) + S_StartSound(player->mo, sfx_klose); + else + S_StartSound(player->mo, sfx_kwin); + } + } + + if (!K_CanChangeRules() || cv_inttime.value > 0) + P_EndingMusic(player); + + if (P_CheckRacers() && !exitcountdown) + exitcountdown = raceexittime+1; + } + else if ((gametyperules & GTR_BUMPERS)) // Battle Mode exiting + { + if (!exitcountdown) + exitcountdown = battleexittime+1; + P_EndingMusic(player); + } + else // Accidental death safeguard??? + { + if (!exitcountdown) + exitcountdown = raceexittime+2; + } + + if (grandprixinfo.gp == true) + { + if (player->bot) + { + // Bots are going to get harder... :) + K_IncreaseBotDifficulty(player); + } + else if (!losing) + { + const UINT8 lifethreshold = 20; + UINT8 extra = 0; + + // YOU WIN + grandprixinfo.wonround = true; + + // Increase your total rings + if (RINGTOTAL(player) > 0) + { + player->totalring += RINGTOTAL(player); + + extra = player->totalring / lifethreshold; + + if (extra > player->xtralife) + { + P_GivePlayerLives(player, extra - player->xtralife); + S_StartSound(NULL, sfx_cdfm73); + player->xtralife = extra; + } } } } diff --git a/src/st_stuff.c b/src/st_stuff.c index d46da54b5..abdd232fb 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -437,6 +437,7 @@ static patch_t *tcol2; static patch_t *tcroundbar; static patch_t *tcround; +static patch_t *tcbonus; static patch_t *tccircletop; static patch_t *tccirclebottom; @@ -446,6 +447,8 @@ static patch_t *tcbanner; static patch_t *tcbanner2; static patch_t *tcroundnum[10]; +static patch_t *tcroundbonus; + static patch_t *tcactnum[10]; static patch_t *tcact; @@ -495,6 +498,7 @@ static void ST_cacheLevelTitle(void) tcroundbar = (patch_t *)W_CachePatchName("TCBB0", PU_HUDGFX); tcround = (patch_t *)W_CachePatchName("TCROUND", PU_HUDGFX); + tcbonus = (patch_t *)W_CachePatchName("TCBONUS", PU_HUDGFX); tccircletop = (patch_t *)W_CachePatchName("TCSN1", PU_HUDGFX); tccirclebottom =(patch_t *)W_CachePatchName("TCSN2", PU_HUDGFX); @@ -514,6 +518,7 @@ static void ST_cacheLevelTitle(void) sprintf(buf, "TT_RND%d", i); tcroundnum[i-1] = (patch_t *)W_CachePatchName(buf, PU_HUDGFX); } + tcroundbonus = (patch_t *)W_CachePatchName("TT_RNDB", PU_HUDGFX); // Cache act # for (i=0; i < 10; i++) @@ -579,7 +584,7 @@ void ST_runTitleCard(void) { boolean run = !(paused || P_AutoPause()); INT32 auxticker; - boolean gp = (grandprixinfo.gp && grandprixinfo.roundnum); // check whether we're in grandprix + boolean gp = (marathonmode || (grandprixinfo.gp && grandprixinfo.roundnum)); if (!G_IsTitleCardAvailable()) return; @@ -764,7 +769,7 @@ void ST_drawTitleCard(void) char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl; char *zonttl = mapheaderinfo[gamemap-1]->zonttl; // SRB2kart UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; - boolean gp = (grandprixinfo.gp && grandprixinfo.roundnum); + boolean gp = (marathonmode || (grandprixinfo.gp && grandprixinfo.roundnum)); INT32 acttimer; fixed_t actscale; @@ -895,7 +900,9 @@ void ST_drawTitleCard(void) V_DrawFixedPatch(roundx*FRACUNIT, ((-32) + (lt_ticker%32))*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, tcroundbar, NULL); // Draw ROUND text if (gp) - V_DrawFixedPatch((roundx+10)*FRACUNIT, roundy*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, tcround, NULL); + V_DrawFixedPatch((roundx+10)*FRACUNIT, roundy*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, + ((grandprixinfo.gp && grandprixinfo.eventmode) ? tcbonus : tcround), + NULL); // round num background V_DrawFixedPatch(roundnumx*FRACUNIT, roundnumy*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tccirclebg, NULL); @@ -912,9 +919,31 @@ void ST_drawTitleCard(void) } } - // If possible, draw round number - if (gp && grandprixinfo.roundnum > 0 && grandprixinfo.roundnum < 11) // Check boundaries JUST IN CASE. - V_DrawFixedPatch(roundnumx*FRACUNIT, roundnumy*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tcroundnum[grandprixinfo.roundnum-1], NULL); + // If possible, draw round number/icon + if (gp) + { + patch_t *roundico = NULL; + if (marathonmode) + ; // TODO: Ruby + else switch (grandprixinfo.eventmode) + { + case GPEVENT_BONUS: + roundico = tcroundbonus; + break; + /*case GPEVENT_SPECIAL: + ; // TODO: Emerald/mount + break;*/ + case GPEVENT_NONE: + if (grandprixinfo.roundnum > 0 && grandprixinfo.roundnum < 11) // Check boundaries JUST IN CASE. + roundico = tcroundnum[grandprixinfo.roundnum-1]; + break; + default: + break; + } + + if (roundico) + V_DrawFixedPatch(roundnumx*FRACUNIT, roundnumy*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, roundico, NULL); + } // Draw both halves of the egg V_DrawFixedPatch(eggx1*FRACUNIT, eggy1*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tccircletop, NULL); diff --git a/src/y_inter.c b/src/y_inter.c index c0fbd8588..f943d09d4 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -753,21 +753,26 @@ void Y_DetermineIntermissionType(void) // set to int_none initially intertype = int_none; - if (intermissiontypes[gametype] != int_none) - intertype = intermissiontypes[gametype]; - else if (gametype == GT_RACE) + if (gametype == GT_RACE) intertype = int_race; else if (gametype == GT_BATTLE) { - UINT8 i = 0, nump = 0; - for (i = 0; i < MAXPLAYERS; i++) + if (grandprixinfo.gp == true && bossinfo.boss == false) + intertype = int_none; + else { - if (!playeringame[i] || players[i].spectator) - continue; - nump++; + UINT8 i = 0, nump = 0; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + nump++; + } + intertype = (nump < 2 ? int_battletime : int_battle); } - intertype = (nump < 2 ? int_battletime : int_battle); } + else //if (intermissiontypes[gametype] != int_none) + intertype = intermissiontypes[gametype]; } //