mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'live-event-backup' into 'master'
GP Crash Backup See merge request KartKrew/Kart!1296
This commit is contained in:
commit
788b673584
27 changed files with 952 additions and 498 deletions
|
|
@ -653,7 +653,6 @@ typedef enum
|
||||||
static void GetPackets(void);
|
static void GetPackets(void);
|
||||||
|
|
||||||
static cl_mode_t cl_mode = CL_SEARCHING;
|
static cl_mode_t cl_mode = CL_SEARCHING;
|
||||||
static cl_mode_t cl_requestmode = CL_ABORTED;
|
|
||||||
|
|
||||||
#ifdef HAVE_CURL
|
#ifdef HAVE_CURL
|
||||||
char http_source[MAX_MIRROR_LENGTH];
|
char http_source[MAX_MIRROR_LENGTH];
|
||||||
|
|
@ -1671,43 +1670,37 @@ void CL_UpdateServerList (void)
|
||||||
SendAskInfo(BROADCASTADDR);
|
SendAskInfo(BROADCASTADDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean M_ConfirmConnect(void)
|
static void M_ConfirmConnect(INT32 choice)
|
||||||
{
|
{
|
||||||
if (G_PlayerInputDown(0, gc_b, 1) || G_PlayerInputDown(0, gc_x, 1) || G_GetDeviceGameKeyDownArray(0)[KEY_ESCAPE])
|
if (choice == MA_YES)
|
||||||
{
|
|
||||||
cl_requestmode = CL_ABORTED;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (G_PlayerInputDown(0, gc_a, 1) || G_GetDeviceGameKeyDownArray(0)[KEY_ENTER])
|
|
||||||
{
|
{
|
||||||
if (totalfilesrequestednum > 0)
|
if (totalfilesrequestednum > 0)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_CURL
|
#ifdef HAVE_CURL
|
||||||
if (http_source[0] == '\0' || curl_failedwebdownload)
|
if (http_source[0] == '\0' || curl_failedwebdownload)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (CL_SendFileRequest())
|
if (CL_SendFileRequest())
|
||||||
{
|
{
|
||||||
cl_requestmode = CL_DOWNLOADFILES;
|
cl_mode = CL_DOWNLOADFILES;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cl_requestmode = CL_DOWNLOADFAILED;
|
cl_mode = CL_DOWNLOADFAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef HAVE_CURL
|
#ifdef HAVE_CURL
|
||||||
else
|
else
|
||||||
cl_requestmode = CL_PREPAREHTTPFILES;
|
cl_mode = CL_PREPAREHTTPFILES;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cl_requestmode = CL_LOADFILES;
|
cl_mode = CL_LOADFILES;
|
||||||
|
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
cl_mode = CL_ABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean CL_FinishedFileList(void)
|
static boolean CL_FinishedFileList(void)
|
||||||
|
|
@ -1759,7 +1752,7 @@ static boolean CL_FinishedFileList(void)
|
||||||
"This server is full!\n"
|
"This server is full!\n"
|
||||||
"\n"
|
"\n"
|
||||||
"You may load server addons (if any), and wait for a slot.\n"
|
"You may load server addons (if any), and wait for a slot.\n"
|
||||||
), NULL, MM_NOTHING, "Continue", "Back to Menu");
|
), &M_ConfirmConnect, MM_YESNO, "Continue", "Back to Menu");
|
||||||
cl_mode = CL_CONFIRMCONNECT;
|
cl_mode = CL_CONFIRMCONNECT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1822,13 +1815,13 @@ static boolean CL_FinishedFileList(void)
|
||||||
"\n"
|
"\n"
|
||||||
"You may download, load server addons,\n"
|
"You may download, load server addons,\n"
|
||||||
"and wait for a slot.\n"
|
"and wait for a slot.\n"
|
||||||
), downloadsize), NULL, MM_NOTHING, "Continue", "Back to Menu");
|
), downloadsize), &M_ConfirmConnect, MM_YESNO, "Continue", "Back to Menu");
|
||||||
else
|
else
|
||||||
M_StartMessage("Server Connection",
|
M_StartMessage("Server Connection",
|
||||||
va(M_GetText(
|
va(M_GetText(
|
||||||
"Download of %s additional content\n"
|
"Download of %s additional content\n"
|
||||||
"is required to join.\n"
|
"is required to join.\n"
|
||||||
), downloadsize), NULL, MM_NOTHING, "Continue", "Back to Menu");
|
), downloadsize), &M_ConfirmConnect, MM_YESNO, "Continue", "Back to Menu");
|
||||||
|
|
||||||
Z_Free(downloadsize);
|
Z_Free(downloadsize);
|
||||||
cl_mode = CL_CONFIRMCONNECT;
|
cl_mode = CL_CONFIRMCONNECT;
|
||||||
|
|
@ -1969,6 +1962,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
|
||||||
{
|
{
|
||||||
boolean waitmore;
|
boolean waitmore;
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
const UINT8 pid = 0;
|
||||||
|
|
||||||
switch (cl_mode)
|
switch (cl_mode)
|
||||||
{
|
{
|
||||||
|
|
@ -2168,26 +2162,27 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
|
||||||
G_MapEventsToControls(&events[eventtail]);
|
G_MapEventsToControls(&events[eventtail]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
I_lock_mutex(&k_menu_mutex);
|
||||||
|
#endif
|
||||||
|
M_UpdateMenuCMD(0, true);
|
||||||
|
|
||||||
if (cl_mode == CL_CONFIRMCONNECT)
|
if (cl_mode == CL_CONFIRMCONNECT)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_THREADS
|
if (menumessage.active)
|
||||||
I_lock_mutex(&k_menu_mutex);
|
M_HandleMenuMessage();
|
||||||
#endif
|
|
||||||
if (M_MenuMessageTick() && M_ConfirmConnect())
|
|
||||||
M_StopMessage(0);
|
|
||||||
else if (menumessage.active == false)
|
|
||||||
cl_mode = cl_requestmode;
|
|
||||||
#ifdef HAVE_THREADS
|
|
||||||
I_unlock_mutex(k_menu_mutex);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (G_PlayerInputDown(0, gc_b, 1)
|
if (M_MenuBackPressed(pid))
|
||||||
|| G_PlayerInputDown(0, gc_x, 1)
|
|
||||||
|| G_GetDeviceGameKeyDownArray(0)[KEY_ESCAPE])
|
|
||||||
cl_mode = CL_ABORTED;
|
cl_mode = CL_ABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M_ScreenshotTicker();
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
I_unlock_mutex(k_menu_mutex);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cl_mode == CL_ABORTED)
|
if (cl_mode == CL_ABORTED)
|
||||||
|
|
@ -2265,7 +2260,6 @@ static void CL_ConnectToServer(void)
|
||||||
lastfilenum = -1;
|
lastfilenum = -1;
|
||||||
|
|
||||||
cl_mode = CL_SEARCHING;
|
cl_mode = CL_SEARCHING;
|
||||||
cl_requestmode = CL_ABORTED; // sane default
|
|
||||||
|
|
||||||
// Don't get a corrupt savegame error because tmpsave already exists
|
// Don't get a corrupt savegame error because tmpsave already exists
|
||||||
if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1)
|
if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1)
|
||||||
|
|
|
||||||
11
src/d_main.c
11
src/d_main.c
|
|
@ -140,7 +140,7 @@ UINT16 numskincolors;
|
||||||
menucolor_t *menucolorhead, *menucolortail;
|
menucolor_t *menucolorhead, *menucolortail;
|
||||||
|
|
||||||
char savegamename[256];
|
char savegamename[256];
|
||||||
char liveeventbackup[256];
|
char gpbackup[256];
|
||||||
|
|
||||||
char srb2home[256] = ".";
|
char srb2home[256] = ".";
|
||||||
char srb2path[256] = ".";
|
char srb2path[256] = ".";
|
||||||
|
|
@ -295,7 +295,7 @@ void D_ProcessEvents(void)
|
||||||
// Update menu CMD
|
// Update menu CMD
|
||||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||||
{
|
{
|
||||||
M_UpdateMenuCMD(i);
|
M_UpdateMenuCMD(i, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -982,7 +982,6 @@ void D_ClearState(void)
|
||||||
cht_debug = 0;
|
cht_debug = 0;
|
||||||
emeralds = 0;
|
emeralds = 0;
|
||||||
memset(&luabanks, 0, sizeof(luabanks));
|
memset(&luabanks, 0, sizeof(luabanks));
|
||||||
lastmaploaded = 0;
|
|
||||||
|
|
||||||
// In case someone exits out at the same time they start a time attack run,
|
// In case someone exits out at the same time they start a time attack run,
|
||||||
// reset modeattacking
|
// reset modeattacking
|
||||||
|
|
@ -1327,7 +1326,7 @@ void D_SRB2Main(void)
|
||||||
|
|
||||||
// default savegame
|
// default savegame
|
||||||
strcpy(savegamename, SAVEGAMENAME"%u.ssg");
|
strcpy(savegamename, SAVEGAMENAME"%u.ssg");
|
||||||
strcpy(liveeventbackup, "live"SAVEGAMENAME".bkp"); // intentionally not ending with .ssg
|
strcpy(gpbackup, "gp"SAVEGAMENAME".bkp"); // intentionally not ending with .ssg
|
||||||
|
|
||||||
// Init the joined IP table for quick rejoining of past games.
|
// Init the joined IP table for quick rejoining of past games.
|
||||||
M_InitJoinedIPArray();
|
M_InitJoinedIPArray();
|
||||||
|
|
@ -1358,7 +1357,7 @@ void D_SRB2Main(void)
|
||||||
|
|
||||||
// can't use sprintf since there is %u in savegamename
|
// can't use sprintf since there is %u in savegamename
|
||||||
strcatbf(savegamename, srb2home, PATHSEP);
|
strcatbf(savegamename, srb2home, PATHSEP);
|
||||||
strcatbf(liveeventbackup, srb2home, PATHSEP);
|
strcatbf(gpbackup, srb2home, PATHSEP);
|
||||||
|
|
||||||
snprintf(luafiledir, sizeof luafiledir, "%s" PATHSEP "luafiles", srb2home);
|
snprintf(luafiledir, sizeof luafiledir, "%s" PATHSEP "luafiles", srb2home);
|
||||||
#else // DEFAULTDIR
|
#else // DEFAULTDIR
|
||||||
|
|
@ -1370,7 +1369,7 @@ void D_SRB2Main(void)
|
||||||
|
|
||||||
// can't use sprintf since there is %u in savegamename
|
// can't use sprintf since there is %u in savegamename
|
||||||
strcatbf(savegamename, userhome, PATHSEP);
|
strcatbf(savegamename, userhome, PATHSEP);
|
||||||
strcatbf(liveeventbackup, userhome, PATHSEP);
|
strcatbf(gpbackup, userhome, PATHSEP);
|
||||||
|
|
||||||
snprintf(luafiledir, sizeof luafiledir, "%s" PATHSEP "luafiles", userhome);
|
snprintf(luafiledir, sizeof luafiledir, "%s" PATHSEP "luafiles", userhome);
|
||||||
#endif // DEFAULTDIR
|
#endif // DEFAULTDIR
|
||||||
|
|
|
||||||
|
|
@ -2997,8 +2997,8 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
||||||
// can't use sprintf since there is %u in savegamename
|
// can't use sprintf since there is %u in savegamename
|
||||||
strcatbf(savegamename, srb2home, PATHSEP);
|
strcatbf(savegamename, srb2home, PATHSEP);
|
||||||
|
|
||||||
strcpy(liveeventbackup, va("live%s.bkp", timeattackfolder));
|
strcpy(gpbackup, va("gp%s.bkp", timeattackfolder));
|
||||||
strcatbf(liveeventbackup, srb2home, PATHSEP);
|
strcatbf(gpbackup, srb2home, PATHSEP);
|
||||||
|
|
||||||
refreshdirmenu |= REFRESHDIR_GAMEDATA;
|
refreshdirmenu |= REFRESHDIR_GAMEDATA;
|
||||||
gamedataadded = true;
|
gamedataadded = true;
|
||||||
|
|
|
||||||
|
|
@ -517,9 +517,9 @@ void CONS_Debug(UINT32 debugflags, const char *fmt, ...) FUNCDEBUG;
|
||||||
#include "m_swap.h"
|
#include "m_swap.h"
|
||||||
|
|
||||||
// Things that used to be in dstrings.h
|
// Things that used to be in dstrings.h
|
||||||
#define SAVEGAMENAME "srb2sav"
|
#define SAVEGAMENAME "ringsav"
|
||||||
extern char savegamename[256];
|
extern char savegamename[256];
|
||||||
extern char liveeventbackup[256];
|
extern char gpbackup[256];
|
||||||
|
|
||||||
// m_misc.h
|
// m_misc.h
|
||||||
#ifdef GETTEXT
|
#ifdef GETTEXT
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,6 @@ extern UINT8 mapmusrng;
|
||||||
extern UINT32 maptol;
|
extern UINT32 maptol;
|
||||||
|
|
||||||
extern INT32 cursaveslot;
|
extern INT32 cursaveslot;
|
||||||
//extern INT16 lastmapsaved;
|
|
||||||
extern INT16 lastmaploaded;
|
|
||||||
extern UINT8 gamecomplete;
|
extern UINT8 gamecomplete;
|
||||||
|
|
||||||
// Extra abilities/settings for skins (combinable stuff)
|
// Extra abilities/settings for skins (combinable stuff)
|
||||||
|
|
|
||||||
|
|
@ -2131,8 +2131,10 @@ void F_TitleScreenTicker(boolean run)
|
||||||
// Now start the music
|
// Now start the music
|
||||||
S_ChangeMusicInternal("_title", looptitle);
|
S_ChangeMusicInternal("_title", looptitle);
|
||||||
}
|
}
|
||||||
else if (menumessage.fadetimer < 9)
|
else if (menumessage.active)
|
||||||
menumessage.fadetimer++;
|
{
|
||||||
|
M_MenuMessageTick();
|
||||||
|
}
|
||||||
|
|
||||||
finalecount++;
|
finalecount++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
324
src/g_game.c
324
src/g_game.c
|
|
@ -123,8 +123,6 @@ precipprops_t precipprops[MAXPRECIP] =
|
||||||
preciptype_t precip_freeslot = PRECIP_FIRSTFREESLOT;
|
preciptype_t precip_freeslot = PRECIP_FIRSTFREESLOT;
|
||||||
|
|
||||||
INT32 cursaveslot = 0; // Auto-save 1p savegame slot
|
INT32 cursaveslot = 0; // Auto-save 1p savegame slot
|
||||||
//INT16 lastmapsaved = 0; // Last map we auto-saved at
|
|
||||||
INT16 lastmaploaded = 0; // Last map the game loaded
|
|
||||||
UINT8 gamecomplete = 0;
|
UINT8 gamecomplete = 0;
|
||||||
|
|
||||||
marathonmode_t marathonmode = 0;
|
marathonmode_t marathonmode = 0;
|
||||||
|
|
@ -3351,6 +3349,7 @@ void G_ExitLevel(void)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Back to the menu with you.
|
// Back to the menu with you.
|
||||||
|
G_HandleSaveLevel(true);
|
||||||
D_QuitNetGame();
|
D_QuitNetGame();
|
||||||
CL_Reset();
|
CL_Reset();
|
||||||
D_ClearState();
|
D_ClearState();
|
||||||
|
|
@ -4018,39 +4017,29 @@ void G_UpdateVisited(void)
|
||||||
G_SaveGameData();
|
G_SaveGameData();
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean CanSaveLevel(INT32 mapnum)
|
void G_HandleSaveLevel(boolean removecondition)
|
||||||
{
|
{
|
||||||
// SRB2Kart: No save files yet
|
if (!grandprixinfo.gp || !grandprixinfo.cup
|
||||||
(void)mapnum;
|
|| splitscreen || netgame)
|
||||||
return false;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
static void G_HandleSaveLevel(void)
|
if (removecondition)
|
||||||
{
|
goto doremove;
|
||||||
// do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c
|
|
||||||
if (nextmap >= NEXTMAP_SPECIAL)
|
if (gamestate != GS_LEVEL
|
||||||
{
|
|| roundqueue.size == 0)
|
||||||
if (!gamecomplete)
|
return;
|
||||||
gamecomplete = 2; // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission
|
|
||||||
if (cursaveslot > 0)
|
if (roundqueue.position == 1
|
||||||
{
|
|| players[consoleplayer].lives <= 1) // because a life is lost on reload
|
||||||
if (marathonmode)
|
goto doremove;
|
||||||
{
|
|
||||||
// don't keep a backup around when the run is done!
|
G_SaveGame();
|
||||||
if (FIL_FileExists(liveeventbackup))
|
return;
|
||||||
remove(liveeventbackup);
|
|
||||||
cursaveslot = 0;
|
doremove:
|
||||||
}
|
if (FIL_FileExists(gpbackup))
|
||||||
else if (!usedCheats && !(netgame || multiplayer || ultimatemode || demo.recording || metalrecording || modeattacking))
|
remove(gpbackup);
|
||||||
G_SaveGame((UINT32)cursaveslot, 0); // TODO when we readd a campaign one day
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// and doing THIS here means you don't lose your progress if you close the game mid-intermission
|
|
||||||
else if (!(ultimatemode || demo.playback || demo.recording || metalrecording || modeattacking)
|
|
||||||
&& cursaveslot > 0 && CanSaveLevel(lastmap+1))
|
|
||||||
{
|
|
||||||
G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next map apparatus
|
// Next map apparatus
|
||||||
|
|
@ -4157,7 +4146,7 @@ void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void G_GetNextMap(void)
|
void G_GetNextMap(void)
|
||||||
{
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
boolean setalready = false;
|
boolean setalready = false;
|
||||||
|
|
@ -4540,7 +4529,6 @@ void G_AfterIntermission(void)
|
||||||
if (gamestate != GS_VOTING)
|
if (gamestate != GS_VOTING)
|
||||||
{
|
{
|
||||||
G_GetNextMap();
|
G_GetNextMap();
|
||||||
G_HandleSaveLevel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((grandprixinfo.gp == true) && mapheaderinfo[prevmap]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene.
|
if ((grandprixinfo.gp == true) && mapheaderinfo[prevmap]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene.
|
||||||
|
|
@ -4645,9 +4633,6 @@ static void G_DoContinued(void)
|
||||||
// Reset score
|
// Reset score
|
||||||
pl->score = 0;
|
pl->score = 0;
|
||||||
|
|
||||||
if (!(netgame || multiplayer || demo.playback || demo.recording || metalrecording || modeattacking) && !usedCheats && cursaveslot > 0)
|
|
||||||
G_SaveGameOver((UINT32)cursaveslot, true);
|
|
||||||
|
|
||||||
// Reset # of lives
|
// Reset # of lives
|
||||||
pl->lives = 3;
|
pl->lives = 3;
|
||||||
|
|
||||||
|
|
@ -5673,24 +5658,23 @@ void G_SaveGameData(void)
|
||||||
// G_InitFromSavegame
|
// G_InitFromSavegame
|
||||||
// Can be called by the startup code or the menu task.
|
// Can be called by the startup code or the menu task.
|
||||||
//
|
//
|
||||||
void G_LoadGame(UINT32 slot, INT16 mapoverride)
|
|
||||||
|
#define SAV_VERSIONMINOR 2
|
||||||
|
|
||||||
|
void G_LoadGame(void)
|
||||||
{
|
{
|
||||||
char vcheck[VERSIONSIZE];
|
char vcheck[VERSIONSIZE+1];
|
||||||
char savename[255];
|
char savename[255];
|
||||||
|
UINT8 versionMinor;
|
||||||
savebuffer_t save = {0};
|
savebuffer_t save = {0};
|
||||||
|
|
||||||
// memset savedata to all 0, fixes calling perfectly valid saves corrupt because of bots
|
// memset savedata to all 0, fixes calling perfectly valid saves corrupt because of bots
|
||||||
memset(&savedata, 0, sizeof(savedata));
|
memset(&savedata, 0, sizeof(savedata));
|
||||||
|
|
||||||
#ifdef SAVEGAME_OTHERVERSIONS
|
//if (makelivebackup)
|
||||||
//Oh christ. The force load response needs access to mapoverride too...
|
strcpy(savename, gpbackup);
|
||||||
startonmapnum = mapoverride;
|
//else
|
||||||
#endif
|
//sprintf(savename, savegamename, cursaveslot);
|
||||||
|
|
||||||
if (marathonmode)
|
|
||||||
strcpy(savename, liveeventbackup);
|
|
||||||
else
|
|
||||||
sprintf(savename, savegamename, slot);
|
|
||||||
|
|
||||||
if (P_SaveBufferFromFile(&save, savename) == false)
|
if (P_SaveBufferFromFile(&save, savename) == false)
|
||||||
{
|
{
|
||||||
|
|
@ -5698,23 +5682,16 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(vcheck, 0, sizeof (vcheck));
|
versionMinor = READUINT8(save.p);
|
||||||
sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION);
|
|
||||||
if (strcmp((const char *)save.p, (const char *)vcheck))
|
|
||||||
{
|
|
||||||
#ifdef SAVEGAME_OTHERVERSIONS
|
|
||||||
M_StartMessage("Savegame Load", M_GetText("Save game from different version.\nYou can load this savegame, but\nsaving afterwards will be disabled.\n\nDo you want to continue anyway?\n"),
|
|
||||||
M_ForceLoadGameResponse, MM_YESNO, NULL, NULL);
|
|
||||||
//Freeing done by the callback function of the above message
|
|
||||||
#else
|
|
||||||
M_ClearMenus(true); // so ESC backs out to title
|
|
||||||
M_StartMessage("Savegame Load", M_GetText("Save game from different version\n\n"), NULL, MM_NOTHING, NULL, "Return to Menu");
|
|
||||||
Command_ExitGame_f();
|
|
||||||
P_SaveBufferFree(&save);
|
|
||||||
|
|
||||||
// no cheating!
|
memset(vcheck, 0, sizeof (vcheck));
|
||||||
memset(&savedata, 0, sizeof(savedata));
|
sprintf(vcheck, "version %d", VERSION);
|
||||||
#endif
|
|
||||||
|
if (versionMinor != SAV_VERSIONMINOR
|
||||||
|
|| memcmp(save.p, vcheck, VERSIONSIZE))
|
||||||
|
{
|
||||||
|
M_StartMessage("Savegame Load", va(M_GetText("Savegame %s is from\na different version."), savename), NULL, MM_NOTHING, NULL, NULL);
|
||||||
|
P_SaveBufferFree(&save);
|
||||||
return; // bad version
|
return; // bad version
|
||||||
}
|
}
|
||||||
save.p += VERSIONSIZE;
|
save.p += VERSIONSIZE;
|
||||||
|
|
@ -5726,62 +5703,91 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
|
||||||
// automapactive = false;
|
// automapactive = false;
|
||||||
|
|
||||||
// dearchive all the modifications
|
// dearchive all the modifications
|
||||||
if (!P_LoadGame(&save, mapoverride))
|
if (!P_LoadGame(&save))
|
||||||
{
|
{
|
||||||
M_ClearMenus(true); // so ESC backs out to title
|
M_StartMessage("Savegame Load", va(M_GetText("Savegame %s could not be loaded.\n"
|
||||||
M_StartMessage("Savegame Load", M_GetText("Savegame file corrupted\n"), NULL, MM_NOTHING, NULL, "Return to Menu");
|
"Check the console log for more info.\n"), savename), NULL, MM_NOTHING, NULL, NULL);
|
||||||
Command_ExitGame_f();
|
|
||||||
Z_Free(save.buffer);
|
Z_Free(save.buffer);
|
||||||
save.p = save.buffer = NULL;
|
save.p = save.buffer = NULL;
|
||||||
|
|
||||||
// no cheating!
|
|
||||||
memset(&savedata, 0, sizeof(savedata));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (marathonmode)
|
|
||||||
{
|
|
||||||
marathontime = READUINT32(save.p);
|
|
||||||
marathonmode |= READUINT8(save.p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// done
|
// done
|
||||||
P_SaveBufferFree(&save);
|
P_SaveBufferFree(&save);
|
||||||
|
|
||||||
// gameaction = ga_nothing;
|
|
||||||
// G_SetGamestate(GS_LEVEL);
|
|
||||||
displayplayers[0] = consoleplayer;
|
|
||||||
multiplayer = false;
|
|
||||||
splitscreen = 0;
|
|
||||||
SplitScreen_OnChange(); // not needed?
|
|
||||||
|
|
||||||
// G_DeferedInitNew(sk_medium, G_BuildMapName(1), 0, 0, 1);
|
|
||||||
if (setsizeneeded)
|
|
||||||
R_ExecuteSetViewSize();
|
|
||||||
|
|
||||||
M_ClearMenus(true);
|
|
||||||
CON_ToggleOff();
|
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
|
// G_SaveGame
|
||||||
// Saves your game.
|
// Saves your game.
|
||||||
//
|
//
|
||||||
void G_SaveGame(UINT32 slot, INT16 mapnum)
|
void G_SaveGame(void)
|
||||||
{
|
{
|
||||||
boolean saved;
|
boolean saved;
|
||||||
char savename[256] = "";
|
char savename[256] = "";
|
||||||
const char *backup;
|
|
||||||
savebuffer_t save = {0};
|
savebuffer_t save = {0};
|
||||||
|
|
||||||
if (marathonmode)
|
//if (makelivebackup)
|
||||||
strcpy(savename, liveeventbackup);
|
strcpy(savename, gpbackup);
|
||||||
else
|
//else
|
||||||
sprintf(savename, savegamename, slot);
|
//sprintf(savename, savegamename, cursaveslot);
|
||||||
backup = va("%s",savename);
|
|
||||||
|
|
||||||
gameaction = ga_nothing;
|
gameaction = ga_nothing;
|
||||||
{
|
{
|
||||||
char name[VERSIONSIZE];
|
char name[VERSIONSIZE+1];
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|
||||||
if (P_SaveBufferAlloc(&save, SAVEGAMESIZE) == false)
|
if (P_SaveBufferAlloc(&save, SAVEGAMESIZE) == false)
|
||||||
|
|
@ -5790,139 +5796,27 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRITEUINT8(save.p, SAV_VERSIONMINOR);
|
||||||
|
|
||||||
memset(name, 0, sizeof (name));
|
memset(name, 0, sizeof (name));
|
||||||
sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION);
|
sprintf(name, "version %d", VERSION);
|
||||||
WRITEMEM(save.p, name, VERSIONSIZE);
|
WRITEMEM(save.p, name, VERSIONSIZE);
|
||||||
|
|
||||||
P_SaveGame(&save, mapnum);
|
P_SaveGame(&save);
|
||||||
if (marathonmode)
|
|
||||||
{
|
|
||||||
UINT32 writetime = marathontime;
|
|
||||||
if (!(marathonmode & MA_INGAME))
|
|
||||||
writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map
|
|
||||||
WRITEUINT32(save.p, writetime);
|
|
||||||
WRITEUINT8(save.p, (marathonmode & ~MA_INIT));
|
|
||||||
}
|
|
||||||
|
|
||||||
length = save.p - save.buffer;
|
length = save.p - save.buffer;
|
||||||
saved = FIL_WriteFile(backup, save.buffer, length);
|
saved = FIL_WriteFile(savename, save.buffer, length);
|
||||||
P_SaveBufferFree(&save);
|
P_SaveBufferFree(&save);
|
||||||
}
|
}
|
||||||
|
|
||||||
gameaction = ga_nothing;
|
gameaction = ga_nothing;
|
||||||
|
|
||||||
if (cht_debug && saved)
|
if (cht_debug && saved)
|
||||||
CONS_Printf(M_GetText("Game saved.\n"));
|
CONS_Printf(M_GetText("%s saved.\n"), savename);
|
||||||
else if (!saved)
|
else if (!saved)
|
||||||
CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename));
|
CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s\n"), savename);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BADSAVE goto cleanup;
|
|
||||||
#define CHECKPOS if (save.p >= save.end) BADSAVE
|
|
||||||
void G_SaveGameOver(UINT32 slot, boolean modifylives)
|
|
||||||
{
|
|
||||||
boolean saved = false;
|
|
||||||
size_t length;
|
|
||||||
char vcheck[VERSIONSIZE];
|
|
||||||
char savename[255];
|
|
||||||
const char *backup;
|
|
||||||
savebuffer_t save = {0};
|
|
||||||
|
|
||||||
if (marathonmode)
|
|
||||||
strcpy(savename, liveeventbackup);
|
|
||||||
else
|
|
||||||
sprintf(savename, savegamename, slot);
|
|
||||||
backup = va("%s",savename);
|
|
||||||
|
|
||||||
if (P_SaveBufferFromFile(&save, savename) == false)
|
|
||||||
{
|
|
||||||
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
length = save.size;
|
|
||||||
|
|
||||||
{
|
|
||||||
char temp[sizeof(timeattackfolder)];
|
|
||||||
UINT8 *lives_p;
|
|
||||||
SINT8 pllives;
|
|
||||||
|
|
||||||
// Version check
|
|
||||||
memset(vcheck, 0, sizeof (vcheck));
|
|
||||||
sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION);
|
|
||||||
if (strcmp((const char *)save.p, (const char *)vcheck)) BADSAVE
|
|
||||||
save.p += VERSIONSIZE;
|
|
||||||
|
|
||||||
// P_UnArchiveMisc()
|
|
||||||
(void)READINT16(save.p);
|
|
||||||
CHECKPOS
|
|
||||||
(void)READUINT16(save.p); // emeralds
|
|
||||||
CHECKPOS
|
|
||||||
READSTRINGN(save.p, temp, sizeof(temp)); // mod it belongs to
|
|
||||||
if (strcmp(temp, timeattackfolder)) BADSAVE
|
|
||||||
|
|
||||||
// P_UnArchivePlayer()
|
|
||||||
CHECKPOS
|
|
||||||
(void)READUINT16(save.p);
|
|
||||||
CHECKPOS
|
|
||||||
|
|
||||||
WRITEUINT8(save.p, numgameovers);
|
|
||||||
CHECKPOS
|
|
||||||
|
|
||||||
lives_p = save.p;
|
|
||||||
pllives = READSINT8(save.p); // lives
|
|
||||||
CHECKPOS
|
|
||||||
if (modifylives && pllives < startinglivesbalance[numgameovers])
|
|
||||||
{
|
|
||||||
pllives = startinglivesbalance[numgameovers];
|
|
||||||
WRITESINT8(lives_p, pllives);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)READINT32(save.p); // Score
|
|
||||||
CHECKPOS
|
|
||||||
(void)READINT32(save.p); // continues
|
|
||||||
|
|
||||||
// File end marker check
|
|
||||||
CHECKPOS
|
|
||||||
switch (READUINT8(save.p))
|
|
||||||
{
|
|
||||||
case 0xb7:
|
|
||||||
{
|
|
||||||
UINT8 i, banksinuse;
|
|
||||||
CHECKPOS
|
|
||||||
banksinuse = READUINT8(save.p);
|
|
||||||
CHECKPOS
|
|
||||||
if (banksinuse > NUM_LUABANKS)
|
|
||||||
BADSAVE
|
|
||||||
for (i = 0; i < banksinuse; i++)
|
|
||||||
{
|
|
||||||
(void)READINT32(save.p);
|
|
||||||
CHECKPOS
|
|
||||||
}
|
|
||||||
if (READUINT8(save.p) != 0x1d)
|
|
||||||
BADSAVE
|
|
||||||
}
|
|
||||||
case 0x1d:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BADSAVE
|
|
||||||
}
|
|
||||||
|
|
||||||
// done
|
|
||||||
saved = FIL_WriteFile(backup, save.buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (cht_debug && saved)
|
|
||||||
CONS_Printf(M_GetText("Game saved.\n"));
|
|
||||||
else if (!saved)
|
|
||||||
CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename));
|
|
||||||
|
|
||||||
P_SaveBufferFree(&save);
|
|
||||||
}
|
|
||||||
#undef CHECKPOS
|
|
||||||
#undef BADSAVE
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// G_DeferedInitNew
|
// G_DeferedInitNew
|
||||||
// Can be called by the startup code or the menu task,
|
// Can be called by the startup code or the menu task,
|
||||||
|
|
|
||||||
11
src/g_game.h
11
src/g_game.h
|
|
@ -187,16 +187,14 @@ void G_StartTitleCard(void);
|
||||||
void G_PreLevelTitleCard(void);
|
void G_PreLevelTitleCard(void);
|
||||||
boolean G_IsTitleCardAvailable(void);
|
boolean G_IsTitleCardAvailable(void);
|
||||||
|
|
||||||
// Can be called by the startup code or M_Responder, calls P_SetupLevel.
|
void G_HandleSaveLevel(boolean removecondition);
|
||||||
void G_LoadGame(UINT32 slot, INT16 mapoverride);
|
void G_SaveGame(void);
|
||||||
|
void G_LoadGame(void);
|
||||||
|
void G_GetBackupCupData(boolean actuallygetdata);
|
||||||
|
|
||||||
void G_SaveGameData(void);
|
void G_SaveGameData(void);
|
||||||
void G_DirtyGameData(void);
|
void G_DirtyGameData(void);
|
||||||
|
|
||||||
void G_SaveGame(UINT32 slot, INT16 mapnum);
|
|
||||||
|
|
||||||
void G_SaveGameOver(UINT32 slot, boolean modifylives);
|
|
||||||
|
|
||||||
void G_SetGametype(INT16 gametype);
|
void G_SetGametype(INT16 gametype);
|
||||||
char *G_PrepareGametypeConstant(const char *newgtconst);
|
char *G_PrepareGametypeConstant(const char *newgtconst);
|
||||||
void G_AddTOL(UINT32 newtol, const char *tolname);
|
void G_AddTOL(UINT32 newtol, const char *tolname);
|
||||||
|
|
@ -209,6 +207,7 @@ boolean G_GametypeHasSpectators(void);
|
||||||
INT16 G_SometimesGetDifferentEncore(void);
|
INT16 G_SometimesGetDifferentEncore(void);
|
||||||
void G_ExitLevel(void);
|
void G_ExitLevel(void);
|
||||||
void G_NextLevel(void);
|
void G_NextLevel(void);
|
||||||
|
void G_GetNextMap(void);
|
||||||
void G_Continue(void);
|
void G_Continue(void);
|
||||||
void G_UseContinue(void);
|
void G_UseContinue(void);
|
||||||
void G_AfterIntermission(void);
|
void G_AfterIntermission(void);
|
||||||
|
|
|
||||||
|
|
@ -274,6 +274,44 @@ void K_InitGrandPrixBots(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
void K_LoadGrandPrixSaveGame(void)
|
||||||
|
|
||||||
|
See header file for description.
|
||||||
|
---------------------------------------------------*/
|
||||||
|
|
||||||
|
void K_LoadGrandPrixSaveGame(void)
|
||||||
|
{
|
||||||
|
if (splitscreen)
|
||||||
|
{
|
||||||
|
// You're not doing splitscreen runs at GDQ.
|
||||||
|
// We are literally 14 days from code freeze
|
||||||
|
// and I am not accomodating weird setup this
|
||||||
|
// second in my last minute QoL feature.
|
||||||
|
// I will *actually* fight you
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
players[consoleplayer].lives = savedata.lives;
|
||||||
|
players[consoleplayer].score = savedata.score;
|
||||||
|
players[consoleplayer].totalring = savedata.totalring;
|
||||||
|
|
||||||
|
UINT8 i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (savedata.bots[i].valid == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
K_SetBot(i, savedata.bots[i].skin, savedata.bots[i].difficulty, BOT_STYLE_NORMAL);
|
||||||
|
|
||||||
|
players[i].botvars.rival = savedata.bots[i].rival;
|
||||||
|
players[i].score = savedata.bots[i].score;
|
||||||
|
|
||||||
|
players[i].spectator = !(gametyperules & GTR_BOTS) || (grandprixinfo.eventmode != GPEVENT_NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
static INT16 K_RivalScore(player_t *bot)
|
static INT16 K_RivalScore(player_t *bot)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ typedef enum
|
||||||
GPEVENT_SPECIAL,
|
GPEVENT_SPECIAL,
|
||||||
} gpEvent_e;
|
} gpEvent_e;
|
||||||
|
|
||||||
|
// Please also see P_ArchiveMisc
|
||||||
extern struct grandprixinfo
|
extern struct grandprixinfo
|
||||||
{
|
{
|
||||||
boolean gp; ///< If true, then we are in a Grand Prix.
|
boolean gp; ///< If true, then we are in a Grand Prix.
|
||||||
|
|
@ -100,6 +101,15 @@ UINT8 K_GetGPPlayerCount(UINT8 humans);
|
||||||
void K_InitGrandPrixBots(void);
|
void K_InitGrandPrixBots(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
void K_LoadGrandPrixSaveGame(void)
|
||||||
|
|
||||||
|
Handles loading savedata_t info for Grand Prix context.
|
||||||
|
---------------------------------------------------*/
|
||||||
|
|
||||||
|
void K_LoadGrandPrixSaveGame(void);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_UpdateGrandPrixBots(void);
|
void K_UpdateGrandPrixBots(void);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "doomstat.h" // MAXSPLITSCREENPLAYERS
|
#include "doomstat.h" // MAXSPLITSCREENPLAYERS
|
||||||
#include "g_demo.h" //menudemo_t
|
#include "g_demo.h" //menudemo_t
|
||||||
|
#include "p_saveg.h" // savedata_cup_t
|
||||||
#include "k_profiles.h" // profile data & functions
|
#include "k_profiles.h" // profile data & functions
|
||||||
#include "g_input.h" // gc_
|
#include "g_input.h" // gc_
|
||||||
#include "i_threads.h"
|
#include "i_threads.h"
|
||||||
|
|
@ -517,10 +518,11 @@ typedef enum
|
||||||
} manswer_e;
|
} manswer_e;
|
||||||
|
|
||||||
#define MAXMENUMESSAGE 256
|
#define MAXMENUMESSAGE 256
|
||||||
|
#define MENUMESSAGECLOSE 2
|
||||||
extern struct menumessage_s
|
extern struct menumessage_s
|
||||||
{
|
{
|
||||||
boolean active;
|
boolean active;
|
||||||
boolean closing;
|
UINT8 closing;
|
||||||
|
|
||||||
INT32 flags; // MM_
|
INT32 flags; // MM_
|
||||||
const char *header;
|
const char *header;
|
||||||
|
|
@ -533,6 +535,7 @@ extern struct menumessage_s
|
||||||
|
|
||||||
void (*routine)(INT32 choice); // Normal routine
|
void (*routine)(INT32 choice); // Normal routine
|
||||||
//void (*eroutine)(event_t *ev); // Event routine (MM_EVENTHANDLER)
|
//void (*eroutine)(event_t *ev); // Event routine (MM_EVENTHANDLER)
|
||||||
|
INT32 answer;
|
||||||
|
|
||||||
const char *defaultstr;
|
const char *defaultstr;
|
||||||
const char *confirmstr;
|
const char *confirmstr;
|
||||||
|
|
@ -599,7 +602,7 @@ void M_SetMenuDelay(UINT8 i);
|
||||||
|
|
||||||
void M_SortServerList(void);
|
void M_SortServerList(void);
|
||||||
|
|
||||||
void M_UpdateMenuCMD(UINT8 i);
|
void M_UpdateMenuCMD(UINT8 i, boolean bailrequired);
|
||||||
boolean M_Responder(event_t *ev);
|
boolean M_Responder(event_t *ev);
|
||||||
boolean M_MenuButtonPressed(UINT8 pid, UINT32 bt);
|
boolean M_MenuButtonPressed(UINT8 pid, UINT32 bt);
|
||||||
boolean M_MenuButtonHeld(UINT8 pid, UINT32 bt);
|
boolean M_MenuButtonHeld(UINT8 pid, UINT32 bt);
|
||||||
|
|
|
||||||
|
|
@ -606,15 +606,15 @@ static void M_DrawMenuTyping(void)
|
||||||
// Draw the message popup submenu
|
// Draw the message popup submenu
|
||||||
void M_DrawMenuMessage(void)
|
void M_DrawMenuMessage(void)
|
||||||
{
|
{
|
||||||
|
if (!menumessage.active)
|
||||||
|
return;
|
||||||
|
|
||||||
INT32 x = (BASEVIDWIDTH - menumessage.x)/2;
|
INT32 x = (BASEVIDWIDTH - menumessage.x)/2;
|
||||||
INT32 y = (BASEVIDHEIGHT - menumessage.y)/2 + floor(pow(2, (double)(9 - menumessage.fadetimer)));
|
INT32 y = (BASEVIDHEIGHT - menumessage.y)/2 + floor(pow(2, (double)(9 - menumessage.fadetimer)));
|
||||||
size_t i, start = 0;
|
size_t i, start = 0;
|
||||||
char string[MAXMENUMESSAGE];
|
char string[MAXMENUMESSAGE];
|
||||||
const char *msg = menumessage.message;
|
const char *msg = menumessage.message;
|
||||||
|
|
||||||
if (!menumessage.active)
|
|
||||||
return;
|
|
||||||
|
|
||||||
V_DrawFadeScreen(31, menumessage.fadetimer);
|
V_DrawFadeScreen(31, menumessage.fadetimer);
|
||||||
|
|
||||||
V_DrawFill(0, y, BASEVIDWIDTH, menumessage.y, 159);
|
V_DrawFill(0, y, BASEVIDWIDTH, menumessage.y, 159);
|
||||||
|
|
@ -629,25 +629,64 @@ void M_DrawMenuMessage(void)
|
||||||
INT32 workx = x + menumessage.x;
|
INT32 workx = x + menumessage.x;
|
||||||
INT32 worky = y + menumessage.y;
|
INT32 worky = y + menumessage.y;
|
||||||
|
|
||||||
|
boolean push;
|
||||||
|
|
||||||
|
if (menumessage.closing)
|
||||||
|
push = (menumessage.answer != MA_YES);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const UINT8 anim_duration = 16;
|
||||||
|
push = ((menumessage.timer % (anim_duration * 2)) < anim_duration);
|
||||||
|
}
|
||||||
|
|
||||||
workx -= V_ThinStringWidth(menumessage.defaultstr, V_6WIDTHSPACE|V_ALLOWLOWERCASE);
|
workx -= V_ThinStringWidth(menumessage.defaultstr, V_6WIDTHSPACE|V_ALLOWLOWERCASE);
|
||||||
V_DrawThinString(workx, worky + 1, V_6WIDTHSPACE|V_ALLOWLOWERCASE, menumessage.defaultstr);
|
V_DrawThinString(
|
||||||
|
workx, worky + 1,
|
||||||
|
V_6WIDTHSPACE|V_ALLOWLOWERCASE
|
||||||
|
| ((push && (menumessage.closing & MENUMESSAGECLOSE)) ? highlightflags : 0),
|
||||||
|
menumessage.defaultstr
|
||||||
|
);
|
||||||
|
|
||||||
|
workx -= 2;
|
||||||
|
|
||||||
workx -= SHORT(kp_button_x[1][0]->width);
|
workx -= SHORT(kp_button_x[1][0]->width);
|
||||||
K_drawButtonAnim(workx, worky, 0, kp_button_x[1], menumessage.timer);
|
K_drawButton(
|
||||||
|
workx * FRACUNIT, worky * FRACUNIT,
|
||||||
|
0, kp_button_x[1],
|
||||||
|
push
|
||||||
|
);
|
||||||
|
|
||||||
workx -= SHORT(kp_button_b[1][0]->width);
|
workx -= SHORT(kp_button_b[1][0]->width);
|
||||||
K_drawButtonAnim(workx, worky, 0, kp_button_b[1], menumessage.timer);
|
K_drawButton(
|
||||||
|
workx * FRACUNIT, worky * FRACUNIT,
|
||||||
|
0, kp_button_b[1],
|
||||||
|
push
|
||||||
|
);
|
||||||
|
|
||||||
if (menumessage.confirmstr)
|
if (menumessage.confirmstr)
|
||||||
{
|
{
|
||||||
workx -= 12;
|
workx -= 12;
|
||||||
|
|
||||||
|
if (menumessage.closing)
|
||||||
|
push = !push;
|
||||||
|
|
||||||
workx -= V_ThinStringWidth(menumessage.confirmstr, V_6WIDTHSPACE|V_ALLOWLOWERCASE);
|
workx -= V_ThinStringWidth(menumessage.confirmstr, V_6WIDTHSPACE|V_ALLOWLOWERCASE);
|
||||||
V_DrawThinString(workx, worky + 1, V_6WIDTHSPACE|V_ALLOWLOWERCASE, menumessage.confirmstr);
|
V_DrawThinString(
|
||||||
|
workx, worky + 1,
|
||||||
|
V_6WIDTHSPACE|V_ALLOWLOWERCASE
|
||||||
|
| ((push && (menumessage.closing & MENUMESSAGECLOSE)) ? highlightflags : 0),
|
||||||
|
menumessage.confirmstr
|
||||||
|
);
|
||||||
|
|
||||||
|
workx -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
workx -= SHORT(kp_button_a[1][0]->width);
|
workx -= SHORT(kp_button_a[1][0]->width);
|
||||||
K_drawButtonAnim(workx, worky, 0, kp_button_a[1], menumessage.timer);
|
K_drawButton(
|
||||||
|
workx * FRACUNIT, worky * FRACUNIT,
|
||||||
|
0, kp_button_a[1],
|
||||||
|
push
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
x -= 4;
|
x -= 4;
|
||||||
|
|
@ -2329,6 +2368,7 @@ static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch)
|
||||||
void M_DrawCupSelect(void)
|
void M_DrawCupSelect(void)
|
||||||
{
|
{
|
||||||
UINT8 i, j, temp = 0;
|
UINT8 i, j, temp = 0;
|
||||||
|
INT16 x, y;
|
||||||
UINT8 *colormap = NULL;
|
UINT8 *colormap = NULL;
|
||||||
cupwindata_t *windata = NULL;
|
cupwindata_t *windata = NULL;
|
||||||
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
|
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
|
||||||
|
|
@ -2339,7 +2379,6 @@ void M_DrawCupSelect(void)
|
||||||
{
|
{
|
||||||
size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
|
size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
|
||||||
patch_t *patch = NULL;
|
patch_t *patch = NULL;
|
||||||
INT16 x, y;
|
|
||||||
INT16 icony = 7;
|
INT16 icony = 7;
|
||||||
char status = 'A';
|
char status = 'A';
|
||||||
char monitor;
|
char monitor;
|
||||||
|
|
@ -2424,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(templevelsearch.cup->icon, PU_CACHE));
|
||||||
V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName("CUPBOX", 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)
|
if (!windata)
|
||||||
;
|
;
|
||||||
else if (windata->best_placement != 0)
|
else if (windata->best_placement != 0)
|
||||||
|
|
@ -2523,17 +2569,38 @@ void M_DrawCupSelect(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
V_DrawScaledPatch(14 + (cupgrid.x*42) - 4,
|
x = 14 + (cupgrid.x*42);
|
||||||
20 + (cupgrid.y*44) - 1 - (24*menutransition.tics),
|
y = 20 + (cupgrid.y*44) - (30*menutransition.tics);
|
||||||
0, W_CachePatchName("CUPCURS", PU_CACHE)
|
|
||||||
);
|
V_DrawScaledPatch(x - 4, y - 1, 0, W_CachePatchName("CUPCURS", PU_CACHE));
|
||||||
|
|
||||||
templevelsearch.cup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
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);
|
V_DrawFill(0, 146 + (24*menutransition.tics), BASEVIDWIDTH, 54, 31);
|
||||||
M_DrawCupPreview(146 + (24*menutransition.tics), &templevelsearch);
|
M_DrawCupPreview(146 + (24*menutransition.tics), &templevelsearch);
|
||||||
|
|
||||||
M_DrawCupTitle(120 - (24*menutransition.tics), &templevelsearch);
|
M_DrawCupTitle(120 - (24*menutransition.tics), &templevelsearch);
|
||||||
|
|
||||||
|
if (cupgrid.numpages > 1)
|
||||||
|
{
|
||||||
|
x = 3 - (skullAnimCounter/5);
|
||||||
|
y = 20 + (44 - 1) - (30*menutransition.tics);
|
||||||
|
|
||||||
|
patch_t *cuparrow = W_CachePatchName("CUPARROW", PU_CACHE);
|
||||||
|
|
||||||
|
if (cupgrid.pageno != 0)
|
||||||
|
V_DrawScaledPatch(x, y, 0, cuparrow);
|
||||||
|
|
||||||
|
if (cupgrid.pageno != cupgrid.numpages-1)
|
||||||
|
V_DrawScaledPatch(BASEVIDWIDTH-x, y, V_FLIP, cuparrow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map)
|
static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map)
|
||||||
|
|
|
||||||
|
|
@ -539,6 +539,21 @@ void M_StartControlPanel(void)
|
||||||
// (We can change this timer later when extra animation is added.)
|
// (We can change this timer later when extra animation is added.)
|
||||||
if (finalecount < 1)
|
if (finalecount < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (menumessage.active)
|
||||||
|
{
|
||||||
|
if (!menumessage.closing && menumessage.fadetimer == 9)
|
||||||
|
{
|
||||||
|
// The following doesn't work with MM_YESNO.
|
||||||
|
// However, because there's no guarantee a profile
|
||||||
|
// is selected or controls set up to our liking,
|
||||||
|
// we can't call M_HandleMenuMessage.
|
||||||
|
|
||||||
|
M_StopMessage(MA_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menuactive = true;
|
menuactive = true;
|
||||||
|
|
@ -549,8 +564,6 @@ void M_StartControlPanel(void)
|
||||||
}
|
}
|
||||||
else if (!Playing())
|
else if (!Playing())
|
||||||
{
|
{
|
||||||
M_StopMessage(0); // Doesn't work with MM_YESNO or MM_EVENTHANDLER... but good enough to get the game as it is currently functional again
|
|
||||||
|
|
||||||
if (gamestate != GS_MENU)
|
if (gamestate != GS_MENU)
|
||||||
{
|
{
|
||||||
G_SetGamestate(GS_MENU);
|
G_SetGamestate(GS_MENU);
|
||||||
|
|
@ -754,7 +767,7 @@ void M_SetMenuDelay(UINT8 i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void M_UpdateMenuCMD(UINT8 i)
|
void M_UpdateMenuCMD(UINT8 i, boolean bailrequired)
|
||||||
{
|
{
|
||||||
UINT8 mp = max(1, setup_numplayers);
|
UINT8 mp = max(1, setup_numplayers);
|
||||||
|
|
||||||
|
|
@ -792,6 +805,11 @@ void M_UpdateMenuCMD(UINT8 i)
|
||||||
|
|
||||||
if (G_PlayerInputDown(i, gc_start, mp)) { menucmd[i].buttons |= MBT_START; }
|
if (G_PlayerInputDown(i, gc_start, mp)) { menucmd[i].buttons |= MBT_START; }
|
||||||
|
|
||||||
|
if (bailrequired && i == 0)
|
||||||
|
{
|
||||||
|
if (G_GetDeviceGameKeyDownArray(0)[KEY_ESCAPE]) { menucmd[i].buttons |= MBT_B; }
|
||||||
|
}
|
||||||
|
|
||||||
if (menucmd[i].dpad_ud == 0 && menucmd[i].dpad_lr == 0 && menucmd[i].buttons == 0)
|
if (menucmd[i].dpad_ud == 0 && menucmd[i].dpad_lr == 0 && menucmd[i].buttons == 0)
|
||||||
{
|
{
|
||||||
// Reset delay count with no buttons.
|
// Reset delay count with no buttons.
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
#include "y_inter.h"
|
#include "y_inter.h"
|
||||||
#include "m_cond.h"
|
#include "m_cond.h"
|
||||||
#include "p_local.h"
|
#include "p_local.h"
|
||||||
|
#include "p_saveg.h"
|
||||||
#include "p_setup.h"
|
#include "p_setup.h"
|
||||||
#include "st_stuff.h" // hud hiding
|
#include "st_stuff.h" // hud hiding
|
||||||
#include "fastcmp.h"
|
#include "fastcmp.h"
|
||||||
|
|
@ -252,6 +253,12 @@ boolean K_StartCeremony(void)
|
||||||
maptol = mapheaderinfo[gamemap-1]->typeoflevel;
|
maptol = mapheaderinfo[gamemap-1]->typeoflevel;
|
||||||
globalweather = mapheaderinfo[gamemap-1]->weather;
|
globalweather = mapheaderinfo[gamemap-1]->weather;
|
||||||
|
|
||||||
|
if (savedata.lives > 0)
|
||||||
|
{
|
||||||
|
K_LoadGrandPrixSaveGame();
|
||||||
|
savedata.lives = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure all of the GAME OVER'd players can spawn
|
// Make sure all of the GAME OVER'd players can spawn
|
||||||
// and be present for the podium
|
// and be present for the podium
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Please also see P_ArchiveMisc
|
||||||
struct gpRank_t
|
struct gpRank_t
|
||||||
{
|
{
|
||||||
UINT8 players;
|
UINT8 players;
|
||||||
|
|
|
||||||
|
|
@ -80,31 +80,45 @@ static UINT8 cheatf_warp(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M_ClearMenus(true);
|
||||||
|
|
||||||
|
const char *text;
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
G_SetUsedCheats();
|
G_SetUsedCheats();
|
||||||
M_ClearMenus(true);
|
|
||||||
S_StartSound(0, sfx_kc42);
|
S_StartSound(0, sfx_kc42);
|
||||||
|
|
||||||
M_StartMessage("Tournament Mode",
|
text = M_GetText(
|
||||||
M_GetText(
|
|
||||||
"All challenges temporarily unlocked.\n"
|
"All challenges temporarily unlocked.\n"
|
||||||
"Saving is disabled - the game will\n"
|
"Saving is disabled - the game will\n"
|
||||||
"return to normal on next launch.\n"
|
"return to normal on next launch.\n"
|
||||||
), NULL, MM_NOTHING, NULL, NULL);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
S_StartSound(0, sfx_s3k7b);
|
S_StartSound(0, sfx_s3k7b);
|
||||||
|
|
||||||
M_StartMessage("Tournament Mode",
|
if (usedCheats)
|
||||||
M_GetText(
|
{
|
||||||
"This is the correct password, but\n"
|
text = M_GetText(
|
||||||
"you already have every challenge\n"
|
"This is the correct password, but\n"
|
||||||
"unlocked, so saving is still allowed!\n"
|
"you already have every challenge\n"
|
||||||
), NULL, MM_NOTHING, NULL, NULL);
|
"unlocked, so nothing has changed.\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = M_GetText(
|
||||||
|
"This is the correct password, but\n"
|
||||||
|
"you already have every challenge\n"
|
||||||
|
"unlocked, so saving is still allowed!\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M_StartMessage("Tournament Mode", text, NULL, MM_NOTHING, NULL, NULL);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,11 +101,12 @@ static boolean prevmajormods = false;
|
||||||
|
|
||||||
static void M_AddonsClearName(INT32 choice)
|
static void M_AddonsClearName(INT32 choice)
|
||||||
{
|
{
|
||||||
|
(void)choice;
|
||||||
|
|
||||||
if (!majormods || prevmajormods)
|
if (!majormods || prevmajormods)
|
||||||
{
|
{
|
||||||
CLEARNAME;
|
CLEARNAME;
|
||||||
}
|
}
|
||||||
M_StopMessage(choice);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles messages for addon errors.
|
// Handles messages for addon errors.
|
||||||
|
|
|
||||||
|
|
@ -484,6 +484,7 @@ void M_CharacterSelectInit(void)
|
||||||
setup_page = 0;
|
setup_page = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void M_CharacterSelect(INT32 choice)
|
void M_CharacterSelect(INT32 choice)
|
||||||
{
|
{
|
||||||
(void)choice;
|
(void)choice;
|
||||||
|
|
|
||||||
|
|
@ -414,7 +414,6 @@ static void M_WriteGuestReplay(INT32 ch)
|
||||||
|
|
||||||
if (FIL_FileExists(rguest))
|
if (FIL_FileExists(rguest))
|
||||||
{
|
{
|
||||||
//M_StopMessage(0);
|
|
||||||
remove(rguest);
|
remove(rguest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@
|
||||||
#include "../../v_video.h"
|
#include "../../v_video.h"
|
||||||
#include "../../k_grandprix.h"
|
#include "../../k_grandprix.h"
|
||||||
#include "../../r_local.h" // SplitScreen_OnChange
|
#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[] =
|
menuitem_t PLAY_CupSelect[] =
|
||||||
{
|
{
|
||||||
|
|
@ -32,6 +35,150 @@ menu_t PLAY_CupSelectDef = {
|
||||||
|
|
||||||
struct cupgrid_s cupgrid;
|
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)
|
void M_CupSelectHandler(INT32 choice)
|
||||||
{
|
{
|
||||||
const UINT8 pid = 0;
|
const UINT8 pid = 0;
|
||||||
|
|
@ -104,67 +251,24 @@ void M_CupSelectHandler(INT32 choice)
|
||||||
|
|
||||||
if (cupgrid.grandprix == true)
|
if (cupgrid.grandprix == true)
|
||||||
{
|
{
|
||||||
UINT8 ssplayers = cv_splitplayers.value-1;
|
if (newcup == cupsavedata.cup
|
||||||
|
&& FIL_FileExists(gpbackup))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
splitscreen = ssplayers;
|
M_StartMessage(
|
||||||
SplitScreen_OnChange();
|
"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
|
M_StartCup(0);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else if (count == 1 && levellist.levelsearch.timeattack == true)
|
else if (count == 1 && levellist.levelsearch.timeattack == true)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
#include "../../r_local.h" // SplitScreen_OnChange
|
#include "../../r_local.h" // SplitScreen_OnChange
|
||||||
#include "../../f_finale.h" // F_WipeStartScreen
|
#include "../../f_finale.h" // F_WipeStartScreen
|
||||||
#include "../../v_video.h"
|
#include "../../v_video.h"
|
||||||
|
#include "../../g_game.h" // G_GetBackupCupData
|
||||||
|
#include "../../p_saveg.h" // cupsavedata
|
||||||
|
|
||||||
cupheader_t dummy_lostandfound;
|
cupheader_t dummy_lostandfound;
|
||||||
|
|
||||||
|
|
@ -262,6 +264,11 @@ boolean M_LevelListFromGametype(INT16 gt)
|
||||||
const size_t pagelen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS);
|
const size_t pagelen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS);
|
||||||
boolean foundany = false, currentvalid = false;
|
boolean foundany = false, currentvalid = false;
|
||||||
|
|
||||||
|
G_GetBackupCupData(
|
||||||
|
cupgrid.grandprix == true
|
||||||
|
|| cv_splitplayers.value <= 1
|
||||||
|
);
|
||||||
|
|
||||||
templevelsearch.cup = kartcupheaders;
|
templevelsearch.cup = kartcupheaders;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
@ -331,7 +338,8 @@ boolean M_LevelListFromGametype(INT16 gt)
|
||||||
|
|
||||||
if (Playing()
|
if (Playing()
|
||||||
? (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == templevelsearch.cup)
|
? (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;
|
GRID_FOCUSCUP;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,14 @@ struct menumessage_s menumessage;
|
||||||
//
|
//
|
||||||
static inline size_t M_StringHeight(const char *string)
|
static inline size_t M_StringHeight(const char *string)
|
||||||
{
|
{
|
||||||
size_t h = 8, i;
|
size_t h = 16, i, len = strlen(string);
|
||||||
|
|
||||||
for (i = 0; i < strlen(string); i++)
|
for (i = 0; i < len-1; i++)
|
||||||
if (string[i] == '\n')
|
{
|
||||||
h += 8;
|
if (string[i] != '\n')
|
||||||
|
continue;
|
||||||
|
h += 8;
|
||||||
|
}
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
@ -68,9 +71,10 @@ void M_StartMessage(const char *header, const char *string, void (*routine)(INT3
|
||||||
menumessage.header = header;
|
menumessage.header = header;
|
||||||
menumessage.flags = itemtype;
|
menumessage.flags = itemtype;
|
||||||
menumessage.routine = routine;
|
menumessage.routine = routine;
|
||||||
|
menumessage.answer = MA_NONE;
|
||||||
menumessage.fadetimer = 1;
|
menumessage.fadetimer = 1;
|
||||||
menumessage.timer = 0;
|
menumessage.timer = 0;
|
||||||
menumessage.closing = false;
|
menumessage.closing = 0;
|
||||||
menumessage.active = true;
|
menumessage.active = true;
|
||||||
|
|
||||||
start = 0;
|
start = 0;
|
||||||
|
|
@ -79,18 +83,21 @@ void M_StartMessage(const char *header, const char *string, void (*routine)(INT3
|
||||||
if (!routine)
|
if (!routine)
|
||||||
{
|
{
|
||||||
menumessage.flags = MM_NOTHING;
|
menumessage.flags = MM_NOTHING;
|
||||||
menumessage.routine = M_StopMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menumessage.flags == MM_YESNO && !defaultstr)
|
// Set action strings
|
||||||
|
switch (menumessage.flags)
|
||||||
{
|
{
|
||||||
menumessage.defaultstr = "No";
|
// Send 1 to the routine if we're pressing A, 2 if B/X, 0 otherwise.
|
||||||
menumessage.confirmstr = "Yes";
|
case MM_YESNO:
|
||||||
}
|
menumessage.defaultstr = defaultstr ? defaultstr : "No";
|
||||||
else
|
menumessage.confirmstr = confirmstr ? confirmstr : "Yes";
|
||||||
{
|
break;
|
||||||
menumessage.defaultstr = defaultstr ? defaultstr : "OK";
|
|
||||||
menumessage.confirmstr = confirmstr;
|
default:
|
||||||
|
menumessage.defaultstr = defaultstr ? defaultstr : "OK";
|
||||||
|
menumessage.confirmstr = NULL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// event routine
|
// event routine
|
||||||
|
|
@ -133,11 +140,25 @@ void M_StartMessage(const char *header, const char *string, void (*routine)(INT3
|
||||||
|
|
||||||
void M_StopMessage(INT32 choice)
|
void M_StopMessage(INT32 choice)
|
||||||
{
|
{
|
||||||
const char pid = 0;
|
if (!menumessage.active || menumessage.closing)
|
||||||
(void) choice;
|
return;
|
||||||
|
|
||||||
|
const char pid = 0;
|
||||||
|
|
||||||
|
// Set the answer.
|
||||||
|
menumessage.answer = choice;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// The below was cool, but it felt annoyingly unresponsive.
|
||||||
|
menumessage.closing = MENUMESSAGECLOSE+1;
|
||||||
|
#else
|
||||||
|
// Intended length of time.
|
||||||
|
menumessage.closing = (TICRATE/2);
|
||||||
|
|
||||||
|
// This weird operation is necessary so the text flash is consistently timed.
|
||||||
|
menumessage.closing |= ((2*MENUMESSAGECLOSE) - 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
menumessage.closing = true;
|
|
||||||
menumessage.timer = 0;
|
|
||||||
M_SetMenuDelay(pid);
|
M_SetMenuDelay(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,14 +166,26 @@ boolean M_MenuMessageTick(void)
|
||||||
{
|
{
|
||||||
if (menumessage.closing)
|
if (menumessage.closing)
|
||||||
{
|
{
|
||||||
if (menumessage.fadetimer > 0)
|
if (menumessage.closing > MENUMESSAGECLOSE)
|
||||||
{
|
{
|
||||||
menumessage.fadetimer--;
|
menumessage.closing--;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (menumessage.fadetimer == 0)
|
|
||||||
{
|
{
|
||||||
menumessage.active = false;
|
if (menumessage.fadetimer > 0)
|
||||||
|
{
|
||||||
|
menumessage.fadetimer--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menumessage.fadetimer == 0)
|
||||||
|
{
|
||||||
|
menumessage.active = false;
|
||||||
|
|
||||||
|
if (menumessage.routine)
|
||||||
|
{
|
||||||
|
menumessage.routine(menumessage.answer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -180,38 +213,22 @@ void M_HandleMenuMessage(void)
|
||||||
|
|
||||||
switch (menumessage.flags)
|
switch (menumessage.flags)
|
||||||
{
|
{
|
||||||
// Send 1 to the routine if we're pressing A/B/X
|
|
||||||
case MM_NOTHING:
|
|
||||||
{
|
|
||||||
if (btok || btnok)
|
|
||||||
menumessage.routine(0);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Send 1 to the routine if we're pressing A, 2 if B/X, 0 otherwise.
|
// Send 1 to the routine if we're pressing A, 2 if B/X, 0 otherwise.
|
||||||
case MM_YESNO:
|
case MM_YESNO:
|
||||||
{
|
{
|
||||||
INT32 answer = MA_NONE;
|
|
||||||
if (btok)
|
if (btok)
|
||||||
answer = MA_YES;
|
M_StopMessage(MA_YES);
|
||||||
else if (btnok)
|
else if (btnok)
|
||||||
answer = MA_NO;
|
M_StopMessage(MA_NO);
|
||||||
|
|
||||||
// send 1 if btok is pressed, 2 if nok is pressed, 0 otherwise.
|
|
||||||
if (answer)
|
|
||||||
{
|
|
||||||
menumessage.routine(answer);
|
|
||||||
M_StopMessage(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// MM_EVENTHANDLER: In M_Responder to allow full event compat.
|
|
||||||
default:
|
default:
|
||||||
break;
|
{
|
||||||
}
|
if (btok || btnok)
|
||||||
|
M_StopMessage(MA_NONE);
|
||||||
|
|
||||||
// if we detect any keypress, don't forget to set the menu delay regardless.
|
break;
|
||||||
if (btok || btnok)
|
}
|
||||||
M_SetMenuDelay(pid);
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -358,6 +358,8 @@ void M_ConfirmEnterGame(INT32 choice)
|
||||||
|
|
||||||
static void M_ExitGameResponse(INT32 ch)
|
static void M_ExitGameResponse(INT32 ch)
|
||||||
{
|
{
|
||||||
|
const UINT8 pid = 0;
|
||||||
|
|
||||||
if (ch != MA_YES)
|
if (ch != MA_YES)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -368,7 +370,7 @@ static void M_ExitGameResponse(INT32 ch)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
G_SetExitGameFlag();
|
G_SetExitGameFlag();
|
||||||
M_ClearMenus(true);
|
M_SetMenuDelay(pid); // prevent another input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
384
src/p_saveg.c
384
src/p_saveg.c
|
|
@ -38,6 +38,7 @@
|
||||||
#include "m_cond.h" // netUnlocked
|
#include "m_cond.h" // netUnlocked
|
||||||
|
|
||||||
// SRB2Kart
|
// SRB2Kart
|
||||||
|
#include "k_grandprix.h"
|
||||||
#include "k_battle.h"
|
#include "k_battle.h"
|
||||||
#include "k_pwrlv.h"
|
#include "k_pwrlv.h"
|
||||||
#include "k_terrain.h"
|
#include "k_terrain.h"
|
||||||
|
|
@ -47,6 +48,7 @@
|
||||||
#include "k_zvote.h"
|
#include "k_zvote.h"
|
||||||
|
|
||||||
savedata_t savedata;
|
savedata_t savedata;
|
||||||
|
savedata_cup_t cupsavedata;
|
||||||
|
|
||||||
// Block UINT32s to attempt to ensure that the correct data is
|
// Block UINT32s to attempt to ensure that the correct data is
|
||||||
// being sent and received
|
// being sent and received
|
||||||
|
|
@ -82,25 +84,106 @@ typedef enum
|
||||||
static inline void P_ArchivePlayer(savebuffer_t *save)
|
static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||||
{
|
{
|
||||||
const player_t *player = &players[consoleplayer];
|
const player_t *player = &players[consoleplayer];
|
||||||
INT16 skininfo = player->skin;
|
|
||||||
SINT8 pllives = player->lives;
|
|
||||||
if (pllives < startinglivesbalance[numgameovers]) // Bump up to 3 lives if the player
|
|
||||||
pllives = startinglivesbalance[numgameovers]; // has less than that.
|
|
||||||
|
|
||||||
WRITEUINT16(save->p, skininfo);
|
// Prevent an exploit from occuring.
|
||||||
WRITEUINT8(save->p, numgameovers);
|
WRITESINT8(save->p, (player->lives - 1));
|
||||||
WRITESINT8(save->p, pllives);
|
|
||||||
WRITEUINT32(save->p, player->score);
|
WRITEUINT32(save->p, player->score);
|
||||||
|
WRITEUINT16(save->p, player->totalring);
|
||||||
|
|
||||||
|
INT32 skin = player->skin;
|
||||||
|
if (skin > numskins)
|
||||||
|
skin = 0;
|
||||||
|
|
||||||
|
WRITESTRINGN(save->p, skins[skin].name, SKINNAMESIZE);
|
||||||
|
|
||||||
|
if (player->followerskin < 0 || player->followerskin >= numfollowers)
|
||||||
|
WRITESTRINGN(save->p, "None", SKINNAMESIZE);
|
||||||
|
else
|
||||||
|
WRITESTRINGN(save->p, followers[player->followerskin].name, SKINNAMESIZE);
|
||||||
|
|
||||||
|
WRITEUINT16(save->p, player->skincolor);
|
||||||
|
WRITEUINT16(save->p, player->followercolor);
|
||||||
|
|
||||||
|
UINT8 i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (playeringame[i] == false)
|
||||||
|
continue;
|
||||||
|
if (players[i].bot == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, i);
|
||||||
|
|
||||||
|
skin = players[i].skin;
|
||||||
|
if (skin > numskins)
|
||||||
|
skin = 0;
|
||||||
|
|
||||||
|
WRITESTRINGN(save->p, skins[skin].name, SKINNAMESIZE);
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, players[i].botvars.difficulty);
|
||||||
|
WRITEUINT8(save->p, (UINT8)players[i].botvars.rival);
|
||||||
|
|
||||||
|
WRITEUINT32(save->p, players[i].score);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, 0xFE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void P_UnArchivePlayer(savebuffer_t *save)
|
static boolean P_UnArchivePlayer(savebuffer_t *save)
|
||||||
{
|
{
|
||||||
INT16 skininfo = READUINT16(save->p);
|
|
||||||
savedata.skin = skininfo;
|
|
||||||
|
|
||||||
savedata.numgameovers = READUINT8(save->p);
|
|
||||||
savedata.lives = READSINT8(save->p);
|
savedata.lives = READSINT8(save->p);
|
||||||
savedata.score = READUINT32(save->p);
|
savedata.score = READUINT32(save->p);
|
||||||
|
savedata.totalring = READUINT16(save->p);
|
||||||
|
|
||||||
|
char skinname[SKINNAMESIZE+1];
|
||||||
|
INT32 skin;
|
||||||
|
|
||||||
|
READSTRINGN(save->p, skinname, SKINNAMESIZE);
|
||||||
|
skin = R_SkinAvailable(skinname);
|
||||||
|
|
||||||
|
if (skin == -1)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, "P_UnArchivePlayer: Character \"%s\" is not currently loaded.\n", skinname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
savedata.skin = skin;
|
||||||
|
|
||||||
|
READSTRINGN(save->p, skinname, SKINNAMESIZE);
|
||||||
|
savedata.followerskin = K_FollowerAvailable(skinname);
|
||||||
|
|
||||||
|
savedata.skincolor = READUINT16(save->p);
|
||||||
|
savedata.followercolor = READUINT16(save->p);
|
||||||
|
|
||||||
|
memset(&savedata.bots, 0, sizeof(savedata.bots));
|
||||||
|
|
||||||
|
UINT8 pid;
|
||||||
|
const UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||||
|
|
||||||
|
while ((pid = READUINT8(save->p)) < MAXPLAYERS)
|
||||||
|
{
|
||||||
|
savedata.bots[pid].valid = true;
|
||||||
|
|
||||||
|
READSTRINGN(save->p, skinname, SKINNAMESIZE);
|
||||||
|
skin = R_SkinAvailable(skinname);
|
||||||
|
|
||||||
|
if (skin == -1)
|
||||||
|
{
|
||||||
|
// It is not worth destroying an otherwise good savedata over extra added skins.
|
||||||
|
// Let's just say they didn't show up to the rematch, so some Eggrobos subbed in.
|
||||||
|
CONS_Alert(CONS_WARNING, "P_UnArchivePlayer: Bot's character \"%s\" was not loaded, replacing with default \"%s\".\n", skinname, skins[defaultbotskin].name);
|
||||||
|
skin = defaultbotskin;
|
||||||
|
}
|
||||||
|
|
||||||
|
savedata.bots[pid].skin = skin;
|
||||||
|
|
||||||
|
savedata.bots[pid].difficulty = READUINT8(save->p);
|
||||||
|
savedata.bots[pid].rival = (boolean)READUINT8(save->p);
|
||||||
|
savedata.bots[pid].score = READUINT32(save->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pid == 0xFE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void P_NetArchivePlayers(savebuffer_t *save)
|
static void P_NetArchivePlayers(savebuffer_t *save)
|
||||||
|
|
@ -1039,6 +1122,9 @@ static void P_NetUnArchiveRoundQueue(savebuffer_t *save)
|
||||||
|
|
||||||
roundqueue.position = READUINT8(save->p);
|
roundqueue.position = READUINT8(save->p);
|
||||||
roundqueue.size = READUINT8(save->p);
|
roundqueue.size = READUINT8(save->p);
|
||||||
|
if (roundqueue.size > ROUNDQUEUE_MAX)
|
||||||
|
I_Error("Bad $$$.sav at illegitimate roundqueue size");
|
||||||
|
|
||||||
roundqueue.roundnum = READUINT8(save->p);
|
roundqueue.roundnum = READUINT8(save->p);
|
||||||
|
|
||||||
for (i = 0; i < roundqueue.size; i++)
|
for (i = 0; i < roundqueue.size; i++)
|
||||||
|
|
@ -5257,55 +5343,230 @@ static void P_NetUnArchiveSpecials(savebuffer_t *save)
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// Misc
|
// Misc
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
static inline void P_ArchiveMisc(savebuffer_t *save, INT16 mapnum)
|
static inline void P_ArchiveMisc(savebuffer_t *save)
|
||||||
{
|
{
|
||||||
//lastmapsaved = mapnum;
|
|
||||||
lastmaploaded = mapnum;
|
|
||||||
|
|
||||||
if (gamecomplete)
|
|
||||||
mapnum |= 8192;
|
|
||||||
|
|
||||||
WRITEINT16(save->p, mapnum);
|
|
||||||
WRITEUINT16(save->p, emeralds+357);
|
|
||||||
WRITESTRINGN(save->p, timeattackfolder, sizeof(timeattackfolder));
|
WRITESTRINGN(save->p, timeattackfolder, sizeof(timeattackfolder));
|
||||||
|
|
||||||
|
// Grand Prix information
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, grandprixinfo.gamespeed);
|
||||||
|
WRITEUINT8(save->p, (UINT8)grandprixinfo.encore);
|
||||||
|
WRITEUINT8(save->p, (UINT8)grandprixinfo.masterbots);
|
||||||
|
|
||||||
|
WRITESTRINGL(save->p, grandprixinfo.cup->name, MAXCUPNAME);
|
||||||
|
|
||||||
|
// Round Queue information
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, roundqueue.position);
|
||||||
|
WRITEUINT8(save->p, roundqueue.size);
|
||||||
|
WRITEUINT8(save->p, roundqueue.roundnum);
|
||||||
|
|
||||||
|
UINT8 i;
|
||||||
|
for (i = 0; i < roundqueue.size; i++)
|
||||||
|
{
|
||||||
|
UINT16 mapnum = roundqueue.entries[i].mapnum;
|
||||||
|
UINT32 val = 0; // no good default, will all-but-guarantee bad save
|
||||||
|
if (mapnum < nummapheaders && mapheaderinfo[mapnum] != NULL)
|
||||||
|
val = mapheaderinfo[mapnum]->lumpnamehash;
|
||||||
|
|
||||||
|
WRITEUINT32(save->p, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rank information
|
||||||
|
|
||||||
|
{
|
||||||
|
WRITEUINT8(save->p, grandprixinfo.rank.players);
|
||||||
|
WRITEUINT8(save->p, grandprixinfo.rank.totalPlayers);
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, grandprixinfo.rank.position);
|
||||||
|
WRITEUINT8(save->p, grandprixinfo.rank.skin);
|
||||||
|
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.winPoints);
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.totalPoints);
|
||||||
|
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.laps);
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.totalLaps);
|
||||||
|
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.continuesUsed);
|
||||||
|
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.prisons);
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.totalPrisons);
|
||||||
|
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.rings);
|
||||||
|
WRITEUINT32(save->p, grandprixinfo.rank.totalRings);
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, (UINT8)grandprixinfo.rank.specialWon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marathon information
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, (marathonmode & ~MA_INIT));
|
||||||
|
|
||||||
|
UINT32 writetime = marathontime;
|
||||||
|
if (!(marathonmode & MA_INGAME))
|
||||||
|
writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map
|
||||||
|
WRITEUINT32(save->p, writetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void P_UnArchiveSPGame(savebuffer_t *save, INT16 mapoverride)
|
void P_GetBackupCupData(savebuffer_t *save)
|
||||||
{
|
{
|
||||||
char testname[sizeof(timeattackfolder)];
|
char testname[sizeof(timeattackfolder)];
|
||||||
|
|
||||||
gamemap = READINT16(save->p);
|
|
||||||
|
|
||||||
if (mapoverride != 0)
|
|
||||||
{
|
|
||||||
gamemap = mapoverride;
|
|
||||||
gamecomplete = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gamecomplete = 0;
|
|
||||||
|
|
||||||
// gamemap changed; we assume that its map header is always valid,
|
|
||||||
// so make it so
|
|
||||||
if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1])
|
|
||||||
I_Error("P_UnArchiveSPGame: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders);
|
|
||||||
|
|
||||||
//lastmapsaved = gamemap;
|
|
||||||
lastmaploaded = gamemap;
|
|
||||||
|
|
||||||
savedata.emeralds = READUINT16(save->p)-357;
|
|
||||||
|
|
||||||
READSTRINGN(save->p, testname, sizeof(testname));
|
READSTRINGN(save->p, testname, sizeof(testname));
|
||||||
|
|
||||||
if (strcmp(testname, timeattackfolder))
|
if (strcmp(testname, timeattackfolder))
|
||||||
{
|
{
|
||||||
if (modifiedgame)
|
cupsavedata.cup = NULL;
|
||||||
I_Error("Save game not for this modification.");
|
return;
|
||||||
else
|
|
||||||
I_Error("This save file is for a particular mod, it cannot be used with the regular game.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(playeringame, 0, sizeof(*playeringame));
|
// Grand Prix information
|
||||||
playeringame[consoleplayer] = true;
|
|
||||||
|
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)];
|
||||||
|
|
||||||
|
READSTRINGN(save->p, testname, sizeof(testname));
|
||||||
|
|
||||||
|
if (strcmp(testname, timeattackfolder))
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, "P_UnArchiveSPGame: Corrupt mod ID.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO do not work off grandprixinfo/roundqueue directly
|
||||||
|
// This is only strictly necessary if we ever re-add a save
|
||||||
|
// select screen or something, for live event backup only
|
||||||
|
// it's *fine* and, more importantly, shippable
|
||||||
|
|
||||||
|
memset(&grandprixinfo, 0, sizeof(grandprixinfo));
|
||||||
|
|
||||||
|
grandprixinfo.gp = true;
|
||||||
|
|
||||||
|
// Grand Prix information
|
||||||
|
|
||||||
|
grandprixinfo.gamespeed = READUINT8(save->p);
|
||||||
|
grandprixinfo.encore = (boolean)READUINT8(save->p);
|
||||||
|
grandprixinfo.masterbots = (boolean)READUINT8(save->p);
|
||||||
|
|
||||||
|
// Find the relevant cup.
|
||||||
|
char cupname[MAXCUPNAME];
|
||||||
|
READSTRINGL(save->p, cupname, sizeof(cupname));
|
||||||
|
UINT32 hash = quickncasehash(cupname, MAXCUPNAME);
|
||||||
|
|
||||||
|
for (grandprixinfo.cup = kartcupheaders; grandprixinfo.cup; grandprixinfo.cup = grandprixinfo.cup->next)
|
||||||
|
{
|
||||||
|
if (grandprixinfo.cup->namehash != hash)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(grandprixinfo.cup->name, cupname))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!grandprixinfo.cup)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, "P_UnArchiveSPGame: Cup \"%s\" is not currently loaded.\n", cupname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round Queue information
|
||||||
|
|
||||||
|
memset(&roundqueue, 0, sizeof(roundqueue));
|
||||||
|
|
||||||
|
G_GPCupIntoRoundQueue(grandprixinfo.cup, GT_RACE, grandprixinfo.encore);
|
||||||
|
|
||||||
|
roundqueue.position = READUINT8(save->p);
|
||||||
|
UINT8 size = READUINT8(save->p);
|
||||||
|
roundqueue.roundnum = READUINT8(save->p);
|
||||||
|
|
||||||
|
if (roundqueue.size != size)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, "P_UnArchiveSPGame: Cup \"%s\"'s level composition has changed between game launches (differs in level count).\n", cupname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundqueue.position == 0 || roundqueue.position > size)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, "P_UnArchiveSPGame: Position in the round queue is invalid.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 i;
|
||||||
|
for (i = 0; i < roundqueue.size; i++)
|
||||||
|
{
|
||||||
|
UINT32 val = READUINT32(save->p);
|
||||||
|
UINT16 mapnum = roundqueue.entries[i].mapnum;
|
||||||
|
|
||||||
|
if (mapnum < nummapheaders && mapheaderinfo[mapnum] != NULL)
|
||||||
|
{
|
||||||
|
if (mapheaderinfo[mapnum]->lumpnamehash == val)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CONS_Alert(CONS_ERROR, "P_UnArchiveSPGame: Cup \"%s\"'s level composition has changed between game launches (differs at level %u).\n", cupname, i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rank information
|
||||||
|
|
||||||
|
{
|
||||||
|
grandprixinfo.rank.players = READUINT8(save->p);
|
||||||
|
grandprixinfo.rank.totalPlayers = READUINT8(save->p);
|
||||||
|
|
||||||
|
grandprixinfo.rank.position = READUINT8(save->p);
|
||||||
|
grandprixinfo.rank.skin = READUINT8(save->p);
|
||||||
|
|
||||||
|
grandprixinfo.rank.winPoints = READUINT32(save->p);
|
||||||
|
grandprixinfo.rank.totalPoints = READUINT32(save->p);
|
||||||
|
|
||||||
|
grandprixinfo.rank.laps = READUINT32(save->p);
|
||||||
|
grandprixinfo.rank.totalLaps = READUINT32(save->p);
|
||||||
|
|
||||||
|
grandprixinfo.rank.continuesUsed = READUINT32(save->p);
|
||||||
|
|
||||||
|
grandprixinfo.rank.prisons = READUINT32(save->p);
|
||||||
|
grandprixinfo.rank.totalPrisons = READUINT32(save->p);
|
||||||
|
|
||||||
|
grandprixinfo.rank.rings = READUINT32(save->p);
|
||||||
|
grandprixinfo.rank.totalRings = READUINT32(save->p);
|
||||||
|
|
||||||
|
grandprixinfo.rank.specialWon = (boolean)READUINT8(save->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marathon information
|
||||||
|
|
||||||
|
marathonmode = READUINT8(save->p);
|
||||||
|
marathontime = READUINT32(save->p);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
|
static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
|
||||||
|
|
@ -5718,9 +5979,9 @@ static inline void P_NetUnArchiveRNG(savebuffer_t *save)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_SaveGame(savebuffer_t *save, INT16 mapnum)
|
void P_SaveGame(savebuffer_t *save)
|
||||||
{
|
{
|
||||||
P_ArchiveMisc(save, mapnum);
|
P_ArchiveMisc(save);
|
||||||
P_ArchivePlayer(save);
|
P_ArchivePlayer(save);
|
||||||
P_ArchiveLuabanksAndConsistency(save);
|
P_ArchiveLuabanksAndConsistency(save);
|
||||||
}
|
}
|
||||||
|
|
@ -5775,7 +6036,7 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending)
|
||||||
P_ArchiveLuabanksAndConsistency(save);
|
P_ArchiveLuabanksAndConsistency(save);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean P_LoadGame(savebuffer_t *save, INT16 mapoverride)
|
boolean P_LoadGame(savebuffer_t *save)
|
||||||
{
|
{
|
||||||
if (gamestate == GS_INTERMISSION)
|
if (gamestate == GS_INTERMISSION)
|
||||||
Y_EndIntermission();
|
Y_EndIntermission();
|
||||||
|
|
@ -5783,17 +6044,24 @@ boolean P_LoadGame(savebuffer_t *save, INT16 mapoverride)
|
||||||
Y_EndVote();
|
Y_EndVote();
|
||||||
G_SetGamestate(GS_NULL); // should be changed in P_UnArchiveMisc
|
G_SetGamestate(GS_NULL); // should be changed in P_UnArchiveMisc
|
||||||
|
|
||||||
P_UnArchiveSPGame(save, mapoverride);
|
if (!P_UnArchiveSPGame(save))
|
||||||
P_UnArchivePlayer(save);
|
goto badloadgame;
|
||||||
|
if (!P_UnArchivePlayer(save))
|
||||||
|
goto badloadgame;
|
||||||
|
|
||||||
if (!P_UnArchiveLuabanksAndConsistency(save))
|
if (!P_UnArchiveLuabanksAndConsistency(save))
|
||||||
return false;
|
goto badloadgame;
|
||||||
|
|
||||||
// Only do this after confirming savegame is ok
|
|
||||||
G_DeferedInitNew(false, gamemap, savedata.skin, 0, true);
|
|
||||||
COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
badloadgame:
|
||||||
|
// these are the side effects of P_UnarchiveSPGame
|
||||||
|
savedata.lives = 0;
|
||||||
|
roundqueue.size = 0;
|
||||||
|
grandprixinfo.gp = false;
|
||||||
|
marathonmode = 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
|
boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
|
||||||
|
|
|
||||||
|
|
@ -31,24 +31,51 @@ extern "C" {
|
||||||
// Persistent storage/archiving.
|
// Persistent storage/archiving.
|
||||||
// These are the load / save game routines.
|
// These are the load / save game routines.
|
||||||
|
|
||||||
void P_SaveGame(savebuffer_t *save, INT16 mapnum);
|
// 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);
|
void P_SaveNetGame(savebuffer_t *save, boolean resending);
|
||||||
boolean P_LoadGame(savebuffer_t *save, INT16 mapoverride);
|
|
||||||
boolean P_LoadNetGame(savebuffer_t *save, boolean reloading);
|
boolean P_LoadNetGame(savebuffer_t *save, boolean reloading);
|
||||||
|
|
||||||
mobj_t *P_FindNewPosition(UINT32 oldposition);
|
mobj_t *P_FindNewPosition(UINT32 oldposition);
|
||||||
|
|
||||||
|
struct savedata_bot_s
|
||||||
|
{
|
||||||
|
boolean valid;
|
||||||
|
UINT8 skin;
|
||||||
|
UINT8 difficulty;
|
||||||
|
boolean rival;
|
||||||
|
UINT32 score;
|
||||||
|
};
|
||||||
|
|
||||||
struct savedata_t
|
struct savedata_t
|
||||||
{
|
{
|
||||||
|
UINT32 score;
|
||||||
|
SINT8 lives;
|
||||||
|
UINT16 totalring;
|
||||||
|
|
||||||
UINT8 skin;
|
UINT8 skin;
|
||||||
INT32 score;
|
UINT16 skincolor;
|
||||||
INT32 lives;
|
INT32 followerskin;
|
||||||
UINT16 emeralds;
|
UINT16 followercolor;
|
||||||
UINT8 numgameovers;
|
|
||||||
|
struct savedata_bot_s bots[MAXPLAYERS];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern savedata_t savedata;
|
extern savedata_t savedata;
|
||||||
|
|
||||||
|
struct savedata_cup_t
|
||||||
|
{
|
||||||
|
cupheader_t *cup;
|
||||||
|
UINT8 difficulty;
|
||||||
|
boolean encore;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern savedata_cup_t cupsavedata;
|
||||||
|
|
||||||
struct savebuffer_t
|
struct savebuffer_t
|
||||||
{
|
{
|
||||||
UINT8 *buffer;
|
UINT8 *buffer;
|
||||||
|
|
|
||||||
|
|
@ -7734,7 +7734,12 @@ static void P_InitGametype(void)
|
||||||
|
|
||||||
if (grandprixinfo.gp == true)
|
if (grandprixinfo.gp == true)
|
||||||
{
|
{
|
||||||
if (grandprixinfo.initalize == true)
|
if (savedata.lives > 0)
|
||||||
|
{
|
||||||
|
K_LoadGrandPrixSaveGame();
|
||||||
|
savedata.lives = 0;
|
||||||
|
}
|
||||||
|
else if (grandprixinfo.initalize == true)
|
||||||
{
|
{
|
||||||
K_InitGrandPrixRank(&grandprixinfo.rank);
|
K_InitGrandPrixRank(&grandprixinfo.rank);
|
||||||
K_InitGrandPrixBots();
|
K_InitGrandPrixBots();
|
||||||
|
|
@ -8152,15 +8157,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
||||||
R_InitMobjInterpolators();
|
R_InitMobjInterpolators();
|
||||||
P_InitCachedActions();
|
P_InitCachedActions();
|
||||||
|
|
||||||
if (!fromnetsave && savedata.lives > 0)
|
|
||||||
{
|
|
||||||
numgameovers = savedata.numgameovers;
|
|
||||||
players[consoleplayer].lives = savedata.lives;
|
|
||||||
players[consoleplayer].score = savedata.score;
|
|
||||||
emeralds = savedata.emeralds;
|
|
||||||
savedata.lives = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// internal game map
|
// internal game map
|
||||||
maplumpname = mapheaderinfo[gamemap-1]->lumpname;
|
maplumpname = mapheaderinfo[gamemap-1]->lumpname;
|
||||||
lastloadedmaplumpnum = mapheaderinfo[gamemap-1]->lumpnum;
|
lastloadedmaplumpnum = mapheaderinfo[gamemap-1]->lumpnum;
|
||||||
|
|
@ -8311,22 +8307,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
||||||
|
|
||||||
P_MapEnd(); // tm.thing is no longer needed from this point onwards
|
P_MapEnd(); // tm.thing is no longer needed from this point onwards
|
||||||
|
|
||||||
// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...
|
|
||||||
if (gamestate == GS_LEVEL)
|
|
||||||
{
|
|
||||||
if (!lastmaploaded) // Start a new game?
|
|
||||||
{
|
|
||||||
// I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020
|
|
||||||
if (!(ultimatemode || netgame || multiplayer || demo.playback || demo.recording || metalrecording || modeattacking || marathonmode)
|
|
||||||
&& !usedCheats && cursaveslot > 0)
|
|
||||||
{
|
|
||||||
G_SaveGame((UINT32)cursaveslot, gamemap);
|
|
||||||
}
|
|
||||||
// If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted.
|
|
||||||
}
|
|
||||||
lastmaploaded = gamemap; // HAS to be set after saving!!
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fromnetsave)
|
if (!fromnetsave)
|
||||||
{
|
{
|
||||||
INT32 buf = gametic % BACKUPTICS;
|
INT32 buf = gametic % BACKUPTICS;
|
||||||
|
|
@ -8382,6 +8362,8 @@ void P_PostLoadLevel(void)
|
||||||
|
|
||||||
P_RunCachedActions();
|
P_RunCachedActions();
|
||||||
|
|
||||||
|
G_HandleSaveLevel(gamestate == GS_CEREMONY);
|
||||||
|
|
||||||
if (marathonmode & MA_INGAME)
|
if (marathonmode & MA_INGAME)
|
||||||
{
|
{
|
||||||
marathonmode &= ~MA_INIT;
|
marathonmode &= ~MA_INIT;
|
||||||
|
|
|
||||||
|
|
@ -297,6 +297,7 @@ TYPEDEF (polyfadedata_t);
|
||||||
|
|
||||||
// p_saveg.h
|
// p_saveg.h
|
||||||
TYPEDEF (savedata_t);
|
TYPEDEF (savedata_t);
|
||||||
|
TYPEDEF (savedata_cup_t);
|
||||||
TYPEDEF (savebuffer_t);
|
TYPEDEF (savebuffer_t);
|
||||||
|
|
||||||
// p_setup.h
|
// p_setup.h
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue