diff --git a/src/g_game.c b/src/g_game.c index b239800447972d1bf9e8931ddf6c5796e397824f..47e670bfecebef38e74d96c20993be11a9f6f5ef 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4309,6 +4309,12 @@ void G_LoadGameData(gamedata_t *data) // Stop saving, until we successfully load it again. data->loaded = false; + // Backwards compat stuff + INT32 max_emblems = MAXEMBLEMS; + INT32 max_extraemblems = MAXEXTRAEMBLEMS; + INT32 max_unlockables = MAXUNLOCKABLES; + INT32 max_conditionsets = MAXCONDITIONSETS; + // Clear things so previously read gamedata doesn't transfer // to new gamedata G_ClearRecords(data); // main and nights records @@ -4325,7 +4331,7 @@ void G_LoadGameData(gamedata_t *data) { // Don't load, but do save. (essentially, reset) data->loaded = true; - return; + return; } length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer); @@ -4355,6 +4361,14 @@ void G_LoadGameData(gamedata_t *data) I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); } +#ifdef COMPAT_GAMEDATA_ID // Account for lower MAXUNLOCKABLES and MAXEXTRAEMBLEMS from older versions + if (versionID == COMPAT_GAMEDATA_ID) + { + max_extraemblems = 16; + max_unlockables = 32; + } +#endif + data->totalplaytime = READUINT32(save_p); #ifdef COMPAT_GAMEDATA_ID @@ -4393,31 +4407,31 @@ void G_LoadGameData(gamedata_t *data) goto datacorrupt; // To save space, use one bit per collected/achieved/unlocked flag - for (i = 0; i < MAXEMBLEMS;) + for (i = 0; i < max_emblems;) { rtemp = READUINT8(save_p); - for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) + for (j = 0; j < 8 && j+i < max_emblems; ++j) data->collected[j+i] = ((rtemp >> j) & 1); i += j; } - for (i = 0; i < MAXEXTRAEMBLEMS;) + for (i = 0; i < max_extraemblems;) { rtemp = READUINT8(save_p); - for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) + for (j = 0; j < 8 && j+i < max_extraemblems; ++j) data->extraCollected[j+i] = ((rtemp >> j) & 1); i += j; } - for (i = 0; i < MAXUNLOCKABLES;) + for (i = 0; i < max_unlockables;) { rtemp = READUINT8(save_p); - for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) + for (j = 0; j < 8 && j+i < max_unlockables; ++j) data->unlocked[j+i] = ((rtemp >> j) & 1); i += j; } - for (i = 0; i < MAXCONDITIONSETS;) + for (i = 0; i < max_conditionsets;) { rtemp = READUINT8(save_p); - for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) + for (j = 0; j < 8 && j+i < max_conditionsets; ++j) data->achieved[j+i] = ((rtemp >> j) & 1); i += j; } diff --git a/src/m_cond.h b/src/m_cond.h index 6a3da79ece7091c7ef0f68981355e6d0a691bb79..95c3e1ebeb0345fe102acf2ab4af4f1331031178 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -139,8 +139,8 @@ typedef struct // you seriously need to get a life. #define MAXCONDITIONSETS 128 #define MAXEMBLEMS 512 -#define MAXEXTRAEMBLEMS 16 -#define MAXUNLOCKABLES 32 +#define MAXEXTRAEMBLEMS 48 +#define MAXUNLOCKABLES 80 /** Time attack information, currently a very small structure. */ diff --git a/src/m_menu.c b/src/m_menu.c index cf61e7fb1a50909fcdefc956fff0733ea204b904..1dc0037d700027b61c8d54065e2aec9e462fb8b2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -694,42 +694,10 @@ static menuitem_t SR_PandorasBox[] = }; // Sky Room Custom Unlocks -static menuitem_t SR_MainMenu[] = +static menuitem_t SR_MainMenu[MAXUNLOCKABLES+1] = { {IT_STRING|IT_SUBMENU,NULL, "Extras Checklist", &SR_UnlockChecklistDef, 0}, - {IT_DISABLED, NULL, "", NULL, 0}, // Custom1 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom2 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom3 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom4 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom5 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom6 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom7 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom8 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom9 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom10 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom11 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom12 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom13 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom14 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom15 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom16 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom17 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom18 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom19 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom20 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom21 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom22 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom23 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom24 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom25 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom26 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom27 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom28 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom29 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom30 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom31 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom32 - + // The remaining (MAXUNLOCKABLES) items are now initialized in M_SecretsMenu }; static menuitem_t SR_LevelSelectMenu[] = @@ -8130,14 +8098,15 @@ static void M_SecretsMenu(INT32 choice) (void)choice; - // Clear all before starting - for (i = 1; i < MAXUNLOCKABLES+1; ++i) - SR_MainMenu[i].status = IT_DISABLED; + // Initialize array with placeholder entries + menuitem_t placeholder = {IT_DISABLED, NULL, "", NULL, 0}; + for (i = 1; i <= MAXUNLOCKABLES; ++i) + SR_MainMenu[i] = placeholder; memset(skyRoomMenuTranslations, 0, sizeof(skyRoomMenuTranslations)); memset(done, 0, sizeof(done)); - for (i = 1; i < MAXUNLOCKABLES+1; ++i) + for (i = 1; i <= MAXUNLOCKABLES; ++i) { curheight = UINT16_MAX; ul = -1; diff --git a/src/p_spec.c b/src/p_spec.c index 9195ef01995315cbd830687804cd91443f5959a3..b9650bfeb583e61403c43e4dd57bfc8978eed4ae 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1808,7 +1808,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller { // An unlockable itself must be unlocked! INT32 unlockid = triggerline->args[1]; - if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count + if (unlockid <= 0 || unlockid > MAXUNLOCKABLES) // limited by unlockable count { CONS_Debug(DBG_GAMELOGIC, "Unlockable check (sidedef %hu): bad unlockable ID %d\n", triggerline->sidenum[0], unlockid); return false; diff --git a/src/r_skins.c b/src/r_skins.c index db3227307244301357aaa5759084b240f90fcc7e..9443ad49b03d492e6856f4125881def0b1f463e4 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -190,7 +190,8 @@ UINT32 R_GetSkinAvailabilities(void) // This crash is impossible to trigger as is, // but it could happen if MAXUNLOCKABLES is ever made higher than 32, // and someone makes a mod that has 33+ unlockable characters. :V - I_Error("Too many unlockable characters\n"); + // 2022/03/15: MAXUNLOCKABLES is now higher than 32 + I_Error("Too many unlockable characters! (maximum is 32)\n"); return 0; }