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