diff options
| author | Derek Hensley <hensley.derek58@gmail.com> | 2025-12-08 21:11:07 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-08 21:11:07 -0800 |
| commit | 7b96e58622a3b8130b19c25d8633defd0beaeca1 (patch) | |
| tree | e36a32bde24b3662f5bf3e272c9ba3e598416263 /src | |
| parent | f6b17e23584c17fd2d6ec0d1867b8e395a0ed747 (diff) | |
Multiversion code support (n64-jp-1.1) (#1826)
* setup n64-jp-1.1 disasm
* Add versions
* New microcode
* Bootstrap z_sram
* Bootstrap ovl_file_choose
* Bootstrap kaleido scope
* Bootstrap BgHeavyBlock
* MessageContext shift
* SaveContext shift
* ItemId shift
* Fix `PLAYER_CSACTION` shift
* format
* Add JP only to Heavy Block Description
* Makefile multi version comment
---------
Co-authored-by: Tom Overton <tom.overton@outlook.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/code/z_message.c | 381 | ||||
| -rw-r--r-- | src/code/z_sram_JPN.c | 2042 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Bg_Heavy_Block/z_bg_heavy_block.c | 40 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Bg_Heavy_Block/z_bg_heavy_block.h | 16 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Obj_Warpstone/z_obj_warpstone.c | 22 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_player_actor/z_player.c | 8 | ||||
| -rw-r--r-- | src/overlays/gamestates/ovl_file_choose/z_file_choose_JPN.c | 2536 | ||||
| -rw-r--r-- | src/overlays/gamestates/ovl_file_choose/z_file_nameset_JPN.c | 1060 | ||||
| -rw-r--r-- | src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_JPN.c | 3746 |
9 files changed, 9685 insertions, 166 deletions
diff --git a/src/code/z_message.c b/src/code/z_message.c index 5a5c5a910..d188627b6 100644 --- a/src/code/z_message.c +++ b/src/code/z_message.c @@ -15,10 +15,55 @@ #include "assets/interface/parameter_static/parameter_static.h" +#if MM_VERSION >= N64_US +#define MESSAGE_DECODE(play) Message_DecodeNES(play) +#define MESSAGE_DRAW_TEXT(play, gfxP, drawPos) Message_DrawTextNES(play, gfxP, drawPos) +#else +#define MESSAGE_DECODE(play) Message_Decode(play) +#define MESSAGE_DRAW_TEXT(play, gfxP, drawPos) Message_DrawTextDefault(play, gfxP) +#endif + u8 D_801C6A70 = 0; s16 sOcarinaButtonIndexBufPos = 0; s16 sOcarinaButtonIndexBufLen = 0; s16 sLastPlayedSong = 0xFF; + +#if MM_VERSION >= N64_US +#define MSGCTX_UNK120BE msgCtx->unk120BE +#define MSGCTX_UNK120C0 msgCtx->unk120C0 +#define MSGCTX_UNK120C2 msgCtx->unk120C2 +#define MSGCTX_UNK120C4 msgCtx->unk120C4 +#define MSGCTX_UNK120C8 msgCtx->unk120C8 +#define MSGCTX_UNK120CA msgCtx->unk120CA +#define MSGCTX_UNK120CC msgCtx->unk120CC +#define MSGCTX_UNK120CE msgCtx->unk120CE +#define MSGCTX_UNK120D0 msgCtx->unk120D0 +#define MSGCTX_UNK120D2 msgCtx->unk120D2 +#else + +s16 D_801C1B00_unknown = 0; +s16 D_801C1B04_unknown = 0; +s16 D_801C1B08_unknown = 0; +s32 D_801C1B0C_unknown = 0; +s16 D_801C1B10_unknown = 0; +s16 D_801C1B14_unknown = 0; +s16 D_801C1B18_unknown = 0; +s16 D_801C1B1C_unknown = 0; +s16 D_801C1B20_unknown = 0; +s16 D_801C1B24_unknown = 0; + +#define MSGCTX_UNK120BE D_801C1B00_unknown +#define MSGCTX_UNK120C0 D_801C1B04_unknown +#define MSGCTX_UNK120C2 D_801C1B08_unknown +#define MSGCTX_UNK120C4 D_801C1B0C_unknown +#define MSGCTX_UNK120C8 D_801C1B10_unknown +#define MSGCTX_UNK120CA D_801C1B14_unknown +#define MSGCTX_UNK120CC D_801C1B18_unknown +#define MSGCTX_UNK120CE D_801C1B1C_unknown +#define MSGCTX_UNK120D0 D_801C1B20_unknown +#define MSGCTX_UNK120D2 D_801C1B24_unknown +#endif + s16 sOcarinaButtonStepR = 0; s16 sOcarinaButtonStepG = 0; s16 sOcarinaButtonStepB = 0; @@ -26,6 +71,19 @@ s16 sOcarinaButtonFlashTimer = 12; s16 sOcarinaButtonFlashColorIndex = 1; s16 D_801C6A94 = 0; +#if MM_VERSION >= N64_US +#define MSGCTX_UNK120D4 msgCtx->unk120D4 +#define MSGCTX_UNK120D6 msgCtx->unk120D6 +#else + +s16 D_801C1B40_unknown = 0; +s16 D_801C1B44_unknown = 0; + +#define MSGCTX_UNK120D4 D_801C1B40_unknown +#define MSGCTX_UNK120D6 D_801C1B44_unknown + +#endif + u8 gPageSwitchNextButtonStatus[][5] = { { BTN_ENABLED, BTN_ENABLED, BTN_DISABLED, BTN_ENABLED, BTN_ENABLED }, { BTN_ENABLED, BTN_ENABLED, BTN_DISABLED, BTN_ENABLED, BTN_ENABLED }, @@ -544,34 +602,34 @@ void func_80148D64(PlayState* play) { MessageContext* msgCtx = &play->msgCtx; if (play->msgCtx.stickAdjY <= -30) { - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2]--; - if (msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] < '0') { - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = '9'; + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2]--; + if (msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] < '0') { + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = '9'; } - Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if (msgCtx->stickAdjY >= 30) { - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2]++; - if (msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] > '9') { - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = '0'; + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2]++; + if (msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] > '9') { + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = '0'; } - Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if ((msgCtx->stickAdjX >= 30) && !sAnalogStickHeld) { sAnalogStickHeld = true; - msgCtx->unk120C2++; - if (msgCtx->unk120C2 > 2) { - msgCtx->unk120C2 = 2; + MSGCTX_UNK120C2++; + if (MSGCTX_UNK120C2 > 2) { + MSGCTX_UNK120C2 = 2; } else { Audio_PlaySfx(NA_SE_SY_CURSOR); } } else if ((msgCtx->stickAdjX <= -30) && !sAnalogStickHeld) { sAnalogStickHeld = true; - msgCtx->unk120C2--; - if (msgCtx->unk120C2 < 0) { - msgCtx->unk120C2 = 0; + MSGCTX_UNK120C2--; + if (MSGCTX_UNK120C2 < 0) { + MSGCTX_UNK120C2 = 0; } else { Audio_PlaySfx(NA_SE_SY_CURSOR); } @@ -579,33 +637,33 @@ void func_80148D64(PlayState* play) { sAnalogStickHeld = false; } - msgCtx->rupeesSelected = (msgCtx->decodedBuffer.schar[msgCtx->unk120C0] - '0') * 100; - msgCtx->rupeesSelected += (msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + 1] - '0') * 10; - msgCtx->rupeesSelected += msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + 2] - '0'; + msgCtx->rupeesSelected = (msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0] - '0') * 100; + msgCtx->rupeesSelected += (msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + 1] - '0') * 10; + msgCtx->rupeesSelected += msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + 2] - '0'; } void func_80149048(PlayState* play) { MessageContext* msgCtx = &play->msgCtx; if (msgCtx->stickAdjY <= -30) { - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2]--; - if (msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] < '0') { - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = '9'; + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2]--; + if (msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] < '0') { + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = '9'; } - Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if (msgCtx->stickAdjY >= 30) { - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2]++; - if (msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] > '9') { - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = '0'; + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2]++; + if (msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] > '9') { + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = '0'; } - Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } - msgCtx->rupeesSelected = (msgCtx->decodedBuffer.schar[msgCtx->unk120C0] - '0') * 10; + msgCtx->rupeesSelected = (msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0] - '0') * 10; } void func_801491DC(PlayState* play) { @@ -613,36 +671,36 @@ void func_801491DC(PlayState* play) { MessageContext* msgCtx = &play->msgCtx; if (msgCtx->stickAdjY <= -30) { - msgCtx->unk12054[msgCtx->unk120C2]--; - if (msgCtx->unk12054[msgCtx->unk120C2] <= 0) { - msgCtx->unk12054[msgCtx->unk120C2] = 5; + msgCtx->unk12054[MSGCTX_UNK120C2]--; + if (msgCtx->unk12054[MSGCTX_UNK120C2] <= 0) { + msgCtx->unk12054[MSGCTX_UNK120C2] = 5; } - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; - Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = msgCtx->unk12054[MSGCTX_UNK120C2] + '0'; + Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if (msgCtx->stickAdjY >= 30) { - msgCtx->unk12054[msgCtx->unk120C2]++; - if (msgCtx->unk12054[msgCtx->unk120C2] > 5) { - msgCtx->unk12054[msgCtx->unk120C2] = 1; + msgCtx->unk12054[MSGCTX_UNK120C2]++; + if (msgCtx->unk12054[MSGCTX_UNK120C2] > 5) { + msgCtx->unk12054[MSGCTX_UNK120C2] = 1; } - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; - Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = msgCtx->unk12054[MSGCTX_UNK120C2] + '0'; + Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if ((msgCtx->stickAdjX >= 30) && !sAnalogStickHeld) { sAnalogStickHeld = true; - msgCtx->unk120C2++; - if (msgCtx->unk120C2 > 4) { - msgCtx->unk120C2 = 4; + MSGCTX_UNK120C2++; + if (MSGCTX_UNK120C2 > 4) { + MSGCTX_UNK120C2 = 4; } else { Audio_PlaySfx(NA_SE_SY_CURSOR); } } else if ((msgCtx->stickAdjX <= -30) && !sAnalogStickHeld) { sAnalogStickHeld = true; - msgCtx->unk120C2--; - if (msgCtx->unk120C2 < 0) { - msgCtx->unk120C2 = 0; + MSGCTX_UNK120C2--; + if (MSGCTX_UNK120C2 < 0) { + MSGCTX_UNK120C2 = 0; } else { Audio_PlaySfx(NA_SE_SY_CURSOR); } @@ -656,36 +714,36 @@ void func_80149454(PlayState* play) { MessageContext* msgCtx = &play->msgCtx; if (msgCtx->stickAdjY <= -30) { - msgCtx->unk12054[msgCtx->unk120C2]--; - if (msgCtx->unk12054[msgCtx->unk120C2] < 0) { - msgCtx->unk12054[msgCtx->unk120C2] = 9; + msgCtx->unk12054[MSGCTX_UNK120C2]--; + if (msgCtx->unk12054[MSGCTX_UNK120C2] < 0) { + msgCtx->unk12054[MSGCTX_UNK120C2] = 9; } - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; - Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = msgCtx->unk12054[MSGCTX_UNK120C2] + '0'; + Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if (msgCtx->stickAdjY >= 30) { - msgCtx->unk12054[msgCtx->unk120C2]++; - if (msgCtx->unk12054[msgCtx->unk120C2] > 9) { - msgCtx->unk12054[msgCtx->unk120C2] = 0; + msgCtx->unk12054[MSGCTX_UNK120C2]++; + if (msgCtx->unk12054[MSGCTX_UNK120C2] > 9) { + msgCtx->unk12054[MSGCTX_UNK120C2] = 0; } - msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; - Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = msgCtx->unk12054[MSGCTX_UNK120C2] + '0'; + Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if ((msgCtx->stickAdjX >= 30) && !sAnalogStickHeld) { sAnalogStickHeld = true; - msgCtx->unk120C2++; - if (msgCtx->unk120C2 > 2) { - msgCtx->unk120C2 = 2; + MSGCTX_UNK120C2++; + if (MSGCTX_UNK120C2 > 2) { + MSGCTX_UNK120C2 = 2; } else { Audio_PlaySfx(NA_SE_SY_CURSOR); } } else if ((msgCtx->stickAdjX <= -30) && !sAnalogStickHeld) { sAnalogStickHeld = true; - msgCtx->unk120C2--; - if (msgCtx->unk120C2 < 0) { - msgCtx->unk120C2 = 0; + MSGCTX_UNK120C2--; + if (MSGCTX_UNK120C2 < 0) { + MSGCTX_UNK120C2 = 0; } else { Audio_PlaySfx(NA_SE_SY_CURSOR); } @@ -699,36 +757,36 @@ void func_801496C8(PlayState* play) { MessageContext* msgCtx = &play->msgCtx; if (play->msgCtx.stickAdjY <= -30) { - msgCtx->unk12054[msgCtx->unk120C2]--; - if (msgCtx->unk12054[msgCtx->unk120C2] < 0) { - msgCtx->unk12054[msgCtx->unk120C2] = 3; + msgCtx->unk12054[MSGCTX_UNK120C2]--; + if (msgCtx->unk12054[MSGCTX_UNK120C2] < 0) { + msgCtx->unk12054[MSGCTX_UNK120C2] = 3; } - msgCtx->decodedBuffer.wchar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; - Font_LoadChar(play, msgCtx->decodedBuffer.wchar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + msgCtx->decodedBuffer.wchar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = msgCtx->unk12054[MSGCTX_UNK120C2] + '0'; + Font_LoadChar(play, msgCtx->decodedBuffer.wchar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if (msgCtx->stickAdjY >= 30) { - msgCtx->unk12054[msgCtx->unk120C2]++; - if (msgCtx->unk12054[msgCtx->unk120C2] >= 4) { - msgCtx->unk12054[msgCtx->unk120C2] = 0; + msgCtx->unk12054[MSGCTX_UNK120C2]++; + if (msgCtx->unk12054[MSGCTX_UNK120C2] >= 4) { + msgCtx->unk12054[MSGCTX_UNK120C2] = 0; } - msgCtx->decodedBuffer.wchar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; - Font_LoadChar(play, msgCtx->decodedBuffer.wchar[msgCtx->unk120C0 + msgCtx->unk120C2], - msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); + msgCtx->decodedBuffer.wchar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2] = msgCtx->unk12054[MSGCTX_UNK120C2] + '0'; + Font_LoadChar(play, msgCtx->decodedBuffer.wchar[MSGCTX_UNK120C0 + MSGCTX_UNK120C2], + MSGCTX_UNK120C4 + (MSGCTX_UNK120C2 << 7)); Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); } else if ((msgCtx->stickAdjX >= 30) && !sAnalogStickHeld) { sAnalogStickHeld = true; - msgCtx->unk120C2++; - if (msgCtx->unk120C2 > 5) { - msgCtx->unk120C2 = 5; + MSGCTX_UNK120C2++; + if (MSGCTX_UNK120C2 > 5) { + MSGCTX_UNK120C2 = 5; } else { Audio_PlaySfx(NA_SE_SY_CURSOR); } } else if ((msgCtx->stickAdjX <= -30) && !sAnalogStickHeld) { sAnalogStickHeld = true; - msgCtx->unk120C2--; - if (msgCtx->unk120C2 < 0) { - msgCtx->unk120C2 = 0; + MSGCTX_UNK120C2--; + if (MSGCTX_UNK120C2 < 0) { + MSGCTX_UNK120C2 = 0; } else { Audio_PlaySfx(NA_SE_SY_CURSOR); } @@ -1101,9 +1159,9 @@ void Message_DrawTextDefault(PlayState* play, Gfx** gfxP) { if (play->msgCtx.itemId != MESSAGE_ITEM_NONE) { Message_DrawItemIcon(play, &gfx); } - msgCtx->textColorR = msgCtx->unk120C8; - msgCtx->textColorG = msgCtx->unk120CA; - msgCtx->textColorB = msgCtx->unk120CC; + msgCtx->textColorR = MSGCTX_UNK120C8; + msgCtx->textColorG = MSGCTX_UNK120CA; + msgCtx->textColorB = MSGCTX_UNK120CC; charTexIndex = 0; @@ -1135,32 +1193,32 @@ void Message_DrawTextDefault(PlayState* play, Gfx** gfxP) { if ((msgCtx->msgMode >= MSGMODE_NEW_CYCLE_0) && (msgCtx->msgMode <= MSGMODE_NEW_CYCLE_2) && (character == 0x2002)) { msgCtx->textDrawPos = msgCtx->decodedTextLen; - if (msgCtx->unk120D6) { - msgCtx->unk120D4 += 25; - if (msgCtx->unk120D4 >= 100) { - msgCtx->unk120D6 = false; + if (MSGCTX_UNK120D6) { + MSGCTX_UNK120D4 += 25; + if (MSGCTX_UNK120D4 >= 100) { + MSGCTX_UNK120D6 = false; } } else { - msgCtx->unk120D4 -= 25; - if (msgCtx->unk120D4 <= -100) { - msgCtx->unk120D6 = true; + MSGCTX_UNK120D4 -= 25; + if (MSGCTX_UNK120D4 <= -100) { + MSGCTX_UNK120D6 = true; } } - if (D_801CFE74[(s16)(character - 0x2001)].r + msgCtx->unk120D4 < 0) { + if (D_801CFE74[(s16)(character - 0x2001)].r + MSGCTX_UNK120D4 < 0) { msgCtx->textColorR = 0; } else { - msgCtx->textColorR = D_801CFE74[(s16)(character - 0x2001)].r + msgCtx->unk120D4; + msgCtx->textColorR = D_801CFE74[(s16)(character - 0x2001)].r + MSGCTX_UNK120D4; } - if (D_801CFE74[(s16)(character - 0x2001)].g + msgCtx->unk120D4 >= 255) { + if (D_801CFE74[(s16)(character - 0x2001)].g + MSGCTX_UNK120D4 >= 255) { msgCtx->textColorG = D_801CFE74[(s16)(character - 0x2001)].g; } else { - msgCtx->textColorG = D_801CFE74[(s16)(character - 0x2001)].g + msgCtx->unk120D4; + msgCtx->textColorG = D_801CFE74[(s16)(character - 0x2001)].g + MSGCTX_UNK120D4; } - if (D_801CFE74[(s16)(character - 0x2001)].b + msgCtx->unk120D4 < 0) { + if (D_801CFE74[(s16)(character - 0x2001)].b + MSGCTX_UNK120D4 < 0) { msgCtx->textColorB = 0; } else { - msgCtx->textColorB = D_801CFE74[(s16)(character - 0x2001)].b + msgCtx->unk120D4; + msgCtx->textColorB = D_801CFE74[(s16)(character - 0x2001)].b + MSGCTX_UNK120D4; } } else if (play->pauseCtx.bombersNotebookOpen) { msgCtx->textColorR = sColorsBombersNotebookJPN[(s16)(character - 0x2001)].r; @@ -1222,9 +1280,9 @@ void Message_DrawTextDefault(PlayState* play, Gfx** gfxP) { msgCtx->textUnskippable = false; msgCtx->msgBufPos++; } - msgCtx->unk120CE = msgCtx->textColorR; - msgCtx->unk120D0 = msgCtx->textColorG; - msgCtx->unk120D2 = msgCtx->textColorB; + MSGCTX_UNK120CE = msgCtx->textColorR; + MSGCTX_UNK120D0 = msgCtx->textColorG; + MSGCTX_UNK120D2 = msgCtx->textColorB; } *gfxP = gfx; return; @@ -2259,9 +2317,9 @@ void Message_Decode(PlayState* play) { msgCtx->textDrawPos = msgCtx->decodedTextLen; } - msgCtx->unk120C8 = msgCtx->unk120CE; - msgCtx->unk120CA = msgCtx->unk120D0; - msgCtx->unk120CC = msgCtx->unk120D2; + MSGCTX_UNK120C8 = MSGCTX_UNK120CE; + MSGCTX_UNK120CA = MSGCTX_UNK120D0; + MSGCTX_UNK120CC = MSGCTX_UNK120D2; break; } @@ -2403,11 +2461,11 @@ void Message_Decode(PlayState* play) { Message_LoadChar(play, 0x9543, &charTexIndex, &spC0, decodedBufPos); } else if (curChar == 0x20C) { decodedBufPos++; - msgCtx->unk120BE = spD2; - msgCtx->unk120C0 = decodedBufPos; - msgCtx->unk120C2 = 2; + MSGCTX_UNK120BE = spD2; + MSGCTX_UNK120C0 = decodedBufPos; + MSGCTX_UNK120C2 = 2; msgCtx->rupeesSelected = 0; - msgCtx->unk120C4 = charTexIndex; + MSGCTX_UNK120C4 = charTexIndex; digits[0] = digits[1] = digits[2] = 0; for (i = 0; i < 3; i++) { @@ -2567,11 +2625,11 @@ void Message_Decode(PlayState* play) { decodedBufPos--; } else if (curChar == 0x220) { decodedBufPos++; - msgCtx->unk120BE = spD2; - msgCtx->unk120C0 = decodedBufPos; - msgCtx->unk120C2 = 0; + MSGCTX_UNK120BE = spD2; + MSGCTX_UNK120C0 = decodedBufPos; + MSGCTX_UNK120C2 = 0; msgCtx->rupeesSelected = 0; - msgCtx->unk120C4 = charTexIndex; + MSGCTX_UNK120C4 = charTexIndex; digits[0] = digits[1] = digits[2] = 0; for (i = 0; i < 2; i++) { Message_LoadChar(play, digits[i] + '0', &charTexIndex, &spC0, decodedBufPos); @@ -2580,11 +2638,11 @@ void Message_Decode(PlayState* play) { Message_LoadRupeesJPN(play, &decodedBufPos, &charTexIndex, &spC0); } else if (curChar == 0x221) { decodedBufPos++; - msgCtx->unk120BE = spD2; - msgCtx->unk120C0 = decodedBufPos; - msgCtx->unk120C2 = 0; + MSGCTX_UNK120BE = spD2; + MSGCTX_UNK120C0 = decodedBufPos; + MSGCTX_UNK120C2 = 0; msgCtx->rupeesSelected = 0; - msgCtx->unk120C4 = charTexIndex; + MSGCTX_UNK120C4 = charTexIndex; for (i = 0; i < 5; i++) { msgCtx->unk12054[i] = 1; @@ -2613,11 +2671,11 @@ void Message_Decode(PlayState* play) { Message_LoadOwlWarpText(play, &charTexIndex, &spC0, &decodedBufPos); } else if (curChar == 0x225) { decodedBufPos++; - msgCtx->unk120BE = spD2; - msgCtx->unk120C0 = decodedBufPos; - msgCtx->unk120C2 = 0; + MSGCTX_UNK120BE = spD2; + MSGCTX_UNK120C0 = decodedBufPos; + MSGCTX_UNK120C2 = 0; msgCtx->rupeesSelected = 0; - msgCtx->unk120C4 = charTexIndex; + MSGCTX_UNK120C4 = charTexIndex; for (i = 0; i < 3; i++) { msgCtx->unk12054[i] = 1; @@ -3054,7 +3112,9 @@ void Message_Decode(PlayState* play) { } else if (msgCtx->textIsCredits) { Message_DecodeCredits(play); } else { +#if MM_VERSION >= N64_US Message_DecodeNES(play); +#endif } } @@ -3199,10 +3259,12 @@ void Message_OpenText(PlayState* play, u16 textId) { DmaMgr_RequestSync(&font->msgBuf, SEGMENT_ROM_START(message_data_static) + font->messageStart, font->messageEnd); } else { +#if MM_VERSION >= N64_US Message_FindMessageNES(play, textId); msgCtx->msgLength = font->messageEnd; DmaMgr_RequestSync(&font->msgBuf, SEGMENT_ROM_START(message_data_static) + font->messageStart, font->messageEnd); +#endif } msgCtx->choiceNum = 0; @@ -3227,9 +3289,9 @@ void Message_OpenText(PlayState* play, u16 textId) { if ((msgCtx->textBoxType == TEXTBOX_TYPE_CLEAR) || (msgCtx->textBoxType == TEXTBOX_TYPE_NOTEBOOK_NOTIFICATION) || (play->pauseCtx.bombersNotebookOpen)) { - msgCtx->unk120CE = msgCtx->unk120D0 = msgCtx->unk120D2 = 0; + MSGCTX_UNK120CE = MSGCTX_UNK120D0 = MSGCTX_UNK120D2 = 0; } else { - msgCtx->unk120CE = msgCtx->unk120D0 = msgCtx->unk120D2 = 0xFF; + MSGCTX_UNK120CE = MSGCTX_UNK120D0 = MSGCTX_UNK120D2 = 0xFF; } msgCtx->choiceIndex = 0; @@ -3293,10 +3355,12 @@ void Message_PauseMenu_ShowDescription(PlayState* play, u16 textId, u8 textBoxPo DmaMgr_RequestSync(&font->msgBuf, SEGMENT_ROM_START(message_data_static) + font->messageStart, font->messageEnd); } else { +#if MM_VERSION >= N64_US Message_FindMessageNES(play, textId); msgCtx->msgLength = font->messageEnd; DmaMgr_RequestSync(&font->msgBuf, SEGMENT_ROM_START(message_data_static) + font->messageStart, font->messageEnd); +#endif } msgCtx->choiceNum = 0; msgCtx->textUnskippable = false; @@ -3323,8 +3387,8 @@ void Message_PauseMenu_ShowDescription(PlayState* play, u16 textId, u8 textBoxPo msgCtx->stateTimer = 0; msgCtx->textDelayTimer = 0; play->msgCtx.ocarinaMode = OCARINA_MODE_NONE; - msgCtx->unk120D2 = 0xFF; - msgCtx->unk120CE = msgCtx->unk120D0 = msgCtx->unk120D2; + MSGCTX_UNK120D2 = 0xFF; + MSGCTX_UNK120CE = MSGCTX_UNK120D0 = MSGCTX_UNK120D2; } void Message_StartTextbox(PlayState* play, u16 textId, Actor* actor) { @@ -3373,7 +3437,7 @@ void Message_DisplaySceneTitleCard(PlayState* play, u16 textId) { msgCtx->msgLength = 0; Message_OpenText(play, textId); Message_SetTextboxColor(play); - Message_DecodeNES(play); + MESSAGE_DECODE(play); msgCtx->msgMode = MSGMODE_SCENE_TITLE_CARD_FADE_IN_BACKGROUND; msgCtx->textDelayTimer = 0; msgCtx->textboxColorAlphaCurrent = msgCtx->textboxColorAlphaTarget = msgCtx->textColorAlpha = 0; @@ -4086,7 +4150,9 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) { } else if (play->msgCtx.textIsCredits) { Message_DrawTextCredits(play, gfxP); } else { +#if MM_VERSION >= N64_US Message_DrawTextNES(play, gfxP, 0); +#endif } } @@ -4115,7 +4181,7 @@ void Message_DrawSceneTitleCard(PlayState* play, Gfx** gfxP) { msgCtx->unk11FF8 = XREG(75); } msgCtx->unk11FFA = XREG(74); - Message_DrawTextNES(play, &gfx, 0); + MESSAGE_DRAW_TEXT(play, &gfx, 0); *gfxP = gfx++; } @@ -4243,9 +4309,9 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) { if (msgCtx->textDelay != 0) { msgCtx->textDrawPos += msgCtx->textDelay; } - Message_DrawTextNES(play, &gfx, 0); + MESSAGE_DRAW_TEXT(play, &gfx, 0); if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { - Message_DrawTextNES(play, &gfx, (s32)msgCtx->textDrawPos); + MESSAGE_DRAW_TEXT(play, &gfx, (s32)msgCtx->textDrawPos); } } else if (msgCtx->textIsCredits) { Message_DrawTextCredits(play, &gfx); @@ -4253,9 +4319,9 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) { if (msgCtx->textDelay != 0) { msgCtx->textDrawPos += msgCtx->textDelay; } - Message_DrawTextNES(play, &gfx, 0); + MESSAGE_DRAW_TEXT(play, &gfx, 0); if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { - Message_DrawTextNES(play, &gfx, (s32)msgCtx->textDrawPos); + MESSAGE_DRAW_TEXT(play, &gfx, (s32)msgCtx->textDrawPos); } } break; @@ -4266,7 +4332,7 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) { case MSGMODE_OWL_SAVE_0: case MSGMODE_OWL_SAVE_1: case MSGMODE_OWL_SAVE_2: - Message_DrawTextNES(play, &gfx, 0); + MESSAGE_DRAW_TEXT(play, &gfx, 0); break; case MSGMODE_TEXT_AWAIT_INPUT: @@ -4997,17 +5063,17 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) { case MSGMODE_TEXT_DONE: switch (msgCtx->textboxEndType) { case TEXTBOX_ENDTYPE_INPUT_BANK: - temp_v0_33 = msgCtx->unk120BE; + temp_v0_33 = MSGCTX_UNK120BE; temp = msgCtx->unk11FFA + (msgCtx->unk11FFC * temp_v0_33); func_80147F18(play, &gfx, msgCtx->unk11F1A[temp_v0_33] + - (s32)(16.0f * msgCtx->textCharScale * (msgCtx->unk120C2 + 5)) - 1, + (s32)(16.0f * msgCtx->textCharScale * (MSGCTX_UNK120C2 + 5)) - 1, temp); func_80148D64(play); break; case TEXTBOX_ENDTYPE_INPUT_DOGGY_RACETRACK_BET: - temp_v0_33 = msgCtx->unk120BE; + temp_v0_33 = MSGCTX_UNK120BE; temp = msgCtx->unk11FFA + (msgCtx->unk11FFC * temp_v0_33); func_80148558(play, &gfx, msgCtx->unk11F1A[temp_v0_33] + (s32)(16.0f * msgCtx->textCharScale * 5.0f) - 1, @@ -5016,31 +5082,31 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) { break; case TEXTBOX_ENDTYPE_INPUT_BOMBER_CODE: - temp_v0_33 = msgCtx->unk120BE; + temp_v0_33 = MSGCTX_UNK120BE; temp = msgCtx->unk11FFA + (msgCtx->unk11FFC * temp_v0_33); func_80147F18(play, &gfx, msgCtx->unk11F1A[temp_v0_33] + - (s32)(16.0f * msgCtx->textCharScale * (msgCtx->unk120C2 + 5)) - 1, + (s32)(16.0f * msgCtx->textCharScale * (MSGCTX_UNK120C2 + 5)) - 1, temp); func_801491DC(play); break; case TEXTBOX_ENDTYPE_INPUT_LOTTERY_CODE: - temp_v0_33 = msgCtx->unk120BE; + temp_v0_33 = MSGCTX_UNK120BE; temp = msgCtx->unk11FFA + (msgCtx->unk11FFC * temp_v0_33); func_80147F18(play, &gfx, msgCtx->unk11F1A[temp_v0_33] + - (s32)(16.0f * msgCtx->textCharScale * (msgCtx->unk120C2 + 5)) - 1, + (s32)(16.0f * msgCtx->textCharScale * (MSGCTX_UNK120C2 + 5)) - 1, temp); func_80149454(play); break; case TEXTBOX_ENDTYPE_64: - temp_v0_33 = msgCtx->unk120BE; + temp_v0_33 = MSGCTX_UNK120BE; temp = msgCtx->unk11FFA + (msgCtx->unk11FFC * temp_v0_33); func_80147F18(play, &gfx, msgCtx->unk11F1A[temp_v0_33] + - (s32)(16.0f * msgCtx->textCharScale * (msgCtx->unk120C2 + 4)) - 6, + (s32)(16.0f * msgCtx->textCharScale * (MSGCTX_UNK120C2 + 4)) - 6, temp); func_801496C8(play); break; @@ -5595,8 +5661,8 @@ void Message_Update(PlayState* play) { Audio_PlaySfx_MessageDecide(); msgCtx->msgMode = MSGMODE_NEW_CYCLE_0; msgCtx->decodedTextLen -= 3; - msgCtx->unk120D6 = 0; - msgCtx->unk120D4 = 0; + MSGCTX_UNK120D6 = 0; + MSGCTX_UNK120D4 = 0; } else { Audio_PlaySfx_MessageCancel(); play->msgCtx.ocarinaMode = OCARINA_MODE_END; @@ -6061,16 +6127,19 @@ void Message_Init(PlayState* play) { msgCtx->textboxX = 52; msgCtx->textboxY = 36; msgCtx->ocarinaSongEffectActive = false; - msgCtx->unk120BE = 0; - msgCtx->unk120C0 = 0; - msgCtx->unk120C2 = 0; - msgCtx->unk120C4 = 0; - msgCtx->unk120C8 = 0; - msgCtx->unk120CA = 0; - msgCtx->unk120CC = 0; - msgCtx->unk120CE = 0; - msgCtx->unk120D0 = 0; - msgCtx->unk120D2 = 0; - msgCtx->unk120D4 = 0; - msgCtx->unk120D6 = 0; + +#if MM_VERSION >= N64_US + MSGCTX_UNK120BE = 0; + MSGCTX_UNK120C0 = 0; + MSGCTX_UNK120C2 = 0; + MSGCTX_UNK120C4 = 0; + MSGCTX_UNK120C8 = 0; + MSGCTX_UNK120CA = 0; + MSGCTX_UNK120CC = 0; + MSGCTX_UNK120CE = 0; + MSGCTX_UNK120D0 = 0; + MSGCTX_UNK120D2 = 0; + MSGCTX_UNK120D4 = 0; + MSGCTX_UNK120D6 = 0; +#endif } diff --git a/src/code/z_sram_JPN.c b/src/code/z_sram_JPN.c new file mode 100644 index 000000000..c6790a1a5 --- /dev/null +++ b/src/code/z_sram_JPN.c @@ -0,0 +1,2042 @@ +#include "z64save.h" +#include "global.h" + +#include "sys_flashrom.h" +#include "z64horse.h" +#include "overlays/gamestates/ovl_file_choose/z_file_select.h" + +void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages); +void func_80147314(SramContext* sramCtx, s32 fileNum); +void func_80147414(SramContext* sramCtx, s32 fileNum, s32 arg2); + +#define CHECK_NEWF(newf) \ + ((newf)[0] != 'Z' || (newf)[1] != 'E' || (newf)[2] != 'L' || (newf)[3] != 'D' || (newf)[4] != 'A' || \ + (newf)[5] != '3') + +typedef struct PersistentCycleSceneFlags { + /* 0x0 */ u32 switch0; + /* 0x4 */ u32 switch1; + /* 0x8 */ u32 chest; + /* 0xC */ u32 collectible; +} PersistentCycleSceneFlags; // size = 0x10 + +#define PERSISTENT_CYCLE_FLAGS_SET(switch0, switch1, chest, collectible) { switch0, switch1, chest, collectible }, +#define PERSISTENT_CYCLE_FLAGS_NONE PERSISTENT_CYCLE_FLAGS_SET(0, 0, 0, 0) + +#define DEFINE_SCENE(_name, _enumValue, _textId, _drawConfig, _restrictionFlags, persistentCycleFlags) \ + persistentCycleFlags +#define DEFINE_SCENE_UNSET(_enumValue) PERSISTENT_CYCLE_FLAGS_NONE + +/** + * Array of bitwise flags which won't be turned off on a cycle reset (will persist between cycles) + */ +PersistentCycleSceneFlags sPersistentCycleSceneFlags[SCENE_MAX] = { +#include "tables/scene_table.h" +}; + +#undef DEFINE_SCENE +#undef DEFINE_SCENE_UNSET + +// Each flag has 2 bits to store persistence over the three-day reset cycle +// Only 1 of these bits need to be set to persist (Values 1, 2, 3). +// Therefore, the final game does not distinguish between these two macros in use +#define PERSISTENT_WEEKEVENTREG(flag) (3 << (2 * BIT_FLAG_TO_SHIFT(flag))) +#define PERSISTENT_WEEKEVENTREG_ALT(flag) (2 << (2 * BIT_FLAG_TO_SHIFT(flag))) + +// weekEventReg flags which will be not be cleared on a cycle reset +//! @note The index of the flag in this array must be the same to its index in the WeekeventReg array +//! Only the mask is read from the `PERSISTENT_` macros. +u16 sPersistentCycleWeekEventRegs[ARRAY_COUNT(gSaveContext.save.saveInfo.weekEventReg)] = { + /* 0 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_TERMINA_FIELD) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_IKANA_GRAVEYARD) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_ROMANI_RANCH) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_GORMAN_TRACK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_MOUNTAIN_VILLAGE_WINTER) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_GORON_SHRINE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_SNOWHEAD), + /* 1 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_SOUTHERN_SWAMP_POISONED) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_WOODFALL) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_DEKU_PALACE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_GREAT_BAY_COAST) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_PIRATES_FORTRESS) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_ZORA_HALL) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_WATERFALL_RAPIDS) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_IKANA_CANYON), + /* 2 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_IKANA_CASTLE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_STONE_TOWER) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_STONE_TOWER_INVERTED) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_EAST_CLOCK_TOWN) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_WEST_CLOCK_TOWN) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_NORTH_CLOCK_TOWN) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_WOODFALL_TEMPLE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_SNOWHEAD_TEMPLE), + /* 3 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_PIRATES_FORTRESS_EXTERIOR) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_STONE_TOWER_TEMPLE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_STONE_TOWER_TEMPLE_INVERTED) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_THE_MOON) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_MOON_DEKU_TRIAL) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_MOON_GORON_TRIAL) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_MOON_ZORA_TRIAL) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_03_80), + /* 4 */ 0, + /* 5 */ 0, + /* 6 */ 0, + /* 7 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_ENTERED_WOODFALL_TEMPLE_PRISON), + /* 8 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_DOGGY_RACETRACK_HEART_PIECE), + /* 9 */ 0, + /* 10 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_BANK_WALLET_UPGRADE), + /* 11 */ 0, + /* 12 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_KOTAKE_BOTTLE), + /* 13 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_OCEANSIDE_WALLET_UPGRADE), + /* 14 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_DEKU_PLAYGROUND_HEART_PIECE), + /* 15 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_15_20), + /* 16 */ 0, + /* 17 */ 0, + /* 18 */ 0, + /* 19 */ 0, + /* 20 */ 0, + /* 21 */ 0, + /* 22 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_ALIENS_BOTTLE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_HONEY_AND_DARLING_HEART_PIECE), + /* 23 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_GREAT_SPIN_ATTACK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_BEAVER_RACE_BOTTLE), + /* 24 */ PERSISTENT_WEEKEVENTREG_ALT(WEEKEVENTREG_24_02) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_24_80), + /* 25 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_BEAVER_BROS_HEART_PIECE), + /* 26 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_26_40), + /* 27 */ 0, + /* 28 */ 0, + /* 29 */ 0, + /* 30 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_30_10) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_30_20) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_30_40) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_30_80), + /* 31 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_31_01) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_31_02) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_31_04) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_31_20), + /* 32 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SEAHORSE_HEART_PIECE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_HEART_PIECE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_HEART_PIECE), + /* 33 */ 0, + /* 34 */ 0, + /* 35 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_CLOCK_TOWN) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_WOODFALL) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_SNOWHEAD) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_ROMANI_RANCH) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_GREAT_BAY) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_STONE_TOWER) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_FROG_CHOIR_HEART_PIECE), + /* 36 */ 0, + /* 37 */ 0, + /* 38 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_38_20), + /* 39 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_EVAN_HEART_PIECE), + /* 40 */ 0, + /* 41 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_GORON_RACE_BOTTLE), + /* 42 */ 0, + /* 43 */ 0, + /* 44 */ 0, + /* 45 */ 0, + /* 46 */ 0, + /* 47 */ 0, + /* 48 */ 0, + /* 49 */ 0, + /* 50 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_50_02) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_50_04), + /* 51 */ PERSISTENT_WEEKEVENTREG_ALT(WEEKEVENTREG_51_04), + /* 52 */ 0, + /* 53 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_BUSINESS_SCRUB_HEART_PIECE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_53_40), + /* 54 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SPIRIT_HOUSE_HEART_PIECE), + /* 55 */ 0, + /* 56 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_MARINE_RESEARCH_LAB_FISH_HEART_PIECE), + /* 57 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_57_08), + /* 58 */ 0, + /* 59 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_59_04) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_BANK_HEART_PIECE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_QUIVER_UPGRADE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_QUIVER_UPGRADE), + /* 60 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_MAYOR_HEART_PIECE), + /* 61 */ 0, + /* 62 */ 0, + /* 63 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWORDSMANS_SCHOOL_HEART_PIECE), + /* 64 */ 0, + /* 65 */ 0, + /* 66 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_ANJU) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_KAFEI) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_CURIOSITY_SHOP_MAN) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_BOMB_SHOP_LADY) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_ROMANI) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_CREMIA) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_MAYOR_DOTOUR) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_MADAME_AROMA), + /* 67 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_TOTO) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_GORMAN) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_POSTMAN) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_ROSA_SISTERS) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_TOILET_HAND) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_ANJUS_GRANDMOTHER) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_KAMARO) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_GROG), + /* 68 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_GORMAN_BROTHERS) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_SHIRO) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_GURU_GURU) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_MET_BOMBERS) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_ROOM_KEY) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_PROMISED_MIDNIGHT_MEETING) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_PROMISED_TO_MEET_KAFEI) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_LETTER_TO_KAFEI), + /* 69 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_DEPOSITED_LETTER_TO_KAFEI) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_PENDANT_OF_MEMORIES) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_DELIVERED_PENDANT_OF_MEMORIES) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_ESCAPED_SAKONS_HIDEOUT) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_PROMISED_TO_HELP_WITH_ALIENS) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_DEFENDED_AGAINST_ALIENS) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_ALIENS_BOTTLE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_ESCORTED_CREMIA), + /* 70 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_ROMANIS_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_KEATON_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_PRIORITY_MAIL) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_DELIVERED_PRIORITY_MAIL) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_LEARNED_SECRET_CODE) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_BOMBERS_NOTEBOOK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_MAYOR_HP) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_ROSA_SISTERS_HP), + /* 71 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_TOILET_HAND_HP) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_GRANDMA_SHORT_STORY_HP) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_GRANDMA_LONG_STORY_HP) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_POSTMAN_HP) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_KAFEIS_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_ALL_NIGHT_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_BUNNY_HOOD) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_GAROS_MASK), + /* 72 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_CIRCUS_LEADERS_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_POSTMANS_HAT) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_COUPLES_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_BLAST_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_KAMAROS_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_STONE_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_BOMBERS_NOTEBOOK_EVENT_RECEIVED_BREMEN_MASK) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_72_80), + /* 73 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_73_08), + /* 74 */ 0, + /* 75 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_ROSA_SISTERS_HEART_PIECE), + /* 76 */ 0, + /* 77 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_POSTMAN_COUNTING_GAME_HEART_PIECE), + /* 78 */ 0, + /* 79 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_KEATON_HEART_PIECE), + /* 80 */ 0, + /* 81 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_81_08), + /* 82 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_FISHERMANS_JUMPING_GAME_HEART_PIECE), + /* 83 */ 0, + /* 84 */ 0, + /* 85 */ 0, + /* 86 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_86_80), + /* 87 */ + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_87_04) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_87_08) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_87_10) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_87_20) | + PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_87_40) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_87_80), + /* 88 */ 0, + /* 89 */ 0, + /* 90 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_GOSSIP_STONE_GROTTO_HEART_PIECE), + /* 91 */ 0, + /* 92 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_92_80), + /* 93 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_93_04) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_93_08), + /* 94 */ 0, + /* 95 */ 0, + /* 96 */ 0, + /* 97 */ 0, + /* 98 */ 0, + /* 99 */ 0, +}; + +// Unused remnant values from OoT. Not the correct sizes in MM. +#define OOT_SAVECONTEXT_SIZE 0x1428 +#define OOT_SLOT_SIZE (OOT_SAVECONTEXT_SIZE + 0x28) +#define OOT_SRAM_HEADER_SIZE 0x10 +#define OOT_SLOT_OFFSET(index) (OOT_SRAM_HEADER_SIZE + 0x10 + (index * OOT_SLOT_SIZE)) + +// used in other files +u32 gSramSlotOffsets[] = { + OOT_SLOT_OFFSET(0), + OOT_SLOT_OFFSET(1), + OOT_SLOT_OFFSET(2), + // the latter three saves are backup saves for the former saves (in OoT) + OOT_SLOT_OFFSET(3), + OOT_SLOT_OFFSET(4), + OOT_SLOT_OFFSET(5), +}; + +u8 gAmmoItems[ITEM_NUM_SLOTS] = { + ITEM_NONE, // SLOT_OCARINA + ITEM_BOW, // SLOT_BOW + ITEM_NONE, // SLOT_ARROW_FIRE + ITEM_NONE, // SLOT_ARROW_ICE + ITEM_NONE, // SLOT_ARROW_LIGHT + ITEM_NONE, // SLOT_TRADE_DEED + ITEM_BOMB, // SLOT_BOMB + ITEM_BOMBCHU, // SLOT_BOMBCHU + ITEM_DEKU_STICK, // SLOT_DEKU_STICK + ITEM_DEKU_NUT, // SLOT_DEKU_NUT + ITEM_MAGIC_BEANS, // SLOT_MAGIC_BEANS + ITEM_NONE, // SLOT_TRADE_KEY_MAMA + ITEM_POWDER_KEG, // SLOT_POWDER_KEG + ITEM_PICTOGRAPH_BOX, // SLOT_PICTOGRAPH_BOX + ITEM_NONE, // SLOT_LENS_OF_TRUTH + ITEM_NONE, // SLOT_HOOKSHOT + ITEM_NONE, // SLOT_SWORD_GREAT_FAIRY + ITEM_NONE, // SLOT_TRADE_COUPLE + ITEM_NONE, // SLOT_BOTTLE_1 + ITEM_NONE, // SLOT_BOTTLE_2 + ITEM_NONE, // SLOT_BOTTLE_3 + ITEM_NONE, // SLOT_BOTTLE_4 + ITEM_NONE, // SLOT_BOTTLE_5 + ITEM_NONE, // SLOT_BOTTLE_6 +}; + +// Stores flash start page number +s32 gFlashSaveStartPages[] = { + 0, // File 1 New Cycle Save + 0x40, // File 1 New Cycle Save Backup + 0x80, // File 2 New Cycle Save + 0xC0, // File 2 New Cycle Save Backup + 0x100, // File 1 Owl Save + 0x180, // File 1 Owl Save Backup + 0x200, // File 2 Owl Save + 0x280, // File 2 Owl Save Backup + 0x300, // Sram Header (SaveOptions) + 0x380, // Sram Header Backup (SaveOptions) +}; + +// Flash rom number of pages +s32 gFlashSaveNumPages[] = { + 0x40, // File 1 New Cycle Save + 0x40, // File 1 New Cycle Save Backup + 0x40, // File 2 New Cycle Save + 0x40, // File 2 New Cycle Save Backup + 0x80, // File 1 Owl Save + 0x80, // File 1 Owl Save Backup + 0x80, // File 2 Owl Save + 0x80, // File 2 Owl Save Backup + 1, // Sram Header (SaveOptions) + 1, // Sram Header Backup (SaveOptions) +}; + +// Flash rom number of pages on very first time Player enters South Clock Town from the Clock Tower +s32 gFlashSpecialSaveNumPages[] = { + 0x80, // File 1 New Cycle Save + 0x80, // File 1 New Cycle Save Backup + 0x80, // File 2 New Cycle Save + 0x80, // File 2 New Cycle Save Backup + 0x80, // File 1 Owl Save + 0x80, // File 1 Owl Save Backup + 0x80, // File 2 Owl Save + 0x80, // File 2 Owl Save Backup + 1, // Sram Header (SaveOptions) + 1, // Sram Header Backup (SaveOptions) +}; + +// Owl Save flash rom start page number +s32 gFlashOwlSaveStartPages[] = { + 0x100, // File 1 Owl Save + 0x180, // File 1 Owl Save Backup + 0x200, // File 2 Owl Save + 0x280, // File 2 Owl Save Backup +}; + +// Owl Save flash rom number of pages +s32 gFlashOwlSaveNumPages[] = { + 0x80, // File 1 Owl Save + 0x80, // File 1 Owl Save Backup + 0x80, // File 2 Owl Save + 0x80, // File 2 Owl Save Backup +}; + +// Save Options Sram Header flash rom start page number +s32 gFlashOptionsSaveStartPages[] = { + 0x300, // Sram Header (SaveOptions) + 0x380, // Sram Header Backup (SaveOptions) +}; + +// Save Options Sram Header flash rom number of pages +s32 gFlashOptionsSaveNumPages[] = { + 1, // Sram Header (SaveOptions) + 1, // Sram Header Backup (SaveOptions) +}; + +// Flash rom actual size needed +s32 gFlashSaveSizes[] = { + sizeof(Save), // size = 0x100C - File 1 New Cycle Save + sizeof(Save), // size = 0x100C - File 1 New Cycle Save Backup + sizeof(Save), // size = 0x100C - File 2 New Cycle Save + sizeof(Save), // size = 0x100C - File 2 New Cycle Save Backup + offsetof(SaveContext, fileNum), // size = 0x3CA0 - File 1 Owl Save + offsetof(SaveContext, fileNum), // size = 0x3CA0 - File 1 Owl Save Backup + offsetof(SaveContext, fileNum), // size = 0x3CA0 - File 2 Owl Save + offsetof(SaveContext, fileNum), // size = 0x3CA0 - File 2 Owl Save Backup +}; + +// Bit Flag array in which sBitFlags8[n] is (1 << n) +u8 sBitFlags8[] = { + (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), +}; + +u16 D_801F6AF0; +u8 D_801F6AF2; + +void Sram_ActivateOwl(u8 owlWarpId) { + SET_OWL_STATUE_ACTIVATED(owlWarpId); + + if (gSaveContext.save.saveInfo.playerData.owlWarpId == OWL_WARP_NONE) { + gSaveContext.save.saveInfo.playerData.owlWarpId = owlWarpId; + } +} + +void Sram_ClearHighscores(void) { + HS_SET_BOAT_ARCHERY_HIGH_SCORE(19); + HS_SET_HIGH_SCORE_3_LOWER(10); + HS_SET_HORSE_BACK_BALLOON_TIME(SECONDS_TO_TIMER(60)); + HS_SET_TOWN_SHOOTING_GALLERY_HIGH_SCORE(39); + HS_SET_SWAMP_SHOOTING_GALLERY_HIGH_SCORE(10); + + gSaveContext.save.saveInfo.dekuPlaygroundHighScores[0] = SECONDS_TO_TIMER(75); + gSaveContext.save.saveInfo.dekuPlaygroundHighScores[1] = SECONDS_TO_TIMER(75); + gSaveContext.save.saveInfo.dekuPlaygroundHighScores[2] = SECONDS_TO_TIMER(76); +} + +/** + * Clears specific weekEventReg flags. Used by the "Dawn of the First Day" message + */ +void Sram_ClearFlagsAtDawnOfTheFirstDay(void) { + CLEAR_WEEKEVENTREG(WEEKEVENTREG_55_02); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_90_01); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_89_40); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_89_08); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_85_80); +} + +/** + * Used by Song of Time (when clicking "Yes") and (indirectly) by the "Dawn of the New Day" cutscene + */ +void Sram_SaveEndOfCycle(PlayState* play) { + s16 sceneId; + s32 j; + s32 i; + u8 slot; + u8 item; + + gSaveContext.save.timeSpeedOffset = 0; + gSaveContext.save.eventDayCount = 0; + gSaveContext.save.day = 0; + gSaveContext.save.time = CLOCK_TIME(6, 0) - 1; + + gSaveContext.save.saveInfo.playerData.threeDayResetCount++; + if (gSaveContext.save.saveInfo.playerData.threeDayResetCount > 999) { + gSaveContext.save.saveInfo.playerData.threeDayResetCount = 999; + } + + sceneId = Play_GetOriginalSceneId(play->sceneId); + Play_SaveCycleSceneFlags(play); + + play->actorCtx.sceneFlags.chest &= sPersistentCycleSceneFlags[sceneId].chest; + play->actorCtx.sceneFlags.switches[0] &= sPersistentCycleSceneFlags[sceneId].switch0; + play->actorCtx.sceneFlags.switches[1] &= sPersistentCycleSceneFlags[sceneId].switch1; + play->actorCtx.sceneFlags.collectible[0] &= sPersistentCycleSceneFlags[sceneId].collectible; + play->actorCtx.sceneFlags.clearedRoom = 0; + + for (i = 0; i < SCENE_MAX; i++) { + gSaveContext.cycleSceneFlags[i].switch0 = + ((void)0, gSaveContext.cycleSceneFlags[i].switch0) & sPersistentCycleSceneFlags[i].switch0; + gSaveContext.cycleSceneFlags[i].switch1 = + ((void)0, gSaveContext.cycleSceneFlags[i].switch1) & sPersistentCycleSceneFlags[i].switch1; + gSaveContext.cycleSceneFlags[i].chest = + ((void)0, gSaveContext.cycleSceneFlags[i].chest) & sPersistentCycleSceneFlags[i].chest; + gSaveContext.cycleSceneFlags[i].collectible = + ((void)0, gSaveContext.cycleSceneFlags[i].collectible) & sPersistentCycleSceneFlags[i].collectible; + gSaveContext.cycleSceneFlags[i].clearedRoom = 0; + gSaveContext.save.saveInfo.permanentSceneFlags[i].unk_14 = 0; + gSaveContext.save.saveInfo.permanentSceneFlags[i].rooms = 0; + } + + for (; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { + gSaveContext.cycleSceneFlags[i].chest = 0; + gSaveContext.cycleSceneFlags[i].switch0 = 0; + gSaveContext.cycleSceneFlags[i].switch1 = 0; + gSaveContext.cycleSceneFlags[i].clearedRoom = 0; + gSaveContext.cycleSceneFlags[i].collectible = 0; + } + + for (i = 0; i < ARRAY_COUNT(gSaveContext.masksGivenOnMoon); i++) { + gSaveContext.masksGivenOnMoon[i] = 0; + } + + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_84_20)) { + Inventory_DeleteItem(ITEM_MASK_FIERCE_DEITY, SLOT(ITEM_MASK_FIERCE_DEITY)); + } + + for (i = 0; i < ARRAY_COUNT(sPersistentCycleWeekEventRegs); i++) { + u16 isPersistentBits = sPersistentCycleWeekEventRegs[i]; + + for (j = 0; j < ARRAY_COUNT(sBitFlags8); j++) { + if (!(isPersistentBits & 3)) { + gSaveContext.save.saveInfo.weekEventReg[i] = + ((void)0, gSaveContext.save.saveInfo.weekEventReg[i]) & (0xFF ^ sBitFlags8[j]); + } + isPersistentBits >>= 2; + } + } + + for (i = 0; i < ARRAY_COUNT(gSaveContext.eventInf); i++) { + gSaveContext.eventInf[i] = 0; + } + + CLEAR_EVENTINF(EVENTINF_THREEDAYRESET_LOST_RUPEES); + CLEAR_EVENTINF(EVENTINF_THREEDAYRESET_LOST_BOMB_AMMO); + CLEAR_EVENTINF(EVENTINF_THREEDAYRESET_LOST_NUT_AMMO); + CLEAR_EVENTINF(EVENTINF_THREEDAYRESET_LOST_STICK_AMMO); + CLEAR_EVENTINF(EVENTINF_THREEDAYRESET_LOST_ARROW_AMMO); + + if (gSaveContext.save.saveInfo.playerData.rupees != 0) { + SET_EVENTINF(EVENTINF_THREEDAYRESET_LOST_RUPEES); + } + + if (INV_CONTENT(ITEM_BOMB) == ITEM_BOMB) { + item = INV_CONTENT(ITEM_BOMB); + if (AMMO(item) != 0) { + SET_EVENTINF(EVENTINF_THREEDAYRESET_LOST_BOMB_AMMO); + } + } + if (INV_CONTENT(ITEM_DEKU_NUT) == ITEM_DEKU_NUT) { + item = INV_CONTENT(ITEM_DEKU_NUT); + if (AMMO(item) != 0) { + SET_EVENTINF(EVENTINF_THREEDAYRESET_LOST_NUT_AMMO); + } + } + if (INV_CONTENT(ITEM_DEKU_STICK) == ITEM_DEKU_STICK) { + item = INV_CONTENT(ITEM_DEKU_STICK); + if (AMMO(item) != 0) { + SET_EVENTINF(EVENTINF_THREEDAYRESET_LOST_STICK_AMMO); + } + } + if (INV_CONTENT(ITEM_BOW) == ITEM_BOW) { + item = INV_CONTENT(ITEM_BOW); + if (AMMO(item) != 0) { + SET_EVENTINF(EVENTINF_THREEDAYRESET_LOST_ARROW_AMMO); + } + } + + for (i = 0; i < ITEM_NUM_SLOTS; i++) { + if (gAmmoItems[i] != ITEM_NONE) { + if ((gSaveContext.save.saveInfo.inventory.items[i] != ITEM_NONE) && (i != SLOT_PICTOGRAPH_BOX)) { + item = gSaveContext.save.saveInfo.inventory.items[i]; + AMMO(item) = 0; + } + } + } + + for (i = SLOT_BOTTLE_1; i <= SLOT_BOTTLE_6; i++) { + // Check for all bottled items + if (gSaveContext.save.saveInfo.inventory.items[i] >= ITEM_POTION_RED) { + if (gSaveContext.save.saveInfo.inventory.items[i] <= ITEM_OBABA_DRINK) { + for (j = EQUIP_SLOT_C_LEFT; j <= EQUIP_SLOT_C_RIGHT; j++) { + if (GET_CUR_FORM_BTN_ITEM(j) == gSaveContext.save.saveInfo.inventory.items[i]) { + SET_CUR_FORM_BTN_ITEM(j, ITEM_BOTTLE); + Interface_LoadItemIconImpl(play, j); + } + } + gSaveContext.save.saveInfo.inventory.items[i] = ITEM_BOTTLE; + } + } + } + + REMOVE_QUEST_ITEM(QUEST_PICTOGRAPH); + + if (gSaveContext.save.saveInfo.playerData.health < 0x30) { + gSaveContext.save.saveInfo.playerData.health = 0x30; + } + + if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) <= EQUIP_VALUE_SWORD_RAZOR) { + SET_EQUIP_VALUE(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_KOKIRI); + + if (CUR_FORM == 0) { + if ((STOLEN_ITEM_1 >= ITEM_SWORD_GILDED) || (STOLEN_ITEM_2 >= ITEM_SWORD_GILDED)) { + CUR_FORM_EQUIP(EQUIP_SLOT_B) = ITEM_SWORD_GILDED; + SET_EQUIP_VALUE(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_GILDED); + } else { + CUR_FORM_EQUIP(EQUIP_SLOT_B) = ITEM_SWORD_KOKIRI; + } + } else { + if ((STOLEN_ITEM_1 >= ITEM_SWORD_GILDED) || (STOLEN_ITEM_2 >= ITEM_SWORD_GILDED)) { + BUTTON_ITEM_EQUIP(0, EQUIP_SLOT_B) = ITEM_SWORD_GILDED; + SET_EQUIP_VALUE(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_GILDED); + } else { + BUTTON_ITEM_EQUIP(0, EQUIP_SLOT_B) = ITEM_SWORD_KOKIRI; + } + } + } + + if ((STOLEN_ITEM_1 == ITEM_SWORD_GREAT_FAIRY) || (STOLEN_ITEM_2 == ITEM_SWORD_GREAT_FAIRY)) { + INV_CONTENT(ITEM_SWORD_GREAT_FAIRY) = ITEM_SWORD_GREAT_FAIRY; + } + + if (STOLEN_ITEM_1 == ITEM_BOTTLE) { + slot = SLOT(ITEM_BOTTLE); + for (i = BOTTLE_FIRST; i < BOTTLE_MAX; i++) { + if (gSaveContext.save.saveInfo.inventory.items[slot + i] == ITEM_NONE) { + gSaveContext.save.saveInfo.inventory.items[slot + i] = ITEM_BOTTLE; + break; + } + } + } + + if (STOLEN_ITEM_2 == ITEM_BOTTLE) { + slot = SLOT(ITEM_BOTTLE); + for (i = BOTTLE_FIRST; i < BOTTLE_MAX; i++) { + if (gSaveContext.save.saveInfo.inventory.items[slot + i] == ITEM_NONE) { + gSaveContext.save.saveInfo.inventory.items[slot + i] = ITEM_BOTTLE; + break; + } + } + } + + SET_STOLEN_ITEM_1(STOLEN_ITEM_NONE); + SET_STOLEN_ITEM_2(STOLEN_ITEM_NONE); + + Inventory_DeleteItem(ITEM_OCARINA_FAIRY, SLOT_TRADE_DEED); + Inventory_DeleteItem(ITEM_SLINGSHOT, SLOT_TRADE_KEY_MAMA); + Inventory_DeleteItem(ITEM_LONGSHOT, SLOT_TRADE_COUPLE); + + for (j = EQUIP_SLOT_C_LEFT; j <= EQUIP_SLOT_C_RIGHT; j++) { + if ((GET_CUR_FORM_BTN_ITEM(j) >= ITEM_MOONS_TEAR) && (GET_CUR_FORM_BTN_ITEM(j) <= ITEM_PENDANT_OF_MEMORIES)) { + SET_CUR_FORM_BTN_ITEM(j, ITEM_NONE); + Interface_LoadItemIconImpl(play, j); + } + } + + gSaveContext.save.saveInfo.skullTokenCount &= ~0xFFFF0000; + gSaveContext.save.saveInfo.skullTokenCount &= ~0x0000FFFF; + gSaveContext.save.saveInfo.unk_EA0 = 0; + + gSaveContext.save.saveInfo.alienInfo[0] = 0; + gSaveContext.save.saveInfo.alienInfo[1] = 0; + gSaveContext.save.saveInfo.alienInfo[2] = 0; + gSaveContext.save.saveInfo.alienInfo[3] = 0; + gSaveContext.save.saveInfo.alienInfo[4] = 0; + gSaveContext.save.saveInfo.alienInfo[5] = 0; + gSaveContext.save.saveInfo.alienInfo[6] = 0; + + Sram_ClearHighscores(); + + for (i = 0; i < 8; i++) { + gSaveContext.save.saveInfo.inventory.dungeonItems[i] &= (u8)~1; // remove boss key + DUNGEON_KEY_COUNT(i) = 0; + gSaveContext.save.saveInfo.inventory.strayFairies[i] = 0; + } + + gSaveContext.save.saveInfo.playerData.rupees = 0; + gSaveContext.save.saveInfo.scarecrowSpawnSongSet = false; + gSaveContext.powderKegTimer = 0; + gSaveContext.unk_1014 = 0; + gSaveContext.jinxTimer = 0; + gSaveContext.rupeeAccumulator = 0; + + Horse_ResetHorseData(play); +} + +void Sram_IncrementDay(void) { + if (CURRENT_DAY <= 3) { + gSaveContext.save.day++; + gSaveContext.save.eventDayCount++; + } + + gSaveContext.save.saveInfo.bombersCaughtNum = 0; + gSaveContext.save.saveInfo.bombersCaughtOrder[0] = 0; + gSaveContext.save.saveInfo.bombersCaughtOrder[1] = 0; + gSaveContext.save.saveInfo.bombersCaughtOrder[2] = 0; + gSaveContext.save.saveInfo.bombersCaughtOrder[3] = 0; + gSaveContext.save.saveInfo.bombersCaughtOrder[4] = 0; + + CLEAR_WEEKEVENTREG(WEEKEVENTREG_73_10); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_85_02); +} + +u16 Sram_CalcChecksum(void* data, size_t count) { + u8* dataPtr = data; + u16 chkSum = 0; + + while (count-- > 0) { + chkSum += *dataPtr; + dataPtr++; + } + return chkSum; +} + +// Resets `Save` substruct +void Sram_ResetSave(void) { + gSaveContext.save.entrance = ENTRANCE(CUTSCENE, 0); + gSaveContext.save.equippedMask = 0; + gSaveContext.save.isFirstCycle = false; + gSaveContext.save.unk_06 = 0; + gSaveContext.save.linkAge = 0; + gSaveContext.save.isNight = false; + gSaveContext.save.timeSpeedOffset = 0; + gSaveContext.save.snowheadCleared = 0; + gSaveContext.save.hasTatl = false; + gSaveContext.save.isOwlSave = false; + + bzero(&gSaveContext.save.saveInfo, sizeof(SaveInfo)); +} + +/** + * Initializes with random values the following fields: + * - lotteryCodes + * - spiderHouseMaskOrder + * - bomberCode + */ +void Sram_GenerateRandomSaveFields(void) { + s32 randBombers; + s16 sp2A; + s16 pad; + s16 i; + s16 j; + s32 k; + s16 randSpiderHouse; + + Sram_ClearHighscores(); + + gSaveContext.save.saveInfo.lotteryCodes[0][0] = Rand_S16Offset(0, 10); + gSaveContext.save.saveInfo.lotteryCodes[0][1] = Rand_S16Offset(0, 10); + gSaveContext.save.saveInfo.lotteryCodes[0][2] = Rand_S16Offset(0, 10); + gSaveContext.save.saveInfo.lotteryCodes[1][0] = Rand_S16Offset(0, 10); + gSaveContext.save.saveInfo.lotteryCodes[1][1] = Rand_S16Offset(0, 10); + gSaveContext.save.saveInfo.lotteryCodes[1][2] = Rand_S16Offset(0, 10); + gSaveContext.save.saveInfo.lotteryCodes[2][0] = Rand_S16Offset(0, 10); + gSaveContext.save.saveInfo.lotteryCodes[2][1] = Rand_S16Offset(0, 10); + gSaveContext.save.saveInfo.lotteryCodes[2][2] = Rand_S16Offset(0, 10); + + // Needed to match... + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) {} + } + + i = 0; + sp2A = Rand_S16Offset(0, 16) & 3; + k = 6; + while (i != k) { + randSpiderHouse = Rand_S16Offset(0, 16) & 3; + if (sp2A != randSpiderHouse) { + gSaveContext.save.saveInfo.spiderHouseMaskOrder[i] = randSpiderHouse; + i++; + sp2A = randSpiderHouse; + } + } + + do { + randBombers = Rand_S16Offset(0, 6); + } while ((randBombers <= 0) || (randBombers >= 6)); + + gSaveContext.save.saveInfo.bomberCode[0] = randBombers; + + i = 1; + while (i != 5) { + k = false; + + do { + randBombers = Rand_S16Offset(0, 6); + } while ((randBombers <= 0) || (randBombers >= 6)); + + sp2A = 0; + do { + if (randBombers == gSaveContext.save.saveInfo.bomberCode[sp2A]) { + k = true; + } + sp2A++; + } while (sp2A < i); + + if (k == false) { + gSaveContext.save.saveInfo.bomberCode[i] = randBombers; + i++; + } + } +} + +SavePlayerData sSaveDefaultPlayerData = { + { '\0', '\0', '\0', '\0', '\0', '\0' }, // newf + 0, // threeDayResetCount + { 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E }, // playerName " " + 0x30, // healthCapacity + 0x30, // health + 0, // magicLevel + MAGIC_NORMAL_METER, // magic + 0, // rupees + 0, // swordHealth + 0, // tatlTimer + false, // isMagicAcquired + false, // isDoubleMagicAcquired + 0, // doubleDefense + 0, // unk_1F + OWL_WARP_NONE, // owlWarpId + 0, // owlActivationFlags + 0xFF, // unk_24 + SCENE_SPOT00, // savedSceneId +}; + +ItemEquips sSaveDefaultItemEquips = { + { + { ITEM_SWORD_KOKIRI, ITEM_NONE, ITEM_NONE, ITEM_NONE }, + { ITEM_SWORD_KOKIRI, ITEM_NONE, ITEM_NONE, ITEM_NONE }, + { ITEM_SWORD_KOKIRI, ITEM_NONE, ITEM_NONE, ITEM_NONE }, + { ITEM_FD, ITEM_NONE, ITEM_NONE, ITEM_NONE }, + }, + { + { SLOT_OCARINA, SLOT_NONE, SLOT_NONE, SLOT_NONE }, + { SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE }, + { SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE }, + { SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE }, + }, + 0x11, +}; + +Inventory sSaveDefaultInventory = { + // items + { + ITEM_NONE, // SLOT_OCARINA + ITEM_NONE, // SLOT_BOW + ITEM_NONE, // SLOT_ARROW_FIRE + ITEM_NONE, // SLOT_ARROW_ICE + ITEM_NONE, // SLOT_ARROW_LIGHT + ITEM_NONE, // SLOT_TRADE_DEED + ITEM_NONE, // SLOT_BOMB + ITEM_NONE, // SLOT_BOMBCHU + ITEM_NONE, // SLOT_DEKU_STICK + ITEM_NONE, // SLOT_DEKU_NUT + ITEM_NONE, // SLOT_MAGIC_BEANS + ITEM_NONE, // SLOT_TRADE_KEY_MAMA + ITEM_NONE, // SLOT_POWDER_KEG + ITEM_NONE, // SLOT_PICTOGRAPH_BOX + ITEM_NONE, // SLOT_LENS_OF_TRUTH + ITEM_NONE, // SLOT_HOOKSHOT + ITEM_NONE, // SLOT_SWORD_GREAT_FAIRY + ITEM_NONE, // SLOT_TRADE_COUPLE + ITEM_NONE, // SLOT_BOTTLE_1 + ITEM_NONE, // SLOT_BOTTLE_2 + ITEM_NONE, // SLOT_BOTTLE_3 + ITEM_NONE, // SLOT_BOTTLE_4 + ITEM_NONE, // SLOT_BOTTLE_5 + ITEM_NONE, // SLOT_BOTTLE_6 + ITEM_NONE, // SLOT_MASK_POSTMAN + ITEM_NONE, // SLOT_MASK_ALL_NIGHT + ITEM_NONE, // SLOT_MASK_BLAST + ITEM_NONE, // SLOT_MASK_STONE + ITEM_NONE, // SLOT_MASK_GREAT_FAIRY + ITEM_NONE, // SLOT_MASK_DEKU + ITEM_NONE, // SLOT_MASK_KEATON + ITEM_NONE, // SLOT_MASK_BREMEN + ITEM_NONE, // SLOT_MASK_BUNNY + ITEM_NONE, // SLOT_MASK_DON_GERO + ITEM_NONE, // SLOT_MASK_SCENTS + ITEM_NONE, // SLOT_MASK_GORON + ITEM_NONE, // SLOT_MASK_ROMANI + ITEM_NONE, // SLOT_MASK_CIRCUS_LEADER + ITEM_NONE, // SLOT_MASK_KAFEIS_MASK + ITEM_NONE, // SLOT_MASK_COUPLE + ITEM_NONE, // SLOT_MASK_TRUTH + ITEM_NONE, // SLOT_MASK_ZORA + ITEM_NONE, // SLOT_MASK_KAMARO + ITEM_NONE, // SLOT_MASK_GIBDO + ITEM_NONE, // SLOT_MASK_GARO + ITEM_NONE, // SLOT_MASK_CAPTAIN + ITEM_NONE, // SLOT_MASK_GIANT + ITEM_NONE, // SLOT_MASK_FIERCE_DEITY + }, + // ammo + { + 0, // SLOT_OCARINA + 0, // SLOT_BOW + 0, // SLOT_ARROW_FIRE + 0, // SLOT_ARROW_ICE + 0, // SLOT_ARROW_LIGHT + 0, // SLOT_TRADE_DEED + 0, // SLOT_BOMB + 0, // SLOT_BOMBCHU + 0, // SLOT_DEKU_STICK + 0, // SLOT_DEKU_NUT + 0, // SLOT_MAGIC_BEANS + 0, // SLOT_TRADE_KEY_MAMA + 0, // SLOT_POWDER_KEG + 0, // SLOT_PICTOGRAPH_BOX + 0, // SLOT_LENS_OF_TRUTH + 0, // SLOT_HOOKSHOT + 0, // SLOT_SWORD_GREAT_FAIRY + 0, // SLOT_TRADE_COUPLE + 0, // SLOT_BOTTLE_1 + 0, // SLOT_BOTTLE_2 + 0, // SLOT_BOTTLE_3 + 0, // SLOT_BOTTLE_4 + 0, // SLOT_BOTTLE_5 + 0, // SLOT_BOTTLE_6 + }, + // upgrades + (0 << 0) | // UPG_QUIVER + (0 << 3) | // UPG_BOMB_BAG + (0 << 6) | // UPG_STRENGTH + (0 << 9) | // UPG_SCALE + (0 << 12) | // UPG_WALLET + (0 << 14) | // UPG_BULLET_BAG + (1 << 17) | // UPG_DEKU_STICKS + (1 << 20), // UPG_DEKU_NUTS + // questItems + 0, + // dungeonItems + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + // dungeonKeys + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + // defenseHearts + 0, + // strayFairies + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + // dekuPlaygroundPlayerName + { + // "LINK " + { 0x15, 0x12, 0x17, 0x14, 0x3E, 0x3E, 0x3E, 0x3E }, + // "LINK " + { 0x15, 0x12, 0x17, 0x14, 0x3E, 0x3E, 0x3E, 0x3E }, + // "LINK " + { 0x15, 0x12, 0x17, 0x14, 0x3E, 0x3E, 0x3E, 0x3E }, + }, +}; + +u16 sSaveDefaultChecksum = 0; + +/** + * Initialize new save. + * This save has an empty inventory with 3 hearts, sword and shield. + */ +void Sram_InitNewSave(void) { + gSaveContext.save.playerForm = PLAYER_FORM_HUMAN; + gSaveContext.save.eventDayCount = 0; + gSaveContext.save.day = 0; + gSaveContext.save.time = CLOCK_TIME(6, 0) - 1; + Sram_ResetSave(); + + Lib_MemCpy(&gSaveContext.save.saveInfo.playerData, &sSaveDefaultPlayerData, sizeof(SavePlayerData)); + Lib_MemCpy(&gSaveContext.save.saveInfo.equips, &sSaveDefaultItemEquips, sizeof(ItemEquips)); + Lib_MemCpy(&gSaveContext.save.saveInfo.inventory, &sSaveDefaultInventory, sizeof(Inventory)); + Lib_MemCpy(&gSaveContext.save.saveInfo.checksum, &sSaveDefaultChecksum, + sizeof(gSaveContext.save.saveInfo.checksum)); + + gSaveContext.save.saveInfo.horseData.sceneId = SCENE_F01; + gSaveContext.save.saveInfo.horseData.pos.x = -1420; + gSaveContext.save.saveInfo.horseData.pos.y = 257; + gSaveContext.save.saveInfo.horseData.pos.z = -1285; + gSaveContext.save.saveInfo.horseData.yaw = -0x7554; + + gSaveContext.nextCutsceneIndex = 0; + gSaveContext.save.saveInfo.playerData.magicLevel = 0; + Sram_GenerateRandomSaveFields(); +} + +SavePlayerData sSaveDebugPlayerData = { + { 'Z', 'E', 'L', 'D', 'A', '3' }, // newf + 0, // threeDayResetCount + { 0x15, 0x12, 0x17, 0x14, 0x3E, 0x3E, 0x3E, 0x3E }, // playerName "LINK " + 0x80, // healthCapacity + 0x80, // health + 0, // magicLevel + MAGIC_NORMAL_METER, // magic + 50, // rupees + 100, // swordHealth + 0, // tatlTimer + true, // isMagicAcquired + false, // isDoubleMagicAcquired + 0, // doubleDefense + 0, // unk_1F + OWL_WARP_NONE, // owlWarpId + 0, // owlActivationFlags + 0xFF, // unk_24 + SCENE_SPOT00, // savedSceneId +}; + +ItemEquips sSaveDebugItemEquips = { + { + { ITEM_SWORD_KOKIRI, ITEM_BOW, ITEM_POTION_RED, ITEM_OCARINA_OF_TIME }, + { ITEM_SWORD_KOKIRI, ITEM_BOW, ITEM_MASK_GORON, ITEM_OCARINA_OF_TIME }, + { ITEM_SWORD_KOKIRI, ITEM_BOW, ITEM_MASK_ZORA, ITEM_OCARINA_OF_TIME }, + { ITEM_DEKU_NUT, ITEM_DEKU_NUT, ITEM_MASK_DEKU, ITEM_OCARINA_OF_TIME }, + }, + { + { SLOT_OCARINA, SLOT_BOW, SLOT_BOTTLE_2, SLOT_OCARINA }, + { SLOT_OCARINA, SLOT_MAGIC_BEANS, SLOT_MASK_GORON, SLOT_BOMBCHU }, + { SLOT_OCARINA, SLOT_POWDER_KEG, SLOT_MASK_ZORA, SLOT_BOMBCHU }, + { SLOT_OCARINA, SLOT_BOW, SLOT_MASK_DEKU, SLOT_BOMBCHU }, + }, + 0x11, +}; + +Inventory sSaveDebugInventory = { + // items + { + ITEM_OCARINA_OF_TIME, // SLOT_OCARINA + ITEM_BOW, // SLOT_BOW + ITEM_ARROW_FIRE, // SLOT_ARROW_FIRE + ITEM_ARROW_ICE, // SLOT_ARROW_ICE + ITEM_ARROW_LIGHT, // SLOT_ARROW_LIGHT + ITEM_MOONS_TEAR, // SLOT_TRADE_DEED + ITEM_BOMB, // SLOT_BOMB + ITEM_BOMBCHU, // SLOT_BOMBCHU + ITEM_DEKU_STICK, // SLOT_DEKU_STICK + ITEM_DEKU_NUT, // SLOT_DEKU_NUT + ITEM_MAGIC_BEANS, // SLOT_MAGIC_BEANS + ITEM_ROOM_KEY, // SLOT_TRADE_KEY_MAMA + ITEM_POWDER_KEG, // SLOT_POWDER_KEG + ITEM_PICTOGRAPH_BOX, // SLOT_PICTOGRAPH_BOX + ITEM_LENS_OF_TRUTH, // SLOT_LENS_OF_TRUTH + ITEM_HOOKSHOT, // SLOT_HOOKSHOT + ITEM_SWORD_GREAT_FAIRY, // SLOT_SWORD_GREAT_FAIRY + ITEM_LETTER_TO_KAFEI, // SLOT_TRADE_COUPLE + ITEM_BOTTLE, // SLOT_BOTTLE_1 + ITEM_POTION_RED, // SLOT_BOTTLE_2 + ITEM_POTION_GREEN, // SLOT_BOTTLE_3 + ITEM_POTION_BLUE, // SLOT_BOTTLE_4 + ITEM_NONE, // SLOT_BOTTLE_5 + ITEM_NONE, // SLOT_BOTTLE_6 + ITEM_MASK_POSTMAN, // SLOT_MASK_POSTMAN + ITEM_MASK_ALL_NIGHT, // SLOT_MASK_ALL_NIGHT + ITEM_MASK_BLAST, // SLOT_MASK_BLAST + ITEM_MASK_STONE, // SLOT_MASK_STONE + ITEM_MASK_GREAT_FAIRY, // SLOT_MASK_GREAT_FAIRY + ITEM_MASK_DEKU, // SLOT_MASK_DEKU + ITEM_MASK_KEATON, // SLOT_MASK_KEATON + ITEM_MASK_BREMEN, // SLOT_MASK_BREMEN + ITEM_MASK_BUNNY, // SLOT_MASK_BUNNY + ITEM_MASK_DON_GERO, // SLOT_MASK_DON_GERO + ITEM_MASK_SCENTS, // SLOT_MASK_SCENTS + ITEM_MASK_GORON, // SLOT_MASK_GORON + ITEM_MASK_ROMANI, // SLOT_MASK_ROMANI + ITEM_MASK_CIRCUS_LEADER, // SLOT_MASK_CIRCUS_LEADER + ITEM_MASK_KAFEIS_MASK, // SLOT_MASK_KAFEIS_MASK + ITEM_MASK_COUPLE, // SLOT_MASK_COUPLE + ITEM_MASK_TRUTH, // SLOT_MASK_TRUTH + ITEM_MASK_ZORA, // SLOT_MASK_ZORA + ITEM_MASK_KAMARO, // SLOT_MASK_KAMARO + ITEM_MASK_GIBDO, // SLOT_MASK_GIBDO + ITEM_MASK_GARO, // SLOT_MASK_GARO + ITEM_MASK_CAPTAIN, // SLOT_MASK_CAPTAIN + ITEM_MASK_GIANT, // SLOT_MASK_GIANT + ITEM_MASK_FIERCE_DEITY, // SLOT_MASK_FIERCE_DEITY + }, + // ammo + { + 1, // SLOT_OCARINA + 30, // SLOT_BOW + 1, // SLOT_ARROW_FIRE + 1, // SLOT_ARROW_ICE + 1, // SLOT_ARROW_LIGHT + 1, // SLOT_TRADE_DEED + 30, // SLOT_BOMB + 30, // SLOT_BOMBCHU + 30, // SLOT_DEKU_STICK + 30, // SLOT_DEKU_NUT + 1, // SLOT_MAGIC_BEANS + 1, // SLOT_TRADE_KEY_MAMA + 1, // SLOT_POWDER_KEG + 1, // SLOT_PICTOGRAPH_BOX + 30, // SLOT_LENS_OF_TRUTH + 1, // SLOT_HOOKSHOT + 1, // SLOT_SWORD_GREAT_FAIRY + 1, // SLOT_TRADE_COUPLE + 1, // SLOT_BOTTLE_1 + 1, // SLOT_BOTTLE_2 + 1, // SLOT_BOTTLE_3 + 1, // SLOT_BOTTLE_4 + 0, // SLOT_BOTTLE_5 + 0, // SLOT_BOTTLE_6 + }, + // upgrades + (1 << 0) | // UPG_QUIVER + (1 << 3) | // UPG_BOMB_BAG + (0 << 6) | // UPG_STRENGTH + (0 << 9) | // UPG_SCALE + (0 << 12) | // UPG_WALLET + (0 << 14) | // UPG_BULLET_BAG + (1 << 17) | // UPG_DEKU_STICKS + (1 << 20), // UPG_DEKU_NUTS + // questItems + (1 << QUEST_SONG_SONATA) | (1 << QUEST_SONG_LULLABY) | (1 << QUEST_SONG_BOSSA_NOVA) | (1 << QUEST_SONG_ELEGY) | + (1 << QUEST_SONG_OATH) | (1 << QUEST_SONG_TIME) | (1 << QUEST_SONG_HEALING) | (1 << QUEST_SONG_EPONA) | + (1 << QUEST_SONG_SOARING) | (1 << QUEST_SONG_STORMS) | (1 << QUEST_BOMBERS_NOTEBOOK) | + (1 << QUEST_SONG_LULLABY_INTRO), + // dungeonItems + { + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + (1 << DUNGEON_BOSS_KEY) | (1 << DUNGEON_COMPASS) | (1 << DUNGEON_MAP), + }, + // dungeonKeys + { 8, 8, 8, 8, 8, 8, 8, 8, 8 }, + // defenseHearts + 0, + // strayFairies + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + // dekuPlaygroundPlayerName + { + // "LINK " + { 0x15, 0x12, 0x17, 0x14, 0x3E, 0x3E, 0x3E, 0x3E }, + // "LINK " + { 0x15, 0x12, 0x17, 0x14, 0x3E, 0x3E, 0x3E, 0x3E }, + // "LINK " + { 0x15, 0x12, 0x17, 0x14, 0x3E, 0x3E, 0x3E, 0x3E }, + }, +}; + +u16 sSaveDebugChecksum = 0; + +u8 D_801C6A48[PLAYER_FORM_MAX] = { + ITEM_MASK_FIERCE_DEITY, // PLAYER_FORM_FIERCE_DEITY + ITEM_MASK_GORON, // PLAYER_FORM_GORON + ITEM_MASK_ZORA, // PLAYER_FORM_ZORA + ITEM_MASK_DEKU, // PLAYER_FORM_DEKU + ITEM_MASK_FIERCE_DEITY, // PLAYER_FORM_HUMAN +}; + +u8 D_801C6A50[PLAYER_FORM_MAX] = { + SLOT_MASK_FIERCE_DEITY, // PLAYER_FORM_FIERCE_DEITY + SLOT_MASK_GORON, // PLAYER_FORM_GORON + SLOT_MASK_ZORA, // PLAYER_FORM_ZORA + SLOT_MASK_DEKU, // PLAYER_FORM_DEKU + SLOT_MASK_FIERCE_DEITY, // PLAYER_FORM_HUMAN +}; + +/** + * Initialize debug save. This is also used on the Title Screen + * This save has a mostly full inventory, every mask and 10 hearts. + * + * Some noteable flags that are set: + * TODO: Investigate the flags + */ +void Sram_InitDebugSave(void) { + Sram_ResetSave(); + + Lib_MemCpy(&gSaveContext.save.saveInfo.playerData, &sSaveDebugPlayerData, sizeof(SavePlayerData)); + Lib_MemCpy(&gSaveContext.save.saveInfo.equips, &sSaveDebugItemEquips, sizeof(ItemEquips)); + Lib_MemCpy(&gSaveContext.save.saveInfo.inventory, &sSaveDebugInventory, sizeof(Inventory)); + Lib_MemCpy(&gSaveContext.save.saveInfo.checksum, &sSaveDebugChecksum, sizeof(gSaveContext.save.saveInfo.checksum)); + + if (GET_PLAYER_FORM != PLAYER_FORM_HUMAN) { + BUTTON_ITEM_EQUIP(0, EQUIP_SLOT_C_DOWN) = D_801C6A48[GET_PLAYER_FORM]; + C_SLOT_EQUIP(0, EQUIP_SLOT_C_DOWN) = D_801C6A50[GET_PLAYER_FORM]; + } + + gSaveContext.save.hasTatl = true; + + gSaveContext.save.saveInfo.horseData.sceneId = SCENE_F01; + gSaveContext.save.saveInfo.horseData.pos.x = -1420; + gSaveContext.save.saveInfo.horseData.pos.y = 257; + gSaveContext.save.saveInfo.horseData.pos.z = -1285; + gSaveContext.save.saveInfo.horseData.yaw = -0x7554; + + gSaveContext.save.entrance = ENTRANCE(CUTSCENE, 0); + gSaveContext.save.isFirstCycle = true; + + SET_WEEKEVENTREG(WEEKEVENTREG_15_20); + SET_WEEKEVENTREG(WEEKEVENTREG_59_04); + SET_WEEKEVENTREG(WEEKEVENTREG_31_04); + + gSaveContext.cycleSceneFlags[SCENE_INSIDETOWER].switch0 = 1; + gSaveContext.save.saveInfo.permanentSceneFlags[SCENE_INSIDETOWER].switch0 = 1; + gSaveContext.save.saveInfo.playerData.magicLevel = 0; + + Sram_GenerateRandomSaveFields(); +} + +void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) { + s32 i; + s32 cutsceneIndex = gSaveContext.save.cutsceneIndex; + + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2], + gFlashSaveNumPages[gSaveContext.fileNum * 2]) != 0) { + SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2 + 1], + gFlashSaveNumPages[gSaveContext.fileNum * 2 + 1]); + } + Lib_MemCpy(&gSaveContext.save, sramCtx->saveBuf, sizeof(Save)); + if (CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf)) { + SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2 + 1], + gFlashSaveNumPages[gSaveContext.fileNum * 2 + 1]); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, sizeof(Save)); + } + gSaveContext.save.cutsceneIndex = cutsceneIndex; + + for (i = 0; i < ARRAY_COUNT(gSaveContext.eventInf); i++) { + gSaveContext.eventInf[i] = 0; + } + + for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { + gSaveContext.cycleSceneFlags[i].chest = gSaveContext.save.saveInfo.permanentSceneFlags[i].chest; + gSaveContext.cycleSceneFlags[i].switch0 = gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0; + gSaveContext.cycleSceneFlags[i].switch1 = gSaveContext.save.saveInfo.permanentSceneFlags[i].switch1; + gSaveContext.cycleSceneFlags[i].clearedRoom = gSaveContext.save.saveInfo.permanentSceneFlags[i].clearedRoom; + gSaveContext.cycleSceneFlags[i].collectible = gSaveContext.save.saveInfo.permanentSceneFlags[i].collectible; + } + + for (i = 0; i < TIMER_ID_MAX; i++) { + gSaveContext.timerStates[i] = TIMER_STATE_OFF; + gSaveContext.timerCurTimes[i] = SECONDS_TO_TIMER(0); + gSaveContext.timerTimeLimits[i] = SECONDS_TO_TIMER(0); + gSaveContext.timerStartOsTimes[i] = 0; + gSaveContext.timerStopTimes[i] = SECONDS_TO_TIMER(0); + gSaveContext.timerPausedOsTimes[i] = 0; + } + + D_801BDAA0 = true; + gHorseIsMounted = false; + gSaveContext.powderKegTimer = 0; + gSaveContext.unk_1014 = 0; + gSaveContext.jinxTimer = 0; +} + +static u16 sOwlWarpEntrances[OWL_WARP_MAX - 1] = { + ENTRANCE(GREAT_BAY_COAST, 11), // OWL_WARP_GREAT_BAY_COAST + ENTRANCE(ZORA_CAPE, 6), // OWL_WARP_ZORA_CAPE + ENTRANCE(SNOWHEAD, 3), // OWL_WARP_SNOWHEAD + ENTRANCE(MOUNTAIN_VILLAGE_WINTER, 8), // OWL_WARP_MOUNTAIN_VILLAGE + ENTRANCE(SOUTH_CLOCK_TOWN, 9), // OWL_WARP_CLOCK_TOWN + ENTRANCE(MILK_ROAD, 4), // OWL_WARP_MILK_ROAD + ENTRANCE(WOODFALL, 4), // OWL_WARP_WOODFALL + ENTRANCE(SOUTHERN_SWAMP_POISONED, 10), // OWL_WARP_SOUTHERN_SWAMP + ENTRANCE(IKANA_CANYON, 4), // OWL_WARP_IKANA_CANYON + ENTRANCE(STONE_TOWER, 3), // OWL_WARP_STONE_TOWER +}; + +void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) { + s32 i; + s32 pad; + s32 phi_t1; + s32 pad1; + s32 fileNum; + + if (gSaveContext.flashSaveAvailable) { + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + + if (gSaveContext.fileNum == 0xFF) { + SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[0], gFlashSaveNumPages[0]); + } else if (fileSelect->isOwlSave[gSaveContext.fileNum + 2]) { + phi_t1 = gSaveContext.fileNum + 2; + phi_t1 *= 2; + + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[phi_t1], gFlashSaveNumPages[phi_t1]) != 0) { + SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[phi_t1 + 1], gFlashSaveNumPages[phi_t1 + 1]); + } + } else { + phi_t1 = gSaveContext.fileNum; + phi_t1 *= 2; + + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[phi_t1], gFlashSaveNumPages[phi_t1]) != 0) { + SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[phi_t1 + 1], gFlashSaveNumPages[phi_t1 + 1]); + } + } + + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[phi_t1]); + + if (CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf)) { + SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[phi_t1 + 1], gFlashSaveNumPages[phi_t1 + 1]); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[phi_t1]); + } + } + + gSaveContext.save.saveInfo.playerData.magicLevel = 0; + + if (!gSaveContext.save.isOwlSave) { + for (i = 0; i < ARRAY_COUNT(gSaveContext.eventInf); i++) { + gSaveContext.eventInf[i] = 0; + } + + for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { + gSaveContext.cycleSceneFlags[i].chest = gSaveContext.save.saveInfo.permanentSceneFlags[i].chest; + gSaveContext.cycleSceneFlags[i].switch0 = gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0; + gSaveContext.cycleSceneFlags[i].switch1 = gSaveContext.save.saveInfo.permanentSceneFlags[i].switch1; + gSaveContext.cycleSceneFlags[i].clearedRoom = gSaveContext.save.saveInfo.permanentSceneFlags[i].clearedRoom; + gSaveContext.cycleSceneFlags[i].collectible = gSaveContext.save.saveInfo.permanentSceneFlags[i].collectible; + } + + for (i = 0; i < TIMER_ID_MAX; i++) { + gSaveContext.timerStates[i] = TIMER_STATE_OFF; + gSaveContext.timerCurTimes[i] = SECONDS_TO_TIMER(0); + gSaveContext.timerTimeLimits[i] = SECONDS_TO_TIMER(0); + gSaveContext.timerStartOsTimes[i] = 0; + gSaveContext.timerStopTimes[i] = SECONDS_TO_TIMER(0); + gSaveContext.timerPausedOsTimes[i] = 0; + } + + if (gSaveContext.save.isFirstCycle) { + gSaveContext.save.entrance = ENTRANCE(SOUTH_CLOCK_TOWN, 0); + gSaveContext.save.day = 0; + gSaveContext.save.time = CLOCK_TIME(6, 0) - 1; + } else { + gSaveContext.save.entrance = ENTRANCE(CUTSCENE, 0); + gSaveContext.nextCutsceneIndex = 0; + gSaveContext.save.playerForm = PLAYER_FORM_HUMAN; + } + } else { + gSaveContext.save.entrance = sOwlWarpEntrances[(void)0, gSaveContext.save.owlWarpId]; + if ((gSaveContext.save.entrance == ENTRANCE(SOUTHERN_SWAMP_POISONED, 10)) && + CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE)) { + gSaveContext.save.entrance = ENTRANCE(SOUTHERN_SWAMP_CLEARED, 10); + } else if ((gSaveContext.save.entrance == ENTRANCE(MOUNTAIN_VILLAGE_WINTER, 8)) && + CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE)) { + gSaveContext.save.entrance = ENTRANCE(MOUNTAIN_VILLAGE_SPRING, 8); + } + + for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { + gSaveContext.cycleSceneFlags[i].chest = gSaveContext.save.saveInfo.permanentSceneFlags[i].chest; + gSaveContext.cycleSceneFlags[i].switch0 = gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0; + gSaveContext.cycleSceneFlags[i].switch1 = gSaveContext.save.saveInfo.permanentSceneFlags[i].switch1; + gSaveContext.cycleSceneFlags[i].clearedRoom = gSaveContext.save.saveInfo.permanentSceneFlags[i].clearedRoom; + gSaveContext.cycleSceneFlags[i].collectible = gSaveContext.save.saveInfo.permanentSceneFlags[i].collectible; + } + + if (gSaveContext.save.saveInfo.scarecrowSpawnSongSet) { + Lib_MemCpy(gScarecrowSpawnSongPtr, gSaveContext.save.saveInfo.scarecrowSpawnSong, + sizeof(gSaveContext.save.saveInfo.scarecrowSpawnSong)); + + for (i = 0; i < ARRAY_COUNT(gSaveContext.save.saveInfo.scarecrowSpawnSong); i++) {} + } + + fileNum = gSaveContext.fileNum; + func_80147314(sramCtx, fileNum); + } +} + +// Similar to func_80145698, but accounts for owl saves? +void func_8014546C(SramContext* sramCtx) { + s32 i; + + if (gSaveContext.save.isOwlSave) { + for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { + gSaveContext.save.saveInfo.permanentSceneFlags[i].chest = gSaveContext.cycleSceneFlags[i].chest; + gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0 = gSaveContext.cycleSceneFlags[i].switch0; + gSaveContext.save.saveInfo.permanentSceneFlags[i].switch1 = gSaveContext.cycleSceneFlags[i].switch1; + gSaveContext.save.saveInfo.permanentSceneFlags[i].clearedRoom = gSaveContext.cycleSceneFlags[i].clearedRoom; + gSaveContext.save.saveInfo.permanentSceneFlags[i].collectible = gSaveContext.cycleSceneFlags[i].collectible; + } + + gSaveContext.save.saveInfo.checksum = 0; + gSaveContext.save.saveInfo.checksum = Sram_CalcChecksum(&gSaveContext, offsetof(SaveContext, fileNum)); + + Lib_MemCpy(sramCtx->saveBuf, &gSaveContext, offsetof(SaveContext, fileNum)); + } else { + for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { + gSaveContext.save.saveInfo.permanentSceneFlags[i].chest = gSaveContext.cycleSceneFlags[i].chest; + gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0 = gSaveContext.cycleSceneFlags[i].switch0; + gSaveContext.save.saveInfo.permanentSceneFlags[i].switch1 = gSaveContext.cycleSceneFlags[i].switch1; + gSaveContext.save.saveInfo.permanentSceneFlags[i].clearedRoom = gSaveContext.cycleSceneFlags[i].clearedRoom; + gSaveContext.save.saveInfo.permanentSceneFlags[i].collectible = gSaveContext.cycleSceneFlags[i].collectible; + } + + gSaveContext.save.saveInfo.checksum = 0; + gSaveContext.save.saveInfo.checksum = Sram_CalcChecksum(&gSaveContext.save, sizeof(Save)); + + if (gSaveContext.flashSaveAvailable) { + Lib_MemCpy(sramCtx->saveBuf, &gSaveContext, sizeof(Save)); + Lib_MemCpy(&sramCtx->saveBuf[0x2000], &gSaveContext.save, sizeof(Save)); + } + } +} + +/** + * Save permanent scene flags, calculate checksum, copy save context to the save buffer + */ +void func_80145698(SramContext* sramCtx) { + s32 i; + + for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { + gSaveContext.save.saveInfo.permanentSceneFlags[i].chest = gSaveContext.cycleSceneFlags[i].chest; + gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0 = gSaveContext.cycleSceneFlags[i].switch0; + gSaveContext.save.saveInfo.permanentSceneFlags[i].switch1 = gSaveContext.cycleSceneFlags[i].switch1; + gSaveContext.save.saveInfo.permanentSceneFlags[i].clearedRoom = gSaveContext.cycleSceneFlags[i].clearedRoom; + gSaveContext.save.saveInfo.permanentSceneFlags[i].collectible = gSaveContext.cycleSceneFlags[i].collectible; + } + + gSaveContext.save.saveInfo.checksum = 0; + gSaveContext.save.saveInfo.checksum = Sram_CalcChecksum(&gSaveContext.save, sizeof(Save)); + if (gSaveContext.flashSaveAvailable) { + Lib_MemCpy(sramCtx->saveBuf, &gSaveContext, sizeof(Save)); + Lib_MemCpy(&sramCtx->saveBuf[0x2000], &gSaveContext.save, sizeof(Save)); + } +} + +// Verifies save and use backup if corrupted? +void func_801457CC(GameState* gameState, SramContext* sramCtx) { + FileSelectState* fileSelect = (FileSelectState*)gameState; + u16 sp7A; + u16 oldCheckSum; + u16 sp76; + u16 sp64; + u16 phi_s2; + u16 pad; + u16 sp6E; + u16 newCheckSum; + u16 maskCount; + + if (gSaveContext.flashSaveAvailable) { + D_801F6AF0 = CURRENT_TIME; + D_801F6AF2 = gSaveContext.flashSaveAvailable; + sp64 = 0; + + for (sp76 = 0; sp76 < 5; sp76++, sp64 += 2) { + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + + phi_s2 = false; + sp6E = 0; + // read main save from flash + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[sp64], gFlashSaveNumPages[sp64]) != 0) { + // main save didn't work + sp6E = 1; + // read backup save from flash + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[sp64 + 1], gFlashSaveNumPages[sp64 + 1]) != + 0) { + // backup save didn't work + phi_s2 = true; + } + } + + if (sp76 < 2) { + // Non-owl save + // sp76 = 0: main save + // sp76 = 1: backup save + + fileSelect->isOwlSave[sp76] = 0; + if (phi_s2) { + // both main save and backup save failed + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + } else { + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + + // test checksum of main save + phi_s2 = gSaveContext.save.saveInfo.checksum; + gSaveContext.save.saveInfo.checksum = 0; + newCheckSum = Sram_CalcChecksum(&gSaveContext, gFlashSaveSizes[sp64]); + gSaveContext.save.saveInfo.checksum = phi_s2; + + if (CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf) || (newCheckSum != phi_s2)) { + // checksum didnt match, try backup save + sp6E = 1; + + if ((gSaveContext.save.saveInfo.playerData.newf[0] == 'Z') && + (gSaveContext.save.saveInfo.playerData.newf[1] == 'E') && + (gSaveContext.save.saveInfo.playerData.newf[2] == 'L') && + (gSaveContext.save.saveInfo.playerData.newf[3] == 'D') && + (gSaveContext.save.saveInfo.playerData.newf[4] == 'A')) {} + + // read backup save from flash + phi_s2 = false; + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[sp64 + 1], + gFlashSaveNumPages[sp64 + 1]) != 0) { + // backup save didn't work + phi_s2 = true; + } + + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + + // test checksum of backup save + oldCheckSum = gSaveContext.save.saveInfo.checksum; + gSaveContext.save.saveInfo.checksum = 0; + + if (phi_s2 || CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf) || + (oldCheckSum != Sram_CalcChecksum(&gSaveContext, gFlashSaveSizes[sp64]))) { + // backup save didn't work + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + Lib_MemCpy(&gSaveContext.save, sramCtx->saveBuf, sizeof(Save)); + sp6E = 999; + } + } + } + + gSaveContext.save.saveInfo.checksum = 0; + //! FAKE: [sp64 + 0]? + gSaveContext.save.saveInfo.checksum = Sram_CalcChecksum(&gSaveContext, gFlashSaveSizes[sp64 + 0]); + + for (sp7A = 0; sp7A < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.newf); sp7A++) { + fileSelect->newf[sp76][sp7A] = gSaveContext.save.saveInfo.playerData.newf[sp7A]; + } + + if (!CHECK_NEWF(fileSelect->newf[sp76])) { + fileSelect->threeDayResetCount[sp76] = gSaveContext.save.saveInfo.playerData.threeDayResetCount; + + for (sp7A = 0; sp7A < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.playerName); sp7A++) { + fileSelect->fileNames[sp76][sp7A] = gSaveContext.save.saveInfo.playerData.playerName[sp7A]; + } + + fileSelect->healthCapacity[sp76] = gSaveContext.save.saveInfo.playerData.healthCapacity; + fileSelect->health[sp76] = gSaveContext.save.saveInfo.playerData.health; + fileSelect->defenseHearts[sp76] = gSaveContext.save.saveInfo.inventory.defenseHearts; + fileSelect->questItems[sp76] = gSaveContext.save.saveInfo.inventory.questItems; + fileSelect->time[sp76] = CURRENT_TIME; + fileSelect->day[sp76] = gSaveContext.save.day; + fileSelect->isOwlSave[sp76] = gSaveContext.save.isOwlSave; + fileSelect->rupees[sp76] = gSaveContext.save.saveInfo.playerData.rupees; + fileSelect->walletUpgrades[sp76] = CUR_UPG_VALUE(UPG_WALLET); + + for (sp7A = 0, maskCount = 0; sp7A < MASK_NUM_SLOTS; sp7A++) { + if (gSaveContext.save.saveInfo.inventory.items[sp7A + ITEM_NUM_SLOTS] == ITEM_NONE) { + continue; + } + maskCount++; + } + fileSelect->maskCount[sp76] = maskCount; + fileSelect->heartPieceCount[sp76] = GET_QUEST_HEART_PIECE_COUNT; + } + + if (sp6E == 1) { + // backup save + Lib_MemCpy(&sramCtx->saveBuf[0x2000], &gSaveContext.save, sizeof(Save)); + Sram_SyncWriteToFlash(sramCtx, gFlashSaveStartPages[sp64], gFlashSpecialSaveNumPages[sp64]); + } else if (!sp6E) { + // main save + oldCheckSum = gSaveContext.save.saveInfo.checksum; + + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[sp64 + 1], + gFlashSaveNumPages[sp64 + 1]) != 0) { + phi_s2 = 1; + } else { + Lib_MemCpy(&gSaveContext.save, sramCtx->saveBuf, sizeof(Save)); + phi_s2 = gSaveContext.save.saveInfo.checksum; + gSaveContext.save.saveInfo.checksum = 0; + sp7A = Sram_CalcChecksum(&gSaveContext.save, sizeof(Save)); + } + + if (CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf) || (sp7A != phi_s2) || + (oldCheckSum != phi_s2)) { + SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[sp64], gFlashSaveNumPages[sp64]); + Lib_MemCpy(&gSaveContext.save, sramCtx->saveBuf, sizeof(Save)); + Lib_MemCpy(&sramCtx->saveBuf[0x2000], &gSaveContext.save, sizeof(Save)); + Sram_SyncWriteToFlash(sramCtx, gFlashSaveStartPages[sp64], gFlashSpecialSaveNumPages[sp64]); + } + } + } else if (sp76 < 4) { + // Owl Save: + // sp76 = 3: main owl save + // sp76 = 4: backup owl save + fileSelect->isOwlSave[sp76] = 0; + + if (!CHECK_NEWF(fileSelect->newf[sp76 - 2])) { + if (phi_s2) { + // both main save and backup save failed + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + } else { + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + phi_s2 = gSaveContext.save.saveInfo.checksum; + + // test checksum of main save + gSaveContext.save.saveInfo.checksum = 0; + newCheckSum = Sram_CalcChecksum(&gSaveContext, gFlashSaveSizes[sp64]); + gSaveContext.save.saveInfo.checksum = phi_s2; + + if (CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf) || (newCheckSum != phi_s2)) { + // checksum didnt match, try backup save + sp6E = 1; + if ((gSaveContext.save.saveInfo.playerData.newf[0] == 'Z') && + (gSaveContext.save.saveInfo.playerData.newf[1] == 'E') && + (gSaveContext.save.saveInfo.playerData.newf[2] == 'L') && + (gSaveContext.save.saveInfo.playerData.newf[3] == 'D') && + (gSaveContext.save.saveInfo.playerData.newf[4] == 'A')) {} + + phi_s2 = false; + // read backup save from flash + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[sp64 + 1], + gFlashSaveNumPages[sp64 + 1]) != 0) { + // backup save didn't work + phi_s2 = true; + } + + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + + // test checksum of backup save + oldCheckSum = gSaveContext.save.saveInfo.checksum; + gSaveContext.save.saveInfo.checksum = 0; + + if (phi_s2 || CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf) || + (oldCheckSum != Sram_CalcChecksum(&gSaveContext, gFlashSaveSizes[sp64]))) { + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + sp6E = 999; + } + } + } + + gSaveContext.save.saveInfo.checksum = 0; + //! FAKE: [sp64 + 0]? + gSaveContext.save.saveInfo.checksum = Sram_CalcChecksum(&gSaveContext, gFlashSaveSizes[sp64 + 0]); + + for (sp7A = 0; sp7A < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.newf); sp7A++) { + fileSelect->newf[sp76][sp7A] = gSaveContext.save.saveInfo.playerData.newf[sp7A]; + } + + if (!CHECK_NEWF(fileSelect->newf[sp76])) { + fileSelect->threeDayResetCount[sp76] = gSaveContext.save.saveInfo.playerData.threeDayResetCount; + + for (sp7A = 0; sp7A < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.playerName); sp7A++) { + fileSelect->fileNames[sp76][sp7A] = + (u32)gSaveContext.save.saveInfo.playerData.playerName[sp7A]; + } + + fileSelect->healthCapacity[sp76] = gSaveContext.save.saveInfo.playerData.healthCapacity; + fileSelect->health[sp76] = gSaveContext.save.saveInfo.playerData.health; + fileSelect->defenseHearts[sp76] = gSaveContext.save.saveInfo.inventory.defenseHearts; + fileSelect->questItems[sp76] = gSaveContext.save.saveInfo.inventory.questItems; + fileSelect->time[sp76] = CURRENT_TIME; + fileSelect->day[sp76] = gSaveContext.save.day; + fileSelect->isOwlSave[sp76] = gSaveContext.save.isOwlSave; + fileSelect->rupees[sp76] = gSaveContext.save.saveInfo.playerData.rupees; + fileSelect->walletUpgrades[sp76] = CUR_UPG_VALUE(UPG_WALLET); + + for (sp7A = 0, maskCount = 0; sp7A < MASK_NUM_SLOTS; sp7A++) { + if (gSaveContext.save.saveInfo.inventory.items[sp7A + ITEM_NUM_SLOTS] == ITEM_NONE) { + continue; + } + maskCount++; + } + fileSelect->maskCount[sp76] = maskCount; + fileSelect->heartPieceCount[sp76] = GET_QUEST_HEART_PIECE_COUNT; + } + + if (sp6E == 1) { + // backup save + Sram_SyncWriteToFlash(sramCtx, gFlashSaveStartPages[sp64], gFlashSaveNumPages[sp64]); + Sram_SyncWriteToFlash(sramCtx, gFlashSaveStartPages[sp64 + 1], gFlashSaveNumPages[sp64 + 1]); + } else if (!sp6E) { + // main save + oldCheckSum = gSaveContext.save.saveInfo.checksum; + + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[sp64 + 1], + gFlashSaveNumPages[sp64 + 1]) != 0) { + phi_s2 = 1; + } else { + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + phi_s2 = gSaveContext.save.saveInfo.checksum; + gSaveContext.save.saveInfo.checksum = 0; + sp7A = Sram_CalcChecksum(&gSaveContext, gFlashSaveSizes[sp64]); + } + + if (CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf) || (sp7A != phi_s2) || + (oldCheckSum != phi_s2)) { + SysFlashrom_Read(sramCtx->saveBuf, gFlashSaveStartPages[sp64], gFlashSaveNumPages[sp64]); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + Sram_SyncWriteToFlash(sramCtx, gFlashSaveStartPages[sp64], gFlashSaveNumPages[sp64]); + Sram_SyncWriteToFlash(sramCtx, gFlashSaveStartPages[sp64 + 1], + gFlashSaveNumPages[sp64 + 1]); + } + } + } else { + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, gFlashSaveSizes[sp64]); + Sram_SyncWriteToFlash(sramCtx, gFlashSaveStartPages[sp64], gFlashSaveNumPages[sp64]); + Sram_SyncWriteToFlash(sramCtx, gFlashSaveStartPages[sp64 + 1], gFlashSaveNumPages[sp64 + 1]); + } + } else { + if (phi_s2) { + gSaveContext.options.optionId = 0xA51D; + gSaveContext.options.language = LANGUAGE_ENG; + gSaveContext.options.audioSetting = SAVE_AUDIO_STEREO; + gSaveContext.options.languageSetting = 0; + gSaveContext.options.zTargetSetting = 0; + } else { + Lib_MemCpy(&gSaveContext.options, sramCtx->saveBuf, sizeof(SaveOptions)); + if (gSaveContext.options.optionId != 0xA51D) { + gSaveContext.options.optionId = 0xA51D; + gSaveContext.options.language = LANGUAGE_ENG; + gSaveContext.options.audioSetting = SAVE_AUDIO_STEREO; + gSaveContext.options.languageSetting = 0; + gSaveContext.options.zTargetSetting = 0; + } + } + Audio_SetFileSelectSettings(gSaveContext.options.audioSetting); + } + } + + gSaveContext.save.time = D_801F6AF0; + gSaveContext.flashSaveAvailable = D_801F6AF2; + } + + gSaveContext.options.language = LANGUAGE_ENG; +} + +void Sram_EraseSave(FileSelectState* fileSelect2, SramContext* sramCtx, s32 fileNum) { + FileSelectState* fileSelect = fileSelect2; + s32 pad; + + if (gSaveContext.flashSaveAvailable) { + if (fileSelect->isOwlSave[fileNum + 2]) { + func_80147314(sramCtx, fileNum); + fileSelect->isOwlSave[fileNum + 2] = false; + } + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, sizeof(Save)); + } + + gSaveContext.save.time = D_801F6AF0; + gSaveContext.flashSaveAvailable = D_801F6AF2; +} + +void Sram_CopySave(FileSelectState* fileSelect2, SramContext* sramCtx) { + FileSelectState* fileSelect = fileSelect2; + u16 i; + s16 maskCount; + + if (gSaveContext.flashSaveAvailable) { + if (fileSelect->isOwlSave[fileSelect->selectedFileIndex + 2]) { + func_80147414(sramCtx, fileSelect->selectedFileIndex, fileSelect->copyDestFileIndex); + fileSelect->threeDayResetCount[fileSelect->copyDestFileIndex + 2] = + gSaveContext.save.saveInfo.playerData.threeDayResetCount; + + for (i = 0; i < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.playerName); i++) { + fileSelect->fileNames[fileSelect->copyDestFileIndex + 2][i] = + gSaveContext.save.saveInfo.playerData.playerName[i]; + } + + fileSelect->healthCapacity[fileSelect->copyDestFileIndex + 2] = + gSaveContext.save.saveInfo.playerData.healthCapacity; + fileSelect->health[fileSelect->copyDestFileIndex + 2] = gSaveContext.save.saveInfo.playerData.health; + fileSelect->defenseHearts[fileSelect->copyDestFileIndex + 2] = + gSaveContext.save.saveInfo.inventory.defenseHearts; + fileSelect->questItems[fileSelect->copyDestFileIndex + 2] = gSaveContext.save.saveInfo.inventory.questItems; + fileSelect->time[fileSelect->copyDestFileIndex + 2] = CURRENT_TIME; + fileSelect->day[fileSelect->copyDestFileIndex + 2] = gSaveContext.save.day; + fileSelect->isOwlSave[fileSelect->copyDestFileIndex + 2] = gSaveContext.save.isOwlSave; + fileSelect->rupees[fileSelect->copyDestFileIndex + 2] = gSaveContext.save.saveInfo.playerData.rupees; + fileSelect->walletUpgrades[fileSelect->copyDestFileIndex + 2] = CUR_UPG_VALUE(UPG_WALLET); + + for (i = 0, maskCount = 0; i < MASK_NUM_SLOTS; i++) { + if (gSaveContext.save.saveInfo.inventory.items[i + ITEM_NUM_SLOTS] != ITEM_NONE) { + maskCount++; + } + } + + fileSelect->maskCount[fileSelect->copyDestFileIndex + 2] = maskCount; + fileSelect->heartPieceCount[fileSelect->copyDestFileIndex + 2] = GET_QUEST_HEART_PIECE_COUNT; + } + + // clear buffer + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + // read to buffer + if (SysFlashrom_Read(&sramCtx->saveBuf[0], gFlashSaveStartPages[fileSelect->selectedFileIndex * 2], + gFlashSaveNumPages[fileSelect->selectedFileIndex * 2])) {} + + if (SysFlashrom_Read(&sramCtx->saveBuf[0x2000], gFlashSaveStartPages[fileSelect->selectedFileIndex * 2 + 1], + gFlashSaveNumPages[fileSelect->selectedFileIndex * 2 + 1])) {} + + // copy buffer to save context + Lib_MemCpy(&gSaveContext.save, sramCtx->saveBuf, sizeof(Save)); + + fileSelect->threeDayResetCount[fileSelect->copyDestFileIndex] = + gSaveContext.save.saveInfo.playerData.threeDayResetCount; + + for (i = 0; i < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.playerName); i++) { + fileSelect->fileNames[fileSelect->copyDestFileIndex][i] = + gSaveContext.save.saveInfo.playerData.playerName[i]; + } + + fileSelect->healthCapacity[fileSelect->copyDestFileIndex] = + gSaveContext.save.saveInfo.playerData.healthCapacity; + fileSelect->health[fileSelect->copyDestFileIndex] = gSaveContext.save.saveInfo.playerData.health; + fileSelect->defenseHearts[fileSelect->copyDestFileIndex] = gSaveContext.save.saveInfo.inventory.defenseHearts; + fileSelect->questItems[fileSelect->copyDestFileIndex] = gSaveContext.save.saveInfo.inventory.questItems; + fileSelect->time[fileSelect->copyDestFileIndex] = CURRENT_TIME; + fileSelect->day[fileSelect->copyDestFileIndex] = gSaveContext.save.day; + fileSelect->isOwlSave[fileSelect->copyDestFileIndex] = gSaveContext.save.isOwlSave; + fileSelect->rupees[fileSelect->copyDestFileIndex] = gSaveContext.save.saveInfo.playerData.rupees; + fileSelect->walletUpgrades[fileSelect->copyDestFileIndex] = CUR_UPG_VALUE(UPG_WALLET); + + for (i = 0, maskCount = 0; i < MASK_NUM_SLOTS; i++) { + if (gSaveContext.save.saveInfo.inventory.items[i + ITEM_NUM_SLOTS] != ITEM_NONE) { + maskCount++; + } + } + + fileSelect->maskCount[fileSelect->copyDestFileIndex] = maskCount; + fileSelect->heartPieceCount[fileSelect->copyDestFileIndex] = GET_QUEST_HEART_PIECE_COUNT; + } + + gSaveContext.save.time = D_801F6AF0; + gSaveContext.flashSaveAvailable = D_801F6AF2; +} + +void Sram_InitSave(FileSelectState* fileSelect2, SramContext* sramCtx) { + s32 phi_v0; + u16 i; + FileSelectState* fileSelect = fileSelect2; + s16 maskCount; + + if (gSaveContext.flashSaveAvailable) { + Sram_InitNewSave(); + if (fileSelect->buttonIndex == 0) { + gSaveContext.save.cutsceneIndex = 0xFFF0; + } + + for (phi_v0 = 0; phi_v0 < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.playerName); phi_v0++) { + gSaveContext.save.saveInfo.playerData.playerName[phi_v0] = + fileSelect->fileNames[fileSelect->buttonIndex][phi_v0]; + } + + gSaveContext.save.saveInfo.playerData.newf[0] = 'Z'; + gSaveContext.save.saveInfo.playerData.newf[1] = 'E'; + gSaveContext.save.saveInfo.playerData.newf[2] = 'L'; + gSaveContext.save.saveInfo.playerData.newf[3] = 'D'; + gSaveContext.save.saveInfo.playerData.newf[4] = 'A'; + gSaveContext.save.saveInfo.playerData.newf[5] = '3'; + + gSaveContext.save.saveInfo.checksum = Sram_CalcChecksum(&gSaveContext.save, sizeof(Save)); + + Lib_MemCpy(sramCtx->saveBuf, &gSaveContext.save, sizeof(Save)); + Lib_MemCpy(&sramCtx->saveBuf[0x2000], &gSaveContext.save, sizeof(Save)); + + for (i = 0; i < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.newf); i++) { + fileSelect->newf[fileSelect->buttonIndex][i] = gSaveContext.save.saveInfo.playerData.newf[i]; + } + + fileSelect->threeDayResetCount[fileSelect->buttonIndex] = + gSaveContext.save.saveInfo.playerData.threeDayResetCount; + + for (i = 0; i < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.playerName); i++) { + fileSelect->fileNames[fileSelect->buttonIndex][i] = gSaveContext.save.saveInfo.playerData.playerName[i]; + } + + fileSelect->healthCapacity[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.playerData.healthCapacity; + fileSelect->health[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.playerData.health; + fileSelect->defenseHearts[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.inventory.defenseHearts; + fileSelect->questItems[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.inventory.questItems; + fileSelect->time[fileSelect->buttonIndex] = CURRENT_TIME; + fileSelect->day[fileSelect->buttonIndex] = gSaveContext.save.day; + fileSelect->isOwlSave[fileSelect->buttonIndex] = gSaveContext.save.isOwlSave; + fileSelect->rupees[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.playerData.rupees; + fileSelect->walletUpgrades[fileSelect->buttonIndex] = CUR_UPG_VALUE(UPG_WALLET); + + for (i = 0, maskCount = 0; i < MASK_NUM_SLOTS; i++) { + if (gSaveContext.save.saveInfo.inventory.items[i + ITEM_NUM_SLOTS] != ITEM_NONE) { + maskCount++; + } + } + + fileSelect->maskCount[fileSelect->buttonIndex] = maskCount; + fileSelect->heartPieceCount[fileSelect->buttonIndex] = GET_QUEST_HEART_PIECE_COUNT; + } + + gSaveContext.save.time = D_801F6AF0; + gSaveContext.flashSaveAvailable = D_801F6AF2; +} + +/** + * Write the SaveOptions of SaveContext to the save buffer + */ +void Sram_WriteSaveOptionsToBuffer(SramContext* sramCtx) { + if (gSaveContext.flashSaveAvailable) { + gSaveContext.options.language = LANGUAGE_ENG; + Lib_MemCpy(sramCtx->saveBuf, &gSaveContext.options, sizeof(SaveOptions)); + } +} + +void Sram_InitSram(GameState* gameState, SramContext* sramCtx) { + if (gSaveContext.save.entrance) {} // Required to match + + Audio_SetFileSelectSettings(gSaveContext.options.audioSetting); +} + +void Sram_Alloc(GameState* gameState, SramContext* sramCtx) { + if (gSaveContext.flashSaveAvailable) { + sramCtx->saveBuf = THA_AllocTailAlign16(&gameState->tha, SAVE_BUFFER_SIZE); + sramCtx->status = 0; + } +} + +/** + * Synchronous flash write + */ +void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages) { + sramCtx->curPage = curPage; + sramCtx->numPages = numPages; + SysFlashrom_WriteSync(sramCtx->saveBuf, curPage, numPages); +} + +/** + * Saves the game on the very first time Player enters South Clock Town from the Clock Tower + */ +void Sram_SaveSpecialEnterClockTown(PlayState* play) { + s32 pad[2]; + SramContext* sramCtx = &play->sramCtx; + + gSaveContext.save.isFirstCycle = true; + gSaveContext.save.isOwlSave = false; + func_80145698(sramCtx); + SysFlashrom_WriteSync(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2], + gFlashSpecialSaveNumPages[gSaveContext.fileNum * 2]); +} + +/** + * Saves when beating the game, after showing the "Dawn of the New Day" message + */ +void Sram_SaveSpecialNewDay(PlayState* play) { + s32 cutsceneIndex = gSaveContext.save.cutsceneIndex; + s32 day; + u16 time = CURRENT_TIME; + + day = gSaveContext.save.day; + + CLEAR_WEEKEVENTREG(WEEKEVENTREG_84_20); + + Sram_SaveEndOfCycle(play); + func_8014546C(&play->sramCtx); + + gSaveContext.save.day = day; + gSaveContext.save.time = time; + gSaveContext.save.cutsceneIndex = cutsceneIndex; + SysFlashrom_WriteSync(play->sramCtx.saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2], + gFlashSaveNumPages[gSaveContext.fileNum * 2]); +} + +void Sram_SetFlashPagesDefault(SramContext* sramCtx, u32 curPage, u32 numPages) { + sramCtx->curPage = curPage; + sramCtx->numPages = numPages; + sramCtx->status = 1; +} + +void Sram_StartWriteToFlashDefault(SramContext* sramCtx) { + // async flash write + SysFlashrom_WriteAsync(sramCtx->saveBuf, sramCtx->curPage, sramCtx->numPages); + + sramCtx->startWriteOsTime = osGetTime(); + sramCtx->status = 2; +} + +void Sram_UpdateWriteToFlashDefault(SramContext* sramCtx) { + if (sramCtx->status == 2) { + if (SysFlashrom_IsBusy() != 0) { // if task running + if (SysFlashrom_AwaitResult() == 0) { // wait for task done + // task success + sramCtx->status = 4; + } else { + // task failure + sramCtx->status = 4; + } + } + } else if (OSTIME_TO_TIMER(osGetTime() - sramCtx->startWriteOsTime) >= SECONDS_TO_TIMER(2)) { + // Finished status is hardcoded to 2 seconds instead of when the task finishes + sramCtx->status = 0; + } +} + +void Sram_SetFlashPagesOwlSave(SramContext* sramCtx, s32 curPage, s32 numPages) { + sramCtx->curPage = curPage; + sramCtx->numPages = numPages; + sramCtx->status = 6; +} + +void Sram_StartWriteToFlashOwlSave(SramContext* sramCtx) { + SysFlashrom_WriteAsync(sramCtx->saveBuf, sramCtx->curPage, sramCtx->numPages); + + sramCtx->startWriteOsTime = osGetTime(); + sramCtx->status = 7; +} + +void Sram_UpdateWriteToFlashOwlSave(SramContext* sramCtx) { + if (sramCtx->status == 7) { + if (SysFlashrom_IsBusy() != 0) { // Is task running + if (SysFlashrom_AwaitResult() == 0) { // Wait for task done + SysFlashrom_WriteAsync(sramCtx->saveBuf, sramCtx->curPage + 0x80, sramCtx->numPages); + sramCtx->status = 8; + } else { + SysFlashrom_WriteAsync(sramCtx->saveBuf, sramCtx->curPage + 0x80, sramCtx->numPages); + sramCtx->status = 8; + } + } + } else if (sramCtx->status == 8) { + if (SysFlashrom_IsBusy() != 0) { // Is task running + if (SysFlashrom_AwaitResult() == 0) { // Wait for task done + sramCtx->status = 4; + } else { + sramCtx->status = 4; + } + } + } else if (OSTIME_TO_TIMER(osGetTime() - sramCtx->startWriteOsTime) >= SECONDS_TO_TIMER(2)) { + // Finished status is hardcoded to 2 seconds instead of when the task finishes + sramCtx->status = 0; + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + gSaveContext.save.isOwlSave = false; + gSaveContext.save.saveInfo.checksum = 0; + // flash read to buffer then copy to save context + SysFlashrom_Read(sramCtx->saveBuf, sramCtx->curPage, sramCtx->numPages); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, offsetof(SaveContext, fileNum)); + } +} + +void func_80147314(SramContext* sramCtx, s32 fileNum) { + s32 pad; + + gSaveContext.save.isOwlSave = false; + + gSaveContext.save.saveInfo.playerData.newf[0] = '\0'; + gSaveContext.save.saveInfo.playerData.newf[1] = '\0'; + gSaveContext.save.saveInfo.playerData.newf[2] = '\0'; + gSaveContext.save.saveInfo.playerData.newf[3] = '\0'; + gSaveContext.save.saveInfo.playerData.newf[4] = '\0'; + gSaveContext.save.saveInfo.playerData.newf[5] = '\0'; + + gSaveContext.save.saveInfo.checksum = 0; + gSaveContext.save.saveInfo.checksum = Sram_CalcChecksum(&gSaveContext, offsetof(SaveContext, fileNum)); + + Lib_MemCpy(sramCtx->saveBuf, &gSaveContext, offsetof(SaveContext, fileNum)); + Sram_SyncWriteToFlash(sramCtx, gFlashOwlSaveStartPages[fileNum * 2], gFlashOwlSaveNumPages[fileNum * 2]); + //! Note: should be `gFlashOwlSaveNumPages[fileNum * 2 + 1]`? + Sram_SyncWriteToFlash(sramCtx, gFlashOwlSaveStartPages[fileNum * 2 + 1], gFlashOwlSaveNumPages[fileNum * 2]); + + gSaveContext.save.isOwlSave = true; + + gSaveContext.save.saveInfo.playerData.newf[0] = 'Z'; + gSaveContext.save.saveInfo.playerData.newf[1] = 'E'; + gSaveContext.save.saveInfo.playerData.newf[2] = 'L'; + gSaveContext.save.saveInfo.playerData.newf[3] = 'D'; + gSaveContext.save.saveInfo.playerData.newf[4] = 'A'; + gSaveContext.save.saveInfo.playerData.newf[5] = '3'; +} + +// Used by `Sram_CopySave` with `isOwlSave` set +void func_80147414(SramContext* sramCtx, s32 fileNum, s32 arg2) { + s32 pad; + + // Clear save buffer + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + + // Read save file + if (SysFlashrom_Read(sramCtx->saveBuf, gFlashOwlSaveStartPages[fileNum * 2], gFlashOwlSaveNumPages[fileNum * 2]) != + 0) { + // If failed, read backup save file + SysFlashrom_Read(sramCtx->saveBuf, gFlashOwlSaveStartPages[fileNum * 2 + 1], + gFlashOwlSaveNumPages[fileNum * 2 + 1]); + } + + // Copy buffer to save context + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, offsetof(SaveContext, fileNum)); + + Sram_SyncWriteToFlash(sramCtx, gFlashOwlSaveStartPages[arg2 * 2], gFlashOwlSaveNumPages[arg2 * 2]); + Sram_SyncWriteToFlash(sramCtx, gFlashOwlSaveStartPages[arg2 * 2 + 1], gFlashOwlSaveNumPages[arg2 * 2]); +} + +void Sram_nop8014750C(UNK_TYPE4 arg0) { +} diff --git a/src/overlays/actors/ovl_Bg_Heavy_Block/z_bg_heavy_block.c b/src/overlays/actors/ovl_Bg_Heavy_Block/z_bg_heavy_block.c new file mode 100644 index 000000000..5b723f45f --- /dev/null +++ b/src/overlays/actors/ovl_Bg_Heavy_Block/z_bg_heavy_block.c @@ -0,0 +1,40 @@ +/* + * File: z_bg_heavy_block.c + * Overlay: ovl_Bg_Heavy_Block + * Description: Large block that can only be lifted with Golden Gauntlets (JP only) + */ + +#include "z_bg_heavy_block.h" + +#include "versions.h" + +#define FLAGS 0 + +void BgHeavyBlock_Init(Actor* thisx, PlayState* play); +void BgHeavyBlock_Destroy(Actor* thisx, PlayState* play); +void BgHeavyBlock_Update(Actor* thisx, PlayState* play); +void BgHeavyBlock_Draw(Actor* thisx, PlayState* play); + +ActorProfile Bg_Heavy_Block_Profile = { + /**/ ACTOR_BG_HEAVY_BLOCK, + /**/ ACTORCAT_BG, + /**/ FLAGS, + /**/ OBJECT_HEAVY_OBJECT, + /**/ sizeof(BgHeavyBlock), + /**/ BgHeavyBlock_Init, + /**/ BgHeavyBlock_Destroy, + /**/ BgHeavyBlock_Update, + /**/ BgHeavyBlock_Draw, +}; + +void BgHeavyBlock_Init(Actor* thisx, PlayState* play) { +} + +void BgHeavyBlock_Destroy(Actor* thisx, PlayState* play) { +} + +void BgHeavyBlock_Update(Actor* thisx, PlayState* play) { +} + +void BgHeavyBlock_Draw(Actor* thisx, PlayState* play) { +} diff --git a/src/overlays/actors/ovl_Bg_Heavy_Block/z_bg_heavy_block.h b/src/overlays/actors/ovl_Bg_Heavy_Block/z_bg_heavy_block.h new file mode 100644 index 000000000..9870296e4 --- /dev/null +++ b/src/overlays/actors/ovl_Bg_Heavy_Block/z_bg_heavy_block.h @@ -0,0 +1,16 @@ +#ifndef Z_BG_HEAVY_BLOCK_H +#define Z_BG_HEAVY_BLOCK_H + +#include "global.h" + +struct BgHeavyBlock; + +typedef void (*BgHeavyBlockActionFunc)(struct BgHeavyBlock*, PlayState*); + +typedef struct BgHeavyBlock { + /* 0x000 */ DynaPolyActor dyna; + /* 0x15C */ char unk_15C[0x16C - 0x15C]; + /* 0x16C */ BgHeavyBlockActionFunc actionFunc; +} BgHeavyBlock; // size = 0x170 + +#endif // Z_BG_HEAVY_BLOCK_H diff --git a/src/overlays/actors/ovl_Obj_Warpstone/z_obj_warpstone.c b/src/overlays/actors/ovl_Obj_Warpstone/z_obj_warpstone.c index 35d7b16ec..d0e38a258 100644 --- a/src/overlays/actors/ovl_Obj_Warpstone/z_obj_warpstone.c +++ b/src/overlays/actors/ovl_Obj_Warpstone/z_obj_warpstone.c @@ -136,16 +136,20 @@ void ObjWarpstone_Update(Actor* thisx, PlayState* play) { if (this->isTalking) { if (Actor_TextboxIsClosing(&this->dyna.actor, play)) { this->isTalking = false; - } else if ((Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE) && Message_ShouldAdvance(play)) { - if (play->msgCtx.choiceIndex != 0) { - Audio_PlaySfx_MessageDecide(); - play->msgCtx.msgMode = MSGMODE_OWL_SAVE_0; - play->msgCtx.unk120D6 = 0; - play->msgCtx.unk120D4 = 0; - gSaveContext.save.owlWarpId = OBJ_WARPSTONE_GET_OWL_WARP_ID(&this->dyna.actor); - } else { - Message_CloseTextbox(play); + } else { +#if MM_VERSION >= N64_US + if ((Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE) && Message_ShouldAdvance(play)) { + if (play->msgCtx.choiceIndex != 0) { + Audio_PlaySfx_MessageDecide(); + play->msgCtx.msgMode = MSGMODE_OWL_SAVE_0; + play->msgCtx.unk120D6 = 0; + play->msgCtx.unk120D4 = 0; + gSaveContext.save.owlWarpId = OBJ_WARPSTONE_GET_OWL_WARP_ID(&this->dyna.actor); + } else { + Message_CloseTextbox(play); + } } +#endif } } else if (Actor_TalkOfferAccepted(&this->dyna.actor, &play->state)) { this->isTalking = true; diff --git a/src/overlays/actors/ovl_player_actor/z_player.c b/src/overlays/actors/ovl_player_actor/z_player.c index e4ba3d02f..349689191 100644 --- a/src/overlays/actors/ovl_player_actor/z_player.c +++ b/src/overlays/actors/ovl_player_actor/z_player.c @@ -12225,7 +12225,9 @@ s8 sPlayerCueToCsActionMap[PLAYER_CUEID_MAX] = { PLAYER_CSACTION_120, // PLAYER_CUEID_88 PLAYER_CSACTION_114, // PLAYER_CUEID_89 PLAYER_CSACTION_111, // PLAYER_CUEID_90 - PLAYER_CSACTION_122, // PLAYER_CUEID_91 +#if MM_VERSION >= N64_US + PLAYER_CSACTION_122, // PLAYER_CUEID_91 +#endif }; f32 D_8085D3E0[PLAYER_FORM_MAX] = { @@ -20204,7 +20206,9 @@ PlayerCsActionEntry sPlayerCsActionInitFuncs[PLAYER_CSACTION_MAX] = { /* PLAYER_CSACTION_119 */ { PLAYER_CSTYPE_ANIM_7, { &gPlayerAnim_demo_suwari2 } }, /* PLAYER_CSACTION_120 */ { PLAYER_CSTYPE_ANIM_7, { &gPlayerAnim_demo_suwari3 } }, /* PLAYER_CSACTION_121 */ { PLAYER_CSTYPE_ACTION, { Player_CsAction_7 } }, +#if MM_VERSION >= N64_US /* PLAYER_CSACTION_122 */ { PLAYER_CSTYPE_NONE, { NULL } }, +#endif /* PLAYER_CSACTION_123 */ { PLAYER_CSTYPE_ACTION, { Player_CsAction_9 } }, /* PLAYER_CSACTION_124 */ { PLAYER_CSTYPE_ANIM_7, { &gPlayerAnim_clink_demo_get1 } }, /* PLAYER_CSACTION_125 */ { PLAYER_CSTYPE_ANIM_5, { &gPlayerAnim_clink_demo_get2 } }, @@ -20347,7 +20351,9 @@ PlayerCsActionEntry sPlayerCsActionUpdateFuncs[PLAYER_CSACTION_MAX] = { /* PLAYER_CSACTION_119 */ { PLAYER_CSTYPE_ANIM_11, { NULL } }, /* PLAYER_CSACTION_120 */ { PLAYER_CSTYPE_ANIM_11, { NULL } }, /* PLAYER_CSACTION_121 */ { PLAYER_CSTYPE_ACTION, { Player_CsAction_8 } }, +#if MM_VERSION >= N64_US /* PLAYER_CSACTION_122 */ { PLAYER_CSTYPE_ACTION, { Player_CsAction_12 } }, +#endif /* PLAYER_CSACTION_123 */ { PLAYER_CSTYPE_ACTION, { Player_CsAction_10 } }, /* PLAYER_CSACTION_125 */ { PLAYER_CSTYPE_ANIM_11, { NULL } }, /* PLAYER_CSACTION_124 */ { PLAYER_CSTYPE_ANIM_11, { NULL } }, diff --git a/src/overlays/gamestates/ovl_file_choose/z_file_choose_JPN.c b/src/overlays/gamestates/ovl_file_choose/z_file_choose_JPN.c new file mode 100644 index 000000000..f7355f72b --- /dev/null +++ b/src/overlays/gamestates/ovl_file_choose/z_file_choose_JPN.c @@ -0,0 +1,2536 @@ +/* + * File: z_file_choose_NES.c + * Overlay: ovl_file_choose + * Description: + */ + +#include "z_file_select.h" +#include "overlays/gamestates/ovl_opening/z_opening.h" +#include "z64rumble.h" +#include "z64save.h" +#include "z64shrink_window.h" +#include "z64view.h" +#include "assets/interface/parameter_static/parameter_static.h" +#include "assets/misc/title_static/title_static.h" + +s32 D_808144F10 = 100; +f32 D_808144F14 = 8.0f; +f32 D_808144F18 = 100.0f; +s32 D_808144F1C = 0; + +static Gfx sScreenFillSetupDL[] = { + gsDPPipeSync(), + gsSPClearGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | + G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH), + gsDPSetOtherMode(G_AD_DISABLE | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | + G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_1PRIMITIVE, + G_AC_NONE | G_ZS_PIXEL | G_RM_CLD_SURF | G_RM_CLD_SURF2), + gsDPSetCombineMode(G_CC_PRIMITIVE, G_CC_PRIMITIVE), + gsSPEndDisplayList(), +}; + +s16 sFileInfoBoxPartWidths[] = { + 36, 36, 36, 36, 24, 28, 28, +}; + +s16 sWindowContentColors[] = { 100, 150, 255 }; + +s16 sFileSelectSkyboxRotation = 0; + +s16 sWalletFirstDigit[] = { + 1, // tens (Default Wallet) + 0, // hundreds (Adult Wallet) + 0, // hundreds (Giant Wallet) +}; + +void FileSelect_IncrementConfigMode(FileSelectState* this) { + this->configMode++; +} + +void FileSelect_Noop1(void) { +} + +void FileSelect_Noop2(FileSelectState* this) { +} + +void FileSelect_InitModeUpdate(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + if (this->configMode == CM_FADE_IN_START) { + if (gSaveContext.options.optionId != 0xA51D) { // Magic number? + this->configMode++; + } else { + this->menuMode = FS_MENU_MODE_CONFIG; + this->configMode = CM_FADE_IN_START; + this->titleLabel = FS_TITLE_SELECT_FILE; + this->nextTitleLabel = FS_TITLE_OPEN_FILE; + } + } + + if (this->configMode == CM_FADE_IN_END) { + this->screenFillAlpha -= 40; + if (this->screenFillAlpha <= 0) { + this->screenFillAlpha = 0; + this->configMode++; // CM_MAIN_MENU + } + } else if (this->configMode == CM_MAIN_MENU) { + FileSelect_IncrementConfigMode(this); // CM_SETUP_COPY_SOURCE + } else { + this->screenFillAlpha += 40; + if (this->screenFillAlpha >= 255) { + this->screenFillAlpha = 255; + this->menuMode = FS_MENU_MODE_CONFIG; + this->configMode = CM_FADE_IN_START; + this->titleLabel = FS_TITLE_SELECT_FILE; + this->nextTitleLabel = FS_TITLE_OPEN_FILE; + } + } +} + +void FileSelect_InitModeDraw(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + Gfx_SetupDL39_Opa(this->state.gfxCtx); + FileSelect_Noop2(this); +} + +void FileSelect_SetView(FileSelectState* this, f32 eyeX, f32 eyeY, f32 eyeZ) { + Vec3f eye; + Vec3f lookAt; + Vec3f up; + + eye.x = eyeX; + eye.y = eyeY; + eye.z = eyeZ; + + lookAt.x = lookAt.y = lookAt.z = 0.0f; + + up.x = up.z = 0.0f; + up.y = 1.0f; + + View_LookAt(&this->view, &eye, &lookAt, &up); + View_Apply(&this->view, VIEW_ALL | VIEW_FORCE_VIEWING | VIEW_FORCE_VIEWPORT | VIEW_FORCE_PROJECTION_PERSPECTIVE); +} + +Gfx* FileSelect_DrawTexQuadIA8(Gfx* gfx, TexturePtr texture, s16 width, s16 height, s16 point) { + gDPLoadTextureBlock(gfx++, texture, G_IM_FMT_IA, G_IM_SIZ_8b, width, height, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + + gSP1Quadrangle(gfx++, point, point + 2, point + 3, point + 1, 0); + + return gfx; +} + +/** + * Fade in the menu window and title label. + * If a file is occupied fade in the name, name box, and connector. + * Fade in the copy erase and options button according to the window alpha. + */ +void FileSelect_FadeInMenuElements(FileSelectState* this) { + SramContext* sramCtx = &this->sramCtx; + s16 i; + + this->titleAlpha[FS_TITLE_CUR] += 20; + this->windowAlpha += 16; + + for (i = 0; i < 3; i++) { + this->fileButtonAlpha[i] = this->windowAlpha; + + if (!gSaveContext.flashSaveAvailable) { + if (NO_FLASH_SLOT_OCCUPIED(sramCtx, i)) { + this->nameBoxAlpha[i] = this->nameAlpha[i] = this->windowAlpha; + this->connectorAlpha[i] += 20; + if (this->connectorAlpha[i] >= 255) { + this->connectorAlpha[i] = 255; + } + } + } else if (SLOT_OCCUPIED(this, i)) { + this->nameBoxAlpha[i] = this->nameAlpha[i] = this->windowAlpha; + this->connectorAlpha[i] += 20; + + if (this->connectorAlpha[i] >= 255) { + this->connectorAlpha[i] = 255; + } + } + } + + this->actionButtonAlpha[FS_BTN_ACTION_COPY] = this->actionButtonAlpha[FS_BTN_ACTION_ERASE] = + this->optionButtonAlpha = this->windowAlpha; +} + +/** + * Converts a numerical value to hundreds-tens-ones digits + */ +void FileSelect_SplitNumber(u16 value, u16* hundreds, u16* tens, u16* ones) { + *hundreds = 0; + *tens = 0; + *ones = value; + + do { + if ((*ones - 100) < 0) { + break; + } + (*hundreds)++; + *ones -= 100; + } while (true); + + do { + if ((*ones - 10) < 0) { + break; + } + (*tens)++; + *ones -= 10; + } while (true); +} + +// Start of Config Mode Update Functions + +/** + * Reduce the alpha of the black screen fill to create a fade in effect. + * Additionally, slide the window from the right to the center of the screen. + * Update function for `CM_FADE_IN_START` + */ +void FileSelect_StartFadeIn(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + FileSelect_FadeInMenuElements(this); + this->screenFillAlpha -= 40; + this->windowPosX -= 20; + + if (this->windowPosX <= -94) { + this->windowPosX = -94; + this->configMode = CM_FADE_IN_END; + this->screenFillAlpha = 0; + } +} + +/** + * Finish fading in the remaining menu elements. + * Fade in the controls text at the bottom of the screen. + * Update function for `CM_FADE_IN_END` + */ +void FileSelect_FinishFadeIn(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->controlsAlpha += 20; + FileSelect_FadeInMenuElements(this); + + if (this->titleAlpha[FS_TITLE_CUR] >= 255) { + this->titleAlpha[FS_TITLE_CUR] = 255; + this->controlsAlpha = 255; + this->windowAlpha = 200; + this->configMode = CM_MAIN_MENU; + } +} + +u8 sEmptyName[] = { 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E }; + +/** + * Update the cursor and wait for the player to select a button to change menus accordingly. + * If an empty file is selected, enter the name entry config mode. + * If an occupied file is selected, enter the `Select` menu mode. + * If copy, erase, or options is selected, set config mode accordingly. + * Lastly, set any warning labels if appropriate. + * Update function for `CM_MAIN_MENU` + */ +void FileSelect_UpdateMainMenu(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + SramContext* sramCtx = &this->sramCtx; + Input* input = CONTROLLER1(&this->state); + + if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) { + if (this->buttonIndex <= FS_BTN_MAIN_FILE_3) { + if (!gSaveContext.flashSaveAvailable) { + if (!NO_FLASH_SLOT_OCCUPIED(sramCtx, this->buttonIndex)) { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + this->configMode = CM_ROTATE_TO_NAME_ENTRY; + this->kbdButton = FS_KBD_BTN_NONE; + this->charPage = FS_CHAR_PAGE_HIRA; + if (gSaveContext.options.language != LANGUAGE_JPN) { + this->charPage = FS_CHAR_PAGE_ENG; + } + this->kbdX = 0; + this->kbdY = 0; + this->charIndex = 0; + this->charBgAlpha = 0; + this->newFileNameCharCount = 0; + this->nameEntryBoxPosX = 120; + this->nameEntryBoxAlpha = 0; + Lib_MemCpy(&this->fileNames[this->buttonIndex], &sEmptyName, ARRAY_COUNT(sEmptyName)); + } else { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + this->actionTimer = 4; + this->selectMode = SM_FADE_MAIN_TO_SELECT; + this->selectedFileIndex = this->buttonIndex; + this->menuMode = FS_MENU_MODE_SELECT; + this->nextTitleLabel = FS_TITLE_OPEN_FILE; + } + } else if (!SLOT_OCCUPIED(this, this->buttonIndex)) { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + this->configMode = CM_ROTATE_TO_NAME_ENTRY; + this->kbdButton = FS_KBD_BTN_NONE; + this->charPage = FS_CHAR_PAGE_HIRA; + if (gSaveContext.options.language != LANGUAGE_JPN) { + this->charPage = FS_CHAR_PAGE_ENG; + } + this->kbdX = 0; + this->kbdY = 0; + this->charIndex = 0; + this->charBgAlpha = 0; + this->newFileNameCharCount = 0; + this->nameEntryBoxPosX = 120; + this->nameEntryBoxAlpha = 0; + Lib_MemCpy(&this->fileNames[this->buttonIndex], &sEmptyName, ARRAY_COUNT(sEmptyName)); + } else { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + this->actionTimer = 4; + this->selectMode = SM_FADE_MAIN_TO_SELECT; + this->selectedFileIndex = this->buttonIndex; + this->menuMode = FS_MENU_MODE_SELECT; + this->nextTitleLabel = FS_TITLE_OPEN_FILE; + } + } else if (this->warningLabel == FS_WARNING_NONE) { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + this->prevConfigMode = this->configMode; + + if (this->buttonIndex == FS_BTN_MAIN_COPY) { + this->configMode = CM_SETUP_COPY_SOURCE; + this->nextTitleLabel = FS_TITLE_COPY_FROM; + } else if (this->buttonIndex == FS_BTN_MAIN_ERASE) { + this->configMode = CM_SETUP_ERASE_SELECT; + this->nextTitleLabel = FS_TITLE_ERASE_FILE; + } else { + this->configMode = CM_MAIN_TO_OPTIONS; + this->kbdButton = FS_KBD_BTN_HIRA; + this->kbdX = 0; + this->kbdY = 0; + this->charBgAlpha = 0; + this->newFileNameCharCount = 0; + this->nameEntryBoxPosX = 120; + } + this->actionTimer = 4; + } else { + Audio_PlaySfx(NA_SE_SY_FSEL_ERROR); + } + } else if (CHECK_BTN_ALL(input->press.button, BTN_B)) { + gSaveContext.gameMode = GAMEMODE_TITLE_SCREEN; + STOP_GAMESTATE(&this->state); + SET_NEXT_GAMESTATE(&this->state, TitleSetup_Init, sizeof(TitleSetupState)); + } else { + if (ABS_ALT(this->stickAdjY) > 30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + if (this->stickAdjY > 30) { + this->buttonIndex--; + if (this->buttonIndex == FS_BTN_MAIN_FILE_3) { + this->buttonIndex = FS_BTN_MAIN_FILE_2; + } + if (this->buttonIndex < FS_BTN_MAIN_FILE_1) { + this->buttonIndex = FS_BTN_MAIN_OPTIONS; + } + } else { + this->buttonIndex++; + if (this->buttonIndex == FS_BTN_MAIN_FILE_3) { + this->buttonIndex = FS_BTN_MAIN_COPY; + } + if (this->buttonIndex > FS_BTN_MAIN_OPTIONS) { + this->buttonIndex = FS_BTN_MAIN_FILE_1; + } + } + } + + if (this->buttonIndex == FS_BTN_MAIN_COPY) { + if (!gSaveContext.flashSaveAvailable) { + if (!NO_FLASH_SLOT_OCCUPIED(sramCtx, 0) && !NO_FLASH_SLOT_OCCUPIED(sramCtx, 1) && + !NO_FLASH_SLOT_OCCUPIED(sramCtx, 2)) { + this->warningButtonIndex = this->buttonIndex; + this->warningLabel = FS_WARNING_NO_FILE_COPY; + this->emptyFileTextAlpha = 255; + } else if (NO_FLASH_SLOT_OCCUPIED(sramCtx, 0) && NO_FLASH_SLOT_OCCUPIED(sramCtx, 1) && + NO_FLASH_SLOT_OCCUPIED(sramCtx, 2)) { + this->warningButtonIndex = this->buttonIndex; + this->warningLabel = FS_WARNING_NO_EMPTY_FILES; + this->emptyFileTextAlpha = 255; + } else { + this->warningLabel = FS_WARNING_NONE; + } + } else { + if (!SLOT_OCCUPIED(this, 0) && !SLOT_OCCUPIED(this, 1) && !SLOT_OCCUPIED(this, 2)) { + this->warningButtonIndex = this->buttonIndex; + this->warningLabel = FS_WARNING_NO_FILE_COPY; + this->emptyFileTextAlpha = 255; + } else if (SLOT_OCCUPIED(this, 0) && SLOT_OCCUPIED(this, 1) && SLOT_OCCUPIED(this, 2)) { + this->warningButtonIndex = this->buttonIndex; + this->warningLabel = FS_WARNING_NO_EMPTY_FILES; + this->emptyFileTextAlpha = 255; + } else { + this->warningLabel = FS_WARNING_NONE; + } + } + } else if (this->buttonIndex == FS_BTN_MAIN_ERASE) { + if (!gSaveContext.flashSaveAvailable) { + if (!NO_FLASH_SLOT_OCCUPIED(sramCtx, 0) && !NO_FLASH_SLOT_OCCUPIED(sramCtx, 1) && + !NO_FLASH_SLOT_OCCUPIED(sramCtx, 2)) { + this->warningButtonIndex = this->buttonIndex; + this->warningLabel = FS_WARNING_NO_FILE_ERASE; + this->emptyFileTextAlpha = 255; + } else { + this->warningLabel = FS_WARNING_NONE; + } + } else { + if (!SLOT_OCCUPIED(this, 0) && !SLOT_OCCUPIED(this, 1) && !SLOT_OCCUPIED(this, 2)) { + this->warningButtonIndex = this->buttonIndex; + this->warningLabel = FS_WARNING_NO_FILE_ERASE; + this->emptyFileTextAlpha = 255; + } else { + this->warningLabel = FS_WARNING_NONE; + } + } + } else { + this->warningLabel = FS_WARNING_NONE; + } + } +} + +/** + * Update function for `CM_UNUSED_31` + */ +void FileSelect_UnusedCM31(GameState* thisx) { +} + +/** + * Delay the next config mode from running until `D_80814564` reaches 254. + * Because the timer increments by 2, the delay is 127 frames (assuming the value was not changed by reg editor). + * Unused in the final game, was possibly used for debugging. + * Update function for `CM_UNUSED_DELAY` + */ +void FileSelect_UnusedCMDelay(GameState* thisx) { + static s16 D_80814564 = 0; + FileSelectState* this = (FileSelectState*)thisx; + + D_80814564 += 2; + + if (D_80814564 == 254) { + this->configMode = this->nextConfigMode; + D_80814564 = 0; + } +} + +/** + * Rotate the window from the main menu to the name entry menu. + * Update function for `CM_ROTATE_TO_NAME_ENTRY` + */ +void FileSelect_RotateToNameEntry(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->windowRot += 50.0f; + + if (this->windowRot >= 314.0f) { + this->windowRot = 314.0f; + this->configMode = CM_START_NAME_ENTRY; + } +} + +/** + * Rotate the window from the main menu to the options menu. + * Update function for `CM_MAIN_TO_OPTIONS` + */ +void FileSelect_RotateToOptions(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->windowRot += 50.0f; + + if (this->windowRot >= 314.0f) { + this->windowRot = 314.0f; + this->configMode = CM_START_OPTIONS; + } +} + +/** + * Rotate the window from the options menu to the main menu. + * Update function for `CM_NAME_ENTRY_TO_MAIN` and `CM_OPTIONS_TO_MAIN` + */ +void FileSelect_RotateToMain(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->windowRot += 50.0f; + + if (this->windowRot >= 628.0f) { + this->windowRot = 0.0f; + this->configMode = CM_MAIN_MENU; + } +} + +void (*sConfigModeUpdateFuncs[])(GameState*) = { + // Main Menu + FileSelect_StartFadeIn, // CM_FADE_IN_START + FileSelect_FinishFadeIn, // CM_FADE_IN_END + FileSelect_UpdateMainMenu, // CM_MAIN_MENU + // Copy File + FileSelect_SetupCopySource, // CM_SETUP_COPY_SOURCE + FileSelect_SelectCopySource, // CM_SELECT_COPY_SOURCE + FileSelect_SetupCopyDest1, // CM_SETUP_COPY_DEST_1 + FileSelect_SetupCopyDest2, // CM_SETUP_COPY_DEST_2 + FileSelect_SelectCopyDest, // CM_SELECT_COPY_DEST + FileSelect_ExitToCopySource1, // CM_EXIT_TO_COPY_SOURCE_1 + FileSelect_ExitToCopySource2, // CM_EXIT_TO_COPY_SOURCE_2 + FileSelect_SetupCopyConfirm1, // CM_SETUP_COPY_CONFIRM_1 + FileSelect_SetupCopyConfirm2, // CM_SETUP_COPY_CONFIRM_2 + FileSelect_CopyConfirm, // CM_COPY_CONFIRM + FileSelect_CopyWaitForFlashSave, // CM_COPY_WAIT_FOR_FLASH_SAVE + FileSelect_ReturnToCopyDest, // CM_RETURN_TO_COPY_DEST + FileSelect_CopyAnim1, // CM_COPY_ANIM_1 + FileSelect_CopyAnim2, // CM_COPY_ANIM_2 + FileSelect_CopyAnim3, // CM_COPY_ANIM_3 + FileSelect_CopyAnim4, // CM_COPY_ANIM_4 + FileSelect_CopyAnim5, // CM_COPY_ANIM_5 + FileSelect_ExitCopyToMain, // CM_COPY_RETURN_MAIN + // Erase File + FileSelect_SetupEraseSelect, // CM_SETUP_ERASE_SELECT + FileSelect_EraseSelect, // CM_ERASE_SELECT + FileSelect_SetupEraseConfirm1, // CM_SETUP_ERASE_CONFIRM_1 + FileSelect_SetupEraseConfirm2, // CM_SETUP_ERASE_CONFIRM_2 + FileSelect_EraseConfirm, // CM_ERASE_CONFIRM + FileSelect_ExitToEraseSelect1, // CM_EXIT_TO_ERASE_SELECT_1 + FileSelect_ExitToEraseSelect2, // CM_EXIT_TO_ERASE_SELECT_2 + FileSelect_EraseAnim1, // CM_ERASE_ANIM_1 + FileSelect_EraseWaitForFlashSave, // CM_ERASE_WAIT_FOR_FLASH_SAVE + FileSelect_EraseAnim2, // CM_ERASE_ANIM_2 + FileSelect_EraseAnim3, // CM_ERASE_ANIM_3 + FileSelect_ExitEraseToMain, // CM_EXIT_ERASE_TO_MAIN + FileSelect_UnusedCM31, // CM_UNUSED_31 + // New File Name Entry + FileSelect_RotateToNameEntry, // CM_ROTATE_TO_NAME_ENTRY + FileSelect_StartNameEntry, // CM_START_NAME_ENTRY + FileSelect_UpdateKeyboardCursor, // CM_NAME_ENTRY + FileSelect_NameEntryWaitForFlashSave, // CM_NAME_ENTRY_WAIT_FOR_FLASH_SAVE + FileSelect_RotateToMain, // CM_NAME_ENTRY_TO_MAIN + // Options + FileSelect_RotateToOptions, // CM_MAIN_TO_OPTIONS + FileSelect_StartOptions, // CM_START_OPTIONS + FileSelect_UpdateOptionsMenu, // CM_OPTIONS_MENU + FileSelect_OptionsWaitForFlashSave, // CM_OPTIONS_WAIT_FOR_FLASH_SAVE + FileSelect_RotateToMain, // CM_OPTIONS_TO_MAIN + // Possible Debug + FileSelect_UnusedCMDelay, // CM_UNUSED_DELAY +}; + +s16 sCursorAlphaTargets[] = { 70, 200 }; + +/** + * Updates the alpha of the cursor to make it pulsate. + */ +void FileSelect_PulsateCursor(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + s32 alphaStep = + ABS_ALT(this->highlightColor[3] - sCursorAlphaTargets[this->highlightPulseDir]) / this->highlightTimer; + + if (this->highlightColor[3] >= sCursorAlphaTargets[this->highlightPulseDir]) { + this->highlightColor[3] -= alphaStep; + } else { + this->highlightColor[3] += alphaStep; + } + + this->highlightTimer--; + + if (this->highlightTimer == 0) { + this->highlightColor[3] = sCursorAlphaTargets[this->highlightPulseDir]; + this->highlightTimer = 20; + this->highlightPulseDir ^= 1; + } +} + +void FileSelect_ConfigModeUpdate(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + sConfigModeUpdateFuncs[this->configMode](&this->state); +} + +void FileSelect_SetWindowVtx(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + s16 i; + s16 j; + s16 x; + s32 tmp; + s32 tmp2; + s32 tmp3; + + this->windowVtx = GRAPH_ALLOC(this->state.gfxCtx, 80 * sizeof(Vtx)); + tmp = this->windowPosX - 90; + + for (x = 0, i = 0; i < 4; i++) { + tmp += 0x40; + tmp2 = (i == 3) ? 0x30 : 0x40; + + for (j = 0, tmp3 = 0x50; j < 5; j++, x += 4, tmp3 -= 0x20) { + this->windowVtx[x].v.ob[0] = this->windowVtx[x + 2].v.ob[0] = tmp; + + this->windowVtx[x + 1].v.ob[0] = this->windowVtx[x + 3].v.ob[0] = tmp2 + tmp; + + this->windowVtx[x].v.ob[1] = this->windowVtx[x + 1].v.ob[1] = tmp3; + + this->windowVtx[x + 2].v.ob[1] = this->windowVtx[x + 3].v.ob[1] = tmp3 - 0x20; + + this->windowVtx[x].v.ob[2] = this->windowVtx[x + 1].v.ob[2] = this->windowVtx[x + 2].v.ob[2] = + this->windowVtx[x + 3].v.ob[2] = 0; + + this->windowVtx[x].v.flag = this->windowVtx[x + 1].v.flag = this->windowVtx[x + 2].v.flag = + this->windowVtx[x + 3].v.flag = 0; + + this->windowVtx[x].v.tc[0] = this->windowVtx[x].v.tc[1] = this->windowVtx[x + 1].v.tc[1] = + this->windowVtx[x + 2].v.tc[0] = 0; + + this->windowVtx[x + 1].v.tc[0] = this->windowVtx[x + 3].v.tc[0] = tmp2 << 5; + + this->windowVtx[x + 2].v.tc[1] = this->windowVtx[x + 3].v.tc[1] = 32 << 5; + + this->windowVtx[x].v.cn[0] = this->windowVtx[x + 2].v.cn[0] = this->windowVtx[x].v.cn[1] = + this->windowVtx[x + 2].v.cn[1] = this->windowVtx[x].v.cn[2] = this->windowVtx[x + 2].v.cn[2] = + this->windowVtx[x + 1].v.cn[0] = this->windowVtx[x + 3].v.cn[0] = this->windowVtx[x + 1].v.cn[1] = + this->windowVtx[x + 3].v.cn[1] = this->windowVtx[x + 1].v.cn[2] = + this->windowVtx[x + 3].v.cn[2] = this->windowVtx[x].v.cn[3] = + this->windowVtx[x + 2].v.cn[3] = this->windowVtx[x + 1].v.cn[3] = + this->windowVtx[x + 3].v.cn[3] = 255; + } + } +} + +s16 D_80814620[] = { 8, 8, 8, 0 }; +s16 D_80814628[] = { 12, 12, 12, 0 }; +s16 D_80814630[] = { 12, 12, 12, 0 }; +s16 D_80814638[] = { + 88, 104, 120, 940, 944, 948, +}; +s16 D_80814644[] = { 88, 104, 120, 944 }; +s16 D_8081464C[] = { 940, 944 }; +s16 D_80814650[] = { 940, 944 }; + +/* + * fileSelect->windowContentVtx[0] -> Title Label (4) + * + * fileSelect->windowContentVtx[4] -> File 1 InfoBox (28) + * fileSelect->windowContentVtx[32] -> File 2 InfoBox (28) + * fileSelect->windowContentVtx[60] -> File 3 InfoBox (28) + * + * ** FILE 1 ** + * + * fileSelect->windowContentVtx[88] -> File Button + * fileSelect->windowContentVtx[92] -> File Name Box + * fileSelect->windowContentVtx[96] -> Connectors + * fileSelect->windowContentVtx[100] -> Blank Button (Owl Save) + * + * ** FILE 2 ** + * + * fileSelect->windowContentVtx[104] -> Repeat of File 1 above + * + * ** FILE 3 ** + * + * fileSelect->windowContentVtx[120] -> Repeat of File 1 above + * + * ** FILE 1 Info ** + * + * fileSelect->windowContentVtx[136] -> File Name (32) + * fileSelect->windowContentVtx[168] -> File Name Shadow (32) + * fileSelect->windowContentVtx[200] -> Rupee Digits (12) + * fileSelect->windowContentVtx[212] -> Rupee Digits Shadow (12) + * fileSelect->windowContentVtx[224] -> Mask Count (8) + * fileSelect->windowContentVtx[232] -> Mask Count Shadow (8) + * fileSelect->windowContentVtx[240] -> Hearts (80) + * fileSelect->windowContentVtx[320] -> Remains (16) + * fileSelect->windowContentVtx[336] -> Rupee Icon (4) + * fileSelect->windowContentVtx[340] -> Heart Piece Count (4) + * fileSelect->windowContentVtx[344] -> Mask Text (8) + * fileSelect->windowContentVtx[352] -> Owl Save Icon (4) + * fileSelect->windowContentVtx[356] -> Day Text (8) + * fileSelect->windowContentVtx[364] -> Time Digits (20) + * fileSelect->windowContentVtx[384] -> Time Digits Shadow (20) + * + * ** FILE 2 Info ** + * + * fileSelect->windowContentVtx[404] -> Repeat of File 1 above + * + * ** FILE 3 Info ** + * + * fileSelect->windowContentVtx[672] -> Repeat of File 1 above + * + * fileSelect->windowContentVtx[940] -> Action buttons (copy/erase/yes/quit) + * fileSelect->windowContentVtx[944] -> Action buttons (copy/erase/yes/quit) + * fileSelect->windowContentVtx[948] -> Option Button + * fileSelect->windowContentVtx[952] -> Highlight over currently selected button + * fileSelect->windowContentVtx[956] -> Warning labels + */ + +void FileSelect_SetWindowContentVtx(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + u16 vtxId; + s16 j; + s16 i; + s16 spAC; + u16 spA4[3]; + u16* ptr; + s32 posY; + s32 relPosY; + s32 tempPosY; + s32 posX; + s32 index; + + this->windowContentVtx = GRAPH_ALLOC(this->state.gfxCtx, 960 * sizeof(Vtx)); + + // Initialize all windowContentVtx + for (vtxId = 0; vtxId < 960; vtxId += 4) { + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = 0x12C; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 16; + + // y-coord (top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = 0; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 16; + + // z-coordinate + this->windowContentVtx[vtxId + 0].v.ob[2] = this->windowContentVtx[vtxId + 1].v.ob[2] = + this->windowContentVtx[vtxId + 2].v.ob[2] = this->windowContentVtx[vtxId + 3].v.ob[2] = 0; + + // flag + this->windowContentVtx[vtxId + 0].v.flag = this->windowContentVtx[vtxId + 1].v.flag = + this->windowContentVtx[vtxId + 2].v.flag = this->windowContentVtx[vtxId + 3].v.flag = 0; + + // texture coordinates + this->windowContentVtx[vtxId + 0].v.tc[0] = this->windowContentVtx[vtxId + 0].v.tc[1] = + this->windowContentVtx[vtxId + 1].v.tc[1] = this->windowContentVtx[vtxId + 2].v.tc[0] = 0; + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 2].v.tc[1] = + this->windowContentVtx[vtxId + 3].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x200; + + // alpha + this->windowContentVtx[vtxId + 0].v.cn[0] = this->windowContentVtx[vtxId + 1].v.cn[0] = + this->windowContentVtx[vtxId + 2].v.cn[0] = this->windowContentVtx[vtxId + 3].v.cn[0] = + this->windowContentVtx[vtxId + 0].v.cn[1] = this->windowContentVtx[vtxId + 1].v.cn[1] = + this->windowContentVtx[vtxId + 2].v.cn[1] = this->windowContentVtx[vtxId + 3].v.cn[1] = + this->windowContentVtx[vtxId + 0].v.cn[2] = this->windowContentVtx[vtxId + 1].v.cn[2] = + this->windowContentVtx[vtxId + 2].v.cn[2] = this->windowContentVtx[vtxId + 3].v.cn[2] = + this->windowContentVtx[vtxId + 0].v.cn[3] = this->windowContentVtx[vtxId + 1].v.cn[3] = + this->windowContentVtx[vtxId + 2].v.cn[3] = + this->windowContentVtx[vtxId + 3].v.cn[3] = 255; + } + + /** Title Label **/ + + // x-coord (left) + this->windowContentVtx[0].v.ob[0] = this->windowContentVtx[2].v.ob[0] = this->windowPosX; + // x-coord (right) + this->windowContentVtx[1].v.ob[0] = this->windowContentVtx[3].v.ob[0] = this->windowContentVtx[0].v.ob[0] + 0x80; + // y-coord (top) + this->windowContentVtx[0].v.ob[1] = this->windowContentVtx[1].v.ob[1] = 0x48; + // y-coord (bottom) + this->windowContentVtx[2].v.ob[1] = this->windowContentVtx[3].v.ob[1] = this->windowContentVtx[0].v.ob[1] - 0x10; + // texture coordinates + this->windowContentVtx[1].v.tc[0] = this->windowContentVtx[3].v.tc[0] = 0x1000; + + /** File InfoBox **/ + + // Loop through 3 files + for (vtxId = 4, i = 0; i < 3; i++) { + posX = this->windowPosX - 6; + + // Loop through 7 textures + for (j = 0; j < 7; j++, vtxId += 4) { + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = posX; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + sFileInfoBoxPartWidths[j]; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = + this->fileNamesY[i] + 0x2C; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x38; + + // texture coordinates + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = + sFileInfoBoxPartWidths[j] << 5; + this->windowContentVtx[vtxId + 2].v.tc[1] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x700; + + // Update X position + posX += sFileInfoBoxPartWidths[j]; + } + } + + // File Buttons + + posX = this->windowPosX - 6; + posY = 44; + + // Loop through 3 files + for (j = 0; j < 3; j++, vtxId += 16, posY -= 0x10) { + + /* File Button */ + + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = posX; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x40; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = + this->buttonYOffsets[j] + posY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x10; + + // texture coordinates + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x800; + + /* File Name Box */ + + // x-coord (left) + this->windowContentVtx[vtxId + 4].v.ob[0] = this->windowContentVtx[vtxId + 6].v.ob[0] = posX + 0x40; + // x-coord (right) + this->windowContentVtx[vtxId + 5].v.ob[0] = this->windowContentVtx[vtxId + 7].v.ob[0] = + this->windowContentVtx[vtxId + 4].v.ob[0] + 0x6C; + + // y-coord(top) + this->windowContentVtx[vtxId + 4].v.ob[1] = this->windowContentVtx[vtxId + 5].v.ob[1] = + this->buttonYOffsets[j] + posY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 6].v.ob[1] = this->windowContentVtx[vtxId + 7].v.ob[1] = + this->windowContentVtx[vtxId + 4].v.ob[1] - 0x10; + + // texture coordinates + this->windowContentVtx[vtxId + 5].v.tc[0] = this->windowContentVtx[vtxId + 7].v.tc[0] = 0xD80; + + /* Connectors */ + + // x-coord (left) + this->windowContentVtx[vtxId + 8].v.ob[0] = this->windowContentVtx[vtxId + 10].v.ob[0] = posX + 0x34; + // x-coord (right) + this->windowContentVtx[vtxId + 9].v.ob[0] = this->windowContentVtx[vtxId + 11].v.ob[0] = + this->windowContentVtx[vtxId + 8].v.ob[0] + 0x18; + + // y-coord(top) + this->windowContentVtx[vtxId + 8].v.ob[1] = this->windowContentVtx[vtxId + 9].v.ob[1] = + this->buttonYOffsets[j] + posY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 10].v.ob[1] = this->windowContentVtx[vtxId + 11].v.ob[1] = + this->windowContentVtx[vtxId + 8].v.ob[1] - 0x10; + + // texture coordinates + this->windowContentVtx[vtxId + 9].v.tc[0] = this->windowContentVtx[vtxId + 11].v.tc[0] = 0x300; + + /* Blank Button (Owl Save) */ + + // x-coord (left) + this->windowContentVtx[vtxId + 12].v.ob[0] = this->windowContentVtx[vtxId + 14].v.ob[0] = posX + 0xA9; + // x-coord (right) + this->windowContentVtx[vtxId + 13].v.ob[0] = this->windowContentVtx[vtxId + 15].v.ob[0] = + this->windowContentVtx[vtxId + 12].v.ob[0] + 0x34; + + // y-coord(top) + this->windowContentVtx[vtxId + 12].v.ob[1] = this->windowContentVtx[vtxId + 13].v.ob[1] = + this->buttonYOffsets[j] + posY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 14].v.ob[1] = this->windowContentVtx[vtxId + 15].v.ob[1] = + this->windowContentVtx[vtxId + 12].v.ob[1] - 0x10; + + // texture coordinates + this->windowContentVtx[vtxId + 13].v.tc[0] = this->windowContentVtx[vtxId + 15].v.tc[0] = 0x680; + } + + posY = 44; + + // Loop through 3 files + for (j = 0; j < 3; j++, posY -= 16) { + if (!gSaveContext.flashSaveAvailable) { + // Should skip vtxId + // vtxId += 268; + continue; + } + + // Account for owl-save offset + + spAC = j; + if (this->isOwlSave[j + 2]) { + spAC = j + 2; + } + + /* File name */ + + posX = this->windowPosX - 6; + + if ((this->configMode == 0x10) && (j == this->copyDestFileIndex)) { + relPosY = this->fileNamesY[j] + 0x2C; + } else if (((this->configMode == 0x11) || (this->configMode == 0x12)) && (j == this->copyDestFileIndex)) { + relPosY = this->buttonYOffsets[j] + posY; + } else { + relPosY = posY + this->buttonYOffsets[j] + this->fileNamesY[j]; + } + + tempPosY = relPosY - 2; + + // Loop through 8 characters of file name + for (i = 0; i < 8; i++, vtxId += 4) { + + index = this->fileNames[j][i]; + + /* File Name */ + + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = + D_80814280[index] + posX + 0x4E; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0xB; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0xC; + + /* File Name Shadow */ + + // x-coord (left) + this->windowContentVtx[vtxId + 32].v.ob[0] = this->windowContentVtx[vtxId + 34].v.ob[0] = + D_80814280[index] + posX + 0x4F; + // x-coord (right) + this->windowContentVtx[vtxId + 33].v.ob[0] = this->windowContentVtx[vtxId + 35].v.ob[0] = + this->windowContentVtx[vtxId + 32].v.ob[0] + 0xB; + + // y-coord(top) + this->windowContentVtx[vtxId + 32].v.ob[1] = this->windowContentVtx[vtxId + 33].v.ob[1] = tempPosY - 1; + // y-coord (bottom) + this->windowContentVtx[vtxId + 34].v.ob[1] = this->windowContentVtx[vtxId + 35].v.ob[1] = + this->windowContentVtx[vtxId + 32].v.ob[1] - 0xC; + + // Update X position + posX += 10; + } + // Account for the shadow + vtxId += 32; + + /* Rupee Digits */ + + posX = this->windowPosX + 14; + tempPosY = relPosY - 0x18; + + FileSelect_SplitNumber(this->rupees[spAC], &spA4[0], &spA4[1], &spA4[2]); + + index = sWalletFirstDigit[this->walletUpgrades[spAC]]; + + ptr = &spA4[index]; + + for (i = 0; i < 3; i++, vtxId += 4, ptr++) { + + /* Rupee Digits */ + + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = + D_80814280[*ptr] + posX; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + D_80814628[i]; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - D_80814630[i]; + + /* Rupee Digits Shadow */ + + // x-coord (left) + this->windowContentVtx[vtxId + 12].v.ob[0] = this->windowContentVtx[vtxId + 14].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 1; + // x-coord (right) + this->windowContentVtx[vtxId + 13].v.ob[0] = this->windowContentVtx[vtxId + 15].v.ob[0] = + this->windowContentVtx[vtxId + 12].v.ob[0] + D_80814628[i]; + + // y-coord(top) + this->windowContentVtx[vtxId + 12].v.ob[1] = this->windowContentVtx[vtxId + 13].v.ob[1] = tempPosY - 1; + // y-coord (bottom) + this->windowContentVtx[vtxId + 14].v.ob[1] = this->windowContentVtx[vtxId + 15].v.ob[1] = + this->windowContentVtx[vtxId + 12].v.ob[1] - D_80814630[i]; + + // Update X position + posX += D_80814620[i]; + } + + // Account for the shadow + vtxId += 12; + + /* Mask Count */ + + posX = this->windowPosX + 42; + tempPosY = relPosY - 0x2A; + + FileSelect_SplitNumber(this->maskCount[spAC], &spA4[0], &spA4[1], &spA4[2]); + + for (i = 1; i < 3; i++, vtxId += 4) { + + /* Mask Count */ + + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = + D_80814280[spA4[i]] + posX; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + D_80814628[i]; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - D_80814630[i]; + + /* Mask Count Shadow */ + + // x-coord (left) + this->windowContentVtx[vtxId + 8].v.ob[0] = this->windowContentVtx[vtxId + 10].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 1; + // x-coord (right) + this->windowContentVtx[vtxId + 9].v.ob[0] = this->windowContentVtx[vtxId + 11].v.ob[0] = + this->windowContentVtx[vtxId + 8].v.ob[0] + D_80814628[i]; + + // y-coord(top) + this->windowContentVtx[vtxId + 8].v.ob[1] = this->windowContentVtx[vtxId + 9].v.ob[1] = tempPosY - 1; + // y-coord (bottom) + this->windowContentVtx[vtxId + 10].v.ob[1] = this->windowContentVtx[vtxId + 11].v.ob[1] = + this->windowContentVtx[vtxId + 8].v.ob[1] - D_80814630[i]; + + // Update X position + posX += D_80814620[i]; + } + + // Account for the shadow + vtxId += 8; + + /* Hearts */ + + posX = this->windowPosX + 63; + tempPosY = relPosY - 0x10; + + // Loop through 20 hearts + for (i = 0; i < 20; i++, vtxId += 4, posX += 9) { + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = posX; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0xA; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0xA; + + // New row of hearts next iteration + if (i == 9) { + posX = this->windowPosX + (63 - 9); + tempPosY -= 8; + } + } + + /* Quest Remains */ + + posX = this->windowPosX + 64; + tempPosY = relPosY - 0x20; + + // Loop through 4 Remains + for (i = 0; i < 4; i++, vtxId += 4, posX += 0x18) { + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = posX; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x14; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x14; + + // texture coordinates + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 2].v.tc[1] = + this->windowContentVtx[vtxId + 3].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x400; + } + + /* Rupee Icon */ + + // posX = this->windowPosX - 1; + tempPosY = relPosY - 0x15; + + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = this->windowPosX - 1; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x10; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x10; + + // texture coordinates + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x200; + this->windowContentVtx[vtxId + 2].v.tc[1] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x200; + + vtxId += 4; + + /* Heart Piece Count */ + + // posX = this->windowPosX + 0x27; + tempPosY = relPosY - 0x15; + + // x-coord (left) + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = this->windowPosX + 0x27; + // x-coord (right) + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x18; + + // y-coord(top) + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY; + // y-coord (bottom) + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x10; + + // texture coordinates + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x300; + this->windowContentVtx[vtxId + 2].v.tc[1] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x200; + + vtxId += 4; + + /* Mask Text */ + + // posX = this->windowPosX - 10; + tempPosY = relPosY - 0x27; + + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = this->windowPosX - 10; + + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x40; + + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY; + + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x10; + + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x800; + this->windowContentVtx[vtxId + 2].v.tc[1] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x200; + + this->windowContentVtx[vtxId + 4].v.ob[0] = this->windowContentVtx[vtxId + 6].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 1; + + this->windowContentVtx[vtxId + 5].v.ob[0] = this->windowContentVtx[vtxId + 7].v.ob[0] = + this->windowContentVtx[vtxId + 4].v.ob[0] + 0x40; + + this->windowContentVtx[vtxId + 4].v.ob[1] = this->windowContentVtx[vtxId + 5].v.ob[1] = tempPosY - 1; + + this->windowContentVtx[vtxId + 6].v.ob[1] = this->windowContentVtx[vtxId + 7].v.ob[1] = + this->windowContentVtx[vtxId + 4].v.ob[1] - 0x10; + + this->windowContentVtx[vtxId + 5].v.tc[0] = this->windowContentVtx[vtxId + 7].v.tc[0] = 0x800; + this->windowContentVtx[vtxId + 6].v.tc[1] = this->windowContentVtx[vtxId + 7].v.tc[1] = 0x200; + + vtxId += 8; + + /* Owl Save Icon */ + + posX = this->windowPosX + 0xA3; + + if ((this->configMode == 0x10) && (j == this->copyDestFileIndex)) { + tempPosY = this->fileNamesY[j] + 0x2C; + } else if (((this->configMode == 0x11) || (this->configMode == 0x12)) && (j == this->copyDestFileIndex)) { + tempPosY = this->buttonYOffsets[j] + posY; + } else { + tempPosY = posY + this->buttonYOffsets[j] + this->fileNamesY[j]; + } + + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = posX + 0xE; + + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x18; + + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY - 2; + + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0xC; + + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x300; + this->windowContentVtx[vtxId + 2].v.tc[1] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x180; + + vtxId += 4; + + /* Day Text */ + + for (i = 0; i < 2; i++, vtxId += 4) { + + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = 2 + posX + i; + + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x30; + + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY - i - 0x12; + + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x18; + + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x600; + + this->windowContentVtx[vtxId + 2].v.tc[1] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x300; + } + + /* Time Digits */ + + posX += 6; + index = vtxId; + + for (i = 0; i < 5; i++, vtxId += 4, posX += 8) { + + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = posX; + + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0xC; + + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = tempPosY - 0x2A; + + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0xC; + + this->windowContentVtx[vtxId + 0x14].v.ob[0] = this->windowContentVtx[vtxId + 0x16].v.ob[0] = posX + 1; + + this->windowContentVtx[vtxId + 0x15].v.ob[0] = this->windowContentVtx[vtxId + 0x17].v.ob[0] = + this->windowContentVtx[vtxId + 0x14].v.ob[0] + 0xC; + + this->windowContentVtx[vtxId + 0x14].v.ob[1] = this->windowContentVtx[vtxId + 0x15].v.ob[1] = + tempPosY - 0x2B; + + this->windowContentVtx[vtxId + 0x16].v.ob[1] = this->windowContentVtx[vtxId + 0x17].v.ob[1] = + this->windowContentVtx[vtxId + 0x14].v.ob[1] - 0xC; + } + + // Adjust the colon to the right + this->windowContentVtx[index + 8].v.ob[0] = this->windowContentVtx[index + 10].v.ob[0] = + this->windowContentVtx[index + 8].v.ob[0] + 3; + + this->windowContentVtx[index + 9].v.ob[0] = this->windowContentVtx[index + 11].v.ob[0] = + this->windowContentVtx[index + 8].v.ob[0] + 0xC; + + this->windowContentVtx[index + 0x1C].v.ob[0] = this->windowContentVtx[index + 0x1E].v.ob[0] = + this->windowContentVtx[index + 8].v.ob[0] + 1; + + this->windowContentVtx[index + 0x1D].v.ob[0] = this->windowContentVtx[index + 0x1F].v.ob[0] = + this->windowContentVtx[index + 0x1C].v.ob[0] + 0xC; + + vtxId += 20; + } + + posX = this->windowPosX - 6; + posY = -0xC; + + for (j = 0; j < 2; j++, vtxId += 4, posY -= 0x10) { + + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = posX; + + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x40; + + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = + this->buttonYOffsets[j + 3] + posY; + + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x10; + + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x800; + } + + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = posX; + + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x40; + + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = + this->buttonYOffsets[5] - 0x34; + + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x10; + + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x800; + + vtxId += 4; + + if (((this->menuMode == FS_MENU_MODE_CONFIG) && (this->configMode >= 2)) || + ((this->menuMode == FS_MENU_MODE_SELECT) && (this->selectMode == 3))) { + if (this->menuMode == FS_MENU_MODE_CONFIG) { + if ((this->configMode == 4) || (this->configMode == 7) || (this->configMode == 0x16)) { + j = D_80814644[this->buttonIndex]; + } else if ((this->configMode == 0x19) || (this->configMode == 0xC)) { + j = D_8081464C[this->buttonIndex]; + } else { + j = D_80814638[this->buttonIndex]; + } + } else { + j = D_80814650[this->confirmButtonIndex]; + } + + this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = this->windowPosX - 0xA; + + this->windowContentVtx[vtxId + 1].v.ob[0] = this->windowContentVtx[vtxId + 3].v.ob[0] = + this->windowContentVtx[vtxId + 0].v.ob[0] + 0x48; + + this->windowContentVtx[vtxId + 0].v.ob[1] = this->windowContentVtx[vtxId + 1].v.ob[1] = + this->windowContentVtx[j].v.ob[1] + 4; + + this->windowContentVtx[vtxId + 2].v.ob[1] = this->windowContentVtx[vtxId + 3].v.ob[1] = + this->windowContentVtx[vtxId + 0].v.ob[1] - 0x18; + + this->windowContentVtx[vtxId + 1].v.tc[0] = this->windowContentVtx[vtxId + 3].v.tc[0] = 0x900; + + this->windowContentVtx[vtxId + 2].v.tc[1] = this->windowContentVtx[vtxId + 3].v.tc[1] = 0x300; + } + + this->windowContentVtx[vtxId + 4].v.ob[0] = this->windowContentVtx[vtxId + 6].v.ob[0] = this->windowPosX + 0x3A; + + this->windowContentVtx[vtxId + 5].v.ob[0] = this->windowContentVtx[vtxId + 7].v.ob[0] = + this->windowContentVtx[vtxId + 4].v.ob[0] + 0x80; + + this->windowContentVtx[vtxId + 4].v.ob[1] = this->windowContentVtx[vtxId + 5].v.ob[1] = + this->windowContentVtx[D_80814638[this->warningButtonIndex]].v.ob[1]; + + this->windowContentVtx[vtxId + 6].v.ob[1] = this->windowContentVtx[vtxId + 7].v.ob[1] = + this->windowContentVtx[vtxId + 4].v.ob[1] - 0x10; + + this->windowContentVtx[vtxId + 5].v.tc[0] = this->windowContentVtx[vtxId + 7].v.tc[0] = 0x1000; +} + +u16 D_80814654[] = { + 0x88, + 0x194, + 0x2A0, +}; +TexturePtr sFileSelRemainsTextures[] = { + gFileSelOdolwasRemainsTex, + gFileSelGohtsRemainsTex, + gFileSelGyorgsRemainsTex, + gFileSelTwinmoldsRemainsTex, +}; +TexturePtr sFileSelDayENGTextures[] = { + gFileSelFirstDayENGTex, + gFileSelFirstDayENGTex, + gFileSelSecondDayENGTex, + gFileSelFinalDayENGTex, +}; +TexturePtr sFileSelHeartPieceTextures[] = { + gFileSel0QuarterHeartENGTex, + gFileSel1QuarterHeartENGTex, + gFileSel2QuarterHeartENGTex, + gFileSel3QuarterHeartENGTex, +}; +static TexturePtr sHeartTextures[2][5] = { + { + gHeartEmptyTex, + gHeartQuarterTex, + gHeartHalfTex, + gHeartThreeQuarterTex, + gHeartFullTex, + }, + { + gDefenseHeartEmptyTex, + gDefenseHeartQuarterTex, + gDefenseHeartHalfTex, + gDefenseHeartThreeQuarterTex, + gDefenseHeartFullTex, + }, +}; +u8 sHealthToQuarterHeartCount[] = { + 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, +}; +s16 sFileSelRupeePrimColors[3][3] = { + { 200, 255, 100 }, // Default Wallet + { 170, 170, 255 }, // Adult Wallet + { 255, 105, 105 }, // Giant Wallet +}; +s16 sFileSelRupeeEnvColors[3][3] = { + { 0, 80, 0 }, // Default Wallet + { 10, 10, 80 }, // Adult Wallet + { 40, 10, 0 }, // Giant Wallet +}; +static s16 sHeartPrimColors[2][3] = { + { 255, 70, 50 }, + { 200, 0, 0 }, +}; +static s16 sHeartEnvColors[2][3] = { + { 50, 40, 60 }, + { 255, 255, 255 }, +}; + +void FileSelect_DrawFileInfo(GameState* thisx, s16 fileIndex) { + FileSelectState* this = (FileSelectState*)thisx; + Font* font = &this->font; + s16 j; + s16 vtxOffset; + s32 heartType; + s16 i; + s16 sp20C; + s16 health; + s16 timeDigits[5]; + u16 digits[3]; // rupees and mask count + u8 quarterHeartCount; + + OPEN_DISPS(this->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, + PRIMITIVE, 0); + + sp20C = fileIndex; + + // draw file name + if (this->nameAlpha[fileIndex] != 0) { + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + (4 * 8)], 32, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 0, 0, 0, this->nameAlpha[fileIndex]); + + for (vtxOffset = 0, i = 0; vtxOffset < (4 * 8); i++, vtxOffset += 4) { + FileSelect_DrawTexQuadI4(this->state.gfxCtx, + font->fontBuf + this->fileNames[fileIndex][i] * FONT_CHAR_TEX_SIZE, vtxOffset); + } + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex]], 32, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 255, 255, this->nameAlpha[fileIndex]); + + for (vtxOffset = 0, i = 0; vtxOffset < (4 * 8); i++, vtxOffset += 4) { + FileSelect_DrawTexQuadI4(this->state.gfxCtx, + font->fontBuf + this->fileNames[fileIndex][i] * FONT_CHAR_TEX_SIZE, vtxOffset); + } + } + + if ((fileIndex == this->selectedFileIndex) || (fileIndex == this->copyDestFileIndex)) { + if (this->isOwlSave[fileIndex + 2]) { + sp20C = fileIndex + 2; + } + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, sFileSelRupeePrimColors[this->walletUpgrades[sp20C]][0], + sFileSelRupeePrimColors[this->walletUpgrades[sp20C]][1], + sFileSelRupeePrimColors[this->walletUpgrades[sp20C]][2], this->fileInfoAlpha[fileIndex]); + gDPSetEnvColor(POLY_OPA_DISP++, sFileSelRupeeEnvColors[this->walletUpgrades[sp20C]][0], + sFileSelRupeeEnvColors[this->walletUpgrades[sp20C]][1], + sFileSelRupeeEnvColors[this->walletUpgrades[sp20C]][2], 255); + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0xC8], 4, 0); + + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelRupeeTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, TEXEL0, 0, + PRIMITIVE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 0, 0, 0, this->fileInfoAlpha[fileIndex]); + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0x4C], 12, 0); + + FileSelect_SplitNumber((u16)this->rupees[sp20C], &digits[0], &digits[1], &digits[2]); + + for (vtxOffset = 0, i = sWalletFirstDigit[this->walletUpgrades[sp20C]]; i < 3; i++, vtxOffset += 4) { + FileSelect_DrawTexQuadI4(this->state.gfxCtx, font->fontBuf + digits[i] * FONT_CHAR_TEX_SIZE, vtxOffset); + } + + if (this->rupees[sp20C] == gUpgradeCapacities[4][this->walletUpgrades[sp20C]]) { + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 120, 255, 0, this->fileInfoAlpha[fileIndex]); + } else if (this->rupees[sp20C] != 0) { + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 255, 255, this->fileInfoAlpha[fileIndex]); + } else { + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 100, 100, 100, this->fileInfoAlpha[fileIndex]); + } + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0x40], 12, 0); + + for (vtxOffset = 0, i = sWalletFirstDigit[this->walletUpgrades[sp20C]]; i < 3; i++, vtxOffset += 4) { + FileSelect_DrawTexQuadI4(this->state.gfxCtx, font->fontBuf + digits[i] * FONT_CHAR_TEX_SIZE, vtxOffset); + } + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 0, 0, this->fileInfoAlpha[fileIndex]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0xCC], 4, 0); + + POLY_OPA_DISP = FileSelect_DrawTexQuadIA8( + POLY_OPA_DISP, sFileSelHeartPieceTextures[this->heartPieceCount[sp20C]], 0x18, 0x10, 0); + + if (this->defenseHearts[sp20C] == 0) { + heartType = 0; + } else { + heartType = 1; + } + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, sHeartPrimColors[heartType][0], sHeartPrimColors[heartType][1], + sHeartPrimColors[heartType][2], this->fileInfoAlpha[fileIndex]); + gDPSetEnvColor(POLY_OPA_DISP++, sHeartEnvColors[heartType][0], sHeartEnvColors[heartType][1], + sHeartEnvColors[heartType][2], 255); + + i = this->healthCapacity[sp20C] / 0x10; + + health = this->health[sp20C]; + if (health <= 0x30) { + health = 0x30; + } + + quarterHeartCount = 4; + for (vtxOffset = 0, j = 0; j < i; j++, vtxOffset += 4) { + if (health < 0x10) { + if (health != 0) { + quarterHeartCount = sHealthToQuarterHeartCount[health]; + health = 0; + } else { + quarterHeartCount = 0; + } + } else { + health -= 0x10; + } + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0x68 + vtxOffset], 4, 0); + POLY_OPA_DISP = + FileSelect_DrawTexQuadIA8(POLY_OPA_DISP, sHeartTextures[heartType][quarterHeartCount], 0x10, 0x10, 0); + } + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 255, 255, this->fileInfoAlpha[fileIndex]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + + for (vtxOffset = 0, j = 0; j < 4; j++, vtxOffset += 4) { + if (this->questItems[sp20C] & gBitFlags[j]) { + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0xB8 + vtxOffset], 4, 0); + gDPLoadTextureBlock(POLY_OPA_DISP++, sFileSelRemainsTextures[j], G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + } + } + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, TEXEL0, 0, + PRIMITIVE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 0, 0, 0, this->fileInfoAlpha[fileIndex]); + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0xD0], 8, 0); + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, gFileSelMASKSENGTex, G_IM_FMT_I, 64, 16, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 4, 6, 7, 5, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 255, 255, this->fileInfoAlpha[fileIndex]); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 0, 0, 0, this->fileInfoAlpha[fileIndex]); + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0x60], 8, 0); + + FileSelect_SplitNumber(this->maskCount[sp20C], &digits[0], &digits[1], &digits[2]); + + for (vtxOffset = 0, i = 1; i < 3; i++, vtxOffset += 4) { + FileSelect_DrawTexQuadI4(this->state.gfxCtx, font->fontBuf + digits[i] * FONT_CHAR_TEX_SIZE, vtxOffset); + } + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 255, 255, this->fileInfoAlpha[fileIndex]); + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0x58], 8, 0); + + for (vtxOffset = 0, i = 1; i < 3; i++, vtxOffset += 4) { + + FileSelect_DrawTexQuadI4(this->state.gfxCtx, font->fontBuf + digits[i] * FONT_CHAR_TEX_SIZE, vtxOffset); + } + } + + if (this->isOwlSave[fileIndex + 2]) { + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 255, 255, this->nameAlpha[fileIndex]); + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0xD8], 4, 0); + + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelOwlSaveIconTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 24, 12, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0xDC], 8, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 0, 0, 0, this->fileInfoAlpha[fileIndex]); + + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, sFileSelDayENGTextures[this->day[sp20C]], G_IM_FMT_I, 48, 24, 0, + G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 4, 6, 7, 5, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 255, 255, this->fileInfoAlpha[fileIndex]); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + + timeDigits[0] = 0; + timeDigits[1] = TIME_TO_MINUTES_F(this->time[sp20C]) / 60.0f; + + while (timeDigits[1] >= 10) { + timeDigits[0]++; + timeDigits[1] -= 10; + } + + timeDigits[3] = 0; + timeDigits[4] = (s32)TIME_TO_MINUTES_F(this->time[sp20C]) % 60; + + while (timeDigits[4] >= 10) { + timeDigits[3]++; + timeDigits[4] -= 10; + } + timeDigits[2] = 0x41; + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, TEXEL0, 0, + PRIMITIVE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 0, 0, 0, this->fileInfoAlpha[fileIndex]); + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0xF8], 20, 0); + + for (i = 0, vtxOffset = 0; i < 5; i++, vtxOffset += 4) { + FileSelect_DrawTexQuadI4(this->state.gfxCtx, font->fontBuf + timeDigits[i] * FONT_CHAR_TEX_SIZE, vtxOffset); + } + + gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 255, 255, 255, this->fileInfoAlpha[fileIndex]); + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_80814654[fileIndex] + 0xE4], 20, 0); + + for (i = 0, vtxOffset = 0; i < 5; i++, vtxOffset += 4) { + FileSelect_DrawTexQuadI4(this->state.gfxCtx, font->fontBuf + timeDigits[i] * FONT_CHAR_TEX_SIZE, vtxOffset); + } + } + + gDPPipeSync(POLY_OPA_DISP++); + + CLOSE_DISPS(this->state.gfxCtx); +} + +TexturePtr sFileInfoBoxTextures[] = { + gFileSelFileInfoBox0Tex, gFileSelFileInfoBox1Tex, gFileSelFileInfoBox2Tex, gFileSelFileInfoBox3Tex, + gFileSelFileInfoBox4Tex, gFileSelFileExtraInfoBox0Tex, gFileSelFileExtraInfoBox1Tex, +}; + +TexturePtr sTitleLabels[] = { + gFileSelPleaseSelectAFileENGTex, gFileSelOpenThisFileENGTex, gFileSelCopyWhichFileENGTex, + gFileSelCopyToWhichFileENGTex, gFileSelAreYouSureCopyENGTex, gFileSelFileCopiedENGTex, + gFileSelEraseWhichFileENGTex, gFileSelAreYouSureEraseENGTex, gFileSelFileErasedENGTex, +}; + +TexturePtr sWarningLabels[] = { + gFileSelNoFileToCopyENGTex, gFileSelNoFileToEraseENGTex, gFileSelNoEmptyFileENGTex, + gFileSelFileEmptyENGTex, gFileSelFileInUseENGTex, +}; + +TexturePtr sFileButtonTextures[] = { + gFileSelFile1ButtonENGTex, + gFileSelFile2ButtonENGTex, + gFileSelFile3ButtonENGTex, +}; + +TexturePtr sActionButtonTextures[] = { + gFileSelCopyButtonENGTex, + gFileSelEraseButtonENGTex, + gFileSelYesButtonENGTex, + gFileSelQuitButtonENGTex, +}; + +/** + * Draw most window contents including buttons, labels, and icons. + * Does not include anything from the keyboard and settings windows. + */ +void FileSelect_DrawWindowContents(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + s16 fileIndex; + s16 temp; + s16 i; + s16 quadVtxIndex; + + OPEN_DISPS(this->state.gfxCtx); + + // draw title label + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[0], 4, 0); + gDPLoadTextureBlock(POLY_OPA_DISP++, sTitleLabels[this->titleLabel], G_IM_FMT_IA, G_IM_SIZ_8b, 128, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + + // draw next title label + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->titleAlpha[FS_TITLE_NEXT]); + gDPLoadTextureBlock(POLY_OPA_DISP++, sTitleLabels[this->nextTitleLabel], G_IM_FMT_IA, G_IM_SIZ_8b, 128, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + + temp = 4; + + gDPPipeSync(POLY_OPA_DISP++); + + // draw file info box (large box when a file is selected) + for (fileIndex = 0; fileIndex < 3; fileIndex++, temp += 28) { + if (fileIndex < 2) { + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->fileInfoAlpha[fileIndex]); + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[temp], 28, 0); + + for (quadVtxIndex = 0, i = 0; i < 7; i++, quadVtxIndex += 4) { + if ((i < 5) || (this->isOwlSave[fileIndex + 2] && (i >= 5))) { + gDPLoadTextureBlock(POLY_OPA_DISP++, sFileInfoBoxTextures[i], G_IM_FMT_IA, G_IM_SIZ_16b, + sFileInfoBoxPartWidths[i], 56, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, quadVtxIndex, quadVtxIndex + 2, quadVtxIndex + 3, quadVtxIndex + 1, + 0); + } + } + } + } + + gDPPipeSync(POLY_OPA_DISP++); + + for (i = 0; i < 3; i++, temp += 16) { + if (i < 2) { + // draw file button + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[temp], 16, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, sWindowContentColors[0], sWindowContentColors[1], + sWindowContentColors[2], this->fileButtonAlpha[i]); + gDPLoadTextureBlock(POLY_OPA_DISP++, sFileButtonTextures[i], G_IM_FMT_IA, G_IM_SIZ_16b, 64, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + + // draw file name box + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, sWindowContentColors[0], sWindowContentColors[1], + sWindowContentColors[2], this->nameBoxAlpha[i]); + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelFileNameBoxTex, G_IM_FMT_IA, G_IM_SIZ_16b, 108, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 4, 6, 7, 5, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, sWindowContentColors[0], sWindowContentColors[1], + sWindowContentColors[2], this->connectorAlpha[i]); + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelConnectorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 8, 10, 11, 9, 0); + + if (this->isOwlSave[i + 2]) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, sWindowContentColors[0], sWindowContentColors[1], + sWindowContentColors[2], this->nameBoxAlpha[i]); + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelBlankButtonTex, G_IM_FMT_IA, G_IM_SIZ_16b, 52, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 12, 14, 15, 13, 0); + } + } + } + + // draw file info + for (fileIndex = 0; fileIndex < 2; fileIndex++) { + FileSelect_DrawFileInfo(&this->state, fileIndex); + } + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[0x3AC], 20, 0); + + // draw primary action buttons (copy/erase) + for (quadVtxIndex = 0, i = 0; i < 2; i++, quadVtxIndex += 4) { + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->actionButtonAlpha[i]); + gDPLoadTextureBlock(POLY_OPA_DISP++, sActionButtonTextures[i], G_IM_FMT_IA, G_IM_SIZ_16b, 64, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, quadVtxIndex, quadVtxIndex + 2, quadVtxIndex + 3, quadVtxIndex + 1, 0); + } + + gDPPipeSync(POLY_OPA_DISP++); + + // draw confirm buttons (yes/quit) + for (quadVtxIndex = 0, i = FS_BTN_CONFIRM_YES; i <= FS_BTN_CONFIRM_QUIT; i++, quadVtxIndex += 4) { + temp = this->confirmButtonTexIndices[i]; + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->confirmButtonAlpha[i]); + gDPLoadTextureBlock(POLY_OPA_DISP++, sActionButtonTextures[temp], G_IM_FMT_IA, G_IM_SIZ_16b, 64, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, quadVtxIndex, quadVtxIndex + 2, quadVtxIndex + 3, quadVtxIndex + 1, 0); + } + + // draw options button + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->optionButtonAlpha); + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelOptionsButtonENGTex, G_IM_FMT_IA, G_IM_SIZ_16b, 64, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 8, 10, 11, 9, 0); + + // draw highlight over currently selected button + if (((this->menuMode == FS_MENU_MODE_CONFIG) && + ((this->configMode == CM_MAIN_MENU) || (this->configMode == CM_SELECT_COPY_SOURCE) || + (this->configMode == CM_SELECT_COPY_DEST) || (this->configMode == CM_COPY_CONFIRM) || + (this->configMode == CM_ERASE_SELECT) || (this->configMode == CM_ERASE_CONFIRM))) || + ((this->menuMode == FS_MENU_MODE_SELECT) && (this->selectMode == SM_CONFIRM_FILE))) { + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, TEXEL0, 0, + PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->highlightColor[0], this->highlightColor[1], + this->highlightColor[2], this->highlightColor[3]); + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelBigButtonHighlightTex, G_IM_FMT_I, G_IM_SIZ_8b, 72, 24, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 12, 14, 15, 13, 0); + } + + // draw warning labels + if (this->warningLabel > FS_WARNING_NONE) { + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->emptyFileTextAlpha); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + gDPLoadTextureBlock(POLY_OPA_DISP++, sWarningLabels[this->warningLabel], G_IM_FMT_IA, G_IM_SIZ_8b, 128, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 16, 18, 19, 17, 0); + } + + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA); + + CLOSE_DISPS(this->state.gfxCtx); +} + +void FileSelect_ConfigModeDraw(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + OPEN_DISPS(this->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + + Gfx_SetupDL42_Opa(this->state.gfxCtx); + FileSelect_SetView(this, 0.0f, 0.0f, 64.0f); + FileSelect_SetWindowVtx(&this->state); + FileSelect_SetWindowContentVtx(&this->state); + + if ((this->configMode != CM_NAME_ENTRY) && (this->configMode != CM_START_NAME_ENTRY)) { + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->windowAlpha); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + + Matrix_Translate(0.0f, 0.0f, -93.6f, MTXMODE_NEW); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + + if (this->windowRot != 0) { + Matrix_RotateXFApply(this->windowRot / 100.0f); + } + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, this->state.gfxCtx); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[0], 32, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow1DL); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[32], 32, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow2DL); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[64], 16, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow3DL); + + gDPPipeSync(POLY_OPA_DISP++); + + FileSelect_DrawWindowContents(&this->state); + } + + // draw name entry menu + if ((this->configMode >= CM_ROTATE_TO_NAME_ENTRY) && (this->configMode <= CM_NAME_ENTRY_TO_MAIN)) { + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->windowAlpha); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + + Matrix_Translate(0.0f, 0.0f, -93.6f, MTXMODE_NEW); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply((this->windowRot - 314.0f) / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, this->state.gfxCtx); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[0], 32, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow1DL); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[32], 32, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow2DL); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[64], 16, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow3DL); + + gDPPipeSync(POLY_OPA_DISP++); + + FileSelect_DrawNameEntry(&this->state); + } + + // draw options menu + if ((this->configMode >= CM_MAIN_TO_OPTIONS) && (this->configMode <= CM_OPTIONS_TO_MAIN)) { + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->windowAlpha); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + + Matrix_Translate(0.0f, 0.0f, -93.6f, MTXMODE_NEW); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply((this->windowRot - 314.0f) / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, this->state.gfxCtx); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[0], 32, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow1DL); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[32], 32, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow2DL); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[64], 16, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow3DL); + + gDPPipeSync(POLY_OPA_DISP++); + + FileSelect_DrawOptions(&this->state); + } + + gDPPipeSync(POLY_OPA_DISP++); + + FileSelect_SetView(this, 0.0f, 0.0f, 64.0f); + + CLOSE_DISPS(this->state.gfxCtx); +} + +/** + * Fade out the main menu elements to transition to select mode. + * Update function for `SM_FADE_MAIN_TO_SELECT` + */ +void FileSelect_FadeMainToSelect(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + SramContext* sramCtx = &this->sramCtx; + s16 i; + + for (i = 0; i < 3; i++) { + if (i != this->buttonIndex) { + this->fileButtonAlpha[i] -= 50; + this->actionButtonAlpha[FS_BTN_ACTION_COPY] = this->actionButtonAlpha[FS_BTN_ACTION_ERASE] = + this->optionButtonAlpha = this->fileButtonAlpha[i]; + + if (!gSaveContext.flashSaveAvailable) { + if (NO_FLASH_SLOT_OCCUPIED(sramCtx, i)) { + this->nameAlpha[i] = this->nameBoxAlpha[i] = this->fileButtonAlpha[i]; + this->connectorAlpha[i] -= 255 / 4; + } + } else { + if (SLOT_OCCUPIED(this, i)) { + this->nameAlpha[i] = this->nameBoxAlpha[i] = this->fileButtonAlpha[i]; + this->connectorAlpha[i] -= 255 / 4; + } + } + } + } + + this->titleAlpha[FS_TITLE_CUR] -= 255 / 4; + this->titleAlpha[FS_TITLE_NEXT] += 255 / 4; + this->actionTimer--; + + if (this->actionTimer == 0) { + this->actionTimer = 4; + this->selectMode++; // SM_MOVE_FILE_TO_TOP + this->confirmButtonIndex = FS_BTN_CONFIRM_YES; + } +} + +// Amount to move by to reach the top of the screen +s16 sFileYOffsets[] = { 0, 16, 32 }; + +/** + * Moves the selected file to the top of the window. + * Update function for `SM_MOVE_FILE_TO_TOP` + */ +void FileSelect_MoveSelectedFileToTop(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + s32 yStep; + + yStep = ABS_ALT(this->buttonYOffsets[this->buttonIndex] - sFileYOffsets[this->buttonIndex]) / this->actionTimer; + this->buttonYOffsets[this->buttonIndex] += yStep; + this->actionTimer--; + + if ((this->actionTimer == 0) || (this->buttonYOffsets[this->buttonIndex] == sFileYOffsets[this->buttonIndex])) { + this->buttonYOffsets[FS_BTN_SELECT_YES] = this->buttonYOffsets[FS_BTN_SELECT_QUIT] = -24; + this->actionTimer = 4; + this->selectMode++; // SM_FADE_IN_FILE_INFO + } +} + +/** + * Fade in the file info for the selected file. + * Update function for `SM_FADE_IN_FILE_INFO` + */ +void FileSelect_FadeInFileInfo(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->fileInfoAlpha[this->buttonIndex] += 50; + this->nameBoxAlpha[this->buttonIndex] -= 100; + + if (this->nameBoxAlpha[this->buttonIndex] <= 0) { + this->nameBoxAlpha[this->buttonIndex] = 0; + } + + this->actionTimer--; + + if (this->actionTimer == 0) { + this->fileInfoAlpha[this->buttonIndex] = 200; + this->actionTimer = 4; + this->selectMode++; // SM_CONFIRM_FILE + } + + this->confirmButtonAlpha[FS_BTN_CONFIRM_YES] = this->confirmButtonAlpha[FS_BTN_CONFIRM_QUIT] = + this->fileInfoAlpha[this->buttonIndex]; +} + +/** + * Update the cursor and handle the option that the player picks for confirming the selected file. + * Update function for `SM_CONFIRM_FILE` + */ +void FileSelect_ConfirmFile(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + Input* input = CONTROLLER1(&this->state); + + if (CHECK_BTN_ALL(input->press.button, BTN_START) || (CHECK_BTN_ALL(input->press.button, BTN_A))) { + if (this->confirmButtonIndex == FS_BTN_CONFIRM_YES) { + Rumble_Request(300.0f, 180, 20, 100); + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + this->selectMode = SM_FADE_OUT; + Audio_MuteAllSeqExceptSystemAndOcarina(15); + } else { // FS_BTN_CONFIRM_QUIT + Audio_PlaySfx(NA_SE_SY_FSEL_CLOSE); + this->selectMode++; // SM_FADE_OUT_FILE_INFO + } + } else if (CHECK_BTN_ALL(input->press.button, BTN_B)) { + Audio_PlaySfx(NA_SE_SY_FSEL_CLOSE); + this->selectMode++; // SM_FADE_OUT_FILE_INFO + } else if (ABS_ALT(this->stickAdjY) >= 30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + this->confirmButtonIndex ^= 1; + } +} + +/** + * Fade out the file info for the selected file before returning to the main menu. + * Update function for `SM_FADE_OUT_FILE_INFO` + */ +void FileSelect_FadeOutFileInfo(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->fileInfoAlpha[this->buttonIndex] -= 200 / 4; + this->nameBoxAlpha[this->buttonIndex] += 200 / 4; + this->actionTimer--; + + if (this->actionTimer == 0) { + this->buttonYOffsets[FS_BTN_SELECT_YES] = this->buttonYOffsets[FS_BTN_SELECT_QUIT] = 0; + this->nameBoxAlpha[this->buttonIndex] = 200; + this->fileInfoAlpha[this->buttonIndex] = 0; + this->nextTitleLabel = FS_TITLE_SELECT_FILE; + this->actionTimer = 4; + this->selectMode++; + } + + this->confirmButtonAlpha[FS_BTN_CONFIRM_YES] = this->confirmButtonAlpha[FS_BTN_CONFIRM_QUIT] = + this->fileInfoAlpha[this->buttonIndex]; +} + +/** + * Move the selected file back to the slot position then go to config mode for the main menu. + * Update function for `SM_MOVE_FILE_TO_SLOT` + */ +void FileSelect_MoveSelectedFileToSlot(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + SramContext* sramCtx = &this->sramCtx; + s32 yStep; + s16 i; + + yStep = ABS_ALT(this->buttonYOffsets[this->buttonIndex]) / this->actionTimer; + this->buttonYOffsets[this->buttonIndex] -= yStep; + + if (this->buttonYOffsets[this->buttonIndex] <= 0) { + this->buttonYOffsets[this->buttonIndex] = 0; + } + + for (i = 0; i < 3; i++) { + if (i != this->buttonIndex) { + this->fileButtonAlpha[i] += 200 / 4; + + if (this->fileButtonAlpha[i] >= 200) { + this->fileButtonAlpha[i] = 200; + } + + this->actionButtonAlpha[FS_BTN_ACTION_COPY] = this->actionButtonAlpha[FS_BTN_ACTION_ERASE] = + this->optionButtonAlpha = this->fileButtonAlpha[i]; + + if (!gSaveContext.flashSaveAvailable) { + if (NO_FLASH_SLOT_OCCUPIED(sramCtx, i)) { + this->nameBoxAlpha[i] = this->nameAlpha[i] = this->fileButtonAlpha[i]; + this->connectorAlpha[i] += 255 / 4; + } + } else { + if (SLOT_OCCUPIED(this, i)) { + this->nameBoxAlpha[i] = this->nameAlpha[i] = this->fileButtonAlpha[i]; + this->connectorAlpha[i] += 255 / 4; + } + } + } + } + + this->titleAlpha[FS_TITLE_CUR] -= 255 / 4; + this->titleAlpha[FS_TITLE_NEXT] += 255 / 4; + this->actionTimer--; + + if (this->actionTimer == 0) { + this->titleAlpha[FS_TITLE_CUR] = 255; + this->titleAlpha[FS_TITLE_NEXT] = 0; + this->titleLabel = this->nextTitleLabel; + this->actionTimer = 4; + this->menuMode = FS_MENU_MODE_CONFIG; + this->configMode = CM_MAIN_MENU; + this->nextConfigMode = CM_MAIN_MENU; + this->selectMode = SM_FADE_MAIN_TO_SELECT; + } +} + +/** + * Fill the screen with black to fade out. + * Update function for `SM_FADE_OUT` + */ +void FileSelect_FadeOut(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->screenFillAlpha += 40; + + if (this->screenFillAlpha >= 255) { + this->screenFillAlpha = 255; + this->selectMode++; // SM_LOAD_GAME + } +} + +/** + * Load the save for the appropriate file and start the game. + * Update function for `SM_LOAD_GAME` + */ +void FileSelect_LoadGame(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + u16 i; + + gSaveContext.fileNum = this->buttonIndex; + Sram_OpenSave(this, &this->sramCtx); + + gSaveContext.gameMode = GAMEMODE_NORMAL; + + STOP_GAMESTATE(&this->state); + SET_NEXT_GAMESTATE(&this->state, Play_Init, sizeof(PlayState)); + + gSaveContext.respawnFlag = 0; + gSaveContext.respawn[RESPAWN_MODE_DOWN].entrance = ENTR_LOAD_OPENING; + gSaveContext.seqId = (u8)NA_BGM_DISABLED; + gSaveContext.ambienceId = AMBIENCE_ID_DISABLED; + gSaveContext.showTitleCard = true; + gSaveContext.dogParams = 0; + + for (i = 0; i < TIMER_ID_MAX; i++) { + gSaveContext.timerStates[i] = TIMER_STATE_OFF; + } + + gSaveContext.prevHudVisibility = HUD_VISIBILITY_ALL; + gSaveContext.nayrusLoveTimer = 0; + gSaveContext.healthAccumulator = 0; + gSaveContext.magicFlag = 0; + gSaveContext.forcedSeqId = 0; + gSaveContext.skyboxTime = CLOCK_TIME(0, 0); + gSaveContext.nextTransitionType = TRANS_NEXT_TYPE_DEFAULT; + gSaveContext.cutsceneTrigger = 0; + gSaveContext.chamberCutsceneNum = 0; + gSaveContext.nextDayTime = NEXT_TIME_NONE; + gSaveContext.retainWeatherMode = false; + + gSaveContext.buttonStatus[EQUIP_SLOT_B] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_ENABLED; + + gSaveContext.hudVisibilityForceButtonAlphasByStatus = false; + gSaveContext.nextHudVisibility = HUD_VISIBILITY_IDLE; + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + gSaveContext.hudVisibilityTimer = 0; + + gSaveContext.save.saveInfo.playerData.tatlTimer = 0; +} + +void (*sSelectModeUpdateFuncs[])(GameState*) = { + FileSelect_FadeMainToSelect, // SM_FADE_MAIN_TO_SELECT + FileSelect_MoveSelectedFileToTop, // SM_MOVE_FILE_TO_TOP + FileSelect_FadeInFileInfo, // SM_FADE_IN_FILE_INFO + FileSelect_ConfirmFile, // SM_CONFIRM_FILE + FileSelect_FadeOutFileInfo, // SM_FADE_OUT_FILE_INFO + FileSelect_MoveSelectedFileToSlot, // SM_MOVE_FILE_TO_SLOT + FileSelect_FadeOut, // SM_FADE_OUT + FileSelect_LoadGame, // SM_LOAD_GAME +}; + +void FileSelect_SelectModeUpdate(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + sSelectModeUpdateFuncs[this->selectMode](&this->state); +} + +void FileSelect_SelectModeDraw(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + OPEN_DISPS(this->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + + Gfx_SetupDL42_Opa(this->state.gfxCtx); + FileSelect_SetView(this, 0.0f, 0.0f, 64.0f); + FileSelect_SetWindowVtx(&this->state); + FileSelect_SetWindowContentVtx(&this->state); + + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->windowAlpha); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + + Matrix_Translate(0.0f, 0.0f, -93.6f, MTXMODE_NEW); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(this->windowRot / 100.0f); + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, this->state.gfxCtx); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[0], 32, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow1DL); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[32], 32, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow2DL); + + gSPVertex(POLY_OPA_DISP++, &this->windowVtx[64], 16, 0); + gSPDisplayList(POLY_OPA_DISP++, gFileSelWindow3DL); + + FileSelect_DrawWindowContents(&this->state); + gDPPipeSync(POLY_OPA_DISP++); + FileSelect_SetView(this, 0.0f, 0.0f, 64.0f); + + CLOSE_DISPS(this->state.gfxCtx); +} + +void FileSelect_UpdateAndDrawSkybox(FileSelectState* this) { + s32 pad; + f32 eyeX; + f32 eyeY; + f32 eyeZ; + + OPEN_DISPS(this->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + + eyeX = 1000.0f * Math_CosS(sFileSelectSkyboxRotation) - 1000.0f * Math_SinS(sFileSelectSkyboxRotation); + eyeY = -700.0f; + eyeZ = 1000.0f * Math_SinS(sFileSelectSkyboxRotation) + 1000.0f * Math_CosS(sFileSelectSkyboxRotation); + + FileSelect_SetView(this, eyeX, eyeY, eyeZ); + Skybox_Draw(&this->skyboxCtx, this->state.gfxCtx, SKYBOX_NORMAL_SKY, this->envCtx.skyboxBlend, eyeX, eyeY, eyeZ); + + gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_NONE); + + sFileSelectSkyboxRotation += -0xA; + + CLOSE_DISPS(this->state.gfxCtx); +} + +void (*gFileSelectDrawFuncs[])(GameState*) = { + FileSelect_InitModeDraw, // FS_MENU_MODE_INIT + FileSelect_ConfigModeDraw, // FS_MENU_MODE_CONFIG + FileSelect_SelectModeDraw, // FS_MENU_MODE_SELECT +}; +void (*gFileSelectUpdateFuncs[])(GameState*) = { + FileSelect_InitModeUpdate, // FS_MENU_MODE_INIT + FileSelect_ConfigModeUpdate, // FS_MENU_MODE_CONFIG + FileSelect_SelectModeUpdate, // FS_MENU_MODE_SELECT +}; + +TexturePtr D_808147B4[] = { gFileSelPleaseWaitENGTex, gFileSelDecideCancelENGTex, gFileSelDecideSaveENGTex }; +s16 D_808147C0[] = { 144, 144, 152 }; +s16 D_808147C8[] = { 90, 90, 86 }; + +void FileSelect_Main(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + Input* input = CONTROLLER1(&this->state); + s32 texIndex; + s32 pad; + + func_8012CF0C(this->state.gfxCtx, 0, 1, 0, 0, 0); + + OPEN_DISPS(this->state.gfxCtx); + + gSPSegment(POLY_OPA_DISP++, 0x01, this->staticSegment); + gSPSegment(POLY_OPA_DISP++, 0x02, this->parameterSegment); + gSPSegment(POLY_OPA_DISP++, 0x06, this->titleSegment); + + this->stickAdjX = input->rel.stick_x; + this->stickAdjY = input->rel.stick_y; + + if (this->stickAdjX < -30) { + if (this->stickXDir == -1) { + this->inputTimerX--; + if (this->inputTimerX < 0) { + this->inputTimerX = 2; + } else { + this->stickAdjX = 0; + } + } else { + this->inputTimerX = 10; + this->stickXDir = -1; + } + } else if (this->stickAdjX > 30) { + if (this->stickXDir == 1) { + this->inputTimerX--; + if (this->inputTimerX < 0) { + this->inputTimerX = 2; + } else { + this->stickAdjX = 0; + } + } else { + this->inputTimerX = 10; + this->stickXDir = 1; + } + } else { + this->stickXDir = 0; + } + + if (this->stickAdjY < -30) { + if (this->stickYDir == -1) { + this->inputTimerY--; + if (this->inputTimerY < 0) { + this->inputTimerY = 2; + } else { + this->stickAdjY = 0; + } + } else { + this->inputTimerY = 10; + this->stickYDir = -1; + } + } else if (this->stickAdjY > 30) { + if (this->stickYDir == 1) { + this->inputTimerY--; + if (this->inputTimerY < 0) { + this->inputTimerY = 2; + } else { + this->stickAdjY = 0; + } + } else { + this->inputTimerY = 10; + this->stickYDir = 1; + } + } else { + this->stickYDir = 0; + } + + this->emptyFileTextAlpha = 0; + + FileSelect_PulsateCursor(&this->state); + gFileSelectUpdateFuncs[this->menuMode](&this->state); + FileSelect_UpdateAndDrawSkybox(this); + gFileSelectDrawFuncs[this->menuMode](&this->state); + + Gfx_SetupDL39_Opa(this->state.gfxCtx); + + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 100, 255, 255, this->controlsAlpha); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + + if (this->sramCtx.status > 0) { + texIndex = 0; + } else if ((this->configMode >= CM_MAIN_TO_OPTIONS) && (this->configMode <= CM_OPTIONS_TO_MAIN)) { + texIndex = 2; + } else { + texIndex = 1; + } + + gDPLoadTextureBlock(POLY_OPA_DISP++, D_808147B4[texIndex], G_IM_FMT_IA, G_IM_SIZ_8b, D_808147C0[texIndex], 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOLOD); + + gSPTextureRectangle(POLY_OPA_DISP++, D_808147C8[texIndex] << 2, 204 << 2, + (D_808147C8[texIndex] + D_808147C0[texIndex]) << 2, (204 + 16) << 2, G_TX_RENDERTILE, 0, 0, + 1 << 10, 1 << 10); + + gDPPipeSync(POLY_OPA_DISP++); + gSPDisplayList(POLY_OPA_DISP++, sScreenFillSetupDL); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 0, 0, this->screenFillAlpha); + gSPDisplayList(POLY_OPA_DISP++, D_0E000000.fillRect); + + CLOSE_DISPS(this->state.gfxCtx); +} + +void FileSelect_InitContext(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + EnvironmentContext* envCtx = &this->envCtx; + + Sram_Alloc(&this->state, &this->sramCtx); + func_801457CC(&this->state, &this->sramCtx); + + this->menuMode = FS_MENU_MODE_INIT; + + this->buttonIndex = this->selectMode = this->selectedFileIndex = this->copyDestFileIndex = + this->confirmButtonIndex = 0; + + this->confirmButtonTexIndices[0] = 2; + this->confirmButtonTexIndices[1] = 3; + this->titleLabel = FS_TITLE_SELECT_FILE; + this->nextTitleLabel = FS_TITLE_OPEN_FILE; + + this->screenFillAlpha = 255; + this->highlightPulseDir = 1; + this->unk_244F4 = 0xC; + this->highlightColor[0] = 155; + this->highlightColor[1] = 255; + this->highlightColor[2] = 255; + this->highlightColor[3] = 70; + this->configMode = CM_FADE_IN_START; + this->windowRot = 0.0f; + + this->stickXDir = this->inputTimerX = 0; + this->stickYDir = this->inputTimerY = 0; + + this->kbdX = this->kbdY = this->charIndex = 0; + + this->kbdButton = FS_KBD_BTN_NONE; + + this->windowColor[0] = 100; + this->windowColor[1] = 150; + this->windowColor[2] = 255; + + this->windowAlpha = this->titleAlpha[FS_TITLE_CUR] = this->titleAlpha[FS_TITLE_NEXT] = this->fileButtonAlpha[0] = + this->fileButtonAlpha[1] = this->fileButtonAlpha[2] = this->nameBoxAlpha[0] = this->nameBoxAlpha[1] = + this->nameBoxAlpha[2] = this->nameAlpha[0] = this->nameAlpha[1] = this->nameAlpha[2] = + this->connectorAlpha[0] = this->connectorAlpha[1] = this->connectorAlpha[2] = this->fileInfoAlpha[0] = + this->fileInfoAlpha[1] = this->fileInfoAlpha[2] = this->actionButtonAlpha[FS_BTN_ACTION_COPY] = + this->actionButtonAlpha[FS_BTN_ACTION_ERASE] = this->confirmButtonAlpha[FS_BTN_CONFIRM_YES] = + this->confirmButtonAlpha[FS_BTN_CONFIRM_QUIT] = this->optionButtonAlpha = + this->nameEntryBoxAlpha = this->controlsAlpha = this->emptyFileTextAlpha = 0; + + this->windowPosX = 6; + this->actionTimer = 4; + this->warningLabel = FS_WARNING_NONE; + + this->warningButtonIndex = this->buttonYOffsets[0] = this->buttonYOffsets[1] = this->buttonYOffsets[2] = + this->buttonYOffsets[3] = this->buttonYOffsets[4] = this->buttonYOffsets[5] = this->fileNamesY[0] = + this->fileNamesY[1] = this->fileNamesY[2] = 0; + + this->unk_2451E[0] = 0; + this->unk_2451E[1] = 3; + this->unk_2451E[2] = 6; + this->unk_2451E[3] = 8; + this->unk_2451E[4] = 10; + this->highlightTimer = 20; + + ShrinkWindow_Letterbox_SetSizeTarget(0); + + gSaveContext.skyboxTime = 0; + gSaveContext.save.time = CLOCK_TIME(0, 0); + + Skybox_Init(&this->state, &this->skyboxCtx, 1); + R_TIME_SPEED = 10; + + envCtx->changeSkyboxState = CHANGE_SKYBOX_INACTIVE; + envCtx->changeSkyboxTimer = 0; + envCtx->changeLightEnabled = false; + envCtx->changeLightTimer = 0; + envCtx->skyboxDmaState = 0; + envCtx->skybox1Index = 99; + envCtx->skybox2Index = 99; + envCtx->lightConfig = 0; + envCtx->changeLightNextConfig = 0; + envCtx->lightSetting = 0; + envCtx->skyboxConfig = SKYBOX_CONFIG_2; + envCtx->skyboxDisabled = 0; + envCtx->skyboxBlend = 0; + envCtx->glareAlpha = 0.0f; + envCtx->lensFlareAlphaScale = 0.0f; + + gSaveContext.buttonStatus[EQUIP_SLOT_B] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_ENABLED; +} + +void FileSelect_Destroy(GameState* this) { + ShrinkWindow_Destroy(); +} + +void FileSelect_Init(GameState* thisx) { + s32 pad; + FileSelectState* this = (FileSelectState*)thisx; + size_t size; + + GameState_SetFramerateDivisor(&this->state, 1); + Matrix_Init(&this->state); + ShrinkWindow_Init(); + View_Init(&this->view, this->state.gfxCtx); + this->state.main = FileSelect_Main; + this->state.destroy = FileSelect_Destroy; + FileSelect_InitContext(&this->state); + Font_LoadOrderedFont(&this->font); + + size = SEGMENT_ROM_SIZE(title_static); + this->staticSegment = THA_AllocTailAlign16(&this->state.tha, size); + DmaMgr_RequestSync(this->staticSegment, SEGMENT_ROM_START(title_static), size); + + size = SEGMENT_ROM_SIZE(parameter_static); + this->parameterSegment = THA_AllocTailAlign16(&this->state.tha, size); + DmaMgr_RequestSync(this->parameterSegment, SEGMENT_ROM_START(parameter_static), size); + + size = gObjectTable[OBJECT_MAG].vromEnd - gObjectTable[OBJECT_MAG].vromStart; + this->titleSegment = THA_AllocTailAlign16(&this->state.tha, size); + DmaMgr_RequestSync(this->titleSegment, gObjectTable[OBJECT_MAG].vromStart, size); + + Audio_SetSpec(0xA); + // Setting ioData to 1 and writing it to ioPort 7 will skip the harp intro + Audio_PlaySequenceWithSeqPlayerIO(SEQ_PLAYER_BGM_MAIN, NA_BGM_FILE_SELECT, 0, 7, 1); +} diff --git a/src/overlays/gamestates/ovl_file_choose/z_file_nameset_JPN.c b/src/overlays/gamestates/ovl_file_choose/z_file_nameset_JPN.c new file mode 100644 index 000000000..870efe2c8 --- /dev/null +++ b/src/overlays/gamestates/ovl_file_choose/z_file_nameset_JPN.c @@ -0,0 +1,1060 @@ +/* + * File: z_file_nameset_NES.c + * Overlay: ovl_file_choose + * Description: Entering name on a new file, selecting options from the options menu + */ + +#include "z_file_select.h" +#include "z64rumble.h" +#include "assets/misc/title_static/title_static.h" +#include "assets/overlays/ovl_file_choose/ovl_file_choose.h" + +void FileSelect_DrawTexQuadI4(GraphicsContext* gfxCtx, TexturePtr texture, s16 point) { + OPEN_DISPS(gfxCtx); + + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, texture, G_IM_FMT_I, 16, 16, 0, G_TX_NOMIRROR | G_TX_CLAMP, + G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, point, point + 2, point + 3, point + 1, 0); + + CLOSE_DISPS(gfxCtx); +} + +void FileSelect_DrawMultiTexQuadI4(GraphicsContext* gfxCtx, TexturePtr texture1, TexturePtr texture2, s16 point) { + OPEN_DISPS(gfxCtx); + + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, texture1, G_IM_FMT_I, 16, 16, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPLoadMultiBlock_4b(POLY_OPA_DISP++, texture2, 0x0080, 1, G_IM_FMT_I, 16, 16, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, point, point + 2, point + 3, point + 1, 0); + + CLOSE_DISPS(gfxCtx); +} + +s16 D_80814280[] = { + 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 0, 1, 1, 2, 1, 1, 4, 2, 2, 2, 1, 1, 0, 2, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 2, 2, 2, 2, 2, 3, 2, 2, 4, 3, 2, 4, 1, 2, 2, 1, 1, 2, 2, 3, 2, 2, 0, 2, 2, 2, 0, 3, 1, 0, +}; + +s16 D_80814304[] = { + 1, 2, 0, 1, 1, 2, 1, 1, 4, 2, 2, 2, 1, 1, 0, 2, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, + 2, 2, 4, 3, 2, 4, 1, 2, 2, 1, 1, 2, 2, 3, 2, 2, 0, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, +}; + +s16 D_80814384[] = { + 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +s16 D_80814404[] = { + -94, -96, -48, 0, 32, 64, +}; + +s16 D_80814410[] = { + 56, 44, 44, 28, 28, 44, +}; + +s16 D_8081441C[] = { + 72, -48, -48, -48, -48, -48, +}; + +void FileSelect_SetKeyboardVtx(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + s16 phi_t2; + s16 phi_t0; + s16 phi_t3; + s16 phi_s1; + s16 phi_t1; + s16 phi_s2; + + this->keyboardVtx = GRAPH_ALLOC(this->state.gfxCtx, sizeof(Vtx) * 4 * 5 * 13); + + phi_s1 = 0x26; + + for (phi_t2 = 0, phi_s2 = 0, phi_t3 = 0; phi_s2 < 5; phi_s2++) { + phi_t0 = -0x60; + + for (phi_t1 = 0; phi_t1 < 13; phi_t1++, phi_t3 += 4, phi_t2++) { + //! @bug D_80814304 is accessed out of bounds when drawing the empty space character (value of 64). Under + //! normal circumstances it reads a halfword from D_80814384. + this->keyboardVtx[phi_t3].v.ob[0] = this->keyboardVtx[phi_t3 + 2].v.ob[0] = D_80814304[phi_t2] + phi_t0; + + this->keyboardVtx[phi_t3 + 1].v.ob[0] = this->keyboardVtx[phi_t3 + 3].v.ob[0] = + D_80814304[phi_t2] + phi_t0 + 12; + + this->keyboardVtx[phi_t3].v.ob[1] = this->keyboardVtx[phi_t3 + 1].v.ob[1] = phi_s1; + + this->keyboardVtx[phi_t3 + 2].v.ob[1] = this->keyboardVtx[phi_t3 + 3].v.ob[1] = phi_s1 - 12; + + this->keyboardVtx[phi_t3].v.ob[2] = this->keyboardVtx[phi_t3 + 1].v.ob[2] = + this->keyboardVtx[phi_t3 + 2].v.ob[2] = this->keyboardVtx[phi_t3 + 3].v.ob[2] = 0; + + this->keyboardVtx[phi_t3].v.flag = this->keyboardVtx[phi_t3 + 1].v.flag = + this->keyboardVtx[phi_t3 + 2].v.flag = this->keyboardVtx[phi_t3 + 3].v.flag = 0; + + this->keyboardVtx[phi_t3].v.tc[0] = this->keyboardVtx[phi_t3].v.tc[1] = + this->keyboardVtx[phi_t3 + 1].v.tc[1] = this->keyboardVtx[phi_t3 + 2].v.tc[0] = 0; + + this->keyboardVtx[phi_t3 + 1].v.tc[0] = this->keyboardVtx[phi_t3 + 2].v.tc[1] = + this->keyboardVtx[phi_t3 + 3].v.tc[0] = this->keyboardVtx[phi_t3 + 3].v.tc[1] = 16 << 5; + + this->keyboardVtx[phi_t3].v.cn[0] = this->keyboardVtx[phi_t3 + 1].v.cn[0] = + this->keyboardVtx[phi_t3 + 2].v.cn[0] = this->keyboardVtx[phi_t3 + 3].v.cn[0] = + this->keyboardVtx[phi_t3].v.cn[1] = this->keyboardVtx[phi_t3 + 1].v.cn[1] = + this->keyboardVtx[phi_t3 + 2].v.cn[1] = this->keyboardVtx[phi_t3 + 3].v.cn[1] = + this->keyboardVtx[phi_t3].v.cn[2] = this->keyboardVtx[phi_t3 + 1].v.cn[2] = + this->keyboardVtx[phi_t3 + 2].v.cn[2] = this->keyboardVtx[phi_t3 + 3].v.cn[2] = + this->keyboardVtx[phi_t3].v.cn[3] = this->keyboardVtx[phi_t3 + 1].v.cn[3] = + this->keyboardVtx[phi_t3 + 2].v.cn[3] = this->keyboardVtx[phi_t3 + 3].v.cn[3] = + 255; + + phi_t0 += 0x10; + } + + phi_s1 -= 0x10; + } + + this->keyboard2Vtx = GRAPH_ALLOC(this->state.gfxCtx, sizeof(Vtx) * 24); + + for (phi_t1 = 0, phi_t3 = 0; phi_t3 < 6; phi_t3++, phi_t1 += 4) { + + this->keyboard2Vtx[phi_t1 + 0].v.ob[0] = this->keyboard2Vtx[phi_t1 + 2].v.ob[0] = D_80814404[phi_t3] + 1; + + this->keyboard2Vtx[phi_t1 + 1].v.ob[0] = this->keyboard2Vtx[phi_t1 + 3].v.ob[0] = + this->keyboard2Vtx[phi_t1 + 0].v.ob[0] + D_80814410[phi_t3] - 2; + + this->keyboard2Vtx[phi_t1 + 0].v.ob[1] = this->keyboard2Vtx[phi_t1 + 1].v.ob[1] = D_8081441C[phi_t3] - 1; + + this->keyboard2Vtx[phi_t1 + 2].v.ob[1] = this->keyboard2Vtx[phi_t1 + 3].v.ob[1] = + this->keyboard2Vtx[phi_t1 + 0].v.ob[1] - 0xE; + + this->keyboard2Vtx[phi_t1 + 0].v.ob[2] = this->keyboard2Vtx[phi_t1 + 1].v.ob[2] = + this->keyboard2Vtx[phi_t1 + 2].v.ob[2] = this->keyboard2Vtx[phi_t1 + 3].v.ob[2] = 0; + + this->keyboard2Vtx[phi_t1 + 0].v.flag = this->keyboard2Vtx[phi_t1 + 1].v.flag = + this->keyboard2Vtx[phi_t1 + 2].v.flag = this->keyboard2Vtx[phi_t1 + 3].v.flag = 0; + + this->keyboard2Vtx[phi_t1 + 0].v.tc[0] = this->keyboard2Vtx[phi_t1 + 0].v.tc[1] = + this->keyboard2Vtx[phi_t1 + 1].v.tc[1] = this->keyboard2Vtx[phi_t1 + 2].v.tc[0] = 0; + + this->keyboard2Vtx[phi_t1 + 1].v.tc[0] = this->keyboard2Vtx[phi_t1 + 3].v.tc[0] = D_80814410[phi_t3] << 5; + + this->keyboard2Vtx[phi_t1 + 2].v.tc[1] = this->keyboard2Vtx[phi_t1 + 3].v.tc[1] = 16 << 5; + + this->keyboard2Vtx[phi_t1 + 0].v.cn[0] = this->keyboard2Vtx[phi_t1 + 1].v.cn[0] = + this->keyboard2Vtx[phi_t1 + 2].v.cn[0] = this->keyboard2Vtx[phi_t1 + 3].v.cn[0] = + this->keyboard2Vtx[phi_t1 + 0].v.cn[1] = this->keyboard2Vtx[phi_t1 + 1].v.cn[1] = + this->keyboard2Vtx[phi_t1 + 2].v.cn[1] = this->keyboard2Vtx[phi_t1 + 3].v.cn[1] = + this->keyboard2Vtx[phi_t1 + 0].v.cn[2] = this->keyboard2Vtx[phi_t1 + 1].v.cn[2] = + this->keyboard2Vtx[phi_t1 + 2].v.cn[2] = this->keyboard2Vtx[phi_t1 + 3].v.cn[2] = + this->keyboard2Vtx[phi_t1 + 0].v.cn[3] = this->keyboard2Vtx[phi_t1 + 1].v.cn[3] = + this->keyboard2Vtx[phi_t1 + 2].v.cn[3] = this->keyboard2Vtx[phi_t1 + 3].v.cn[3] = + 255; + } +} + +TexturePtr sBackspaceEndTextures[] = { + gFileSelBackspaceButtonTex, + gFileSelENDButtonENGTex, +}; + +u16 sBackspaceEndWidths[] = { 28, 44 }; + +s16 D_80814434[] = { + -30, -16, -6, 4, 14, 24, 34, 44, 54, -16, -16, 0, +}; + +s16 D_8081444C[] = { + 72, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, +}; + +/** + * Set vertices used by all elements of the name entry screen that are NOT the keyboard. + * This includes the cursor highlight, the name entry plate and characters, and the buttons. + */ +void FileSelect_SetNameEntryVtx(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + Font* font = &this->font; + u8 temp; + s16 var_s0; + s16 var_t1; + s16 sp108; + + OPEN_DISPS(this->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->titleAlpha[FS_TITLE_CUR]); + + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + gSPVertex(POLY_OPA_DISP++, this->keyboard2Vtx, 24, 0); + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelNameENGTex, G_IM_FMT_IA, G_IM_SIZ_8b, 56, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + gDPPipeSync(POLY_OPA_DISP++); + + for (var_t1 = 0, var_s0 = 0x10; var_t1 < 2; var_t1++, var_s0 += 4) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], 255); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + gDPLoadTextureBlock(POLY_OPA_DISP++, sBackspaceEndTextures[var_t1], G_IM_FMT_IA, G_IM_SIZ_16b, + sBackspaceEndWidths[var_t1], 16, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, var_s0, var_s0 + 2, var_s0 + 3, var_s0 + 1, 0); + } + + this->nameEntryVtx = GRAPH_ALLOC(this->state.gfxCtx, 44 * sizeof(Vtx)); + + for (var_s0 = 0, var_t1 = 0; var_t1 < 44; var_t1 += 4, var_s0++) { + if ((var_s0 > 0) && (var_s0 < 9)) { + temp = this->fileNames[this->buttonIndex][var_s0 - 1]; + + this->nameEntryVtx[var_t1 + 0].v.ob[0] = this->nameEntryVtx[var_t1 + 2].v.ob[0] = + D_80814434[var_s0] + this->nameEntryBoxPosX + D_80814280[temp]; + + this->nameEntryVtx[var_t1 + 1].v.ob[0] = this->nameEntryVtx[var_t1 + 3].v.ob[0] = + this->nameEntryVtx[var_t1 + 0].v.ob[0] + 10; + } else { + this->nameEntryVtx[var_t1 + 0].v.ob[0] = this->nameEntryVtx[var_t1 + 2].v.ob[0] = + D_80814434[var_s0] + this->nameEntryBoxPosX; + + this->nameEntryVtx[var_t1 + 1].v.ob[0] = this->nameEntryVtx[var_t1 + 3].v.ob[0] = + this->nameEntryVtx[var_t1 + 0].v.ob[0] + 10; + } + + this->nameEntryVtx[var_t1 + 0].v.ob[1] = this->nameEntryVtx[var_t1 + 1].v.ob[1] = D_8081444C[var_s0]; + + this->nameEntryVtx[var_t1 + 2].v.ob[1] = this->nameEntryVtx[var_t1 + 3].v.ob[1] = + this->nameEntryVtx[var_t1 + 0].v.ob[1] - 10; + + this->nameEntryVtx[var_t1 + 0].v.ob[2] = this->nameEntryVtx[var_t1 + 1].v.ob[2] = + this->nameEntryVtx[var_t1 + 2].v.ob[2] = this->nameEntryVtx[var_t1 + 3].v.ob[2] = 0; + + this->nameEntryVtx[var_t1 + 0].v.flag = this->nameEntryVtx[var_t1 + 1].v.flag = + this->nameEntryVtx[var_t1 + 2].v.flag = this->nameEntryVtx[var_t1 + 3].v.flag = 0; + + this->nameEntryVtx[var_t1 + 0].v.tc[0] = this->nameEntryVtx[var_t1 + 0].v.tc[1] = + this->nameEntryVtx[var_t1 + 1].v.tc[1] = this->nameEntryVtx[var_t1 + 2].v.tc[0] = 0; + + this->nameEntryVtx[var_t1 + 1].v.tc[0] = this->nameEntryVtx[var_t1 + 2].v.tc[1] = + this->nameEntryVtx[var_t1 + 3].v.tc[0] = this->nameEntryVtx[var_t1 + 3].v.tc[1] = 16 << 5; + + this->nameEntryVtx[var_t1 + 0].v.cn[0] = this->nameEntryVtx[var_t1 + 1].v.cn[0] = + this->nameEntryVtx[var_t1 + 2].v.cn[0] = this->nameEntryVtx[var_t1 + 3].v.cn[0] = + this->nameEntryVtx[var_t1 + 0].v.cn[1] = this->nameEntryVtx[var_t1 + 1].v.cn[1] = + this->nameEntryVtx[var_t1 + 2].v.cn[1] = this->nameEntryVtx[var_t1 + 3].v.cn[1] = + this->nameEntryVtx[var_t1 + 0].v.cn[2] = this->nameEntryVtx[var_t1 + 1].v.cn[2] = + this->nameEntryVtx[var_t1 + 2].v.cn[2] = this->nameEntryVtx[var_t1 + 3].v.cn[2] = + this->nameEntryVtx[var_t1 + 0].v.cn[3] = this->nameEntryVtx[var_t1 + 1].v.cn[3] = + this->nameEntryVtx[var_t1 + 2].v.cn[3] = this->nameEntryVtx[var_t1 + 3].v.cn[3] = + 255; + } + + this->nameEntryVtx[1].v.ob[0] = this->nameEntryVtx[3].v.ob[0] = this->nameEntryVtx[0].v.ob[0] + 0x6C; + this->nameEntryVtx[2].v.ob[1] = this->nameEntryVtx[3].v.ob[1] = this->nameEntryVtx[0].v.ob[1] - 0x10; + this->nameEntryVtx[1].v.tc[0] = this->nameEntryVtx[3].v.tc[0] = 108 << 5; + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->windowColor[0], this->windowColor[1], this->windowColor[2], + this->nameEntryBoxAlpha); + gSPVertex(POLY_OPA_DISP++, this->nameEntryVtx, 4, 0); + + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelFileNameBoxTex, G_IM_FMT_IA, G_IM_SIZ_16b, 108, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, + PRIMITIVE, 0); + gSPVertex(POLY_OPA_DISP++, this->nameEntryVtx + 4, 32, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->nameEntryBoxAlpha); + + for (sp108 = 0, var_s0 = 0; var_s0 < 0x20; var_s0 += 4, sp108++) { + FileSelect_DrawTexQuadI4( + this->state.gfxCtx, font->fontBuf + this->fileNames[this->buttonIndex][sp108] * FONT_CHAR_TEX_SIZE, var_s0); + } + + this->nameEntryVtx[37].v.tc[0] = this->nameEntryVtx[38].v.tc[1] = this->nameEntryVtx[39].v.tc[0] = + this->nameEntryVtx[39].v.tc[1] = this->nameEntryVtx[41].v.tc[0] = this->nameEntryVtx[42].v.tc[1] = + this->nameEntryVtx[43].v.tc[0] = this->nameEntryVtx[43].v.tc[1] = 24 << 5; + + if ((this->kbdButton == FS_KBD_BTN_HIRA) || (this->kbdButton == FS_KBD_BTN_KATA) || + (this->kbdButton == FS_KBD_BTN_END)) { + this->nameEntryVtx[41].v.tc[0] = this->nameEntryVtx[43].v.tc[0] = 56 << 5; + } else if ((this->kbdButton == FS_KBD_BTN_ENG) || (this->kbdButton == FS_KBD_BTN_BACKSPACE)) { + this->nameEntryVtx[41].v.tc[0] = this->nameEntryVtx[43].v.tc[0] = 40 << 5; + } + + CLOSE_DISPS(this->state.gfxCtx); +} + +void FileSelect_DrawKeyboard(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + Font* font = &this->font; + s16 i; + s16 tmp; + s16 vtx; + + OPEN_DISPS(this->state.gfxCtx); + + Gfx_SetupDL42_Opa(this->state.gfxCtx); + gDPSetCycleType(POLY_OPA_DISP++, G_CYC_2CYCLE); + gDPSetRenderMode(POLY_OPA_DISP++, G_RM_PASS, G_RM_XLU_SURF2); + gDPSetCombineLERP(POLY_OPA_DISP++, 0, 0, 0, PRIMITIVE, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, 0, 0, 0, COMBINED, 0, + 0, 0, COMBINED); + gDPSetPrimColor(POLY_OPA_DISP++, 0, this->charBgAlpha, 255, 255, 255, 255); + + for (i = 0, vtx = 0; vtx < 0x100; vtx += 32) { + gSPVertex(POLY_OPA_DISP++, &this->keyboardVtx[vtx], 32, 0); + + for (tmp = 0; tmp < 32; i++, tmp += 4) { + FileSelect_DrawTexQuadI4(this->state.gfxCtx, font->fontBuf + D_808141F0[i] * FONT_CHAR_TEX_SIZE, tmp); + } + } + + gSPVertex(POLY_OPA_DISP++, &this->keyboardVtx[0x100], 4, 0); + FileSelect_DrawTexQuadI4(this->state.gfxCtx, font->fontBuf + D_808141F0[i] * FONT_CHAR_TEX_SIZE, 0); + + CLOSE_DISPS(this->state.gfxCtx); +} + +void FileSelect_DrawNameEntry(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + SramContext* sramCtx = &this->sramCtx; + Font* font = &this->font; + Input* input = CONTROLLER1(&this->state); + s16 i; + s16 tmp; + u16 time; + s16 validName; + + OPEN_DISPS(this->state.gfxCtx); + + FileSelect_SetKeyboardVtx(&this->state); + FileSelect_SetNameEntryVtx(&this->state); + FileSelect_PulsateCursor(&this->state); + + tmp = (this->newFileNameCharCount * 4) + 4; + this->nameEntryVtx[36].v.ob[0] = this->nameEntryVtx[38].v.ob[0] = this->nameEntryVtx[tmp].v.ob[0] - 6; + this->nameEntryVtx[37].v.ob[0] = this->nameEntryVtx[39].v.ob[0] = this->nameEntryVtx[36].v.ob[0] + 24; + this->nameEntryVtx[36].v.ob[1] = this->nameEntryVtx[37].v.ob[1] = this->nameEntryVtx[tmp].v.ob[1] + 7; + this->nameEntryVtx[38].v.ob[1] = this->nameEntryVtx[39].v.ob[1] = this->nameEntryVtx[36].v.ob[1] - 24; + + if ((this->kbdButton == FS_KBD_BTN_HIRA) || (this->kbdButton == FS_KBD_BTN_KATA) || + (this->kbdButton == FS_KBD_BTN_END)) { + this->nameEntryVtx[40].v.ob[0] = this->nameEntryVtx[42].v.ob[0] = + this->keyboard2Vtx[(this->kbdX + 1) * 4].v.ob[0] - 4; + this->nameEntryVtx[41].v.ob[0] = this->nameEntryVtx[43].v.ob[0] = this->nameEntryVtx[40].v.ob[0] + 52; + this->nameEntryVtx[40].v.ob[1] = this->nameEntryVtx[41].v.ob[1] = + this->keyboard2Vtx[(this->kbdX + 1) * 4].v.ob[1] + 4; + } else if ((this->kbdButton == FS_KBD_BTN_ENG) || (this->kbdButton == FS_KBD_BTN_BACKSPACE)) { + this->nameEntryVtx[40].v.ob[0] = this->nameEntryVtx[42].v.ob[0] = + this->keyboard2Vtx[(this->kbdX + 1) * 4].v.ob[0] - 4; + this->nameEntryVtx[41].v.ob[0] = this->nameEntryVtx[43].v.ob[0] = this->nameEntryVtx[40].v.ob[0] + 40; + this->nameEntryVtx[40].v.ob[1] = this->nameEntryVtx[41].v.ob[1] = + this->keyboard2Vtx[(this->kbdX + 1) * 4].v.ob[1] + 4; + } else { + this->nameEntryVtx[40].v.ob[0] = this->nameEntryVtx[42].v.ob[0] = + this->keyboardVtx[this->charIndex * 4].v.ob[0] - D_80814304[this->charIndex] - 6; + this->nameEntryVtx[41].v.ob[0] = this->nameEntryVtx[43].v.ob[0] = this->nameEntryVtx[40].v.ob[0] + 24; + this->nameEntryVtx[40].v.ob[1] = this->nameEntryVtx[41].v.ob[1] = + this->keyboardVtx[this->charIndex * 4].v.ob[1] + 6; + } + + this->nameEntryVtx[42].v.ob[1] = this->nameEntryVtx[43].v.ob[1] = this->nameEntryVtx[40].v.ob[1] - 24; + + gSPVertex(POLY_OPA_DISP++, &this->nameEntryVtx[36], 8, 0); + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, TEXEL0, 0, + PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, this->highlightColor[0], this->highlightColor[1], this->highlightColor[2], + this->highlightColor[3]); + + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelCharHighlightTex, G_IM_FMT_I, G_IM_SIZ_8b, 24, 24, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + + if ((this->kbdButton == FS_KBD_BTN_HIRA) || (this->kbdButton == FS_KBD_BTN_KATA) || + (this->kbdButton == FS_KBD_BTN_END)) { + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelMediumButtonHighlightTex, G_IM_FMT_I, G_IM_SIZ_8b, 56, 24, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + } else if ((this->kbdButton == FS_KBD_BTN_ENG) || (this->kbdButton == FS_KBD_BTN_BACKSPACE)) { + gDPLoadTextureBlock(POLY_OPA_DISP++, gFileSelSmallButtonHighlightTex, G_IM_FMT_I, G_IM_SIZ_8b, 40, 24, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + } + + gSP1Quadrangle(POLY_OPA_DISP++, 4, 6, 7, 5, 0); + + FileSelect_DrawKeyboard(&this->state); + gDPPipeSync(POLY_OPA_DISP++); + Gfx_SetupDL42_Opa(this->state.gfxCtx); + + gDPSetCombineLERP(POLY_OPA_DISP++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, + PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + + if (this->configMode == CM_NAME_ENTRY) { + if (CHECK_BTN_ALL(input->press.button, BTN_START)) { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + // place cursor on END button + this->kbdY = 5; + this->kbdX = 4; + } else if (CHECK_BTN_ALL(input->press.button, BTN_B)) { + if ((this->newFileNameCharCount == 7) && (this->fileNames[this->buttonIndex][7] != 0x3E)) { + + for (i = this->newFileNameCharCount; i < 7; i++) { + this->fileNames[this->buttonIndex][i] = this->fileNames[this->buttonIndex][i + 1]; + } + + this->fileNames[this->buttonIndex][i] = 0x3E; + Audio_PlaySfx(NA_SE_SY_FSEL_CLOSE); + } else { + this->newFileNameCharCount--; + + if (this->newFileNameCharCount < 0) { + this->newFileNameCharCount = 0; + this->configMode = CM_NAME_ENTRY_TO_MAIN; + Audio_PlaySfx(NA_SE_SY_FSEL_CLOSE); + } else { + for (i = this->newFileNameCharCount; i < 7; i++) { + this->fileNames[this->buttonIndex][i] = this->fileNames[this->buttonIndex][i + 1]; + } + + this->fileNames[this->buttonIndex][i] = 0x3E; + Audio_PlaySfx(NA_SE_SY_FSEL_CLOSE); + } + } + } else { + if (this->charPage <= FS_CHAR_PAGE_ENG) { + if (this->kbdY != 5) { + // draw the character the cursor is hovering over in yellow + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 0, 255); + + //! @bug D_80814384 is accessed out of bounds when drawing the empty space character (value of 64). + //! Under normal circumstances it reads a halfword from D_80814404. + this->keyboardVtx[(this->charIndex * 4) + 0].v.ob[0] = + this->keyboardVtx[(this->charIndex * 4) + 2].v.ob[0] = + this->keyboardVtx[(this->charIndex * 4) + 0].v.ob[0] + D_80814384[this->charIndex] - 2; + + this->keyboardVtx[(this->charIndex * 4) + 1].v.ob[0] = + this->keyboardVtx[(this->charIndex * 4) + 3].v.ob[0] = + this->keyboardVtx[(this->charIndex * 4) + 0].v.ob[0] + 0x10; + + this->keyboardVtx[(this->charIndex * 4) + 0].v.ob[1] = + this->keyboardVtx[(this->charIndex * 4) + 1].v.ob[1] = + this->keyboardVtx[(this->charIndex * 4) + 0].v.ob[1] + 2; + + this->keyboardVtx[(this->charIndex * 4) + 2].v.ob[1] = + this->keyboardVtx[(this->charIndex * 4) + 3].v.ob[1] = + this->keyboardVtx[(this->charIndex * 4) + 0].v.ob[1] - 0x10; + + gSPVertex(POLY_OPA_DISP++, &this->keyboardVtx[this->charIndex * 4], 4, 0); + + FileSelect_DrawTexQuadI4(this->state.gfxCtx, + font->fontBuf + D_808141F0[this->charIndex] * FONT_CHAR_TEX_SIZE, 0); + + if (CHECK_BTN_ALL(input->press.button, BTN_A)) { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_S); + this->fileNames[this->buttonIndex][this->newFileNameCharCount] = D_808141F0[this->charIndex]; + + this->newFileNameCharCount++; + + if (this->newFileNameCharCount > 7) { + this->newFileNameCharCount = 7; + } + } + } else if (CHECK_BTN_ALL(input->press.button, BTN_A)) { + if (this->charPage != this->kbdButton) { + if (this->kbdButton == FS_KBD_BTN_BACKSPACE) { + if ((this->newFileNameCharCount == 7) && (this->fileNames[this->buttonIndex][7] != 0x3E)) { + + for (i = this->newFileNameCharCount; i < 7; i++) { + this->fileNames[this->buttonIndex][i] = this->fileNames[this->buttonIndex][i + 1]; + } + + this->fileNames[this->buttonIndex][i] = 0x3E; + Audio_PlaySfx(NA_SE_SY_FSEL_CLOSE); + } else { + this->newFileNameCharCount--; + + if (this->newFileNameCharCount < 0) { + this->newFileNameCharCount = 0; + } + + for (i = this->newFileNameCharCount; i < 7; i++) { + this->fileNames[this->buttonIndex][i] = this->fileNames[this->buttonIndex][i + 1]; + } + + this->fileNames[this->buttonIndex][i] = 0x3E; + Audio_PlaySfx(NA_SE_SY_FSEL_CLOSE); + } + } else if (this->kbdButton == FS_KBD_BTN_END) { + validName = false; + + for (i = 0; i < 8; i++) { + if (this->fileNames[this->buttonIndex][i] != 0x3E) { + validName = true; + break; + } + } + + if (validName) { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + gSaveContext.fileNum = this->buttonIndex; + time = CURRENT_TIME; + Sram_InitSave(this, sramCtx); + gSaveContext.save.time = time; + + if (!gSaveContext.flashSaveAvailable) { + this->configMode = CM_NAME_ENTRY_TO_MAIN; + } else { + Sram_SetFlashPagesDefault(sramCtx, gFlashSaveStartPages[this->buttonIndex * 2], + gFlashSpecialSaveNumPages[this->buttonIndex * 2]); + Sram_StartWriteToFlashDefault(sramCtx); + this->configMode = CM_NAME_ENTRY_WAIT_FOR_FLASH_SAVE; + } + + this->nameBoxAlpha[this->buttonIndex] = this->nameAlpha[this->buttonIndex] = 200; + this->connectorAlpha[this->buttonIndex] = 255; + Rumble_Request(300.0f, 180, 20, 100); + } else { + Audio_PlaySfx(NA_SE_SY_FSEL_ERROR); + } + } + } + } + + if (CHECK_BTN_ALL(input->press.button, BTN_CRIGHT)) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + this->newFileNameCharCount++; + + if (this->newFileNameCharCount > 7) { + this->newFileNameCharCount = 7; + } + } else if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + this->newFileNameCharCount--; + + if (this->newFileNameCharCount < 0) { + this->newFileNameCharCount = 0; + } + } + } + } + } + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA); + + CLOSE_DISPS(this->state.gfxCtx); +} + +/** + * Fade in the name entry box and slide it to the center of the screen from the right side. + * After the name entry box is in place, init the keyboard/cursor and change modes. + * Update function for `CM_START_NAME_ENTRY` + */ +void FileSelect_StartNameEntry(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->nameEntryBoxAlpha += 25; + + if (this->nameEntryBoxAlpha >= 255) { + this->nameEntryBoxAlpha = 255; + } + + this->nameEntryBoxPosX -= 30; + + if (this->nameEntryBoxPosX <= 0) { + this->nameEntryBoxPosX = 0; + this->nameEntryBoxAlpha = 255; + this->kbdX = 0; + this->kbdY = 0; + this->kbdButton = FS_KBD_BTN_NONE; + this->configMode = CM_NAME_ENTRY; + } +} + +/** + * Update the keyboard cursor and play sound effects at the appropriate times. + * There are many special cases for warping the cursor depending on where + * the cursor currently is. + * Update function for `CM_NAME_ENTRY` + */ +void FileSelect_UpdateKeyboardCursor(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + s16 prevKbdX; + + this->kbdButton = FS_KBD_BTN_NONE; + + if (this->kbdY != 5) { + if (this->stickAdjX < -30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + this->charIndex--; + this->kbdX--; + if (this->kbdX < 0) { + this->kbdX = 12; + this->charIndex = (this->kbdY * 13) + this->kbdX; + } + } else if (this->stickAdjX > 30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + this->charIndex++; + this->kbdX++; + if (this->kbdX > 12) { + this->kbdX = 0; + this->charIndex = (this->kbdY * 13) + this->kbdX; + } + } + } else { + if (this->stickAdjX < -30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + this->kbdX--; + if (this->kbdX < 3) { + this->kbdX = 4; + } + } else if (this->stickAdjX > 30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + this->kbdX++; + if (this->kbdX > 4) { + this->kbdX = 3; + } + } + } + + if (this->stickAdjY > 30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + + this->kbdY--; + + if (this->kbdY < 0) { + // Don't go to bottom row + if (this->kbdX < 8) { + this->kbdY = 4; + this->charIndex = (s32)(this->kbdX + 52); + } else { + this->kbdY = 5; + this->charIndex += 52; + prevKbdX = this->kbdX; + + if (this->kbdX < 10) { + this->kbdX = 3; + } else if (this->kbdX < 13) { + this->kbdX = 4; + } + this->unk_2451E[this->kbdX] = prevKbdX; + } + } else { + this->charIndex -= 13; + + if (this->kbdY == 4) { + this->charIndex = 52; + this->kbdX = this->unk_2451E[this->kbdX]; + this->charIndex += this->kbdX; + } + } + } else if (this->stickAdjY < -30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + this->kbdY++; + + if (this->kbdY > 5) { + this->kbdY = 0; + this->kbdX = this->unk_2451E[this->kbdX]; + this->charIndex = this->kbdX; + } else { + this->charIndex += 13; + + if (this->kbdY == 5) { + if (this->kbdX < 8) { + this->kbdY = 0; + this->charIndex = this->kbdX; + } else { + prevKbdX = this->kbdX; + + if (this->kbdX < 3) { + this->kbdX = 0; + } else if (this->kbdX < 6) { + this->kbdX = 1; + } else if (this->kbdX < 8) { + this->kbdX = 2; + } else if (this->kbdX < 10) { + this->kbdX = 3; + } else if (this->kbdX < 13) { + this->kbdX = 4; + } + this->unk_2451E[this->kbdX] = prevKbdX; + } + } + } + } + if (this->kbdY == 5) { + this->kbdButton = this->kbdX; + } +} + +/** + * Update and wait for the save to flash to complete. + * Update function for `CM_NAME_ENTRY_WAIT_FOR_FLASH_SAVE` + */ +void FileSelect_NameEntryWaitForFlashSave(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + SramContext* sramCtx = &this->sramCtx; + + Sram_UpdateWriteToFlashDefault(sramCtx); + + if (sramCtx->status == 0) { + this->configMode = CM_NAME_ENTRY_TO_MAIN; + } +} + +/** + * This function is mostly a copy paste of `FileSelect_StartNameEntry`. + * The name entry box fades and slides in even though it is not visible. + * After this is complete, change to the options config mode. + * Update function for `CM_START_OPTIONS` + */ +void FileSelect_StartOptions(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + + this->nameEntryBoxAlpha += 25; + + if (this->nameEntryBoxAlpha >= 255) { + this->nameEntryBoxAlpha = 255; + } + + this->nameEntryBoxPosX -= 30; + + if (this->nameEntryBoxPosX <= 0) { + this->nameEntryBoxPosX = 0; + this->nameEntryBoxAlpha = 255; + this->configMode = CM_OPTIONS_MENU; + } +} + +u8 sSelectedSetting; +// bss padding +s32 D_80814E94; +s32 D_80814E98; +s32 D_80814E9C; +s32 D_80814EA0; + +/** + * Update the cursor and appropriate settings for the options menu. + * If the player presses B, write the selected options to the SRAM header + * and set config mode to rotate back to the main menu. + * Update function for `CM_OPTIONS_MENU` + */ +void FileSelect_UpdateOptionsMenu(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + SramContext* sramCtx = &this->sramCtx; + Input* input = CONTROLLER1(&this->state); + + if (CHECK_BTN_ALL(input->press.button, BTN_B)) { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + Sram_WriteSaveOptionsToBuffer(sramCtx); + + if (!gSaveContext.flashSaveAvailable) { + this->configMode = CM_OPTIONS_TO_MAIN; + } else { + Sram_SetFlashPagesDefault(sramCtx, gFlashSaveStartPages[8], gFlashSpecialSaveNumPages[8]); + Sram_StartWriteToFlashDefault(sramCtx); + this->configMode = CM_OPTIONS_WAIT_FOR_FLASH_SAVE; + } + Audio_SetFileSelectSettings(gSaveContext.options.audioSetting); + return; + } + + if (this->stickAdjX < -30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + + if (sSelectedSetting == FS_SETTING_AUDIO) { + gSaveContext.options.audioSetting--; + + // because audio setting is unsigned, can't check for < 0 + if (gSaveContext.options.audioSetting > 0xF0) { + gSaveContext.options.audioSetting = SAVE_AUDIO_SURROUND; + } + } else { + gSaveContext.options.zTargetSetting ^= 1; + } + } else if (this->stickAdjX > 30) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + + if (sSelectedSetting == FS_SETTING_AUDIO) { + gSaveContext.options.audioSetting++; + if (gSaveContext.options.audioSetting > SAVE_AUDIO_SURROUND) { + gSaveContext.options.audioSetting = SAVE_AUDIO_STEREO; + } + } else { + gSaveContext.options.zTargetSetting ^= 1; + } + } + + if ((this->stickAdjY < -30) || (this->stickAdjY > 30)) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + sSelectedSetting ^= 1; + return; + } + if (CHECK_BTN_ALL(input->press.button, BTN_A)) { + Audio_PlaySfx(NA_SE_SY_FSEL_DECIDE_L); + sSelectedSetting ^= 1; + } +} + +/** + * Update and wait for the save to flash to complete. + * Update function for `CM_OPTIONS_WAIT_FOR_FLASH_SAVE` + */ +void FileSelect_OptionsWaitForFlashSave(GameState* thisx) { + FileSelectState* this = (FileSelectState*)thisx; + SramContext* sramCtx = &this->sramCtx; + + Sram_UpdateWriteToFlashDefault(sramCtx); + + if (sramCtx->status == 0) { + this->configMode = CM_OPTIONS_TO_MAIN; + } +} + +typedef struct { + /* 0x0 */ TexturePtr texture; + /* 0x4 */ u16 width; + /* 0x6 */ u16 height; +} OptionsMenuTextureInfo; // size = 0x8 + +OptionsMenuTextureInfo gOptionsMenuHeaders[] = { + { gFileSelOptionsENGTex, 128, 16 }, { gFileSelSoundENGTex, 64, 16 }, + { gFileSelTargetingENGTex, 64, 16 }, { gFileSelCheckBrightnessENGTex, 96, 16 }, + { gFileSelDolbySurroundLogoENGTex, 48, 17 }, +}; + +OptionsMenuTextureInfo gOptionsMenuSettings[] = { + { gFileSelStereoENGTex, 48, 16 }, { gFileSelMonoENGTex, 48, 16 }, { gFileSelHeadsetENGTex, 48, 16 }, + { gFileSelSurroundENGTex, 48, 16 }, { gFileSelSwitchENGTex, 48, 16 }, { gFileSelHoldENGTex, 48, 16 }, +}; + +void FileSelect_DrawOptionsImpl(GameState* thisx) { + static s16 sCursorPrimRed = 255; + static s16 sCursorPrimGreen = 255; + static s16 sCursorPrimBlue = 255; + static s16 sCursorEnvRed = 0; + static s16 sCursorEnvGreen = 0; + static s16 sCursorEnvBlue = 0; + static s16 sCursorPulseDir = 1; + static s16 sCursorFlashTimer = 20; + static s16 sCursorPrimColors[][3] = { + { 255, 255, 255 }, + { 0, 255, 255 }, + }; + static s16 sCursorEnvColors[][3] = { + { 0, 0, 0 }, + { 0, 150, 150 }, + }; + FileSelectState* this = (FileSelectState*)thisx; + s16 cursorRedStep; + s16 cursorGreenStep; + s16 cursorBlueStep; + s16 i; + s16 j; + s16 vtx; + + OPEN_DISPS(this->state.gfxCtx); + + cursorRedStep = ABS_ALT(sCursorPrimRed - sCursorPrimColors[sCursorPulseDir][0]) / sCursorFlashTimer; + cursorGreenStep = ABS_ALT(sCursorPrimGreen - sCursorPrimColors[sCursorPulseDir][1]) / sCursorFlashTimer; + cursorBlueStep = ABS_ALT(sCursorPrimBlue - sCursorPrimColors[sCursorPulseDir][2]) / sCursorFlashTimer; + + if (sCursorPrimRed >= sCursorPrimColors[sCursorPulseDir][0]) { + sCursorPrimRed -= cursorRedStep; + } else { + sCursorPrimRed += cursorRedStep; + } + + if (sCursorPrimGreen >= sCursorPrimColors[sCursorPulseDir][1]) { + sCursorPrimGreen -= cursorGreenStep; + } else { + sCursorPrimGreen += cursorGreenStep; + } + + if (sCursorPrimBlue >= sCursorPrimColors[sCursorPulseDir][2]) { + sCursorPrimBlue -= cursorBlueStep; + } else { + sCursorPrimBlue += cursorBlueStep; + } + + cursorRedStep = ABS_ALT(sCursorEnvRed - sCursorEnvColors[sCursorPulseDir][0]) / sCursorFlashTimer; + cursorGreenStep = ABS_ALT(sCursorEnvGreen - sCursorEnvColors[sCursorPulseDir][1]) / sCursorFlashTimer; + cursorBlueStep = ABS_ALT(sCursorEnvBlue - sCursorEnvColors[sCursorPulseDir][2]) / sCursorFlashTimer; + + if (sCursorEnvRed >= sCursorEnvColors[sCursorPulseDir][0]) { + sCursorEnvRed -= cursorRedStep; + } else { + sCursorEnvRed += cursorRedStep; + } + + if (sCursorEnvGreen >= sCursorEnvColors[sCursorPulseDir][1]) { + sCursorEnvGreen -= cursorGreenStep; + } else { + sCursorEnvGreen += cursorGreenStep; + } + + if (sCursorEnvBlue >= sCursorEnvColors[sCursorPulseDir][2]) { + sCursorEnvBlue -= cursorBlueStep; + } else { + sCursorEnvBlue += cursorBlueStep; + } + + if (--sCursorFlashTimer == 0) { + sCursorPrimRed = sCursorPrimColors[sCursorPulseDir][0]; + sCursorPrimGreen = sCursorPrimColors[sCursorPulseDir][1]; + sCursorPrimBlue = sCursorPrimColors[sCursorPulseDir][2]; + + sCursorEnvRed = sCursorEnvColors[sCursorPulseDir][0]; + sCursorEnvGreen = sCursorEnvColors[sCursorPulseDir][1]; + sCursorEnvBlue = sCursorEnvColors[sCursorPulseDir][2]; + + sCursorFlashTimer = 20; + + if (++sCursorPulseDir > 1) { + sCursorPulseDir = 0; + } + } + + // blue divider lines + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 255, 255, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0); + + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, gFileSelOptionsDividerTex, G_IM_FMT_IA, 256, 2, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + + Matrix_Push(); + Matrix_Translate(0.0f, 0.1f, 0.0f, MTXMODE_APPLY); + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, this->state.gfxCtx); + gSPVertex(POLY_OPA_DISP++, gOptionsDividerTopVtx, 4, 0); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + Matrix_Pop(); + + Matrix_Push(); + Matrix_Translate(0.0f, 0.2f, 0.0f, MTXMODE_APPLY); + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, this->state.gfxCtx); + gSPVertex(POLY_OPA_DISP++, gOptionsDividerMiddleVtx, 4, 0); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + Matrix_Pop(); + + Matrix_Push(); + Matrix_Translate(0.0f, 0.4f, 0.0f, MTXMODE_APPLY); + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, this->state.gfxCtx); + gSPVertex(POLY_OPA_DISP++, gOptionsDividerBottomVtx, 4, 0); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + Matrix_Pop(); + + gSPVertex(POLY_OPA_DISP++, D_80813DF0, 32, 0); + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + + for (i = 0, vtx = 0; i < 5; i++, vtx += 4) { + if (i == 4) { + gDPPipeSync(POLY_OPA_DISP++); + if (gSaveContext.options.audioSetting == SAVE_AUDIO_SURROUND) { + gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255); + } else { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 0, 0, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + } + } + + gDPLoadTextureBlock(POLY_OPA_DISP++, gOptionsMenuHeaders[i].texture, G_IM_FMT_IA, G_IM_SIZ_8b, + gOptionsMenuHeaders[i].width, gOptionsMenuHeaders[i].height, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + } + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + gSPVertex(POLY_OPA_DISP++, D_80813F30, 32, 0); + + for (i = 0, vtx = 0; i < 4; i++, vtx += 4) { + gDPPipeSync(POLY_OPA_DISP++); + if (i == gSaveContext.options.audioSetting) { + if (sSelectedSetting == FS_SETTING_AUDIO) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, sCursorPrimRed, sCursorPrimGreen, sCursorPrimBlue, + this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, sCursorEnvRed, sCursorEnvGreen, sCursorEnvBlue, 255); + } else { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + } + } else { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 120, 120, 120, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + } + + gDPLoadTextureBlock(POLY_OPA_DISP++, gOptionsMenuSettings[i].texture, G_IM_FMT_IA, G_IM_SIZ_8b, + gOptionsMenuSettings[i].width, gOptionsMenuHeaders[i].height, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + } + + for (; i < 6; i++, vtx += 4) { + gDPPipeSync(POLY_OPA_DISP++); + + if (i == (gSaveContext.options.zTargetSetting + 4)) { + if (sSelectedSetting == FS_SETTING_ZTARGET) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, sCursorPrimRed, sCursorPrimGreen, sCursorPrimBlue, + this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, sCursorEnvRed, sCursorEnvGreen, sCursorEnvBlue, 255); + } else { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + } + } else { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 120, 120, 120, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + } + + //! @bug the gOptionsMenuHeaders usage here will produce an OoB read for i == 5. It reads the first element of + //! `gOptionsMenuSettings` + gDPLoadTextureBlock(POLY_OPA_DISP++, gOptionsMenuSettings[i].texture, G_IM_FMT_IA, G_IM_SIZ_8b, + gOptionsMenuSettings[i].width, gOptionsMenuHeaders[i].height, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + } + + gDPPipeSync(POLY_OPA_DISP++); + + // check brightness bars + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, gFileSelBrightnessCheckTex, G_IM_FMT_IA, 96, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 55, 55, 55, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 40, 40, 40, 255); + gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + + vtx += 4; + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 30, 30, 30, this->titleAlpha[FS_TITLE_CUR]); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + gSP1Quadrangle(POLY_OPA_DISP++, vtx, vtx + 2, vtx + 3, vtx + 1, 0); + + CLOSE_DISPS(this->state.gfxCtx); +} + +void FileSelect_DrawOptions(GameState* thisx) { + FileSelect_DrawOptionsImpl(thisx); +} diff --git a/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_JPN.c b/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_JPN.c new file mode 100644 index 000000000..e629ceeb6 --- /dev/null +++ b/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_JPN.c @@ -0,0 +1,3746 @@ +/* + * File: z_kaleido_scope_NES.c + * Overlay: ovl_kaleido_scope + * Description: Pause Menu + */ + +#include "z_kaleido_scope.h" + +#include "sys_cmpdma.h" +#include "z64map.h" +#include "z64skybox.h" +#include "z64view.h" + +#include "overlays/gamestates/ovl_opening/z_opening.h" + +#include "assets/archives/icon_item_static/icon_item_static_yar.h" +#include "assets/interface/icon_item_gameover_static/icon_item_gameover_static.h" +#include "assets/interface/icon_item_jpn_static/icon_item_jpn_static.h" +#include "assets/interface/icon_item_vtx_static/icon_item_vtx_static.h" + +// Page Textures (Background of Page): +// Broken up into multiple textures. +// Numbered by column/row. +TexturePtr sMaskPageBgTextures[] = { + // Column 0 + gPauseMasks00Tex, + gPauseMasks01Tex, + gPauseMasks02Tex, + gPauseMasks03Tex, + gPauseMasks04Tex, + // Column 1 + gPauseMasks10ENGTex, + gPauseMasks11Tex, + gPauseMasks12Tex, + gPauseMasks13Tex, + gPauseMasks14Tex, + // Column 2 + gPauseMasks20Tex, + gPauseMasks21Tex, + gPauseMasks22Tex, + gPauseMasks23Tex, + gPauseMasks24Tex, +}; +TexturePtr sItemPageBgTextures[] = { + // Column 0 + gPauseSelectItem00ENGTex, + gPauseSelectItem01Tex, + gPauseSelectItem02Tex, + gPauseSelectItem03Tex, + gPauseSelectItem04Tex, + // Column 1 + gPauseSelectItem10ENGTex, + gPauseSelectItem11Tex, + gPauseSelectItem12Tex, + gPauseSelectItem13Tex, + gPauseSelectItem14Tex, + // Column 2 + gPauseSelectItem20ENGTex, + gPauseSelectItem21Tex, + gPauseSelectItem22Tex, + gPauseSelectItem23Tex, + gPauseSelectItem24Tex, +}; +TexturePtr sMapPageBgTextures[] = { + // Column 0 + gPauseMap00Tex, + gPauseMap01Tex, + gPauseMap02Tex, + gPauseMap03Tex, + gPauseMap04Tex, + // Column 1 + gPauseMap10ENGTex, + gPauseMap11Tex, + gPauseMap12Tex, + gPauseMap13Tex, + gPauseMap14Tex, + // Column 2 + gPauseMap20Tex, + gPauseMap21Tex, + gPauseMap22Tex, + gPauseMap23Tex, + gPauseMap24Tex, +}; +TexturePtr sQuestPageBgTextures[] = { + // Column 0 + gPauseQuestStatus00ENGTex, + gPauseQuestStatus01Tex, + gPauseQuestStatus02Tex, + gPauseQuestStatus03Tex, + gPauseQuestStatus04Tex, + // Column 1 + gPauseQuestStatus10ENGTex, + gPauseQuestStatus11Tex, + gPauseQuestStatus12Tex, + gPauseQuestStatus13Tex, + gPauseQuestStatus14Tex, + // Column 2 + gPauseQuestStatus20ENGTex, + gPauseQuestStatus21Tex, + gPauseQuestStatus22Tex, + gPauseQuestStatus23Tex, + gPauseQuestStatus24Tex, +}; + +s16 gVtxPageMapWorldQuadsWidth[VTX_PAGE_MAP_WORLD_QUADS] = { + 80, // mapPageVtx[60] clouds Clock Town 1 + 64, // mapPageVtx[64] clouds Clock Town 2 + 64, // mapPageVtx[68] clouds Woodfall 1 + 64, // mapPageVtx[72] clouds Woodfall 2 + 16, // mapPageVtx[76] clouds Woodfall 3 + 64, // mapPageVtx[80] clouds Snowhead 1 + 112, // mapPageVtx[84] clouds Snowhead 2 + 112, // mapPageVtx[88] clouds Snowhead 3 + 48, // mapPageVtx[92] clouds Romani Ranch + 64, // mapPageVtx[96] clouds Great Bay 1 + 64, // mapPageVtx[100] clouds Great Bay 2 + 64, // mapPageVtx[104] clouds Great Bay 3 + 64, // mapPageVtx[108] clouds Great Bay 4 + 48, // mapPageVtx[112] clouds Stone Tower 1 + 64, // mapPageVtx[116] clouds Stone Tower 2 + 8, // mapPageVtx[120] region Great Bay + 8, // mapPageVtx[124] region Zora Hall + 8, // mapPageVtx[128] region Romani Ranch + 8, // mapPageVtx[132] region Deku Palace + 8, // mapPageVtx[136] region Woodfall + 8, // mapPageVtx[140] region Clock Town + 8, // mapPageVtx[144] region Snowhead + 8, // mapPageVtx[148] region Ikana Graveyard + 8, // mapPageVtx[152] region Ikana Canyon + 8, // mapPageVtx[156] region Goron Village + 8, // mapPageVtx[160] region Stone Tower + 24, // mapPageVtx[164] owl warp Great Bay Coast + 24, // mapPageVtx[168] owl warp Zora Cape + 24, // mapPageVtx[172] owl warp Snowhead + 24, // mapPageVtx[176] owl warp Mountain Village + 24, // mapPageVtx[180] owl warp Clock Town + 24, // mapPageVtx[184] owl warp Milk Road + 24, // mapPageVtx[188] owl warp Woodfall + 24, // mapPageVtx[192] owl warp Southern Swamp + 24, // mapPageVtx[196] owl warp Ikana Canyon + 24, // mapPageVtx[200] owl warp Stone Tower +}; +s16 gVtxPageMapWorldQuadsHeight[VTX_PAGE_MAP_WORLD_QUADS] = { + 40, // mapPageVtx[60] clouds Clock Town 1 + 31, // mapPageVtx[64] clouds Clock Town 2 + 53, // mapPageVtx[68] clouds Woodfall 1 + 53, // mapPageVtx[72] clouds Woodfall 2 + 53, // mapPageVtx[76] clouds Woodfall 3 + 52, // mapPageVtx[80] clouds Snowhead 1 + 35, // mapPageVtx[84] clouds Snowhead 2 + 35, // mapPageVtx[88] clouds Snowhead 3 + 32, // mapPageVtx[92] clouds Romani Ranch + 64, // mapPageVtx[96] clouds Great Bay 1 + 64, // mapPageVtx[100] clouds Great Bay 2 + 64, // mapPageVtx[104] clouds Great Bay 3 + 64, // mapPageVtx[108] clouds Great Bay 4 + 82, // mapPageVtx[112] clouds Stone Tower 1 + 61, // mapPageVtx[116] clouds Stone Tower 2 + 8, // mapPageVtx[120] region Great Bay + 8, // mapPageVtx[124] region Zora Hall + 8, // mapPageVtx[128] region Romani Ranch + 8, // mapPageVtx[132] region Deku Palace + 8, // mapPageVtx[136] region Woodfall + 8, // mapPageVtx[140] region Clock Town + 8, // mapPageVtx[144] region Snowhead + 8, // mapPageVtx[148] region Ikana Graveyard + 8, // mapPageVtx[152] region Ikana Canyon + 8, // mapPageVtx[156] region Goron Village + 8, // mapPageVtx[160] region Stone Tower + 12, // mapPageVtx[164] owl warp Great Bay Coast + 12, // mapPageVtx[168] owl warp Zora Cape + 12, // mapPageVtx[172] owl warp Snowhead + 12, // mapPageVtx[176] owl warp Mountain Village + 12, // mapPageVtx[180] owl warp Clock Town + 12, // mapPageVtx[184] owl warp Milk Road + 12, // mapPageVtx[188] owl warp Woodfall + 12, // mapPageVtx[192] owl warp Southern Swamp + 12, // mapPageVtx[196] owl warp Ikana Canyon + 12, // mapPageVtx[200] owl warp Stone Tower +}; + +s16 sGameOverPrimR = 0; +s16 sGameOverPrimG = 0; +s16 sGameOverPrimB = 0; +s16 sGameOverPrimAlpha = 255; +s16 sCursorPrimR = 0; +s16 sCursorPrimG = 0; +s16 sCursorPrimB = 0; +s16 sCursorEnvR = 0; +s16 sCursorEnvG = 0; +s16 sCursorEnvB = 0; +s16 sGameOverEnvR = 255; +s16 sGameOverEnvG = 0; +s16 sGameOverEnvB = 0; + +s16 sInDungeonScene = false; + +f32 sPageSwitchEyeDx[] = { + -PAUSE_EYE_DIST * (PAUSE_MAP_X - PAUSE_ITEM_X) / 16, // From PAUSE_ITEM to PAUSE_MAP (switching right) + -PAUSE_EYE_DIST*(PAUSE_MASK_X - PAUSE_ITEM_X) / 16, // From PAUSE_ITEM to PAUSE_MASK (switching left) + -PAUSE_EYE_DIST*(PAUSE_QUEST_X - PAUSE_MAP_X) / 16, // From PAUSE_MAP to PAUSE_QUEST (switching right) + -PAUSE_EYE_DIST*(PAUSE_ITEM_X - PAUSE_MAP_X) / 16, // From PAUSE_MAP to PAUSE_ITEM (switching left) + -PAUSE_EYE_DIST*(PAUSE_MASK_X - PAUSE_QUEST_X) / 16, // From PAUSE_QUEST to PAUSE_MASK (switching right) + -PAUSE_EYE_DIST*(PAUSE_MAP_X - PAUSE_QUEST_X) / 16, // From PAUSE_QUEST to PAUSE_MAP (switching left) + -PAUSE_EYE_DIST*(PAUSE_ITEM_X - PAUSE_MASK_X) / 16, // From PAUSE_MASK to PAUSE_ITEM (switching right) + -PAUSE_EYE_DIST*(PAUSE_QUEST_X - PAUSE_MASK_X) / 16, // From PAUSE_MASK to PAUSE_QUEST (switching left) +}; + +f32 sPageSwitchEyeDz[] = { + -PAUSE_EYE_DIST * (PAUSE_MAP_Z - PAUSE_ITEM_Z) / 16, // From PAUSE_ITEM to PAUSE_MAP (switching right) + -PAUSE_EYE_DIST*(PAUSE_MASK_Z - PAUSE_ITEM_Z) / 16, // From PAUSE_ITEM to PAUSE_MASK (switching left) + -PAUSE_EYE_DIST*(PAUSE_QUEST_Z - PAUSE_MAP_Z) / 16, // From PAUSE_MAP to PAUSE_QUEST (switching right) + -PAUSE_EYE_DIST*(PAUSE_ITEM_Z - PAUSE_MAP_Z) / 16, // From PAUSE_MAP to PAUSE_ITEM (switching left) + -PAUSE_EYE_DIST*(PAUSE_MASK_Z - PAUSE_QUEST_Z) / 16, // From PAUSE_QUEST to PAUSE_MASK (switching right) + -PAUSE_EYE_DIST*(PAUSE_MAP_Z - PAUSE_QUEST_Z) / 16, // From PAUSE_QUEST to PAUSE_MAP (switching left) + -PAUSE_EYE_DIST*(PAUSE_ITEM_Z - PAUSE_MASK_Z) / 16, // From PAUSE_MASK to PAUSE_ITEM (switching right) + -PAUSE_EYE_DIST*(PAUSE_QUEST_Z - PAUSE_MASK_Z) / 16, // From PAUSE_MASK to PAUSE_QUEST (switching left) +}; + +u16 sPageSwitchNextPageIndex[] = { + PAUSE_MAP, // From PAUSE_ITEM (switching right) + PAUSE_MASK, // From PAUSE_ITEM (switching left) + PAUSE_QUEST, // From PAUSE_MAP (switching right) + PAUSE_ITEM, // From PAUSE_MAP (switching left) + PAUSE_MASK, // From PAUSE_QUEST (switching right) + PAUSE_MAP, // From PAUSE_QUEST (switching left) + PAUSE_ITEM, // From PAUSE_MASK (switching right) + PAUSE_QUEST, // From PAUSE_MASK (switching left) +}; + +f32 sPauseMenuVerticalOffset = 0.0f; +f32 D_8082B90C = 0.0f; +f32 sPauseCursorLeftMoveOffsetX = 40.0f; +f32 sPauseCursorRightMoveOffsetX = -40.0f; + +s16 sPauseCursorLeftX = 0; +s16 sPauseCursorRightX = 0; + +s16 D_8082B920 = 10; + +s16 sPauseZRCursorColorTimerInits[] = { 20, 4, 20, 10 }; + +// Unused remnant of OoT +u8 gAreaGsFlags[] = { + 0x0F, 0x1F, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x07, 0x07, 0x03, 0x0F, + 0x07, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0x1F, 0x0F, 0x03, 0x0F, 0x00, 0x00, +}; + +// TODO: Also applies to owl warps +s16 sGameOverRectPosY = 66; + +void Kaleido_LoadMapNameStatic(void* segment, u32 texIndex) { + CmpDma_LoadFile(SEGMENT_ROM_START(map_name_static), texIndex, segment, 0x400); +} + +//! note: nothing from `map_name_static` is of size `0xA00` in US 1.0 +void Kaleido_LoadMapNameStaticLarge(void* segment, u32 texIndex) { + CmpDma_LoadFile(SEGMENT_ROM_START(map_name_static), texIndex, segment, 0xA00); +} + +void Kaleido_LoadItemNameStatic(void* segment, u32 texIndex) { + CmpDma_LoadFile(SEGMENT_ROM_START(item_name_static), texIndex, segment, 0x400); +} + +void KaleidoScope_MoveCursorToSpecialPos(PlayState* play, s16 cursorSpecialPos) { + PauseContext* pauseCtx = &play->pauseCtx; + + pauseCtx->cursorSlot[pauseCtx->pageIndex] = 0; + pauseCtx->cursorSpecialPos = cursorSpecialPos; + pauseCtx->pageSwitchInputTimer = 0; + + Audio_PlaySfx(NA_SE_SY_DECIDE); + + gSaveContext.buttonStatus[EQUIP_SLOT_B] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_DISABLED; + + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + Interface_SetHudVisibility(HUD_VISIBILITY_ALL); +} + +void KaleidoScope_MoveCursorFromSpecialPos(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + + pauseCtx->nameDisplayTimer = 0; + pauseCtx->cursorSpecialPos = 0; + + Audio_PlaySfx(NA_SE_SY_CURSOR); + + pauseCtx->cursorShrinkRate = 4.0f; + + gSaveContext.buttonStatus[EQUIP_SLOT_B] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex + 1][1]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex + 1][1]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex + 1][1]; + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_ENABLED; + + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + + Interface_SetHudVisibility(HUD_VISIBILITY_ALL); +} + +void KaleidoScope_DrawTexQuadRGBA32(GraphicsContext* gfxCtx, TexturePtr texture, u16 width, u16 height, u16 point) { + OPEN_DISPS(gfxCtx); + + gDPLoadTextureBlock(POLY_OPA_DISP++, texture, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, height, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSP1Quadrangle(POLY_OPA_DISP++, point, point + 2, point + 3, point + 1, 0); + + CLOSE_DISPS(gfxCtx); +} + +#define SWITCH_PAGE_LEFT 0 +#define SWITCH_PAGE_RIGHT 2 + +void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 direction) { + pauseCtx->cursorSlot[pauseCtx->pageIndex] = 0; + pauseCtx->mainState = PAUSE_MAIN_STATE_SWITCHING_PAGE; + pauseCtx->switchPageTimer = 0; + + if (direction == SWITCH_PAGE_LEFT) { + pauseCtx->nextPageMode = (pauseCtx->pageIndex * 2) + 1; + Audio_PlaySfx(NA_SE_SY_WIN_SCROLL_LEFT); + pauseCtx->cursorSpecialPos = PAUSE_CURSOR_PAGE_RIGHT; + } else { // SWITCH_PAGE_RIGHT + pauseCtx->nextPageMode = pauseCtx->pageIndex * 2; + Audio_PlaySfx(NA_SE_SY_WIN_SCROLL_RIGHT); + pauseCtx->cursorSpecialPos = PAUSE_CURSOR_PAGE_LEFT; + } + + gSaveContext.buttonStatus[EQUIP_SLOT_B] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_DISABLED; + + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + Interface_SetHudVisibility(HUD_VISIBILITY_ALL); +} + +/** + * Process inputs to decide whether to switch pages + */ +void KaleidoScope_HandlePageToggles(PlayState* play, Input* input) { + PauseContext* pauseCtx = &play->pauseCtx; + InterfaceContext* interfaceCtx = &play->interfaceCtx; + + //! FAKE + if (1) {} + + if ((pauseCtx->debugEditor != DEBUG_EDITOR_NONE) || pauseCtx->itemDescriptionOn) { + return; + } + + if (CHECK_BTN_ALL(input->cur.button, BTN_DRIGHT) || CHECK_BTN_ALL(input->press.button, BTN_R)) { + // Switch the page to the right regardless of where the cursor is + if (interfaceCtx->aButtonDoActionDelayed == DO_ACTION_DECIDE) { + Interface_SetAButtonDoAction(play, DO_ACTION_INFO); + } + KaleidoScope_SwitchPage(pauseCtx, SWITCH_PAGE_RIGHT); + return; + } + + if (CHECK_BTN_ALL(input->cur.button, BTN_DLEFT) || CHECK_BTN_ALL(input->press.button, BTN_Z)) { + // Switch the page to the left regardless of where the cursor is + if (interfaceCtx->aButtonDoActionDelayed == DO_ACTION_DECIDE) { + Interface_SetAButtonDoAction(play, DO_ACTION_INFO); + } + KaleidoScope_SwitchPage(pauseCtx, SWITCH_PAGE_LEFT); + return; + } + + if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) { + if (pauseCtx->stickAdjX < -30) { + pauseCtx->pageSwitchInputTimer++; + // Switch the page to the left after a certain number of frames with held input or after a second press + if ((pauseCtx->pageSwitchInputTimer >= 10) || (pauseCtx->pageSwitchInputTimer == 0)) { + KaleidoScope_SwitchPage(pauseCtx, SWITCH_PAGE_LEFT); + } + } else { + // stickAdjX is no longer held, so that the next input to the left will immediately switch pages + pauseCtx->pageSwitchInputTimer = -1; + } + } else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT) { + if (pauseCtx->stickAdjX > 30) { + pauseCtx->pageSwitchInputTimer++; + // Switch the page to the right after a certain number of frames with held input or after a second press + if ((pauseCtx->pageSwitchInputTimer >= 10) || (pauseCtx->pageSwitchInputTimer == 0)) { + KaleidoScope_SwitchPage(pauseCtx, SWITCH_PAGE_RIGHT); + } + } else { + // stickAdjY is no longer held, so that the next input to the right will immediately switch pages + pauseCtx->pageSwitchInputTimer = -1; + } + } +} + +// Draw 15 (PAGE_BG_QUADS) quads with IA8 80x32 textures +Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, TexturePtr* textures) { + s32 i; + s32 j; + + gSPVertex(gfx++, vertices, 8 * 4, 0); + + i = 0; + j = 0; + // Draw first 8/15 background textures + while (j < 32) { + gDPPipeSync(gfx++); + gDPLoadTextureBlock(gfx++, textures[i], G_IM_FMT_IA, G_IM_SIZ_8b, 80, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(gfx++, j, j + 2, j + 3, j + 1, 0); + + j += 4; + i++; + } + + gSPVertex(gfx++, vertices + (8 * 4), 7 * 4, 0); + + j = 0; + // Draw last 7/15 background textures + while (j < 28) { + gDPPipeSync(gfx++); + gDPLoadTextureBlock(gfx++, textures[i], G_IM_FMT_IA, G_IM_SIZ_8b, 80, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(gfx++, j, j + 2, j + 3, j + 1, 0); + + j += 4; + i++; + } + + return gfx; +} + +s16 sCursorPrimColorTarget[][3] = { + { 255, 255, 255 }, { 255, 255, 255 }, { 255, 255, 0 }, { 255, 255, 0 }, { 100, 150, 255 }, { 100, 255, 255 }, +}; + +s16 sCursorEnvColorTarget[][3] = { + { 0, 0, 0 }, { 170, 170, 170 }, { 0, 0, 0 }, { 255, 160, 0 }, { 0, 0, 100 }, { 0, 150, 255 }, +}; + +void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { + static s16 sCursorColorTimer = 10; + static s16 sCursorColorTargetIndex = 0; + PauseContext* pauseCtx = &play->pauseCtx; + s16 stepR; + s16 stepG; + s16 stepB; + + OPEN_DISPS(gfxCtx); + + if (!IS_PAUSE_STATE_GAMEOVER(pauseCtx)) { + if (pauseCtx->state != PAUSE_STATE_SAVEPROMPT) { + + stepR = + ABS_ALT(sCursorPrimR - sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][0]) / + sCursorColorTimer; + stepG = + ABS_ALT(sCursorPrimG - sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][1]) / + sCursorColorTimer; + stepB = + ABS_ALT(sCursorPrimB - sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][2]) / + sCursorColorTimer; + + if (sCursorPrimR >= sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][0]) { + sCursorPrimR -= stepR; + } else { + sCursorPrimR += stepR; + } + + if (sCursorPrimG >= sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][1]) { + sCursorPrimG -= stepG; + } else { + sCursorPrimG += stepG; + } + + if (sCursorPrimB >= sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][2]) { + sCursorPrimB -= stepB; + } else { + sCursorPrimB += stepB; + } + + stepR = + ABS_ALT(sCursorEnvR - sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][0]) / + sCursorColorTimer; + stepG = + ABS_ALT(sCursorEnvG - sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][1]) / + sCursorColorTimer; + stepB = + ABS_ALT(sCursorEnvB - sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][2]) / + sCursorColorTimer; + + if (sCursorEnvR >= sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][0]) { + sCursorEnvR -= stepR; + } else { + sCursorEnvR += stepR; + } + + if (sCursorEnvG >= sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][1]) { + sCursorEnvG -= stepG; + } else { + sCursorEnvG += stepG; + } + + if (sCursorEnvB >= sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][2]) { + sCursorEnvB -= stepB; + } else { + sCursorEnvB += stepB; + } + + sCursorColorTimer--; + if (sCursorColorTimer == 0) { + sCursorPrimR = sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][0]; + sCursorPrimG = sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][1]; + sCursorPrimB = sCursorPrimColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][2]; + sCursorEnvR = sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][0]; + sCursorEnvG = sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][1]; + sCursorEnvB = sCursorEnvColorTarget[pauseCtx->cursorColorSet + sCursorColorTargetIndex][2]; + sCursorColorTargetIndex ^= 1; + sCursorColorTimer = 10; + } + } + + if ((pauseCtx->pageIndex != PAUSE_ITEM) && (pauseCtx->pageIndex != PAUSE_QUEST)) { + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, PRIMITIVE, 0, + TEXEL0, 0, SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + Matrix_RotateYF(0.0f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->itemPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->itemPageVtx, sItemPageBgTextures); + + KaleidoScope_DrawItemSelect(play); + } + + if ((pauseCtx->pageIndex != PAUSE_MAP) && (pauseCtx->pageIndex != PAUSE_MASK)) { + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, PRIMITIVE, 0, + TEXEL0, 0, SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + Matrix_RotateYF(-1.57f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->mapPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->mapPageVtx, sMapPageBgTextures); + + if (sInDungeonScene) { + KaleidoScope_DrawDungeonMap(play); + Gfx_SetupDL42_Opa(gfxCtx); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + MapDisp_DrawDungeonMap(play); + } else { + KaleidoScope_DrawWorldMap(play); + } + } + + if ((pauseCtx->pageIndex != PAUSE_QUEST) && (pauseCtx->pageIndex != PAUSE_ITEM)) { + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetTextureFilter(POLY_OPA_DISP++, G_TF_BILERP); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, PRIMITIVE, 0, + TEXEL0, 0, SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + Matrix_RotateYF(-3.14f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->questPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->questPageVtx, sQuestPageBgTextures); + + KaleidoScope_DrawQuestStatus(play); + } + + if ((pauseCtx->pageIndex != PAUSE_MASK) && (pauseCtx->pageIndex != PAUSE_MAP)) { + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetTextureFilter(POLY_OPA_DISP++, G_TF_BILERP); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, PRIMITIVE, 0, + TEXEL0, 0, SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + Matrix_RotateYF(1.57f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->maskPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->maskPageVtx, sMaskPageBgTextures); + + KaleidoScope_DrawMaskSelect(play); + } + + switch (pauseCtx->pageIndex) { + case PAUSE_ITEM: + if (pauseCtx->mainState <= PAUSE_MAIN_STATE_EQUIP_MASK) { + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, + PRIMITIVE, 0, TEXEL0, 0, SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + Matrix_RotateYF(0.0f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->itemPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + POLY_OPA_DISP = + KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->itemPageVtx, sItemPageBgTextures); + + KaleidoScope_DrawItemSelect(play); + } + break; + + case PAUSE_MAP: + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, PRIMITIVE, + 0, TEXEL0, 0, SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + Matrix_RotateYF(-1.57f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->mapPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->mapPageVtx, sMapPageBgTextures); + + if (sInDungeonScene) { + KaleidoScope_DrawDungeonMap(play); + Gfx_SetupDL42_Opa(gfxCtx); + + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + + MapDisp_DrawDungeonMap(play); + } else { + Matrix_RotateYF(R_PAUSE_WORLD_MAP_YAW / 1000.0f, MTXMODE_NEW); + + if ((pauseCtx->state == PAUSE_STATE_OPENING_3) || (pauseCtx->state == PAUSE_STATE_OWL_WARP_3) || + (pauseCtx->state >= PAUSE_STATE_OWL_WARP_6) || + ((pauseCtx->state == PAUSE_STATE_SAVEPROMPT) && + ((pauseCtx->savePromptState == PAUSE_SAVEPROMPT_STATE_3) || + (pauseCtx->savePromptState == PAUSE_SAVEPROMPT_STATE_7)))) { + Matrix_Translate(0.0f, (R_PAUSE_WORLD_MAP_Y_OFFSET - 8000) / 100.0f, + R_PAUSE_WORLD_MAP_DEPTH / 100.0f, MTXMODE_APPLY); + } else { + Matrix_Translate(0.0f, R_PAUSE_WORLD_MAP_Y_OFFSET / 100.0f, R_PAUSE_WORLD_MAP_DEPTH / 100.0f, + MTXMODE_APPLY); + } + + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->mapPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + KaleidoScope_DrawWorldMap(play); + } + break; + + case PAUSE_QUEST: + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, PRIMITIVE, + 0, TEXEL0, 0, SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + gDPSetTextureFilter(POLY_OPA_DISP++, G_TF_BILERP); + + Matrix_RotateYF(-3.14f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->questPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + POLY_OPA_DISP = + KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->questPageVtx, sQuestPageBgTextures); + + KaleidoScope_DrawQuestStatus(play); + break; + + case PAUSE_MASK: + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, PRIMITIVE, + 0, TEXEL0, 0, SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + Matrix_RotateYF(1.57f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->maskPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, gfxCtx); + + POLY_OPA_DISP = + KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->maskPageVtx, sMaskPageBgTextures); + + KaleidoScope_DrawMaskSelect(play); + break; + } + } + + CLOSE_DISPS(gfxCtx); +} + +TexturePtr D_8082B998[] = { + gPauseToMasksENGTex, + gPauseToSelectItemENGTex, + gPauseToMapENGTex, + gPauseToQuestStatusENGTex, +}; +TexturePtr D_8082B9A8[] = { + gPauseToMapENGTex, + gPauseToQuestStatusENGTex, + gPauseToMasksENGTex, + gPauseToSelectItemENGTex, +}; +void KaleidoScope_DrawInfoPanel(PlayState* play) { + static s16 sPauseZRCursorColorTargets[][4] = { + { 180, 210, 255, 220 }, + { 100, 100, 150, 220 }, + }; + static s16 sPauseZRCursorColorTimer = 20; + static s16 sPauseZRCursorColorIndex = 0; + static s16 sPauseZRCursorRed; + static s16 sPauseZRCursorGreen; + static s16 sPauseZRCursorBlue; + static s16 sPauseZRCursorAlpha; + PauseContext* pauseCtx = &play->pauseCtx; + s16 stepR; + s16 stepG; + s16 stepB; + s16 stepA; + s16 y; + s16 i; + s16 j; + + OPEN_DISPS(play->state.gfxCtx); + + stepR = + ABS_ALT(sPauseZRCursorRed - sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][0]) / sPauseZRCursorColorTimer; + stepG = ABS_ALT(sPauseZRCursorGreen - sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][1]) / + sPauseZRCursorColorTimer; + stepB = ABS_ALT(sPauseZRCursorBlue - sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][2]) / + sPauseZRCursorColorTimer; + stepA = ABS_ALT(sPauseZRCursorAlpha - sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][3]) / + sPauseZRCursorColorTimer; + + if (sPauseZRCursorRed >= sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][0]) { + sPauseZRCursorRed -= stepR; + } else { + sPauseZRCursorRed += stepR; + } + + if (sPauseZRCursorGreen >= sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][1]) { + sPauseZRCursorGreen -= stepG; + } else { + sPauseZRCursorGreen += stepG; + } + + if (sPauseZRCursorBlue >= sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][2]) { + sPauseZRCursorBlue -= stepB; + } else { + sPauseZRCursorBlue += stepB; + } + + if (sPauseZRCursorAlpha >= sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][3]) { + sPauseZRCursorAlpha -= stepA; + } else { + sPauseZRCursorAlpha += stepA; + } + + sPauseZRCursorColorTimer--; + if (sPauseZRCursorColorTimer == 0) { + sPauseZRCursorRed = sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][0]; + sPauseZRCursorGreen = sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][1]; + sPauseZRCursorBlue = sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][2]; + sPauseZRCursorAlpha = sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][3]; + sPauseZRCursorColorTimer = sPauseZRCursorColorTimerInits[0]; + sPauseZRCursorColorIndex ^= 1; + } + + y = pauseCtx->infoPanelOffsetY - 76; + for (j = 0, i = 0; i < 7; i++, j += 4) { + pauseCtx->infoPanelVtx[j + 0].v.ob[0] = pauseCtx->infoPanelVtx[j + 2].v.ob[0] = -72; + + pauseCtx->infoPanelVtx[j + 1].v.ob[0] = pauseCtx->infoPanelVtx[j + 3].v.ob[0] = 0; + + pauseCtx->infoPanelVtx[j + 0].v.ob[1] = pauseCtx->infoPanelVtx[j + 1].v.ob[1] = y; + + pauseCtx->infoPanelVtx[j + 2].v.ob[1] = pauseCtx->infoPanelVtx[j + 3].v.ob[1] = y - 24; + + pauseCtx->infoPanelVtx[j + 0].v.ob[2] = pauseCtx->infoPanelVtx[j + 1].v.ob[2] = + pauseCtx->infoPanelVtx[j + 2].v.ob[2] = pauseCtx->infoPanelVtx[j + 3].v.ob[2] = 0; + + pauseCtx->infoPanelVtx[j + 0].v.flag = pauseCtx->infoPanelVtx[j + 1].v.flag = + pauseCtx->infoPanelVtx[j + 2].v.flag = pauseCtx->infoPanelVtx[j + 3].v.flag = 0; + + pauseCtx->infoPanelVtx[j + 0].v.tc[0] = pauseCtx->infoPanelVtx[j + 0].v.tc[1] = + pauseCtx->infoPanelVtx[j + 1].v.tc[1] = pauseCtx->infoPanelVtx[j + 2].v.tc[0] = 0; + + pauseCtx->infoPanelVtx[j + 1].v.tc[0] = pauseCtx->infoPanelVtx[j + 3].v.tc[0] = 72 * (1 << 5); + + pauseCtx->infoPanelVtx[j + 2].v.tc[1] = pauseCtx->infoPanelVtx[j + 3].v.tc[1] = 24 * (1 << 5); + + pauseCtx->infoPanelVtx[j + 0].v.cn[0] = pauseCtx->infoPanelVtx[j + 2].v.cn[0] = + pauseCtx->infoPanelVtx[j + 0].v.cn[1] = pauseCtx->infoPanelVtx[j + 2].v.cn[1] = + pauseCtx->infoPanelVtx[j + 0].v.cn[2] = pauseCtx->infoPanelVtx[j + 2].v.cn[2] = + pauseCtx->infoPanelVtx[j + 1].v.cn[0] = pauseCtx->infoPanelVtx[j + 3].v.cn[0] = + pauseCtx->infoPanelVtx[j + 1].v.cn[1] = pauseCtx->infoPanelVtx[j + 3].v.cn[1] = + pauseCtx->infoPanelVtx[j + 1].v.cn[2] = pauseCtx->infoPanelVtx[j + 3].v.cn[2] = 200; + + pauseCtx->infoPanelVtx[j + 0].v.cn[3] = pauseCtx->infoPanelVtx[j + 2].v.cn[3] = + pauseCtx->infoPanelVtx[j + 1].v.cn[3] = pauseCtx->infoPanelVtx[j + 3].v.cn[3] = pauseCtx->alpha; + } + + pauseCtx->infoPanelVtx[4].v.ob[0] = pauseCtx->infoPanelVtx[6].v.ob[0] = pauseCtx->infoPanelVtx[0].v.ob[0] + 72; + + pauseCtx->infoPanelVtx[5].v.ob[0] = pauseCtx->infoPanelVtx[7].v.ob[0] = pauseCtx->infoPanelVtx[4].v.ob[0] + 72; + + if ((pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE)) { + pauseCtx->infoPanelVtx[8].v.ob[0] = pauseCtx->infoPanelVtx[10].v.ob[0] = sPauseCursorLeftX; + + pauseCtx->infoPanelVtx[9].v.ob[0] = pauseCtx->infoPanelVtx[11].v.ob[0] = pauseCtx->infoPanelVtx[8].v.ob[0] + 24; + + pauseCtx->infoPanelVtx[8].v.ob[1] = pauseCtx->infoPanelVtx[9].v.ob[1] = D_8082B920; + + pauseCtx->infoPanelVtx[10].v.ob[1] = pauseCtx->infoPanelVtx[11].v.ob[1] = + pauseCtx->infoPanelVtx[8].v.ob[1] - 32; + } else { + pauseCtx->infoPanelVtx[8].v.ob[0] = pauseCtx->infoPanelVtx[10].v.ob[0] = sPauseCursorLeftX + 3; + + pauseCtx->infoPanelVtx[9].v.ob[0] = pauseCtx->infoPanelVtx[11].v.ob[0] = pauseCtx->infoPanelVtx[8].v.ob[0] + 18; + + pauseCtx->infoPanelVtx[8].v.ob[1] = pauseCtx->infoPanelVtx[9].v.ob[1] = D_8082B920 - 3; + + pauseCtx->infoPanelVtx[10].v.ob[1] = pauseCtx->infoPanelVtx[11].v.ob[1] = + pauseCtx->infoPanelVtx[8].v.ob[1] - 26; + } + + if ((pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE)) { + pauseCtx->infoPanelVtx[12].v.ob[0] = pauseCtx->infoPanelVtx[14].v.ob[0] = sPauseCursorRightX; + + pauseCtx->infoPanelVtx[13].v.ob[0] = pauseCtx->infoPanelVtx[15].v.ob[0] = + pauseCtx->infoPanelVtx[12].v.ob[0] + 24; + + pauseCtx->infoPanelVtx[12].v.ob[1] = pauseCtx->infoPanelVtx[13].v.ob[1] = D_8082B920; + + pauseCtx->infoPanelVtx[14].v.ob[1] = pauseCtx->infoPanelVtx[15].v.ob[1] = + pauseCtx->infoPanelVtx[12].v.ob[1] - 32; + } else { + pauseCtx->infoPanelVtx[12].v.ob[0] = pauseCtx->infoPanelVtx[14].v.ob[0] = sPauseCursorRightX + 3; + + pauseCtx->infoPanelVtx[13].v.ob[0] = pauseCtx->infoPanelVtx[15].v.ob[0] = + pauseCtx->infoPanelVtx[12].v.ob[0] + 18; + + pauseCtx->infoPanelVtx[12].v.ob[1] = pauseCtx->infoPanelVtx[13].v.ob[1] = D_8082B920 - 3; + + pauseCtx->infoPanelVtx[14].v.ob[1] = pauseCtx->infoPanelVtx[15].v.ob[1] = + pauseCtx->infoPanelVtx[12].v.ob[1] - 26; + } + + pauseCtx->infoPanelVtx[9].v.tc[0] = pauseCtx->infoPanelVtx[11].v.tc[0] = pauseCtx->infoPanelVtx[13].v.tc[0] = + pauseCtx->infoPanelVtx[15].v.tc[0] = 24 * (1 << 5); + + pauseCtx->infoPanelVtx[10].v.tc[1] = pauseCtx->infoPanelVtx[11].v.tc[1] = pauseCtx->infoPanelVtx[14].v.tc[1] = + pauseCtx->infoPanelVtx[15].v.tc[1] = 32 * (1 << 5); + + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + + Matrix_Translate(0.0f, 0.0f, -144.0f, MTXMODE_NEW); + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 150, 140, 90, 255); + gSPVertex(POLY_OPA_DISP++, &pauseCtx->infoPanelVtx[0], 16, 0); + + gSPDisplayList(POLY_OPA_DISP++, gItemNamePanelDL); + + if ((pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) && + (!pauseCtx->mainState || (pauseCtx->mainState == PAUSE_MAIN_STATE_UNK))) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 150, 140, 90, sPauseZRCursorAlpha); + } + + gSPDisplayList(POLY_OPA_DISP++, gZButtonIconDL); + + if ((pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT) && + (!pauseCtx->mainState || (pauseCtx->mainState == PAUSE_MAIN_STATE_UNK))) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 150, 140, 90, sPauseZRCursorAlpha); + } + + gSPDisplayList(POLY_OPA_DISP++, gRButtonIconDL); + + if (pauseCtx->cursorSpecialPos != 0) { + j = (pauseCtx->cursorSpecialPos * 4) - 32; + pauseCtx->cursorVtx[0].v.ob[0] = pauseCtx->infoPanelVtx[j].v.ob[0]; + pauseCtx->cursorVtx[0].v.ob[1] = pauseCtx->infoPanelVtx[j].v.ob[1]; + } + + y = pauseCtx->infoPanelOffsetY - 80; + pauseCtx->infoPanelVtx[16].v.ob[1] = pauseCtx->infoPanelVtx[17].v.ob[1] = y; + + pauseCtx->infoPanelVtx[18].v.ob[1] = pauseCtx->infoPanelVtx[19].v.ob[1] = pauseCtx->infoPanelVtx[16].v.ob[1] - 16; + + pauseCtx->infoPanelVtx[18].v.tc[1] = pauseCtx->infoPanelVtx[19].v.tc[1] = 16 * (1 << 5); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetEnvColor(POLY_OPA_DISP++, 20, 30, 40, 0); + + if (pauseCtx->itemDescriptionOn || + ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->namedItem != PAUSE_ITEM_NONE) && + (pauseCtx->nameDisplayTimer < 40) && + (!pauseCtx->mainState || (pauseCtx->mainState == PAUSE_MAIN_STATE_SONG_PLAYBACK) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_UNK) || + ((pauseCtx->mainState >= PAUSE_MAIN_STATE_SONG_PROMPT_INIT) && + (pauseCtx->mainState <= PAUSE_MAIN_STATE_SONG_PROMPT_UNUSED)) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG)) && + (pauseCtx->cursorSpecialPos == 0))) { + if (!pauseCtx->mainState || (pauseCtx->mainState == PAUSE_MAIN_STATE_SONG_PLAYBACK) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_UNK) || + ((pauseCtx->mainState >= PAUSE_MAIN_STATE_SONG_PROMPT_INIT) && + (pauseCtx->mainState <= PAUSE_MAIN_STATE_SONG_PROMPT_UNUSED)) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG)) { + + pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = -63; + + pauseCtx->infoPanelVtx[17].v.ob[0] = pauseCtx->infoPanelVtx[19].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 128; + + pauseCtx->infoPanelVtx[17].v.tc[0] = pauseCtx->infoPanelVtx[19].v.tc[0] = 128 * (1 << 5); + + gSPVertex(POLY_OPA_DISP++, &pauseCtx->infoPanelVtx[16], 4, 0); + + if (pauseCtx->nameColorSet == PAUSE_NAME_COLOR_SET_GREY) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 70, 70, 70, 255); + } else { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + } + + POLY_OPA_DISP = Gfx_DrawTexQuad4b(POLY_OPA_DISP, pauseCtx->nameSegment, G_IM_FMT_IA, 128, 16, 0); + } + } else if ((pauseCtx->mainState <= PAUSE_MAIN_STATE_SONG_PLAYBACK) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_SONG_PROMPT_UNUSED) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_UNK)) { + pauseCtx->infoPanelVtx[20].v.ob[1] = pauseCtx->infoPanelVtx[21].v.ob[1] = y; + + pauseCtx->infoPanelVtx[22].v.ob[1] = pauseCtx->infoPanelVtx[23].v.ob[1] = + pauseCtx->infoPanelVtx[20].v.ob[1] - 16; + + pauseCtx->infoPanelVtx[22].v.tc[1] = pauseCtx->infoPanelVtx[23].v.tc[1] = 16 * (1 << 5); + + gSPVertex(POLY_OPA_DISP++, &pauseCtx->infoPanelVtx[16], 8, 0); + + if (pauseCtx->state == PAUSE_STATE_SAVEPROMPT) { + pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = -33; + + pauseCtx->infoPanelVtx[17].v.ob[0] = pauseCtx->infoPanelVtx[19].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 24; + + pauseCtx->infoPanelVtx[20].v.ob[0] = pauseCtx->infoPanelVtx[22].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 0x10; + + pauseCtx->infoPanelVtx[21].v.ob[0] = pauseCtx->infoPanelVtx[23].v.ob[0] = + pauseCtx->infoPanelVtx[20].v.ob[0] + 0x30; + + pauseCtx->infoPanelVtx[17].v.tc[0] = pauseCtx->infoPanelVtx[19].v.tc[0] = 24 * (1 << 5); + + pauseCtx->infoPanelVtx[21].v.tc[0] = pauseCtx->infoPanelVtx[23].v.tc[0] = 48 * (1 << 5); + + gSPDisplayList(POLY_OPA_DISP++, gAButtonIconDL); + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + + //! @bug: Incorrect dimensions. Should be 64x16 + POLY_OPA_DISP = Gfx_DrawTexQuad4b(POLY_OPA_DISP, gPauseToDecideENGTex, G_IM_FMT_IA, 48, 16, 4); + + } else if (pauseCtx->cursorSpecialPos != 0) { + if ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE)) { + + pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = -63; + + pauseCtx->infoPanelVtx[17].v.ob[0] = pauseCtx->infoPanelVtx[19].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 128; + + pauseCtx->infoPanelVtx[17].v.tc[0] = pauseCtx->infoPanelVtx[19].v.tc[0] = 128 * (1 << 5); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 200, 0, 255); + + if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) { + POLY_OPA_DISP = + Gfx_DrawTexQuad4b(POLY_OPA_DISP, D_8082B998[pauseCtx->pageIndex], G_IM_FMT_IA, 128, 16, 0); + } else { + POLY_OPA_DISP = + Gfx_DrawTexQuad4b(POLY_OPA_DISP, D_8082B9A8[pauseCtx->pageIndex], G_IM_FMT_IA, 128, 16, 0); + } + } + } else if ((!pauseCtx->pageIndex || (pauseCtx->pageIndex == PAUSE_MASK)) && + (pauseCtx->namedItem != PAUSE_ITEM_NONE)) { + pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = -49; + + pauseCtx->infoPanelVtx[17].v.ob[0] = pauseCtx->infoPanelVtx[19].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 48; + + pauseCtx->infoPanelVtx[20].v.ob[0] = pauseCtx->infoPanelVtx[22].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 47; + + pauseCtx->infoPanelVtx[21].v.ob[0] = pauseCtx->infoPanelVtx[23].v.ob[0] = + pauseCtx->infoPanelVtx[20].v.ob[0] + 64; + + pauseCtx->infoPanelVtx[17].v.tc[0] = pauseCtx->infoPanelVtx[19].v.tc[0] = 48 * (1 << 5); + + pauseCtx->infoPanelVtx[21].v.tc[0] = pauseCtx->infoPanelVtx[23].v.tc[0] = 64 * (1 << 5); + + gSPDisplayList(POLY_OPA_DISP++, gCButtonIconsDL); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + + POLY_OPA_DISP = Gfx_DrawTexQuad4b(POLY_OPA_DISP, gPauseToEquipENGTex, G_IM_FMT_IA, 64, 16, 4); + } else if ((pauseCtx->pageIndex == PAUSE_MAP) && sInDungeonScene) { + // No code in this case + } else if ((pauseCtx->pageIndex == PAUSE_QUEST) && + (pauseCtx->cursorSlot[PAUSE_QUEST] == QUEST_BOMBERS_NOTEBOOK)) { + if (pauseCtx->namedItem != PAUSE_ITEM_NONE) { + // The cursor is on the bombers notebook + pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = -58; + + pauseCtx->infoPanelVtx[17].v.ob[0] = pauseCtx->infoPanelVtx[19].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 24; + + pauseCtx->infoPanelVtx[20].v.ob[0] = pauseCtx->infoPanelVtx[22].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 0x14; + + pauseCtx->infoPanelVtx[21].v.ob[0] = pauseCtx->infoPanelVtx[23].v.ob[0] = + pauseCtx->infoPanelVtx[20].v.ob[0] + 0x60; + + pauseCtx->infoPanelVtx[17].v.tc[0] = pauseCtx->infoPanelVtx[19].v.tc[0] = 24 * (1 << 5); + + pauseCtx->infoPanelVtx[21].v.tc[0] = pauseCtx->infoPanelVtx[23].v.tc[0] = 96 * (1 << 5); + + gSPDisplayList(POLY_OPA_DISP++, gAButtonIconDL); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + + POLY_OPA_DISP = Gfx_DrawTexQuad4b(POLY_OPA_DISP, gPauseToViewNotebookENGTex, G_IM_FMT_IA, 96, 16, 4); + } + } else if ((pauseCtx->pageIndex == PAUSE_QUEST) && (pauseCtx->cursorSlot[PAUSE_QUEST] >= QUEST_SONG_SONATA) && + (pauseCtx->cursorSlot[PAUSE_QUEST] <= QUEST_SONG_SUN) && (pauseCtx->namedItem != PAUSE_ITEM_NONE)) { + // The cursor is on a learned song + pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = -55; + + pauseCtx->infoPanelVtx[17].v.ob[0] = pauseCtx->infoPanelVtx[19].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 24; + + pauseCtx->infoPanelVtx[20].v.ob[0] = pauseCtx->infoPanelVtx[22].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 20; + + pauseCtx->infoPanelVtx[21].v.ob[0] = pauseCtx->infoPanelVtx[23].v.ob[0] = + pauseCtx->infoPanelVtx[20].v.ob[0] + 96; + + pauseCtx->infoPanelVtx[17].v.tc[0] = pauseCtx->infoPanelVtx[19].v.tc[0] = 24 * (1 << 5); + + pauseCtx->infoPanelVtx[21].v.tc[0] = pauseCtx->infoPanelVtx[23].v.tc[0] = 96 * (1 << 5); + + gSPDisplayList(POLY_OPA_DISP++, gAButtonIconDL); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + + POLY_OPA_DISP = Gfx_DrawTexQuad4b(POLY_OPA_DISP, gPauseToPlayMelodyENGTex, G_IM_FMT_IA, 96, 16, 4); + } + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +u8 sUnpausedButtonStatus[5]; +f32 sCursorCirclesX[4]; +f32 sCursorCirclesY[4]; + +void KaleidoScope_UpdateNamePanel(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + u16 namedItem; + + if ((pauseCtx->namedItem != pauseCtx->cursorItem[pauseCtx->pageIndex]) || + ((pauseCtx->pageIndex == PAUSE_MAP) && (pauseCtx->cursorSpecialPos != 0))) { + + pauseCtx->namedItem = pauseCtx->cursorItem[pauseCtx->pageIndex]; + namedItem = pauseCtx->namedItem; + + osCreateMesgQueue(&pauseCtx->loadQueue, &pauseCtx->loadMsg, 1); + + if (pauseCtx->namedItem != PAUSE_ITEM_NONE) { + if ((pauseCtx->pageIndex == PAUSE_MAP) && !sInDungeonScene) { + Kaleido_LoadMapNameStatic(pauseCtx->nameSegment, namedItem); + } else { + Kaleido_LoadItemNameStatic(pauseCtx->nameSegment, namedItem); + } + pauseCtx->nameDisplayTimer = 0; + } + } else if (pauseCtx->nameColorSet == PAUSE_NAME_COLOR_SET_WHITE) { + if (((pauseCtx->pageIndex == PAUSE_QUEST) && (pauseCtx->cursorSlot[PAUSE_QUEST] >= QUEST_SONG_SONATA) && + (pauseCtx->cursorSlot[PAUSE_QUEST] <= QUEST_SONG_SUN) && + (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG)) || + ((pauseCtx->pageIndex == PAUSE_QUEST) && (pauseCtx->cursorSlot[PAUSE_QUEST] == QUEST_BOMBERS_NOTEBOOK)) || + (pauseCtx->pageIndex == PAUSE_ITEM) || (pauseCtx->pageIndex == PAUSE_MASK)) { + + pauseCtx->nameDisplayTimer++; + if (pauseCtx->nameDisplayTimer > 70) { + pauseCtx->nameDisplayTimer = 0; + } + } else { + pauseCtx->nameDisplayTimer = 0; + } + } else { + pauseCtx->nameDisplayTimer = 0; + } +} + +void KaleidoScope_DrawOwlWarpMapPage(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + + OPEN_DISPS(play->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, + SHADE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 180, 180, 120, 255); + + Matrix_RotateYF(-1.57f, MTXMODE_NEW); + Matrix_Translate(0.0f, sPauseMenuVerticalOffset / 100.0f, -93.0f, MTXMODE_APPLY); + Matrix_Scale(0.78f, 0.78f, 0.78f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->mapPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx); + + POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->mapPageVtx, sMapPageBgTextures); + + Matrix_RotateYF(R_PAUSE_WORLD_MAP_YAW / 1000.0f, MTXMODE_NEW); + + if ((pauseCtx->state == PAUSE_STATE_OPENING_3) || (pauseCtx->state == PAUSE_STATE_OWL_WARP_3) || + (pauseCtx->state >= PAUSE_STATE_OWL_WARP_6) || + ((pauseCtx->state == PAUSE_STATE_SAVEPROMPT) && ((pauseCtx->savePromptState == PAUSE_SAVEPROMPT_STATE_3) || + (pauseCtx->savePromptState == PAUSE_SAVEPROMPT_STATE_7)))) { + Matrix_Translate(0.0f, (R_PAUSE_WORLD_MAP_Y_OFFSET - 8000) / 100.0f, R_PAUSE_WORLD_MAP_DEPTH / 100.0f, + MTXMODE_APPLY); + } else { + Matrix_Translate(0.0f, R_PAUSE_WORLD_MAP_Y_OFFSET / 100.0f, R_PAUSE_WORLD_MAP_DEPTH / 100.0f, MTXMODE_APPLY); + } + + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + Matrix_RotateXFApply(-pauseCtx->mapPageRoll / 100.0f); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx); + + KaleidoScope_DrawWorldMap(play); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void KaleidoScope_DrawOwlWarpInfoPanel(PlayState* play) { + static s16 sPauseZRCursorColorTargets[][4] = { + { 180, 210, 255, 220 }, + { 100, 100, 150, 220 }, + }; + static s16 sPauseZRCursorColorTimer = 20; + static s16 sPauseZRCursorColorIndex = 0; + static s16 sPauseZRCursorRed; + static s16 sPauseZRCursorGreen; + static s16 sPauseZRCursorBlue; + static s16 sPauseZRCursorAlpha; + PauseContext* pauseCtx = &play->pauseCtx; + s16 stepR; + s16 stepG; + s16 stepB; + s16 stepA; + s16 y; + s16 i; + s16 j; + + OPEN_DISPS(play->state.gfxCtx); + + stepR = + ABS_ALT(sPauseZRCursorRed - sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][0]) / sPauseZRCursorColorTimer; + stepG = ABS_ALT(sPauseZRCursorGreen - sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][1]) / + sPauseZRCursorColorTimer; + stepB = ABS_ALT(sPauseZRCursorBlue - sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][2]) / + sPauseZRCursorColorTimer; + stepA = ABS_ALT(sPauseZRCursorAlpha - sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][3]) / + sPauseZRCursorColorTimer; + + if (sPauseZRCursorRed >= sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][0]) { + sPauseZRCursorRed -= stepR; + } else { + sPauseZRCursorRed += stepR; + } + + if (sPauseZRCursorGreen >= sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][1]) { + sPauseZRCursorGreen -= stepG; + } else { + sPauseZRCursorGreen += stepG; + } + + if (sPauseZRCursorBlue >= sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][2]) { + sPauseZRCursorBlue -= stepB; + } else { + sPauseZRCursorBlue += stepB; + } + + if (sPauseZRCursorAlpha >= sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][3]) { + sPauseZRCursorAlpha -= stepA; + } else { + sPauseZRCursorAlpha += stepA; + } + + sPauseZRCursorColorTimer--; + if (sPauseZRCursorColorTimer == 0) { + sPauseZRCursorRed = sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][0]; + sPauseZRCursorGreen = sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][1]; + sPauseZRCursorBlue = sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][2]; + sPauseZRCursorAlpha = sPauseZRCursorColorTargets[sPauseZRCursorColorIndex][3]; + sPauseZRCursorColorTimer = sPauseZRCursorColorTimerInits[0]; + sPauseZRCursorColorIndex ^= 1; + } + + y = pauseCtx->infoPanelOffsetY - 76; + for (j = 0, i = 0; i < 7; i++, j += 4) { + pauseCtx->infoPanelVtx[j + 0].v.ob[0] = pauseCtx->infoPanelVtx[j + 2].v.ob[0] = -72; + + pauseCtx->infoPanelVtx[j + 1].v.ob[0] = pauseCtx->infoPanelVtx[j + 3].v.ob[0] = 0; + + pauseCtx->infoPanelVtx[j + 0].v.ob[1] = pauseCtx->infoPanelVtx[j + 1].v.ob[1] = y; + + pauseCtx->infoPanelVtx[j + 2].v.ob[1] = pauseCtx->infoPanelVtx[j + 3].v.ob[1] = y - 24; + + pauseCtx->infoPanelVtx[j + 0].v.ob[2] = pauseCtx->infoPanelVtx[j + 1].v.ob[2] = + pauseCtx->infoPanelVtx[j + 2].v.ob[2] = pauseCtx->infoPanelVtx[j + 3].v.ob[2] = 0; + + pauseCtx->infoPanelVtx[j + 0].v.flag = pauseCtx->infoPanelVtx[j + 1].v.flag = + pauseCtx->infoPanelVtx[j + 2].v.flag = pauseCtx->infoPanelVtx[j + 3].v.flag = 0; + + pauseCtx->infoPanelVtx[j + 0].v.tc[0] = pauseCtx->infoPanelVtx[j + 0].v.tc[1] = + pauseCtx->infoPanelVtx[j + 1].v.tc[1] = pauseCtx->infoPanelVtx[j + 2].v.tc[0] = 0; + + pauseCtx->infoPanelVtx[j + 1].v.tc[0] = pauseCtx->infoPanelVtx[j + 3].v.tc[0] = 72 * (1 << 5); + + pauseCtx->infoPanelVtx[j + 2].v.tc[1] = pauseCtx->infoPanelVtx[j + 3].v.tc[1] = 24 * (1 << 5); + + pauseCtx->infoPanelVtx[j + 0].v.cn[0] = pauseCtx->infoPanelVtx[j + 2].v.cn[0] = + pauseCtx->infoPanelVtx[j + 0].v.cn[1] = pauseCtx->infoPanelVtx[j + 2].v.cn[1] = + pauseCtx->infoPanelVtx[j + 0].v.cn[2] = pauseCtx->infoPanelVtx[j + 2].v.cn[2] = + pauseCtx->infoPanelVtx[j + 1].v.cn[0] = pauseCtx->infoPanelVtx[j + 3].v.cn[0] = + pauseCtx->infoPanelVtx[j + 1].v.cn[1] = pauseCtx->infoPanelVtx[j + 3].v.cn[1] = + pauseCtx->infoPanelVtx[j + 1].v.cn[2] = pauseCtx->infoPanelVtx[j + 3].v.cn[2] = 200; + + pauseCtx->infoPanelVtx[j + 0].v.cn[3] = pauseCtx->infoPanelVtx[j + 2].v.cn[3] = + pauseCtx->infoPanelVtx[j + 1].v.cn[3] = pauseCtx->infoPanelVtx[j + 3].v.cn[3] = pauseCtx->alpha; + } + + pauseCtx->infoPanelVtx[4].v.ob[0] = pauseCtx->infoPanelVtx[6].v.ob[0] = pauseCtx->infoPanelVtx[0].v.ob[0] + 72; + + pauseCtx->infoPanelVtx[5].v.ob[0] = pauseCtx->infoPanelVtx[7].v.ob[0] = pauseCtx->infoPanelVtx[4].v.ob[0] + 72; + + if ((pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE)) { + pauseCtx->infoPanelVtx[8].v.ob[0] = pauseCtx->infoPanelVtx[10].v.ob[0] = sPauseCursorLeftX; + + pauseCtx->infoPanelVtx[9].v.ob[0] = pauseCtx->infoPanelVtx[11].v.ob[0] = pauseCtx->infoPanelVtx[8].v.ob[0] + 24; + + pauseCtx->infoPanelVtx[8].v.ob[1] = pauseCtx->infoPanelVtx[9].v.ob[1] = D_8082B920; + + pauseCtx->infoPanelVtx[10].v.ob[1] = pauseCtx->infoPanelVtx[11].v.ob[1] = + pauseCtx->infoPanelVtx[8].v.ob[1] - 32; + } else { + pauseCtx->infoPanelVtx[8].v.ob[0] = pauseCtx->infoPanelVtx[10].v.ob[0] = sPauseCursorLeftX + 3; + + pauseCtx->infoPanelVtx[9].v.ob[0] = pauseCtx->infoPanelVtx[11].v.ob[0] = pauseCtx->infoPanelVtx[8].v.ob[0] + 18; + + pauseCtx->infoPanelVtx[8].v.ob[1] = pauseCtx->infoPanelVtx[9].v.ob[1] = D_8082B920 - 3; + + pauseCtx->infoPanelVtx[10].v.ob[1] = pauseCtx->infoPanelVtx[11].v.ob[1] = + pauseCtx->infoPanelVtx[8].v.ob[1] - 26; + } + + if ((pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE)) { + pauseCtx->infoPanelVtx[12].v.ob[0] = pauseCtx->infoPanelVtx[14].v.ob[0] = sPauseCursorRightX; + + pauseCtx->infoPanelVtx[13].v.ob[0] = pauseCtx->infoPanelVtx[15].v.ob[0] = + pauseCtx->infoPanelVtx[12].v.ob[0] + 24; + + pauseCtx->infoPanelVtx[12].v.ob[1] = pauseCtx->infoPanelVtx[13].v.ob[1] = D_8082B920; + + pauseCtx->infoPanelVtx[14].v.ob[1] = pauseCtx->infoPanelVtx[15].v.ob[1] = + pauseCtx->infoPanelVtx[12].v.ob[1] - 32; + } else { + pauseCtx->infoPanelVtx[12].v.ob[0] = pauseCtx->infoPanelVtx[14].v.ob[0] = sPauseCursorRightX + 3; + + pauseCtx->infoPanelVtx[13].v.ob[0] = pauseCtx->infoPanelVtx[15].v.ob[0] = + pauseCtx->infoPanelVtx[12].v.ob[0] + 18; + + pauseCtx->infoPanelVtx[12].v.ob[1] = pauseCtx->infoPanelVtx[13].v.ob[1] = D_8082B920 - 3; + + pauseCtx->infoPanelVtx[14].v.ob[1] = pauseCtx->infoPanelVtx[15].v.ob[1] = + pauseCtx->infoPanelVtx[12].v.ob[1] - 26; + } + + pauseCtx->infoPanelVtx[9].v.tc[0] = pauseCtx->infoPanelVtx[11].v.tc[0] = pauseCtx->infoPanelVtx[13].v.tc[0] = + pauseCtx->infoPanelVtx[15].v.tc[0] = 24 * (1 << 5); + + pauseCtx->infoPanelVtx[10].v.tc[1] = pauseCtx->infoPanelVtx[11].v.tc[1] = pauseCtx->infoPanelVtx[14].v.tc[1] = + pauseCtx->infoPanelVtx[15].v.tc[1] = 32 * (1 << 5); + + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + + Matrix_Translate(0.0f, 0.0f, -144.0f, MTXMODE_NEW); + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 150, 140, 90, 255); + gSPVertex(POLY_OPA_DISP++, &pauseCtx->infoPanelVtx[0], 16, 0); + + gSPDisplayList(POLY_OPA_DISP++, gItemNamePanelDL); + + if (pauseCtx->cursorSpecialPos != 0) { + j = (pauseCtx->cursorSpecialPos * 4) - 32; + pauseCtx->cursorVtx[0].v.ob[0] = pauseCtx->infoPanelVtx[j].v.ob[0]; + pauseCtx->cursorVtx[0].v.ob[1] = pauseCtx->infoPanelVtx[j].v.ob[1]; + } + + y = pauseCtx->infoPanelOffsetY - 80; + pauseCtx->infoPanelVtx[16].v.ob[1] = pauseCtx->infoPanelVtx[17].v.ob[1] = y; + + pauseCtx->infoPanelVtx[18].v.ob[1] = pauseCtx->infoPanelVtx[19].v.ob[1] = pauseCtx->infoPanelVtx[16].v.ob[1] - 16; + + pauseCtx->infoPanelVtx[18].v.tc[1] = pauseCtx->infoPanelVtx[19].v.tc[1] = 16 * (1 << 5); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetEnvColor(POLY_OPA_DISP++, 20, 30, 40, 0); + + if ((pauseCtx->state == PAUSE_STATE_OWL_WARP_SELECT) && (pauseCtx->namedItem != PAUSE_ITEM_NONE) && + (pauseCtx->nameDisplayTimer < 40)) { + pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = -63; + + pauseCtx->infoPanelVtx[17].v.ob[0] = pauseCtx->infoPanelVtx[19].v.ob[0] = + pauseCtx->infoPanelVtx[16].v.ob[0] + 128; + + pauseCtx->infoPanelVtx[17].v.tc[0] = pauseCtx->infoPanelVtx[19].v.tc[0] = 128 * (1 << 5); + + gSPVertex(POLY_OPA_DISP++, &pauseCtx->infoPanelVtx[16], 4, 0); + + if (pauseCtx->nameColorSet == PAUSE_NAME_COLOR_SET_GREY) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 70, 70, 70, 255); + } else { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + } + + POLY_OPA_DISP = Gfx_DrawTexQuad4b(POLY_OPA_DISP, pauseCtx->nameSegment, G_IM_FMT_IA, 128, 16, 0); + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +void KaleidoScope_UpdateOwlWarpNamePanel(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + u16 texIndex; + + if ((pauseCtx->namedItem != pauseCtx->cursorItem[pauseCtx->pageIndex]) || + ((pauseCtx->pageIndex == PAUSE_MAP) && (pauseCtx->cursorSpecialPos != 0))) { + + pauseCtx->namedItem = pauseCtx->cursorItem[pauseCtx->pageIndex]; + texIndex = pauseCtx->namedItem; + + osCreateMesgQueue(&pauseCtx->loadQueue, &pauseCtx->loadMsg, 1); + + if (pauseCtx->namedItem != PAUSE_ITEM_NONE) { + if ((pauseCtx->pageIndex == PAUSE_MAP) && !sInDungeonScene) { + Kaleido_LoadMapNameStatic(pauseCtx->nameSegment, texIndex); + } else { + Kaleido_LoadItemNameStatic(pauseCtx->nameSegment, texIndex); + } + pauseCtx->nameDisplayTimer = 0; + } + } else if (pauseCtx->nameColorSet == PAUSE_NAME_COLOR_SET_WHITE) { + if (((pauseCtx->pageIndex == PAUSE_QUEST) && (pauseCtx->cursorSlot[PAUSE_QUEST] >= QUEST_SONG_SONATA) && + (pauseCtx->cursorSlot[PAUSE_QUEST] <= QUEST_SONG_SUN) && + (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG)) || + (pauseCtx->pageIndex == PAUSE_ITEM)) { + + pauseCtx->nameDisplayTimer++; + if (pauseCtx->nameDisplayTimer > 70) { + pauseCtx->nameDisplayTimer = 0; + } + } else { + pauseCtx->nameDisplayTimer = 0; + } + } else { + pauseCtx->nameDisplayTimer = 0; + } +} + +void KaleidoScope_UpdateSwitchPage(PlayState* play, Input* input) { + PauseContext* pauseCtx = &play->pauseCtx; + + //! FAKE + if (1) { + pauseCtx->eye.x += sPageSwitchEyeDx[pauseCtx->nextPageMode] * 2.0f; + pauseCtx->eye.z += sPageSwitchEyeDz[pauseCtx->nextPageMode] * 2.0f; + + if (pauseCtx->switchPageTimer < 32) { + sPauseCursorLeftX -= TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX -= TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + } else { + sPauseCursorLeftX += TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX += TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + } + + pauseCtx->switchPageTimer += 8; + + if (pauseCtx->switchPageTimer == 64) { + pauseCtx->switchPageTimer = 0; + pauseCtx->pageIndex = sPageSwitchNextPageIndex[pauseCtx->nextPageMode]; + pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE; + + KaleidoScope_HandlePageToggles(play, input); + } + } +} + +void KaleidoScope_SetView(PauseContext* pauseCtx, f32 eyeX, f32 eyeY, f32 eyeZ) { + Vec3f eye; + Vec3f at; + Vec3f up; + + eye.x = eyeX; + eye.y = eyeY; + eye.z = eyeZ; + at.x = at.y = at.z = 0.0f; + up.x = up.z = 0.0f; + up.y = 1.0f; + + View_LookAt(&pauseCtx->view, &eye, &at, &up); + View_Apply(&pauseCtx->view, + VIEW_ALL | VIEW_FORCE_VIEWING | VIEW_FORCE_VIEWPORT | VIEW_FORCE_PROJECTION_PERSPECTIVE); +} + +// CLAMP_MIN(*, 1) because C arrays can't have 0 length +s16 sVtxPageMaskQuadsX[CLAMP_MIN(VTX_PAGE_MASK_QUADS, 1)] = { 0 }; +s16 sVtxPageItemQuadsX[CLAMP_MIN(VTX_PAGE_ITEM_QUADS, 1)] = { 0 }; +s16 sVtxPageMapDungeonQuadsX[VTX_PAGE_MAP_DUNGEON_QUADS] = { + -21, // mapPageVtx[60] QUAD_MAP_DUNGEON_TITLE + -104, // mapPageVtx[64] QUAD_MAP_DUNGEON_BOSS_KEY + -76, // mapPageVtx[68] QUAD_MAP_DUNGEON_COMPASS + -48, // mapPageVtx[72] QUAD_MAP_DUNGEON_MAP + -104, // mapPageVtx[76] QUAD_MAP_DUNGEON_STRAY_FAIRY_GLOWING_CIRCLE + -40 // mapPageVtx[80] QUAD_MAP_DUNGEON_UNUSED +}; +s16 sVtxPageQuestQuadsX[CLAMP_MIN(VTX_PAGE_QUEST_QUADS, 1)] = { 0 }; +s16 sVtxPageMapWorldQuadsX[VTX_PAGE_MAP_WORLD_QUADS] = { + -41, // mapPageVtx[60] world map clouds Clock Town 1 + 9, // mapPageVtx[64] world map clouds Clock Town 2 + 43, // mapPageVtx[68] world map clouds Woodfall 1 + -21, // mapPageVtx[72] world map clouds Woodfall 2 + -37, // mapPageVtx[76] world map clouds Woodfall 3 + 43, // mapPageVtx[80] world map clouds Snowhead 1 + -69, // mapPageVtx[84] world map clouds Snowhead 2 + -69, // mapPageVtx[88] world map clouds Snowhead 3 + -32, // mapPageVtx[92] world map clouds Romani Ranch + -109, // mapPageVtx[96] world map clouds Great Bay 1 + -45, // mapPageVtx[100] world map clouds Great Bay 2 + -109, // mapPageVtx[104] world map clouds Great Bay 3 + -45, // mapPageVtx[108] world map clouds Great Bay 4 + 59, // mapPageVtx[112] world map clouds Stone Tower 1 + -5, // mapPageVtx[116] world map clouds Stone Tower 2 + -70, // mapPageVtx[120] world map region Great Bay + -52, // mapPageVtx[124] world map region Zora Hall + -11, // mapPageVtx[128] world map region Romani Ranch + -2, // mapPageVtx[132] world map region Deku Palace + 8, // mapPageVtx[136] world map region Woodfall + 2, // mapPageVtx[140] world map region Clock Town + 1, // mapPageVtx[144] world map region Snowhead + 43, // mapPageVtx[148] world map region Ikana Graveyard + 52, // mapPageVtx[152] world map region Ikana Canyon + 54, // mapPageVtx[156] world map region Goron Village + 62, // mapPageVtx[160] world map region Stone Tower + -80, // mapPageVtx[164] world map owl warp Great Bay Coast + -64, // mapPageVtx[168] world map owl warp Zora Cape + -9, // mapPageVtx[172] world map owl warp Snowhead + -3, // mapPageVtx[176] world map owl warp Mountain Village + -7, // mapPageVtx[180] world map owl warp Clock Town + -16, // mapPageVtx[184] world map owl warp Milk Road + -1, // mapPageVtx[188] world map owl warp Woodfall + 23, // mapPageVtx[192] world map owl warp Southern Swamp + 44, // mapPageVtx[196] world map owl warp Ikana Canyon + 54, // mapPageVtx[200] world map owl warp Stone Tower +}; +s16 sVtxPagePromptQuadsX[VTX_PAGE_SAVE_QUADS] = { + -76, // promptPageVtx[60] QUAD_PROMPT_MESSAGE + -58, // promptPageVtx[64] QUAD_PROMPT_CURSOR_LEFT + 10, // promptPageVtx[68] QUAD_PROMPT_CURSOR_RIGHT + -58, // promptPageVtx[72] QUAD_PROMPT_CHOICE_YES + 10, // promptPageVtx[76] QUAD_PROMPT_CHOICE_NO +}; + +// CLAMP_MIN(*, 1) because C arrays can't have 0 length +s16 sVtxPageMaskQuadsWidth[CLAMP_MIN(VTX_PAGE_MASK_QUADS, 1)] = { 0 }; +s16 sVtxPageItemQuadsWidth[CLAMP_MIN(VTX_PAGE_ITEM_QUADS, 1)] = { 0 }; +s16 sVtxPageMapDungeonQuadsWidth[VTX_PAGE_MAP_DUNGEON_QUADS] = { + 128, // mapPageVtx[60] QUAD_MAP_DUNGEON_TITLE + 24, // mapPageVtx[64] QUAD_MAP_DUNGEON_BOSS_KEY + 24, // mapPageVtx[68] QUAD_MAP_DUNGEON_COMPASS + 24, // mapPageVtx[72] QUAD_MAP_DUNGEON_MAP + 32, // mapPageVtx[76] QUAD_MAP_DUNGEON_STRAY_FAIRY_GLOWING_CIRCLE + 24, // mapPageVtx[80] QUAD_MAP_DUNGEON_UNUSED +}; +s16 sVtxPageQuestQuadsWidth[CLAMP_MIN(VTX_PAGE_QUEST_QUADS, 1)] = { 0 }; +s16 sVtxPagePromptQuadsWidth[VTX_PAGE_SAVE_QUADS] = { + 152, // promptPageVtx[60] QUAD_PROMPT_MESSAGE + 48, // promptPageVtx[64] QUAD_PROMPT_CURSOR_LEFT + 48, // promptPageVtx[68] QUAD_PROMPT_CURSOR_RIGHT + 48, // promptPageVtx[72] QUAD_PROMPT_CHOICE_YES + 48, // promptPageVtx[76] QUAD_PROMPT_CHOICE_NO +}; + +// CLAMP_MIN(*, 1) because C arrays can't have 0 length +s16 sVtxPageMaskQuadsY[CLAMP_MIN(VTX_PAGE_MASK_QUADS, 1)] = { 0 }; +s16 sVtxPageItemQuadsY[CLAMP_MIN(VTX_PAGE_ITEM_QUADS, 1)] = { 0 }; + +s16 sVtxPageMapDungeonQuadsY[VTX_PAGE_MAP_DUNGEON_QUADS] = { + 54, // mapPageVtx[60] QUAD_MAP_DUNGEON_TITLE + -42, // mapPageVtx[64] QUAD_MAP_DUNGEON_BOSS_KEY + -42, // mapPageVtx[68] QUAD_MAP_DUNGEON_COMPASS + -42, // mapPageVtx[72] QUAD_MAP_DUNGEON_MAP + -24, // mapPageVtx[76] QUAD_MAP_DUNGEON_STRAY_FAIRY_GLOWING_CIRCLE + 50, // mapPageVtx[80] QUAD_MAP_DUNGEON_UNUSED +}; +s16 sVtxPageQuestQuadsY[CLAMP_MIN(VTX_PAGE_QUEST_QUADS, 1)] = { 0 }; +s16 sVtxPageMapWorldQuadsY[VTX_PAGE_MAP_WORLD_QUADS] = { + 11, // mapPageVtx[60] world map clouds Clock Town 1 + 22, // mapPageVtx[64] world map clouds Clock Town 2 + -16, // mapPageVtx[68] world map clouds Woodfall 1 + -16, // mapPageVtx[72] world map clouds Woodfall 2 + -16, // mapPageVtx[76] world map clouds Woodfall 3 + 59, // mapPageVtx[80] world map clouds Snowhead 1 + 24, // mapPageVtx[84] world map clouds Snowhead 2 + 59, // mapPageVtx[88] world map clouds Snowhead 3 + -11, // mapPageVtx[92] world map clouds Romani Ranch + -5, // mapPageVtx[96] world map clouds Great Bay 1 + -5, // mapPageVtx[100] world map clouds Great Bay 2 + 59, // mapPageVtx[104] world map clouds Great Bay 3 + 59, // mapPageVtx[108] world map clouds Great Bay 4 + 39, // mapPageVtx[112] world map clouds Stone Tower 1 + 31, // mapPageVtx[116] world map clouds Stone Tower 2 + -10, // mapPageVtx[120] world map region Great Bay + -36, // mapPageVtx[124] world map region Zora Hall + -19, // mapPageVtx[128] world map region Romani Ranch + -53, // mapPageVtx[132] world map region Deku Palace + -27, // mapPageVtx[136] world map region Woodfall + -2, // mapPageVtx[140] world map region Clock Town + 41, // mapPageVtx[144] world map region Snowhead + 11, // mapPageVtx[148] world map region Ikana Graveyard + -3, // mapPageVtx[152] world map region Ikana Canyon + 45, // mapPageVtx[156] world map region Goron Village + 18, // mapPageVtx[160] world map region Stone Tower + -8, // mapPageVtx[164] world map owl warp Great Bay Coast + -38, // mapPageVtx[168] world map owl warp Zora Cape + 39, // mapPageVtx[172] world map owl warp Snowhead + 26, // mapPageVtx[176] world map owl warp Mountain Village + 1, // mapPageVtx[180] world map owl warp Clock Town + -7, // mapPageVtx[184] world map owl warp Milk Road + -28, // mapPageVtx[188] world map owl warp Woodfall + -27, // mapPageVtx[192] world map owl warp Southern Swamp + -1, // mapPageVtx[196] world map owl warp Ikana Canyon + 24, // mapPageVtx[200] world map owl warp Stone Tower +}; +s16 sVtxPagePromptQuadsY[VTX_PAGE_SAVE_QUADS] = { + 36, // promptPageVtx[60] QUAD_PROMPT_MESSAGE + 10, // promptPageVtx[64] QUAD_PROMPT_CURSOR_LEFT + 10, // promptPageVtx[68] QUAD_PROMPT_CURSOR_RIGHT + -6, // promptPageVtx[72] QUAD_PROMPT_CHOICE_YES + -6, // promptPageVtx[76] QUAD_PROMPT_CHOICE_NO +}; + +// CLAMP_MIN(*, 1) because C arrays can't have 0 length +s16 sVtxPageMaskQuadsHeight[CLAMP_MIN(VTX_PAGE_MASK_QUADS, 1)] = { 0 }; +s16 sVtxPageItemQuadsHeight[CLAMP_MIN(VTX_PAGE_ITEM_QUADS, 1)] = { 0 }; +s16 sVtxPageMapDungeonQuadsHeight[] = { + 16, // mapPageVtx[60] QUAD_MAP_DUNGEON_TITLE + 24, // mapPageVtx[64] QUAD_MAP_DUNGEON_BOSS_KEY + 24, // mapPageVtx[68] QUAD_MAP_DUNGEON_COMPASS + 24, // mapPageVtx[72] QUAD_MAP_DUNGEON_MAP + 24, // mapPageVtx[76] QUAD_MAP_DUNGEON_STRAY_FAIRY_GLOWING_CIRCLE + 24, // mapPageVtx[80] QUAD_MAP_DUNGEON_UNUSED +}; +s16 sVtxPageQuestQuadsHeight[CLAMP_MIN(VTX_PAGE_QUEST_QUADS, 1)] = { 0 }; +s16 sVtxPagePromptQuadsHeight[VTX_PAGE_SAVE_QUADS] = { + 16, // promptPageVtx[60] QUAD_PROMPT_MESSAGE + 48, // promptPageVtx[64] QUAD_PROMPT_CURSOR_LEFT + 48, // promptPageVtx[68] QUAD_PROMPT_CURSOR_RIGHT + 16, // promptPageVtx[72] QUAD_PROMPT_CHOICE_YES + 16, // promptPageVtx[76] QUAD_PROMPT_CHOICE_NO +}; + +s16* sVtxPageQuadsX[VTX_PAGE_MAX] = { + sVtxPageMaskQuadsX, // VTX_PAGE_MASK + sVtxPageItemQuadsX, // VTX_PAGE_ITEM + sVtxPageMapDungeonQuadsX, // VTX_PAGE_MAP_DUNGEON + sVtxPageQuestQuadsX, // VTX_PAGE_QUEST + sVtxPageMapWorldQuadsX, // VTX_PAGE_MAP_WORLD + sVtxPagePromptQuadsX, // VTX_PAGE_PROMPT +}; + +s16* sVtxPageQuadsWidth[VTX_PAGE_MAX] = { + sVtxPageMaskQuadsWidth, // VTX_PAGE_MASK + sVtxPageItemQuadsWidth, // VTX_PAGE_ITEM + sVtxPageMapDungeonQuadsWidth, // VTX_PAGE_MAP_DUNGEON + sVtxPageQuestQuadsWidth, // VTX_PAGE_QUEST + gVtxPageMapWorldQuadsWidth, // VTX_PAGE_MAP_WORLD + sVtxPagePromptQuadsWidth, // VTX_PAGE_PROMPT +}; + +s16* sVtxPageQuadsY[VTX_PAGE_MAX] = { + sVtxPageMaskQuadsY, // VTX_PAGE_MASK + sVtxPageItemQuadsY, // VTX_PAGE_ITEM + sVtxPageMapDungeonQuadsY, // VTX_PAGE_MAP_DUNGEON + sVtxPageQuestQuadsY, // VTX_PAGE_QUEST + sVtxPageMapWorldQuadsY, // VTX_PAGE_MAP_WORLD + sVtxPagePromptQuadsY, // VTX_PAGE_PROMPT +}; + +s16* sVtxPageQuadsHeight[VTX_PAGE_MAX] = { + sVtxPageMaskQuadsHeight, // VTX_PAGE_MASK + sVtxPageItemQuadsHeight, // VTX_PAGE_ITEM + sVtxPageMapDungeonQuadsHeight, // VTX_PAGE_MAP_DUNGEON + sVtxPageQuestQuadsHeight, // VTX_PAGE_QUEST + gVtxPageMapWorldQuadsHeight, // VTX_PAGE_MAP_WORLD + sVtxPagePromptQuadsHeight, // VTX_PAGE_PROMPT +}; + +s16 sVtxPageGameOverSaveQuadsY[VTX_PAGE_SAVE_QUADS] = { + 14, // promptPageVtx[60] QUAD_PROMPT_MESSAGE + -2, // promptPageVtx[64] QUAD_PROMPT_CURSOR_LEFT + -2, // promptPageVtx[68] QUAD_PROMPT_CURSOR_RIGHT + -18, // promptPageVtx[72] QUAD_PROMPT_CHOICE_YES + -18, // promptPageVtx[76] QUAD_PROMPT_CHOICE_NO +}; + +s16 KaleidoScope_SetPageVertices(PlayState* play, Vtx* vtx, s16 vtxPage, s16 numQuads) { + PauseContext* pauseCtx = &play->pauseCtx; + GameOverContext* gameOverCtx = &play->gameOverCtx; + s16* quadsX; + s16* quadsWidth; + s16* quadsY; + s16* quadsHeight; + s16 pageBgQuadX; + s16 pageBgQuadY; + s16 i; + s16 j; + s16 k; + + // Vertices for KaleidoScope_DrawPageSections + + pageBgQuadX = 0 - (PAGE_BG_COLS * PAGE_BG_QUAD_WIDTH) / 2 - PAGE_BG_QUAD_WIDTH; + + // For each column + for (k = 0, i = 0; i < 3; i++) { + pageBgQuadX += PAGE_BG_QUAD_WIDTH; + + // For each row + for (pageBgQuadY = (PAGE_BG_ROWS * PAGE_BG_QUAD_HEIGHT) / 2, j = 0; j < 5; j++, k += 4, pageBgQuadY -= 32) { + vtx[k + 0].v.ob[0] = vtx[k + 2].v.ob[0] = pageBgQuadX; + vtx[k + 1].v.ob[0] = vtx[k + 3].v.ob[0] = vtx[k + 0].v.ob[0] + PAGE_BG_QUAD_WIDTH; + + vtx[k + 0].v.ob[1] = vtx[k + 1].v.ob[1] = pageBgQuadY + pauseCtx->offsetY; + vtx[k + 2].v.ob[1] = vtx[k + 3].v.ob[1] = vtx[k + 0].v.ob[1] - PAGE_BG_QUAD_HEIGHT; + + vtx[k + 0].v.ob[2] = vtx[k + 1].v.ob[2] = vtx[k + 2].v.ob[2] = vtx[k + 3].v.ob[2] = 0; + + vtx[k + 0].v.flag = vtx[k + 1].v.flag = vtx[k + 2].v.flag = vtx[k + 3].v.flag = 0; + + vtx[k + 0].v.tc[0] = vtx[k + 0].v.tc[1] = 0; + vtx[k + 1].v.tc[1] = vtx[k + 2].v.tc[0] = 0; + vtx[k + 1].v.tc[0] = vtx[k + 3].v.tc[0] = PAGE_BG_QUAD_TEX_WIDTH * (1 << 5); + vtx[k + 2].v.tc[1] = vtx[k + 3].v.tc[1] = PAGE_BG_QUAD_TEX_HEIGHT * (1 << 5); + + vtx[k + 0].v.cn[0] = vtx[k + 2].v.cn[0] = vtx[k + 0].v.cn[1] = vtx[k + 2].v.cn[1] = vtx[k + 0].v.cn[2] = + vtx[k + 2].v.cn[2] = 0; + + vtx[k + 1].v.cn[0] = vtx[k + 3].v.cn[0] = vtx[k + 1].v.cn[1] = vtx[k + 3].v.cn[1] = vtx[k + 1].v.cn[2] = + vtx[k + 3].v.cn[2] = 0; + + vtx[k + 0].v.cn[3] = vtx[k + 2].v.cn[3] = vtx[k + 1].v.cn[3] = vtx[k + 3].v.cn[3] = pauseCtx->alpha; + } + } + + if (numQuads != 0) { + quadsX = sVtxPageQuadsX[vtxPage]; + quadsWidth = sVtxPageQuadsWidth[vtxPage]; + quadsY = sVtxPageQuadsY[vtxPage]; + quadsHeight = sVtxPageQuadsHeight[vtxPage]; + + for (i = 0; i < numQuads; i++, k += 4) { + vtx[k + 2].v.ob[0] = vtx[k + 0].v.ob[0] = quadsX[i]; + + vtx[k + 1].v.ob[0] = vtx[k + 3].v.ob[0] = vtx[k + 0].v.ob[0] + quadsWidth[i]; + + if (!IS_PAUSE_STATE_GAMEOVER(pauseCtx)) { + vtx[k + 0].v.ob[1] = vtx[k + 1].v.ob[1] = quadsY[i] + pauseCtx->offsetY; + } else if (gameOverCtx->state == GAMEOVER_INACTIVE) { + vtx[k + 0].v.ob[1] = vtx[k + 1].v.ob[1] = quadsY[i] + pauseCtx->offsetY; + } else { + vtx[k + 0].v.ob[1] = vtx[k + 1].v.ob[1] = sVtxPageGameOverSaveQuadsY[i] + pauseCtx->offsetY; + } + + vtx[k + 2].v.ob[1] = vtx[k + 3].v.ob[1] = vtx[k + 0].v.ob[1] - quadsHeight[i]; + + vtx[k + 0].v.ob[2] = vtx[k + 1].v.ob[2] = vtx[k + 2].v.ob[2] = vtx[k + 3].v.ob[2] = 0; + + vtx[k + 0].v.flag = vtx[k + 1].v.flag = vtx[k + 2].v.flag = vtx[k + 3].v.flag = 0; + + vtx[k + 0].v.tc[0] = vtx[k + 0].v.tc[1] = vtx[k + 1].v.tc[1] = vtx[k + 2].v.tc[0] = 0; + vtx[k + 1].v.tc[0] = vtx[k + 3].v.tc[0] = quadsWidth[i] << 5; + vtx[k + 2].v.tc[1] = vtx[k + 3].v.tc[1] = quadsHeight[i] << 5; + + vtx[k + 0].v.cn[0] = vtx[k + 2].v.cn[0] = vtx[k + 0].v.cn[1] = vtx[k + 2].v.cn[1] = vtx[k + 0].v.cn[2] = + vtx[k + 2].v.cn[2] = 255; + + vtx[k + 1].v.cn[0] = vtx[k + 3].v.cn[0] = vtx[k + 1].v.cn[1] = vtx[k + 3].v.cn[1] = vtx[k + 1].v.cn[2] = + vtx[k + 3].v.cn[2] = 255; + + vtx[k + 0].v.cn[3] = vtx[k + 2].v.cn[3] = vtx[k + 1].v.cn[3] = vtx[k + 3].v.cn[3] = pauseCtx->alpha; + } + } + return k; +} + +s16 sQuestVtxRectLeft[] = { + 45, // QUEST_REMAINS_ODOLWA + 78, // QUEST_REMAINS_GOHT + 10, // QUEST_REMAINS_GYORG + 45, // QUEST_REMAINS_TWINMOLD + 80, // QUEST_SHIELD + 11, // QUEST_SWORD + -109, // QUEST_SONG_SONATA + -87, // QUEST_SONG_LULLABY + -65, // QUEST_SONG_BOSSA_NOVA + -41, // QUEST_SONG_ELEGY + -19, // QUEST_SONG_OATH + -18, // QUEST_SONG_SARIA + -109, // QUEST_SONG_TIME + -87, // QUEST_SONG_HEALING + -65, // QUEST_SONG_EPONA + -41, // QUEST_SONG_SOARING + -19, // QUEST_SONG_STORMS + -18, // QUEST_SONG_SUN + -103, // QUEST_BOMBERS_NOTEBOOK + 7, // QUEST_QUIVER + 82, // QUEST_BOMB_BAG + -110, // QUEST_SKULL_TOKEN (unused) + -54, // QUEST_HEART_PIECE + -98, // ocarina song button index 0 + -86, // ocarina song button index 1 + -74, // ocarina song button index 2 + -62, // ocarina song button index 3 + -50, // ocarina song button index 4 + -38, // ocarina song button index 5 + -26, // ocarina song button index 6 + -14, // ocarina song button index 7 + -98, // ocarina input button index 0 + -86, // ocarina input button index 1 + -74, // ocarina input button index 2 + -62, // ocarina input button index 3 + -50, // ocarina input button index 4 + -38, // ocarina input button index 5 + -26, // ocarina input button index 6 + -14, // ocarina input button index 7 +}; + +s16 sQuestVtxRectTop[] = { + 62, // QUEST_REMAINS_ODOLWA + 42, // QUEST_REMAINS_GOHT + 42, // QUEST_REMAINS_GYORG + 20, // QUEST_REMAINS_TWINMOLD + -9, // QUEST_SHIELD + -9, // QUEST_SWORD + -20, // QUEST_SONG_SONATA + -20, // QUEST_SONG_LULLABY + -20, // QUEST_SONG_BOSSA_NOVA + -20, // QUEST_SONG_ELEGY + -20, // QUEST_SONG_OATH + -20, // QUEST_SONG_SARIA + 2, // QUEST_SONG_TIME + 2, // QUEST_SONG_HEALING + 2, // QUEST_SONG_EPONA + 2, // QUEST_SONG_SOARING + 2, // QUEST_SONG_STORMS + 2, // QUEST_SONG_SUN + 54, // QUEST_BOMBERS_NOTEBOOK + -44, // QUEST_QUIVER + -44, // QUEST_BOMB_BAG + 34, // QUEST_SKULL_TOKEN (unused) + 58, // QUEST_HEART_PIECE + -52, // ocarina song button index 0 + -52, // ocarina song button index 1 + -52, // ocarina song button index 2 + -52, // ocarina song button index 3 + -52, // ocarina song button index 4 + -52, // ocarina song button index 5 + -52, // ocarina song button index 6 + -52, // ocarina song button index 7 + -52, // ocarina input button index 0 + -52, // ocarina input button index 1 + -52, // ocarina input button index 2 + -52, // ocarina input button index 3 + -52, // ocarina input button index 4 + -52, // ocarina input button index 5 + -52, // ocarina input button index 6 + -52, // ocarina input button index 7 +}; + +s16 sQuestVtxWidths[] = { + 32, // QUEST_REMAINS_ODOLWA + 32, // QUEST_REMAINS_GOHT + 32, // QUEST_REMAINS_GYORG + 32, // QUEST_REMAINS_TWINMOLD + 32, // QUEST_SHIELD + 32, // QUEST_SWORD + 16, // QUEST_SONG_SONATA + 16, // QUEST_SONG_LULLABY + 16, // QUEST_SONG_BOSSA_NOVA + 16, // QUEST_SONG_ELEGY + 16, // QUEST_SONG_OATH + 16, // QUEST_SONG_SARIA + 16, // QUEST_SONG_TIME + 16, // QUEST_SONG_HEALING + 16, // QUEST_SONG_EPONA + 16, // QUEST_SONG_SOARING + 16, // QUEST_SONG_STORMS + 16, // QUEST_SONG_SUN + 32, // QUEST_BOMBERS_NOTEBOOK + 32, // QUEST_QUIVER + 32, // QUEST_BOMB_BAG + 24, // QUEST_SKULL_TOKEN (unused) + 48, // QUEST_HEART_PIECE + 16, // ocarina song button index 0 + 16, // ocarina song button index 1 + 16, // ocarina song button index 2 + 16, // ocarina song button index 3 + 16, // ocarina song button index 4 + 16, // ocarina song button index 5 + 16, // ocarina song button index 6 + 16, // ocarina song button index 7 + 16, // ocarina input button index 0 + 16, // ocarina input button index 1 + 16, // ocarina input button index 2 + 16, // ocarina input button index 3 + 16, // ocarina input button index 4 + 16, // ocarina input button index 5 + 16, // ocarina input button index 6 + 16, // ocarina input button index 7 +}; + +s16 sQuestVtxHeights[] = { + 32, // QUEST_REMAINS_ODOLWA + 32, // QUEST_REMAINS_GOHT + 32, // QUEST_REMAINS_GYORG + 32, // QUEST_REMAINS_TWINMOLD + 32, // QUEST_SHIELD + 32, // QUEST_SWORD + 24, // QUEST_SONG_SONATA + 24, // QUEST_SONG_LULLABY + 24, // QUEST_SONG_BOSSA_NOVA + 24, // QUEST_SONG_ELEGY + 24, // QUEST_SONG_OATH + 24, // QUEST_SONG_SARIA + 24, // QUEST_SONG_TIME + 24, // QUEST_SONG_HEALING + 24, // QUEST_SONG_EPONA + 24, // QUEST_SONG_SOARING + 24, // QUEST_SONG_STORMS + 24, // QUEST_SONG_SUN + 32, // QUEST_BOMBERS_NOTEBOOK + 32, // QUEST_QUIVER + 32, // QUEST_BOMB_BAG + 24, // QUEST_SKULL_TOKEN (unused) + 48, // QUEST_HEART_PIECE + 16, // ocarina song button index 0 + 16, // ocarina song button index 1 + 16, // ocarina song button index 2 + 16, // ocarina song button index 3 + 16, // ocarina song button index 4 + 16, // ocarina song button index 5 + 16, // ocarina song button index 6 + 16, // ocarina song button index 7 + 16, // ocarina input button index 0 + 16, // ocarina input button index 1 + 16, // ocarina input button index 2 + 16, // ocarina input button index 3 + 16, // ocarina input button index 4 + 16, // ocarina input button index 5 + 16, // ocarina input button index 6 + 16, // ocarina input button index 7 +}; + +void KaleidoScope_SetVertices(PlayState* play, GraphicsContext* gfxCtx) { + PauseContext* pauseCtx = &play->pauseCtx; + s16 i; + s16 j; + s16 k; + s16 vtx_x; + s16 vtx_y; + + pauseCtx->offsetY = 0; + + if ((pauseCtx->state == PAUSE_STATE_OPENING_3) || (pauseCtx->state == PAUSE_STATE_OWL_WARP_3) || + (pauseCtx->state >= PAUSE_STATE_OWL_WARP_6) || + ((pauseCtx->state == PAUSE_STATE_SAVEPROMPT) && ((pauseCtx->savePromptState == PAUSE_SAVEPROMPT_STATE_3) || + (pauseCtx->savePromptState == PAUSE_SAVEPROMPT_STATE_7)))) { + pauseCtx->offsetY = 80; + } + + if (pauseCtx->pageIndex != PAUSE_QUEST) { + pauseCtx->itemPageVtx = GRAPH_ALLOC(gfxCtx, ((PAGE_BG_QUADS + VTX_PAGE_ITEM_QUADS) * 4) * sizeof(Vtx)); + KaleidoScope_SetPageVertices(play, pauseCtx->itemPageVtx, VTX_PAGE_ITEM, VTX_PAGE_ITEM_QUADS); + + pauseCtx->itemVtx = GRAPH_ALLOC(gfxCtx, (QUAD_ITEM_MAX * 4) * sizeof(Vtx)); + + // QUAD_ITEM_GRID_FIRST..QUAD_ITEM_GRID_LAST + + // Loop over grid rows + for (k = 0, i = 0, vtx_y = (ITEM_GRID_ROWS * ITEM_GRID_CELL_HEIGHT) / 2 - 6; k < ITEM_GRID_ROWS; + k++, vtx_y -= ITEM_GRID_CELL_HEIGHT) { + // Loop over grid columns + for (vtx_x = 0 - (ITEM_GRID_COLS * ITEM_GRID_CELL_WIDTH) / 2, j = 0; j < ITEM_GRID_COLS; + j++, i += 4, vtx_x += ITEM_GRID_CELL_WIDTH) { + pauseCtx->itemVtx[i + 0].v.ob[0] = pauseCtx->itemVtx[i + 2].v.ob[0] = vtx_x + ITEM_GRID_QUAD_MARGIN; + pauseCtx->itemVtx[i + 1].v.ob[0] = pauseCtx->itemVtx[i + 3].v.ob[0] = + pauseCtx->itemVtx[i + 0].v.ob[0] + ITEM_GRID_QUAD_WIDTH; + + pauseCtx->itemVtx[i + 0].v.ob[1] = pauseCtx->itemVtx[i + 1].v.ob[1] = + vtx_y + pauseCtx->offsetY - ITEM_GRID_QUAD_MARGIN; + pauseCtx->itemVtx[i + 2].v.ob[1] = pauseCtx->itemVtx[i + 3].v.ob[1] = + pauseCtx->itemVtx[i + 0].v.ob[1] - ITEM_GRID_QUAD_WIDTH; + + pauseCtx->itemVtx[i + 0].v.ob[2] = pauseCtx->itemVtx[i + 1].v.ob[2] = pauseCtx->itemVtx[i + 2].v.ob[2] = + pauseCtx->itemVtx[i + 3].v.ob[2] = 0; + + pauseCtx->itemVtx[i + 0].v.flag = pauseCtx->itemVtx[i + 1].v.flag = pauseCtx->itemVtx[i + 2].v.flag = + pauseCtx->itemVtx[i + 3].v.flag = 0; + + pauseCtx->itemVtx[i + 0].v.tc[0] = pauseCtx->itemVtx[i + 0].v.tc[1] = pauseCtx->itemVtx[i + 1].v.tc[1] = + pauseCtx->itemVtx[i + 2].v.tc[0] = 0; + + pauseCtx->itemVtx[i + 1].v.tc[0] = pauseCtx->itemVtx[i + 2].v.tc[1] = pauseCtx->itemVtx[i + 3].v.tc[0] = + pauseCtx->itemVtx[i + 3].v.tc[1] = ITEM_GRID_QUAD_TEX_SIZE * (1 << 5); + + pauseCtx->itemVtx[i + 0].v.cn[0] = pauseCtx->itemVtx[i + 1].v.cn[0] = pauseCtx->itemVtx[i + 2].v.cn[0] = + pauseCtx->itemVtx[i + 3].v.cn[0] = pauseCtx->itemVtx[i + 0].v.cn[1] = + pauseCtx->itemVtx[i + 1].v.cn[1] = pauseCtx->itemVtx[i + 2].v.cn[1] = + pauseCtx->itemVtx[i + 3].v.cn[1] = pauseCtx->itemVtx[i + 0].v.cn[2] = + pauseCtx->itemVtx[i + 1].v.cn[2] = pauseCtx->itemVtx[i + 2].v.cn[2] = + pauseCtx->itemVtx[i + 3].v.cn[2] = 255; + + pauseCtx->itemVtx[i + 0].v.cn[3] = pauseCtx->itemVtx[i + 1].v.cn[3] = pauseCtx->itemVtx[i + 2].v.cn[3] = + pauseCtx->itemVtx[i + 3].v.cn[3] = 255; + } + } + + // QUAD_ITEM_GRID_SELECTED_C_LEFT, QUAD_ITEM_GRID_SELECTED_C_DOWN, QUAD_ITEM_GRID_SELECTED_C_RIGHT + + for (j = EQUIP_SLOT_C_LEFT; j <= EQUIP_SLOT_C_RIGHT; j++, i += 4) { + if (GET_CUR_FORM_BTN_SLOT(j) != ITEM_NONE) { + k = GET_CUR_FORM_BTN_SLOT(j) * 4; + + pauseCtx->itemVtx[i + 0].v.ob[0] = pauseCtx->itemVtx[i + 2].v.ob[0] = + pauseCtx->itemVtx[k].v.ob[0] + ITEM_GRID_SELECTED_QUAD_MARGIN; + + pauseCtx->itemVtx[i + 1].v.ob[0] = pauseCtx->itemVtx[i + 3].v.ob[0] = + pauseCtx->itemVtx[i + 0].v.ob[0] + ITEM_GRID_SELECTED_QUAD_WIDTH; + + pauseCtx->itemVtx[i + 0].v.ob[1] = pauseCtx->itemVtx[i + 1].v.ob[1] = + pauseCtx->itemVtx[k].v.ob[1] - ITEM_GRID_SELECTED_QUAD_MARGIN; + + pauseCtx->itemVtx[i + 2].v.ob[1] = pauseCtx->itemVtx[i + 3].v.ob[1] = + pauseCtx->itemVtx[i + 0].v.ob[1] - ITEM_GRID_SELECTED_QUAD_WIDTH; + + pauseCtx->itemVtx[i + 0].v.ob[2] = pauseCtx->itemVtx[i + 1].v.ob[2] = pauseCtx->itemVtx[i + 2].v.ob[2] = + pauseCtx->itemVtx[i + 3].v.ob[2] = 0; + + pauseCtx->itemVtx[i + 0].v.flag = pauseCtx->itemVtx[i + 1].v.flag = pauseCtx->itemVtx[i + 2].v.flag = + pauseCtx->itemVtx[i + 3].v.flag = 0; + + pauseCtx->itemVtx[i + 0].v.tc[0] = pauseCtx->itemVtx[i + 0].v.tc[1] = pauseCtx->itemVtx[i + 1].v.tc[1] = + pauseCtx->itemVtx[i + 2].v.tc[0] = 0; + + pauseCtx->itemVtx[i + 1].v.tc[0] = pauseCtx->itemVtx[i + 2].v.tc[1] = pauseCtx->itemVtx[i + 3].v.tc[0] = + pauseCtx->itemVtx[i + 3].v.tc[1] = ITEM_GRID_SELECTED_QUAD_TEX_SIZE * (1 << 5); + + pauseCtx->itemVtx[i + 0].v.cn[0] = pauseCtx->itemVtx[i + 1].v.cn[0] = pauseCtx->itemVtx[i + 2].v.cn[0] = + pauseCtx->itemVtx[i + 3].v.cn[0] = pauseCtx->itemVtx[i + 0].v.cn[1] = + pauseCtx->itemVtx[i + 1].v.cn[1] = pauseCtx->itemVtx[i + 2].v.cn[1] = + pauseCtx->itemVtx[i + 3].v.cn[1] = pauseCtx->itemVtx[i + 0].v.cn[2] = + pauseCtx->itemVtx[i + 1].v.cn[2] = pauseCtx->itemVtx[i + 2].v.cn[2] = + pauseCtx->itemVtx[i + 3].v.cn[2] = 255; + + pauseCtx->itemVtx[i + 0].v.cn[3] = pauseCtx->itemVtx[i + 1].v.cn[3] = pauseCtx->itemVtx[i + 2].v.cn[3] = + pauseCtx->itemVtx[i + 3].v.cn[3] = pauseCtx->alpha; + } else { + // No item equipped on the C button, put the quad out of view + + pauseCtx->itemVtx[i + 2].v.ob[0] = -300; + pauseCtx->itemVtx[i + 0].v.ob[0] = pauseCtx->itemVtx[i + 2].v.ob[0]; + + pauseCtx->itemVtx[i + 1].v.ob[0] = pauseCtx->itemVtx[i + 3].v.ob[0] = + pauseCtx->itemVtx[i + 0].v.ob[0] + ITEM_GRID_SELECTED_QUAD_WIDTH; + + pauseCtx->itemVtx[i + 0].v.ob[1] = pauseCtx->itemVtx[i + 1].v.ob[1] = 300; + pauseCtx->itemVtx[i + 2].v.ob[1] = pauseCtx->itemVtx[i + 3].v.ob[1] = + pauseCtx->itemVtx[i + 0].v.ob[1] - ITEM_GRID_SELECTED_QUAD_HEIGHT; + } + } + } + + if (pauseCtx->pageIndex != PAUSE_MASK) { + if (!sInDungeonScene) { + pauseCtx->mapPageVtx = GRAPH_ALLOC( + gfxCtx, ((PAGE_BG_QUADS + VTX_PAGE_MAP_WORLD_QUADS + WORLD_MAP_IMAGE_FRAG_NUM) * 4) * sizeof(Vtx)); + j = KaleidoScope_SetPageVertices(play, pauseCtx->mapPageVtx, VTX_PAGE_MAP_WORLD, VTX_PAGE_MAP_WORLD_QUADS); + + for (i = 0, vtx_y = 59; i < WORLD_MAP_IMAGE_FRAG_NUM; i++, j += 4, vtx_y -= WORLD_MAP_IMAGE_FRAG_HEIGHT) { + pauseCtx->mapPageVtx[j + 2].v.ob[0] = 0 - (WORLD_MAP_IMAGE_WIDTH / 2) - 1; + pauseCtx->mapPageVtx[j + 0].v.ob[0] = pauseCtx->mapPageVtx[j + 2].v.ob[0]; + + pauseCtx->mapPageVtx[j + 1].v.ob[0] = pauseCtx->mapPageVtx[j + 3].v.ob[0] = + pauseCtx->mapPageVtx[j + 0].v.ob[0] + WORLD_MAP_IMAGE_WIDTH; + + pauseCtx->mapPageVtx[j + 0].v.ob[1] = pauseCtx->mapPageVtx[j + 1].v.ob[1] = vtx_y + pauseCtx->offsetY; + + pauseCtx->mapPageVtx[j + 2].v.ob[1] = pauseCtx->mapPageVtx[j + 3].v.ob[1] = + pauseCtx->mapPageVtx[j + 0].v.ob[1] - WORLD_MAP_IMAGE_FRAG_HEIGHT; + + pauseCtx->mapPageVtx[j + 0].v.ob[2] = pauseCtx->mapPageVtx[j + 1].v.ob[2] = + pauseCtx->mapPageVtx[j + 2].v.ob[2] = pauseCtx->mapPageVtx[j + 3].v.ob[2] = 0; + + pauseCtx->mapPageVtx[j + 0].v.flag = pauseCtx->mapPageVtx[j + 1].v.flag = + pauseCtx->mapPageVtx[j + 2].v.flag = pauseCtx->mapPageVtx[j + 3].v.flag = 0; + + pauseCtx->mapPageVtx[j + 0].v.tc[0] = pauseCtx->mapPageVtx[j + 0].v.tc[1] = + pauseCtx->mapPageVtx[j + 1].v.tc[1] = pauseCtx->mapPageVtx[j + 2].v.tc[0] = 0; + + pauseCtx->mapPageVtx[j + 1].v.tc[0] = pauseCtx->mapPageVtx[j + 3].v.tc[0] = + WORLD_MAP_IMAGE_WIDTH * (1 << 5); + pauseCtx->mapPageVtx[j + 2].v.tc[1] = pauseCtx->mapPageVtx[j + 3].v.tc[1] = + WORLD_MAP_IMAGE_FRAG_HEIGHT * (1 << 5); + + pauseCtx->mapPageVtx[j + 0].v.cn[0] = pauseCtx->mapPageVtx[j + 2].v.cn[0] = + pauseCtx->mapPageVtx[j + 0].v.cn[1] = pauseCtx->mapPageVtx[j + 2].v.cn[1] = + pauseCtx->mapPageVtx[j + 0].v.cn[2] = pauseCtx->mapPageVtx[j + 2].v.cn[2] = + pauseCtx->mapPageVtx[j + 1].v.cn[0] = pauseCtx->mapPageVtx[j + 3].v.cn[0] = + pauseCtx->mapPageVtx[j + 1].v.cn[1] = pauseCtx->mapPageVtx[j + 3].v.cn[1] = + pauseCtx->mapPageVtx[j + 1].v.cn[2] = pauseCtx->mapPageVtx[j + 3].v.cn[2] = + pauseCtx->mapPageVtx[j + 0].v.cn[3] = pauseCtx->mapPageVtx[j + 2].v.cn[3] = + pauseCtx->mapPageVtx[j + 1].v.cn[3] = pauseCtx->mapPageVtx[j + 3].v.cn[3] = + pauseCtx->alpha; + } + + pauseCtx->mapPageVtx[j - 2].v.ob[1] = pauseCtx->mapPageVtx[j - 1].v.ob[1] = + pauseCtx->mapPageVtx[j - 4].v.ob[1] - (WORLD_MAP_IMAGE_HEIGHT % WORLD_MAP_IMAGE_FRAG_HEIGHT); + + pauseCtx->mapPageVtx[j - 2].v.tc[1] = pauseCtx->mapPageVtx[j - 1].v.tc[1] = + (WORLD_MAP_IMAGE_HEIGHT % WORLD_MAP_IMAGE_FRAG_HEIGHT) * (1 << 5); + + } else { + pauseCtx->mapPageVtx = + GRAPH_ALLOC(gfxCtx, ((PAGE_BG_QUADS + VTX_PAGE_MAP_DUNGEON_QUADS) * 4) * sizeof(Vtx)); + KaleidoScope_SetPageVertices(play, pauseCtx->mapPageVtx, VTX_PAGE_MAP_DUNGEON, VTX_PAGE_MAP_DUNGEON_QUADS); + } + } + + if (pauseCtx->pageIndex != PAUSE_ITEM) { + pauseCtx->questPageVtx = GRAPH_ALLOC(gfxCtx, ((PAGE_BG_QUADS + VTX_PAGE_QUEST_QUADS) * 4) * sizeof(Vtx)); + KaleidoScope_SetPageVertices(play, pauseCtx->questPageVtx, VTX_PAGE_QUEST, VTX_PAGE_QUEST_QUADS); + + pauseCtx->questVtx = GRAPH_ALLOC(gfxCtx, (39 * 4) * sizeof(Vtx)); + + for (k = 0, j = 0; j < 39; j++, k += 4) { + if (j <= QUEST_SWORD) { + pauseCtx->questVtx[k + 0].v.ob[0] = pauseCtx->questVtx[k + 2].v.ob[0] = sQuestVtxRectLeft[j]; + + pauseCtx->questVtx[k + 1].v.ob[0] = pauseCtx->questVtx[k + 3].v.ob[0] = + pauseCtx->questVtx[k + 0].v.ob[0] + sQuestVtxWidths[j]; + + pauseCtx->questVtx[k + 0].v.ob[1] = pauseCtx->questVtx[k + 1].v.ob[1] = + sQuestVtxRectTop[j] + pauseCtx->offsetY; + + pauseCtx->questVtx[k + 2].v.ob[1] = pauseCtx->questVtx[k + 3].v.ob[1] = + pauseCtx->questVtx[k + 0].v.ob[1] - sQuestVtxHeights[j]; + } else { + pauseCtx->questVtx[k + 0].v.ob[0] = pauseCtx->questVtx[k + 2].v.ob[0] = sQuestVtxRectLeft[j] + 2; + + pauseCtx->questVtx[k + 1].v.ob[0] = pauseCtx->questVtx[k + 3].v.ob[0] = + pauseCtx->questVtx[k + 0].v.ob[0] + sQuestVtxWidths[j] - 4; + + pauseCtx->questVtx[k + 0].v.ob[1] = pauseCtx->questVtx[k + 1].v.ob[1] = + sQuestVtxRectTop[j] + pauseCtx->offsetY - 2; + + pauseCtx->questVtx[k + 2].v.ob[1] = pauseCtx->questVtx[k + 3].v.ob[1] = + pauseCtx->questVtx[k + 0].v.ob[1] - sQuestVtxHeights[j] + 4; + } + + pauseCtx->questVtx[k + 0].v.ob[2] = pauseCtx->questVtx[k + 1].v.ob[2] = pauseCtx->questVtx[k + 2].v.ob[2] = + pauseCtx->questVtx[k + 3].v.ob[2] = 0; + + pauseCtx->questVtx[k + 0].v.flag = pauseCtx->questVtx[k + 1].v.flag = pauseCtx->questVtx[k + 2].v.flag = + pauseCtx->questVtx[k + 3].v.flag = 0; + + pauseCtx->questVtx[k + 0].v.tc[0] = pauseCtx->questVtx[k + 0].v.tc[1] = pauseCtx->questVtx[k + 1].v.tc[1] = + pauseCtx->questVtx[k + 2].v.tc[0] = 0; + + pauseCtx->questVtx[k + 1].v.tc[0] = pauseCtx->questVtx[k + 3].v.tc[0] = sQuestVtxWidths[j] << 5; + pauseCtx->questVtx[k + 2].v.tc[1] = pauseCtx->questVtx[k + 3].v.tc[1] = sQuestVtxHeights[j] << 5; + + pauseCtx->questVtx[k + 0].v.cn[0] = pauseCtx->questVtx[k + 1].v.cn[0] = pauseCtx->questVtx[k + 2].v.cn[0] = + pauseCtx->questVtx[k + 3].v.cn[0] = pauseCtx->questVtx[k + 0].v.cn[1] = + pauseCtx->questVtx[k + 1].v.cn[1] = pauseCtx->questVtx[k + 2].v.cn[1] = + pauseCtx->questVtx[k + 3].v.cn[1] = pauseCtx->questVtx[k + 0].v.cn[2] = + pauseCtx->questVtx[k + 1].v.cn[2] = pauseCtx->questVtx[k + 2].v.cn[2] = + pauseCtx->questVtx[k + 3].v.cn[2] = 255; + + pauseCtx->questVtx[k + 0].v.cn[3] = pauseCtx->questVtx[k + 1].v.cn[3] = pauseCtx->questVtx[k + 2].v.cn[3] = + pauseCtx->questVtx[k + 3].v.cn[3] = pauseCtx->alpha; + } + } + + if (pauseCtx->pageIndex != PAUSE_MAP) { + pauseCtx->maskPageVtx = GRAPH_ALLOC(gfxCtx, ((PAGE_BG_QUADS + VTX_PAGE_MASK_QUADS) * 4) * sizeof(Vtx)); + KaleidoScope_SetPageVertices(play, pauseCtx->maskPageVtx, VTX_PAGE_MASK, VTX_PAGE_MASK_QUADS); + + pauseCtx->maskVtx = GRAPH_ALLOC(gfxCtx, (QUAD_MASK_MAX * 4) * sizeof(Vtx)); + + // Loop over grid rows + for (k = 0, i = 0, vtx_y = (MASK_GRID_ROWS * MASK_GRID_CELL_HEIGHT) / 2 - 6; k < MASK_GRID_ROWS; + k++, vtx_y -= MASK_GRID_CELL_HEIGHT) { + // Loop over grid columns + for (vtx_x = 0 - (MASK_GRID_COLS * MASK_GRID_CELL_WIDTH) / 2, j = 0; j < MASK_GRID_COLS; + j++, i += 4, vtx_x += MASK_GRID_CELL_WIDTH) { + pauseCtx->maskVtx[i + 0].v.ob[0] = pauseCtx->maskVtx[i + 2].v.ob[0] = vtx_x + MASK_GRID_QUAD_MARGIN; + pauseCtx->maskVtx[i + 1].v.ob[0] = pauseCtx->maskVtx[i + 3].v.ob[0] = + pauseCtx->maskVtx[i + 0].v.ob[0] + MASK_GRID_QUAD_WIDTH; + + pauseCtx->maskVtx[i + 0].v.ob[1] = pauseCtx->maskVtx[i + 1].v.ob[1] = + vtx_y + pauseCtx->offsetY - MASK_GRID_QUAD_MARGIN; + pauseCtx->maskVtx[i + 2].v.ob[1] = pauseCtx->maskVtx[i + 3].v.ob[1] = + pauseCtx->maskVtx[i + 0].v.ob[1] - MASK_GRID_QUAD_HEIGHT; + + pauseCtx->maskVtx[i + 0].v.ob[2] = pauseCtx->maskVtx[i + 1].v.ob[2] = pauseCtx->maskVtx[i + 2].v.ob[2] = + pauseCtx->maskVtx[i + 3].v.ob[2] = 0; + + pauseCtx->maskVtx[i + 0].v.flag = pauseCtx->maskVtx[i + 1].v.flag = pauseCtx->maskVtx[i + 2].v.flag = + pauseCtx->maskVtx[i + 3].v.flag = 0; + + pauseCtx->maskVtx[i + 0].v.tc[0] = pauseCtx->maskVtx[i + 0].v.tc[1] = pauseCtx->maskVtx[i + 1].v.tc[1] = + pauseCtx->maskVtx[i + 2].v.tc[0] = 0; + + pauseCtx->maskVtx[i + 1].v.tc[0] = pauseCtx->maskVtx[i + 2].v.tc[1] = pauseCtx->maskVtx[i + 3].v.tc[0] = + pauseCtx->maskVtx[i + 3].v.tc[1] = MASK_GRID_QUAD_TEX_SIZE * (1 << 5); + + pauseCtx->maskVtx[i + 0].v.cn[0] = pauseCtx->maskVtx[i + 1].v.cn[0] = pauseCtx->maskVtx[i + 2].v.cn[0] = + pauseCtx->maskVtx[i + 3].v.cn[0] = pauseCtx->maskVtx[i + 0].v.cn[1] = + pauseCtx->maskVtx[i + 1].v.cn[1] = pauseCtx->maskVtx[i + 2].v.cn[1] = + pauseCtx->maskVtx[i + 3].v.cn[1] = pauseCtx->maskVtx[i + 0].v.cn[2] = + pauseCtx->maskVtx[i + 1].v.cn[2] = pauseCtx->maskVtx[i + 2].v.cn[2] = + pauseCtx->maskVtx[i + 3].v.cn[2] = 255; + + pauseCtx->maskVtx[i + 0].v.cn[3] = pauseCtx->maskVtx[i + 1].v.cn[3] = pauseCtx->maskVtx[i + 2].v.cn[3] = + pauseCtx->maskVtx[i + 3].v.cn[3] = 255; + } + } + + // QUAD_MASK_GRID_SELECTED_C_LEFT, QUAD_MASK_GRID_SELECTED_C_DOWN, QUAD_MASK_GRID_SELECTED_C_RIGHT + + for (j = EQUIP_SLOT_C_LEFT; j <= EQUIP_SLOT_C_RIGHT; j++, i += 4) { + if (GET_CUR_FORM_BTN_SLOT(j) != ITEM_NONE) { + k = (GET_CUR_FORM_BTN_SLOT(j) - ITEM_NUM_SLOTS) * 4; + + pauseCtx->maskVtx[i + 0].v.ob[0] = pauseCtx->maskVtx[i + 2].v.ob[0] = + pauseCtx->maskVtx[k].v.ob[0] + MASK_GRID_SELECTED_QUAD_MARGIN; + + pauseCtx->maskVtx[i + 1].v.ob[0] = pauseCtx->maskVtx[i + 3].v.ob[0] = + pauseCtx->maskVtx[i + 0].v.ob[0] + MASK_GRID_SELECTED_QUAD_WIDTH; + + pauseCtx->maskVtx[i + 0].v.ob[1] = pauseCtx->maskVtx[i + 1].v.ob[1] = + pauseCtx->maskVtx[k].v.ob[1] - MASK_GRID_SELECTED_QUAD_MARGIN; + + pauseCtx->maskVtx[i + 2].v.ob[1] = pauseCtx->maskVtx[i + 3].v.ob[1] = + pauseCtx->maskVtx[i + 0].v.ob[1] - MASK_GRID_SELECTED_QUAD_HEIGHT; + + pauseCtx->maskVtx[i + 0].v.ob[2] = pauseCtx->maskVtx[i + 1].v.ob[2] = pauseCtx->maskVtx[i + 2].v.ob[2] = + pauseCtx->maskVtx[i + 3].v.ob[2] = 0; + + pauseCtx->maskVtx[i + 0].v.flag = pauseCtx->maskVtx[i + 1].v.flag = pauseCtx->maskVtx[i + 2].v.flag = + pauseCtx->maskVtx[i + 3].v.flag = 0; + + pauseCtx->maskVtx[i + 0].v.tc[0] = pauseCtx->maskVtx[i + 0].v.tc[1] = pauseCtx->maskVtx[i + 1].v.tc[1] = + pauseCtx->maskVtx[i + 2].v.tc[0] = 0; + + pauseCtx->maskVtx[i + 1].v.tc[0] = pauseCtx->maskVtx[i + 2].v.tc[1] = pauseCtx->maskVtx[i + 3].v.tc[0] = + pauseCtx->maskVtx[i + 3].v.tc[1] = MASK_GRID_SELECTED_QUAD_TEX_SIZE * (1 << 5); + + pauseCtx->maskVtx[i + 0].v.cn[0] = pauseCtx->maskVtx[i + 1].v.cn[0] = pauseCtx->maskVtx[i + 2].v.cn[0] = + pauseCtx->maskVtx[i + 3].v.cn[0] = pauseCtx->maskVtx[i + 0].v.cn[1] = + pauseCtx->maskVtx[i + 1].v.cn[1] = pauseCtx->maskVtx[i + 2].v.cn[1] = + pauseCtx->maskVtx[i + 3].v.cn[1] = pauseCtx->maskVtx[i + 0].v.cn[2] = + pauseCtx->maskVtx[i + 1].v.cn[2] = pauseCtx->maskVtx[i + 2].v.cn[2] = + pauseCtx->maskVtx[i + 3].v.cn[2] = 255; + + pauseCtx->maskVtx[i + 0].v.cn[3] = pauseCtx->maskVtx[i + 1].v.cn[3] = pauseCtx->maskVtx[i + 2].v.cn[3] = + pauseCtx->maskVtx[i + 3].v.cn[3] = pauseCtx->alpha; + } else { + pauseCtx->maskVtx[i + 2].v.ob[0] = -300; + pauseCtx->maskVtx[i + 0].v.ob[0] = pauseCtx->maskVtx[i + 2].v.ob[0]; + + pauseCtx->maskVtx[i + 1].v.ob[0] = pauseCtx->maskVtx[i + 3].v.ob[0] = + pauseCtx->maskVtx[i + 0].v.ob[0] + MASK_GRID_SELECTED_QUAD_WIDTH; + + pauseCtx->maskVtx[i + 0].v.ob[1] = pauseCtx->maskVtx[i + 1].v.ob[1] = 300; + pauseCtx->maskVtx[i + 2].v.ob[1] = pauseCtx->maskVtx[i + 3].v.ob[1] = + pauseCtx->maskVtx[i + 0].v.ob[1] - MASK_GRID_SELECTED_QUAD_HEIGHT; + } + } + } + + pauseCtx->cursorVtx = GRAPH_ALLOC(play->state.gfxCtx, (PAUSE_QUAD_CURSOR_MAX * 4) * sizeof(Vtx)); + + for (i = 0; i < (PAUSE_QUAD_CURSOR_MAX * 4); i++) { + pauseCtx->cursorVtx[i].v.ob[0] = pauseCtx->cursorVtx[i].v.ob[1] = pauseCtx->cursorVtx[i].v.ob[2] = 0; + + pauseCtx->cursorVtx[i].v.flag = 0; + + pauseCtx->cursorVtx[i].v.tc[0] = pauseCtx->cursorVtx[i].v.tc[1] = 0; + + pauseCtx->cursorVtx[i].v.cn[0] = pauseCtx->cursorVtx[i].v.cn[1] = pauseCtx->cursorVtx[i].v.cn[2] = + pauseCtx->cursorVtx[i].v.cn[3] = 255; + } + + // PAUSE_QUAD_CURSOR_0 + pauseCtx->cursorVtx[1].v.tc[0] = pauseCtx->cursorVtx[2].v.tc[1] = pauseCtx->cursorVtx[3].v.tc[0] = + pauseCtx->cursorVtx[3].v.tc[1] + // PAUSE_QUAD_CURSOR_1 + = pauseCtx->cursorVtx[5].v.tc[0] = pauseCtx->cursorVtx[6].v.tc[1] = pauseCtx->cursorVtx[7].v.tc[0] = + pauseCtx->cursorVtx[7].v.tc[1] + // PAUSE_QUAD_CURSOR_2 + = pauseCtx->cursorVtx[9].v.tc[0] = pauseCtx->cursorVtx[10].v.tc[1] = pauseCtx->cursorVtx[11].v.tc[0] = + pauseCtx->cursorVtx[11].v.tc[1] + // PAUSE_QUAD_CURSOR_3 + = pauseCtx->cursorVtx[13].v.tc[0] = pauseCtx->cursorVtx[14].v.tc[1] = pauseCtx->cursorVtx[15].v.tc[0] = + pauseCtx->cursorVtx[15].v.tc[1] = 16 * (1 << 5); + + // PAUSE_QUAD_CURSOR_4 + pauseCtx->cursorVtx[17].v.tc[0] = pauseCtx->cursorVtx[18].v.tc[1] = pauseCtx->cursorVtx[19].v.tc[0] = + pauseCtx->cursorVtx[19].v.tc[1] = 32 * (1 << 5); + + pauseCtx->infoPanelVtx = GRAPH_ALLOC(gfxCtx, 28 * sizeof(Vtx)); + + if ((pauseCtx->state == PAUSE_STATE_SAVEPROMPT) || IS_PAUSE_STATE_GAMEOVER(pauseCtx)) { + pauseCtx->promptPageVtx = GRAPH_ALLOC(gfxCtx, ((PAGE_BG_QUADS + VTX_PAGE_SAVE_QUADS) * 4) * sizeof(Vtx)); + KaleidoScope_SetPageVertices(play, pauseCtx->promptPageVtx, VTX_PAGE_PROMPT, VTX_PAGE_SAVE_QUADS); + } +} + +f32 sItemMaskCursorsX[] = { + -62.0f, // Column 1 + -36.0f, // Column 2 + -10.0f, // Column 3 + 16.0f, // Column 4 + 42.0f, // Column 5 + 68.0f, // Column 6 +}; + +f32 sItemMaskCursorsY[] = { + 31.0f, // Row 1 + 5.0f, // Row 2 + -21.0f, // Row 3 + -47.0f, // Row 4 +}; + +f32 sWorldMapCursorsX[REGION_MAX] = { + -49.0f, // REGION_GREAT_BAY + -35.0f, // REGION_ZORA_HALL + -3.0f, // REGION_ROMANI_RANCH + 4.0f, // REGION_DEKU_PALACE + 12.0f, // REGION_WOODFALL + 8.0f, // REGION_CLOCK_TOWN + 7.0f, // REGION_SNOWHEAD + 40.0f, // REGION_IKANA_GRAVEYARD + 47.0f, // REGION_IKANA_CANYON + 49.0f, // REGION_GORON_VILLAGE + 55.0f, // REGION_STONE_TOWER +}; + +f32 sWorldMapCursorsY[REGION_MAX] = { + -15.0f, // REGION_GREAT_BAY + -36.0f, // REGION_ZORA_HALL + -23.0f, // REGION_ROMANI_RANCH + -49.0f, // REGION_DEKU_PALACE + -29.0f, // REGION_WOODFALL + -8.0f, // REGION_CLOCK_TOWN + 25.0f, // REGION_SNOWHEAD + 2.0f, // REGION_IKANA_GRAVEYARD + -9.0f, // REGION_IKANA_CANYON + 28.0f, // REGION_GORON_VILLAGE + 7.0f, // REGION_STONE_TOWER +}; + +f32 sOwlWarpWorldMapCursorsX[OWL_WARP_MAX - 1] = { + -50.0f, // OWL_WARP_GREAT_BAY_COAST + -38.0f, // OWL_WARP_ZORA_CAPE + 6.0f, // OWL_WARP_SNOWHEAD + 11.0f, // OWL_WARP_MOUNTAIN_VILLAGE + 8.0f, // OWL_WARP_CLOCK_TOWN + 0.0f, // OWL_WARP_MILK_ROAD + 12.0f, // OWL_WARP_WOODFALL + 31.0f, // OWL_WARP_SOUTHERN_SWAMP + 48.0f, // OWL_WARP_IKANA_CANYON + 56.0f, // OWL_WARP_STONE_TOWER +}; + +f32 sOwlWarpWorldMapCursorsY[OWL_WARP_MAX - 1] = { + -14.0f, // OWL_WARP_GREAT_BAY_COAST + -39.0f, // OWL_WARP_ZORA_CAPE + 23.0f, // OWL_WARP_SNOWHEAD + 11.0f, // OWL_WARP_MOUNTAIN_VILLAGE + -8.0f, // OWL_WARP_CLOCK_TOWN + -15.0f, // OWL_WARP_MILK_ROAD + -31.0f, // OWL_WARP_WOODFALL + -30.0f, // OWL_WARP_SOUTHERN_SWAMP + -10.0f, // OWL_WARP_IKANA_CANYON + 11.0f, // OWL_WARP_STONE_TOWER +}; + +f32 sDungeonMapCursorsX[] = { + -72.0f, // DUNGEON_BOSS_KEY + -47.0f, // DUNGEON_COMPASS + -26.0f, // DUNGEON_MAP + -50.0f, // DUNGEON_STRAY_FAIRIES + -48.0f, // DUNGEON_FLOOR_INDEX_4 (top floor) + -48.0f, // DUNGEON_FLOOR_INDEX_3 + -48.0f, // DUNGEON_FLOOR_INDEX_2 + -48.0f, // DUNGEON_FLOOR_INDEX_1 + -48.0f, // DUNGEON_FLOOR_INDEX_0 (bottom floor) +}; + +f32 sDungeonMapCursorsY[] = { + -47.0f, // DUNGEON_BOSS_KEY + -47.0f, // DUNGEON_COMPASS + -47.0f, // DUNGEON_MAP + -30.0f, // DUNGEON_STRAY_FAIRIES + 33.0f, // DUNGEON_FLOOR_INDEX_4 (top floor) + 22.0f, // DUNGEON_FLOOR_INDEX_3 + 11.0f, // DUNGEON_FLOOR_INDEX_2 + -2.0f, // DUNGEON_FLOOR_INDEX_1 + -13.0f, // DUNGEON_FLOOR_INDEX_0 (bottom floor) +}; + +f32 sQuestStatusCursorsX[] = { + 52.0f, // QUEST_REMAINS_ODOLWA + 80.0f, // QUEST_REMAINS_GOHT + 24.0f, // QUEST_REMAINS_GYORG + 52.0f, // QUEST_REMAINS_TWINMOLD + 81.0f, // QUEST_SHIELD + 24.0f, // QUEST_SWORD + -78.0f, // QUEST_SONG_SONATA + -61.0f, // QUEST_SONG_LULLABY + -44.0f, // QUEST_SONG_BOSSA_NOVA + -24.0f, // QUEST_SONG_ELEGY + -6.0f, // QUEST_SONG_OATH + -3.0f, // QUEST_SONG_SARIA + -78.0f, // QUEST_SONG_TIME + -61.0f, // QUEST_SONG_HEALING + -44.0f, // QUEST_SONG_EPONA + -24.0f, // QUEST_SONG_SOARING + -6.0f, // QUEST_SONG_STORMS + -3.0f, // QUEST_SONG_SUN + -68.0f, // QUEST_BOMBERS_NOTEBOOK + 22.0f, // QUEST_QUIVER + 83.0f, // QUEST_BOMB_BAG + -67.0f, // QUEST_SKULL_TOKEN + -21.0f, // QUEST_HEART_PIECE +}; + +f32 sQuestStatusCursorsY[] = { + 33.0f, // QUEST_REMAINS_ODOLWA + 18.0f, // QUEST_REMAINS_GOHT + 18.0f, // QUEST_REMAINS_GYORG + 0.0f, // QUEST_REMAINS_TWINMOLD + -23.0f, // QUEST_SHIELD + -23.0f, // QUEST_SWORD + -29.0f, // QUEST_SONG_SONATA + -29.0f, // QUEST_SONG_LULLABY + -29.0f, // QUEST_SONG_BOSSA_NOVA + -29.0f, // QUEST_SONG_ELEGY + -29.0f, // QUEST_SONG_OATH + -29.0f, // QUEST_SONG_SARIA + -11.0f, // QUEST_SONG_TIME + -11.0f, // QUEST_SONG_HEALING + -11.0f, // QUEST_SONG_EPONA + -11.0f, // QUEST_SONG_SOARING + -11.0f, // QUEST_SONG_STORMS + -11.0f, // QUEST_SONG_SUN + 27.0f, // QUEST_BOMBERS_NOTEBOOK + -53.0f, // QUEST_QUIVER + -53.0f, // QUEST_BOMB_BAG + 14.0f, // QUEST_SKULL_TOKEN + 26.0f, // QUEST_HEART_PIECE +}; + +void KaleidoScope_UpdateCursorSize(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + s16 index; + + pauseCtx->cursorVtx[0].v.ob[0] = pauseCtx->cursorVtx[2].v.ob[0] = -8; + pauseCtx->cursorVtx[1].v.ob[0] = pauseCtx->cursorVtx[3].v.ob[0] = pauseCtx->cursorVtx[0].v.ob[0] + 16; + + pauseCtx->cursorVtx[0].v.ob[1] = pauseCtx->cursorVtx[1].v.ob[1] = 8; + pauseCtx->cursorVtx[2].v.ob[1] = pauseCtx->cursorVtx[3].v.ob[1] = pauseCtx->cursorVtx[0].v.ob[1] - 16; + + if (pauseCtx->cursorSpecialPos == 0) { + switch (pauseCtx->pageIndex) { + case PAUSE_ITEM: + pauseCtx->cursorX = sItemMaskCursorsX[pauseCtx->cursorXIndex[PAUSE_ITEM]]; + pauseCtx->cursorY = sItemMaskCursorsY[pauseCtx->cursorYIndex[PAUSE_ITEM]]; + pauseCtx->cursorWidth = 15.0f; + pauseCtx->cursorHeight = 15.0f; + break; + + case PAUSE_MAP: + if (!sInDungeonScene) { + if (IS_PAUSE_STATE_OWL_WARP(pauseCtx)) { + pauseCtx->cursorX = sOwlWarpWorldMapCursorsX[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; + pauseCtx->cursorY = sOwlWarpWorldMapCursorsY[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; + } else { + pauseCtx->cursorX = sWorldMapCursorsX[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; + pauseCtx->cursorY = sWorldMapCursorsY[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; + } + if (!IS_PAUSE_STATE_OWL_WARP(pauseCtx)) { + pauseCtx->cursorHeight = 10.0f; + pauseCtx->cursorWidth = 10.0f; + } else { + pauseCtx->cursorHeight = 15.0f; + pauseCtx->cursorWidth = 15.0f; + } + } else { + pauseCtx->cursorX = sDungeonMapCursorsX[pauseCtx->cursorPoint[PAUSE_MAP]]; + pauseCtx->cursorY = sDungeonMapCursorsY[pauseCtx->cursorPoint[PAUSE_MAP]]; + if (pauseCtx->cursorSlot[pauseCtx->pageIndex] >= DUNGEON_FLOOR_INDEX_4) { + // Floors + pauseCtx->cursorWidth = 18.0f; + pauseCtx->cursorHeight = 12.0f; + } else if (pauseCtx->cursorSlot[pauseCtx->pageIndex] == DUNGEON_STRAY_FAIRIES) { + // Stray Fairies + pauseCtx->cursorHeight = 12.0f; + pauseCtx->cursorWidth = 40.0f; + } else { + // Map, Compass, Boss Key + pauseCtx->cursorHeight = 15.0f; + pauseCtx->cursorWidth = 15.0f; + } + } + break; + + case PAUSE_QUEST: + if (!R_PAUSE_DBG_QUEST_CURSOR_ON) { + pauseCtx->cursorX = sQuestStatusCursorsX[pauseCtx->cursorPoint[PAUSE_QUEST]]; + pauseCtx->cursorY = sQuestStatusCursorsY[pauseCtx->cursorPoint[PAUSE_QUEST]]; + } else { + pauseCtx->cursorX = R_PAUSE_DBG_QUEST_CURSOR_X; + pauseCtx->cursorY = R_PAUSE_DBG_QUEST_CURSOR_Y; + } + pauseCtx->cursorHeight = 17.0f; + pauseCtx->cursorWidth = 17.0f; + if (pauseCtx->cursorSlot[pauseCtx->pageIndex] == QUEST_17) { + pauseCtx->cursorHeight = 25.0f; + pauseCtx->cursorWidth = 25.0f; + } else if (pauseCtx->cursorSlot[pauseCtx->pageIndex] <= QUEST_SWORD) { + pauseCtx->cursorHeight = 18.0f; + pauseCtx->cursorWidth = 18.0f; + } else if ((pauseCtx->cursorSlot[pauseCtx->pageIndex] >= QUEST_SONG_SONATA) && + (pauseCtx->cursorSlot[pauseCtx->pageIndex] <= QUEST_SONG_SUN)) { + pauseCtx->cursorHeight = 12.0f; + pauseCtx->cursorWidth = 12.0f; + } + break; + + case PAUSE_MASK: + pauseCtx->cursorX = sItemMaskCursorsX[pauseCtx->cursorXIndex[PAUSE_MASK]]; + pauseCtx->cursorY = sItemMaskCursorsY[pauseCtx->cursorYIndex[PAUSE_MASK]]; + pauseCtx->cursorWidth = 15.0f; + pauseCtx->cursorHeight = 15.0f; + break; + + default: + break; + } + + pauseCtx->cursorSpinPhase += 0x300; + } else { + if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) { + pauseCtx->cursorX = -93.0f; + } else { // PAUSE_CURSOR_PAGE_RIGHT + pauseCtx->cursorX = 101.0f; + } + pauseCtx->cursorSpinPhase += 0x300; + pauseCtx->cursorHeight = 16.0f; + pauseCtx->cursorWidth = 16.0f; + pauseCtx->cursorY = -4.0f; + } + + if (pauseCtx->cursorWidth < pauseCtx->cursorShrinkRate) { + pauseCtx->cursorWidth = 0; + } else { + pauseCtx->cursorWidth -= pauseCtx->cursorShrinkRate; + } + + if (pauseCtx->cursorHeight < pauseCtx->cursorShrinkRate) { + pauseCtx->cursorHeight = 0.0f; + } else { + pauseCtx->cursorHeight -= pauseCtx->cursorShrinkRate; + } + + if (pauseCtx->cursorShrinkRate != 0.0f) { + pauseCtx->cursorShrinkRate -= 1.0f; + } + + sCursorCirclesX[0] = Math_SinS(pauseCtx->cursorSpinPhase) * pauseCtx->cursorWidth; + sCursorCirclesX[1] = Math_SinS(pauseCtx->cursorSpinPhase + 0x4000) * pauseCtx->cursorWidth; + sCursorCirclesX[2] = Math_SinS(pauseCtx->cursorSpinPhase + 0x8000) * pauseCtx->cursorWidth; + sCursorCirclesX[3] = Math_SinS(pauseCtx->cursorSpinPhase + 0xC000) * pauseCtx->cursorWidth; + sCursorCirclesY[0] = Math_CosS(pauseCtx->cursorSpinPhase) * pauseCtx->cursorHeight; + sCursorCirclesY[1] = Math_CosS(pauseCtx->cursorSpinPhase + 0x4000) * pauseCtx->cursorHeight; + sCursorCirclesY[2] = Math_CosS(pauseCtx->cursorSpinPhase + 0x8000) * pauseCtx->cursorHeight; + sCursorCirclesY[3] = Math_CosS(pauseCtx->cursorSpinPhase + 0xC000) * pauseCtx->cursorHeight; +} + +void KaleidoScope_DrawCursor(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + s16 i; + + OPEN_DISPS(play->state.gfxCtx); + + if ((pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG) || + ((pauseCtx->pageIndex == PAUSE_QUEST) && ((pauseCtx->mainState <= PAUSE_MAIN_STATE_SONG_PLAYBACK) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_SONG_PROMPT) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG)))) { + gDPPipeSync(POLY_OPA_DISP++); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, sCursorPrimR, sCursorPrimG, sCursorPrimB, 255); + gDPSetEnvColor(POLY_OPA_DISP++, sCursorEnvR, sCursorEnvG, sCursorEnvB, 255); + + Matrix_Translate(pauseCtx->cursorX, pauseCtx->cursorY, -50.0f, MTXMODE_NEW); + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + + for (i = 0; i < 4; i++) { + Matrix_Push(); + Matrix_Translate(sCursorCirclesX[i], sCursorCirclesY[i], -50.0f, MTXMODE_APPLY); + MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx); + gDPPipeSync(POLY_OPA_DISP++); + gDPLoadTextureBlock(POLY_OPA_DISP++, gPauseMenuCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + gSPVertex(POLY_OPA_DISP++, &pauseCtx->cursorVtx[0], 4, 0); + gSP1Quadrangle(POLY_OPA_DISP++, 0, 2, 3, 1, 0); + Matrix_Pop(); + } + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +void KaleidoScope_DrawGameOver(PlayState* play) { + static s16 sGameOverUlt = 0; + GraphicsContext* gfxCtx = play->state.gfxCtx; + + OPEN_DISPS(gfxCtx); + + Gfx_SetupDL39_Opa(gfxCtx); + + gDPSetCycleType(POLY_OPA_DISP++, G_CYC_2CYCLE); + gDPSetRenderMode(POLY_OPA_DISP++, G_RM_PASS, G_RM_XLU_SURF2); + gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, 0, 0, 0, TEXEL0, PRIMITIVE, ENVIRONMENT, + COMBINED, ENVIRONMENT, COMBINED, 0, PRIMITIVE, 0); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 80, sGameOverPrimR, sGameOverPrimG, sGameOverPrimB, sGameOverPrimAlpha); + gDPSetEnvColor(POLY_OPA_DISP++, sGameOverEnvR, sGameOverEnvG, sGameOverEnvB, 255); + + sGameOverUlt -= 2; + + gDPLoadTextureBlock(POLY_OPA_DISP++, gGameOverP1Tex, G_IM_FMT_IA, G_IM_SIZ_8b, 64, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + + gDPLoadMultiBlock(POLY_OPA_DISP++, gGameOverMaskTex, 256, 1, G_IM_FMT_IA, G_IM_SIZ_8b, 64, 32, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, 5, G_TX_NOLOD, G_TX_NOLOD); + + gDPSetTileSize(POLY_OPA_DISP++, 1, 0, sGameOverUlt & 0x7F, 252, (sGameOverUlt & 0x7F) + 124); + + gSPTextureRectangle(POLY_OPA_DISP++, 0x100, sGameOverRectPosY << 2, 0x200, (sGameOverRectPosY + 32) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + + gDPLoadTextureBlock(POLY_OPA_DISP++, gGameOverP2Tex, G_IM_FMT_IA, G_IM_SIZ_8b, 64, 32, 0, + G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + + gSPTextureRectangle(POLY_OPA_DISP++, 0x200, sGameOverRectPosY << 2, 0x300, (sGameOverRectPosY + 32) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + + gDPLoadTextureBlock(POLY_OPA_DISP++, gGameOverP3Tex, G_IM_FMT_IA, G_IM_SIZ_8b, 64, 32, 0, + G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + + gSPTextureRectangle(POLY_OPA_DISP++, 0x300, sGameOverRectPosY << 2, 0x400, (sGameOverRectPosY + 32) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + + CLOSE_DISPS(gfxCtx); +} + +void KaleidoScope_Draw(PlayState* play) { + s32 pad; + PauseContext* pauseCtx = &play->pauseCtx; + InterfaceContext* interfaceCtx = &play->interfaceCtx; + + OPEN_DISPS(play->state.gfxCtx); + + gSPSegment(POLY_OPA_DISP++, 0x02, interfaceCtx->parameterSegment); + gSPSegment(POLY_OPA_DISP++, 0x08, pauseCtx->iconItemSegment); + gSPSegment(POLY_OPA_DISP++, 0x09, pauseCtx->iconItem24Segment); + gSPSegment(POLY_OPA_DISP++, 0x0A, pauseCtx->nameSegment); + gSPSegment(POLY_OPA_DISP++, 0x0C, pauseCtx->iconItemAltSegment); + gSPSegment(POLY_OPA_DISP++, 0x0D, pauseCtx->iconItemLangSegment); + gSPSegment(POLY_OPA_DISP++, 0x0B, pauseCtx->iconItemVtxSegment); + + if (pauseCtx->debugEditor == DEBUG_EDITOR_NONE) { + KaleidoScope_SetView(pauseCtx, pauseCtx->eye.x, pauseCtx->eye.y, pauseCtx->eye.z); + Gfx_SetupDL42_Opa(play->state.gfxCtx); + + if (!IS_PAUSE_STATE_OWL_WARP(pauseCtx)) { + // Draw Default or Game Over Menus + KaleidoScope_SetVertices(play, play->state.gfxCtx); + KaleidoScope_DrawPages(play, play->state.gfxCtx); + + Gfx_SetupDL42_Opa(play->state.gfxCtx); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + + KaleidoScope_SetView(pauseCtx, 0.0f, 0.0f, 64.0f); + + if (!IS_PAUSE_STATE_GAMEOVER(pauseCtx)) { + KaleidoScope_DrawInfoPanel(play); + } + + KaleidoScope_UpdateCursorSize(play); + + if (pauseCtx->state == PAUSE_STATE_MAIN) { + KaleidoScope_DrawCursor(play); + } + + if ((pauseCtx->state >= PAUSE_STATE_GAMEOVER_3) && (pauseCtx->state <= PAUSE_STATE_GAMEOVER_10) && + (play->gameOverCtx.state != GAMEOVER_INACTIVE)) { + KaleidoScope_DrawGameOver(play); + } + } else { + // Draw Owl Warp Menu + KaleidoScope_SetVertices(play, play->state.gfxCtx); + KaleidoScope_DrawPages(play, play->state.gfxCtx); + KaleidoScope_DrawOwlWarpMapPage(play); + + Gfx_SetupDL42_Opa(play->state.gfxCtx); + gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + + KaleidoScope_SetView(pauseCtx, 0.0f, 0.0f, 64.0f); + KaleidoScope_DrawOwlWarpInfoPanel(play); + KaleidoScope_UpdateCursorSize(play); + + if (pauseCtx->state == PAUSE_STATE_OWL_WARP_SELECT) { + KaleidoScope_DrawCursor(play); + } + } + } + + if ((pauseCtx->debugEditor == DEBUG_EDITOR_INVENTORY_INIT) || (pauseCtx->debugEditor == DEBUG_EDITOR_INVENTORY)) { + KaleidoScope_DrawInventoryEditor(play); + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +void KaleidoScope_GrayOutTextureRGBA32(u32* texture, u16 pixelCount) { + u32 rgb; + u32 gray; + u16 i; + s32 j; + + //! FAKE + if (texture == NULL) {} + + for (i = 0; i < pixelCount; i++) { + //! FAKE + j = i; + if ((texture[j] & 0xFFFFFF00) != 0) { + rgb = texture[j] >> 8; + gray = ((((rgb & 0xFF0000) >> 16) + ((rgb & 0xFF00) >> 7) + (rgb & 0xFF)) / 7) & 0xFF; + + rgb = gray; + rgb <<= 8; + rgb |= gray; + rgb <<= 8; + rgb |= gray; + + texture[j] = (rgb << 8) | (texture[j] & 0xFF); + } + } +} + +void KaleidoScope_UpdateOpening(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + + pauseCtx->eye.x += sPageSwitchEyeDx[pauseCtx->nextPageMode] * 2.0f; + pauseCtx->eye.z += sPageSwitchEyeDz[pauseCtx->nextPageMode] * 2.0f; + pauseCtx->switchPageTimer += 8; + + if (pauseCtx->switchPageTimer == 64) { + // Finished opening + Interface_UpdateButtonsAlt(play, 1); + + if (pauseCtx->cursorSpecialPos == 0) { + gSaveContext.buttonStatus[EQUIP_SLOT_B] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][0]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][1]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][1]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][1]; + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_ENABLED; + } else { + gSaveContext.buttonStatus[EQUIP_SLOT_B] = BTN_ENABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = BTN_DISABLED; + gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_DISABLED; + } + + pauseCtx->pageIndex = sPageSwitchNextPageIndex[pauseCtx->nextPageMode]; + pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE; + pauseCtx->state++; // PAUSE_STATE_MAIN + pauseCtx->alpha = 255; + Interface_SetBButtonInterfaceDoAction(play, DO_ACTION_RETURN); + } else if (pauseCtx->switchPageTimer == 64) { + pauseCtx->pageIndex = sPageSwitchNextPageIndex[pauseCtx->nextPageMode]; + pauseCtx->nextPageMode = (pauseCtx->pageIndex * 2) + 1; + } +} + +u16 sCursorPointsToOcarinaModes[] = { + OCARINA_MODE_WARP_TO_GREAT_BAY_COAST, OCARINA_MODE_WARP_TO_ZORA_CAPE, OCARINA_MODE_WARP_TO_SNOWHEAD, + OCARINA_MODE_WARP_TO_MOUNTAIN_VILLAGE, OCARINA_MODE_WARP_TO_SOUTH_CLOCK_TOWN, OCARINA_MODE_WARP_TO_MILK_ROAD, + OCARINA_MODE_WARP_TO_WOODFALL, OCARINA_MODE_WARP_TO_SOUTHERN_SWAMP, OCARINA_MODE_WARP_TO_IKANA_CANYON, + OCARINA_MODE_WARP_TO_STONE_TOWER, +}; + +void KaleidoScope_Update(PlayState* play) { + static s16 sUnpausedHudVisibility = HUD_VISIBILITY_IDLE; + static s16 sNextMainState = PAUSE_MAIN_STATE_IDLE; + static s16 sDelayTimer = 10; + static s16 sGameOverColorTimer = 0; + static s16 sStickXRepeatTimer = 0; + static s16 sStickYRepeatTimer = 0; + static s16 sStickXRepeatState = 0; + static s16 sStickYRepeatState = 0; + PauseContext* pauseCtx = &play->pauseCtx; + InterfaceContext* interfaceCtx = &play->interfaceCtx; + MessageContext* msgCtx = &play->msgCtx; + GameOverContext* gameOverCtx = &play->gameOverCtx; + SramContext* sramCtx = &play->sramCtx; + Input* input = CONTROLLER1(&play->state); + size_t size0; + size_t size1; + size_t size2; + u16 itemId; + u16 worldMapCursorPoint; + void* iconItemLangSegment; + s16 stepR; + s16 stepG; + s16 stepB; + s16 stepA; + s16 stickAdjX = input->rel.stick_x; + + MapDisp_UpdateDungeonMap(play); + + pauseCtx->stickAdjX = input->rel.stick_x; + pauseCtx->stickAdjY = input->rel.stick_y; + + switch (pauseCtx->state) { + case PAUSE_STATE_OPENING_2: + sUnpausedHudVisibility = gSaveContext.hudVisibility; + sPauseMenuVerticalOffset = -6240.0f; + + sUnpausedButtonStatus[EQUIP_SLOT_B] = gSaveContext.buttonStatus[EQUIP_SLOT_B]; + sUnpausedButtonStatus[EQUIP_SLOT_C_LEFT] = gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT]; + sUnpausedButtonStatus[EQUIP_SLOT_C_DOWN] = gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN]; + sUnpausedButtonStatus[EQUIP_SLOT_C_RIGHT] = gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT]; + sUnpausedButtonStatus[EQUIP_SLOT_A] = gSaveContext.buttonStatus[EQUIP_SLOT_A]; + + pauseCtx->cursorXIndex[PAUSE_MAP] = 0; + pauseCtx->cursorSlot[PAUSE_MAP] = R_PLAYER_FLOOR_REVERSE_INDEX + DUNGEON_FLOOR_INDEX_4; + pauseCtx->cursorPoint[PAUSE_MAP] = pauseCtx->cursorMapDungeonItem = + R_PLAYER_FLOOR_REVERSE_INDEX + DUNGEON_FLOOR_INDEX_4; + + sPauseCursorLeftX = -175; + sPauseCursorRightX = 155; + pauseCtx->roll = -314.0f; + + pauseCtx->iconItemSegment = (void*)ALIGN16((uintptr_t)play->objectCtx.spaceStart); + size0 = SEGMENT_ROM_SIZE(icon_item_static_syms); + CmpDma_LoadAllFiles(SEGMENT_ROM_START(icon_item_static_yar), pauseCtx->iconItemSegment, size0); + + gSegments[0x08] = OS_K0_TO_PHYSICAL(pauseCtx->iconItemSegment); + + for (itemId = 0; itemId <= ITEM_BOW_FIRE; itemId++) { + if (!gPlayerFormItemRestrictions[GET_PLAYER_FORM][(s32)itemId]) { + KaleidoScope_GrayOutTextureRGBA32(Lib_SegmentedToVirtual(gItemIcons[(s32)itemId]), + ICON_ITEM_TEX_WIDTH * ICON_ITEM_TEX_HEIGHT); + } + } + + pauseCtx->iconItem24Segment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemSegment + size0); + size1 = SEGMENT_ROM_SIZE(icon_item_24_static_syms); + CmpDma_LoadAllFiles(SEGMENT_ROM_START(icon_item_24_static_yar), pauseCtx->iconItem24Segment, size1); + + pauseCtx->iconItemAltSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItem24Segment + size1); + if (Map_CurRoomHasMapI(play)) { + size_t size = SEGMENT_ROM_SIZE(icon_item_dungeon_static); + + DmaMgr_RequestSync(pauseCtx->iconItemAltSegment, SEGMENT_ROM_START(icon_item_dungeon_static), size); + iconItemLangSegment = + MapDisp_AllocDungeonMap(play, (void*)ALIGN16((uintptr_t)pauseCtx->iconItemAltSegment + size)); + sInDungeonScene = true; + } else { + size_t size; + + sInDungeonScene = false; + size = SEGMENT_ROM_SIZE(icon_item_field_static); + DmaMgr_RequestSync(pauseCtx->iconItemAltSegment, SEGMENT_ROM_START(icon_item_field_static), size); + iconItemLangSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemAltSegment + size); + } + + pauseCtx->iconItemLangSegment = iconItemLangSegment; + size2 = SEGMENT_ROM_SIZE(icon_item_jpn_static); + DmaMgr_RequestSync(pauseCtx->iconItemLangSegment, SEGMENT_ROM_START(icon_item_jpn_static), size2); + + pauseCtx->nameSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemLangSegment + size2); + Interface_SetAButtonDoAction(play, DO_ACTION_INFO); + + //! note: `worldMapArea` never set to a value other than 0 + if (((void)0, gSaveContext.worldMapArea) < 22) { + Kaleido_LoadMapNameStaticLarge(pauseCtx->nameSegment + 0x400, ((void)0, gSaveContext.worldMapArea)); + } + + pauseCtx->iconItemVtxSegment = (void*)ALIGN16((uintptr_t)pauseCtx->nameSegment + 0xA00); + DmaMgr_RequestSync(pauseCtx->iconItemVtxSegment, SEGMENT_ROM_START(icon_item_vtx_static), + SEGMENT_ROM_SIZE(icon_item_vtx_static)); + + pauseCtx->unk_2B6 = 255; + pauseCtx->unk_2B7 = 255; + pauseCtx->unk_2B8 = 255; + pauseCtx->state = PAUSE_STATE_OPENING_3; + break; + + case PAUSE_STATE_OPENING_3: + pauseCtx->infoPanelOffsetY += 10; + pauseCtx->itemPageRoll = pauseCtx->mapPageRoll = pauseCtx->questPageRoll = pauseCtx->maskPageRoll -= 40.0f; + + interfaceCtx->startAlpha += 63; + sPauseCursorLeftX += TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX += TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + pauseCtx->alpha += 31; + if (pauseCtx->itemPageRoll == 0) { + interfaceCtx->startAlpha = 255; + sPauseMenuVerticalOffset = 0.0f; + pauseCtx->state = PAUSE_STATE_OPENING_4; + } + + KaleidoScope_UpdateOpening(play); + break; + + case PAUSE_STATE_OPENING_4: + pauseCtx->alpha += 31; + KaleidoScope_UpdateOpening(play); + + if (pauseCtx->state == PAUSE_STATE_MAIN) { + KaleidoScope_UpdateNamePanel(play); + } + break; + + case PAUSE_STATE_MAIN: + switch (pauseCtx->mainState) { + case PAUSE_MAIN_STATE_IDLE: + if (!pauseCtx->itemDescriptionOn && + (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_B))) { + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->state = PAUSE_STATE_UNPAUSE_SETUP; + sPauseMenuVerticalOffset = -6240.0f; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + } + break; + + case PAUSE_MAIN_STATE_SWITCHING_PAGE: + KaleidoScope_UpdateSwitchPage(play, input); + break; + + case PAUSE_MAIN_STATE_SONG_PLAYBACK: + // Song is in playback + pauseCtx->ocarinaStaff = AudioOcarina_GetPlaybackStaff(); + if (pauseCtx->ocarinaStaff->state == 0) { + // Song playback is finished, give song prompt to player + pauseCtx->mainState = PAUSE_MAIN_STATE_SONG_PROMPT_INIT; + AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF); + } + break; + + case PAUSE_MAIN_STATE_EQUIP_ITEM: + KaleidoScope_UpdateItemEquip(play); + break; + + case PAUSE_MAIN_STATE_SONG_PROMPT_INIT: + break; + + case PAUSE_MAIN_STATE_SONG_PROMPT: + pauseCtx->ocarinaStaff = AudioOcarina_GetPlayingStaff(); + + if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_B)) { + // Abort having the player play the song and close the pause menu + AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF); + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->state = PAUSE_STATE_UNPAUSE_SETUP; + sPauseMenuVerticalOffset = -6240.0f; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE; + } else if (pauseCtx->ocarinaStaff->state == pauseCtx->ocarinaSongIndex) { + // The player successfully played the song + Audio_PlaySfx(NA_SE_SY_TRE_BOX_APPEAR); + sNextMainState = PAUSE_MAIN_STATE_IDLE; + sDelayTimer = 30; + pauseCtx->mainState = PAUSE_MAIN_STATE_SONG_PROMPT_DONE; + } else if (pauseCtx->ocarinaStaff->state == 0xFF) { + // The player failed to play the song + Audio_PlaySfx(NA_SE_SY_OCARINA_ERROR); + sNextMainState = PAUSE_MAIN_STATE_SONG_PROMPT_INIT; + sDelayTimer = 20; + pauseCtx->mainState = PAUSE_MAIN_STATE_SONG_PROMPT_DONE; + } + break; + + case PAUSE_MAIN_STATE_SONG_PROMPT_DONE: + sDelayTimer--; + if (sDelayTimer == 0) { + pauseCtx->mainState = sNextMainState; + if (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) { + AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF); + } + } + break; + + case PAUSE_MAIN_STATE_SONG_PROMPT_UNUSED: + break; + + case PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG: + if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_B)) { + AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF); + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->state = PAUSE_STATE_UNPAUSE_SETUP; + sPauseMenuVerticalOffset = -6240.0f; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE; + } + break; + + case PAUSE_MAIN_STATE_SONG_PLAYBACK_INIT: + break; + + case PAUSE_MAIN_STATE_EQUIP_MASK: + KaleidoScope_UpdateMaskEquip(play); + break; + + case PAUSE_MAIN_STATE_BOMBERS_NOTEBOOK_OPEN: + if (!play->pauseCtx.bombersNotebookOpen) { + pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE; + } + break; + + default: + pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE; + break; + } + break; + + case PAUSE_STATE_SAVEPROMPT: + switch (pauseCtx->savePromptState) { + case PAUSE_SAVEPROMPT_STATE_APPEARING: + pauseCtx->roll -= 78.5f; + sPauseCursorLeftX -= TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX -= TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + if (pauseCtx->roll <= -628.0f) { + pauseCtx->roll = -628.0f; + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_1; + } + break; + + case PAUSE_SAVEPROMPT_STATE_1: + if (CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_CUP)) { + if (pauseCtx->promptChoice != PAUSE_PROMPT_YES) { + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_RETURN_TO_MENU; + } else { + Audio_PlaySfx(NA_SE_SY_PIECE_OF_HEART); + Play_SaveCycleSceneFlags(play); + gSaveContext.save.saveInfo.playerData.savedSceneId = play->sceneId; + func_8014546C(sramCtx); + if (!gSaveContext.flashSaveAvailable) { + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_5; + } else { + Sram_SetFlashPagesDefault(sramCtx, gFlashSaveStartPages[gSaveContext.fileNum], + gFlashSaveNumPages[gSaveContext.fileNum]); + Sram_StartWriteToFlashDefault(sramCtx); + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_4; + } + sDelayTimer = 90; + } + } else if (CHECK_BTN_ALL(input->press.button, BTN_START)) { + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_3; + sPauseMenuVerticalOffset = -6240.0f; + D_8082B90C = pauseCtx->roll; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + } else if (CHECK_BTN_ALL(input->press.button, BTN_B)) { + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_RETURN_TO_MENU; + D_8082B90C = pauseCtx->roll; + } + break; + + case PAUSE_SAVEPROMPT_STATE_4: + if (sramCtx->status == 0) { + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_5; + } + break; + + case PAUSE_SAVEPROMPT_STATE_5: + if (CHECK_BTN_ALL(input->press.button, BTN_B) || CHECK_BTN_ALL(input->press.button, BTN_A) || + CHECK_BTN_ALL(input->press.button, BTN_START) || (--sDelayTimer == 0)) { + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_3; + sPauseMenuVerticalOffset = -6240.0f; + D_8082B90C = pauseCtx->roll; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + } + break; + + case PAUSE_SAVEPROMPT_STATE_3: + case PAUSE_SAVEPROMPT_STATE_7: + if (pauseCtx->roll != (D_8082B90C + 160.0f)) { + pauseCtx->itemPageRoll = pauseCtx->mapPageRoll = pauseCtx->questPageRoll = + pauseCtx->maskPageRoll += 40.0f; + pauseCtx->roll += 40.0f; + pauseCtx->infoPanelOffsetY -= 10; + sPauseCursorLeftX -= TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX -= TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + pauseCtx->alpha -= 63; + if (pauseCtx->roll == (D_8082B90C + 160.0f)) { + pauseCtx->alpha = 0; + } + } else { + pauseCtx->debugEditor = DEBUG_EDITOR_NONE; + pauseCtx->state = PAUSE_STATE_UNPAUSE_CLOSE; + pauseCtx->itemPageRoll = pauseCtx->mapPageRoll = pauseCtx->questPageRoll = + pauseCtx->maskPageRoll = 160.0f; + pauseCtx->roll = -434.0f; + pauseCtx->namedItem = PAUSE_ITEM_NONE; + pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE; + } + break; + + case PAUSE_SAVEPROMPT_STATE_RETURN_TO_MENU: + pauseCtx->roll += 78.5f; + sPauseCursorLeftX += TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX += TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + + if (pauseCtx->roll >= -314.0f) { + pauseCtx->state = PAUSE_STATE_MAIN; + pauseCtx->savePromptState = PAUSE_SAVEPROMPT_STATE_APPEARING; + pauseCtx->roll = -314.0f; + pauseCtx->itemPageRoll = pauseCtx->mapPageRoll = pauseCtx->questPageRoll = + pauseCtx->maskPageRoll = 0.0f; + Interface_SetAButtonDoAction(play, DO_ACTION_INFO); + gSaveContext.buttonStatus[EQUIP_SLOT_B] = + gPageSwitchNextButtonStatus[pauseCtx->pageIndex + 1][0]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = + gPageSwitchNextButtonStatus[pauseCtx->pageIndex + 1][1]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = + gPageSwitchNextButtonStatus[pauseCtx->pageIndex + 1][1]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = + gPageSwitchNextButtonStatus[pauseCtx->pageIndex + 1][1]; + if ((pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) || + (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT)) { + KaleidoScope_MoveCursorToSpecialPos(play, pauseCtx->cursorSpecialPos); + } else { + KaleidoScope_MoveCursorFromSpecialPos(play); + } + } + break; + + case PAUSE_SAVEPROMPT_STATE_6: + if (interfaceCtx->screenFillAlpha != 255) { + interfaceCtx->screenFillAlpha += 10; + if (interfaceCtx->screenFillAlpha >= 255) { + interfaceCtx->screenFillAlpha = 255; + pauseCtx->state = PAUSE_STATE_OFF; + GameState_SetFramerateDivisor(&play->state, 3); + R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_UNK4; + Object_LoadAll(&play->objectCtx); + BgCheck_InitCollisionHeaders(&play->colCtx, play); + STOP_GAMESTATE(&play->state); + SET_NEXT_GAMESTATE(&play->state, TitleSetup_Init, sizeof(TitleSetupState)); + Audio_MuteAllSeqExceptSystemAndOcarina(20); + gSaveContext.seqId = (u8)NA_BGM_DISABLED; + gSaveContext.ambienceId = AMBIENCE_ID_DISABLED; + } + } + break; + } + break; + + case PAUSE_STATE_GAMEOVER_2: + pauseCtx->cursorSlot[PAUSE_MAP] = R_PLAYER_FLOOR_REVERSE_INDEX + DUNGEON_FLOOR_INDEX_4; + pauseCtx->cursorPoint[PAUSE_MAP] = R_PLAYER_FLOOR_REVERSE_INDEX + DUNGEON_FLOOR_INDEX_4; + sPauseCursorLeftX = -175; + sPauseCursorRightX = 155; + pauseCtx->roll = -434.0f; + Interface_SetHudVisibility(HUD_VISIBILITY_NONE); + + pauseCtx->iconItemSegment = + (void*)(((uintptr_t)play->objectCtx.spaceStart + 0x30) & ~0x3F); // Messed up ALIGN64 + size0 = SEGMENT_ROM_SIZE(icon_item_static_syms); + CmpDma_LoadAllFiles(SEGMENT_ROM_START(icon_item_static_yar), pauseCtx->iconItemSegment, size0); + + pauseCtx->iconItem24Segment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemSegment + size0); + size1 = SEGMENT_ROM_SIZE(icon_item_24_static_syms); + CmpDma_LoadAllFiles(SEGMENT_ROM_START(icon_item_24_static_yar), pauseCtx->iconItem24Segment, size1); + + pauseCtx->iconItemAltSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItem24Segment + size1); + size2 = SEGMENT_ROM_SIZE(icon_item_gameover_static); + DmaMgr_RequestSync(pauseCtx->iconItemAltSegment, SEGMENT_ROM_START(icon_item_gameover_static), size2); + + pauseCtx->iconItemLangSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemAltSegment + size2); + DmaMgr_RequestSync(pauseCtx->iconItemLangSegment, SEGMENT_ROM_START(icon_item_jpn_static), + SEGMENT_ROM_SIZE(icon_item_jpn_static)); + + gSaveContext.timerStates[TIMER_ID_MOON_CRASH] = TIMER_STATE_OFF; + + sGameOverPrimR = 255; + sGameOverPrimG = 130; + sGameOverPrimB = 0; + sGameOverPrimAlpha = 0; + sGameOverEnvR = 30; + sGameOverEnvG = 0; + sGameOverEnvB = 0; + sGameOverRectPosY = 98; + sGameOverColorTimer = 30; + + pauseCtx->promptChoice = PAUSE_PROMPT_YES; + pauseCtx->state++; + if (gameOverCtx->state == GAMEOVER_INACTIVE) { + pauseCtx->state++; // GAMEOVER_DEATH_START + } + break; + + case PAUSE_STATE_GAMEOVER_3: + stepR = ABS_ALT(sGameOverPrimR - 30) / sGameOverColorTimer; + stepG = ABS_ALT(sGameOverPrimG - 0) / sGameOverColorTimer; + stepB = ABS_ALT(sGameOverPrimB - 0) / sGameOverColorTimer; + stepA = ABS_ALT(sGameOverPrimAlpha - 255) / sGameOverColorTimer; + if (sGameOverPrimR >= 30) { + sGameOverPrimR -= stepR; + } else { + sGameOverPrimR += stepR; + } + if (sGameOverPrimG >= 0) { + sGameOverPrimG -= stepG; + } else { + sGameOverPrimG += stepG; + } + if (sGameOverPrimB >= 0) { + sGameOverPrimB -= stepB; + } else { + sGameOverPrimB += stepB; + } + if (sGameOverPrimAlpha >= 255) { + sGameOverPrimAlpha -= stepA; + } else { + sGameOverPrimAlpha += stepA; + } + + stepR = ABS_ALT(sGameOverEnvR - 255) / sGameOverColorTimer; + stepG = ABS_ALT(sGameOverEnvG - 130) / sGameOverColorTimer; + stepB = ABS_ALT(sGameOverEnvB - 0) / sGameOverColorTimer; + if (sGameOverEnvR >= 255) { + sGameOverEnvR -= stepR; + } else { + sGameOverEnvR += stepR; + } + if (sGameOverEnvG >= 130) { + sGameOverEnvG -= stepG; + } else { + sGameOverEnvG += stepG; + } + if (sGameOverEnvB >= 0) { + sGameOverEnvB -= stepB; + } else { + sGameOverEnvB += stepB; + } + + sGameOverColorTimer--; + if (sGameOverColorTimer == 0) { + sGameOverPrimR = 30; + sGameOverPrimG = 0; + sGameOverPrimB = 0; + sGameOverPrimAlpha = 255; + + sGameOverEnvR = 255; + sGameOverEnvG = 130; + sGameOverEnvB = 0; + + sGameOverColorTimer = 40; + pauseCtx->state++; + } + break; + + case PAUSE_STATE_GAMEOVER_4: + sGameOverColorTimer--; + if (sGameOverColorTimer == 0) { + pauseCtx->state = PAUSE_STATE_GAMEOVER_5; + } + break; + + case PAUSE_STATE_GAMEOVER_5: + pauseCtx->infoPanelOffsetY += 10; + pauseCtx->roll -= 40.0f; + pauseCtx->itemPageRoll = pauseCtx->mapPageRoll = pauseCtx->questPageRoll = pauseCtx->maskPageRoll = + pauseCtx->roll; + interfaceCtx->startAlpha += 63; + sGameOverRectPosY -= 3; + sPauseCursorLeftX += TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX += TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + pauseCtx->alpha += 31; + if (pauseCtx->roll < -628.0f) { + pauseCtx->roll = -628.0f; + interfaceCtx->startAlpha = 255; + sGameOverRectPosY = 66; + sPauseMenuVerticalOffset = 0.0f; + pauseCtx->alpha = 255; + if (gameOverCtx->state == GAMEOVER_INACTIVE) { + pauseCtx->state = PAUSE_STATE_GAMEOVER_SAVE_PROMPT; + } else { + pauseCtx->state = PAUSE_STATE_GAMEOVER_CONTINUE_PROMPT; + } + } + break; + + case PAUSE_STATE_GAMEOVER_SAVE_PROMPT: + if (CHECK_BTN_ALL(input->press.button, BTN_A)) { + if (pauseCtx->promptChoice != PAUSE_PROMPT_YES) { + pauseCtx->promptChoice = PAUSE_PROMPT_YES; + Audio_PlaySfx(NA_SE_SY_DECIDE); + pauseCtx->state = PAUSE_STATE_OFF; + GameState_SetFramerateDivisor(&play->state, 3); + R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_UNK4; + Object_LoadAll(&play->objectCtx); + BgCheck_InitCollisionHeaders(&play->colCtx, play); + } else { + Audio_PlaySfx(NA_SE_SY_PIECE_OF_HEART); + pauseCtx->promptChoice = PAUSE_PROMPT_YES; + Play_SaveCycleSceneFlags(play); + gSaveContext.save.saveInfo.playerData.savedSceneId = play->sceneId; + gSaveContext.save.saveInfo.playerData.health = 0x30; + func_8014546C(sramCtx); + if (!gSaveContext.flashSaveAvailable) { + pauseCtx->state = PAUSE_STATE_GAMEOVER_8; + } else { + Sram_SetFlashPagesDefault(sramCtx, gFlashSaveStartPages[gSaveContext.fileNum], + gFlashSaveNumPages[gSaveContext.fileNum]); + Sram_StartWriteToFlashDefault(sramCtx); + pauseCtx->state = PAUSE_STATE_GAMEOVER_7; + } + sDelayTimer = 90; + } + } else if ((pauseCtx->promptChoice == PAUSE_PROMPT_YES) && (stickAdjX >= 30)) { + Audio_PlaySfx(NA_SE_SY_CURSOR); + pauseCtx->promptChoice = PAUSE_PROMPT_NO; + } else if ((pauseCtx->promptChoice != PAUSE_PROMPT_YES) && (stickAdjX <= -30)) { + Audio_PlaySfx(NA_SE_SY_CURSOR); + pauseCtx->promptChoice = PAUSE_PROMPT_YES; + } + break; + + case PAUSE_STATE_GAMEOVER_7: + if (sramCtx->status == 0) { + pauseCtx->state = PAUSE_STATE_OFF; + GameState_SetFramerateDivisor(&play->state, 3); + R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_UNK4; + Object_LoadAll(&play->objectCtx); + BgCheck_InitCollisionHeaders(&play->colCtx, play); + } + break; + + case PAUSE_STATE_GAMEOVER_8: + sDelayTimer--; + if (sDelayTimer == 0) { + pauseCtx->state = PAUSE_STATE_GAMEOVER_CONTINUE_PROMPT; + gameOverCtx->state++; + } else if ((sDelayTimer <= 80) && + (CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_START))) { + pauseCtx->state = PAUSE_STATE_GAMEOVER_CONTINUE_PROMPT; + gameOverCtx->state++; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + } + break; + + case PAUSE_STATE_GAMEOVER_CONTINUE_PROMPT: + if (CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_START)) { + if (pauseCtx->promptChoice == PAUSE_PROMPT_YES) { + Audio_PlaySfx(NA_SE_SY_PIECE_OF_HEART); + Play_SaveCycleSceneFlags(play); + if (gSaveContext.save.entrance == ENTRANCE(UNSET_0D, 0)) {} + } else { // PAUSE_PROMPT_NO + Audio_PlaySfx(NA_SE_SY_DECIDE); + } + pauseCtx->state = PAUSE_STATE_GAMEOVER_10; + } + break; + + case PAUSE_STATE_GAMEOVER_10: + if (interfaceCtx->screenFillAlpha != 255) { + interfaceCtx->screenFillAlpha += 10; + if (interfaceCtx->screenFillAlpha >= 255) { + interfaceCtx->screenFillAlpha = 255; + + pauseCtx->state = PAUSE_STATE_OFF; + GameState_SetFramerateDivisor(&play->state, 3); + R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_UNK4; + Object_LoadAll(&play->objectCtx); + BgCheck_InitCollisionHeaders(&play->colCtx, play); + + if (pauseCtx->promptChoice == PAUSE_PROMPT_YES) { + func_80169FDC(play); + gSaveContext.respawnFlag = -2; + gSaveContext.nextTransitionType = TRANS_TYPE_FADE_BLACK; + gSaveContext.save.saveInfo.playerData.health = 0x30; + Audio_SetSpec(0xA); + gSaveContext.healthAccumulator = 0; + gSaveContext.magicState = MAGIC_STATE_IDLE; + gSaveContext.magicFlag = 0; + gSaveContext.magicCapacity = 0; + gSaveContext.magicFillTarget = gSaveContext.save.saveInfo.playerData.magic; + gSaveContext.save.saveInfo.playerData.magicLevel = 0; + gSaveContext.save.saveInfo.playerData.magic = 0; + } else { // PAUSE_PROMPT_NO + STOP_GAMESTATE(&play->state); + SET_NEXT_GAMESTATE(&play->state, TitleSetup_Init, sizeof(TitleSetupState)); + } + } + } + break; + + case PAUSE_STATE_OWL_WARP_2: + sPauseMenuVerticalOffset = -6240.0f; + + sUnpausedButtonStatus[EQUIP_SLOT_B] = gSaveContext.buttonStatus[EQUIP_SLOT_B]; + sUnpausedButtonStatus[EQUIP_SLOT_C_LEFT] = gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT]; + sUnpausedButtonStatus[EQUIP_SLOT_C_DOWN] = gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN]; + sUnpausedButtonStatus[EQUIP_SLOT_C_RIGHT] = gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT]; + sUnpausedButtonStatus[EQUIP_SLOT_A] = gSaveContext.buttonStatus[EQUIP_SLOT_A]; + + pauseCtx->cursorXIndex[PAUSE_MAP] = 0; + pauseCtx->cursorSlot[PAUSE_MAP] = R_PLAYER_FLOOR_REVERSE_INDEX + DUNGEON_FLOOR_INDEX_4; + pauseCtx->cursorPoint[PAUSE_MAP] = pauseCtx->cursorMapDungeonItem = + R_PLAYER_FLOOR_REVERSE_INDEX + DUNGEON_FLOOR_INDEX_4; + + sPauseCursorLeftX = -175; + sPauseCursorRightX = 155; + + pauseCtx->iconItemSegment = (void*)ALIGN16((uintptr_t)play->objectCtx.spaceStart); + size0 = SEGMENT_ROM_SIZE(icon_item_static_syms); + CmpDma_LoadAllFiles(SEGMENT_ROM_START(icon_item_static_yar), pauseCtx->iconItemSegment, size0); + + pauseCtx->iconItemAltSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemSegment + size0); + sInDungeonScene = false; + size1 = SEGMENT_ROM_SIZE(icon_item_field_static); + DmaMgr_RequestSync(pauseCtx->iconItemAltSegment, SEGMENT_ROM_START(icon_item_field_static), size1); + + pauseCtx->iconItemLangSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemAltSegment + size1); + size2 = SEGMENT_ROM_SIZE(icon_item_jpn_static); + DmaMgr_RequestSync(pauseCtx->iconItemLangSegment, SEGMENT_ROM_START(icon_item_jpn_static), size2); + + pauseCtx->nameSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemLangSegment + size2); + Interface_SetAButtonDoAction(play, DO_ACTION_WARP); + worldMapCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; + Kaleido_LoadMapNameStatic(pauseCtx->nameSegment, worldMapCursorPoint); + + pauseCtx->iconItemVtxSegment = (void*)ALIGN16((uintptr_t)pauseCtx->nameSegment + 0xA00); + DmaMgr_RequestSync(pauseCtx->iconItemVtxSegment, SEGMENT_ROM_START(icon_item_vtx_static), + SEGMENT_ROM_SIZE(icon_item_vtx_static)); + + pauseCtx->state = PAUSE_STATE_OWL_WARP_3; + sGameOverRectPosY = 98; + pauseCtx->promptChoice = PAUSE_PROMPT_YES; + break; + + case PAUSE_STATE_OWL_WARP_3: + R_PAUSE_OWL_WARP_ALPHA += 20; + pauseCtx->infoPanelOffsetY += 10; + pauseCtx->mapPageRoll -= 40.0f; + interfaceCtx->startAlpha += 63; + sGameOverRectPosY -= 3; + sPauseCursorLeftX += TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX += TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + pauseCtx->alpha += 31; + + if (pauseCtx->mapPageRoll == 0) { + interfaceCtx->startAlpha = 255; + sPauseMenuVerticalOffset = 0.0f; + pauseCtx->alpha = 255; + pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE; + pauseCtx->cursorSpecialPos = 0; + pauseCtx->state = PAUSE_STATE_OWL_WARP_SELECT; + R_PAUSE_OWL_WARP_ALPHA = 120; + } + break; + + case PAUSE_STATE_OWL_WARP_SELECT: + if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_B)) { + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->state = PAUSE_STATE_OWL_WARP_6; + sPauseMenuVerticalOffset = -6240.0f; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + play->msgCtx.ocarinaMode = OCARINA_MODE_END; + gSaveContext.prevHudVisibility = HUD_VISIBILITY_ALL; + } else if (CHECK_BTN_ALL(input->press.button, BTN_A)) { + Audio_PlaySfx(NA_SE_SY_DECIDE); + Message_StartTextbox(play, 0x1B93, NULL); + pauseCtx->state = PAUSE_STATE_OWL_WARP_CONFIRM; + } else { + KaleidoScope_UpdateOwlWarpNamePanel(play); + } + break; + + case PAUSE_STATE_OWL_WARP_CONFIRM: + if (CHECK_BTN_ALL(input->press.button, BTN_A)) { + msgCtx->msgLength = 0; + msgCtx->msgMode = MSGMODE_NONE; + if (msgCtx->choiceIndex == 0) { + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->state = PAUSE_STATE_OWL_WARP_6; + sPauseMenuVerticalOffset = -6240.0f; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + play->msgCtx.ocarinaMode = sCursorPointsToOcarinaModes[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]; + Audio_PlaySfx(NA_SE_SY_DECIDE); + } else { + pauseCtx->state = PAUSE_STATE_OWL_WARP_SELECT; + Interface_SetAButtonDoAction(play, DO_ACTION_WARP); + Audio_PlaySfx(NA_SE_SY_MESSAGE_PASS); + } + } else if (CHECK_BTN_ALL(input->press.button, BTN_B)) { + msgCtx->msgLength = 0; + msgCtx->msgMode = MSGMODE_NONE; + pauseCtx->state = PAUSE_STATE_OWL_WARP_SELECT; + Audio_PlaySfx(NA_SE_SY_MESSAGE_PASS); + } else if (CHECK_BTN_ALL(input->press.button, BTN_START)) { + msgCtx->msgLength = 0; + msgCtx->msgMode = MSGMODE_NONE; + Interface_SetAButtonDoAction(play, DO_ACTION_NONE); + pauseCtx->state = PAUSE_STATE_OWL_WARP_6; + sPauseMenuVerticalOffset = -6240.0f; + Audio_PlaySfx_PauseMenuOpenOrClose(SFX_PAUSE_MENU_CLOSE); + play->msgCtx.ocarinaMode = OCARINA_MODE_END; + gSaveContext.prevHudVisibility = HUD_VISIBILITY_ALL; + } + break; + + case PAUSE_STATE_OWL_WARP_6: + if (pauseCtx->mapPageRoll != 160.0f) { + R_PAUSE_OWL_WARP_ALPHA -= 60; + if (R_PAUSE_OWL_WARP_ALPHA <= 0) { + R_PAUSE_OWL_WARP_ALPHA = 0; + } + pauseCtx->infoPanelOffsetY -= 10; + pauseCtx->mapPageRoll += 40.0f; + interfaceCtx->startAlpha -= 63; + sPauseCursorLeftX -= TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX -= TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + pauseCtx->alpha -= 63; + if (pauseCtx->mapPageRoll == 160.0f) { + pauseCtx->alpha = 0; + } + } else { + pauseCtx->debugEditor = DEBUG_EDITOR_NONE; + pauseCtx->state = PAUSE_STATE_UNPAUSE_CLOSE; + pauseCtx->itemPageRoll = pauseCtx->mapPageRoll = pauseCtx->questPageRoll = pauseCtx->maskPageRoll = + 160.0f; + pauseCtx->namedItem = PAUSE_ITEM_NONE; + interfaceCtx->startAlpha = 0; + pauseCtx->pageIndex = pauseCtx->unk_2C8; + pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = pauseCtx->unk_2CA; + } + break; + + case PAUSE_STATE_UNPAUSE_SETUP: + if (pauseCtx->itemPageRoll != 160.0f) { + pauseCtx->infoPanelOffsetY -= 10; + pauseCtx->itemPageRoll = pauseCtx->mapPageRoll = pauseCtx->questPageRoll = pauseCtx->maskPageRoll += + 40.0f; + interfaceCtx->startAlpha -= 63; + sPauseCursorLeftX -= TRUNCF_BINANG(sPauseCursorLeftMoveOffsetX / 4); + sPauseCursorRightX -= TRUNCF_BINANG(sPauseCursorRightMoveOffsetX / 4); + pauseCtx->alpha -= 63; + if (pauseCtx->itemPageRoll == 160.0f) { + pauseCtx->alpha = 0; + } + } else { + pauseCtx->debugEditor = DEBUG_EDITOR_NONE; + pauseCtx->state = PAUSE_STATE_UNPAUSE_CLOSE; + pauseCtx->maskPageRoll = 160.0f; + pauseCtx->questPageRoll = 160.0f; + pauseCtx->mapPageRoll = 160.0f; + pauseCtx->itemPageRoll = 160.0f; + pauseCtx->namedItem = PAUSE_ITEM_NONE; + interfaceCtx->startAlpha = 0; + } + break; + + case PAUSE_STATE_UNPAUSE_CLOSE: + pauseCtx->state = PAUSE_STATE_OFF; + GameState_SetFramerateDivisor(&play->state, 3); + R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_UNK4; + Object_LoadAll(&play->objectCtx); + BgCheck_InitCollisionHeaders(&play->colCtx, play); + + gSaveContext.buttonStatus[EQUIP_SLOT_B] = sUnpausedButtonStatus[EQUIP_SLOT_B]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = sUnpausedButtonStatus[EQUIP_SLOT_C_LEFT]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = sUnpausedButtonStatus[EQUIP_SLOT_C_DOWN]; + gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = sUnpausedButtonStatus[EQUIP_SLOT_C_RIGHT]; + gSaveContext.buttonStatus[EQUIP_SLOT_A] = sUnpausedButtonStatus[EQUIP_SLOT_A]; + + Interface_UpdateButtonsPart2(play); + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + Interface_SetHudVisibility(HUD_VISIBILITY_ALL); + Sched_FlushTaskQueue(); + Skybox_Reload(play, &play->skyboxCtx, play->skyboxId); + + if ((msgCtx->msgMode != MSGMODE_NONE) && (msgCtx->currentTextId == 0xFF)) { + Interface_SetBButtonInterfaceDoAction(play, DO_ACTION_STOP); + Interface_SetAButtonDoAction(play, DO_ACTION_STOP); + Interface_SetHudVisibility(HUD_VISIBILITY_A_B_C); + } else { + interfaceCtx->bButtonInterfaceDoActionActive = interfaceCtx->bButtonInterfaceDoAction = 0; + } + gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE; + Interface_SetHudVisibility(sUnpausedHudVisibility); + Audio_SetPauseState(false); + break; + + default: + break; + } + + // If stickAdj is held, set a delay to allow the cursor to read the next input. + // The first delay is given a longer time than all subsequent delays. + if (!IS_PAUSE_STATE_GAMEOVER(pauseCtx) && (pauseCtx->state != PAUSE_STATE_SAVEPROMPT)) { + if (pauseCtx->stickAdjX < -30) { + if (sStickXRepeatState == -1) { + sStickXRepeatTimer--; + if (sStickXRepeatTimer < 0) { + // Allow the input to register and apply the delay for all subsequent repeated inputs + sStickXRepeatTimer = 2; + } else { + // Cancel the current input + pauseCtx->stickAdjX = 0; + } + } else { + // Allow the input to register and apply the delay for the first repeated input + sStickXRepeatTimer = 10; + sStickXRepeatState = -1; + } + } else if (pauseCtx->stickAdjX > 30) { + if (sStickXRepeatState == 1) { + sStickXRepeatTimer--; + if (sStickXRepeatTimer < 0) { + // Allow the input to register and apply the delay for all subsequent repeated inputs + sStickXRepeatTimer = 2; + } else { + // Cancel the current input + pauseCtx->stickAdjX = 0; + } + } else { + // Allow the input to register and apply the delay for the first repeated input + sStickXRepeatTimer = 10; + sStickXRepeatState = 1; + } + } else { + sStickXRepeatState = 0; + } + + if (pauseCtx->stickAdjY < -30) { + if (sStickYRepeatState == -1) { + sStickYRepeatTimer--; + if (sStickYRepeatTimer < 0) { + // Allow the input to register and apply the delay for all subsequent repeated inputs + sStickYRepeatTimer = 2; + } else { + // Cancel the current input + pauseCtx->stickAdjY = 0; + } + } else { + // Allow the input to register and apply the delay for the first repeated input + sStickYRepeatTimer = 10; + sStickYRepeatState = -1; + } + } else if (pauseCtx->stickAdjY > 30) { + if (sStickYRepeatState == 1) { + sStickYRepeatTimer--; + if (sStickYRepeatTimer < 0) { + // Allow the input to register and apply the delay for all subsequent repeated inputs + sStickYRepeatTimer = 2; + } else { + // Cancel the current input + pauseCtx->stickAdjY = 0; + } + } else { + // Allow the input to register and apply the delay for the first repeated input + sStickYRepeatTimer = 10; + sStickYRepeatState = 1; + } + } else { + sStickYRepeatState = 0; + } + } + + // Process the Cursor input + if ((R_PAUSE_BG_PRERENDER_STATE == PAUSE_BG_PRERENDER_READY) && (pauseCtx->debugEditor == DEBUG_EDITOR_NONE) && + !IS_PAUSE_STATE_OWL_WARP(pauseCtx) && + (((pauseCtx->state >= PAUSE_STATE_OPENING_3) && (pauseCtx->state <= PAUSE_STATE_SAVEPROMPT)) || + ((pauseCtx->state >= PAUSE_STATE_GAMEOVER_2) && (pauseCtx->state <= PAUSE_STATE_UNPAUSE_SETUP)))) { + if (!IS_PAUSE_STATE_GAMEOVER(pauseCtx)) { + switch (pauseCtx->pageIndex) { + case PAUSE_ITEM: + KaleidoScope_UpdateItemCursor(play); + break; + + case PAUSE_MAP: + if (sInDungeonScene) { + KaleidoScope_UpdateDungeonCursor(play); + } else { + KaleidoScope_UpdateWorldMapCursor(play); + } + break; + + case PAUSE_QUEST: + KaleidoScope_UpdateQuestCursor(play); + break; + + case PAUSE_MASK: + KaleidoScope_UpdateMaskCursor(play); + break; + } + + if ((pauseCtx->state == PAUSE_STATE_MAIN) && + ((pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) || + (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG))) { + KaleidoScope_HandlePageToggles(play, input); + } + } + if (pauseCtx->state == PAUSE_STATE_MAIN) { + KaleidoScope_UpdateNamePanel(play); + } + } else if (pauseCtx->state == PAUSE_STATE_OWL_WARP_SELECT) { + KaleidoScope_UpdateWorldMapCursor(play); + KaleidoScope_UpdateNamePanel(play); + } + + // Update the inventory editor + if ((pauseCtx->debugEditor == DEBUG_EDITOR_INVENTORY_INIT) || (pauseCtx->debugEditor == DEBUG_EDITOR_INVENTORY)) { + KaleidoScope_UpdateInventoryEditor(play); + } +} |
