diff --git a/src/d_main.c b/src/d_main.c index c52749504..fe7e312ee 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1136,7 +1136,24 @@ void D_SRB2Main(void) else { if (!M_CheckParm("-server")) + { G_SetGameModified(true, true); + + // Start up a "minor" grand prix session + memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); + + grandprixinfo.gamespeed = KARTSPEED_NORMAL; + grandprixinfo.encore = false; + grandprixinfo.masterbots = false; + + grandprixinfo.gp = true; + grandprixinfo.roundnum = 0; + grandprixinfo.cup = NULL; + grandprixinfo.wonround = false; + + grandprixinfo.initalize = true; + } + autostart = true; } } @@ -1519,18 +1536,46 @@ void D_SRB2Main(void) INT16 newskill = -1; const char *sskill = M_GetNextParm(); - for (j = 0; kartspeed_cons_t[j].strvalue; j++) - if (!strcasecmp(kartspeed_cons_t[j].strvalue, sskill)) + const UINT8 master = KARTSPEED_HARD+1; + const char *masterstr = "Master"; + + if (!strcasecmp(masterstr, sskill)) + { + newskill = master; + } + else + { + for (j = 0; kartspeed_cons_t[j].strvalue; j++) { - newskill = (INT16)kartspeed_cons_t[j].value; - break; + if (!strcasecmp(kartspeed_cons_t[j].strvalue, sskill)) + { + newskill = (INT16)kartspeed_cons_t[j].value; + break; + } } - if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match + if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match + { + j = atoi(sskill); // assume they gave us a skill number, which is okay too + if (j >= KARTSPEED_EASY && j <= master) + newskill = (INT16)j; + } + } + + if (grandprixinfo.gp == true) { - j = atoi(sskill); // assume they gave us a skill number, which is okay too - if (j >= KARTSPEED_EASY && j <= KARTSPEED_HARD) - newskill = (INT16)j; + if (newskill == master) + { + grandprixinfo.masterbots = true; + newskill = KARTSPEED_HARD; + } + + grandprixinfo.gamespeed = newskill; + } + else if (newskill == master) + { + grandprixinfo.masterbots = true; + newskill = KARTSPEED_HARD; } if (newskill != -1) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 2ac42910f..3ce214aab 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2769,7 +2769,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r if (netgame || multiplayer) FLS = false; - if (grandprixinfo.roundnum != 0) + if (grandprixinfo.gp == true) { // Too lazy to change the input value for every instance of this function....... pencoremode = grandprixinfo.encore; @@ -2922,6 +2922,7 @@ static void Command_Map_f(void) INT32 newmapnum; boolean newresetplayers, newencoremode; INT32 newgametype = gametype; + boolean startgp = false; // max length of command: map map03 -gametype race -noresetplayers -force -encore // 1 2 3 4 5 6 7 @@ -2952,6 +2953,7 @@ static void Command_Map_f(void) if (COM_CheckParm("-force")) { G_SetGameModified(false, true); + startgp = true; } else { @@ -3044,6 +3046,69 @@ static void Command_Map_f(void) return; } + if (startgp) + { + i = COM_CheckParm("-skill"); + + grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value); + grandprixinfo.masterbots = false; + + if (i) + { + const UINT8 master = KARTSPEED_HARD+1; + const char *masterstr = "Master"; + const char *skillname = COM_Argv(i+1); + INT32 newskill = -1; + INT32 j; + + if (!strcasecmp(masterstr, skillname)) + { + newskill = master; + } + else + { + for (j = 0; kartspeed_cons_t[j].strvalue; j++) + { + if (!strcasecmp(kartspeed_cons_t[j].strvalue, skillname)) + { + newskill = (INT16)kartspeed_cons_t[j].value; + break; + } + } + + if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match + { + j = atoi(COM_Argv(i+1)); // assume they gave us a skill number, which is okay too + if (j >= KARTSPEED_EASY && j <= master) + newskill = (INT16)j; + } + } + + if (newskill != -1) + { + if (newskill == master) + { + grandprixinfo.gamespeed = KARTSPEED_HARD; + grandprixinfo.masterbots = true; + } + else + { + grandprixinfo.gamespeed = newskill; + grandprixinfo.masterbots = false; + } + } + } + + grandprixinfo.encore = newencoremode; + + grandprixinfo.gp = true; + grandprixinfo.roundnum = 0; + grandprixinfo.cup = NULL; + grandprixinfo.wonround = false; + + grandprixinfo.initalize = true; + } + fromlevelselect = false; D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false); } @@ -5067,14 +5132,16 @@ static void PointLimit_OnChange(void) static void NumLaps_OnChange(void) { - if (!G_RaceGametype() || (modeattacking || demo.playback)) + if (K_CanChangeRules() == false) + { return; + } - if (server && Playing() - && (netgame || multiplayer) - && (mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) - && (cv_numlaps.value > mapheaderinfo[gamemap - 1]->numlaps)) + if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) + && (cv_numlaps.value > mapheaderinfo[gamemap - 1]->numlaps)) + { CV_StealthSetValue(&cv_numlaps, mapheaderinfo[gamemap - 1]->numlaps); + } // Just don't be verbose CONS_Printf(M_GetText("Number of laps set to %d\n"), cv_numlaps.value); @@ -5707,7 +5774,7 @@ void Command_Retry_f(void) { CONS_Printf(M_GetText("You must be in a level to use this.\n")); } - else if (netgame || grandprixinfo.roundnum == 0) + else if (grandprixinfo.gp == false) { CONS_Printf(M_GetText("This only works in Grand Prix.\n")); } @@ -6201,24 +6268,35 @@ static void Command_ShowTime_f(void) // SRB2Kart: On change messages static void BaseNumLaps_OnChange(void) { - if (gamestate == GS_LEVEL && grandprixinfo.roundnum == 0) + if (K_CanChangeRules() == true) { - if (cv_basenumlaps.value) - CONS_Printf(M_GetText("Number of laps will be changed to %d next round.\n"), cv_basenumlaps.value); - else - CONS_Printf(M_GetText("Number of laps will be changed to map defaults next round.\n")); + const char *str = va("%d", cv_basenumlaps.value); + + if (cv_basenumlaps.value == 0) + { + str = "map defaults"; + } + + CONS_Printf(M_GetText("Number of laps will be changed to %s next round.\n"), str); } } static void KartFrantic_OnChange(void) { - if ((boolean)cv_kartfrantic.value != franticitems && gamestate == GS_LEVEL && leveltime > starttime) - CONS_Printf(M_GetText("Frantic items will be turned %s next round.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off")); + if (K_CanChangeRules() == false) + { + return; + } + + if (leveltime < starttime) + { + CONS_Printf(M_GetText("Frantic items has been set to %s.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off")); + franticitems = (boolean)cv_kartfrantic.value; + } else { - CONS_Printf(M_GetText("Frantic items has been turned %s.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off")); - franticitems = (boolean)cv_kartfrantic.value; + CONS_Printf(M_GetText("Frantic items will be turned %s next round.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off")); } } @@ -6231,47 +6309,59 @@ static void KartSpeed_OnChange(void) return; } - if (G_RaceGametype() && grandprixinfo.roundnum == 0) + if (K_CanChangeRules() == false) { - if ((gamestate == GS_LEVEL && leveltime < starttime) && (cv_kartspeed.value != KARTSPEED_AUTO)) - { - CONS_Printf(M_GetText("Game speed has been changed to \"%s\".\n"), cv_kartspeed.string); - gamespeed = (UINT8)cv_kartspeed.value; - } - else if (cv_kartspeed.value != (signed)gamespeed) - { - CONS_Printf(M_GetText("Game speed will be changed to \"%s\" next round.\n"), cv_kartspeed.string); - } + return; + } + + if (leveltime < starttime && cv_kartspeed.value != KARTSPEED_AUTO) + { + CONS_Printf(M_GetText("Game speed has been changed to \"%s\".\n"), cv_kartspeed.string); + gamespeed = (UINT8)cv_kartspeed.value; + } + else + { + CONS_Printf(M_GetText("Game speed will be changed to \"%s\" next round.\n"), cv_kartspeed.string); } } static void KartEncore_OnChange(void) { - if (G_RaceGametype() && grandprixinfo.roundnum == 0) + if (K_CanChangeRules() == false) { - if ((cv_kartencore.value == 1) != encoremode && gamestate == GS_LEVEL /*&& leveltime > starttime*/) - CONS_Printf(M_GetText("Encore Mode will be set to %s next round.\n"), cv_kartencore.string); - else - CONS_Printf(M_GetText("Encore Mode has been set to %s.\n"), cv_kartencore.string); + return; } + + CONS_Printf(M_GetText("Encore Mode will be set to %s next round.\n"), cv_kartencore.string); } static void KartComeback_OnChange(void) { - if (G_BattleGametype()) + if (K_CanChangeRules() == false) { - if ((boolean)cv_kartcomeback.value != comeback && gamestate == GS_LEVEL && leveltime > starttime) - CONS_Printf(M_GetText("Karma Comeback will be turned %s next round.\n"), cv_kartcomeback.value ? M_GetText("on") : M_GetText("off")); - else - { - CONS_Printf(M_GetText("Karma Comeback has been turned %s.\n"), cv_kartcomeback.value ? M_GetText("on") : M_GetText("off")); - comeback = (boolean)cv_kartcomeback.value; - } + return; + } + + if (leveltime < starttime) + { + CONS_Printf(M_GetText("Karma Comeback has been turned %s.\n"), cv_kartcomeback.value ? M_GetText("on") : M_GetText("off")); + comeback = (boolean)cv_kartcomeback.value; + } + else + { + CONS_Printf(M_GetText("Karma Comeback will be turned %s next round.\n"), cv_kartcomeback.value ? M_GetText("on") : M_GetText("off")); } } static void KartEliminateLast_OnChange(void) { - if (G_RaceGametype() && cv_karteliminatelast.value && grandprixinfo.roundnum == 0) + if (K_CanChangeRules() == false) + { + CV_StealthSet(&cv_karteliminatelast, cv_karteliminatelast.defaultvalue); + } + + if (G_RaceGametype()) + { P_CheckRacers(); + } } diff --git a/src/g_game.c b/src/g_game.c index ca3fc4a9e..617905a55 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3220,7 +3220,7 @@ void G_ExitLevel(void) { if (gamestate == GS_LEVEL) { - if (grandprixinfo.roundnum > 0 && grandprixinfo.wonround != true) + if (grandprixinfo.gp == true && grandprixinfo.wonround != true) { UINT8 i; @@ -3336,7 +3336,7 @@ boolean G_IsSpecialStage(INT32 mapnum) // boolean G_GametypeUsesLives(void) { - if ((grandprixinfo.roundnum > 0) // In Grand Prix + if ((grandprixinfo.gp == true) // In Grand Prix && (gametype == GT_RACE) // NOT in bonus round && !(modeattacking) // NOT in Record Attack && !G_IsSpecialStage(gamemap)) // NOT in special stage @@ -3734,16 +3734,24 @@ static void G_DoCompleted(void) { nextmap = (INT16)(nextmapoverride-1); } - else if (grandprixinfo.roundnum != 0) + else if (grandprixinfo.gp == true) { - if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) + if (grandprixinfo.roundnum == 0 || grandprixinfo.cup == NULL) // Single session { - nextmap = 1101; // ceremonymap + nextmap = prevmap; // Same map } else { - nextmap = grandprixinfo.cup->levellist[grandprixinfo.roundnum]; - grandprixinfo.roundnum++; + if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map + { + nextmap = 1101; // ceremonymap + } + else + { + // Proceed to next map + nextmap = grandprixinfo.cup->levellist[grandprixinfo.roundnum]; + grandprixinfo.roundnum++; + } } } else @@ -3759,7 +3767,7 @@ static void G_DoCompleted(void) // a map of the proper gametype -- skip levels that don't support // the current gametype. (Helps avoid playing boss levels in Race, // for instance). - if (!modeattacking && (grandprixinfo.roundnum == 0) && (nextmap >= 0 && nextmap < NUMMAPS)) + if (!modeattacking && grandprixinfo.gp == false && (nextmap >= 0 && nextmap < NUMMAPS)) { register INT16 cm = nextmap; INT16 tolflag = G_TOLFlag(gametype); @@ -3883,7 +3891,7 @@ void G_NextLevel(void) { if (gamestate != GS_VOTING) { - if ((cv_advancemap.value == 3) && grandprixinfo.roundnum == 0 && !modeattacking && !skipstats && (multiplayer || netgame)) + if ((cv_advancemap.value == 3) && grandprixinfo.gp == false && !modeattacking && !skipstats && (multiplayer || netgame)) { UINT8 i; for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 09f61252b..a4882147a 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -280,11 +280,17 @@ static INT16 K_RivalScore(player_t *bot) { const UINT16 difficulty = bot->botvars.difficulty; const UINT16 score = bot->score; - const SINT8 roundsleft = grandprixinfo.cup->numlevels - grandprixinfo.roundnum; + SINT8 roundnum = 1, roundsleft = 1; UINT16 lowestscore = UINT16_MAX; UINT8 lowestdifficulty = MAXBOTDIFFICULTY; UINT8 i; + if (grandprixinfo.cup != NULL) + { + roundnum = grandprixinfo.roundnum; + roundsleft = grandprixinfo.cup->numlevels - grandprixinfo.roundnum; + } + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) @@ -307,7 +313,7 @@ static INT16 K_RivalScore(player_t *bot) // This will try to influence the higher difficulty bots to get rival more often & get even more points. // However, when we're running low on matches left, we need to focus more on raw score! - return ((difficulty - lowestdifficulty) * roundsleft) + ((score - lowestscore) * grandprixinfo.roundnum); + return ((difficulty - lowestdifficulty) * roundsleft) + ((score - lowestscore) * roundnum); } /*-------------------------------------------------- @@ -569,3 +575,31 @@ void K_PlayerLoseLife(player_t *player) } #endif } + +/*-------------------------------------------------- + boolean K_CanChangeRules(void) + + See header file for description. +--------------------------------------------------*/ +boolean K_CanChangeRules(void) +{ + if (demo.playback) + { + // We've already got our important settings! + return false; + } + + if (grandprixinfo.gp == true && grandprixinfo.roundnum > 0) + { + // Don't cheat the rules of the GP! + return false; + } + + if (modeattacking == true) + { + // Don't cheat the rules of Time Trials! + return false; + } + + return true; +} diff --git a/src/k_grandprix.h b/src/k_grandprix.h index 3deccabd1..9f27b485b 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -18,7 +18,8 @@ extern struct grandprixinfo { - UINT8 roundnum; ///< Round number -- if 0, then we're not in a Grand Prix. + boolean gp; ///< If true, then we are in a Grand Prix. + UINT8 roundnum; ///< Round number. If 0, this is a single session from the warp command. cupheader_t *cup; ///< Which cup are we playing? UINT8 gamespeed; ///< Copy of gamespeed, just to make sure you can't cheat it with cvars boolean encore; ///< Ditto, but for encore mode @@ -124,4 +125,20 @@ void K_FakeBotResults(player_t *bot); void K_PlayerLoseLife(player_t *player); + +/*-------------------------------------------------- + boolean K_CanChangeRules(void); + + Returns whenver or not the server is allowed + to change the game rules. + + Input Arguments:- + None + + Return:- + None +--------------------------------------------------*/ + +boolean K_CanChangeRules(void); + #endif diff --git a/src/k_pwrlv.c b/src/k_pwrlv.c index ee7c28849..eac664408 100644 --- a/src/k_pwrlv.c +++ b/src/k_pwrlv.c @@ -30,7 +30,7 @@ SINT8 K_UsingPowerLevels(void) { SINT8 pt = PWRLV_DISABLED; - if (!cv_kartusepwrlv.value || !netgame || grandprixinfo.roundnum > 0) + if (!cv_kartusepwrlv.value || !netgame || grandprixinfo.gp == true) { return PWRLV_DISABLED; } diff --git a/src/m_menu.c b/src/m_menu.c index 72efa88a5..16cef2eb9 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7649,6 +7649,7 @@ static void M_StartGrandPrix(INT32 choice) grandprixinfo.cup = gpcup; + grandprixinfo.gp = true; grandprixinfo.roundnum = 1; grandprixinfo.wonround = false; diff --git a/src/p_inter.c b/src/p_inter.c index c34673d80..cb662f482 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2028,7 +2028,7 @@ boolean P_CheckRacers(void) } else { - if (grandprixinfo.roundnum > 0) + if (grandprixinfo.gp == true) { // Always do this in GP eliminatelast = true; diff --git a/src/p_setup.c b/src/p_setup.c index 1071f5da3..e9a25dd84 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2418,7 +2418,7 @@ static void P_LevelInitStuff(void) for (i = 0; i < MAXPLAYERS; i++) { - if (grandprixinfo.roundnum == 0) + if (grandprixinfo.gp == false) { players[i].lives = 3; players[i].xtralife = 0; @@ -2465,7 +2465,7 @@ static void P_LevelInitStuff(void) } // SRB2Kart: map load variables - if (grandprixinfo.roundnum != 0) + if (grandprixinfo.gp == true) { if (G_BattleGametype()) { @@ -3389,7 +3389,7 @@ boolean P_SetupLevel(boolean skipprecip) // NOW you can try to spawn in the Battle capsules, if there's not enough players for a match K_SpawnBattleCapsules(); - if (grandprixinfo.roundnum != 0) + if (grandprixinfo.gp == true) { if (grandprixinfo.initalize == true) { diff --git a/src/p_user.c b/src/p_user.c index ef2c36090..efea837aa 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1739,7 +1739,7 @@ void P_DoPlayerExit(player_t *player) else player->exiting = raceexittime+2; // Accidental death safeguard??? - if (grandprixinfo.roundnum > 0) + if (grandprixinfo.gp == true) { if (player->bot) { diff --git a/src/y_inter.c b/src/y_inter.c index 7121bf404..c216497af 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -645,7 +645,7 @@ void Y_IntermissionDrawer(void) } dotimer: - if (timer && grandprixinfo.roundnum == 0) + if (timer && grandprixinfo.gp == false) { char *string; INT32 tickdown = (timer+1)/TICRATE;