sm64pc/src/game/ingame_menu.c

3088 lines
101 KiB
C
Raw Normal View History

2019-08-25 04:46:40 +00:00
#include <ultra64.h>
#include "sm64.h"
2020-05-07 18:21:22 +00:00
#include "gfx_dimensions.h"
2019-08-25 04:46:40 +00:00
#include "memory.h"
#include "types.h"
#include "audio/external.h"
#include "seq_ids.h"
2019-12-02 02:52:53 +00:00
#include "dialog_ids.h"
2020-04-03 18:57:26 +00:00
#include "game_init.h"
2019-08-25 04:46:40 +00:00
#include "save_file.h"
#include "level_update.h"
#include "camera.h"
#include "text_strings.h"
#include "segment2.h"
#include "segment7.h"
#include "eu_translation.h"
#include "ingame_menu.h"
2019-10-05 19:08:05 +00:00
#include "print.h"
2019-08-25 04:46:40 +00:00
#include "engine/math_util.h"
2020-04-03 18:57:26 +00:00
#include "course_table.h"
2019-08-25 04:46:40 +00:00
extern Gfx *gDisplayListHead;
extern s16 gCurrCourseNum;
extern s16 gCurrSaveFileNum;
extern Gfx coin_seg3_dl_03007940[];
extern Gfx coin_seg3_dl_03007968[];
extern Gfx coin_seg3_dl_03007990[];
extern Gfx coin_seg3_dl_030079B8[];
extern u8 main_menu_seg7_table_0700ABD0[];
extern Gfx castle_grounds_seg7_dl_0700EA58[];
2019-10-05 19:08:05 +00:00
u16 gDialogColorFadeTimer;
2019-08-25 04:46:40 +00:00
s8 gLastDialogLineNum;
s32 gDialogVariable;
2019-10-05 19:08:05 +00:00
u16 gDialogTextAlpha;
2020-03-02 03:42:52 +00:00
#if defined(VERSION_EU)
2020-02-03 05:51:26 +00:00
s16 gDialogX; // D_8032F69A
s16 gDialogY; // D_8032F69C
#endif
2019-08-25 04:46:40 +00:00
s16 gCutsceneMsgXOffset;
s16 gCutsceneMsgYOffset;
2019-10-05 19:08:05 +00:00
s8 gRedCoinsCollected;
2019-08-25 04:46:40 +00:00
extern u8 gLastCompletedCourseNum;
extern u8 gLastCompletedStarNum;
enum DialogBoxState {
DIALOG_STATE_OPENING,
2019-10-05 19:08:05 +00:00
DIALOG_STATE_VERTICAL,
DIALOG_STATE_HORIZONTAL,
2019-08-25 04:46:40 +00:00
DIALOG_STATE_CLOSING
};
2019-10-05 19:08:05 +00:00
enum DialogBoxPageState {
DIALOG_PAGE_STATE_NONE,
DIALOG_PAGE_STATE_SCROLL,
DIALOG_PAGE_STATE_END
};
2019-08-25 04:46:40 +00:00
enum DialogBoxType {
DIALOG_TYPE_ROTATE, // used in NPCs and level messages
DIALOG_TYPE_ZOOM // used in signposts and wall signs and etc
};
enum DialogMark { DIALOG_MARK_NONE = 0, DIALOG_MARK_DAKUTEN = 1, DIALOG_MARK_HANDAKUTEN = 2 };
#define DEFAULT_DIALOG_BOX_ANGLE 90.0f
#define DEFAULT_DIALOG_BOX_SCALE 19.0f
2020-04-03 18:57:26 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
u8 gDialogCharWidths[256] = { // TODO: Is there a way to auto generate this?
2019-09-01 19:50:50 +00:00
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6,
6, 6, 5, 6, 6, 5, 8, 8, 6, 6, 6, 6, 6, 5, 6, 6,
8, 7, 6, 6, 6, 5, 5, 6, 5, 5, 6, 5, 4, 5, 5, 3,
7, 5, 5, 5, 6, 5, 5, 5, 5, 5, 7, 7, 5, 5, 4, 4,
8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8, 8, 8, 8, 7, 7, 6, 7, 7, 0, 0, 0, 0, 0, 0, 0,
#ifdef VERSION_EU
6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 4,
5, 5, 5, 5, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0,
5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 5, 5, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 5, 6,
0, 4, 4, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#else
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#ifdef VERSION_EU
7, 5, 10, 5, 9, 8, 4, 0, 0, 0, 0, 5, 5, 6, 5, 0,
#else
7, 5, 10, 5, 9, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
0, 0, 5, 7, 7, 6, 6, 8, 0, 8, 10, 6, 4, 10, 0, 0
2019-08-25 04:46:40 +00:00
};
#endif
s8 gDialogBoxState = DIALOG_STATE_OPENING;
f32 gDialogBoxOpenTimer = DEFAULT_DIALOG_BOX_ANGLE;
f32 gDialogBoxScale = DEFAULT_DIALOG_BOX_SCALE;
s16 gDialogScrollOffsetY = 0;
s8 gDialogBoxType = DIALOG_TYPE_ROTATE;
s16 gDialogID = -1;
s16 gLastDialogPageStrPos = 0;
2019-10-05 19:08:05 +00:00
s16 gDialogTextPos = 0; // EU: D_802FD64C
2020-02-03 05:51:26 +00:00
#ifdef VERSION_EU
s32 gInGameLanguage = 0;
#endif
2019-10-05 19:08:05 +00:00
s8 gDialogLineNum = 1;
s8 gLastDialogResponse = 0;
u8 gMenuHoldKeyIndex = 0;
u8 gMenuHoldKeyTimer = 0;
2019-08-25 04:46:40 +00:00
s32 gDialogResponse = 0;
2019-10-05 19:08:05 +00:00
void create_dl_identity_matrix(void) {
2019-08-25 04:46:40 +00:00
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
2019-09-01 19:50:50 +00:00
if (matrix == NULL) {
2019-08-25 04:46:40 +00:00
return;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2020-05-07 18:21:22 +00:00
#ifdef TARGET_N64
2020-02-03 05:51:26 +00:00
matrix->m[0][0] = 0x00010000; matrix->m[1][0] = 0x00000000; matrix->m[2][0] = 0x00000000; matrix->m[3][0] = 0x00000000;
matrix->m[0][1] = 0x00000000; matrix->m[1][1] = 0x00010000; matrix->m[2][1] = 0x00000000; matrix->m[3][1] = 0x00000000;
matrix->m[0][2] = 0x00000001; matrix->m[1][2] = 0x00000000; matrix->m[2][2] = 0x00000000; matrix->m[3][2] = 0x00000000;
matrix->m[0][3] = 0x00000000; matrix->m[1][3] = 0x00000001; matrix->m[2][3] = 0x00000000; matrix->m[3][3] = 0x00000000;
2020-05-07 18:21:22 +00:00
#else
guMtxIdent(matrix);
#endif
2019-11-03 19:36:27 +00:00
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z) {
2019-08-25 04:46:40 +00:00
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
2019-09-01 19:50:50 +00:00
if (matrix == NULL) {
2019-08-25 04:46:40 +00:00
return;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
guTranslate(matrix, x, y, z);
if (pushOp == MENU_MTX_PUSH)
2019-11-03 19:36:27 +00:00
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
2019-08-25 04:46:40 +00:00
if (pushOp == MENU_MTX_NOPUSH)
2019-11-03 19:36:27 +00:00
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
void create_dl_rotation_matrix(s8 pushOp, f32 a, f32 x, f32 y, f32 z) {
2019-08-25 04:46:40 +00:00
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
2019-09-01 19:50:50 +00:00
if (matrix == NULL) {
2019-08-25 04:46:40 +00:00
return;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
guRotate(matrix, a, x, y, z);
if (pushOp == MENU_MTX_PUSH)
2019-11-03 19:36:27 +00:00
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
2019-08-25 04:46:40 +00:00
if (pushOp == MENU_MTX_NOPUSH)
2019-11-03 19:36:27 +00:00
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
void create_dl_scale_matrix(s8 pushOp, f32 x, f32 y, f32 z) {
2019-08-25 04:46:40 +00:00
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
2019-09-01 19:50:50 +00:00
if (matrix == NULL) {
2019-08-25 04:46:40 +00:00
return;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
guScale(matrix, x, y, z);
if (pushOp == MENU_MTX_PUSH)
2019-11-03 19:36:27 +00:00
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
2019-08-25 04:46:40 +00:00
if (pushOp == MENU_MTX_NOPUSH)
2019-11-03 19:36:27 +00:00
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
void create_dl_ortho_matrix(void) {
2019-08-25 04:46:40 +00:00
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
2019-09-01 19:50:50 +00:00
if (matrix == NULL) {
2019-08-25 04:46:40 +00:00
return;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
create_dl_identity_matrix();
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
guOrtho(matrix, 0.0f, SCREEN_WIDTH, 0.0f, SCREEN_HEIGHT, -10.0f, 10.0f, 1.0f);
2019-08-25 04:46:40 +00:00
// Should produce G_RDPHALF_1 in Fast3D
2020-04-03 18:57:26 +00:00
gSPPerspNormalize(gDisplayListHead++, 0xFFFF);
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_PROJECTION | G_MTX_MUL | G_MTX_NOPUSH)
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
static u8 *alloc_ia8_text_from_i1(u16 *in, s16 width, s16 height) {
2019-08-25 04:46:40 +00:00
s32 inPos;
u16 bitMask;
u8 *out;
2020-04-03 18:57:26 +00:00
s16 outPos = 0;
2019-08-25 04:46:40 +00:00
2020-04-03 18:57:26 +00:00
out = alloc_display_list((u32) width * (u32) height);
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (out == NULL) {
2019-08-25 04:46:40 +00:00
return NULL;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
for (inPos = 0; inPos < (width * height) / 16; inPos++) {
bitMask = 0x8000;
while (bitMask != 0) {
2019-09-01 19:50:50 +00:00
if (in[inPos] & bitMask) {
2019-08-25 04:46:40 +00:00
out[outPos] = 0xFF;
2019-09-01 19:50:50 +00:00
} else {
2019-08-25 04:46:40 +00:00
out[outPos] = 0x00;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
bitMask /= 2;
outPos++;
}
}
return out;
}
void render_generic_char(u8 c) {
2019-10-05 19:08:05 +00:00
void **fontLUT;
2019-08-25 04:46:40 +00:00
void *packedTexture;
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
void *unpackedTexture;
#endif
2019-10-05 19:08:05 +00:00
fontLUT = segmented_to_virtual(main_font_lut);
packedTexture = segmented_to_virtual(fontLUT[c]);
2019-08-25 04:46:40 +00:00
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
unpackedTexture = alloc_ia8_text_from_i1(packedTexture, 8, 16);
2019-08-25 04:46:40 +00:00
gDPPipeSync(gDisplayListHead++);
2019-09-01 19:50:50 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, VIRTUAL_TO_PHYSICAL(unpackedTexture));
2019-08-25 04:46:40 +00:00
#else
#ifdef VERSION_US
gDPPipeSync(gDisplayListHead++);
#endif
2019-09-01 19:50:50 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture));
2019-08-25 04:46:40 +00:00
#endif
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
gSPTextureRectangleFlip(gDisplayListHead++, gDialogX << 2, (gDialogY - 16) << 2,
2020-04-03 18:57:26 +00:00
(gDialogX + 8) << 2, gDialogY << 2, G_TX_RENDERTILE, 8 << 6, 4 << 6, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
#endif
}
#ifdef VERSION_EU
u8 *alloc_ia4_tex_from_i1(u8 *in, s16 width, s16 height) {
u32 size = (u32) width * (u32) height;
u8 *out;
s32 inPos;
s16 outPos;
u8 bitMask;
outPos = 0;
out = (u8 *) alloc_display_list(size);
2019-09-01 19:50:50 +00:00
if (out == NULL) {
2019-08-25 04:46:40 +00:00
return NULL;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
for (inPos = 0; inPos < (width * height) / 4; inPos++) {
bitMask = 0x80;
while (bitMask != 0) {
out[outPos] = (in[inPos] & bitMask) ? 0xF0 : 0x00;
bitMask /= 2;
out[outPos] = (in[inPos] & bitMask) ? out[outPos] + 0x0F : out[outPos];
bitMask /= 2;
outPos++;
}
}
return out;
}
void render_generic_char_at_pos(s16 xPos, s16 yPos, u8 c) {
2019-10-05 19:08:05 +00:00
void **fontLUT;
2019-08-25 04:46:40 +00:00
void *packedTexture;
void *unpackedTexture;
2019-10-05 19:08:05 +00:00
fontLUT = segmented_to_virtual(main_font_lut);
packedTexture = segmented_to_virtual(fontLUT[c]);
2019-08-25 04:46:40 +00:00
unpackedTexture = alloc_ia4_tex_from_i1(packedTexture, 8, 8);
gDPPipeSync(gDisplayListHead++);
2019-09-01 19:50:50 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(unpackedTexture));
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
2019-08-25 04:46:40 +00:00
gSPTextureRectangleFlip(gDisplayListHead++, xPos << 2, (yPos - 16) << 2, (xPos + 8) << 2, yPos << 2,
2020-04-03 18:57:26 +00:00
G_TX_RENDERTILE, 8 << 6, 4 << 6, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
}
void render_lowercase_diacritic(s16 *xPos, s16 *yPos, u8 letter, u8 diacritic) {
render_generic_char_at_pos(*xPos, *yPos, letter);
render_generic_char_at_pos(*xPos, *yPos, diacritic + 0xE7);
*xPos += gDialogCharWidths[letter];
}
void render_uppercase_diacritic(s16 *xPos, s16 *yPos, u8 letter, u8 diacritic) {
render_generic_char_at_pos(*xPos, *yPos, letter);
render_generic_char_at_pos(*xPos, *yPos - 4, diacritic + 0xE3);
*xPos += gDialogCharWidths[letter];
}
#endif // VERSION_EU
2020-03-02 03:42:52 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
struct MultiTextEntry {
u8 length;
u8 str[4];
};
#define TEXT_THE_RAW ASCII_TO_DIALOG('t'), ASCII_TO_DIALOG('h'), ASCII_TO_DIALOG('e'), 0x00
#define TEXT_YOU_RAW ASCII_TO_DIALOG('y'), ASCII_TO_DIALOG('o'), ASCII_TO_DIALOG('u'), 0x00
2019-12-02 02:52:53 +00:00
enum MultiStringIDs { STRING_THE, STRING_YOU };
2019-08-25 04:46:40 +00:00
/*
* Place the multi-text string according to the ID passed. (US, EU)
* 0: 'the'
* 1: 'you'
*/
#ifdef VERSION_US
2019-10-05 19:08:05 +00:00
void render_multi_text_string(s8 multiTextID) // US: 802D76C8
2019-08-25 04:46:40 +00:00
#elif defined(VERSION_EU)
2019-10-05 19:08:05 +00:00
void render_multi_text_string(s16 *xPos, s16 *yPos, s8 multiTextID) // EU: 802AD650
2019-08-25 04:46:40 +00:00
#endif
{
s8 i;
struct MultiTextEntry textLengths[2] = {
{ 3, { TEXT_THE_RAW } },
{ 3, { TEXT_YOU_RAW } },
};
for (i = 0; i < textLengths[multiTextID].length; i++) {
#ifdef VERSION_US
render_generic_char(textLengths[multiTextID].str[i]);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[textLengths[multiTextID].str[i]]), 0.0f, 0.0f);
2019-08-25 04:46:40 +00:00
#elif defined(VERSION_EU)
render_generic_char_at_pos(*xPos, *yPos, textLengths[multiTextID].str[i]);
*xPos += gDialogCharWidths[textLengths[multiTextID].str[i]];
#endif
}
}
#endif
2020-03-02 03:42:52 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
#define MAX_STRING_WIDTH 18
#else
#define MAX_STRING_WIDTH 16
#endif
/**
* Prints a generic white string.
* In JP/EU a IA1 texture is used but in US a IA4 texture is used.
*/
void print_generic_string(s16 x, s16 y, const u8 *str) {
2019-08-25 04:46:40 +00:00
UNUSED s8 mark = DIALOG_MARK_NONE; // unused in EU
s32 strPos = 0;
u8 lineNum = 1;
#ifdef VERSION_EU
s16 xCoord = x;
s16 yCoord = 240 - y;
#endif
#ifndef VERSION_EU
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, x, y, 0.0f);
2019-08-25 04:46:40 +00:00
#endif
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
switch (str[strPos]) {
#ifdef VERSION_EU
case DIALOG_CHAR_SPACE:
xCoord += 5;
break;
case DIALOG_CHAR_NEWLINE:
yCoord += 16;
xCoord = x;
lineNum++;
break;
case DIALOG_CHAR_LOWER_A_GRAVE:
case DIALOG_CHAR_LOWER_A_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_A_UMLAUT:
render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('a'), str[strPos] & 0xF);
break;
case DIALOG_CHAR_UPPER_A_UMLAUT: // @bug grave and circumflux (0x64-0x65) are absent here
render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('A'), str[strPos] & 0xF);
break;
case DIALOG_CHAR_LOWER_E_GRAVE:
case DIALOG_CHAR_LOWER_E_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_E_UMLAUT:
case DIALOG_CHAR_LOWER_E_ACUTE:
render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('e'), str[strPos] & 0xF);
break;
case DIALOG_CHAR_UPPER_E_GRAVE:
case DIALOG_CHAR_UPPER_E_CIRCUMFLEX:
case DIALOG_CHAR_UPPER_E_UMLAUT:
case DIALOG_CHAR_UPPER_E_ACUTE:
render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('E'), str[strPos] & 0xF);
break;
case DIALOG_CHAR_LOWER_U_GRAVE:
case DIALOG_CHAR_LOWER_U_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_U_UMLAUT:
render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('u'), str[strPos] & 0xF);
break;
case DIALOG_CHAR_UPPER_U_UMLAUT: // @bug grave and circumflex (0x84-0x85) are absent here
render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('U'), str[strPos] & 0xF);
break;
case DIALOG_CHAR_LOWER_O_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_O_UMLAUT:
render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('o'), str[strPos] & 0xF);
break;
case DIALOG_CHAR_UPPER_O_UMLAUT: // @bug circumflex (0x95) is absent here
render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('O'), str[strPos] & 0xF);
break;
case DIALOG_CHAR_LOWER_I_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_I_UMLAUT:
render_lowercase_diacritic(&xCoord, &yCoord, DIALOG_CHAR_I_NO_DIA, str[strPos] & 0xF);
break;
#else // i.e. not EU
2020-01-03 15:38:57 +00:00
case DIALOG_CHAR_DAKUTEN:
2019-08-25 04:46:40 +00:00
mark = DIALOG_MARK_DAKUTEN;
break;
2020-01-03 15:38:57 +00:00
case DIALOG_CHAR_PERIOD_OR_HANDAKUTEN:
2019-08-25 04:46:40 +00:00
mark = DIALOG_MARK_HANDAKUTEN;
break;
case DIALOG_CHAR_NEWLINE:
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, x, y - (lineNum * MAX_STRING_WIDTH), 0.0f);
2019-08-25 04:46:40 +00:00
lineNum++;
break;
2020-01-03 15:38:57 +00:00
case DIALOG_CHAR_PERIOD:
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, -2.0f, -5.0f, 0.0f);
2020-01-03 15:38:57 +00:00
render_generic_char(DIALOG_CHAR_PERIOD_OR_HANDAKUTEN);
2019-08-25 04:46:40 +00:00
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
break;
#endif
2020-03-02 03:42:52 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
case DIALOG_CHAR_SLASH:
2019-08-25 04:46:40 +00:00
#ifdef VERSION_US
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE] * 2), 0.0f, 0.0f);
2019-08-25 04:46:40 +00:00
#elif defined(VERSION_EU)
xCoord += gDialogCharWidths[DIALOG_CHAR_SPACE] * 2;
#endif
break;
case DIALOG_CHAR_MULTI_THE:
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
render_multi_text_string(&xCoord, &yCoord, STRING_THE);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
render_multi_text_string(STRING_THE);
2019-08-25 04:46:40 +00:00
#endif
break;
case DIALOG_CHAR_MULTI_YOU:
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
render_multi_text_string(&xCoord, &yCoord, STRING_YOU);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
render_multi_text_string(STRING_YOU);
2019-08-25 04:46:40 +00:00
#endif
break;
#endif
#ifndef VERSION_EU
case DIALOG_CHAR_SPACE:
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, 5.0f, 0.0f, 0.0f);
2019-08-25 04:46:40 +00:00
break;
#else
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE]), 0.0f, 0.0f);
2019-08-25 04:46:40 +00:00
#endif
#endif
break; // ? needed to match
default:
#ifdef VERSION_EU
render_generic_char_at_pos(xCoord, yCoord, str[strPos]);
xCoord += gDialogCharWidths[str[strPos]];
break;
#else
render_generic_char(str[strPos]);
if (mark != DIALOG_MARK_NONE) {
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, 5.0f, 5.0f, 0.0f);
2019-08-25 04:46:40 +00:00
render_generic_char(mark + 0xEF);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
mark = DIALOG_MARK_NONE;
}
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, 10.0f, 0.0f, 0.0f);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[str[strPos]]), 0.0f, 0.0f);
2019-08-25 04:46:40 +00:00
break; // what an odd difference. US added a useless break here.
#endif
#endif
}
strPos++;
}
#ifndef VERSION_EU
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
#endif
}
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
void print_hud_char_umlaut(s16 x, s16 y, u8 chr) {
void **fontLUT = segmented_to_virtual(main_hud_lut);
2019-08-25 04:46:40 +00:00
gDPPipeSync(gDisplayListHead++);
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, fontLUT[chr]);
gSPDisplayList(gDisplayListHead++, dl_rgba16_load_tex_block);
2019-10-05 19:08:05 +00:00
gSPTextureRectangle(gDisplayListHead++, x << 2, y << 2, (x + 16) << 2, (y + 16) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, fontLUT[GLYPH_UMLAUT]);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_load_tex_block);
2019-10-05 19:08:05 +00:00
gSPTextureRectangle(gDisplayListHead++, x << 2, (y - 4) << 2, (x + 16) << 2, (y + 12) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
}
#endif
2019-10-05 19:08:05 +00:00
/**
* Prints a hud string depending of the hud table list defined.
*/
void print_hud_lut_string(s8 hudLUT, s16 x, s16 y, const u8 *str) {
2019-08-25 04:46:40 +00:00
s32 strPos = 0;
2019-10-05 19:08:05 +00:00
void **hudLUT1 = segmented_to_virtual(menu_hud_lut); // Japanese Menu HUD Color font
void **hudLUT2 = segmented_to_virtual(main_hud_lut); // 0-9 A-Z HUD Color Font
2019-08-25 04:46:40 +00:00
u32 curX = x;
u32 curY = y;
2019-10-05 19:08:05 +00:00
u32 xStride; // X separation
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (hudLUT == HUD_LUT_JPMENU) {
2019-08-25 04:46:40 +00:00
xStride = 16;
2019-10-05 19:08:05 +00:00
} else { // HUD_LUT_GLOBAL
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP)
2019-08-25 04:46:40 +00:00
xStride = 14;
#else
2020-04-03 18:57:26 +00:00
xStride = 12; //? Shindou uses this.
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
while (str[strPos] != GLOBAR_CHAR_TERMINATOR) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
switch (str[strPos]) {
2019-10-05 19:08:05 +00:00
case GLOBAL_CHAR_SPACE:
2019-08-25 04:46:40 +00:00
curX += xStride / 2;
break;
case HUD_CHAR_A_UMLAUT:
2019-10-05 19:08:05 +00:00
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('A'));
2019-08-25 04:46:40 +00:00
curX += xStride;
break;
case HUD_CHAR_O_UMLAUT:
2019-10-05 19:08:05 +00:00
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('O'));
2019-08-25 04:46:40 +00:00
curX += xStride;
break;
case HUD_CHAR_U_UMLAUT:
2019-10-05 19:08:05 +00:00
print_hud_char_umlaut(curX, curY, ASCII_TO_DIALOG('U'));
2019-08-25 04:46:40 +00:00
curX += xStride;
break;
default:
2019-09-01 19:50:50 +00:00
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_US) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
if (str[strPos] == GLOBAL_CHAR_SPACE) {
2019-08-25 04:46:40 +00:00
if (0) //! dead code
{
}
curX += 8;
; //! useless statement
} else {
#endif
2019-09-01 19:50:50 +00:00
gDPPipeSync(gDisplayListHead++);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (hudLUT == HUD_LUT_JPMENU)
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, hudLUT1[str[strPos]]);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (hudLUT == HUD_LUT_GLOBAL)
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, hudLUT2[str[strPos]]);
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_load_tex_block);
gSPTextureRectangle(gDisplayListHead++, curX << 2, curY << 2, (curX + 16) << 2,
2019-10-05 19:08:05 +00:00
(curY + 16) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
curX += xStride;
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
break;
2019-08-25 04:46:40 +00:00
}
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_US) || defined(VERSION_SH)
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
#endif
strPos++;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
void print_menu_char_umlaut(s16 x, s16 y, u8 chr) {
void **fontLUT = segmented_to_virtual(menu_font_lut);
2019-08-25 04:46:40 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, fontLUT[chr]);
gDPLoadSync(gDisplayListHead++);
2019-11-03 19:36:27 +00:00
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_8b_BYTES));
2019-10-05 19:08:05 +00:00
gSPTextureRectangle(gDisplayListHead++, x << 2, y << 2, (x + 8) << 2, (y + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, fontLUT[DIALOG_CHAR_UMLAUT]);
2019-08-25 04:46:40 +00:00
gDPLoadSync(gDisplayListHead++);
2019-11-03 19:36:27 +00:00
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_8b_BYTES));
2019-10-05 19:08:05 +00:00
gSPTextureRectangle(gDisplayListHead++, x << 2, (y - 4) << 2, (x + 8) << 2, (y + 4) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
}
#endif
2019-10-05 19:08:05 +00:00
void print_menu_generic_string(s16 x, s16 y, const u8 *str) {
2019-08-25 04:46:40 +00:00
UNUSED s8 mark = DIALOG_MARK_NONE; // unused in EU
s32 strPos = 0;
s32 curX = x;
s32 curY = y;
2019-10-05 19:08:05 +00:00
void **fontLUT = segmented_to_virtual(menu_font_lut);
2019-08-25 04:46:40 +00:00
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
switch (str[strPos]) {
#ifdef VERSION_EU
case DIALOG_CHAR_UPPER_A_UMLAUT:
2019-10-05 19:08:05 +00:00
print_menu_char_umlaut(curX, curY, ASCII_TO_DIALOG('A'));
2019-08-25 04:46:40 +00:00
curX += gDialogCharWidths[str[strPos]];
break;
case DIALOG_CHAR_UPPER_U_UMLAUT:
2019-10-05 19:08:05 +00:00
print_menu_char_umlaut(curX, curY, ASCII_TO_DIALOG('U'));
2019-08-25 04:46:40 +00:00
curX += gDialogCharWidths[str[strPos]];
break;
case DIALOG_CHAR_UPPER_O_UMLAUT:
2019-10-05 19:08:05 +00:00
print_menu_char_umlaut(curX, curY, ASCII_TO_DIALOG('O'));
2019-08-25 04:46:40 +00:00
curX += gDialogCharWidths[str[strPos]];
break;
#else
2020-01-03 15:38:57 +00:00
case DIALOG_CHAR_DAKUTEN:
2019-09-01 19:50:50 +00:00
mark = DIALOG_MARK_DAKUTEN;
break;
2020-01-03 15:38:57 +00:00
case DIALOG_CHAR_PERIOD_OR_HANDAKUTEN:
2019-09-01 19:50:50 +00:00
mark = DIALOG_MARK_HANDAKUTEN;
break;
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
case DIALOG_CHAR_SPACE:
2019-08-25 04:46:40 +00:00
curX += 4;
break;
default:
2019-09-01 19:50:50 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, fontLUT[str[strPos]]);
2019-08-25 04:46:40 +00:00
gDPLoadSync(gDisplayListHead++);
2019-11-03 19:36:27 +00:00
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_8b_BYTES));
2019-08-25 04:46:40 +00:00
gSPTextureRectangle(gDisplayListHead++, curX << 2, curY << 2, (curX + 8) << 2,
2019-10-05 19:08:05 +00:00
(curY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
#ifndef VERSION_EU
if (mark != DIALOG_MARK_NONE) {
2019-09-01 19:50:50 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_8b, 1, fontLUT[mark + 0xEF]);
2019-08-25 04:46:40 +00:00
gDPLoadSync(gDisplayListHead++);
2019-11-03 19:36:27 +00:00
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_8b_BYTES));
2019-08-25 04:46:40 +00:00
gSPTextureRectangle(gDisplayListHead++, (curX + 6) << 2, (curY - 7) << 2,
2019-10-05 19:08:05 +00:00
(curX + 14) << 2, (curY + 1) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
mark = DIALOG_MARK_NONE;
}
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
curX += 9;
#else
2019-09-01 19:50:50 +00:00
curX += gDialogCharWidths[str[strPos]];
2019-08-25 04:46:40 +00:00
#endif
}
strPos++;
}
}
2019-10-05 19:08:05 +00:00
void print_credits_string(s16 x, s16 y, const u8 *str) {
2019-08-25 04:46:40 +00:00
s32 strPos = 0;
2019-10-05 19:08:05 +00:00
void **fontLUT = segmented_to_virtual(main_credits_font_lut);
2019-08-25 04:46:40 +00:00
u32 curX = x;
u32 curY = y;
2019-11-03 19:36:27 +00:00
gDPSetTile(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0,
G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD);
2019-09-01 19:50:50 +00:00
gDPTileSync(gDisplayListHead++);
2019-11-03 19:36:27 +00:00
gDPSetTile(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 2, 0, G_TX_RENDERTILE, 0,
G_TX_CLAMP, 3, G_TX_NOLOD, G_TX_CLAMP, 3, G_TX_NOLOD);
gDPSetTileSize(gDisplayListHead++, G_TX_RENDERTILE, 0, 0, (8 - 1) << G_TEXTURE_IMAGE_FRAC, (8 - 1) << G_TEXTURE_IMAGE_FRAC);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
while (str[strPos] != GLOBAR_CHAR_TERMINATOR) {
2019-08-25 04:46:40 +00:00
switch (str[strPos]) {
2019-10-05 19:08:05 +00:00
case GLOBAL_CHAR_SPACE:
2019-08-25 04:46:40 +00:00
curX += 4;
break;
default:
gDPPipeSync(gDisplayListHead++);
2019-09-01 19:50:50 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, fontLUT[str[strPos]]);
2019-08-25 04:46:40 +00:00
gDPLoadSync(gDisplayListHead++);
2019-11-03 19:36:27 +00:00
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 8 * 8 - 1, CALC_DXT(8, G_IM_SIZ_16b_BYTES));
2019-08-25 04:46:40 +00:00
gSPTextureRectangle(gDisplayListHead++, curX << 2, curY << 2, (curX + 8) << 2,
2019-10-05 19:08:05 +00:00
(curY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
curX += 7;
break;
}
strPos++;
}
}
2019-10-05 19:08:05 +00:00
void handle_menu_scrolling(s8 scrollDirection, s8 *currentIndex, s8 minIndex, s8 maxIndex) {
u8 index = 0;
2019-08-25 04:46:40 +00:00
if (scrollDirection == MENU_SCROLL_VERTICAL) {
2019-09-01 19:50:50 +00:00
if (gPlayer3Controller->rawStickY > 60) {
2019-10-05 19:08:05 +00:00
index++;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (gPlayer3Controller->rawStickY < -60) {
2019-10-05 19:08:05 +00:00
index += 2;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
} else if (scrollDirection == MENU_SCROLL_HORIZONTAL) {
2019-09-01 19:50:50 +00:00
if (gPlayer3Controller->rawStickX > 60) {
2019-10-05 19:08:05 +00:00
index += 2;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (gPlayer3Controller->rawStickX < -60) {
2019-10-05 19:08:05 +00:00
index++;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
if (((index ^ gMenuHoldKeyIndex) & index) == 2) {
2019-09-01 19:50:50 +00:00
if (currentIndex[0] == maxIndex) {
//! Probably originally a >=, but later replaced with an == and an else statement.
currentIndex[0] = maxIndex;
2019-08-25 04:46:40 +00:00
} else {
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
currentIndex[0]++;
}
}
2019-10-05 19:08:05 +00:00
if (((index ^ gMenuHoldKeyIndex) & index) == 1) {
2019-09-01 19:50:50 +00:00
if (currentIndex[0] == minIndex) {
// Same applies to here as above
2019-08-25 04:46:40 +00:00
} else {
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
currentIndex[0]--;
}
}
2019-10-05 19:08:05 +00:00
if (gMenuHoldKeyTimer == 10) {
gMenuHoldKeyTimer = 8;
gMenuHoldKeyIndex = 0;
2019-08-25 04:46:40 +00:00
} else {
2019-10-05 19:08:05 +00:00
gMenuHoldKeyTimer++;
gMenuHoldKeyIndex = index;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
if ((index & 3) == 0) {
gMenuHoldKeyTimer = 0;
2019-08-25 04:46:40 +00:00
}
}
// EU has both get_str_x_pos_from_center and get_str_x_pos_from_center_scale
2019-09-01 19:50:50 +00:00
// US and JP only implement one or the other
2019-08-25 04:46:40 +00:00
#if defined(VERSION_US) || defined(VERSION_EU)
s16 get_str_x_pos_from_center(s16 centerPos, u8 *str, UNUSED f32 scale) {
s16 strPos = 0;
f32 spacesWidth = 0.0f;
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
spacesWidth += gDialogCharWidths[str[strPos]];
strPos++;
}
// return the x position of where the string starts as half the string's
// length from the position of the provided center.
return (s16)(centerPos - (s16)(spacesWidth / 2.0));
}
#endif
2020-03-02 03:42:52 +00:00
#if defined(VERSION_JP) || defined(VERSION_EU) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
s16 get_str_x_pos_from_center_scale(s16 centerPos, u8 *str, f32 scale) {
s16 strPos = 0;
f32 charsWidth = 0.0f;
f32 spacesWidth = 0.0f;
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
//! EU checks for dakuten and handakuten despite dialog code unable to handle it
2019-09-01 19:50:50 +00:00
if (str[strPos] == DIALOG_CHAR_SPACE) {
2019-08-25 04:46:40 +00:00
spacesWidth += 1.0;
2020-01-03 15:38:57 +00:00
} else if (str[strPos] != DIALOG_CHAR_DAKUTEN
&& str[strPos] != DIALOG_CHAR_PERIOD_OR_HANDAKUTEN) {
2019-08-25 04:46:40 +00:00
charsWidth += 1.0;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
strPos++;
}
// return the x position of where the string starts as half the string's
// length from the position of the provided center.
return (f32) centerPos - (scale * (charsWidth / 2.0)) - ((scale / 2.0) * (spacesWidth / 2.0));
}
#endif
2020-04-03 18:57:26 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
s16 get_string_width(u8 *str) {
2019-08-25 04:46:40 +00:00
s16 strPos = 0;
s16 width = 0;
while (str[strPos] != DIALOG_CHAR_TERMINATOR) {
width += gDialogCharWidths[str[strPos]];
strPos++;
}
return width;
}
#endif
2019-10-05 19:08:05 +00:00
u8 gHudSymCoin[] = { GLYPH_COIN, GLYPH_SPACE };
u8 gHudSymX[] = { GLYPH_MULTIPLY, GLYPH_SPACE };
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
void print_hud_my_score_coins(s32 useCourseCoinScore, s8 fileNum, s8 courseNum, s16 x, s16 y) {
2019-08-25 04:46:40 +00:00
u8 strNumCoins[4];
s16 numCoins;
2019-09-01 19:50:50 +00:00
if (!useCourseCoinScore) {
2019-10-05 19:08:05 +00:00
numCoins = (u16)(save_file_get_max_coin_score(courseNum) & 0xFFFF);
2019-09-01 19:50:50 +00:00
} else {
2019-10-05 19:08:05 +00:00
numCoins = save_file_get_course_coin_score(fileNum, courseNum);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
if (numCoins != 0) {
2019-10-05 19:08:05 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, x, y, gHudSymCoin);
print_hud_lut_string(HUD_LUT_GLOBAL, x + 16, y, gHudSymX);
int_to_str(numCoins, strNumCoins);
print_hud_lut_string(HUD_LUT_GLOBAL, x + 32, y, strNumCoins);
2019-08-25 04:46:40 +00:00
}
}
2019-10-05 19:08:05 +00:00
void print_hud_my_score_stars(s8 fileNum, s8 courseNum, s16 x, s16 y) {
2019-08-25 04:46:40 +00:00
u8 strStarCount[4];
s16 starCount;
2019-10-05 19:08:05 +00:00
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
2019-08-25 04:46:40 +00:00
UNUSED u16 unused;
2019-10-05 19:08:05 +00:00
u8 textSymX[] = { GLYPH_MULTIPLY, GLYPH_SPACE };
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
starCount = save_file_get_course_star_count(fileNum, courseNum);
2019-08-25 04:46:40 +00:00
if (starCount != 0) {
2019-10-05 19:08:05 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, x, y, textSymStar);
print_hud_lut_string(HUD_LUT_GLOBAL, x + 16, y, textSymX);
int_to_str(starCount, strStarCount);
print_hud_lut_string(HUD_LUT_GLOBAL, x + 32, y, strStarCount);
2019-08-25 04:46:40 +00:00
}
}
2019-10-05 19:08:05 +00:00
void int_to_str(s32 num, u8 *dst) {
2019-08-25 04:46:40 +00:00
s32 digit1;
s32 digit2;
s32 digit3;
s8 pos = 0;
if (num > 999) {
2020-02-03 05:51:26 +00:00
dst[0] = 0x00; dst[1] = DIALOG_CHAR_TERMINATOR;
2019-08-25 04:46:40 +00:00
return;
}
digit1 = num / 100;
digit2 = (num - digit1 * 100) / 10;
digit3 = (num - digit1 * 100) - (digit2 * 10);
2019-09-01 19:50:50 +00:00
if (digit1 != 0) {
2019-08-25 04:46:40 +00:00
dst[pos++] = digit1;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (digit2 != 0 || digit1 != 0) {
2019-08-25 04:46:40 +00:00
dst[pos++] = digit2;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
dst[pos++] = digit3;
dst[pos] = DIALOG_CHAR_TERMINATOR;
}
s16 get_dialog_id(void) {
return gDialogID;
}
2019-10-05 19:08:05 +00:00
void create_dialog_box(s16 dialog) {
2019-08-25 04:46:40 +00:00
if (gDialogID == -1) {
2019-10-05 19:08:05 +00:00
gDialogID = dialog;
2019-08-25 04:46:40 +00:00
gDialogBoxType = DIALOG_TYPE_ROTATE;
}
}
2019-10-05 19:08:05 +00:00
void create_dialog_box_with_var(s16 dialog, s32 dialogVar) {
2019-08-25 04:46:40 +00:00
if (gDialogID == -1) {
2019-10-05 19:08:05 +00:00
gDialogID = dialog;
gDialogVariable = dialogVar;
2019-08-25 04:46:40 +00:00
gDialogBoxType = DIALOG_TYPE_ROTATE;
}
}
2019-10-05 19:08:05 +00:00
void create_dialog_inverted_box(s16 dialog) {
2019-08-25 04:46:40 +00:00
if (gDialogID == -1) {
2019-10-05 19:08:05 +00:00
gDialogID = dialog;
2019-08-25 04:46:40 +00:00
gDialogBoxType = DIALOG_TYPE_ZOOM;
}
}
2019-10-05 19:08:05 +00:00
void create_dialog_box_with_response(s16 dialog) {
2019-08-25 04:46:40 +00:00
if (gDialogID == -1) {
2019-10-05 19:08:05 +00:00
gDialogID = dialog;
2019-08-25 04:46:40 +00:00
gDialogBoxType = DIALOG_TYPE_ROTATE;
2019-10-05 19:08:05 +00:00
gLastDialogResponse = 1;
2019-08-25 04:46:40 +00:00
}
}
2019-10-05 19:08:05 +00:00
void reset_dialog_render_state(void) {
2019-08-25 04:46:40 +00:00
level_set_transition(0, 0);
2019-09-01 19:50:50 +00:00
if (gDialogBoxType == DIALOG_TYPE_ZOOM) {
2020-01-03 15:38:57 +00:00
trigger_cutscene_dialog(2);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gDialogBoxScale = 19.0f;
gDialogBoxOpenTimer = 90.0f;
gDialogBoxState = DIALOG_STATE_OPENING;
gDialogID = -1;
2019-10-05 19:08:05 +00:00
gDialogTextPos = 0;
gLastDialogResponse = 0;
2019-08-25 04:46:40 +00:00
gLastDialogPageStrPos = 0;
gDialogResponse = 0;
}
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define X_VAL1 -5.0f
#define Y_VAL1 2.0
#define Y_VAL2 4.0f
#else
#define X_VAL1 -7.0f
#define Y_VAL1 5.0
#define Y_VAL2 5.0f
#endif
2019-10-05 19:08:05 +00:00
void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) {
2019-08-25 04:46:40 +00:00
UNUSED s32 unused;
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, dialog->leftOffset, dialog->width, 0);
2019-08-25 04:46:40 +00:00
switch (gDialogBoxType) {
2019-10-05 19:08:05 +00:00
case DIALOG_TYPE_ROTATE: // Renders a dialog black box with zoom and rotation
2019-08-25 04:46:40 +00:00
if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) {
2019-10-05 19:08:05 +00:00
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f);
// convert the speed into angle
create_dl_rotation_matrix(MENU_MTX_NOPUSH, gDialogBoxOpenTimer * 4.0f, 0, 0, 1.0f);
2019-08-25 04:46:40 +00:00
}
2019-12-02 02:52:53 +00:00
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 150);
2019-08-25 04:46:40 +00:00
break;
2019-10-05 19:08:05 +00:00
case DIALOG_TYPE_ZOOM: // Renders a dialog white box with zoom
2019-08-25 04:46:40 +00:00
if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) {
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, 65.0 - (65.0 / gDialogBoxScale),
2019-08-25 04:46:40 +00:00
(40.0 / gDialogBoxScale) - 40, 0);
2019-10-05 19:08:05 +00:00
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f);
2019-08-25 04:46:40 +00:00
}
2019-12-02 02:52:53 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 150);
2019-08-25 04:46:40 +00:00
break;
}
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL1, Y_VAL1, 0);
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.1f, ((f32) linesPerBox / Y_VAL2) + 0.1, 1.0f);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
2019-10-05 19:08:05 +00:00
void change_and_flash_dialog_text_color_lines(s8 colorMode, s8 lineNum) {
u8 colorFade;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (colorMode == 1) {
if (lineNum == 1) {
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
} else {
2019-10-05 19:08:05 +00:00
if (lineNum == gDialogLineNum) {
colorFade = (gSineTable[gDialogColorFadeTimer >> 4] * 50.0f) + 200.0f;
gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255);
2019-08-25 04:46:40 +00:00
} else {
gDPSetEnvColor(gDisplayListHead++, 200, 200, 200, 255);
}
}
} else {
switch (gDialogBoxType) {
case DIALOG_TYPE_ROTATE:
break;
case DIALOG_TYPE_ZOOM:
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
break;
}
}
}
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
void render_generic_dialog_char_at_pos(struct DialogEntry *dialog, s16 x, s16 y, u8 c) {
2019-08-25 04:46:40 +00:00
s16 width; // sp26
s16 height; // sp24
s16 tmpX;
s16 tmpY;
s16 xCoord; // sp1E
s16 yCoord; // sp1C
2019-10-05 19:08:05 +00:00
void **fontLUT;
2019-08-25 04:46:40 +00:00
void *packedTexture;
void *unpackedTexture;
width = (8.0 - (gDialogBoxScale * 0.8));
height = (16.0 - (gDialogBoxScale * 0.8));
tmpX = (dialog->leftOffset + (65.0 - (65.0 / gDialogBoxScale)));
tmpY = ((240 - dialog->width) - ((40.0 / gDialogBoxScale) - 40));
xCoord = (tmpX + (x / gDialogBoxScale));
yCoord = (tmpY + (y / gDialogBoxScale));
2019-10-05 19:08:05 +00:00
fontLUT = segmented_to_virtual(main_font_lut);
packedTexture = segmented_to_virtual(fontLUT[c]);
2019-08-25 04:46:40 +00:00
unpackedTexture = alloc_ia4_tex_from_i1(packedTexture, 8, 8);
2019-09-01 19:50:50 +00:00
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(unpackedTexture));
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
2019-08-25 04:46:40 +00:00
gSPTextureRectangleFlip(gDisplayListHead++, xCoord << 2, (yCoord - height) << 2,
2020-04-03 18:57:26 +00:00
(xCoord + width) << 2, yCoord << 2, G_TX_RENDERTILE, 8 << 6, 4 << 6, 1 << 10, 1 << 10);
2019-08-25 04:46:40 +00:00
}
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define X_VAL3 5.0f
#define Y_VAL3 20
#else
#define X_VAL3 0.0f
#define Y_VAL3 16
#endif
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
void handle_dialog_scroll_page_state(s8 lineNum, s8 totalLines, s8 *pageState, s8 *xMatrix)
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
void handle_dialog_scroll_page_state(s8 lineNum, s8 totalLines, s8 *pageState, s8 *xMatrix, s16 *linePos)
2019-08-25 04:46:40 +00:00
#endif
{
#ifndef VERSION_EU
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
#endif
2019-10-05 19:08:05 +00:00
if (lineNum == totalLines) {
pageState[0] = DIALOG_PAGE_STATE_SCROLL;
2019-08-25 04:46:40 +00:00
return;
}
#ifdef VERSION_EU
gDialogY += 16;
#else
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL3, 2 - (lineNum * Y_VAL3), 0);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
linePos[0] = 0;
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
xMatrix[0] = 1;
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2020-01-03 15:38:57 +00:00
void adjust_pos_and_print_period_char(s8 *xMatrix, s16 *linePos) {
2019-10-05 19:08:05 +00:00
if (linePos[0] != 0) {
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix[0] * 10, 0, 0);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, -2.0f, -5.0f, 0);
2020-01-03 15:38:57 +00:00
render_generic_char(DIALOG_CHAR_PERIOD_OR_HANDAKUTEN);
2019-08-25 04:46:40 +00:00
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-10-05 19:08:05 +00:00
linePos[0]++;
xMatrix[0] = 1;
2019-08-25 04:46:40 +00:00
}
#endif
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
void render_star_count_dialog_text(struct DialogEntry *dialog, s8 *linePos)
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
void render_star_count_dialog_text(s8 *xMatrix, s16 *linePos)
2019-08-25 04:46:40 +00:00
#endif
{
s8 tensDigit = gDialogVariable / 10;
s8 onesDigit = gDialogVariable - (tensDigit * 10); // remainder
if (tensDigit != 0) {
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix[0] * 10, 0, 0);
2019-08-25 04:46:40 +00:00
render_generic_char(tensDigit);
#elif defined(VERSION_EU)
2019-10-05 19:08:05 +00:00
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, tensDigit);
2019-09-01 19:50:50 +00:00
gDialogX += gDialogCharWidths[tensDigit];
2019-10-05 19:08:05 +00:00
linePos[0] = 1;
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
if (xMatrix[0] != 1) {
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE] * xMatrix[0]), 0, 0);
2019-08-25 04:46:40 +00:00
}
render_generic_char(tensDigit);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32) gDialogCharWidths[tensDigit], 0, 0);
xMatrix[0] = 1;
linePos[0]++;
2019-08-25 04:46:40 +00:00
#endif
}
#ifndef VERSION_EU
else {
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
xMatrix[0]++;
2019-08-25 04:46:40 +00:00
#endif
}
#endif
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, onesDigit);
2019-08-25 04:46:40 +00:00
gDialogX += gDialogCharWidths[onesDigit];
2019-10-05 19:08:05 +00:00
linePos[0] = 1;
2019-08-25 04:46:40 +00:00
#else
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix[0] * 10, 0, 0);
2019-09-01 19:50:50 +00:00
render_generic_char(onesDigit);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
if (xMatrix[0] != 1) {
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE] * (xMatrix[0] - 1)), 0, 0);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
render_generic_char(onesDigit);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32) gDialogCharWidths[onesDigit], 0, 0);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
linePos[0]++;
xMatrix[0] = 1;
2019-08-25 04:46:40 +00:00
#endif
}
2020-03-02 03:42:52 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
void render_multi_text_string_lines(s8 multiTextId, s8 lineNum, s8 linesPerBox, UNUSED s16 linePos, s8 lowerBound, struct DialogEntry *dialog)
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
void render_multi_text_string_lines(s8 multiTextId, s8 lineNum, s16 *linePos, s8 linesPerBox, s8 xMatrix, s8 lowerBound)
2019-08-25 04:46:40 +00:00
#endif
{
s8 i;
struct MultiTextEntry textLengths[2] = {
{ 3, { TEXT_THE_RAW } },
{ 3, { TEXT_YOU_RAW } },
};
2019-10-05 19:08:05 +00:00
if (lineNum >= lowerBound && lineNum <= (lowerBound + linesPerBox)) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_US
2019-10-05 19:08:05 +00:00
if (linePos[0] != 0 || (xMatrix != 1)) {
create_dl_translation_matrix(MENU_MTX_NOPUSH, (gDialogCharWidths[DIALOG_CHAR_SPACE] * (xMatrix - 1)), 0, 0);
2019-08-25 04:46:40 +00:00
}
#endif
for (i = 0; i < textLengths[multiTextId].length; i++) {
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, textLengths[multiTextId].str[i]);
2019-08-25 04:46:40 +00:00
gDialogX += gDialogCharWidths[textLengths[multiTextId].str[i]];
#else
render_generic_char(textLengths[multiTextId].str[i]);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (gDialogCharWidths[textLengths[multiTextId].str[i]]), 0, 0);
2019-08-25 04:46:40 +00:00
#endif
}
}
#ifdef VERSION_US
2019-10-05 19:08:05 +00:00
linePos += textLengths[multiTextId].length;
2019-08-25 04:46:40 +00:00
#endif
}
#endif
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
void render_dialog_lowercase_diacritic(struct DialogEntry *dialog, u8 chr, u8 diacritic) {
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, chr);
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, diacritic + 0xE7);
2019-08-25 04:46:40 +00:00
gDialogX += gDialogCharWidths[chr];
}
2019-10-05 19:08:05 +00:00
void render_dialog_uppercase_diacritic(struct DialogEntry *dialog, u8 chr, u8 diacritic) {
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, chr);
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY - 4, diacritic + 0xE3);
2019-08-25 04:46:40 +00:00
gDialogX += gDialogCharWidths[chr];
}
#endif
2019-10-05 19:08:05 +00:00
u32 ensure_nonnegative(s16 value) {
if (value < 0) {
value = 0;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
return value;
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog)
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 lowerBound)
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
{
2019-10-05 19:08:05 +00:00
UNUSED s32 pad[2];
2020-03-02 03:42:52 +00:00
#ifdef VERSION_EU
s16 startY = 14;
#endif
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
u8 strChar;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
u8 *str = segmented_to_virtual(dialog->str);
s8 lineNum = 1;
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
s8 totalLines;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
s8 pageState = DIALOG_PAGE_STATE_NONE;
2019-09-01 19:50:50 +00:00
UNUSED s8 mark = DIALOG_MARK_NONE; // unused in US, EU
2019-10-05 19:08:05 +00:00
s8 xMatrix = 1;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
s8 linesPerBox = dialog->linesPerBox;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
s16 strIdx;
2019-08-25 04:46:40 +00:00
#ifndef VERSION_EU
2019-10-05 19:08:05 +00:00
s16 linePos = 0;
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
if (gDialogBoxState == DIALOG_STATE_HORIZONTAL) {
// If scrolling, consider the number of lines for both
// the current page and the page being scrolled to.
totalLines = linesPerBox * 2 + 1;
2019-09-01 19:50:50 +00:00
} else {
totalLines = linesPerBox + 1;
}
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-10-05 19:08:05 +00:00
strIdx = gDialogTextPos;
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
gDialogX = 0;
2020-03-02 03:42:52 +00:00
gDialogY = startY;
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
if (gDialogBoxState == DIALOG_STATE_HORIZONTAL) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
gDialogY -= gDialogScrollOffsetY;
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, 0, (f32) gDialogScrollOffsetY, 0);
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
#ifndef VERSION_EU
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL3, 2 - lineNum * Y_VAL3, 0);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
while (pageState == DIALOG_PAGE_STATE_NONE) {
change_and_flash_dialog_text_color_lines(colorMode, lineNum);
2019-09-01 19:50:50 +00:00
strChar = str[strIdx];
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
switch (strChar) {
case DIALOG_CHAR_TERMINATOR:
2019-10-05 19:08:05 +00:00
pageState = DIALOG_PAGE_STATE_END;
2019-08-25 04:46:40 +00:00
#ifndef VERSION_EU
2019-09-01 19:50:50 +00:00
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_NEWLINE:
lineNum++;
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
handle_dialog_scroll_page_state(lineNum, totalLines, &pageState, &xMatrix);
2019-09-01 19:50:50 +00:00
gDialogX = 0;
#else
2019-10-05 19:08:05 +00:00
handle_dialog_scroll_page_state(lineNum, totalLines, &pageState, &xMatrix, &linePos);
2019-09-01 19:50:50 +00:00
#endif
break;
#ifdef VERSION_EU
case DIALOG_CHAR_LOWER_A_GRAVE:
case DIALOG_CHAR_LOWER_A_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_A_UMLAUT:
2019-10-05 19:08:05 +00:00
render_dialog_lowercase_diacritic(dialog, ASCII_TO_DIALOG('a'), strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_UPPER_A_GRAVE:
case DIALOG_CHAR_UPPER_A_CIRCUMFLEX:
case DIALOG_CHAR_UPPER_A_UMLAUT:
2019-10-05 19:08:05 +00:00
render_dialog_uppercase_diacritic(dialog, ASCII_TO_DIALOG('A'), strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_LOWER_E_GRAVE:
case DIALOG_CHAR_LOWER_E_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_E_UMLAUT:
case DIALOG_CHAR_LOWER_E_ACUTE:
2019-10-05 19:08:05 +00:00
render_dialog_lowercase_diacritic(dialog, ASCII_TO_DIALOG('e'), strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_UPPER_E_GRAVE:
case DIALOG_CHAR_UPPER_E_CIRCUMFLEX:
case DIALOG_CHAR_UPPER_E_UMLAUT:
case DIALOG_CHAR_UPPER_E_ACUTE:
2019-10-05 19:08:05 +00:00
render_dialog_uppercase_diacritic(dialog, ASCII_TO_DIALOG('E'), strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_LOWER_U_GRAVE:
case DIALOG_CHAR_LOWER_U_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_U_UMLAUT:
2019-10-05 19:08:05 +00:00
render_dialog_lowercase_diacritic(dialog, ASCII_TO_DIALOG('u'), strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_UPPER_U_GRAVE:
case DIALOG_CHAR_UPPER_U_CIRCUMFLEX:
case DIALOG_CHAR_UPPER_U_UMLAUT:
2019-10-05 19:08:05 +00:00
render_dialog_uppercase_diacritic(dialog, ASCII_TO_DIALOG('U'), strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_LOWER_O_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_O_UMLAUT:
2019-10-05 19:08:05 +00:00
render_dialog_lowercase_diacritic(dialog, ASCII_TO_DIALOG('o'), strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_UPPER_O_CIRCUMFLEX:
case DIALOG_CHAR_UPPER_O_UMLAUT:
2019-10-05 19:08:05 +00:00
render_dialog_uppercase_diacritic(dialog, ASCII_TO_DIALOG('O'), strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_LOWER_I_CIRCUMFLEX:
case DIALOG_CHAR_LOWER_I_UMLAUT:
2019-10-05 19:08:05 +00:00
render_dialog_lowercase_diacritic(dialog, DIALOG_CHAR_I_NO_DIA, strChar & 0xF);
2019-09-01 19:50:50 +00:00
break;
#else
2020-01-03 15:38:57 +00:00
case DIALOG_CHAR_DAKUTEN:
2019-09-01 19:50:50 +00:00
mark = DIALOG_MARK_DAKUTEN;
break;
2020-01-03 15:38:57 +00:00
case DIALOG_CHAR_PERIOD_OR_HANDAKUTEN:
2019-09-01 19:50:50 +00:00
mark = DIALOG_MARK_HANDAKUTEN;
break;
#endif
case DIALOG_CHAR_SPACE:
#ifdef VERSION_EU
gDialogX += gDialogCharWidths[DIALOG_CHAR_SPACE];
2019-08-25 04:46:40 +00:00
#else
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-09-01 19:50:50 +00:00
if (linePos != 0) {
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
xMatrix++;
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-09-01 19:50:50 +00:00
}
#endif
linePos++;
2019-10-05 19:08:05 +00:00
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
break;
2020-03-02 03:42:52 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2020-01-03 15:38:57 +00:00
case DIALOG_CHAR_PERIOD:
adjust_pos_and_print_period_char(&xMatrix, &linePos);
2019-09-01 19:50:50 +00:00
break;
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
case DIALOG_CHAR_SLASH:
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
gDialogX += gDialogCharWidths[DIALOG_CHAR_SPACE] * 2;
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
xMatrix += 2;
2019-09-01 19:50:50 +00:00
linePos += 2;
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_MULTI_THE:
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
render_multi_text_string_lines(STRING_THE, lineNum, linesPerBox, xMatrix, lowerBound, dialog);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
render_multi_text_string_lines(STRING_THE, lineNum, &linePos, linesPerBox, xMatrix, lowerBound);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
xMatrix = 1;
2019-09-01 19:50:50 +00:00
break;
case DIALOG_CHAR_MULTI_YOU:
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
render_multi_text_string_lines(STRING_YOU, lineNum, linesPerBox, xMatrix, lowerBound, dialog);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
render_multi_text_string_lines(STRING_YOU, lineNum, &linePos, linesPerBox, xMatrix, lowerBound);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
xMatrix = 1;
2019-09-01 19:50:50 +00:00
break;
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
case DIALOG_CHAR_STAR_COUNT:
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
render_star_count_dialog_text(dialog, &xMatrix);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
render_star_count_dialog_text(&xMatrix, &linePos);
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
break;
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
case DIALOG_CHAR_DOUBLE_LOW_QUOTE:
2019-10-05 19:08:05 +00:00
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY + 8, 0xF6);
2019-09-01 19:50:50 +00:00
gDialogX += gDialogCharWidths[0xF6];
break;
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
default: // any other character
2020-03-02 03:42:52 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-09-01 19:50:50 +00:00
if (linePos != 0) {
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix * 10, 0, 0);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
render_generic_char(strChar);
2019-10-05 19:08:05 +00:00
xMatrix = 1;
2019-09-01 19:50:50 +00:00
linePos++;
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (mark != 0) {
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, 5.0f, 7.0f, 0);
2019-09-01 19:50:50 +00:00
render_generic_char(mark + 0xEF);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
mark = 0;
}
2019-10-05 19:08:05 +00:00
#elif defined(VERSION_US)
if (lineNum >= lowerBound && lineNum <= lowerBound + linesPerBox) {
if (linePos || xMatrix != 1) {
create_dl_translation_matrix(
MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[DIALOG_CHAR_SPACE] * (xMatrix - 1)), 0, 0);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
render_generic_char(strChar);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[strChar]), 0, 0);
xMatrix = 1;
2019-09-01 19:50:50 +00:00
linePos++;
}
2019-10-05 19:08:05 +00:00
#else // VERSION_EU
if (lineNum >= lowerBound && lineNum <= lowerBound + linesPerBox) {
render_generic_dialog_char_at_pos(dialog, gDialogX, gDialogY, strChar);
}
gDialogX += gDialogCharWidths[strChar];
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-09-01 19:50:50 +00:00
if (linePos == 12) {
2020-01-03 15:38:57 +00:00
if (str[strIdx + 1] == DIALOG_CHAR_PERIOD) {
adjust_pos_and_print_period_char(&xMatrix, &linePos);
2019-09-01 19:50:50 +00:00
strIdx++;
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (str[strIdx + 1] == DIALOG_CHAR_COMMA) {
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, xMatrix * 10, 0, 0);
2019-09-01 19:50:50 +00:00
render_generic_char(DIALOG_CHAR_COMMA);
strIdx++;
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (str[strIdx + 1] == DIALOG_CHAR_NEWLINE) {
strIdx++;
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (str[strIdx + 1] == DIALOG_CHAR_TERMINATOR) {
2019-10-05 19:08:05 +00:00
pageState = DIALOG_PAGE_STATE_END;
2019-09-01 19:50:50 +00:00
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
break; // exit loop
} else {
lineNum++;
2019-10-05 19:08:05 +00:00
handle_dialog_scroll_page_state(lineNum, totalLines, &pageState, &xMatrix, &linePos);
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
strIdx++;
}
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gDialogBoxState == DIALOG_STATE_VERTICAL) {
if (pageState == DIALOG_PAGE_STATE_END) {
2019-09-01 19:50:50 +00:00
gLastDialogPageStrPos = -1;
} else {
gLastDialogPageStrPos = strIdx;
2019-08-25 04:46:40 +00:00
}
}
2019-09-01 19:50:50 +00:00
gLastDialogLineNum = lineNum;
}
2019-08-25 04:46:40 +00:00
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define X_VAL4_1 50
#define X_VAL4_2 25
#define Y_VAL4_1 1
#define Y_VAL4_2 20
#else
#define X_VAL4_1 56
#define X_VAL4_2 47
#define Y_VAL4_1 2
#define Y_VAL4_2 16
#endif
2019-10-05 19:08:05 +00:00
void render_dialog_triangle_choice(void) {
if (gDialogBoxState == DIALOG_STATE_VERTICAL) {
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &gDialogLineNum, 1, 2);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_NOPUSH, (gDialogLineNum * X_VAL4_1) - X_VAL4_2, Y_VAL4_1 - (gLastDialogLineNum * Y_VAL4_2), 0);
2019-08-25 04:46:40 +00:00
if (gDialogBoxType == DIALOG_TYPE_ROTATE) {
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
} else {
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
}
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
}
#ifdef VERSION_EU
#define X_VAL5 122.0f
#define Y_VAL5_1 -16
#define Y_VAL5_2 3
#define X_Y_VAL6 0.5f
#elif defined(VERSION_US)
#define X_VAL5 118.0f
#define Y_VAL5_1 -16
#define Y_VAL5_2 5
#define X_Y_VAL6 0.8f
2020-03-02 03:42:52 +00:00
#elif defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define X_VAL5 123.0f
#define Y_VAL5_1 -20
#define Y_VAL5_2 2
#define X_Y_VAL6 0.8f
#endif
2019-10-05 19:08:05 +00:00
void render_dialog_string_color(s8 linesPerBox) {
s32 timer = gGlobalTimer;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (timer & 0x08) {
2019-08-25 04:46:40 +00:00
return;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL5, (linesPerBox * Y_VAL5_1) + Y_VAL5_2, 0);
create_dl_scale_matrix(MENU_MTX_NOPUSH, X_Y_VAL6, X_Y_VAL6, 1.0f);
create_dl_rotation_matrix(MENU_MTX_NOPUSH, -DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gDialogBoxType == DIALOG_TYPE_ROTATE) { // White Text
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
2019-10-05 19:08:05 +00:00
} else { // Black Text
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
}
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
2019-10-05 19:08:05 +00:00
void handle_special_dialog_text(s16 dialogID) { // dialog ID tables, in order
// King Bob-omb (Start), Whomp (Start), King Bob-omb (throw him out), Eyerock (Start), Wiggler (Start)
s16 dialogBossStart[] = { 17, 114, 128, 117, 150 };
// Koopa the Quick (BOB), Koopa the Quick (THI), Penguin Race, Fat Penguin Race (120 stars)
s16 dialogRaceSound[] = { 5, 9, 55, 164 };
// Red Switch, Green Switch, Blue Switch, 100 coins star, Bowser Red Coin Star
s16 dialogStarSound[] = { 10, 11, 12, 13, 14 };
// King Bob-omb (Start), Whomp (Defeated), King Bob-omb (Defeated, missing in JP), Eyerock (Defeated), Wiggler (Defeated)
#if BUGFIX_KING_BOB_OMB_FADE_MUSIC
s16 dialogBossStop[] = { 17, 115, 116, 118, 152 };
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
//! @bug JP misses King Bob-omb defeated dialog "116", meaning that the boss music will still
//! play after King Bob-omb is defeated until BOB loads it's music after the star cutscene
s16 dialogBossStop[] = { 17, 115, 118, 152 };
2019-08-25 04:46:40 +00:00
#endif
s16 i;
2019-10-05 19:08:05 +00:00
for (i = 0; i < (s16) ARRAY_COUNT(dialogBossStart); i++) {
if (dialogBossStart[i] == dialogID) {
2020-04-03 18:57:26 +00:00
sequence_player_unlower(SEQ_PLAYER_LEVEL, 60);
play_music(SEQ_PLAYER_LEVEL, SEQUENCE_ARGS(4, SEQ_EVENT_BOSS), 0);
2019-08-25 04:46:40 +00:00
return;
}
}
2019-10-05 19:08:05 +00:00
for (i = 0; i < (s16) ARRAY_COUNT(dialogRaceSound); i++) {
if (dialogRaceSound[i] == dialogID && gDialogLineNum == 1) {
2019-08-25 04:46:40 +00:00
play_race_fanfare();
return;
}
}
2019-10-05 19:08:05 +00:00
for (i = 0; i < (s16) ARRAY_COUNT(dialogStarSound); i++) {
if (dialogStarSound[i] == dialogID && gDialogLineNum == 1) {
play_sound(SOUND_MENU_STAR_SOUND, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
return;
}
}
2019-10-05 19:08:05 +00:00
for (i = 0; i < (s16) ARRAY_COUNT(dialogBossStop); i++) {
if (dialogBossStop[i] == dialogID) {
sequence_player_fade_out(0, 1);
2019-08-25 04:46:40 +00:00
return;
}
}
}
2019-10-05 19:08:05 +00:00
s16 gMenuMode = -1;
2019-08-25 04:46:40 +00:00
u8 gEndCutsceneStrEn0[] = { TEXT_FILE_MARIO_EXCLAMATION };
u8 gEndCutsceneStrEn1[] = { TEXT_POWER_STARS_RESTORED };
u8 gEndCutsceneStrEn2[] = { TEXT_THANKS_TO_YOU };
u8 gEndCutsceneStrEn3[] = { TEXT_THANK_YOU_MARIO };
u8 gEndCutsceneStrEn4[] = { TEXT_SOMETHING_SPECIAL };
2019-10-05 19:08:05 +00:00
u8 gEndCutsceneStrEn5[] = { TEXT_LISTEN_EVERYBODY };
2019-08-25 04:46:40 +00:00
u8 gEndCutsceneStrEn6[] = { TEXT_LETS_HAVE_CAKE };
u8 gEndCutsceneStrEn7[] = { TEXT_FOR_MARIO };
u8 gEndCutsceneStrEn8[] = { TEXT_FILE_MARIO_QUESTION };
2019-09-01 19:50:50 +00:00
u8 *gEndCutsceneStringsEn[] = {
gEndCutsceneStrEn0,
gEndCutsceneStrEn1,
gEndCutsceneStrEn2,
gEndCutsceneStrEn3,
gEndCutsceneStrEn4,
gEndCutsceneStrEn5,
gEndCutsceneStrEn6,
gEndCutsceneStrEn7,
// This [8] string is actually unused. In the cutscene handler, the developers do not
// set the 8th one, but use the first string again at the very end, so Peach ends up
// saying "Mario!" twice. It is likely that she was originally meant to say "Mario?" at
// the end but the developers changed their mind, possibly because the line recorded
// sounded more like an exclamation than a question.
gEndCutsceneStrEn8,
NULL
};
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
u8 gEndCutsceneStrFr0[] = { TEXT_FILE_MARIO_EXCLAMATION };
u8 gEndCutsceneStrFr1[] = { TEXT_POWER_STARS_RESTORED_FR };
u8 gEndCutsceneStrFr2[] = { TEXT_THANKS_TO_YOU_FR };
u8 gEndCutsceneStrFr3[] = { TEXT_THANK_YOU_MARIO_FR };
u8 gEndCutsceneStrFr4[] = { TEXT_SOMETHING_SPECIAL_FR };
u8 gEndCutsceneStrFr5[] = { TEXT_COME_ON_EVERYBODY_FR };
u8 gEndCutsceneStrFr6[] = { TEXT_LETS_HAVE_CAKE_FR };
u8 gEndCutsceneStrFr7[] = { TEXT_FOR_MARIO_FR };
u8 gEndCutsceneStrFr8[] = { TEXT_FILE_MARIO_QUESTION };
u8 *gEndCutsceneStringsFr[] = {
2019-09-01 19:50:50 +00:00
gEndCutsceneStrFr0,
gEndCutsceneStrFr1,
gEndCutsceneStrFr2,
gEndCutsceneStrFr3,
gEndCutsceneStrFr4,
gEndCutsceneStrFr5,
gEndCutsceneStrFr6,
gEndCutsceneStrFr7,
gEndCutsceneStrFr8,
NULL
2019-08-25 04:46:40 +00:00
};
u8 gEndCutsceneStrDe0[] = { TEXT_FILE_MARIO_EXCLAMATION };
u8 gEndCutsceneStrDe1[] = { TEXT_POWER_STARS_RESTORED_DE };
u8 gEndCutsceneStrDe2[] = { TEXT_THANKS_TO_YOU_DE };
u8 gEndCutsceneStrDe3[] = { TEXT_THANK_YOU_MARIO_DE };
u8 gEndCutsceneStrDe4[] = { TEXT_SOMETHING_SPECIAL_DE };
u8 gEndCutsceneStrDe5[] = { TEXT_COME_ON_EVERYBODY_DE };
u8 gEndCutsceneStrDe6[] = { TEXT_LETS_HAVE_CAKE_DE };
u8 gEndCutsceneStrDe7[] = { TEXT_FOR_MARIO_DE };
u8 gEndCutsceneStrDe8[] = { TEXT_FILE_MARIO_QUESTION };
u8 *gEndCutsceneStringsDe[] = {
2019-09-01 19:50:50 +00:00
gEndCutsceneStrDe0,
gEndCutsceneStrDe1,
gEndCutsceneStrDe2,
gEndCutsceneStrDe3,
gEndCutsceneStrDe4,
gEndCutsceneStrDe5,
gEndCutsceneStrDe6,
gEndCutsceneStrDe7,
gEndCutsceneStrDe8,
NULL
2019-08-25 04:46:40 +00:00
};
#endif
u16 gCutsceneMsgFade = 0;
s16 gCutsceneMsgIndex = -1;
s16 gCutsceneMsgDuration = -1;
s16 gCutsceneMsgTimer = 0;
2020-01-03 15:38:57 +00:00
s8 gDialogCameraAngleIndex = CAM_SELECTION_MARIO;
2019-10-05 19:08:05 +00:00
s8 gDialogCourseActNum = 1;
2019-08-25 04:46:40 +00:00
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define DIAG_VAL1 20
#define DIAG_VAL3 130
#define DIAG_VAL4 4
#else
#define DIAG_VAL1 16
#define DIAG_VAL3 132 // US & EU
#define DIAG_VAL4 5
#endif
#ifdef VERSION_EU
#define DIAG_VAL2 238
#else
#define DIAG_VAL2 240 // JP & US
#endif
2019-10-05 19:08:05 +00:00
void render_dialog_entries(void) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
s8 lowerBound;
2019-08-25 04:46:40 +00:00
#endif
void **dialogTable;
struct DialogEntry *dialog;
#ifdef VERSION_US
2019-10-05 19:08:05 +00:00
s8 lowerBound;
2019-08-25 04:46:40 +00:00
#endif
#ifdef VERSION_EU
gInGameLanguage = eu_get_language();
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
dialogTable = segmented_to_virtual(dialog_table_eu_en);
break;
case LANGUAGE_FRENCH:
dialogTable = segmented_to_virtual(dialog_table_eu_fr);
break;
case LANGUAGE_GERMAN:
dialogTable = segmented_to_virtual(dialog_table_eu_de);
break;
}
#else
2019-09-01 19:50:50 +00:00
dialogTable = segmented_to_virtual(seg2_dialog_table);
2019-08-25 04:46:40 +00:00
#endif
dialog = segmented_to_virtual(dialogTable[gDialogID]);
// if the dialog entry is invalid, set the ID to -1.
if (segmented_to_virtual(NULL) == dialog) {
gDialogID = -1;
return;
}
#ifdef VERSION_EU
gDialogX = 0;
gDialogY = 0;
#endif
switch (gDialogBoxState) {
case DIALOG_STATE_OPENING:
if (gDialogBoxOpenTimer == DEFAULT_DIALOG_BOX_ANGLE) {
play_dialog_sound(gDialogID);
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
}
if (gDialogBoxType == DIALOG_TYPE_ROTATE) {
gDialogBoxOpenTimer -= 7.5;
gDialogBoxScale -= 1.5;
} else {
gDialogBoxOpenTimer -= 10.0;
gDialogBoxScale -= 2.0;
}
if (gDialogBoxOpenTimer == 0.0f) {
2019-10-05 19:08:05 +00:00
gDialogBoxState = DIALOG_STATE_VERTICAL;
gDialogLineNum = 1;
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
lowerBound = 1;
2019-08-25 04:46:40 +00:00
#endif
break;
2019-10-05 19:08:05 +00:00
case DIALOG_STATE_VERTICAL:
2019-08-25 04:46:40 +00:00
gDialogBoxOpenTimer = 0.0f;
if ((gPlayer3Controller->buttonPressed & A_BUTTON)
|| (gPlayer3Controller->buttonPressed & B_BUTTON)) {
if (gLastDialogPageStrPos == -1) {
2019-10-05 19:08:05 +00:00
handle_special_dialog_text(gDialogID);
2019-08-25 04:46:40 +00:00
gDialogBoxState = DIALOG_STATE_CLOSING;
} else {
2019-10-05 19:08:05 +00:00
gDialogBoxState = DIALOG_STATE_HORIZONTAL;
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
}
}
2020-03-02 03:42:52 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
lowerBound = 1;
2019-08-25 04:46:40 +00:00
#endif
break;
2019-10-05 19:08:05 +00:00
case DIALOG_STATE_HORIZONTAL:
2019-08-25 04:46:40 +00:00
gDialogScrollOffsetY += dialog->linesPerBox * 2;
if (gDialogScrollOffsetY >= dialog->linesPerBox * DIAG_VAL1) {
2019-10-05 19:08:05 +00:00
gDialogTextPos = gLastDialogPageStrPos;
gDialogBoxState = DIALOG_STATE_VERTICAL;
2019-08-25 04:46:40 +00:00
gDialogScrollOffsetY = 0;
}
2020-03-02 03:42:52 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
lowerBound = (gDialogScrollOffsetY / 16) + 1;
2019-08-25 04:46:40 +00:00
#endif
break;
case DIALOG_STATE_CLOSING:
if (gDialogBoxOpenTimer == 20.0f) {
level_set_transition(0, 0);
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_MESSAGE_DISAPPEAR, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (gDialogBoxType == DIALOG_TYPE_ZOOM) {
2020-01-03 15:38:57 +00:00
trigger_cutscene_dialog(2);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
gDialogResponse = gDialogLineNum;
2019-08-25 04:46:40 +00:00
}
gDialogBoxOpenTimer = gDialogBoxOpenTimer + 10.0f;
gDialogBoxScale = gDialogBoxScale + 2.0f;
if (gDialogBoxOpenTimer == DEFAULT_DIALOG_BOX_ANGLE) {
gDialogBoxState = DIALOG_STATE_OPENING;
gDialogID = -1;
2019-10-05 19:08:05 +00:00
gDialogTextPos = 0;
gLastDialogResponse = 0;
2019-08-25 04:46:40 +00:00
gLastDialogPageStrPos = 0;
gDialogResponse = 0;
}
2020-03-02 03:42:52 +00:00
#if !defined(VERSION_JP) && !defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
lowerBound = 1;
2019-08-25 04:46:40 +00:00
#endif
break;
}
2019-10-05 19:08:05 +00:00
render_dialog_box_type(dialog, dialog->linesPerBox);
2019-08-25 04:46:40 +00:00
2020-05-07 18:21:22 +00:00
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE,
#ifdef TARGET_N64
ensure_nonnegative(dialog->leftOffset),
#else
0,
#endif
2019-10-05 19:08:05 +00:00
ensure_nonnegative(DIAG_VAL2 - dialog->width),
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2020-05-07 18:21:22 +00:00
#ifdef TARGET_N64
2019-10-05 19:08:05 +00:00
ensure_nonnegative(dialog->leftOffset + DIAG_VAL3 / gDialogBoxScale),
2020-05-07 18:21:22 +00:00
#else
SCREEN_WIDTH,
#endif
2019-10-05 19:08:05 +00:00
ensure_nonnegative((240 - dialog->width) + ((dialog->linesPerBox * 80) / DIAG_VAL4) / gDialogBoxScale));
2019-08-25 04:46:40 +00:00
#else
2020-05-07 18:21:22 +00:00
#ifdef TARGET_N64
2019-10-05 19:08:05 +00:00
ensure_nonnegative(DIAG_VAL3 + dialog->leftOffset),
2020-05-07 18:21:22 +00:00
#else
SCREEN_WIDTH,
#endif
2019-10-05 19:08:05 +00:00
ensure_nonnegative(240 + ((dialog->linesPerBox * 80) / DIAG_VAL4) - dialog->width));
2019-08-25 04:46:40 +00:00
#endif
2020-03-02 03:42:52 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
handle_dialog_text_and_pages(0, dialog);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
handle_dialog_text_and_pages(0, dialog, lowerBound);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
if (gLastDialogPageStrPos == -1 && gLastDialogResponse == 1) {
render_dialog_triangle_choice();
2019-09-01 19:50:50 +00:00
}
2020-02-03 05:51:26 +00:00
#ifdef VERSION_EU
#undef BORDER_HEIGHT
#define BORDER_HEIGHT 8
#endif
2019-10-05 19:08:05 +00:00
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 2, 2, SCREEN_WIDTH - BORDER_HEIGHT/2, SCREEN_HEIGHT - BORDER_HEIGHT/2);
2020-02-03 05:51:26 +00:00
#ifdef VERSION_EU
#undef BORDER_HEIGHT
#define BORDER_HEIGHT 1
#endif
2019-10-05 19:08:05 +00:00
if (gLastDialogPageStrPos != -1 && gDialogBoxState == DIALOG_STATE_VERTICAL) {
render_dialog_string_color(dialog->linesPerBox);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
// Calls a gMenuMode value defined by render_menus_and_dialogs cases
void set_menu_mode(s16 mode) {
if (gMenuMode == -1) {
gMenuMode = mode;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
void reset_cutscene_msg_fade(void) {
gCutsceneMsgFade = 0;
}
2019-10-05 19:08:05 +00:00
void dl_rgba16_begin_cutscene_msg_fade(void) {
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gCutsceneMsgFade);
}
2019-10-05 19:08:05 +00:00
void dl_rgba16_stop_cutscene_msg_fade(void) {
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
2019-09-01 19:50:50 +00:00
if (gCutsceneMsgFade < 250) {
2019-08-25 04:46:40 +00:00
gCutsceneMsgFade += 25;
2019-09-01 19:50:50 +00:00
} else {
2019-08-25 04:46:40 +00:00
gCutsceneMsgFade = 255;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
u8 ascii_to_credits_char(u8 c) {
2019-09-01 19:50:50 +00:00
if (c >= 'A' && c <= 'Z') {
2019-08-25 04:46:40 +00:00
return (c - ('A' - 0xA));
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (c >= 'a' && c <= 'z') { // remap lower to upper case
2019-08-25 04:46:40 +00:00
return (c - ('a' - 0xA));
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (c == ' ') {
2019-10-05 19:08:05 +00:00
return GLOBAL_CHAR_SPACE;
2019-09-01 19:50:50 +00:00
}
if (c == '.') {
2019-08-25 04:46:40 +00:00
return 0x24;
2019-09-01 19:50:50 +00:00
}
if (c == '3') {
2019-08-25 04:46:40 +00:00
return ASCII_TO_DIALOG('3');
2019-09-01 19:50:50 +00:00
}
if (c == '4') {
2019-08-25 04:46:40 +00:00
return ASCII_TO_DIALOG('4');
2019-09-01 19:50:50 +00:00
}
if (c == '6') {
2019-08-25 04:46:40 +00:00
return ASCII_TO_DIALOG('6');
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
return GLOBAL_CHAR_SPACE;
2019-08-25 04:46:40 +00:00
}
void print_credits_str_ascii(s16 x, s16 y, const char *str) {
s32 pos = 0;
u8 c = str[pos];
u8 creditStr[100];
while (c != 0) {
creditStr[pos++] = ascii_to_credits_char(c);
c = str[pos];
}
2019-10-05 19:08:05 +00:00
creditStr[pos] = GLOBAR_CHAR_TERMINATOR;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
print_credits_string(x, y, creditStr);
2019-08-25 04:46:40 +00:00
}
void set_cutscene_message(s16 xOffset, s16 yOffset, s16 msgIndex, s16 msgDuration) {
// is message done printing?
if (gCutsceneMsgIndex == -1) {
gCutsceneMsgIndex = msgIndex;
gCutsceneMsgDuration = msgDuration;
gCutsceneMsgTimer = 0;
gCutsceneMsgXOffset = xOffset;
gCutsceneMsgYOffset = yOffset;
gCutsceneMsgFade = 0;
}
}
void do_cutscene_handler(void) {
s16 x;
2019-09-01 19:50:50 +00:00
// is a cutscene playing? do not perform this handler's actions if so.
if (gCutsceneMsgIndex == -1) {
2019-08-25 04:46:40 +00:00
return;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
create_dl_ortho_matrix();
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gCutsceneMsgFade);
#ifdef VERSION_EU
switch (eu_get_language()) {
case LANGUAGE_ENGLISH:
2019-09-01 19:50:50 +00:00
x = get_str_x_pos_from_center(gCutsceneMsgXOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex], 10.0f);
2019-10-05 19:08:05 +00:00
print_generic_string(x, 240 - gCutsceneMsgYOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex]);
2019-08-25 04:46:40 +00:00
break;
case LANGUAGE_FRENCH:
2019-09-01 19:50:50 +00:00
x = get_str_x_pos_from_center(gCutsceneMsgXOffset, gEndCutsceneStringsFr[gCutsceneMsgIndex], 10.0f);
2020-02-03 05:51:26 +00:00
print_generic_string(x, 240 - gCutsceneMsgYOffset, gEndCutsceneStringsFr[gCutsceneMsgIndex]);
2019-08-25 04:46:40 +00:00
break;
case LANGUAGE_GERMAN:
2019-09-01 19:50:50 +00:00
x = get_str_x_pos_from_center(gCutsceneMsgXOffset, gEndCutsceneStringsDe[gCutsceneMsgIndex], 10.0f);
2020-02-03 05:51:26 +00:00
print_generic_string(x, 240 - gCutsceneMsgYOffset, gEndCutsceneStringsDe[gCutsceneMsgIndex]);
2019-08-25 04:46:40 +00:00
break;
}
2020-03-02 03:42:52 +00:00
#else
#if defined(VERSION_SH)
// get the x coordinate of where the cutscene string starts.
x = get_str_x_pos_from_center_scale(gCutsceneMsgXOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex], 10.0f);
2019-08-25 04:46:40 +00:00
#else
2019-09-01 19:50:50 +00:00
// get the x coordinate of where the cutscene string starts.
x = get_str_x_pos_from_center(gCutsceneMsgXOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex], 10.0f);
2020-03-02 03:42:52 +00:00
#endif
2019-10-05 19:08:05 +00:00
print_generic_string(x, 240 - gCutsceneMsgYOffset, gEndCutsceneStringsEn[gCutsceneMsgIndex]);
2019-08-25 04:46:40 +00:00
#endif
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-08-25 04:46:40 +00:00
// if the timing variable is less than 5, increment
// the fade until we are at full opacity.
2019-09-01 19:50:50 +00:00
if (gCutsceneMsgTimer < 5) {
2019-08-25 04:46:40 +00:00
gCutsceneMsgFade += 50;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
// if the cutscene frame length + the fade-in counter is
// less than the timer, it means we have exceeded the
// time that the message is supposed to remain on
// screen. if (message_duration = 50) and (msg_timer = 55)
// then after the first 5 frames, the message will remain
// on screen for another 50 frames until it starts fading.
2019-09-01 19:50:50 +00:00
if (gCutsceneMsgDuration + 5 < gCutsceneMsgTimer) {
2019-08-25 04:46:40 +00:00
gCutsceneMsgFade -= 50;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
// like the first check, it takes 5 frames to fade out, so
// perform a + 10 to account for the earlier check (10-5=5).
if (gCutsceneMsgDuration + 10 < gCutsceneMsgTimer) {
gCutsceneMsgIndex = -1;
gCutsceneMsgFade = 0;
gCutsceneMsgTimer = 0;
return;
}
gCutsceneMsgTimer++;
}
#ifndef VERSION_JP
extern Gfx castle_grounds_seg7_us_dl_0700F2E8[];
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define PEACH_MESSAGE_TIMER 170
#else
#define PEACH_MESSAGE_TIMER 250
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define STR_X 53
#define STR_Y 136
#else
#define STR_X 38
#define STR_Y 142
#endif
2019-10-05 19:08:05 +00:00
2019-08-25 04:46:40 +00:00
// "Dear Mario" message handler
void print_peach_letter_message(void) {
void **dialogTable;
struct DialogEntry *dialog;
u8 *str;
#ifdef VERSION_EU
gInGameLanguage = eu_get_language();
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
dialogTable = segmented_to_virtual(dialog_table_eu_en);
break;
case LANGUAGE_FRENCH:
dialogTable = segmented_to_virtual(dialog_table_eu_fr);
break;
case LANGUAGE_GERMAN:
dialogTable = segmented_to_virtual(dialog_table_eu_de);
break;
}
#else
2019-09-01 19:50:50 +00:00
dialogTable = segmented_to_virtual(seg2_dialog_table);
2019-08-25 04:46:40 +00:00
#endif
dialog = segmented_to_virtual(dialogTable[gDialogID]);
str = segmented_to_virtual(dialog->str);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, 97.0f, 118.0f, 0);
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gCutsceneMsgFade);
gSPDisplayList(gDisplayListHead++, castle_grounds_seg7_dl_0700EA58);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 20, 20, 20, gCutsceneMsgFade);
2019-10-05 19:08:05 +00:00
print_generic_string(STR_X, STR_Y, str);
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-10-05 19:08:05 +00:00
#endif
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
2019-10-05 19:08:05 +00:00
#ifndef VERSION_JP
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-09-01 19:50:50 +00:00
gDPSetEnvColor(gDisplayListHead++, 200, 80, 120, gCutsceneMsgFade);
gSPDisplayList(gDisplayListHead++, castle_grounds_seg7_us_dl_0700F2E8);
2019-08-25 04:46:40 +00:00
#endif
// at the start/end of message, reset the fade.
2019-09-01 19:50:50 +00:00
if (gCutsceneMsgTimer == 0) {
2019-08-25 04:46:40 +00:00
gCutsceneMsgFade = 0;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
// we're less than 20 increments, so increase the fade.
2019-09-01 19:50:50 +00:00
if (gCutsceneMsgTimer < 20) {
2019-08-25 04:46:40 +00:00
gCutsceneMsgFade += 10;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
// we're after PEACH_MESSAGE_TIMER increments, so decrease the fade.
2019-09-01 19:50:50 +00:00
if (gCutsceneMsgTimer > PEACH_MESSAGE_TIMER) {
2019-08-25 04:46:40 +00:00
gCutsceneMsgFade -= 10;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
// 20 increments after the start of the decrease, we're
// back where we are, so reset everything at the end.
if (gCutsceneMsgTimer > (PEACH_MESSAGE_TIMER + 20)) {
gCutsceneMsgIndex = -1;
2019-09-01 19:50:50 +00:00
gCutsceneMsgFade = 0; //! uselessly reset since the next execution will just set it to 0 again.
2019-08-25 04:46:40 +00:00
gDialogID = -1;
gCutsceneMsgTimer = 0;
return; // return to avoid incrementing the timer
}
gCutsceneMsgTimer++;
}
2019-10-05 19:08:05 +00:00
/**
* Renders the cannon reticle when Mario is inside a cannon.
* Formed by four triangles.
*/
void render_hud_cannon_reticle(void) {
create_dl_translation_matrix(MENU_MTX_PUSH, 160.0f, 120.0f, 0);
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 50, 50, 50, 180);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, -20.0f, -8.0f, 0);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, 20.0f, 8.0f, 0);
create_dl_rotation_matrix(MENU_MTX_NOPUSH, 180.0f, 0, 0, 1.0f);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, 8.0f, -20.0f, 0);
create_dl_rotation_matrix(MENU_MTX_NOPUSH, DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, -8.0f, 20.0f, 0);
create_dl_rotation_matrix(MENU_MTX_NOPUSH, -DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
2019-10-05 19:08:05 +00:00
void reset_red_coins_collected(void) {
gRedCoinsCollected = 0;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
void change_dialog_camera_angle(void) {
2020-01-03 15:38:57 +00:00
if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) {
gDialogCameraAngleIndex = CAM_SELECTION_MARIO;
2019-09-01 19:50:50 +00:00
} else {
2020-01-03 15:38:57 +00:00
gDialogCameraAngleIndex = CAM_SELECTION_FIXED;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
void shade_screen(void) {
2020-05-07 18:21:22 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 240.0f, 0);
// This is a bit weird. It reuses the dialog text box (width 130, height -80),
// so scale to at least fit the screen.
#ifdef TARGET_N64
2019-10-05 19:08:05 +00:00
create_dl_scale_matrix(MENU_MTX_NOPUSH, 2.6f, 3.4f, 1.0f);
2020-05-07 18:21:22 +00:00
#else
create_dl_scale_matrix(MENU_MTX_NOPUSH,
GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT / 130.0f, 3.0f, 1.0f);
#endif
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 110);
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
2019-10-05 19:08:05 +00:00
void print_animated_red_coin(s16 x, s16 y) {
2019-08-25 04:46:40 +00:00
s32 timer = gGlobalTimer;
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, x, y, 0);
create_dl_scale_matrix(MENU_MTX_NOPUSH, 0.2f, 0.2f, 1.0f);
2019-08-25 04:46:40 +00:00
gDPSetRenderMode(gDisplayListHead++, G_RM_TEX_EDGE, G_RM_TEX_EDGE2);
switch (timer & 6) {
case 0:
gSPDisplayList(gDisplayListHead++, coin_seg3_dl_03007940);
break;
case 2:
gSPDisplayList(gDisplayListHead++, coin_seg3_dl_03007968);
break;
case 4:
gSPDisplayList(gDisplayListHead++, coin_seg3_dl_03007990);
break;
case 6:
gSPDisplayList(gDisplayListHead++, coin_seg3_dl_030079B8);
break;
}
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
2019-10-05 19:08:05 +00:00
void render_pause_red_coins(void) {
s8 x;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
for (x = 0; x < gRedCoinsCollected; x++) {
2020-05-07 18:21:22 +00:00
print_animated_red_coin(GFX_DIMENSIONS_FROM_RIGHT_EDGE(30) - x * 20, 16);
2019-08-25 04:46:40 +00:00
}
}
#ifdef VERSION_EU
u8 gTextCourseArr[][7] = { // D_802FDA10
{ TEXT_COURSE },
{ TEXT_COURSE_FR },
{ TEXT_COURSE_DE }
};
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define CRS_NUM_X1 93
#else
#define CRS_NUM_X1 100
#endif
#ifdef VERSION_EU
#define TXT_STAR_X 89
#define ACT_NAME_X 107
#define LVL_NAME_X 108
2019-10-05 19:08:05 +00:00
#define MYSCORE_X 48
2019-08-25 04:46:40 +00:00
#else
#define TXT_STAR_X 98
#define ACT_NAME_X 116
#define LVL_NAME_X 117
2019-10-05 19:08:05 +00:00
#define MYSCORE_X 62
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
void render_pause_my_score_coins(void) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
u8 textMyScore[][10] = {
{ TEXT_MY_SCORE },
{ TEXT_MY_SCORE_FR },
{ TEXT_MY_SCORE_DE }
};
#define textMyScore textMyScore[gInGameLanguage]
2019-08-25 04:46:40 +00:00
#else
2019-09-01 19:50:50 +00:00
u8 textCourse[] = { TEXT_COURSE };
u8 textMyScore[] = { TEXT_MY_SCORE };
2019-08-25 04:46:40 +00:00
#endif
u8 textStar[] = { TEXT_STAR };
u8 textUnfilledStar[] = { TEXT_UNFILLED_STAR };
u8 strCourseNum[4];
2019-12-02 02:52:53 +00:00
void **courseNameTbl;
u8 *courseName;
2019-08-25 04:46:40 +00:00
void **actNameTbl;
u8 *actName;
u8 courseIndex;
u8 starFlags;
#ifndef VERSION_EU
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
2019-08-25 04:46:40 +00:00
actNameTbl = segmented_to_virtual(seg2_act_name_table);
#endif
courseIndex = gCurrCourseNum - 1;
starFlags = save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1);
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
2019-08-25 04:46:40 +00:00
break;
case LANGUAGE_FRENCH:
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
2019-08-25 04:46:40 +00:00
break;
case LANGUAGE_GERMAN:
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
2019-08-25 04:46:40 +00:00
break;
}
#endif
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
if (courseIndex < COURSE_STAGES_COUNT) {
2019-10-05 19:08:05 +00:00
print_hud_my_score_coins(1, gCurrSaveFileNum - 1, courseIndex, 178, 103);
print_hud_my_score_stars(gCurrSaveFileNum - 1, courseIndex, 118, 103);
2019-08-25 04:46:40 +00:00
}
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (courseIndex < COURSE_STAGES_COUNT && save_file_get_course_star_count(gCurrSaveFileNum - 1, courseIndex) != 0) {
2019-10-05 19:08:05 +00:00
print_generic_string(MYSCORE_X, 121, textMyScore);
2019-08-25 04:46:40 +00:00
}
2019-12-02 02:52:53 +00:00
courseName = segmented_to_virtual(courseNameTbl[courseIndex]);
2019-08-25 04:46:40 +00:00
if (courseIndex < COURSE_STAGES_COUNT) {
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
print_generic_string(48, 157, gTextCourseArr[gInGameLanguage]);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
print_generic_string(63, 157, textCourse);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
int_to_str(gCurrCourseNum, strCourseNum);
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
print_generic_string(get_string_width(gTextCourseArr[gInGameLanguage]) + 51, 157, strCourseNum);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
print_generic_string(CRS_NUM_X1, 157, strCourseNum);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
actName = segmented_to_virtual(actNameTbl[(gCurrCourseNum - 1) * 6 + gDialogCourseActNum - 1]);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (starFlags & (1 << (gDialogCourseActNum - 1))) {
print_generic_string(TXT_STAR_X, 140, textStar);
2019-09-01 19:50:50 +00:00
} else {
2019-10-05 19:08:05 +00:00
print_generic_string(TXT_STAR_X, 140, textUnfilledStar);
2019-09-01 19:50:50 +00:00
}
2019-10-05 19:08:05 +00:00
print_generic_string(ACT_NAME_X, 140, actName);
2019-08-25 04:46:40 +00:00
#ifndef VERSION_JP
2019-12-02 02:52:53 +00:00
print_generic_string(LVL_NAME_X, 157, &courseName[3]);
2019-08-25 04:46:40 +00:00
#endif
}
#ifndef VERSION_JP
else {
#ifdef VERSION_US
2019-12-02 02:52:53 +00:00
print_generic_string(94, 157, &courseName[3]);
2019-08-25 04:46:40 +00:00
#elif defined(VERSION_EU)
2019-12-02 02:52:53 +00:00
print_generic_string(get_str_x_pos_from_center(159, &courseName[3], 10.0f), 157, &courseName[3]);
2019-08-25 04:46:40 +00:00
#endif
}
#else
2019-12-02 02:52:53 +00:00
print_generic_string(117, 157, &courseName[3]);
2019-08-25 04:46:40 +00:00
#endif
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-08-25 04:46:40 +00:00
}
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define TXT1_X 4
#define TXT2_X 116
#define Y_VAL7 0
#else
#define TXT1_X 3
#define TXT2_X 119
#define Y_VAL7 2
#endif
2019-10-05 19:08:05 +00:00
void render_pause_camera_options(s16 x, s16 y, s8 *index, s16 xIndex) {
2019-08-25 04:46:40 +00:00
u8 textLakituMario[] = { TEXT_LAKITU_MARIO };
u8 textLakituStop[] = { TEXT_LAKITU_STOP };
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
u8 textNormalUpClose[][20] = {
{ TEXT_NORMAL_UPCLOSE },
{ TEXT_NORMAL_UPCLOSE_FR },
{ TEXT_NORMAL_UPCLOSE_DE }
};
2019-08-25 04:46:40 +00:00
u8 textNormalFixed[][17] = {
{ TEXT_NORMAL_FIXED },
{ TEXT_NORMAL_FIXED_FR },
{ TEXT_NORMAL_FIXED_DE },
};
2019-10-05 19:08:05 +00:00
#define textNormalUpClose textNormalUpClose[gInGameLanguage]
#define textNormalFixed textNormalFixed[gInGameLanguage]
2019-08-25 04:46:40 +00:00
#else
2019-09-01 19:50:50 +00:00
u8 textNormalUpClose[] = { TEXT_NORMAL_UPCLOSE };
u8 textNormalFixed[] = { TEXT_NORMAL_FIXED };
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, index, 1, 2);
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
print_generic_string(x + 14, y + 2, textLakituMario);
print_generic_string(x + TXT1_X, y - 13, textNormalUpClose);
print_generic_string(x + 124, y + 2, textLakituStop);
print_generic_string(x + TXT2_X, y - 13, textNormalFixed);
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, ((index[0] - 1) * xIndex) + x, y + Y_VAL7, 0);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-10-05 19:08:05 +00:00
switch (index[0]) {
2019-08-25 04:46:40 +00:00
case 1:
2020-01-03 15:38:57 +00:00
cam_select_alt_mode(1);
2019-08-25 04:46:40 +00:00
break;
case 2:
2020-01-03 15:38:57 +00:00
cam_select_alt_mode(2);
2019-08-25 04:46:40 +00:00
break;
}
}
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define X_VAL8 0
#define Y_VAL8 4
#else
#define X_VAL8 4
#define Y_VAL8 2
#endif
2019-10-05 19:08:05 +00:00
void render_pause_course_options(s16 x, s16 y, s8 *index, s16 yIndex) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
u8 textContinue[][10] = {
{ TEXT_CONTINUE },
{ TEXT_CONTINUE_FR },
{ TEXT_CONTINUE_DE }
};
u8 textExitCourse[][15] = {
{ TEXT_EXIT_COURSE },
{ TEXT_EXIT_COURSE_FR },
{ TEXT_EXIT_COURSE_DE }
};
u8 textCameraAngleR[][24] = {
2019-10-05 19:08:05 +00:00
{ TEXT_CAMERA_ANGLE_R },
2019-09-01 19:50:50 +00:00
{ TEXT_CAMERA_ANGLE_R_FR },
{ TEXT_CAMERA_ANGLE_R_DE }
};
2019-10-05 19:08:05 +00:00
#define textContinue textContinue[gInGameLanguage]
#define textExitCourse textExitCourse[gInGameLanguage]
#define textCameraAngleR textCameraAngleR[gInGameLanguage]
2019-08-25 04:46:40 +00:00
#else
2019-09-01 19:50:50 +00:00
u8 textContinue[] = { TEXT_CONTINUE };
u8 textExitCourse[] = { TEXT_EXIT_COURSE };
u8 textCameraAngleR[] = { TEXT_CAMERA_ANGLE_R };
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
handle_menu_scrolling(MENU_SCROLL_VERTICAL, index, 1, 3);
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
print_generic_string(x + 10, y - 2, textContinue);
print_generic_string(x + 10, y - 17, textExitCourse);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (index[0] != 3) {
print_generic_string(x + 10, y - 33, textCameraAngleR);
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, x - X_VAL8, (y - ((index[0] - 1) * yIndex)) - Y_VAL8, 0);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
2019-10-05 19:08:05 +00:00
if (index[0] == 3) {
render_pause_camera_options(x - 42, y - 42, &gDialogCameraAngleIndex, 110);
2019-08-25 04:46:40 +00:00
}
}
2019-10-05 19:08:05 +00:00
void render_pause_castle_menu_box(s16 x, s16 y) {
create_dl_translation_matrix(MENU_MTX_PUSH, x - 78, y - 32, 0);
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.2f, 0.8f, 1.0f);
2019-08-25 04:46:40 +00:00
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 105);
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, x + 6, y - 28, 0);
create_dl_rotation_matrix(MENU_MTX_NOPUSH, DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, x - 9, y - 101, 0);
create_dl_rotation_matrix(MENU_MTX_NOPUSH, 270.0f, 0, 0, 1.0f);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
2019-10-05 19:08:05 +00:00
void highlight_last_course_complete_stars(void) {
u8 courseDone;
2019-08-25 04:46:40 +00:00
2020-04-03 18:57:26 +00:00
if (gLastCompletedCourseNum == COURSE_NONE) {
2019-10-05 19:08:05 +00:00
courseDone = 0;
2019-08-25 04:46:40 +00:00
} else {
2019-10-05 19:08:05 +00:00
courseDone = gLastCompletedCourseNum - 1;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (courseDone >= COURSE_STAGES_COUNT) {
courseDone = COURSE_STAGES_COUNT;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
gDialogLineNum = courseDone;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
void print_hud_pause_colorful_str(void) {
u8 textPause[] = { TEXT_PAUSE };
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2020-05-07 18:21:22 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, get_str_x_pos_from_center_scale(
SCREEN_WIDTH / 2, textPause, 12.0f), 81, textPause);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, 123, 81, textPause);
2019-08-25 04:46:40 +00:00
#endif
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
}
2019-10-05 19:08:05 +00:00
void render_pause_castle_course_stars(s16 x, s16 y, s16 fileNum, s16 courseNum) {
s16 hasStar = 0;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
u8 str[COURSE_STAGES_COUNT * 2];
2019-08-25 04:46:40 +00:00
u8 textStar[] = { TEXT_STAR };
2019-10-05 19:08:05 +00:00
u8 starFlags = save_file_get_star_flags(fileNum, courseNum);
u16 starCount = save_file_get_course_star_count(fileNum, courseNum);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
u16 nextStar = 0;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (starFlags & 0x40) {
starCount--;
print_generic_string(x + 89, y - 5, textStar);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
while (hasStar != starCount) {
if (starFlags & (1 << nextStar)) {
str[nextStar * 2] = DIALOG_CHAR_STAR_FILLED;
hasStar++;
2019-08-25 04:46:40 +00:00
} else {
2019-10-05 19:08:05 +00:00
str[nextStar * 2] = DIALOG_CHAR_STAR_OPEN;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
str[nextStar * 2 + 1] = DIALOG_CHAR_SPACE;
nextStar++;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
if (starCount == nextStar && starCount != 6) {
str[nextStar * 2] = DIALOG_CHAR_STAR_OPEN;
str[nextStar * 2 + 1] = DIALOG_CHAR_SPACE;
nextStar++;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
str[nextStar * 2] = DIALOG_CHAR_TERMINATOR;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
print_generic_string(x + 14, y + 13, str);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
void render_pause_castle_main_strings(s16 x, s16 y) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-12-02 02:52:53 +00:00
void **courseNameTbl;
2019-08-25 04:46:40 +00:00
#else
2019-12-02 02:52:53 +00:00
void **courseNameTbl = segmented_to_virtual(seg2_course_name_table);
2019-08-25 04:46:40 +00:00
#endif
#ifdef VERSION_EU
u8 textCoin[] = { TEXT_COIN };
u8 textX[] = { TEXT_VARIABLE_X };
#else
2019-09-01 19:50:50 +00:00
u8 textCoin[] = { TEXT_COIN_X };
2019-08-25 04:46:40 +00:00
#endif
2019-12-02 02:52:53 +00:00
void *courseName;
2019-08-25 04:46:40 +00:00
u8 strVal[8];
2019-10-05 19:08:05 +00:00
s16 starNum = gDialogLineNum;
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
2019-08-25 04:46:40 +00:00
break;
case LANGUAGE_FRENCH:
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
2019-08-25 04:46:40 +00:00
break;
case LANGUAGE_GERMAN:
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
2019-08-25 04:46:40 +00:00
break;
}
#endif
2019-10-05 19:08:05 +00:00
handle_menu_scrolling(MENU_SCROLL_VERTICAL, &gDialogLineNum, -1, COURSE_STAGES_COUNT + 1);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gDialogLineNum == COURSE_STAGES_COUNT + 1) {
gDialogLineNum = 0;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gDialogLineNum == -1) {
gDialogLineNum = COURSE_STAGES_COUNT;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gDialogLineNum != COURSE_STAGES_COUNT) {
while (save_file_get_course_star_count(gCurrSaveFileNum - 1, gDialogLineNum) == 0) {
if (gDialogLineNum >= starNum) {
gDialogLineNum++;
2019-09-01 19:50:50 +00:00
} else {
2019-10-05 19:08:05 +00:00
gDialogLineNum--;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gDialogLineNum == COURSE_STAGES_COUNT || gDialogLineNum == -1) {
gDialogLineNum = COURSE_STAGES_COUNT;
2019-08-25 04:46:40 +00:00
break;
}
}
}
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gDialogLineNum < COURSE_STAGES_COUNT) {
2019-12-02 02:52:53 +00:00
courseName = segmented_to_virtual(courseNameTbl[gDialogLineNum]);
2019-10-05 19:08:05 +00:00
render_pause_castle_course_stars(x, y, gCurrSaveFileNum - 1, gDialogLineNum);
print_generic_string(x + 34, y - 5, textCoin);
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
print_generic_string(x + 44, y - 5, textX);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
int_to_str(save_file_get_course_coin_score(gCurrSaveFileNum - 1, gDialogLineNum), strVal);
print_generic_string(x + 54, y - 5, strVal);
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-12-02 02:52:53 +00:00
print_generic_string(x - 17, y + 30, courseName);
2019-08-25 04:46:40 +00:00
#endif
} else {
u8 textStarX[] = { TEXT_STAR_X };
2019-12-02 02:52:53 +00:00
courseName = segmented_to_virtual(courseNameTbl[COURSE_MAX]);
2019-10-05 19:08:05 +00:00
print_generic_string(x + 40, y + 13, textStarX);
int_to_str(save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_BONUS_STAGES - 1, COURSE_MAX - 1), strVal);
print_generic_string(x + 60, y + 13, strVal);
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-12-02 02:52:53 +00:00
print_generic_string(get_str_x_pos_from_center(x + 51, courseName, 10.0f), y + 30, courseName);
2019-08-25 04:46:40 +00:00
#endif
}
#ifndef VERSION_EU
2019-12-02 02:52:53 +00:00
print_generic_string(x - 9, y + 30, courseName);
2019-08-25 04:46:40 +00:00
#endif
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
s8 gCourseCompleteCoinsEqual = 0;
s32 gCourseDoneMenuTimer = 0;
s32 gCourseCompleteCoins = 0;
s8 gHudFlash = 0;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
s16 render_pause_courses_and_castle(void) {
s16 num;
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
gInGameLanguage = eu_get_language();
#endif
switch (gDialogBoxState) {
case DIALOG_STATE_OPENING:
2019-10-05 19:08:05 +00:00
gDialogLineNum = 1;
gDialogTextAlpha = 0;
2019-08-25 04:46:40 +00:00
level_set_transition(-1, 0);
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_PAUSE, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_PAUSE_HIGHPRIO, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
#endif
if (gCurrCourseNum >= COURSE_MIN && gCurrCourseNum <= COURSE_MAX) {
2019-10-05 19:08:05 +00:00
change_dialog_camera_angle();
gDialogBoxState = DIALOG_STATE_VERTICAL;
2019-08-25 04:46:40 +00:00
} else {
2019-10-05 19:08:05 +00:00
highlight_last_course_complete_stars();
gDialogBoxState = DIALOG_STATE_HORIZONTAL;
2019-08-25 04:46:40 +00:00
}
break;
2019-10-05 19:08:05 +00:00
case DIALOG_STATE_VERTICAL:
shade_screen();
render_pause_my_score_coins();
render_pause_red_coins();
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if (gMarioStates[0].action & ACT_FLAG_PAUSE_EXIT) {
2019-10-05 19:08:05 +00:00
render_pause_course_options(99, 93, &gDialogLineNum, 15);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
if (gPlayer3Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON))
#else
2019-09-01 19:50:50 +00:00
if (gPlayer3Controller->buttonPressed & A_BUTTON
|| gPlayer3Controller->buttonPressed & START_BUTTON)
2019-08-25 04:46:40 +00:00
#endif
{
level_set_transition(0, 0);
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_PAUSE_2, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
gDialogBoxState = DIALOG_STATE_OPENING;
2019-10-05 19:08:05 +00:00
gMenuMode = -1;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gDialogLineNum == 2) {
num = gDialogLineNum;
2019-08-25 04:46:40 +00:00
} else {
2019-10-05 19:08:05 +00:00
num = 1;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
return num;
2019-08-25 04:46:40 +00:00
}
break;
2019-10-05 19:08:05 +00:00
case DIALOG_STATE_HORIZONTAL:
shade_screen();
print_hud_pause_colorful_str();
render_pause_castle_menu_box(160, 143);
render_pause_castle_main_strings(104, 60);
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
if (gPlayer3Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON))
#else
2019-09-01 19:50:50 +00:00
if (gPlayer3Controller->buttonPressed & A_BUTTON
|| gPlayer3Controller->buttonPressed & START_BUTTON)
2019-08-25 04:46:40 +00:00
#endif
{
level_set_transition(0, 0);
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_PAUSE_2, gDefaultSoundArgs);
gMenuMode = -1;
2019-08-25 04:46:40 +00:00
gDialogBoxState = DIALOG_STATE_OPENING;
return 1;
}
break;
}
2019-10-05 19:08:05 +00:00
if (gDialogTextAlpha < 250) {
gDialogTextAlpha += 25;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
return 0;
}
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define TXT_HISCORE_X 112
#define TXT_HISCORE_Y 48
#define TXT_CONGRATS_X 60
#else
#define TXT_HISCORE_X 109
#define TXT_HISCORE_Y 36
#define TXT_CONGRATS_X 70
#endif
2019-10-05 19:08:05 +00:00
#define HUD_PRINT_HISCORE 0
#define HUD_PRINT_CONGRATULATIONS 1
void print_hud_course_complete_string(s8 str) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
u8 textHiScore[][15] = {
2019-10-05 19:08:05 +00:00
{ TEXT_HUD_HI_SCORE },
{ TEXT_HUD_HI_SCORE_FR },
{ TEXT_HUD_HI_SCORE_DE }
2019-09-01 19:50:50 +00:00
};
u8 textCongratulations[][16] = {
2019-10-05 19:08:05 +00:00
{ TEXT_HUD_CONGRATULATIONS },
{ TEXT_HUD_CONGRATULATIONS_FR },
{ TEXT_HUD_CONGRATULATIONS_DE }
2019-09-01 19:50:50 +00:00
};
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
u8 textHiScore[] = { TEXT_HUD_HI_SCORE };
u8 textCongratulations[] = { TEXT_HUD_CONGRATULATIONS };
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
u8 colorFade = sins(gDialogColorFadeTimer) * 50.0f + 200.0f;
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (str == HUD_PRINT_HISCORE) {
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, get_str_x_pos_from_center_scale(160, textHiScore[gInGameLanguage], 12.0f),
2019-09-01 19:50:50 +00:00
36, textHiScore[gInGameLanguage]);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, TXT_HISCORE_X, TXT_HISCORE_Y, textHiScore);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
} else { // HUD_PRINT_CONGRATULATIONS
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, get_str_x_pos_from_center_scale(160, textCongratulations[gInGameLanguage], 12.0f),
2019-08-25 04:46:40 +00:00
67, textCongratulations[gInGameLanguage]);
#else
2019-10-05 19:08:05 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, TXT_CONGRATS_X, 67, textCongratulations);
2019-08-25 04:46:40 +00:00
#endif
}
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
}
2019-10-05 19:08:05 +00:00
void print_hud_course_complete_coins(s16 x, s16 y) {
u8 courseCompleteCoinsStr[4];
u8 hudTextSymCoin[] = { GLYPH_COIN, GLYPH_SPACE };
u8 hudTextSymX[] = { GLYPH_MULTIPLY, GLYPH_SPACE };
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
2019-10-05 19:08:05 +00:00
print_hud_lut_string(HUD_LUT_GLOBAL, x, y, hudTextSymCoin);
print_hud_lut_string(HUD_LUT_GLOBAL, x + 16, y, hudTextSymX);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
int_to_str(gCourseCompleteCoins, courseCompleteCoinsStr);
print_hud_lut_string(HUD_LUT_GLOBAL, x + 32, y, courseCompleteCoinsStr);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
2019-10-05 19:08:05 +00:00
if (gCourseCompleteCoins >= gHudDisplay.coins) {
gCourseCompleteCoinsEqual = 1;
gCourseCompleteCoins = gHudDisplay.coins;
2019-08-25 04:46:40 +00:00
if (gGotFileCoinHiScore != 0) {
2019-10-05 19:08:05 +00:00
print_hud_course_complete_string(HUD_PRINT_HISCORE);
2019-08-25 04:46:40 +00:00
}
} else {
2019-10-05 19:08:05 +00:00
if ((gCourseDoneMenuTimer & 1) || gHudDisplay.coins > 70) {
gCourseCompleteCoins++;
play_sound(SOUND_MENU_YOSHI_GAIN_LIVES, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gCourseCompleteCoins == 50 || gCourseCompleteCoins == 100 || gCourseCompleteCoins == 150) {
play_sound(SOUND_GENERAL_COLLECT_1UP, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
gMarioState[0].numLives++;
}
}
2019-10-05 19:08:05 +00:00
if (gHudDisplay.coins == gCourseCompleteCoins && gGotFileCoinHiScore != 0) {
play_sound(SOUND_MENU_MARIO_CASTLE_WARP2, gDefaultSoundArgs);
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
}
2019-10-05 19:08:05 +00:00
void play_star_fanfare_and_flash_hud(s32 arg, u8 starNum) {
if (gHudDisplay.coins == gCourseCompleteCoins && (gCurrCourseStarFlags & starNum) == 0 && gHudFlash == 0) {
2019-08-25 04:46:40 +00:00
play_star_fanfare();
2019-10-05 19:08:05 +00:00
gHudFlash = arg;
2019-08-25 04:46:40 +00:00
}
}
#ifdef VERSION_EU
#define TXT_NAME_X1 centerX
#define TXT_NAME_X2 centerX - 1
#else
#define TXT_NAME_X1 71
#define TXT_NAME_X2 69
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define CRS_NUM_X2 95
#define CRS_NUM_X3 93
#define TXT_CLEAR_X1 205
#define TXT_CLEAR_X2 203
#else
#define CRS_NUM_X2 104
#define CRS_NUM_X3 102
2019-10-05 19:08:05 +00:00
#define TXT_CLEAR_X1 get_string_width(name) + 81
#define TXT_CLEAR_X2 get_string_width(name) + 79
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
void render_course_complete_lvl_info_and_hud_str(void) {
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
2019-08-25 04:46:40 +00:00
u8 textCourse[] = { TEXT_COURSE };
u8 textCatch[] = { TEXT_CATCH };
u8 textClear[] = { TEXT_CLEAR };
#elif defined(VERSION_EU)
2020-02-03 05:51:26 +00:00
UNUSED u8 textCatch[] = { TEXT_CATCH }; // unused in EU
2019-10-05 19:08:05 +00:00
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
2019-08-25 04:46:40 +00:00
#define textCourse gTextCourseArr[gInGameLanguage]
#else
u8 textCourse[] = { TEXT_COURSE };
UNUSED u8 textCatch[] = { TEXT_CATCH }; // unused in US
UNUSED u8 textClear[] = { TEXT_CLEAR };
2019-10-05 19:08:05 +00:00
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
2019-08-25 04:46:40 +00:00
#endif
void **actNameTbl;
2019-12-02 02:52:53 +00:00
void **courseNameTbl;
2019-08-25 04:46:40 +00:00
u8 *name;
u8 strCourseNum[4];
#ifdef VERSION_EU
s16 centerX;
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
2019-08-25 04:46:40 +00:00
break;
case LANGUAGE_FRENCH:
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
2019-08-25 04:46:40 +00:00
break;
case LANGUAGE_GERMAN:
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
2019-08-25 04:46:40 +00:00
break;
}
#else
2019-09-01 19:50:50 +00:00
actNameTbl = segmented_to_virtual(seg2_act_name_table);
2019-12-02 02:52:53 +00:00
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
2019-08-25 04:46:40 +00:00
#endif
if (gLastCompletedCourseNum <= COURSE_STAGES_MAX) {
2019-10-05 19:08:05 +00:00
print_hud_course_complete_coins(118, 103);
play_star_fanfare_and_flash_hud(1, 1 << (gLastCompletedStarNum - 1));
2019-08-25 04:46:40 +00:00
if (gLastCompletedStarNum == 7) {
name = segmented_to_virtual(actNameTbl[COURSE_STAGES_MAX * 6 + 1]);
} else {
2019-09-01 19:50:50 +00:00
name = segmented_to_virtual(actNameTbl[(gLastCompletedCourseNum - 1) * 6 + gLastCompletedStarNum - 1]);
2019-08-25 04:46:40 +00:00
}
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-10-05 19:08:05 +00:00
int_to_str(gLastCompletedCourseNum, strCourseNum);
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, gDialogTextAlpha);
print_generic_string(65, 165, textCourse);
print_generic_string(CRS_NUM_X2, 165, strCourseNum);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
print_generic_string(63, 167, textCourse);
print_generic_string(CRS_NUM_X3, 167, strCourseNum);
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-08-25 04:46:40 +00:00
} else if (gLastCompletedCourseNum == COURSE_BITDW || gLastCompletedCourseNum == COURSE_BITFS) {
2019-12-02 02:52:53 +00:00
name = segmented_to_virtual(courseNameTbl[gLastCompletedCourseNum - 1]);
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
centerX = get_str_x_pos_from_center(153, name, 12.0f);
#endif
2019-10-05 19:08:05 +00:00
print_generic_string(TXT_NAME_X1, 130, name);
2019-08-25 04:46:40 +00:00
#ifndef VERSION_EU
2019-10-05 19:08:05 +00:00
print_generic_string(TXT_CLEAR_X1, 130, textClear);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
print_generic_string(TXT_NAME_X2, 132, name);
2019-08-25 04:46:40 +00:00
#ifndef VERSION_EU
2019-10-05 19:08:05 +00:00
print_generic_string(TXT_CLEAR_X2, 132, textClear);
2019-08-25 04:46:40 +00:00
#endif
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-10-05 19:08:05 +00:00
print_hud_course_complete_string(HUD_PRINT_CONGRATULATIONS);
print_hud_course_complete_coins(118, 111);
play_star_fanfare_and_flash_hud(2, 0); //! 2 isn't defined, originally for key hud?
2019-08-25 04:46:40 +00:00
return;
} else {
name = segmented_to_virtual(actNameTbl[COURSE_STAGES_MAX * 6]);
2019-10-05 19:08:05 +00:00
print_hud_course_complete_coins(118, 103);
play_star_fanfare_and_flash_hud(1, 1 << (gLastCompletedStarNum - 1));
2019-08-25 04:46:40 +00:00
}
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
print_hud_lut_string(HUD_LUT_GLOBAL, 55, 77, textSymStar);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, gDialogTextAlpha);
print_generic_string(76, 145, name);
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
print_generic_string(220, 145, textCatch);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
print_generic_string(74, 147, name);
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-10-05 19:08:05 +00:00
print_generic_string(218, 147, textCatch);
2019-08-25 04:46:40 +00:00
#endif
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define TXT_SAVEOPTIONS_X x + 10
#elif defined(VERSION_US)
#define TXT_SAVEOPTIONS_X x + 12
#elif defined(VERSION_EU)
#define TXT_SAVEOPTIONS_X xOffset
#endif
2020-04-03 18:57:26 +00:00
#if defined(VERSION_JP) || defined(VERSION_SH)
2019-08-25 04:46:40 +00:00
#define TXT_SAVECONT_Y 2
#define TXT_SAVEQUIT_Y 18
#define TXT_CONTNOSAVE_Y 38
#else
#define TXT_SAVECONT_Y 0
#define TXT_SAVEQUIT_Y 20
#define TXT_CONTNOSAVE_Y 40
#endif
#ifdef VERSION_EU
#define X_VAL9 xOffset - 12
2019-10-05 19:08:05 +00:00
void render_save_confirmation(s16 y, s8 *index, s16 sp6e)
2019-08-25 04:46:40 +00:00
#else
#define X_VAL9 x
2019-10-05 19:08:05 +00:00
void render_save_confirmation(s16 x, s16 y, s8 *index, s16 sp6e)
2019-08-25 04:46:40 +00:00
#endif
{
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
u8 textSaveAndContinueArr[][24] = {
{ TEXT_SAVE_AND_CONTINUE },
{ TEXT_SAVE_AND_CONTINUE_FR },
{ TEXT_SAVE_AND_CONTINUE_DE }
};
u8 textSaveAndQuitArr[][22] = {
{ TEXT_SAVE_AND_QUIT },
{ TEXT_SAVE_AND_QUIT_FR },
{ TEXT_SAVE_AND_QUIT_DE }
};
u8 textContinueWithoutSaveArr[][27] = {
{ TEXT_CONTINUE_WITHOUT_SAVING },
{ TEXT_CONTINUE_WITHOUT_SAVING_FR },
{ TEXT_CONTINUE_WITHOUT_SAVING_DE }
};
2019-08-25 04:46:40 +00:00
#define textSaveAndContinue textSaveAndContinueArr[gInGameLanguage]
#define textSaveAndQuit textSaveAndQuitArr[gInGameLanguage]
#define textContinueWithoutSave textContinueWithoutSaveArr[gInGameLanguage]
s16 xOffset = get_str_x_pos_from_center(160, textContinueWithoutSaveArr[gInGameLanguage], 12.0f);
#else
2019-09-01 19:50:50 +00:00
u8 textSaveAndContinue[] = { TEXT_SAVE_AND_CONTINUE };
u8 textSaveAndQuit[] = { TEXT_SAVE_AND_QUIT };
u8 textContinueWithoutSave[] = { TEXT_CONTINUE_WITHOUT_SAVING };
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
handle_menu_scrolling(MENU_SCROLL_VERTICAL, index, 1, 3);
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
print_generic_string(TXT_SAVEOPTIONS_X, y + TXT_SAVECONT_Y, textSaveAndContinue);
print_generic_string(TXT_SAVEOPTIONS_X, y - TXT_SAVEQUIT_Y, textSaveAndQuit);
print_generic_string(TXT_SAVEOPTIONS_X, y - TXT_CONTNOSAVE_Y, textContinueWithoutSave);
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL9, y - ((index[0] - 1) * sp6e), 0);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
2019-08-25 04:46:40 +00:00
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
2019-10-05 19:08:05 +00:00
s16 render_course_complete_screen(void) {
s16 num;
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
gInGameLanguage = eu_get_language();
#endif
switch (gDialogBoxState) {
case DIALOG_STATE_OPENING:
2019-10-05 19:08:05 +00:00
render_course_complete_lvl_info_and_hud_str();
if (gCourseDoneMenuTimer > 100 && gCourseCompleteCoinsEqual == 1) {
gDialogBoxState = DIALOG_STATE_VERTICAL;
2019-08-25 04:46:40 +00:00
level_set_transition(-1, 0);
2019-10-05 19:08:05 +00:00
gDialogTextAlpha = 0;
gDialogLineNum = 1;
2019-08-25 04:46:40 +00:00
}
break;
2019-10-05 19:08:05 +00:00
case DIALOG_STATE_VERTICAL:
shade_screen();
render_course_complete_lvl_info_and_hud_str();
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-10-05 19:08:05 +00:00
render_save_confirmation(86, &gDialogLineNum, 20);
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
render_save_confirmation(100, 86, &gDialogLineNum, 20);
2019-08-25 04:46:40 +00:00
#endif
2019-10-05 19:08:05 +00:00
if (gCourseDoneMenuTimer > 110
2019-08-25 04:46:40 +00:00
&& (gPlayer3Controller->buttonPressed & A_BUTTON
2019-09-01 19:50:50 +00:00
|| gPlayer3Controller->buttonPressed & START_BUTTON
2019-08-25 04:46:40 +00:00
#ifdef VERSION_EU
2019-09-01 19:50:50 +00:00
|| gPlayer3Controller->buttonPressed & Z_TRIG
2019-08-25 04:46:40 +00:00
#endif
2019-09-01 19:50:50 +00:00
)) {
2019-08-25 04:46:40 +00:00
level_set_transition(0, 0);
2019-10-05 19:08:05 +00:00
play_sound(SOUND_MENU_STAR_SOUND, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
gDialogBoxState = DIALOG_STATE_OPENING;
2019-10-05 19:08:05 +00:00
gMenuMode = -1;
num = gDialogLineNum;
gCourseDoneMenuTimer = 0;
gCourseCompleteCoins = 0;
gCourseCompleteCoinsEqual = 0;
gHudFlash = 0;
return num;
2019-08-25 04:46:40 +00:00
}
break;
}
2019-10-05 19:08:05 +00:00
if (gDialogTextAlpha < 250) {
gDialogTextAlpha += 25;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
gCourseDoneMenuTimer++;
2019-08-25 04:46:40 +00:00
return 0;
}
2019-10-05 19:08:05 +00:00
// Only case 1 and 2 are used
s16 render_menus_and_dialogs() {
s16 mode = 0;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
create_dl_ortho_matrix();
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (gMenuMode != -1) {
switch (gMenuMode) {
2019-08-25 04:46:40 +00:00
case 0:
2019-10-05 19:08:05 +00:00
mode = render_pause_courses_and_castle();
2019-08-25 04:46:40 +00:00
break;
case 1:
2019-10-05 19:08:05 +00:00
mode = render_pause_courses_and_castle();
2019-08-25 04:46:40 +00:00
break;
case 2:
2019-10-05 19:08:05 +00:00
mode = render_course_complete_screen();
2019-08-25 04:46:40 +00:00
break;
case 3:
2019-10-05 19:08:05 +00:00
mode = render_course_complete_screen();
2019-08-25 04:46:40 +00:00
break;
}
2019-10-05 19:08:05 +00:00
gDialogColorFadeTimer = (s16) gDialogColorFadeTimer + 0x1000;
2019-08-25 04:46:40 +00:00
} else if (gDialogID != -1) {
2019-10-05 19:08:05 +00:00
// Peach message "Dear Mario" new game dialog
2019-08-25 04:46:40 +00:00
if (gDialogID == 20) {
print_peach_letter_message(); // the peach message needs to be
// repositioned seperately
2019-10-05 19:08:05 +00:00
return mode;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
render_dialog_entries();
gDialogColorFadeTimer = (s16) gDialogColorFadeTimer + 0x1000;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
return mode;
2019-08-25 04:46:40 +00:00
}