Merge branch 'seal-a-carte' into 'master'

Sealed Star re-ordering (resolves #606)

Closes #606

See merge request KartKrew/Kart!1980
This commit is contained in:
James R. 2024-03-03 05:18:26 +00:00
commit b136df4d41
14 changed files with 336 additions and 43 deletions

View file

@ -3933,15 +3933,68 @@ void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencor
// At the end of the Cup is a Rank-restricted treat. // At the end of the Cup is a Rank-restricted treat.
// So we append it to the end of the roundqueue. // So we append it to the end of the roundqueue.
// (as long as it exists, of course!) // (as long as it exists, of course!)
cupLevelNum = cup->cachedlevels[CUPCACHE_SPECIAL];
if (cupLevelNum < nummapheaders)
{ {
G_MapIntoRoundQueue( // Of course, this last minute game design tweak
cupLevelNum, // has to make things a little complicated. We
G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel), // basically just make sure they're dispensed
setencore, // if this isn't correct, Got_Mapcmd will fix it // at the intended difficulty sequence until
true // Rank-restricted! // you've got them all, at which point they
); // become their intended order permanently.
// ~toast 010324
cupheader_t *emeraldcup = NULL;
if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found
|| cup->id >= basenumkartcupheaders // custom content
|| M_SecretUnlocked(SECRET_SPECIALATTACK, false)) // true order
{
// Standard order.
emeraldcup = cup;
}
else
{
// Determine order from sealedswaps.
for (i = 0; (i < GDMAX_SEALEDSWAPS && gamedata->sealedswaps[i]); i++)
{
if (gamedata->sealedswaps[i] != grandprixinfo.cup)
continue;
// Repeat visit, grab the same ID.
break;
}
// If there's pending stars, get them from the associated cup order.
if (i < GDMAX_SEALEDSWAPS)
{
emeraldcup = kartcupheaders;
while (emeraldcup)
{
if (emeraldcup->id >= basenumkartcupheaders)
{
emeraldcup = NULL;
break;
}
if (emeraldcup->emeraldnum == i+1)
break;
emeraldcup = emeraldcup->next;
}
}
}
if (emeraldcup)
{
cupLevelNum = emeraldcup->cachedlevels[CUPCACHE_SPECIAL];
if (cupLevelNum < nummapheaders)
{
G_MapIntoRoundQueue(
cupLevelNum,
G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel),
setencore, // if this isn't correct, Got_Mapcmd will fix it
true // Rank-restricted!
);
}
}
} }
if (roundqueue.size == 0) if (roundqueue.size == 0)

View file

@ -64,6 +64,7 @@ void srb2::save_ng_gamedata()
ng.milestones.majorkeyskipattempted = gamedata->majorkeyskipattempted; ng.milestones.majorkeyskipattempted = gamedata->majorkeyskipattempted;
ng.milestones.finishedtutorialchallenge = gamedata->finishedtutorialchallenge; ng.milestones.finishedtutorialchallenge = gamedata->finishedtutorialchallenge;
ng.milestones.enteredtutorialchallenge = gamedata->enteredtutorialchallenge; ng.milestones.enteredtutorialchallenge = gamedata->enteredtutorialchallenge;
ng.milestones.sealedswapalerted = gamedata->sealedswapalerted;
ng.milestones.gonerlevel = gamedata->gonerlevel; ng.milestones.gonerlevel = gamedata->gonerlevel;
ng.prisons.thisprisoneggpickup = gamedata->thisprisoneggpickup; ng.prisons.thisprisoneggpickup = gamedata->thisprisoneggpickup;
ng.prisons.prisoneggstothispickup = gamedata->prisoneggstothispickup; ng.prisons.prisoneggstothispickup = gamedata->prisoneggstothispickup;
@ -176,7 +177,7 @@ void srb2::save_ng_gamedata()
} }
for (auto cup = kartcupheaders; cup; cup = cup->next) for (auto cup = kartcupheaders; cup; cup = cup->next)
{ {
if (cup->windata[0].best_placement == 0) if (cup->windata[0].best_placement == 0 && cup->windata[1].got_emerald == false)
{ {
continue; continue;
} }
@ -229,6 +230,17 @@ void srb2::save_ng_gamedata()
ng.cups[cupdata.name] = std::move(cupdata); ng.cups[cupdata.name] = std::move(cupdata);
} }
for (int i = 0; (i < GDMAX_SEALEDSWAPS && gamedata->sealedswaps[i]); i++)
{
srb2::GamedataSealedSwapJson sealedswap {};
cupheader_t* cup = gamedata->sealedswaps[i];
sealedswap.name = std::string(cup->name);
ng.sealedswaps.emplace_back(std::move(sealedswap));
}
std::string gamedataname_s {gamedatafilename}; std::string gamedataname_s {gamedatafilename};
fs::path savepath {fmt::format("{}/{}", srb2home, gamedataname_s)}; fs::path savepath {fmt::format("{}/{}", srb2home, gamedataname_s)};
fs::path tmpsavepath {fmt::format("{}/{}.tmp", srb2home, gamedataname_s)}; fs::path tmpsavepath {fmt::format("{}/{}.tmp", srb2home, gamedataname_s)};
@ -418,6 +430,7 @@ void srb2::load_ng_gamedata()
gamedata->majorkeyskipattempted = js.milestones.majorkeyskipattempted; gamedata->majorkeyskipattempted = js.milestones.majorkeyskipattempted;
gamedata->finishedtutorialchallenge = js.milestones.finishedtutorialchallenge; gamedata->finishedtutorialchallenge = js.milestones.finishedtutorialchallenge;
gamedata->enteredtutorialchallenge = js.milestones.enteredtutorialchallenge; gamedata->enteredtutorialchallenge = js.milestones.enteredtutorialchallenge;
gamedata->sealedswapalerted = js.milestones.sealedswapalerted;
gamedata->gonerlevel = js.milestones.gonerlevel; gamedata->gonerlevel = js.milestones.gonerlevel;
gamedata->thisprisoneggpickup = js.prisons.thisprisoneggpickup; gamedata->thisprisoneggpickup = js.prisons.thisprisoneggpickup;
gamedata->prisoneggstothispickup = js.prisons.prisoneggstothispickup; gamedata->prisoneggstothispickup = js.prisons.prisoneggstothispickup;
@ -720,6 +733,33 @@ void srb2::load_ng_gamedata()
} }
} }
size_t sealedswaps_size = js.sealedswaps.size();
for (size_t i = 0; i < std::min((size_t)GDMAX_SEALEDSWAPS, sealedswaps_size); i++)
{
cupheader_t* cup = nullptr;
// Find BASE cups only
for (cup = kartcupheaders; cup; cup = cup->next)
{
if (cup->id >= basenumkartcupheaders)
{
cup = NULL;
break;
}
std::string cupname = std::string(cup->name);
if (cupname == js.sealedswaps[i].name)
{
break;
}
}
if (cup)
{
gamedata->sealedswaps[i] = cup;
}
}
M_FinaliseGameData(); M_FinaliseGameData();
} }

View file

@ -70,6 +70,7 @@ struct GamedataMilestonesJson final
bool majorkeyskipattempted; bool majorkeyskipattempted;
bool finishedtutorialchallenge; bool finishedtutorialchallenge;
bool enteredtutorialchallenge; bool enteredtutorialchallenge;
bool sealedswapalerted;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataMilestonesJson, GamedataMilestonesJson,
@ -81,7 +82,8 @@ struct GamedataMilestonesJson final
chaokeytutorial, chaokeytutorial,
majorkeyskipattempted, majorkeyskipattempted,
finishedtutorialchallenge, finishedtutorialchallenge,
enteredtutorialchallenge enteredtutorialchallenge,
sealedswapalerted
) )
}; };
@ -184,6 +186,13 @@ struct GamedataCupJson final
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupJson, name, records) NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupJson, name, records)
}; };
struct GamedataSealedSwapJson final
{
std::string name;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSealedSwapJson, name)
};
struct GamedataJson final struct GamedataJson final
{ {
GamedataPlaytimeJson playtime; GamedataPlaytimeJson playtime;
@ -203,6 +212,7 @@ struct GamedataJson final
std::unordered_map<std::string, GamedataMapJson> maps; std::unordered_map<std::string, GamedataMapJson> maps;
std::vector<GamedataSprayCanJson> spraycans; std::vector<GamedataSprayCanJson> spraycans;
std::unordered_map<std::string, GamedataCupJson> cups; std::unordered_map<std::string, GamedataCupJson> cups;
std::vector<GamedataSealedSwapJson> sealedswaps;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataJson, GamedataJson,
@ -222,7 +232,8 @@ struct GamedataJson final
skins, skins,
maps, maps,
spraycans, spraycans,
cups cups,
sealedswaps
) )
}; };

View file

@ -680,6 +680,8 @@ void M_Init(void);
void M_PlayMenuJam(void); void M_PlayMenuJam(void);
boolean M_ConsiderSealedSwapAlert(void);
void M_OpenVirtualKeyboard(boolean gamepad); void M_OpenVirtualKeyboard(boolean gamepad);
void M_MenuTypingInput(INT32 key); void M_MenuTypingInput(INT32 key);
@ -1347,6 +1349,8 @@ extern struct challengesmenu_s {
boolean chaokeyadd, keywasadded; boolean chaokeyadd, keywasadded;
UINT8 chaokeyhold; UINT8 chaokeyhold;
boolean considersealedswapalert;
boolean requestflip; boolean requestflip;
UINT16 unlockcount[CMC_MAX]; UINT16 unlockcount[CMC_MAX];

View file

@ -2823,6 +2823,57 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi
rankx += 19 - (rankw / 2); rankx += 19 - (rankw / 2);
cupwindata_t *windata = &(cup->windata[difficulty]); cupwindata_t *windata = &(cup->windata[difficulty]);
UINT8 emeraldnum = UINT8_MAX;
if (!noemerald)
{
if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found
|| cup->id >= basenumkartcupheaders // custom content
|| M_SecretUnlocked(SECRET_SPECIALATTACK, true)) // true order
{
// Standard order.
if (windata->got_emerald == true)
{
emeraldnum = cup->emeraldnum;
}
}
else
{
// Determine order from sealedswaps.
UINT8 i;
for (i = 0; (i < GDMAX_SEALEDSWAPS && gamedata->sealedswaps[i]); i++)
{
if (gamedata->sealedswaps[i] != cup)
continue;
break;
}
// If there's pending stars, get them from the associated cup order.
if (i < GDMAX_SEALEDSWAPS)
{
cupheader_t *emeraldcup = kartcupheaders;
while (emeraldcup)
{
if (emeraldcup->id >= basenumkartcupheaders)
{
emeraldcup = NULL;
break;
}
if (emeraldcup->emeraldnum == i+1)
{
if (emeraldcup->windata[difficulty].got_emerald == true)
emeraldnum = i+1;
break;
}
emeraldcup = emeraldcup->next;
}
}
}
}
if (windata->best_placement == 0) if (windata->best_placement == 0)
{ {
if (statsmode) if (statsmode)
@ -2832,14 +2883,13 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi
V_DrawCharacter((14-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false); V_DrawCharacter((14-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false);
rankx += 14 + 1; rankx += 14 + 1;
V_DrawCharacter((12-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false); V_DrawCharacter((12-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false);
if (!noemerald)
{
rankx += 12 + 1;
V_DrawCharacter((12-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false);
}
} }
return rankw; else
{
rankx += 14 + 1;
}
goto windataemeraldmaybe;
} }
UINT8 *colormap = NULL; UINT8 *colormap = NULL;
@ -2934,13 +2984,15 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi
if (charPat) if (charPat)
V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, charPat, colormap); V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, charPat, colormap);
windataemeraldmaybe:
rankx += 12 + 1; rankx += 12 + 1;
if (noemerald) if (noemerald)
; ;
else if (windata->got_emerald == true) else if (emeraldnum != UINT8_MAX)
{ {
if (cup->emeraldnum == 0) if (emeraldnum == 0)
V_DrawCharacter(rankx+2, ranky+2, '+', false); V_DrawCharacter(rankx+2, ranky+2, '+', false);
else else
{ {
@ -2948,14 +3000,14 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi
if (!flash) if (!flash)
{ {
UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (cup->emeraldnum-1) % 7; UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (emeraldnum-1) % 7;
colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
} }
const char *emname = va( const char *emname = va(
"%sMAP%c", "%sMAP%c",
(cup->emeraldnum > 7) ? "SUP" : "EME", (emeraldnum > 7) ? "SUP" : "EME",
colormap ? '\0' : 'B' colormap ? '\0' : 'B'
); );
@ -3116,7 +3168,7 @@ void M_DrawCupSelect(void)
y += 44; //(8 + 100) - (20 + 44) y += 44; //(8 + 100) - (20 + 44)
} }
if (windata && windata->best_placement != 0) if (windata)
{ {
M_DrawCupWinData( M_DrawCupWinData(
x, x,

View file

@ -560,6 +560,35 @@ void M_PlayMenuJam(void)
#undef IsCurrentlyPlaying #undef IsCurrentlyPlaying
boolean M_ConsiderSealedSwapAlert(void)
{
if (gamedata->sealedswapalerted == true)
return false;
if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found
|| M_SecretUnlocked(SECRET_SPECIALATTACK, true)) // true order
{
gamedata->sealedswapalerted = true;
// Don't make a message if no Sealed Stars have yet been found.
if (gamedata->everseenspecial == false)
return false;
M_StartMessage(
"Message from the Stars",
"As if called by fate, the Emeralds you've\n"
"collected return to their rightful places...\n"
"\n"
"The Sealed Stars are now ordered via Cups!\n",
NULL, MM_NOTHING, NULL, NULL
);
return true;
}
return false;
}
void M_ValidateRestoreMenu(void) void M_ValidateRestoreMenu(void)
{ {
if (restoreMenu == NULL || restoreMenu == &MAIN_GonerDef) if (restoreMenu == NULL || restoreMenu == &MAIN_GonerDef)
@ -629,6 +658,11 @@ menu_t *M_SpecificMenuRestore(menu_t *torestore)
M_SetupPlayMenu(-1); M_SetupPlayMenu(-1);
PLAY_CharSelectDef.prevMenu = &MainDef; PLAY_CharSelectDef.prevMenu = &MainDef;
if (torestore != &MISC_ChallengesDef)
{
M_ConsiderSealedSwapAlert();
}
return torestore; return torestore;
} }

View file

@ -83,6 +83,7 @@ static struct podiumData_s
sfxenum_t gradeVoice; sfxenum_t gradeVoice;
cupheader_t *cup; cupheader_t *cup;
UINT8 emeraldnum;
boolean fastForward; boolean fastForward;
@ -102,6 +103,7 @@ void podiumData_s::Init(void)
{ {
rank = grandprixinfo.rank; rank = grandprixinfo.rank;
cup = grandprixinfo.cup; cup = grandprixinfo.cup;
emeraldnum = cup->emeraldnum;
} }
else else
{ {
@ -119,6 +121,7 @@ void podiumData_s::Init(void)
cup = cup->next; cup = cup->next;
} }
emeraldnum = 0;
memset(&rank, 0, sizeof(gpRank_t)); memset(&rank, 0, sizeof(gpRank_t));
rank.skin = players[consoleplayer].skin; rank.skin = players[consoleplayer].skin;
@ -628,12 +631,7 @@ void podiumData_s::Draw(void)
case GPEVENT_SPECIAL: case GPEVENT_SPECIAL:
{ {
srb2::Draw drawer_emerald = drawer_gametype; srb2::Draw drawer_emerald = drawer_gametype;
UINT8 emeraldNum = 0; UINT8 emeraldNum = g_podiumData.emeraldnum;
if (cup != nullptr)
{
emeraldNum = cup->emeraldnum;
}
boolean useWhiteFrame = ((leveltime & 1) || !dta->gotSpecialPrize); boolean useWhiteFrame = ((leveltime & 1) || !dta->gotSpecialPrize);
patch_t *emeraldPatch = nullptr; patch_t *emeraldPatch = nullptr;
@ -844,12 +842,7 @@ void podiumData_s::Draw(void)
if (rank.specialWon == true) if (rank.specialWon == true)
{ {
UINT8 emeraldNum = 0; UINT8 emeraldNum = g_podiumData.emeraldnum;
if (cup != nullptr)
{
emeraldNum = cup->emeraldnum;
}
const boolean emeraldBlink = (leveltime & 1); const boolean emeraldBlink = (leveltime & 1);
patch_t *emeraldOverlay = nullptr; patch_t *emeraldOverlay = nullptr;
@ -1263,6 +1256,60 @@ void K_ResetCeremony(void)
return; return;
} }
cupheader_t *emeraldcup = NULL;
if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found
|| grandprixinfo.cup->id >= basenumkartcupheaders // custom content
|| M_SecretUnlocked(SECRET_SPECIALATTACK, false)) // true order
{
// Standard order.
emeraldcup = grandprixinfo.cup;
}
else
{
// Determine order from sealedswaps.
for (i = 0; i < GDMAX_SEALEDSWAPS; i++)
{
if (gamedata->sealedswaps[i] == NULL)
{
if (g_podiumData.rank.specialWon == true)
{
// First visit! Mark it off.
gamedata->sealedswaps[i] = grandprixinfo.cup;
}
break;
}
if (gamedata->sealedswaps[i] != grandprixinfo.cup)
continue;
// Repeat visit, grab the same ID.
break;
}
// If there's pending stars, apply them to the new cup order.
if (i < GDMAX_SEALEDSWAPS)
{
emeraldcup = kartcupheaders;
while (emeraldcup)
{
if (emeraldcup->id >= basenumkartcupheaders)
{
emeraldcup = NULL;
break;
}
if (emeraldcup->emeraldnum == i+1)
break;
emeraldcup = emeraldcup->next;
}
g_podiumData.emeraldnum = i+1;
}
}
// Write grade, position, and emerald-having-ness for later sessions! // Write grade, position, and emerald-having-ness for later sessions!
i = (grandprixinfo.masterbots) ? KARTGP_MASTER : grandprixinfo.gamespeed; i = (grandprixinfo.masterbots) ? KARTGP_MASTER : grandprixinfo.gamespeed;
@ -1292,9 +1339,9 @@ void K_ResetCeremony(void)
anymerit = true; anymerit = true;
} }
if (g_podiumData.rank.specialWon == true) if (g_podiumData.rank.specialWon == true && emeraldcup)
{ {
grandprixinfo.cup->windata[i].got_emerald = true; emeraldcup->windata[i].got_emerald = true;
anymerit = true; anymerit = true;
} }

View file

@ -96,6 +96,7 @@ static UINT8 cheatf_warp(void)
if (success) if (success)
{ {
gamedata->gonerlevel = GDGONER_DONE; gamedata->gonerlevel = GDGONER_DONE;
gamedata->sealedswapalerted = true;
G_SetUsedCheats(); G_SetUsedCheats();
} }
@ -231,6 +232,7 @@ static UINT8 cheatf_devmode(void)
} }
gamedata->gonerlevel = GDGONER_DONE; gamedata->gonerlevel = GDGONER_DONE;
gamedata->sealedswapalerted = true;
M_ClearMenus(true); M_ClearMenus(true);

View file

@ -666,6 +666,7 @@ void M_ClearStats(void)
gamedata->majorkeyskipattempted = false; gamedata->majorkeyskipattempted = false;
gamedata->enteredtutorialchallenge = false; gamedata->enteredtutorialchallenge = false;
gamedata->finishedtutorialchallenge = false; gamedata->finishedtutorialchallenge = false;
gamedata->sealedswapalerted = false;
gamedata->musicstate = GDMUSIC_NONE; gamedata->musicstate = GDMUSIC_NONE;
gamedata->importprofilewins = false; gamedata->importprofilewins = false;
@ -720,6 +721,8 @@ void M_ClearSecrets(void)
skincolors[i].cache_spraycan = UINT16_MAX; skincolors[i].cache_spraycan = UINT16_MAX;
} }
memset(gamedata->sealedswaps, 0, sizeof(gamedata->sealedswaps));
Z_Free(gamedata->challengegrid); Z_Free(gamedata->challengegrid);
gamedata->challengegrid = NULL; gamedata->challengegrid = NULL;
gamedata->challengegridwidth = 0; gamedata->challengegridwidth = 0;

View file

@ -291,6 +291,7 @@ typedef enum {
// This is the largest number of 9s that will fit in UINT32 and UINT16 respectively. // This is the largest number of 9s that will fit in UINT32 and UINT16 respectively.
#define GDMAX_RINGS 999999999 #define GDMAX_RINGS 999999999
#define GDMAX_CHAOKEYS 9999 #define GDMAX_CHAOKEYS 9999
#define GDMAX_SEALEDSWAPS 7
#define GDCONVERT_ROUNDSTOKEY 14 #define GDCONVERT_ROUNDSTOKEY 14
@ -371,12 +372,15 @@ struct gamedata_t
UINT32 totalrings; UINT32 totalrings;
UINT32 totaltumbletime; UINT32 totaltumbletime;
// Chao Key condition bypass // CHAO KEYS AND THEIR GENERATION
UINT32 pendingkeyrounds; UINT32 pendingkeyrounds;
UINT8 pendingkeyroundoffset; UINT8 pendingkeyroundoffset;
UINT16 keyspending; UINT16 keyspending;
UINT16 chaokeys; UINT16 chaokeys;
// EMERALD REMAPPING
cupheader_t *sealedswaps[GDMAX_SEALEDSWAPS];
// SPECIFIC SPECIAL EVENTS // SPECIFIC SPECIAL EVENTS
boolean everloadedaddon; boolean everloadedaddon;
boolean everfinishedcredits; boolean everfinishedcredits;
@ -387,6 +391,7 @@ struct gamedata_t
boolean majorkeyskipattempted; boolean majorkeyskipattempted;
boolean enteredtutorialchallenge; boolean enteredtutorialchallenge;
boolean finishedtutorialchallenge; boolean finishedtutorialchallenge;
boolean sealedswapalerted;
gdmusic_t musicstate; gdmusic_t musicstate;
UINT8 gonerlevel; UINT8 gonerlevel;

View file

@ -335,6 +335,7 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
challengesmenu.requestnew = false; challengesmenu.requestnew = false;
challengesmenu.chaokeyadd = false; challengesmenu.chaokeyadd = false;
challengesmenu.keywasadded = false; challengesmenu.keywasadded = false;
challengesmenu.considersealedswapalert = false;
challengesmenu.chaokeyhold = 0; challengesmenu.chaokeyhold = 0;
challengesmenu.currentunlock = MAXUNLOCKABLES; challengesmenu.currentunlock = MAXUNLOCKABLES;
challengesmenu.unlockcondition = NULL; challengesmenu.unlockcondition = NULL;
@ -668,10 +669,15 @@ void M_ChallengesTick(void)
if (challengesmenu.currentunlock < MAXUNLOCKABLES if (challengesmenu.currentunlock < MAXUNLOCKABLES
&& challengesmenu.unlockanim == UNLOCKTIME) && challengesmenu.unlockanim == UNLOCKTIME)
{ {
unlockable_t *ref = &unlockables[challengesmenu.currentunlock];
// Unlock animation... also tied directly to the actual unlock! // Unlock animation... also tied directly to the actual unlock!
gamedata->unlocked[challengesmenu.currentunlock] = true; gamedata->unlocked[challengesmenu.currentunlock] = true;
M_UpdateUnlockablesAndExtraEmblems(true, true); M_UpdateUnlockablesAndExtraEmblems(true, true);
if (ref->type == SECRET_SPECIALATTACK)
challengesmenu.considersealedswapalert = true;
// Update shown description just in case..? // Update shown description just in case..?
if (challengesmenu.unlockcondition) if (challengesmenu.unlockcondition)
Z_Free(challengesmenu.unlockcondition); Z_Free(challengesmenu.unlockcondition);
@ -682,12 +688,10 @@ void M_ChallengesTick(void)
if (challengesmenu.extradata) if (challengesmenu.extradata)
{ {
unlockable_t *ref;
UINT16 bombcolor; UINT16 bombcolor;
M_UpdateChallengeGridExtraData(challengesmenu.extradata); M_UpdateChallengeGridExtraData(challengesmenu.extradata);
ref = &unlockables[challengesmenu.currentunlock];
bombcolor = SKINCOLOR_NONE; bombcolor = SKINCOLOR_NONE;
if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors)
@ -747,7 +751,14 @@ void M_ChallengesTick(void)
// Play music the moment control returns. // Play music the moment control returns.
M_PlayMenuJam(); M_PlayMenuJam();
if (gamedata->chaokeytutorial == false if (challengesmenu.considersealedswapalert == true
&& M_ConsiderSealedSwapAlert() == true)
{
// No keygen tutorial in this case...
// not ideal but at least unlikely to
// get at same time?? :V
}
else if (gamedata->chaokeytutorial == false
&& challengesmenu.keywasadded == true) && challengesmenu.keywasadded == true)
{ {
M_ChallengesTutorial(CCTUTORIAL_KEYGEN); M_ChallengesTutorial(CCTUTORIAL_KEYGEN);

View file

@ -116,6 +116,9 @@ void M_StopMessage(INT32 choice)
boolean M_MenuMessageTick(void) boolean M_MenuMessageTick(void)
{ {
if (menuwipe)
return false;
if (menumessage.closing) if (menumessage.closing)
{ {
if (menumessage.closing > MENUMESSAGECLOSE) if (menumessage.closing > MENUMESSAGECLOSE)

View file

@ -6284,6 +6284,14 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save)
{ {
UINT32 val = READUINT32(save->p); UINT32 val = READUINT32(save->p);
if (roundqueue.entries[i].rankrestricted && roundqueue.position != i+1)
{
// If this is a Sealed Star that hasn't yet been
// reached, don't be picky about divergance. Just
// use the base game without question. ~toast 010324
continue;
}
mapnum = roundqueue.entries[i].mapnum; mapnum = roundqueue.entries[i].mapnum;
if (mapnum < nummapheaders && mapheaderinfo[mapnum] != NULL) if (mapnum < nummapheaders && mapheaderinfo[mapnum] != NULL)
{ {

View file

@ -296,9 +296,29 @@ UINT8 P_GetNextEmerald(void)
{ {
cupheader_t *cup = NULL; cupheader_t *cup = NULL;
if (grandprixinfo.gp == true) if (grandprixinfo.gp == true && grandprixinfo.cup)
{ {
cup = grandprixinfo.cup; if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found
|| grandprixinfo.cup->id >= basenumkartcupheaders // custom content
|| M_SecretUnlocked(SECRET_SPECIALATTACK, false)) // true order
{
cup = grandprixinfo.cup;
}
else
{
// Determine order from sealedswaps.
UINT8 i;
for (i = 0; (i < GDMAX_SEALEDSWAPS && gamedata->sealedswaps[i]); i++)
{
if (gamedata->sealedswaps[i] != grandprixinfo.cup)
continue;
// Repeat visit, grab the same ID.
break;
}
return i+1;
}
} }
if (cup == NULL) if (cup == NULL)