sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

file_select.c (124616B)


      1 #include <PR/ultratypes.h>
      2 #include <PR/gbi.h>
      3 
      4 #include "audio/external.h"
      5 #include "behavior_data.h"
      6 #include "dialog_ids.h"
      7 #include "engine/behavior_script.h"
      8 #include "engine/graph_node.h"
      9 #include "engine/math_util.h"
     10 #include "file_select.h"
     11 #include "game/area.h"
     12 #include "game/game_init.h"
     13 #include "game/ingame_menu.h"
     14 #include "game/object_helpers.h"
     15 #include "game/object_list_processor.h"
     16 #include "game/print.h"
     17 #include "game/save_file.h"
     18 #include "game/segment2.h"
     19 #include "game/segment7.h"
     20 #include "game/spawn_object.h"
     21 #include "game/rumble_init.h"
     22 #include "sm64.h"
     23 #include "text_strings.h"
     24 
     25 #include "eu_translation.h"
     26 #ifdef VERSION_EU
     27 #undef LANGUAGE_FUNCTION
     28 #define LANGUAGE_FUNCTION sLanguageMode
     29 #endif
     30 
     31 #ifdef VERSION_CN
     32 #define FILE_SELECT_PRINT_STRING print_generic_string
     33 #define FILE_SELECT_TEXT_DL_BEGIN dl_ia_text_begin
     34 #define FILE_SELECT_TEXT_DL_END dl_ia_text_end
     35 #else
     36 #define FILE_SELECT_PRINT_STRING print_menu_generic_string
     37 #define FILE_SELECT_TEXT_DL_BEGIN dl_menu_ia8_text_begin
     38 #define FILE_SELECT_TEXT_DL_END dl_menu_ia8_text_end
     39 #endif
     40 
     41 /**
     42  * @file file_select.c
     43  * This file implements how the file select and it's menus render and function.
     44  * That includes button IDs rendered as object models, strings, hand cursor,
     45  * special menu messages and phases, button states and button clicked checks.
     46  */
     47 
     48 #ifdef VERSION_US
     49 // The current sound mode is automatically centered on US and Shindou.
     50 static s16 sSoundTextX;
     51 #endif
     52 
     53 //! @Bug (UB Array Access) For EU, more buttons were added than the array was extended.
     54 //! This causes no currently known issues on console (as the other variables are not changed
     55 //! while this is used) but can cause issues with other compilers.
     56 #if defined(VERSION_EU) && !defined(AVOID_UB)
     57 #define NUM_BUTTONS (MENU_BUTTON_OPTION_MAX - 1)
     58 #else
     59 #define NUM_BUTTONS MENU_BUTTON_OPTION_MAX
     60 #endif
     61 
     62 // Amount of main menu buttons defined in the code called by spawn_object_rel_with_rot.
     63 // See file_select.h for the names in MenuButtonTypes.
     64 static struct Object *sMainMenuButtons[NUM_BUTTONS];
     65 
     66 // Used to defined yes/no fade colors after a file is selected in the erase menu.
     67 // sYesNoColor[0]: YES | sYesNoColor[1]: NO
     68 static u8 sYesNoColor[2];
     69 
     70 // The button that is selected when it is clicked.
     71 static s8 sSelectedButtonID = MENU_BUTTON_NONE;
     72 
     73 // On iQue, the courses can't all fit on one screen; there are two pages,
     74 // switched between with the L and R triggers.
     75 #ifdef VERSION_CN
     76 static s8 sScorePage = 0;
     77 #endif
     78 
     79 // Whether we are on the main menu or one of the submenus.
     80 static s8 sCurrentMenuLevel = MENU_LAYER_MAIN;
     81 
     82 // Used for text opacifying. If it is below 250, it is constantly incremented.
     83 static u8 sTextBaseAlpha = 0;
     84 
     85 // 2D position of the cursor on the screen.
     86 // sCursorPos[0]: X | sCursorPos[1]: Y
     87 static f32 sCursorPos[] = {0, 0};
     88 
     89 // Determines which graphic to use for the cursor.
     90 static s16 sCursorClickingTimer = 0;
     91 
     92 // Equal to sCursorPos if the cursor gets clicked, {-10000, -10000} otherwise.
     93 static s16 sClickPos[] = {-10000, -10000};
     94 
     95 // Used for determining which file has been selected during copying and erasing.
     96 static s8 sSelectedFileIndex = -1;
     97 
     98 // Whether to fade out text or not.
     99 static s8 sFadeOutText = FALSE;
    100 
    101 // The message currently being displayed at the top of a menu.
    102 static s8 sStatusMessageID = 0;
    103 
    104 // Used for text fading. The alpha value of text is calculated as
    105 // sTextBaseAlpha - sTextFadeAlpha.
    106 static u8 sTextFadeAlpha = 0;
    107 
    108 // File select timer that keeps counting until it reaches 1000.
    109 // Used to prevent buttons from being clickable as soon as a menu loads.
    110 // Gets reset when you click an empty save, existing saves in copy and erase menus
    111 // and when you click yes/no in the erase confirmation prompt.
    112 static s16 sMainMenuTimer = 0;
    113 
    114 // Sound mode menu buttonID, has different values compared to gSoundMode in audio.
    115 // 0: gSoundMode = 0 (Stereo) | 1: gSoundMode = 3 (Mono) | 2: gSoundMode = 1 (Headset)
    116 static s8 sSoundMode = 0;
    117 
    118 // Active language for EU arrays, values defined similar to sSoundMode
    119 // 0: English | 1: French | 2: German
    120 #ifdef VERSION_EU
    121 static s8 sLanguageMode = LANGUAGE_ENGLISH;
    122 #endif
    123 
    124 // Tracks which button will be pressed in the erase confirmation prompt (yes/no).
    125 static s8 sEraseYesNoHoverState = MENU_ERASE_HOVER_NONE;
    126 
    127 // Used for the copy menu, defines if the game as all 4 save slots with data.
    128 // if TRUE, it doesn't allow copying more files.
    129 static s8 sAllFilesExist = FALSE;
    130 
    131 // Defines the value of the save slot selected in the menu.
    132 // Mario A: 1 | Mario B: 2 | Mario C: 3 | Mario D: 4
    133 static s8 sSelectedFileNum = 0;
    134 
    135 // Which coin score mode to use when scoring files. 0 for local
    136 // coin high score, 1 for high score across all files.
    137 static s8 sScoreFileCoinScoreMode = 0;
    138 
    139 // In EU, if no save file exists, open the language menu so the user can find it.
    140 #ifdef VERSION_EU
    141 static s8 sOpenLangSettings = FALSE;
    142 #endif
    143 
    144 #ifndef VERSION_EU
    145 static u8 textReturn[] = { TEXT_RETURN };
    146 #else
    147 static u8 textReturn[][8] = {{ TEXT_RETURN }, { TEXT_RETURN_FR }, { TEXT_RETURN_DE }};
    148 #endif
    149 
    150 #ifndef VERSION_EU
    151 static u8 textViewScore[] = { TEXT_CHECK_SCORE };
    152 #else
    153 static u8 textViewScore[][12] = {{ TEXT_CHECK_SCORE }, {TEXT_CHECK_SCORE_FR}, {TEXT_CHECK_SCORE_DE}};
    154 #endif
    155 
    156 #ifndef VERSION_EU
    157 static u8 textCopyFileButton[] = { TEXT_COPY_FILE_BUTTON };
    158 #else
    159 static u8 textCopyFileButton[][15] = {{ TEXT_COPY_FILE }, { TEXT_COPY_FILE_FR }, { TEXT_COPY_FILE_DE }};
    160 #endif
    161 
    162 #ifndef VERSION_EU
    163 static u8 textEraseFileButton[] = { TEXT_ERASE_FILE_BUTTON };
    164 #else
    165 static u8 textEraseFileButton[][16] = { {TEXT_ERASE_FILE}, {TEXT_ERASE_FILE_FR}, {TEXT_ERASE_FILE_DE} };
    166 #endif
    167 
    168 #ifndef VERSION_EU
    169 static u8 textSoundModes[][8] = { { TEXT_STEREO }, { TEXT_MONO }, { TEXT_HEADSET } };
    170 #endif
    171 
    172 static u8 textMarioA[] = { TEXT_FILE_MARIO_A };
    173 static u8 textMarioB[] = { TEXT_FILE_MARIO_B };
    174 static u8 textMarioC[] = { TEXT_FILE_MARIO_C };
    175 static u8 textMarioD[] = { TEXT_FILE_MARIO_D };
    176 
    177 #ifndef VERSION_EU
    178 static u8 textNew[] = { TEXT_NEW };
    179 static u8 starIcon[] = { GLYPH_STAR, GLYPH_SPACE };
    180 static u8 xIcon[] = { GLYPH_MULTIPLY, GLYPH_SPACE };
    181 #endif
    182 
    183 #ifndef VERSION_EU
    184 static u8 textSelectFile[] = { TEXT_SELECT_FILE };
    185 #else
    186 static u8 textSelectFile[][17] = {{ TEXT_SELECT_FILE }, { TEXT_SELECT_FILE_FR }, { TEXT_SELECT_FILE_DE }};
    187 #endif
    188 
    189 #ifndef VERSION_EU
    190 static u8 textScore[] = { TEXT_SCORE };
    191 #else
    192 static u8 textScore[][9] = {{ TEXT_SCORE }, { TEXT_SCORE_FR }, { TEXT_SCORE_DE }};
    193 #endif
    194 
    195 #ifndef VERSION_EU
    196 static u8 textCopy[] = { TEXT_COPY };
    197 #else
    198 static u8 textCopy[][9] = {{ TEXT_COPY }, { TEXT_COPY_FR }, { TEXT_COPY_DE }};
    199 #endif
    200 
    201 #ifndef VERSION_EU
    202 static u8 textErase[] = { TEXT_ERASE };
    203 #else
    204 static u8 textErase[][8] = {{ TEXT_ERASE }, { TEXT_ERASE_FR }, { TEXT_ERASE_DE }};
    205 #endif
    206 
    207 #ifdef VERSION_EU
    208 static u8 textOption[][9] = {{ TEXT_OPTION }, { TEXT_OPTION_FR }, { TEXT_OPTION_DE } };
    209 #endif
    210 
    211 #ifndef VERSION_EU
    212 static u8 textCheckFile[] = { TEXT_CHECK_FILE };
    213 #else
    214 static u8 textCheckFile[][18] = {{ TEXT_CHECK_FILE }, { TEXT_CHECK_FILE_FR }, { TEXT_CHECK_FILE_DE }};
    215 #endif
    216 
    217 #ifndef VERSION_EU
    218 static u8 textNoSavedDataExists[] = { TEXT_NO_SAVED_DATA_EXISTS };
    219 #else
    220 static u8 textNoSavedDataExists[][30] = {{ TEXT_NO_SAVED_DATA_EXISTS }, { TEXT_NO_SAVED_DATA_EXISTS_FR }, { TEXT_NO_SAVED_DATA_EXISTS_DE }};
    221 #endif
    222 
    223 #ifndef VERSION_EU
    224 static u8 textCopyFile[] = { TEXT_COPY_FILE };
    225 #else
    226 static u8 textCopyFile[][16] = {{ TEXT_COPY_FILE_BUTTON }, { TEXT_COPY_FILE_BUTTON_FR }, { TEXT_COPY_FILE_BUTTON_DE }};
    227 #endif
    228 
    229 #ifndef VERSION_EU
    230 static u8 textCopyItToWhere[] = { TEXT_COPY_IT_TO_WHERE };
    231 #else
    232 static u8 textCopyItToWhere[][18] = {{ TEXT_COPY_IT_TO_WHERE }, { TEXT_COPY_IT_TO_WHERE_FR }, { TEXT_COPY_IT_TO_WHERE_DE }};
    233 #endif
    234 
    235 #if !defined(VERSION_EU)
    236 static u8 textNoSavedDataExistsCopy[] = { TEXT_NO_SAVED_DATA_EXISTS };
    237 #endif
    238 
    239 #ifndef VERSION_EU
    240 static u8 textCopyCompleted[] = { TEXT_COPYING_COMPLETED };
    241 #else
    242 static u8 textCopyCompleted[][18] = {{ TEXT_COPYING_COMPLETED }, { TEXT_COPYING_COMPLETED_FR }, { TEXT_COPYING_COMPLETED_DE }};
    243 #endif
    244 
    245 #ifndef VERSION_EU
    246 static u8 textSavedDataExists[] = { TEXT_SAVED_DATA_EXISTS };
    247 #else
    248 static u8 textSavedDataExists[][20] = {{ TEXT_SAVED_DATA_EXISTS }, { TEXT_SAVED_DATA_EXISTS_FR }, { TEXT_SAVED_DATA_EXISTS_DE }};
    249 #endif
    250 
    251 #ifndef VERSION_EU
    252 static u8 textNoFileToCopyFrom[] = { TEXT_NO_FILE_TO_COPY_FROM };
    253 #else
    254 static u8 textNoFileToCopyFrom[][21] = {{ TEXT_NO_FILE_TO_COPY_FROM }, { TEXT_NO_FILE_TO_COPY_FROM_FR }, { TEXT_NO_FILE_TO_COPY_FROM_DE }};
    255 #endif
    256 
    257 #ifndef VERSION_EU
    258 static u8 textYes[] = { TEXT_YES };
    259 #else
    260 static u8 textYes[][4] = {{ TEXT_YES }, { TEXT_YES_FR }, { TEXT_YES_DE }};
    261 #endif
    262 
    263 #ifndef VERSION_EU
    264 static u8 textNo[] = { TEXT_NO };
    265 #else
    266 static u8 textNo[][5] = {{ TEXT_NO }, { TEXT_NO_FR }, { TEXT_NO_DE }};
    267 #endif
    268 
    269 #ifdef VERSION_EU
    270 // In EU, Erase File and Sound Select strings are outside it's print string function
    271 static u8 textEraseFile[][17] = {
    272     { TEXT_ERASE_FILE_BUTTON }, { TEXT_ERASE_FILE_BUTTON_FR }, { TEXT_ERASE_FILE_BUTTON_DE }
    273 };
    274 static u8 textSure[][8] = {{ TEXT_SURE }, { TEXT_SURE_FR }, { TEXT_SURE_DE }};
    275 static u8 textMarioAJustErased[][20] = {
    276     { TEXT_FILE_MARIO_A_JUST_ERASED }, { TEXT_FILE_MARIO_A_JUST_ERASED_FR }, { TEXT_FILE_MARIO_A_JUST_ERASED_DE }
    277 };
    278 
    279 static u8 textSoundSelect[][13] = {
    280     { TEXT_SOUND_SELECT }, { TEXT_SOUND_SELECT_FR }, { TEXT_SOUND_SELECT_DE }
    281 };
    282 
    283 static u8 textLanguageSelect[][17] = {
    284     { TEXT_LANGUAGE_SELECT }, { TEXT_LANGUAGE_SELECT_FR }, { TEXT_LANGUAGE_SELECT_DE }
    285 };
    286 
    287 static u8 textSoundModes[][10] = {
    288     { TEXT_STEREO }, { TEXT_MONO }, { TEXT_HEADSET },
    289     { TEXT_STEREO_FR }, { TEXT_MONO_FR }, { TEXT_HEADSET_FR },
    290     { TEXT_STEREO_DE }, { TEXT_MONO_DE }, { TEXT_HEADSET_DE }
    291 };
    292 
    293 static u8 textLanguage[][9] = {{ TEXT_ENGLISH }, { TEXT_FRENCH }, { TEXT_GERMAN }};
    294 
    295 static u8 textMario[] = { TEXT_MARIO };
    296 static u8 textHiScore[][15] = {{ TEXT_HI_SCORE }, { TEXT_HI_SCORE_FR }, { TEXT_HI_SCORE_DE }};
    297 static u8 textMyScore[][10] = {{ TEXT_MY_SCORE }, { TEXT_MY_SCORE_FR }, { TEXT_MY_SCORE_DE }};
    298 
    299 static u8 textNew[][5] = {{ TEXT_NEW }, { TEXT_NEW_FR }, { TEXT_NEW_DE }};
    300 static u8 starIcon[] = { GLYPH_STAR, GLYPH_SPACE };
    301 static u8 xIcon[] = { GLYPH_MULTIPLY, GLYPH_SPACE };
    302 #endif
    303 
    304 /**
    305  * Yellow Background Menu Initial Action
    306  * Rotates the background at 180 grades and it's scale.
    307  * Although the scale is properly applied in the loop function.
    308  */
    309 void beh_yellow_background_menu_init(void) {
    310     gCurrentObject->oFaceAngleYaw = 0x8000;
    311     gCurrentObject->oMenuButtonScale = 9.0f;
    312 }
    313 
    314 /**
    315  * Yellow Background Menu Loop Action
    316  * Properly scales the background in the main menu.
    317  */
    318 void beh_yellow_background_menu_loop(void) {
    319     cur_obj_scale(9.0f);
    320 }
    321 
    322 /**
    323  * Check if a button was clicked.
    324  * depth = 200.0 for main menu, 22.0 for submenus.
    325  */
    326 s32 check_clicked_button(s16 x, s16 y, f32 depth) {
    327     f32 a = 52.4213;
    328     f32 newX = ((f32) x * 160.0) / (a * depth);
    329     f32 newY = ((f32) y * 120.0) / (a * 3 / 4 * depth);
    330     s16 maxX = newX + 25.0f;
    331     s16 minX = newX - 25.0f;
    332     s16 maxY = newY + 21.0f;
    333     s16 minY = newY - 21.0f;
    334 
    335     if (sClickPos[0] < maxX && minX < sClickPos[0] && sClickPos[1] < maxY && minY < sClickPos[1]) {
    336         return TRUE;
    337     }
    338     return FALSE;
    339 }
    340 
    341 /**
    342  * Grow from main menu, used by selecting files and menus.
    343  */
    344 static void bhv_menu_button_growing_from_main_menu(struct Object *button) {
    345     if (button->oMenuButtonTimer < 16) {
    346         button->oFaceAngleYaw += 0x800;
    347     }
    348     if (button->oMenuButtonTimer < 8) {
    349         button->oFaceAnglePitch += 0x800;
    350     }
    351     if (button->oMenuButtonTimer >= 8 && button->oMenuButtonTimer < 16) {
    352         button->oFaceAnglePitch -= 0x800;
    353     }
    354     button->oParentRelativePosX -= button->oMenuButtonOrigPosX / 16.0;
    355     button->oParentRelativePosY -= button->oMenuButtonOrigPosY / 16.0;
    356     if (button->oPosZ < button->oMenuButtonOrigPosZ + 17800.0) {
    357         button->oParentRelativePosZ += 1112.5;
    358     }
    359     button->oMenuButtonTimer++;
    360     if (button->oMenuButtonTimer == 16) {
    361         button->oParentRelativePosX = 0.0f;
    362         button->oParentRelativePosY = 0.0f;
    363         button->oMenuButtonState = MENU_BUTTON_STATE_FULLSCREEN;
    364         button->oMenuButtonTimer = 0;
    365     }
    366 }
    367 
    368 /**
    369  * Shrink back to main menu, used to return back while inside menus.
    370  */
    371 static void bhv_menu_button_shrinking_to_main_menu(struct Object *button) {
    372     if (button->oMenuButtonTimer < 16) {
    373         button->oFaceAngleYaw -= 0x800;
    374     }
    375     if (button->oMenuButtonTimer < 8) {
    376         button->oFaceAnglePitch -= 0x800;
    377     }
    378     if (button->oMenuButtonTimer >= 8 && button->oMenuButtonTimer < 16) {
    379         button->oFaceAnglePitch += 0x800;
    380     }
    381     button->oParentRelativePosX += button->oMenuButtonOrigPosX / 16.0;
    382     button->oParentRelativePosY += button->oMenuButtonOrigPosY / 16.0;
    383     if (button->oPosZ > button->oMenuButtonOrigPosZ) {
    384         button->oParentRelativePosZ -= 1112.5;
    385     }
    386     button->oMenuButtonTimer++;
    387     if (button->oMenuButtonTimer == 16) {
    388         button->oParentRelativePosX = button->oMenuButtonOrigPosX;
    389         button->oParentRelativePosY = button->oMenuButtonOrigPosY;
    390         button->oMenuButtonState = MENU_BUTTON_STATE_DEFAULT;
    391         button->oMenuButtonTimer = 0;
    392     }
    393 }
    394 
    395 /**
    396  * Grow from submenu, used by selecting a file in the score menu.
    397  */
    398 static void bhv_menu_button_growing_from_submenu(struct Object *button) {
    399     if (button->oMenuButtonTimer < 16) {
    400         button->oFaceAngleYaw += 0x800;
    401     }
    402     if (button->oMenuButtonTimer < 8) {
    403         button->oFaceAnglePitch += 0x800;
    404     }
    405     if (button->oMenuButtonTimer >= 8 && button->oMenuButtonTimer < 16) {
    406         button->oFaceAnglePitch -= 0x800;
    407     }
    408     button->oParentRelativePosX -= button->oMenuButtonOrigPosX / 16.0;
    409     button->oParentRelativePosY -= button->oMenuButtonOrigPosY / 16.0;
    410     button->oParentRelativePosZ -= 116.25;
    411     button->oMenuButtonTimer++;
    412     if (button->oMenuButtonTimer == 16) {
    413         button->oParentRelativePosX = 0.0f;
    414         button->oParentRelativePosY = 0.0f;
    415         button->oMenuButtonState = MENU_BUTTON_STATE_FULLSCREEN;
    416         button->oMenuButtonTimer = 0;
    417     }
    418 }
    419 
    420 /**
    421  * Shrink back to submenu, used to return back while inside a score save menu.
    422  */
    423 static void bhv_menu_button_shrinking_to_submenu(struct Object *button) {
    424     if (button->oMenuButtonTimer < 16) {
    425         button->oFaceAngleYaw -= 0x800;
    426     }
    427     if (button->oMenuButtonTimer < 8) {
    428         button->oFaceAnglePitch -= 0x800;
    429     }
    430     if (button->oMenuButtonTimer >= 8 && button->oMenuButtonTimer < 16) {
    431         button->oFaceAnglePitch += 0x800;
    432     }
    433     button->oParentRelativePosX += button->oMenuButtonOrigPosX / 16.0;
    434     button->oParentRelativePosY += button->oMenuButtonOrigPosY / 16.0;
    435     if (button->oPosZ > button->oMenuButtonOrigPosZ) {
    436         button->oParentRelativePosZ += 116.25;
    437     }
    438     button->oMenuButtonTimer++;
    439     if (button->oMenuButtonTimer == 16) {
    440         button->oParentRelativePosX = button->oMenuButtonOrigPosX;
    441         button->oParentRelativePosY = button->oMenuButtonOrigPosY;
    442         button->oMenuButtonState = MENU_BUTTON_STATE_DEFAULT;
    443         button->oMenuButtonTimer = 0;
    444     }
    445 }
    446 
    447 /**
    448  * A small increase and decrease in size.
    449  * Used by failed copy/erase/score operations and sound mode select.
    450  */
    451 static void bhv_menu_button_zoom_in_out(struct Object *button) {
    452     if (sCurrentMenuLevel == MENU_LAYER_MAIN) {
    453         if (button->oMenuButtonTimer < 4) {
    454             button->oParentRelativePosZ -= 20.0f;
    455         }
    456         if (button->oMenuButtonTimer >= 4) {
    457             button->oParentRelativePosZ += 20.0f;
    458         }
    459     } else {
    460         if (button->oMenuButtonTimer < 4) {
    461             button->oParentRelativePosZ += 20.0f;
    462         }
    463         if (button->oMenuButtonTimer >= 4) {
    464             button->oParentRelativePosZ -= 20.0f;
    465         }
    466     }
    467     button->oMenuButtonTimer++;
    468     if (button->oMenuButtonTimer == 8) {
    469         button->oMenuButtonState = MENU_BUTTON_STATE_DEFAULT;
    470         button->oMenuButtonTimer = 0;
    471     }
    472 }
    473 
    474 /**
    475  * A small temporary increase in size.
    476  * Used while selecting a target copy/erase file or yes/no erase confirmation prompt.
    477  */
    478 static void bhv_menu_button_zoom_in(struct Object *button) {
    479     button->oMenuButtonScale += 0.0022;
    480     button->oMenuButtonTimer++;
    481     if (button->oMenuButtonTimer == 10) {
    482         button->oMenuButtonState = MENU_BUTTON_STATE_DEFAULT;
    483         button->oMenuButtonTimer = 0;
    484     }
    485 }
    486 
    487 /**
    488  * A small temporary decrease in size.
    489  * Used after selecting a target copy/erase file or
    490  * yes/no erase confirmation prompt to undo the zoom in.
    491  */
    492 static void bhv_menu_button_zoom_out(struct Object *button) {
    493     button->oMenuButtonScale -= 0.0022;
    494     button->oMenuButtonTimer++;
    495     if (button->oMenuButtonTimer == 10) {
    496         button->oMenuButtonState = MENU_BUTTON_STATE_DEFAULT;
    497         button->oMenuButtonTimer = 0;
    498     }
    499 }
    500 
    501 /**
    502  * Menu Buttons Menu Initial Action
    503  * Aligns menu buttons so they can stay in their original
    504  * positions when you choose a button.
    505  */
    506 void bhv_menu_button_init(void) {
    507     gCurrentObject->oMenuButtonOrigPosX = gCurrentObject->oParentRelativePosX;
    508     gCurrentObject->oMenuButtonOrigPosY = gCurrentObject->oParentRelativePosY;
    509 }
    510 
    511 /**
    512  * Menu Buttons Menu Loop Action
    513  * Handles the functions of the button states and
    514  * object scale for each button.
    515  */
    516 void bhv_menu_button_loop(void) {
    517     switch (gCurrentObject->oMenuButtonState) {
    518         case MENU_BUTTON_STATE_DEFAULT: // Button state
    519             gCurrentObject->oMenuButtonOrigPosZ = gCurrentObject->oPosZ;
    520             break;
    521         case MENU_BUTTON_STATE_GROWING: // Switching from button to menu state
    522             if (sCurrentMenuLevel == MENU_LAYER_MAIN) {
    523                 bhv_menu_button_growing_from_main_menu(gCurrentObject);
    524             }
    525             if (sCurrentMenuLevel == MENU_LAYER_SUBMENU) {
    526                 bhv_menu_button_growing_from_submenu(gCurrentObject); // Only used for score files
    527             }
    528             sTextBaseAlpha = 0;
    529             sCursorClickingTimer = 4;
    530             break;
    531         case MENU_BUTTON_STATE_FULLSCREEN: // Menu state
    532             break;
    533         case MENU_BUTTON_STATE_SHRINKING: // Switching from menu to button state
    534             if (sCurrentMenuLevel == MENU_LAYER_MAIN) {
    535                 bhv_menu_button_shrinking_to_main_menu(gCurrentObject);
    536             }
    537             if (sCurrentMenuLevel == MENU_LAYER_SUBMENU) {
    538                 bhv_menu_button_shrinking_to_submenu(gCurrentObject); // Only used for score files
    539             }
    540             sTextBaseAlpha = 0;
    541             sCursorClickingTimer = 4;
    542             break;
    543         case MENU_BUTTON_STATE_ZOOM_IN_OUT:
    544             bhv_menu_button_zoom_in_out(gCurrentObject);
    545             sCursorClickingTimer = 4;
    546             break;
    547         case MENU_BUTTON_STATE_ZOOM_IN:
    548             bhv_menu_button_zoom_in(gCurrentObject);
    549             sCursorClickingTimer = 4;
    550             break;
    551         case MENU_BUTTON_STATE_ZOOM_OUT:
    552             bhv_menu_button_zoom_out(gCurrentObject);
    553             sCursorClickingTimer = 4;
    554             break;
    555     }
    556     cur_obj_scale(gCurrentObject->oMenuButtonScale);
    557 }
    558 
    559 /**
    560  * Handles how to exit the score file menu using button states.
    561  */
    562 void exit_score_file_to_score_menu(struct Object *scoreFileButton, s8 scoreButtonID) {
    563     // Begin exit
    564     if (scoreFileButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN
    565         && sCursorClickingTimer == 2) {
    566         play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource);
    567 #if ENABLE_RUMBLE
    568         queue_rumble_data(5, 80);
    569 #endif
    570         scoreFileButton->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING;
    571     }
    572     // End exit
    573     if (scoreFileButton->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT) {
    574         sSelectedButtonID = scoreButtonID;
    575         if (sCurrentMenuLevel == MENU_LAYER_SUBMENU) {
    576             sCurrentMenuLevel = MENU_LAYER_MAIN;
    577         }
    578     }
    579 }
    580 
    581 /**
    582  * Render buttons for the score menu.
    583  * Also check if the save file exists to render a different Mario button.
    584  */
    585 void render_score_menu_buttons(struct Object *scoreButton) {
    586     // File A
    587     if (save_file_exists(SAVE_FILE_A) == TRUE) {
    588         sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A] =
    589             spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton,
    590                                       711, 311, -100, 0, -0x8000, 0);
    591     } else {
    592         sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A] =
    593             spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711,
    594                                       311, -100, 0, -0x8000, 0);
    595     }
    596     sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A]->oMenuButtonScale = 0.11111111f;
    597     // File B
    598     if (save_file_exists(SAVE_FILE_B) == TRUE) {
    599         sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B] =
    600             spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton,
    601                                       -166, 311, -100, 0, -0x8000, 0);
    602     } else {
    603         sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B] =
    604             spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton,
    605                                       -166, 311, -100, 0, -0x8000, 0);
    606     }
    607     sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B]->oMenuButtonScale = 0.11111111f;
    608     // File C
    609     if (save_file_exists(SAVE_FILE_C) == TRUE) {
    610         sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C] = spawn_object_rel_with_rot(
    611             scoreButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0);
    612     } else {
    613         sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C] = spawn_object_rel_with_rot(
    614             scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0);
    615     }
    616     sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C]->oMenuButtonScale = 0.11111111f;
    617     // File D
    618     if (save_file_exists(SAVE_FILE_D) == TRUE) {
    619         sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D] =
    620             spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton,
    621                                       -166, 0, -100, 0, -0x8000, 0);
    622     } else {
    623         sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D] = spawn_object_rel_with_rot(
    624             scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0);
    625     }
    626     sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D]->oMenuButtonScale = 0.11111111f;
    627     // Return to main menu button
    628     sMainMenuButtons[MENU_BUTTON_SCORE_RETURN] = spawn_object_rel_with_rot(
    629         scoreButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 711, -388, -100, 0, -0x8000, 0);
    630     sMainMenuButtons[MENU_BUTTON_SCORE_RETURN]->oMenuButtonScale = 0.11111111f;
    631     // Switch to copy menu button
    632     sMainMenuButtons[MENU_BUTTON_SCORE_COPY_FILE] = spawn_object_rel_with_rot(
    633         scoreButton, MODEL_MAIN_MENU_BLUE_COPY_BUTTON, bhvMenuButton, 0, -388, -100, 0, -0x8000, 0);
    634     sMainMenuButtons[MENU_BUTTON_SCORE_COPY_FILE]->oMenuButtonScale = 0.11111111f;
    635     // Switch to erase menu button
    636     sMainMenuButtons[MENU_BUTTON_SCORE_ERASE_FILE] = spawn_object_rel_with_rot(
    637         scoreButton, MODEL_MAIN_MENU_RED_ERASE_BUTTON, bhvMenuButton, -711, -388, -100, 0, -0x8000, 0);
    638     sMainMenuButtons[MENU_BUTTON_SCORE_ERASE_FILE]->oMenuButtonScale = 0.11111111f;
    639 }
    640 
    641 #ifdef VERSION_EU
    642     #define SCORE_TIMER 46
    643 #else
    644     #define SCORE_TIMER 31
    645 #endif
    646 
    647 /**
    648  * In the score menu, checks if a button was clicked to play a sound, button state and other functions.
    649  */
    650 void check_score_menu_clicked_buttons(struct Object *scoreButton) {
    651     if (scoreButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
    652         s32 buttonID;
    653         // Configure score menu button group
    654         for (buttonID = MENU_BUTTON_SCORE_MIN; buttonID < MENU_BUTTON_SCORE_MAX; buttonID++) {
    655             s16 buttonX = sMainMenuButtons[buttonID]->oPosX;
    656             s16 buttonY = sMainMenuButtons[buttonID]->oPosY;
    657 
    658             if (check_clicked_button(buttonX, buttonY, 22.0f) == TRUE && sMainMenuTimer >= SCORE_TIMER) {
    659                 // If menu button clicked, select it
    660                 if (buttonID == MENU_BUTTON_SCORE_RETURN || buttonID == MENU_BUTTON_SCORE_COPY_FILE
    661                     || buttonID == MENU_BUTTON_SCORE_ERASE_FILE) {
    662                     play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
    663 #if ENABLE_RUMBLE
    664                     queue_rumble_data(5, 80);
    665 #endif
    666                     sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
    667                     sSelectedButtonID = buttonID;
    668                 }
    669                 else { // Check if a save file is clicked
    670                     if (sMainMenuTimer >= SCORE_TIMER) {
    671                         // If clicked in a existing save file, select it too see it's score
    672                         if (save_file_exists(buttonID - MENU_BUTTON_SCORE_MIN) == TRUE) {
    673                             play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
    674 #if ENABLE_RUMBLE
    675                             queue_rumble_data(5, 80);
    676 #endif
    677                             sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_GROWING;
    678                             sSelectedButtonID = buttonID;
    679                         }
    680                         else {
    681                             // If clicked in a non-existing save file, play buzz sound
    682                             play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource);
    683 #if ENABLE_RUMBLE
    684                             queue_rumble_data(5, 80);
    685 #endif
    686                             sMainMenuButtons[buttonID]->oMenuButtonState =
    687                                 MENU_BUTTON_STATE_ZOOM_IN_OUT;
    688                             if (sMainMenuTimer >= SCORE_TIMER) {
    689                                 sFadeOutText = TRUE;
    690                                 sMainMenuTimer = 0;
    691                             }
    692                         }
    693                     }
    694                 }
    695                 sCurrentMenuLevel = MENU_LAYER_SUBMENU;
    696                 break;
    697             }
    698         }
    699     }
    700 }
    701 
    702 #undef SCORE_TIMER
    703 
    704 /**
    705  * Render buttons for the copy menu.
    706  * Also check if the save file exists to render a different Mario button.
    707  */
    708 void render_copy_menu_buttons(struct Object *copyButton) {
    709     // File A
    710     if (save_file_exists(SAVE_FILE_A) == TRUE) {
    711         sMainMenuButtons[MENU_BUTTON_COPY_FILE_A] =
    712             spawn_object_rel_with_rot(copyButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, 711,
    713                                       311, -100, 0, -0x8000, 0);
    714     } else {
    715         sMainMenuButtons[MENU_BUTTON_COPY_FILE_A] = spawn_object_rel_with_rot(
    716             copyButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 311, -100, 0, -0x8000, 0);
    717     }
    718     sMainMenuButtons[MENU_BUTTON_COPY_FILE_A]->oMenuButtonScale = 0.11111111f;
    719     // File B
    720     if (save_file_exists(SAVE_FILE_B) == TRUE) {
    721         sMainMenuButtons[MENU_BUTTON_COPY_FILE_B] =
    722             spawn_object_rel_with_rot(copyButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton,
    723                                       -166, 311, -100, 0, -0x8000, 0);
    724     } else {
    725         sMainMenuButtons[MENU_BUTTON_COPY_FILE_B] =
    726             spawn_object_rel_with_rot(copyButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166,
    727                                       311, -100, 0, -0x8000, 0);
    728     }
    729     sMainMenuButtons[MENU_BUTTON_COPY_FILE_B]->oMenuButtonScale = 0.11111111f;
    730     // File C
    731     if (save_file_exists(SAVE_FILE_C) == TRUE) {
    732         sMainMenuButtons[MENU_BUTTON_COPY_FILE_C] = spawn_object_rel_with_rot(
    733             copyButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0);
    734     } else {
    735         sMainMenuButtons[MENU_BUTTON_COPY_FILE_C] = spawn_object_rel_with_rot(
    736             copyButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0);
    737     }
    738     sMainMenuButtons[MENU_BUTTON_COPY_FILE_C]->oMenuButtonScale = 0.11111111f;
    739     // File D
    740     if (save_file_exists(SAVE_FILE_D) == TRUE) {
    741         sMainMenuButtons[MENU_BUTTON_COPY_FILE_D] = spawn_object_rel_with_rot(
    742             copyButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0);
    743     } else {
    744         sMainMenuButtons[MENU_BUTTON_COPY_FILE_D] = spawn_object_rel_with_rot(
    745             copyButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0);
    746     }
    747     sMainMenuButtons[MENU_BUTTON_COPY_FILE_D]->oMenuButtonScale = 0.11111111f;
    748     // Return to main menu button
    749     sMainMenuButtons[MENU_BUTTON_COPY_RETURN] = spawn_object_rel_with_rot(
    750         copyButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 711, -388, -100, 0, -0x8000, 0);
    751     sMainMenuButtons[MENU_BUTTON_COPY_RETURN]->oMenuButtonScale = 0.11111111f;
    752     // Switch to scire menu button
    753     sMainMenuButtons[MENU_BUTTON_COPY_CHECK_SCORE] = spawn_object_rel_with_rot(
    754         copyButton, MODEL_MAIN_MENU_GREEN_SCORE_BUTTON, bhvMenuButton, 0, -388, -100, 0, -0x8000, 0);
    755     sMainMenuButtons[MENU_BUTTON_COPY_CHECK_SCORE]->oMenuButtonScale = 0.11111111f;
    756     // Switch to erase menu button
    757     sMainMenuButtons[MENU_BUTTON_COPY_ERASE_FILE] = spawn_object_rel_with_rot(
    758         copyButton, MODEL_MAIN_MENU_RED_ERASE_BUTTON, bhvMenuButton, -711, -388, -100, 0, -0x8000, 0);
    759     sMainMenuButtons[MENU_BUTTON_COPY_ERASE_FILE]->oMenuButtonScale = 0.11111111f;
    760 }
    761 
    762 #ifdef VERSION_EU
    763     #define BUZZ_TIMER 36
    764 #else
    765     #define BUZZ_TIMER 21
    766 #endif
    767 
    768 /**
    769  * Copy Menu phase actions that handles what to do when a file button is clicked.
    770  */
    771 void copy_action_file_button(struct Object *copyButton, s32 copyFileButtonID) {
    772     switch (copyButton->oMenuButtonActionPhase) {
    773         case COPY_PHASE_MAIN: // Copy Menu Main Phase
    774             if (sAllFilesExist == TRUE) { // Don't enable copy if all save files exists
    775                 return;
    776             }
    777             if (save_file_exists(copyFileButtonID - MENU_BUTTON_COPY_MIN) == TRUE) {
    778                 // If clicked in a existing save file, ask where it wants to copy
    779                 play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
    780 #if ENABLE_RUMBLE
    781                 queue_rumble_data(5, 80);
    782 #endif
    783                 sMainMenuButtons[copyFileButtonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN;
    784                 sSelectedFileIndex = copyFileButtonID - MENU_BUTTON_COPY_MIN;
    785                 copyButton->oMenuButtonActionPhase = COPY_PHASE_COPY_WHERE;
    786                 sFadeOutText = TRUE;
    787                 sMainMenuTimer = 0;
    788             } else {
    789                 // If clicked in a non-existing save file, play buzz sound
    790                 play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource);
    791 #if ENABLE_RUMBLE
    792                 queue_rumble_data(5, 80);
    793 #endif
    794                 sMainMenuButtons[copyFileButtonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
    795                 if (sMainMenuTimer >= BUZZ_TIMER) {
    796                     sFadeOutText = TRUE;
    797                     sMainMenuTimer = 0;
    798                 }
    799             }
    800             break;
    801         case COPY_PHASE_COPY_WHERE: // Copy Menu "COPY IT TO WHERE?" Phase (after a file is selected)
    802             sMainMenuButtons[copyFileButtonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
    803             if (save_file_exists(copyFileButtonID - MENU_BUTTON_COPY_MIN) == FALSE) {
    804                 // If clicked in a non-existing save file, copy the file
    805                 play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
    806 #if ENABLE_RUMBLE
    807                 queue_rumble_data(5, 80);
    808 #endif
    809                 copyButton->oMenuButtonActionPhase = COPY_PHASE_COPY_COMPLETE;
    810                 sFadeOutText = TRUE;
    811                 sMainMenuTimer = 0;
    812                 save_file_copy(sSelectedFileIndex, copyFileButtonID - MENU_BUTTON_COPY_MIN);
    813                 sMainMenuButtons[copyFileButtonID]->header.gfx.sharedChild =
    814                     gLoadedGraphNodes[MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE];
    815                 sMainMenuButtons[copyFileButtonID - MENU_BUTTON_COPY_MIN]->header.gfx.sharedChild =
    816                     gLoadedGraphNodes[MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE];
    817             } else {
    818                 // If clicked in a existing save file, play buzz sound
    819                 if (copyFileButtonID == MENU_BUTTON_COPY_FILE_A + sSelectedFileIndex) {
    820                     play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource);
    821 #if ENABLE_RUMBLE
    822                     queue_rumble_data(5, 80);
    823 #endif
    824                     sMainMenuButtons[MENU_BUTTON_COPY_FILE_A + sSelectedFileIndex]->oMenuButtonState =
    825                         MENU_BUTTON_STATE_ZOOM_OUT;
    826                     copyButton->oMenuButtonActionPhase = COPY_PHASE_MAIN;
    827                     sFadeOutText = TRUE;
    828                     return;
    829                 }
    830                 if (sMainMenuTimer >= BUZZ_TIMER) {
    831                     sFadeOutText = TRUE;
    832                     sMainMenuTimer = 0;
    833                 }
    834             }
    835             break;
    836     }
    837 }
    838 
    839 #ifdef VERSION_EU
    840     #define ACTION_TIMER      41
    841     #define MAIN_RETURN_TIMER 36
    842 #else
    843     #define ACTION_TIMER      31
    844     #define MAIN_RETURN_TIMER 31
    845 #endif
    846 
    847 /**
    848  * In the copy menu, checks if a button was clicked to play a sound, button state and other functions.
    849  */
    850 void check_copy_menu_clicked_buttons(struct Object *copyButton) {
    851     if (copyButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
    852         s32 buttonID;
    853         // Configure copy menu button group
    854         for (buttonID = MENU_BUTTON_COPY_MIN; buttonID < MENU_BUTTON_COPY_MAX; buttonID++) {
    855             s16 buttonX = sMainMenuButtons[buttonID]->oPosX;
    856             s16 buttonY = sMainMenuButtons[buttonID]->oPosY;
    857 
    858             if (check_clicked_button(buttonX, buttonY, 22.0f) == TRUE) {
    859                 // If menu button clicked, select it
    860                 if (buttonID == MENU_BUTTON_COPY_RETURN || buttonID == MENU_BUTTON_COPY_CHECK_SCORE
    861                     || buttonID == MENU_BUTTON_COPY_ERASE_FILE) {
    862                     if (copyButton->oMenuButtonActionPhase == COPY_PHASE_MAIN) {
    863                         play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
    864 #if ENABLE_RUMBLE
    865                         queue_rumble_data(5, 80);
    866 #endif
    867                         sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
    868                         sSelectedButtonID = buttonID;
    869                     }
    870                 }
    871                 else {
    872                     // Check if a file button is clicked to play a copy action
    873                     if (sMainMenuButtons[buttonID]->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT
    874                         && sMainMenuTimer >= ACTION_TIMER) {
    875                         copy_action_file_button(copyButton, buttonID);
    876                     }
    877                 }
    878                 sCurrentMenuLevel = MENU_LAYER_SUBMENU;
    879                 break;
    880             }
    881         }
    882 
    883         // After copy is complete, return to main copy phase
    884         if (copyButton->oMenuButtonActionPhase == COPY_PHASE_COPY_COMPLETE
    885             && sMainMenuTimer >= MAIN_RETURN_TIMER) {
    886             copyButton->oMenuButtonActionPhase = COPY_PHASE_MAIN;
    887             sMainMenuButtons[MENU_BUTTON_COPY_MIN + sSelectedFileIndex]->oMenuButtonState =
    888                 MENU_BUTTON_STATE_ZOOM_OUT;
    889         }
    890     }
    891 }
    892 
    893 /**
    894  * Render buttons for the erase menu.
    895  * Also check if the save file exists to render a different Mario button.
    896  */
    897 void render_erase_menu_buttons(struct Object *eraseButton) {
    898     // File A
    899     if (save_file_exists(SAVE_FILE_A) == TRUE) {
    900         sMainMenuButtons[MENU_BUTTON_ERASE_FILE_A] =
    901             spawn_object_rel_with_rot(eraseButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton,
    902                                       711, 311, -100, 0, -0x8000, 0);
    903     } else {
    904         sMainMenuButtons[MENU_BUTTON_ERASE_FILE_A] =
    905             spawn_object_rel_with_rot(eraseButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711,
    906                                       311, -100, 0, -0x8000, 0);
    907     }
    908     sMainMenuButtons[MENU_BUTTON_ERASE_FILE_A]->oMenuButtonScale = 0.11111111f;
    909     // File B
    910     if (save_file_exists(SAVE_FILE_B) == TRUE) {
    911         sMainMenuButtons[MENU_BUTTON_ERASE_FILE_B] =
    912             spawn_object_rel_with_rot(eraseButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton,
    913                                       -166, 311, -100, 0, -0x8000, 0);
    914     } else {
    915         sMainMenuButtons[MENU_BUTTON_ERASE_FILE_B] =
    916             spawn_object_rel_with_rot(eraseButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton,
    917                                       -166, 311, -100, 0, -0x8000, 0);
    918     }
    919     sMainMenuButtons[MENU_BUTTON_ERASE_FILE_B]->oMenuButtonScale = 0.11111111f;
    920     // File C
    921     if (save_file_exists(SAVE_FILE_C) == TRUE) {
    922         sMainMenuButtons[MENU_BUTTON_ERASE_FILE_C] = spawn_object_rel_with_rot(
    923             eraseButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0);
    924     } else {
    925         sMainMenuButtons[MENU_BUTTON_ERASE_FILE_C] = spawn_object_rel_with_rot(
    926             eraseButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0);
    927     }
    928     sMainMenuButtons[MENU_BUTTON_ERASE_FILE_C]->oMenuButtonScale = 0.11111111f;
    929     // File D
    930     if (save_file_exists(SAVE_FILE_D) == TRUE) {
    931         sMainMenuButtons[MENU_BUTTON_ERASE_FILE_D] =
    932             spawn_object_rel_with_rot(eraseButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton,
    933                                       -166, 0, -100, 0, -0x8000, 0);
    934     } else {
    935         sMainMenuButtons[MENU_BUTTON_ERASE_FILE_D] = spawn_object_rel_with_rot(
    936             eraseButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0);
    937     }
    938     sMainMenuButtons[MENU_BUTTON_ERASE_FILE_D]->oMenuButtonScale = 0.11111111f;
    939     // Return to main menu button
    940     sMainMenuButtons[MENU_BUTTON_ERASE_RETURN] = spawn_object_rel_with_rot(
    941         eraseButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 711, -388, -100, 0, -0x8000, 0);
    942     sMainMenuButtons[MENU_BUTTON_ERASE_RETURN]->oMenuButtonScale = 0.11111111f;
    943     // Switch to score menu button
    944     sMainMenuButtons[MENU_BUTTON_ERASE_CHECK_SCORE] = spawn_object_rel_with_rot(
    945         eraseButton, MODEL_MAIN_MENU_GREEN_SCORE_BUTTON, bhvMenuButton, 0, -388, -100, 0, -0x8000, 0);
    946     sMainMenuButtons[MENU_BUTTON_ERASE_CHECK_SCORE]->oMenuButtonScale = 0.11111111f;
    947     // Switch to copy menu button
    948     sMainMenuButtons[MENU_BUTTON_ERASE_COPY_FILE] = spawn_object_rel_with_rot(
    949         eraseButton, MODEL_MAIN_MENU_BLUE_COPY_BUTTON, bhvMenuButton, -711, -388, -100, 0, -0x8000, 0);
    950     sMainMenuButtons[MENU_BUTTON_ERASE_COPY_FILE]->oMenuButtonScale = 0.11111111f;
    951 }
    952 
    953 /**
    954  * Erase Menu phase actions that handles what to do when a file button is clicked.
    955  */
    956 void erase_action_file_button(struct Object *eraseButton, s32 eraseFileButtonID) {
    957     switch (eraseButton->oMenuButtonActionPhase) {
    958         case ERASE_PHASE_MAIN: // Erase Menu Main Phase
    959             if (save_file_exists(eraseFileButtonID - MENU_BUTTON_ERASE_MIN) == TRUE) {
    960                 // If clicked in a existing save file, ask if it wants to delete it
    961                 play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
    962 #if ENABLE_RUMBLE
    963                 queue_rumble_data(5, 80);
    964 #endif
    965                 sMainMenuButtons[eraseFileButtonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN;
    966                 sSelectedFileIndex = eraseFileButtonID - MENU_BUTTON_ERASE_MIN;
    967                 eraseButton->oMenuButtonActionPhase = ERASE_PHASE_PROMPT;
    968                 sFadeOutText = TRUE;
    969                 sMainMenuTimer = 0;
    970             } else {
    971                 // If clicked in a non-existing save file, play buzz sound
    972                 play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource);
    973 #if ENABLE_RUMBLE
    974                 queue_rumble_data(5, 80);
    975 #endif
    976                 sMainMenuButtons[eraseFileButtonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
    977 
    978                 if (sMainMenuTimer >= BUZZ_TIMER) {
    979                     sFadeOutText = TRUE;
    980                     sMainMenuTimer = 0;
    981                 }
    982             }
    983             break;
    984         case ERASE_PHASE_PROMPT: // Erase Menu "SURE? YES NO" Phase (after a file is selected)
    985             if (eraseFileButtonID == MENU_BUTTON_ERASE_MIN + sSelectedFileIndex) {
    986                 // If clicked in a existing save file, play click sound and zoom out button
    987                 // Note: The prompt functions are actually called when the ERASE_MSG_PROMPT
    988                 // message is displayed with print_erase_menu_prompt
    989                 play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
    990 #if ENABLE_RUMBLE
    991                 queue_rumble_data(5, 80);
    992 #endif
    993                 sMainMenuButtons[MENU_BUTTON_ERASE_MIN + sSelectedFileIndex]->oMenuButtonState =
    994                     MENU_BUTTON_STATE_ZOOM_OUT;
    995                 eraseButton->oMenuButtonActionPhase = ERASE_PHASE_MAIN;
    996                 sFadeOutText = TRUE;
    997             }
    998             break;
    999     }
   1000 }
   1001 
   1002 #undef BUZZ_TIMER
   1003 
   1004 /**
   1005  * In the erase menu, checks if a button was clicked to play a sound, button state and other functions.
   1006  */
   1007 void check_erase_menu_clicked_buttons(struct Object *eraseButton) {
   1008     if (eraseButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
   1009         s32 buttonID;
   1010         // Configure erase menu button group
   1011         for (buttonID = MENU_BUTTON_ERASE_MIN; buttonID < MENU_BUTTON_ERASE_MAX; buttonID++) {
   1012             s16 buttonX = sMainMenuButtons[buttonID]->oPosX;
   1013             s16 buttonY = sMainMenuButtons[buttonID]->oPosY;
   1014 
   1015             if (check_clicked_button(buttonX, buttonY, 22.0f) == TRUE) {
   1016                 // If menu button clicked, select it
   1017                 if (buttonID == MENU_BUTTON_ERASE_RETURN || buttonID == MENU_BUTTON_ERASE_CHECK_SCORE
   1018                     || buttonID == MENU_BUTTON_ERASE_COPY_FILE) {
   1019                     if (eraseButton->oMenuButtonActionPhase == ERASE_PHASE_MAIN) {
   1020                         play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
   1021 #if ENABLE_RUMBLE
   1022                         queue_rumble_data(5, 80);
   1023 #endif
   1024                         sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
   1025                         sSelectedButtonID = buttonID;
   1026                     }
   1027                 }
   1028                 else {
   1029                     // Check if a file button is clicked to play an erase action
   1030                     if (sMainMenuTimer >= ACTION_TIMER) {
   1031                         erase_action_file_button(eraseButton, buttonID);
   1032                     }
   1033                 }
   1034                 sCurrentMenuLevel = MENU_LAYER_SUBMENU;
   1035                 break;
   1036             }
   1037         }
   1038         // After erase is complete, return to main erase phase
   1039         if (eraseButton->oMenuButtonActionPhase == ERASE_PHASE_MARIO_ERASED
   1040             && sMainMenuTimer >= MAIN_RETURN_TIMER) {
   1041             eraseButton->oMenuButtonActionPhase = ERASE_PHASE_MAIN;
   1042             sMainMenuButtons[MENU_BUTTON_ERASE_MIN + sSelectedFileIndex]->oMenuButtonState =
   1043                 MENU_BUTTON_STATE_ZOOM_OUT;
   1044         }
   1045     }
   1046 }
   1047 
   1048 #undef ACTION_TIMER
   1049 #undef MAIN_RETURN_TIMER
   1050 
   1051 #ifdef VERSION_EU
   1052     #define SOUND_BUTTON_Y 388
   1053 #else
   1054     #define SOUND_BUTTON_Y 0
   1055 #endif
   1056 
   1057 /**
   1058  * Render buttons for the sound mode menu.
   1059  */
   1060 void render_sound_mode_menu_buttons(struct Object *soundModeButton) {
   1061     // Stereo option button
   1062     sMainMenuButtons[MENU_BUTTON_STEREO] = spawn_object_rel_with_rot(
   1063         soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, 533, SOUND_BUTTON_Y, -100, 0, -0x8000, 0);
   1064     sMainMenuButtons[MENU_BUTTON_STEREO]->oMenuButtonScale = 0.11111111f;
   1065     // Mono option button
   1066     sMainMenuButtons[MENU_BUTTON_MONO] = spawn_object_rel_with_rot(
   1067         soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, 0, SOUND_BUTTON_Y, -100, 0, -0x8000, 0);
   1068     sMainMenuButtons[MENU_BUTTON_MONO]->oMenuButtonScale = 0.11111111f;
   1069     // Headset option button
   1070     sMainMenuButtons[MENU_BUTTON_HEADSET] = spawn_object_rel_with_rot(
   1071         soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, -533, SOUND_BUTTON_Y, -100, 0, -0x8000, 0);
   1072     sMainMenuButtons[MENU_BUTTON_HEADSET]->oMenuButtonScale = 0.11111111f;
   1073 
   1074 #ifdef VERSION_EU
   1075     // English option button
   1076     sMainMenuButtons[MENU_BUTTON_LANGUAGE_ENGLISH] = spawn_object_rel_with_rot(
   1077         soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, 533, -111, -100, 0, -0x8000, 0);
   1078     sMainMenuButtons[MENU_BUTTON_LANGUAGE_ENGLISH]->oMenuButtonScale = 0.11111111f;
   1079     // French option button
   1080     sMainMenuButtons[MENU_BUTTON_LANGUAGE_FRENCH] = spawn_object_rel_with_rot(
   1081         soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, 0, -111, -100, 0, -0x8000, 0);
   1082     sMainMenuButtons[MENU_BUTTON_LANGUAGE_FRENCH]->oMenuButtonScale = 0.11111111f;
   1083     // German option button
   1084     sMainMenuButtons[MENU_BUTTON_LANGUAGE_GERMAN] = spawn_object_rel_with_rot(
   1085         soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, -533, -111, -100, 0, -0x8000, 0);
   1086     sMainMenuButtons[MENU_BUTTON_LANGUAGE_GERMAN]->oMenuButtonScale = 0.11111111f;
   1087 
   1088     // Return button
   1089     sMainMenuButtons[MENU_BUTTON_LANGUAGE_RETURN] = spawn_object_rel_with_rot(
   1090         soundModeButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 0, -533, -100, 0, -0x8000, 0);
   1091     sMainMenuButtons[MENU_BUTTON_LANGUAGE_RETURN]->oMenuButtonScale = 0.11111111f;
   1092 #else
   1093     // Zoom in current selection
   1094     sMainMenuButtons[MENU_BUTTON_OPTION_MIN + sSoundMode]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN;
   1095 #endif
   1096 }
   1097 
   1098 #undef SOUND_BUTTON_Y
   1099 
   1100 /**
   1101  * In the sound mode menu, checks if a button was clicked to change sound mode & button state.
   1102  */
   1103 void check_sound_mode_menu_clicked_buttons(struct Object *soundModeButton) {
   1104     if (soundModeButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
   1105         s32 buttonID;
   1106         // Configure sound mode menu button group
   1107         for (buttonID = MENU_BUTTON_OPTION_MIN; buttonID < MENU_BUTTON_OPTION_MAX; buttonID++) {
   1108             s16 buttonX = sMainMenuButtons[buttonID]->oPosX;
   1109             s16 buttonY = sMainMenuButtons[buttonID]->oPosY;
   1110 
   1111             if (check_clicked_button(buttonX, buttonY, 22.0f) == TRUE) {
   1112                 // If sound mode button clicked, select it and define sound mode
   1113                 // The check will always be true because of the group configured above (In JP & US)
   1114                 if (buttonID == MENU_BUTTON_STEREO || buttonID == MENU_BUTTON_MONO
   1115                     || buttonID == MENU_BUTTON_HEADSET) {
   1116                     if (soundModeButton->oMenuButtonActionPhase == SOUND_MODE_PHASE_MAIN) {
   1117                         play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
   1118 #if ENABLE_RUMBLE
   1119                         queue_rumble_data(5, 80);
   1120 #endif
   1121                         sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
   1122 #ifndef VERSION_EU
   1123                         // Sound menu buttons don't return to Main Menu in EU
   1124                         // because they don't have a case in bhv_menu_button_manager_loop
   1125                         sSelectedButtonID = buttonID;
   1126 #endif
   1127                         sSoundMode = buttonID - MENU_BUTTON_OPTION_MIN;
   1128                         save_file_set_sound_mode(sSoundMode);
   1129                     }
   1130                 }
   1131 #ifdef VERSION_EU
   1132                 // If language mode button clicked, select it and change language
   1133                 if (buttonID == MENU_BUTTON_LANGUAGE_ENGLISH || buttonID == MENU_BUTTON_LANGUAGE_FRENCH
   1134                          || buttonID == MENU_BUTTON_LANGUAGE_GERMAN) {
   1135                     if (soundModeButton->oMenuButtonActionPhase == SOUND_MODE_PHASE_MAIN) {
   1136                         play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
   1137                         sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
   1138                         sLanguageMode = buttonID - MENU_BUTTON_LANGUAGE_MIN;
   1139                         eu_set_language(sLanguageMode);
   1140                     }
   1141                 }
   1142                 // If neither of the buttons above are pressed, return to main menu
   1143                 if (buttonID == MENU_BUTTON_LANGUAGE_RETURN) {
   1144                     play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
   1145                     sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT;
   1146                     sSelectedButtonID = buttonID;
   1147                 }
   1148 #endif
   1149                 sCurrentMenuLevel = MENU_LAYER_SUBMENU;
   1150 
   1151                 break;
   1152             }
   1153         }
   1154     }
   1155 }
   1156 
   1157 /**
   1158  * Loads a save file selected after it goes into a full screen state
   1159  * retuning sSelectedFileNum to a save value defined in fileNum.
   1160  */
   1161 void load_main_menu_save_file(struct Object *fileButton, s32 fileNum) {
   1162     if (fileButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
   1163         sSelectedFileNum = fileNum;
   1164     }
   1165 }
   1166 
   1167 /**
   1168  * Returns from the previous menu back to the main menu using
   1169  * the return button (or sound mode) as source button.
   1170  */
   1171 void return_to_main_menu(s16 prevMenuButtonID, struct Object *sourceButton) {
   1172     s32 buttonID;
   1173     // If the source button is in default state and the previous menu in full screen,
   1174     // play zoom out sound and shrink previous menu
   1175     if (sourceButton->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT
   1176         && sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
   1177         play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource);
   1178         sMainMenuButtons[prevMenuButtonID]->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING;
   1179         sCurrentMenuLevel = MENU_LAYER_MAIN;
   1180     }
   1181     // If the previous button is in default state, return back to the main menu
   1182     if (sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT) {
   1183         sSelectedButtonID = MENU_BUTTON_NONE;
   1184         // Hide buttons of corresponding button menu groups
   1185         if (prevMenuButtonID == MENU_BUTTON_SCORE) {
   1186             for (buttonID = MENU_BUTTON_SCORE_MIN; buttonID < MENU_BUTTON_SCORE_MAX; buttonID++) {
   1187                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1188             }
   1189         }
   1190         if (prevMenuButtonID == MENU_BUTTON_COPY) {
   1191             for (buttonID = MENU_BUTTON_COPY_MIN; buttonID < MENU_BUTTON_COPY_MAX; buttonID++) {
   1192                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1193             }
   1194         }
   1195         if (prevMenuButtonID == MENU_BUTTON_ERASE) {
   1196             for (buttonID = MENU_BUTTON_ERASE_MIN; buttonID < MENU_BUTTON_ERASE_MAX; buttonID++) {
   1197                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1198             }
   1199         }
   1200         if (prevMenuButtonID == MENU_BUTTON_SOUND_MODE) {
   1201             for (buttonID = MENU_BUTTON_OPTION_MIN; buttonID < MENU_BUTTON_OPTION_MAX; buttonID++) {
   1202                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1203             }
   1204         }
   1205     }
   1206 }
   1207 
   1208 /**
   1209  * Loads score menu from the previous menu using "CHECK SCORE" as source button.
   1210  */
   1211 void load_score_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceButton) {
   1212     s32 buttonID;
   1213     // If the source button is in default state and the previous menu in full screen,
   1214     // play zoom out sound and shrink previous menu
   1215     if (sourceButton->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT
   1216         && sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
   1217         play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource);
   1218         sMainMenuButtons[prevMenuButtonID]->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING;
   1219         sCurrentMenuLevel = MENU_LAYER_MAIN;
   1220     }
   1221     // If the previous button is in default state
   1222     if (sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT) {
   1223         // Hide buttons of corresponding button menu groups
   1224         //! Not possible, this is checking if the score menu was opened from the score menu!
   1225         if (prevMenuButtonID == MENU_BUTTON_SCORE) {
   1226             for (buttonID = MENU_BUTTON_SCORE_MIN; buttonID < MENU_BUTTON_SCORE_MAX; buttonID++) {
   1227                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1228             }
   1229         }
   1230         if (prevMenuButtonID == MENU_BUTTON_COPY) {
   1231             for (buttonID = MENU_BUTTON_COPY_MIN; buttonID < MENU_BUTTON_COPY_MAX; buttonID++) {
   1232                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1233             }
   1234         }
   1235         if (prevMenuButtonID == MENU_BUTTON_ERASE) {
   1236             for (buttonID = MENU_BUTTON_ERASE_MIN; buttonID < MENU_BUTTON_ERASE_MAX; buttonID++) {
   1237                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1238             }
   1239         }
   1240         // Play zoom in sound, select score menu and render it's buttons
   1241         sSelectedButtonID = MENU_BUTTON_SCORE;
   1242         play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
   1243         sMainMenuButtons[MENU_BUTTON_SCORE]->oMenuButtonState = MENU_BUTTON_STATE_GROWING;
   1244         render_score_menu_buttons(sMainMenuButtons[MENU_BUTTON_SCORE]);
   1245     }
   1246 }
   1247 
   1248 /**
   1249  * Loads copy menu from the previous menu using "COPY FILE" as source button.
   1250  */
   1251 void load_copy_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceButton) {
   1252     s32 buttonID;
   1253     // If the source button is in default state and the previous menu in full screen,
   1254     // play zoom out sound and shrink previous menu
   1255     if (sourceButton->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT
   1256         && sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
   1257         play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource);
   1258         sMainMenuButtons[prevMenuButtonID]->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING;
   1259         sCurrentMenuLevel = MENU_LAYER_MAIN;
   1260     }
   1261     // If the previous button is in default state
   1262     if (sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT) {
   1263         // Hide buttons of corresponding button menu groups
   1264         if (prevMenuButtonID == MENU_BUTTON_SCORE) {
   1265             for (buttonID = MENU_BUTTON_SCORE_MIN; buttonID < MENU_BUTTON_SCORE_MAX; buttonID++) {
   1266                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1267             }
   1268         }
   1269         //! Not possible, this is checking if the copy menu was opened from the copy menu!
   1270         if (prevMenuButtonID == MENU_BUTTON_COPY) {
   1271             for (buttonID = MENU_BUTTON_COPY_MIN; buttonID < MENU_BUTTON_COPY_MAX; buttonID++) {
   1272                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1273             }
   1274         }
   1275         if (prevMenuButtonID == MENU_BUTTON_ERASE) {
   1276             for (buttonID = MENU_BUTTON_ERASE_MIN; buttonID < MENU_BUTTON_ERASE_MAX; buttonID++) {
   1277                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1278             }
   1279         }
   1280         // Play zoom in sound, select copy menu and render it's buttons
   1281         sSelectedButtonID = MENU_BUTTON_COPY;
   1282         play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
   1283         sMainMenuButtons[MENU_BUTTON_COPY]->oMenuButtonState = MENU_BUTTON_STATE_GROWING;
   1284         render_copy_menu_buttons(sMainMenuButtons[MENU_BUTTON_COPY]);
   1285     }
   1286 }
   1287 
   1288 /**
   1289  * Loads erase menu from the previous menu using "ERASE FILE" as source button.
   1290  */
   1291 void load_erase_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceButton) {
   1292     s32 buttonID;
   1293     // If the source button is in default state and the previous menu in full screen,
   1294     // play zoom out sound and shrink previous menu
   1295     if (sourceButton->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT
   1296         && sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
   1297         play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource);
   1298         sMainMenuButtons[prevMenuButtonID]->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING;
   1299         sCurrentMenuLevel = MENU_LAYER_MAIN;
   1300     }
   1301     // If the previous button is in default state
   1302     if (sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT) {
   1303         // Hide buttons of corresponding button menu groups
   1304         if (prevMenuButtonID == MENU_BUTTON_SCORE) {
   1305             for (buttonID = MENU_BUTTON_SCORE_MIN; buttonID < MENU_BUTTON_SCORE_MAX; buttonID++) {
   1306                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1307             }
   1308         }
   1309         if (prevMenuButtonID == MENU_BUTTON_COPY) {
   1310             for (buttonID = MENU_BUTTON_COPY_MIN; buttonID < MENU_BUTTON_COPY_MAX; buttonID++) {
   1311                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1312             }
   1313         }
   1314         //! Not possible, this is checking if the erase menu was opened from the erase menu!
   1315         if (prevMenuButtonID == MENU_BUTTON_ERASE) {
   1316             for (buttonID = MENU_BUTTON_ERASE_MIN; buttonID < MENU_BUTTON_ERASE_MAX; buttonID++) {
   1317                 mark_obj_for_deletion(sMainMenuButtons[buttonID]);
   1318             }
   1319         }
   1320         // Play zoom in sound, select erase menu and render it's buttons
   1321         sSelectedButtonID = MENU_BUTTON_ERASE;
   1322         play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
   1323         sMainMenuButtons[MENU_BUTTON_ERASE]->oMenuButtonState = MENU_BUTTON_STATE_GROWING;
   1324         render_erase_menu_buttons(sMainMenuButtons[MENU_BUTTON_ERASE]);
   1325     }
   1326 }
   1327 
   1328 
   1329 /**
   1330  * Menu Buttons Menu Manager Initial Action
   1331  * Creates models of the buttons in the menu. For the Mario buttons it
   1332  * checks if a save file exists to render an specific button model for it.
   1333  * Unlike buttons on submenus, these are never hidden or recreated.
   1334  */
   1335 void bhv_menu_button_manager_init(void) {
   1336     // File A
   1337     if (save_file_exists(SAVE_FILE_A) == TRUE) {
   1338         sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A] =
   1339             spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE,
   1340                                       bhvMenuButton, -6400, 2800, 0, 0, 0, 0);
   1341     } else {
   1342         sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A] =
   1343             spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE,
   1344                                       bhvMenuButton, -6400, 2800, 0, 0, 0, 0);
   1345     }
   1346     sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A]->oMenuButtonScale = 1.0f;
   1347     // File B
   1348     if (save_file_exists(SAVE_FILE_B) == TRUE) {
   1349         sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B] =
   1350             spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE,
   1351                                       bhvMenuButton, 1500, 2800, 0, 0, 0, 0);
   1352     } else {
   1353         sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B] =
   1354             spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE,
   1355                                       bhvMenuButton, 1500, 2800, 0, 0, 0, 0);
   1356     }
   1357     sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B]->oMenuButtonScale = 1.0f;
   1358     // File C
   1359     if (save_file_exists(SAVE_FILE_C) == TRUE) {
   1360         sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C] =
   1361             spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE,
   1362                                       bhvMenuButton, -6400, 0, 0, 0, 0, 0);
   1363     } else {
   1364         sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C] = spawn_object_rel_with_rot(
   1365             gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, bhvMenuButton, -6400, 0, 0, 0, 0, 0);
   1366     }
   1367     sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C]->oMenuButtonScale = 1.0f;
   1368     // File D
   1369     if (save_file_exists(SAVE_FILE_D) == TRUE) {
   1370         sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D] = spawn_object_rel_with_rot(
   1371             gCurrentObject, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE, bhvMenuButton, 1500, 0, 0, 0, 0, 0);
   1372     } else {
   1373         sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D] = spawn_object_rel_with_rot(
   1374             gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, bhvMenuButton, 1500, 0, 0, 0, 0, 0);
   1375     }
   1376     sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D]->oMenuButtonScale = 1.0f;
   1377     // Score menu button
   1378     sMainMenuButtons[MENU_BUTTON_SCORE] = spawn_object_rel_with_rot(
   1379         gCurrentObject, MODEL_MAIN_MENU_GREEN_SCORE_BUTTON, bhvMenuButton, -6400, -3500, 0, 0, 0, 0);
   1380     sMainMenuButtons[MENU_BUTTON_SCORE]->oMenuButtonScale = 1.0f;
   1381     // Copy menu button
   1382     sMainMenuButtons[MENU_BUTTON_COPY] = spawn_object_rel_with_rot(
   1383         gCurrentObject, MODEL_MAIN_MENU_BLUE_COPY_BUTTON, bhvMenuButton, -2134, -3500, 0, 0, 0, 0);
   1384     sMainMenuButtons[MENU_BUTTON_COPY]->oMenuButtonScale = 1.0f;
   1385     // Erase menu button
   1386     sMainMenuButtons[MENU_BUTTON_ERASE] = spawn_object_rel_with_rot(
   1387         gCurrentObject, MODEL_MAIN_MENU_RED_ERASE_BUTTON, bhvMenuButton, 2134, -3500, 0, 0, 0, 0);
   1388     sMainMenuButtons[MENU_BUTTON_ERASE]->oMenuButtonScale = 1.0f;
   1389     // Sound mode menu button (Option Mode in EU)
   1390     sMainMenuButtons[MENU_BUTTON_SOUND_MODE] = spawn_object_rel_with_rot(
   1391         gCurrentObject, MODEL_MAIN_MENU_PURPLE_SOUND_BUTTON, bhvMenuButton, 6400, -3500, 0, 0, 0, 0);
   1392     sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonScale = 1.0f;
   1393 
   1394     sTextBaseAlpha = 0;
   1395 }
   1396 
   1397 #ifdef VERSION_JP
   1398     #define SAVE_FILE_SOUND SOUND_MENU_STAR_SOUND
   1399 #else
   1400     #define SAVE_FILE_SOUND SOUND_MENU_STAR_SOUND_OKEY_DOKEY
   1401 #endif
   1402 
   1403 /**
   1404  * In the main menu, check if a button was clicked to play it's button growing state.
   1405  * Also play a sound and/or render buttons depending of the button ID selected.
   1406  */
   1407 void check_main_menu_clicked_buttons(void) {
   1408 #ifdef VERSION_EU
   1409     if (sMainMenuTimer >= 5) {
   1410 #endif
   1411         // Sound mode menu is handled separately because the button ID for it
   1412         // is not grouped with the IDs of the other submenus.
   1413         if (check_clicked_button(sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oPosX,
   1414                                 sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oPosY, 200.0f) == TRUE) {
   1415             sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonState = MENU_BUTTON_STATE_GROWING;
   1416             sSelectedButtonID = MENU_BUTTON_SOUND_MODE;
   1417         } else {
   1418             // Main Menu buttons
   1419             s8 buttonID;
   1420             // Configure Main Menu button group
   1421             for (buttonID = MENU_BUTTON_MAIN_MIN; buttonID < MENU_BUTTON_MAIN_MAX; buttonID++) {
   1422                 s16 buttonX = sMainMenuButtons[buttonID]->oPosX;
   1423                 s16 buttonY = sMainMenuButtons[buttonID]->oPosY;
   1424 
   1425                 if (check_clicked_button(buttonX, buttonY, 200.0f) == TRUE) {
   1426                     // If menu button clicked, select it
   1427                     sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_GROWING;
   1428                     sSelectedButtonID = buttonID;
   1429                     break;
   1430                 }
   1431             }
   1432         }
   1433 #ifdef VERSION_EU
   1434         // Open Options Menu if sOpenLangSettings is TRUE (It's TRUE when there's no saves)
   1435         if (sOpenLangSettings == TRUE) {
   1436             sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonState = MENU_BUTTON_STATE_GROWING;
   1437             sSelectedButtonID = MENU_BUTTON_SOUND_MODE;
   1438             sOpenLangSettings = FALSE;
   1439         }
   1440 #endif
   1441 
   1442         // Play sound of the save file clicked
   1443         switch (sSelectedButtonID) {
   1444             case MENU_BUTTON_PLAY_FILE_A:
   1445                 play_sound(SAVE_FILE_SOUND, gGlobalSoundSource);
   1446 #if ENABLE_RUMBLE
   1447                 queue_rumble_data(60, 70);
   1448                 func_sh_8024C89C(1);
   1449 #endif
   1450                 break;
   1451             case MENU_BUTTON_PLAY_FILE_B:
   1452                 play_sound(SAVE_FILE_SOUND, gGlobalSoundSource);
   1453 #if ENABLE_RUMBLE
   1454                 queue_rumble_data(60, 70);
   1455                 func_sh_8024C89C(1);
   1456 #endif
   1457                 break;
   1458             case MENU_BUTTON_PLAY_FILE_C:
   1459                 play_sound(SAVE_FILE_SOUND, gGlobalSoundSource);
   1460 #if ENABLE_RUMBLE
   1461                 queue_rumble_data(60, 70);
   1462                 func_sh_8024C89C(1);
   1463 #endif
   1464                 break;
   1465             case MENU_BUTTON_PLAY_FILE_D:
   1466                 play_sound(SAVE_FILE_SOUND, gGlobalSoundSource);
   1467 #if ENABLE_RUMBLE
   1468                 queue_rumble_data(60, 70);
   1469                 func_sh_8024C89C(1);
   1470 #endif
   1471                 break;
   1472             // Play sound of the button clicked and render buttons of that menu.
   1473             case MENU_BUTTON_SCORE:
   1474                 play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
   1475 #if ENABLE_RUMBLE
   1476                 queue_rumble_data(5, 80);
   1477 #endif
   1478                 render_score_menu_buttons(sMainMenuButtons[MENU_BUTTON_SCORE]);
   1479                 break;
   1480             case MENU_BUTTON_COPY:
   1481                 play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
   1482 #if ENABLE_RUMBLE
   1483                 queue_rumble_data(5, 80);
   1484 #endif
   1485                 render_copy_menu_buttons(sMainMenuButtons[MENU_BUTTON_COPY]);
   1486                 break;
   1487             case MENU_BUTTON_ERASE:
   1488                 play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
   1489 #if ENABLE_RUMBLE
   1490                 queue_rumble_data(5, 80);
   1491 #endif
   1492                 render_erase_menu_buttons(sMainMenuButtons[MENU_BUTTON_ERASE]);
   1493                 break;
   1494             case MENU_BUTTON_SOUND_MODE:
   1495                 play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
   1496 #if ENABLE_RUMBLE
   1497                 queue_rumble_data(5, 80);
   1498 #endif
   1499                 render_sound_mode_menu_buttons(sMainMenuButtons[MENU_BUTTON_SOUND_MODE]);
   1500                 break;
   1501         }
   1502 #ifdef VERSION_EU
   1503     }
   1504 #endif
   1505 }
   1506 
   1507 #undef SAVE_FILE_SOUND
   1508 
   1509 /**
   1510  * Menu Buttons Menu Manager Loop Action
   1511  * Calls a menu function depending of the button chosen.
   1512  * sSelectedButtonID is MENU_BUTTON_NONE when the file select
   1513  * is loaded, and that checks what buttonID is clicked in the main menu.
   1514  */
   1515 void bhv_menu_button_manager_loop(void) {
   1516     switch (sSelectedButtonID) {
   1517         case MENU_BUTTON_NONE:
   1518             check_main_menu_clicked_buttons();
   1519             break;
   1520         case MENU_BUTTON_PLAY_FILE_A:
   1521             load_main_menu_save_file(sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A], 1);
   1522             break;
   1523         case MENU_BUTTON_PLAY_FILE_B:
   1524             load_main_menu_save_file(sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B], 2);
   1525             break;
   1526         case MENU_BUTTON_PLAY_FILE_C:
   1527             load_main_menu_save_file(sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C], 3);
   1528             break;
   1529         case MENU_BUTTON_PLAY_FILE_D:
   1530             load_main_menu_save_file(sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D], 4);
   1531             break;
   1532         case MENU_BUTTON_SCORE:
   1533             check_score_menu_clicked_buttons(sMainMenuButtons[MENU_BUTTON_SCORE]);
   1534             break;
   1535         case MENU_BUTTON_COPY:
   1536             check_copy_menu_clicked_buttons(sMainMenuButtons[MENU_BUTTON_COPY]);
   1537             break;
   1538         case MENU_BUTTON_ERASE:
   1539             check_erase_menu_clicked_buttons(sMainMenuButtons[MENU_BUTTON_ERASE]);
   1540             break;
   1541 
   1542         case MENU_BUTTON_SCORE_FILE_A:
   1543             exit_score_file_to_score_menu(sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A], MENU_BUTTON_SCORE);
   1544             break;
   1545         case MENU_BUTTON_SCORE_FILE_B:
   1546             exit_score_file_to_score_menu(sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B], MENU_BUTTON_SCORE);
   1547             break;
   1548         case MENU_BUTTON_SCORE_FILE_C:
   1549             exit_score_file_to_score_menu(sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C], MENU_BUTTON_SCORE);
   1550             break;
   1551         case MENU_BUTTON_SCORE_FILE_D:
   1552             exit_score_file_to_score_menu(sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D], MENU_BUTTON_SCORE);
   1553             break;
   1554         case MENU_BUTTON_SCORE_RETURN:
   1555             return_to_main_menu(MENU_BUTTON_SCORE, sMainMenuButtons[MENU_BUTTON_SCORE_RETURN]);
   1556             break;
   1557         case MENU_BUTTON_SCORE_COPY_FILE:
   1558             load_copy_menu_from_submenu(MENU_BUTTON_SCORE,
   1559                                         sMainMenuButtons[MENU_BUTTON_SCORE_COPY_FILE]);
   1560             break;
   1561         case MENU_BUTTON_SCORE_ERASE_FILE:
   1562             load_erase_menu_from_submenu(MENU_BUTTON_SCORE,
   1563                                          sMainMenuButtons[MENU_BUTTON_SCORE_ERASE_FILE]);
   1564             break;
   1565 
   1566         case MENU_BUTTON_COPY_FILE_A:
   1567             break;
   1568         case MENU_BUTTON_COPY_FILE_B:
   1569             break;
   1570         case MENU_BUTTON_COPY_FILE_C:
   1571             break;
   1572         case MENU_BUTTON_COPY_FILE_D:
   1573             break;
   1574         case MENU_BUTTON_COPY_RETURN:
   1575             return_to_main_menu(MENU_BUTTON_COPY, sMainMenuButtons[MENU_BUTTON_COPY_RETURN]);
   1576             break;
   1577         case MENU_BUTTON_COPY_CHECK_SCORE:
   1578             load_score_menu_from_submenu(MENU_BUTTON_COPY,
   1579                                          sMainMenuButtons[MENU_BUTTON_COPY_CHECK_SCORE]);
   1580             break;
   1581         case MENU_BUTTON_COPY_ERASE_FILE:
   1582             load_erase_menu_from_submenu(MENU_BUTTON_COPY,
   1583                                          sMainMenuButtons[MENU_BUTTON_COPY_ERASE_FILE]);
   1584             break;
   1585 
   1586         case MENU_BUTTON_ERASE_FILE_A:
   1587             break;
   1588         case MENU_BUTTON_ERASE_FILE_B:
   1589             break;
   1590         case MENU_BUTTON_ERASE_FILE_C:
   1591             break;
   1592         case MENU_BUTTON_ERASE_FILE_D:
   1593             break;
   1594         case MENU_BUTTON_ERASE_RETURN:
   1595             return_to_main_menu(MENU_BUTTON_ERASE, sMainMenuButtons[MENU_BUTTON_ERASE_RETURN]);
   1596             break;
   1597         case MENU_BUTTON_ERASE_CHECK_SCORE:
   1598             load_score_menu_from_submenu(MENU_BUTTON_ERASE,
   1599                                          sMainMenuButtons[MENU_BUTTON_ERASE_CHECK_SCORE]);
   1600             break;
   1601         case MENU_BUTTON_ERASE_COPY_FILE:
   1602             load_copy_menu_from_submenu(MENU_BUTTON_ERASE,
   1603                                         sMainMenuButtons[MENU_BUTTON_ERASE_COPY_FILE]);
   1604             break;
   1605 
   1606         case MENU_BUTTON_SOUND_MODE:
   1607             check_sound_mode_menu_clicked_buttons(sMainMenuButtons[MENU_BUTTON_SOUND_MODE]);
   1608             break;
   1609 
   1610         // STEREO, MONO and HEADSET buttons are undefined so they can be selected without
   1611         // exiting the Options menu, as a result they added a return button
   1612 #ifdef VERSION_EU
   1613         case MENU_BUTTON_LANGUAGE_RETURN:
   1614             return_to_main_menu(MENU_BUTTON_SOUND_MODE, sMainMenuButtons[MENU_BUTTON_LANGUAGE_RETURN]);
   1615             break;
   1616 #else
   1617         case MENU_BUTTON_STEREO:
   1618             return_to_main_menu(MENU_BUTTON_SOUND_MODE, sMainMenuButtons[MENU_BUTTON_STEREO]);
   1619             break;
   1620         case MENU_BUTTON_MONO:
   1621             return_to_main_menu(MENU_BUTTON_SOUND_MODE, sMainMenuButtons[MENU_BUTTON_MONO]);
   1622             break;
   1623         case MENU_BUTTON_HEADSET:
   1624             return_to_main_menu(MENU_BUTTON_SOUND_MODE, sMainMenuButtons[MENU_BUTTON_HEADSET]);
   1625             break;
   1626 #endif
   1627     }
   1628 
   1629     sClickPos[0] = -10000;
   1630     sClickPos[1] = -10000;
   1631 }
   1632 
   1633 /**
   1634  * Cursor function that handles button inputs.
   1635  * If the cursor is clicked, sClickPos uses the same value as sCursorPos.
   1636  */
   1637 void handle_cursor_button_input(void) {
   1638     // If scoring a file, pressing A just changes the coin score mode.
   1639     if (sSelectedButtonID == MENU_BUTTON_SCORE_FILE_A || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_B
   1640         || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_C
   1641         || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_D) {
   1642         if (gPlayer3Controller->buttonPressed
   1643 #ifdef VERSION_EU
   1644             & (B_BUTTON | START_BUTTON | Z_TRIG)
   1645 #else
   1646             & (B_BUTTON | START_BUTTON)
   1647 #endif
   1648         ) {
   1649             sClickPos[0] = sCursorPos[0];
   1650             sClickPos[1] = sCursorPos[1];
   1651             sCursorClickingTimer = 1;
   1652         } else if (gPlayer3Controller->buttonPressed & A_BUTTON) {
   1653             sScoreFileCoinScoreMode = 1 - sScoreFileCoinScoreMode;
   1654             play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
   1655 #ifdef VERSION_CN
   1656         } else if ((gPlayer3Controller->buttonPressed & L_TRIG) || (gPlayer3Controller->buttonPressed & R_TRIG)) {
   1657             sScorePage = 1 - sScorePage;
   1658             play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
   1659 #endif
   1660         }
   1661     } else { // If cursor is clicked
   1662         if (gPlayer3Controller->buttonPressed
   1663 #ifdef VERSION_EU
   1664             & (A_BUTTON | B_BUTTON | START_BUTTON | Z_TRIG)) {
   1665 #else
   1666             & (A_BUTTON | B_BUTTON | START_BUTTON)) {
   1667 #endif
   1668             sClickPos[0] = sCursorPos[0];
   1669             sClickPos[1] = sCursorPos[1];
   1670             sCursorClickingTimer = 1;
   1671         }
   1672     }
   1673 }
   1674 
   1675 /**
   1676  * Cursor function that handles analog stick input and button presses with a function near the end.
   1677  */
   1678 void handle_controller_cursor_input(void) {
   1679     s16 rawStickX = gPlayer3Controller->rawStickX;
   1680     s16 rawStickY = gPlayer3Controller->rawStickY;
   1681 
   1682     // Handle deadzone
   1683     if (rawStickY > -2 && rawStickY < 2) {
   1684         rawStickY = 0;
   1685     }
   1686     if (rawStickX > -2 && rawStickX < 2) {
   1687         rawStickX = 0;
   1688     }
   1689 
   1690     // Move cursor
   1691     sCursorPos[0] += rawStickX / 8;
   1692     sCursorPos[1] += rawStickY / 8;
   1693 
   1694     // Stop cursor from going offscreen
   1695     if (sCursorPos[0] > 132.0f) {
   1696         sCursorPos[0] = 132.0f;
   1697     }
   1698     if (sCursorPos[0] < -132.0f) {
   1699         sCursorPos[0] = -132.0f;
   1700     }
   1701 
   1702     if (sCursorPos[1] > 90.0f) {
   1703         sCursorPos[1] = 90.0f;
   1704     }
   1705     if (sCursorPos[1] < -90.0f) {
   1706         sCursorPos[1] = -90.0f;
   1707     }
   1708 
   1709     if (sCursorClickingTimer == 0) {
   1710         handle_cursor_button_input();
   1711     }
   1712 }
   1713 
   1714 /**
   1715  * Prints the cursor (Mario Hand, different to the one in the Mario screen)
   1716  * and loads it's controller inputs in handle_controller_cursor_input
   1717  * to be usable on the file select.
   1718  */
   1719 void print_menu_cursor(void) {
   1720     handle_controller_cursor_input();
   1721     create_dl_translation_matrix(MENU_MTX_PUSH, sCursorPos[0] + 160.0f - 5.0, sCursorPos[1] + 120.0f - 25.0, 0.0f);
   1722     // Get the right graphic to use for the cursor.
   1723     if (sCursorClickingTimer == 0) {
   1724         // Idle
   1725         gSPDisplayList(gDisplayListHead++, dl_menu_idle_hand);
   1726     }
   1727     if (sCursorClickingTimer != 0) {
   1728         // Grabbing
   1729         gSPDisplayList(gDisplayListHead++, dl_menu_grabbing_hand);
   1730     }
   1731     gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
   1732     if (sCursorClickingTimer != 0) {
   1733         sCursorClickingTimer++; // This is a very strange way to implement a timer? It counts up and
   1734                                 // then resets to 0 instead of just counting down to 0.
   1735         if (sCursorClickingTimer == 5) {
   1736             sCursorClickingTimer = 0;
   1737         }
   1738     }
   1739 }
   1740 
   1741 /**
   1742  * Prints a hud string depending of the hud table list defined with text fade properties.
   1743  */
   1744 void print_hud_lut_string_fade(s8 hudLUT, s16 x, s16 y, const u8 *text) {
   1745     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
   1746     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha - sTextFadeAlpha);
   1747     print_hud_lut_string(hudLUT, x, y, text);
   1748     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
   1749 }
   1750 
   1751 /**
   1752  * Prints a generic white string with text fade properties.
   1753  */
   1754 void print_generic_string_fade(s16 x, s16 y, const u8 *text) {
   1755     gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
   1756     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha - sTextFadeAlpha);
   1757     print_generic_string(x, y, text);
   1758     gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
   1759 }
   1760 
   1761 /**
   1762  * Updates text fade at the top of a menu.
   1763  */
   1764 s32 update_text_fade_out(void) {
   1765     if (sFadeOutText == TRUE) {
   1766         sTextFadeAlpha += 50;
   1767         if (sTextFadeAlpha == 250) {
   1768             sFadeOutText = FALSE;
   1769             return TRUE;
   1770         }
   1771     } else {
   1772         if (sTextFadeAlpha > 0) {
   1773             sTextFadeAlpha -= 50;
   1774         }
   1775     }
   1776     return FALSE;
   1777 }
   1778 
   1779 /**
   1780  * Prints the amount of stars of a save file.
   1781  * If a save doesn't exist, print "NEW" instead.
   1782  */
   1783 void print_save_file_star_count(s8 fileIndex, s16 x, s16 y) {
   1784     u8 starCountText[4];
   1785     s8 offset = 0;
   1786     s16 starCount;
   1787 
   1788     if (save_file_exists(fileIndex) == TRUE) {
   1789         starCount = save_file_get_total_star_count(fileIndex, COURSE_MIN - 1, COURSE_MAX - 1);
   1790         // Print star icon
   1791         print_hud_lut_string(HUD_LUT_GLOBAL, x, y, starIcon);
   1792         // If star count is less than 100, print x icon and move
   1793         // the star count text one digit to the right.
   1794         if (starCount < 100) {
   1795             print_hud_lut_string(HUD_LUT_GLOBAL, x + 16, y, xIcon);
   1796             offset = 16;
   1797         }
   1798         // Print star count
   1799         int_to_str(starCount, starCountText);
   1800         print_hud_lut_string(HUD_LUT_GLOBAL, x + (offset + 16), y, starCountText);
   1801     } else {
   1802         // Print "new" text
   1803 #ifdef VERSION_CN
   1804         print_hud_lut_string(HUD_LUT_GLOBAL, x - 2, y - 5, LANGUAGE_ARRAY(textNew));
   1805 #else
   1806         print_hud_lut_string(HUD_LUT_GLOBAL, x, y, LANGUAGE_ARRAY(textNew));
   1807 #endif
   1808     }
   1809 }
   1810 
   1811 #if defined(VERSION_JP) || defined(VERSION_SH)
   1812     #define SELECT_FILE_X 96
   1813     #define SELECT_FILE_Y 35
   1814     #define SCORE_X 50
   1815     #define COPY_X 115
   1816     #define ERASE_X 180
   1817 #ifdef VERSION_JP
   1818     #define SOUNDMODE_X1 235
   1819 #else
   1820     #define SOUNDMODE_X1 sSoundTextX
   1821 #endif
   1822     #define SAVEFILE_X1 92
   1823     #define SAVEFILE_X2 209
   1824     #define MARIOTEXT_X1 92
   1825     #define MARIOTEXT_X2 207
   1826     #define MARIOTEXT_Y1 65
   1827     #define MARIOTEXT_Y2 105
   1828 #elif defined(VERSION_US)
   1829     #define SELECT_FILE_X 93
   1830     #define SELECT_FILE_Y 35
   1831     #define SCORE_X 52
   1832     #define COPY_X 117
   1833     #define ERASE_X 177
   1834     #define SOUNDMODE_X1 sSoundTextX
   1835     #define SAVEFILE_X1 92
   1836     #define SAVEFILE_X2 209
   1837     #define MARIOTEXT_X1 92
   1838     #define MARIOTEXT_X2 207
   1839     #define MARIOTEXT_Y1 65
   1840     #define MARIOTEXT_Y2 105
   1841 #elif defined(VERSION_EU)
   1842     #define SAVEFILE_X1 97
   1843     #define SAVEFILE_X2 204
   1844     #define MARIOTEXT_X1 97
   1845     #define MARIOTEXT_X2 204
   1846     #define MARIOTEXT_Y1 65
   1847     #define MARIOTEXT_Y2 105
   1848 #elif defined(VERSION_CN)
   1849     #define SELECT_FILE_X 106
   1850     #define SELECT_FILE_Y 25
   1851     #define SCORE_X 52
   1852     #define COPY_X 113
   1853     #define ERASE_X 177
   1854     #define SOUNDMODE_X1 sSoundTextX
   1855     #define SAVEFILE_X1 92
   1856     #define SAVEFILE_X2 209
   1857     #define MARIOTEXT_X1 92
   1858     #define MARIOTEXT_X2 207
   1859     #define MARIOTEXT_Y1 164
   1860     #define MARIOTEXT_Y2 124
   1861 #endif
   1862 
   1863 /**
   1864  * Prints main menu strings that shows on the yellow background menu screen.
   1865  *
   1866  * In EU this function acts like "print_save_file_strings" because
   1867  * print_main_lang_strings is first called to render the strings for the 4 buttons.
   1868  * Same rule applies for score, copy and erase strings.
   1869  */
   1870 void print_main_menu_strings(void) {
   1871 #if defined(VERSION_SH) || defined(VERSION_CN)
   1872     // The current sound mode is automatically centered on US and Shindou.
   1873     static s16 sSoundTextX; // TODO: There should be a way to make this match on both US and Shindou.
   1874 #endif
   1875     // Print "SELECT FILE" text
   1876     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
   1877     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   1878 #ifndef VERSION_EU
   1879     print_hud_lut_string(HUD_LUT_DIFF2, SELECT_FILE_X, SELECT_FILE_Y, textSelectFile);
   1880 #endif
   1881     // Print file star counts
   1882     print_save_file_star_count(SAVE_FILE_A, SAVEFILE_X1, 78);
   1883     print_save_file_star_count(SAVE_FILE_B, SAVEFILE_X2, 78);
   1884     print_save_file_star_count(SAVE_FILE_C, SAVEFILE_X1, 118);
   1885     print_save_file_star_count(SAVE_FILE_D, SAVEFILE_X2, 118);
   1886     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
   1887 #ifndef VERSION_EU
   1888     // Print menu names
   1889     gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
   1890     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   1891     print_generic_string(SCORE_X, 39, textScore);
   1892     print_generic_string(COPY_X, 39, textCopy);
   1893     print_generic_string(ERASE_X, 39, textErase);
   1894 #ifndef VERSION_JP
   1895     sSoundTextX = get_str_x_pos_from_center(254, textSoundModes[sSoundMode], 10.0f);
   1896 #endif
   1897     print_generic_string(SOUNDMODE_X1, 39, textSoundModes[sSoundMode]);
   1898     gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
   1899 #endif
   1900 
   1901     // Print file names
   1902     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_BEGIN);
   1903     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   1904     FILE_SELECT_PRINT_STRING(MARIOTEXT_X1, MARIOTEXT_Y1, textMarioA);
   1905     FILE_SELECT_PRINT_STRING(MARIOTEXT_X2, MARIOTEXT_Y1, textMarioB);
   1906     FILE_SELECT_PRINT_STRING(MARIOTEXT_X1, MARIOTEXT_Y2, textMarioC);
   1907     FILE_SELECT_PRINT_STRING(MARIOTEXT_X2, MARIOTEXT_Y2, textMarioD);
   1908     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_END);
   1909 }
   1910 
   1911 #ifdef VERSION_EU
   1912 /**
   1913  * Prints the first part main menu strings that shows on the yellow background menu screen.
   1914  * Has the strings for the 4 buttons below the save buttons that get changed depending of the language.
   1915  * Calls print_main_menu_strings to print the remaining strings.
   1916  */
   1917 void print_main_lang_strings(void) {
   1918     static s16 centeredX;
   1919 
   1920     // Print "SELECT FILE" text
   1921     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
   1922     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   1923     centeredX = get_str_x_pos_from_center_scale(160, textSelectFile[sLanguageMode], 12.0f);
   1924     print_hud_lut_string(HUD_LUT_GLOBAL, centeredX, 35, textSelectFile[sLanguageMode]);
   1925     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
   1926 
   1927     // Print menu names
   1928     gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
   1929     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   1930     centeredX = get_str_x_pos_from_center(76, textScore[sLanguageMode], 10.0f);
   1931     print_generic_string(centeredX, 39, textScore[sLanguageMode]);
   1932     centeredX = get_str_x_pos_from_center(131, textCopy[sLanguageMode], 10.0f);
   1933     print_generic_string(centeredX, 39, textCopy[sLanguageMode]);
   1934     centeredX = get_str_x_pos_from_center(189, textErase[sLanguageMode], 10.0f);
   1935     print_generic_string(centeredX, 39, textErase[sLanguageMode]);
   1936     centeredX = get_str_x_pos_from_center(245, textOption[sLanguageMode], 10.0f);
   1937     print_generic_string(centeredX, 39, textOption[sLanguageMode]);
   1938     gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
   1939 
   1940     print_main_menu_strings();
   1941 }
   1942 #endif
   1943 
   1944 #if defined(VERSION_JP) || defined(VERSION_SH)
   1945     #define CHECK_FILE_X 90
   1946     #define CHECK_FILE_Y 35
   1947     #define NOSAVE_DATA_X1 90
   1948 #elif defined(VERSION_US)
   1949     #define CHECK_FILE_X 95
   1950     #define CHECK_FILE_Y 35
   1951     #define NOSAVE_DATA_X1 99
   1952 #elif defined(VERSION_EU)
   1953     #define CHECK_FILE_X checkFileX
   1954     #define CHECK_FILE_Y 35
   1955     #define NOSAVE_DATA_X1 noSaveDataX
   1956 #elif defined(VERSION_CN)
   1957     #define CHECK_FILE_X 106
   1958     #define CHECK_FILE_Y 25
   1959     #define NOSAVE_DATA_X1 99
   1960 #endif
   1961 
   1962 /**
   1963  * Defines IDs for the top message of the score menu and displays it if the ID is called in messageID.
   1964  */
   1965 void score_menu_display_message(s8 messageID) {
   1966 #ifdef VERSION_EU
   1967     s16 checkFileX, noSaveDataX;
   1968 #endif
   1969 
   1970     switch (messageID) {
   1971         case SCORE_MSG_CHECK_FILE:
   1972 #ifdef VERSION_EU
   1973             checkFileX = get_str_x_pos_from_center_scale(160, LANGUAGE_ARRAY(textCheckFile), 12.0f);
   1974 #endif
   1975             print_hud_lut_string_fade(HUD_LUT_DIFF, CHECK_FILE_X, CHECK_FILE_Y, LANGUAGE_ARRAY(textCheckFile));
   1976             break;
   1977         case SCORE_MSG_NOSAVE_DATA:
   1978 #ifdef VERSION_EU
   1979             noSaveDataX = get_str_x_pos_from_center(160, LANGUAGE_ARRAY(textNoSavedDataExists), 10.0f);
   1980 #endif
   1981             print_generic_string_fade(NOSAVE_DATA_X1, 190, LANGUAGE_ARRAY(textNoSavedDataExists));
   1982             break;
   1983     }
   1984 }
   1985 
   1986 #if defined(VERSION_JP) || defined(VERSION_SH)
   1987     #define RETURN_X     45
   1988     #define COPYFILE_X1  128
   1989     #define ERASEFILE_X1 228
   1990     #define SCORE_FILE_Y1 62
   1991     #define SCORE_FILE_Y2 105
   1992 #elif defined(VERSION_US)
   1993     #define RETURN_X     44
   1994     #define COPYFILE_X1  135
   1995     #define ERASEFILE_X1 231
   1996     #define SCORE_FILE_Y1 62
   1997     #define SCORE_FILE_Y2 105
   1998 #elif defined(VERSION_EU)
   1999     #define RETURN_X     centeredX
   2000     #define COPYFILE_X1  centeredX
   2001     #define ERASEFILE_X1 centeredX
   2002 #elif defined(VERSION_CN)
   2003     #define RETURN_X     44
   2004     #define COPYFILE_X1  135
   2005     #define ERASEFILE_X1 231
   2006     #define SCORE_FILE_Y1 164
   2007     #define SCORE_FILE_Y2 121
   2008 #endif
   2009 
   2010 #ifdef VERSION_CN
   2011     #define RETURN_X_OLD 45 // this X wasn't changed in all places
   2012 #else
   2013     #define RETURN_X_OLD RETURN_X
   2014 #endif
   2015 
   2016 #ifdef VERSION_EU
   2017     #define FADEOUT_TIMER 35
   2018 #else
   2019     #define FADEOUT_TIMER 20
   2020 #endif
   2021 
   2022 /**
   2023  * Prints score menu strings that shows on the green background menu screen.
   2024  */
   2025 void print_score_menu_strings(void) {
   2026 #ifdef VERSION_EU
   2027     s16 centeredX;
   2028 #endif
   2029 
   2030     // Update and print the message at the top of the menu.
   2031     if (sMainMenuTimer == FADEOUT_TIMER) {
   2032         sFadeOutText = TRUE;
   2033     }
   2034     if (update_text_fade_out() == TRUE) {
   2035         if (sStatusMessageID == SCORE_MSG_CHECK_FILE) {
   2036             sStatusMessageID = SCORE_MSG_NOSAVE_DATA;
   2037         } else {
   2038             sStatusMessageID = SCORE_MSG_CHECK_FILE;
   2039         }
   2040     }
   2041     // Print messageID called above
   2042     score_menu_display_message(sStatusMessageID);
   2043 
   2044 #ifndef VERSION_EU
   2045     // Print file star counts
   2046     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
   2047     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2048     print_save_file_star_count(SAVE_FILE_A, 90, 76);
   2049     print_save_file_star_count(SAVE_FILE_B, 211, 76);
   2050     print_save_file_star_count(SAVE_FILE_C, 90, 119);
   2051     print_save_file_star_count(SAVE_FILE_D, 211, 119);
   2052     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
   2053 #endif
   2054 
   2055     // Print menu names
   2056     gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
   2057     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2058 #ifdef VERSION_EU
   2059     centeredX = get_str_x_pos_from_center(69, textReturn[sLanguageMode], 10.0f);
   2060 #endif
   2061     print_generic_string(RETURN_X, 35, LANGUAGE_ARRAY(textReturn));
   2062 #ifdef VERSION_EU
   2063     centeredX = get_str_x_pos_from_center(159, textCopyFileButton[sLanguageMode], 10.0f);
   2064 #endif
   2065     print_generic_string(COPYFILE_X1, 35, LANGUAGE_ARRAY(textCopyFileButton));
   2066 #ifdef VERSION_EU
   2067     centeredX = get_str_x_pos_from_center(249, textEraseFileButton[sLanguageMode], 10.0f);
   2068 #endif
   2069     print_generic_string(ERASEFILE_X1, 35, LANGUAGE_ARRAY(textEraseFileButton));
   2070     gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
   2071 
   2072     // Print file names
   2073 #ifdef VERSION_EU
   2074     print_main_menu_strings();
   2075 #else
   2076     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_BEGIN);
   2077     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2078     FILE_SELECT_PRINT_STRING(89, SCORE_FILE_Y1, textMarioA);
   2079     FILE_SELECT_PRINT_STRING(211, SCORE_FILE_Y1, textMarioB);
   2080     FILE_SELECT_PRINT_STRING(89, SCORE_FILE_Y2, textMarioC);
   2081     FILE_SELECT_PRINT_STRING(211, SCORE_FILE_Y2, textMarioD);
   2082     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_END);
   2083 #endif
   2084 }
   2085 
   2086 #if defined(VERSION_JP) || defined(VERSION_SH)
   2087     #define NOFILE_COPY_X  90
   2088     #define COPY_FILE_X    90
   2089     #define COPYIT_WHERE_X 90
   2090     #define NOSAVE_DATA_X2 90
   2091     #define COPYCOMPLETE_X 90
   2092     #define SAVE_EXISTS_X1 90
   2093     #define COPY_FILE_Y    35
   2094 #elif defined(VERSION_US)
   2095     #define NOFILE_COPY_X  119
   2096     #define COPY_FILE_X    104
   2097     #define COPYIT_WHERE_X 109
   2098     #define NOSAVE_DATA_X2 101
   2099     #define COPYCOMPLETE_X 110
   2100     #define SAVE_EXISTS_X1 110
   2101     #define COPY_FILE_Y    35
   2102 #elif defined(VERSION_EU)
   2103     #define NOFILE_COPY_X  centeredX
   2104     #define COPY_FILE_X    centeredX
   2105     #define COPYIT_WHERE_X centeredX
   2106     #define NOSAVE_DATA_X2 centeredX
   2107     #define COPYCOMPLETE_X centeredX
   2108     #define SAVE_EXISTS_X1 centeredX
   2109     #define COPY_FILE_Y    35
   2110 #elif defined(VERSION_CN)
   2111     #define NOFILE_COPY_X  119
   2112     #define COPY_FILE_X    104
   2113     #define COPYIT_WHERE_X 109
   2114     #define NOSAVE_DATA_X2 101
   2115     #define COPYCOMPLETE_X 110
   2116     #define SAVE_EXISTS_X1 110
   2117     #define COPY_FILE_Y    25
   2118 #endif
   2119 
   2120 /**
   2121  * Defines IDs for the top message of the copy menu and displays it if the ID is called in messageID.
   2122  */
   2123 void copy_menu_display_message(s8 messageID) {
   2124 #ifdef VERSION_EU
   2125     s16 centeredX;
   2126 #endif
   2127 
   2128     switch (messageID) {
   2129         case COPY_MSG_MAIN_TEXT:
   2130             if (sAllFilesExist == TRUE) {
   2131 #ifdef VERSION_EU
   2132                 centeredX = get_str_x_pos_from_center(160, textNoFileToCopyFrom[sLanguageMode], 10.0f);
   2133 #endif
   2134                 print_generic_string_fade(NOFILE_COPY_X, 190, LANGUAGE_ARRAY(textNoFileToCopyFrom));
   2135             } else {
   2136 #ifdef VERSION_EU
   2137                 centeredX = get_str_x_pos_from_center_scale(160, textCopyFile[sLanguageMode], 12.0f);
   2138 #endif
   2139                 print_hud_lut_string_fade(HUD_LUT_DIFF, COPY_FILE_X, COPY_FILE_Y, LANGUAGE_ARRAY(textCopyFile));
   2140             }
   2141             break;
   2142         case COPY_MSG_COPY_WHERE:
   2143 #ifdef VERSION_EU
   2144             centeredX = get_str_x_pos_from_center(160, textCopyItToWhere[sLanguageMode], 10.0f);
   2145 #endif
   2146             print_generic_string_fade(COPYIT_WHERE_X, 190, LANGUAGE_ARRAY(textCopyItToWhere));
   2147             break;
   2148         case COPY_MSG_NOSAVE_EXISTS:
   2149 #ifdef VERSION_EU
   2150             centeredX = get_str_x_pos_from_center(160, textNoSavedDataExists[sLanguageMode], 10.0f);
   2151             print_generic_string_fade(NOSAVE_DATA_X2, 190, textNoSavedDataExists[sLanguageMode]);
   2152 #else
   2153             print_generic_string_fade(NOSAVE_DATA_X2, 190, textNoSavedDataExistsCopy);
   2154 #endif
   2155             break;
   2156         case COPY_MSG_COPY_COMPLETE:
   2157 #ifdef VERSION_EU
   2158             centeredX = get_str_x_pos_from_center(160, textCopyCompleted[sLanguageMode], 10.0f);
   2159 #endif
   2160             print_generic_string_fade(COPYCOMPLETE_X, 190, LANGUAGE_ARRAY(textCopyCompleted));
   2161             break;
   2162         case COPY_MSG_SAVE_EXISTS:
   2163 #ifdef VERSION_EU
   2164             centeredX = get_str_x_pos_from_center(160, textSavedDataExists[sLanguageMode], 10.0f);
   2165 #endif
   2166             print_generic_string_fade(SAVE_EXISTS_X1, 190, LANGUAGE_ARRAY(textSavedDataExists));
   2167             break;
   2168     }
   2169 }
   2170 
   2171 /**
   2172  * Updates messageIDs of the copy menu depending of the copy phase value defined.
   2173  */
   2174 void copy_menu_update_message(void) {
   2175     switch (sMainMenuButtons[MENU_BUTTON_COPY]->oMenuButtonActionPhase) {
   2176         case COPY_PHASE_MAIN:
   2177             if (sMainMenuTimer == FADEOUT_TIMER) {
   2178                 sFadeOutText = TRUE;
   2179             }
   2180             if (update_text_fade_out() == TRUE) {
   2181                 if (sStatusMessageID == COPY_MSG_MAIN_TEXT) {
   2182                     sStatusMessageID = COPY_MSG_NOSAVE_EXISTS;
   2183                 } else {
   2184                     sStatusMessageID = COPY_MSG_MAIN_TEXT;
   2185                 }
   2186             }
   2187             break;
   2188         case COPY_PHASE_COPY_WHERE:
   2189             if (sMainMenuTimer == FADEOUT_TIMER
   2190                 && sStatusMessageID == COPY_MSG_SAVE_EXISTS) {
   2191                 sFadeOutText = TRUE;
   2192             }
   2193             if (update_text_fade_out() == TRUE) {
   2194                 if (sStatusMessageID != COPY_MSG_COPY_WHERE) {
   2195                     sStatusMessageID = COPY_MSG_COPY_WHERE;
   2196                 } else {
   2197                     sStatusMessageID = COPY_MSG_SAVE_EXISTS;
   2198                 }
   2199             }
   2200             break;
   2201         case COPY_PHASE_COPY_COMPLETE:
   2202             if (sMainMenuTimer == FADEOUT_TIMER) {
   2203                 sFadeOutText = TRUE;
   2204             }
   2205             if (update_text_fade_out() == TRUE) {
   2206                 if (sStatusMessageID != COPY_MSG_COPY_COMPLETE) {
   2207                     sStatusMessageID = COPY_MSG_COPY_COMPLETE;
   2208                 } else {
   2209                     sStatusMessageID = COPY_MSG_MAIN_TEXT;
   2210                 }
   2211             }
   2212             break;
   2213     }
   2214 }
   2215 
   2216 #if defined(VERSION_JP)
   2217     #define VIEWSCORE_X1 133
   2218     #define ERASEFILE_X2 220
   2219     #define COPY_FILE_Y1 62
   2220     #define COPY_FILE_Y2 105
   2221 #elif defined(VERSION_US)
   2222     #define VIEWSCORE_X1 128
   2223     #define ERASEFILE_X2 230
   2224     #define COPY_FILE_Y1 62
   2225     #define COPY_FILE_Y2 105
   2226 #elif defined(VERSION_EU)
   2227     #define VIEWSCORE_X1 centeredX
   2228     #define ERASEFILE_X2 centeredX
   2229 #elif defined(VERSION_SH)
   2230     #define VIEWSCORE_X1 133
   2231     #define ERASEFILE_X2 230
   2232     #define COPY_FILE_Y1 62
   2233     #define COPY_FILE_Y2 105
   2234 #elif defined(VERSION_CN)
   2235     #define VIEWSCORE_X1 128
   2236     #define ERASEFILE_X2 230
   2237     #define COPY_FILE_Y1 164
   2238     #define COPY_FILE_Y2 121
   2239 #endif
   2240 
   2241 /**
   2242  * Prints copy menu strings that shows on the blue background menu screen.
   2243  */
   2244 void print_copy_menu_strings(void) {
   2245 #ifdef VERSION_EU
   2246     s16 centeredX;
   2247 #endif
   2248 
   2249     // Update and print the message at the top of the menu.
   2250     copy_menu_update_message();
   2251     // Print messageID called inside a copy_menu_update_message case
   2252     copy_menu_display_message(sStatusMessageID);
   2253 #ifndef VERSION_EU
   2254     // Print file star counts
   2255     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
   2256     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2257     print_save_file_star_count(SAVE_FILE_A, 90, 76);
   2258     print_save_file_star_count(SAVE_FILE_B, 211, 76);
   2259     print_save_file_star_count(SAVE_FILE_C, 90, 119);
   2260     print_save_file_star_count(SAVE_FILE_D, 211, 119);
   2261     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
   2262 #endif
   2263     // Print menu names
   2264     gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
   2265     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2266 #ifdef VERSION_EU
   2267     centeredX = get_str_x_pos_from_center(69, textReturn[sLanguageMode], 10.0f);
   2268 #endif
   2269     print_generic_string(RETURN_X, 35, LANGUAGE_ARRAY(textReturn));
   2270 #ifdef VERSION_EU
   2271     centeredX = get_str_x_pos_from_center(159, textViewScore[sLanguageMode], 10.0f);
   2272 #endif
   2273     print_generic_string(VIEWSCORE_X1, 35, LANGUAGE_ARRAY(textViewScore));
   2274 #ifdef VERSION_EU
   2275     centeredX = get_str_x_pos_from_center(249, textEraseFileButton[sLanguageMode], 10.0f);
   2276 #endif
   2277     print_generic_string(ERASEFILE_X2, 35, LANGUAGE_ARRAY(textEraseFileButton));
   2278     gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
   2279 
   2280     // Print file names
   2281 #ifdef VERSION_EU
   2282     print_main_menu_strings();
   2283 #else
   2284     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_BEGIN);
   2285     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2286     FILE_SELECT_PRINT_STRING(89, COPY_FILE_Y1, textMarioA);
   2287     FILE_SELECT_PRINT_STRING(211, COPY_FILE_Y1, textMarioB);
   2288     FILE_SELECT_PRINT_STRING(89, COPY_FILE_Y2, textMarioC);
   2289     FILE_SELECT_PRINT_STRING(211, COPY_FILE_Y2, textMarioD);
   2290     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_END);
   2291 #endif
   2292 }
   2293 
   2294 #if defined(VERSION_JP) || defined(VERSION_SH)
   2295 #ifdef VERSION_JP
   2296     #define CURSOR_X 160.0f
   2297 #else
   2298     #define CURSOR_X (x + 70)
   2299 #endif
   2300     #define MENU_ERASE_YES_MIN_X 145
   2301     #define MENU_ERASE_YES_MAX_X 164
   2302 #elif defined(VERSION_CN)
   2303     #define CURSOR_X (x + 70)
   2304     #define MENU_ERASE_YES_MIN_X 144
   2305     #define MENU_ERASE_YES_MAX_X 173
   2306 #else
   2307     #define CURSOR_X (x + 70)
   2308     #define MENU_ERASE_YES_MIN_X 140
   2309     #define MENU_ERASE_YES_MAX_X 169
   2310 #endif
   2311 
   2312 #ifdef VERSION_CN
   2313     #define MENU_ERASE_YES_NO_MIN_Y 191
   2314     #define MENU_ERASE_YES_NO_MAX_Y 210
   2315     #define MENU_ERASE_NO_MIN_X 189
   2316     #define MENU_ERASE_NO_MAX_X 218
   2317     #define MENU_ERASE_YES_X_OFFSET 60
   2318 #elif defined(VERSION_SH)
   2319     #define MENU_ERASE_YES_NO_MIN_Y 191
   2320     #define MENU_ERASE_YES_NO_MAX_Y 210
   2321     #define MENU_ERASE_NO_MIN_X 194
   2322     #define MENU_ERASE_NO_MAX_X 213
   2323     #define MENU_ERASE_YES_X_OFFSET 56
   2324 #else
   2325     #define MENU_ERASE_YES_NO_MIN_Y 191
   2326     #define MENU_ERASE_YES_NO_MAX_Y 210
   2327     #define MENU_ERASE_NO_MIN_X 189
   2328     #define MENU_ERASE_NO_MAX_X 218
   2329     #define MENU_ERASE_YES_X_OFFSET 56
   2330 #endif
   2331 
   2332 /**
   2333  * Prints the "YES NO" prompt and checks if one of the prompts are hovered to do it's functions.
   2334  */
   2335 void print_erase_menu_prompt(s16 x, s16 y) {
   2336     s16 colorTransTimer = gGlobalTimer * (1 << 12);
   2337 
   2338     s16 cursorX = sCursorPos[0] + CURSOR_X;
   2339     s16 cursorY = sCursorPos[1] + 120.0f;
   2340 
   2341     // TODO: Merge IDO/GCC
   2342     if (cursorX < MENU_ERASE_YES_MAX_X && cursorX >= MENU_ERASE_YES_MIN_X &&
   2343 #ifdef VERSION_CN
   2344         (u16) (cursorY - MENU_ERASE_YES_NO_MIN_Y) < MENU_ERASE_YES_NO_MAX_Y - MENU_ERASE_YES_NO_MIN_Y
   2345 #else
   2346         cursorY < MENU_ERASE_YES_NO_MAX_Y && cursorY >= MENU_ERASE_YES_NO_MIN_Y
   2347 #endif
   2348     ) {
   2349         // Fade "YES" string color but keep "NO" gray
   2350         sYesNoColor[0] = sins(colorTransTimer) * 50.0f + 205.0f;
   2351         sYesNoColor[1] = 150;
   2352         sEraseYesNoHoverState = MENU_ERASE_HOVER_YES;
   2353     } else if (cursorX < MENU_ERASE_NO_MAX_X && cursorX >= MENU_ERASE_NO_MIN_X &&
   2354 #ifdef VERSION_CN
   2355         (u16) (cursorY - MENU_ERASE_YES_NO_MIN_Y) < MENU_ERASE_YES_NO_MAX_Y - MENU_ERASE_YES_NO_MIN_Y
   2356 #else
   2357         cursorY < MENU_ERASE_YES_NO_MAX_Y && cursorY >= MENU_ERASE_YES_NO_MIN_Y
   2358 #endif
   2359     ) {
   2360         // Fade "NO" string color but keep "YES" gray
   2361         sYesNoColor[0] = 150;
   2362         sYesNoColor[1] = sins(colorTransTimer) * 50.0f + 205.0f;
   2363         sEraseYesNoHoverState = MENU_ERASE_HOVER_NO;
   2364     } else {
   2365         // Don't fade both strings and keep them gray
   2366         sYesNoColor[0] = 150;
   2367         sYesNoColor[1] = 150;
   2368         sEraseYesNoHoverState = MENU_ERASE_HOVER_NONE;
   2369     }
   2370     // If the cursor is clicked...
   2371     if (sCursorClickingTimer == 2) {
   2372         // ..and is hovering "YES", delete file
   2373         if (sEraseYesNoHoverState == MENU_ERASE_HOVER_YES) {
   2374             play_sound(SOUND_MARIO_WAAAOOOW, gGlobalSoundSource);
   2375 #if ENABLE_RUMBLE
   2376             queue_rumble_data(5, 80);
   2377 #endif
   2378             sMainMenuButtons[MENU_BUTTON_ERASE]->oMenuButtonActionPhase = ERASE_PHASE_MARIO_ERASED;
   2379             sFadeOutText = TRUE;
   2380             sMainMenuTimer = 0;
   2381             save_file_erase(sSelectedFileIndex);
   2382             sMainMenuButtons[MENU_BUTTON_ERASE_MIN + sSelectedFileIndex]->header.gfx.sharedChild =
   2383                 gLoadedGraphNodes[MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE];
   2384             sMainMenuButtons[sSelectedFileIndex]->header.gfx.sharedChild =
   2385                 gLoadedGraphNodes[MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE];
   2386             sEraseYesNoHoverState = MENU_ERASE_HOVER_NONE;
   2387             // ..and is hovering "NO", return back to main phase
   2388         } else if (sEraseYesNoHoverState == MENU_ERASE_HOVER_NO) {
   2389             play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource);
   2390 #if ENABLE_RUMBLE
   2391             queue_rumble_data(5, 80);
   2392 #endif
   2393             sMainMenuButtons[MENU_BUTTON_ERASE_MIN + sSelectedFileIndex]->oMenuButtonState =
   2394                 MENU_BUTTON_STATE_ZOOM_OUT;
   2395             sMainMenuButtons[MENU_BUTTON_ERASE]->oMenuButtonActionPhase = ERASE_PHASE_MAIN;
   2396             sFadeOutText = TRUE;
   2397             sMainMenuTimer = 0;
   2398             sEraseYesNoHoverState = MENU_ERASE_HOVER_NONE;
   2399         }
   2400     }
   2401 
   2402     // Print "YES NO" strings
   2403     gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
   2404     gDPSetEnvColor(gDisplayListHead++, sYesNoColor[0], sYesNoColor[0], sYesNoColor[0], sTextBaseAlpha);
   2405     print_generic_string(x + MENU_ERASE_YES_X_OFFSET, y, LANGUAGE_ARRAY(textYes));
   2406     gDPSetEnvColor(gDisplayListHead++, sYesNoColor[1], sYesNoColor[1], sYesNoColor[1], sTextBaseAlpha);
   2407     print_generic_string(x + 98, y, LANGUAGE_ARRAY(textNo));
   2408     gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
   2409 }
   2410 
   2411 // MARIO_ERASED_VAR is the value there the letter "A" is, it works like this:
   2412 //   US and EU   ---    JP
   2413 // M a r i o   A --- マ リ オ A
   2414 // 0 1 2 3 4 5 6 --- 0 1 2 3
   2415 #if defined(VERSION_JP) || defined(VERSION_SH)
   2416 #ifdef VERSION_JP
   2417     #define ERASE_FILE_X     96
   2418 #else
   2419     #define ERASE_FILE_X     111
   2420 #endif
   2421     #define ERASE_FILE_Y     35
   2422     #define NOSAVE_DATA_X3   90
   2423     #define MARIO_ERASED_VAR 3
   2424     #define MARIO_ERASED_X   90
   2425     #define SAVE_EXISTS_X2   90
   2426 #elif defined(VERSION_US)
   2427     #define ERASE_FILE_X     98
   2428     #define ERASE_FILE_Y     35
   2429     #define NOSAVE_DATA_X3   100
   2430     #define MARIO_ERASED_VAR 6
   2431     #define MARIO_ERASED_X   100
   2432     #define SAVE_EXISTS_X2   100
   2433 #elif defined(VERSION_EU)
   2434     #define ERASE_FILE_X     centeredX
   2435     #define ERASE_FILE_Y     35
   2436     #define NOSAVE_DATA_X3   centeredX
   2437     #define MARIO_ERASED_VAR 6
   2438     #define MARIO_ERASED_X   centeredX
   2439     #define SAVE_EXISTS_X2   centeredX
   2440 #elif defined(VERSION_CN)
   2441     #define ERASE_FILE_X     106
   2442     #define ERASE_FILE_Y     25
   2443     #define NOSAVE_DATA_X3   100
   2444     #define MARIO_ERASED_VAR 15
   2445     #define MARIO_ERASED_X   100
   2446     #define SAVE_EXISTS_X2   100
   2447 #endif
   2448 
   2449 /**
   2450  * Defines IDs for the top message of the erase menu and displays it if the ID is called in messageID.
   2451  */
   2452 void erase_menu_display_message(s8 messageID) {
   2453 #ifdef VERSION_EU
   2454     s16 centeredX;
   2455 #endif
   2456 
   2457 #ifndef VERSION_EU
   2458     u8 textEraseFile[] = { TEXT_ERASE_FILE };
   2459     u8 textSure[] = { TEXT_SURE };
   2460     u8 textNoSavedDataExists[] = { TEXT_NO_SAVED_DATA_EXISTS };
   2461     u8 textMarioAJustErased[] = { TEXT_FILE_MARIO_A_JUST_ERASED };
   2462     u8 textSavedDataExists[] = { TEXT_SAVED_DATA_EXISTS };
   2463 #endif
   2464 
   2465     switch (messageID) {
   2466         case ERASE_MSG_MAIN_TEXT:
   2467 #ifdef VERSION_EU
   2468             centeredX = get_str_x_pos_from_center_scale(160, textEraseFile[sLanguageMode], 12.0f);
   2469 #endif
   2470             print_hud_lut_string_fade(HUD_LUT_DIFF, ERASE_FILE_X, ERASE_FILE_Y, LANGUAGE_ARRAY(textEraseFile));
   2471             break;
   2472         case ERASE_MSG_PROMPT:
   2473             print_generic_string_fade(90, 190, LANGUAGE_ARRAY(textSure));
   2474             print_erase_menu_prompt(90, 190); // YES NO, has functions for it too
   2475             break;
   2476         case ERASE_MSG_NOSAVE_EXISTS:
   2477 #ifdef VERSION_EU
   2478             centeredX = get_str_x_pos_from_center(160, textNoSavedDataExists[sLanguageMode], 10.0f);
   2479 #endif
   2480             print_generic_string_fade(NOSAVE_DATA_X3, 190, LANGUAGE_ARRAY(textNoSavedDataExists));
   2481             break;
   2482         case ERASE_MSG_MARIO_ERASED:
   2483             LANGUAGE_ARRAY(textMarioAJustErased)[MARIO_ERASED_VAR] = sSelectedFileIndex + 10;
   2484 #ifdef VERSION_EU
   2485             centeredX = get_str_x_pos_from_center(160, textMarioAJustErased[sLanguageMode], 10.0f);
   2486 #endif
   2487             print_generic_string_fade(MARIO_ERASED_X, 190, LANGUAGE_ARRAY(textMarioAJustErased));
   2488             break;
   2489         case ERASE_MSG_SAVE_EXISTS: // unused
   2490 #ifdef VERSION_EU
   2491             centeredX = get_str_x_pos_from_center(160, textSavedDataExists[sLanguageMode], 10.0f);
   2492 #endif
   2493             print_generic_string_fade(SAVE_EXISTS_X2, 190, LANGUAGE_ARRAY(textSavedDataExists));
   2494             break;
   2495     }
   2496 }
   2497 
   2498 /**
   2499  * Updates messageIDs of the erase menu depending of the erase phase value defined.
   2500  */
   2501 void erase_menu_update_message(void) {
   2502     switch (sMainMenuButtons[MENU_BUTTON_ERASE]->oMenuButtonActionPhase) {
   2503         case ERASE_PHASE_MAIN:
   2504             if (sMainMenuTimer == FADEOUT_TIMER
   2505                 && sStatusMessageID == ERASE_MSG_NOSAVE_EXISTS) {
   2506                 sFadeOutText = TRUE;
   2507             }
   2508             if (update_text_fade_out() == TRUE) {
   2509                 if (sStatusMessageID == ERASE_MSG_MAIN_TEXT) {
   2510                     sStatusMessageID = ERASE_MSG_NOSAVE_EXISTS;
   2511                 } else {
   2512                     sStatusMessageID = ERASE_MSG_MAIN_TEXT;
   2513                 }
   2514             }
   2515             break;
   2516         case ERASE_PHASE_PROMPT:
   2517             if (update_text_fade_out() == TRUE) {
   2518                 if (sStatusMessageID != ERASE_MSG_PROMPT) {
   2519                     sStatusMessageID = ERASE_MSG_PROMPT;
   2520                 }
   2521                 sCursorPos[0] = 43.0f;
   2522                 sCursorPos[1] = 80.0f;
   2523             }
   2524             break;
   2525         case ERASE_PHASE_MARIO_ERASED:
   2526             if (sMainMenuTimer == FADEOUT_TIMER) {
   2527                 sFadeOutText = TRUE;
   2528             }
   2529             if (update_text_fade_out() == TRUE) {
   2530                 if (sStatusMessageID != ERASE_MSG_MARIO_ERASED) {
   2531                     sStatusMessageID = ERASE_MSG_MARIO_ERASED;
   2532                 } else {
   2533                     sStatusMessageID = ERASE_MSG_MAIN_TEXT;
   2534                 }
   2535             }
   2536             break;
   2537     }
   2538 }
   2539 
   2540 #if defined(VERSION_JP) || defined(VERSION_SH)
   2541     #define VIEWSCORE_X2 133
   2542     #define COPYFILE_X2 223
   2543     #define ERASE_FILE_Y1 62
   2544     #define ERASE_FILE_Y2 105
   2545 #elif defined(VERSION_CN)
   2546     #define VIEWSCORE_X2 129
   2547     #define COPYFILE_X2 228
   2548     #define ERASE_FILE_Y1 164
   2549     #define ERASE_FILE_Y2 121
   2550 #else
   2551     #define VIEWSCORE_X2 127
   2552     #define COPYFILE_X2 233
   2553     #define ERASE_FILE_Y1 62
   2554     #define ERASE_FILE_Y2 105
   2555 #endif
   2556 
   2557 /**
   2558  * Prints erase menu strings that shows on the red background menu screen.
   2559  */
   2560 void print_erase_menu_strings(void) {
   2561 #ifdef VERSION_EU
   2562     s16 centeredX;
   2563 #endif
   2564 
   2565     // Update and print the message at the top of the menu.
   2566     erase_menu_update_message();
   2567 
   2568     // Print messageID called inside a erase_menu_update_message case
   2569     erase_menu_display_message(sStatusMessageID);
   2570 
   2571 #ifndef VERSION_EU
   2572     // Print file star counts
   2573     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
   2574     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2575     print_save_file_star_count(SAVE_FILE_A, 90, 76);
   2576     print_save_file_star_count(SAVE_FILE_B, 211, 76);
   2577     print_save_file_star_count(SAVE_FILE_C, 90, 119);
   2578     print_save_file_star_count(SAVE_FILE_D, 211, 119);
   2579     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
   2580 #endif
   2581 
   2582     // Print menu names
   2583     gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
   2584     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2585 
   2586 #ifdef VERSION_EU
   2587     centeredX = get_str_x_pos_from_center(69, textReturn[sLanguageMode], 10.0f);
   2588     print_generic_string(centeredX, 35, textReturn[sLanguageMode]);
   2589     centeredX = get_str_x_pos_from_center(159, textViewScore[sLanguageMode], 10.0f);
   2590     print_generic_string(centeredX, 35, textViewScore[sLanguageMode]);
   2591     centeredX = get_str_x_pos_from_center(249, textCopyFileButton[sLanguageMode], 10.0f);
   2592     print_generic_string(centeredX, 35, textCopyFileButton[sLanguageMode]);
   2593 #else
   2594     print_generic_string(RETURN_X_OLD, 35, textReturn);
   2595     print_generic_string(VIEWSCORE_X2, 35, textViewScore);
   2596     print_generic_string(COPYFILE_X2, 35, textCopyFileButton);
   2597 #endif
   2598     gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
   2599 
   2600     // Print file names
   2601 #ifdef VERSION_EU
   2602     print_main_menu_strings();
   2603 #else
   2604     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_BEGIN);
   2605     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2606     FILE_SELECT_PRINT_STRING(89, ERASE_FILE_Y1, textMarioA);
   2607     FILE_SELECT_PRINT_STRING(211, ERASE_FILE_Y1, textMarioB);
   2608     FILE_SELECT_PRINT_STRING(89, ERASE_FILE_Y2, textMarioC);
   2609     FILE_SELECT_PRINT_STRING(211, ERASE_FILE_Y2, textMarioD);
   2610     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_END);
   2611 #endif
   2612 }
   2613 
   2614 #if defined(VERSION_JP) || defined(VERSION_SH)
   2615     #define SOUND_HUD_X 96
   2616     #define SOUND_HUD_Y 35
   2617 #elif defined(VERSION_US)
   2618     #define SOUND_HUD_X 88
   2619     #define SOUND_HUD_Y 35
   2620 #elif defined(VERSION_CN)
   2621     #define SOUND_HUD_X 106
   2622     #define SOUND_HUD_Y 55
   2623 #endif
   2624 
   2625 /**
   2626  * Prints sound mode menu strings that shows on the purple background menu screen.
   2627  *
   2628  * In EU, this function acts like "print_option_mode_menu_strings" because of languages.
   2629  */
   2630 void print_sound_mode_menu_strings(void) {
   2631     s32 mode;
   2632 
   2633 #if defined(VERSION_US) || defined(VERSION_SH) || defined(VERSION_CN)
   2634     s16 textX;
   2635 #elif defined(VERSION_EU)
   2636     s32 textX;
   2637 #endif
   2638 
   2639 #ifndef VERSION_EU
   2640     u8 textSoundSelect[] = { TEXT_SOUND_SELECT };
   2641 #endif
   2642 
   2643     // Print "SOUND SELECT" text
   2644     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
   2645     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2646 
   2647 #ifdef VERSION_EU
   2648     print_hud_lut_string(HUD_LUT_DIFF, 47, 32, textSoundSelect[sLanguageMode]);
   2649     print_hud_lut_string(HUD_LUT_DIFF, 47, 101, textLanguageSelect[sLanguageMode]);
   2650 #else
   2651     print_hud_lut_string(HUD_LUT_DIFF, SOUND_HUD_X, SOUND_HUD_Y, textSoundSelect);
   2652 #endif
   2653 
   2654     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
   2655 
   2656     gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
   2657 
   2658 #ifdef VERSION_EU // In EU their X position get increased each string
   2659     // Print sound mode names
   2660     for (mode = 0, textX = 90; mode < 3; textX += 70, mode++) {
   2661         if (mode == sSoundMode) {
   2662             gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2663         } else {
   2664             gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, sTextBaseAlpha);
   2665         }
   2666         print_generic_string(
   2667             get_str_x_pos_from_center(textX, textSoundModes[sLanguageMode * 3 + mode], 10.0f),
   2668             141, textSoundModes[sLanguageMode * 3 + mode]);
   2669     }
   2670 
   2671     // In EU, print language mode names
   2672     for (mode = 0, textX = 90; mode < 3; textX += 70, mode++) {
   2673         if (mode == sLanguageMode) {
   2674             gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2675         } else {
   2676             gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, sTextBaseAlpha);
   2677         }
   2678         print_generic_string(
   2679             get_str_x_pos_from_center(textX, textLanguage[mode], 10.0f),
   2680             72, textLanguage[mode]);
   2681     }
   2682 #else
   2683     // Print sound mode names
   2684     for (mode = 0; mode < 3; mode++) {
   2685         if (sSoundMode == mode) {
   2686             gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2687         } else {
   2688             gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, sTextBaseAlpha);
   2689         }
   2690         #ifndef VERSION_JP
   2691             // Mode names are centered correctly on US and Shindou
   2692             textX = get_str_x_pos_from_center(mode * 74 + 87, textSoundModes[mode], 10.0f);
   2693             print_generic_string(textX, 87, textSoundModes[mode]);
   2694         #else
   2695             print_generic_string(mode * 74 + 67, 87, textSoundModes[mode]);
   2696         #endif
   2697     }
   2698 #endif
   2699 
   2700 #ifdef VERSION_EU
   2701     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2702     print_generic_string(182, 29, textReturn[sLanguageMode]);
   2703 #endif
   2704 
   2705     gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
   2706 }
   2707 
   2708 #ifndef VERSION_CN
   2709 u8 textStarX[] = { TEXT_STAR_X };
   2710 #endif
   2711 
   2712 /**
   2713  * Prints castle secret stars collected in a score menu save file.
   2714  */
   2715 void print_score_file_castle_secret_stars(s8 fileIndex, s16 x, s16 y) {
   2716 #ifdef VERSION_CN
   2717     u8 secretStarsText[36];
   2718     u8 textStarX[] = { TEXT_STAR_X };
   2719 #else
   2720     u8 secretStarsText[20];
   2721 #endif
   2722 
   2723     // Print "[star] x"
   2724     FILE_SELECT_PRINT_STRING(x, y, textStarX);
   2725 
   2726     // Print number of castle secret stars
   2727     INT_TO_STR_DIFF(save_file_get_total_star_count(fileIndex, COURSE_BONUS_STAGES - 1, COURSE_MAX - 1),
   2728                secretStarsText);
   2729 
   2730 #ifdef VERSION_EU
   2731     FILE_SELECT_PRINT_STRING(x + 20, y, secretStarsText);
   2732 #else
   2733     FILE_SELECT_PRINT_STRING(x + 16, y, secretStarsText);
   2734 #endif
   2735 }
   2736 
   2737 #if defined(VERSION_JP) || defined(VERSION_SH)
   2738     #define HISCORE_COIN_ICON_X  0
   2739     #define HISCORE_COIN_TEXT_X  16
   2740     #define HISCORE_COIN_NAMES_X 45
   2741 #else
   2742     #define HISCORE_COIN_ICON_X  18
   2743     #define HISCORE_COIN_TEXT_X  34
   2744     #define HISCORE_COIN_NAMES_X 60
   2745 #endif
   2746 
   2747 /**
   2748  * Prints course coins collected in a score menu save file.
   2749  */
   2750 void print_score_file_course_coin_score(s8 fileIndex, s16 courseIndex, s16 x, s16 y) {
   2751 #ifdef VERSION_CN
   2752     u8 coinScoreText[36];
   2753 #else
   2754     u8 coinScoreText[20];
   2755 #endif
   2756 
   2757     u8 stars = save_file_get_star_flags(fileIndex, courseIndex);
   2758     u8 textCoinX[] = { TEXT_COIN_X };
   2759     u8 textStar[] = { TEXT_STAR };
   2760 
   2761 #if defined(VERSION_JP) || defined(VERSION_SH)
   2762     #define LENGTH 5
   2763 #elif defined(VERSION_CN)
   2764     #define LENGTH 16
   2765 #else
   2766     #define LENGTH 8
   2767 #endif
   2768     u8 fileNames[][LENGTH] = {
   2769         { TEXT_4DASHES }, // huh?
   2770         { TEXT_SCORE_MARIO_A }, { TEXT_SCORE_MARIO_B }, { TEXT_SCORE_MARIO_C }, { TEXT_SCORE_MARIO_D },
   2771     };
   2772 #undef LENGTH
   2773 
   2774     // MYSCORE
   2775     if (sScoreFileCoinScoreMode == 0) {
   2776         // Print "[coin] x"
   2777         FILE_SELECT_PRINT_STRING(x + 25, y, textCoinX);
   2778 
   2779         // Print coin score
   2780         INT_TO_STR_DIFF(save_file_get_course_coin_score(fileIndex, courseIndex), coinScoreText);
   2781         FILE_SELECT_PRINT_STRING(x + 41, y, coinScoreText);
   2782 
   2783         // If collected, print 100 coin star
   2784         if (stars & (1 << 6)) {
   2785             FILE_SELECT_PRINT_STRING(x + 70, y, textStar);
   2786         }
   2787     }
   2788     // HISCORE
   2789     else {
   2790         // Print "[coin] x"
   2791         FILE_SELECT_PRINT_STRING(x + HISCORE_COIN_ICON_X, y, textCoinX);
   2792 
   2793         // Print coin highscore
   2794         INT_TO_STR_DIFF((u16) save_file_get_max_coin_score(courseIndex) & 0xFFFF, coinScoreText);
   2795         FILE_SELECT_PRINT_STRING(x + HISCORE_COIN_TEXT_X, y, coinScoreText);
   2796 
   2797         // Print coin highscore file
   2798         FILE_SELECT_PRINT_STRING(x + HISCORE_COIN_NAMES_X, y,
   2799                          fileNames[(save_file_get_max_coin_score(courseIndex) >> 16) & 0xFFFF]);
   2800     }
   2801 }
   2802 
   2803 /**
   2804  * Prints stars collected in a score menu save file.
   2805  */
   2806 void print_score_file_star_score(s8 fileIndex, s16 courseIndex, s16 x, s16 y) {
   2807     s16 i = 0;
   2808 
   2809 #ifdef VERSION_CN
   2810     u8 starScoreText[36];
   2811 #else
   2812     u8 starScoreText[19];
   2813 #endif
   2814 
   2815     u8 stars = save_file_get_star_flags(fileIndex, courseIndex);
   2816     s8 starCount = save_file_get_course_star_count(fileIndex, courseIndex);
   2817     // Don't count 100 coin star
   2818     if (stars & (1 << 6)) {
   2819         starCount--;
   2820     }
   2821     // Add 1 star character for every star collected
   2822     for (i = 0; i < starCount; i++) {
   2823 #ifdef VERSION_CN
   2824         starScoreText[i * 2] = 0x00;
   2825         starScoreText[i * 2 + 1] = DIALOG_CHAR_STAR_FILLED;
   2826 #else
   2827         starScoreText[i] = DIALOG_CHAR_STAR_FILLED;
   2828 #endif
   2829     }
   2830 
   2831     // Terminating byte
   2832 #ifdef VERSION_CN
   2833     starScoreText[i * 2] = DIALOG_CHAR_TERMINATOR;
   2834     starScoreText[i * 2 + 1] = DIALOG_CHAR_TERMINATOR;
   2835 #else
   2836     starScoreText[i] = DIALOG_CHAR_TERMINATOR;
   2837 #endif
   2838 
   2839     FILE_SELECT_PRINT_STRING(x, y, starScoreText);
   2840 }
   2841 
   2842 #if defined(VERSION_JP) || defined(VERSION_SH)
   2843     #define MARIO_X 28
   2844     #define MARIO_Y 15
   2845     #define FILE_LETTER_X 86
   2846 #ifdef VERSION_JP
   2847     #define LEVEL_NUM_PAD 0
   2848     #define SECRET_STARS_PAD 0
   2849 #else
   2850     #define LEVEL_NUM_PAD 5
   2851     #define SECRET_STARS_PAD 10
   2852 #endif
   2853     #define LEVEL_NAME_X 23
   2854     #define STAR_SCORE_X 152
   2855     #define MYSCORE_X 237
   2856     #define HISCORE_X 237
   2857     #define MYSCORE_Y 24
   2858     #define HISCORE_Y 24
   2859 #elif defined(VERSION_CN)
   2860     #define MARIO_X 25
   2861     #define MARIO_Y 9
   2862     #define FILE_LETTER_X 95
   2863     #define SECRET_STARS_PAD 6
   2864     #define LEVEL_NAME_X 26
   2865     #define STAR_SCORE_X 171
   2866     #define MYSCORE_X 238
   2867     #define HISCORE_X 231
   2868     #define MYSCORE_Y 200
   2869     #define HISCORE_Y 200
   2870 #else
   2871     #define MARIO_X 25
   2872     #define MARIO_Y 15
   2873     #define FILE_LETTER_X 95
   2874     #define LEVEL_NUM_PAD 3
   2875     #define SECRET_STARS_PAD 6
   2876     #define LEVEL_NAME_X 23
   2877     #define STAR_SCORE_X 171
   2878 #ifdef VERSION_EU
   2879     #define MYSCORE_X get_str_x_pos_from_center(257, textMyScore[sLanguageMode], 10.0f)
   2880     #define HISCORE_X get_str_x_pos_from_center(257, textHiScore[sLanguageMode], 10.0f)
   2881 #else
   2882     #define MYSCORE_X 238
   2883     #define HISCORE_X 231
   2884 #endif
   2885     #define MYSCORE_Y 24
   2886     #define HISCORE_Y 24
   2887 #endif
   2888 
   2889 #ifdef VERSION_EU
   2890 #include "game/segment7.h"
   2891 #endif
   2892 
   2893 #define PRINT_COURSE_NAME_CN(courseIndex, shift) \
   2894     FILE_SELECT_PRINT_STRING(LEVEL_NAME_X, 14 + 21 * (9 - courseIndex) + shift, \
   2895                              segmented_to_virtual(levelNameTable[courseIndex - 1]));
   2896 
   2897 #define PRINT_COURSE_SCORES_CN(courseIndex, shift) \
   2898     print_score_file_star_score(fileIndex, courseIndex - 1, STAR_SCORE_X, 14 + 21 * (9 - courseIndex) + shift); \
   2899     print_score_file_course_coin_score(fileIndex, courseIndex - 1, 213, 14 + 21 * (9 - courseIndex) + shift);
   2900 
   2901 #define PRINT_COURSE_NAME_AND_SCORES(courseIndex, pad) \
   2902     FILE_SELECT_PRINT_STRING(LEVEL_NAME_X + (pad * LEVEL_NUM_PAD), 23 + 12 * courseIndex, \
   2903                              segmented_to_virtual(levelNameTable[courseIndex - 1])); \
   2904     print_score_file_star_score(fileIndex, courseIndex - 1, STAR_SCORE_X, 23 + 12 * courseIndex); \
   2905     print_score_file_course_coin_score(fileIndex, courseIndex - 1, 213, 23 + 12 * courseIndex);
   2906 
   2907 /**
   2908  * Prints save file score strings that shows when a save file is chosen inside the score menu.
   2909  */
   2910 void print_save_file_scores(s8 fileIndex) {
   2911 #ifndef VERSION_EU
   2912 
   2913     u8 textMario[] = { TEXT_MARIO };
   2914 #ifdef VERSION_JP
   2915     u8 textFileLetter[] = { TEXT_ZERO };
   2916     void **levelNameTable = segmented_to_virtual(seg2_course_name_table);
   2917 #endif
   2918     u8 textHiScore[] = { TEXT_HI_SCORE };
   2919     u8 textMyScore[] = { TEXT_MY_SCORE };
   2920 #ifdef VERSION_CN
   2921     u8 textArrowL[] = { TEXT_ARROW_L };
   2922     u8 textRArrow[] = { TEXT_R_ARROW };
   2923 #endif
   2924 #ifndef VERSION_JP
   2925     u8 textFileLetter[] = { TEXT_ZERO };
   2926     void **levelNameTable = segmented_to_virtual(seg2_course_name_table);
   2927 #endif
   2928 
   2929 #else
   2930     u8 textFileLetter[] = { TEXT_ZERO };
   2931     void **levelNameTable;
   2932 
   2933     switch (sLanguageMode) {
   2934         case LANGUAGE_ENGLISH:
   2935             levelNameTable = segmented_to_virtual(eu_course_strings_en_table);
   2936             break;
   2937         case LANGUAGE_FRENCH:
   2938             levelNameTable = segmented_to_virtual(eu_course_strings_fr_table);
   2939             break;
   2940         case LANGUAGE_GERMAN:
   2941             levelNameTable = segmented_to_virtual(eu_course_strings_de_table);
   2942             break;
   2943     }
   2944 #endif
   2945 
   2946     textFileLetter[0] = fileIndex + ASCII_TO_DIALOG('A'); // get letter of file selected
   2947 
   2948     // Print file name at top
   2949     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
   2950     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2951     print_hud_lut_string(HUD_LUT_DIFF, MARIO_X, MARIO_Y, textMario);
   2952     print_hud_lut_string(HUD_LUT_GLOBAL, FILE_LETTER_X, 15, textFileLetter);
   2953 
   2954     // Print save file star count at top
   2955     print_save_file_star_count(fileIndex, 124, 15);
   2956     gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
   2957 
   2958     // Print course scores
   2959     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_BEGIN);
   2960     gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha);
   2961 
   2962     //! Huge print list, for loops exist for a reason!
   2963 #ifdef VERSION_CN
   2964     if (sScorePage == 0) {
   2965         PRINT_COURSE_NAME_CN(COURSE_SSL, 0)
   2966         PRINT_COURSE_NAME_CN(COURSE_LLL, 0)
   2967         PRINT_COURSE_NAME_CN(COURSE_HMC, 0)
   2968         PRINT_COURSE_NAME_CN(COURSE_BBH, 0)
   2969         PRINT_COURSE_NAME_CN(COURSE_CCM, 0)
   2970         PRINT_COURSE_NAME_CN(COURSE_JRB, 0)
   2971         PRINT_COURSE_NAME_CN(COURSE_WF, 0)
   2972         PRINT_COURSE_NAME_CN(COURSE_BOB, 0)
   2973 
   2974         PRINT_COURSE_SCORES_CN(COURSE_SSL, 0)
   2975         PRINT_COURSE_SCORES_CN(COURSE_LLL, 0)
   2976         PRINT_COURSE_SCORES_CN(COURSE_HMC, 0)
   2977         PRINT_COURSE_SCORES_CN(COURSE_BBH, 0)
   2978         PRINT_COURSE_SCORES_CN(COURSE_CCM, 0)
   2979         PRINT_COURSE_SCORES_CN(COURSE_JRB, 0)
   2980         PRINT_COURSE_SCORES_CN(COURSE_WF, 0)
   2981         PRINT_COURSE_SCORES_CN(COURSE_BOB, 0)
   2982     } else if (sScorePage == 1) {
   2983         // Print castle secret stars text
   2984         print_generic_string(LEVEL_NAME_X, 23 + 12 * 1,
   2985                                   segmented_to_virtual(levelNameTable[25]));
   2986 
   2987         PRINT_COURSE_NAME_CN(COURSE_RR, 168)
   2988         PRINT_COURSE_NAME_CN(COURSE_TTC, 168)
   2989         PRINT_COURSE_NAME_CN(COURSE_THI, 168)
   2990         PRINT_COURSE_NAME_CN(COURSE_TTM, 168)
   2991         PRINT_COURSE_NAME_CN(COURSE_WDW, 168)
   2992         PRINT_COURSE_NAME_CN(COURSE_SL, 168)
   2993         PRINT_COURSE_NAME_CN(COURSE_DDD, 168)
   2994 
   2995         // Print castle secret stars score
   2996         print_score_file_castle_secret_stars(fileIndex, STAR_SCORE_X, 23 + 12 * 1);
   2997 
   2998         PRINT_COURSE_SCORES_CN(COURSE_RR, 168)
   2999         PRINT_COURSE_SCORES_CN(COURSE_TTC, 168)
   3000         PRINT_COURSE_SCORES_CN(COURSE_THI, 168)
   3001         PRINT_COURSE_SCORES_CN(COURSE_TTM, 168)
   3002         PRINT_COURSE_SCORES_CN(COURSE_WDW, 168)
   3003         PRINT_COURSE_SCORES_CN(COURSE_SL, 168)
   3004         PRINT_COURSE_SCORES_CN(COURSE_DDD, 168)
   3005     }
   3006 #else
   3007     // Course values are indexed, from Bob-omb Battlefield to Rainbow Ride
   3008     PRINT_COURSE_NAME_AND_SCORES(COURSE_BOB, 1)
   3009     PRINT_COURSE_NAME_AND_SCORES(COURSE_WF,  1)
   3010     PRINT_COURSE_NAME_AND_SCORES(COURSE_JRB, 1)
   3011     PRINT_COURSE_NAME_AND_SCORES(COURSE_CCM, 1)
   3012     PRINT_COURSE_NAME_AND_SCORES(COURSE_BBH, 1)
   3013     PRINT_COURSE_NAME_AND_SCORES(COURSE_HMC, 1)
   3014     PRINT_COURSE_NAME_AND_SCORES(COURSE_LLL, 1)
   3015     PRINT_COURSE_NAME_AND_SCORES(COURSE_SSL, 1)
   3016     PRINT_COURSE_NAME_AND_SCORES(COURSE_DDD, 1)
   3017     PRINT_COURSE_NAME_AND_SCORES(COURSE_SL,  0)
   3018     PRINT_COURSE_NAME_AND_SCORES(COURSE_WDW, 0)
   3019     PRINT_COURSE_NAME_AND_SCORES(COURSE_TTM, 0)
   3020     PRINT_COURSE_NAME_AND_SCORES(COURSE_THI, 0)
   3021     PRINT_COURSE_NAME_AND_SCORES(COURSE_TTC, 0)
   3022     PRINT_COURSE_NAME_AND_SCORES(COURSE_RR,  0)
   3023 
   3024     // Print castle secret stars text
   3025     FILE_SELECT_PRINT_STRING(LEVEL_NAME_X + SECRET_STARS_PAD, 23 + 12 * 16,
   3026                               segmented_to_virtual(levelNameTable[25]));
   3027     // Print castle secret stars score
   3028     print_score_file_castle_secret_stars(fileIndex, STAR_SCORE_X, 23 + 12 * 16);
   3029 #endif
   3030 
   3031     // Print current coin score mode
   3032     if (sScoreFileCoinScoreMode == 0) {
   3033         FILE_SELECT_PRINT_STRING(MYSCORE_X, MYSCORE_Y, LANGUAGE_ARRAY(textMyScore));
   3034     } else {
   3035         FILE_SELECT_PRINT_STRING(HISCORE_X, HISCORE_Y, LANGUAGE_ARRAY(textHiScore));
   3036     }
   3037 
   3038 #ifdef VERSION_CN
   3039     // Print L and R button indicators
   3040     FILE_SELECT_PRINT_STRING(30, 17, textArrowL);
   3041     FILE_SELECT_PRINT_STRING(270, 17, textRArrow);
   3042 #endif
   3043 
   3044     gSPDisplayList(gDisplayListHead++, FILE_SELECT_TEXT_DL_END);
   3045 }
   3046 
   3047 #undef PRINT_COURSE_NAME_CN
   3048 #undef PRINT_COURSE_SCORES_CN
   3049 #undef PRINT_COURSE_NAME_AND_SCORES
   3050 
   3051 /**
   3052  * Prints file select strings depending on the menu selected.
   3053  * Also checks if all saves exists and defines text and main menu timers.
   3054  */
   3055 static void print_file_select_strings(void) {
   3056 #ifndef VERSION_CN
   3057     UNUSED u8 filler[8];
   3058 #endif
   3059 
   3060     create_dl_ortho_matrix();
   3061     switch (sSelectedButtonID) {
   3062         case MENU_BUTTON_NONE:
   3063 #ifdef VERSION_EU
   3064             // Ultimately calls print_main_menu_strings, but prints main language strings first.
   3065             print_main_lang_strings();
   3066 #else
   3067             print_main_menu_strings();
   3068 #endif
   3069             break;
   3070         case MENU_BUTTON_SCORE:
   3071             print_score_menu_strings();
   3072             sScoreFileCoinScoreMode = 0;
   3073             break;
   3074         case MENU_BUTTON_COPY:
   3075             print_copy_menu_strings();
   3076             break;
   3077         case MENU_BUTTON_ERASE:
   3078             print_erase_menu_strings();
   3079             break;
   3080         case MENU_BUTTON_SCORE_FILE_A:
   3081             print_save_file_scores(SAVE_FILE_A);
   3082             break;
   3083         case MENU_BUTTON_SCORE_FILE_B:
   3084             print_save_file_scores(SAVE_FILE_B);
   3085             break;
   3086         case MENU_BUTTON_SCORE_FILE_C:
   3087             print_save_file_scores(SAVE_FILE_C);
   3088             break;
   3089         case MENU_BUTTON_SCORE_FILE_D:
   3090             print_save_file_scores(SAVE_FILE_D);
   3091             break;
   3092         case MENU_BUTTON_SOUND_MODE:
   3093             print_sound_mode_menu_strings();
   3094             break;
   3095     }
   3096     // If all 4 save file exists, define true to sAllFilesExist to prevent more copies in copy menu
   3097     if (save_file_exists(SAVE_FILE_A) == TRUE && save_file_exists(SAVE_FILE_B) == TRUE &&
   3098         save_file_exists(SAVE_FILE_C) == TRUE && save_file_exists(SAVE_FILE_D) == TRUE) {
   3099         sAllFilesExist = TRUE;
   3100     } else {
   3101         sAllFilesExist = FALSE;
   3102     }
   3103     // Timers for menu alpha text and the main menu itself
   3104     if (sTextBaseAlpha < 250) {
   3105         sTextBaseAlpha += 10;
   3106     }
   3107     if (sMainMenuTimer < 1000) {
   3108         sMainMenuTimer++;
   3109     }
   3110 }
   3111 
   3112 /**
   3113  * Geo function that prints file select strings and the cursor.
   3114  */
   3115 Gfx *geo_file_select_strings_and_menu_cursor(s32 callContext, UNUSED struct GraphNode *node, UNUSED Mat4 mtx) {
   3116     if (callContext == GEO_CONTEXT_RENDER) {
   3117         print_file_select_strings();
   3118         print_menu_cursor();
   3119     }
   3120     return NULL;
   3121 }
   3122 
   3123 /**
   3124  * Initiates file select values after Mario Screen.
   3125  * Relocates cursor position of the last save if the game goes back to the Mario Screen
   3126  * either completing a course choosing "SAVE & QUIT" or having a game over.
   3127  */
   3128 s32 lvl_init_menu_values_and_cursor_pos(UNUSED s32 arg, UNUSED s32 unused) {
   3129 #ifdef VERSION_EU
   3130     s8 fileIndex;
   3131 #endif
   3132     sSelectedButtonID = MENU_BUTTON_NONE;
   3133     sCurrentMenuLevel = MENU_LAYER_MAIN;
   3134     sTextBaseAlpha = 0;
   3135     // Place the cursor over the save file that was being played.
   3136     // gCurrSaveFileNum is 1 by default when the game boots, as such
   3137     // the cursor will point on Mario A save file.
   3138     switch (gCurrSaveFileNum) {
   3139         case 1: // File A
   3140             sCursorPos[0] = -94.0f;
   3141             sCursorPos[1] = 46.0f;
   3142             break;
   3143         case 2: // File B
   3144             sCursorPos[0] = 24.0f;
   3145             sCursorPos[1] = 46.0f;
   3146             break;
   3147         case 3: // File C
   3148             sCursorPos[0] = -94.0f;
   3149             sCursorPos[1] = 5.0f;
   3150             break;
   3151         case 4: // File D
   3152             sCursorPos[0] = 24.0f;
   3153             sCursorPos[1] = 5.0f;
   3154             break;
   3155     }
   3156     sClickPos[0] = -10000;
   3157     sClickPos[1] = -10000;
   3158     sCursorClickingTimer = 0;
   3159     sSelectedFileNum = 0;
   3160     sSelectedFileIndex = MENU_BUTTON_NONE;
   3161     sFadeOutText = FALSE;
   3162     sStatusMessageID = 0;
   3163     sTextFadeAlpha = 0;
   3164     sMainMenuTimer = 0;
   3165     sEraseYesNoHoverState = MENU_ERASE_HOVER_NONE;
   3166     sSoundMode = save_file_get_sound_mode();
   3167 #ifdef VERSION_EU
   3168     sLanguageMode = eu_get_language();
   3169 
   3170     for (fileIndex = 0; fileIndex <= 3; fileIndex++) {
   3171         if (save_file_exists(fileIndex) == TRUE) {
   3172             sOpenLangSettings = FALSE;
   3173             break;
   3174         } else {
   3175             sOpenLangSettings = TRUE;
   3176         }
   3177     }
   3178 #endif
   3179     //! no return value
   3180 #ifdef AVOID_UB
   3181     return 0;
   3182 #endif
   3183 }
   3184 
   3185 /**
   3186  * Updates file select menu button objects so they can be interacted.
   3187  * When a save file is selected, it returns fileNum value
   3188  * defined in load_main_menu_save_file.
   3189  */
   3190 s32 lvl_update_obj_and_load_file_selected(UNUSED s32 arg, UNUSED s32 unused) {
   3191     area_update_objects();
   3192     return sSelectedFileNum;
   3193 }
   3194 
   3195 #undef FILE_SELECT_PRINT_STRING
   3196 #undef FILE_SELECT_TEXT_DL_BEGIN
   3197 #undef FILE_SELECT_TEXT_DL_END