Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/ingame_menu.c
7858 views
1
#include <ultra64.h>
2
#include <stdlib.h>
3
#include <string.h>
4
5
#include "actors/common1.h"
6
#include "area.h"
7
#include "audio/external.h"
8
#include "camera.h"
9
#include "course_table.h"
10
#include "dialog_ids.h"
11
#include "engine/math_util.h"
12
#include "eu_translation.h"
13
#include "game_init.h"
14
#include "gfx_dimensions.h"
15
#include "ingame_menu.h"
16
#include "level_update.h"
17
#include "levels/castle_grounds/header.h"
18
#include "memory.h"
19
#include "print.h"
20
#include "save_file.h"
21
#include "segment2.h"
22
#include "segment7.h"
23
#include "seq_ids.h"
24
#include "sm64.h"
25
#include "text_strings.h"
26
#include "types.h"
27
28
#include "settings.h"
29
30
u16 gDialogColorFadeTimer;
31
s8 gLastDialogLineNum;
32
s32 gDialogVariable;
33
u16 gDialogTextAlpha;
34
#if defined(VERSION_EU)
35
s16 gDialogX; // D_8032F69A
36
s16 gDialogY; // D_8032F69C
37
#endif
38
s16 gCutsceneMsgXOffset;
39
s16 gCutsceneMsgYOffset;
40
s8 gRedCoinsCollected;
41
42
extern u8 gLastCompletedCourseNum;
43
extern u8 gLastCompletedStarNum;
44
45
enum DialogBoxState {
46
DIALOG_STATE_OPENING,
47
DIALOG_STATE_VERTICAL,
48
DIALOG_STATE_HORIZONTAL,
49
DIALOG_STATE_CLOSING
50
};
51
52
enum DialogBoxPageState {
53
DIALOG_PAGE_STATE_NONE,
54
DIALOG_PAGE_STATE_SCROLL,
55
DIALOG_PAGE_STATE_END
56
};
57
58
enum DialogBoxType {
59
DIALOG_TYPE_ROTATE, // used in NPCs and level messages
60
DIALOG_TYPE_ZOOM // used in signposts and wall signs and etc
61
};
62
63
enum DialogMark { DIALOG_MARK_NONE = 0, DIALOG_MARK_DAKUTEN = 1, DIALOG_MARK_HANDAKUTEN = 2 };
64
65
#define DEFAULT_DIALOG_BOX_ANGLE 90.0f
66
#define DEFAULT_DIALOG_BOX_SCALE 19.0f
67
68
#if defined(VERSION_US) || defined(VERSION_EU)
69
u8 gDialogCharWidths[256] = { // TODO: Is there a way to auto generate this?
70
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6,
71
6, 6, 5, 6, 6, 5, 8, 8, 6, 6, 6, 6, 6, 5, 6, 6,
72
8, 7, 6, 6, 6, 5, 5, 6, 5, 5, 6, 5, 4, 5, 5, 3,
73
7, 5, 5, 5, 6, 5, 5, 5, 5, 5, 7, 7, 5, 5, 4, 4,
74
8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75
8, 8, 8, 8, 7, 7, 6, 7, 7, 0, 0, 0, 0, 0, 0, 0,
76
#ifdef VERSION_EU
77
6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 4,
78
5, 5, 5, 5, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0,
79
5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80
0, 5, 5, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 5, 6,
81
0, 4, 4, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82
#else
83
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
84
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6,
87
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88
#endif
89
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92
#ifdef VERSION_EU
93
7, 5, 10, 5, 9, 8, 4, 0, 0, 0, 0, 5, 5, 6, 5, 0,
94
#else
95
7, 5, 10, 5, 9, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96
#endif
97
0, 0, 5, 7, 7, 6, 6, 8, 0, 8, 10, 6, 4, 10, 0, 0
98
};
99
#endif
100
101
s8 gDialogBoxState = DIALOG_STATE_OPENING;
102
f32 gDialogBoxOpenTimer = DEFAULT_DIALOG_BOX_ANGLE;
103
f32 gDialogBoxScale = DEFAULT_DIALOG_BOX_SCALE;
104
s16 gDialogScrollOffsetY = 0;
105
s8 gDialogBoxType = DIALOG_TYPE_ROTATE;
106
s16 gDialogID = DIALOG_NONE;
107
s16 gLastDialogPageStrPos = 0;
108
s16 gDialogTextPos = 0;
109
#ifdef VERSION_EU
110
s32 gInGameLanguage = 0;
111
#endif
112
s8 gDialogLineNum = 1;
113
s8 gLastDialogResponse = 0;
114
u8 gMenuHoldKeyIndex = 0;
115
u8 gMenuHoldKeyTimer = 0;
116
s32 gDialogResponse = DIALOG_RESPONSE_NONE;
117
118
static Gfx *sInterpolatedDialogOffsetPos;
119
static f32 sInterpolatedDialogOffset;
120
static Gfx *sInterpolatedDialogRotationPos;
121
static f32 sInterpolatedDialogScale;
122
static f32 sInterpolatedDialogRotation;
123
static Gfx *sInterpolatedDialogZoomPos;
124
125
// Text fixes. I'm sorry for what you're about to see.
126
static void copy_dialog_text(u8 *dst, const u8 *src, s16 *outLen, s16 dstSize) {
127
s16 n = 0;
128
if (dstSize <= 0) {
129
if (outLen) {
130
*outLen = 0;
131
}
132
return;
133
}
134
while (src[n] != DIALOG_CHAR_TERMINATOR && n < (dstSize - 1)) {
135
dst[n] = src[n];
136
n++;
137
}
138
dst[n] = DIALOG_CHAR_TERMINATOR;
139
if (outLen) {
140
*outLen = n;
141
}
142
}
143
144
// "It that " -> "Is that "
145
static void fix_yoshi_typo(u8 *buf, s16 *pLen) {
146
static const u8 pat[] = { ASCII_TO_DIALOG('I'), ASCII_TO_DIALOG('t'), DIALOG_CHAR_SPACE,
147
ASCII_TO_DIALOG('t'), ASCII_TO_DIALOG('h'), ASCII_TO_DIALOG('a'), ASCII_TO_DIALOG('t'), DIALOG_CHAR_SPACE };
148
s16 len = *pLen;
149
for (s16 i = 0; i + (s16)sizeof(pat) <= len; i++) {
150
if (memcmp(&buf[i], pat, sizeof(pat)) == 0) {
151
buf[i + 1] = ASCII_TO_DIALOG('s');
152
return;
153
}
154
}
155
}
156
157
// "run in to " -> "run into "
158
static void fix_run_into(u8 *buf, s16 *pLen) {
159
static const u8 pat[] = { ASCII_TO_DIALOG('r'), ASCII_TO_DIALOG('u'), ASCII_TO_DIALOG('n'), DIALOG_CHAR_SPACE,
160
ASCII_TO_DIALOG('i'), ASCII_TO_DIALOG('n'), DIALOG_CHAR_SPACE,
161
ASCII_TO_DIALOG('t'), ASCII_TO_DIALOG('o'), DIALOG_CHAR_SPACE };
162
s16 len = *pLen;
163
for (s16 i = 0; i + (s16)sizeof(pat) <= len; i++) {
164
if (memcmp(&buf[i], pat, sizeof(pat)) == 0) {
165
s16 src = i + 7; // Position of "t" in "to "
166
s16 dst = i + 6; // Overwrite the extra space
167
s16 tailLen = len - src + 1; // Move the rest of the string, INCLUDING THE TERMINATOR!!!
168
memmove(&buf[dst], &buf[src], tailLen);
169
*pLen -= 1;
170
return;
171
}
172
}
173
}
174
175
// "Pull back to\n
176
// to fly up, press forward\n
177
// to nose down, and press [Z]\n
178
// to land."
179
//
180
// ->
181
//
182
// "Pull back to\n
183
// fly up, press forward to\n
184
// nose down, and press [Z] to\n
185
// land."
186
static void fix_wing_cap_tip(u8 *buf, s16 *pLen) {
187
static const u8 lead[] = { ASCII_TO_DIALOG('P'), ASCII_TO_DIALOG('u'), ASCII_TO_DIALOG('l'), ASCII_TO_DIALOG('l'), DIALOG_CHAR_SPACE,
188
ASCII_TO_DIALOG('b'), ASCII_TO_DIALOG('a'), ASCII_TO_DIALOG('c'), ASCII_TO_DIALOG('k'), DIALOG_CHAR_SPACE,
189
ASCII_TO_DIALOG('t'), ASCII_TO_DIALOG('o'), DIALOG_CHAR_NEWLINE };
190
s16 len = *pLen;
191
for (s16 p = 0; p + (s16)sizeof(lead) <= len; p++) {
192
193
if (memcmp(&buf[p], lead, sizeof(lead)) != 0) {
194
continue;
195
}
196
197
s16 line2 = p + (s16)sizeof(lead);
198
if (line2 + 2 < len &&
199
buf[line2 ] == ASCII_TO_DIALOG('t') &&
200
buf[line2 + 1] == ASCII_TO_DIALOG('o') &&
201
buf[line2 + 2] == DIALOG_CHAR_SPACE) {
202
memmove(&buf[line2], &buf[line2 + 3], len - (line2 + 2));
203
len -= 3;
204
}
205
s16 end2 = line2;
206
while (end2 < len && buf[end2] != DIALOG_CHAR_NEWLINE) {
207
end2++;
208
}
209
if (end2 >= len) {
210
break;
211
}
212
memmove(&buf[end2 + 3], &buf[end2], len - end2 + 1);
213
buf[end2 + 0] = DIALOG_CHAR_SPACE;
214
buf[end2 + 1] = ASCII_TO_DIALOG('t');
215
buf[end2 + 2] = ASCII_TO_DIALOG('o');
216
len += 3;
217
218
s16 line3 = end2 + 4;
219
s16 m = line3;
220
while (m < len && buf[m] == DIALOG_CHAR_SPACE) {
221
m++;
222
}
223
if (m + 2 < len &&
224
buf[m ] == ASCII_TO_DIALOG('t') &&
225
buf[m + 1] == ASCII_TO_DIALOG('o') &&
226
buf[m + 2] == DIALOG_CHAR_SPACE) {
227
memmove(&buf[m], &buf[m + 3], len - (m + 2));
228
len -= 3;
229
}
230
s16 end3 = m;
231
while (end3 < len && buf[end3] != DIALOG_CHAR_NEWLINE) {
232
end3++;
233
}
234
if (end3 >= len) {
235
break;
236
}
237
memmove(&buf[end3 + 3], &buf[end3], len - end3 + 1);
238
buf[end3 + 0] = DIALOG_CHAR_SPACE;
239
buf[end3 + 1] = ASCII_TO_DIALOG('t');
240
buf[end3 + 2] = ASCII_TO_DIALOG('o');
241
len += 3;
242
243
s16 line4 = end3 + 4;
244
s16 n = line4;
245
while (n < len && buf[n] == DIALOG_CHAR_SPACE) {
246
n++;
247
}
248
if (n + 2 < len &&
249
buf[n ] == ASCII_TO_DIALOG('t') &&
250
buf[n + 1] == ASCII_TO_DIALOG('o') &&
251
buf[n + 2] == DIALOG_CHAR_SPACE) {
252
memmove(&buf[n], &buf[n + 3], len - (n + 2));
253
len -= 3;
254
}
255
*pLen = len;
256
return;
257
}
258
}
259
260
void patch_interpolated_dialog(void) {
261
Mtx *matrix;
262
263
if (sInterpolatedDialogOffsetPos != NULL) {
264
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
265
guTranslate(matrix, 0, sInterpolatedDialogOffset, 0);
266
gSPMatrix(sInterpolatedDialogOffsetPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
267
sInterpolatedDialogOffsetPos = NULL;
268
}
269
if (sInterpolatedDialogRotationPos != NULL) {
270
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
271
guScale(matrix, 1.0 / sInterpolatedDialogScale, 1.0 / sInterpolatedDialogScale, 1.0f);
272
gSPMatrix(sInterpolatedDialogRotationPos++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
273
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
274
guRotate(matrix, sInterpolatedDialogRotation * 4.0f, 0, 0, 1.0f);
275
gSPMatrix(sInterpolatedDialogRotationPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
276
sInterpolatedDialogRotationPos = NULL;
277
}
278
if (sInterpolatedDialogZoomPos != NULL) {
279
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
280
guTranslate(matrix, 65.0 - (65.0 / sInterpolatedDialogScale), (40.0 / sInterpolatedDialogScale) - 40, 0);
281
gSPMatrix(sInterpolatedDialogZoomPos++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
282
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
283
guScale(matrix, 1.0 / sInterpolatedDialogScale, 1.0 / sInterpolatedDialogScale, 1.0f);
284
gSPMatrix(sInterpolatedDialogZoomPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
285
sInterpolatedDialogZoomPos = NULL;
286
}
287
}
288
289
void create_dl_identity_matrix(void) {
290
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
291
292
if (matrix == NULL) {
293
return;
294
}
295
296
#ifndef GBI_FLOATS
297
matrix->m[0][0] = 0x00010000; matrix->m[1][0] = 0x00000000; matrix->m[2][0] = 0x00000000; matrix->m[3][0] = 0x00000000;
298
matrix->m[0][1] = 0x00000000; matrix->m[1][1] = 0x00010000; matrix->m[2][1] = 0x00000000; matrix->m[3][1] = 0x00000000;
299
matrix->m[0][2] = 0x00000001; matrix->m[1][2] = 0x00000000; matrix->m[2][2] = 0x00000000; matrix->m[3][2] = 0x00000000;
300
matrix->m[0][3] = 0x00000000; matrix->m[1][3] = 0x00000001; matrix->m[2][3] = 0x00000000; matrix->m[3][3] = 0x00000000;
301
#else
302
guMtxIdent(matrix);
303
#endif
304
305
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
306
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
307
}
308
309
void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z) {
310
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
311
312
if (matrix == NULL) {
313
return;
314
}
315
316
guTranslate(matrix, x, y, z);
317
318
if (pushOp == MENU_MTX_PUSH)
319
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
320
321
if (pushOp == MENU_MTX_NOPUSH)
322
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
323
}
324
325
void create_dl_rotation_matrix(s8 pushOp, f32 a, f32 x, f32 y, f32 z) {
326
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
327
328
if (matrix == NULL) {
329
return;
330
}
331
332
guRotate(matrix, a, x, y, z);
333
334
if (pushOp == MENU_MTX_PUSH)
335
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
336
337
if (pushOp == MENU_MTX_NOPUSH)
338
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
339
}
340
341
void create_dl_scale_matrix(s8 pushOp, f32 x, f32 y, f32 z) {
342
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
343
344
if (matrix == NULL) {
345
return;
346
}
347
348
guScale(matrix, x, y, z);
349
350
if (pushOp == MENU_MTX_PUSH)
351
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
352
353
if (pushOp == MENU_MTX_NOPUSH)
354
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
355
}
356
357
void create_dl_ortho_matrix(void) {
358
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
359
360
if (matrix == NULL) {
361
return;
362
}
363
364
create_dl_identity_matrix();
365
366
guOrtho(matrix, 0.0f, SCREEN_WIDTH, 0.0f, SCREEN_HEIGHT, -10.0f, 10.0f, 1.0f);
367
368
// Should produce G_RDPHALF_1 in Fast3D
369
gSPPerspNormalize(gDisplayListHead++, 0xFFFF);
370
371
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_PROJECTION | G_MTX_MUL | G_MTX_NOPUSH)
372
}
373
374
#if !defined(VERSION_JP) && !defined(VERSION_SH)
375
UNUSED
376
#endif
377
static u8 *alloc_ia8_text_from_i1(u16 *in, s16 width, s16 height) {
378
s32 inPos;
379
u16 bitMask;
380
u8 *out;
381
s16 outPos = 0;
382
383
out = alloc_display_list((u32) width * (u32) height);
384
385
if (out == NULL) {
386
return NULL;
387
}
388
389
for (inPos = 0; inPos < (width * height) / 16; inPos++) {
390
bitMask = 0x8000;
391
392
while (bitMask != 0) {
393
if (in[inPos] & bitMask) {
394
out[outPos] = 0xFF;
395
} else {
396
out[outPos] = 0x00;
397
}
398
399
bitMask /= 2;
400
outPos++;
401
}
402
}
403
404
return out;
405
}
406
407
void render_generic_char(u8 c) {
408
void **fontLUT;
409
void *packedTexture;
410
#if defined(VERSION_JP) || defined(VERSION_SH)
411
void *unpackedTexture;
412
#endif
413
414
fontLUT = segmented_to_virtual(main_font_lut);
415
packedTexture = segmented_to_virtual(fontLUT[c]);
416
417
#if defined(VERSION_JP) || defined(VERSION_SH)
418
unpackedTexture = alloc_ia8_text_from_i1(packedTexture, 8, 16);
419
420
gDPPipeSync(gDisplayListHead++);
421
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, VIRTUAL_TO_PHYSICAL(unpackedTexture));
422
#else
423
#ifdef VERSION_US
424
gDPPipeSync(gDisplayListHead++);
425
#endif
426
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture));
427
#endif
428
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
429
#ifdef VERSION_EU
430
gSPTextureRectangleFlip(gDisplayListHead++, gDialogX << 2, (gDialogY - 16) << 2,
431
(gDialogX + 8) << 2, gDialogY << 2, G_TX_RENDERTILE, 8 << 6, 4 << 6, 1 << 10, 1 << 10);
432
#endif
433
}
434
435
#ifdef VERSION_EU
436
u8 *alloc_ia4_tex_from_i1(u8 *in, s16 width, s16 height) {
437
u32 size = (u32) width * (u32) height;
438
u8 *out;
439
s32 inPos;
440
s16 outPos;
441
u8 bitMask;
442
443
outPos = 0;
444
out = (u8 *) alloc_display_list(size);
445
446
if (out == NULL) {
447
return NULL;
448
}
449
450
for (inPos = 0; inPos < (width * height) / 4; inPos++) {
451
bitMask = 0x80;
452
while (bitMask != 0) {
453
out[outPos] = (in[inPos] & bitMask) ? 0xF0 : 0x00;
454
bitMask /= 2;
455
out[outPos] = (in[inPos] & bitMask) ? out[outPos] + 0x0F : out[outPos];
456
bitMask /= 2;
457
outPos++;
458
}
459
}
460
461
return out;
462
}
463
464
void render_generic_char_at_pos(s16 xPos, s16 yPos, u8 c) {
465
void **fontLUT;
466
void *packedTexture;
467
void *unpackedTexture;
468
469
fontLUT = segmented_to_virtual(main_font_lut);
470
packedTexture = segmented_to_virtual(fontLUT[c]);
471
unpackedTexture = alloc_ia4_tex_from_i1(packedTexture, 8, 8);
472
473
gDPPipeSync(gDisplayListHead++);
474
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(unpackedTexture));
475
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
476
gSPTextureRectangleFlip(gDisplayListHead++, xPos << 2, (yPos - 16) << 2, (xPos + 8) << 2, yPos << 2,
477
G_TX_RENDERTILE, 8 << 6, 4 << 6, 1 << 10, 1 << 10);
478
}
479
480
void render_lowercase_diacritic(s16 *xPos, s16 *yPos, u8 letter, u8 diacritic) {
481
render_generic_char_at_pos(*xPos, *yPos, letter);
482
render_generic_char_at_pos(*xPos, *yPos, diacritic + 0xE7);
483
*xPos += gDialogCharWidths[letter];
484
}
485
486
void render_uppercase_diacritic(s16 *xPos, s16 *yPos, u8 letter, u8 diacritic) {
487
render_generic_char_at_pos(*xPos, *yPos, letter);
488
render_generic_char_at_pos(*xPos, *yPos - 4, diacritic + 0xE3);
489
*xPos += gDialogCharWidths[letter];
490
}
491
#endif // VERSION_EU
492
493
#if !defined(VERSION_JP) && !defined(VERSION_SH)
494
struct MultiTextEntry {
495
u8 length;
496
u8 str[4];
497
};
498
499
#define TEXT_THE_RAW ASCII_TO_DIALOG('t'), ASCII_TO_DIALOG('h'), ASCII_TO_DIALOG('e'), 0x00
500
#define TEXT_YOU_RAW ASCII_TO_DIALOG('y'), ASCII_TO_DIALOG('o'), ASCII_TO_DIALOG('u'), 0x00
501
502
enum MultiStringIDs { STRING_THE, STRING_YOU };
503
504
/*
505
* Place the multi-text string according to the ID passed. (US, EU)
506
* 0: 'the'
507
* 1: 'you'
508
*/
509
#ifdef VERSION_US
510
void render_multi_text_string(s8 multiTextID)
511
#elif defined(VERSION_EU)
512
void render_multi_text_string(s16 *xPos, s16 *yPos, s8 multiTextID)
513
#endif
514
{
515
s8 i;
516
struct MultiTextEntry textLengths[2] = {
517
{ 3, { TEXT_THE_RAW } },
518
{ 3, { TEXT_YOU_RAW } },
519
};
520
521
for (i = 0; i < textLengths[multiTextID].length; i++) {
522
#ifdef VERSION_US
523
render_generic_char(textLengths[multiTextID].str[i]);
524
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[textLengths[multiTextID].str[i]]), 0.0f, 0.0f);
525
#elif defined(VERSION_EU)
526
render_generic_char_at_pos(*xPos, *yPos, textLengths[multiTextID].str[i]);
527
*xPos += gDialogCharWidths[textLengths[multiTextID].str[i]];
528
#endif
529
}
530
}
531
#endif
532
533
#if defined(VERSION_JP) || defined(VERSION_SH)
534
#define MAX_STRING_WIDTH 18
535
#else
536
#define MAX_STRING_WIDTH 16
537
#endif
538
539
/**
540
* Prints a generic white string.
541
* In JP/EU a IA1 texture is used but in US a IA4 texture is used.
542
*/
543
void print_generic_string(s16 x, s16 y, const u8 *str) {
544
UNUSED s8 mark = DIALOG_MARK_NONE; // unused in EU
545
s32 strPos = 0;
546
u8 lineNum = 1;
547
#ifdef VERSION_EU
548
s16 xCoord = x;
549
s16 yCoord = 240 - y;
550
#endif
551
552
#ifndef VERSION_EU
553
create_dl_translation_matrix(MENU_MTX_PUSH, x, y, 0.0f);
554
#endif
555
556
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
557
switch (str[strPos]) {
558
#ifdef VERSION_EU
559
case DIALOG_CHAR_SPACE:
560
xCoord += 5;
561
break;
562
case DIALOG_CHAR_NEWLINE:
563
yCoord += 16;
564
xCoord = x;
565
lineNum++;
566
break;
567
case DIALOG_CHAR_LOWER_A_GRAVE:
568
case DIALOG_CHAR_LOWER_A_CIRCUMFLEX:
569
case DIALOG_CHAR_LOWER_A_UMLAUT:
570
render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('a'), str[strPos] & 0xF);
571
break;
572
case DIALOG_CHAR_UPPER_A_UMLAUT: // @bug grave and circumflex (0x64-0x65) are absent here
573
render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('A'), str[strPos] & 0xF);
574
break;
575
case DIALOG_CHAR_LOWER_E_GRAVE:
576
case DIALOG_CHAR_LOWER_E_CIRCUMFLEX:
577
case DIALOG_CHAR_LOWER_E_UMLAUT:
578
case DIALOG_CHAR_LOWER_E_ACUTE:
579
render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('e'), str[strPos] & 0xF);
580
break;
581
case DIALOG_CHAR_UPPER_E_GRAVE:
582
case DIALOG_CHAR_UPPER_E_CIRCUMFLEX:
583
case DIALOG_CHAR_UPPER_E_UMLAUT:
584
case DIALOG_CHAR_UPPER_E_ACUTE:
585
render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('E'), str[strPos] & 0xF);
586
break;
587
case DIALOG_CHAR_LOWER_U_GRAVE:
588
case DIALOG_CHAR_LOWER_U_CIRCUMFLEX:
589
case DIALOG_CHAR_LOWER_U_UMLAUT:
590
render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('u'), str[strPos] & 0xF);
591
break;
592
case DIALOG_CHAR_UPPER_U_UMLAUT: // @bug grave and circumflex (0x84-0x85) are absent here
593
render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('U'), str[strPos] & 0xF);
594
break;
595
case DIALOG_CHAR_LOWER_O_CIRCUMFLEX:
596
case DIALOG_CHAR_LOWER_O_UMLAUT:
597
render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('o'), str[strPos] & 0xF);
598
break;
599
case DIALOG_CHAR_UPPER_O_UMLAUT: // @bug circumflex (0x95) is absent here
600
render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('O'), str[strPos] & 0xF);
601
break;
602
case DIALOG_CHAR_LOWER_I_CIRCUMFLEX:
603
case DIALOG_CHAR_LOWER_I_UMLAUT:
604
render_lowercase_diacritic(&xCoord, &yCoord, DIALOG_CHAR_I_NO_DIA, str[strPos] & 0xF);
605
break;
606
#else // i.e. not EU
607
case DIALOG_CHAR_DAKUTEN:
608
mark = DIALOG_MARK_DAKUTEN;
609
break;
610
case DIALOG_CHAR_PERIOD_OR_HANDAKUTEN:
611
mark = DIALOG_MARK_HANDAKUTEN;
612
break;
613
case DIALOG_CHAR_NEWLINE:
614
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
615
create_dl_translation_matrix(MENU_MTX_PUSH, x, y - (lineNum * MAX_STRING_WIDTH), 0.0f);
616
lineNum++;
617
break;
618
case DIALOG_CHAR_PERIOD:
619
create_dl_translation_matrix(MENU_MTX_PUSH, -2.0f, -5.0f, 0.0f);
620
render_generic_char(DIALOG_CHAR_PERIOD_OR_HANDAKUTEN);
621
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
622
break;
623
#endif
624
#if !defined(VERSION_JP) && !defined(VERSION_SH)
625
case DIALOG_CHAR_SLASH:
626
#ifdef VERSION_US
627
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE] * 2), 0.0f, 0.0f);
628
#elif defined(VERSION_EU)
629
xCoord += gDialogCharWidths[DIALOG_CHAR_SPACE] * 2;
630
#endif
631
break;
632
case DIALOG_CHAR_MULTI_THE:
633
#ifdef VERSION_EU
634
render_multi_text_string(&xCoord, &yCoord, STRING_THE);
635
#else
636
render_multi_text_string(STRING_THE);
637
#endif
638
break;
639
case DIALOG_CHAR_MULTI_YOU:
640
#ifdef VERSION_EU
641
render_multi_text_string(&xCoord, &yCoord, STRING_YOU);
642
#else
643
render_multi_text_string(STRING_YOU);
644
#endif
645
break;
646
#endif
647
#ifndef VERSION_EU
648
case DIALOG_CHAR_SPACE:
649
#if defined(VERSION_JP) || defined(VERSION_SH)
650
create_dl_translation_matrix(MENU_MTX_NOPUSH, 5.0f, 0.0f, 0.0f);
651
break;
652
#else
653
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE]), 0.0f, 0.0f);
654
#endif
655
#endif
656
break; // ? needed to match
657
default:
658
#ifdef VERSION_EU
659
render_generic_char_at_pos(xCoord, yCoord, str[strPos]);
660
xCoord += gDialogCharWidths[str[strPos]];
661
break;
662
#else
663
render_generic_char(str[strPos]);
664
if (mark != DIALOG_MARK_NONE) {
665
create_dl_translation_matrix(MENU_MTX_PUSH, 5.0f, 5.0f, 0.0f);
666
render_generic_char(mark + 0xEF);
667
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
668
mark = DIALOG_MARK_NONE;
669
}
670
671
#if defined(VERSION_JP) || defined(VERSION_SH)
672
create_dl_translation_matrix(MENU_MTX_NOPUSH, 10.0f, 0.0f, 0.0f);
673
#else
674
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[str[strPos]]), 0.0f, 0.0f);
675
break; // what an odd difference. US added a useless break here.
676
#endif
677
#endif
678
}
679
680
strPos++;
681
}
682
683
#ifndef VERSION_EU
684
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
685
#endif
686
}
687
688
#ifdef VERSION_EU
689
void print_hud_char_umlaut(s16 x, s16 y, u8 chr) {
690
void **fontLUT = segmented_to_virtual(main_hud_lut);
691
692
gDPPipeSync(gDisplayListHead++);
693
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, fontLUT[chr]);
694
gSPDisplayList(gDisplayListHead++, dl_rgba16_load_tex_block);
695
gSPTextureRectangle(gDisplayListHead++, x << 2, y << 2, (x + 16) << 2, (y + 16) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
696
697
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, fontLUT[GLYPH_UMLAUT]);
698
gSPDisplayList(gDisplayListHead++, dl_rgba16_load_tex_block);
699
gSPTextureRectangle(gDisplayListHead++, x << 2, (y - 4) << 2, (x + 16) << 2, (y + 12) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
700
}
701
#endif
702
703
/**
704
* Prints a hud string depending of the hud table list defined.
705
*/
706
void print_hud_lut_string(s8 hudLUT, s16 x, s16 y, const u8 *str) {
707
s32 strPos = 0;
708
void **hudLUT1 = segmented_to_virtual(menu_hud_lut); // Japanese Menu HUD Color font
709
void **hudLUT2 = segmented_to_virtual(main_hud_lut); // 0-9 A-Z HUD Color Font
710
u32 curX = x;
711
u32 curY = y;
712
713
u32 xStride; // X separation
714
715
if (hudLUT == HUD_LUT_JPMENU) {
716
xStride = 16;
717
} else { // HUD_LUT_GLOBAL
718
#ifdef VERSION_JP
719
xStride = 14;
720
#else
721
xStride = 12; //? Shindou uses this.
722
#endif
723
}
724
725
while (str[strPos] != GLOBAR_CHAR_TERMINATOR) {
726
#ifndef VERSION_JP
727
switch (str[strPos]) {
728
#ifdef VERSION_EU
729
case GLOBAL_CHAR_SPACE:
730
curX += xStride / 2;
731
break;
732
case HUD_CHAR_A_UMLAUT:
733
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('A'));
734
curX += xStride;
735
break;
736
case HUD_CHAR_O_UMLAUT:
737
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('O'));
738
curX += xStride;
739
break;
740
case HUD_CHAR_U_UMLAUT:
741
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('U'));
742
curX += xStride;
743
break;
744
#else
745
case GLOBAL_CHAR_SPACE:
746
curX += 8;
747
break;
748
#endif
749
default:
750
#endif
751
gDPPipeSync(gDisplayListHead++);
752
753
if (hudLUT == HUD_LUT_JPMENU) {
754
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, hudLUT1[str[strPos]]);
755
}
756
757
if (hudLUT == HUD_LUT_GLOBAL) {
758
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, hudLUT2[str[strPos]]);
759
}
760
761
gSPDisplayList(gDisplayListHead++, dl_rgba16_load_tex_block);
762
gSPTextureRectangle(gDisplayListHead++, curX << 2, curY << 2, (curX + 16) << 2,
763
(curY + 16) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
764
765
curX += xStride;
766
#ifndef VERSION_JP
767
}
768
#endif
769
strPos++;
770
}
771
}
772
void print_hud_lut_string_to_displaylist(s8 hudLUT, s16 x, s16 y, const u8 *str, Gfx* displayList) {
773
s32 strPos = 0;
774
void **hudLUT1 = segmented_to_virtual(menu_hud_lut); // Japanese Menu HUD Color font
775
void **hudLUT2 = segmented_to_virtual(main_hud_lut); // 0-9 A-Z HUD Color Font
776
u32 curX = x;
777
u32 curY = y;
778
779
u32 xStride; // X separation
780
781
if (hudLUT == HUD_LUT_JPMENU) {
782
xStride = 16;
783
} else { // HUD_LUT_GLOBAL
784
#if defined(VERSION_JP)
785
xStride = 14;
786
#else
787
xStride = 12; //? Shindou uses this.
788
#endif
789
}
790
791
while (str[strPos] != GLOBAR_CHAR_TERMINATOR) {
792
#ifdef VERSION_EU
793
switch (str[strPos]) {
794
case GLOBAL_CHAR_SPACE:
795
curX += xStride / 2;
796
break;
797
case HUD_CHAR_A_UMLAUT:
798
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('A'));
799
curX += xStride;
800
break;
801
case HUD_CHAR_O_UMLAUT:
802
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('O'));
803
curX += xStride;
804
break;
805
case HUD_CHAR_U_UMLAUT:
806
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('U'));
807
curX += xStride;
808
break;
809
default:
810
#endif
811
#if defined(VERSION_US) || defined(VERSION_SH)
812
if (str[strPos] == GLOBAL_CHAR_SPACE) {
813
if (0) //! dead code
814
{
815
}
816
curX += 8;
817
; //! useless statement
818
} else {
819
#endif
820
gDPPipeSync(displayList++);
821
822
if (hudLUT == HUD_LUT_JPMENU)
823
gDPSetTextureImage(displayList++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, hudLUT1[str[strPos]]);
824
825
if (hudLUT == HUD_LUT_GLOBAL)
826
gDPSetTextureImage(displayList++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, hudLUT2[str[strPos]]);
827
828
gSPDisplayList(displayList++, dl_rgba16_load_tex_block);
829
gSPTextureRectangle(displayList++, curX << 2, curY << 2, (curX + 16) << 2,
830
(curY + 16) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
831
832
curX += xStride;
833
#ifdef VERSION_EU
834
break;
835
}
836
#endif
837
#if defined(VERSION_US) || defined(VERSION_SH)
838
}
839
#endif
840
strPos++;
841
}
842
}
843
844
#ifdef VERSION_EU
845
void print_menu_char_umlaut(s16 x, s16 y, u8 chr) {
846
void **fontLUT = segmented_to_virtual(menu_font_lut);
847
848
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, fontLUT[chr]);
849
gDPLoadSync(gDisplayListHead++);
850
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_8b_BYTES));
851
gSPTextureRectangle(gDisplayListHead++, x << 2, y << 2, (x + 8) << 2, (y + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
852
853
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, fontLUT[DIALOG_CHAR_UMLAUT]);
854
gDPLoadSync(gDisplayListHead++);
855
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_8b_BYTES));
856
gSPTextureRectangle(gDisplayListHead++, x << 2, (y - 4) << 2, (x + 8) << 2, (y + 4) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
857
}
858
#endif
859
860
void print_menu_generic_string(s16 x, s16 y, const u8 *str) {
861
UNUSED s8 mark = DIALOG_MARK_NONE; // unused in EU
862
s32 strPos = 0;
863
u32 curX = x;
864
u32 curY = y;
865
void **fontLUT = segmented_to_virtual(menu_font_lut);
866
867
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
868
switch (str[strPos]) {
869
#ifdef VERSION_EU
870
case DIALOG_CHAR_UPPER_A_UMLAUT:
871
print_menu_char_umlaut(curX, curY, ASCII_TO_DIALOG('A'));
872
curX += gDialogCharWidths[str[strPos]];
873
break;
874
case DIALOG_CHAR_UPPER_U_UMLAUT:
875
print_menu_char_umlaut(curX, curY, ASCII_TO_DIALOG('U'));
876
curX += gDialogCharWidths[str[strPos]];
877
break;
878
case DIALOG_CHAR_UPPER_O_UMLAUT:
879
print_menu_char_umlaut(curX, curY, ASCII_TO_DIALOG('O'));
880
curX += gDialogCharWidths[str[strPos]];
881
break;
882
#else
883
case DIALOG_CHAR_DAKUTEN:
884
mark = DIALOG_MARK_DAKUTEN;
885
break;
886
case DIALOG_CHAR_PERIOD_OR_HANDAKUTEN:
887
mark = DIALOG_MARK_HANDAKUTEN;
888
break;
889
#endif
890
case DIALOG_CHAR_SPACE:
891
curX += 4;
892
break;
893
default:
894
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, fontLUT[str[strPos]]);
895
gDPLoadSync(gDisplayListHead++);
896
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_8b_BYTES));
897
gSPTextureRectangle(gDisplayListHead++, curX << 2, curY << 2, (curX + 8) << 2,
898
(curY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
899
900
#ifndef VERSION_EU
901
if (mark != DIALOG_MARK_NONE) {
902
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, fontLUT[mark + 0xEF]);
903
gDPLoadSync(gDisplayListHead++);
904
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_8b_BYTES));
905
gSPTextureRectangle(gDisplayListHead++, (curX + 6) << 2, (curY - 7) << 2,
906
(curX + 6 + 8) << 2, (curY - 7 + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
907
908
mark = DIALOG_MARK_NONE;
909
}
910
#endif
911
#if defined(VERSION_JP) || defined(VERSION_SH)
912
curX += 9;
913
#else
914
curX += gDialogCharWidths[str[strPos]];
915
#endif
916
}
917
strPos++;
918
}
919
}
920
921
void print_credits_string(s16 x, s16 y, const u8 *str) {
922
s32 strPos = 0;
923
void **fontLUT = segmented_to_virtual(main_credits_font_lut);
924
u32 curX = x;
925
u32 curY = y;
926
927
gDPSetTile(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0,
928
G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD);
929
gDPTileSync(gDisplayListHead++);
930
gDPSetTile(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 2, 0, G_TX_RENDERTILE, 0,
931
G_TX_CLAMP, 3, G_TX_NOLOD, G_TX_CLAMP, 3, G_TX_NOLOD);
932
gDPSetTileSize(gDisplayListHead++, G_TX_RENDERTILE, 0, 0, (8 - 1) << G_TEXTURE_IMAGE_FRAC, (8 - 1) << G_TEXTURE_IMAGE_FRAC);
933
934
while (str[strPos] != GLOBAR_CHAR_TERMINATOR) {
935
switch (str[strPos]) {
936
case GLOBAL_CHAR_SPACE:
937
curX += 4;
938
break;
939
default:
940
gDPPipeSync(gDisplayListHead++);
941
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, fontLUT[str[strPos]]);
942
gDPLoadSync(gDisplayListHead++);
943
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_16b_BYTES));
944
gSPTextureRectangle(gDisplayListHead++, curX << 2, curY << 2, (curX + 8) << 2,
945
(curY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
946
curX += 7;
947
break;
948
}
949
strPos++;
950
}
951
}
952
953
void handle_menu_scrolling(s8 scrollDirection, s8 *currentIndex, s8 minIndex, s8 maxIndex) {
954
u8 index = 0;
955
956
if (scrollDirection == MENU_SCROLL_VERTICAL) {
957
if (gPlayer3Controller->rawStickY > 60) {
958
index++;
959
}
960
961
if (gPlayer3Controller->rawStickY < -60) {
962
index += 2;
963
}
964
} else if (scrollDirection == MENU_SCROLL_HORIZONTAL) {
965
if (gPlayer3Controller->rawStickX > 60) {
966
index += 2;
967
}
968
969
if (gPlayer3Controller->rawStickX < -60) {
970
index++;
971
}
972
}
973
974
if (((index ^ gMenuHoldKeyIndex) & index) == 2) {
975
if (currentIndex[0] == maxIndex) {
976
//! Probably originally a >=, but later replaced with an == and an else statement.
977
currentIndex[0] = maxIndex;
978
} else {
979
play_sound(SOUND_MENU_CHANGE_SELECT, gGlobalSoundSource);
980
currentIndex[0]++;
981
}
982
}
983
984
if (((index ^ gMenuHoldKeyIndex) & index) == 1) {
985
if (currentIndex[0] == minIndex) {
986
// Same applies to here as above
987
} else {
988
play_sound(SOUND_MENU_CHANGE_SELECT, gGlobalSoundSource);
989
currentIndex[0]--;
990
}
991
}
992
993
if (configQuitOption && gMenuHoldKeyTimer == 14) {
994
gMenuHoldKeyTimer = 12;
995
gMenuHoldKeyIndex = 0;
996
}
997
else if (gMenuHoldKeyTimer == 10) {
998
gMenuHoldKeyTimer = 8;
999
gMenuHoldKeyIndex = 0;
1000
} else {
1001
gMenuHoldKeyTimer++;
1002
gMenuHoldKeyIndex = index;
1003
}
1004
1005
if ((index & 3) == 0) {
1006
gMenuHoldKeyTimer = 0;
1007
}
1008
}
1009
1010
// EU has both get_str_x_pos_from_center and get_str_x_pos_from_center_scale
1011
// US and JP only implement one or the other
1012
#if defined(VERSION_US) || defined(VERSION_EU)
1013
s16 get_str_x_pos_from_center(s16 centerPos, u8 *str, UNUSED f32 scale) {
1014
s16 strPos = 0;
1015
f32 spacesWidth = 0.0f;
1016
1017
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
1018
spacesWidth += gDialogCharWidths[str[strPos]];
1019
strPos++;
1020
}
1021
// return the x position of where the string starts as half the string's
1022
// length from the position of the provided center.
1023
return (s16)(centerPos - (s16)(spacesWidth / 2.0));
1024
}
1025
#endif
1026
1027
#if defined(VERSION_JP) || defined(VERSION_EU) || defined(VERSION_SH)
1028
s16 get_str_x_pos_from_center_scale(s16 centerPos, u8 *str, f32 scale) {
1029
s16 strPos = 0;
1030
f32 charsWidth = 0.0f;
1031
f32 spacesWidth = 0.0f;
1032
1033
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
1034
//! EU checks for dakuten and handakuten despite dialog code unable to handle it
1035
if (str[strPos] == DIALOG_CHAR_SPACE) {
1036
spacesWidth += 1.0;
1037
} else if (str[strPos] != DIALOG_CHAR_DAKUTEN
1038
&& str[strPos] != DIALOG_CHAR_PERIOD_OR_HANDAKUTEN) {
1039
charsWidth += 1.0;
1040
}
1041
strPos++;
1042
}
1043
// return the x position of where the string starts as half the string's
1044
// length from the position of the provided center.
1045
return (f32) centerPos - (scale * (charsWidth / 2.0)) - ((scale / 2.0) * (spacesWidth / 2.0));
1046
}
1047
#endif
1048
1049
#if !defined(VERSION_JP) && !defined(VERSION_SH)
1050
s16 get_string_width(u8 *str) {
1051
s16 strPos = 0;
1052
s16 width = 0;
1053
1054
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
1055
width += gDialogCharWidths[str[strPos]];
1056
strPos++;
1057
}
1058
return width;
1059
}
1060
#endif
1061
1062
u8 gHudSymCoin[] = { GLYPH_COIN, GLYPH_SPACE };
1063
u8 gHudSymX[] = { GLYPH_MULTIPLY, GLYPH_SPACE };
1064
1065
void print_hud_my_score_coins(s32 useCourseCoinScore, s8 fileNum, s8 courseNum, s16 x, s16 y) {
1066
u8 strNumCoins[4];
1067
s16 numCoins;
1068
1069
if (!useCourseCoinScore) {
1070
numCoins = (u16)(save_file_get_max_coin_score(courseNum) & 0xFFFF);
1071
} else {
1072
numCoins = save_file_get_course_coin_score(fileNum, courseNum);
1073
}
1074
1075
if (numCoins != 0) {
1076
print_hud_lut_string(HUD_LUT_GLOBAL, x, y, gHudSymCoin);
1077
print_hud_lut_string(HUD_LUT_GLOBAL, x + 16, y, gHudSymX);
1078
int_to_str(numCoins, strNumCoins);
1079
print_hud_lut_string(HUD_LUT_GLOBAL, x + 32, y, strNumCoins);
1080
}
1081
}
1082
1083
void print_hud_my_score_stars(s8 fileNum, s8 courseNum, s16 x, s16 y) {
1084
u8 strStarCount[4];
1085
s16 starCount;
1086
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
1087
UNUSED u16 unused;
1088
u8 textSymX[] = { GLYPH_MULTIPLY, GLYPH_SPACE };
1089
1090
starCount = save_file_get_course_star_count(fileNum, courseNum);
1091
1092
if (starCount != 0) {
1093
print_hud_lut_string(HUD_LUT_GLOBAL, x, y, textSymStar);
1094
print_hud_lut_string(HUD_LUT_GLOBAL, x + 16, y, textSymX);
1095
int_to_str(starCount, strStarCount);
1096
print_hud_lut_string(HUD_LUT_GLOBAL, x + 32, y, strStarCount);
1097
}
1098
}
1099
1100
void int_to_str(s32 num, u8 *dst) {
1101
s32 digit1;
1102
s32 digit2;
1103
s32 digit3;
1104
1105
s8 pos = 0;
1106
1107
if (num > 999) {
1108
dst[0] = 0x00; dst[1] = DIALOG_CHAR_TERMINATOR;
1109
return;
1110
}
1111
1112
digit1 = num / 100;
1113
digit2 = (num - digit1 * 100) / 10;
1114
digit3 = (num - digit1 * 100) - (digit2 * 10);
1115
1116
if (digit1 != 0) {
1117
dst[pos++] = digit1;
1118
}
1119
1120
if (digit2 != 0 || digit1 != 0) {
1121
dst[pos++] = digit2;
1122
}
1123
1124
dst[pos++] = digit3;
1125
dst[pos] = DIALOG_CHAR_TERMINATOR;
1126
}
1127
1128
s16 get_dialog_id(void) {
1129
return gDialogID;
1130
}
1131
1132
void create_dialog_box(s16 dialog) {
1133
if (gDialogID == DIALOG_NONE) {
1134
gDialogID = dialog;
1135
gDialogBoxType = DIALOG_TYPE_ROTATE;
1136
}
1137
}
1138
1139
void create_dialog_box_with_var(s16 dialog, s32 dialogVar) {
1140
if (gDialogID == DIALOG_NONE) {
1141
gDialogID = dialog;
1142
gDialogVariable = dialogVar;
1143
gDialogBoxType = DIALOG_TYPE_ROTATE;
1144
}
1145
}
1146
1147
void create_dialog_inverted_box(s16 dialog) {
1148
if (gDialogID == DIALOG_NONE) {
1149
gDialogID = dialog;
1150
gDialogBoxType = DIALOG_TYPE_ZOOM;
1151
}
1152
}
1153
1154
void create_dialog_box_with_response(s16 dialog) {
1155
if (gDialogID == DIALOG_NONE) {
1156
gDialogID = dialog;
1157
gDialogBoxType = DIALOG_TYPE_ROTATE;
1158
gLastDialogResponse = 1;
1159
}
1160
}
1161
1162
void reset_dialog_render_state(void) {
1163
level_set_transition(0, NULL);
1164
1165
if (gDialogBoxType == DIALOG_TYPE_ZOOM) {
1166
trigger_cutscene_dialog(2);
1167
}
1168
1169
gDialogBoxScale = 19.0f;
1170
gDialogBoxOpenTimer = 90.0f;
1171
gDialogBoxState = DIALOG_STATE_OPENING;
1172
gDialogID = DIALOG_NONE;
1173
gDialogTextPos = 0;
1174
gLastDialogResponse = 0;
1175
gLastDialogPageStrPos = 0;
1176
gDialogResponse = DIALOG_RESPONSE_NONE;
1177
}
1178
1179
#if defined(VERSION_JP) || defined(VERSION_SH)
1180
#define X_VAL1 -5.0f
1181
#define Y_VAL1 2.0
1182
#define Y_VAL2 4
1183
#else
1184
#define X_VAL1 -7.0f
1185
#define Y_VAL1 5.0
1186
#define Y_VAL2 5.0f
1187
#endif
1188
1189
void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) {
1190
UNUSED s32 unused;
1191
1192
create_dl_translation_matrix(MENU_MTX_NOPUSH, dialog->leftOffset, dialog->width, 0);
1193
1194
switch (gDialogBoxType) {
1195
case DIALOG_TYPE_ROTATE: // Renders a dialog black box with zoom and rotation
1196
if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) {
1197
sInterpolatedDialogRotationPos = gDisplayListHead;
1198
if (gDialogBoxState == DIALOG_STATE_OPENING) {
1199
sInterpolatedDialogScale = gDialogBoxScale - 2 / 2;
1200
sInterpolatedDialogRotation = gDialogBoxOpenTimer - 7.5f / 2;
1201
} else {
1202
sInterpolatedDialogScale = gDialogBoxScale + 2 / 2;
1203
sInterpolatedDialogRotation = gDialogBoxOpenTimer + 7.5f / 2;
1204
}
1205
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f);
1206
// convert the speed into angle
1207
create_dl_rotation_matrix(MENU_MTX_NOPUSH, gDialogBoxOpenTimer * 4.0f, 0, 0, 1.0f);
1208
}
1209
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 150);
1210
break;
1211
case DIALOG_TYPE_ZOOM: // Renders a dialog white box with zoom
1212
if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) {
1213
sInterpolatedDialogZoomPos = gDisplayListHead;
1214
if (gDialogBoxState == DIALOG_STATE_OPENING) {
1215
sInterpolatedDialogScale = gDialogBoxScale - 2 / 2;
1216
} else {
1217
sInterpolatedDialogScale = gDialogBoxScale + 2 / 2;
1218
}
1219
create_dl_translation_matrix(MENU_MTX_NOPUSH, 65.0 - (65.0 / gDialogBoxScale),
1220
(40.0 / gDialogBoxScale) - 40, 0);
1221
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f);
1222
}
1223
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 150);
1224
break;
1225
}
1226
1227
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL1, Y_VAL1, 0);
1228
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.1f, ((f32) linesPerBox / Y_VAL2) + 0.1, 1.0f);
1229
1230
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
1231
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
1232
}
1233
1234
void change_and_flash_dialog_text_color_lines(s8 colorMode, s8 lineNum) {
1235
u8 colorFade;
1236
1237
if (colorMode == 1) {
1238
if (lineNum == 1) {
1239
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
1240
} else {
1241
if (lineNum == gDialogLineNum) {
1242
colorFade = (gSineTable[gDialogColorFadeTimer >> 4] * 50.0f) + 200.0f;
1243
gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255);
1244
} else {
1245
gDPSetEnvColor(gDisplayListHead++, 200, 200, 200, 255);
1246
}
1247
}
1248
} else {
1249
switch (gDialogBoxType) {
1250
case DIALOG_TYPE_ROTATE:
1251
break;
1252
case DIALOG_TYPE_ZOOM:
1253
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
1254
break;
1255
}
1256
}
1257
}
1258
1259
#ifdef VERSION_EU
1260
void render_generic_dialog_char_at_pos(struct DialogEntry *dialog, s16 x, s16 y, u8 c) {
1261
s16 width;
1262
s16 height;
1263
s16 tmpX;
1264
s16 tmpY;
1265
s16 xCoord;
1266
s16 yCoord;
1267
void **fontLUT;
1268
void *packedTexture;
1269
void *unpackedTexture;
1270
1271
width = (8.0 - (gDialogBoxScale * 0.8));
1272
height = (16.0 - (gDialogBoxScale * 0.8));
1273
tmpX = (dialog->leftOffset + (65.0 - (65.0 / gDialogBoxScale)));
1274
tmpY = ((240 - dialog->width) - ((40.0 / gDialogBoxScale) - 40));
1275
xCoord = (tmpX + (x / gDialogBoxScale));
1276
yCoord = (tmpY + (y / gDialogBoxScale));
1277
1278
fontLUT = segmented_to_virtual(main_font_lut);
1279
packedTexture = segmented_to_virtual(fontLUT[c]);
1280
unpackedTexture = alloc_ia4_tex_from_i1(packedTexture, 8, 8);
1281
1282
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(unpackedTexture));
1283
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
1284
gSPTextureRectangleFlip(gDisplayListHead++, xCoord << 2, (yCoord - height) << 2,
1285
(xCoord + width) << 2, yCoord << 2, G_TX_RENDERTILE, 8 << 6, 4 << 6, 1 << 10, 1 << 10);
1286
}
1287
#endif
1288
1289
#if defined(VERSION_JP) || defined(VERSION_SH)
1290
#define X_VAL3 5.0f
1291
#define Y_VAL3 20
1292
#else
1293
#define X_VAL3 0.0f
1294
#define Y_VAL3 16
1295
#endif
1296
1297
#ifdef VERSION_EU
1298
void handle_dialog_scroll_page_state(s8 lineNum, s8 totalLines, s8 *pageState, s8 *xMatrix)
1299
#else
1300
void handle_dialog_scroll_page_state(s8 lineNum, s8 totalLines, s8 *pageState, s8 *xMatrix, s16 *linePos)
1301
#endif
1302
{
1303
#ifndef VERSION_EU
1304
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
1305
#endif
1306
1307
if (lineNum == totalLines) {
1308
pageState[0] = DIALOG_PAGE_STATE_SCROLL;
1309
return;
1310
}
1311
#ifdef VERSION_EU
1312
gDialogY += 16;
1313
#else
1314
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL3, 2 - (lineNum * Y_VAL3), 0);
1315
1316
linePos[0] = 0;
1317
#endif
1318
xMatrix[0] = 1;
1319
}
1320
1321
#if defined(VERSION_JP) || defined(VERSION_SH)
1322
void adjust_pos_and_print_period_char(s8 *xMatrix, s16 *linePos) {
1323
if (linePos[0] != 0) {
1324
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix[0] * 10, 0, 0);
1325
}
1326
1327
create_dl_translation_matrix(MENU_MTX_PUSH, -2.0f, -5.0f, 0);
1328
render_generic_char(DIALOG_CHAR_PERIOD_OR_HANDAKUTEN);
1329
1330
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
1331
1332
linePos[0]++;
1333
xMatrix[0] = 1;
1334
}
1335
#endif
1336
1337
#ifdef VERSION_EU
1338
void render_star_count_dialog_text(struct DialogEntry *dialog, s8 *linePos)
1339
#else
1340
void render_star_count_dialog_text(s8 *xMatrix, s16 *linePos)
1341
#endif
1342
{
1343
s8 tensDigit = gDialogVariable / 10;
1344
s8 onesDigit = gDialogVariable - (tensDigit * 10); // remainder
1345
1346
if (tensDigit != 0) {
1347
#if defined(VERSION_JP) || defined(VERSION_SH)
1348
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix[0] * 10, 0, 0);
1349
render_generic_char(tensDigit);
1350
#elif defined(VERSION_EU)
1351
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, tensDigit);
1352
gDialogX += gDialogCharWidths[tensDigit];
1353
linePos[0] = 1;
1354
#else
1355
if (xMatrix[0] != 1) {
1356
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE] * xMatrix[0]), 0, 0);
1357
}
1358
1359
render_generic_char(tensDigit);
1360
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32) gDialogCharWidths[tensDigit], 0, 0);
1361
xMatrix[0] = 1;
1362
linePos[0]++;
1363
#endif
1364
}
1365
#ifndef VERSION_EU
1366
else {
1367
#if defined(VERSION_JP) || defined(VERSION_SH)
1368
xMatrix[0]++;
1369
#endif
1370
}
1371
#endif
1372
1373
#ifdef VERSION_EU
1374
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, onesDigit);
1375
gDialogX += gDialogCharWidths[onesDigit];
1376
linePos[0] = 1;
1377
#else
1378
1379
#if defined(VERSION_JP) || defined(VERSION_SH)
1380
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix[0] * 10, 0, 0);
1381
render_generic_char(onesDigit);
1382
#else
1383
if (xMatrix[0] != 1) {
1384
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE] * (xMatrix[0] - 1)), 0, 0);
1385
}
1386
1387
render_generic_char(onesDigit);
1388
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32) gDialogCharWidths[onesDigit], 0, 0);
1389
#endif
1390
1391
linePos[0]++;
1392
xMatrix[0] = 1;
1393
#endif
1394
}
1395
1396
#if !defined(VERSION_JP) && !defined(VERSION_SH)
1397
#ifdef VERSION_EU
1398
void render_multi_text_string_lines(s8 multiTextId, s8 lineNum, s8 linesPerBox, UNUSED s16 linePos, s8 lowerBound, struct DialogEntry *dialog)
1399
#else
1400
void render_multi_text_string_lines(s8 multiTextId, s8 lineNum, s16 *linePos, s8 linesPerBox, s8 xMatrix, s8 lowerBound)
1401
#endif
1402
{
1403
s8 i;
1404
struct MultiTextEntry textLengths[2] = {
1405
{ 3, { TEXT_THE_RAW } },
1406
{ 3, { TEXT_YOU_RAW } },
1407
};
1408
1409
if (lineNum >= lowerBound && lineNum <= (lowerBound + linesPerBox)) {
1410
#ifdef VERSION_US
1411
if (linePos[0] != 0 || (xMatrix != 1)) {
1412
create_dl_translation_matrix(MENU_MTX_NOPUSH, (gDialogCharWidths[DIALOG_CHAR_SPACE] * (xMatrix - 1)), 0, 0);
1413
}
1414
#endif
1415
for (i = 0; i < textLengths[multiTextId].length; i++) {
1416
#ifdef VERSION_EU
1417
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, textLengths[multiTextId].str[i]);
1418
gDialogX += gDialogCharWidths[textLengths[multiTextId].str[i]];
1419
#else
1420
render_generic_char(textLengths[multiTextId].str[i]);
1421
create_dl_translation_matrix(MENU_MTX_NOPUSH, (gDialogCharWidths[textLengths[multiTextId].str[i]]), 0, 0);
1422
#endif
1423
}
1424
}
1425
#ifdef VERSION_US
1426
linePos += textLengths[multiTextId].length;
1427
#endif
1428
}
1429
#endif
1430
1431
#ifdef VERSION_EU
1432
void render_dialog_lowercase_diacritic(struct DialogEntry *dialog, u8 chr, u8 diacritic) {
1433
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, chr);
1434
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, diacritic + 0xE7);
1435
gDialogX += gDialogCharWidths[chr];
1436
}
1437
1438
void render_dialog_uppercase_diacritic(struct DialogEntry *dialog, u8 chr, u8 diacritic) {
1439
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, chr);
1440
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY - 4, diacritic + 0xE3);
1441
gDialogX += gDialogCharWidths[chr];
1442
}
1443
#endif
1444
1445
u32 ensure_nonnegative(s16 value) {
1446
if (value < 0) {
1447
value = 0;
1448
}
1449
1450
return value;
1451
}
1452
1453
#if defined(VERSION_JP)
1454
void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog)
1455
#else
1456
void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 lowerBound)
1457
#endif
1458
{
1459
UNUSED s32 pad[2];
1460
#ifdef VERSION_EU
1461
s16 startY = 14;
1462
#endif
1463
1464
u8 strChar;
1465
1466
u8 *str = segmented_to_virtual(dialog->str);
1467
1468
if (configFixTextTypos) {
1469
static u8 sDialogPatchedBuf[2048];
1470
s16 lenCopy = 0;
1471
copy_dialog_text(sDialogPatchedBuf, str, &lenCopy, (s16)sizeof(sDialogPatchedBuf));
1472
fix_wing_cap_tip(sDialogPatchedBuf, &lenCopy);
1473
fix_yoshi_typo(sDialogPatchedBuf, &lenCopy);
1474
fix_run_into(sDialogPatchedBuf, &lenCopy);
1475
str = sDialogPatchedBuf;
1476
}
1477
1478
s8 lineNum = 1;
1479
1480
s8 totalLines;
1481
1482
s8 pageState = DIALOG_PAGE_STATE_NONE;
1483
UNUSED s8 mark = DIALOG_MARK_NONE; // unused in US, EU
1484
s8 xMatrix = 1;
1485
1486
s8 linesPerBox = dialog->linesPerBox;
1487
1488
s16 strIdx;
1489
#ifndef VERSION_EU
1490
s16 linePos = 0;
1491
#endif
1492
1493
if (gDialogBoxState == DIALOG_STATE_HORIZONTAL) {
1494
// If scrolling, consider the number of lines for both
1495
// the current page and the page being scrolled to.
1496
totalLines = linesPerBox * 2 + 1;
1497
} else {
1498
totalLines = linesPerBox + 1;
1499
}
1500
1501
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
1502
strIdx = gDialogTextPos;
1503
#ifdef VERSION_EU
1504
gDialogX = 0;
1505
gDialogY = startY;
1506
#endif
1507
1508
if (gDialogBoxState == DIALOG_STATE_HORIZONTAL) {
1509
#ifdef VERSION_EU
1510
gDialogY -= gDialogScrollOffsetY;
1511
#else
1512
sInterpolatedDialogOffset = gDialogScrollOffsetY + dialog->linesPerBox;
1513
sInterpolatedDialogOffsetPos = gDisplayListHead;
1514
create_dl_translation_matrix(MENU_MTX_NOPUSH, 0, (f32) gDialogScrollOffsetY, 0);
1515
#endif
1516
}
1517
1518
#ifndef VERSION_EU
1519
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL3, 2 - lineNum * Y_VAL3, 0);
1520
#endif
1521
1522
while (pageState == DIALOG_PAGE_STATE_NONE) {
1523
change_and_flash_dialog_text_color_lines(colorMode, lineNum);
1524
strChar = str[strIdx];
1525
1526
switch (strChar) {
1527
case DIALOG_CHAR_TERMINATOR:
1528
pageState = DIALOG_PAGE_STATE_END;
1529
#ifndef VERSION_EU
1530
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
1531
#endif
1532
break;
1533
case DIALOG_CHAR_NEWLINE:
1534
lineNum++;
1535
#ifdef VERSION_EU
1536
handle_dialog_scroll_page_state(lineNum, totalLines, &pageState, &xMatrix);
1537
gDialogX = 0;
1538
#else
1539
handle_dialog_scroll_page_state(lineNum, totalLines, &pageState, &xMatrix, &linePos);
1540
#ifdef VERSION_SH
1541
mark = 0;
1542
#endif
1543
#endif
1544
break;
1545
#ifdef VERSION_EU
1546
case DIALOG_CHAR_LOWER_A_GRAVE:
1547
case DIALOG_CHAR_LOWER_A_CIRCUMFLEX:
1548
case DIALOG_CHAR_LOWER_A_UMLAUT:
1549
render_dialog_lowercase_diacritic(dialog, ASCII_TO_DIALOG('a'), strChar & 0xF);
1550
break;
1551
case DIALOG_CHAR_UPPER_A_GRAVE:
1552
case DIALOG_CHAR_UPPER_A_CIRCUMFLEX:
1553
case DIALOG_CHAR_UPPER_A_UMLAUT:
1554
render_dialog_uppercase_diacritic(dialog, ASCII_TO_DIALOG('A'), strChar & 0xF);
1555
break;
1556
case DIALOG_CHAR_LOWER_E_GRAVE:
1557
case DIALOG_CHAR_LOWER_E_CIRCUMFLEX:
1558
case DIALOG_CHAR_LOWER_E_UMLAUT:
1559
case DIALOG_CHAR_LOWER_E_ACUTE:
1560
render_dialog_lowercase_diacritic(dialog, ASCII_TO_DIALOG('e'), strChar & 0xF);
1561
break;
1562
case DIALOG_CHAR_UPPER_E_GRAVE:
1563
case DIALOG_CHAR_UPPER_E_CIRCUMFLEX:
1564
case DIALOG_CHAR_UPPER_E_UMLAUT:
1565
case DIALOG_CHAR_UPPER_E_ACUTE:
1566
render_dialog_uppercase_diacritic(dialog, ASCII_TO_DIALOG('E'), strChar & 0xF);
1567
break;
1568
case DIALOG_CHAR_LOWER_U_GRAVE:
1569
case DIALOG_CHAR_LOWER_U_CIRCUMFLEX:
1570
case DIALOG_CHAR_LOWER_U_UMLAUT:
1571
render_dialog_lowercase_diacritic(dialog, ASCII_TO_DIALOG('u'), strChar & 0xF);
1572
break;
1573
case DIALOG_CHAR_UPPER_U_GRAVE:
1574
case DIALOG_CHAR_UPPER_U_CIRCUMFLEX:
1575
case DIALOG_CHAR_UPPER_U_UMLAUT:
1576
render_dialog_uppercase_diacritic(dialog, ASCII_TO_DIALOG('U'), strChar & 0xF);
1577
break;
1578
case DIALOG_CHAR_LOWER_O_CIRCUMFLEX:
1579
case DIALOG_CHAR_LOWER_O_UMLAUT:
1580
render_dialog_lowercase_diacritic(dialog, ASCII_TO_DIALOG('o'), strChar & 0xF);
1581
break;
1582
case DIALOG_CHAR_UPPER_O_CIRCUMFLEX:
1583
case DIALOG_CHAR_UPPER_O_UMLAUT:
1584
render_dialog_uppercase_diacritic(dialog, ASCII_TO_DIALOG('O'), strChar & 0xF);
1585
break;
1586
case DIALOG_CHAR_LOWER_I_CIRCUMFLEX:
1587
case DIALOG_CHAR_LOWER_I_UMLAUT:
1588
render_dialog_lowercase_diacritic(dialog, DIALOG_CHAR_I_NO_DIA, strChar & 0xF);
1589
break;
1590
#else
1591
case DIALOG_CHAR_DAKUTEN:
1592
mark = DIALOG_MARK_DAKUTEN;
1593
break;
1594
case DIALOG_CHAR_PERIOD_OR_HANDAKUTEN:
1595
mark = DIALOG_MARK_HANDAKUTEN;
1596
break;
1597
#endif
1598
case DIALOG_CHAR_SPACE:
1599
#ifdef VERSION_EU
1600
gDialogX += gDialogCharWidths[DIALOG_CHAR_SPACE];
1601
#else
1602
#if defined(VERSION_JP) || defined(VERSION_SH)
1603
if (linePos != 0) {
1604
#endif
1605
xMatrix++;
1606
#if defined(VERSION_JP) || defined(VERSION_SH)
1607
}
1608
#endif
1609
linePos++;
1610
1611
#endif
1612
break;
1613
#if defined(VERSION_JP) || defined(VERSION_SH)
1614
case DIALOG_CHAR_PERIOD:
1615
adjust_pos_and_print_period_char(&xMatrix, &linePos);
1616
break;
1617
#else
1618
case DIALOG_CHAR_SLASH:
1619
#ifdef VERSION_EU
1620
gDialogX += gDialogCharWidths[DIALOG_CHAR_SPACE] * 2;
1621
#else
1622
xMatrix += 2;
1623
linePos += 2;
1624
#endif
1625
break;
1626
case DIALOG_CHAR_MULTI_THE:
1627
#ifdef VERSION_EU
1628
render_multi_text_string_lines(STRING_THE, lineNum, linesPerBox, xMatrix, lowerBound, dialog);
1629
#else
1630
render_multi_text_string_lines(STRING_THE, lineNum, &linePos, linesPerBox, xMatrix, lowerBound);
1631
#endif
1632
xMatrix = 1;
1633
break;
1634
case DIALOG_CHAR_MULTI_YOU:
1635
#ifdef VERSION_EU
1636
render_multi_text_string_lines(STRING_YOU, lineNum, linesPerBox, xMatrix, lowerBound, dialog);
1637
#else
1638
render_multi_text_string_lines(STRING_YOU, lineNum, &linePos, linesPerBox, xMatrix, lowerBound);
1639
#endif
1640
xMatrix = 1;
1641
break;
1642
#endif
1643
case DIALOG_CHAR_STAR_COUNT:
1644
#ifdef VERSION_EU
1645
render_star_count_dialog_text(dialog, &xMatrix);
1646
#else
1647
render_star_count_dialog_text(&xMatrix, &linePos);
1648
#endif
1649
break;
1650
#ifdef VERSION_EU
1651
case DIALOG_CHAR_DOUBLE_LOW_QUOTE:
1652
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY + 8, 0xF6);
1653
gDialogX += gDialogCharWidths[0xF6];
1654
break;
1655
#endif
1656
default: // any other character
1657
#if defined(VERSION_JP) || defined(VERSION_SH)
1658
#ifdef VERSION_SH
1659
if (lineNum >= lowerBound && lineNum <= lowerBound + linesPerBox) {
1660
#endif
1661
if (linePos != 0) {
1662
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix * 10, 0, 0);
1663
}
1664
1665
render_generic_char(strChar);
1666
xMatrix = 1;
1667
linePos++;
1668
1669
if (mark != 0) {
1670
create_dl_translation_matrix(MENU_MTX_PUSH, 5.0f, 7.0f, 0);
1671
render_generic_char(mark + 0xEF);
1672
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
1673
mark = 0;
1674
}
1675
#ifdef VERSION_SH
1676
}
1677
#endif
1678
#elif defined(VERSION_US)
1679
if (lineNum >= lowerBound && lineNum <= lowerBound + linesPerBox) {
1680
if (linePos || xMatrix != 1) {
1681
create_dl_translation_matrix(
1682
MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE] * (xMatrix - 1)), 0, 0);
1683
}
1684
1685
render_generic_char(strChar);
1686
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[strChar]), 0, 0);
1687
xMatrix = 1;
1688
linePos++;
1689
}
1690
#else // VERSION_EU
1691
if (lineNum >= lowerBound && lineNum <= lowerBound + linesPerBox) {
1692
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, strChar);
1693
}
1694
gDialogX += gDialogCharWidths[strChar];
1695
#endif
1696
}
1697
1698
#if defined(VERSION_JP)
1699
if (linePos == 12) {
1700
if (str[strIdx + 1] == DIALOG_CHAR_PERIOD) {
1701
adjust_pos_and_print_period_char(&xMatrix, &linePos);
1702
strIdx++;
1703
}
1704
1705
if (str[strIdx + 1] == DIALOG_CHAR_COMMA) {
1706
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix * 10, 0, 0);
1707
render_generic_char(DIALOG_CHAR_COMMA);
1708
strIdx++;
1709
}
1710
1711
if (str[strIdx + 1] == DIALOG_CHAR_NEWLINE) {
1712
strIdx++;
1713
}
1714
1715
if (str[strIdx + 1] == DIALOG_CHAR_TERMINATOR) {
1716
pageState = DIALOG_PAGE_STATE_END;
1717
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
1718
break; // exit loop
1719
} else {
1720
lineNum++;
1721
handle_dialog_scroll_page_state(lineNum, totalLines, &pageState, &xMatrix, &linePos);
1722
}
1723
}
1724
#endif
1725
1726
strIdx++;
1727
}
1728
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
1729
1730
if (gDialogBoxState == DIALOG_STATE_VERTICAL) {
1731
if (pageState == DIALOG_PAGE_STATE_END) {
1732
gLastDialogPageStrPos = -1;
1733
} else {
1734
gLastDialogPageStrPos = strIdx;
1735
}
1736
}
1737
1738
gLastDialogLineNum = lineNum;
1739
}
1740
1741
#if defined(VERSION_JP) || defined(VERSION_SH)
1742
#define X_VAL4_1 50
1743
#define X_VAL4_2 25
1744
#define Y_VAL4_1 1
1745
#define Y_VAL4_2 20
1746
#else
1747
#define X_VAL4_1 56
1748
#define X_VAL4_2 47
1749
#define Y_VAL4_1 2
1750
#define Y_VAL4_2 16
1751
#endif
1752
1753
void render_dialog_triangle_choice(void) {
1754
if (gDialogBoxState == DIALOG_STATE_VERTICAL) {
1755
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &gDialogLineNum, 1, 2);
1756
}
1757
1758
create_dl_translation_matrix(MENU_MTX_NOPUSH, (gDialogLineNum * X_VAL4_1) - X_VAL4_2, Y_VAL4_1 - (gLastDialogLineNum * Y_VAL4_2), 0);
1759
1760
if (gDialogBoxType == DIALOG_TYPE_ROTATE) {
1761
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
1762
} else {
1763
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
1764
}
1765
1766
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
1767
}
1768
1769
#ifdef VERSION_EU
1770
#define X_VAL5 122.0f
1771
#define Y_VAL5_1 -16
1772
#define Y_VAL5_2 3
1773
#define X_Y_VAL6 0.5f
1774
#elif defined(VERSION_US)
1775
#define X_VAL5 118.0f
1776
#define Y_VAL5_1 -16
1777
#define Y_VAL5_2 5
1778
#define X_Y_VAL6 0.8f
1779
#elif defined(VERSION_JP) || defined(VERSION_SH)
1780
#define X_VAL5 123.0f
1781
#define Y_VAL5_1 -20
1782
#define Y_VAL5_2 2
1783
#define X_Y_VAL6 0.8f
1784
#endif
1785
1786
void render_dialog_string_color(s8 linesPerBox) {
1787
s32 timer = gGlobalTimer;
1788
1789
if (timer & 0x08) {
1790
return;
1791
}
1792
1793
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL5, (linesPerBox * Y_VAL5_1) + Y_VAL5_2, 0);
1794
create_dl_scale_matrix(MENU_MTX_NOPUSH, X_Y_VAL6, X_Y_VAL6, 1.0f);
1795
create_dl_rotation_matrix(MENU_MTX_NOPUSH, -DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f);
1796
1797
if (gDialogBoxType == DIALOG_TYPE_ROTATE) { // White Text
1798
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
1799
} else { // Black Text
1800
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
1801
}
1802
1803
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
1804
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
1805
}
1806
1807
void handle_special_dialog_text(s16 dialogID) { // dialog ID tables, in order
1808
// King Bob-omb (Start), Whomp (Start), King Bob-omb (throw him out), Eyerock (Start), Wiggler (Start)
1809
s16 dialogBossStart[] = { DIALOG_017, DIALOG_114, DIALOG_128, DIALOG_117, DIALOG_150 };
1810
// Koopa the Quick (BOB), Koopa the Quick (THI), Penguin Race, Fat Penguin Race (120 stars)
1811
s16 dialogRaceSound[] = { DIALOG_005, DIALOG_009, DIALOG_055, DIALOG_164 };
1812
// Red Switch, Green Switch, Blue Switch, 100 coins star, Bowser Red Coin Star
1813
s16 dialogStarSound[] = { DIALOG_010, DIALOG_011, DIALOG_012, DIALOG_013, DIALOG_014 };
1814
// King Bob-omb (Start), Whomp (Defeated), King Bob-omb (Defeated, missing in JP), Eyerock (Defeated), Wiggler (Defeated)
1815
#if BUGFIX_KING_BOB_OMB_FADE_MUSIC
1816
s16 dialogBossStop[] = { DIALOG_017, DIALOG_115, DIALOG_116, DIALOG_118, DIALOG_152 };
1817
#else
1818
//! @bug JP misses King Bob-omb defeated DIALOG_116, meaning that the boss music will still
1819
//! play after King Bob-omb is defeated until BOB loads it's music after the star cutscene
1820
s16 dialogBossStop[] = { DIALOG_017, DIALOG_115, DIALOG_118, DIALOG_152 };
1821
#endif
1822
s16 i;
1823
1824
for (i = 0; i < (s16) ARRAY_COUNT(dialogBossStart); i++) {
1825
if (dialogBossStart[i] == dialogID) {
1826
seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60);
1827
play_music(SEQ_PLAYER_LEVEL, SEQUENCE_ARGS(4, SEQ_EVENT_BOSS), 0);
1828
return;
1829
}
1830
}
1831
1832
for (i = 0; i < (s16) ARRAY_COUNT(dialogRaceSound); i++) {
1833
if (dialogRaceSound[i] == dialogID && gDialogLineNum == 1) {
1834
play_race_fanfare();
1835
return;
1836
}
1837
}
1838
1839
for (i = 0; i < (s16) ARRAY_COUNT(dialogStarSound); i++) {
1840
if (dialogStarSound[i] == dialogID && gDialogLineNum == 1) {
1841
play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
1842
return;
1843
}
1844
}
1845
1846
for (i = 0; i < (s16) ARRAY_COUNT(dialogBossStop); i++) {
1847
if (dialogBossStop[i] == dialogID) {
1848
seq_player_fade_out(SEQ_PLAYER_LEVEL, 1);
1849
return;
1850
}
1851
}
1852
}
1853
1854
s16 gMenuMode = MENU_MODE_NONE;
1855
1856
u8 gEndCutsceneStrEn0[] = { TEXT_FILE_MARIO_EXCLAMATION };
1857
u8 gEndCutsceneStrEn1[] = { TEXT_POWER_STARS_RESTORED };
1858
u8 gEndCutsceneStrEn2[] = { TEXT_THANKS_TO_YOU };
1859
u8 gEndCutsceneStrEn3[] = { TEXT_THANK_YOU_MARIO };
1860
u8 gEndCutsceneStrEn4[] = { TEXT_SOMETHING_SPECIAL };
1861
u8 gEndCutsceneStrEn5[] = { TEXT_LISTEN_EVERYBODY };
1862
u8 gEndCutsceneStrEn6[] = { TEXT_LETS_HAVE_CAKE };
1863
u8 gEndCutsceneStrEn7[] = { TEXT_FOR_MARIO };
1864
u8 gEndCutsceneStrEn8[] = { TEXT_FILE_MARIO_QUESTION };
1865
1866
u8 *gEndCutsceneStringsEn[] = {
1867
gEndCutsceneStrEn0,
1868
gEndCutsceneStrEn1,
1869
gEndCutsceneStrEn2,
1870
gEndCutsceneStrEn3,
1871
gEndCutsceneStrEn4,
1872
gEndCutsceneStrEn5,
1873
gEndCutsceneStrEn6,
1874
gEndCutsceneStrEn7,
1875
// This [8] string is actually unused. In the cutscene handler, the developers do not
1876
// set the 8th one, but use the first string again at the very end, so Peach ends up
1877
// saying "Mario!" twice. It is likely that she was originally meant to say "Mario?" at
1878
// the end but the developers changed their mind, possibly because the line recorded
1879
// sounded more like an exclamation than a question.
1880
gEndCutsceneStrEn8,
1881
NULL
1882
};
1883
1884
#ifdef VERSION_EU
1885
u8 gEndCutsceneStrFr0[] = { TEXT_FILE_MARIO_EXCLAMATION };
1886
u8 gEndCutsceneStrFr1[] = { TEXT_POWER_STARS_RESTORED_FR };
1887
u8 gEndCutsceneStrFr2[] = { TEXT_THANKS_TO_YOU_FR };
1888
u8 gEndCutsceneStrFr3[] = { TEXT_THANK_YOU_MARIO_FR };
1889
u8 gEndCutsceneStrFr4[] = { TEXT_SOMETHING_SPECIAL_FR };
1890
u8 gEndCutsceneStrFr5[] = { TEXT_COME_ON_EVERYBODY_FR };
1891
u8 gEndCutsceneStrFr6[] = { TEXT_LETS_HAVE_CAKE_FR };
1892
u8 gEndCutsceneStrFr7[] = { TEXT_FOR_MARIO_FR };
1893
u8 gEndCutsceneStrFr8[] = { TEXT_FILE_MARIO_QUESTION };
1894
1895
u8 *gEndCutsceneStringsFr[] = {
1896
gEndCutsceneStrFr0,
1897
gEndCutsceneStrFr1,
1898
gEndCutsceneStrFr2,
1899
gEndCutsceneStrFr3,
1900
gEndCutsceneStrFr4,
1901
gEndCutsceneStrFr5,
1902
gEndCutsceneStrFr6,
1903
gEndCutsceneStrFr7,
1904
gEndCutsceneStrFr8,
1905
NULL
1906
};
1907
1908
u8 gEndCutsceneStrDe0[] = { TEXT_FILE_MARIO_EXCLAMATION };
1909
u8 gEndCutsceneStrDe1[] = { TEXT_POWER_STARS_RESTORED_DE };
1910
u8 gEndCutsceneStrDe2[] = { TEXT_THANKS_TO_YOU_DE };
1911
u8 gEndCutsceneStrDe3[] = { TEXT_THANK_YOU_MARIO_DE };
1912
u8 gEndCutsceneStrDe4[] = { TEXT_SOMETHING_SPECIAL_DE };
1913
u8 gEndCutsceneStrDe5[] = { TEXT_COME_ON_EVERYBODY_DE };
1914
u8 gEndCutsceneStrDe6[] = { TEXT_LETS_HAVE_CAKE_DE };
1915
u8 gEndCutsceneStrDe7[] = { TEXT_FOR_MARIO_DE };
1916
u8 gEndCutsceneStrDe8[] = { TEXT_FILE_MARIO_QUESTION };
1917
1918
u8 *gEndCutsceneStringsDe[] = {
1919
gEndCutsceneStrDe0,
1920
gEndCutsceneStrDe1,
1921
gEndCutsceneStrDe2,
1922
gEndCutsceneStrDe3,
1923
gEndCutsceneStrDe4,
1924
gEndCutsceneStrDe5,
1925
gEndCutsceneStrDe6,
1926
gEndCutsceneStrDe7,
1927
gEndCutsceneStrDe8,
1928
NULL
1929
};
1930
#endif
1931
1932
u16 gCutsceneMsgFade = 0;
1933
s16 gCutsceneMsgIndex = -1;
1934
s16 gCutsceneMsgDuration = -1;
1935
s16 gCutsceneMsgTimer = 0;
1936
s8 gDialogCameraAngleIndex = CAM_SELECTION_MARIO;
1937
s8 gDialogCourseActNum = 1;
1938
1939
#if defined(VERSION_JP) || defined(VERSION_SH)
1940
#define DIAG_VAL1 20
1941
#define DIAG_VAL3 130
1942
#define DIAG_VAL4 4
1943
#else
1944
#define DIAG_VAL1 16
1945
#define DIAG_VAL3 132 // US & EU
1946
#define DIAG_VAL4 5
1947
#endif
1948
#ifdef VERSION_EU
1949
#define DIAG_VAL2 238
1950
#else
1951
#define DIAG_VAL2 240 // JP & US
1952
#endif
1953
1954
void render_dialog_entries(void) {
1955
#ifdef VERSION_EU
1956
s8 lowerBound;
1957
#endif
1958
void **dialogTable;
1959
struct DialogEntry *dialog;
1960
#if defined(VERSION_US) || defined(VERSION_SH)
1961
s8 lowerBound;
1962
#endif
1963
#ifdef VERSION_EU
1964
gInGameLanguage = eu_get_language();
1965
switch (gInGameLanguage) {
1966
case LANGUAGE_ENGLISH:
1967
dialogTable = segmented_to_virtual(dialog_table_eu_en);
1968
break;
1969
case LANGUAGE_FRENCH:
1970
dialogTable = segmented_to_virtual(dialog_table_eu_fr);
1971
break;
1972
case LANGUAGE_GERMAN:
1973
dialogTable = segmented_to_virtual(dialog_table_eu_de);
1974
break;
1975
}
1976
#else
1977
dialogTable = segmented_to_virtual(seg2_dialog_table);
1978
#endif
1979
dialog = segmented_to_virtual(dialogTable[gDialogID]);
1980
1981
// if the dialog entry is invalid, set the ID to -1.
1982
if (segmented_to_virtual(NULL) == dialog) {
1983
gDialogID = DIALOG_NONE;
1984
return;
1985
}
1986
1987
#ifdef VERSION_EU
1988
gDialogX = 0;
1989
gDialogY = 0;
1990
#endif
1991
1992
switch (gDialogBoxState) {
1993
case DIALOG_STATE_OPENING:
1994
if (gDialogBoxOpenTimer == DEFAULT_DIALOG_BOX_ANGLE) {
1995
play_dialog_sound(gDialogID);
1996
play_sound(SOUND_MENU_MESSAGE_APPEAR, gGlobalSoundSource);
1997
}
1998
1999
if (gDialogBoxType == DIALOG_TYPE_ROTATE) {
2000
gDialogBoxOpenTimer -= 7.5;
2001
gDialogBoxScale -= 1.5;
2002
} else {
2003
gDialogBoxOpenTimer -= 10.0;
2004
gDialogBoxScale -= 2.0;
2005
}
2006
2007
if (gDialogBoxOpenTimer == 0.0f) {
2008
gDialogBoxState = DIALOG_STATE_VERTICAL;
2009
gDialogLineNum = 1;
2010
}
2011
#if !defined(VERSION_JP)
2012
lowerBound = 1;
2013
#endif
2014
break;
2015
case DIALOG_STATE_VERTICAL:
2016
gDialogBoxOpenTimer = 0.0f;
2017
2018
if ((gPlayer3Controller->buttonPressed & A_BUTTON)
2019
|| (gPlayer3Controller->buttonPressed & B_BUTTON)) {
2020
if (gLastDialogPageStrPos == -1) {
2021
handle_special_dialog_text(gDialogID);
2022
gDialogBoxState = DIALOG_STATE_CLOSING;
2023
} else {
2024
gDialogBoxState = DIALOG_STATE_HORIZONTAL;
2025
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, gGlobalSoundSource);
2026
}
2027
}
2028
#if !defined(VERSION_JP)
2029
lowerBound = 1;
2030
#endif
2031
break;
2032
case DIALOG_STATE_HORIZONTAL:
2033
gDialogScrollOffsetY += dialog->linesPerBox * 2;
2034
2035
if (gDialogScrollOffsetY >= dialog->linesPerBox * DIAG_VAL1) {
2036
gDialogTextPos = gLastDialogPageStrPos;
2037
gDialogBoxState = DIALOG_STATE_VERTICAL;
2038
gDialogScrollOffsetY = 0;
2039
}
2040
#if !defined(VERSION_JP)
2041
lowerBound = (gDialogScrollOffsetY / DIAG_VAL1) + 1;
2042
#endif
2043
break;
2044
case DIALOG_STATE_CLOSING:
2045
if (gDialogBoxOpenTimer == 20.0f) {
2046
level_set_transition(0, NULL);
2047
play_sound(SOUND_MENU_MESSAGE_DISAPPEAR, gGlobalSoundSource);
2048
2049
if (gDialogBoxType == DIALOG_TYPE_ZOOM) {
2050
trigger_cutscene_dialog(2);
2051
}
2052
2053
gDialogResponse = gDialogLineNum;
2054
}
2055
2056
gDialogBoxOpenTimer = gDialogBoxOpenTimer + 10.0f;
2057
gDialogBoxScale = gDialogBoxScale + 2.0f;
2058
2059
if (gDialogBoxOpenTimer == DEFAULT_DIALOG_BOX_ANGLE) {
2060
gDialogBoxState = DIALOG_STATE_OPENING;
2061
gDialogID = DIALOG_NONE;
2062
gDialogTextPos = 0;
2063
gLastDialogResponse = 0;
2064
gLastDialogPageStrPos = 0;
2065
gDialogResponse = DIALOG_RESPONSE_NONE;
2066
}
2067
#if !defined(VERSION_JP)
2068
lowerBound = 1;
2069
#endif
2070
break;
2071
}
2072
2073
render_dialog_box_type(dialog, dialog->linesPerBox);
2074
2075
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE,
2076
// Horizontal scissoring isn't really required and can potentially mess up widescreen enhancements.
2077
#ifdef WIDESCREEN
2078
0,
2079
#else
2080
ensure_nonnegative(dialog->leftOffset),
2081
#endif
2082
ensure_nonnegative(DIAG_VAL2 - dialog->width),
2083
#ifdef VERSION_EU
2084
#ifdef WIDESCREEN
2085
SCREEN_WIDTH,
2086
#else
2087
ensure_nonnegative(dialog->leftOffset + DIAG_VAL3 / gDialogBoxScale),
2088
#endif
2089
ensure_nonnegative((240 - dialog->width) + ((dialog->linesPerBox * 80) / DIAG_VAL4) / gDialogBoxScale));
2090
#else
2091
#ifdef WIDESCREEN
2092
SCREEN_WIDTH,
2093
#else
2094
ensure_nonnegative(DIAG_VAL3 + dialog->leftOffset),
2095
#endif
2096
ensure_nonnegative(240 + ((dialog->linesPerBox * 80) / DIAG_VAL4) - dialog->width));
2097
#endif
2098
#if defined(VERSION_JP)
2099
handle_dialog_text_and_pages(0, dialog);
2100
#else
2101
handle_dialog_text_and_pages(0, dialog, lowerBound);
2102
#endif
2103
2104
if (gLastDialogPageStrPos == -1 && gLastDialogResponse == 1) {
2105
render_dialog_triangle_choice();
2106
}
2107
#ifdef VERSION_EU
2108
#undef BORDER_HEIGHT
2109
#define BORDER_HEIGHT 8
2110
#endif
2111
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 2, 2, SCREEN_WIDTH - BORDER_HEIGHT/2, SCREEN_HEIGHT - BORDER_HEIGHT/2);
2112
#ifdef VERSION_EU
2113
#undef BORDER_HEIGHT
2114
#define BORDER_HEIGHT 1
2115
#endif
2116
if (gLastDialogPageStrPos != -1 && gDialogBoxState == DIALOG_STATE_VERTICAL) {
2117
render_dialog_string_color(dialog->linesPerBox);
2118
}
2119
}
2120
2121
// Calls a gMenuMode value defined by render_menus_and_dialogs cases
2122
void set_menu_mode(s16 mode) {
2123
if (gMenuMode == MENU_MODE_NONE) {
2124
gMenuMode = mode;
2125
}
2126
}
2127
2128
void reset_cutscene_msg_fade(void) {
2129
gCutsceneMsgFade = 0;
2130
}
2131
2132
void dl_rgba16_begin_cutscene_msg_fade(void) {
2133
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
2134
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gCutsceneMsgFade);
2135
}
2136
2137
void dl_rgba16_stop_cutscene_msg_fade(void) {
2138
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
2139
2140
if (gCutsceneMsgFade < 250) {
2141
gCutsceneMsgFade += 25;
2142
} else {
2143
gCutsceneMsgFade = 255;
2144
}
2145
}
2146
2147
u8 ascii_to_credits_char(u8 c) {
2148
if (c >= 'A' && c <= 'Z') {
2149
return (c - ('A' - 0xA));
2150
}
2151
2152
if (c >= 'a' && c <= 'z') { // remap lower to upper case
2153
return (c - ('a' - 0xA));
2154
}
2155
2156
if (c == ' ') {
2157
return GLOBAL_CHAR_SPACE;
2158
}
2159
if (c == '.') {
2160
return 0x24;
2161
}
2162
if (c == '3') {
2163
return ASCII_TO_DIALOG('3');
2164
}
2165
if (c == '4') {
2166
return ASCII_TO_DIALOG('4');
2167
}
2168
if (c == '6') {
2169
return ASCII_TO_DIALOG('6');
2170
}
2171
2172
return GLOBAL_CHAR_SPACE;
2173
}
2174
2175
void print_credits_str_ascii(s16 x, s16 y, const char *str) {
2176
s32 pos = 0;
2177
u8 c = str[pos];
2178
u8 creditStr[100];
2179
2180
while (c != 0) {
2181
creditStr[pos++] = ascii_to_credits_char(c);
2182
c = str[pos];
2183
}
2184
2185
creditStr[pos] = GLOBAR_CHAR_TERMINATOR;
2186
2187
print_credits_string(x, y, creditStr);
2188
}
2189
2190
void set_cutscene_message(s16 xOffset, s16 yOffset, s16 msgIndex, s16 msgDuration) {
2191
// is message done printing?
2192
if (gCutsceneMsgIndex == -1) {
2193
gCutsceneMsgIndex = msgIndex;
2194
gCutsceneMsgDuration = msgDuration;
2195
gCutsceneMsgTimer = 0;
2196
gCutsceneMsgXOffset = xOffset;
2197
gCutsceneMsgYOffset = yOffset;
2198
gCutsceneMsgFade = 0;
2199
}
2200
}
2201
2202
void do_cutscene_handler(void) {
2203
s16 x;
2204
2205
// is a cutscene playing? do not perform this handler's actions if so.
2206
if (gCutsceneMsgIndex == -1) {
2207
return;
2208
}
2209
2210
create_dl_ortho_matrix();
2211
2212
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2213
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gCutsceneMsgFade);
2214
2215
#ifdef VERSION_EU
2216
switch (eu_get_language()) {
2217
case LANGUAGE_ENGLISH:
2218
x = get_str_x_pos_from_center(gCutsceneMsgXOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex], 10.0f);
2219
print_generic_string(x, 240 - gCutsceneMsgYOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex]);
2220
break;
2221
case LANGUAGE_FRENCH:
2222
x = get_str_x_pos_from_center(gCutsceneMsgXOffset, gEndCutsceneStringsFr[gCutsceneMsgIndex], 10.0f);
2223
print_generic_string(x, 240 - gCutsceneMsgYOffset, gEndCutsceneStringsFr[gCutsceneMsgIndex]);
2224
break;
2225
case LANGUAGE_GERMAN:
2226
x = get_str_x_pos_from_center(gCutsceneMsgXOffset, gEndCutsceneStringsDe[gCutsceneMsgIndex], 10.0f);
2227
print_generic_string(x, 240 - gCutsceneMsgYOffset, gEndCutsceneStringsDe[gCutsceneMsgIndex]);
2228
break;
2229
}
2230
#else
2231
// get the x coordinate of where the cutscene string starts.
2232
x = get_str_x_pos_from_center(gCutsceneMsgXOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex], 10.0f);
2233
print_generic_string(x, 240 - gCutsceneMsgYOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex]);
2234
#endif
2235
2236
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2237
2238
// if the timing variable is less than 5, increment
2239
// the fade until we are at full opacity.
2240
if (gCutsceneMsgTimer < 5) {
2241
gCutsceneMsgFade += 50;
2242
}
2243
2244
// if the cutscene frame length + the fade-in counter is
2245
// less than the timer, it means we have exceeded the
2246
// time that the message is supposed to remain on
2247
// screen. if (message_duration = 50) and (msg_timer = 55)
2248
// then after the first 5 frames, the message will remain
2249
// on screen for another 50 frames until it starts fading.
2250
if (gCutsceneMsgDuration + 5 < gCutsceneMsgTimer) {
2251
gCutsceneMsgFade -= 50;
2252
}
2253
2254
// like the first check, it takes 5 frames to fade out, so
2255
// perform a + 10 to account for the earlier check (10-5=5).
2256
if (gCutsceneMsgDuration + 10 < gCutsceneMsgTimer) {
2257
gCutsceneMsgIndex = -1;
2258
gCutsceneMsgFade = 0;
2259
gCutsceneMsgTimer = 0;
2260
return;
2261
}
2262
2263
gCutsceneMsgTimer++;
2264
}
2265
2266
#ifdef VERSION_JP
2267
#define PEACH_MESSAGE_TIMER 170
2268
#else
2269
#define PEACH_MESSAGE_TIMER 250
2270
#endif
2271
2272
#if defined(VERSION_JP) || defined(VERSION_SH)
2273
#define STR_X 53
2274
#define STR_Y 136
2275
#else
2276
#define STR_X 38
2277
#define STR_Y 142
2278
#endif
2279
2280
// "Dear Mario" message handler
2281
void print_peach_letter_message(void) {
2282
void **dialogTable;
2283
struct DialogEntry *dialog;
2284
u8 *str;
2285
#ifdef VERSION_EU
2286
gInGameLanguage = eu_get_language();
2287
switch (gInGameLanguage) {
2288
case LANGUAGE_ENGLISH:
2289
dialogTable = segmented_to_virtual(dialog_table_eu_en);
2290
break;
2291
case LANGUAGE_FRENCH:
2292
dialogTable = segmented_to_virtual(dialog_table_eu_fr);
2293
break;
2294
case LANGUAGE_GERMAN:
2295
dialogTable = segmented_to_virtual(dialog_table_eu_de);
2296
break;
2297
}
2298
#else
2299
dialogTable = segmented_to_virtual(seg2_dialog_table);
2300
#endif
2301
dialog = segmented_to_virtual(dialogTable[gDialogID]);
2302
2303
str = segmented_to_virtual(dialog->str);
2304
2305
create_dl_translation_matrix(MENU_MTX_PUSH, 97.0f, 118.0f, 0);
2306
2307
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gCutsceneMsgFade);
2308
gSPDisplayList(gDisplayListHead++, castle_grounds_seg7_dl_0700EA58);
2309
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2310
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2311
gDPSetEnvColor(gDisplayListHead++, 20, 20, 20, gCutsceneMsgFade);
2312
2313
print_generic_string(STR_X, STR_Y, str);
2314
#if defined(VERSION_JP)
2315
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2316
#endif
2317
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
2318
#ifndef VERSION_JP
2319
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2320
gDPSetEnvColor(gDisplayListHead++, 200, 80, 120, gCutsceneMsgFade);
2321
gSPDisplayList(gDisplayListHead++, castle_grounds_seg7_us_dl_0700F2E8);
2322
#endif
2323
2324
// at the start/end of message, reset the fade.
2325
if (gCutsceneMsgTimer == 0) {
2326
gCutsceneMsgFade = 0;
2327
}
2328
2329
// we're less than 20 increments, so increase the fade.
2330
if (gCutsceneMsgTimer < 20) {
2331
gCutsceneMsgFade += 10;
2332
}
2333
2334
// we're after PEACH_MESSAGE_TIMER increments, so decrease the fade.
2335
if (gCutsceneMsgTimer > PEACH_MESSAGE_TIMER) {
2336
gCutsceneMsgFade -= 10;
2337
}
2338
2339
// 20 increments after the start of the decrease, we're
2340
// back where we are, so reset everything at the end.
2341
if (gCutsceneMsgTimer > (PEACH_MESSAGE_TIMER + 20)) {
2342
gCutsceneMsgIndex = -1;
2343
gCutsceneMsgFade = 0; //! uselessly reset since the next execution will just set it to 0 again.
2344
gDialogID = DIALOG_NONE;
2345
gCutsceneMsgTimer = 0;
2346
return; // return to avoid incrementing the timer
2347
}
2348
2349
gCutsceneMsgTimer++;
2350
}
2351
2352
/**
2353
* Renders the cannon reticle when Mario is inside a cannon.
2354
* Formed by four triangles.
2355
*/
2356
void render_hud_cannon_reticle(void) {
2357
create_dl_translation_matrix(MENU_MTX_PUSH, 160.0f, 120.0f, 0);
2358
2359
gDPSetEnvColor(gDisplayListHead++, 50, 50, 50, 180);
2360
create_dl_translation_matrix(MENU_MTX_PUSH, -20.0f, -8.0f, 0);
2361
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
2362
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2363
2364
create_dl_translation_matrix(MENU_MTX_PUSH, 20.0f, 8.0f, 0);
2365
create_dl_rotation_matrix(MENU_MTX_NOPUSH, 180.0f, 0, 0, 1.0f);
2366
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
2367
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2368
2369
create_dl_translation_matrix(MENU_MTX_PUSH, 8.0f, -20.0f, 0);
2370
create_dl_rotation_matrix(MENU_MTX_NOPUSH, DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f);
2371
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
2372
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2373
2374
create_dl_translation_matrix(MENU_MTX_PUSH, -8.0f, 20.0f, 0);
2375
create_dl_rotation_matrix(MENU_MTX_NOPUSH, -DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f);
2376
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
2377
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2378
2379
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2380
}
2381
2382
void reset_red_coins_collected(void) {
2383
gRedCoinsCollected = 0;
2384
}
2385
2386
void change_dialog_camera_angle(void) {
2387
if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) {
2388
gDialogCameraAngleIndex = CAM_SELECTION_MARIO;
2389
} else {
2390
gDialogCameraAngleIndex = CAM_SELECTION_FIXED;
2391
}
2392
}
2393
2394
void shade_screen(void) {
2395
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), SCREEN_HEIGHT, 0);
2396
2397
// This is a bit weird. It reuses the dialog text box (width 130, height -80),
2398
// so scale to at least fit the screen.
2399
#ifndef WIDESCREEN
2400
create_dl_scale_matrix(MENU_MTX_NOPUSH, 2.6f, 3.4f, 1.0f);
2401
#else
2402
create_dl_scale_matrix(MENU_MTX_NOPUSH,
2403
GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT / 130.0f, 3.0f, 1.0f);
2404
#endif
2405
2406
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 110);
2407
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
2408
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2409
}
2410
2411
void print_animated_red_coin(s16 x, s16 y) {
2412
s32 timer = gGlobalTimer;
2413
2414
create_dl_translation_matrix(MENU_MTX_PUSH, x, y, 0);
2415
create_dl_scale_matrix(MENU_MTX_NOPUSH, 0.2f, 0.2f, 1.0f);
2416
gDPSetRenderMode(gDisplayListHead++, G_RM_TEX_EDGE, G_RM_TEX_EDGE2);
2417
2418
switch (timer & 6) {
2419
case 0:
2420
gSPDisplayList(gDisplayListHead++, coin_seg3_dl_03007940);
2421
break;
2422
case 2:
2423
gSPDisplayList(gDisplayListHead++, coin_seg3_dl_03007968);
2424
break;
2425
case 4:
2426
gSPDisplayList(gDisplayListHead++, coin_seg3_dl_03007990);
2427
break;
2428
case 6:
2429
gSPDisplayList(gDisplayListHead++, coin_seg3_dl_030079B8);
2430
break;
2431
}
2432
2433
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
2434
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2435
}
2436
2437
void render_pause_red_coins(void) {
2438
s8 x;
2439
2440
for (x = 0; x < gRedCoinsCollected; x++) {
2441
print_animated_red_coin(GFX_DIMENSIONS_FROM_RIGHT_EDGE(30) - x * 20, 16);
2442
}
2443
}
2444
2445
void render_pause_exit_text() {
2446
u8 textExitGameR[] = { TEXT_EXIT_GAME_ZR };
2447
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2448
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2449
print_generic_string(GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(12), 8, textExitGameR);
2450
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2451
2452
if ((gPlayer1Controller->buttonDown & Z_TRIG) && (gPlayer1Controller->buttonDown & R_TRIG)) {
2453
exit(0);
2454
}
2455
}
2456
2457
#ifdef VERSION_EU
2458
u8 gTextCourseArr[][7] = {
2459
{ TEXT_COURSE },
2460
{ TEXT_COURSE_FR },
2461
{ TEXT_COURSE_DE }
2462
};
2463
#endif
2464
2465
#if defined(VERSION_JP) || defined(VERSION_SH)
2466
#define CRS_NUM_X1 93
2467
#else
2468
#define CRS_NUM_X1 100
2469
#endif
2470
#ifdef VERSION_EU
2471
#define TXT_STAR_X 89
2472
#define ACT_NAME_X 107
2473
#define LVL_NAME_X 108
2474
#define MYSCORE_X 48
2475
#else
2476
#define TXT_STAR_X 98
2477
#define ACT_NAME_X 116
2478
#define LVL_NAME_X 117
2479
#define MYSCORE_X 62
2480
#endif
2481
2482
void render_pause_my_score_coins(void) {
2483
#ifdef VERSION_EU
2484
u8 textMyScore[][10] = {
2485
{ TEXT_MY_SCORE },
2486
{ TEXT_MY_SCORE_FR },
2487
{ TEXT_MY_SCORE_DE }
2488
};
2489
#define textMyScore textMyScore[gInGameLanguage]
2490
#else
2491
u8 textCourse[] = { TEXT_COURSE };
2492
u8 textMyScore[] = { TEXT_MY_SCORE };
2493
#endif
2494
u8 textStar[] = { TEXT_STAR };
2495
u8 textUnfilledStar[] = { TEXT_UNFILLED_STAR };
2496
2497
u8 strCourseNum[4];
2498
void **courseNameTbl;
2499
u8 *courseName;
2500
void **actNameTbl;
2501
u8 *actName;
2502
u8 courseIndex;
2503
u8 starFlags;
2504
2505
#ifndef VERSION_EU
2506
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
2507
actNameTbl = segmented_to_virtual(seg2_act_name_table);
2508
#endif
2509
2510
courseIndex = gCurrCourseNum - 1;
2511
starFlags = save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1);
2512
2513
#ifdef VERSION_EU
2514
switch (gInGameLanguage) {
2515
case LANGUAGE_ENGLISH:
2516
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
2517
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
2518
break;
2519
case LANGUAGE_FRENCH:
2520
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
2521
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
2522
break;
2523
case LANGUAGE_GERMAN:
2524
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
2525
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
2526
break;
2527
}
2528
#endif
2529
2530
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
2531
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2532
2533
if (courseIndex < COURSE_STAGES_COUNT) {
2534
print_hud_my_score_coins(1, gCurrSaveFileNum - 1, courseIndex, 178, 103);
2535
print_hud_my_score_stars(gCurrSaveFileNum - 1, courseIndex, 118, 103);
2536
}
2537
2538
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
2539
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2540
2541
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2542
2543
if (courseIndex < COURSE_STAGES_COUNT && save_file_get_course_star_count(gCurrSaveFileNum - 1, courseIndex) != 0) {
2544
print_generic_string(MYSCORE_X, 121, textMyScore);
2545
}
2546
2547
courseName = segmented_to_virtual(courseNameTbl[courseIndex]);
2548
2549
if (courseIndex < COURSE_STAGES_COUNT) {
2550
#ifdef VERSION_EU
2551
print_generic_string(48, 157, gTextCourseArr[gInGameLanguage]);
2552
#else
2553
print_generic_string(63, 157, textCourse);
2554
#endif
2555
int_to_str(gCurrCourseNum, strCourseNum);
2556
#ifdef VERSION_EU
2557
print_generic_string(get_string_width(gTextCourseArr[gInGameLanguage]) + 51, 157, strCourseNum);
2558
#else
2559
print_generic_string(CRS_NUM_X1, 157, strCourseNum);
2560
#endif
2561
2562
actName = segmented_to_virtual(actNameTbl[(gCurrCourseNum - 1) * 6 + gDialogCourseActNum - 1]);
2563
2564
if (starFlags & (1 << (gDialogCourseActNum - 1))) {
2565
print_generic_string(TXT_STAR_X, 140, textStar);
2566
} else {
2567
print_generic_string(TXT_STAR_X, 140, textUnfilledStar);
2568
}
2569
print_generic_string(ACT_NAME_X, 140, actName);
2570
#ifndef VERSION_JP
2571
print_generic_string(LVL_NAME_X, 157, &courseName[3]);
2572
#endif
2573
}
2574
#ifndef VERSION_JP
2575
else {
2576
#if defined(VERSION_US) || defined(VERSION_SH)
2577
print_generic_string(94, 157, &courseName[3]);
2578
#elif defined(VERSION_EU)
2579
print_generic_string(get_str_x_pos_from_center(159, &courseName[3], 10.0f), 157, &courseName[3]);
2580
#endif
2581
}
2582
#else
2583
print_generic_string(117, 157, &courseName[3]);
2584
#endif
2585
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2586
}
2587
2588
#if defined(VERSION_JP) || defined(VERSION_SH)
2589
#define TXT1_X 4
2590
#define TXT2_X 116
2591
#define Y_VAL7 0
2592
#else
2593
#define TXT1_X 3
2594
#define TXT2_X 119
2595
#define Y_VAL7 2
2596
#endif
2597
2598
void render_pause_camera_options(s16 x, s16 y, s8 *index, s16 xIndex) {
2599
u8 textLakituMario[] = { TEXT_LAKITU_MARIO };
2600
u8 textLakituStop[] = { TEXT_LAKITU_STOP };
2601
2602
u8 textDefaultAlternate[] = { TEXT_DEFAULT_ALTERNATE };
2603
u8 textDefaultStop[] = { TEXT_DEFAULT_STOP };
2604
#ifdef VERSION_EU
2605
u8 textNormalUpClose[][20] = {
2606
{ TEXT_NORMAL_UPCLOSE },
2607
{ TEXT_NORMAL_UPCLOSE_FR },
2608
{ TEXT_NORMAL_UPCLOSE_DE }
2609
};
2610
u8 textNormalFixed[][17] = {
2611
{ TEXT_NORMAL_FIXED },
2612
{ TEXT_NORMAL_FIXED_FR },
2613
{ TEXT_NORMAL_FIXED_DE },
2614
};
2615
#define textNormalUpClose textNormalUpClose[gInGameLanguage]
2616
#define textNormalFixed textNormalFixed[gInGameLanguage]
2617
#else
2618
u8 textNormalUpClose[] = { TEXT_NORMAL_UPCLOSE };
2619
u8 textNormalFixed[] = { TEXT_NORMAL_FIXED };
2620
#endif
2621
2622
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, index, 1, 2);
2623
2624
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2625
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2626
2627
s8 defaultConfig = configDefaultCameraMode == 0 && configDefaultCameraMode == 1;
2628
2629
print_generic_string(x + 14, y + 2, defaultConfig ? textLakituMario : textDefaultAlternate);
2630
if (defaultConfig)
2631
print_generic_string(x + TXT1_X, y - 13, textNormalUpClose);
2632
print_generic_string(x + 124, y + 2, defaultConfig ? textLakituStop : textDefaultStop);
2633
if (defaultConfig)
2634
print_generic_string(x + TXT2_X, y - 13, textNormalFixed);
2635
2636
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2637
create_dl_translation_matrix(MENU_MTX_PUSH, ((*index - 1) * xIndex) + x, y + Y_VAL7, 0);
2638
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2639
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
2640
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2641
2642
switch (*index) {
2643
case CAM_SELECTION_MARIO:
2644
cam_select_alt_mode(CAM_SELECTION_MARIO);
2645
break;
2646
case CAM_SELECTION_FIXED:
2647
cam_select_alt_mode(CAM_SELECTION_FIXED);
2648
break;
2649
}
2650
}
2651
2652
#if defined(VERSION_JP) || defined(VERSION_SH)
2653
#define X_VAL8 0
2654
#define Y_VAL8 4
2655
#else
2656
#define X_VAL8 4
2657
#define Y_VAL8 2
2658
#endif
2659
2660
void render_pause_course_options(s16 x, s16 y, s8 *index, s16 yIndex) {
2661
#ifdef VERSION_EU
2662
u8 textContinue[][10] = {
2663
{ TEXT_CONTINUE },
2664
{ TEXT_CONTINUE_FR },
2665
{ TEXT_CONTINUE_DE }
2666
};
2667
u8 textExitCourse[][15] = {
2668
{ TEXT_EXIT_COURSE },
2669
{ TEXT_EXIT_COURSE_FR },
2670
{ TEXT_EXIT_COURSE_DE }
2671
};
2672
u8 textCameraAngleR[][24] = {
2673
{ TEXT_CAMERA_ANGLE_R },
2674
{ TEXT_CAMERA_ANGLE_R_FR },
2675
{ TEXT_CAMERA_ANGLE_R_DE }
2676
};
2677
#define textContinue textContinue[gInGameLanguage]
2678
#define textExitCourse textExitCourse[gInGameLanguage]
2679
#define textCameraAngleR textCameraAngleR[gInGameLanguage]
2680
#else
2681
u8 textContinue[] = { TEXT_CONTINUE };
2682
u8 textExitCourse[] = { TEXT_EXIT_COURSE };
2683
u8 textCameraAngleR[] = { TEXT_CAMERA_ANGLE_R };
2684
u8 textExitGame[] = { TEXT_EXIT_GAME };
2685
#endif
2686
2687
if (configQuitOption)
2688
handle_menu_scrolling(MENU_SCROLL_VERTICAL, index, 1, 4);
2689
else
2690
handle_menu_scrolling(MENU_SCROLL_VERTICAL, index, 1, 3);
2691
2692
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2693
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2694
2695
print_generic_string(x + 10, y - 2, textContinue);
2696
print_generic_string(x + 10, y - 17, textExitCourse);
2697
2698
if (((!configQuitOption) && (*index != MENU_OPT_CAMERA_ANGLE_R)) || (configQuitOption && (*index != MENU_OPT_QUIT))) {
2699
if (configQuitOption) {
2700
print_generic_string(x + 10, y - 33, textExitGame);
2701
print_generic_string(x + 10, y - 49, textCameraAngleR);
2702
}
2703
else {
2704
print_generic_string(x + 10, y - 33, textCameraAngleR);
2705
}
2706
2707
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2708
2709
create_dl_translation_matrix(MENU_MTX_PUSH, x - X_VAL8, (y - ((*index - 1) * yIndex)) - Y_VAL8, 0);
2710
2711
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2712
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
2713
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2714
}
2715
2716
if ((!configQuitOption) && (*index == MENU_OPT_CAMERA_ANGLE_R)) {
2717
render_pause_camera_options(x - 42, y - 42, &gDialogCameraAngleIndex, 110);
2718
}
2719
if (configQuitOption && (*index == MENU_OPT_QUIT)) {
2720
print_generic_string(x + 10, y - 33, textExitGame);
2721
render_pause_camera_options(x - 42, y - 50, &gDialogCameraAngleIndex, 110);
2722
}
2723
}
2724
2725
void render_pause_castle_menu_box(s16 x, s16 y) {
2726
create_dl_translation_matrix(MENU_MTX_PUSH, x - 78, y - 32, 0);
2727
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.2f, 0.8f, 1.0f);
2728
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 105);
2729
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
2730
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2731
2732
create_dl_translation_matrix(MENU_MTX_PUSH, x + 6, y - 28, 0);
2733
create_dl_rotation_matrix(MENU_MTX_NOPUSH, DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f);
2734
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2735
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
2736
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2737
2738
create_dl_translation_matrix(MENU_MTX_PUSH, x - 9, y - 101, 0);
2739
create_dl_rotation_matrix(MENU_MTX_NOPUSH, 270.0f, 0, 0, 1.0f);
2740
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
2741
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2742
}
2743
2744
void highlight_last_course_complete_stars(void) {
2745
u8 courseDone;
2746
2747
if (gLastCompletedCourseNum == COURSE_NONE) {
2748
courseDone = 0;
2749
} else {
2750
courseDone = gLastCompletedCourseNum - 1;
2751
2752
if (courseDone >= COURSE_STAGES_COUNT) {
2753
courseDone = COURSE_STAGES_COUNT;
2754
}
2755
}
2756
2757
gDialogLineNum = courseDone;
2758
}
2759
2760
void print_hud_pause_colorful_str(void) {
2761
u8 textPause[] = { TEXT_PAUSE };
2762
2763
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
2764
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2765
2766
#ifdef VERSION_EU
2767
print_hud_lut_string(HUD_LUT_GLOBAL, get_str_x_pos_from_center_scale(
2768
SCREEN_WIDTH / 2, textPause, 12.0f), 81, textPause);
2769
#else
2770
print_hud_lut_string(HUD_LUT_GLOBAL, 123, 81, textPause);
2771
#endif
2772
2773
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
2774
}
2775
2776
void render_pause_castle_course_stars(s16 x, s16 y, s16 fileNum, s16 courseNum) {
2777
s16 hasStar = 0;
2778
2779
u8 str[COURSE_STAGES_COUNT * 2];
2780
2781
u8 textStar[] = { TEXT_STAR };
2782
2783
u8 starFlags = save_file_get_star_flags(fileNum, courseNum);
2784
u16 starCount = save_file_get_course_star_count(fileNum, courseNum);
2785
2786
u16 nextStar = 0;
2787
2788
if (starFlags & 0x40) {
2789
starCount--;
2790
print_generic_string(x + 89, y - 5, textStar);
2791
}
2792
2793
while (hasStar != starCount) {
2794
if (starFlags & (1 << nextStar)) {
2795
str[nextStar * 2] = DIALOG_CHAR_STAR_FILLED;
2796
hasStar++;
2797
} else {
2798
str[nextStar * 2] = DIALOG_CHAR_STAR_OPEN;
2799
}
2800
2801
str[nextStar * 2 + 1] = DIALOG_CHAR_SPACE;
2802
nextStar++;
2803
}
2804
2805
if (starCount == nextStar && starCount != 6) {
2806
str[nextStar * 2] = DIALOG_CHAR_STAR_OPEN;
2807
str[nextStar * 2 + 1] = DIALOG_CHAR_SPACE;
2808
nextStar++;
2809
}
2810
2811
str[nextStar * 2] = DIALOG_CHAR_TERMINATOR;
2812
2813
print_generic_string(x + 14, y + 13, str);
2814
}
2815
2816
void render_pause_castle_main_strings(s16 x, s16 y) {
2817
#ifdef VERSION_EU
2818
void **courseNameTbl;
2819
#else
2820
void **courseNameTbl = segmented_to_virtual(seg2_course_name_table);
2821
#endif
2822
2823
#ifdef VERSION_EU
2824
u8 textCoin[] = { TEXT_COIN };
2825
u8 textX[] = { TEXT_VARIABLE_X };
2826
#else
2827
u8 textCoin[] = { TEXT_COIN_X };
2828
#endif
2829
2830
void *courseName;
2831
2832
u8 strVal[8];
2833
s16 starNum = gDialogLineNum;
2834
2835
#ifdef VERSION_EU
2836
switch (gInGameLanguage) {
2837
case LANGUAGE_ENGLISH:
2838
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
2839
break;
2840
case LANGUAGE_FRENCH:
2841
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
2842
break;
2843
case LANGUAGE_GERMAN:
2844
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
2845
break;
2846
}
2847
#endif
2848
2849
handle_menu_scrolling(MENU_SCROLL_VERTICAL, &gDialogLineNum, -1, COURSE_STAGES_COUNT + 1);
2850
2851
if (gDialogLineNum == COURSE_STAGES_COUNT + 1) {
2852
gDialogLineNum = 0;
2853
}
2854
2855
if (gDialogLineNum == -1) {
2856
gDialogLineNum = COURSE_STAGES_COUNT;
2857
}
2858
2859
if (gDialogLineNum != COURSE_STAGES_COUNT) {
2860
while (save_file_get_course_star_count(gCurrSaveFileNum - 1, gDialogLineNum) == 0) {
2861
if (gDialogLineNum >= starNum) {
2862
gDialogLineNum++;
2863
} else {
2864
gDialogLineNum--;
2865
}
2866
2867
if (gDialogLineNum == COURSE_STAGES_COUNT || gDialogLineNum == -1) {
2868
gDialogLineNum = COURSE_STAGES_COUNT;
2869
break;
2870
}
2871
}
2872
}
2873
2874
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2875
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2876
2877
if (gDialogLineNum < COURSE_STAGES_COUNT) {
2878
courseName = segmented_to_virtual(courseNameTbl[gDialogLineNum]);
2879
render_pause_castle_course_stars(x, y, gCurrSaveFileNum - 1, gDialogLineNum);
2880
print_generic_string(x + 34, y - 5, textCoin);
2881
#ifdef VERSION_EU
2882
print_generic_string(x + 44, y - 5, textX);
2883
#endif
2884
int_to_str(save_file_get_course_coin_score(gCurrSaveFileNum - 1, gDialogLineNum), strVal);
2885
print_generic_string(x + 54, y - 5, strVal);
2886
#ifdef VERSION_EU
2887
print_generic_string(x - 17, y + 30, courseName);
2888
#endif
2889
} else {
2890
u8 textStarX[] = { TEXT_STAR_X };
2891
courseName = segmented_to_virtual(courseNameTbl[COURSE_MAX]);
2892
print_generic_string(x + 40, y + 13, textStarX);
2893
int_to_str(save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_BONUS_STAGES - 1, COURSE_MAX - 1), strVal);
2894
print_generic_string(x + 60, y + 13, strVal);
2895
#ifdef VERSION_EU
2896
print_generic_string(get_str_x_pos_from_center(x + 51, courseName, 10.0f), y + 30, courseName);
2897
#endif
2898
}
2899
2900
#ifndef VERSION_EU
2901
print_generic_string(x - 9, y + 30, courseName);
2902
#endif
2903
2904
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2905
}
2906
2907
s8 gCourseCompleteCoinsEqual = 0;
2908
s32 gCourseDoneMenuTimer = 0;
2909
s32 gCourseCompleteCoins = 0;
2910
s8 gHudFlash = 0;
2911
2912
s16 render_pause_courses_and_castle(void) {
2913
s16 index;
2914
2915
#ifdef VERSION_EU
2916
gInGameLanguage = eu_get_language();
2917
#endif
2918
2919
switch (gDialogBoxState) {
2920
case DIALOG_STATE_OPENING:
2921
gDialogLineNum = MENU_OPT_DEFAULT;
2922
gDialogTextAlpha = 0;
2923
level_set_transition(-1, NULL);
2924
#ifdef VERSION_JP
2925
play_sound(SOUND_MENU_PAUSE, gGlobalSoundSource);
2926
#else
2927
play_sound(SOUND_MENU_PAUSE_HIGHPRIO, gGlobalSoundSource);
2928
#endif
2929
2930
if (gCurrCourseNum >= COURSE_MIN && gCurrCourseNum <= COURSE_MAX) {
2931
change_dialog_camera_angle();
2932
gDialogBoxState = DIALOG_STATE_VERTICAL;
2933
} else {
2934
highlight_last_course_complete_stars();
2935
gDialogBoxState = DIALOG_STATE_HORIZONTAL;
2936
}
2937
break;
2938
case DIALOG_STATE_VERTICAL:
2939
shade_screen();
2940
render_pause_my_score_coins();
2941
render_pause_red_coins();
2942
2943
if (configLeaveAnyTime || gMarioStates[0].action & ACT_FLAG_PAUSE_EXIT) {
2944
render_pause_course_options(99, 93, &gDialogLineNum, 15);
2945
}
2946
2947
#ifdef VERSION_EU
2948
if (gPlayer3Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON))
2949
#else
2950
if (gPlayer3Controller->buttonPressed & A_BUTTON
2951
|| gPlayer3Controller->buttonPressed & START_BUTTON)
2952
#endif
2953
{
2954
level_set_transition(0, NULL);
2955
play_sound(SOUND_MENU_PAUSE_2, gGlobalSoundSource);
2956
gDialogBoxState = DIALOG_STATE_OPENING;
2957
gMenuMode = MENU_MODE_NONE;
2958
2959
if ((configQuitOption && (gDialogLineNum == MENU_OPT_CAMERA_ANGLE_R)) || (gDialogLineNum == MENU_OPT_EXIT_COURSE)) {
2960
index = gDialogLineNum;
2961
} else { // MENU_OPT_CONTINUE or MENU_OPT_CAMERA_ANGLE_R
2962
index = MENU_OPT_DEFAULT;
2963
}
2964
2965
return index;
2966
}
2967
break;
2968
case DIALOG_STATE_HORIZONTAL:
2969
shade_screen();
2970
print_hud_pause_colorful_str();
2971
render_pause_castle_menu_box(160, 143);
2972
render_pause_castle_main_strings(104, 60);
2973
if (configQuitOption) {
2974
render_pause_exit_text();
2975
}
2976
2977
#ifdef VERSION_EU
2978
if (gPlayer3Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON))
2979
#else
2980
if (gPlayer3Controller->buttonPressed & A_BUTTON
2981
|| gPlayer3Controller->buttonPressed & START_BUTTON)
2982
#endif
2983
{
2984
level_set_transition(0, NULL);
2985
play_sound(SOUND_MENU_PAUSE_2, gGlobalSoundSource);
2986
gMenuMode = MENU_MODE_NONE;
2987
gDialogBoxState = DIALOG_STATE_OPENING;
2988
2989
return MENU_OPT_DEFAULT;
2990
}
2991
break;
2992
}
2993
2994
if (gDialogTextAlpha < 250) {
2995
gDialogTextAlpha += 25;
2996
}
2997
2998
return MENU_OPT_NONE;
2999
}
3000
3001
#if defined(VERSION_JP)
3002
#define TXT_HISCORE_X 112
3003
#define TXT_HISCORE_Y 48
3004
#define TXT_CONGRATS_X 60
3005
#elif defined(VERSION_SH)
3006
#define TXT_HISCORE_X 118
3007
#define TXT_HISCORE_Y 48
3008
#define TXT_CONGRATS_X 70
3009
#else
3010
#define TXT_HISCORE_X 109
3011
#define TXT_HISCORE_Y 36
3012
#define TXT_CONGRATS_X 70
3013
#endif
3014
3015
#define HUD_PRINT_HISCORE 0
3016
#define HUD_PRINT_CONGRATULATIONS 1
3017
3018
void print_hud_course_complete_string(s8 str) {
3019
#ifdef VERSION_EU
3020
u8 textHiScore[][15] = {
3021
{ TEXT_HUD_HI_SCORE },
3022
{ TEXT_HUD_HI_SCORE_FR },
3023
{ TEXT_HUD_HI_SCORE_DE }
3024
};
3025
u8 textCongratulations[][16] = {
3026
{ TEXT_HUD_CONGRATULATIONS },
3027
{ TEXT_HUD_CONGRATULATIONS_FR },
3028
{ TEXT_HUD_CONGRATULATIONS_DE }
3029
};
3030
#else
3031
u8 textHiScore[] = { TEXT_HUD_HI_SCORE };
3032
u8 textCongratulations[] = { TEXT_HUD_CONGRATULATIONS };
3033
#endif
3034
3035
u8 colorFade = sins(gDialogColorFadeTimer) * 50.0f + 200.0f;
3036
3037
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
3038
gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255);
3039
3040
if (str == HUD_PRINT_HISCORE) {
3041
#ifdef VERSION_EU
3042
print_hud_lut_string(HUD_LUT_GLOBAL, get_str_x_pos_from_center_scale(160, textHiScore[gInGameLanguage], 12.0f),
3043
36, textHiScore[gInGameLanguage]);
3044
#else
3045
print_hud_lut_string(HUD_LUT_GLOBAL, TXT_HISCORE_X, TXT_HISCORE_Y, textHiScore);
3046
#endif
3047
} else { // HUD_PRINT_CONGRATULATIONS
3048
#ifdef VERSION_EU
3049
print_hud_lut_string(HUD_LUT_GLOBAL, get_str_x_pos_from_center_scale(160, textCongratulations[gInGameLanguage], 12.0f),
3050
67, textCongratulations[gInGameLanguage]);
3051
#else
3052
print_hud_lut_string(HUD_LUT_GLOBAL, TXT_CONGRATS_X, 67, textCongratulations);
3053
#endif
3054
}
3055
3056
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
3057
}
3058
3059
void print_hud_course_complete_coins(s16 x, s16 y) {
3060
u8 courseCompleteCoinsStr[4];
3061
u8 hudTextSymCoin[] = { GLYPH_COIN, GLYPH_SPACE };
3062
u8 hudTextSymX[] = { GLYPH_MULTIPLY, GLYPH_SPACE };
3063
3064
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
3065
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
3066
3067
print_hud_lut_string(HUD_LUT_GLOBAL, x, y, hudTextSymCoin);
3068
print_hud_lut_string(HUD_LUT_GLOBAL, x + 16, y, hudTextSymX);
3069
3070
int_to_str(gCourseCompleteCoins, courseCompleteCoinsStr);
3071
print_hud_lut_string(HUD_LUT_GLOBAL, x + 32, y, courseCompleteCoinsStr);
3072
3073
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
3074
3075
if (gCourseCompleteCoins >= gHudDisplay.coins) {
3076
gCourseCompleteCoinsEqual = 1;
3077
gCourseCompleteCoins = gHudDisplay.coins;
3078
3079
if (gGotFileCoinHiScore) {
3080
print_hud_course_complete_string(HUD_PRINT_HISCORE);
3081
}
3082
} else {
3083
if ((gCourseDoneMenuTimer & 1) || gHudDisplay.coins > 70) {
3084
gCourseCompleteCoins++;
3085
play_sound(SOUND_MENU_YOSHI_GAIN_LIVES, gGlobalSoundSource);
3086
3087
if (gCourseCompleteCoins == 50 || gCourseCompleteCoins == 100 || gCourseCompleteCoins == 150) {
3088
play_sound(SOUND_GENERAL_COLLECT_1UP, gGlobalSoundSource);
3089
if (!configLifeMode) {
3090
gMarioState->numLives++;
3091
}
3092
}
3093
}
3094
3095
if (gHudDisplay.coins == gCourseCompleteCoins && gGotFileCoinHiScore) {
3096
play_sound(SOUND_MENU_MARIO_CASTLE_WARP2, gGlobalSoundSource);
3097
}
3098
}
3099
}
3100
3101
void play_star_fanfare_and_flash_hud(s32 arg, u8 starNum) {
3102
if (gHudDisplay.coins == gCourseCompleteCoins && (gCurrCourseStarFlags & starNum) == 0 && gHudFlash == 0) {
3103
play_star_fanfare();
3104
gHudFlash = arg;
3105
}
3106
}
3107
3108
#ifdef VERSION_EU
3109
#define TXT_NAME_X1 centerX
3110
#define TXT_NAME_X2 centerX - 1
3111
#else
3112
#define TXT_NAME_X1 71
3113
#define TXT_NAME_X2 69
3114
#endif
3115
#if defined(VERSION_JP) || defined(VERSION_SH)
3116
#define CRS_NUM_X2 95
3117
#define CRS_NUM_X3 93
3118
#define TXT_CLEAR_X1 205
3119
#define TXT_CLEAR_X2 203
3120
#else
3121
#define CRS_NUM_X2 104
3122
#define CRS_NUM_X3 102
3123
#define TXT_CLEAR_X1 get_string_width(name) + 81
3124
#define TXT_CLEAR_X2 get_string_width(name) + 79
3125
#endif
3126
3127
void render_course_complete_lvl_info_and_hud_str(void) {
3128
#if defined(VERSION_JP)
3129
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
3130
u8 textCourse[] = { TEXT_COURSE };
3131
u8 textCatch[] = { TEXT_CATCH };
3132
u8 textClear[] = { TEXT_CLEAR };
3133
#elif defined(VERSION_EU)
3134
UNUSED u8 textCatch[] = { TEXT_CATCH }; // unused in EU
3135
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
3136
#define textCourse gTextCourseArr[gInGameLanguage]
3137
#else
3138
u8 textCourse[] = { TEXT_COURSE };
3139
UNUSED u8 textCatch[] = { TEXT_CATCH }; // unused in US
3140
UNUSED u8 textClear[] = { TEXT_CLEAR };
3141
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
3142
#endif
3143
3144
void **actNameTbl;
3145
void **courseNameTbl;
3146
u8 *name;
3147
3148
u8 strCourseNum[4];
3149
3150
#ifdef VERSION_EU
3151
s16 centerX;
3152
switch (gInGameLanguage) {
3153
case LANGUAGE_ENGLISH:
3154
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
3155
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
3156
break;
3157
case LANGUAGE_FRENCH:
3158
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
3159
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
3160
break;
3161
case LANGUAGE_GERMAN:
3162
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
3163
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
3164
break;
3165
}
3166
#else
3167
actNameTbl = segmented_to_virtual(seg2_act_name_table);
3168
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
3169
#endif
3170
3171
if (gLastCompletedCourseNum <= COURSE_STAGES_MAX) {
3172
print_hud_course_complete_coins(118, 103);
3173
play_star_fanfare_and_flash_hud(1, 1 << (gLastCompletedStarNum - 1));
3174
3175
if (gLastCompletedStarNum == 7) {
3176
name = segmented_to_virtual(actNameTbl[COURSE_STAGES_MAX * 6 + 1]);
3177
} else {
3178
name = segmented_to_virtual(actNameTbl[(gLastCompletedCourseNum - 1) * 6 + gLastCompletedStarNum - 1]);
3179
}
3180
3181
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
3182
int_to_str(gLastCompletedCourseNum, strCourseNum);
3183
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, gDialogTextAlpha);
3184
print_generic_string(65, 165, textCourse);
3185
print_generic_string(CRS_NUM_X2, 165, strCourseNum);
3186
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
3187
print_generic_string(63, 167, textCourse);
3188
print_generic_string(CRS_NUM_X3, 167, strCourseNum);
3189
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
3190
} else if (gLastCompletedCourseNum == COURSE_BITDW || gLastCompletedCourseNum == COURSE_BITFS) {
3191
name = segmented_to_virtual(courseNameTbl[gLastCompletedCourseNum - 1]);
3192
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
3193
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, gDialogTextAlpha);
3194
#ifdef VERSION_EU
3195
centerX = get_str_x_pos_from_center(153, name, 12.0f);
3196
#endif
3197
print_generic_string(TXT_NAME_X1, 130, name);
3198
#ifndef VERSION_EU
3199
print_generic_string(TXT_CLEAR_X1, 130, textClear);
3200
#endif
3201
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
3202
print_generic_string(TXT_NAME_X2, 132, name);
3203
#ifndef VERSION_EU
3204
print_generic_string(TXT_CLEAR_X2, 132, textClear);
3205
#endif
3206
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
3207
print_hud_course_complete_string(HUD_PRINT_CONGRATULATIONS);
3208
print_hud_course_complete_coins(118, 111);
3209
play_star_fanfare_and_flash_hud(2, 0); //! 2 isn't defined, originally for key hud?
3210
return;
3211
} else {
3212
name = segmented_to_virtual(actNameTbl[COURSE_STAGES_MAX * 6]);
3213
print_hud_course_complete_coins(118, 103);
3214
play_star_fanfare_and_flash_hud(1, 1 << (gLastCompletedStarNum - 1));
3215
}
3216
3217
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
3218
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
3219
print_hud_lut_string(HUD_LUT_GLOBAL, 55, 77, textSymStar);
3220
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
3221
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
3222
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, gDialogTextAlpha);
3223
print_generic_string(76, 145, name);
3224
#if defined(VERSION_JP) || defined(VERSION_SH)
3225
print_generic_string(220, 145, textCatch);
3226
#endif
3227
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
3228
print_generic_string(74, 147, name);
3229
#if defined(VERSION_JP) || defined(VERSION_SH)
3230
print_generic_string(218, 147, textCatch);
3231
#endif
3232
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
3233
}
3234
3235
#if defined(VERSION_JP) || defined(VERSION_SH)
3236
#define TXT_SAVEOPTIONS_X x + 10
3237
#elif defined(VERSION_US)
3238
#define TXT_SAVEOPTIONS_X x + 12
3239
#elif defined(VERSION_EU)
3240
#define TXT_SAVEOPTIONS_X xOffset
3241
#endif
3242
#if defined(VERSION_JP) || defined(VERSION_SH)
3243
#define TXT_SAVECONT_Y 2
3244
#define TXT_SAVEQUIT_Y 18
3245
#define TXT_CONTNOSAVE_Y 38
3246
#else
3247
#define TXT_SAVECONT_Y 0
3248
#define TXT_SAVEQUIT_Y 20
3249
#define TXT_CONTNOSAVE_Y 40
3250
#endif
3251
3252
#ifdef VERSION_EU
3253
#define X_VAL9 xOffset - 12
3254
void render_save_confirmation(s16 y, s8 *index, s16 sp6e)
3255
#else
3256
#define X_VAL9 x
3257
void render_save_confirmation(s16 x, s16 y, s8 *index, s16 sp6e)
3258
#endif
3259
{
3260
#ifdef VERSION_EU
3261
u8 textSaveAndContinueArr[][24] = {
3262
{ TEXT_SAVE_AND_CONTINUE },
3263
{ TEXT_SAVE_AND_CONTINUE_FR },
3264
{ TEXT_SAVE_AND_CONTINUE_DE }
3265
};
3266
u8 textSaveAndQuitArr[][22] = {
3267
{ TEXT_SAVE_AND_QUIT },
3268
{ TEXT_SAVE_AND_QUIT_FR },
3269
{ TEXT_SAVE_AND_QUIT_DE }
3270
};
3271
u8 textContinueWithoutSaveArr[][27] = {
3272
{ TEXT_CONTINUE_WITHOUT_SAVING },
3273
{ TEXT_CONTINUE_WITHOUT_SAVING_FR },
3274
{ TEXT_CONTINUE_WITHOUT_SAVING_DE }
3275
};
3276
#define textSaveAndContinue textSaveAndContinueArr[gInGameLanguage]
3277
#define textSaveAndQuit textSaveAndQuitArr[gInGameLanguage]
3278
#define textContinueWithoutSave textContinueWithoutSaveArr[gInGameLanguage]
3279
s16 xOffset = get_str_x_pos_from_center(160, textContinueWithoutSaveArr[gInGameLanguage], 12.0f);
3280
#else
3281
u8 textSaveAndContinue[] = { TEXT_SAVE_AND_CONTINUE };
3282
u8 textSaveAndQuit[] = { TEXT_SAVE_AND_QUIT };
3283
u8 textContinueWithoutSave[] = { TEXT_CONTINUE_WITHOUT_SAVING };
3284
#endif
3285
3286
handle_menu_scrolling(MENU_SCROLL_VERTICAL, index, 1, 3);
3287
3288
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
3289
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
3290
3291
print_generic_string(TXT_SAVEOPTIONS_X, y + TXT_SAVECONT_Y, textSaveAndContinue);
3292
print_generic_string(TXT_SAVEOPTIONS_X, y - TXT_SAVEQUIT_Y, textSaveAndQuit);
3293
print_generic_string(TXT_SAVEOPTIONS_X, y - TXT_CONTNOSAVE_Y, textContinueWithoutSave);
3294
3295
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
3296
3297
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL9, y - ((*index - 1) * sp6e), 0);
3298
3299
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
3300
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
3301
3302
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
3303
}
3304
3305
s16 render_course_complete_screen(void) {
3306
s16 index;
3307
#ifdef VERSION_EU
3308
gInGameLanguage = eu_get_language();
3309
#endif
3310
3311
switch (gDialogBoxState) {
3312
case DIALOG_STATE_OPENING:
3313
render_course_complete_lvl_info_and_hud_str();
3314
if (gCourseDoneMenuTimer > 100 && gCourseCompleteCoinsEqual == 1) {
3315
save_file_set_num_lives(gMarioState->numLives);
3316
gDialogBoxState = DIALOG_STATE_VERTICAL;
3317
level_set_transition(-1, NULL);
3318
gDialogTextAlpha = 0;
3319
gDialogLineNum = MENU_OPT_DEFAULT;
3320
}
3321
break;
3322
case DIALOG_STATE_VERTICAL:
3323
shade_screen();
3324
render_course_complete_lvl_info_and_hud_str();
3325
#ifdef VERSION_EU
3326
render_save_confirmation(86, &gDialogLineNum, 20);
3327
#else
3328
render_save_confirmation(100, 86, &gDialogLineNum, 20);
3329
#endif
3330
3331
if (gCourseDoneMenuTimer > 110
3332
&& (gPlayer3Controller->buttonPressed & A_BUTTON
3333
|| gPlayer3Controller->buttonPressed & START_BUTTON
3334
#ifdef VERSION_EU
3335
|| gPlayer3Controller->buttonPressed & Z_TRIG
3336
#endif
3337
)) {
3338
level_set_transition(0, NULL);
3339
play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
3340
gDialogBoxState = DIALOG_STATE_OPENING;
3341
gMenuMode = MENU_MODE_NONE;
3342
index = gDialogLineNum;
3343
gCourseDoneMenuTimer = 0;
3344
gCourseCompleteCoins = 0;
3345
gCourseCompleteCoinsEqual = 0;
3346
gHudFlash = 0;
3347
3348
return index;
3349
}
3350
break;
3351
}
3352
3353
if (gDialogTextAlpha < 250) {
3354
gDialogTextAlpha += 25;
3355
}
3356
3357
gCourseDoneMenuTimer++;
3358
3359
return MENU_OPT_NONE;
3360
}
3361
3362
s16 render_menus_and_dialogs(void) {
3363
s16 index = MENU_OPT_NONE;
3364
3365
create_dl_ortho_matrix();
3366
3367
if (gMenuMode != MENU_MODE_NONE) {
3368
switch (gMenuMode) {
3369
case MENU_MODE_UNUSED_0:
3370
index = render_pause_courses_and_castle();
3371
break;
3372
case MENU_MODE_RENDER_PAUSE_SCREEN:
3373
index = render_pause_courses_and_castle();
3374
break;
3375
case MENU_MODE_RENDER_COURSE_COMPLETE_SCREEN:
3376
index = render_course_complete_screen();
3377
break;
3378
case MENU_MODE_UNUSED_3:
3379
index = render_course_complete_screen();
3380
break;
3381
}
3382
3383
gDialogColorFadeTimer = (s16) gDialogColorFadeTimer + 0x1000;
3384
} else if (gDialogID != DIALOG_NONE) {
3385
// The Peach "Dear Mario" message needs to be repositioned separately
3386
if (gDialogID == DIALOG_020) {
3387
print_peach_letter_message();
3388
return index;
3389
}
3390
3391
render_dialog_entries();
3392
gDialogColorFadeTimer = (s16) gDialogColorFadeTimer + 0x1000;
3393
}
3394
return index;
3395
}
3396