diff --git a/Makefile b/Makefile index 47e0960e2a..c73d6fddca 100644 --- a/Makefile +++ b/Makefile @@ -220,22 +220,29 @@ endif # create extracted directories $(shell mkdir -p $(EXTRACTED_DIR) $(EXTRACTED_DIR)/assets $(EXTRACTED_DIR)/text) -ASSET_BIN_DIRS := $(shell find $(EXTRACTED_DIR)/assets -type d) -ASSET_FILES_BIN := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.bin)) -ASSET_FILES_OUT := $(foreach f,$(ASSET_FILES_BIN:.bin=.bin.inc.c),$(f:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)) \ - $(foreach f,$(wildcard assets/text/*.c),$(BUILD_DIR)/$(f:.c=.o)) +ASSET_BIN_DIRS_EXTRACTED := $(shell find $(EXTRACTED_DIR)/assets -type d) +ASSET_BIN_DIRS_COMMITTED := $(shell find assets -type d -not -path "assets/xml*" -not -path assets/text) +ASSET_BIN_DIRS := $(ASSET_BIN_DIRS_EXTRACTED) $(ASSET_BIN_DIRS_COMMITTED) + +ASSET_FILES_BIN_EXTRACTED := $(foreach dir,$(ASSET_BIN_DIRS_EXTRACTED),$(wildcard $(dir)/*.bin)) +ASSET_FILES_BIN_COMMITTED := $(foreach dir,$(ASSET_BIN_DIRS_COMMITTED),$(wildcard $(dir)/*.bin)) +ASSET_FILES_OUT := $(foreach f,$(ASSET_FILES_BIN_EXTRACTED:.bin=.bin.inc.c),$(f:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)) \ + $(foreach f,$(ASSET_FILES_BIN_COMMITTED:.bin=.bin.inc.c),$(BUILD_DIR)/$f) \ + $(foreach f,$(wildcard assets/text/*.c),$(BUILD_DIR)/$(f:.c=.o)) UNDECOMPILED_DATA_DIRS := $(shell find data -type d) BASEROM_BIN_FILES := $(wildcard $(EXTRACTED_DIR)/baserom/*) # source files +ASSET_C_FILES_EXTRACTED := $(filter-out %.inc.c,$(foreach dir,$(ASSET_BIN_DIRS_EXTRACTED),$(wildcard $(dir)/*.c))) +ASSET_C_FILES_COMMITTED := $(filter-out %.inc.c,$(foreach dir,$(ASSET_BIN_DIRS_COMMITTED),$(wildcard $(dir)/*.c))) SRC_C_FILES := $(filter-out %.inc.c,$(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))) -ASSET_C_FILES := $(filter-out %.inc.c,$(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.c))) S_FILES := $(foreach dir,$(SRC_DIRS) $(UNDECOMPILED_DATA_DIRS),$(wildcard $(dir)/*.s)) O_FILES := $(foreach f,$(S_FILES:.s=.o),$(BUILD_DIR)/$f) \ $(foreach f,$(SRC_C_FILES:.c=.o),$(BUILD_DIR)/$f) \ - $(foreach f,$(ASSET_C_FILES:.c=.o),$(f:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)) \ + $(foreach f,$(ASSET_C_FILES_EXTRACTED:.c=.o),$(f:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)) \ + $(foreach f,$(ASSET_C_FILES_COMMITTED:.c=.o),$(BUILD_DIR)/$f) \ $(foreach f,$(BASEROM_BIN_FILES),$(BUILD_DIR)/baserom/$(notdir $f).o) OVL_RELOC_FILES := $(shell $(CPP) $(CPPFLAGS) $(SPEC) | $(SPEC_REPLACE_VARS) | grep -o '[^"]*_reloc.o' ) @@ -245,10 +252,14 @@ OVL_RELOC_FILES := $(shell $(CPP) $(CPPFLAGS) $(SPEC) | $(SPEC_REPLACE_VARS) | g DEP_FILES := $(O_FILES:.o=.asmproc.d) $(OVL_RELOC_FILES:.o=.d) -TEXTURE_FILES_PNG := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.png)) -TEXTURE_FILES_JPG := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.jpg)) -TEXTURE_FILES_OUT := $(foreach f,$(TEXTURE_FILES_PNG:.png=.inc.c),$(f:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)) \ - $(foreach f,$(TEXTURE_FILES_JPG:.jpg=.jpg.inc.c),$(f:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)) +TEXTURE_FILES_PNG_EXTRACTED := $(foreach dir,$(ASSET_BIN_DIRS_EXTRACTED),$(wildcard $(dir)/*.png)) +TEXTURE_FILES_PNG_COMMITTED := $(foreach dir,$(ASSET_BIN_DIRS_COMMITTED),$(wildcard $(dir)/*.png)) +TEXTURE_FILES_JPG_EXTRACTED := $(foreach dir,$(ASSET_BIN_DIRS_EXTRACTED),$(wildcard $(dir)/*.jpg)) +TEXTURE_FILES_JPG_COMMITTED := $(foreach dir,$(ASSET_BIN_DIRS_COMMITTED),$(wildcard $(dir)/*.jpg)) +TEXTURE_FILES_OUT := $(foreach f,$(TEXTURE_FILES_PNG_EXTRACTED:.png=.inc.c),$(f:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)) \ + $(foreach f,$(TEXTURE_FILES_PNG_COMMITTED:.png=.inc.c),$(BUILD_DIR)/$f) \ + $(foreach f,$(TEXTURE_FILES_JPG_EXTRACTED:.jpg=.jpg.inc.c),$(f:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)) \ + $(foreach f,$(TEXTURE_FILES_JPG_COMMITTED:.jpg=.jpg.inc.c),$(BUILD_DIR)/$f) # create build directories $(shell mkdir -p $(BUILD_DIR)/baserom $(BUILD_DIR)/assets/text $(foreach dir,$(SRC_DIRS) $(UNDECOMPILED_DATA_DIRS),$(BUILD_DIR)/$(dir)) $(foreach dir,$(ASSET_BIN_DIRS),$(dir:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%))) @@ -464,6 +475,10 @@ else endif $(OBJCOPY) -O binary -j.rodata $@ $@.bin +$(BUILD_DIR)/assets/%.o: assets/%.c + $(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $< + $(OBJCOPY) -O binary $@ $@.bin + $(BUILD_DIR)/assets/%.o: $(EXTRACTED_DIR)/assets/%.c $(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $< $(OBJCOPY) -O binary $@ $@.bin @@ -515,12 +530,21 @@ $(BUILD_DIR)/src/overlays/%_reloc.o: $(BUILD_DIR)/$(SPEC) $(FADO) $$(tools/reloc_prereq $< $(notdir $*)) -n $(notdir $*) -o $(@:.o=.s) -M $(@:.o=.d) $(AS) $(ASFLAGS) $(@:.o=.s) -o $@ +$(BUILD_DIR)/assets/%.inc.c: assets/%.png + $(ZAPD) btex -eh -tt $(subst .,,$(suffix $*)) -i $< -o $@ + $(BUILD_DIR)/assets/%.inc.c: $(EXTRACTED_DIR)/assets/%.png $(ZAPD) btex -eh -tt $(subst .,,$(suffix $*)) -i $< -o $@ +$(BUILD_DIR)/assets/%.bin.inc.c: assets/%.bin + $(ZAPD) bblb -eh -i $< -o $@ + $(BUILD_DIR)/assets/%.bin.inc.c: $(EXTRACTED_DIR)/assets/%.bin $(ZAPD) bblb -eh -i $< -o $@ +$(BUILD_DIR)/assets/%.jpg.inc.c: assets/%.jpg + $(ZAPD) bren -eh -i $< -o $@ + $(BUILD_DIR)/assets/%.jpg.inc.c: $(EXTRACTED_DIR)/assets/%.jpg $(ZAPD) bren -eh -i $< -o $@ diff --git a/include/functions.h b/include/functions.h index d9c29270a6..d0547e5d68 100644 --- a/include/functions.h +++ b/include/functions.h @@ -776,7 +776,8 @@ s32 Jpeg_Decode(void* data, void* zbuffer, void* work, u32 workSize); void KaleidoSetup_Update(PlayState* play); void KaleidoSetup_Init(PlayState* play); void KaleidoSetup_Destroy(PlayState* play); -void func_8006EE50(Font* font, u16 arg1, u16 arg2); +s32 Kanji_OffsetFromShiftJIS(s32 character); +void Font_LoadCharWide(Font* font, u16 character, u16 codePointIndex); void Font_LoadChar(Font* font, u8 character, u16 codePointIndex); void Font_LoadMessageBoxIcon(Font* font, u16 icon); void Font_LoadOrderedFont(Font* font); diff --git a/include/message_data_fmt.h b/include/message_data_fmt.h index 2b184dac0d..08e3a49990 100644 --- a/include/message_data_fmt.h +++ b/include/message_data_fmt.h @@ -75,6 +75,38 @@ #define MESSAGE_WIDE_HIGHSCORE 0x869F #define MESSAGE_WIDE_TIME 0x81A1 +/* + * Message character constants + */ + +// Non-Wide (nes/ger/fra) + +#define MESSAGE_CHAR_SPACE 0x20 // ' ' + +// Wide (jpn) + +#define MESSAGE_WIDE_CHAR_SPACE 0x8140 // ' ' +#define MESSAGE_WIDE_CHAR_TOUTEN 0x8141 // '、' +#define MESSAGE_WIDE_CHAR_KUTEN 0x8142 // '。' +#define MESSAGE_WIDE_CHAR_PERIOD 0x8144 // '.' +#define MESSAGE_WIDE_CHAR_NAKATEN 0x8145 // '・' +#define MESSAGE_WIDE_CHAR_QUESTION_MARK 0x8148 // '?' +#define MESSAGE_WIDE_CHAR_EXCLAMATION_MARK 0x8149 // '!' +#define MESSAGE_WIDE_CHAR_CIRCUMFLEX_ACCENT 0x814F // '^' +#define MESSAGE_WIDE_CHAR_DOUBLE_QUOTATION_MARK_LEFT 0x8167 // '“' +#define MESSAGE_WIDE_CHAR_DOUBLE_QUOTATION_MARK_RIGHT 0x8168 // '”' +#define MESSAGE_WIDE_CHAR_PARENTHESES_LEFT 0x8169 // '(' +#define MESSAGE_WIDE_CHAR_PARENTHESES_RIGHT 0x816A // ')' +#define MESSAGE_WIDE_CHAR_KAGIKAKKO_LEFT 0x8175 // '「' +#define MESSAGE_WIDE_CHAR_KAGIKAKKO_RIGHT 0x8176 // '」' +#define MESSAGE_WIDE_CHAR_NUMBER_SIGN 0x8194 // '#' +#define MESSAGE_WIDE_CHAR_ASTERISK 0x8196 // '*' +#define MESSAGE_WIDE_CHAR_ZERO 0x824F // '0' +#define MESSAGE_WIDE_CHAR_ONE 0x8250 // '1' +#define MESSAGE_WIDE_CHAR_HOURS 0x8E9E // '時' +#define MESSAGE_WIDE_CHAR_SECONDS 0x9562 // '秒' +#define MESSAGE_WIDE_CHAR_MINUTES 0x95AA // '分' + /* * Colors */ diff --git a/include/z64animation.h b/include/z64animation.h index 782380ad20..ff4df48a22 100644 --- a/include/z64animation.h +++ b/include/z64animation.h @@ -106,8 +106,15 @@ typedef enum { // An option is to implement and use `ANIM_FLAG_OVERRIDE_MOVEMENT`. #define ANIM_FLAG_UPDATE_Y (1 << 1) -// (player-only) Related to scaling an animation from/to child/adult -#define ANIM_FLAG_PLAYER_2 (1 << 2) +// When this flag is set, Player's root limb position adjustment as child is disabled. +// Many of Player's animations are originally created for Adult Link. When playing those +// animations as Child Link without any adjustment, he will appear to be floating in the air. +// To fix this, Child Link's root position is scaled down by default to fit his smaller size. +// However, if an animation is created specifically for Child Link, it is desirable to disable +// this scaling of the root position by using this flag. +// Note that this flag will be ignored if `ANIM_FLAG_UPDATE_XZ` or `ANIM_FLAG_UPDATE_Y` are also +// set. The adjustment will be applied in this case regardless of this flag being enabled. +#define ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT (1 << 2) // (player-only) Call AnimTaskQueue_AddActorMove #define ANIM_FLAG_PLAYER_SETMOVE (1 << 3) @@ -123,7 +130,7 @@ typedef enum { // Some animations have translation data that does not begin at the "origin". This is common when a // longer sequence of animation is broken up into different parts as seperate animations. // In this case, when one animation starts its translation at the same position where a different animation -// left off, resetting `prevTransl` is not desireable. This will cause the actor's position to noticeably change +// left off, resetting `prevTransl` is not desirable. This will cause the actor's position to noticeably change // when the translation data from the first frame of the new animation is applied. // // When this flag is used during a transition between two animations, the first frame of movement is not applied. diff --git a/include/z64message.h b/include/z64message.h index cf942a4c51..014c379b82 100644 --- a/include/z64message.h +++ b/include/z64message.h @@ -235,8 +235,10 @@ typedef struct { /* 0xE2FE */ u8 textBoxPos; // text box position /* 0xE300 */ s32 msgLength; // original name : "msg_data" /* 0xE304 */ u8 msgMode; // original name: "msg_mode" - /* 0xE305 */ char unk_E305[0x1]; - /* 0xE306 */ u8 msgBufDecoded[200]; // decoded message buffer, may be smaller than this + /* 0xE306 */ union { + u8 msgBufDecoded[200]; + u16 msgBufDecodedWide[100]; + }; /* 0xE3CE */ u16 msgBufPos; // original name : "rdp" /* 0xE3D0 */ u16 unk_E3D0; // unused, only ever set to 0 /* 0xE3D2 */ u16 textDrawPos; // draw all decoded characters up to this buffer position diff --git a/src/code/z_kanfont.c b/src/code/z_kanfont.c index 83686a02ed..30fa15d41e 100644 --- a/src/code/z_kanfont.c +++ b/src/code/z_kanfont.c @@ -1,7 +1,15 @@ #include "global.h" #include "message_data_static.h" -void func_8006EE50(Font* font, u16 arg1, u16 arg2) { +/** + * Loads a texture from kanji for the requested `character` into the character texture buffer + * at `codePointIndex`. The value of `character` is the SHIFT-JIS encoding of the character. + */ +void Font_LoadCharWide(Font* font, u16 character, u16 codePointIndex) { +#if OOT_NTSC + DmaMgr_RequestSync(&font->charTexBuf[codePointIndex], + (uintptr_t)_kanjiSegmentRomStart + Kanji_OffsetFromShiftJIS(character), FONT_CHAR_TEX_SIZE); +#endif } /** @@ -33,14 +41,34 @@ void Font_LoadMessageBoxIcon(Font* font, u16 icon) { * the font buffer. */ void Font_LoadOrderedFont(Font* font) { + s32 size; s32 len; s32 codePointIndex; s32 fontBufIndex; u32 offset; font->msgOffset = FONT_MESSAGE_OFFSET; - len = font->msgLength = FONT_MESSAGE_LENGTH; + size = font->msgLength = FONT_MESSAGE_LENGTH; +#if OOT_NTSC + len = (u32)size / 2; + DmaMgr_RequestSync(font->msgBufWide, (uintptr_t)_jpn_message_data_staticSegmentRomStart + font->msgOffset, size); + + fontBufIndex = 0; + for (codePointIndex = 0; font->msgBufWide[codePointIndex] != MESSAGE_WIDE_END; codePointIndex++) { + if (len < codePointIndex) { + return; + } + + if (font->msgBufWide[codePointIndex] != MESSAGE_WIDE_NEWLINE) { + offset = Kanji_OffsetFromShiftJIS(font->msgBufWide[codePointIndex]); + DmaMgr_RequestSync(&font->fontBuf[fontBufIndex * 8], (uintptr_t)_kanjiSegmentRomStart + offset, + FONT_CHAR_TEX_SIZE); + fontBufIndex += FONT_CHAR_TEX_SIZE / 8; + } + } +#else + len = size; DMA_REQUEST_SYNC(font->msgBuf, (uintptr_t)_nes_message_data_staticSegmentRomStart + font->msgOffset, len, "../z_kanfont.c", 122); @@ -62,4 +90,5 @@ void Font_LoadOrderedFont(Font* font) { fontBufIndex += FONT_CHAR_TEX_SIZE / 8; } } +#endif } diff --git a/src/code/z_message.c b/src/code/z_message.c index e95f059475..999e95dc8f 100644 --- a/src/code/z_message.c +++ b/src/code/z_message.c @@ -17,7 +17,9 @@ u16 sNextTextId = 0; s16 sTextIsCredits = false; +#if OOT_PAL UNK_TYPE D_8014B30C = 0; +#endif s16 sLastPlayedSong = 0xFF; @@ -356,9 +358,75 @@ void Message_GrowTextbox(MessageContext* msgCtx) { R_TEXTBOX_X = (R_TEXTBOX_X_TARGET + R_TEXTBOX_WIDTH_TARGET) - (R_TEXTBOX_WIDTH / 2); } -#if OOT_PAL // TODO: implement NTSC version +#if OOT_NTSC -void Message_FindMessage(PlayState* play, u16 textId) { +void Message_FindMessageJPN(PlayState* play, u16 textId) { + const char* foundSeg; + const char* nextSeg; + const char* seg; + Font* font = &play->msgCtx.font; + MessageTableEntry* messageTableEntry = sJpnMessageEntryTablePtr; + + seg = messageTableEntry->segment; + + while (messageTableEntry->textId != 0xFFFF) { + if (messageTableEntry->textId == textId) { + foundSeg = messageTableEntry->segment; + font->charTexBuf[0] = messageTableEntry->typePos; + messageTableEntry++; + nextSeg = messageTableEntry->segment; + font->msgOffset = foundSeg - seg; + font->msgLength = nextSeg - foundSeg; + return; + } + messageTableEntry++; + } + + messageTableEntry = sJpnMessageEntryTablePtr; + + foundSeg = messageTableEntry->segment; + font->charTexBuf[0] = messageTableEntry->typePos; + messageTableEntry++; + nextSeg = messageTableEntry->segment; + + font->msgOffset = foundSeg - seg; + font->msgLength = nextSeg - foundSeg; +} + +void Message_FindMessageNES(PlayState* play, u16 textId) { + const char* foundSeg; + const char* nextSeg; + const char* seg; + Font* font = &play->msgCtx.font; + MessageTableEntry* messageTableEntry = sNesMessageEntryTablePtr; + + seg = messageTableEntry->segment; + while (messageTableEntry->textId != 0xFFFF) { + if (messageTableEntry->textId == textId) { + foundSeg = messageTableEntry->segment; + font->charTexBuf[0] = messageTableEntry->typePos; + messageTableEntry++; + nextSeg = messageTableEntry->segment; + font->msgOffset = foundSeg - seg; + font->msgLength = nextSeg - foundSeg; + return; + } + messageTableEntry++; + } + + messageTableEntry = sNesMessageEntryTablePtr; + + foundSeg = messageTableEntry->segment; + font->charTexBuf[0] = messageTableEntry->typePos; + messageTableEntry++; + nextSeg = messageTableEntry->segment; + font->msgOffset = foundSeg - seg; + font->msgLength = nextSeg - foundSeg; +} + +#else + +void Message_FindMessagePAL(PlayState* play, u16 textId) { const char* foundSeg; const char* nextSeg; Font* font = &play->msgCtx.font; @@ -753,7 +821,11 @@ f32 sFontWidths[144] = { 10.0f, // '~' 10.0f, // '‾' 12.0f, // 'À' - 6.0f, // 'î' +#if OOT_NTSC + 12.0f, // 'î' +#else + 6.0f, // 'î' +#endif 12.0f, // 'Â' 12.0f, // 'Ä' 11.0f, // 'Ç' @@ -907,8 +979,332 @@ void Message_HandleOcarina(PlayState* play) { } } +#if OOT_NTSC /** - * Draws the text contents of a textbox, up to the current point that has + * Draws the text contents of a jpn textbox, up to the current point that has + * been scrolled to so far. + */ +void Message_DrawTextWide(PlayState* play, Gfx** gfxP) { + MessageContext* msgCtx = &play->msgCtx; + Font* font = &play->msgCtx.font; + u16 character; + u16 j; + u16 i; + u16 charTexIdx; + Gfx* gfx = *gfxP; + + play->msgCtx.textPosX = R_TEXT_INIT_XPOS; + play->msgCtx.textPosY = R_TEXT_INIT_YPOS; + + if (msgCtx->textBoxType == TEXTBOX_TYPE_NONE_NO_SHADOW) { + msgCtx->textColorR = msgCtx->textColorG = msgCtx->textColorB = 0; + } else { + msgCtx->textColorR = msgCtx->textColorG = msgCtx->textColorB = 255; + } + + msgCtx->unk_E3D0 = 0; + charTexIdx = 0; + + for (i = 0; i < msgCtx->textDrawPos; i++) { + character = msgCtx->msgBufDecodedWide[i]; + + switch (character) { + case MESSAGE_WIDE_NEWLINE: + msgCtx->textPosY += R_TEXT_LINE_SPACING; + msgCtx->textPosX = R_TEXT_INIT_XPOS; + if (msgCtx->choiceNum == 1) { + msgCtx->textPosX += 32; + } + if (msgCtx->choiceNum == 2) { + msgCtx->textPosX += 32; + } + break; + case MESSAGE_WIDE_COLOR: + Message_SetTextColor(msgCtx, msgCtx->msgBufDecodedWide[++i]); + break; + case MESSAGE_WIDE_CHAR_SPACE: + msgCtx->textPosX += MESSAGE_SPACE_WIDTH; + break; + case MESSAGE_WIDE_BOX_BREAK: + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + if (!sTextboxSkipped) { + Audio_PlaySfxGeneral(NA_SE_NONE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + msgCtx->msgMode = MSGMODE_TEXT_AWAIT_NEXT; + Font_LoadMessageBoxIcon(&play->msgCtx.font, TEXTBOX_ICON_TRIANGLE); + } else { + msgCtx->msgMode = MSGMODE_TEXT_NEXT_MSG; + msgCtx->textUnskippable = false; + msgCtx->msgBufPos++; + } + } + *gfxP = gfx; + return; + case MESSAGE_WIDE_SHIFT: + msgCtx->textPosX += msgCtx->msgBufDecodedWide[++i]; + break; + case MESSAGE_WIDE_TEXTID: + msgCtx->textboxEndType = TEXTBOX_ENDTYPE_HAS_NEXT; + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + Audio_PlaySfxGeneral(NA_SE_NONE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + msgCtx->msgMode = MSGMODE_TEXT_DONE; + Font_LoadMessageBoxIcon(&play->msgCtx.font, TEXTBOX_ICON_TRIANGLE); + } + *gfxP = gfx; + return; + case MESSAGE_WIDE_QUICKTEXT_ENABLE: + if (i + 1 == msgCtx->textDrawPos && (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING || + (msgCtx->msgMode >= MSGMODE_OCARINA_STARTING && + msgCtx->msgMode < MSGMODE_SCARECROW_LONG_RECORDING_START))) { + j = i; + while (true) { + character = msgCtx->msgBufDecodedWide[j]; + if ((character != MESSAGE_WIDE_QUICKTEXT_DISABLE) && (character != MESSAGE_WIDE_PERSISTENT) && + (character != MESSAGE_WIDE_EVENT) && (character != MESSAGE_WIDE_BOX_BREAK_DELAYED) && + (character != MESSAGE_WIDE_AWAIT_BUTTON_PRESS) && (character != MESSAGE_WIDE_BOX_BREAK) && + (character != MESSAGE_WIDE_END)) { + j++; + } else { + break; + } + } + i = j - 1; + msgCtx->textDrawPos = i + 1; + } + FALLTHROUGH; + case MESSAGE_WIDE_QUICKTEXT_DISABLE: + break; + case MESSAGE_WIDE_AWAIT_BUTTON_PRESS: + if (i + 1 == msgCtx->textDrawPos) { + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + msgCtx->msgMode = MSGMODE_TEXT_AWAIT_INPUT; + Font_LoadMessageBoxIcon(&play->msgCtx.font, TEXTBOX_ICON_TRIANGLE); + } + *gfxP = gfx; + return; + } + break; + case MESSAGE_WIDE_BOX_BREAK_DELAYED: + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + msgCtx->stateTimer = msgCtx->msgBufDecodedWide[++i]; + msgCtx->msgMode = MSGMODE_TEXT_DELAYED_BREAK; + } + *gfxP = gfx; + return; + case MESSAGE_WIDE_FADE2: + break; + case MESSAGE_WIDE_SFX: + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING && !sMessageHasSetSfx) { + sMessageHasSetSfx = true; + Audio_PlaySfxGeneral(msgCtx->msgBufDecodedWide[i + 1], &gSfxDefaultPos, 4, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + } + i++; + break; + case MESSAGE_WIDE_ITEM_ICON: + i = Message_DrawItemIcon(play, msgCtx->msgBufDecodedWide[i + 1], &gfx, i); + break; + case MESSAGE_WIDE_BACKGROUND: + // clang-format off + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { \ + Audio_PlaySfxGeneral(NA_SE_NONE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + } + // clang-format on + gDPPipeSync(gfx++); + gDPSetCombineMode(gfx++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor(gfx++, 0, 0, sTextboxBackgroundBackPrimColors[msgCtx->textboxBackgroundBackColorIdx][0], + sTextboxBackgroundBackPrimColors[msgCtx->textboxBackgroundBackColorIdx][1], + sTextboxBackgroundBackPrimColors[msgCtx->textboxBackgroundBackColorIdx][2], + msgCtx->textColorAlpha); + + gDPLoadTextureBlock_4b(gfx++, msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE, G_IM_FMT_I, 96, 48, 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); + gSPTextureRectangle( + gfx++, (msgCtx->textPosX + 1) << 2, + (R_TEXTBOX_BG_YPOS + sTextboxBackgroundYOffsets[msgCtx->textboxBackgroundYOffsetIdx]) << 2, + (msgCtx->textPosX + 96 + 1) << 2, + (R_TEXTBOX_BG_YPOS + sTextboxBackgroundYOffsets[msgCtx->textboxBackgroundYOffsetIdx] + 48) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + + gDPLoadTextureBlock_4b(gfx++, msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE + 0x900, G_IM_FMT_I, 96, + 48, 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); + gSPTextureRectangle( + gfx++, (msgCtx->textPosX + 96 + 1) << 2, + (R_TEXTBOX_BG_YPOS + sTextboxBackgroundYOffsets[msgCtx->textboxBackgroundYOffsetIdx]) << 2, + (msgCtx->textPosX + 96 + 1 + 96 + 1) << 2, + (R_TEXTBOX_BG_YPOS + sTextboxBackgroundYOffsets[msgCtx->textboxBackgroundYOffsetIdx] + 48) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + + gDPPipeSync(gfx++); + gDPSetPrimColor(gfx++, 0, 0, sTextboxBackgroundForePrimColors[msgCtx->textboxBackgroundForeColorIdx][0], + sTextboxBackgroundForePrimColors[msgCtx->textboxBackgroundForeColorIdx][1], + sTextboxBackgroundForePrimColors[msgCtx->textboxBackgroundForeColorIdx][2], + msgCtx->textColorAlpha); + + gDPLoadTextureBlock_4b(gfx++, (msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE), G_IM_FMT_I, 96, 48, 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); + gSPTextureRectangle(gfx++, msgCtx->textPosX << 2, R_TEXTBOX_BG_YPOS << 2, (msgCtx->textPosX + 96) << 2, + (R_TEXTBOX_BG_YPOS + 48) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + + gDPLoadTextureBlock_4b(gfx++, (msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE + 0x900), G_IM_FMT_I, + 96, 48, 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); + gSPTextureRectangle(gfx++, (msgCtx->textPosX + 96) << 2, R_TEXTBOX_BG_YPOS << 2, + (msgCtx->textPosX + 192) << 2, (R_TEXTBOX_BG_YPOS + 48) << 2, G_TX_RENDERTILE, 0, 0, + 1 << 10, 1 << 10); + + gDPPipeSync(gfx++); + gDPSetCombineLERP(gfx++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, + PRIMITIVE, 0); + + msgCtx->textPosX += 32; + break; + case MESSAGE_WIDE_TEXT_SPEED: + msgCtx->textDelay = msgCtx->msgBufDecodedWide[++i]; + break; + case MESSAGE_WIDE_UNSKIPPABLE: + msgCtx->textUnskippable = true; + break; + case MESSAGE_WIDE_TWO_CHOICE: + msgCtx->textboxEndType = TEXTBOX_ENDTYPE_2_CHOICE; + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + msgCtx->choiceTextId = msgCtx->textId; + msgCtx->stateTimer = 4; + msgCtx->choiceIndex = 0; + Font_LoadMessageBoxIcon(font, TEXTBOX_ICON_ARROW); + } + break; + case MESSAGE_WIDE_THREE_CHOICE: + msgCtx->textboxEndType = TEXTBOX_ENDTYPE_3_CHOICE; + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + msgCtx->choiceTextId = msgCtx->textId; + msgCtx->stateTimer = 4; + msgCtx->choiceIndex = 0; + Font_LoadMessageBoxIcon(font, TEXTBOX_ICON_ARROW); + } + break; + case MESSAGE_WIDE_END: + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + msgCtx->msgMode = MSGMODE_TEXT_DONE; + if (msgCtx->textboxEndType == TEXTBOX_ENDTYPE_DEFAULT) { + Audio_PlaySfxGeneral(NA_SE_SY_MESSAGE_END, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + Font_LoadMessageBoxIcon(font, TEXTBOX_ICON_SQUARE); + if (play->csCtx.state == CS_STATE_IDLE) { + Interface_SetDoAction(play, DO_ACTION_RETURN); + } + } + } + *gfxP = gfx; + return; + case MESSAGE_WIDE_OCARINA: + if (i + 1 == msgCtx->textDrawPos) { + Message_HandleOcarina(play); + *gfxP = gfx; + return; + } + break; + case MESSAGE_WIDE_FADE: + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + msgCtx->msgMode = MSGMODE_TEXT_DONE; + msgCtx->textboxEndType = TEXTBOX_ENDTYPE_FADING; + msgCtx->stateTimer = msgCtx->msgBufDecodedWide[++i]; + Font_LoadMessageBoxIcon(font, TEXTBOX_ICON_SQUARE); + if (play->csCtx.state == CS_STATE_IDLE) { + Interface_SetDoAction(play, DO_ACTION_RETURN); + } + } + *gfxP = gfx; + return; + case MESSAGE_WIDE_PERSISTENT: + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + Audio_PlaySfxGeneral(NA_SE_NONE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + msgCtx->msgMode = MSGMODE_TEXT_DONE; + msgCtx->textboxEndType = TEXTBOX_ENDTYPE_PERSISTENT; + } + *gfxP = gfx; + return; + case MESSAGE_WIDE_EVENT: + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { + msgCtx->msgMode = MSGMODE_TEXT_DONE; + msgCtx->textboxEndType = TEXTBOX_ENDTYPE_EVENT; + Font_LoadMessageBoxIcon(&play->msgCtx.font, TEXTBOX_ICON_TRIANGLE); + Audio_PlaySfxGeneral(NA_SE_SY_MESSAGE_END, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + } + *gfxP = gfx; + return; + default: + switch (character) { + case MESSAGE_WIDE_CHAR_PARENTHESES_LEFT: + case MESSAGE_WIDE_CHAR_KAGIKAKKO_LEFT: + msgCtx->textPosX -= 6; + break; + case MESSAGE_WIDE_CHAR_NAKATEN: + msgCtx->textPosX -= 3; + break; + case MESSAGE_WIDE_CHAR_QUESTION_MARK: + case MESSAGE_WIDE_CHAR_EXCLAMATION_MARK: + case MESSAGE_WIDE_CHAR_CIRCUMFLEX_ACCENT: + case MESSAGE_WIDE_CHAR_ONE: + msgCtx->textPosX -= 2; + break; + } + if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING && i + 1 == msgCtx->textDrawPos && + msgCtx->textDelayTimer == msgCtx->textDelay) { + Audio_PlaySfxGeneral(NA_SE_NONE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + } + Message_DrawTextChar(play, &font->charTexBuf[charTexIdx], &gfx); + charTexIdx += FONT_CHAR_TEX_SIZE; + + switch (character) { + case MESSAGE_WIDE_CHAR_PERIOD: + msgCtx->textPosX += 3; + break; + case MESSAGE_WIDE_CHAR_PARENTHESES_RIGHT: + case MESSAGE_WIDE_CHAR_KAGIKAKKO_RIGHT: + msgCtx->textPosX += 5; + break; + case MESSAGE_WIDE_CHAR_TOUTEN: + case MESSAGE_WIDE_CHAR_KUTEN: + case MESSAGE_WIDE_CHAR_DOUBLE_QUOTATION_MARK_RIGHT: + msgCtx->textPosX += 7; + break; + case MESSAGE_WIDE_CHAR_CIRCUMFLEX_ACCENT: + case MESSAGE_WIDE_CHAR_NUMBER_SIGN: + case MESSAGE_WIDE_CHAR_ASTERISK: + msgCtx->textPosX += 9; + break; + case MESSAGE_WIDE_CHAR_NAKATEN: + msgCtx->textPosX += 10; + break; + default: + msgCtx->textPosX += (s32)(16.0f * (R_TEXT_CHAR_SCALE / 100.0f)); + break; + } + break; + } + } + + if (msgCtx->textDelayTimer == 0) { + msgCtx->textDrawPos = i + 1; + msgCtx->textDelayTimer = msgCtx->textDelay; + } else { + msgCtx->textDelayTimer--; + } + *gfxP = gfx; +} +#endif + +/** + * Draws the text contents of an eng/ger/fra textbox, up to the current point that has * been scrolled to so far. */ void Message_DrawText(PlayState* play, Gfx** gfxP) { @@ -923,7 +1319,6 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) { Gfx* gfx = *gfxP; play->msgCtx.textPosX = R_TEXT_INIT_XPOS; - if (!sTextIsCredits) { msgCtx->textPosY = R_TEXT_INIT_YPOS; } else { @@ -956,7 +1351,7 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) { case MESSAGE_COLOR: Message_SetTextColor(msgCtx, msgCtx->msgBufDecoded[++i] & 0xF); break; - case ' ': + case MESSAGE_CHAR_SPACE: msgCtx->textPosX += MESSAGE_SPACE_WIDTH; break; case MESSAGE_BOX_BREAK: @@ -1214,8 +1609,8 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) { } void Message_LoadItemIcon(PlayState* play, u16 itemId, s16 y) { - static s16 sIconItem32XOffsets[] = { 74, 74, 74 }; - static s16 sIconItem24XOffsets[] = { 72, 72, 72 }; + static s16 sIconItem32XOffsets[] = LANGUAGE_ARRAY(54, 74, 74, 74); + static s16 sIconItem24XOffsets[] = LANGUAGE_ARRAY(50, 72, 72, 72); MessageContext* msgCtx = &play->msgCtx; InterfaceContext* interfaceCtx = &play->interfaceCtx; @@ -1245,398 +1640,744 @@ void Message_LoadItemIcon(PlayState* play, u16 itemId, s16 y) { } void Message_Decode(PlayState* play) { - u8 curChar; - u8 curChar2; - u16 value; - s32 loadChar; - s32 charTexIdx = 0; - s16 playerNameLen; - s16 decodedBufPos = 0; - s16 numLines = 0; - s16 i; - s16 digits[4]; - f32 timeInSeconds; MessageContext* msgCtx = &play->msgCtx; Font* font = &play->msgCtx.font; + s32 charTexIdx = 0; + s16 i; +#if OOT_NTSC + s16 j; +#endif + s16 decodedBufPos = 0; + s16 numLines = 0; + s16 digits[4]; + f32 timeInSeconds; + s16 playerNameLen; + s16 loadChar; + u16 value; + u8 curChar; +#if OOT_NTSC + u16 curCharWide; + u8* fontBuf; +#endif play->msgCtx.textDelayTimer = 0; play->msgCtx.textUnskippable = play->msgCtx.textDelay = play->msgCtx.textDelayTimer = 0; sTextFade = false; - while (true) { - curChar2 = curChar = msgCtx->msgBufDecoded[decodedBufPos] = font->msgBuf[msgCtx->msgBufPos]; +#if OOT_NTSC + if (gSaveContext.language == LANGUAGE_JPN && !sTextIsCredits) { + // Japanese text (NTSC only) + while (true) { + curCharWide = msgCtx->msgBufDecodedWide[decodedBufPos] = font->msgBufWide[msgCtx->msgBufPos]; - if (curChar == MESSAGE_BOX_BREAK || curChar == MESSAGE_TEXTID || curChar == MESSAGE_BOX_BREAK_DELAYED || - curChar == MESSAGE_EVENT || curChar == MESSAGE_END) { - // Textbox decoding ends with any of the above text control characters - msgCtx->msgMode = MSGMODE_TEXT_DISPLAYING; - msgCtx->textDrawPos = 1; - R_TEXT_INIT_YPOS = R_TEXTBOX_Y + 8; - PRINTF("JJ=%d\n", numLines); - if (msgCtx->textBoxType != TEXTBOX_TYPE_NONE_BOTTOM) { - if (numLines == 0) { - R_TEXT_INIT_YPOS = (u16)(R_TEXTBOX_Y + 26); - } else if (numLines == 1) { - R_TEXT_INIT_YPOS = (u16)(R_TEXTBOX_Y + 20); - } else if (numLines == 2) { - R_TEXT_INIT_YPOS = (u16)(R_TEXTBOX_Y + 16); + if (curCharWide == MESSAGE_WIDE_BOX_BREAK || curCharWide == MESSAGE_WIDE_TEXTID || + curCharWide == MESSAGE_WIDE_BOX_BREAK_DELAYED || curCharWide == MESSAGE_WIDE_EVENT || + curCharWide == MESSAGE_WIDE_END) { + // Textbox decoding ends with any of the above text control characters + msgCtx->msgMode = MSGMODE_TEXT_DISPLAYING; + msgCtx->textDrawPos = 1; + R_TEXT_INIT_YPOS = R_TEXTBOX_Y + 6; + if (msgCtx->textBoxType != TEXTBOX_TYPE_NONE_BOTTOM) { + if (numLines == 0) { + R_TEXT_INIT_YPOS = (u16)(R_TEXTBOX_Y + 22); + } else if (numLines == 1) { + R_TEXT_INIT_YPOS = (u16)(R_TEXTBOX_Y + 14); + } } - } - if (curChar2 == MESSAGE_TEXTID) { - PRINTF("NZ_NEXTMSG=%x, %x, %x\n", font->msgBuf[msgCtx->msgBufPos], font->msgBuf[msgCtx->msgBufPos + 1], - font->msgBuf[msgCtx->msgBufPos + 2]); - curChar = msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[msgCtx->msgBufPos + 1]; - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[msgCtx->msgBufPos + 2]; - value = curChar << 8; - sNextTextId = msgCtx->msgBufDecoded[decodedBufPos] | value; - } - if (curChar2 == MESSAGE_BOX_BREAK_DELAYED) { - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[msgCtx->msgBufPos + 1]; - msgCtx->msgBufPos += 2; - } - msgCtx->decodedTextLen = decodedBufPos; - if (sTextboxSkipped) { - msgCtx->textDrawPos = msgCtx->decodedTextLen; - } - break; - } else if (curChar == MESSAGE_NAME) { - // Substitute the player name control character for the file's player name. - for (playerNameLen = ARRAY_COUNT(gSaveContext.save.info.playerData.playerName); playerNameLen > 0; - playerNameLen--) { - if (gSaveContext.save.info.playerData.playerName[playerNameLen - 1] != FILENAME_SPACE) { - break; + if (curCharWide == MESSAGE_WIDE_TEXTID) { + sNextTextId = msgCtx->msgBufDecodedWide[++decodedBufPos] = font->msgBufWide[msgCtx->msgBufPos + 1]; } - } - // "Name" - PRINTF("\n名前 = "); - for (i = 0; i < playerNameLen; i++) { - curChar2 = gSaveContext.save.info.playerData.playerName[i]; - if (curChar2 == FILENAME_SPACE) { - curChar2 = ' '; - } else if (curChar2 == FILENAME_PERIOD) { - curChar2 = '.'; - } else if (curChar2 == FILENAME_DASH) { - curChar2 = '-'; - } else if (curChar2 <= FILENAME_DIGIT('9')) { - curChar2 -= FILENAME_DIGIT('0'); - curChar2 += '0'; - } else if (curChar2 <= FILENAME_UPPERCASE('Z')) { - curChar2 -= FILENAME_UPPERCASE('A'); - curChar2 += 'A'; - } else if (curChar2 <= FILENAME_LOWERCASE('z')) { - curChar2 -= FILENAME_LOWERCASE('a'); - curChar2 += 'a'; + if (curCharWide == MESSAGE_WIDE_BOX_BREAK_DELAYED) { + msgCtx->msgBufDecodedWide[++decodedBufPos] = font->msgBufWide[msgCtx->msgBufPos + 1]; + msgCtx->msgBufPos += 2; } - if (curChar2 != ' ') { - Font_LoadChar(font, curChar2 - ' ', charTexIdx); + msgCtx->decodedTextLen = decodedBufPos; + if (sTextboxSkipped) { + msgCtx->textDrawPos = msgCtx->decodedTextLen; + } + break; + } + if (curCharWide == MESSAGE_WIDE_NAME) { + // Substitute the player name control character for the file's player name. + for (playerNameLen = ARRAY_COUNT(gSaveContext.save.info.playerData.playerName); playerNameLen > 0; + playerNameLen--) { + if (gSaveContext.save.info.playerData.playerName[playerNameLen - 1] != FILENAME_SPACE) { + break; + } + } + for (i = 0; i < playerNameLen; i++) { + curCharWide = gSaveContext.save.info.playerData.playerName[i]; + fontBuf = &font->fontBuf[(curCharWide * 32) << 2]; // fake + msgCtx->msgBufDecodedWide[decodedBufPos + i] = MESSAGE_WIDE_NAME; + + for (j = 0; j < FONT_CHAR_TEX_SIZE; j += 4) { + font->charTexBuf[charTexIdx + j + 0] = fontBuf[j + 0]; + font->charTexBuf[charTexIdx + j + 1] = fontBuf[j + 1]; + font->charTexBuf[charTexIdx + j + 2] = fontBuf[j + 2]; + font->charTexBuf[charTexIdx + j + 3] = fontBuf[j + 3]; + } charTexIdx += FONT_CHAR_TEX_SIZE; } - PRINTF("%x ", curChar2); - msgCtx->msgBufDecoded[decodedBufPos] = curChar2; - decodedBufPos++; - } - decodedBufPos--; - } else if (curChar == MESSAGE_MARATHON_TIME || curChar == MESSAGE_RACE_TIME) { - // Convert the values of the appropriate timer to digits and add the - // digits to the decoded buffer in place of the control character. - // "EVENT timer" - PRINTF("\nEVENTタイマー = "); - digits[0] = digits[1] = digits[2] = 0; - if (curChar == MESSAGE_RACE_TIME) { - digits[3] = gSaveContext.timerSeconds; - } else { - digits[3] = gSaveContext.subTimerSeconds; - } + decodedBufPos += playerNameLen - 1; + } else if (curCharWide == MESSAGE_WIDE_MARATHON_TIME || curCharWide == MESSAGE_WIDE_RACE_TIME) { + // Convert the values of the appropriate timer to digits and add the + // digits to the decoded buffer in place of the control character. + digits[0] = digits[1] = digits[2] = 0; + if (curCharWide == MESSAGE_WIDE_RACE_TIME) { + digits[3] = gSaveContext.timerSeconds; + } else { + digits[3] = gSaveContext.subTimerSeconds; + } + while (digits[3] >= 60) { + digits[1]++; + if (digits[1] >= 10) { + digits[0]++; + digits[1] -= 10; + } + digits[3] -= 60; + } + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } - while (digits[3] >= 60) { - digits[1]++; - if (digits[1] >= 10) { + for (i = 0; i < 4; i++) { + Font_LoadCharWide(font, digits[i] + MESSAGE_WIDE_CHAR_ZERO, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = digits[i] + MESSAGE_WIDE_CHAR_ZERO; + decodedBufPos++; + if (i == 1) { + Font_LoadCharWide(font, MESSAGE_WIDE_CHAR_MINUTES, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = MESSAGE_WIDE_CHAR_MINUTES; + decodedBufPos++; + } else if (i == 3) { + Font_LoadCharWide(font, MESSAGE_WIDE_CHAR_SECONDS, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = MESSAGE_WIDE_CHAR_SECONDS; + } + } + } else if (curCharWide == MESSAGE_WIDE_POINTS) { + // Convert the values of the current minigame score to digits and + // add the digits to the decoded buffer in place of the control character. + digits[0] = digits[1] = digits[2] = 0; + digits[3] = gSaveContext.minigameScore; + + while (digits[3] >= 1000) { + digits[0]++; + digits[3] -= 1000; + } + while (digits[3] >= 100) { + digits[1]++; + digits[3] -= 100; + } + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } + loadChar = false; + for (i = 0; i < 4; i++) { + if (i == 3 || digits[i] != 0) { + loadChar = true; + } + if (loadChar) { + Font_LoadCharWide(font, digits[i] + MESSAGE_WIDE_CHAR_ZERO, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = digits[i] + MESSAGE_WIDE_CHAR_ZERO; + decodedBufPos++; + } + } + decodedBufPos--; + } else if (curCharWide == MESSAGE_WIDE_TOKENS) { + // Convert the current number of collected gold skulltula tokens to digits and + // add the digits to the decoded buffer in place of the control character. + digits[0] = digits[1] = 0; + digits[2] = gSaveContext.save.info.inventory.gsTokens; + + while (digits[2] >= 100) { + digits[0]++; + digits[2] -= 100; + } + while (digits[2] >= 10) { + digits[1]++; + digits[2] -= 10; + } + + loadChar = false; + for (i = 0; i < 3; i++) { + if (i == 2 || digits[i] != 0) { + loadChar = true; + } + if (loadChar) { + Font_LoadCharWide(font, digits[i] + MESSAGE_WIDE_CHAR_ZERO, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = digits[i] + MESSAGE_WIDE_CHAR_ZERO; + decodedBufPos++; + } + } + decodedBufPos--; + } else if (curCharWide == MESSAGE_WIDE_FISH_INFO) { + digits[0] = 0; + digits[1] = gSaveContext.minigameScore; + + while (digits[1] >= 10) { digits[0]++; digits[1] -= 10; } - digits[3] -= 60; - } - while (digits[3] >= 10) { - digits[2]++; - digits[3] -= 10; - } - for (i = 0; i < 4; i++) { - Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; - decodedBufPos++; - if (i == 1) { - Font_LoadChar(font, '"' - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = '"'; - decodedBufPos++; - } else if (i == 3) { - Font_LoadChar(font, '"' - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = '"'; - } - } - } else if (curChar == MESSAGE_POINTS) { - // Convert the values of the current minigame score to digits and - // add the digits to the decoded buffer in place of the control character. - // "Yabusame score" - PRINTF("\n流鏑馬スコア = %d\n", gSaveContext.minigameScore); - digits[0] = digits[1] = digits[2] = 0; - digits[3] = gSaveContext.minigameScore; - - while (digits[3] >= 1000) { - digits[0]++; - digits[3] -= 1000; - } - while (digits[3] >= 100) { - digits[1]++; - digits[3] -= 100; - } - while (digits[3] >= 10) { - digits[2]++; - digits[3] -= 10; - } - - loadChar = false; - for (i = 0; i < 4; i++) { - if (i == 3 || digits[i] != 0) { - loadChar = true; - } - if (loadChar) { - Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); - msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; - charTexIdx += FONT_CHAR_TEX_SIZE; - decodedBufPos++; - } - } - decodedBufPos--; - } else if (curChar == MESSAGE_TOKENS) { - // Convert the current number of collected gold skulltula tokens to digits and - // add the digits to the decoded buffer in place of the control character. - // "Total number of gold stars" - PRINTF("\n金スタ合計数 = %d", gSaveContext.save.info.inventory.gsTokens); - digits[0] = digits[1] = 0; - digits[2] = gSaveContext.save.info.inventory.gsTokens; - - while (digits[2] >= 100) { - digits[0]++; - digits[2] -= 100; - } - while (digits[2] >= 10) { - digits[1]++; - digits[2] -= 10; - } - - loadChar = false; - for (i = 0; i < 3; i++) { - if (i == 2 || digits[i] != 0) { - loadChar = true; - } - if (loadChar) { - Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; - PRINTF("%x(%x) ", digits[i] + '0' - ' ', digits[i]); - decodedBufPos++; - } - } - decodedBufPos--; - } else if (curChar == MESSAGE_FISH_INFO) { - // "Fishing hole fish size" - PRINTF("\n釣り堀魚サイズ = "); - digits[0] = 0; - digits[1] = gSaveContext.minigameScore; - - while (digits[1] >= 10) { - digits[0]++; - digits[1] -= 10; - } - - for (i = 0; i < 2; i++) { - if (i == 1 || digits[i] != 0) { - Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; - PRINTF("%x(%x) ", digits[i] + '0' - ' ', digits[i]); - decodedBufPos++; - } - } - decodedBufPos--; - } else if (curChar == MESSAGE_HIGHSCORE) { - value = HIGH_SCORE((u8)font->msgBuf[++msgCtx->msgBufPos]); - // "Highscore" - PRINTF("ランキング=%d\n", font->msgBuf[msgCtx->msgBufPos]); - if ((font->msgBuf[msgCtx->msgBufPos] & 0xFF) == 2) { - if (LINK_AGE_IN_YEARS == YEARS_CHILD) { - value &= 0x7F; - } else { - PRINTF("HI_SCORE( kanfont->mbuff.nes_mes_buf[message->rdp] & 0xff000000 ) = %x\n", - HIGH_SCORE(font->msgBufWide[msgCtx->msgBufPos] & 0xFF000000)); - value = ((HIGH_SCORE((u8)font->msgBuf[msgCtx->msgBufPos]) & 0xFF000000) >> 0x18) & 0x7F; - } - value = SQ((f32)value) * 0.0036f + 0.5f; - PRINTF("score=%d\n", value); - } - switch (font->msgBuf[msgCtx->msgBufPos] & 0xFF) { - case HS_HBA: - case HS_POE_POINTS: - case HS_FISHING: - digits[0] = digits[1] = digits[2] = 0; - digits[3] = value; - - while (digits[3] >= 1000) { - digits[0]++; - digits[3] -= 1000; + for (i = 0; i < 2; i++) { + if (i == 1 || digits[i] != 0) { + Font_LoadCharWide(font, digits[i] + MESSAGE_WIDE_CHAR_ZERO, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = digits[i] + MESSAGE_WIDE_CHAR_ZERO; + decodedBufPos++; } - while (digits[3] >= 100) { - digits[1]++; - digits[3] -= 100; - } - while (digits[3] >= 10) { - digits[2]++; - digits[3] -= 10; + } + decodedBufPos--; + } else if (curCharWide == MESSAGE_WIDE_HIGHSCORE) { + value = HIGH_SCORE(font->msgBufWide[++msgCtx->msgBufPos] & 0xFF); + if ((font->msgBufWide[msgCtx->msgBufPos] & 0xFF) == 2) { + if (LINK_AGE_IN_YEARS == YEARS_CHILD) { + value &= 0x7F; + } else { + value = ((HIGH_SCORE(font->msgBufWide[msgCtx->msgBufPos]) & 0xFF000000) >> 0x18) & 0x7F; } + } + switch (font->msgBufWide[msgCtx->msgBufPos] & 0xFF) { + case HS_HBA: + case HS_POE_POINTS: + case HS_FISHING: + digits[0] = digits[1] = digits[2] = 0; + digits[3] = value; - loadChar = false; - for (i = 0; i < 4; i++) { - if (i == 3 || digits[i] != 0) { - loadChar = true; - } - if (loadChar) { - Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); - msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; - charTexIdx += FONT_CHAR_TEX_SIZE; - decodedBufPos++; - } - } - decodedBufPos--; - break; - case HS_UNK_05: - break; - case HS_HORSE_RACE: - case HS_MARATHON: - case HS_DAMPE_RACE: - digits[0] = digits[1] = digits[2] = 0; - digits[3] = value; - - while (digits[3] >= 60) { - digits[1]++; - if (digits[1] >= 10) { + while (digits[3] >= 1000) { digits[0]++; - digits[1] -= 10; + digits[3] -= 1000; + } + while (digits[3] >= 100) { + digits[1]++; + digits[3] -= 100; + } + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; } - digits[3] -= 60; - } - while (digits[3] >= 10) { - digits[2]++; - digits[3] -= 10; - } - for (i = 0; i < 4; i++) { + loadChar = false; + for (i = 0; i < 4; i++) { + if (i == 3 || digits[i] != 0) { + loadChar = true; + } + if (loadChar) { + Font_LoadCharWide(font, digits[i] + MESSAGE_WIDE_CHAR_ZERO, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = digits[i] + MESSAGE_WIDE_CHAR_ZERO; + decodedBufPos++; + } + } + decodedBufPos--; + break; + case HS_UNK_05: + break; + case HS_HORSE_RACE: + case HS_MARATHON: + case HS_DAMPE_RACE: + digits[0] = digits[1] = digits[2] = 0; + digits[3] = value; + + while (digits[3] >= 60) { + digits[1]++; + if (digits[1] >= 10) { + digits[0]++; + digits[1] -= 10; + } + digits[3] -= 60; + } + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } + + for (i = 0; i < 4; i++) { + Font_LoadCharWide(font, digits[i] + MESSAGE_WIDE_CHAR_ZERO, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = digits[i] + MESSAGE_WIDE_CHAR_ZERO; + decodedBufPos++; + if (i == 1) { + Font_LoadCharWide(font, MESSAGE_WIDE_CHAR_MINUTES, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = MESSAGE_WIDE_CHAR_MINUTES; + decodedBufPos++; + } else if (i == 3) { + Font_LoadCharWide(font, MESSAGE_WIDE_CHAR_SECONDS, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = MESSAGE_WIDE_CHAR_SECONDS; + } + } + break; + } + } else if (curCharWide == MESSAGE_WIDE_TIME) { + digits[0] = 0; + timeInSeconds = gSaveContext.save.dayTime * (24.0f * 60.0f / 0x10000); + + digits[1] = timeInSeconds / 60.0f; + while (digits[1] >= 10) { + digits[0]++; + digits[1] -= 10; + } + digits[2] = 0; + digits[3] = (s16)timeInSeconds % 60; + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } + + for (i = 0; i < 4; i++) { + Font_LoadCharWide(font, digits[i] + MESSAGE_WIDE_CHAR_ZERO, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = digits[i] + MESSAGE_WIDE_CHAR_ZERO; + decodedBufPos++; + if (i == 1) { + Font_LoadCharWide(font, MESSAGE_WIDE_CHAR_HOURS, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = MESSAGE_WIDE_CHAR_HOURS; + decodedBufPos++; + } else if (i == 3) { + Font_LoadCharWide(font, MESSAGE_WIDE_CHAR_MINUTES, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecodedWide[decodedBufPos] = MESSAGE_WIDE_CHAR_MINUTES; + } + } + } else if (curCharWide == MESSAGE_WIDE_ITEM_ICON) { + msgCtx->msgBufDecodedWide[++decodedBufPos] = font->msgBufWide[msgCtx->msgBufPos + 1]; + Message_LoadItemIcon(play, font->msgBufWide[msgCtx->msgBufPos + 1], R_TEXTBOX_Y + 10); + } else if (curCharWide == MESSAGE_WIDE_BACKGROUND) { + msgCtx->textboxBackgroundIdx = font->msgBufWide[msgCtx->msgBufPos + 1] * 2; + msgCtx->textboxBackgroundForeColorIdx = (font->msgBufWide[msgCtx->msgBufPos + 2] & 0xF000) >> 12; + msgCtx->textboxBackgroundBackColorIdx = (font->msgBufWide[msgCtx->msgBufPos + 2] & 0xF00) >> 8; + msgCtx->textboxBackgroundYOffsetIdx = (font->msgBufWide[msgCtx->msgBufPos + 2] & 0xF0) >> 4; + msgCtx->textboxBackgroundUnkArg = font->msgBufWide[msgCtx->msgBufPos + 2] & 0xF; + DmaMgr_RequestSync(msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE, + (uintptr_t)_message_texture_staticSegmentRomStart + + msgCtx->textboxBackgroundIdx * MESSAGE_TEXTURE_STATIC_TEX_SIZE, + MESSAGE_TEXTURE_STATIC_TEX_SIZE); + DmaMgr_RequestSync(msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE + MESSAGE_TEXTURE_STATIC_TEX_SIZE, + (uintptr_t)_message_texture_staticSegmentRomStart + + (msgCtx->textboxBackgroundIdx + 1) * MESSAGE_TEXTURE_STATIC_TEX_SIZE, + MESSAGE_TEXTURE_STATIC_TEX_SIZE); + numLines = 2; + msgCtx->msgBufPos += 2; + R_TEXTBOX_BG_YPOS = R_TEXTBOX_Y + 8; + } else if (curCharWide == MESSAGE_WIDE_COLOR) { + msgCtx->msgBufDecodedWide[++decodedBufPos] = font->msgBufWide[++msgCtx->msgBufPos] & 0xF; + } else if (curCharWide == MESSAGE_WIDE_NEWLINE) { + numLines++; + } else if (curCharWide != MESSAGE_WIDE_QUICKTEXT_ENABLE && curCharWide != MESSAGE_WIDE_QUICKTEXT_DISABLE && + curCharWide != MESSAGE_WIDE_AWAIT_BUTTON_PRESS && curCharWide != MESSAGE_WIDE_OCARINA && + curCharWide != MESSAGE_WIDE_PERSISTENT && curCharWide != MESSAGE_WIDE_UNSKIPPABLE) { + if (curCharWide == MESSAGE_WIDE_FADE) { + sTextFade = true; + msgCtx->msgBufDecodedWide[++decodedBufPos] = font->msgBufWide[++msgCtx->msgBufPos] & 0xFF; + } else if (curCharWide == MESSAGE_WIDE_SHIFT || curCharWide == MESSAGE_WIDE_TEXT_SPEED) { + msgCtx->msgBufDecodedWide[++decodedBufPos] = font->msgBufWide[++msgCtx->msgBufPos] & 0xFF; + } else if (curCharWide == MESSAGE_WIDE_SFX) { + msgCtx->msgBufDecodedWide[++decodedBufPos] = font->msgBufWide[++msgCtx->msgBufPos]; + } else if (curCharWide == MESSAGE_WIDE_TWO_CHOICE) { + msgCtx->choiceNum = 2; + } else if (curCharWide == MESSAGE_WIDE_THREE_CHOICE) { + msgCtx->choiceNum = 3; + R_TEXT_INIT_XPOS += 32; + } else if (curCharWide != MESSAGE_WIDE_CHAR_SPACE) { + Font_LoadCharWide(font, curCharWide, charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + } + } + decodedBufPos++; + msgCtx->msgBufPos++; + } + } else { +#endif + // English text for NTSC, eng/ger/fra text for PAL + while (true) { + curChar = msgCtx->msgBufDecoded[decodedBufPos] = font->msgBuf[msgCtx->msgBufPos]; + + if (curChar == MESSAGE_BOX_BREAK || curChar == MESSAGE_TEXTID || curChar == MESSAGE_BOX_BREAK_DELAYED || + curChar == MESSAGE_EVENT || curChar == MESSAGE_END) { + // Textbox decoding ends with any of the above text control characters + msgCtx->msgMode = MSGMODE_TEXT_DISPLAYING; + msgCtx->textDrawPos = 1; + R_TEXT_INIT_YPOS = R_TEXTBOX_Y + 8; + PRINTF("JJ=%d\n", numLines); + if (msgCtx->textBoxType != TEXTBOX_TYPE_NONE_BOTTOM) { + if (numLines == 0) { + R_TEXT_INIT_YPOS = (u16)(R_TEXTBOX_Y + 26); + } else if (numLines == 1) { + R_TEXT_INIT_YPOS = (u16)(R_TEXTBOX_Y + 20); + } else if (numLines == 2) { + R_TEXT_INIT_YPOS = (u16)(R_TEXTBOX_Y + 16); + } + } + if (curChar == MESSAGE_TEXTID) { + PRINTF("NZ_NEXTMSG=%x, %x, %x\n", font->msgBuf[msgCtx->msgBufPos], + font->msgBuf[msgCtx->msgBufPos + 1], font->msgBuf[msgCtx->msgBufPos + 2]); + value = msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[msgCtx->msgBufPos + 1]; + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[msgCtx->msgBufPos + 2]; + value <<= 8; + sNextTextId = msgCtx->msgBufDecoded[decodedBufPos] | value; + } + if (curChar == MESSAGE_BOX_BREAK_DELAYED) { + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[msgCtx->msgBufPos + 1]; + msgCtx->msgBufPos += 2; + } + msgCtx->decodedTextLen = decodedBufPos; + if (sTextboxSkipped) { + msgCtx->textDrawPos = msgCtx->decodedTextLen; + } + break; + } else if (curChar == MESSAGE_NAME) { + // Substitute the player name control character for the file's player name. + for (playerNameLen = ARRAY_COUNT(gSaveContext.save.info.playerData.playerName); playerNameLen > 0; + playerNameLen--) { + if (gSaveContext.save.info.playerData.playerName[playerNameLen - 1] != FILENAME_SPACE) { + break; + } + } + // "Name" + PRINTF("\n名前 = "); + for (i = 0; i < playerNameLen; i++) { + curChar = gSaveContext.save.info.playerData.playerName[i]; + if (curChar == FILENAME_SPACE) { + curChar = ' '; + } else if (curChar == FILENAME_PERIOD) { + curChar = '.'; + } else if (curChar == FILENAME_DASH) { + curChar = '-'; + } else if (curChar <= FILENAME_DIGIT('9')) { + curChar -= FILENAME_DIGIT('0'); + curChar += '0'; + } else if (curChar <= FILENAME_UPPERCASE('Z')) { + curChar -= FILENAME_UPPERCASE('A'); + curChar += 'A'; + } else if (curChar <= FILENAME_LOWERCASE('z')) { + curChar -= FILENAME_LOWERCASE('a'); + curChar += 'a'; + } + if (curChar != ' ') { + Font_LoadChar(font, curChar - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + } + PRINTF("%x ", curChar); + msgCtx->msgBufDecoded[decodedBufPos] = curChar; + decodedBufPos++; + } + decodedBufPos--; + } else if (curChar == MESSAGE_MARATHON_TIME || curChar == MESSAGE_RACE_TIME) { + // Convert the values of the appropriate timer to digits and add the + // digits to the decoded buffer in place of the control character. + // "EVENT timer" + PRINTF("\nEVENTタイマー = "); + digits[0] = digits[1] = digits[2] = 0; + if (curChar == MESSAGE_RACE_TIME) { + digits[3] = gSaveContext.timerSeconds; + } else { + digits[3] = gSaveContext.subTimerSeconds; + } + + while (digits[3] >= 60) { + digits[1]++; + if (digits[1] >= 10) { + digits[0]++; + digits[1] -= 10; + } + digits[3] -= 60; + } + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } + + for (i = 0; i < 4; i++) { + Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; + decodedBufPos++; + if (i == 1) { + Font_LoadChar(font, '"' - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecoded[decodedBufPos] = '"'; + decodedBufPos++; + } else if (i == 3) { + Font_LoadChar(font, '"' - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecoded[decodedBufPos] = '"'; + } + } + } else if (curChar == MESSAGE_POINTS) { + // Convert the values of the current minigame score to digits and + // add the digits to the decoded buffer in place of the control character. + // "Yabusame score" + PRINTF("\n流鏑馬スコア = %d\n", gSaveContext.minigameScore); + digits[0] = digits[1] = digits[2] = 0; + digits[3] = gSaveContext.minigameScore; + + while (digits[3] >= 1000) { + digits[0]++; + digits[3] -= 1000; + } + while (digits[3] >= 100) { + digits[1]++; + digits[3] -= 100; + } + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } + + loadChar = false; + for (i = 0; i < 4; i++) { + if (i == 3 || digits[i] != 0) { + loadChar = true; + } + if (loadChar) { + Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); + msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; + charTexIdx += FONT_CHAR_TEX_SIZE; + decodedBufPos++; + } + } + decodedBufPos--; + } else if (curChar == MESSAGE_TOKENS) { + // Convert the current number of collected gold skulltula tokens to digits and + // add the digits to the decoded buffer in place of the control character. + // "Total number of gold stars" + PRINTF("\n金スタ合計数 = %d", gSaveContext.save.info.inventory.gsTokens); + digits[0] = digits[1] = 0; + digits[2] = gSaveContext.save.info.inventory.gsTokens; + + while (digits[2] >= 100) { + digits[0]++; + digits[2] -= 100; + } + while (digits[2] >= 10) { + digits[1]++; + digits[2] -= 10; + } + + loadChar = false; + for (i = 0; i < 3; i++) { + if (i == 2 || digits[i] != 0) { + loadChar = true; + } + if (loadChar) { Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); charTexIdx += FONT_CHAR_TEX_SIZE; msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; + PRINTF("%x(%x) ", digits[i] + '0' - ' ', digits[i]); decodedBufPos++; - if (i == 1) { - Font_LoadChar(font, '"' - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = '"'; - decodedBufPos++; - } else if (i == 3) { - Font_LoadChar(font, '"' - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = '"'; - } } - break; - } - } else if (curChar == MESSAGE_TIME) { - // "Zelda time" - PRINTF("\nゼルダ時間 = "); - digits[0] = 0; - timeInSeconds = gSaveContext.save.dayTime * (24.0f * 60.0f / 0x10000); + } + decodedBufPos--; + } else if (curChar == MESSAGE_FISH_INFO) { + // "Fishing hole fish size" + PRINTF("\n釣り堀魚サイズ = "); + digits[0] = 0; + digits[1] = gSaveContext.minigameScore; - digits[1] = timeInSeconds / 60.0f; - while (digits[1] >= 10) { - digits[0]++; - digits[1] -= 10; - } - digits[2] = 0; - digits[3] = (s16)timeInSeconds % 60; - while (digits[3] >= 10) { - digits[2]++; - digits[3] -= 10; - } + while (digits[1] >= 10) { + digits[0]++; + digits[1] -= 10; + } - for (i = 0; i < 4; i++) { - Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; - decodedBufPos++; - if (i == 1) { - Font_LoadChar(font, ':' - ' ', charTexIdx); + for (i = 0; i < 2; i++) { + if (i == 1 || digits[i] != 0) { + Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; + PRINTF("%x(%x) ", digits[i] + '0' - ' ', digits[i]); + decodedBufPos++; + } + } + decodedBufPos--; + } else if (curChar == MESSAGE_HIGHSCORE) { + value = HIGH_SCORE((u8)font->msgBuf[++msgCtx->msgBufPos]); + // "Highscore" + PRINTF("ランキング=%d\n", font->msgBuf[msgCtx->msgBufPos]); + if ((font->msgBuf[msgCtx->msgBufPos] & 0xFF) == 2) { + if (LINK_AGE_IN_YEARS == YEARS_CHILD) { + value &= 0x7F; + } else { + PRINTF("HI_SCORE( kanfont->mbuff.nes_mes_buf[message->rdp] & 0xff000000 ) = %x\n", + HIGH_SCORE(font->msgBufWide[msgCtx->msgBufPos] & 0xFF000000)); + value = ((HIGH_SCORE((u8)font->msgBuf[msgCtx->msgBufPos]) & 0xFF000000) >> 0x18) & 0x7F; + } + value = SQ((f32)value) * 0.0036f + 0.5f; + PRINTF("score=%d\n", value); + } + switch (font->msgBuf[msgCtx->msgBufPos] & 0xFF) { + case HS_HBA: + case HS_POE_POINTS: + case HS_FISHING: + digits[0] = digits[1] = digits[2] = 0; + digits[3] = value; + + while (digits[3] >= 1000) { + digits[0]++; + digits[3] -= 1000; + } + while (digits[3] >= 100) { + digits[1]++; + digits[3] -= 100; + } + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } + + loadChar = false; + for (i = 0; i < 4; i++) { + if (i == 3 || digits[i] != 0) { + loadChar = true; + } + if (loadChar) { + Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); + msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; + charTexIdx += FONT_CHAR_TEX_SIZE; + decodedBufPos++; + } + } + decodedBufPos--; + break; + case HS_UNK_05: + break; + case HS_HORSE_RACE: + case HS_MARATHON: + case HS_DAMPE_RACE: + digits[0] = digits[1] = digits[2] = 0; + digits[3] = value; + + while (digits[3] >= 60) { + digits[1]++; + if (digits[1] >= 10) { + digits[0]++; + digits[1] -= 10; + } + digits[3] -= 60; + } + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } + + for (i = 0; i < 4; i++) { + Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; + decodedBufPos++; + if (i == 1) { + Font_LoadChar(font, '"' - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecoded[decodedBufPos] = '"'; + decodedBufPos++; + } else if (i == 3) { + Font_LoadChar(font, '"' - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecoded[decodedBufPos] = '"'; + } + } + break; + } + } else if (curChar == MESSAGE_TIME) { + // "Zelda time" + PRINTF("\nゼルダ時間 = "); + digits[0] = 0; + timeInSeconds = gSaveContext.save.dayTime * (24.0f * 60.0f / 0x10000); + + digits[1] = timeInSeconds / 60.0f; + while (digits[1] >= 10) { + digits[0]++; + digits[1] -= 10; + } + digits[2] = 0; + digits[3] = (s16)timeInSeconds % 60; + while (digits[3] >= 10) { + digits[2]++; + digits[3] -= 10; + } + + for (i = 0; i < 4; i++) { + Font_LoadChar(font, digits[i] + '0' - ' ', charTexIdx); charTexIdx += FONT_CHAR_TEX_SIZE; - msgCtx->msgBufDecoded[decodedBufPos] = ':'; + msgCtx->msgBufDecoded[decodedBufPos] = digits[i] + '0'; decodedBufPos++; + if (i == 1) { + Font_LoadChar(font, ':' - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; + msgCtx->msgBufDecoded[decodedBufPos] = ':'; + decodedBufPos++; + } + } + decodedBufPos--; + } else if (curChar == MESSAGE_ITEM_ICON) { + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[msgCtx->msgBufPos + 1]; + PRINTF("ITEM_NO=(%d) (%d)\n", msgCtx->msgBufDecoded[decodedBufPos], + font->msgBuf[msgCtx->msgBufPos + 1]); + Message_LoadItemIcon(play, font->msgBuf[msgCtx->msgBufPos + 1], R_TEXTBOX_Y + 10); + } else if (curChar == MESSAGE_BACKGROUND) { + msgCtx->textboxBackgroundIdx = font->msgBuf[msgCtx->msgBufPos + 1] * 2; + msgCtx->textboxBackgroundForeColorIdx = (font->msgBuf[msgCtx->msgBufPos + 2] & 0xF0) >> 4; + msgCtx->textboxBackgroundBackColorIdx = font->msgBuf[msgCtx->msgBufPos + 2] & 0xF; + msgCtx->textboxBackgroundYOffsetIdx = (font->msgBuf[msgCtx->msgBufPos + 3] & 0xF0) >> 4; + msgCtx->textboxBackgroundUnkArg = font->msgBuf[msgCtx->msgBufPos + 3] & 0xF; + DMA_REQUEST_SYNC(msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE, + (uintptr_t)_message_texture_staticSegmentRomStart + + msgCtx->textboxBackgroundIdx * MESSAGE_TEXTURE_STATIC_TEX_SIZE, + MESSAGE_TEXTURE_STATIC_TEX_SIZE, "../z_message_PAL.c", 1830); + DMA_REQUEST_SYNC(msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE + MESSAGE_TEXTURE_STATIC_TEX_SIZE, + (uintptr_t)_message_texture_staticSegmentRomStart + + (msgCtx->textboxBackgroundIdx + 1) * MESSAGE_TEXTURE_STATIC_TEX_SIZE, + MESSAGE_TEXTURE_STATIC_TEX_SIZE, "../z_message_PAL.c", 1834); + msgCtx->msgBufPos += 3; + R_TEXTBOX_BG_YPOS = R_TEXTBOX_Y + 8; + numLines = 2; +#if OOT_PAL + R_TEXT_INIT_XPOS = 50; +#endif + } else if (curChar == MESSAGE_COLOR) { + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; + } else if (curChar == MESSAGE_NEWLINE) { + numLines++; + } else if (curChar != MESSAGE_QUICKTEXT_ENABLE && curChar != MESSAGE_QUICKTEXT_DISABLE && + curChar != MESSAGE_AWAIT_BUTTON_PRESS && curChar != MESSAGE_OCARINA && + curChar != MESSAGE_PERSISTENT && curChar != MESSAGE_UNSKIPPABLE) { + if (curChar == MESSAGE_FADE) { + sTextFade = true; + PRINTF("NZ_TIMER_END (key_off_flag=%d)\n", sTextFade); + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; + } else if (curChar == MESSAGE_FADE2) { + sTextFade = true; + PRINTF("NZ_BGM (key_off_flag=%d)\n", sTextFade); + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; + } else if (curChar == MESSAGE_SHIFT || curChar == MESSAGE_TEXT_SPEED) { + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos] & 0xFF; + } else if (curChar == MESSAGE_SFX) { + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; + msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; + } else if (curChar == MESSAGE_TWO_CHOICE) { + msgCtx->choiceNum = 2; + } else if (curChar == MESSAGE_THREE_CHOICE) { + msgCtx->choiceNum = 3; + } else if (curChar != MESSAGE_CHAR_SPACE) { + Font_LoadChar(font, curChar - ' ', charTexIdx); + charTexIdx += FONT_CHAR_TEX_SIZE; } } - decodedBufPos--; - } else if (curChar == MESSAGE_ITEM_ICON) { - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[msgCtx->msgBufPos + 1]; - PRINTF("ITEM_NO=(%d) (%d)\n", msgCtx->msgBufDecoded[decodedBufPos], font->msgBuf[msgCtx->msgBufPos + 1]); - Message_LoadItemIcon(play, font->msgBuf[msgCtx->msgBufPos + 1], R_TEXTBOX_Y + 10); - } else if (curChar == MESSAGE_BACKGROUND) { - msgCtx->textboxBackgroundIdx = font->msgBuf[msgCtx->msgBufPos + 1] * 2; - msgCtx->textboxBackgroundForeColorIdx = (font->msgBuf[msgCtx->msgBufPos + 2] & 0xF0) >> 4; - msgCtx->textboxBackgroundBackColorIdx = font->msgBuf[msgCtx->msgBufPos + 2] & 0xF; - msgCtx->textboxBackgroundYOffsetIdx = (font->msgBuf[msgCtx->msgBufPos + 3] & 0xF0) >> 4; - msgCtx->textboxBackgroundUnkArg = font->msgBuf[msgCtx->msgBufPos + 3] & 0xF; - DMA_REQUEST_SYNC(msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE, - (uintptr_t)_message_texture_staticSegmentRomStart + - msgCtx->textboxBackgroundIdx * MESSAGE_TEXTURE_STATIC_TEX_SIZE, - MESSAGE_TEXTURE_STATIC_TEX_SIZE, "../z_message_PAL.c", 1830); - DMA_REQUEST_SYNC(msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE + MESSAGE_TEXTURE_STATIC_TEX_SIZE, - (uintptr_t)_message_texture_staticSegmentRomStart + - (msgCtx->textboxBackgroundIdx + 1) * MESSAGE_TEXTURE_STATIC_TEX_SIZE, - MESSAGE_TEXTURE_STATIC_TEX_SIZE, "../z_message_PAL.c", 1834); - msgCtx->msgBufPos += 3; - R_TEXTBOX_BG_YPOS = R_TEXTBOX_Y + 8; - numLines = 2; - R_TEXT_INIT_XPOS = 50; - } else if (curChar == MESSAGE_COLOR) { - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; - } else if (curChar == MESSAGE_NEWLINE) { - numLines++; - } else if (curChar != MESSAGE_QUICKTEXT_ENABLE && curChar != MESSAGE_QUICKTEXT_DISABLE && - curChar != MESSAGE_AWAIT_BUTTON_PRESS && curChar != MESSAGE_OCARINA && - curChar != MESSAGE_PERSISTENT && curChar != MESSAGE_UNSKIPPABLE) { - if (curChar == MESSAGE_FADE) { - sTextFade = true; - PRINTF("NZ_TIMER_END (key_off_flag=%d)\n", sTextFade); - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; - } else if (curChar == MESSAGE_FADE2) { - sTextFade = true; - PRINTF("NZ_BGM (key_off_flag=%d)\n", sTextFade); - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; - } else if (curChar == MESSAGE_SHIFT || curChar == MESSAGE_TEXT_SPEED) { - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos] & 0xFF; - } else if (curChar == MESSAGE_SFX) { - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; - msgCtx->msgBufDecoded[++decodedBufPos] = font->msgBuf[++msgCtx->msgBufPos]; - } else if (curChar == MESSAGE_TWO_CHOICE) { - msgCtx->choiceNum = 2; - } else if (curChar == MESSAGE_THREE_CHOICE) { - msgCtx->choiceNum = 3; - } else if (curChar != ' ') { - Font_LoadChar(font, curChar - ' ', charTexIdx); - charTexIdx += FONT_CHAR_TEX_SIZE; - } + decodedBufPos++; + msgCtx->msgBufPos++; } - decodedBufPos++; - msgCtx->msgBufPos++; +#if OOT_NTSC } +#endif } void Message_OpenText(PlayState* play, u16 textId) { @@ -1661,6 +2402,12 @@ void Message_OpenText(PlayState* play, u16 textId) { R_TEXT_LINE_SPACING = 6; R_TEXT_INIT_XPOS = 20; YREG(1) = 48; +#if OOT_NTSC + } else if (gSaveContext.language == LANGUAGE_JPN) { + R_TEXT_CHAR_SCALE = 88; + R_TEXT_LINE_SPACING = 18; + R_TEXT_INIT_XPOS = 50; +#endif } else { R_TEXT_CHAR_SCALE = 75; R_TEXT_LINE_SPACING = 12; @@ -1698,19 +2445,31 @@ void Message_OpenText(PlayState* play, u16 textId) { DMA_REQUEST_SYNC(font->msgBuf, (uintptr_t)_staff_message_data_staticSegmentRomStart + font->msgOffset, font->msgLength, "../z_message_PAL.c", 1954); } else { -#if OOT_PAL // TODO: implement NTSC version +#if OOT_NTSC + if (gSaveContext.language == LANGUAGE_JPN) { + Message_FindMessageJPN(play, textId); + msgCtx->msgLength = font->msgLength; + DmaMgr_RequestSync(font->msgBuf, (uintptr_t)_jpn_message_data_staticSegmentRomStart + font->msgOffset, + font->msgLength); + } else { + Message_FindMessageNES(play, textId); + msgCtx->msgLength = font->msgLength; + DmaMgr_RequestSync(font->msgBuf, (uintptr_t)_nes_message_data_staticSegmentRomStart + font->msgOffset, + font->msgLength); + } +#else if (gSaveContext.language == LANGUAGE_ENG) { - Message_FindMessage(play, textId); + Message_FindMessagePAL(play, textId); msgCtx->msgLength = font->msgLength; DMA_REQUEST_SYNC(font->msgBuf, (uintptr_t)_nes_message_data_staticSegmentRomStart + font->msgOffset, font->msgLength, "../z_message_PAL.c", 1966); } else if (gSaveContext.language == LANGUAGE_GER) { - Message_FindMessage(play, textId); + Message_FindMessagePAL(play, textId); msgCtx->msgLength = font->msgLength; DMA_REQUEST_SYNC(font->msgBuf, (uintptr_t)_ger_message_data_staticSegmentRomStart + font->msgOffset, font->msgLength, "../z_message_PAL.c", 1978); } else { - Message_FindMessage(play, textId); + Message_FindMessagePAL(play, textId); msgCtx->msgLength = font->msgLength; DMA_REQUEST_SYNC(font->msgBuf, (uintptr_t)_fra_message_data_staticSegmentRomStart + font->msgOffset, font->msgLength, "../z_message_PAL.c", 1990); @@ -1932,8 +2691,8 @@ void Message_StartOcarinaImpl(PlayState* play, u16 ocarinaActionId) { gSaveContext.hudVisibilityMode = HUD_VISIBILITY_NO_CHANGE; Interface_ChangeHudVisibilityMode(HUD_VISIBILITY_NOTHING); } - for (k = 0, j = 0; j < 48; j++, k += 0x80) { - func_8006EE50(&play->msgCtx.font, 0x8140, k); + for (k = 0, j = 0; j < 48; j++, k += FONT_CHAR_TEX_SIZE) { + Font_LoadCharWide(&play->msgCtx.font, MESSAGE_WIDE_CHAR_SPACE, k); } } @@ -2028,6 +2787,18 @@ void Message_SetView(View* view) { View_ApplyOrthoToOverlay(view); } +#if OOT_NTSC +#define DRAW_TEXT(play, gfx, isCredits) \ + if (gSaveContext.language == LANGUAGE_JPN && !(isCredits)) { \ + Message_DrawTextWide(play, gfx); \ + } else { \ + Message_DrawText(play, gfx); \ + } \ + (void)0 +#else +#define DRAW_TEXT(play, gfx, isCredits) Message_DrawText(play, gfx) +#endif + /** * Draws the textbox in full and updates ocarina state */ @@ -2107,19 +2878,19 @@ void Message_DrawMain(PlayState* play, Gfx** p) { break; case MSGMODE_TEXT_CONTINUING: if (msgCtx->stateTimer == 1) { - for (j = 0, i = 0; i < 48; i++, j += 0x80) { - func_8006EE50(&play->msgCtx.font, 0x8140, j); + for (j = 0, i = 0; i < 48; i++, j += FONT_CHAR_TEX_SIZE) { + Font_LoadCharWide(&play->msgCtx.font, MESSAGE_WIDE_CHAR_SPACE, j); } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, sTextIsCredits); } break; case MSGMODE_TEXT_DISPLAYING: case MSGMODE_TEXT_DELAYED_BREAK: - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, sTextIsCredits); break; case MSGMODE_TEXT_AWAIT_INPUT: case MSGMODE_TEXT_AWAIT_NEXT: - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, sTextIsCredits); Message_DrawTextboxIcon(play, &gfx, R_TEXTBOX_END_XPOS, R_TEXTBOX_END_YPOS); break; case MSGMODE_OCARINA_STARTING: @@ -2162,7 +2933,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { } if (msgCtx->ocarinaAction != OCARINA_ACTION_FREE_PLAY && msgCtx->ocarinaAction != OCARINA_ACTION_CHECK_NOWARP) { - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, sTextIsCredits); } break; case MSGMODE_OCARINA_PLAYING: @@ -2241,6 +3012,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } + if (msgCtx->ocarinaStaff == NULL) {} // fake Interface_ChangeHudVisibilityMode(HUD_VISIBILITY_NOTHING); } else { AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF); @@ -2261,7 +3033,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { } if (msgCtx->ocarinaAction != OCARINA_ACTION_FREE_PLAY && msgCtx->ocarinaAction != OCARINA_ACTION_CHECK_NOWARP) { - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, sTextIsCredits); } break; case MSGMODE_OCARINA_CORRECT_PLAYBACK: @@ -2402,11 +3174,11 @@ void Message_DrawMain(PlayState* play, Gfx** p) { play->msgCtx.ocarinaMode = OCARINA_MODE_03; } } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_OCARINA_FAIL: case MSGMODE_SONG_PLAYBACK_FAIL: - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); FALLTHROUGH; case MSGMODE_OCARINA_FAIL_NO_TEXT: msgCtx->stateTimer--; @@ -2468,7 +3240,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { } break; case MSGMODE_SETUP_DISPLAY_SONG_PLAYED: - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_DEFAULT); AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_DEFAULT); AudioOcarina_SetPlaybackSong(msgCtx->lastPlayedSong + 1, 1); @@ -2508,28 +3280,28 @@ void Message_DrawMain(PlayState* play, Gfx** p) { sOcarinaButtonIndexBufPos = 0; msgCtx->msgMode = MSGMODE_SONG_DEMONSTRATION; } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_DISPLAY_SONG_PLAYED_TEXT_BEGIN: Message_ContinueTextbox(play, msgCtx->lastPlayedSong + 0x893); // You played [song name] Message_Decode(play); msgCtx->msgMode = MSGMODE_DISPLAY_SONG_PLAYED_TEXT; msgCtx->stateTimer = 20; - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_DISPLAY_SONG_PLAYED_TEXT: msgCtx->stateTimer--; if (msgCtx->stateTimer == 0) { msgCtx->msgMode = MSGMODE_SONG_PLAYED_ACT_BEGIN; } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_SONG_PLAYED_ACT_BEGIN: AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF); Message_ResetOcarinaNoteState(); msgCtx->msgMode = MSGMODE_SONG_PLAYED_ACT; msgCtx->stateTimer = 2; - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_SONG_PLAYED_ACT: msgCtx->stateTimer--; @@ -2609,7 +3381,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { } FALLTHROUGH; case MSGMODE_SONG_DEMONSTRATION_DONE: - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_SONG_PLAYBACK: msgCtx->ocarinaStaff = AudioOcarina_GetPlayingStaff(); @@ -2638,10 +3410,10 @@ void Message_DrawMain(PlayState* play, Gfx** p) { msgCtx->stateTimer = 10; msgCtx->msgMode = MSGMODE_SONG_PLAYBACK_FAIL; } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_OCARINA_AWAIT_INPUT: - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); if (Message_ShouldAdvance(play)) { Message_StartOcarina(play, msgCtx->ocarinaAction); } @@ -2656,7 +3428,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { sOcarinaButtonIndexBufLen = 0; Message_ResetOcarinaNoteState(); msgCtx->msgMode = MSGMODE_SCARECROW_LONG_RECORDING_ONGOING; - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_SCARECROW_LONG_RECORDING_ONGOING: msgCtx->ocarinaStaff = AudioOcarina_GetRecordingStaff(); @@ -2706,7 +3478,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { PRINTF(VT_RST); PRINTF("\n====================================================================\n"); } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_SCARECROW_LONG_PLAYBACK: case MSGMODE_SCARECROW_SPAWN_PLAYBACK: @@ -2743,7 +3515,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { AudioOcarina_SetRecordingState(OCARINA_RECORD_SCARECROW_SPAWN); AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_DEFAULT); msgCtx->msgMode = MSGMODE_SCARECROW_SPAWN_RECORDING_ONGOING; - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_SCARECROW_SPAWN_RECORDING_ONGOING: msgCtx->ocarinaStaff = AudioOcarina_GetRecordingStaff(); @@ -2781,7 +3553,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { Message_CloseTextbox(play); msgCtx->msgMode = MSGMODE_SCARECROW_SPAWN_RECORDING_FAILED; } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_SCARECROW_SPAWN_RECORDING_FAILED: PRINTF("cccccccccccc\n"); @@ -2862,7 +3634,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { msgCtx->msgMode = MSGMODE_MEMORY_GAME_ROUND_SUCCESS; msgCtx->stateTimer = 30; } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_MEMORY_GAME_ROUND_SUCCESS: msgCtx->ocarinaStaff = AudioOcarina_GetPlayingStaff(); @@ -2885,7 +3657,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { play->msgCtx.ocarinaMode = OCARINA_MODE_0F; } } - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, false); break; case MSGMODE_MEMORY_GAME_START_NEXT_ROUND: if (!Audio_IsSfxPlaying(NA_SE_SY_METRONOME)) { @@ -2917,7 +3689,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { case MSGMODE_FROGS_WAITING: break; case MSGMODE_TEXT_DONE: - Message_DrawText(play, &gfx); + DRAW_TEXT(play, &gfx, sTextIsCredits); switch (msgCtx->textboxEndType) { case TEXTBOX_ENDTYPE_2_CHOICE: @@ -3239,9 +4011,22 @@ void Message_Update(PlayState* play) { R_TEXTBOX_X_TARGET = sTextboxXPositions[var]; R_TEXTBOX_END_YPOS = sTextboxEndIconYOffset[var] + R_TEXTBOX_Y_TARGET; +#if OOT_NTSC + if (gSaveContext.language == LANGUAGE_JPN && !sTextIsCredits) { + R_TEXT_CHOICE_YPOS(0) = R_TEXTBOX_Y_TARGET + 7; + R_TEXT_CHOICE_YPOS(1) = R_TEXTBOX_Y_TARGET + 25; + R_TEXT_CHOICE_YPOS(2) = R_TEXTBOX_Y_TARGET + 43; + + } else { + R_TEXT_CHOICE_YPOS(0) = R_TEXTBOX_Y_TARGET + 20; + R_TEXT_CHOICE_YPOS(1) = R_TEXTBOX_Y_TARGET + 32; + R_TEXT_CHOICE_YPOS(2) = R_TEXTBOX_Y_TARGET + 44; + } +#else R_TEXT_CHOICE_YPOS(0) = R_TEXTBOX_Y_TARGET + 20; R_TEXT_CHOICE_YPOS(1) = R_TEXTBOX_Y_TARGET + 32; R_TEXT_CHOICE_YPOS(2) = R_TEXTBOX_Y_TARGET + 44; +#endif PRINTF("message->msg_disp_type=%x\n", msgCtx->textBoxProperties & 0xF0); if (msgCtx->textBoxType == TEXTBOX_TYPE_NONE_BOTTOM || msgCtx->textBoxType == TEXTBOX_TYPE_NONE_NO_SHADOW) { @@ -3334,7 +4119,15 @@ void Message_Update(PlayState* play) { if (msgCtx->textboxEndType == TEXTBOX_ENDTYPE_HAS_NEXT) { Audio_PlaySfxGeneral(NA_SE_SY_MESSAGE_PASS, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); +#if OOT_NTSC + if (gSaveContext.language == LANGUAGE_JPN && !sTextIsCredits) { + Message_ContinueTextbox(play, msgCtx->msgBufDecodedWide[msgCtx->textDrawPos]); + } else { + Message_ContinueTextbox(play, sNextTextId); + } +#else Message_ContinueTextbox(play, sNextTextId); +#endif } else { Audio_PlaySfxGeneral(NA_SE_SY_DECIDE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); diff --git a/src/code/z_player_lib.c b/src/code/z_player_lib.c index 80d4c210d1..7b90a1e35f 100644 --- a/src/code/z_player_lib.c +++ b/src/code/z_player_lib.c @@ -1125,13 +1125,14 @@ s32 Player_OverrideLimbDrawGameplayCommon(PlayState* play, s32 limbIndex, Gfx** sCurBodyPartPos = &this->bodyPartsPos[0] - 1; if (!LINK_IS_ADULT) { - if (!(this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_2) || + if (!(this->skelAnime.moveFlags & ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT) || (this->skelAnime.moveFlags & ANIM_FLAG_UPDATE_XZ)) { pos->x *= 0.64f; pos->z *= 0.64f; } - if (!(this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_2) || (this->skelAnime.moveFlags & ANIM_FLAG_UPDATE_Y)) { + if (!(this->skelAnime.moveFlags & ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT) || + (this->skelAnime.moveFlags & ANIM_FLAG_UPDATE_Y)) { pos->y *= 0.64f; } } @@ -1522,6 +1523,11 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Ve func_80090A28(this, spE4); func_800906D4(play, this, spE4); } else if ((*dList != NULL) && (this->leftHandType == PLAYER_MODELTYPE_LH_BOTTLE)) { + //! @bug When Player is actively using shield, the `itemAction` value will be set to -1. + //! If shield is used at the same time a bottle is in hand, `Player_ActionToBottle` will + //! return -1, which results in an out of bounds access behind the `sBottleColors` array. + //! A value of -1 happens to access `gLinkChildBottleDL` (0x06018478). The last 3 bytes of + //! this pointer are read as a color, which results in a dark teal color used for the bottle. Color_RGB8* bottleColor = &sBottleColors[Player_ActionToBottle(this, this->itemAction)]; OPEN_DISPS(play->state.gfxCtx, "../z_player_lib.c", 2710); diff --git a/src/overlays/actors/ovl_Fishing/z_fishing.c b/src/overlays/actors/ovl_Fishing/z_fishing.c index d1a18134cf..49ff3b5f1e 100644 --- a/src/overlays/actors/ovl_Fishing/z_fishing.c +++ b/src/overlays/actors/ovl_Fishing/z_fishing.c @@ -12,7 +12,7 @@ #include "terminal.h" // For retail BSS ordering, the block number of sStreamSfxProjectedPos must be 0. -#pragma increment_block_number 208 +#pragma increment_block_number 206 #define FLAGS ACTOR_FLAG_4 diff --git a/src/overlays/actors/ovl_player_actor/z_player.c b/src/overlays/actors/ovl_player_actor/z_player.c index 9ac957cc02..0073b5d76e 100644 --- a/src/overlays/actors/ovl_player_actor/z_player.c +++ b/src/overlays/actors/ovl_player_actor/z_player.c @@ -2008,7 +2008,8 @@ void Player_AnimReplacePlayOnceAdjusted(PlayState* play, Player* this, LinkAnima void Player_AnimReplaceNormalPlayOnceAdjusted(PlayState* play, Player* this, LinkAnimationHeader* anim) { Player_AnimReplacePlayOnceAdjusted(play, this, anim, - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_ADJUST_STARTING_POS); } void Player_AnimReplacePlayLoopSetSpeed(PlayState* play, Player* this, LinkAnimationHeader* anim, s32 flags, @@ -2027,7 +2028,8 @@ void Player_AnimReplacePlayLoopAdjusted(PlayState* play, Player* this, LinkAnima void Player_AnimReplaceNormalPlayLoopAdjusted(PlayState* play, Player* this, LinkAnimationHeader* anim) { Player_AnimReplacePlayLoopAdjusted(play, this, anim, - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_ADJUST_STARTING_POS); } void Player_ProcessControlStick(PlayState* play, Player* this) { @@ -5056,7 +5058,7 @@ s32 Player_ActionChange_1(Player* this, PlayState* play) { func_80832224(this); Player_AnimReplaceApplyFlags(play, this, ANIM_REPLACE_APPLY_FLAG_9 | ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_OVERRIDE_MOVEMENT); // If this door is the second half of a double door (spawned as child) @@ -5367,9 +5369,9 @@ s32 func_8083A6AC(Player* this, PlayState* play) { this->stateFlags1 |= PLAYER_STATE1_21; Player_AnimReplaceApplyFlags(play, this, - ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | ANIM_FLAG_PLAYER_2 | - ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | - ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); this->av2.actionVar2 = -1; this->av1.actionVar1 = sp50; @@ -6062,7 +6064,7 @@ s32 Player_ActionChange_11(Player* this, PlayState* play) { LinkAnimation_Change(play, &this->skelAnime, anim, 1.0f, frame, frame, ANIMMODE_ONCE, 0.0f); if (Player_IsChildWithHylianShield(this)) { - Player_AnimReplaceApplyFlags(play, this, ANIM_FLAG_PLAYER_2); + Player_AnimReplaceApplyFlags(play, this, ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT); } Player_PlaySfx(this, NA_SE_IT_SHIELD_POSTURE); @@ -6892,8 +6894,8 @@ s32 Player_ActionChange_2(Player* this, PlayState* play) { Player_AnimPlayOnceAdjusted(play, this, this->ageProperties->unk_98); Player_AnimReplaceApplyFlags(play, this, ANIM_REPLACE_APPLY_FLAG_9 | ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | - ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | + ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_OVERRIDE_MOVEMENT); chest->unk_1F4 = 1; Camera_RequestSetting(Play_GetCamera(play, CAM_ID_MAIN), CAM_SET_SLOW_CHEST_CS); } else { @@ -7069,10 +7071,10 @@ s32 func_8083EC18(Player* this, PlayState* play, u32 wallFlags) { func_80832224(this); Math_Vec3f_Copy(&this->actor.prevPos, &this->actor.world.pos); Player_AnimPlayOnce(play, this, anim); - Player_AnimReplaceApplyFlags(play, this, - ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | ANIM_FLAG_PLAYER_2 | - ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | - ANIM_FLAG_OVERRIDE_MOVEMENT); + Player_AnimReplaceApplyFlags( + play, this, + ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | + ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); return true; } @@ -7152,8 +7154,9 @@ s32 Player_TryEnteringCrawlspace(Player* this, PlayState* play, u32 interactWall this->actor.prevPos = this->actor.world.pos; Player_AnimPlayOnce(play, this, &gPlayerAnim_link_child_tunnel_start); Player_AnimReplaceApplyFlags(play, this, - ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | - ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | + ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | + ANIM_FLAG_OVERRIDE_MOVEMENT); return true; } @@ -7242,8 +7245,9 @@ s32 Player_TryLeavingCrawlspace(Player* this, PlayState* play) { this->actor.shape.rot.y = this->actor.wallYaw + 0x8000; Player_AnimPlayOnce(play, this, &gPlayerAnim_link_child_tunnel_end); Player_AnimReplaceApplyFlags(play, this, - ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | - ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | + ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | + ANIM_FLAG_OVERRIDE_MOVEMENT); OnePointCutscene_Init(play, 9601, 999, NULL, CAM_ID_MAIN); } else { // Leaving a crawlspace backwards @@ -7252,8 +7256,9 @@ s32 Player_TryLeavingCrawlspace(Player* this, PlayState* play) { Animation_GetLastFrame(&gPlayerAnim_link_child_tunnel_start), 0.0f, ANIMMODE_ONCE, 0.0f); Player_AnimReplaceApplyFlags(play, this, - ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | - ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | + ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | + ANIM_FLAG_OVERRIDE_MOVEMENT); OnePointCutscene_Init(play, 9602, 999, NULL, CAM_ID_MAIN); } @@ -8661,7 +8666,7 @@ void Player_Action_80843188(Player* this, PlayState* play) { LinkAnimation_Change(play, &this->skelAnime, &gPlayerAnim_clink_normal_defense_ALL, 1.0f, Animation_GetLastFrame(&gPlayerAnim_clink_normal_defense_ALL), 0.0f, ANIMMODE_ONCE, 0.0f); - Player_AnimReplaceApplyFlags(play, this, ANIM_FLAG_PLAYER_2); + Player_AnimReplaceApplyFlags(play, this, ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT); } else { if (this->itemAction < 0) { func_8008EC70(this); @@ -9972,7 +9977,8 @@ void func_808467D4(PlayState* play, Player* this) { 0.0f); Player_AnimReplaceApplyFlags(play, this, ANIM_REPLACE_APPLY_FLAG_9 | ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_OVERRIDE_MOVEMENT); if (LINK_IS_ADULT) { func_80846720(play, this, 0); } @@ -11350,8 +11356,9 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { if (this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_SETMOVE) { AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, - (this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_2) ? 1.0f - : this->ageProperties->unk_08); + (this->skelAnime.moveFlags & ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT) + ? 1.0f + : this->ageProperties->unk_08); } Player_UpdateShapeYaw(this, play); @@ -14549,8 +14556,8 @@ void func_808510D4(PlayState* play, Player* this, void* anim) { void func_808510F4(PlayState* play, Player* this, void* anim) { Player_AnimReplacePlayOnce(play, this, anim, - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | - ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); } void func_80851114(PlayState* play, Player* this, void* anim) { @@ -14559,8 +14566,8 @@ void func_80851114(PlayState* play, Player* this, void* anim) { void func_80851134(PlayState* play, Player* this, void* anim) { Player_AnimReplacePlayLoop(play, this, anim, - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | - ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); } void func_80851154(PlayState* play, Player* this, void* anim) { @@ -14807,7 +14814,8 @@ void func_808519EC(PlayState* play, Player* this, CsCmdActorCue* cue) { Player_AnimPlayOnceAdjusted(play, this, this->ageProperties->unk_9C); Player_AnimReplaceApplyFlags(play, this, ANIM_REPLACE_APPLY_FLAG_9 | ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_OVERRIDE_MOVEMENT); } static struct_808551A4 D_808551A4[] = { @@ -14924,16 +14932,16 @@ void func_80851E64(PlayState* play, Player* this, CsCmdActorCue* cue) { void func_80851E90(PlayState* play, Player* this, CsCmdActorCue* cue) { Player_AnimReplacePlayOnce(play, this, &gPlayerAnim_clink_op3_negaeri, - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | - ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); func_80832698(this, NA_SE_VO_LI_GROAN); } void func_80851ECC(PlayState* play, Player* this, CsCmdActorCue* cue) { if (LinkAnimation_Update(play, &this->skelAnime)) { Player_AnimReplacePlayLoop(play, this, &gPlayerAnim_clink_op3_wait2, - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | - ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); } } @@ -14960,8 +14968,8 @@ static AnimSfxEntry D_808551BC[] = { void func_80851FB0(PlayState* play, Player* this, CsCmdActorCue* cue) { if (LinkAnimation_Update(play, &this->skelAnime)) { Player_AnimReplacePlayLoop(play, this, &gPlayerAnim_clink_op3_wait3, - ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | - ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_PLAYER_SETMOVE | + ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); this->av2.actionVar2 = 1; } else if (this->av2.actionVar2 == 0) { Player_ProcessAnimSfxList(this, D_808551BC); @@ -14985,8 +14993,9 @@ void func_80852048(PlayState* play, Player* this, CsCmdActorCue* cue) { void func_80852080(PlayState* play, Player* this, CsCmdActorCue* cue) { Player_AnimReplacePlayOnceAdjusted(play, this, &gPlayerAnim_clink_demo_futtobi, - ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_PLAYER_2 | ANIM_FLAG_PLAYER_SETMOVE | - ANIM_FLAG_ADJUST_STARTING_POS | ANIM_FLAG_OVERRIDE_MOVEMENT); + ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | + ANIM_FLAG_PLAYER_SETMOVE | ANIM_FLAG_ADJUST_STARTING_POS | + ANIM_FLAG_OVERRIDE_MOVEMENT); func_80832698(this, NA_SE_VO_LI_FALL_L); } @@ -15273,7 +15282,8 @@ void func_80852B4C(PlayState* play, Player* this, CsCmdActorCue* cue, struct_808 arg3->func(play, this, cue); } - if ((D_80858AA0 & ANIM_FLAG_PLAYER_2) && !(this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_2)) { + if ((D_80858AA0 & ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT) && + !(this->skelAnime.moveFlags & ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT)) { this->skelAnime.morphTable[0].y /= this->ageProperties->unk_08; D_80858AA0 = 0; } diff --git a/tools/check_ordering.py b/tools/check_ordering.py index 83eecfacb4..0af2d9a949 100755 --- a/tools/check_ordering.py +++ b/tools/check_ordering.py @@ -94,7 +94,7 @@ def read_s16(f: BinaryIO, offset: int) -> int: def main(): parser = argparse.ArgumentParser( - description="Report data/bss reorderings between the baserom and the current build " + description="Report bss reorderings between the baserom and the current build " "by parsing relocations from the built object files and comparing their final values " "between the baserom and the current build. " "Assumes that the only differences are due to ordering and that the text sections of the " @@ -112,6 +112,11 @@ def main(): type=str, help="ROM segment to check, e.g. 'boot', 'code', or 'ovl_player_actor' (default: all)", ) + parser.add_argument( + "--all-sections", + action="store_true", + help="Check ordering for all section types, not just .bss", + ) args = parser.parse_args() version = args.oot_version @@ -176,10 +181,9 @@ def main(): else: assert False, "Invalid relocation" - if base_value != build_value: - pointers.append( - Pointer(reloc.name, reloc.addend, base_value, build_value) - ) + pointers.append( + Pointer(reloc.name, reloc.addend, base_value, build_value) + ) # Remove duplicates and sort by baserom address pointers = list({p.base_value: p for p in pointers}.values()) @@ -188,6 +192,9 @@ def main(): # Go through sections and report differences for mapfile_segment in source_code_segments: for file in mapfile_segment: + if not args.all_sections and not file.sectionType == ".bss": + continue + pointers_in_section = [ p for p in pointers @@ -196,6 +203,17 @@ def main(): if not pointers_in_section: continue + # Try to detect if the section is shifted by comparing the lowest + # address among any pointer into the section between base and build + base_min_address = min(p.base_value for p in pointers_in_section) + build_min_address = min(p.build_value for p in pointers_in_section) + section_shift = build_min_address - base_min_address + if all( + p.build_value == p.base_value + section_shift + for p in pointers_in_section + ): + continue + print(f"{file.filepath} {file.sectionType} is reordered:") for i, p in enumerate(pointers_in_section): if p.addend > 0: diff --git a/tools/disasm/gc-us/functions.txt b/tools/disasm/gc-us/functions.txt index 6a84ee67b8..5300b4ed5e 100644 --- a/tools/disasm/gc-us/functions.txt +++ b/tools/disasm/gc-us/functions.txt @@ -1169,7 +1169,7 @@ Jpeg_Decode = 0x8005B1AC; // type:func KaleidoSetup_Update = 0x8005B4E0; // type:func KaleidoSetup_Init = 0x8005B74C; // type:func KaleidoSetup_Destroy = 0x8005B8A0; // type:func -func_8006EE50 = 0x8005B8B0; // type:func +Font_LoadCharWide = 0x8005B8B0; // type:func Font_LoadChar = 0x8005B904; // type:func Font_LoadMessageBoxIcon = 0x8005B954; // type:func Font_LoadOrderedFont = 0x8005B998; // type:func @@ -3072,8 +3072,8 @@ Message_SetTextColor = 0x800D7514; // type:func Message_DrawTextboxIcon = 0x800D77C8; // type:func Message_DrawItemIcon = 0x800D7F0C; // type:func Message_HandleOcarina = 0x800D8258; // type:func -Message_DrawTextJPN = 0x800D8468; // type:func -Message_DrawTextNES = 0x800D985C; // type:func +Message_DrawTextWide = 0x800D8468; // type:func +Message_DrawText = 0x800D985C; // type:func Message_LoadItemIcon = 0x800DAAD4; // type:func Message_Decode = 0x800DAC74; // type:func Message_OpenText = 0x800DD19C; // type:func