From 343f84e34a592b74c73736edc1052abcf9b6ae55 Mon Sep 17 00:00:00 2001 From: Ben Hetherington Date: Thu, 10 Apr 2025 18:47:57 +0100 Subject: [PATCH 1/6] Amend button descriptions in game selection menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the ‘Control Stick: Select’, ‘B: Cancel’, and ‘A: Confirm’ descriptions appear while in the game selection menu, while still keeping just ‘B: Cancel’ when on the ‘Press Start’ screen. To do this, this patches the function that updates the button descriptions, replacing two jump table entries, allowing our own code to be run (and determine which descriptions to display) while within the gameplay menu. --- patches/linker/link_ntsc10.ld | 5 ++ patches/linker/link_ntsc11.ld | 5 ++ patches/linker/link_ntsc12_001.ld | 5 ++ patches/linker/link_ntsc12_101.ld | 5 ++ patches/linker/link_pal10.ld | 5 ++ patches/linker/link_pal11.ld | 5 ++ patches/linker/link_pal12.ld | 5 ++ patches/source/button_descriptions.c | 69 ++++++++++++++++++++++++++++ patches/source/button_descriptions.h | 52 +++++++++++++++++++++ patches/source/menu.h | 4 ++ patches/source/patch.s | 7 +++ 11 files changed, 167 insertions(+) create mode 100644 patches/source/button_descriptions.c create mode 100644 patches/source/button_descriptions.h diff --git a/patches/linker/link_ntsc10.ld b/patches/linker/link_ntsc10.ld index d054458..bea0ab7 100644 --- a/patches/linker/link_ntsc10.ld +++ b/patches/linker/link_ntsc10.ld @@ -104,3 +104,8 @@ ntsc10_EXIDeselect = 0x81335838; ntsc10_EXISync = 0x81335134; ntsc10_EXIImm = 0x81334d4c; ntsc10_EXIImmEx = 0x81334fa8; + +ntsc10_all_element_alphas = 0x81465a9c; +ntsc10_update_element_alpha = 0x8130aa58; +ntsc10_after_update_button_text_jump_table = 0x81311de0; +ntsc10_after_update_button_icons_jump_table = 0x81311f4c; diff --git a/patches/linker/link_ntsc11.ld b/patches/linker/link_ntsc11.ld index f4c171b..26496bb 100644 --- a/patches/linker/link_ntsc11.ld +++ b/patches/linker/link_ntsc11.ld @@ -104,3 +104,8 @@ ntsc11_EXIDeselect = 0x8135b298; ntsc11_EXISync = 0x8135ab5c; ntsc11_EXIImm = 0x8135a774; ntsc11_EXIImmEx = 0x8135a9d0; + +ntsc11_all_element_alphas = 0x8148a21c; +ntsc11_update_element_alpha = 0x8130a964; +ntsc11_after_update_button_text_jump_table = 0x81312030; +ntsc11_after_update_button_icons_jump_table = 0x8131219c; diff --git a/patches/linker/link_ntsc12_001.ld b/patches/linker/link_ntsc12_001.ld index 0114570..bf6563d 100644 --- a/patches/linker/link_ntsc12_001.ld +++ b/patches/linker/link_ntsc12_001.ld @@ -99,3 +99,8 @@ ntsc12_001_EXIDeselect = 0x81364790; ntsc12_001_EXISync = 0x81363f4c; ntsc12_001_EXIImm = 0x81363b64; ntsc12_001_EXIImmEx = 0x81363dc0; + +ntsc12_001_all_element_alphas = 0x8148b7fc; +ntsc12_001_update_element_alpha = 0x8130acd8; +ntsc12_001_after_update_button_text_jump_table = 0x813123c8; +ntsc12_001_after_update_button_icons_jump_table = 0x81312534; diff --git a/patches/linker/link_ntsc12_101.ld b/patches/linker/link_ntsc12_101.ld index 2161f9d..745f250 100644 --- a/patches/linker/link_ntsc12_101.ld +++ b/patches/linker/link_ntsc12_101.ld @@ -99,3 +99,8 @@ ntsc12_101_EXIDeselect = 0x813648f4; ntsc12_101_EXISync = 0x813640b0; ntsc12_101_EXIImm = 0x81363cc8; ntsc12_101_EXIImmEx = 0x81363f24; + +ntsc12_101_all_element_alphas = 0x8148bc9c; +ntsc12_101_update_element_alpha = 0x8130acf0; +ntsc12_101_after_update_button_text_jump_table = 0x813123e0; +ntsc12_101_after_update_button_icons_jump_table = 0x8131254c; diff --git a/patches/linker/link_pal10.ld b/patches/linker/link_pal10.ld index 76ec3d7..a768713 100644 --- a/patches/linker/link_pal10.ld +++ b/patches/linker/link_pal10.ld @@ -101,3 +101,8 @@ pal10_EXIDeselect = 0x8135e878; pal10_EXISync = 0x8135e13c; pal10_EXIImm = 0x8135dd54; pal10_EXIImmEx = 0x8135dfb0; + +pal10_all_element_alphas = 0x814b611c; +pal10_update_element_alpha = 0x8130a87c; +pal10_after_update_button_text_jump_table = 0x813128cc; +pal10_after_update_button_icons_jump_table = 0x81312a38; diff --git a/patches/linker/link_pal11.ld b/patches/linker/link_pal11.ld index 5a070fb..d5e24a3 100644 --- a/patches/linker/link_pal11.ld +++ b/patches/linker/link_pal11.ld @@ -99,3 +99,8 @@ pal11_EXIDeselect = 0x8135b1b8; pal11_EXISync = 0x8135aa7c; pal11_EXIImm = 0x8135a694; pal11_EXIImmEx = 0x8135a8f0; + +pal11_all_element_alphas = 0x81484edc; +pal11_update_element_alpha = 0x8130a964; +pal11_after_update_button_text_jump_table = 0x81311f5c; +pal11_after_update_button_icons_jump_table = 0x813120c8; diff --git a/patches/linker/link_pal12.ld b/patches/linker/link_pal12.ld index 9e4985d..090cd09 100644 --- a/patches/linker/link_pal12.ld +++ b/patches/linker/link_pal12.ld @@ -100,3 +100,8 @@ pal12_EXIDeselect = 0x81367c6c; pal12_EXISync = 0x81367428; pal12_EXIImm = 0x81367040; pal12_EXIImmEx = 0x8136729c; + +pal12_all_element_alphas = 0x814b78dc; +pal12_update_element_alpha = 0x8130a9bc; +pal12_after_update_button_text_jump_table = 0x81312a0c; +pal12_after_update_button_icons_jump_table = 0x81312b78; diff --git a/patches/source/button_descriptions.c b/patches/source/button_descriptions.c new file mode 100644 index 0000000..2dcfbec --- /dev/null +++ b/patches/source/button_descriptions.c @@ -0,0 +1,69 @@ +#include "button_descriptions.h" + +#include "menu.h" +#include "attr.h" + +__attribute_reloc__ void (*update_element_alpha)(element_alpha_state_t* element_ptr, bool disabled); + +// Locations to branch back to, after the patched switch statement entry +__attribute_reloc__ void* after_update_button_text_jump_table; +__attribute_reloc__ void* after_update_button_icons_jump_table; + +__attribute_reloc__ all_element_alphas_t* all_element_alphas; + +__attribute_used__ void update_gameplay_button_text() { + // Disable button descriptions used by the outer menu + update_element_alpha(&all_element_alphas->text.one_column.menu_selection, true); + update_element_alpha(&all_element_alphas->text.two_columns.left_cancel, true); + update_element_alpha(&all_element_alphas->text.two_columns.right_confirm, true); + + // And also disable button descriptions used by other menus + update_element_alpha(&all_element_alphas->text.three_columns.left_change, true); + update_element_alpha(&all_element_alphas->text.three_columns.centre_finish, true); + + // Show 'B: Cancel' on both the loader and start screens + update_element_alpha(&all_element_alphas->text.three_columns.centre_cancel, false); + + // Show 'Control Stick: Select' and 'A: Confirm' just on the loader menu + update_element_alpha(&all_element_alphas->text.three_columns.left_select, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); + update_element_alpha(&all_element_alphas->text.three_columns.right_confirm, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); +} + +__attribute_used__ void update_gameplay_button_icons() { + // Disable button icons used by the outer menu + update_element_alpha(&all_element_alphas->icons.one_column.control_stick, true); + update_element_alpha(&all_element_alphas->icons.two_columns.left_b_button, true); + update_element_alpha(&all_element_alphas->icons.two_columns.right_a_button, true); + + // Show 'B: Cancel' on both the loader and start screens + update_element_alpha(&all_element_alphas->icons.three_columns.centre_b_button, false); + + // Show 'Control Stick: Select' and 'A: Confirm' just on the loader menu + update_element_alpha(&all_element_alphas->icons.three_columns.left_control_stick, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); + update_element_alpha(&all_element_alphas->icons.three_columns.right_a_button, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); +} + +// Within the function that updates the alpha of button descriptions, we patch two jump table entries +// corresponding to the 'gameplay' menu state, so they point to these two assembly snippets - +// these run the new C functions, then jump to the code following its jump table +asm( +".global patched_update_gameplay_button_text\n" +"patched_update_gameplay_button_text:\n" +" bl update_gameplay_button_text\n" +" lis 3, after_update_button_text_jump_table@h\n" +" ori 3, 3, after_update_button_text_jump_table@l\n" +" lwz 3, 0(3)\n" +" mtctr 3\n" +" bctr\n" +); + +asm( +".global patched_update_gameplay_button_icons\n" +"patched_update_gameplay_button_icons:\n" +" bl update_gameplay_button_icons\n" +" lis 3, after_update_button_icons_jump_table@h\n" +" ori 3, 3, after_update_button_icons_jump_table@l\n" +" lwz 3, 0(3)\n" +" mtctr 3\n" +" bctr\n" +); diff --git a/patches/source/button_descriptions.h b/patches/source/button_descriptions.h new file mode 100644 index 0000000..c7bfe83 --- /dev/null +++ b/patches/source/button_descriptions.h @@ -0,0 +1,52 @@ +#include + +typedef struct { + u16 current_alpha; // Typically 0x00-0x14 + u16 unk0; + u16 unk1; + u16 unk2; + u16 unk3; + u16 unk4; + u16 unk5; + u16 unk6; +} element_alpha_state_t; + +typedef struct { + struct { + struct { + element_alpha_state_t left_control_stick; + element_alpha_state_t centre_b_button; + element_alpha_state_t right_a_button; + } three_columns; + + struct { + element_alpha_state_t control_stick; + } one_column; + + struct { + element_alpha_state_t left_b_button; + element_alpha_state_t right_a_button; + } two_columns; + } icons; + + struct { + struct { + element_alpha_state_t menu_selection; + } one_column; + + struct { + element_alpha_state_t left_cancel; + element_alpha_state_t right_confirm; + } two_columns; + + struct { + element_alpha_state_t left_select; + element_alpha_state_t left_change; + element_alpha_state_t centre_cancel; + element_alpha_state_t centre_finish; + element_alpha_state_t right_confirm; + } three_columns; + } text; + + // There are more elements past this point that relate to other elements, e.g. menus +} all_element_alphas_t; diff --git a/patches/source/menu.h b/patches/source/menu.h index ffd7a9f..b710ea7 100644 --- a/patches/source/menu.h +++ b/patches/source/menu.h @@ -1,3 +1,5 @@ +#include + #define MENU_SELECTION_ID 0 #define MENU_GAMESELECT_ID 1 #define MENU_GAMESELECT_TRANSITION_ID 2 @@ -25,6 +27,8 @@ #define SOUND_CARD_MOVE 0x0b #define SOUND_CARD_ERROR 0x0d +extern u32 current_gameselect_state; + extern int selected_slot; extern int top_line_num; diff --git a/patches/source/patch.s b/patches/source/patch.s index 22d128f..01b6152 100644 --- a/patches/source/patch.s +++ b/patches/source/patch.s @@ -115,3 +115,10 @@ patch_inst_pal "_patch_menu_alpha_setup" 0x81312c3c 0x81312284 0x81312d7c bl pre patch_inst_pal "_fix_video_mode_init" 0x81300520 0x81300520 0x81300610 bl get_tvmode patch_inst_global "_patch_pre_main" 0x81300090 bl pre_main + +// Within the function that updates the alpha of button descriptions, +// patch two jump table entries corresponding to the 'gameplay' menu state +patch_inst_ntsc "_patch_update_gameplay_button_text_jump_table" 0x813a5b70 0x8137e780 0x8137fa48 0x8137fec8 .4byte patched_update_gameplay_button_text +patch_inst_pal "_patch_update_gameplay_button_text_jump_table" 0x81381250 0x8137e6a0 0x813826f0 .4byte patched_update_gameplay_button_text +patch_inst_ntsc "_patch_update_gameplay_button_icons_jump_table" 0x813a5b50 0x8137e760 0x8137fa28 0x8137fea8 .4byte patched_update_gameplay_button_icons +patch_inst_pal "_patch_update_gameplay_button_icons_jump_table" 0x81381230 0x8137e680 0x813826d0 .4byte patched_update_gameplay_button_icons From 0665938dde31895fe66a3d1515ba141ed1981c90 Mon Sep 17 00:00:00 2001 From: Ben Hetherington Date: Thu, 10 Apr 2025 19:47:52 +0100 Subject: [PATCH 2/6] Split assembly into a separate file Compared to just using `asm()` in the .c file, this seems a bit more readable to me, and allows the assembly code to use the `r3` alias in `asm.h`. --- patches/source/button_descriptions.c | 27 +----------------------- patches/source/button_descriptions_asm.s | 24 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 26 deletions(-) create mode 100644 patches/source/button_descriptions_asm.s diff --git a/patches/source/button_descriptions.c b/patches/source/button_descriptions.c index 2dcfbec..f856512 100644 --- a/patches/source/button_descriptions.c +++ b/patches/source/button_descriptions.c @@ -5,7 +5,7 @@ __attribute_reloc__ void (*update_element_alpha)(element_alpha_state_t* element_ptr, bool disabled); -// Locations to branch back to, after the patched switch statement entry +// Locations to branch back to, after the patched switch statement entry (used in button_descriptions_asm.s) __attribute_reloc__ void* after_update_button_text_jump_table; __attribute_reloc__ void* after_update_button_icons_jump_table; @@ -42,28 +42,3 @@ __attribute_used__ void update_gameplay_button_icons() { update_element_alpha(&all_element_alphas->icons.three_columns.left_control_stick, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); update_element_alpha(&all_element_alphas->icons.three_columns.right_a_button, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); } - -// Within the function that updates the alpha of button descriptions, we patch two jump table entries -// corresponding to the 'gameplay' menu state, so they point to these two assembly snippets - -// these run the new C functions, then jump to the code following its jump table -asm( -".global patched_update_gameplay_button_text\n" -"patched_update_gameplay_button_text:\n" -" bl update_gameplay_button_text\n" -" lis 3, after_update_button_text_jump_table@h\n" -" ori 3, 3, after_update_button_text_jump_table@l\n" -" lwz 3, 0(3)\n" -" mtctr 3\n" -" bctr\n" -); - -asm( -".global patched_update_gameplay_button_icons\n" -"patched_update_gameplay_button_icons:\n" -" bl update_gameplay_button_icons\n" -" lis 3, after_update_button_icons_jump_table@h\n" -" ori 3, 3, after_update_button_icons_jump_table@l\n" -" lwz 3, 0(3)\n" -" mtctr 3\n" -" bctr\n" -); diff --git a/patches/source/button_descriptions_asm.s b/patches/source/button_descriptions_asm.s new file mode 100644 index 0000000..b14c2a7 --- /dev/null +++ b/patches/source/button_descriptions_asm.s @@ -0,0 +1,24 @@ +#define _LANGUAGE_ASSEMBLY +#include "asm.h" + +// Within the function that updates the alpha of button descriptions, we patch two jump table entries +// corresponding to the 'gameplay' menu state, so they point to these two assembly snippets - these +// run the new functions (in the corresponding .c file), then jump to the code following its jump table +.global patched_update_gameplay_button_text +.global patched_update_gameplay_button_icons + +patched_update_gameplay_button_text: + bl update_gameplay_button_text + lis r3, after_update_button_text_jump_table@h + ori r3, r3, after_update_button_text_jump_table@l + lwz r3, 0(r3) + mtctr r3 + bctr + +patched_update_gameplay_button_icons: + bl update_gameplay_button_icons + lis r3, after_update_button_icons_jump_table@h + ori r3, r3, after_update_button_icons_jump_table@l + lwz r3, 0(r3) + mtctr r3 + bctr From dbe53f8c14c0ddf9f1865f688490ce54e1e8619d Mon Sep 17 00:00:00 2001 From: Ben Hetherington Date: Mon, 14 Apr 2025 21:37:23 +0100 Subject: [PATCH 3/6] Simplify the patches for button descriptions Rather than patching jump tables to point to unrelated addresses, and then having to jump back to the original code, this just replaces the code at the original jump target instead. --- patches/linker/link_ntsc10.ld | 2 -- patches/linker/link_ntsc11.ld | 2 -- patches/linker/link_ntsc12_001.ld | 2 -- patches/linker/link_ntsc12_101.ld | 2 -- patches/linker/link_pal10.ld | 2 -- patches/linker/link_pal11.ld | 2 -- patches/linker/link_pal12.ld | 2 -- patches/source/button_descriptions.c | 4 ---- patches/source/button_descriptions_asm.s | 24 --------------------- patches/source/patch.s | 27 +++++++++++++++++++----- 10 files changed, 22 insertions(+), 47 deletions(-) delete mode 100644 patches/source/button_descriptions_asm.s diff --git a/patches/linker/link_ntsc10.ld b/patches/linker/link_ntsc10.ld index bea0ab7..5f7bcd5 100644 --- a/patches/linker/link_ntsc10.ld +++ b/patches/linker/link_ntsc10.ld @@ -107,5 +107,3 @@ ntsc10_EXIImmEx = 0x81334fa8; ntsc10_all_element_alphas = 0x81465a9c; ntsc10_update_element_alpha = 0x8130aa58; -ntsc10_after_update_button_text_jump_table = 0x81311de0; -ntsc10_after_update_button_icons_jump_table = 0x81311f4c; diff --git a/patches/linker/link_ntsc11.ld b/patches/linker/link_ntsc11.ld index 26496bb..93a8df9 100644 --- a/patches/linker/link_ntsc11.ld +++ b/patches/linker/link_ntsc11.ld @@ -107,5 +107,3 @@ ntsc11_EXIImmEx = 0x8135a9d0; ntsc11_all_element_alphas = 0x8148a21c; ntsc11_update_element_alpha = 0x8130a964; -ntsc11_after_update_button_text_jump_table = 0x81312030; -ntsc11_after_update_button_icons_jump_table = 0x8131219c; diff --git a/patches/linker/link_ntsc12_001.ld b/patches/linker/link_ntsc12_001.ld index bf6563d..c865576 100644 --- a/patches/linker/link_ntsc12_001.ld +++ b/patches/linker/link_ntsc12_001.ld @@ -102,5 +102,3 @@ ntsc12_001_EXIImmEx = 0x81363dc0; ntsc12_001_all_element_alphas = 0x8148b7fc; ntsc12_001_update_element_alpha = 0x8130acd8; -ntsc12_001_after_update_button_text_jump_table = 0x813123c8; -ntsc12_001_after_update_button_icons_jump_table = 0x81312534; diff --git a/patches/linker/link_ntsc12_101.ld b/patches/linker/link_ntsc12_101.ld index 745f250..7303945 100644 --- a/patches/linker/link_ntsc12_101.ld +++ b/patches/linker/link_ntsc12_101.ld @@ -102,5 +102,3 @@ ntsc12_101_EXIImmEx = 0x81363f24; ntsc12_101_all_element_alphas = 0x8148bc9c; ntsc12_101_update_element_alpha = 0x8130acf0; -ntsc12_101_after_update_button_text_jump_table = 0x813123e0; -ntsc12_101_after_update_button_icons_jump_table = 0x8131254c; diff --git a/patches/linker/link_pal10.ld b/patches/linker/link_pal10.ld index a768713..d7e76ed 100644 --- a/patches/linker/link_pal10.ld +++ b/patches/linker/link_pal10.ld @@ -104,5 +104,3 @@ pal10_EXIImmEx = 0x8135dfb0; pal10_all_element_alphas = 0x814b611c; pal10_update_element_alpha = 0x8130a87c; -pal10_after_update_button_text_jump_table = 0x813128cc; -pal10_after_update_button_icons_jump_table = 0x81312a38; diff --git a/patches/linker/link_pal11.ld b/patches/linker/link_pal11.ld index d5e24a3..584eeb3 100644 --- a/patches/linker/link_pal11.ld +++ b/patches/linker/link_pal11.ld @@ -102,5 +102,3 @@ pal11_EXIImmEx = 0x8135a8f0; pal11_all_element_alphas = 0x81484edc; pal11_update_element_alpha = 0x8130a964; -pal11_after_update_button_text_jump_table = 0x81311f5c; -pal11_after_update_button_icons_jump_table = 0x813120c8; diff --git a/patches/linker/link_pal12.ld b/patches/linker/link_pal12.ld index 090cd09..291bea0 100644 --- a/patches/linker/link_pal12.ld +++ b/patches/linker/link_pal12.ld @@ -103,5 +103,3 @@ pal12_EXIImmEx = 0x8136729c; pal12_all_element_alphas = 0x814b78dc; pal12_update_element_alpha = 0x8130a9bc; -pal12_after_update_button_text_jump_table = 0x81312a0c; -pal12_after_update_button_icons_jump_table = 0x81312b78; diff --git a/patches/source/button_descriptions.c b/patches/source/button_descriptions.c index f856512..efebbbe 100644 --- a/patches/source/button_descriptions.c +++ b/patches/source/button_descriptions.c @@ -5,10 +5,6 @@ __attribute_reloc__ void (*update_element_alpha)(element_alpha_state_t* element_ptr, bool disabled); -// Locations to branch back to, after the patched switch statement entry (used in button_descriptions_asm.s) -__attribute_reloc__ void* after_update_button_text_jump_table; -__attribute_reloc__ void* after_update_button_icons_jump_table; - __attribute_reloc__ all_element_alphas_t* all_element_alphas; __attribute_used__ void update_gameplay_button_text() { diff --git a/patches/source/button_descriptions_asm.s b/patches/source/button_descriptions_asm.s deleted file mode 100644 index b14c2a7..0000000 --- a/patches/source/button_descriptions_asm.s +++ /dev/null @@ -1,24 +0,0 @@ -#define _LANGUAGE_ASSEMBLY -#include "asm.h" - -// Within the function that updates the alpha of button descriptions, we patch two jump table entries -// corresponding to the 'gameplay' menu state, so they point to these two assembly snippets - these -// run the new functions (in the corresponding .c file), then jump to the code following its jump table -.global patched_update_gameplay_button_text -.global patched_update_gameplay_button_icons - -patched_update_gameplay_button_text: - bl update_gameplay_button_text - lis r3, after_update_button_text_jump_table@h - ori r3, r3, after_update_button_text_jump_table@l - lwz r3, 0(r3) - mtctr r3 - bctr - -patched_update_gameplay_button_icons: - bl update_gameplay_button_icons - lis r3, after_update_button_icons_jump_table@h - ori r3, r3, after_update_button_icons_jump_table@l - lwz r3, 0(r3) - mtctr r3 - bctr diff --git a/patches/source/patch.s b/patches/source/patch.s index 01b6152..be2c431 100644 --- a/patches/source/patch.s +++ b/patches/source/patch.s @@ -117,8 +117,25 @@ patch_inst_pal "_fix_video_mode_init" 0x81300520 0x81300520 0x81300610 bl get_tv patch_inst_global "_patch_pre_main" 0x81300090 bl pre_main // Within the function that updates the alpha of button descriptions, -// patch two jump table entries corresponding to the 'gameplay' menu state -patch_inst_ntsc "_patch_update_gameplay_button_text_jump_table" 0x813a5b70 0x8137e780 0x8137fa48 0x8137fec8 .4byte patched_update_gameplay_button_text -patch_inst_pal "_patch_update_gameplay_button_text_jump_table" 0x81381250 0x8137e6a0 0x813826f0 .4byte patched_update_gameplay_button_text -patch_inst_ntsc "_patch_update_gameplay_button_icons_jump_table" 0x813a5b50 0x8137e760 0x8137fa28 0x8137fea8 .4byte patched_update_gameplay_button_icons -patch_inst_pal "_patch_update_gameplay_button_icons_jump_table" 0x81381230 0x8137e680 0x813826d0 .4byte patched_update_gameplay_button_icons +// patch two code paths corresponding to the 'gameplay' menu state +.macro patched_update_gameplay_button_text + bl update_gameplay_button_text + + // Annoyingly, this state's code path falls through into code for another state (which we don't want to touch) before moving onto the next part of the function, so we can't just use a no-op slide + // As the previous state's code finishes with the branch instruction we need, let's just use that + b -8 + + // May as well no-op out the rest of the code path + repeat_inst 20 nop +.endm + +.macro patched_update_gameplay_button_icons + bl update_gameplay_button_icons + repeat_inst 24 nop + // Fortunately, we can just use the branch instruction that follows +.endm + +patch_inst_ntsc "_patch_update_gameplay_button_text_jump_table" 0x81311b9c 0x81311dec 0x81312184 0x8131219c patched_update_gameplay_button_text +patch_inst_pal "_patch_update_gameplay_button_text_jump_table" 0x81312688 0x81311d18 0x813127c8 patched_update_gameplay_button_text +patch_inst_ntsc "_patch_update_gameplay_button_icons_jump_table" 0x81311e50 0x813120a0 0x81312438 0x81312450 patched_update_gameplay_button_icons +patch_inst_pal "_patch_update_gameplay_button_icons_jump_table" 0x8131293c 0x81311fcc 0x81312a7c patched_update_gameplay_button_icons From 02b8be940daaa14c25720e69baedbcca2dfba786 Mon Sep 17 00:00:00 2001 From: Ben Hetherington Date: Wed, 9 Jul 2025 19:33:07 +0100 Subject: [PATCH 4/6] Add shared element alpha code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on the element alpha code for the disc/FlippyDrive selection UI, this: - Wraps `update_button_alphas()` - for now just calling the original function - Moves element alpha structs and functions to its own file - Updates the `element_alpha_state_t`, to name more members - Updates `update_element_alpha` to take a `element_alpha_update_state_t` enum, rather than the `bool` that was there before (as this function also supports a ‘dimmed’ state) --- patches/linker/link_ntsc10.ld | 2 ++ patches/linker/link_ntsc11.ld | 2 ++ patches/linker/link_ntsc12_001.ld | 2 ++ patches/linker/link_ntsc12_101.ld | 2 ++ patches/linker/link_pal10.ld | 2 ++ patches/linker/link_pal11.ld | 2 ++ patches/linker/link_pal12.ld | 2 ++ patches/source/button_descriptions.c | 35 ++++++++++++++++------------ patches/source/button_descriptions.h | 11 +-------- patches/source/element_alpha.c | 5 ++++ patches/source/element_alpha.h | 22 +++++++++++++++++ patches/source/patch.s | 3 +++ 12 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 patches/source/element_alpha.c create mode 100644 patches/source/element_alpha.h diff --git a/patches/linker/link_ntsc10.ld b/patches/linker/link_ntsc10.ld index 5f7bcd5..c551ddb 100644 --- a/patches/linker/link_ntsc10.ld +++ b/patches/linker/link_ntsc10.ld @@ -107,3 +107,5 @@ ntsc10_EXIImmEx = 0x81334fa8; ntsc10_all_element_alphas = 0x81465a9c; ntsc10_update_element_alpha = 0x8130aa58; + +ntsc10_update_button_alphas = 0x81311a98; diff --git a/patches/linker/link_ntsc11.ld b/patches/linker/link_ntsc11.ld index 93a8df9..4302320 100644 --- a/patches/linker/link_ntsc11.ld +++ b/patches/linker/link_ntsc11.ld @@ -107,3 +107,5 @@ ntsc11_EXIImmEx = 0x8135a9d0; ntsc11_all_element_alphas = 0x8148a21c; ntsc11_update_element_alpha = 0x8130a964; + +ntsc11_update_button_alphas = 0x81311ce8; diff --git a/patches/linker/link_ntsc12_001.ld b/patches/linker/link_ntsc12_001.ld index c865576..a90f977 100644 --- a/patches/linker/link_ntsc12_001.ld +++ b/patches/linker/link_ntsc12_001.ld @@ -102,3 +102,5 @@ ntsc12_001_EXIImmEx = 0x81363dc0; ntsc12_001_all_element_alphas = 0x8148b7fc; ntsc12_001_update_element_alpha = 0x8130acd8; + +ntsc12_001_update_button_alphas = 0x81312080; diff --git a/patches/linker/link_ntsc12_101.ld b/patches/linker/link_ntsc12_101.ld index 7303945..ba30907 100644 --- a/patches/linker/link_ntsc12_101.ld +++ b/patches/linker/link_ntsc12_101.ld @@ -102,3 +102,5 @@ ntsc12_101_EXIImmEx = 0x81363f24; ntsc12_101_all_element_alphas = 0x8148bc9c; ntsc12_101_update_element_alpha = 0x8130acf0; + +ntsc12_101_update_button_alphas = 0x81312098; diff --git a/patches/linker/link_pal10.ld b/patches/linker/link_pal10.ld index d7e76ed..c169783 100644 --- a/patches/linker/link_pal10.ld +++ b/patches/linker/link_pal10.ld @@ -104,3 +104,5 @@ pal10_EXIImmEx = 0x8135dfb0; pal10_all_element_alphas = 0x814b611c; pal10_update_element_alpha = 0x8130a87c; + +pal10_update_button_alphas = 0x81312580; diff --git a/patches/linker/link_pal11.ld b/patches/linker/link_pal11.ld index 584eeb3..68e6e76 100644 --- a/patches/linker/link_pal11.ld +++ b/patches/linker/link_pal11.ld @@ -102,3 +102,5 @@ pal11_EXIImmEx = 0x8135a8f0; pal11_all_element_alphas = 0x81484edc; pal11_update_element_alpha = 0x8130a964; + +pal11_update_button_alphas = 0x81311c14; diff --git a/patches/linker/link_pal12.ld b/patches/linker/link_pal12.ld index 291bea0..0d5e7a7 100644 --- a/patches/linker/link_pal12.ld +++ b/patches/linker/link_pal12.ld @@ -103,3 +103,5 @@ pal12_EXIImmEx = 0x8136729c; pal12_all_element_alphas = 0x814b78dc; pal12_update_element_alpha = 0x8130a9bc; + +pal12_update_button_alphas = 0x813126c0; diff --git a/patches/source/button_descriptions.c b/patches/source/button_descriptions.c index efebbbe..72bf283 100644 --- a/patches/source/button_descriptions.c +++ b/patches/source/button_descriptions.c @@ -2,39 +2,44 @@ #include "menu.h" #include "attr.h" +#include "reloc.h" -__attribute_reloc__ void (*update_element_alpha)(element_alpha_state_t* element_ptr, bool disabled); +__attribute_reloc__ void (*update_button_alphas)(); __attribute_reloc__ all_element_alphas_t* all_element_alphas; __attribute_used__ void update_gameplay_button_text() { // Disable button descriptions used by the outer menu - update_element_alpha(&all_element_alphas->text.one_column.menu_selection, true); - update_element_alpha(&all_element_alphas->text.two_columns.left_cancel, true); - update_element_alpha(&all_element_alphas->text.two_columns.right_confirm, true); + update_element_alpha(&all_element_alphas->text.one_column.menu_selection, element_alpha_hidden); + update_element_alpha(&all_element_alphas->text.two_columns.left_cancel, element_alpha_hidden); + update_element_alpha(&all_element_alphas->text.two_columns.right_confirm, element_alpha_hidden); // And also disable button descriptions used by other menus - update_element_alpha(&all_element_alphas->text.three_columns.left_change, true); - update_element_alpha(&all_element_alphas->text.three_columns.centre_finish, true); + update_element_alpha(&all_element_alphas->text.three_columns.left_change, element_alpha_hidden); + update_element_alpha(&all_element_alphas->text.three_columns.centre_finish, element_alpha_hidden); // Show 'B: Cancel' on both the loader and start screens - update_element_alpha(&all_element_alphas->text.three_columns.centre_cancel, false); + update_element_alpha(&all_element_alphas->text.three_columns.centre_cancel, element_alpha_visible); // Show 'Control Stick: Select' and 'A: Confirm' just on the loader menu - update_element_alpha(&all_element_alphas->text.three_columns.left_select, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); - update_element_alpha(&all_element_alphas->text.three_columns.right_confirm, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); + update_element_alpha(&all_element_alphas->text.three_columns.left_select, current_gameselect_state == SUBMENU_GAMESELECT_LOADER ? element_alpha_visible : element_alpha_hidden); + update_element_alpha(&all_element_alphas->text.three_columns.right_confirm, current_gameselect_state == SUBMENU_GAMESELECT_LOADER ? element_alpha_visible : element_alpha_hidden); } __attribute_used__ void update_gameplay_button_icons() { // Disable button icons used by the outer menu - update_element_alpha(&all_element_alphas->icons.one_column.control_stick, true); - update_element_alpha(&all_element_alphas->icons.two_columns.left_b_button, true); - update_element_alpha(&all_element_alphas->icons.two_columns.right_a_button, true); + update_element_alpha(&all_element_alphas->icons.one_column.control_stick, element_alpha_hidden); + update_element_alpha(&all_element_alphas->icons.two_columns.left_b_button, element_alpha_hidden); + update_element_alpha(&all_element_alphas->icons.two_columns.right_a_button, element_alpha_hidden); // Show 'B: Cancel' on both the loader and start screens - update_element_alpha(&all_element_alphas->icons.three_columns.centre_b_button, false); + update_element_alpha(&all_element_alphas->icons.three_columns.centre_b_button, element_alpha_visible); // Show 'Control Stick: Select' and 'A: Confirm' just on the loader menu - update_element_alpha(&all_element_alphas->icons.three_columns.left_control_stick, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); - update_element_alpha(&all_element_alphas->icons.three_columns.right_a_button, current_gameselect_state != SUBMENU_GAMESELECT_LOADER); + update_element_alpha(&all_element_alphas->icons.three_columns.left_control_stick, current_gameselect_state == SUBMENU_GAMESELECT_LOADER ? element_alpha_visible : element_alpha_hidden); + update_element_alpha(&all_element_alphas->icons.three_columns.right_a_button, current_gameselect_state == SUBMENU_GAMESELECT_LOADER ? element_alpha_visible : element_alpha_hidden); +} + +__attribute_used__ void patch_update_button_alphas() { + update_button_alphas(); } diff --git a/patches/source/button_descriptions.h b/patches/source/button_descriptions.h index c7bfe83..a3ac435 100644 --- a/patches/source/button_descriptions.h +++ b/patches/source/button_descriptions.h @@ -1,15 +1,6 @@ #include -typedef struct { - u16 current_alpha; // Typically 0x00-0x14 - u16 unk0; - u16 unk1; - u16 unk2; - u16 unk3; - u16 unk4; - u16 unk5; - u16 unk6; -} element_alpha_state_t; +#include "element_alpha.h" typedef struct { struct { diff --git a/patches/source/element_alpha.c b/patches/source/element_alpha.c new file mode 100644 index 0000000..d0e47ac --- /dev/null +++ b/patches/source/element_alpha.c @@ -0,0 +1,5 @@ +#include "element_alpha.h" + +#include "attr.h" + +__attribute_reloc__ void (*update_element_alpha)(element_alpha_state_t *element, element_alpha_update_state_t new_state); diff --git a/patches/source/element_alpha.h b/patches/source/element_alpha.h new file mode 100644 index 0000000..fef4ca0 --- /dev/null +++ b/patches/source/element_alpha.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +typedef struct { + u16 current_alpha; // Ranges from 0 to (fade_duration + start_delay) + u16 fade_duration; // Frames; typically 0x14 + u16 start_delay; // Frames; typically 0 + u16 frame_counter; // Incremented with every update + u8 unk0; + u8 max_output; + u16 unknown_output_multiplier; + u32 unk1; +} element_alpha_state_t; + +typedef enum { + element_alpha_visible, + element_alpha_hidden, + element_alpha_dimmed +} element_alpha_update_state_t; + +extern void (*update_element_alpha)(element_alpha_state_t *element, element_alpha_update_state_t new_state); diff --git a/patches/source/patch.s b/patches/source/patch.s index be2c431..e020f2d 100644 --- a/patches/source/patch.s +++ b/patches/source/patch.s @@ -139,3 +139,6 @@ patch_inst_ntsc "_patch_update_gameplay_button_text_jump_table" 0x81311b9c 0x813 patch_inst_pal "_patch_update_gameplay_button_text_jump_table" 0x81312688 0x81311d18 0x813127c8 patched_update_gameplay_button_text patch_inst_ntsc "_patch_update_gameplay_button_icons_jump_table" 0x81311e50 0x813120a0 0x81312438 0x81312450 patched_update_gameplay_button_icons patch_inst_pal "_patch_update_gameplay_button_icons_jump_table" 0x8131293c 0x81311fcc 0x81312a7c patched_update_gameplay_button_icons + +patch_inst_ntsc "_patch_update_button_alphas" 0x81312104 0x81312354 0x813126ec 0x81312704 bl patch_update_button_alphas +patch_inst_pal "_patch_update_button_alphas" 0x81312c38 0x81312280 0x81312d78 bl patch_update_button_alphas From e0862da3a78d94d7656a0b1e510f787a9b0802ce Mon Sep 17 00:00:00 2001 From: Ben Hetherington Date: Wed, 9 Jul 2025 19:42:28 +0100 Subject: [PATCH 5/6] Move custom button updating code to wrapper This replaces the patches-within-a-jump-table with straightforward C calls in the `patch_update_button_alphas()`. Either we run the original code, or we call our custom update functions. --- patches/source/button_descriptions.c | 15 ++++++++++++--- patches/source/patch.s | 24 ------------------------ 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/patches/source/button_descriptions.c b/patches/source/button_descriptions.c index 72bf283..3c56de5 100644 --- a/patches/source/button_descriptions.c +++ b/patches/source/button_descriptions.c @@ -8,7 +8,7 @@ __attribute_reloc__ void (*update_button_alphas)(); __attribute_reloc__ all_element_alphas_t* all_element_alphas; -__attribute_used__ void update_gameplay_button_text() { +static void update_gameplay_button_text() { // Disable button descriptions used by the outer menu update_element_alpha(&all_element_alphas->text.one_column.menu_selection, element_alpha_hidden); update_element_alpha(&all_element_alphas->text.two_columns.left_cancel, element_alpha_hidden); @@ -26,7 +26,7 @@ __attribute_used__ void update_gameplay_button_text() { update_element_alpha(&all_element_alphas->text.three_columns.right_confirm, current_gameselect_state == SUBMENU_GAMESELECT_LOADER ? element_alpha_visible : element_alpha_hidden); } -__attribute_used__ void update_gameplay_button_icons() { +static void update_gameplay_button_icons() { // Disable button icons used by the outer menu update_element_alpha(&all_element_alphas->icons.one_column.control_stick, element_alpha_hidden); update_element_alpha(&all_element_alphas->icons.two_columns.left_b_button, element_alpha_hidden); @@ -41,5 +41,14 @@ __attribute_used__ void update_gameplay_button_icons() { } __attribute_used__ void patch_update_button_alphas() { - update_button_alphas(); + switch (*cur_menu_id) { + case MENU_GAMESELECT_TRANSITION_ID: + update_gameplay_button_text(); + update_gameplay_button_icons(); + break; + + default: + update_button_alphas(); + break; + } } diff --git a/patches/source/patch.s b/patches/source/patch.s index e020f2d..3970361 100644 --- a/patches/source/patch.s +++ b/patches/source/patch.s @@ -116,29 +116,5 @@ patch_inst_pal "_fix_video_mode_init" 0x81300520 0x81300520 0x81300610 bl get_tv patch_inst_global "_patch_pre_main" 0x81300090 bl pre_main -// Within the function that updates the alpha of button descriptions, -// patch two code paths corresponding to the 'gameplay' menu state -.macro patched_update_gameplay_button_text - bl update_gameplay_button_text - - // Annoyingly, this state's code path falls through into code for another state (which we don't want to touch) before moving onto the next part of the function, so we can't just use a no-op slide - // As the previous state's code finishes with the branch instruction we need, let's just use that - b -8 - - // May as well no-op out the rest of the code path - repeat_inst 20 nop -.endm - -.macro patched_update_gameplay_button_icons - bl update_gameplay_button_icons - repeat_inst 24 nop - // Fortunately, we can just use the branch instruction that follows -.endm - -patch_inst_ntsc "_patch_update_gameplay_button_text_jump_table" 0x81311b9c 0x81311dec 0x81312184 0x8131219c patched_update_gameplay_button_text -patch_inst_pal "_patch_update_gameplay_button_text_jump_table" 0x81312688 0x81311d18 0x813127c8 patched_update_gameplay_button_text -patch_inst_ntsc "_patch_update_gameplay_button_icons_jump_table" 0x81311e50 0x813120a0 0x81312438 0x81312450 patched_update_gameplay_button_icons -patch_inst_pal "_patch_update_gameplay_button_icons_jump_table" 0x8131293c 0x81311fcc 0x81312a7c patched_update_gameplay_button_icons - patch_inst_ntsc "_patch_update_button_alphas" 0x81312104 0x81312354 0x813126ec 0x81312704 bl patch_update_button_alphas patch_inst_pal "_patch_update_button_alphas" 0x81312c38 0x81312280 0x81312d78 bl patch_update_button_alphas From 0c9b96b199af97eef9db51c7efa6a68de115c395 Mon Sep 17 00:00:00 2001 From: Ben Hetherington Date: Wed, 9 Jul 2025 20:01:22 +0100 Subject: [PATCH 6/6] Add additional PAL code after custom button update The standard `update_button_alphas` has some additional code on PAL systems to update the button alphas for the different languages. This reimplements this behaviour when using custom button description updates. --- patches/linker/link_ntsc10.ld | 3 +++ patches/linker/link_ntsc11.ld | 3 +++ patches/linker/link_ntsc12_001.ld | 3 +++ patches/linker/link_ntsc12_101.ld | 3 +++ patches/linker/link_pal10.ld | 3 +++ patches/linker/link_pal11.ld | 3 +++ patches/linker/link_pal12.ld | 3 +++ patches/source/button_descriptions.c | 25 +++++++++++++++++++++++++ 8 files changed, 46 insertions(+) diff --git a/patches/linker/link_ntsc10.ld b/patches/linker/link_ntsc10.ld index c551ddb..8eed495 100644 --- a/patches/linker/link_ntsc10.ld +++ b/patches/linker/link_ntsc10.ld @@ -109,3 +109,6 @@ ntsc10_all_element_alphas = 0x81465a9c; ntsc10_update_element_alpha = 0x8130aa58; ntsc10_update_button_alphas = 0x81311a98; + +ntsc10_current_pal_buttons_language = 0; +ntsc10_pal_button_language_elements = 0; diff --git a/patches/linker/link_ntsc11.ld b/patches/linker/link_ntsc11.ld index 4302320..a6c7b9c 100644 --- a/patches/linker/link_ntsc11.ld +++ b/patches/linker/link_ntsc11.ld @@ -109,3 +109,6 @@ ntsc11_all_element_alphas = 0x8148a21c; ntsc11_update_element_alpha = 0x8130a964; ntsc11_update_button_alphas = 0x81311ce8; + +ntsc11_current_pal_buttons_language = 0; +ntsc11_pal_button_language_elements = 0; diff --git a/patches/linker/link_ntsc12_001.ld b/patches/linker/link_ntsc12_001.ld index a90f977..0a32f83 100644 --- a/patches/linker/link_ntsc12_001.ld +++ b/patches/linker/link_ntsc12_001.ld @@ -104,3 +104,6 @@ ntsc12_001_all_element_alphas = 0x8148b7fc; ntsc12_001_update_element_alpha = 0x8130acd8; ntsc12_001_update_button_alphas = 0x81312080; + +ntsc12_001_current_pal_buttons_language = 0; +ntsc12_001_pal_button_language_elements = 0; diff --git a/patches/linker/link_ntsc12_101.ld b/patches/linker/link_ntsc12_101.ld index ba30907..ca559c9 100644 --- a/patches/linker/link_ntsc12_101.ld +++ b/patches/linker/link_ntsc12_101.ld @@ -104,3 +104,6 @@ ntsc12_101_all_element_alphas = 0x8148bc9c; ntsc12_101_update_element_alpha = 0x8130acf0; ntsc12_101_update_button_alphas = 0x81312098; + +ntsc12_101_current_pal_buttons_language = 0; +ntsc12_101_pal_button_language_elements = 0; diff --git a/patches/linker/link_pal10.ld b/patches/linker/link_pal10.ld index c169783..b262c47 100644 --- a/patches/linker/link_pal10.ld +++ b/patches/linker/link_pal10.ld @@ -106,3 +106,6 @@ pal10_all_element_alphas = 0x814b611c; pal10_update_element_alpha = 0x8130a87c; pal10_update_button_alphas = 0x81312580; + +pal10_current_pal_buttons_language = 0x814ad438; +pal10_pal_button_language_elements = 0x814b62fc; diff --git a/patches/linker/link_pal11.ld b/patches/linker/link_pal11.ld index 68e6e76..aad7608 100644 --- a/patches/linker/link_pal11.ld +++ b/patches/linker/link_pal11.ld @@ -104,3 +104,6 @@ pal11_all_element_alphas = 0x81484edc; pal11_update_element_alpha = 0x8130a964; pal11_update_button_alphas = 0x81311c14; + +pal11_current_pal_buttons_language = 0; +pal11_pal_button_language_elements = 0; diff --git a/patches/linker/link_pal12.ld b/patches/linker/link_pal12.ld index 0d5e7a7..05debca 100644 --- a/patches/linker/link_pal12.ld +++ b/patches/linker/link_pal12.ld @@ -105,3 +105,6 @@ pal12_all_element_alphas = 0x814b78dc; pal12_update_element_alpha = 0x8130a9bc; pal12_update_button_alphas = 0x813126c0; + +pal12_current_pal_buttons_language = 0x814af730; +pal12_pal_button_language_elements = 0x814b7abc; diff --git a/patches/source/button_descriptions.c b/patches/source/button_descriptions.c index 3c56de5..4a12a51 100644 --- a/patches/source/button_descriptions.c +++ b/patches/source/button_descriptions.c @@ -4,10 +4,15 @@ #include "attr.h" #include "reloc.h" +#define NUM_PAL_LANGUAGES 6 + __attribute_reloc__ void (*update_button_alphas)(); __attribute_reloc__ all_element_alphas_t* all_element_alphas; +__attribute_reloc__ u16 *current_pal_buttons_language; +__attribute_reloc__ element_alpha_state_t *pal_button_language_elements; + static void update_gameplay_button_text() { // Disable button descriptions used by the outer menu update_element_alpha(&all_element_alphas->text.one_column.menu_selection, element_alpha_hidden); @@ -40,7 +45,21 @@ static void update_gameplay_button_icons() { update_element_alpha(&all_element_alphas->icons.three_columns.right_a_button, current_gameselect_state == SUBMENU_GAMESELECT_LOADER ? element_alpha_visible : element_alpha_hidden); } +static void update_pal_button_languages() { + if (!current_pal_buttons_language || !pal_button_language_elements) { + // Only PAL 1.0 and 1.2 have runtime-configurable languages; other versions don't need this additional step + return; + } + + for (int i = 0; i < NUM_PAL_LANGUAGES; i++) { + element_alpha_update_state_t language_state = (i == *current_pal_buttons_language) ? element_alpha_visible : element_alpha_hidden; + update_element_alpha(&pal_button_language_elements[i], language_state); + } +} + __attribute_used__ void patch_update_button_alphas() { + bool ran_default_code = false; + switch (*cur_menu_id) { case MENU_GAMESELECT_TRANSITION_ID: update_gameplay_button_text(); @@ -49,6 +68,12 @@ __attribute_used__ void patch_update_button_alphas() { default: update_button_alphas(); + ran_default_code = true; break; } + + if (!ran_default_code) { + // If we didn't run the default code, we also have to take care of updating the per-language elements on PAL systems + update_pal_button_languages(); + } }