diff --git a/src/g_game.c b/src/g_game.c index d8ddd00ce..553a905cb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4974,6 +4974,8 @@ void G_LoadGameData(void) gamedata->challengegrid[i] = READUINT16(save.p); } } + + M_SanitiseChallengeGrid(); } else { diff --git a/src/m_cond.c b/src/m_cond.c index 5edbbeb4c..fc24c3986 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -312,6 +312,88 @@ quickcheckagain: } } +void M_SanitiseChallengeGrid(void) +{ + UINT8 seen[MAXUNLOCKABLES]; + UINT16 empty[MAXUNLOCKABLES + (CHALLENGEGRIDHEIGHT-1)]; + UINT16 i, j, numempty = 0; + + if (gamedata->challengegrid == NULL) + return; + + memset(seen, 0, sizeof(seen)); + + // Go through all spots to identify duplicates and absences. + for (j = 0; j < gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT; j++) + { + i = gamedata->challengegrid[j]; + + if (i >= MAXUNLOCKABLES || !unlockables[i].conditionset) + { + empty[numempty++] = j; + continue; + } + + if (seen[i] != 5) // Arbitrary cap greater than 4 + { + seen[i]++; + + if (seen[i] == 1 || unlockables[i].majorunlock) + { + continue; + } + } + + empty[numempty++] = j; + } + + // Go through unlockables to identify if any haven't been seen. + for (i = 0; i < MAXUNLOCKABLES; ++i) + { + if (!unlockables[i].conditionset) + { + continue; + } + + if (unlockables[i].majorunlock && seen[i] != 4) + { + // Probably not enough spots to retrofit. + goto badgrid; + } + + if (seen[i] != 0) + { + // Present on the challenge grid. + continue; + } + + if (numempty != 0) + { + // Small ones can be slotted in easy. + j = empty[--numempty]; + gamedata->challengegrid[j] = i; + } + + // Nothing we can do to recover. + goto badgrid; + } + + // Fill the remaining spots with empties. + while (numempty != 0) + { + j = empty[--numempty]; + gamedata->challengegrid[j] = MAXUNLOCKABLES; + } + + return; + +badgrid: + // Just remove everything and let it get regenerated. + Z_Free(gamedata->challengegrid); + gamedata->challengegrid = NULL; + gamedata->challengegridwidth = 0; +} + void M_UpdateChallengeGridExtraData(challengegridextradata_t *extradata) { UINT16 i, j, num, id, tempid, work; diff --git a/src/m_cond.h b/src/m_cond.h index fb96a14b7..2dfb1a221 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -302,6 +302,7 @@ void M_NewGameDataStruct(void); // Challenges menu stuff void M_PopulateChallengeGrid(void); +void M_SanitiseChallengeGrid(void); struct challengegridextradata_t {