From f9aac26433c36d319c41f836f00c804e135d4210 Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Sun, 15 Feb 2026 04:21:13 +0100 Subject: [PATCH 1/7] initial menu rework part 1 --- include/common.hpp | 5 + include/gz_commands.hpp | 6 +- include/gz_menu.hpp | 23 ++-- include/gz_settings.hpp | 3 - src/gz_commands.cpp | 55 +++++---- src/gz_game.cpp | 9 +- src/gz_menu.cpp | 267 ++++++++++++++++++---------------------- src/gz_settings.cpp | 17 +-- 8 files changed, 181 insertions(+), 204 deletions(-) create mode 100644 include/common.hpp diff --git a/include/common.hpp b/include/common.hpp new file mode 100644 index 0000000..7120b9f --- /dev/null +++ b/include/common.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +typedef void (*GZAction)(u32 params); diff --git a/include/gz_commands.hpp b/include/gz_commands.hpp index f85fbe2..1cc4600 100644 --- a/include/gz_commands.hpp +++ b/include/gz_commands.hpp @@ -1,25 +1,27 @@ #pragma once +#include "common.hpp" #include "gz_controls.hpp" #include "gz_menu.hpp" #include typedef void (*GZCmdInit)(void); -typedef void (*GZCmdAction)(void); struct GZCmdItem { ButtonCombo btnCombo; - GZCmdAction actionCallback; + GZAction actionCallback; }; class GZCommandManager { public: Input* mpButtons; GZCmdItem* mpCommands; + GZMenu mMenu; GZCommandManager(); + void CreateMenuItems(); void Update(); void Draw(Vec2b* pPos); }; diff --git a/include/gz_menu.hpp b/include/gz_menu.hpp index 0baf1ae..9e3b4bb 100644 --- a/include/gz_menu.hpp +++ b/include/gz_menu.hpp @@ -1,5 +1,6 @@ #pragma once +#include "common.hpp" #include "gz_controls.hpp" #include @@ -8,7 +9,8 @@ #include #include -typedef void (*GZMenuAction)(u32 params); +#define DRAW_TO_TOP_SCREEN 1 + struct GZMenu; typedef enum InventoryAmountType { @@ -24,18 +26,18 @@ typedef enum InventoryAmountType { } InventoryAmountType; struct GZMenuItem { - const char* mName; // menu item name - GZMenuAction mActionCallback; // associated action - u32 params; // parameters for the action callback - GZMenu* mSubMenu; // tied submenu - bool needSaveFile; // does it require the save data - s32 value; // misc value for internal use + const char* name; + GZAction action; + u32 params; + GZMenu* submenu; + int value; }; struct GZMenu { - GZMenuItem* mpItems; + GZMenuItem* entries; s32 mCount; - GZMenu* mPrev; + bool needSaveFile; + s16 itemIndex; }; struct GZMenuState { @@ -78,6 +80,7 @@ class GZMenuManager { public: GZMenuState mState; GZMenu* mpActiveMenu; + GZMenu* mpPrevMenu; GZMenuControls mControls; Input* mpButtons; @@ -90,7 +93,7 @@ class GZMenuManager { this->mState.isOpened = false; } - GZMenuItem* GetActiveMenuItem() { return &this->mpActiveMenu->mpItems[this->mState.itemIndex]; } + GZMenuItem* GetActiveMenuItem() { return &this->mpActiveMenu->entries[this->mState.itemIndex]; } bool IsInventoryMenuActive(); bool IsAmountsMenuActive(); diff --git a/include/gz_settings.hpp b/include/gz_settings.hpp index 0d733cb..a1b460a 100644 --- a/include/gz_settings.hpp +++ b/include/gz_settings.hpp @@ -16,8 +16,6 @@ extern "C" void func_02030d58(u16 lockID); // CARD_UnlockBackup #define MAX_POS_SLOTS 8 #define MAX_SAVE_PROFILES 8 -//! TODO: make it one setting set per save file - extern "C" { typedef struct GZProfileHeader { u8 curProfileIndex; @@ -25,7 +23,6 @@ typedef struct GZProfileHeader { // the save file is large so we don't care about packing stuff to save space typedef struct GZProfile { - u8 profileIndex; bool mFasterTitleScreen; // goes into the "touch or start to exit" state immediately bool mSkipTitleScreen; // same as above except it jump straight into the file select without requiring any input s8 mPositionIndex; diff --git a/src/gz_commands.cpp b/src/gz_commands.cpp index 2187b85..ea7eb8c 100644 --- a/src/gz_commands.cpp +++ b/src/gz_commands.cpp @@ -12,17 +12,17 @@ extern "C" void DisplayDebugText(int, void*, int, int, const char*); extern "C" void DisplayDebugTextF(int, void*, int, int, const char*, ...); -static void ExecuteLevitate(); -static void ExecutePause(); -static void ExecuteFrameAdvance(); -static void ExecutePrevPosition(); -static void ExecuteNextPosition(); -static void ExecuteSavePosition(); -static void ExecuteLoadPosition(); -static void ExecuteVoidOut(); -static void ExecuteTurbo(); - -// commands with default button combos +static void ExecuteLevitate(u32 params); +static void ExecutePause(u32 params); +static void ExecuteFrameAdvance(u32 params); +static void ExecutePrevPosition(u32 params); +static void ExecuteNextPosition(u32 params); +static void ExecuteSavePosition(u32 params); +static void ExecuteLoadPosition(u32 params); +static void ExecuteVoidOut(u32 params); +static void ExecuteTurbo(u32 params); + +// commands with default button combos, assigning the held btn to none means it's not required (and vice versa) static GZCmdItem sCommands[] = { {ButtonCombo("Levitate", BTN_X, BTN_NONE), ExecuteLevitate}, {ButtonCombo("Pause/Unpause", BTN_NONE, BTN_DDOWN), ExecutePause}, @@ -35,9 +35,9 @@ static GZCmdItem sCommands[] = { {ButtonCombo("Turbo", BTN_R, BTN_B), ExecuteTurbo}, }; -static void ExecuteLevitate() { data_027e0478.mPlayer.mVel.y = FLOAT_TO_Q20(0.334375f); } +static void ExecuteLevitate(u32 params) { data_027e0478.mPlayer.mVel.y = FLOAT_TO_Q20(0.334375f); } -static void ExecutePause() { +static void ExecutePause(u32 params) { if (!gGZ.mState.isPaused) { gGZ.mState.isPaused = true; } else { @@ -45,9 +45,9 @@ static void ExecutePause() { } } -static void ExecuteFrameAdvance() { gGZ.mState.requestedFrames++; } +static void ExecuteFrameAdvance(u32 params) { gGZ.mState.requestedFrames++; } -static void ExecutePrevPosition() { +static void ExecutePrevPosition(u32 params) { GZProfile* pProfile = gSettings.GetProfile(); pProfile->mPositionIndex--; @@ -57,7 +57,7 @@ static void ExecutePrevPosition() { } } -static void ExecuteNextPosition() { +static void ExecuteNextPosition(u32 params) { GZProfile* pProfile = gSettings.GetProfile(); pProfile->mPositionIndex++; @@ -67,31 +67,42 @@ static void ExecuteNextPosition() { } } -static void ExecuteSavePosition() { +static void ExecuteSavePosition(u32 params) { GZProfile* pProfile = gSettings.GetProfile(); Vec3p* pPosArray = gSettings.GetPosArray(); pPosArray[pProfile->mPositionIndex] = data_027e0478.mPlayer.mPos; } -static void ExecuteLoadPosition() { +static void ExecuteLoadPosition(u32 params) { GZProfile* pProfile = gSettings.GetProfile(); Vec3p* pPosArray = gSettings.GetPosArray(); data_027e0478.mPlayer.mPos = pPosArray[pProfile->mPositionIndex]; } -static void ExecuteVoidOut() { +static void ExecuteVoidOut(u32 params) { if (gGZ.IsOnLand()) { data_027e0478.mPlayer.mPos.y = FLOAT_TO_Q20(-4000.0f); } } -static void ExecuteTurbo() {} +static void ExecuteTurbo(u32 params) {} GZCommandManager gCommandManager; GZCommandManager::GZCommandManager() { this->mpButtons = &gGZ.mButtons; this->mpCommands = sCommands; + this->CreateMenuItems(); +} + +void GZCommandManager::CreateMenuItems() { + this->mMenu.entries = new GZMenuItem[ARRAY_LEN(sCommands)]; + + for (int i = 0; i < ARRAY_LEN(sCommands); i++) { + this->mMenu.entries[i].name = sCommands[i].btnCombo.name; + this->mMenu.entries[i].action = sCommands[i].actionCallback; + this->mMenu.entries[i].submenu = NULL; + } } void GZCommandManager::Update() { @@ -104,7 +115,7 @@ void GZCommandManager::Update() { if (pCmd->btnCombo.Executed(this->mpButtons)) { if (pCmd->actionCallback != NULL) { - pCmd->actionCallback(); + pCmd->actionCallback(0); } } } @@ -118,7 +129,7 @@ void GZCommandManager::Draw(Vec2b* pPos) { bool selected = i + 1 == gMenuManager.mState.itemIndex; pCmd->btnCombo.SetComboString(); - DisplayDebugText(0, &elemPos, 0, selected, pCmd->btnCombo.fullName); + DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, selected, pCmd->btnCombo.fullName); elemPos.y++; } } diff --git a/src/gz_game.cpp b/src/gz_game.cpp index 922ede7..a9472bb 100644 --- a/src/gz_game.cpp +++ b/src/gz_game.cpp @@ -62,14 +62,7 @@ void CustomGame::Run() { do { gGZ.Update(); - - { - gMenuManager.Update(); - - if (gMenuManager.IsActive()) { - gMenuManager.Draw(); - } - } + gMenuManager.Update(); // stgz: pause and frame advance block { diff --git a/src/gz_menu.cpp b/src/gz_menu.cpp index e0fa826..1d9f3cd 100644 --- a/src/gz_menu.cpp +++ b/src/gz_menu.cpp @@ -4,7 +4,10 @@ #include "gz_commands.hpp" #include "gz_settings.hpp" +#include +#include #include +#include #include #include #include @@ -48,9 +51,19 @@ - About */ +/* +TODO LIST: +- OBJ toggle (~0x1400) +- reimplement about menu and back/quit +*/ + struct Screen { - u8 unk_00[0x0C]; - u8 data[0x600]; + /* 00 */ u16 width; + /* 02 */ u16 height; + /* 04 */ u16 mUnk_04; + /* 06 */ u16 mUnk_06; // thing passed to func_0200a4a8 + /* 08 */ u32 mUnk_08; + /* 0C */ u8 data[0x600]; }; extern Screen data_0204d9d0[2]; @@ -58,7 +71,6 @@ extern "C" void DisplayDebugText(int, void*, int, int, const char*); extern "C" void DisplayDebugTextF(int, void*, int, int, const char*, ...); extern "C" void DC_FlushAll(); extern "C" void func_020131ec(); -extern "C" void func_02023770(int); extern "C" void GX_SetGraphicsMode(int, int, int); extern "C" void GXS_SetGraphicsMode(int); extern "C" void func_0201b180(bool, bool); @@ -82,77 +94,62 @@ extern GZMenu sInventoryMenu; extern GZMenu sAmountsMenu; extern GZMenu sCollectionMenu; extern GZMenu sSettingsMenu; -extern GZMenu sCommandsMenu; extern GZMenu sAboutMenu; static GZMenuItem sInventoryMenuItems[] = { - {"Back", Back, 0, NULL, false, 0}, - {"Whirlwind", UpdateInventory, ItemFlag_Whirlwind, NULL, true, 0}, - {"Boomerang", UpdateInventory, ItemFlag_Boomerang, NULL, true, 0}, - {"Whip", UpdateInventory, ItemFlag_Whip, NULL, true, 0}, - {"Bow", UpdateInventory, ItemFlag_Bow, NULL, true, 0}, - {"Bombs", UpdateInventory, ItemFlag_Bombs, NULL, true, 0}, - {"SandRod", UpdateInventory, ItemFlag_SandRod, NULL, true, 0}, - {"Amounts", NULL, 0, &sAmountsMenu, true, 0}, + {"Whirlwind", UpdateInventory, ItemFlag_Whirlwind, NULL, 0}, + {"Boomerang", UpdateInventory, ItemFlag_Boomerang, NULL, 0}, + {"Whip", UpdateInventory, ItemFlag_Whip, NULL, 0}, + {"Bow", UpdateInventory, ItemFlag_Bow, NULL, 0}, + {"Bombs", UpdateInventory, ItemFlag_Bombs, NULL, 0}, + {"SandRod", UpdateInventory, ItemFlag_SandRod, NULL, 0}, + {"Amounts", NULL, 0, &sAmountsMenu, 0}, }; static GZMenuItem sAmountsMenuItems[] = { - {"Back", Back, 0, NULL, false, 0}, - {"Bow", UpdateAmounts, InventoryAmountType_Bow, NULL, true, 0}, - {"Bombs", UpdateAmounts, InventoryAmountType_Bombs, NULL, true, 0}, - {"Quiver Capacity", UpdateAmounts, InventoryAmountType_QuiverCapacity, NULL, true, 0}, - {"Bomb Bag Capacity", UpdateAmounts, InventoryAmountType_BombCapacity, NULL, true, 0}, - {"Potion 1", UpdateAmounts, InventoryAmountType_Potion1, NULL, true, 0}, - {"Potion 2", UpdateAmounts, InventoryAmountType_Potion2, NULL, true, 0}, - {"Small Keys", UpdateAmounts, InventoryAmountType_SmallKeys, NULL, true, 0}, - {"Light Tears", UpdateAmounts, InventoryAmountType_LightTears, NULL, true, 0}, + {"Bow", UpdateAmounts, InventoryAmountType_Bow, NULL, 0}, + {"Bombs", UpdateAmounts, InventoryAmountType_Bombs, NULL, 0}, + {"Quiver Capacity", UpdateAmounts, InventoryAmountType_QuiverCapacity, NULL, 0}, + {"Bomb Bag Capacity", UpdateAmounts, InventoryAmountType_BombCapacity, NULL, 0}, + {"Potion 1", UpdateAmounts, InventoryAmountType_Potion1, NULL, 0}, + {"Potion 2", UpdateAmounts, InventoryAmountType_Potion2, NULL, 0}, + {"Small Keys", UpdateAmounts, InventoryAmountType_SmallKeys, NULL, 0}, + {"Light Tears", UpdateAmounts, InventoryAmountType_LightTears, NULL, 0}, }; static GZMenuItem sCollectionMenuItems[] = { - {"Back", Back, 0, NULL, false, 0}, - {"Shield", UpdateInventory, ItemFlag_Shield, NULL, true, 0}, - {"Sword", UpdateInventory, ItemFlag_Sword, NULL, true, 0}, - {"LokomoSword", UpdateInventory, ItemFlag_LokomoSword, NULL, true, 0}, - {"RecruitUniform", UpdateInventory, ItemFlag_RecruitUniform, NULL, true, 0}, - {"ScrollBeam", UpdateInventory, ItemFlag_ScrollBeam, NULL, true, 0}, - {"ScrollSpinAttack", UpdateInventory, ItemFlag_ScrollSpinAttack, NULL, true, 0}, - {"AncientShield", UpdateInventory, ItemFlag_AncientShield, NULL, true, 0}, - {"PanFlute", UpdateInventory, ItemFlag_PanFlute, NULL, true, 0}, + {"Shield", UpdateInventory, ItemFlag_Shield, NULL, 0}, + {"Sword", UpdateInventory, ItemFlag_Sword, NULL, 0}, + {"LokomoSword", UpdateInventory, ItemFlag_LokomoSword, NULL, 0}, + {"RecruitUniform", UpdateInventory, ItemFlag_RecruitUniform, NULL, 0}, + {"ScrollBeam", UpdateInventory, ItemFlag_ScrollBeam, NULL, 0}, + {"ScrollSpinAttack", UpdateInventory, ItemFlag_ScrollSpinAttack, NULL, 0}, + {"AncientShield", UpdateInventory, ItemFlag_AncientShield, NULL, 0}, + {"PanFlute", UpdateInventory, ItemFlag_PanFlute, NULL, 0}, }; static GZMenuItem sSettingsMenuItems[] = { - {"Back", Back, 0, NULL, false, 0}, - {"Prev Profile", PrevProfile, 0, NULL, false, 0}, - {"Next Profile", NextProfile, 0, NULL, false, 0}, - {"Load Default Profile", LoadDefaultProfile, 0, NULL, false, 0}, - {"Save Settings", SaveSettings, 0, NULL, false, 0}, -}; - -static GZMenuItem sCommandsMenuItems[] = { - {"Back", Back, 0, NULL, false, 0}, -}; - -static GZMenuItem sAboutMenuItems[] = { - {"Back", Back, 0, NULL, false, 0}, + {"Prev Profile", PrevProfile, 0, NULL, 0}, + {"Next Profile", NextProfile, 0, NULL, 0}, + {"Load Default Profile", LoadDefaultProfile, 0, NULL, 0}, + {"Save Settings", SaveSettings, 0, NULL, 0}, }; static GZMenuItem sMainMenuItems[] = { - {"Quit", Quit, 0, NULL, false, 0}, - {"Inventory", NULL, 0, &sInventoryMenu, true, 0}, - {"Collection", NULL, 0, &sCollectionMenu, true, 0}, - {"Settings", NULL, 0, &sSettingsMenu, false, 0}, - {"Commands", NULL, 0, &sCommandsMenu, false, 0}, - {"About", NULL, 0, &sAboutMenu, false, 0}, + {"Inventory", NULL, 0, &sInventoryMenu, 0}, + {"Collection", NULL, 0, &sCollectionMenu, 0}, + {"Settings", NULL, 0, &sSettingsMenu, 0}, + {"Commands", NULL, 0, &gCommandManager.mMenu, 0}, }; // pointer to the item list, number of items, pointer to the previous menu -GZMenu sMainMenu = {sMainMenuItems, ARRAY_LEN(sMainMenuItems), NULL}; -GZMenu sInventoryMenu = {sInventoryMenuItems, ARRAY_LEN(sInventoryMenuItems), &sMainMenu}; -GZMenu sAmountsMenu = {sAmountsMenuItems, ARRAY_LEN(sAmountsMenuItems), &sInventoryMenu}; -GZMenu sCollectionMenu = {sCollectionMenuItems, ARRAY_LEN(sCollectionMenuItems), &sMainMenu}; -GZMenu sSettingsMenu = {sSettingsMenuItems, ARRAY_LEN(sSettingsMenuItems), &sMainMenu}; -GZMenu sCommandsMenu = {sCommandsMenuItems, ARRAY_LEN(sCommandsMenuItems), &sMainMenu}; -GZMenu sAboutMenu = {sAboutMenuItems, ARRAY_LEN(sAboutMenuItems), &sMainMenu}; +GZMenu sMainMenu = {sMainMenuItems, ARRAY_LEN(sMainMenuItems), false, 0}; +GZMenu sInventoryMenu = {sInventoryMenuItems, ARRAY_LEN(sInventoryMenuItems), true, 0}; +GZMenu sAmountsMenu = {sAmountsMenuItems, ARRAY_LEN(sAmountsMenuItems), true, 0}; +GZMenu sCollectionMenu = {sCollectionMenuItems, ARRAY_LEN(sCollectionMenuItems), true, 0}; +GZMenu sSettingsMenu = {sSettingsMenuItems, ARRAY_LEN(sSettingsMenuItems), false, 0}; +// GZMenu sCommandsMenu = {sCommandsMenuItems, ARRAY_LEN(sCommandsMenuItems), 0}; +// GZMenu sAboutMenu = {sAboutMenuItems, ARRAY_LEN(sAboutMenuItems), 0}; static void Quit(u32 params) { gMenuManager.Quit(); } @@ -256,9 +253,7 @@ static void SaveSettings(u32 params) { gMenuManager.mState.requestRedraw = true; } -static u32 prevDispCnt; static u32 prevDispCnt_Sub; -static u8 prevVRAM_CNT_B; GZMenuManager gMenuManager; @@ -266,19 +261,18 @@ GZMenuManager::GZMenuManager() { this->mState.Init(); this->mpActiveMenu = &sMainMenu; this->mpButtons = &gGZ.mButtons; - memset(&data_0204d9d0[0], 0, sizeof(Screen)); - memset(&data_0204d9d0[1], 0, sizeof(Screen)); + memset(&data_0204d9d0[DRAW_TO_TOP_SCREEN], 0, sizeof(Screen)); } bool GZMenuManager::IsInventoryMenuActive() { return this->mpActiveMenu == &sInventoryMenu; } bool GZMenuManager::IsAmountsMenuActive() { return this->mpActiveMenu == &sAmountsMenu; } -bool GZMenuManager::IsCommandsMenuActive() { return this->mpActiveMenu == &sCommandsMenu; } +bool GZMenuManager::IsCommandsMenuActive() { return this->mpActiveMenu == &gCommandManager.mMenu; } bool GZMenuManager::IsSettingsMenuActive() { return this->mpActiveMenu == &sSettingsMenu; } -bool GZMenuManager::IsAboutMenuActive() { return this->mpActiveMenu == &sAboutMenu; } +bool GZMenuManager::IsAboutMenuActive() { return false; } // this->mpActiveMenu == &sAboutMenu; } void GZMenuManager::ValidateNewIncrement() { GZMenuItem* pActiveMenuItem = this->GetActiveMenuItem(); @@ -338,8 +332,10 @@ void GZMenuManager::ValidateNewIncrement() { } void GZMenuManager::AssignPrevMenu() { - if (this->mpActiveMenu->mPrev != NULL) { - this->mpActiveMenu = this->mpActiveMenu->mPrev; + if (this->mpPrevMenu != NULL) { + GZMenu* pPrevMenu = this->mpActiveMenu; + this->mpActiveMenu = this->mpPrevMenu; + this->mpPrevMenu = pPrevMenu; this->mState.itemIndex = 0; this->mState.requestRedraw = true; } @@ -394,8 +390,8 @@ void GZMenuManager::Update() { changed = true; } - if (changed && this->mState.itemIndex > 0 && pActiveMenuItem->mActionCallback != NULL) { - pActiveMenuItem->mActionCallback(pActiveMenuItem->params); + if (changed && this->mState.itemIndex > 0 && pActiveMenuItem->action != NULL) { + pActiveMenuItem->action(pActiveMenuItem->params); this->mState.requestRedraw = true; } } @@ -403,16 +399,15 @@ void GZMenuManager::Update() { if (this->mControls.ok.Executed(this->mpButtons)) { // handle confirmation stuff - if (!pActiveMenuItem->needSaveFile || (pActiveMenuItem->needSaveFile && gGZ.IsAdventureMode())) { - if ((!this->IsAmountsMenuActive() || this->mState.itemIndex == 0) && - pActiveMenuItem->mActionCallback != NULL) { - pActiveMenuItem->mActionCallback(pActiveMenuItem->params); + if (!this->mpActiveMenu->needSaveFile || (this->mpActiveMenu->needSaveFile && gGZ.IsAdventureMode())) { + if ((!this->IsAmountsMenuActive() || this->mState.itemIndex == 0) && pActiveMenuItem->action != NULL) { + pActiveMenuItem->action(pActiveMenuItem->params); if (this->IsInventoryMenuActive()) { this->mState.requestRedraw = true; } - } else if (pActiveMenuItem->mSubMenu != NULL) { - this->mpActiveMenu = pActiveMenuItem->mSubMenu; + } else if (pActiveMenuItem->submenu != NULL) { + this->mpActiveMenu = pActiveMenuItem->submenu; this->mState.itemIndex = 0; this->mState.requestRedraw = true; } @@ -452,31 +447,36 @@ void GZMenuManager::SetAmountString(s16 index, Vec2b* pPos, bool selected) { switch (index - 1) { case InventoryAmountType_Bow: if (data_027e0ce0 != NULL && data_027e0ce0->mUnk_28 != NULL) { - DisplayDebugTextF(0, pPos, 0, selected, " (%d/%d)", data_027e0ce0->mUnk_28->mArrowAmount, maxArrows); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%d/%d)", + data_027e0ce0->mUnk_28->mArrowAmount, maxArrows); } break; case InventoryAmountType_Bombs: if (data_027e0ce0 != NULL && data_027e0ce0->mUnk_28 != NULL) { - DisplayDebugTextF(0, pPos, 0, selected, " (%d/%d)", data_027e0ce0->mUnk_28->mBombAmount, maxBombs); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%d/%d)", + data_027e0ce0->mUnk_28->mBombAmount, maxBombs); } break; case InventoryAmountType_QuiverCapacity: - DisplayDebugTextF(0, pPos, 0, selected, " (%d)", maxArrows); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%d)", maxArrows); break; case InventoryAmountType_BombCapacity: - DisplayDebugTextF(0, pPos, 0, selected, " (%d)", maxBombs); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%d)", maxBombs); break; case InventoryAmountType_Potion1: - DisplayDebugTextF(0, pPos, 0, selected, " (%s)", szValueToPotion[data_027e0ce0->mUnk_28->mPotions[0]]); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%s)", + szValueToPotion[data_027e0ce0->mUnk_28->mPotions[0]]); break; case InventoryAmountType_Potion2: - DisplayDebugTextF(0, pPos, 0, selected, " (%s)", szValueToPotion[data_027e0ce0->mUnk_28->mPotions[1]]); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%s)", + szValueToPotion[data_027e0ce0->mUnk_28->mPotions[1]]); break; case InventoryAmountType_SmallKeys: - DisplayDebugTextF(0, pPos, 0, selected, " (%d/%d)", data_027e0ce0->mUnk_28->mKeyAmount, MAX_KEYS); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%d/%d)", data_027e0ce0->mUnk_28->mKeyAmount, + MAX_KEYS); break; case InventoryAmountType_LightTears: - DisplayDebugTextF(0, pPos, 0, selected, " (%d/%d)", data_027e0ce0->mUnk_28->mTearsAmount, + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%d/%d)", data_027e0ce0->mUnk_28->mTearsAmount, MAX_TEARS_OF_LIGHT); break; default: @@ -486,124 +486,97 @@ void GZMenuManager::SetAmountString(s16 index, Vec2b* pPos, bool selected) { void GZMenuManager::SetupScreen() { // reset the top screen buffer - memset(&data_0204d9d0[0], 0, sizeof(Screen)); + memset(&data_0204d9d0[DRAW_TO_TOP_SCREEN], 0, sizeof(Screen)); // send the menu item strings to the buffer Vec2b elemPos = this->mState.menuPos; - for (s16 i = 0; i < this->mpActiveMenu->mCount; i++) { - GZMenuItem* pActiveMenuItem = &this->mpActiveMenu->mpItems[i]; - const char* szName = pActiveMenuItem->mName; - Vec2b extraPos = elemPos; - bool selected = i == this->mState.itemIndex; - extraPos.x += strlen(szName); + if (this->IsCommandsMenuActive()) { + gCommandManager.Draw(&elemPos); + } else { + for (s16 i = 0; i < this->mpActiveMenu->mCount; i++) { + GZMenuItem* pActiveMenuItem = &this->mpActiveMenu->entries[i]; + const char* szName = pActiveMenuItem->name; + Vec2b extraPos = elemPos; + bool selected = i == this->mState.itemIndex; + extraPos.x += strlen(szName); - // 0 = white, 1 = red, 2 = darker red, 3 = dark green - DisplayDebugText(0, &elemPos, 0, selected, szName); + // 0 = white, 1 = red, 2 = darker red, 3 = dark green + DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, selected, szName); - if (i > 0) { if (this->IsAmountsMenuActive()) { this->SetAmountString(i, &extraPos, selected); - } else if (this->IsInventoryMenuActive() && pActiveMenuItem->mSubMenu == NULL) { + } else if (this->IsInventoryMenuActive() && pActiveMenuItem->submenu == NULL) { bool hasItem = GET_FLAG(data_027e0ce0->mUnk_28->mUnk_08, pActiveMenuItem->params & 0xFF); - DisplayDebugText(0, &extraPos, 0, selected, hasItem ? " (obtained)" : " (not obtained)"); - } else if (pActiveMenuItem->needSaveFile && !gGZ.IsAdventureMode()) { - DisplayDebugText(0, &extraPos, 0, selected, " (disabled)"); + DisplayDebugText(DRAW_TO_TOP_SCREEN, &extraPos, 0, selected, + hasItem ? " (obtained)" : " (not obtained)"); + } else if (this->mpActiveMenu->needSaveFile && !gGZ.IsAdventureMode()) { + DisplayDebugText(DRAW_TO_TOP_SCREEN, &extraPos, 0, selected, " (disabled)"); } - } - - elemPos.y++; - } - if (this->IsCommandsMenuActive()) { - gCommandManager.Draw(&elemPos); + elemPos.y++; + } } // send the arrow to the buffer Vec2b arrowPos = this->mState.menuPos; arrowPos.x--; arrowPos.y += this->mState.itemIndex; - DisplayDebugText(0, &arrowPos, 0, 1, ">"); + DisplayDebugText(DRAW_TO_TOP_SCREEN, &arrowPos, 0, 1, ">"); arrowPos.y++; if (this->IsSettingsMenuActive()) { // special handling for the settings screen Vec2b settingsPos = this->mState.menuPos; settingsPos.y = elemPos.y + 1; - DisplayDebugTextF(0, &settingsPos, 0, 0, "Current Profile: %d", gSettings.mProfileHeader.curProfileIndex + 1); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &settingsPos, 0, 0, "Current Profile: %d", + gSettings.mProfileHeader.curProfileIndex + 1); settingsPos.y += 15; if (gSettings.error) { - DisplayDebugTextF(0, &settingsPos, 0, 1, "Error detected: 0x%X", gSettings.errorCode); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &settingsPos, 0, 1, "Error detected: 0x%X", gSettings.errorCode); } else if (this->mState.successTimer > 0) { - DisplayDebugTextF(0, &settingsPos, 0, 0, "Success!", gSettings.errorCode); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &settingsPos, 0, 0, "Success!", gSettings.errorCode); } } else if (this->IsAboutMenuActive()) { // special handling for the about screen Vec2b aboutPos = this->mState.menuPos; aboutPos.y = elemPos.y + 1; // start wherever the item list ended - DisplayDebugTextF(0, &aboutPos, 0, 0, "Code Version: %s", gBuildGitVersion); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Code Version: %s", gBuildGitVersion); aboutPos.y++; - DisplayDebugTextF(0, &aboutPos, 0, 0, "Build Author: %s", gBuildAuthor); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Build Author: %s", gBuildAuthor); aboutPos.y++; - DisplayDebugTextF(0, &aboutPos, 0, 0, "Commit Author: %s", gCommitAuthor); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Commit Author: %s", gCommitAuthor); aboutPos.y++; - DisplayDebugTextF(0, &aboutPos, 0, 0, "Commit Name: %s", gCommitGitString); + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Commit Name: %s", gCommitGitString); aboutPos.y += 16; - DisplayDebugText(0, &aboutPos, 0, 0, "Licensed under GPL-3.0"); + DisplayDebugText(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Licensed under GPL-3.0"); aboutPos.y++; - DisplayDebugText(0, &aboutPos, 0, 0, "Made with <3 by Yanis2"); + DisplayDebugText(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Made with <3 by Yanis2"); } } void GZMenuManager::StartDraw() { - // don't ask me I have no idea how this works, feel free to improve - - prevDispCnt = REG_DISPCNT; prevDispCnt_Sub = REG_DISPCNT_SUB; - prevVRAM_CNT_B = REG_VRAM_CNT_B; - - DC_FlushAll(); - func_020131ec(); - REG_POWER_CNT |= 0x8000; - func_02023770(2); // no corruption when commented but no text - GX_SetGraphicsMode(1, 0, 0); - GXS_SetGraphicsMode(0); - - REG_DISPCNT = ((REG_DISPCNT & ~0x1F00) | 0x100); - REG_DISPCNT_SUB = (REG_DISPCNT_SUB & ~0x1F00) | 0x100; - func_0201b180(true, true); // loads the font (participate in the corruption also?) + REG_DISPCNT_SUB = (REG_DISPCNT_SUB & ~0x0400) | 0x100; // disable BG2 and make sure BG0 is enabled + func_0201b180(false, true); // loads the font (participate in the corruption also?) } void GZMenuManager::Draw() { - func_0201b278(true, true); // copy screen - func_020131ec(); - SetBrightColor((void*)®_MASTER_BRIGHT, 0); - SetBrightColor((void*)®_MASTER_BRIGHT_SUB, 0); - - if (func_020147a8() != 0) { - data_ov000_020b50c0.func_ov000_02069f58(); - } - - while (this->mState.isOpened && !this->mState.requestRedraw) { - func_020131ec(); - gGZ.Update(); - this->Update(); - } + func_0201b278(false, true); // copy screen } void GZMenuManager::StopDraw() { - if (gOverlayManager.mLoadedOverlays[OverlaySlot_4] == OverlayIndex_Title) { - GX_SetGraphicsMode(1, 0, 1); - GXS_SetGraphicsMode(5); - } - - memset((void*)0x068A0000, 0, 0x21A0); - REG_DISPCNT = prevDispCnt; REG_DISPCNT_SUB = prevDispCnt_Sub; - REG_VRAM_CNT_B = prevVRAM_CNT_B; + + // good solution to fix the map but the issue is also fixable with the painting stuff + // might better to figure that out instead + // if (data_027e0994 != NULL && data_027e09a4 != NULL && gGZ.IsAdventureMode()) { + // 99 because we load map99.bin + // data_027e0994->vfunc_38(data_027e09a4->mSceneIndex, 99, 0, 0); + // } } diff --git a/src/gz_settings.cpp b/src/gz_settings.cpp index 23dac38..92fbf28 100644 --- a/src/gz_settings.cpp +++ b/src/gz_settings.cpp @@ -33,32 +33,25 @@ void GZSettings::Update() { this->ProcessTitleScreen(); } void GZSettings::ProcessTitleScreen() { GZProfile* pProfile = this->GetProfile(); - if (!pProfile->mFasterTitleScreen && !pProfile->mSkipTitleScreen) { + if (data_027e0994 == NULL || (!pProfile->mFasterTitleScreen && !pProfile->mSkipTitleScreen)) { return; } - if (!gGZ.IsTitleScreen()) { - return; - } - - if (data_027e0994 == NULL && data_027e0994->mpTitleScreen == NULL) { - return; - } + TitleScreen* pTitleScreen = data_027e0994->GetTitleScreen(); - if (data_027e0994->mpTitleScreen->mShowUI) { + if (!gGZ.IsTitleScreen() || pTitleScreen == NULL || pTitleScreen->mShowUI) { return; } - data_027e0994->mpTitleScreen->func_ov025_020c4e54(); + pTitleScreen->func_ov025_020c4e54(); if (pProfile->mSkipTitleScreen) { data_ov000_020b5214.func_ov000_0206db44(0x0B); - data_027e0994->mpTitleScreen->func_ov025_020c4ea0(TitleScreenState_ToFileSelect); + pTitleScreen->func_ov025_020c4ea0(TitleScreenState_ToFileSelect); } } static GZProfile sDefaultProfile = { - .profileIndex = 0xF0, .mFasterTitleScreen = true, .mSkipTitleScreen = true, .mPositionIndex = 0, From d3962b76ac620d8462431df932a4af5044b85122 Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:08:30 +0100 Subject: [PATCH 2/7] complete reimplementing existing stuff --- include/gz_menu.hpp | 10 ++-- src/gz_commands.cpp | 10 +++- src/gz_menu.cpp | 108 ++++++++++++++++++++++---------------------- 3 files changed, 69 insertions(+), 59 deletions(-) diff --git a/include/gz_menu.hpp b/include/gz_menu.hpp index 9e3b4bb..387a3e1 100644 --- a/include/gz_menu.hpp +++ b/include/gz_menu.hpp @@ -34,6 +34,7 @@ struct GZMenuItem { }; struct GZMenu { + GZMenu* parent; GZMenuItem* entries; s32 mCount; bool needSaveFile; @@ -80,7 +81,6 @@ class GZMenuManager { public: GZMenuState mState; GZMenu* mpActiveMenu; - GZMenu* mpPrevMenu; GZMenuControls mControls; Input* mpButtons; @@ -93,15 +93,19 @@ class GZMenuManager { this->mState.isOpened = false; } - GZMenuItem* GetActiveMenuItem() { return &this->mpActiveMenu->entries[this->mState.itemIndex]; } + GZMenuItem* GetActiveMenuItem() { + return this->mState.itemIndex == 0 ? NULL : &this->mpActiveMenu->entries[this->mState.itemIndex - 1]; + } + bool IsMainMenuActive(); bool IsInventoryMenuActive(); bool IsAmountsMenuActive(); bool IsCommandsMenuActive(); bool IsSettingsMenuActive(); bool IsAboutMenuActive(); - void SetAmountString(s16 index, Vec2b* pPos, bool selected); + GZMenu* GetMainMenu(); + void SetAmountString(InventoryAmountType eType, Vec2b* pPos, bool selected); void ValidateNewIncrement(); void AssignPrevMenu(); void Update(); // update routine diff --git a/src/gz_commands.cpp b/src/gz_commands.cpp index ea7eb8c..7a5fec2 100644 --- a/src/gz_commands.cpp +++ b/src/gz_commands.cpp @@ -96,12 +96,18 @@ GZCommandManager::GZCommandManager() { } void GZCommandManager::CreateMenuItems() { - this->mMenu.entries = new GZMenuItem[ARRAY_LEN(sCommands)]; + this->mMenu.parent = gMenuManager.GetMainMenu(); + this->mMenu.mCount = ARRAY_LEN(sCommands); + this->mMenu.entries = new GZMenuItem[this->mMenu.mCount]; + this->mMenu.needSaveFile = false; + this->mMenu.itemIndex = 0; - for (int i = 0; i < ARRAY_LEN(sCommands); i++) { + for (int i = 0; i < this->mMenu.mCount; i++) { this->mMenu.entries[i].name = sCommands[i].btnCombo.name; this->mMenu.entries[i].action = sCommands[i].actionCallback; + this->mMenu.entries[i].params = 0; this->mMenu.entries[i].submenu = NULL; + this->mMenu.entries[i].value = 0; } } diff --git a/src/gz_menu.cpp b/src/gz_menu.cpp index 1d9f3cd..db05522 100644 --- a/src/gz_menu.cpp +++ b/src/gz_menu.cpp @@ -51,12 +51,6 @@ - About */ -/* -TODO LIST: -- OBJ toggle (~0x1400) -- reimplement about menu and back/quit -*/ - struct Screen { /* 00 */ u16 width; /* 02 */ u16 height; @@ -69,17 +63,11 @@ extern Screen data_0204d9d0[2]; extern "C" void DisplayDebugText(int, void*, int, int, const char*); extern "C" void DisplayDebugTextF(int, void*, int, int, const char*, ...); -extern "C" void DC_FlushAll(); -extern "C" void func_020131ec(); -extern "C" void GX_SetGraphicsMode(int, int, int); extern "C" void GXS_SetGraphicsMode(int); extern "C" void func_0201b180(bool, bool); -extern "C" unk32 func_020147a8(); -extern "C" void func_0201b278(bool, bool); -extern "C" void SetBrightColor(void*, int); +extern "C" void func_02027654(void*, int); // DC_FlushRange +extern "C" void func_020252ec(void*, int, int); // GX0_LoadBG0Scr -static void Quit(u32 params); -static void Back(u32 params); static void UpdateInventory(u32 params); static void UpdateAmounts(u32 params); @@ -136,27 +124,20 @@ static GZMenuItem sSettingsMenuItems[] = { }; static GZMenuItem sMainMenuItems[] = { - {"Inventory", NULL, 0, &sInventoryMenu, 0}, - {"Collection", NULL, 0, &sCollectionMenu, 0}, - {"Settings", NULL, 0, &sSettingsMenu, 0}, - {"Commands", NULL, 0, &gCommandManager.mMenu, 0}, + {"Inventory", NULL, 0, &sInventoryMenu, 0}, {"Collection", NULL, 0, &sCollectionMenu, 0}, + {"Settings", NULL, 0, &sSettingsMenu, 0}, {"Commands", NULL, 0, &gCommandManager.mMenu, 0}, + {"About", NULL, 0, &sAboutMenu, 0}, }; // pointer to the item list, number of items, pointer to the previous menu -GZMenu sMainMenu = {sMainMenuItems, ARRAY_LEN(sMainMenuItems), false, 0}; -GZMenu sInventoryMenu = {sInventoryMenuItems, ARRAY_LEN(sInventoryMenuItems), true, 0}; -GZMenu sAmountsMenu = {sAmountsMenuItems, ARRAY_LEN(sAmountsMenuItems), true, 0}; -GZMenu sCollectionMenu = {sCollectionMenuItems, ARRAY_LEN(sCollectionMenuItems), true, 0}; -GZMenu sSettingsMenu = {sSettingsMenuItems, ARRAY_LEN(sSettingsMenuItems), false, 0}; -// GZMenu sCommandsMenu = {sCommandsMenuItems, ARRAY_LEN(sCommandsMenuItems), 0}; -// GZMenu sAboutMenu = {sAboutMenuItems, ARRAY_LEN(sAboutMenuItems), 0}; - -static void Quit(u32 params) { gMenuManager.Quit(); } - -static void Back(u32 params) { gMenuManager.AssignPrevMenu(); } +GZMenu sMainMenu = {NULL, sMainMenuItems, ARRAY_LEN(sMainMenuItems), false, 0}; +GZMenu sInventoryMenu = {&sMainMenu, sInventoryMenuItems, ARRAY_LEN(sInventoryMenuItems), true, 0}; +GZMenu sAmountsMenu = {&sInventoryMenu, sAmountsMenuItems, ARRAY_LEN(sAmountsMenuItems), true, 0}; +GZMenu sCollectionMenu = {&sMainMenu, sCollectionMenuItems, ARRAY_LEN(sCollectionMenuItems), true, 0}; +GZMenu sSettingsMenu = {&sMainMenu, sSettingsMenuItems, ARRAY_LEN(sSettingsMenuItems), false, 0}; +GZMenu sAboutMenu = {&sMainMenu, NULL, 0, false, 0}; static void UpdateInventory(u32 params) { - GZMenuItem* pActiveMenuItem = gMenuManager.GetActiveMenuItem(); ItemFlag eFlag = params & 0xFF; if (data_027e0ce0 == NULL || data_027e0ce0->mUnk_28 == NULL) { @@ -185,7 +166,7 @@ static void UpdateAmounts(u32 params) { GZMenuItem* pActiveMenuItem = gMenuManager.GetActiveMenuItem(); InventoryAmountType eType = (InventoryAmountType)(params & 0xFF); - if (data_027e0ce0 == NULL || data_027e0ce0->mUnk_28 == NULL) { + if (pActiveMenuItem == NULL || data_027e0ce0 == NULL || data_027e0ce0->mUnk_28 == NULL) { return; } @@ -264,6 +245,10 @@ GZMenuManager::GZMenuManager() { memset(&data_0204d9d0[DRAW_TO_TOP_SCREEN], 0, sizeof(Screen)); } +GZMenu* GZMenuManager::GetMainMenu() { return &sMainMenu; } + +bool GZMenuManager::IsMainMenuActive() { return this->mpActiveMenu == &sMainMenu; } + bool GZMenuManager::IsInventoryMenuActive() { return this->mpActiveMenu == &sInventoryMenu; } bool GZMenuManager::IsAmountsMenuActive() { return this->mpActiveMenu == &sAmountsMenu; } @@ -272,12 +257,13 @@ bool GZMenuManager::IsCommandsMenuActive() { return this->mpActiveMenu == &gComm bool GZMenuManager::IsSettingsMenuActive() { return this->mpActiveMenu == &sSettingsMenu; } -bool GZMenuManager::IsAboutMenuActive() { return false; } // this->mpActiveMenu == &sAboutMenu; } +bool GZMenuManager::IsAboutMenuActive() { return this->mpActiveMenu == &sAboutMenu; } void GZMenuManager::ValidateNewIncrement() { GZMenuItem* pActiveMenuItem = this->GetActiveMenuItem(); - if (this->mState.itemIndex == 0) { + // redundant but whatever + if (pActiveMenuItem == NULL || this->mState.itemIndex == 0) { return; } @@ -332,10 +318,8 @@ void GZMenuManager::ValidateNewIncrement() { } void GZMenuManager::AssignPrevMenu() { - if (this->mpPrevMenu != NULL) { - GZMenu* pPrevMenu = this->mpActiveMenu; - this->mpActiveMenu = this->mpPrevMenu; - this->mpPrevMenu = pPrevMenu; + if (this->mpActiveMenu->parent != NULL) { + this->mpActiveMenu = this->mpActiveMenu->parent; this->mState.itemIndex = 0; this->mState.requestRedraw = true; } @@ -373,13 +357,13 @@ void GZMenuManager::Update() { } if (this->mControls.down.Executed(this->mpButtons)) { - if (this->mState.itemIndex + 1 < this->mpActiveMenu->mCount) { + if (this->mState.itemIndex + 1 < this->mpActiveMenu->mCount + 1) { this->mState.itemIndex++; this->mState.requestRedraw = true; } } - if (this->IsAmountsMenuActive()) { + if (this->IsAmountsMenuActive() && pActiveMenuItem != NULL) { bool changed = false; if (this->mControls.decrease.Executed(this->mpButtons)) { @@ -399,17 +383,26 @@ void GZMenuManager::Update() { if (this->mControls.ok.Executed(this->mpButtons)) { // handle confirmation stuff - if (!this->mpActiveMenu->needSaveFile || (this->mpActiveMenu->needSaveFile && gGZ.IsAdventureMode())) { - if ((!this->IsAmountsMenuActive() || this->mState.itemIndex == 0) && pActiveMenuItem->action != NULL) { - pActiveMenuItem->action(pActiveMenuItem->params); + // null when "back" or "quit" is selected + if (pActiveMenuItem != NULL) { + if (!this->mpActiveMenu->needSaveFile || (this->mpActiveMenu->needSaveFile && gGZ.IsAdventureMode())) { + if ((!this->IsAmountsMenuActive() || this->mState.itemIndex == 0) && pActiveMenuItem->action != NULL) { + pActiveMenuItem->action(pActiveMenuItem->params); - if (this->IsInventoryMenuActive()) { + if (this->IsInventoryMenuActive()) { + this->mState.requestRedraw = true; + } + } else if (pActiveMenuItem->submenu != NULL) { + this->mpActiveMenu = pActiveMenuItem->submenu; + this->mState.itemIndex = 0; this->mState.requestRedraw = true; } - } else if (pActiveMenuItem->submenu != NULL) { - this->mpActiveMenu = pActiveMenuItem->submenu; - this->mState.itemIndex = 0; - this->mState.requestRedraw = true; + } + } else { + if (this->IsMainMenuActive()) { + this->Quit(); + } else { + this->AssignPrevMenu(); } } } @@ -433,7 +426,7 @@ void GZMenuManager::Update() { } } -void GZMenuManager::SetAmountString(s16 index, Vec2b* pPos, bool selected) { +void GZMenuManager::SetAmountString(InventoryAmountType eType, Vec2b* pPos, bool selected) { u8 maxArrows = data_027e0ce0->mUnk_28->func_ov000_020a8728(); u8 maxBombs = data_027e0ce0->mUnk_28->func_ov000_020a8748(); @@ -444,7 +437,7 @@ void GZMenuManager::SetAmountString(s16 index, Vec2b* pPos, bool selected) { "Yellow Potion", // PotionType_Yellow }; - switch (index - 1) { + switch (eType) { case InventoryAmountType_Bow: if (data_027e0ce0 != NULL && data_027e0ce0->mUnk_28 != NULL) { DisplayDebugTextF(DRAW_TO_TOP_SCREEN, pPos, 0, selected, " (%d/%d)", @@ -485,11 +478,16 @@ void GZMenuManager::SetAmountString(s16 index, Vec2b* pPos, bool selected) { } void GZMenuManager::SetupScreen() { + Vec2b elemPos = this->mState.menuPos; + // reset the top screen buffer memset(&data_0204d9d0[DRAW_TO_TOP_SCREEN], 0, sizeof(Screen)); // send the menu item strings to the buffer - Vec2b elemPos = this->mState.menuPos; + const char* retStr = this->IsMainMenuActive() ? "Quit" : "Back"; + DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, this->mState.itemIndex == 0, retStr); + elemPos.y++; + if (this->IsCommandsMenuActive()) { gCommandManager.Draw(&elemPos); } else { @@ -497,14 +495,14 @@ void GZMenuManager::SetupScreen() { GZMenuItem* pActiveMenuItem = &this->mpActiveMenu->entries[i]; const char* szName = pActiveMenuItem->name; Vec2b extraPos = elemPos; - bool selected = i == this->mState.itemIndex; + bool selected = i + 1 == this->mState.itemIndex; extraPos.x += strlen(szName); // 0 = white, 1 = red, 2 = darker red, 3 = dark green DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, selected, szName); if (this->IsAmountsMenuActive()) { - this->SetAmountString(i, &extraPos, selected); + this->SetAmountString((InventoryAmountType)(pActiveMenuItem->params & 0xFF), &extraPos, selected); } else if (this->IsInventoryMenuActive() && pActiveMenuItem->submenu == NULL) { bool hasItem = GET_FLAG(data_027e0ce0->mUnk_28->mUnk_08, pActiveMenuItem->params & 0xFF); DisplayDebugText(DRAW_TO_TOP_SCREEN, &extraPos, 0, selected, @@ -552,7 +550,7 @@ void GZMenuManager::SetupScreen() { aboutPos.y++; DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Commit Name: %s", gCommitGitString); - aboutPos.y += 16; + aboutPos.y += 15; DisplayDebugText(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Licensed under GPL-3.0"); aboutPos.y++; @@ -567,7 +565,9 @@ void GZMenuManager::StartDraw() { } void GZMenuManager::Draw() { - func_0201b278(false, true); // copy screen + // copy screen + func_02027654(data_0204d9d0[DRAW_TO_TOP_SCREEN].data, sizeof(data_0204d9d0[DRAW_TO_TOP_SCREEN].data)); + func_020252ec(data_0204d9d0[DRAW_TO_TOP_SCREEN].data, 0, sizeof(data_0204d9d0[DRAW_TO_TOP_SCREEN].data)); } void GZMenuManager::StopDraw() { From bcad802300a0686a11e450e8bb9e83b60e6a5e62 Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Mon, 16 Feb 2026 02:03:25 +0100 Subject: [PATCH 3/7] "fix" some visual glitches while on train --- include/gz.hpp | 2 + src/gz_menu.cpp | 100 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 89 insertions(+), 13 deletions(-) diff --git a/include/gz.hpp b/include/gz.hpp index df1394d..91e6995 100644 --- a/include/gz.hpp +++ b/include/gz.hpp @@ -55,6 +55,8 @@ class GZ { bool IsOnLand() { return gOverlayManager.mLoadedOverlays[OverlaySlot_6] == OverlayIndex_Land; } + bool IsSceneInit() { return gOverlayManager.mLoadedOverlays[OverlaySlot_1] == OverlayIndex_SceneInit; } + // global init void Init(); diff --git a/src/gz_menu.cpp b/src/gz_menu.cpp index db05522..8b1a833 100644 --- a/src/gz_menu.cpp +++ b/src/gz_menu.cpp @@ -77,13 +77,34 @@ static void NextProfile(u32 params); static void LoadDefaultProfile(u32 params); static void SaveSettings(u32 params); +// display menu + +static void UpdateRegs(u32 params); + extern GZMenu sMainMenu; extern GZMenu sInventoryMenu; extern GZMenu sAmountsMenu; extern GZMenu sCollectionMenu; extern GZMenu sSettingsMenu; +extern GZMenu sDebugMenu; +extern GZMenu sRegsMenu; extern GZMenu sAboutMenu; +// clang-format off + +// -- main menu items -- + +static GZMenuItem sMainMenuItems[] = { + {"Inventory", NULL, 0, &sInventoryMenu, 0}, + {"Collection", NULL, 0, &sCollectionMenu, 0}, + {"Commands", NULL, 0, &gCommandManager.mMenu, 0}, + {"Debug", NULL, 0, &sDebugMenu, 0}, + {"Settings", NULL, 0, &sSettingsMenu, 0}, + {"About", NULL, 0, &sAboutMenu, 0}, +}; + +// -- inventory menu items -- + static GZMenuItem sInventoryMenuItems[] = { {"Whirlwind", UpdateInventory, ItemFlag_Whirlwind, NULL, 0}, {"Boomerang", UpdateInventory, ItemFlag_Boomerang, NULL, 0}, @@ -105,6 +126,8 @@ static GZMenuItem sAmountsMenuItems[] = { {"Light Tears", UpdateAmounts, InventoryAmountType_LightTears, NULL, 0}, }; +// -- collection menu items -- + static GZMenuItem sCollectionMenuItems[] = { {"Shield", UpdateInventory, ItemFlag_Shield, NULL, 0}, {"Sword", UpdateInventory, ItemFlag_Sword, NULL, 0}, @@ -116,6 +139,8 @@ static GZMenuItem sCollectionMenuItems[] = { {"PanFlute", UpdateInventory, ItemFlag_PanFlute, NULL, 0}, }; +// -- settings menu items -- + static GZMenuItem sSettingsMenuItems[] = { {"Prev Profile", PrevProfile, 0, NULL, 0}, {"Next Profile", NextProfile, 0, NULL, 0}, @@ -123,19 +148,33 @@ static GZMenuItem sSettingsMenuItems[] = { {"Save Settings", SaveSettings, 0, NULL, 0}, }; -static GZMenuItem sMainMenuItems[] = { - {"Inventory", NULL, 0, &sInventoryMenu, 0}, {"Collection", NULL, 0, &sCollectionMenu, 0}, - {"Settings", NULL, 0, &sSettingsMenu, 0}, {"Commands", NULL, 0, &gCommandManager.mMenu, 0}, - {"About", NULL, 0, &sAboutMenu, 0}, +// -- debug menu items -- + +static GZMenuItem sDebugMenuItems[] = { + {"Regs", NULL, 0, &sRegsMenu, 0}, +}; + +static GZMenuItem sRegsMenuItems[] = { + {"Init. State", UpdateRegs, 0xFF, NULL, 0}, + {"Toggle BG1", UpdateRegs, 9, NULL, 0}, + {"Toggle BG2", UpdateRegs, 10, NULL, 0}, + {"Toggle BG3", UpdateRegs, 11, NULL, 0}, + {"Toggle OBJ", UpdateRegs, 12, NULL, 0}, }; -// pointer to the item list, number of items, pointer to the previous menu +// -- menu list -- + +// pointer to parent menu, pointer to items, number of items, does it require adventure mode, internal value GZMenu sMainMenu = {NULL, sMainMenuItems, ARRAY_LEN(sMainMenuItems), false, 0}; GZMenu sInventoryMenu = {&sMainMenu, sInventoryMenuItems, ARRAY_LEN(sInventoryMenuItems), true, 0}; GZMenu sAmountsMenu = {&sInventoryMenu, sAmountsMenuItems, ARRAY_LEN(sAmountsMenuItems), true, 0}; GZMenu sCollectionMenu = {&sMainMenu, sCollectionMenuItems, ARRAY_LEN(sCollectionMenuItems), true, 0}; GZMenu sSettingsMenu = {&sMainMenu, sSettingsMenuItems, ARRAY_LEN(sSettingsMenuItems), false, 0}; GZMenu sAboutMenu = {&sMainMenu, NULL, 0, false, 0}; +GZMenu sDebugMenu = {&sMainMenu, sDebugMenuItems, ARRAY_LEN(sDebugMenuItems), false, 0}; +GZMenu sRegsMenu = {&sDebugMenu, sRegsMenuItems, ARRAY_LEN(sRegsMenuItems), false, 0}; + +// clang-format on static void UpdateInventory(u32 params) { ItemFlag eFlag = params & 0xFF; @@ -234,7 +273,33 @@ static void SaveSettings(u32 params) { gMenuManager.mState.requestRedraw = true; } +static void UpdateRegs(u32 params) { + static u32 dispCnt = 0xFF; + + if (params == 0xFF) { + REG_DISPCNT_SUB = dispCnt; + } else { + if (dispCnt == 0xFF) { + dispCnt = REG_DISPCNT_SUB; + } + + u32 value = 1 << params; + + if (REG_DISPCNT_SUB & value) { + REG_DISPCNT_SUB &= ~value; + } else { + REG_DISPCNT_SUB |= value; + } + } +} + static u32 prevDispCnt_Sub; +static vu16 prevBG0Cnt_Sub; + +//! TODO: find a better way to avoid display glitches +// for now we back up BG0 VRAM and palettes data and restore them when done +static u8 prevBG0VRAM[0x1430]; // size of "DbgFntM.NCGR" +static u8 prevBGPalettes[0x400]; // size of sub palettes space GZMenuManager gMenuManager; @@ -560,8 +625,19 @@ void GZMenuManager::SetupScreen() { void GZMenuManager::StartDraw() { prevDispCnt_Sub = REG_DISPCNT_SUB; + prevBG0Cnt_Sub = REG_BG0CNT_SUB; + Copy256((void*)0x06208000, prevBG0VRAM, sizeof(prevBG0VRAM)); + Copy256((void*)0x05000400, prevBGPalettes, sizeof(prevBGPalettes)); + REG_DISPCNT_SUB = (REG_DISPCNT_SUB & ~0x0400) | 0x100; // disable BG2 and make sure BG0 is enabled - func_0201b180(false, true); // loads the font (participate in the corruption also?) + REG_BG0CNT_SUB &= ~3; // make BG0 on top of everything else + + if (gGZ.IsAdventureMode() && !gGZ.IsOnLand()) { + //! TODO: fix issue where the font is displayed on the screen + REG_DISPCNT_SUB &= ~0x0200; // disable BG1 for the overworld + } + + func_0201b180(false, true); // loads the font } void GZMenuManager::Draw() { @@ -572,11 +648,9 @@ void GZMenuManager::Draw() { void GZMenuManager::StopDraw() { REG_DISPCNT_SUB = prevDispCnt_Sub; - - // good solution to fix the map but the issue is also fixable with the painting stuff - // might better to figure that out instead - // if (data_027e0994 != NULL && data_027e09a4 != NULL && gGZ.IsAdventureMode()) { - // 99 because we load map99.bin - // data_027e0994->vfunc_38(data_027e09a4->mSceneIndex, 99, 0, 0); - // } + REG_BG0CNT_SUB = prevBG0Cnt_Sub; + func_02027654(prevBG0VRAM, sizeof(prevBG0VRAM)); + Copy256(prevBG0VRAM, (void*)0x06208000, sizeof(prevBG0VRAM)); + func_02027654(prevBGPalettes, sizeof(prevBGPalettes)); + Copy256(prevBGPalettes, (void*)0x05000400, sizeof(prevBGPalettes)); } From 7ddaa54e43dc42f29571a2473e32f6e138f614d5 Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Mon, 16 Feb 2026 02:56:53 +0100 Subject: [PATCH 4/7] menu improvements --- include/common.hpp | 1 + include/gz_menu.hpp | 20 +++++- src/gz_commands.cpp | 1 + src/gz_menu.cpp | 154 +++++++++++++++++++++++--------------------- 4 files changed, 98 insertions(+), 78 deletions(-) diff --git a/include/common.hpp b/include/common.hpp index 7120b9f..3094bf3 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -3,3 +3,4 @@ #include typedef void (*GZAction)(u32 params); +typedef bool (*GZCheckCallback)(int itemIndex); diff --git a/include/gz_menu.hpp b/include/gz_menu.hpp index 387a3e1..360d778 100644 --- a/include/gz_menu.hpp +++ b/include/gz_menu.hpp @@ -13,7 +13,8 @@ struct GZMenu; -typedef enum InventoryAmountType { +typedef u32 InventoryAmountType; +enum InventoryAmountType_ { InventoryAmountType_Bow, InventoryAmountType_Bombs, InventoryAmountType_QuiverCapacity, @@ -23,13 +24,24 @@ typedef enum InventoryAmountType { InventoryAmountType_SmallKeys, InventoryAmountType_LightTears, InventoryAmountType_Max -} InventoryAmountType; +}; + +typedef u32 GZMenuItemType; +enum GZMenuItemType_ { + GZMenuItemType_Default, + GZMenuItemType_Bool, + GZMenuItemType_Increment, +}; struct GZMenuItem { const char* name; + GZMenuItemType eType; + GZCheckCallback checkCallback; // must be set when using `GZMenuItemType_Bool` GZAction action; u32 params; GZMenu* submenu; + + // internal int value; }; @@ -38,6 +50,8 @@ struct GZMenu { GZMenuItem* entries; s32 mCount; bool needSaveFile; + + // internal s16 itemIndex; }; @@ -106,7 +120,7 @@ class GZMenuManager { GZMenu* GetMainMenu(); void SetAmountString(InventoryAmountType eType, Vec2b* pPos, bool selected); - void ValidateNewIncrement(); + void ValidateAmountIncrement(); void AssignPrevMenu(); void Update(); // update routine void SetupScreen(); // creates the strings etc diff --git a/src/gz_commands.cpp b/src/gz_commands.cpp index 7a5fec2..02d9bde 100644 --- a/src/gz_commands.cpp +++ b/src/gz_commands.cpp @@ -104,6 +104,7 @@ void GZCommandManager::CreateMenuItems() { for (int i = 0; i < this->mMenu.mCount; i++) { this->mMenu.entries[i].name = sCommands[i].btnCombo.name; + this->mMenu.entries[i].eType = GZMenuItemType_Default; this->mMenu.entries[i].action = sCommands[i].actionCallback; this->mMenu.entries[i].params = 0; this->mMenu.entries[i].submenu = NULL; diff --git a/src/gz_menu.cpp b/src/gz_menu.cpp index 8b1a833..bf62bf7 100644 --- a/src/gz_menu.cpp +++ b/src/gz_menu.cpp @@ -68,19 +68,6 @@ extern "C" void func_0201b180(bool, bool); extern "C" void func_02027654(void*, int); // DC_FlushRange extern "C" void func_020252ec(void*, int, int); // GX0_LoadBG0Scr -static void UpdateInventory(u32 params); -static void UpdateAmounts(u32 params); - -// settings menu -static void PrevProfile(u32 params); -static void NextProfile(u32 params); -static void LoadDefaultProfile(u32 params); -static void SaveSettings(u32 params); - -// display menu - -static void UpdateRegs(u32 params); - extern GZMenu sMainMenu; extern GZMenu sInventoryMenu; extern GZMenu sAmountsMenu; @@ -95,71 +82,84 @@ extern GZMenu sAboutMenu; // -- main menu items -- static GZMenuItem sMainMenuItems[] = { - {"Inventory", NULL, 0, &sInventoryMenu, 0}, - {"Collection", NULL, 0, &sCollectionMenu, 0}, - {"Commands", NULL, 0, &gCommandManager.mMenu, 0}, - {"Debug", NULL, 0, &sDebugMenu, 0}, - {"Settings", NULL, 0, &sSettingsMenu, 0}, - {"About", NULL, 0, &sAboutMenu, 0}, + {"Inventory", GZMenuItemType_Default, NULL, NULL, 0, &sInventoryMenu, 0}, + {"Collection", GZMenuItemType_Default, NULL, NULL, 0, &sCollectionMenu, 0}, + {"Commands", GZMenuItemType_Default, NULL, NULL, 0, &gCommandManager.mMenu, 0}, + {"Debug", GZMenuItemType_Default, NULL, NULL, 0, &sDebugMenu, 0}, + {"Settings", GZMenuItemType_Default, NULL, NULL, 0, &sSettingsMenu, 0}, + {"About", GZMenuItemType_Default, NULL, NULL, 0, &sAboutMenu, 0}, }; // -- inventory menu items -- +static void UpdateInventory(u32 params); +static bool HasObtainedItem(int itemIndex); + static GZMenuItem sInventoryMenuItems[] = { - {"Whirlwind", UpdateInventory, ItemFlag_Whirlwind, NULL, 0}, - {"Boomerang", UpdateInventory, ItemFlag_Boomerang, NULL, 0}, - {"Whip", UpdateInventory, ItemFlag_Whip, NULL, 0}, - {"Bow", UpdateInventory, ItemFlag_Bow, NULL, 0}, - {"Bombs", UpdateInventory, ItemFlag_Bombs, NULL, 0}, - {"SandRod", UpdateInventory, ItemFlag_SandRod, NULL, 0}, - {"Amounts", NULL, 0, &sAmountsMenu, 0}, + {"Amounts", GZMenuItemType_Default, NULL, NULL, 0, &sAmountsMenu, 0}, + {"Whirlwind", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_Whirlwind, NULL, 0}, + {"Boomerang", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_Boomerang, NULL, 0}, + {"Whip", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_Whip, NULL, 0}, + {"Bow", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_Bow, NULL, 0}, + {"Bombs", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_Bombs, NULL, 0}, + {"SandRod", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_SandRod, NULL, 0}, }; +static void UpdateAmounts(u32 params); + static GZMenuItem sAmountsMenuItems[] = { - {"Bow", UpdateAmounts, InventoryAmountType_Bow, NULL, 0}, - {"Bombs", UpdateAmounts, InventoryAmountType_Bombs, NULL, 0}, - {"Quiver Capacity", UpdateAmounts, InventoryAmountType_QuiverCapacity, NULL, 0}, - {"Bomb Bag Capacity", UpdateAmounts, InventoryAmountType_BombCapacity, NULL, 0}, - {"Potion 1", UpdateAmounts, InventoryAmountType_Potion1, NULL, 0}, - {"Potion 2", UpdateAmounts, InventoryAmountType_Potion2, NULL, 0}, - {"Small Keys", UpdateAmounts, InventoryAmountType_SmallKeys, NULL, 0}, - {"Light Tears", UpdateAmounts, InventoryAmountType_LightTears, NULL, 0}, + {"Bow", GZMenuItemType_Increment, NULL, UpdateAmounts, InventoryAmountType_Bow, NULL, 0}, + {"Bombs", GZMenuItemType_Increment, NULL, UpdateAmounts, InventoryAmountType_Bombs, NULL, 0}, + {"Quiver Capacity", GZMenuItemType_Increment, NULL, UpdateAmounts, InventoryAmountType_QuiverCapacity, NULL, 0}, + {"Bomb Bag Capacity", GZMenuItemType_Increment, NULL, UpdateAmounts, InventoryAmountType_BombCapacity, NULL, 0}, + {"Potion 1", GZMenuItemType_Increment, NULL, UpdateAmounts, InventoryAmountType_Potion1, NULL, 0}, + {"Potion 2", GZMenuItemType_Increment, NULL, UpdateAmounts, InventoryAmountType_Potion2, NULL, 0}, + {"Small Keys", GZMenuItemType_Increment, NULL, UpdateAmounts, InventoryAmountType_SmallKeys, NULL, 0}, + {"Light Tears", GZMenuItemType_Increment, NULL, UpdateAmounts, InventoryAmountType_LightTears, NULL, 0}, }; // -- collection menu items -- static GZMenuItem sCollectionMenuItems[] = { - {"Shield", UpdateInventory, ItemFlag_Shield, NULL, 0}, - {"Sword", UpdateInventory, ItemFlag_Sword, NULL, 0}, - {"LokomoSword", UpdateInventory, ItemFlag_LokomoSword, NULL, 0}, - {"RecruitUniform", UpdateInventory, ItemFlag_RecruitUniform, NULL, 0}, - {"ScrollBeam", UpdateInventory, ItemFlag_ScrollBeam, NULL, 0}, - {"ScrollSpinAttack", UpdateInventory, ItemFlag_ScrollSpinAttack, NULL, 0}, - {"AncientShield", UpdateInventory, ItemFlag_AncientShield, NULL, 0}, - {"PanFlute", UpdateInventory, ItemFlag_PanFlute, NULL, 0}, + {"Shield", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_Shield, NULL, 0}, + {"Sword", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_Sword, NULL, 0}, + {"LokomoSword", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_LokomoSword, NULL, 0}, + {"RecruitUniform", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_RecruitUniform, NULL, 0}, + {"ScrollBeam", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_ScrollBeam, NULL, 0}, + {"ScrollSpinAttack", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_ScrollSpinAttack, NULL, 0}, + {"AncientShield", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_AncientShield, NULL, 0}, + {"PanFlute", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_PanFlute, NULL, 0}, }; // -- settings menu items -- +static void PrevProfile(u32 params); +static void NextProfile(u32 params); +static void LoadDefaultProfile(u32 params); +static void SaveSettings(u32 params); + static GZMenuItem sSettingsMenuItems[] = { - {"Prev Profile", PrevProfile, 0, NULL, 0}, - {"Next Profile", NextProfile, 0, NULL, 0}, - {"Load Default Profile", LoadDefaultProfile, 0, NULL, 0}, - {"Save Settings", SaveSettings, 0, NULL, 0}, + {"Prev Profile", GZMenuItemType_Default, NULL, PrevProfile, 0, NULL, 0}, + {"Next Profile", GZMenuItemType_Default, NULL, NextProfile, 0, NULL, 0}, + {"Load Default Profile", GZMenuItemType_Default, NULL, LoadDefaultProfile, 0, NULL, 0}, + {"Save Settings", GZMenuItemType_Default, NULL, SaveSettings, 0, NULL, 0}, }; // -- debug menu items -- static GZMenuItem sDebugMenuItems[] = { - {"Regs", NULL, 0, &sRegsMenu, 0}, + {"Regs", GZMenuItemType_Default, NULL, NULL, 0, &sRegsMenu, 0}, }; +static void UpdateRegs(u32 params); +static bool IsLayerEnabled(int itemIndex); + static GZMenuItem sRegsMenuItems[] = { - {"Init. State", UpdateRegs, 0xFF, NULL, 0}, - {"Toggle BG1", UpdateRegs, 9, NULL, 0}, - {"Toggle BG2", UpdateRegs, 10, NULL, 0}, - {"Toggle BG3", UpdateRegs, 11, NULL, 0}, - {"Toggle OBJ", UpdateRegs, 12, NULL, 0}, + {"Init. State", GZMenuItemType_Default, NULL, UpdateRegs, 0xFF, NULL, 0}, + {"Toggle BG1", GZMenuItemType_Bool, IsLayerEnabled, UpdateRegs, 9, NULL, 0}, + {"Toggle BG2", GZMenuItemType_Bool, IsLayerEnabled, UpdateRegs, 10, NULL, 0}, + {"Toggle BG3", GZMenuItemType_Bool, IsLayerEnabled, UpdateRegs, 11, NULL, 0}, + {"Toggle OBJ", GZMenuItemType_Bool, IsLayerEnabled, UpdateRegs, 12, NULL, 0}, }; // -- menu list -- @@ -201,15 +201,19 @@ static void UpdateInventory(u32 params) { } } +static bool HasObtainedItem(int itemIndex) { + return GET_FLAG(data_027e0ce0->mUnk_28->mUnk_08, gMenuManager.mpActiveMenu->entries[itemIndex].params & 0xFF); +} + static void UpdateAmounts(u32 params) { GZMenuItem* pActiveMenuItem = gMenuManager.GetActiveMenuItem(); - InventoryAmountType eType = (InventoryAmountType)(params & 0xFF); + InventoryAmountType eType = params & 0xFF; if (pActiveMenuItem == NULL || data_027e0ce0 == NULL || data_027e0ce0->mUnk_28 == NULL) { return; } - gMenuManager.ValidateNewIncrement(); + gMenuManager.ValidateAmountIncrement(); switch (eType) { case InventoryAmountType_Bow: @@ -247,8 +251,6 @@ static void PrevProfile(u32 params) { } else { gSettings.mProfileHeader.curProfileIndex = 0; } - - gMenuManager.mState.requestRedraw = true; } static void NextProfile(u32 params) { @@ -257,20 +259,16 @@ static void NextProfile(u32 params) { if (gSettings.mProfileHeader.curProfileIndex >= ARRAY_LEN(gSettings.mProfiles)) { gSettings.mProfileHeader.curProfileIndex = ARRAY_LEN(gSettings.mProfiles) - 1; } - - gMenuManager.mState.requestRedraw = true; } static void LoadDefaultProfile(u32 params) { gSettings.LoadDefaultProfile(); gMenuManager.mState.successTimer = 90; - gMenuManager.mState.requestRedraw = true; } static void SaveSettings(u32 params) { gSettings.WriteSave(); gMenuManager.mState.successTimer = 90; - gMenuManager.mState.requestRedraw = true; } static void UpdateRegs(u32 params) { @@ -293,6 +291,12 @@ static void UpdateRegs(u32 params) { } } +static bool IsLayerEnabled(int itemIndex) { + GZMenuItem* pActiveItem = &gMenuManager.mpActiveMenu->entries[itemIndex]; + u32 value = 1 << (pActiveItem->params & 0x0F); + return REG_DISPCNT_SUB & value; +} + static u32 prevDispCnt_Sub; static vu16 prevBG0Cnt_Sub; @@ -324,7 +328,7 @@ bool GZMenuManager::IsSettingsMenuActive() { return this->mpActiveMenu == &sSett bool GZMenuManager::IsAboutMenuActive() { return this->mpActiveMenu == &sAboutMenu; } -void GZMenuManager::ValidateNewIncrement() { +void GZMenuManager::ValidateAmountIncrement() { GZMenuItem* pActiveMenuItem = this->GetActiveMenuItem(); // redundant but whatever @@ -399,6 +403,7 @@ void GZMenuManager::Update() { this->SetupScreen(); this->StartDraw(); this->mState.isOpened = true; + this->mState.requestRedraw = true; } else { this->Quit(); } @@ -428,7 +433,7 @@ void GZMenuManager::Update() { } } - if (this->IsAmountsMenuActive() && pActiveMenuItem != NULL) { + if (pActiveMenuItem != NULL && pActiveMenuItem->eType == GZMenuItemType_Increment) { bool changed = false; if (this->mControls.decrease.Executed(this->mpButtons)) { @@ -439,7 +444,8 @@ void GZMenuManager::Update() { changed = true; } - if (changed && this->mState.itemIndex > 0 && pActiveMenuItem->action != NULL) { + // for now only amounts is using increments + if (this->IsAmountsMenuActive() && changed && this->mState.itemIndex > 0 && pActiveMenuItem->action != NULL) { pActiveMenuItem->action(pActiveMenuItem->params); this->mState.requestRedraw = true; } @@ -453,15 +459,12 @@ void GZMenuManager::Update() { if (!this->mpActiveMenu->needSaveFile || (this->mpActiveMenu->needSaveFile && gGZ.IsAdventureMode())) { if ((!this->IsAmountsMenuActive() || this->mState.itemIndex == 0) && pActiveMenuItem->action != NULL) { pActiveMenuItem->action(pActiveMenuItem->params); - - if (this->IsInventoryMenuActive()) { - this->mState.requestRedraw = true; - } } else if (pActiveMenuItem->submenu != NULL) { this->mpActiveMenu = pActiveMenuItem->submenu; this->mState.itemIndex = 0; - this->mState.requestRedraw = true; } + + this->mState.requestRedraw = true; } } else { if (this->IsMainMenuActive()) { @@ -563,15 +566,16 @@ void GZMenuManager::SetupScreen() { bool selected = i + 1 == this->mState.itemIndex; extraPos.x += strlen(szName); - // 0 = white, 1 = red, 2 = darker red, 3 = dark green - DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, selected, szName); + if (pActiveMenuItem->eType == GZMenuItemType_Bool && pActiveMenuItem->checkCallback != NULL) { + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &elemPos, 0, selected, "[%s]%s", + pActiveMenuItem->checkCallback(i) ? "x" : " ", szName); + } else { + // 0 = white, 1 = red, 2 = darker red, 3 = dark green + DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, selected, szName); + } if (this->IsAmountsMenuActive()) { - this->SetAmountString((InventoryAmountType)(pActiveMenuItem->params & 0xFF), &extraPos, selected); - } else if (this->IsInventoryMenuActive() && pActiveMenuItem->submenu == NULL) { - bool hasItem = GET_FLAG(data_027e0ce0->mUnk_28->mUnk_08, pActiveMenuItem->params & 0xFF); - DisplayDebugText(DRAW_TO_TOP_SCREEN, &extraPos, 0, selected, - hasItem ? " (obtained)" : " (not obtained)"); + this->SetAmountString(pActiveMenuItem->params & 0xFF, &extraPos, selected); } else if (this->mpActiveMenu->needSaveFile && !gGZ.IsAdventureMode()) { DisplayDebugText(DRAW_TO_TOP_SCREEN, &extraPos, 0, selected, " (disabled)"); } From 0a4756d96d8964ab59e3eee2beb8e41b501a6d19 Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Mon, 16 Feb 2026 03:53:07 +0100 Subject: [PATCH 5/7] random improvements --- include/common.hpp | 3 +++ include/gz_commands.hpp | 2 +- include/gz_menu.hpp | 1 + include/gz_settings.hpp | 14 +++++++----- src/common.cpp | 22 ++++++++++++++++++ src/gz_commands.cpp | 5 +++-- src/gz_controls.cpp | 17 +------------- src/gz_menu.cpp | 49 +++++++++++++++++++++++++---------------- 8 files changed, 70 insertions(+), 43 deletions(-) create mode 100644 src/common.cpp diff --git a/include/common.hpp b/include/common.hpp index 3094bf3..b1956a0 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -4,3 +4,6 @@ typedef void (*GZAction)(u32 params); typedef bool (*GZCheckCallback)(int itemIndex); + +// from oot-gc +extern "C" char* strcat(char* dst, const char* src); diff --git a/include/gz_commands.hpp b/include/gz_commands.hpp index 1cc4600..d246ac3 100644 --- a/include/gz_commands.hpp +++ b/include/gz_commands.hpp @@ -21,7 +21,7 @@ class GZCommandManager { GZCommandManager(); - void CreateMenuItems(); + void InitMenu(); void Update(); void Draw(Vec2b* pPos); }; diff --git a/include/gz_menu.hpp b/include/gz_menu.hpp index 360d778..8c68c03 100644 --- a/include/gz_menu.hpp +++ b/include/gz_menu.hpp @@ -46,6 +46,7 @@ struct GZMenuItem { }; struct GZMenu { + const char* title; GZMenu* parent; GZMenuItem* entries; s32 mCount; diff --git a/include/gz_settings.hpp b/include/gz_settings.hpp index a1b460a..6ed7244 100644 --- a/include/gz_settings.hpp +++ b/include/gz_settings.hpp @@ -17,22 +17,26 @@ extern "C" void func_02030d58(u16 lockID); // CARD_UnlockBackup #define MAX_SAVE_PROFILES 8 extern "C" { +// IMPORTANT: do not reorder, retype or resize members!!! otherwise it will break older versions + typedef struct GZProfileHeader { u8 curProfileIndex; -} GZProfileHeader __attribute__((aligned(32))); +} GZProfileHeader; // the save file is large so we don't care about packing stuff to save space typedef struct GZProfile { bool mFasterTitleScreen; // goes into the "touch or start to exit" state immediately bool mSkipTitleScreen; // same as above except it jump straight into the file select without requiring any input - s8 mPositionIndex; + s16 mPositionIndex; Vec3p mLandPosSlots[MAX_POS_SLOTS]; Vec3p mTrainPosSlots[MAX_POS_SLOTS]; } GZProfile; -#define GZ_SAVE_OFFSET 0xF5000 -#define GZ_PROFILE_HEADER_OFFSET (GZ_SAVE_OFFSET) -#define GZ_PROFILES_OFFSET (GZ_SAVE_OFFSET + sizeof(GZProfileHeader)) +// profiles first because they might take a lot of space +#define GZ_PROFILES_OFFSET 0xF5000 + +// profile header at the end because the space it will take shouldn't be that large +#define GZ_PROFILE_HEADER_OFFSET 0xFFF00 } class GZSettings { diff --git a/src/common.cpp b/src/common.cpp new file mode 100644 index 0000000..737b289 --- /dev/null +++ b/src/common.cpp @@ -0,0 +1,22 @@ +#include "common.hpp" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wparentheses" + +// from oot-gc +extern "C" char* strcat(char* dst, const char* src) { + const u8* p = (u8*)src - 1; + u8* q = (u8*)dst - 1; + + while (*++q) + ; + + q--; + + while (*++q = *++p) + ; + + return (dst); +} + +#pragma GCC diagnostic pop diff --git a/src/gz_commands.cpp b/src/gz_commands.cpp index 02d9bde..ee65514 100644 --- a/src/gz_commands.cpp +++ b/src/gz_commands.cpp @@ -92,10 +92,11 @@ GZCommandManager gCommandManager; GZCommandManager::GZCommandManager() { this->mpButtons = &gGZ.mButtons; this->mpCommands = sCommands; - this->CreateMenuItems(); + this->InitMenu(); } -void GZCommandManager::CreateMenuItems() { +void GZCommandManager::InitMenu() { + this->mMenu.title = "Commands"; this->mMenu.parent = gMenuManager.GetMainMenu(); this->mMenu.mCount = ARRAY_LEN(sCommands); this->mMenu.entries = new GZMenuItem[this->mMenu.mCount]; diff --git a/src/gz_controls.cpp b/src/gz_controls.cpp index 4d8df6a..27d48d4 100644 --- a/src/gz_controls.cpp +++ b/src/gz_controls.cpp @@ -1,24 +1,9 @@ #include "gz_controls.hpp" +#include "common.hpp" #include #include -// from oot-gc -char* strcat(char* dst, const char* src) { - const u8* p = (u8*)src - 1; - u8* q = (u8*)dst - 1; - - while (*++q) - ; - - q--; - - while (*++q = *++p) - ; - - return (dst); -} - ButtonCombo::ButtonCombo() { this->name = NULL; this->Assign(BTN_NONE, BTN_NONE); diff --git a/src/gz_menu.cpp b/src/gz_menu.cpp index bf62bf7..749b06d 100644 --- a/src/gz_menu.cpp +++ b/src/gz_menu.cpp @@ -85,8 +85,8 @@ static GZMenuItem sMainMenuItems[] = { {"Inventory", GZMenuItemType_Default, NULL, NULL, 0, &sInventoryMenu, 0}, {"Collection", GZMenuItemType_Default, NULL, NULL, 0, &sCollectionMenu, 0}, {"Commands", GZMenuItemType_Default, NULL, NULL, 0, &gCommandManager.mMenu, 0}, - {"Debug", GZMenuItemType_Default, NULL, NULL, 0, &sDebugMenu, 0}, {"Settings", GZMenuItemType_Default, NULL, NULL, 0, &sSettingsMenu, 0}, + {"Debug", GZMenuItemType_Default, NULL, NULL, 0, &sDebugMenu, 0}, {"About", GZMenuItemType_Default, NULL, NULL, 0, &sAboutMenu, 0}, }; @@ -165,14 +165,14 @@ static GZMenuItem sRegsMenuItems[] = { // -- menu list -- // pointer to parent menu, pointer to items, number of items, does it require adventure mode, internal value -GZMenu sMainMenu = {NULL, sMainMenuItems, ARRAY_LEN(sMainMenuItems), false, 0}; -GZMenu sInventoryMenu = {&sMainMenu, sInventoryMenuItems, ARRAY_LEN(sInventoryMenuItems), true, 0}; -GZMenu sAmountsMenu = {&sInventoryMenu, sAmountsMenuItems, ARRAY_LEN(sAmountsMenuItems), true, 0}; -GZMenu sCollectionMenu = {&sMainMenu, sCollectionMenuItems, ARRAY_LEN(sCollectionMenuItems), true, 0}; -GZMenu sSettingsMenu = {&sMainMenu, sSettingsMenuItems, ARRAY_LEN(sSettingsMenuItems), false, 0}; -GZMenu sAboutMenu = {&sMainMenu, NULL, 0, false, 0}; -GZMenu sDebugMenu = {&sMainMenu, sDebugMenuItems, ARRAY_LEN(sDebugMenuItems), false, 0}; -GZMenu sRegsMenu = {&sDebugMenu, sRegsMenuItems, ARRAY_LEN(sRegsMenuItems), false, 0}; +GZMenu sMainMenu = {"Main Menu", NULL, sMainMenuItems, ARRAY_LEN(sMainMenuItems), false, 0}; +GZMenu sInventoryMenu = {"Inventory", &sMainMenu, sInventoryMenuItems, ARRAY_LEN(sInventoryMenuItems), true, 0}; +GZMenu sAmountsMenu = {"Inventory - Amounts", &sInventoryMenu, sAmountsMenuItems, ARRAY_LEN(sAmountsMenuItems), true, 0}; +GZMenu sCollectionMenu = {"Collection", &sMainMenu, sCollectionMenuItems, ARRAY_LEN(sCollectionMenuItems), true, 0}; +GZMenu sSettingsMenu = {"Settings", &sMainMenu, sSettingsMenuItems, ARRAY_LEN(sSettingsMenuItems), false, 0}; +GZMenu sAboutMenu = {"About", &sMainMenu, NULL, 0, false, 0}; +GZMenu sDebugMenu = {"Debug", &sMainMenu, sDebugMenuItems, ARRAY_LEN(sDebugMenuItems), false, 0}; +GZMenu sRegsMenu = {"Debug - Regs", &sDebugMenu, sRegsMenuItems, ARRAY_LEN(sRegsMenuItems), false, 0}; // clang-format on @@ -548,14 +548,22 @@ void GZMenuManager::SetAmountString(InventoryAmountType eType, Vec2b* pPos, bool void GZMenuManager::SetupScreen() { Vec2b elemPos = this->mState.menuPos; - // reset the top screen buffer + // reset the top screen buffer then send the menu item strings to the buffer memset(&data_0204d9d0[DRAW_TO_TOP_SCREEN], 0, sizeof(Screen)); - // send the menu item strings to the buffer + // current menu title + Vec2b titlePos = elemPos; + const char* titleStr = "stgz - "; + titlePos.x += (28 - strlen(titleStr) - strlen(this->mpActiveMenu->title)) / 2; + titlePos.y--; + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &titlePos, 0, 0, "%s%s", titleStr, this->mpActiveMenu->title); + + // return element const char* retStr = this->IsMainMenuActive() ? "Quit" : "Back"; - DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, this->mState.itemIndex == 0, retStr); + DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, this->mState.itemIndex == 0 ? 3 : 0, retStr); elemPos.y++; + // menu items if (this->IsCommandsMenuActive()) { gCommandManager.Draw(&elemPos); } else { @@ -567,10 +575,11 @@ void GZMenuManager::SetupScreen() { extraPos.x += strlen(szName); if (pActiveMenuItem->eType == GZMenuItemType_Bool && pActiveMenuItem->checkCallback != NULL) { - DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &elemPos, 0, selected, "[%s]%s", + Vec2b boolPos = elemPos; + DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &boolPos, 0, selected, "[%s]%s", pActiveMenuItem->checkCallback(i) ? "x" : " ", szName); } else { - // 0 = white, 1 = red, 2 = darker red, 3 = dark green + // 0 = white, 1 = red, 2 = darker red, 3 = dark green, seems to be palette indices? DisplayDebugText(DRAW_TO_TOP_SCREEN, &elemPos, 0, selected, szName); } @@ -584,13 +593,14 @@ void GZMenuManager::SetupScreen() { } } - // send the arrow to the buffer + // current selection arrow Vec2b arrowPos = this->mState.menuPos; arrowPos.x--; arrowPos.y += this->mState.itemIndex; - DisplayDebugText(DRAW_TO_TOP_SCREEN, &arrowPos, 0, 1, ">"); + DisplayDebugText(DRAW_TO_TOP_SCREEN, &arrowPos, 0, this->mState.itemIndex == 0 ? 3 : 1, ">"); arrowPos.y++; + // about and settings screens (TODO: move to GZSettings) if (this->IsSettingsMenuActive()) { // special handling for the settings screen Vec2b settingsPos = this->mState.menuPos; @@ -598,7 +608,7 @@ void GZMenuManager::SetupScreen() { DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &settingsPos, 0, 0, "Current Profile: %d", gSettings.mProfileHeader.curProfileIndex + 1); - settingsPos.y += 15; + settingsPos.y = 21; if (gSettings.error) { DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &settingsPos, 0, 1, "Error detected: 0x%X", gSettings.errorCode); } else if (this->mState.successTimer > 0) { @@ -607,7 +617,8 @@ void GZMenuManager::SetupScreen() { } else if (this->IsAboutMenuActive()) { // special handling for the about screen Vec2b aboutPos = this->mState.menuPos; - aboutPos.y = elemPos.y + 1; // start wherever the item list ended + + aboutPos.y += 2; DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Code Version: %s", gBuildGitVersion); aboutPos.y++; @@ -619,7 +630,7 @@ void GZMenuManager::SetupScreen() { aboutPos.y++; DisplayDebugTextF(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Commit Name: %s", gCommitGitString); - aboutPos.y += 15; + aboutPos.y = 21; DisplayDebugText(DRAW_TO_TOP_SCREEN, &aboutPos, 0, 0, "Licensed under GPL-3.0"); aboutPos.y++; From 0269a3a70fedb2bc5675cc7bdc320107c674bf4b Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:05:28 +0100 Subject: [PATCH 6/7] implement collection --- src/gz_menu.cpp | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/gz_menu.cpp b/src/gz_menu.cpp index 749b06d..4d57472 100644 --- a/src/gz_menu.cpp +++ b/src/gz_menu.cpp @@ -121,14 +121,14 @@ static GZMenuItem sAmountsMenuItems[] = { // -- collection menu items -- static GZMenuItem sCollectionMenuItems[] = { - {"Shield", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_Shield, NULL, 0}, - {"Sword", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_Sword, NULL, 0}, - {"LokomoSword", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_LokomoSword, NULL, 0}, - {"RecruitUniform", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_RecruitUniform, NULL, 0}, - {"ScrollBeam", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_ScrollBeam, NULL, 0}, - {"ScrollSpinAttack", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_ScrollSpinAttack, NULL, 0}, - {"AncientShield", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_AncientShield, NULL, 0}, - {"PanFlute", GZMenuItemType_Default, NULL, UpdateInventory, ItemFlag_PanFlute, NULL, 0}, + {"Shield", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_Shield, NULL, 0}, + {"Sword", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_Sword, NULL, 0}, + {"Lokomo Sword", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_LokomoSword, NULL, 0}, + {"Recruit Uniform", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_RecruitUniform, NULL, 0}, + {"Scroll Beam", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_ScrollBeam, NULL, 0}, + {"Scroll Spin Attack", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_ScrollSpinAttack, NULL, 0}, + {"Ancient Shield", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_AncientShield, NULL, 0}, + {"Pan Flute", GZMenuItemType_Bool, HasObtainedItem, UpdateInventory, ItemFlag_PanFlute, NULL, 0}, }; // -- settings menu items -- @@ -183,25 +183,18 @@ static void UpdateInventory(u32 params) { return; } - switch (eFlag) { - case ItemFlag_Whirlwind: - case ItemFlag_Boomerang: - case ItemFlag_Whip: - case ItemFlag_Bow: - case ItemFlag_Bombs: - case ItemFlag_SandRod: - if (!GET_FLAG(data_027e0ce0->mUnk_28->mUnk_08, eFlag)) { - data_027e0ce0->mUnk_28->func_ov000_020a863c(eFlag); - } else { - data_027e0ce0->mUnk_28->func_ov000_020a865c(eFlag); - } - break; - default: - break; + if (!GET_FLAG(data_027e0ce0->mUnk_28->mUnk_08, eFlag)) { + data_027e0ce0->mUnk_28->func_ov000_020a863c(eFlag); + } else { + data_027e0ce0->mUnk_28->func_ov000_020a865c(eFlag); } } static bool HasObtainedItem(int itemIndex) { + if (data_027e0ce0 == NULL || data_027e0ce0->mUnk_28 == NULL) { + return false; + } + return GET_FLAG(data_027e0ce0->mUnk_28->mUnk_08, gMenuManager.mpActiveMenu->entries[itemIndex].params & 0xFF); } From 6d194ec520e4c7ca1a3518fc58844ef11a1e94fe Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:14:45 +0100 Subject: [PATCH 7/7] updated decomp revision --- resources/decomp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/decomp b/resources/decomp index 269e5c5..c2b66a9 160000 --- a/resources/decomp +++ b/resources/decomp @@ -1 +1 @@ -Subproject commit 269e5c5c56bbbb6c70a03b08a57c091aae03c6b0 +Subproject commit c2b66a9996fa3e030fd17f14478326baca0eb311