diff --git a/src/g_game.c b/src/g_game.c index 64424da4f..1b3dfa770 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5719,6 +5719,57 @@ void G_LoadGame(void) CON_ToggleOff(); } +void G_GetBackupCupData(boolean actuallygetdata) +{ + if (actuallygetdata == false) + { + cupsavedata.cup = NULL; + return; + } + + char vcheck[VERSIONSIZE+1]; + char savename[255]; + UINT8 versionMinor; + savebuffer_t save = {0}; + + //if (makelivebackup) + strcpy(savename, gpbackup); + //else + //sprintf(savename, savegamename, cursaveslot); + + if (P_SaveBufferFromFile(&save, savename) == false) + { + cupsavedata.cup = NULL; + return; + } + + versionMinor = READUINT8(save.p); + + memset(vcheck, 0, sizeof (vcheck)); + sprintf(vcheck, "version %d", VERSION); + + if (versionMinor != SAV_VERSIONMINOR + || memcmp(save.p, vcheck, VERSIONSIZE)) + { + cupsavedata.cup = NULL; + P_SaveBufferFree(&save); + return; // bad version + } + save.p += VERSIONSIZE; + + P_GetBackupCupData(&save); + + if (cv_dummygpdifficulty.value != cupsavedata.difficulty + || !!cv_dummygpencore.value != cupsavedata.encore) + { + // Still not compatible. + cupsavedata.cup = NULL; + } + + // done + P_SaveBufferFree(&save); +} + // // G_SaveGame // Saves your game. diff --git a/src/g_game.h b/src/g_game.h index a05d7ef0c..71dd4ada8 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -190,6 +190,7 @@ boolean G_IsTitleCardAvailable(void); void G_HandleSaveLevel(boolean removecondition); void G_SaveGame(void); void G_LoadGame(void); +void G_GetBackupCupData(boolean actuallygetdata); void G_SaveGameData(void); void G_DirtyGameData(void); diff --git a/src/k_menu.h b/src/k_menu.h index 6fb5a2571..7eefd06ea 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -19,6 +19,7 @@ #include "command.h" #include "doomstat.h" // MAXSPLITSCREENPLAYERS #include "g_demo.h" //menudemo_t +#include "p_saveg.h" // savedata_cup_t #include "k_profiles.h" // profile data & functions #include "g_input.h" // gc_ #include "i_threads.h" diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 0b56ae847..361e61d46 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2368,6 +2368,7 @@ static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch) void M_DrawCupSelect(void) { UINT8 i, j, temp = 0; + INT16 x, y; UINT8 *colormap = NULL; cupwindata_t *windata = NULL; levelsearch_t templevelsearch = levellist.levelsearch; // full copy @@ -2378,7 +2379,6 @@ void M_DrawCupSelect(void) { size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS)); patch_t *patch = NULL; - INT16 x, y; INT16 icony = 7; char status = 'A'; char monitor; @@ -2463,6 +2463,13 @@ void M_DrawCupSelect(void) V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName(templevelsearch.cup->icon, PU_CACHE)); V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName("CUPBOX", PU_CACHE)); + if (cupgrid.grandprix == true + && templevelsearch.cup == cupsavedata.cup + && id != CUPMENU_CURSORID) + { + V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP1", PU_CACHE)); + } + if (!windata) ; else if (windata->best_placement != 0) @@ -2562,13 +2569,20 @@ void M_DrawCupSelect(void) } } - V_DrawScaledPatch(14 + (cupgrid.x*42) - 4, - 20 + (cupgrid.y*44) - 1 - (24*menutransition.tics), - 0, W_CachePatchName("CUPCURS", PU_CACHE) - ); + x = 14 + (cupgrid.x*42); + y = 20 + (cupgrid.y*44) - (30*menutransition.tics); + + V_DrawScaledPatch(x - 4, y - 1, 0, W_CachePatchName("CUPCURS", PU_CACHE)); templevelsearch.cup = cupgrid.builtgrid[CUPMENU_CURSORID]; + if (cupgrid.grandprix == true + && templevelsearch.cup != NULL + && templevelsearch.cup == cupsavedata.cup) + { + V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP2", PU_CACHE)); + } + V_DrawFill(0, 146 + (24*menutransition.tics), BASEVIDWIDTH, 54, 31); M_DrawCupPreview(146 + (24*menutransition.tics), &templevelsearch); diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index 837f81527..edd3c99c8 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -5,10 +5,7 @@ #include "../r_skins.h" #include "../s_sound.h" #include "../k_grandprix.h" // K_CanChangeRules -#include "../k_podium.h" // K_StartCeremony #include "../m_cond.h" // Condition Sets -#include "../r_local.h" // SplitScreen_OnChange -#include "../m_misc.h" // FIL_FileExists //#define CHARSELECT_DEVICEDEBUG @@ -488,123 +485,9 @@ void M_CharacterSelectInit(void) } -static void M_GPBackup(INT32 choice) -{ - if (choice == MA_YES) - { - G_LoadGame(); - - if (savedata.lives != 0) - { - // Only do this after confirming savegame is ok - const UINT8 ssplayers = 0; - - { - CV_StealthSetValue(&cv_playercolor[0], savedata.skincolor); - - // follower - if (savedata.followerskin < 0 || savedata.followerskin >= numfollowers) - CV_StealthSet(&cv_follower[0], "None"); - else - CV_StealthSet(&cv_follower[0], followers[savedata.followerskin].name); - - // finally, call the skin[x] console command. - // This will call SendNameAndColor which will synch everything we sent here and apply the changes! - - CV_StealthSet(&cv_skin[0], skins[savedata.skin].name); - - // ...actually, let's do this last - Skin_OnChange has some return-early occasions - // follower color - CV_SetValue(&cv_followercolor[0], savedata.followercolor); - } - - paused = false; - - S_StopMusicCredit(); - - if (cv_maxconnections.value < ssplayers+1) - CV_SetValue(&cv_maxconnections, ssplayers+1); - - if (splitscreen != ssplayers) - { - splitscreen = ssplayers; - SplitScreen_OnChange(); - } - - UINT8 entry = roundqueue.position-1; - - SV_StartSinglePlayerServer(roundqueue.entries[entry].gametype, false); - - // Skip Bonus rounds. - if (roundqueue.entries[entry].gametype != roundqueue.entries[0].gametype - && roundqueue.entries[entry].rankrestricted == false) - { - G_GetNextMap(); // updates position in the roundqueue - entry = roundqueue.position-1; - } - - if (entry < roundqueue.size) - { - D_MapChange( - roundqueue.entries[entry].mapnum + 1, - roundqueue.entries[entry].gametype, - roundqueue.entries[entry].encore, - true, - 1, - false, - roundqueue.entries[entry].rankrestricted - ); - } - else - { - if (K_StartCeremony() == false) - { - // Accomodate our buffoonery with the artificial fade. - wipegamestate = -1; - - M_StartMessage( - "Grand Prix Backup", - "The session is concluded!\n" - "You exited a final Bonus Round,\n" - "and the Podium failed to load.\n", - NULL, MM_NOTHING, NULL, NULL); - - G_HandleSaveLevel(true); - - return; - } - } - - M_ClearMenus(true); - - // We can't put it deeper in the menuflow due to lack of guaranteed setup - restoreMenu = &MainDef; - } - - return; - } - - M_CharacterSelect(-1); -} - void M_CharacterSelect(INT32 choice) { - if (currentMenu == &MainDef - && choice != -1 - && FIL_FileExists(gpbackup)) - { - M_StartMessage( - "Grand Prix Backup", - "A progress backup was found.\n" - "Do you want to resurrect your\n" - "last Grand Prix session?\n", - M_GPBackup, - MM_YESNO, - "Yes, let's try again", - "No, play another way"); - return; - } - + (void)choice; PLAY_CharSelectDef.music = currentMenu->music; PLAY_CharSelectDef.prevMenu = currentMenu; M_SetupNextMenu(&PLAY_CharSelectDef, false); diff --git a/src/menus/transient/cup-select.c b/src/menus/transient/cup-select.c index c97246e04..f146cd74f 100644 --- a/src/menus/transient/cup-select.c +++ b/src/menus/transient/cup-select.c @@ -7,6 +7,9 @@ #include "../../v_video.h" #include "../../k_grandprix.h" #include "../../r_local.h" // SplitScreen_OnChange +#include "../../k_podium.h" // K_StartCeremony +#include "../../m_misc.h" // FIL_FileExists +#include "../../d_main.h" // D_ClearState menuitem_t PLAY_CupSelect[] = { @@ -32,6 +35,150 @@ menu_t PLAY_CupSelectDef = { struct cupgrid_s cupgrid; +static void M_StartCup(UINT8 entry) +{ + UINT8 ssplayers = cv_splitplayers.value-1; + + if (ssplayers > 0) + { + // Splitscreen is not accomodated with this recovery feature. + entry = 0; + } + + S_StartSound(NULL, sfx_s3k63); + + paused = false; + + S_StopMusicCredit(); + + // Early fadeout to let the sound finish playing + F_WipeStartScreen(); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + F_WipeEndScreen(); + F_RunWipe(wipe_level_toblack, wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false); + + if (cv_maxconnections.value < ssplayers+1) + CV_SetValue(&cv_maxconnections, ssplayers+1); + + if (splitscreen != ssplayers) + { + splitscreen = ssplayers; + SplitScreen_OnChange(); + } + + if (entry == 0) + { + memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); + + // read our dummy cvars + + grandprixinfo.gamespeed = min(KARTSPEED_HARD, cv_dummygpdifficulty.value); + grandprixinfo.masterbots = (cv_dummygpdifficulty.value == 3); + + grandprixinfo.gp = true; + grandprixinfo.initalize = true; + grandprixinfo.cup = levellist.levelsearch.cup; + + // Populate the roundqueue + memset(&roundqueue, 0, sizeof(struct roundqueue)); + G_GPCupIntoRoundQueue(levellist.levelsearch.cup, levellist.newgametype, (boolean)cv_dummygpencore.value); + roundqueue.position = roundqueue.roundnum = 1; + roundqueue.netcommunicate = true; // relevant for future Online GP + } + else + { + // Silently change player setup + { + CV_StealthSetValue(&cv_playercolor[0], savedata.skincolor); + + // follower + if (savedata.followerskin < 0 || savedata.followerskin >= numfollowers) + CV_StealthSet(&cv_follower[0], "None"); + else + CV_StealthSet(&cv_follower[0], followers[savedata.followerskin].name); + + // finally, call the skin[x] console command. + // This will call SendNameAndColor which will synch everything we sent here and apply the changes! + + CV_StealthSet(&cv_skin[0], skins[savedata.skin].name); + + // ...actually, let's do this last - Skin_OnChange has some return-early occasions + // follower color + CV_SetValue(&cv_followercolor[0], savedata.followercolor); + } + + // Skip Bonus rounds. + if (roundqueue.entries[entry].gametype != roundqueue.entries[0].gametype + && roundqueue.entries[entry].rankrestricted == false) + { + G_GetNextMap(); // updates position in the roundqueue + entry = roundqueue.position-1; + } + } + + paused = false; + + SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame); + + M_ClearMenus(true); + restoreMenu = &PLAY_CupSelectDef; + + if (entry < roundqueue.size) + { + D_MapChange( + roundqueue.entries[entry].mapnum + 1, + roundqueue.entries[entry].gametype, + roundqueue.entries[entry].encore, + true, + 1, + false, + roundqueue.entries[entry].rankrestricted + ); + } + else if (entry == 0) + { + I_Error("M_StartCup: roundqueue is empty on startup!!"); + } + else + { + if (K_StartCeremony() == false) + { + // Accomodate our buffoonery + D_ClearState(); + M_StartControlPanel(); + + M_StartMessage( + "Grand Prix Backup", + "The session is concluded!\n" + "You exited a final Bonus Round,\n" + "and the Podium failed to load.\n", + NULL, MM_NOTHING, NULL, NULL + ); + + G_HandleSaveLevel(true); + + return; + } + } +} + +static void M_GPBackup(INT32 choice) +{ + if (choice == MA_YES) + { + G_LoadGame(); + + if (savedata.lives != 0) + { + M_StartCup(roundqueue.position-1); + } + + return; + } + + M_StartCup(0); +} + void M_CupSelectHandler(INT32 choice) { const UINT8 pid = 0; @@ -104,67 +251,24 @@ void M_CupSelectHandler(INT32 choice) if (cupgrid.grandprix == true) { - UINT8 ssplayers = cv_splitplayers.value-1; - - S_StartSound(NULL, sfx_s3k63); - - paused = false; - - S_StopMusicCredit(); - - // Early fadeout to let the sound finish playing - F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - F_WipeEndScreen(); - F_RunWipe(wipe_level_toblack, wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false); - - memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); - - if (cv_maxconnections.value < ssplayers+1) - CV_SetValue(&cv_maxconnections, ssplayers+1); - - if (splitscreen != ssplayers) + if (newcup == cupsavedata.cup + && FIL_FileExists(gpbackup)) { - splitscreen = ssplayers; - SplitScreen_OnChange(); + M_StartMessage( + "Grand Prix Backup", + "A progress backup was found.\n" + "Do you want to resurrect your\n" + "last Grand Prix session?\n", + M_GPBackup, + MM_YESNO, + "Yes, let's try again", + "No, start from Round 1" + ); + + return; } - // read our dummy cvars - - grandprixinfo.gamespeed = min(KARTSPEED_HARD, cv_dummygpdifficulty.value); - grandprixinfo.masterbots = (cv_dummygpdifficulty.value == 3); - - grandprixinfo.gp = true; - grandprixinfo.initalize = true; - grandprixinfo.cup = newcup; - - // Populate the roundqueue - memset(&roundqueue, 0, sizeof(struct roundqueue)); - G_GPCupIntoRoundQueue(newcup, levellist.newgametype, (boolean)cv_dummygpencore.value); - roundqueue.position = roundqueue.roundnum = 1; - roundqueue.netcommunicate = true; // relevant for future Online GP - - paused = false; - - // Don't restart the server if we're already in a game lol - if (gamestate == GS_MENU) - { - SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame); - } - - D_MapChange( - roundqueue.entries[0].mapnum + 1, - roundqueue.entries[0].gametype, - roundqueue.entries[0].encore, - true, - 1, - false, - roundqueue.entries[0].rankrestricted - ); - - M_ClearMenus(true); - - restoreMenu = &PLAY_CupSelectDef; + M_StartCup(0); } else if (count == 1 && levellist.levelsearch.timeattack == true) { diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index a54096b1b..a759f7c0b 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -8,6 +8,8 @@ #include "../../r_local.h" // SplitScreen_OnChange #include "../../f_finale.h" // F_WipeStartScreen #include "../../v_video.h" +#include "../../g_game.h" // G_GetBackupCupData +#include "../../p_saveg.h" // cupsavedata cupheader_t dummy_lostandfound; @@ -262,6 +264,11 @@ boolean M_LevelListFromGametype(INT16 gt) const size_t pagelen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS); boolean foundany = false, currentvalid = false; + G_GetBackupCupData( + cupgrid.grandprix == true + || cv_splitplayers.value <= 1 + ); + templevelsearch.cup = kartcupheaders; #if 0 @@ -331,7 +338,8 @@ boolean M_LevelListFromGametype(INT16 gt) if (Playing() ? (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == templevelsearch.cup) - : (gt == -1 && levellist.levelsearch.cup == templevelsearch.cup)) + : (cupsavedata.cup == templevelsearch.cup + || (gt == -1 && levellist.levelsearch.cup == templevelsearch.cup))) { GRID_FOCUSCUP; } diff --git a/src/p_saveg.c b/src/p_saveg.c index 729b38d42..f80ffff7b 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -48,6 +48,7 @@ #include "k_zvote.h" savedata_t savedata; +savedata_cup_t cupsavedata; // Block UINT32s to attempt to ensure that the correct data is // being sent and received @@ -5407,6 +5408,46 @@ static inline void P_ArchiveMisc(savebuffer_t *save) WRITEUINT32(save->p, writetime); } +void P_GetBackupCupData(savebuffer_t *save) +{ + char testname[sizeof(timeattackfolder)]; + + READSTRINGN(save->p, testname, sizeof(testname)); + + if (strcmp(testname, timeattackfolder)) + { + cupsavedata.cup = NULL; + return; + } + + // Grand Prix information + + cupsavedata.difficulty = READUINT8(save->p); + cupsavedata.encore = (boolean)READUINT8(save->p); + boolean masterbots = (boolean)READUINT8(save->p); + + if (masterbots == true) + cupsavedata.difficulty = KARTGP_MASTER; + + // Find the relevant cup. + char cupname[MAXCUPNAME]; + READSTRINGL(save->p, cupname, sizeof(cupname)); + UINT32 hash = quickncasehash(cupname, MAXCUPNAME); + + for (cupsavedata.cup = kartcupheaders; cupsavedata.cup; cupsavedata.cup = cupsavedata.cup->next) + { + if (cupsavedata.cup->namehash != hash) + continue; + + if (strcmp(cupsavedata.cup->name, cupname)) + continue; + + break; + } + + // Okay, no further! We've got everything we need. +} + static boolean P_UnArchiveSPGame(savebuffer_t *save) { char testname[sizeof(timeattackfolder)]; diff --git a/src/p_saveg.h b/src/p_saveg.h index ad2537087..66345367d 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -34,6 +34,7 @@ extern "C" { // Local Play void P_SaveGame(savebuffer_t *save); boolean P_LoadGame(savebuffer_t *save); +void P_GetBackupCupData(savebuffer_t *save); // Online void P_SaveNetGame(savebuffer_t *save, boolean resending); @@ -66,6 +67,15 @@ struct savedata_t extern savedata_t savedata; +struct savedata_cup_t +{ + cupheader_t *cup; + UINT8 difficulty; + boolean encore; +}; + +extern savedata_cup_t cupsavedata; + struct savebuffer_t { UINT8 *buffer; diff --git a/src/typedef.h b/src/typedef.h index a54ae82e5..275a30da4 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -297,6 +297,7 @@ TYPEDEF (polyfadedata_t); // p_saveg.h TYPEDEF (savedata_t); +TYPEDEF (savedata_cup_t); TYPEDEF (savebuffer_t); // p_setup.h