diff --git a/src/d_main.c b/src/d_main.c index 075a3f8b1..bc3260134 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -75,6 +75,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "fastcmp.h" #include "keys.h" #include "filesrch.h" // refreshdirmenu +#include "k_grandprix.h" #ifdef CMAKECONFIG #include "config.h" @@ -774,7 +775,9 @@ void D_StartTitle(void) // In case someone exits out at the same time they start a time attack run, // reset modeattacking modeattacking = ATTACKING_NONE; - grandprixmatch = 0; + + // Reset GP + memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); // empty maptol so mario/etc sounds don't play in sound test when they shouldn't maptol = 0; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 12d246405..c330b36ee 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -50,6 +50,7 @@ #include "k_battle.h" #include "k_pwrlv.h" #include "y_inter.h" +#include "k_grandprix.h" #ifdef NETGAME_DEVMODE #define CV_RESTRICT CV_NETVAR @@ -2760,6 +2761,12 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r if (netgame || multiplayer) FLS = false; + if (grandprixinfo.roundnum != 0) + { + // Too lazy to change the input value for every instance of this function....... + pencoremode = grandprixinfo.encore; + } + if (delay != 2) { UINT8 flags = 0; @@ -2983,7 +2990,6 @@ static void Command_Map_f(void) // new encoremode value // use cvar by default - newencoremode = (cv_kartencore.value == 1); if (COM_CheckParm("-encore")) @@ -6314,7 +6320,7 @@ static void Command_ShowTime_f(void) // SRB2Kart: On change messages static void BaseNumLaps_OnChange(void) { - if (gamestate == GS_LEVEL) + if (gamestate == GS_LEVEL && grandprixinfo.roundnum == 0) { if (cv_basenumlaps.value) CONS_Printf(M_GetText("Number of laps will be changed to %d next round.\n"), cv_basenumlaps.value); @@ -6344,7 +6350,7 @@ static void KartSpeed_OnChange(void) return; } - if (G_RaceGametype()) + if (G_RaceGametype() && grandprixinfo.roundnum == 0) { if ((gamestate == GS_LEVEL && leveltime < starttime) && (cv_kartspeed.value != KARTSPEED_AUTO)) { @@ -6360,7 +6366,7 @@ static void KartSpeed_OnChange(void) static void KartEncore_OnChange(void) { - if (G_RaceGametype()) + if (G_RaceGametype() && grandprixinfo.roundnum == 0) { 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); @@ -6385,6 +6391,6 @@ static void KartComeback_OnChange(void) static void KartEliminateLast_OnChange(void) { - if (G_RaceGametype() && cv_karteliminatelast.value) + if (G_RaceGametype() && cv_karteliminatelast.value && grandprixinfo.roundnum == 0) P_CheckRacers(); } diff --git a/src/g_game.c b/src/g_game.c index 405ebbc72..0d6b27289 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -50,6 +50,7 @@ #include "k_kart.h" // SRB2kart #include "k_battle.h" #include "k_pwrlv.h" +#include "k_grandprix.h" gameaction_t gameaction; gamestate_t gamestate = GS_NULL; @@ -3628,7 +3629,6 @@ void G_AddMapToBuffer(INT16 map) static void G_DoCompleted(void) { INT32 i, j = 0; - boolean gottoken = false; SINT8 powertype = PWRLV_DISABLED; tokenlist = 0; // Reset the list @@ -3669,11 +3669,25 @@ static void G_DoCompleted(void) // go to next level // nextmap is 0-based, unlike gamemap if (nextmapoverride != 0) + { nextmap = (INT16)(nextmapoverride-1); - else if (mapheaderinfo[gamemap-1]->nextlevel == 1101) // SRB2Kart: !!! WHENEVER WE GET GRAND PRIX, GO TO AWARDS MAP INSTEAD !!! - nextmap = (INT16)(mapheaderinfo[gamemap] ? gamemap : (spstage_start-1)); // (gamemap-1)+1 == gamemap :V + } + else if (grandprixinfo.roundnum != 0) + { + if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) + { + nextmap = 1101; // ceremonymap + } + else + { + nextmap = grandprixinfo.cup->levellist[grandprixinfo.roundnum]; + grandprixinfo.roundnum++; + } + } else + { nextmap = (INT16)(mapheaderinfo[gamemap-1]->nextlevel-1); + } // Remember last map for when you come out of the special stage. if (!G_IsSpecialStage(gamemap)) @@ -3683,8 +3697,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 (!token && !G_IsSpecialStage(gamemap) && !modeattacking - && (nextmap >= 0 && nextmap < NUMMAPS)) + if (!modeattacking && (grandprixinfo.roundnum == 0) && (nextmap >= 0 && nextmap < NUMMAPS)) { register INT16 cm = nextmap; INT16 tolflag = G_TOLFlag(gametype); @@ -3728,44 +3741,18 @@ static void G_DoCompleted(void) if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1102-1) I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); - // wrap around in race - if (nextmap >= 1100-1 && nextmap <= 1102-1 && G_RaceGametype()) - nextmap = (INT16)(spstage_start-1); - - if (gametype == GT_COOP && token) - { - token--; - gottoken = true; - - if (!(emeralds & EMERALD1)) - nextmap = (INT16)(sstage_start - 1); // Special Stage 1 - else if (!(emeralds & EMERALD2)) - nextmap = (INT16)(sstage_start); // Special Stage 2 - else if (!(emeralds & EMERALD3)) - nextmap = (INT16)(sstage_start + 1); // Special Stage 3 - else if (!(emeralds & EMERALD4)) - nextmap = (INT16)(sstage_start + 2); // Special Stage 4 - else if (!(emeralds & EMERALD5)) - nextmap = (INT16)(sstage_start + 3); // Special Stage 5 - else if (!(emeralds & EMERALD6)) - nextmap = (INT16)(sstage_start + 4); // Special Stage 6 - else if (!(emeralds & EMERALD7)) - nextmap = (INT16)(sstage_start + 5); // Special Stage 7 - else - gottoken = false; - } - - if (G_IsSpecialStage(gamemap) && !gottoken) - nextmap = lastmap; // Exiting from a special stage? Go back to the game. Tails 08-11-2001 - automapactive = false; if (gametype != GT_COOP) { if (cv_advancemap.value == 0) // Stay on same map. + { nextmap = prevmap; + } else if (cv_advancemap.value == 2) // Go to random map. + { nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, false, NULL); + } } // We are committed to this map now. @@ -3842,7 +3829,7 @@ void G_NextLevel(void) { if (gamestate != GS_VOTING) { - if ((cv_advancemap.value == 3) && !modeattacking && !skipstats && (multiplayer || netgame)) + if ((cv_advancemap.value == 3) && grandprixinfo.roundnum == 0 && !modeattacking && !skipstats && (multiplayer || netgame)) { UINT8 i; for (i = 0; i < MAXPLAYERS; i++) @@ -4508,7 +4495,7 @@ void G_SaveGame(UINT32 savegameslot) void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar, UINT8 ssplayers, boolean FLS) { INT32 i; - UINT8 color = 0; + //UINT8 color = 0; paused = false; if (demo.playback) @@ -4528,23 +4515,20 @@ void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar // this leave the actual game if needed SV_StartSinglePlayerServer(); - if (savedata.lives > 0) - { - color = savedata.skincolor; - } - else if (splitscreen != ssplayers) + if (splitscreen != ssplayers) { splitscreen = ssplayers; SplitScreen_OnChange(); } - if (!color && !modeattacking) - color = skins[pickedchar].prefcolor; + //if (!color) + //color = skins[pickedchar].prefcolor; + SetPlayerSkinByNum(consoleplayer, pickedchar); CV_StealthSet(&cv_skin, skins[pickedchar].name); - if (color) - CV_StealthSetValue(&cv_playercolor, color); + //if (color) + //CV_StealthSetValue(&cv_playercolor, color); if (mapname) D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, pencoremode, true, 1, false, FLS); diff --git a/src/k_grandprix.c b/src/k_grandprix.c index b8f04aa6e..ddbda5a2e 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -19,8 +19,7 @@ #include "m_random.h" #include "r_things.h" -UINT8 grandprixmatch = 0; -boolean initgpbots = false; +struct grandprixinfo grandprixinfo; void K_InitGrandPrixBots(void) { @@ -43,11 +42,6 @@ void K_InitGrandPrixBots(void) UINT8 newplayernum = 0; UINT8 i; - if (initgpbots != true) - { - return; - } - memset(difficultylevels, MAXBOTDIFFICULTY, sizeof (difficultylevels)); memset(competitors, MAXPLAYERS, sizeof (competitors)); memset(botskinlist, defaultbotskin, sizeof (botskinlist)); @@ -163,6 +157,4 @@ void K_InitGrandPrixBots(void) break; } } - - initgpbots = false; } diff --git a/src/k_grandprix.h b/src/k_grandprix.h index 4644c43ca..0eacf8ff9 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -1,18 +1,20 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 2007-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2018 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file k_grandprix.h -/// \brief Grand Prix mode specific code +#ifndef __K_GRANDPRIX__ +#define __K_GRANDPRIX__ #include "doomdef.h" +#include "doomstat.h" -extern UINT8 grandprixmatch; -extern boolean initgpbots; +extern struct grandprixinfo +{ + UINT8 roundnum; ///< Round number -- if 0, then we're not in a Grand Prix. + 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 + boolean masterbots; ///< If true, all bots should be max difficulty (Master Mode) + boolean initbots; ///< If true, we need to initialize the bots that are competing. +} grandprixinfo; void K_InitGrandPrixBots(void); + +#endif + diff --git a/src/m_menu.c b/src/m_menu.c index f9a9112ac..879db62ea 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -226,6 +226,7 @@ menu_t SP_MainDef, MP_MainDef, OP_MainDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef, MISC_ChangeSpectateDef; // Single Player +static void M_GrandPrixTemp(INT32 choice); static void M_StartGrandPrix(INT32 choice); static void M_TimeAttack(INT32 choice); static boolean M_QuitTimeAttackMenu(void); @@ -240,6 +241,7 @@ static void M_ModeAttackEndGame(INT32 choice); static void M_SetGuestReplay(INT32 choice); //static void M_ChoosePlayer(INT32 choice); menu_t SP_LevelStatsDef; +static menu_t SP_GrandPrixTempDef; static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; //static menu_t SP_NightsAttackDef, SP_NightsReplayDef, SP_NightsGuestReplayDef, SP_NightsGhostDef; @@ -466,6 +468,13 @@ static consvar_t cv_dummycontinues = {"dummycontinues", "0", CV_HIDEN, liveslimi //static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dummymares_cons_t, Dummymares_OnChange, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummystaff = {"dummystaff", "0", CV_HIDEN|CV_CALL, dummystaff_cons_t, Dummystaff_OnChange, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t dummygpdifficulty_cons_t[] = {{0, "Easy"}, {1, "Normal"}, {2, "Hard"}, {3, "Master"}, {0, NULL}}; +static CV_PossibleValue_t dummygpcup_cons_t[50] = {{1, "TEMP"}}; // A REALLY BIG NUMBER, SINCE THIS IS TEMP UNTIL NEW MENUS + +static consvar_t cv_dummygpdifficulty = {"dummygpdifficulty", "Normal", CV_HIDEN, dummygpdifficulty_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static consvar_t cv_dummygpencore = {"dummygpencore", "Off", CV_HIDEN, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +static consvar_t cv_dummygpcup = {"dummygpcup", "TEMP", CV_HIDEN, dummygpcup_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + // ========================================================================== // ORGANIZATION START. // ========================================================================== @@ -804,7 +813,7 @@ static menuitem_t SR_EmblemHintMenu[] = // Single Player Main static menuitem_t SP_MainMenu[] = { - {IT_CALL | IT_STRING, NULL, "Grand Prix", M_StartGrandPrix, 92}, + {IT_STRING|IT_CALL, NULL, "Grand Prix", M_GrandPrixTemp, 92}, {IT_SECRET, NULL, "Time Attack", M_TimeAttack, 100}, {IT_SECRET, NULL, "Break the Capsules", M_BreakTheCapsules, 108}, }; @@ -817,17 +826,17 @@ enum }; // Single Player Load Game -/*static menuitem_t SP_LoadGameMenu[] = +static menuitem_t SP_GrandPrixPlaceholderMenu[] = { - {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleLoadSave, '\0'}, // dummy menuitem for the control func -}; + {IT_STRING|IT_CVAR, NULL, "Character", &cv_chooseskin, 10}, + {IT_STRING|IT_CVAR, NULL, "Color", &cv_playercolor, 20}, -// Single Player Level Select -static menuitem_t SP_LevelSelectMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, - {IT_WHITESTRING|IT_CALL, NULL, "Start", M_LevelSelectWarp, 130}, -};*/ + {IT_STRING|IT_CVAR, NULL, "Difficulty", &cv_dummygpdifficulty, 40}, + {IT_STRING|IT_CVAR, NULL, "Encore Mode", &cv_dummygpencore, 50}, + + {IT_STRING|IT_CVAR, NULL, "Cup", &cv_dummygpcup, 70}, + {IT_STRING|IT_CALL, NULL, "Start", M_StartGrandPrix, 80}, +}; // Single Player Time Attack static menuitem_t SP_TimeAttackMenu[] = @@ -1830,6 +1839,8 @@ menu_t SP_LevelStatsDef = NULL }; +static menu_t SP_GrandPrixTempDef = DEFAULTMENUSTYLE(NULL, SP_GrandPrixPlaceholderMenu, &MainDef, 60, 30); + static menu_t SP_TimeAttackDef = { "M_ATTACK", @@ -3277,6 +3288,10 @@ void M_Init(void) //CV_RegisterVar(&cv_dummymares); CV_RegisterVar(&cv_dummystaff); + CV_RegisterVar(&cv_dummygpdifficulty); + CV_RegisterVar(&cv_dummygpencore); + CV_RegisterVar(&cv_dummygpcup); + quitmsg[QUITMSG] = M_GetText("Eggman's tied explosives\nto your girlfriend, and\nwill activate them if\nyou press the 'Y' key!\nPress 'N' to save her!\n\n(Press 'Y' to quit)"); quitmsg[QUITMSG1] = M_GetText("What would Tails say if\nhe saw you quitting the game?\n\n(Press 'Y' to quit)"); quitmsg[QUITMSG2] = M_GetText("Hey!\nWhere do ya think you're goin'?\n\n(Press 'Y' to quit)"); @@ -4147,6 +4162,35 @@ static void M_PatchSkinNameTable(void) return; } +// +// M_PrepareCupList +// +static void M_PrepareCupList(void) +{ + cupheader_t *cup = kartcupheaders; + INT32 i = 0; + + memset(dummygpcup_cons_t, 0, sizeof (dummygpcup_cons_t)); + + while (cup != NULL) + { + dummygpcup_cons_t[i].strvalue = cup->name; + dummygpcup_cons_t[i].value = i+1; + // this will probably crash or do something stupid at over 50 cups, + // but this is all behavior that gets completely overwritten in new-menus, so I'm not worried + i++; + cup = cup->next; + } + + for (; i < 50; i++) + { + dummygpcup_cons_t[i].strvalue = NULL; + dummygpcup_cons_t[i].value = 0; + } + + CV_SetValue(&cv_dummygpcup, 1); // This causes crash sometimes?! +} + // Call before showing any level-select menus static void M_PrepareLevelSelect(void) { @@ -7455,6 +7499,77 @@ static void M_HandleLevelStats(INT32 choice) } } +static void M_GrandPrixTemp(INT32 choice) +{ + (void)choice; + M_PatchSkinNameTable(); + M_PrepareCupList(); + M_SetupNextMenu(&SP_GrandPrixTempDef); +} + +// Start Grand Prix! +static void M_StartGrandPrix(INT32 choice) +{ + cupheader_t *gpcup = kartcupheaders; + + (void)choice; + + if (gpcup == NULL) + { + // welp + I_Error("No cup definitions for GP\n"); + return; + } + + M_ClearMenus(true); + + memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); + + switch (cv_dummygpdifficulty.value) + { + case 0: + grandprixinfo.gamespeed = KARTSPEED_EASY; + break; + case 1: + default: + grandprixinfo.gamespeed = KARTSPEED_NORMAL; + break; + case 2: + grandprixinfo.gamespeed = KARTSPEED_HARD; + break; + case 3: + grandprixinfo.gamespeed = KARTSPEED_HARD; + grandprixinfo.masterbots = true; + break; + + } + + grandprixinfo.encore = (boolean)(cv_dummygpencore.value); + + while (gpcup != NULL && gpcup->id != cv_dummygpcup.value-1) + { + gpcup = gpcup->next; + } + + if (gpcup == NULL) + { + gpcup = kartcupheaders; + } + + grandprixinfo.cup = gpcup; + + grandprixinfo.roundnum = 1; + grandprixinfo.initbots = true; + + G_DeferedInitNew( + false, + G_BuildMapName(grandprixinfo.cup->levellist[0] + 1), + (UINT8)(cv_chooseskin.value - 1), + (UINT8)(cv_splitplayers.value - 1), + false + ); +} + // =========== // MODE ATTACK // =========== @@ -7649,20 +7764,6 @@ void M_DrawTimeAttackMenu(void) } } -// Start Grand Prix! -static void M_StartGrandPrix(INT32 choice) -{ - (void)choice; - - M_ClearMenus(true); - - grandprixmatch = 1; - initgpbots = true; - - G_DeferedInitNew(false, "MAP01", (UINT8)(cv_chooseskin.value-1), 0, false); // G_BuildMapName(startmap) -} - - // Going to Time Attack menu... static void M_TimeAttack(INT32 choice) { diff --git a/src/p_setup.c b/src/p_setup.c index b4a2def48..dbb1769f7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2401,8 +2401,23 @@ static void P_LevelInitStuff(void) } // SRB2Kart: map load variables - if (modeattacking) // Just play it safe and set everything + if (grandprixinfo.roundnum != 0) { + if (G_BattleGametype()) + { + gamespeed = KARTSPEED_EASY; + } + else + { + gamespeed = grandprixinfo.gamespeed; + } + + franticitems = false; + comeback = true; + } + else if (modeattacking) + { + // Just play it safe and set everything gamespeed = KARTSPEED_HARD; franticitems = false; comeback = true; @@ -2611,12 +2626,6 @@ static void P_ForceCharacter(const char *forcecharskin) } SetPlayerSkin(consoleplayer, forcecharskin); - // normal player colors in single player - if ((unsigned)cv_playercolor.value != skins[players[consoleplayer].skin].prefcolor && !modeattacking) - { - CV_StealthSetValue(&cv_playercolor, skins[players[consoleplayer].skin].prefcolor); - players[consoleplayer].skincolor = skins[players[consoleplayer].skin].prefcolor; - } } } @@ -3366,17 +3375,18 @@ 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 (grandprixmatch == 0) + if (grandprixinfo.roundnum != 0) { - K_UpdateMatchRaceBots(); + if (grandprixinfo.initbots == true) + { + K_InitGrandPrixBots(); + grandprixinfo.initbots = false; + } } else { - if (initgpbots == true) - { - K_InitGrandPrixBots(); - initgpbots = false; - } + // We're in a Match Race, use simplistic randomized bots. + K_UpdateMatchRaceBots(); } return true;