From 6b8a3468ef481b7675761011a54ecf8b3edee488 Mon Sep 17 00:00:00 2001 From: HylianFreddy <82058772+HylianFreddy@users.noreply.github.com> Date: Tue, 2 Jun 2026 22:28:12 +0200 Subject: [PATCH] Add alert message for seed mismatch --- code/src/actors/title_screen.c | 7 ++---- code/src/actors/title_screen.h | 3 --- code/src/alert.h | 13 ++++++++++ code/src/main.c | 46 ++++++++++++++++++++++++++-------- code/src/savefile.c | 7 ++++++ code/src/savefile.h | 3 ++- 6 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 code/src/alert.h diff --git a/code/src/actors/title_screen.c b/code/src/actors/title_screen.c index 7e1db51b3..c63e7a944 100644 --- a/code/src/actors/title_screen.c +++ b/code/src/actors/title_screen.c @@ -2,12 +2,10 @@ #include "custom_models.h" #include "objects.h" #include "title_screen.h" +#include "alert.h" void EnMag_Init(Actor* thisx, GlobalContext* globalCtx); -u8 missingRomfsAlert = 0; -s16 romfsAlertFrames = 0; - void EnMag_rInit(Actor* thisx, GlobalContext* globalCtx) { EnMag* this = (EnMag*)thisx; @@ -32,7 +30,6 @@ void EnMag_rInit(Actor* thisx, GlobalContext* globalCtx) { if (cmabMan == 0) { // If the pointer is 0, the romfs folder is not present. // The 3DS would've crashed by this point, so this alert is for Citra only. - missingRomfsAlert = 1; - romfsAlertFrames = 300; + Alert_Set(ALERT_MISSING_ROMFS); } } diff --git a/code/src/actors/title_screen.h b/code/src/actors/title_screen.h index 58a1a1870..a437f056f 100644 --- a/code/src/actors/title_screen.h +++ b/code/src/actors/title_screen.h @@ -13,7 +13,4 @@ typedef struct { void EnMag_rInit(Actor* thisx, GlobalContext* globalCtx); -extern u8 missingRomfsAlert; -extern s16 romfsAlertFrames; - #endif //_TITLE_SCREEN_H_ diff --git a/code/src/alert.h b/code/src/alert.h new file mode 100644 index 000000000..00a42210a --- /dev/null +++ b/code/src/alert.h @@ -0,0 +1,13 @@ +#ifndef _ALERT_H_ +#define _ALERT_H_ + +typedef enum AlertType { + ALERT_NONE = -1, + ALERT_MISSING_ROMFS, + ALERT_HASH_MISMATCH, +} AlertType; + +// Display a warning message on the top screen. +void Alert_Set(AlertType alert); + +#endif //_ALERT_H_ diff --git a/code/src/main.c b/code/src/main.c index f9f19a000..eb1698885 100644 --- a/code/src/main.c +++ b/code/src/main.c @@ -22,6 +22,7 @@ #include "icetrap.h" #include "bgm.h" #include "business_scrubs.h" +#include "alert.h" #include "z3D/z3D.h" #include "3ds/extdata.h" @@ -31,6 +32,10 @@ GlobalContext* gGlobalContext = NULL; static u8 rRandomizerInit = 0; u32 rGameplayFrames = 0; +static AlertType sActiveAlert = ALERT_NONE; +static s16 sAlertFrames = 0; + +static void Alert_Update(void); void Randomizer_Init() { rHeap_Init(); @@ -76,19 +81,40 @@ void before_GlobalContext_Update(GlobalContext* globalCtx) { } void after_GlobalContext_Update() { - // The alert is always displayed on the Title Screen, and for 10 seconds after opening a save file. - if (missingRomfsAlert && romfsAlertFrames > 0) { - Draw_DrawFormattedStringTop(75, 180, COLOR_WHITE, - "WARNING: THE ROMFS FOLDER IS MISSING!\nCOPY IT FROM AND TO THE SAME " - "LOCATIONS\nUSED FOR CODE.IPS AND EXHEADER.BIN"); - if (IsInGame()) { - romfsAlertFrames--; - } - } - + Alert_Update(); Multiplayer_Sync_Update(); if (gGlobalContext->state.running == 0) { Model_DestroyAll(); } } + +void Alert_Set(AlertType alert) { + sActiveAlert = alert; + sAlertFrames = 450; // 15 seconds +} + +static void Alert_Update(void) { + if (sActiveAlert == ALERT_NONE || sAlertFrames <= 0) { + return; + } + + const char* const alertMessages[] = { + [ALERT_MISSING_ROMFS] = "WARNING: THE ROMFS FOLDER IS MISSING!\n" + "COPY IT ALONGSIDE CODE.IPS AND EXHEADER.BIN", + [ALERT_HASH_MISMATCH] = "WARNING: THIS SAVE FILE DOES NOT MATCH\n" + "THE CURRENT RANDOMIZER SEED!\n" + "CONTINUING MAY RESULT IN SOFTLOCKS.\n" + "PLEASE CREATE A NEW FILE.", + }; + + // The alert is always displayed on the Title Screen, decrease timer only in game. + if (IsInGame()) { + sAlertFrames--; + } else if (sActiveAlert == ALERT_HASH_MISMATCH) { + sActiveAlert = ALERT_NONE; + return; + } + + Draw_DrawFormattedStringTop(75, 150, COLOR_WHITE, alertMessages[sActiveAlert]); +} diff --git a/code/src/savefile.c b/code/src/savefile.c index 3d6269e52..6be772640 100644 --- a/code/src/savefile.c +++ b/code/src/savefile.c @@ -10,6 +10,7 @@ #include "item_override.h" #include "permadeath.h" #include "gloom.h" +#include "alert.h" #include "savefile.h" @@ -728,6 +729,9 @@ void SaveFile_InitExtSaveData(u32 saveNumber, u8 fromSaveCreation) { memset(&gExtSaveData, 0, sizeof(gExtSaveData)); gExtSaveData.version = EXTSAVEDATA_VERSION; // Do not change this line + if (fromSaveCreation) { + memcpy(&gExtSaveData.hashIndexes, &gSettingsContext.hashIndexes, sizeof(gExtSaveData.hashIndexes)); + } gExtSaveData.extInf.masterSwordFlags = (gSettingsContext.shuffleMasterSword && !(gSettingsContext.startingEquipment & 0x2)) ? 0 : 1; gExtSaveData.permadeath = fromSaveCreation ? gSettingsContext.permadeath : 0; @@ -859,6 +863,9 @@ void SaveFile_BeforeLoadGame(u32 saveNumber) { } void SaveFile_AfterLoadGame(void) { + if (memcmp(&gExtSaveData.hashIndexes, &gSettingsContext.hashIndexes, sizeof(gExtSaveData.hashIndexes)) != 0) { + Alert_Set(ALERT_HASH_MISMATCH); + } // Give Ganon BK if Triforce Hunt has been completed if (gSettingsContext.triforceHunt == ON && gExtSaveData.triforcePieces >= gSettingsContext.triforcePiecesRequired && (gSaveContext.dungeonItems[DUNGEON_GANONS_TOWER] & 1) == 0) { diff --git a/code/src/savefile.h b/code/src/savefile.h index 7578a74c1..bb9980a66 100644 --- a/code/src/savefile.h +++ b/code/src/savefile.h @@ -36,7 +36,7 @@ void SaveFile_SetRupeeSanityFlag(s16 sceneNum, u16 collectibleFlag); u8 SaveFile_GetRupeeSanityFlag(s16 sceneNum, u16 collectibleFlag); // Increment the version number whenever the ExtSaveData structure is changed -#define EXTSAVEDATA_VERSION 18 +#define EXTSAVEDATA_VERSION 19 typedef struct ExtInf { u32 rupeesanityFlags[SCENE_MAX]; @@ -52,6 +52,7 @@ typedef struct ExtInf { typedef struct { u32 version; // Needs to always be the first field of the structure + u8 hashIndexes[5]; union { ExtInf extInf; // Used for various bit flags that should also be synced in multiplayer with shared progress u8 extInfArray[EXTINF_SIZE]; // Used only by multiplayer code for easier management of bit flags