From c9817b957a604c6b4a0d71dcf4faa9cdaaffbe5f Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 26 Jun 2023 22:32:47 +0100 Subject: [PATCH] New unlockable type for watching the Credits from start to finish Also makes gamedata save/load a little more forward compatible longterm by making a UINT32 bitfield for various once-event flags, with increased minor version --- src/deh_soc.c | 1 + src/f_finale.c | 5 +++++ src/g_game.c | 49 ++++++++++++++++++++++++++++++++++++++++--------- src/m_cond.c | 5 +++++ src/m_cond.h | 2 ++ 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 860d6ad0d..6bda19b5c 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2583,6 +2583,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) } } else if ((offset=0) || fastcmp(params[0], "ADDON") + || (++offset && fastcmp(params[0], "CREDITS")) || (++offset && fastcmp(params[0], "REPLAY")) || (++offset && fastcmp(params[0], "CRASH"))) { diff --git a/src/f_finale.c b/src/f_finale.c index 48b95ad43..98d0c15eb 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -808,6 +808,11 @@ void F_CreditTicker(void) { timetonext = 5*TICRATE+1; finalecount = 5*TICRATE; + + // You watched all the credits? What a trooper! + gamedata->everfinishedcredits = true; + if (M_UpdateUnlockablesAndExtraEmblems(true, true)) + G_SaveGameData(); } if (timetonext) diff --git a/src/g_game.c b/src/g_game.c index b1f036edd..6f6e3bc79 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4725,7 +4725,15 @@ void G_LoadGameSettings(void) } #define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual -#define GD_VERSIONMINOR 3 // Change every format update +#define GD_VERSIONMINOR 4 // Change every format update + +typedef enum +{ + GDEVER_ADDON = 1, + GDEVER_CREDITS = 1<<1, + GDEVER_REPLAY = 1<<2, + GDEVER_SPECIAL = 1<<3, +} gdeverdone_t; static const char *G_GameDataFolder(void) { @@ -4849,9 +4857,21 @@ void G_LoadGameData(void) gamedata->chaokeys = READUINT16(save.p); - gamedata->everloadedaddon = (boolean)READUINT8(save.p); - gamedata->eversavedreplay = (boolean)READUINT8(save.p); - gamedata->everseenspecial = (boolean)READUINT8(save.p); + if (versionMinor >= 4) + { + UINT32 everflags = READUINT32(save.p); + + gamedata->everloadedaddon = !!(everflags & GDEVER_ADDON); + gamedata->everfinishedcredits = !!(everflags & GDEVER_CREDITS); + gamedata->eversavedreplay = !!(everflags & GDEVER_REPLAY); + gamedata->everseenspecial = !!(everflags & GDEVER_SPECIAL); + } + else + { + gamedata->everloadedaddon = (boolean)READUINT8(save.p); + gamedata->eversavedreplay = (boolean)READUINT8(save.p); + gamedata->everseenspecial = (boolean)READUINT8(save.p); + } } else { @@ -5278,7 +5298,7 @@ void G_SaveGameData(void) 4+4+ (4*GDGT_MAX)+ 4+1+2+2+ - 1+1+1+ + 4+ 4+ (MAXEMBLEMS+(MAXUNLOCKABLES*2)+MAXCONDITIONSETS)+ 4+2); @@ -5415,11 +5435,22 @@ void G_SaveGameData(void) WRITEUINT16(save.p, gamedata->keyspending); // 2 WRITEUINT16(save.p, gamedata->chaokeys); // 2 - WRITEUINT8(save.p, gamedata->everloadedaddon); // 1 - WRITEUINT8(save.p, gamedata->eversavedreplay); // 1 - WRITEUINT8(save.p, gamedata->everseenspecial); // 1 + { + UINT32 everflags = 0; - WRITEUINT32(save.p, quickncasehash(timeattackfolder, 64)); + if (gamedata->everloadedaddon) + everflags |= GDEVER_ADDON; + if (gamedata->everfinishedcredits) + everflags |= GDEVER_CREDITS; + if (gamedata->eversavedreplay) + everflags |= GDEVER_REPLAY; + if (gamedata->everseenspecial) + everflags |= GDEVER_SPECIAL; + + WRITEUINT32(save.p, everflags); // 4 + } + + WRITEUINT32(save.p, quickncasehash(timeattackfolder, 64)); // 4 // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) // MAXEMBLEMS * 1; diff --git a/src/m_cond.c b/src/m_cond.c index a152204eb..2e69a211f 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -610,6 +610,7 @@ void M_ClearStats(void) gamedata->timesBeaten = 0; gamedata->everloadedaddon = false; + gamedata->everfinishedcredits = false; gamedata->eversavedreplay = false; gamedata->everseenspecial = false; gamedata->evercrashed = false; @@ -854,6 +855,8 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) case UC_ADDON: return ((gamedata->everloadedaddon == true) && M_SecretUnlocked(SECRET_ADDONS, true)); + case UC_CREDITS: + return (gamedata->everfinishedcredits == true); case UC_REPLAY: return (gamedata->eversavedreplay == true); case UC_CRASH: @@ -1308,6 +1311,8 @@ static const char *M_GetConditionString(condition_t *cn) if (!M_SecretUnlocked(SECRET_ADDONS, true)) return NULL; return "load a custom addon into \"Dr. Robotnik's Ring Racers\""; + case UC_CREDITS: + return "watch the developer credits all the way from start to finish"; case UC_REPLAY: return "save a replay after finishing a round"; case UC_CRASH: diff --git a/src/m_cond.h b/src/m_cond.h index 83207aad0..e3975a957 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -52,6 +52,7 @@ typedef enum UC_CONDITIONSET, // CONDITIONSET [condition set number] UC_ADDON, // Ever loaded a custom file? + UC_CREDITS, // Finish watching the credits UC_REPLAY, // Save a replay UC_CRASH, // Hee ho ! @@ -287,6 +288,7 @@ struct gamedata_t // SPECIFIC SPECIAL EVENTS boolean everloadedaddon; + boolean everfinishedcredits; boolean eversavedreplay; boolean everseenspecial; boolean evercrashed;