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