diff --git a/src/g_game.c b/src/g_game.c index 32fd13643..f1a0ffd3f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4626,6 +4626,9 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) UINT8 *end_p = savebuffer + length; UINT8 *lives_p; SINT8 pllives; +#ifdef NEWSKINSAVES + INT16 backwardsCompat = 0; +#endif save_p = savebuffer; // Version check @@ -4644,9 +4647,23 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) // P_UnArchivePlayer() CHECKPOS - (void)READUINT16(save_p); +#ifdef NEWSKINSAVES + backwardsCompat = READUINT16(save_p); CHECKPOS + if (backwardsCompat == NEWSKINSAVES) // New save, read skin names +#endif + { + char ourSkinName[SKINNAMESIZE+1]; + char botSkinName[SKINNAMESIZE+1]; + + READSTRINGN(save_p, ourSkinName, SKINNAMESIZE); + CHECKPOS + + READSTRINGN(save_p, botSkinName, SKINNAMESIZE); + CHECKPOS + } + WRITEUINT8(save_p, numgameovers); CHECKPOS diff --git a/src/m_menu.c b/src/m_menu.c index d2daecc6b..b19479797 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -62,6 +62,8 @@ #include "i_joy.h" // for joystick menu controls +#include "p_saveg.h" // Only for NEWSKINSAVES + // Condition Sets #include "m_cond.h" @@ -8681,7 +8683,7 @@ static void M_LoadSelect(INT32 choice) #define VERSIONSIZE 16 #define BADSAVE { savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; } -#define CHECKPOS if (save_p >= end_p) BADSAVE +#define CHECKPOS if (sav_p >= end_p) BADSAVE // Reads the save file to list lives, level, player, etc. // Tails 05-29-2003 static void M_ReadSavegameInfo(UINT32 slot) @@ -8690,10 +8692,13 @@ static void M_ReadSavegameInfo(UINT32 slot) char savename[255]; UINT8 *savebuffer; UINT8 *end_p; // buffer end point, don't read past here - UINT8 *save_p; + UINT8 *sav_p; INT32 fake; // Dummy variable char temp[sizeof(timeattackfolder)]; char vcheck[VERSIONSIZE]; +#ifdef NEWSKINSAVES + INT16 backwardsCompat = 0; +#endif sprintf(savename, savegamename, slot); @@ -8709,19 +8714,19 @@ static void M_ReadSavegameInfo(UINT32 slot) end_p = savebuffer + length; // skip the description field - save_p = savebuffer; + sav_p = savebuffer; // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, "version %d", VERSION); - if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE - save_p += VERSIONSIZE; + if (strcmp((const char *)sav_p, (const char *)vcheck)) BADSAVE + sav_p += VERSIONSIZE; // dearchive all the modifications // P_UnArchiveMisc() CHECKPOS - fake = READINT16(save_p); + fake = READINT16(sav_p); if (((fake-1) & 8191) >= NUMMAPS) BADSAVE @@ -8738,54 +8743,84 @@ static void M_ReadSavegameInfo(UINT32 slot) savegameinfo[slot].gamemap = fake; CHECKPOS - savegameinfo[slot].numemeralds = READUINT16(save_p)-357; // emeralds + savegameinfo[slot].numemeralds = READUINT16(sav_p)-357; // emeralds CHECKPOS - READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to + READSTRINGN(sav_p, temp, sizeof(temp)); // mod it belongs to if (strcmp(temp, timeattackfolder)) BADSAVE // P_UnArchivePlayer() +#ifdef NEWSKINSAVES CHECKPOS - fake = READUINT16(save_p); - savegameinfo[slot].skinnum = fake & ((1<<5) - 1); - if (savegameinfo[slot].skinnum >= numskins - || !R_SkinUsable(-1, savegameinfo[slot].skinnum)) - BADSAVE - savegameinfo[slot].botskin = fake >> 5; - if (savegameinfo[slot].botskin-1 >= numskins - || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) - BADSAVE + backwardsCompat = READUINT16(sav_p); + + if (backwardsCompat != NEWSKINSAVES) + { + // Backwards compat + savegameinfo[slot].skinnum = backwardsCompat & ((1<<5) - 1); + + if (savegameinfo[slot].skinnum >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].skinnum)) + BADSAVE + + savegameinfo[slot].botskin = backwardsCompat >> 5; + if (savegameinfo[slot].botskin-1 >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) + BADSAVE + } + else +#endif + { + char ourSkinName[SKINNAMESIZE+1]; + char botSkinName[SKINNAMESIZE+1]; + + CHECKPOS + READSTRINGN(sav_p, ourSkinName, SKINNAMESIZE); + savegameinfo[slot].skinnum = R_SkinAvailable(ourSkinName); + + if (savegameinfo[slot].skinnum >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].skinnum)) + BADSAVE + + CHECKPOS + READSTRINGN(sav_p, botSkinName, SKINNAMESIZE); + savegameinfo[slot].botskin = (R_SkinAvailable(botSkinName) + 1); + + if (savegameinfo[slot].botskin-1 >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) + BADSAVE + } CHECKPOS - savegameinfo[slot].numgameovers = READUINT8(save_p); // numgameovers + savegameinfo[slot].numgameovers = READUINT8(sav_p); // numgameovers CHECKPOS - savegameinfo[slot].lives = READSINT8(save_p); // lives + savegameinfo[slot].lives = READSINT8(sav_p); // lives CHECKPOS - savegameinfo[slot].continuescore = READINT32(save_p); // score + savegameinfo[slot].continuescore = READINT32(sav_p); // score CHECKPOS - fake = READINT32(save_p); // continues + fake = READINT32(sav_p); // continues if (useContinues) savegameinfo[slot].continuescore = fake; // File end marker check CHECKPOS - switch (READUINT8(save_p)) + switch (READUINT8(sav_p)) { case 0xb7: { UINT8 i, banksinuse; CHECKPOS - banksinuse = READUINT8(save_p); + banksinuse = READUINT8(sav_p); CHECKPOS if (banksinuse > NUM_LUABANKS) BADSAVE for (i = 0; i < banksinuse; i++) { - (void)READINT32(save_p); + (void)READINT32(sav_p); CHECKPOS } - if (READUINT8(save_p) != 0x1d) + if (READUINT8(sav_p) != 0x1d) BADSAVE } case 0x1d: diff --git a/src/p_saveg.c b/src/p_saveg.c index c2434cd3a..770c641b9 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -64,12 +64,29 @@ typedef enum static inline void P_ArchivePlayer(void) { const player_t *player = &players[consoleplayer]; - INT16 skininfo = player->skin + (botskin<<5); 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); +#ifdef NEWSKINSAVES + // Write a specific value into the old skininfo location. + // If we read something other than this, it's an older save file that used skin numbers. + WRITEUINT16(save_p, NEWSKINSAVES); +#endif + + // Write skin names, so that loading skins in different orders + // doesn't change who the save file is for! + WRITESTRINGN(save_p, skins[player->skin].name, SKINNAMESIZE); + + if (botskin != 0) + { + WRITESTRINGN(save_p, skins[botskin-1].name, SKINNAMESIZE); + } + else + { + WRITESTRINGN(save_p, "\0", SKINNAMESIZE); + } + WRITEUINT8(save_p, numgameovers); WRITESINT8(save_p, pllives); WRITEUINT32(save_p, player->score); @@ -78,9 +95,27 @@ static inline void P_ArchivePlayer(void) static inline void P_UnArchivePlayer(void) { - INT16 skininfo = READUINT16(save_p); - savedata.skin = skininfo & ((1<<5) - 1); - savedata.botskin = skininfo >> 5; +#ifdef NEWSKINSAVES + INT16 backwardsCompat = READUINT16(save_p); + + if (backwardsCompat != NEWSKINSAVES) + { + // This is an older save file, which used direct skin numbers. + savedata.skin = backwardsCompat & ((1<<5) - 1); + savedata.botskin = backwardsCompat >> 5; + } + else +#endif + { + char ourSkinName[SKINNAMESIZE+1]; + char botSkinName[SKINNAMESIZE+1]; + + READSTRINGN(save_p, ourSkinName, SKINNAMESIZE); + savedata.skin = R_SkinAvailable(ourSkinName); + + READSTRINGN(save_p, botSkinName, SKINNAMESIZE); + savedata.botskin = R_SkinAvailable(botSkinName) + 1; + } savedata.numgameovers = READUINT8(save_p); savedata.lives = READSINT8(save_p); diff --git a/src/p_saveg.h b/src/p_saveg.h index ed9297a4d..a909282fe 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -18,6 +18,8 @@ #pragma interface #endif +#define NEWSKINSAVES (INT16_MAX) // Purely for backwards compatibility, remove this for 2.3 + // Persistent storage/archiving. // These are the load / save game routines.