Fix level/cup unlocks

- M_MapLocked
    - If a level has a cup, will return true if that cup is locked
    - will return always false in marathon mode (not yet accessible, that'll be another branch's work, but thinking ahead)
- Getting rid of a bunch of index fudging caused by SINT8 rather than UINT8 - we can use MAXUNLOCKABLES as the special invalid value
This commit is contained in:
toaster 2022-12-03 17:29:14 +00:00
parent f25907d7bc
commit a33d6d9235
8 changed files with 32 additions and 16 deletions

View file

@ -1183,8 +1183,10 @@ void readlevelheader(MYFILE *f, char * name)
mapheaderinfo[num]->numlaps = (UINT8)i;
else if (fastcmp(word, "UNLOCKABLE"))
{
if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something
mapheaderinfo[num]->unlockrequired = (SINT8)i - 1;
if (i == 0 || word2[0] == 'F' || word2[0] == 'N')
mapheaderinfo[num]->unlockrequired = MAXUNLOCKABLES;
else if (i > 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something
mapheaderinfo[num]->unlockrequired = (UINT8)(i-1);
else
deh_warning("Level header %d: invalid unlockable number %d", num, i);
}
@ -3087,8 +3089,10 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
}
else if (fastcmp(word, "UNLOCKABLE"))
{
if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something
cup->unlockrequired = (SINT8)i - 1;
if (i == 0 || word2[0] == 'F' || word2[0] == 'N')
cup->unlockrequired = MAXUNLOCKABLES;
else if (i > 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something
cup->unlockrequired = (UINT8)(i-1);
else
deh_warning("%s Cup: invalid unlockable number %d", cup->name, i);
}

View file

@ -486,7 +486,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
{
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
cup->unlockrequired = -1;
cup->unlockrequired = MAXUNLOCKABLES;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
if (prev != NULL)

View file

@ -355,7 +355,7 @@ typedef struct cupheader_s
UINT8 numlevels; ///< Number of levels defined in levellist
UINT8 numbonus; ///< Number of bonus stages defined
UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald)
SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required.
UINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required.
struct cupheader_s *next; ///< Next cup in linked list
} cupheader_t;
@ -391,7 +391,7 @@ typedef struct
// Selection metadata
char keywords[33]; ///< Keywords separated by space to search for. 32 characters.
SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no.
UINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no.
UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in?
UINT16 menuflags; ///< LF2_flags: options that affect record attack menus

View file

@ -3870,7 +3870,7 @@ static void G_GetNextMap(void)
while (cup)
{
// Not unlocked? Grab the next result afterwards
if (!marathonmode && cup->unlockrequired != -1 && !gamedata->unlocked[cup->unlockrequired])
if (!marathonmode && cup->unlockrequired < MAXUNLOCKABLES && !gamedata->unlocked[cup->unlockrequired])
{
cup = cup->next;
gettingresult = 1;

View file

@ -1911,7 +1911,7 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup)
V_DrawFill(0, y, BASEVIDWIDTH, 54, 31);
if (cup && (cup->unlockrequired == -1 || gamedata->unlocked[cup->unlockrequired]))
if (cup && (cup->unlockrequired >= MAXUNLOCKABLES || gamedata->unlocked[cup->unlockrequired]))
{
i = (cupgrid.previewanim / 82) % cup->numlevels;
while (x < BASEVIDWIDTH + pad)
@ -1949,7 +1949,7 @@ static void M_DrawCupTitle(INT16 y, cupheader_t *cup)
if (cup)
{
boolean unlocked = (cup->unlockrequired == -1 || gamedata->unlocked[cup->unlockrequired]);
boolean unlocked = (cup->unlockrequired >= MAXUNLOCKABLES || gamedata->unlocked[cup->unlockrequired]);
UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GREY, GTC_MENUCACHE);
patch_t *icon = W_CachePatchName(cup->icon, PU_CACHE);
const char *str = (unlocked ? va("%s Cup", cup->name) : "???");
@ -2017,7 +2017,7 @@ void M_DrawCupSelect(void)
V_DrawScaledPatch(x, y, 0, patch);
if (iconcup->unlockrequired != -1 && !gamedata->unlocked[iconcup->unlockrequired])
if (iconcup->unlockrequired < MAXUNLOCKABLES && !gamedata->unlocked[iconcup->unlockrequired])
{
patch_t *st = W_CachePatchName(va("ICONST0%d", (cupgrid.previewanim % 4) + 1), PU_CACHE);
V_DrawScaledPatch(x + 8, y + icony, 0, st);

View file

@ -3459,7 +3459,7 @@ static void M_LevelListFromGametype(INT16 gt)
while (cup)
{
if (cup->unlockrequired == -1 || gamedata->unlocked[cup->unlockrequired])
if (cup->unlockrequired >= MAXUNLOCKABLES || gamedata->unlocked[cup->unlockrequired])
{
highestid = cup->id;
if (Playing() && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == cup)
@ -3593,7 +3593,7 @@ void M_CupSelectHandler(INT32 choice)
M_SetMenuDelay(pid);
if ((!newcup)
|| (newcup && newcup->unlockrequired != -1 && !gamedata->unlocked[newcup->unlockrequired])
|| (newcup && newcup->unlockrequired < MAXUNLOCKABLES && !gamedata->unlocked[newcup->unlockrequired])
|| (newcup->cachedlevels[0] == NEXTMAP_INVALID))
{
S_StartSound(NULL, sfx_s3kb2);

View file

@ -761,11 +761,23 @@ UINT8 M_MapLocked(INT32 mapnum)
// That just makes hosts' lives hell.
if (dedicated)
return false;
// No skipping over any part of your marathon.
if (marathonmode)
return false;
if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0)
if (!mapheaderinfo[mapnum-1])
return false;
if (!gamedata->unlocked[mapheaderinfo[mapnum-1]->unlockrequired])
if (mapheaderinfo[mapnum-1]->cup)
{
if ((mapheaderinfo[mapnum-1]->cup->unlockrequired < MAXUNLOCKABLES)
&& (!gamedata->unlocked[mapheaderinfo[mapnum-1]->cup->unlockrequired]))
return true;
}
if ((mapheaderinfo[mapnum-1]->unlockrequired < MAXUNLOCKABLES)
&& (!gamedata->unlocked[mapheaderinfo[mapnum-1]->unlockrequired]))
return true;
return false;

View file

@ -400,7 +400,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 num)
mapheaderinfo[num]->palette = UINT16_MAX;
mapheaderinfo[num]->encorepal = UINT16_MAX;
mapheaderinfo[num]->numlaps = NUMLAPS_DEFAULT;
mapheaderinfo[num]->unlockrequired = -1;
mapheaderinfo[num]->unlockrequired = MAXUNLOCKABLES;
mapheaderinfo[num]->levelselect = 0;
mapheaderinfo[num]->levelflags = 0;
mapheaderinfo[num]->menuflags = 0;