#include "common.h" #include "ld_addrs.h" #include "message_ids.h" #include "sprite.h" #if !VERSION_IQUE // TODO: remove if assets are dumped in iQue release #include "charset/postcard.png.h" #include "charset/letter_content_1.png.h" #endif #if VERSION_IQUE // TODO: remove if section is split in iQue release extern Addr charset_ROM_START; extern Addr charset_standard_OFFSET; extern Addr charset_standard_pal_OFFSET; extern Addr charset_title_OFFSET; extern Addr charset_credits_pal_OFFSET; extern Addr charset_subtitle_OFFSET; #endif enum RewindArrowStates { REWIND_ARROW_STATE_INIT = 0, REWIND_ARROW_STATE_GROW = 1, REWIND_ARROW_STATE_NEUTRAL = 2, REWIND_ARROW_STATE_CHANGE_COLOR = 3, REWIND_ARROW_STATE_CHANGE_COLOR_BACK = 4, }; #ifdef SHIFT #define MSG_ROM_START (s32)msg_ROM_START #else #define MSG_ROM_START 0x1B83000 #endif #if VERSION_PAL #define CONST_A 7 #define CONST_B 5.0 #else #define CONST_A 6 #define CONST_B 6.0 #endif typedef MessageImageData* MessageImageDataList[1]; s32 D_8014C280[] = { 0x028001E0, 0x01FF0000, 0x028001E0, 0x01FF0000 }; u8 MessagePlural[] = { MSG_CHAR_LOWER_S, MSG_CHAR_READ_END }; #if VERSION_PAL u8 MessagePlural_de[] = { MSG_CHAR_LOWER_N, MSG_CHAR_READ_END }; #endif u8 MessageSingular[] = { MSG_CHAR_READ_ENDL, MSG_CHAR_READ_END }; #if VERSION_PAL s32 gCurrentLanguage = 0; void* D_PAL_8014AE50[] = { [LANGUAGE_EN] = msg_pal_en_ROM_START, [LANGUAGE_DE] = msg_pal_de_ROM_START, [LANGUAGE_FR] = msg_pal_fr_ROM_START, [LANGUAGE_ES] = msg_pal_es_ROM_START, }; #endif s16 gNextMessageBuffer = 0; //TODO Vtx ALIGNED(8) s32 gRewindArrowQuad[] = { 0xFFF00009, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00100009, 0x00000000, 0x04000000, 0xFFFFFFFF, 0xFFF0FFF7, 0x00000000, 0x00000240, 0xFFFFFFFF, 0x0010FFF7, 0x00000000, 0x04000240, 0xFFFFFFFF, }; Gfx D_8014C2D8[] = { gsDPSetCycleType(G_CYC_2CYCLE), gsSPClearGeometryMode(G_CULL_BOTH | G_LIGHTING), gsSPSetGeometryMode(G_SHADE | G_SHADING_SMOOTH), gsDPSetColorDither(G_CD_DISABLE), gsDPSetAlphaDither(G_AD_DISABLE), gsDPSetAlphaCompare(G_AC_NONE), gsSPTexture(-1, -1, 0, G_TX_RENDERTILE, G_ON), gsDPSetTexturePersp(G_TP_PERSP), gsDPSetTextureLUT(G_TT_NONE), gsDPSetTextureFilter(G_TF_AVERAGE), gsDPSetRenderMode(IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | G_RM_PASS, IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)), gsDPSetCombineMode(PM_CC_13, G_CC_PASS2), gsSPEndDisplayList(), }; SHIFT_BSS s32 gMsgBGScrollAmtX; SHIFT_BSS u16 gMsgGlobalWaveCounter; SHIFT_BSS MessageImageDataList gMsgVarImages; SHIFT_BSS s32 gMsgBGScrollAmtY; SHIFT_BSS u8* D_8015131C; SHIFT_BSS Gfx* D_80151338; SHIFT_BSS char gMessageBuffers[2][1024]; SHIFT_BSS u8 gMessageMsgVars[3][32]; SHIFT_BSS s16 D_80155C98; SHIFT_BSS Mtx gMessageWindowProjMatrix[2]; SHIFT_BSS MessageDrawState D_80155D20; SHIFT_BSS MessageDrawState* msg_drawState; SHIFT_BSS IMG_BIN D_80159B50[0x200]; SHIFT_BSS PAL_BIN D_8015C7E0[0x10]; SHIFT_BSS MessagePrintState gMessagePrinters[3]; extern s16 MsgStyleVerticalLineOffsets[]; extern IMG_BIN ui_msg_bubble_left_png[]; extern IMG_BIN ui_msg_bubble_mid_png[]; extern IMG_BIN ui_msg_bubble_right_png[]; extern IMG_BIN ui_msg_arrow_png[]; extern unsigned char ui_msg_palettes[16][32]; extern IMG_BIN ui_msg_sign_corner_topleft_png[]; extern IMG_BIN ui_msg_sign_corner_topright_png[]; extern IMG_BIN ui_msg_sign_corner_bottomleft_png[]; extern IMG_BIN ui_msg_sign_corner_bottomright_png[]; extern IMG_BIN ui_msg_lamppost_corner_bottomright_png[]; extern IMG_BIN ui_msg_sign_side_top_png[]; extern IMG_BIN ui_msg_sign_side_left_png[]; extern IMG_BIN ui_msg_sign_side_right_png[]; extern IMG_BIN ui_msg_sign_side_bottom_png[]; extern IMG_BIN ui_msg_sign_fill_png[]; extern PAL_BIN ui_msg_sign_pal[]; extern PAL_BIN ui_msg_lamppost_pal[]; extern IMG_BIN ui_msg_background_png[]; extern IMG_BIN ui_msg_rewind_arrow_png[]; extern PAL_BIN ui_msg_rewind_arrow_pal[]; extern IMG_BIN ui_msg_star_png[]; extern IMG_BIN ui_msg_star_silhouette_png[]; extern IMG_BIN D_802ED550[]; extern PAL_BIN D_802ED670[]; extern IMG_BIN MsgCharImgTitle[]; extern IMG_BIN MsgCharImgNormal[]; extern MessageCharset* MsgCharsets[5]; extern IMG_BIN MsgCharImgSubtitle[]; extern PAL_BIN D_802F4560[80][8]; extern s32 gMessageBoxFrameParts[2][16]; extern IMG_BIN ui_point_right_png[]; extern PAL_BIN ui_point_right_pal[]; MessageNumber gMsgNumbers[] = { { .rasters = &MsgCharImgNormal[0x800], .texSize = 128, .texWidth = 16, .texHeight = 16, .digitWidth = {11, 8, 11, 11, 11, 11, 11, 11, 11, 11}, .fixedWidth = 11 }, { .rasters = &MsgCharImgNormal[0x800], .texSize = 128, .texWidth = 16, .texHeight = 16, .digitWidth = {9, 8, 9, 9, 9, 9, 9, 9, 9, 9}, .fixedWidth = 9 } }; Gfx gMsgDlistInitDrawNumber[] = { gsDPPipeSync(), gsDPSetCycleType(G_CYC_1CYCLE), gsDPSetTextureFilter(G_TF_POINT), gsDPSetTexturePersp(G_TP_NONE), gsDPSetColorDither(G_CD_DISABLE), gsDPSetAlphaDither(G_AD_DISABLE), gsDPSetCombineKey(G_CK_NONE), gsDPSetAlphaCompare(G_AC_NONE), gsDPSetTextureLUT(G_TT_RGBA16), gsSPTexture(-1, -1, 0, G_TX_RENDERTILE, G_ON), gsSPEndDisplayList(), }; Vtx gMsgSpeechBoxLQuad[4] = { { .v = { .ob = {1, 0, 0}, .tc = {0, 0}, .cn = {255, 255, 248, 255} } }, { .v = { .ob = {0x20, 0, 0}, .tc = {0x400, 0}, .cn = {255, 255, 248, 255} } }, { .v = { .ob = {0x1, 0xFFC0, 0}, .tc = {0, 0x800}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {0x20, 0xFFC0, 0}, .tc = {0x400, 0x800}, .cn = {191, 184, 176, 255} } }, }; Vtx gMsgSpeechBoxMQuad[] = { { .v = { .ob = {0x20, 0, 0}, .tc = {0, 0}, .cn = {255, 255, 248, 255} } }, { .v = { .ob = {0xE1, 0, 0}, .tc = {0x100, 0}, .cn = {255, 255, 248, 255} } }, { .v = { .ob = {0x20, 0xFFC0, 0}, .tc = {0, 0x800}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {0xE1, 0xFFC0, 0}, .tc = {0x100, 0x800}, .cn = {191, 184, 176, 255} } }, }; Vtx gMsgSpeechBoxRQuad[] = { { .v = { .ob = {0xE1, 0, 0}, .tc = {0, 0}, .cn = {255, 255, 248, 255} } }, { .v = { .ob = {0x100, 0, 0}, .tc = {0x400, 0}, .cn = {255, 255, 248, 255} } }, { .v = { .ob = {0xE1, 0xFFC0, 0}, .tc = {0, 0x800}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {0x100, 0xFFC0, 0}, .tc = {0x400, 0x800}, .cn = {191, 184, 176, 255} } }, }; Vtx gMsgArrowQuad1[] = { { .v = { .ob = {0xFFF1, 0x001E, 0}, .tc = {0, 0}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {0xF, 0x001E, 0}, .tc = {0x1E0, 0}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {0xFFFF, 0, 0}, .tc = {0, 0x1E0}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {1, 0, 0}, .tc = {0x1E0, 0x1E0}, .cn = {191, 184, 176, 255} } }, }; Vtx gMsgArrowQuad2[] = { { .v = { .ob = {0xFFF1, 0x001E, 0}, .tc = {0, 0}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {0xF, 0x001E, 0}, .tc = {0x1E0, 0}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {0xFFFF, 0, 0}, .tc = {0, 0x1E0}, .cn = {191, 184, 176, 255} } }, { .v = { .ob = {1, 0, 0}, .tc = {0x1E0, 0x1E0}, .cn = {191, 184, 176, 255} } }, }; Gfx D_8014C500[] = { gsDPSetCycleType(G_CYC_1CYCLE), gsDPSetRenderMode(G_RM_TEX_EDGE, G_RM_TEX_EDGE2), gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA), gsDPSetTextureFilter(G_TF_AVERAGE), gsSPTexture(-1, -1, 0, G_TX_RENDERTILE, G_ON), gsDPSetTexturePersp(G_TP_NONE), gsDPSetColorDither(G_CD_DISABLE), gsDPSetAlphaDither(G_AD_DISABLE), gsDPSetTextureLOD(G_TL_TILE), gsDPSetTextureLUT(G_TT_RGBA16), gsDPSetTextureDetail(G_TD_CLAMP), gsDPSetTextureConvert(G_TC_FILT), gsDPSetCombineKey(G_CK_NONE), gsDPSetAlphaCompare(G_AC_NONE), gsDPNoOp(), gsSPEndDisplayList(), }; u8 D_8014C580[] = { 50, 80, 100, 105, 100, 0, 0, 0 }; u8 D_8014C588[] = { 105, 100, 77, 57, 40, 27, 16, 8, 3, 0, 0, 0}; #if VERSION_IQUE u32 D_8014AD24 = 2; #else u8 D_8014C594[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #endif s32 draw_image_with_clipping(IMG_PTR raster, s32 width, s32 height, s32 fmt, s32 bitDepth, s16 posX, s16 posY, u16 clipULx, u16 clipULy, u16 clipLRx, u16 clipRLy); s32 _update_message(MessagePrintState* printer); void msg_copy_to_print_buffer(MessagePrintState* printer, s32 arg1, s32 arg2); void initialize_printer(MessagePrintState* printer, s32 arg1, s32 arg2); MessagePrintState* _msg_get_printer_for_msg(s32 msgID, s32* donePrintingWriteback, s32 arg2); void msg_update_rewind_arrow(s32); void msg_draw_rewind_arrow(s32); void msg_draw_choice_pointer(MessagePrintState* printer); void draw_message_window(MessagePrintState* printer); void appendGfx_message(MessagePrintState*, s16, s16, u16, u16, u16, u8); void appendGfx_msg_prim_rect(u8 r, u8 g, u8 b, u8 a, u16 ulX, u16 ulY, u16 lrX, u16 lrY); void msg_reset_gfx_state(void); void msg_draw_char(MessagePrintState* printer, MessageDrawState* drawState, s32 charIndex, s32 palette, s32 posX, s32 posY); void msg_draw_prim_rect(u8 r, u8 g, u8 b, u8 a, u16 posX, u16 posY, u16 sizeX, u16 sizeY); void msg_draw_speech_arrow(MessagePrintState* printer); void msg_draw_frame(s32 posX, s32 posY, s32 sizeX, s32 sizeY, s32 style, s32 palette, s32 fading, s32 bgAlpha, s32 frameAlpha); void msg_draw_speech_bubble(MessagePrintState* printer, s16 posX, s16 posY, s16 straightWidth, s16 curveWidth, s16 height, f32 scaleX, f32 scaleY, u8 opacity, s32 arg9); void clear_character_set(void) { D_80155C98 = -1; } void clear_printers(void) { s32 i; for (i = 0; i < ARRAY_COUNT(gMessagePrinters); i++) { initialize_printer(&gMessagePrinters[i], 0, 0); } gMsgBGScrollAmtX = 0; gMsgBGScrollAmtY = 0; for (i = 0; i < ARRAY_COUNT(gMessageMsgVars); i++) { gMessageMsgVars[i][0] = 0; } D_80151338 = NULL; gMsgGlobalWaveCounter = 0; load_font(0); } #if VERSION_IQUE void load_font_data(Addr offset, u32 size, void* dest) { #else void load_font_data(Addr offset, u16 size, void* dest) { #endif u8* base = charset_ROM_START + (s32) offset; dma_copy(base, base + size, dest); } void load_font(s32 font) { if (font != D_80155C98) { if (font == 0) { load_font_data(charset_standard_OFFSET, 0x5100, MsgCharImgNormal); load_font_data(charset_standard_pal_OFFSET, 0x500, D_802F4560); } else if (font == 1) { load_font_data(charset_title_OFFSET, 0xF60, MsgCharImgTitle); load_font_data(charset_subtitle_OFFSET, 0xB88, MsgCharImgSubtitle); load_font_data(charset_credits_pal_OFFSET, 0x80, D_802F4560); } } } void update_messages(void) { s32 i; gMsgGlobalWaveCounter++; if (gMsgGlobalWaveCounter >= 360) { gMsgGlobalWaveCounter = 0; } for (i = 0; i < ARRAY_COUNT(gMessagePrinters); i++) { if (gMessagePrinters[i].stateFlags & MSG_STATE_FLAG_2) { _update_message(&gMessagePrinters[i]); } } gMsgBGScrollAmtX += 12; gMsgBGScrollAmtY -= 12; if (gMsgBGScrollAmtX >= 2048) { gMsgBGScrollAmtX -= 2048; } if (gMsgBGScrollAmtY < 0) { gMsgBGScrollAmtY += 2048; } } s32 _update_message(MessagePrintState* printer) { f32 speechPan; u8 cond; s32 buttons; s16 endPosDist; s16 lineIncAmt; s32 charsToPrint; s32 i; printer->effectFrameCounter++; if (printer->effectFrameCounter >= 3600) { printer->effectFrameCounter = 0; } speechPan = (((f32)printer->initOpenPos.x - (SCREEN_WIDTH / 2.0)) / 3.8) + 64.0; if (speechPan < 5.0) { speechPan = 5.0f; } else if (speechPan > 122.0) { speechPan = 122.0f; } printer->speechPan = speechPan; cond = FALSE; if (!(printer->stateFlags & MSG_STATE_FLAG_40)) { if (!(printer->stateFlags & (MSG_STATE_FLAG_20 | MSG_STATE_FLAG_10))) { s32 buttons = BUTTON_A; switch (printer->windowState) { case MSG_WINDOW_STATE_WAITING: if (printer->stateFlags & MSG_STATE_FLAG_80000) { buttons = BUTTON_A | BUTTON_C_DOWN; } if ((buttons & gGameStatusPtr->pressedButtons[0]) || (gGameStatusPtr->curButtons[0] & BUTTON_B)) { printer->windowState = MSG_WINDOW_STATE_PRINTING; printer->curPrintDelay = 0; printer->stateFlags |= MSG_STATE_FLAG_4; if (gGameStatusPtr->pressedButtons[0] & (BUTTON_A | BUTTON_C_DOWN)) { cond = TRUE; sfx_play_sound_with_params(SOUND_MENU_NEXT, 0, 0, 0); } else if (printer->srcBuffer[printer->srcBufferPos] != MSG_CHAR_READ_END) { printer->stateFlags |= MSG_STATE_FLAG_PRINT_QUICKLY | MSG_STATE_FLAG_4; if (printer->fontVariant != 0 || printer->srcBuffer[printer->srcBufferPos] != MSG_CHAR_UNK_C3) { printer->stateFlags |= MSG_STATE_FLAG_PRINT_QUICKLY | MSG_STATE_FLAG_80 | MSG_STATE_FLAG_4; } sfx_play_sound_with_params(SOUND_MSG_SKIP, 0, 0, 0); } else if (printer->style == MSG_STYLE_RIGHT || printer->style == MSG_STYLE_LEFT || printer->style == MSG_STYLE_CENTER || printer->style == MSG_STYLE_TATTLE) { sfx_play_sound_with_params(SOUND_MENU_NEXT, 0, 0, 0); } } else if ((gGameStatusPtr->pressedButtons[0] & BUTTON_Z) && !(printer->stateFlags & MSG_STATE_FLAG_40000) && (printer->curLine != 0)) { printer->windowState = MSG_WINDOW_STATE_B; printer->unk_4CC = 0; printer->unkArraySize = printer->curLine - 1; printer->unk_4C8 = abs(printer->curLinePos - printer->lineEndPos[printer->unkArraySize]); sfx_play_sound_with_params(SOUND_MSG_REWIND, 0, 0, 0); } break; case MSG_WINDOW_STATE_C: if (gGameStatusPtr->pressedButtons[0] & BUTTON_B) { printer->windowState = MSG_WINDOW_STATE_B; printer->unk_4CC = 0; printer->unkArraySize = printer->curLine; printer->unk_4C8 = abs(printer->curLinePos - printer->lineEndPos[printer->unkArraySize]); sfx_play_sound_with_params(SOUND_MSG_SKIP, 0, 0, 0); } else if (gGameStatusPtr->pressedButtons[0] & BUTTON_Z) { if (printer->unkArraySize > 0) { printer->windowState = MSG_WINDOW_STATE_B; printer->unk_4CC = 0; printer->unkArraySize--; printer->unk_4C8 = abs(printer->curLinePos - printer->lineEndPos[printer->unkArraySize]); sfx_play_sound_with_params(SOUND_MSG_REWIND, 0, 0, 0); } } else { if (gGameStatusPtr->pressedButtons[0] & BUTTON_A) { printer->windowState = MSG_WINDOW_STATE_B; printer->unk_4CC = 0; printer->unkArraySize++; printer->unk_4C8 = abs(printer->curLinePos - printer->lineEndPos[printer->unkArraySize]); sfx_play_sound_with_params(SOUND_MSG_UNREWIND, 0, 0, 0); } } break; case MSG_WINDOW_STATE_WAITING_FOR_CHOICE: if (gGameStatusPtr->pressedButtons[0] & BUTTON_A) { printer->madeChoice = 1; printer->windowState = MSG_WINDOW_STATE_PRINTING; printer->scrollingTime = 0; printer->stateFlags |= MSG_STATE_FLAG_20000; sfx_play_sound_with_params(SOUND_MENU_NEXT, 0, 0, 0); } else if (printer->cancelOption != 0xFF && (gGameStatusPtr->pressedButtons[0] & BUTTON_B)) { if (printer->cancelOption >= printer->maxOption) { printer->selectedOption = printer->curOption; } else { printer->selectedOption = printer->cancelOption; } printer->madeChoice = 1; printer->windowState = MSG_WINDOW_STATE_PRINTING; printer->scrollingTime = 0; printer->curOption = printer->cancelOption; printer->stateFlags |= MSG_STATE_FLAG_20000; sfx_play_sound_with_params(SOUND_MENU_BACK, 0, 0, 0); } else if (gGameStatusPtr->heldButtons[0] & BUTTON_STICK_DOWN) { if (printer->curOption != printer->maxOption - 1) { printer->targetOption = printer->curOption + 1; printer->windowState = MSG_WINDOW_STATE_SCROLLING_BACK; printer->scrollingTime = 1; sfx_play_sound_with_params(SOUND_MENU_CHANGE_SELECTION, 0, 0, 0); } } else if (gGameStatusPtr->heldButtons[0] & BUTTON_STICK_UP) { if (printer->curOption != 0) { printer->targetOption = printer->curOption - 1; printer->windowState = MSG_WINDOW_STATE_SCROLLING_BACK; printer->scrollingTime = 1; sfx_play_sound_with_params(SOUND_MENU_CHANGE_SELECTION, 0, 0, 0); } } if (printer->windowState != MSG_WINDOW_STATE_SCROLLING_BACK) { break; } case MSG_WINDOW_STATE_SCROLLING_BACK: printer->scrollingTime++; if (printer->scrollingTime >= (s32)(5 * DT)) { printer->windowState = MSG_WINDOW_STATE_WAITING_FOR_CHOICE; printer->curOption = printer->targetOption; printer->selectedOption = printer->curOption; } break; } } else if (!(printer->stateFlags & MSG_STATE_FLAG_20) && printer->windowState == MSG_WINDOW_STATE_WAITING && (gGameStatusPtr->pressedButtons[0] & BUTTON_A)) { printer->windowState = MSG_WINDOW_STATE_PRINTING; printer->curPrintDelay = 0; printer->stateFlags |= MSG_STATE_FLAG_4; } if (printer->stateFlags & MSG_STATE_FLAG_4 && !(gGameStatusPtr->curButtons[0] & BUTTON_A)) { printer->stateFlags &= ~MSG_STATE_FLAG_4; } for (i = 0; i < ARRAY_COUNT(printer->animTimers); i++) { if (printer->animTimers[i] > 0) { printer->animTimers[i]--; } } switch (printer->windowState) { case MSG_WINDOW_STATE_PRINTING: if ((gGameStatusPtr->pressedButtons[0] & BUTTON_A) | (gGameStatusPtr->curButtons[0] & BUTTON_B)) { if (!(printer->stateFlags & (MSG_STATE_FLAG_20 | MSG_STATE_FLAG_10)) && !cond) { printer->stateFlags |= MSG_STATE_FLAG_PRINT_QUICKLY; } } // fallthrough case MSG_WINDOW_STATE_INIT: charsToPrint = printer->charsPerChunk; if (printer->windowState == MSG_WINDOW_STATE_INIT) { printer->windowState = MSG_WINDOW_STATE_PRINTING; printer->curPrintDelay = 0; } else if (printer->stateFlags & MSG_STATE_FLAG_PRINT_QUICKLY) { charsToPrint = 12; printer->curPrintDelay = 0; } else if (!(printer->stateFlags & MSG_STATE_FLAG_4)) { if (!(printer->stateFlags & (MSG_STATE_FLAG_20 | MSG_STATE_FLAG_10)) && (gGameStatusPtr->curButtons[0] & BUTTON_A)) { charsToPrint = 6; printer->curPrintDelay = 0; } } if ((printer->curPrintDelay == 0) || --printer->curPrintDelay == 0) { msg_copy_to_print_buffer(printer, charsToPrint, 0); } break; case MSG_WINDOW_STATE_SCROLLING: if (gGameStatusPtr->pressedButtons[0] & (BUTTON_A | BUTTON_B)) { if (!(printer->stateFlags & (MSG_STATE_FLAG_20 | MSG_STATE_FLAG_10))) { printer->stateFlags |= MSG_STATE_FLAG_PRINT_QUICKLY; } } printer->curLinePos += printer->unk_464; if ((printer->stateFlags & MSG_STATE_FLAG_PRINT_QUICKLY) || (!(printer->stateFlags & (MSG_STATE_FLAG_10 | MSG_STATE_FLAG_4)) && (gGameStatusPtr->curButtons[0] & BUTTON_A))) { printer->curLinePos += CONST_A; } if (printer->curLinePos >= printer->nextLinePos) { printer->windowState = MSG_WINDOW_STATE_PRINTING; printer->curLinePos = printer->nextLinePos; printer->stateFlags |= MSG_STATE_FLAG_4; if (printer->style == MSG_STYLE_SIGN || printer->style == MSG_STYLE_LAMPPOST || printer->srcBuffer[printer->srcBufferPos] == MSG_CHAR_READ_WAIT) { printer->curPrintDelay = 0; } else { printer->curPrintDelay = 5; } printer->lineEndPos[printer->curLine] = printer->curLinePos; } break; case MSG_WINDOW_STATE_B: printer->unk_4CC += 1; endPosDist = abs(printer->curLinePos - printer->lineEndPos[printer->unkArraySize]); lineIncAmt = 2; if (printer->unk_4C8 <= 16) { if (endPosDist >= 15) { lineIncAmt = 4; } else if (endPosDist >= 9) { lineIncAmt = 3; } } else if (endPosDist > 96) { lineIncAmt = 10; } else if (endPosDist > 48) { lineIncAmt = 9; } else if (endPosDist >= 24) { lineIncAmt = 7; } else if (endPosDist >= 16) { lineIncAmt = 5; } else if (endPosDist >= 8) { lineIncAmt = 4; } else if (endPosDist > 4) { lineIncAmt = 3; } printer->unk_4CA = lineIncAmt; if (printer->lineEndPos[printer->unkArraySize] < printer->curLinePos) { printer->curLinePos -= printer->unk_4CA; if (printer->lineEndPos[printer->unkArraySize] >= printer->curLinePos) { printer->curLinePos = printer->lineEndPos[printer->unkArraySize]; printer->windowState = MSG_WINDOW_STATE_C; } } else { printer->curLinePos += printer->unk_4CA; if (printer->curLinePos >= printer->lineEndPos[printer->unkArraySize]) { printer->curLinePos = printer->lineEndPos[printer->unkArraySize]; printer->windowState = MSG_WINDOW_STATE_C; if (printer->unkArraySize == printer->curLine) { printer->windowState = MSG_WINDOW_STATE_WAITING; printer->rewindArrowAnimState = REWIND_ARROW_STATE_INIT; printer->rewindArrowCounter = 0; } } } break; case MSG_WINDOW_STATE_OPENING: case MSG_WINDOW_STATE_CLOSING: case MSG_WINDOW_STATE_WAITING: case MSG_WINDOW_STATE_WAITING_FOR_CHOICE: case MSG_WINDOW_STATE_SCROLLING_BACK: case MSG_WINDOW_STATE_VIEWING_PREV: case MSG_WINDOW_STATE_A: case MSG_WINDOW_STATE_C: case MSG_WINDOW_STATE_D: case MSG_WINDOW_STATE_E: break; } } if (printer->stateFlags & MSG_STATE_FLAG_1) { printer->windowState = MSG_WINDOW_STATE_DONE; printer->stateFlags = 0; if (printer->letterBackgroundImg != NULL) { general_heap_free(printer->letterBackgroundImg); } if (printer->letterBackgroundPal != NULL) { general_heap_free(printer->letterBackgroundPal); } if (printer->letterContentImg != NULL) { general_heap_free(printer->letterContentImg); } if (printer->letterContentPal != NULL) { general_heap_free(printer->letterContentPal); } if (printer->closedWritebackBool != NULL) { *printer->closedWritebackBool = TRUE; printer->closedWritebackBool = NULL; } } return printer->windowState; } void render_messages(void) { Mtx* matrix = &gMessageWindowProjMatrix[gCurrentDisplayContextIndex]; s32 i; for (i = 0; i < ARRAY_COUNT(gMessagePrinters); i++) { if (gMessagePrinters[i].stateFlags & MSG_STATE_FLAG_2) { gSPViewport(gMainGfxPos++, D_8014C280); guOrtho(matrix, 0.0f, 319.0f, -240.0f, 0.0f, -500.0f, 500.0f, 1.0f); gSPMatrix(gMainGfxPos++, OS_K0_TO_PHYSICAL(matrix), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gDPPipeSync(gMainGfxPos++); gDPSetCycleType(gMainGfxPos++, G_CYC_1CYCLE); gSPClearGeometryMode(gMainGfxPos++, G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH); gSPSetGeometryMode(gMainGfxPos++, G_SHADE | G_SHADING_SMOOTH); break; } } for (i = 0; i < ARRAY_COUNT(gMessagePrinters); i++) { if (gMessagePrinters[i].stateFlags & MSG_STATE_FLAG_2) { draw_message_window(&gMessagePrinters[i]); if (gMessagePrinters[i].windowState == MSG_WINDOW_STATE_WAITING) { if (!(gMessagePrinters[i].stateFlags & MSG_STATE_FLAG_8000) && !(gMessagePrinters[i].stateFlags & MSG_STATE_FLAG_40)) { msg_update_rewind_arrow(i); } } else if (gMessagePrinters[i].windowState == MSG_WINDOW_STATE_C) { msg_draw_rewind_arrow(i); } else if (gMessagePrinters[i].windowState == MSG_WINDOW_STATE_WAITING_FOR_CHOICE || gMessagePrinters[i].windowState == MSG_WINDOW_STATE_SCROLLING_BACK || gMessagePrinters[i].stateFlags & MSG_STATE_FLAG_10000 || gMessagePrinters[i].stateFlags & MSG_STATE_FLAG_20000) { msg_draw_choice_pointer(&gMessagePrinters[i]); } } } } void msg_play_speech_sound(MessagePrintState* printer, u8 character) { f32 volTemp; s16 volume; s32 pitchShift; s32 flag = 1; s32 baseShift = 100; if (printer->stateFlags & MSG_STATE_FLAG_800000 && !(printer->delayFlags & (MSG_DELAY_FLAG_2 | MSG_DELAY_FLAG_4)) && printer->volume != 0) { volTemp = (f32)printer->volume / 100.0; pitchShift = ((character % 20) * 10) + (printer->speechPitchShift - baseShift); volume = ((rand_int(15) + 78) * volTemp); if (volume > 255) { volume = 255; } if (character & flag) { sfx_play_sound_with_params(printer->speechSoundIDA, volume, printer->speechPan, pitchShift); } else { sfx_play_sound_with_params(printer->speechSoundIDB, volume, printer->speechPan, pitchShift); } } } extern s32 gItemIconRasterOffsets[]; extern s32 gItemIconPaletteOffsets[]; extern s32 MsgLetterRasterOffsets[]; extern s32 MsgLetterPaletteOffsets[]; extern MsgVoice MsgVoices[]; #if VERSION_IQUE || VERSION_PAL INCLUDE_ASM(s32, "msg", msg_copy_to_print_buffer); #else void msg_copy_to_print_buffer(MessagePrintState* printer, s32 arg1, s32 arg2) { u8 arg; u8 argQ; u8 argW; u8 argE; u8 sp10[4]; s32 addr; s16 offset; s32 i; u8* romAddr; u8* romEnd; s32 temp; void* a2; s8 s8 = arg2 & 1; u8* printBuf = &printer->printBuffer[printer->printBufferPos]; u8* srcBuf = &printer->srcBuffer[printer->srcBufferPos]; do { u8 c = *srcBuf++; // a1 u8 nextArg = *srcBuf; // a2 switch (c) { case MSG_CHAR_READ_ENDL: *printBuf++ = MSG_CHAR_PRINT_ENDL; printer->lineCount += (u8)printer->sizeScale; break; case MSG_CHAR_READ_WAIT: printer->windowState = MSG_WINDOW_STATE_WAITING; printer->delayFlags |= MSG_DELAY_FLAG_1; printer->delayFlags &= ~MSG_DELAY_FLAG_2; printer->rewindArrowAnimState = REWIND_ARROW_STATE_INIT; printer->rewindArrowCounter = 0; printer->stateFlags &= ~MSG_STATE_FLAG_80; printer->stateFlags &= ~MSG_STATE_FLAG_PRINT_QUICKLY; if (printer->style != MSG_STYLE_F) { sfx_play_sound_with_params(SOUND_MSG_WAIT, 0, 0, 0); } break; case MSG_CHAR_READ_PAUSE: printer->curPrintDelay = *srcBuf++; printer->delayFlags |= MSG_DELAY_FLAG_1; printer->stateFlags &= ~MSG_STATE_FLAG_80; break; case MSG_CHAR_READ_VARIANT0: case MSG_CHAR_READ_VARIANT1: case MSG_CHAR_READ_VARIANT2: case MSG_CHAR_READ_VARIANT3: *printBuf++ = MSG_CHAR_PRINT_VARIANT0 + (c - MSG_CHAR_READ_VARIANT0); printer->fontVariant = c + 13; break; case MSG_CHAR_READ_SPACE: *printBuf++ = MSG_CHAR_PRINT_SPACE; break; case MSG_CHAR_READ_FULL_SPACE: *printBuf++ = MSG_CHAR_PRINT_FULL_SPACE; break; case MSG_CHAR_READ_HALF_SPACE: *printBuf++ = MSG_CHAR_PRINT_HALF_SPACE; break; case MSG_CHAR_READ_UNK_CHAR_FA: *printBuf++ = MSG_CHAR_PRINT_UNK_CHAR_FA; arg1--; break; case MSG_CHAR_READ_NEXT: if (printer->lineCount != 0) { printer->lineEndPos[printer->curLine] = printer->curLinePos; printer->curLine++; *printBuf++ = MSG_CHAR_PRINT_NEXT; printer->nextLinePos = printer->curLinePos + (MsgCharsets[printer->font]->newLineY + MsgStyleVerticalLineOffsets[printer->style]) * printer->lineCount; printer->windowState = MSG_WINDOW_STATE_SCROLLING; printer->delayFlags |= MSG_DELAY_FLAG_1; } printer->lineCount = 0; break; case MSG_CHAR_READ_STYLE: *printBuf++ = MSG_CHAR_PRINT_STYLE; arg = *srcBuf++; printer->style = arg; *printBuf++ = arg; printer->fadeInCounter = 0; switch (arg) { case MSG_STYLE_RIGHT: case MSG_STYLE_LEFT: case MSG_STYLE_CENTER: case MSG_STYLE_TATTLE: if (arg == MSG_STYLE_RIGHT || arg == MSG_STYLE_LEFT || arg == MSG_STYLE_CENTER) { printer->maxLinesPerPage = 3; } printer->delayFlags |= MSG_DELAY_FLAG_1; printer->stateFlags |= MSG_STATE_FLAG_800000 | MSG_STATE_FLAG_800; if (nextArg != MSG_CHAR_UNK_C3) { printer->stateFlags |= MSG_STATE_FLAG_80; } printer->speechSoundIDA = SOUND_MSG_VOICE_1A; printer->speechSoundIDB = SOUND_MSG_VOICE_1B; printer->windowState = MSG_WINDOW_STATE_OPENING; break; case MSG_STYLE_CHOICE: do { printer->windowBasePos.x = *srcBuf++; printer->windowBasePos.y = *srcBuf++; printer->windowSize.x = *srcBuf++; printer->windowSize.y = *srcBuf++; printer->windowState = MSG_WINDOW_STATE_OPENING; printer->stateFlags |= MSG_STATE_FLAG_800; } while (0); break; case MSG_STYLE_INSPECT: case MSG_STYLE_NARRATE: case MSG_STYLE_F: if (!s8) { printer->windowBasePos.x = 20; printer->windowBasePos.y = 28; printer->windowSize.y = 58; printer->windowSize.x = 280; printer->windowState = MSG_WINDOW_STATE_OPENING; printer->stateFlags |= MSG_STATE_FLAG_800; printer->delayFlags |= MSG_DELAY_FLAG_1; if (arg == MSG_STYLE_INSPECT) { sfx_play_sound_with_params(SOUND_021C, 0, 0, 0); } } break; case MSG_STYLE_UPGRADE: printer->windowBasePos.x = *srcBuf++; printer->windowBasePos.y = *srcBuf++; printer->windowSize.x = *srcBuf++; printer->windowSize.y = *srcBuf++; sfx_play_sound_with_params(SOUND_021C, 0, 0, 0); printer->windowState = MSG_WINDOW_STATE_OPENING; printer->delayFlags |= MSG_DELAY_FLAG_1; printer->stateFlags |= MSG_STATE_FLAG_800; break; case MSG_STYLE_LAMPPOST: printer->windowSize.y = *srcBuf++; // fallthrough case MSG_STYLE_SIGN: do { if (!s8) { printer->windowState = MSG_WINDOW_STATE_OPENING; printer->stateFlags |= MSG_STATE_FLAG_800; printer->delayFlags |= MSG_DELAY_FLAG_1; } } while (0); break; case MSG_STYLE_POSTCARD: arg = *srcBuf++; printer->windowState = MSG_WINDOW_STATE_OPENING; printer->stateFlags |= MSG_STATE_FLAG_800; printer->delayFlags |= MSG_DELAY_FLAG_1; printer->letterBackgroundImg = heap_malloc(((charset_postcard_png_width * charset_postcard_png_height) / 2)); romAddr = charset_ROM_START + (s32)charset_postcard_OFFSET; dma_copy(romAddr, romAddr + ((charset_postcard_png_width * charset_postcard_png_height) / 2), printer->letterBackgroundImg); printer->letterBackgroundPal = heap_malloc(0x20); romAddr = charset_ROM_START + ((s32)charset_postcard_pal_OFFSET + 5); dma_copy(romAddr, romAddr + 0x20, printer->letterBackgroundPal); printer->letterContentImg = heap_malloc(charset_letter_content_1_png_width * charset_letter_content_1_png_height); romAddr = charset_ROM_START + MsgLetterRasterOffsets[arg]; dma_copy(romAddr, romAddr + (charset_letter_content_1_png_width * charset_letter_content_1_png_height), printer->letterContentImg); printer->letterContentPal = heap_malloc(0x200); romAddr = charset_ROM_START + MsgLetterPaletteOffsets[arg]; dma_copy(romAddr, romAddr + 0x200, printer->letterContentPal); break; case MSG_STYLE_POPUP: case MSG_STYLE_B: printer->windowSize.x = printer->msgWidth + 32; printer->windowSize.y = 40; printer->stateFlags |= MSG_STATE_FLAG_8000; do { if (!s8) { printer->stateFlags |= MSG_STATE_FLAG_8000 | MSG_STATE_FLAG_800; printer->windowState = MSG_WINDOW_STATE_D; printer->delayFlags |= MSG_DELAY_FLAG_1; } } while (0); break; case MSG_STYLE_EPILOGUE: printer->windowState = MSG_WINDOW_STATE_PRINTING; break; } if ((printer->delayFlags & MSG_DELAY_FLAG_1) && (printer->delayFlags & (MSG_DELAY_FLAG_4 | MSG_DELAY_FLAG_2))) { printer->delayFlags &= ~MSG_DELAY_FLAG_1; } break; case MSG_CHAR_READ_END: *printBuf++ = MSG_CHAR_PRINT_END; if (printer->stateFlags & MSG_STATE_FLAG_800) { if (printer->stateFlags & MSG_STATE_FLAG_1000) { if (printer->closedWritebackBool != NULL) { *printer->closedWritebackBool = TRUE; } } if (printer->style != MSG_STYLE_POPUP && printer->style != MSG_STYLE_B) { printer->windowState = MSG_WINDOW_STATE_CLOSING; } else { printer->windowState = MSG_WINDOW_STATE_E; } printer->fadeOutCounter = 0; } else { printer->stateFlags |= MSG_STATE_FLAG_1; } printer->delayFlags |= MSG_DELAY_FLAG_1; printer->delayFlags &= ~MSG_DELAY_FLAG_2; break; case MSG_CHAR_READ_FUNCTION: switch (*srcBuf++) { case MSG_READ_FUNC_FONT: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_FONT; *printBuf++ = printer->font = *srcBuf++; break; case MSG_READ_FUNC_VARIANT: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_VARIANT; *printBuf++ = printer->fontVariant = *srcBuf++; break; case MSG_READ_FUNC_COLOR: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_COLOR; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_NO_SKIP: printer->stateFlags |= MSG_STATE_FLAG_10; break; case MSG_READ_FUNC_INPUT_OFF: printer->stateFlags |= MSG_STATE_FLAG_20; printer->stateFlags &= ~MSG_STATE_FLAG_PRINT_QUICKLY; break; case MSG_READ_FUNC_INPUT_ON: printer->stateFlags &= ~MSG_STATE_FLAG_20; break; case MSG_READ_FUNC_SPACING: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_SPACING; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_DELAY_OFF: printer->delayFlags |= MSG_DELAY_FLAG_2; break; case MSG_READ_FUNC_DELAY_ON: printer->delayFlags &= ~MSG_DELAY_FLAG_2; printer->delayFlags |= MSG_DELAY_FLAG_1; break; case MSG_READ_FUNC_SCROLL: printer->lineEndPos[printer->curLine] = printer->curLinePos; printer->curLine++; *printBuf++ = MSG_CHAR_PRINT_NEXT; arg = *srcBuf++; printer->nextLinePos = printer->curLinePos + (MsgCharsets[printer->font]->newLineY + MsgStyleVerticalLineOffsets[printer->style]) * arg; printer->windowState = MSG_WINDOW_STATE_SCROLLING; printer->delayFlags |= MSG_DELAY_FLAG_1; printer->lineCount = 0; break; case MSG_READ_FUNC_SIZE: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_SIZE; *printBuf++ = *srcBuf++; *printBuf++ = arg = *srcBuf++; printer->sizeScale = (arg >> 4) + (arg & 0xF) * 0.0625f; break; case MSG_READ_FUNC_SIZE_RESET: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_SIZE_RESET; printer->sizeScale = 1.0f; break; case MSG_READ_FUNC_SPEED: printer->printDelayTime = *srcBuf++; printer->charsPerChunk = *srcBuf++; break; case MSG_READ_FUNC_SET_X: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_SET_X; *printBuf++ = *srcBuf++; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_SET_Y: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_SET_Y; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_RIGHT: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_RIGHT; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_DOWN: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_DOWN; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_UP: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_UP; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_INLINE_IMAGE: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_INLINE_IMAGE; *printBuf++ = *srcBuf++; arg1--; printer->curPrintDelay = printer->printDelayTime; if (arg1 <= 0) { printer->delayFlags |= MSG_DELAY_FLAG_1; } if (printer->delayFlags & (MSG_DELAY_FLAG_4 | MSG_DELAY_FLAG_2)) { printer->delayFlags &= ~MSG_DELAY_FLAG_1; } break; case MSG_READ_FUNC_ANIM_SPRITE: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_ANIM_SPRITE; *printBuf++ = *srcBuf++; *printBuf++ = *srcBuf++; *printBuf++ = *srcBuf++; printer->curPrintDelay = printer->printDelayTime; if (--arg1 <= 0) { printer->delayFlags |= MSG_DELAY_FLAG_1; } if (printer->delayFlags & (MSG_DELAY_FLAG_4 | MSG_DELAY_FLAG_2)) { printer->delayFlags &= ~MSG_DELAY_FLAG_1; } break; case MSG_READ_FUNC_ITEM_ICON: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_ITEM_ICON; arg = *srcBuf++; argQ = *srcBuf++; a2 = D_80159B50; offset = arg << 8 | argQ; D_8015131C = D_80159B50; dma_copy(icon_ROM_START + gItemIconRasterOffsets[offset], icon_ROM_START + gItemIconRasterOffsets[offset] + 0x200, a2); romEnd = icon_ROM_START + gItemIconPaletteOffsets[offset] + 0x20; dma_copy(icon_ROM_START + gItemIconPaletteOffsets[offset], romEnd, D_8015C7E0); printer->curPrintDelay = printer->printDelayTime; if (--arg1 <= 0) { printer->delayFlags |= MSG_DELAY_FLAG_1; } if (printer->delayFlags & (MSG_DELAY_FLAG_4 | MSG_DELAY_FLAG_2)) { printer->delayFlags &= ~MSG_DELAY_FLAG_1; } break; case MSG_READ_FUNC_IMAGE: printer->curImageIndex = *srcBuf++; arg = *srcBuf++; argQ = *srcBuf++; printer->varImageScreenPos.x = arg << 8 | argQ; printer->varImageScreenPos.y = *srcBuf++; printer->varImgHasBorder = *srcBuf++; printer->varImgFinalAlpha = *srcBuf++; printer->varImgAlphaFadeStep = *srcBuf++; printer->varImageDisplayState = 0; printer->varImageFadeTimer = 0; if (--arg1 <= 0) { printer->delayFlags |= MSG_DELAY_FLAG_1; } if (printer->delayFlags & (MSG_DELAY_FLAG_4 | MSG_DELAY_FLAG_2)) { printer->delayFlags &= ~MSG_DELAY_FLAG_1; } break; case MSG_READ_FUNC_HIDE_IMAGE: arg = *srcBuf++; if (arg != 0) { printer->varImageDisplayState = 2; printer->varImgAlphaFadeStep = arg; printer->varImageFadeTimer = 0; } else { printer->varImageScreenPos.x = 0; } break; case MSG_READ_FUNC_ANIM_DELAY: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_ANIM_DELAY; *printBuf++ = *srcBuf++; *printBuf++ = *srcBuf++; *printBuf++ = *srcBuf++; printer->delayFlags |= MSG_DELAY_FLAG_4; break; case MSG_READ_FUNC_ANIM_LOOP: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_ANIM_LOOP; *printBuf++ = *srcBuf++; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_ANIM_DONE: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_ANIM_DONE; *printBuf++ = *srcBuf++; printer->delayFlags &= ~MSG_DELAY_FLAG_4; if (--arg1 <= 0) { printer->delayFlags |= MSG_DELAY_FLAG_1; } break; case MSG_READ_FUNC_SET_CURSOR: arg = *srcBuf++; argQ = *srcBuf++; argW = *srcBuf++; argE = *srcBuf++; printer->cursorPosX[arg] = argQ << 8 | argW; printer->cursorPosY[arg] = argE; break; case MSG_READ_FUNC_CURSOR: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_CURSOR; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_END_CHOICE: sfx_play_sound_with_params(SOUND_MENU_SHOW_CHOICE, 0, 0, 0); printer->maxOption = *srcBuf++; printer->madeChoice = 0; printer->curOption = 0; printer->selectedOption = 0; printer->windowState = MSG_WINDOW_STATE_WAITING_FOR_CHOICE; printer->delayFlags |= MSG_DELAY_FLAG_1; break; case MSG_READ_FUNC_SET_CANCEL: printer->cancelOption = *srcBuf++; break; case MSG_READ_FUNC_OPTION: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_OPTION; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_RESET_GFX: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_RESET_GFX; break; case MSG_READ_FUNC_YIELD: printer->stateFlags |= MSG_STATE_FLAG_100000 | MSG_STATE_FLAG_40; printer->delayFlags |= MSG_DELAY_FLAG_1; printer->stateFlags &= ~MSG_STATE_FLAG_80; printer->stateFlags &= ~MSG_STATE_FLAG_PRINT_QUICKLY; break; case MSG_READ_FUNC_SAVE_POS: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_SAVE_POS; break; case MSG_READ_FUNC_RESTORE_POS: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_RESTORE_POS; break; case MSG_READ_FUNC_SAVE_COLOR: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_SAVE_COLOR; break; case MSG_READ_FUNC_RESTORE_COLOR: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_RESTORE_COLOR; break; case MSG_READ_FUNC_START_FX: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_START_FX; arg = *srcBuf++; switch (arg) { case MSG_FX_SHAKE: case MSG_FX_WAVE: case MSG_FX_NOISE_OUTLINE: case MSG_FX_RAINBOW: case MSG_FX_GLOBAL_WAVE: case MSG_FX_GLOBAL_RAINBOW: case MSG_FX_RISE_PRINT: case MSG_FX_GROW_PRINT: case MSG_FX_SIZE_JITTER: case MSG_FX_SIZE_WAVE: case MSG_FX_DROP_SHADOW: *printBuf++ = arg; break; case MSG_FX_STATIC: case MSG_FX_BLUR: case MSG_FX_DITHER_FADE: *printBuf++ = arg; *printBuf++ = *srcBuf++; break; } break; case MSG_READ_FUNC_END_FX: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_END_FX; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_VAR: arg = *srcBuf++; srcBuf -= 3; if (printer->varBufferReadPos == 0) { printer->unk_52A = printer->fontVariant; *printBuf++ = MSG_CHAR_PRINT_VARIANT0; } do { s32 a0 = 1; argQ = gMessageMsgVars[arg][printer->varBufferReadPos++]; if (argQ >= MSG_CONTROL_CHAR) { s32 tmp; switch (argQ) { case MSG_CHAR_READ_ENDL: if (gMessageMsgVars[arg][printer->varBufferReadPos] != MSG_CHAR_READ_END) { sp10[0] = MSG_CHAR_PRINT_ENDL; } else { a0 = 0; } break; case MSG_CHAR_READ_VARIANT0: case MSG_CHAR_READ_VARIANT1: case MSG_CHAR_READ_VARIANT2: case MSG_CHAR_READ_VARIANT3: sp10[0] = (argQ - MSG_CHAR_READ_VARIANT0) + MSG_CHAR_PRINT_VARIANT0; temp = argQ - MSG_CHAR_READ_VARIANT0 + 0x200; printer->fontVariant = temp; break; case MSG_CHAR_READ_SPACE: sp10[0] = MSG_CHAR_PRINT_SPACE; break; case MSG_CHAR_READ_FUNCTION: sp10[0] = MSG_CHAR_PRINT_FUNCTION; switch (gMessageMsgVars[arg][printer->varBufferReadPos++]) { case MSG_READ_FUNC_COLOR: sp10[1] = MSG_PRINT_FUNC_COLOR; sp10[2] = gMessageMsgVars[arg][printer->varBufferReadPos++]; a0 = 3; break; case MSG_READ_FUNC_SAVE_COLOR: sp10[1] = MSG_PRINT_FUNC_SAVE_COLOR; a0 = 2; break; case MSG_READ_FUNC_RESTORE_COLOR: sp10[1] = MSG_PRINT_FUNC_RESTORE_COLOR; a0 = 2; break; } break; } } else { sp10[0] = argQ; } for (i = 0; i < a0; i++) { arg1--; *printBuf++ = sp10[i]; } if (gMessageMsgVars[arg][printer->varBufferReadPos] == MSG_CHAR_READ_END) { srcBuf += 3; printer->varBufferReadPos = 0; printer->fontVariant = printer->unk_52A; *printBuf++ = MSG_CHAR_PRINT_VARIANT0 + printer->fontVariant; break; } } while ((printer->delayFlags & (MSG_DELAY_FLAG_4 | MSG_DELAY_FLAG_2)) || arg1 > 0); if (!(printer->delayFlags & (MSG_DELAY_FLAG_4 | MSG_DELAY_FLAG_2)) && arg1 <= 0) { printer->delayFlags |= MSG_DELAY_FLAG_1; printer->curPrintDelay = printer->printDelayTime; } msg_play_speech_sound(printer, argQ); if (printer->stateFlags & MSG_STATE_FLAG_800000) { printer->stateFlags |= MSG_STATE_FLAG_80; } break; case MSG_READ_FUNC_VOICE: arg = *srcBuf++; printer->speechSoundType = arg; printer->speechSoundIDA = MsgVoices[arg].voiceA; printer->speechSoundIDB = MsgVoices[arg].voiceB; printer->speechPitchShift = MsgVoices[arg].pitchShift; break; case MSG_READ_FUNC_VOLUME: printer->volume = *srcBuf++; break; case MSG_READ_FUNC_CUSTOM_VOICE: arg = *srcBuf++; argQ = *srcBuf++; argW = *srcBuf++; argE = *srcBuf++; printer->speechSoundIDA = (arg << 0x18) + (argQ << 0x10) + (argW << 0x8) + (argE); arg = *srcBuf++; argQ = *srcBuf++; argW = *srcBuf++; argE = *srcBuf++; printer->speechSoundIDB = (arg << 0x18) + (argQ << 0x10) + (argW << 0x8) + (argE); break; case MSG_READ_FUNC_CENTER_X: *printBuf++ = MSG_CHAR_PRINT_FUNCTION; *printBuf++ = MSG_PRINT_FUNC_CENTER_X; *printBuf++ = *srcBuf++; break; case MSG_READ_FUNC_SET_REWIND: if (*srcBuf++) { printer->stateFlags |= MSG_STATE_FLAG_40000; } else { printer->stateFlags &= ~MSG_STATE_FLAG_40000; } break; case MSG_READ_FUNC_ENABLE_CDOWN_NEXT: printer->stateFlags |= MSG_STATE_FLAG_80000; break; } break; default: *printBuf++ = c; arg1--; if (printer->fontVariant == 0 && c == MSG_CHAR_UNK_C3) { printer->stateFlags &= ~MSG_STATE_FLAG_80; } else { msg_play_speech_sound(printer, c); if (printer->stateFlags & MSG_STATE_FLAG_800000) { printer->stateFlags |= MSG_STATE_FLAG_80; } } break; } if (!(printer->delayFlags & (MSG_DELAY_FLAG_4 | MSG_DELAY_FLAG_2)) && arg1 <= 0) { printer->delayFlags |= MSG_DELAY_FLAG_1; printer->curPrintDelay = printer->printDelayTime; } if (!(printer->delayFlags & MSG_DELAY_FLAG_1)) { continue; } if (!s8) { break; } if (srcBuf[-1] == MSG_CHAR_READ_END) { break; } arg1 = 10000; } while (TRUE); printer->printBufferPos = printBuf - printer->printBuffer; printer->delayFlags = 0; printer->srcBufferPos = (u16)(s32)(srcBuf - (s32)printer->srcBuffer); *printBuf = MSG_CHAR_PRINT_END; } #endif void initialize_printer(MessagePrintState* printer, s32 arg1, s32 arg2) { s32 i; printer->printBufferSize = ARRAY_COUNT(printer->printBuffer); printer->printBuffer[0] = MSG_CHAR_PRINT_END; printer->printDelayTime = 1; printer->charsPerChunk = 1; printer->unk_464 = CONST_A; printer->srcBuffer = NULL; printer->msgID = 0; printer->curPrintDelay = 0; printer->windowOffsetPos.x = 0; printer->windowOffsetPos.y = 0; printer->windowBasePos.x = 0; printer->windowBasePos.y = 0; printer->rewindArrowAnimState = REWIND_ARROW_STATE_INIT; printer->rewindArrowCounter = 0; printer->rewindArrowPos.x = 0; printer->rewindArrowPos.y = 0; printer->curLine = 0; printer->unkArraySize = 0; printer->maxOption = 0; printer->madeChoice = 0; printer->curOption = 0; printer->selectedOption = 0; printer->cancelOption = -1; printer->windowState = MSG_WINDOW_STATE_DONE; printer->stateFlags = 0; printer->delayFlags = 0; printer->closedWritebackBool = NULL; printer->printBufferPos = 0; printer->srcBufferPos = 0; printer->font = 0; printer->fontVariant = 0; printer->effectFrameCounter = 0; printer->curLinePos = 0; printer->unk_46C = 0; printer->lineCount = 0; for (i = 0; i < ARRAY_COUNT(printer->animTimers); i++) { printer->curAnimFrame[i] = 0; printer->animTimers[i] = -1; } printer->initOpenPos.x = 160; printer->initOpenPos.y = 40; printer->speechSoundType = -1; printer->speechPan = 64; printer->volume = 75; printer->rewindArrowCounter = 0; printer->style = 0; printer->fadeInCounter = 0; printer->openStartPos.x = 0; printer->openStartPos.y = 0; printer->fadeOutCounter = 0; printer->windowSize.y = 0; printer->windowSize.x = 0; printer->speechPitchShift = 0; printer->speechSoundIDA = 0; printer->speechSoundIDB = 0; printer->varBufferReadPos = 0; printer->curImageIndex = 0; printer->varImageScreenPos.x = 0; printer->varImageScreenPos.y = 0; printer->varImgHasBorder = 0; printer->varImgFinalAlpha = 255; printer->varImageDisplayState = 0; printer->varImageFadeTimer = 0; printer->letterBackgroundImg = NULL; printer->letterBackgroundPal = NULL; printer->letterContentImg = NULL; printer->letterContentPal = NULL; printer->sizeScale = 1.0f; } #if VERSION_PAL void dma_load_msg(u32 msgID, void* dest); INCLUDE_ASM(s32, "msg", dma_load_msg); #else void dma_load_msg(u32 msgID, void* dest) { u8* addr = (u8*) MSG_ROM_START + (msgID >> 14); // (msgID >> 16) * 4 u8* offset[2]; // start, end dma_copy(addr, addr + 4, &offset[0]); // Load section offset addr = MSG_ROM_START + offset[0] + (msgID & 0xFFFF) * 4; dma_copy(addr, addr + 8, &offset); // Load message start and end offsets // Load the msg data dma_copy(MSG_ROM_START + offset[0], MSG_ROM_START + offset[1], dest); } #endif s8* load_message_to_buffer(s32 msgID) { s8* prevBufferPos; dma_load_msg(msgID, &gMessageBuffers[gNextMessageBuffer]); prevBufferPos = gMessageBuffers[gNextMessageBuffer]; gNextMessageBuffer++; if (gNextMessageBuffer >= ARRAY_COUNT(gMessageBuffers)) { gNextMessageBuffer = 0; } return prevBufferPos; } MessagePrintState* msg_get_printer_for_msg(s32 msgID, s32* donePrintingWriteback) { return _msg_get_printer_for_msg(msgID, donePrintingWriteback, 0); } MessagePrintState* _msg_get_printer_for_msg(s32 msgID, s32* donePrintingWriteback, s32 arg2) { MessagePrintState* printer; s8* srcBuffer; s32 height; s32 width; s32 maxLineChars; s32 numLines; s32 maxLinesPerPage; s32 i; if (msgID == MSG_NONE) { return NULL; } srcBuffer = (s8*) msgID; if (msgID >= 0) { srcBuffer = load_message_to_buffer((s32)srcBuffer); } for (i = 0; i < ARRAY_COUNT(gMessagePrinters); i++) { printer = &gMessagePrinters[i]; if (!(printer->stateFlags & MSG_STATE_FLAG_2)) { initialize_printer(printer, 1, arg2); printer->windowState = MSG_WINDOW_STATE_INIT; printer->srcBuffer = srcBuffer; printer->msgID = msgID; printer->stateFlags |= MSG_STATE_FLAG_2; get_msg_properties(msgID, &height, &width, &maxLineChars, &numLines, &maxLinesPerPage, NULL, 0); printer->msgHeight = height; printer->msgWidth = width; printer->maxLineChars = maxLineChars; printer->numLines = numLines; printer->maxLinesPerPage = maxLinesPerPage; printer->closedWritebackBool = donePrintingWriteback; if (donePrintingWriteback != NULL) { *donePrintingWriteback = FALSE; } return printer; } } return NULL; } s32 msg_printer_load_msg(s32 msgID, MessagePrintState* printer) { s8* buffer; if (msgID >= 0) { buffer = load_message_to_buffer(msgID); } else { buffer = (s8*) msgID; } printer->srcBuffer = buffer; printer->srcBufferPos = 0; printer->stateFlags &= ~MSG_STATE_FLAG_40; return 1; } void msg_printer_set_origin_pos(MessagePrintState* msgPrintState, s32 x, s32 y) { msgPrintState->initOpenPos.x = x; msgPrintState->initOpenPos.y = y; if (msgPrintState->initOpenPos.x < 0) { msgPrintState->initOpenPos.x = 0; } if (msgPrintState->initOpenPos.x > SCREEN_WIDTH) { msgPrintState->initOpenPos.x = SCREEN_WIDTH; } if (msgPrintState->initOpenPos.y < 0) { msgPrintState->initOpenPos.y = 0; } if (msgPrintState->initOpenPos.y > 220) { msgPrintState->initOpenPos.y = 220; } } s32 cancel_message(MessagePrintState* msgPrintState) { if (!(msgPrintState->stateFlags & MSG_STATE_FLAG_2)) { return FALSE; } msgPrintState->stateFlags |= MSG_STATE_FLAG_1; return TRUE; } void set_message_images(MessageImageData* images) { *gMsgVarImages = images; } void set_message_msg(s32 msgID, s32 index) { u8* mallocSpace = NULL; s32 i; u8* msgVars; if (msgID >= 0) { mallocSpace = general_heap_malloc(0x400); dma_load_msg(msgID, mallocSpace); msgID = (s32)mallocSpace; } i = 0; msgVars = gMessageMsgVars[index]; while (TRUE) { msgVars[i] = ((u8*)msgID)[i]; if (((u8*)msgID)[i] == MSG_CHAR_READ_END) { break; } if (++i >= 32) { msgVars[i - 1] = MSG_CHAR_READ_END; break; } } if (mallocSpace != NULL) { general_heap_free(mallocSpace); } } void set_message_value(s32 value, s32 index) { s8 strBuffer[ARRAY_COUNT(gMessageMsgVars[index])]; s8* bufferIt; s32 i; int_to_string(value, strBuffer, 10); for (i = 0, bufferIt = strBuffer; i < ARRAY_COUNT(gMessageMsgVars[index]) - 1; i++) { s8 thisChar = bufferIt[i]; if (thisChar == 0) { break; } gMessageMsgVars[index][i] = thisChar - '0' + MSG_CHAR_DIGIT_0; } gMessageMsgVars[index][i] = MSG_CHAR_READ_END; } void close_message(MessagePrintState* msgPrintState) { msgPrintState->stateFlags &= ~MSG_STATE_FLAG_40; } s32 msg_get_print_char_width(s32 character, s32 charset, s32 variation, f32 msgScale, s32 overrideCharWidth, u8 flags) { f32 charWidth; if (character >= MSG_CONTROL_CHAR && (character != MSG_CHAR_READ_SPACE && character != MSG_CHAR_READ_FULL_SPACE && character != MSG_CHAR_READ_HALF_SPACE)) { return 0; } #if VERSION_IQUE if (character >= 0x5F && character<=0x8F) { charWidth = 16.0; return charWidth * msgScale; } #endif if (overrideCharWidth != 0) { charWidth = overrideCharWidth; } else if (flags != 0) { u8* charWidthTable = MsgCharsets[charset]->rasters[variation].charWidthTable; if (charWidthTable != NULL && character != MSG_CHAR_READ_SPACE && character != MSG_CHAR_READ_FULL_SPACE && character != MSG_CHAR_READ_HALF_SPACE) { charWidth = charWidthTable[character]; } else { charWidth = MsgCharsets[charset]->rasters[variation].monospaceWidth; } } else { charWidth = MsgCharsets[charset]->rasters[variation].monospaceWidth; } if (character == MSG_CHAR_READ_SPACE) { return charWidth * msgScale * 0.6; } if (character == MSG_CHAR_READ_FULL_SPACE) { f64 retWidth = charWidth * msgScale; return retWidth; } if (character == MSG_CHAR_READ_HALF_SPACE) { return charWidth * msgScale * 0.5; } if (character >= MSG_CONTROL_CHAR) { return 0; } return charWidth * msgScale; } s32 msg_get_draw_char_width(s32 character, s32 charset, s32 variation, f32 msgScale, s32 overrideCharWidth, u16 flags) { f32 baseWidth; if (character >= MSG_CONTROL_CHAR && (character != MSG_CHAR_PRINT_SPACE && character != MSG_CHAR_PRINT_FULL_SPACE && character != MSG_CHAR_PRINT_HALF_SPACE)) { return 0; } if (overrideCharWidth != 0) { baseWidth = overrideCharWidth; } else if (flags & MSG_PRINT_FLAG_100) { u8* charWidthTable = MsgCharsets[charset]->rasters[variation].charWidthTable; if (charWidthTable != NULL && character != MSG_CHAR_PRINT_SPACE && character != MSG_CHAR_PRINT_FULL_SPACE && character != MSG_CHAR_PRINT_HALF_SPACE) { baseWidth = charWidthTable[character]; } else { baseWidth = MsgCharsets[charset]->rasters[variation].monospaceWidth; } } else { baseWidth = MsgCharsets[charset]->rasters[variation].monospaceWidth; } if (character == MSG_CHAR_PRINT_SPACE) { return baseWidth * msgScale * 0.6; } if (character == MSG_CHAR_PRINT_FULL_SPACE) { f64 charWidth = baseWidth * msgScale; return charWidth; } if (character == MSG_CHAR_PRINT_HALF_SPACE) { return baseWidth * msgScale * 0.5; } if (character >= MSG_CONTROL_CHAR) { return 0; } return baseWidth * msgScale; } void get_msg_properties(s32 msgID, s32* height, s32* width, s32* maxLineChars, s32* numLines, s32* maxLinesPerPage, s32* numSpaces, u16 charset) { u8* message; s32 i; u16 pageCount; s32 linesOnPage; u8 stop; s32 lineWidth; s32 charCount; u16 lineIndex; s32 msgStyle; s32 functionCode; u8 packedScaleY; f32 scale; s32 temp; u16 lineWidths[32]; u16 lineCharNumbers[32]; u16 linesPerPage[32]; s32 lineCount; u16 varIndex; u16 font; u8* buffer; u16 maxLineWidth; u16 maxCharsPerLine; u16 maxLinesOnPage; u16 spaceCount; u16 endl; u8 c; u8 prevChar; scale = 1.0f; c = 0; lineIndex = 0; pageCount = 0; varIndex = 0; font = 0; buffer = NULL; maxLineWidth = 0; maxCharsPerLine = 0; maxLinesOnPage = 0; spaceCount = 0; if (msgID == MSG_NONE) { return; } if (msgID >= 0) { buffer = general_heap_malloc(0x400); dma_load_msg(msgID, buffer); message = buffer; } else { message = (u8*)msgID; } if (charset & 1) { font = 1; } i = 0; stop = FALSE; lineWidth = 0; linesOnPage = 0; charCount = 0; endl = TRUE; lineCount = 0; do { prevChar = c; c = message[i++]; switch (c) { case MSG_CHAR_READ_VARIANT0: case MSG_CHAR_READ_VARIANT1: case MSG_CHAR_READ_VARIANT2: case MSG_CHAR_READ_VARIANT3: varIndex = c - MSG_CHAR_READ_VARIANT0; break; case MSG_CHAR_READ_PAUSE: i++; break; case MSG_CHAR_READ_WAIT: case MSG_CHAR_READ_NEXT: if (linesOnPage != 0) { linesPerPage[pageCount] = linesOnPage; pageCount++; if (pageCount >= 32) { stop = 1; } linesOnPage = 0; } break; case MSG_CHAR_READ_ENDL: lineWidths[lineIndex] = lineWidth; lineCharNumbers[lineIndex] = charCount; lineIndex++; if (lineIndex >= 32) { stop = 1; } lineWidth = 0; charCount = 0; endl = TRUE; break; case MSG_CHAR_READ_STYLE: msgStyle = message[i++]; switch (msgStyle) { case MSG_STYLE_CHOICE: i += 4; break; case MSG_STYLE_POSTCARD: i++; break; case MSG_STYLE_RIGHT: case MSG_STYLE_LEFT: case MSG_STYLE_CENTER: case MSG_STYLE_TATTLE: case MSG_STYLE_INSPECT: case MSG_STYLE_SIGN: case MSG_STYLE_LAMPPOST: case MSG_STYLE_POPUP: case MSG_STYLE_B: break; } break; case MSG_CHAR_READ_END: lineWidths[lineIndex] = lineWidth; lineCharNumbers[lineIndex] = charCount; lineIndex++; stop = TRUE; break; case MSG_CHAR_READ_FUNCTION: functionCode = message[i++]; switch (functionCode) { case MSG_READ_FUNC_FONT: font = message[i++]; break; case MSG_READ_FUNC_RESET_GFX: case MSG_READ_FUNC_NO_SKIP: case MSG_READ_FUNC_INPUT_OFF: case MSG_READ_FUNC_INPUT_ON: case MSG_READ_FUNC_DELAY_OFF: case MSG_READ_FUNC_DELAY_ON: case MSG_READ_FUNC_SAVE_POS: case MSG_READ_FUNC_RESTORE_POS: case MSG_READ_FUNC_SAVE_COLOR: case MSG_READ_FUNC_RESTORE_COLOR: case MSG_READ_FUNC_ENABLE_CDOWN_NEXT: break; default: stop = TRUE; break; case MSG_READ_FUNC_CUSTOM_VOICE: i++; // fallthrough temp = 4; case MSG_READ_FUNC_IMAGE: i += temp; // fallthrough case MSG_READ_FUNC_ANIM_SPRITE: case MSG_READ_FUNC_ANIM_DELAY: i++; // fallthrough case MSG_READ_FUNC_SPEED: case MSG_READ_FUNC_SET_X: case MSG_READ_FUNC_ANIM_LOOP: i++; // fallthrough case MSG_READ_FUNC_COLOR: case MSG_READ_FUNC_SPACING: case MSG_READ_FUNC_SCROLL: case MSG_READ_FUNC_SET_Y: case MSG_READ_FUNC_RIGHT: case MSG_READ_FUNC_DOWN: case MSG_READ_FUNC_UP: case MSG_READ_FUNC_INLINE_IMAGE: case MSG_READ_FUNC_ITEM_ICON: case MSG_READ_FUNC_HIDE_IMAGE: case MSG_READ_FUNC_ANIM_DONE: case MSG_READ_FUNC_CURSOR: case MSG_READ_FUNC_END_CHOICE: case MSG_READ_FUNC_SET_CANCEL: case MSG_READ_FUNC_OPTION: case MSG_READ_FUNC_END_FX: case MSG_READ_FUNC_SET_REWIND: case MSG_READ_FUNC_VOICE: i++; break; case MSG_READ_FUNC_CENTER_X: if (message[i] == 0) { stop = TRUE; } i++; break; case MSG_READ_FUNC_YIELD: if (message[i] == MSG_CHAR_READ_END) { stop = TRUE; } break; case MSG_READ_FUNC_SIZE: packedScaleY = message[i + 1]; i += 2; scale = (f32)(packedScaleY >> 4) + ((packedScaleY & 0xF) * 0.0625f); break; case MSG_READ_FUNC_SIZE_RESET: scale = 1.0f; break; case MSG_READ_FUNC_START_FX: switch (message[i++]) { case MSG_FX_STATIC: case MSG_FX_BLUR: case MSG_FX_DITHER_FADE: i++; break; case MSG_FX_SHAKE: case MSG_FX_WAVE: case MSG_FX_NOISE_OUTLINE: case MSG_FX_RAINBOW: case MSG_FX_GLOBAL_WAVE: case MSG_FX_GLOBAL_RAINBOW: case MSG_FX_RISE_PRINT: case MSG_FX_GROW_PRINT: case MSG_FX_SIZE_JITTER: case MSG_FX_SIZE_WAVE: case MSG_FX_DROP_SHADOW: break; } break; case MSG_READ_FUNC_VAR: lineWidth += get_msg_width((s32)gMessageMsgVars[message[i++]], 0); break; } break; case MSG_CHAR_READ_UNK_CHAR_FA: break; case MSG_CHAR_READ_SPACE: case MSG_CHAR_READ_FULL_SPACE: case MSG_CHAR_READ_HALF_SPACE: spaceCount++; // fallthrough default: if (endl) { lineCount++; linesOnPage++; endl = FALSE; } #if VERSION_IQUE if (prevChar >= 0x5f && prevChar <= 0x8F) { break; } #endif lineWidth += msg_get_print_char_width(c, font, varIndex, scale, 0, 1); charCount++; break; } } while (!stop); if (buffer != NULL) { general_heap_free(buffer); } for (i = 0; i < lineIndex; i++) { if (maxLineWidth < lineWidths[i]) { maxLineWidth = lineWidths[i]; } if (maxCharsPerLine < lineCharNumbers[i]) { maxCharsPerLine = lineCharNumbers[i]; } } if (pageCount == 0) { maxLinesOnPage = linesOnPage; } else { for (i = 0; i < pageCount; i++) { if (maxLinesOnPage < linesPerPage[i]) { maxLinesOnPage = linesPerPage[i]; } } } if (width != NULL) { *width = maxLineWidth; } if (height != NULL) { *height = lineCount * MsgCharsets[font]->newLineY; } if (maxLineChars != NULL) { *maxLineChars = maxCharsPerLine; } if (numLines != NULL) { *numLines = lineCount; } if (maxLinesPerPage != NULL) { *maxLinesPerPage = maxLinesOnPage; } if (numSpaces != NULL) { *numSpaces = spaceCount; } } static const f32 padding = 0.0f; s32 get_msg_width(s32 msgID, u16 charset) { s32 width; get_msg_properties(msgID, NULL, &width, NULL, NULL, NULL, NULL, charset); return width; } s32 get_msg_lines(s32 msgID) { s32 numLines; get_msg_properties(msgID, NULL, NULL, NULL, &numLines, NULL, NULL, 0); return numLines; } void draw_msg(s32 msgID, s32 posX, s32 posY, s32 opacity, s32 palette, u8 style) { MessagePrintState stackPrinter; MessagePrintState* printer; u16 bufferPos; s8* mallocSpace; s32 charset; u16 flags; s32 width; flags = 0; bufferPos = 0; mallocSpace = NULL; charset = 0; if (msgID != 0) { if (style & DRAW_MSG_STYLE_MENU) { flags = 2; charset = 1; } if (opacity < 0xFF) { flags |= 1; } printer = &stackPrinter; initialize_printer(printer, 1, 0); if (msgID < 0) { printer->srcBuffer = (u8*)msgID; } else { mallocSpace = general_heap_malloc(0x400); dma_load_msg(msgID, mallocSpace); printer->srcBuffer = mallocSpace; get_msg_properties((s32) printer->srcBuffer, 0, &width, 0, 0, 0, 0, charset); printer->msgWidth = width; } if (palette >= 0) { printer->printBuffer[bufferPos++] = MSG_CHAR_PRINT_FUNCTION; printer->printBuffer[bufferPos++] = MSG_PRINT_FUNC_COLOR; printer->printBuffer[bufferPos++] = palette; printer->printBufferPos += 3; } if (style & DRAW_MSG_STYLE_WAVY) { printer->printBuffer[bufferPos++] = MSG_CHAR_PRINT_FUNCTION; printer->printBuffer[bufferPos++] = MSG_PRINT_FUNC_START_FX; printer->printBuffer[bufferPos++] = MSG_FX_GLOBAL_WAVE; printer->printBufferPos += 3; } if (style & DRAW_MSG_STYLE_RAINBOW) { printer->printBuffer[bufferPos++] = MSG_CHAR_PRINT_FUNCTION; printer->printBuffer[bufferPos++] = MSG_PRINT_FUNC_START_FX; printer->printBuffer[bufferPos++] = MSG_FX_GLOBAL_RAINBOW; printer->printBufferPos += 3; } if (style & DRAW_MSG_STYLE_DROP_SHADOW) { printer->printBuffer[bufferPos++] = MSG_CHAR_PRINT_FUNCTION; printer->printBuffer[bufferPos++] = MSG_PRINT_FUNC_START_FX; printer->printBuffer[bufferPos++] = MSG_FX_DROP_SHADOW; printer->printBufferPos += 3; } msg_copy_to_print_buffer(printer, 10000, 1); appendGfx_message(printer, (s16)posX, (s16)posY, 0, 0, flags, opacity & 0xFF); if (mallocSpace != NULL) { general_heap_free(mallocSpace); } } } void msg_update_rewind_arrow(s32 printerIndex) { MessagePrintState* printer = &gMessagePrinters[printerIndex]; f32 angle = 0.0f; f32 scale = 1.0f; f32 colorG = 255.0f; f32 colorR = 255.0f; f32 colorB = 255.0f; Matrix4f sp18; Matrix4f sp58; f32 temp; gDPPipeSync(gMainGfxPos++); gSPDisplayList(gMainGfxPos++, D_8014C2D8); switch (printer->rewindArrowAnimState) { case REWIND_ARROW_STATE_INIT: printer->rewindArrowCounter = 0; printer->rewindArrowSwingPhase = 0; printer->rewindArrowAnimState = REWIND_ARROW_STATE_GROW; // fallthrough case REWIND_ARROW_STATE_GROW: temp = printer->rewindArrowCounter; scale = temp * 0.2 + 0.5; if (++printer->rewindArrowCounter >= 4) { printer->rewindArrowCounter = 0; printer->rewindArrowAnimState = REWIND_ARROW_STATE_NEUTRAL; } break; case REWIND_ARROW_STATE_NEUTRAL: if (++printer->rewindArrowCounter >= 25) { printer->rewindArrowCounter = 0; printer->rewindArrowAnimState = REWIND_ARROW_STATE_CHANGE_COLOR; } break; case REWIND_ARROW_STATE_CHANGE_COLOR: colorR = update_lerp(EASING_LINEAR, 255.0f, 224.0f, printer->rewindArrowCounter, 15); colorG = update_lerp(EASING_LINEAR, 255.0f, 224.0f, printer->rewindArrowCounter, 15); colorB = update_lerp(EASING_LINEAR, 255.0f, 208.0f, printer->rewindArrowCounter, 15); if (++printer->rewindArrowCounter >= 15) { printer->rewindArrowCounter = 0; printer->rewindArrowAnimState = REWIND_ARROW_STATE_CHANGE_COLOR_BACK; } break; case REWIND_ARROW_STATE_CHANGE_COLOR_BACK: colorR = update_lerp(EASING_LINEAR, 224.0f, 255.0f, printer->rewindArrowCounter, 15); colorG = update_lerp(EASING_LINEAR, 224.0f, 255.0f, printer->rewindArrowCounter, 15); colorB = update_lerp(EASING_LINEAR, 208.0f, 255.0f, printer->rewindArrowCounter, 15); if (++printer->rewindArrowCounter >= 15) { printer->rewindArrowCounter = 0; printer->rewindArrowAnimState = REWIND_ARROW_STATE_NEUTRAL; } break; } gDPSetPrimColor(gMainGfxPos++, 0, 0, colorR, colorG, colorB, 255); if (printer->rewindArrowAnimState == REWIND_ARROW_STATE_NEUTRAL || printer->rewindArrowAnimState == REWIND_ARROW_STATE_CHANGE_COLOR || printer->rewindArrowAnimState == REWIND_ARROW_STATE_CHANGE_COLOR_BACK) { angle = cosine(printer->rewindArrowSwingPhase) * 30.0f; printer->rewindArrowSwingPhase += 15; if (printer->rewindArrowSwingPhase >= 360) { printer->rewindArrowSwingPhase -= 360; } } guTranslateF(sp18, printer->rewindArrowPos.x + 12, -(printer->rewindArrowPos.y + 12), 0); if (angle != 0.0) { guRotateF(sp58, angle, 0, 0, 1.0f); guMtxCatF(sp58, sp18, sp18); } if (scale != 1.0) { guScaleF(sp58, scale, scale, 1.0f); guMtxCatF(sp58, sp18, sp18); } guMtxF2L(sp18, &gDisplayContext->matrixStack[gMatrixListPos]); gSPMatrix(gMainGfxPos++, VIRTUAL_TO_PHYSICAL(&gDisplayContext->matrixStack[gMatrixListPos++]), G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gDPLoadTextureTile(gMainGfxPos++, ui_msg_star_png, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 0, 0, 0, 15, 17, 0, G_TX_MIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, 4, G_TX_NOLOD, G_TX_NOLOD); gDPLoadMultiTile_4b(gMainGfxPos++, ui_msg_star_silhouette_png, 0x0100, 1, G_IM_FMT_I, 16, 0, 0, 0, 15, 18, 0, G_TX_MIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, 5, G_TX_NOLOD, G_TX_NOLOD); gSPVertex(gMainGfxPos++, gRewindArrowQuad, 4, 0); gSP2Triangles(gMainGfxPos++, 0, 2, 1, 0, 1, 2, 3, 0); } void msg_draw_rewind_arrow(s32 printerIndex) { MessagePrintState* printer = &gMessagePrinters[printerIndex]; if (printer->rewindArrowCounter < 6) { draw_ci_image_with_clipping(ui_msg_rewind_arrow_png, 24, 24, G_IM_FMT_CI, G_IM_SIZ_4b, ui_msg_rewind_arrow_pal, printer->rewindArrowPos.x, printer->rewindArrowPos.y, 10, 10, SCREEN_WIDTH - 20, SCREEN_HEIGHT - 20, 255); } printer->rewindArrowCounter++; if (printer->rewindArrowCounter >= 12) { printer->rewindArrowCounter = 0; } } void msg_draw_choice_pointer(MessagePrintState* printer) { s32 pointerAlpha = 255; s32 shadowAlpha = 72; s32 posInterpPhase = gGameStatusPtr->frameCounter % 360; s32 posX, posY; if (printer->windowState == MSG_WINDOW_STATE_WAITING_FOR_CHOICE || (printer->stateFlags & MSG_STATE_FLAG_20000)) { posX = printer->windowOffsetPos.x + printer->windowBasePos.x + printer->cursorPosX[printer->selectedOption]; posY = printer->windowOffsetPos.y + printer->windowBasePos.y + printer->cursorPosY[printer->selectedOption]; } else { s32 baseX, baseY, targetX, targetY; f32 moveToTargetAlpha = (f32)(printer->scrollingTime + 1.0) / CONST_B; baseX = printer->windowOffsetPos.x + printer->windowBasePos.x + printer->cursorPosX[printer->selectedOption]; targetX = printer->windowOffsetPos.x + printer->windowBasePos.x + printer->cursorPosX[printer->targetOption]; posX = baseX + (targetX - baseX) * moveToTargetAlpha; baseY = printer->windowOffsetPos.y + printer->windowBasePos.y + printer->cursorPosY[printer->selectedOption]; targetY = printer->windowOffsetPos.y + printer->windowBasePos.y + printer->cursorPosY[printer->targetOption]; posY = baseY + (targetY - baseY) * moveToTargetAlpha; } posY += 1; posX += (cosine(posInterpPhase * 38 + 270) + 1.0) * 0.5 * 3.2; posX -= 2; if (printer->stateFlags & MSG_STATE_FLAG_20000) { u32 opacity; opacity = 255.0 - printer->fadeOutCounter * 46.0; pointerAlpha = opacity; opacity = 72.0 - printer->fadeOutCounter * 14.4; shadowAlpha = opacity; } gDPPipeSync(gMainGfxPos++); gDPSetTextureLUT(gMainGfxPos++, G_TT_RGBA16); gDPLoadTLUT_pal16(gMainGfxPos++, 0, ui_point_right_pal); gDPSetRenderMode(gMainGfxPos++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetCombineMode(gMainGfxPos++, PM_CC_07, PM_CC_07); gDPSetPrimColor(gMainGfxPos++, 0, 0, 40, 40, 40, shadowAlpha); draw_image_with_clipping(ui_point_right_png, 16, 16, G_IM_FMT_CI, G_IM_SIZ_4b, posX + 2, posY + 2, 10, 10, 300, 220); draw_ci_image_with_clipping(ui_point_right_png, 16, 16, G_IM_FMT_CI, G_IM_SIZ_4b, ui_point_right_pal, posX, posY, 20, 20, 300, 200, pointerAlpha); } void draw_digit(IMG_PTR img, s32 charset, s32 posX, s32 posY) { MessageNumber* num = &gMsgNumbers[charset]; gDPLoadTextureTile_4b(gMainGfxPos++, img, G_IM_FMT_CI, num->texWidth , num->texHeight, 0, 0, num->texWidth - 1, num->texHeight - 1, 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(gMainGfxPos++, 4 * posX, 4 * posY, 4 * (posX + num->texWidth), 4 * (posY + num->texHeight), G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } void draw_number(s32 value, s32 x, s32 y, s32 charset, s32 palette, s32 opacity, u16 style) { u8 valueStr[24]; u8 digits[24]; s32 digitPosX[24]; s32 i; s32 count; s32 posX; IMG_PTR raster = gMsgNumbers[charset].rasters; s32 texSize = gMsgNumbers[charset].texSize; y -= 2; if (y < 0 || y > 240) { return; } int_to_string(value, valueStr, 10); for (i = 0; i < 10; i++) { u8 digit; if (valueStr[i] == '\0') { break; } digit = valueStr[i] - '0'; if (digit < 10){ digits[i] = digit; } } posX = x; count = i; gSPDisplayList(gMainGfxPos++, gMsgDlistInitDrawNumber); if (style & DRAW_NUMBER_STYLE_ALIGN_RIGHT) { for (i = count - 1; i >= 0; i--) { if (style & DRAW_NUMBER_STYLE_MONOSPACE) { posX -= gMsgNumbers[charset].fixedWidth; } else { posX -= gMsgNumbers[charset].digitWidth[digits[i]]; } digitPosX[i] = posX; } } else { for (i = 0; i < count; i++) { digitPosX[i] = posX; if (style & DRAW_NUMBER_STYLE_MONOSPACE) { posX += gMsgNumbers[charset].fixedWidth; } else { posX += gMsgNumbers[charset].digitWidth[digits[i]]; } } } if (style & DRAW_NUMBER_STYLE_DROP_SHADOW) { for (i = 0; i < count; i++) { gDPPipeSync(gMainGfxPos++); gDPSetRenderMode(gMainGfxPos++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetCombineMode(gMainGfxPos++, PM_CC_07, PM_CC_07); gDPSetPrimColor(gMainGfxPos++, 0, 0, 40, 40, 40, 72); draw_digit(raster + digits[i] * texSize, charset, digitPosX[i] + 2, y + 2); gDPPipeSync(gMainGfxPos++); } } if (opacity == 255) { gDPSetRenderMode(gMainGfxPos++, G_RM_TEX_EDGE, G_RM_TEX_EDGE2); gDPSetCombineMode(gMainGfxPos++, G_CC_DECALRGBA, G_CC_DECALRGBA); } else { gDPSetRenderMode(gMainGfxPos++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetCombineMode(gMainGfxPos++, PM_CC_01, PM_CC_01); gDPSetPrimColor(gMainGfxPos++, 0, 0, 255, 255, 255, opacity); } gDPLoadTLUT_pal16(gMainGfxPos++, 0, D_802F4560[palette]); for (i = 0; i < count; i++) { posX = digitPosX[i]; if (posX > 0 && posX < 320) { draw_digit(raster + digits[i] * texSize, charset, posX, y); } } gDPPipeSync(gMainGfxPos++); } void drawbox_message_delegate(s32 data, s32 baseX, s32 baseY, s32 width, s32 height, s32 opacity, s32 darkening) { MessagePrintState* printer = (MessagePrintState*)data; appendGfx_message(printer, 0, 0, 0, 0, 4, 0); } void draw_message_window(MessagePrintState* printer) { f32 scale = 1.0f; s32 rotZ = 0; switch (printer->windowState) { case MSG_WINDOW_STATE_D: scale = (f32)D_8014C580[printer->fadeInCounter] / 100.0; rotZ = (4 - printer->fadeInCounter) * 3; printer->fadeInCounter++; if (D_8014C580[printer->fadeInCounter] == 0) { printer->windowState = MSG_WINDOW_STATE_PRINTING; } break; case MSG_WINDOW_STATE_E: scale = (f32)D_8014C588[printer->fadeOutCounter] / 100.0; rotZ = -printer->fadeOutCounter; printer->fadeOutCounter++; if (D_8014C588[printer->fadeOutCounter] == 0) { printer->stateFlags |= MSG_STATE_FLAG_1; } break; } switch (printer->windowState) { case MSG_WINDOW_STATE_D: case MSG_WINDOW_STATE_E: printer->windowBasePos.x = 160 - (printer->windowSize.x / 2); printer->windowBasePos.y = 56; draw_box(DRAW_FLAG_ROTSCALE, WINDOW_STYLE_0, printer->windowBasePos.x, 56, 0, printer->windowSize.x, printer->windowSize.y, 255, 0, scale, scale, 0.0f, 0.0f, rotZ, drawbox_message_delegate, printer, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL); break; default: appendGfx_message(printer, printer->windowOffsetPos.x, printer->windowOffsetPos.y, printer->unk_46C, printer->curLinePos, 4, 0); break; } } #if VERSION_IQUE || VERSION_PAL INCLUDE_ASM(s32, "msg", appendGfx_message); #else void appendGfx_message(MessagePrintState* printer, s16 posX, s16 posY, u16 additionalOffsetX, u16 additionalOffsetY, u16 flag, u8 alpha) { SpriteRasterInfo sprRasterInfo; u16 sp80bool; s16 sp8E; s16 sp96; s16 sp9E; s16 palette; s16 spAE; u16 spB6; u8 spB8; f32 windowScaleX; MessageCharset* msgCharset; f32 temp_f10; f32 temp_f20; f32 temp_f20_3; f32 temp_f22_2; f32 temp_f24; f32 bubbleX; f32 bubbleY; f32 temp_f28; f32 windowScaleY; f32 temp_f8; f32 temp_f8_5; f64 temp_f0; f32 temp_f0_2; f32 temp_f2_2; f64 temp_f20_2; f64 temp_f22; f32 temp_f2; f64 temp_f2_3; s32 temp_s0_7; s32 temp_s0_8; s32 temp_a2; s32 temp_s1_5; s32 i; s16 temp_s3; s16 temp_s4; s32 windowSizeX; s32 windowSizeY; s16 temp_s5; s16 temp_s6; u32 temp_a0_49; s32 animIdx; u8 packedScaleX; u8 packedScaleY; MessageImageData* msgVarImage; MessageImageData* msgImageData; s32 phi_a0; s32 straightWidth; s32 curveWidth; s32 height; s32 frameX; s32 frameY; s32 frameSizeX; s32 frameSizeY; s32 frameFading; u8 frameAlpha; u16 fading; u8 phi_s0_5; IMG_PTR signRaster; PAL_PTR signPalette; s8 phi_s2_4; u8 phi_s3_2; s32 phi_v0_3; s32 phi_a0_4; s16 phi_t5; s16 phi_s0_6; s16 phi_t3; s32 dbPos; s16 charPosX; s16 charPosY; s16 phi_s2_5; s32 phi_s0_7; s32 phi_s1_8; s8 varImgHasBorder; s16 imgDrawPosX; s16 imgDrawPosY; f32 z1; f32 z2; f32 temp1; f32 temp2; msg_drawState = &D_80155D20; msg_drawState->printBuffer = printer->printBuffer; msg_drawState->printModeFlags = 0; if (gMainGfxPos != D_80151338) { msg_reset_gfx_state(); } msg_drawState->printModeFlags |= (MSG_PRINT_FLAG_1 | MSG_PRINT_FLAG_100); sp8E = 255; if (flag & 1) { sp8E = alpha; } msg_drawState->textStartPos[0] = 0; msg_drawState->textStartPos[1] = 0; msg_drawState->clipX[0] = 0; msg_drawState->clipY[0] = 0; msg_drawState->clipX[1] = SCREEN_WIDTH - 1; msg_drawState->clipY[1] = SCREEN_HEIGHT - 1; msg_drawState->msgScale.x = 1.0f; msg_drawState->msgScale.y = 1.0f; msg_drawState->unk_29 = 0; msg_drawState->framePalette = 0; msg_drawState->unk_2C = 0; msg_drawState->visiblePrintedCount = 0; msg_drawState->centerPos = 0; msg_drawState->fontVariant = 0; msg_drawState->curPosX = 0; msg_drawState->nextPos[0] = 0; msg_drawState->nextPos[1] = 0; msg_drawState->font = 0; msg_drawState->effectFlags = 0; msg_drawState->nextCounter = 0; msg_drawState->textColor = MSG_PAL_WHITE; sp96 = 0xFF; spAE = 0xFF; spB6 = 0; spB8 = 0; sp9E = -1; if (flag & 2) { msg_drawState->font = 1; } if (flag & 4) { gDPSetScissor(gMainGfxPos++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); } sp80bool = FALSE; msg_drawState->drawBufferPos = 0; while (!sp80bool) { switch (msg_drawState->printBuffer[msg_drawState->drawBufferPos]) { case MSG_CHAR_PRINT_ENDL: msg_drawState->nextPos[0] = 0; msg_drawState->nextPos[1] += (s32)((msg_drawState->msgScale.y * MsgCharsets[msg_drawState->font]->newLineY) + MsgStyleVerticalLineOffsets[printer->style]); if (msg_drawState->printModeFlags & MSG_PRINT_FLAG_40) { msg_drawState->printModeFlags |= MSG_PRINT_FLAG_80; } msg_drawState->drawBufferPos++; break; case MSG_CHAR_PRINT_UNK_CHAR_FA: msg_drawState->drawBufferPos++; break; case MSG_CHAR_PRINT_VARIANT0: case MSG_CHAR_PRINT_VARIANT1: case MSG_CHAR_PRINT_VARIANT2: case MSG_CHAR_PRINT_VARIANT3: msg_drawState->fontVariant = msg_drawState->printBuffer[msg_drawState->drawBufferPos] - MSG_CHAR_PRINT_VARIANT0; msg_drawState->drawBufferPos++; break; case MSG_CHAR_PRINT_SPACE: case MSG_CHAR_PRINT_FULL_SPACE: case MSG_CHAR_PRINT_HALF_SPACE: msg_drawState->nextPos[0] += msg_get_draw_char_width(msg_drawState->printBuffer[msg_drawState->drawBufferPos], msg_drawState->font, msg_drawState->fontVariant, msg_drawState->msgScale.x, msg_drawState->curPosX, msg_drawState->printModeFlags); msg_drawState->drawBufferPos++; break; case MSG_CHAR_PRINT_STYLE: switch (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]) { case MSG_STYLE_RIGHT: case MSG_STYLE_LEFT: case MSG_STYLE_CENTER: case MSG_STYLE_TATTLE: if (printer->windowState == MSG_WINDOW_STATE_OPENING && printer->fadeInCounter == 0) { printer->openStartPos.x = printer->initOpenPos.x; printer->openStartPos.y = printer->initOpenPos.y; } temp_s6 = printer->openStartPos.x; temp_s5 = printer->openStartPos.y; temp_s4 = printer->windowBasePos.x + (f32) printer->windowSize.x * 0.5; temp_s3 = printer->windowBasePos.y + (f32) printer->windowSize.y * 0.5; msg_drawState->textColor = MSG_PAL_STANDARD; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; if (printer->style == MSG_STYLE_RIGHT || printer->style == MSG_STYLE_LEFT || printer->style == MSG_STYLE_CENTER) { straightWidth = 218; printer->windowBasePos.x = 22; printer->windowBasePos.y = 13; printer->windowSize.x = 296; printer->windowSize.y = 68; msg_drawState->textStartPos[0] = 26; msg_drawState->textStartPos[1] = 6; printer->rewindArrowPos.x = 276; printer->rewindArrowPos.y = 57; curveWidth = 32; height = 68; } else { straightWidth = 218; switch (printer->maxLinesPerPage) { case 1: msg_drawState->textStartPos[0] = 18; msg_drawState->textStartPos[1] = 10; curveWidth = 24; break; case 2: msg_drawState->textStartPos[0] = 22; msg_drawState->textStartPos[1] = 6; curveWidth = 28; break; case 3: msg_drawState->textStartPos[0] = 26; msg_drawState->textStartPos[1] = 8; curveWidth = 32; break; default: msg_drawState->textStartPos[0] = 26; msg_drawState->textStartPos[1] = 6; curveWidth = 32; break; } straightWidth = printer->msgWidth; if (straightWidth > 256) { straightWidth = 256; } if (straightWidth < 70) { straightWidth = 70; } straightWidth -= 12; printer->windowSize.x = straightWidth + (curveWidth * 2); height = (printer->maxLinesPerPage * 14) + 16; if (height > 68) { height = 68; } if (height < 36) { height = 36; } printer->windowSize.y = height; temp_a2 = printer->openStartPos.x - printer->windowSize.x / 2; if (temp_a2 < 18) { temp_a2 = 18; } if (temp_a2 + printer->windowSize.x > SCREEN_WIDTH - 18) { temp_a2 = SCREEN_WIDTH - 18 - printer->windowSize.x; } phi_a0 = printer->openStartPos.y - 38 - printer->windowSize.y; if (phi_a0 < 20) { phi_a0 = 20; } if (phi_a0 + printer->windowSize.y > 170) { phi_a0 = 170 - printer->windowSize.y; } printer->windowBasePos.x = temp_a2; printer->windowBasePos.y = phi_a0; printer->rewindArrowPos.x = (printer->windowSize.x + temp_a2) - 30; printer->rewindArrowPos.y = (printer->windowSize.y + phi_a0) - 18; } if (printer->windowState == MSG_WINDOW_STATE_B || printer->windowState == MSG_WINDOW_STATE_C) { msg_drawState->framePalette = 1; } if (printer->windowState == MSG_WINDOW_STATE_OPENING) { windowScaleX = update_lerp(EASING_LINEAR, 0.07f, 1.0f, printer->fadeInCounter, 7); windowScaleY = update_lerp(EASING_LINEAR, 0.3f, 1.0f, printer->fadeInCounter, 7); temp_f28 = update_lerp(EASING_LINEAR, 96.0f, 200.0f, printer->fadeInCounter, 7); temp_f20 = update_lerp(EASING_SIN_OUT, temp_s5, temp_s3, printer->fadeInCounter, 7); temp_f24 = update_lerp(EASING_SIN_OUT, temp_s6, temp_s4, printer->fadeInCounter, 7); temp_f2_2 = printer->windowSize.x * windowScaleX; temp_f0_2 = printer->windowSize.y * windowScaleY; bubbleX = (temp_f24 - temp_f2_2 * 0.5) + 0.5; bubbleY = (temp_f20 - temp_f0_2 * 0.5) + 0.5; msg_draw_speech_bubble(printer, bubbleX, bubbleY, straightWidth, curveWidth, height, windowScaleX, windowScaleY, temp_f28, 1); printer->fadeInCounter++; if (printer->fadeInCounter == 7) { printer->windowState = MSG_WINDOW_STATE_PRINTING; } } else if (printer->windowState == MSG_WINDOW_STATE_CLOSING) { printer->fadeOutCounter++; windowScaleX = update_lerp(EASING_LINEAR, 1.0f, 0.6f, printer->fadeOutCounter, 5); windowScaleY = update_lerp(EASING_LINEAR, 1.0f, 0.8f, printer->fadeOutCounter, 5); temp_f2 = (printer->windowSize.x * windowScaleX); temp_f0 = (printer->windowSize.y * windowScaleY); temp_f24 = temp_s4; temp_f20 = temp_s3; bubbleX = (temp_f24 - temp_f2 * 0.5) + 0.5; bubbleY = (temp_f20 - temp_f0 * 0.5) + 0.5; temp_f22_2 = (temp_f24 + temp_f2 * 0.5) - 0.5; temp_f20_3 = (temp_f20 + temp_f0 * 0.5) - 0.5; temp_f28 = update_lerp(EASING_LINEAR, 255.0f, 64.0f, printer->fadeOutCounter, 5); sp8E = temp_f28 * 0.35; spAE = temp_f28; msg_drawState->clipX[0] = bubbleX + msg_drawState->textStartPos[0]; msg_drawState->clipY[0] = bubbleY + msg_drawState->textStartPos[1]; msg_drawState->clipX[1] = temp_f22_2 - msg_drawState->textStartPos[0]; msg_drawState->clipY[1] = temp_f20_3 - msg_drawState->textStartPos[1]; msg_draw_speech_bubble(printer, bubbleX, bubbleY, straightWidth, curveWidth, height, windowScaleX, windowScaleY, temp_f28, 1); if (printer->fadeOutCounter >= 5) { printer->stateFlags |= MSG_STATE_FLAG_1; } } else { bubbleX = posX + printer->windowBasePos.x; bubbleY = posY + printer->windowBasePos.y; msg_draw_speech_bubble(printer, bubbleX, bubbleY, straightWidth, curveWidth, height, 1.0f, 1.0f, 255, 1); if (((u32)(printer->openStartPos.x - 20) <= 280) && (printer->openStartPos.y <= 220)) { msg_draw_speech_arrow(printer); } } if (printer->windowState != MSG_WINDOW_STATE_CLOSING) { msg_drawState->clipX[0] = 20; msg_drawState->clipY[0] = printer->windowOffsetPos.y + printer->windowBasePos.y + msg_drawState->textStartPos[1]; msg_drawState->clipX[1] = SCREEN_WIDTH - 20; msg_drawState->clipY[1] = msg_drawState->clipY[0] + printer->windowSize.y - 16; } msg_reset_gfx_state(); msg_drawState->drawBufferPos += 2; break; case MSG_STYLE_CHOICE: frameFading = 0; windowSizeX = printer->windowSize.x; windowSizeY = printer->windowSize.y; frameSizeX = windowSizeX; frameSizeY = windowSizeY; msg_drawState->framePalette = 0; msg_drawState->textStartPos[0] = 12; msg_drawState->textStartPos[1] = 6; frameAlpha = 255; if (printer->windowState == MSG_WINDOW_STATE_OPENING) { printer->fadeInCounter++; if (printer->fadeInCounter == 6) { printer->windowState = MSG_WINDOW_STATE_PRINTING; } temp_f10 = ((f32) printer->fadeInCounter * (2.0 / 15.0)) + 0.2; z1 = printer->windowBasePos.x + (windowSizeX / 2); z2 = printer->windowBasePos.y + (windowSizeY / 2); temp1 = z1 - (windowSizeX * temp_f10 * 0.5); temp2 = z2 - (windowSizeY * temp_f10 * 0.5); frameX = temp1 + 0.5; frameY = temp2 + 0.5; frameSizeX = windowSizeX * temp_f10 + 0.5; frameSizeY = windowSizeY * temp_f10 + 0.5; if (frameSizeX < 24) { frameSizeX = 24; } if (frameSizeY < 24) { frameSizeY = 24; } sp8E = (u8)(temp_f10 * 255.0) * 0.6; } else if (printer->windowState == MSG_WINDOW_STATE_CLOSING) { printer->fadeOutCounter++; if (printer->fadeOutCounter >= 5) { printer->stateFlags |= MSG_STATE_FLAG_1; } frameAlpha = ~(printer->fadeOutCounter * 0x2E); sp8E = ((u8)frameAlpha) * 0.6; frameFading = 1; if (sp8E >= 32) { sp8E -= 32; } frameX = printer->windowBasePos.x; frameY = printer->windowBasePos.y; } else { frameX = printer->windowBasePos.x; frameY = printer->windowBasePos.y; msg_draw_prim_rect(255, 32, 32, 0, frameX - 1, frameY - 1, windowSizeX + 2, windowSizeY + 2); } msg_drawState->clipX[0] = frameX + 2; msg_drawState->clipY[0] = frameY + 2; msg_drawState->clipX[1] = frameX + frameSizeX - 2; msg_drawState->clipY[1] = frameY + frameSizeY - 2; msg_draw_frame(frameX, frameY, frameSizeX, frameSizeY, MSG_STYLE_CHOICE, msg_drawState->framePalette, frameFading, frameAlpha, frameAlpha); msg_reset_gfx_state(); spAE = frameAlpha & 0xFF; msg_drawState->textColor = MSG_PAL_STANDARD; msg_drawState->drawBufferPos += 2; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; break; case MSG_STYLE_INSPECT: case MSG_STYLE_UPGRADE: case MSG_STYLE_NARRATE: case MSG_STYLE_F: fading = 0; msg_drawState->textStartPos[0] = 16; msg_drawState->textStartPos[1] = 3; msg_drawState->clipX[0] = printer->windowBasePos.x + 5; msg_drawState->clipY[0] = printer->windowBasePos.y + 4; msg_drawState->clipX[1] = printer->windowBasePos.x + printer->windowSize.x - 8; msg_drawState->clipY[1] = printer->windowBasePos.y + printer->windowSize.y - 5; printer->rewindArrowPos.x = msg_drawState->clipX[1] - 17; printer->rewindArrowPos.y = msg_drawState->clipY[1] - 17; msg_drawState->textColor = MSG_PAL_WHITE; phi_s0_5 = 0xFF; msg_draw_prim_rect(255, 32, 32, 0, printer->windowBasePos.x + 3, printer->windowBasePos.y - 1, printer->windowSize.x - 6, 1); msg_draw_prim_rect(32, 255, 32, 0, printer->windowBasePos.x + 3, printer->windowBasePos.y + printer->windowSize.y, printer->windowSize.x - 6, 1); if (printer->windowState == MSG_WINDOW_STATE_OPENING) { phi_s0_5 = (printer->fadeInCounter * 0x30) + 0x50; sp8E = (phi_s0_5 & 0xFF) - 0x30; printer->fadeInCounter++; fading = 1; if ((s16)printer->fadeInCounter == 4) { // TODO why is this cast needed printer->windowState = MSG_WINDOW_STATE_PRINTING; } } else if (printer->windowState == MSG_WINDOW_STATE_CLOSING) { phi_s0_5 = -0x30 - (printer->fadeOutCounter * 40); sp8E = (phi_s0_5 & 0xFF) - 0x30; printer->fadeOutCounter++; fading = 1; if (printer->fadeOutCounter == 4) { printer->stateFlags |= MSG_STATE_FLAG_1; } } msg_draw_frame(printer->windowBasePos.x, printer->windowBasePos.y, printer->windowSize.x, printer->windowSize.y, MSG_STYLE_INSPECT, msg_drawState->framePalette, fading, phi_s0_5, phi_s0_5); msg_reset_gfx_state(); spAE = phi_s0_5 & 0xFF; msg_drawState->drawBufferPos += 2; break; case MSG_STYLE_SIGN: case MSG_STYLE_LAMPPOST: msg_drawState->textStartPos[0] = 18; msg_drawState->textStartPos[1] = 11; printer->windowBasePos.x = 20; printer->windowBasePos.y = 28; printer->windowSize.x = 280; msg_drawState->framePalette = 15; temp_s1_5 = 0xFF; if (printer->style == MSG_STYLE_SIGN) { signRaster = ui_msg_sign_corner_bottomright_png; printer->windowSize.y = 72; msg_drawState->textColor = MSG_PAL_18; signPalette = ui_msg_sign_pal; } else { signRaster = ui_msg_lamppost_corner_bottomright_png; msg_drawState->textColor = MSG_PAL_1C; signPalette = ui_msg_lamppost_pal; } msg_drawState->clipX[0] = 34; msg_drawState->clipY[0] = 40; msg_drawState->clipX[1] = 283; msg_drawState->clipY[1] = printer->windowSize.y + 17; printer->rewindArrowPos.x = msg_drawState->clipX[1] - 16; printer->rewindArrowPos.y = msg_drawState->clipY[1] - 9; if (printer->windowState == MSG_WINDOW_STATE_OPENING) { temp_s1_5 = (printer->fadeInCounter << 6) + 0x50; sp8E = (temp_s1_5 & 0xFF) - 0x30; printer->fadeInCounter++; if (printer->fadeInCounter == 3) { printer->windowState = MSG_WINDOW_STATE_PRINTING; } } else { if (printer->windowState == MSG_WINDOW_STATE_CLOSING) { temp_s1_5 = -0x30 - (printer->fadeOutCounter * 0x30); sp8E = (temp_s1_5 & 0xFF) - 0x30; printer->fadeOutCounter++; if (printer->fadeOutCounter == 3) { printer->stateFlags |= MSG_STATE_FLAG_1; } } } spAE = (u8)temp_s1_5; draw_ci_image_with_clipping(ui_msg_sign_corner_topleft_png, 16, 16, G_IM_FMT_CI, G_IM_SIZ_4b, signPalette, 20, 28, 10, 10, 310, 230, temp_s1_5); draw_ci_image_with_clipping(ui_msg_sign_corner_topright_png, 16, 16, G_IM_FMT_CI, G_IM_SIZ_4b, signPalette, 284, 28, 10, 10, 310, 230, temp_s1_5); draw_ci_image_with_clipping(ui_msg_sign_corner_bottomleft_png, 16, 16, G_IM_FMT_CI, G_IM_SIZ_4b, signPalette, 20, printer->windowSize.y + 12, 10, 10, 310, 230, temp_s1_5); draw_ci_image_with_clipping(signRaster, 16, 16, G_IM_FMT_CI, G_IM_SIZ_4b, signPalette, 284, printer->windowSize.y + 12, 10, 10, 310, 230, temp_s1_5); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_sign_side_top_png, G_IM_FMT_CI, 32, 0, 0, 0, 31, 15, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 4, G_TX_NOLOD, G_TX_NOLOD); gSPTextureRectangle(gMainGfxPos++, 0x0090, 0x0070, 0x0470, 0x00B0, G_TX_RENDERTILE, 0, 0, 0x0400, 0x0400); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_sign_side_left_png, G_IM_FMT_CI, 16, 0, 0, 0, 15, 31, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, 5, G_TX_NOLOD, G_TX_NOLOD); gSPTextureRectangle(gMainGfxPos++, 0x0050, 0x00B0, 0x0090, (printer->windowSize.y + 12) * 4, G_TX_RENDERTILE, 0, 0, 0x0400, 0x0400); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_sign_side_right_png, G_IM_FMT_CI, 16, 0, 0, 0, 15, 31, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, 5, G_TX_NOLOD, G_TX_NOLOD); gSPTextureRectangle(gMainGfxPos++, 0x0470, 0x00B0, 0x04B0, (printer->windowSize.y + 12) * 4, G_TX_RENDERTILE, 0, 0, 0x0400, 0x0400); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_sign_side_bottom_png, G_IM_FMT_CI, 32, 0, 0, 0, 31, 15, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 4, G_TX_NOLOD, G_TX_NOLOD); gSPTextureRectangle(gMainGfxPos++, 0x0090, (printer->windowSize.y + 12) * 4, 0x0470, (printer->windowSize.y + 28) * 4, G_TX_RENDERTILE, 0, 0, 0x0400, 0x0400); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_sign_fill_png, G_IM_FMT_CI, 8, 0, 0, 0, 7, 7, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 3, 3, G_TX_NOLOD, G_TX_NOLOD); gSPTextureRectangle(gMainGfxPos++, 0x0090, 0x00B0, 0x0470, (printer->windowSize.y + 12) * 4, G_TX_RENDERTILE, 0, 0, 0x0400, 0x0400); msg_reset_gfx_state(); msg_drawState->drawBufferPos += 2; break; case MSG_STYLE_POSTCARD: phi_s2_4 = 0; msg_drawState->textStartPos[0] = 12; msg_drawState->textStartPos[1] = 5; printer->windowBasePos.x = 40; printer->windowBasePos.y = 28; msg_drawState->clipX[0] = 45; msg_drawState->clipY[0] = 32; msg_drawState->clipX[1] = 272; msg_drawState->clipY[1] = 81; printer->rewindArrowPos.x = msg_drawState->clipX[1] - 21; printer->rewindArrowPos.y = msg_drawState->clipY[1] - 20; msg_drawState->framePalette = 0; msg_drawState->textColor = MSG_PAL_WHITE; msg_draw_prim_rect(255, 32, 32, 0, 43, 27, 234, 1); msg_draw_prim_rect(32, 255, 32, 0, 43, 86, 234, 1); phi_s3_2 = 0xFF; if (printer->windowState == MSG_WINDOW_STATE_OPENING) { phi_s3_2 = (printer->fadeInCounter * 64) + 80; sp8E = (phi_s3_2 & 0xFF) - 0x30; printer->fadeInCounter++; if (printer->fadeInCounter == 3) { printer->windowState = MSG_WINDOW_STATE_PRINTING; } phi_s2_4 = 1; } else if (printer->windowState == MSG_WINDOW_STATE_CLOSING) { phi_s3_2 = -0x30 - (printer->fadeOutCounter * 0x30); sp8E = (phi_s3_2 & 0xFF) - 0x30; printer->fadeOutCounter++; if (printer->fadeOutCounter == 3) { printer->stateFlags |= MSG_STATE_FLAG_1; } phi_s2_4 = 1; } msg_draw_frame(40, 28, 240, 58, MSG_STYLE_INSPECT, msg_drawState->framePalette, phi_s2_4, phi_s3_2, phi_s3_2); draw_ci_image_with_clipping(printer->letterBackgroundImg, 150, 105, G_IM_FMT_CI, G_IM_SIZ_4b, printer->letterBackgroundPal, 85, 97, 10, 10, 300, 220, phi_s3_2); draw_ci_image_with_clipping(printer->letterContentImg, 70, 95, G_IM_FMT_CI, G_IM_SIZ_8b, printer->letterContentPal, 160, 102, 10, 10, 300, 220, phi_s3_2); msg_reset_gfx_state(); spAE = phi_s3_2 & 0xFF; msg_drawState->drawBufferPos += 2; break; case MSG_STYLE_POPUP: case MSG_STYLE_B: msg_drawState->textStartPos[0] = 16; msg_drawState->textStartPos[1] = 4; msg_drawState->clipX[0] = 0; msg_drawState->clipX[1] = SCREEN_WIDTH - 1; msg_drawState->clipY[0] = 0; msg_drawState->clipY[1] = SCREEN_HEIGHT - 1; msg_drawState->textColor = MSG_PAL_WHITE; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; if (printer->windowState == MSG_WINDOW_STATE_D || printer->windowState == MSG_WINDOW_STATE_E) { printer->windowBasePos.x = 0; printer->windowBasePos.y = 0; } else { printer->windowBasePos.x = 160 - printer->windowSize.x / 2; printer->windowBasePos.y = 56; draw_box(0, WINDOW_STYLE_0, printer->windowBasePos.x, 56, 0, printer->windowSize.x, printer->windowSize.y, 255, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NULL, 0, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL); } msg_reset_gfx_state(); msg_drawState->drawBufferPos += 2; break; case MSG_STYLE_EPILOGUE: printer->windowBasePos.x = 60; printer->windowBasePos.y = 110; printer->windowSize.x = 200; printer->windowSize.y = 50; msg_drawState->textStartPos[0] = 0; msg_drawState->textStartPos[1] = -2; msg_drawState->clipX[0] = printer->windowBasePos.x; msg_drawState->clipY[0] = printer->windowBasePos.y; msg_drawState->clipX[1] = printer->windowBasePos.x + printer->windowSize.x; msg_drawState->clipY[1] = printer->windowBasePos.y + printer->windowSize.y; printer->rewindArrowPos.x = printer->windowBasePos.x + printer->windowSize.x - 10; printer->rewindArrowPos.y = printer->windowBasePos.y + printer->windowSize.y - 10; msg_reset_gfx_state(); msg_drawState->drawBufferPos += 2; break; } break; case MSG_CHAR_PRINT_NEXT: if (printer->windowState == MSG_WINDOW_STATE_C) { if (msg_drawState->nextCounter >= printer->unkArraySize) { sp80bool = TRUE; } } else if (printer->windowState == MSG_WINDOW_STATE_B) { if (printer->curLinePos < printer->lineEndPos[printer->unkArraySize]) { if (msg_drawState->nextCounter >= printer->unkArraySize) { sp80bool = TRUE; } } else { if (printer->unkArraySize < msg_drawState->nextCounter) { sp80bool = TRUE; } else if (msg_drawState->nextCounter >= printer->unkArraySize) { phi_a0_4 = 36; if (printer->maxLinesPerPage >= 2) { phi_v0_3 = 48; if (printer->maxLinesPerPage == 2) { phi_v0_3 = 32; } if (printer->unk_4C8 < phi_v0_3) { if (printer->unk_4C8 <= 0x10) { phi_a0_4 = 56; } sp8E = 0xFF - (phi_a0_4 * printer->unk_4CC); if (sp8E < 0) { sp8E = 0; } } } } } } msg_drawState->nextCounter++; msg_drawState->drawBufferPos++; break; case MSG_CHAR_PRINT_END: sp80bool = TRUE; break; case MSG_CHAR_PRINT_FUNCTION: msg_drawState->drawBufferPos++; switch (msg_drawState->printBuffer[msg_drawState->drawBufferPos]) { case MSG_PRINT_FUNC_FONT: msg_drawState->font = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->drawBufferPos += 2; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; break; case MSG_PRINT_FUNC_VARIANT: msg_drawState->fontVariant = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_COLOR: msg_drawState->textColor = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_SPACING: msg_drawState->curPosX = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_SIZE: packedScaleX = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->msgScale.x = (f32)(packedScaleX >> 4) + ((packedScaleX & 0xF) * 0.0625f); packedScaleY = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2]; msg_drawState->msgScale.y = (f32)(packedScaleY >> 4) + ((packedScaleY & 0xF) * 0.0625f); msg_drawState->drawBufferPos += 3; if (msg_drawState->msgScale.x > 1.0 || msg_drawState->msgScale.y > 1.0) { gDPSetTextureFilter(gMainGfxPos++, G_TF_POINT); } else if (msg_drawState->msgScale.x < 1.0 || msg_drawState->msgScale.y < 1.0) { gDPSetTextureFilter(gMainGfxPos++, G_TF_AVERAGE); } break; case MSG_PRINT_FUNC_SIZE_RESET: msg_drawState->msgScale.x = 1.0f; msg_drawState->msgScale.y = 1.0f; msg_drawState->drawBufferPos++; gDPSetTextureFilter(gMainGfxPos++, G_TF_AVERAGE); break; case MSG_PRINT_FUNC_SET_X: msg_drawState->nextPos[0] = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1] * 256 + (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2]); msg_drawState->drawBufferPos += 3; break; case MSG_PRINT_FUNC_SET_Y: msg_drawState->nextPos[1] = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_RIGHT: msg_drawState->nextPos[0] += msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_DOWN: msg_drawState->nextPos[1] += msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_UP: msg_drawState->nextPos[1] -= msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_INLINE_IMAGE: msgImageData = &(*gMsgVarImages)[msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]]; phi_t5 = sp8E; if (sp8E < 0xFF) { phi_t5 = (s32)(sp8E * 0.7); } imgDrawPosX = (s16)((msg_drawState->nextPos[0] + (msg_drawState->textStartPos[0] + (printer->windowBasePos.x + posX))) - additionalOffsetX); imgDrawPosY = (s16)((msg_drawState->nextPos[1] + (msg_drawState->textStartPos[1] + (printer->windowBasePos.y + posY))) - additionalOffsetY); draw_ci_image_with_clipping(msgImageData->raster, msgImageData->width, msgImageData->height, msgImageData->format, msgImageData->bitDepth, msgImageData->palette, imgDrawPosX, imgDrawPosY, (s32) msg_drawState->clipX[0], (s32) msg_drawState->clipY[0], msg_drawState->clipX[1] - msg_drawState->clipX[0], msg_drawState->clipY[1] - msg_drawState->clipY[0], phi_t5); msg_drawState->printModeFlags |= (MSG_PRINT_FLAG_2 | MSG_PRINT_FLAG_10); msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_ANIM_SPRITE: phi_s0_6 = sp8E; if (sp8E < 0xFF) { phi_s0_6 = (s32)(sp8E * 0.7); } if (spr_get_npc_raster_info(&sprRasterInfo, (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1] << 8) | msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2], msg_drawState->printBuffer[msg_drawState->drawBufferPos + 3]) != 0) { imgDrawPosX = (s16)((msg_drawState->nextPos[0] + (msg_drawState->textStartPos[0] + (printer->windowBasePos.x + posX))) - additionalOffsetX); imgDrawPosY = (s16)((msg_drawState->nextPos[1] + (msg_drawState->textStartPos[1] + (printer->windowBasePos.y + posY))) - additionalOffsetY); draw_ci_image_with_clipping(sprRasterInfo.raster, sprRasterInfo.width, sprRasterInfo.height, G_IM_FMT_CI, G_IM_SIZ_4b, sprRasterInfo.defaultPal, imgDrawPosX, imgDrawPosY, msg_drawState->clipX[0], msg_drawState->clipY[0], msg_drawState->clipX[1] - msg_drawState->clipX[0], msg_drawState->clipY[1] - msg_drawState->clipY[0], phi_s0_6); msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; } msg_drawState->drawBufferPos += 4; break; case MSG_PRINT_FUNC_ITEM_ICON: if (D_8015131C != 0) { phi_t3 = sp8E; if (sp8E < 0xFF) { phi_t3 = (s32)(sp8E * 0.7); } imgDrawPosX = (s16)((msg_drawState->nextPos[0] + (msg_drawState->textStartPos[0] + (printer->windowBasePos.x + posX))) - additionalOffsetX); imgDrawPosY = (s16)((msg_drawState->nextPos[1] + (msg_drawState->textStartPos[1] + (printer->windowBasePos.y + posY))) - additionalOffsetY); draw_ci_image_with_clipping(D_80159B50, 32, 32, G_IM_FMT_CI, G_IM_SIZ_4b, D_8015C7E0, imgDrawPosX, imgDrawPosY, msg_drawState->clipX[0], msg_drawState->clipY[0], msg_drawState->clipX[1] - msg_drawState->clipX[0], msg_drawState->clipY[1] - msg_drawState->clipY[0], phi_t3); msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; } msg_drawState->drawBufferPos++; break; case MSG_PRINT_FUNC_ANIM_DELAY: animIdx = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; if (printer->animTimers[animIdx] == -1) { printer->animTimers[animIdx] = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 3]; } if (printer->animTimers[animIdx] == 0) { printer->curAnimFrame[animIdx]++; } dbPos = msg_drawState->drawBufferPos; while (TRUE) { if ((msg_drawState->printBuffer[dbPos - 1] == MSG_CHAR_PRINT_FUNCTION) && (msg_drawState->printBuffer[dbPos] == MSG_PRINT_FUNC_ANIM_DELAY) && (msg_drawState->printBuffer[dbPos + 1] == animIdx)) { if (msg_drawState->printBuffer[dbPos + 2] != printer->curAnimFrame[animIdx]) { dbPos += 4; } else { break; } } else { if ((msg_drawState->printBuffer[dbPos] == MSG_CHAR_PRINT_FUNCTION) && (msg_drawState->printBuffer[dbPos + 1] == MSG_PRINT_FUNC_ANIM_LOOP) && (msg_drawState->printBuffer[dbPos + 2] == animIdx)) { if (printer->animTimers[animIdx] == 0) { printer->curAnimFrame[animIdx] = msg_drawState->printBuffer[dbPos + 3]; dbPos = msg_drawState->drawBufferPos; continue; } else { dbPos++; break; } } else { if (msg_drawState->printBuffer[dbPos] == MSG_CHAR_PRINT_FUNCTION && msg_drawState->printBuffer[dbPos + 1] == MSG_PRINT_FUNC_ANIM_DONE) { if (msg_drawState->printBuffer[dbPos + 2] == animIdx) { dbPos++; break; } } } } dbPos++; } msg_drawState->drawBufferPos = dbPos; switch (msg_drawState->printBuffer[msg_drawState->drawBufferPos]) { case MSG_PRINT_FUNC_ANIM_DELAY: if (printer->animTimers[animIdx] == 0) { if (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 3] == 0) { printer->animTimers[animIdx] = -2; } else { printer->animTimers[animIdx] = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 3]; } } msg_drawState->drawBufferPos += 4; break; case MSG_PRINT_FUNC_ANIM_LOOP: msg_drawState->drawBufferPos += 3; break; case MSG_PRINT_FUNC_ANIM_DONE: msg_drawState->drawBufferPos += 2; break; } break; case MSG_PRINT_FUNC_ANIM_LOOP: msg_drawState->drawBufferPos += 3; break; case MSG_PRINT_FUNC_ANIM_DONE: msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_CURSOR: printer->cursorPosX[msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]] = msg_drawState->textStartPos[0] + msg_drawState->nextPos[0] - additionalOffsetX - 6; printer->cursorPosY[msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]] = msg_drawState->textStartPos[1] + msg_drawState->nextPos[1] - additionalOffsetY - 1; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_OPTION: if (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1] == 0xFF) { msg_drawState->printModeFlags &= ~MSG_PRINT_FLAG_20; } else { msg_drawState->unk_2D = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_20; msg_drawState->nextPos[0] += 14; } msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_SET_FRAME_PALETTE: msg_drawState->framePalette = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_RESET_GFX: msg_reset_gfx_state(); msg_drawState->drawBufferPos++; break; case MSG_PRINT_FUNC_SAVE_POS: msg_drawState->savedPos[0] = msg_drawState->nextPos[0]; msg_drawState->savedPos[1] = msg_drawState->nextPos[1]; msg_drawState->drawBufferPos++; break; case MSG_PRINT_FUNC_RESTORE_POS: msg_drawState->nextPos[0] = msg_drawState->savedPos[0]; msg_drawState->nextPos[1] = msg_drawState->savedPos[1]; msg_drawState->drawBufferPos++; break; case MSG_PRINT_FUNC_SAVE_COLOR: msg_drawState->savedColor = msg_drawState->textColor; msg_drawState->drawBufferPos++; break; case MSG_PRINT_FUNC_RESTORE_COLOR: msg_drawState->textColor = msg_drawState->savedColor; msg_drawState->drawBufferPos++; break; case MSG_PRINT_FUNC_START_FX: switch (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]) { case MSG_FX_SHAKE: msg_drawState->effectFlags |= MSG_FX_FLAG_SHAKE; msg_drawState->drawBufferPos += 2; break; case MSG_FX_WAVE: msg_drawState->effectFlags |= MSG_FX_FLAG_WAVE; msg_drawState->drawBufferPos += 2; break; case MSG_FX_NOISE_OUTLINE: msg_drawState->effectFlags |= MSG_FX_FLAG_NOISE_OUTLINE; gDPSetCombineMode(gMainGfxPos++, PM_CC_MSG_NOISE_OUTLINE, PM_CC_MSG_NOISE_OUTLINE); msg_drawState->drawBufferPos += 2; break; case MSG_FX_STATIC: msg_drawState->effectFlags |= MSG_FX_FLAG_STATIC; gDPSetEnvColor(gMainGfxPos++, msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2], msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2], msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2], 0); gDPSetCombineMode(gMainGfxPos++, PM_CC_MSG_STATIC, PM_CC_MSG_STATIC); msg_drawState->drawBufferPos += 3; break; case MSG_FX_BLUR: msg_drawState->effectFlags |= MSG_FX_FLAG_BLUR; spB8 = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2]; msg_drawState->drawBufferPos += 3; break; case MSG_FX_RAINBOW: msg_drawState->effectFlags |= MSG_FX_FLAG_RAINBOW; msg_drawState->drawBufferPos += 2; break; case MSG_FX_DITHER_FADE: msg_drawState->effectFlags |= MSG_FX_FLAG_DITHER_FADE; spB6 = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2]; msg_drawState->drawBufferPos += 3; break; case MSG_FX_GLOBAL_WAVE: msg_drawState->effectFlags |= MSG_FX_FLAG_GLOBAL_WAVE; msg_drawState->drawBufferPos += 2; break; case MSG_FX_GLOBAL_RAINBOW: msg_drawState->effectFlags |= MSG_FX_FLAG_GLOBAL_RAINBOW; msg_drawState->drawBufferPos += 2; break; case MSG_FX_RISE_PRINT: msg_drawState->effectFlags |= MSG_FX_FLAG_RISE_PRINT; msg_drawState->drawBufferPos += 2; break; case MSG_FX_GROW_PRINT: msg_drawState->effectFlags |= MSG_FX_FLAG_GROW_PRINT; msg_drawState->drawBufferPos += 2; break; case MSG_FX_SIZE_JITTER: msg_drawState->effectFlags |= MSG_FX_FLAG_SIZE_JITTER; msg_drawState->drawBufferPos += 2; break; case MSG_FX_SIZE_WAVE: msg_drawState->effectFlags |= MSG_FX_FLAG_SIZE_WAVE; msg_drawState->drawBufferPos += 2; break; case MSG_FX_DROP_SHADOW: msg_drawState->effectFlags |= MSG_FX_FLAG_DROP_SHADOW; msg_drawState->drawBufferPos += 2; break; } break; case MSG_PRINT_FUNC_END_FX: switch (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]) { case MSG_FX_SHAKE: msg_drawState->effectFlags &= ~MSG_FX_FLAG_SHAKE; break; case MSG_FX_WAVE: msg_drawState->effectFlags &= ~MSG_FX_FLAG_WAVE; break; case MSG_FX_NOISE_OUTLINE: msg_drawState->effectFlags &= ~MSG_FX_FLAG_NOISE_OUTLINE; break; case MSG_FX_STATIC: msg_drawState->effectFlags &= ~MSG_FX_FLAG_STATIC; break; case MSG_FX_BLUR: msg_drawState->effectFlags &= ~MSG_FX_FLAG_BLUR; break; case MSG_FX_RAINBOW: msg_drawState->effectFlags &= ~MSG_FX_FLAG_RAINBOW; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; break; case MSG_FX_DITHER_FADE: msg_drawState->effectFlags &= ~MSG_FX_FLAG_DITHER_FADE; break; case MSG_FX_GLOBAL_WAVE: msg_drawState->effectFlags &= ~MSG_FX_FLAG_GLOBAL_WAVE; break; case MSG_FX_GLOBAL_RAINBOW: msg_drawState->effectFlags &= ~MSG_FX_FLAG_GLOBAL_RAINBOW; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; break; case MSG_FX_RISE_PRINT: msg_drawState->effectFlags &= ~MSG_FX_FLAG_RISE_PRINT; break; case MSG_FX_GROW_PRINT: msg_drawState->effectFlags &= ~MSG_FX_FLAG_GROW_PRINT; break; case MSG_FX_SIZE_JITTER: msg_drawState->effectFlags &= ~MSG_FX_FLAG_SIZE_JITTER; break; case MSG_FX_SIZE_WAVE: msg_drawState->effectFlags &= ~MSG_FX_FLAG_SIZE_WAVE; break; case MSG_FX_DROP_SHADOW: msg_drawState->effectFlags &= ~MSG_FX_FLAG_DROP_SHADOW; break; } msg_drawState->drawBufferPos += 2; break; case MSG_PRINT_FUNC_CENTER_X: if (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1] != 0) { msg_drawState->centerPos = msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1]; if (msg_drawState->centerPos == 0xFF) { msg_drawState->centerPos = printer->windowSize.x / 2; } msg_drawState->printModeFlags |= (MSG_PRINT_FLAG_40 | MSG_PRINT_FLAG_80); } else { msg_drawState->nextPos[0] = 0; msg_drawState->printModeFlags &= ~(MSG_PRINT_FLAG_40 | MSG_PRINT_FLAG_80); } msg_drawState->drawBufferPos += 2; break; } break; default: if (msg_drawState->printModeFlags & MSG_PRINT_FLAG_2) { sp96 = 0xFF; gDPPipeSync(gMainGfxPos++); gSPDisplayList(gMainGfxPos++, D_8014C500); } msg_drawState->charScale.x = msg_drawState->msgScale.x; msg_drawState->charScale.y = msg_drawState->msgScale.y; if (msg_drawState->printModeFlags & MSG_PRINT_FLAG_80) { msg_drawState->nextPos[0] += msg_drawState->centerPos - printer->msgWidth / 2; msg_drawState->printModeFlags &= ~MSG_PRINT_FLAG_80; } if (msg_drawState->printModeFlags & MSG_PRINT_FLAG_40) { charPosX = (u16) msg_drawState->nextPos[0] + ((u16) printer->windowBasePos.x + (u16) posX); } else { charPosX = (u16) msg_drawState->nextPos[0] + ((u16) msg_drawState->textStartPos[0] + ((u16) printer->windowBasePos.x + (u16) posX)); } msgCharset = MsgCharsets[msg_drawState->font]; charPosY = (s8) msgCharset->rasters[msg_drawState->fontVariant].baseHeightOffset + (msg_drawState->nextPos[1] + (msg_drawState->textStartPos[1] + (printer->windowBasePos.y + posY)) - additionalOffsetY); if ((sp8E != 0) && (charPosX < msg_drawState->clipX[1]) && (charPosY < msg_drawState->clipY[1]) && (msg_drawState->clipX[0] < charPosX + (s32)(msg_drawState->msgScale.x * msgCharset->rasters[msg_drawState->fontVariant].monospaceWidth)) && (msg_drawState->clipY[0] < charPosY + (s32)(msg_drawState->msgScale.y * msgCharset->newLineY + MsgStyleVerticalLineOffsets[printer->style]))) { palette = msg_drawState->textColor; phi_s2_5 = sp8E; if (msg_drawState->effectFlags & MSG_FX_FLAG_BLUR) { phi_s2_5 = (f32) phi_s2_5 * 0.35; } if ((printer->windowState == MSG_WINDOW_STATE_WAITING_FOR_CHOICE) && (msg_drawState->printModeFlags & MSG_PRINT_FLAG_20)) { if (msg_drawState->unk_2D == printer->curOption) { msg_drawState->effectFlags |= MSG_FX_FLAG_DROP_SHADOW | MSG_FX_FLAG_GLOBAL_RAINBOW | MSG_FX_FLAG_GLOBAL_WAVE; } else { msg_drawState->effectFlags &= ~MSG_FX_FLAG_GLOBAL_RAINBOW; msg_drawState->effectFlags &= ~MSG_FX_FLAG_GLOBAL_WAVE; msg_drawState->effectFlags &= ~MSG_FX_FLAG_DROP_SHADOW; palette = msg_drawState->textColor; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; } } if (msg_drawState->effectFlags & MSG_FX_FLAG_SHAKE) { charPosX += rand_int(10000) % 2; charPosY += rand_int(10000) % 2; } if (msg_drawState->effectFlags & MSG_FX_FLAG_WAVE) { temp_f2_3 = msg_drawState->msgScale.x - 1.0; temp_s0_7 = (printer->effectFrameCounter * (s32)(20.0 - (temp_f2_3 * 5.0))) - (msg_drawState->visiblePrintedCount * (s32)(45.0 - (temp_f2_3 * 15.0))); charPosX += cosine(temp_s0_7) * ((msg_drawState->msgScale.x - 1.0) + 1.6); charPosY += cosine((temp_s0_7 + 180.0 + 90.0)) * (msg_drawState->msgScale.y - 1.0 + 1.6); } if (msg_drawState->effectFlags & MSG_FX_FLAG_GLOBAL_WAVE) { temp_s0_8 = (gMsgGlobalWaveCounter * (s32)(20.0 - ((msg_drawState->msgScale.x - 1.0) * 5.0))) - (msg_drawState->visiblePrintedCount * 45); charPosX += cosine(temp_s0_8) * ((msg_drawState->msgScale.x - 1.0) + 1.6); charPosY += cosine((temp_s0_8 + 180.0 + 90.0)) * ((msg_drawState->msgScale.y - 1.0) + 1.6); } if (msg_drawState->effectFlags & MSG_FX_FLAG_RAINBOW) { palette = abs(msg_drawState->visiblePrintedCount - (u16)(printer->effectFrameCounter / 3)) % 10; } if (msg_drawState->effectFlags & MSG_FX_FLAG_GLOBAL_RAINBOW) { palette = abs(msg_drawState->visiblePrintedCount - (u16)(gGameStatusPtr->frameCounter / 3)) % 10; } if (msg_drawState->effectFlags & MSG_FX_FLAG_DITHER_FADE) { gDPSetAlphaDither(gMainGfxPos++, G_AD_NOISE); gDPSetAlphaCompare(gMainGfxPos++, G_AC_DITHER); phi_s2_5 = spB6 * (phi_s2_5 / 255.0); } if ((msg_drawState->printModeFlags & MSG_PRINT_FLAG_2) || (phi_s2_5 != sp96)) { if ((sp96 < 0xFF) && (phi_s2_5 < 0xFF)) { gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, phi_s2_5); } else if ((sp96 == 0xFF) && (phi_s2_5 < 0xFF)) { gDPPipeSync(gMainGfxPos++); if (printer->stateFlags & MSG_STATE_FLAG_4000) { gDPSetRenderMode(gMainGfxPos++, IM_RD | CVG_DST_CLAMP | ZMODE_XLU | FORCE_BL | GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA), IM_RD | CVG_DST_CLAMP | ZMODE_XLU | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); } else { gDPSetRenderMode(gMainGfxPos++, IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA), IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); } gDPSetCombineMode(gMainGfxPos++, PM_CC_02, PM_CC_02); gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, phi_s2_5); } else if ((sp96 < 0xFF) && (phi_s2_5 == 0xFF)) { gDPPipeSync(gMainGfxPos++); gDPSetRenderMode(gMainGfxPos++, G_RM_TEX_EDGE, G_RM_TEX_EDGE2); gDPSetCombineMode(gMainGfxPos++, G_CC_DECALRGBA, G_CC_DECALRGBA); } sp96 = phi_s2_5; } if (phi_s2_5 > 0) { if (msg_drawState->effectFlags & MSG_FX_FLAG_RISE_PRINT) { if ((msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1] != MSG_CHAR_PRINT_ENDL) && (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2] != MSG_CHAR_PRINT_ENDL) && (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 3] != MSG_CHAR_PRINT_ENDL) && (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 4] != MSG_CHAR_PRINT_ENDL)) { if ((msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1] == MSG_CHAR_PRINT_END) && (printer->windowState == MSG_WINDOW_STATE_PRINTING)) { msg_drawState->charScale.x = msg_drawState->msgScale.x * 1.7; msg_drawState->charScale.y = msg_drawState->msgScale.y * 1.7; temp_f8 = (msg_drawState->charScale.y / 1.7) * 6.0; charPosX -= temp_f8; charPosY -= temp_f8; } else if ((msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2] == MSG_CHAR_PRINT_END) && (printer->windowState == MSG_WINDOW_STATE_PRINTING)) { msg_drawState->charScale.x = msg_drawState->msgScale.x * 1.4; msg_drawState->charScale.y = msg_drawState->msgScale.y * 1.4; temp_f8 = (msg_drawState->charScale.y / 1.4) * 3.0; charPosX -= temp_f8; charPosY -= temp_f8; } else if ((msg_drawState->printBuffer[msg_drawState->drawBufferPos + 3] == MSG_CHAR_PRINT_END) && (printer->windowState == MSG_WINDOW_STATE_PRINTING)) { msg_drawState->charScale.x = msg_drawState->msgScale.x * 1.2; msg_drawState->charScale.y = msg_drawState->msgScale.y * 1.2; temp_f8 = (msg_drawState->charScale.y / 1.2) * 2.0; charPosX -= temp_f8; charPosY -= temp_f8; } } } else if (msg_drawState->effectFlags & MSG_FX_FLAG_GROW_PRINT) { if ((msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1] != MSG_CHAR_PRINT_ENDL) && (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2] != MSG_CHAR_PRINT_ENDL) && (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 3] != MSG_CHAR_PRINT_ENDL) && (msg_drawState->printBuffer[msg_drawState->drawBufferPos + 4] != MSG_CHAR_PRINT_ENDL)) { if ((msg_drawState->printBuffer[msg_drawState->drawBufferPos + 1] == MSG_CHAR_PRINT_END) && (printer->windowState == MSG_WINDOW_STATE_PRINTING)) { msg_drawState->charScale.x = msg_drawState->msgScale.x * 0.3; msg_drawState->charScale.y = msg_drawState->msgScale.y * 0.3; charPosX += 5; charPosY += 5; } else if ((msg_drawState->printBuffer[msg_drawState->drawBufferPos + 2] == MSG_CHAR_PRINT_END) && (printer->windowState == MSG_WINDOW_STATE_PRINTING)) { msg_drawState->charScale.x = msg_drawState->msgScale.x * 0.5; msg_drawState->charScale.y = msg_drawState->msgScale.y * 0.5; charPosX += 3; charPosY += 3; } else if ((msg_drawState->printBuffer[msg_drawState->drawBufferPos + 3] == MSG_CHAR_PRINT_END) && (printer->windowState == MSG_WINDOW_STATE_PRINTING)) { msg_drawState->charScale.x = msg_drawState->msgScale.x * 0.75; msg_drawState->charScale.y = msg_drawState->msgScale.y * 0.75; charPosX += 2; charPosY += 2; } } } else if (msg_drawState->effectFlags & MSG_FX_FLAG_SIZE_JITTER) { temp_f8_5 = rand_int(10000) % 101; temp_f8_5 /= 100.0; temp_f8_5 = ((temp_f8_5 * 0.5) + 1.0) - 0.25; if (temp_f8_5 > 1.0) { msg_drawState->charScale.x = msg_drawState->msgScale.x * temp_f8_5; msg_drawState->charScale.y = msg_drawState->msgScale.y * temp_f8_5; charPosX -= (temp_f8_5 * 8.0) - 8.5; charPosY -= (temp_f8_5 * 8.0) - 8.5; } else if (temp_f8_5 < 1.0) { msg_drawState->charScale.x = msg_drawState->msgScale.x * temp_f8_5; msg_drawState->charScale.y = msg_drawState->msgScale.y * temp_f8_5; charPosX += 8.0 - (temp_f8_5 * 16.0) * 0.5; charPosY += 8.0 - (temp_f8_5 * 16.0) * 0.5; } } else if (msg_drawState->effectFlags & MSG_FX_FLAG_SIZE_WAVE) { s32 mod360; temp_a0_49 = printer->effectFrameCounter * 15; temp_a0_49 -= msg_drawState->visiblePrintedCount * 15; mod360 = temp_a0_49 % 360; temp_f8_5 = (cosine(mod360) * 0.25) + 1.0; if (temp_f8_5 > 1.0) { msg_drawState->charScale.x = msg_drawState->msgScale.x * temp_f8_5; msg_drawState->charScale.y = msg_drawState->msgScale.y * temp_f8_5; charPosX -= (temp_f8_5 * 8.0) - 8.5; charPosY -= (temp_f8_5 * 8.0) - 8.5; } else if (temp_f8_5 < 1.0) { msg_drawState->charScale.x = msg_drawState->msgScale.x * temp_f8_5; msg_drawState->charScale.y = msg_drawState->msgScale.y * temp_f8_5; charPosX += 8.0 - (temp_f8_5 * 16.0) * 0.5; charPosY += 8.0 - (temp_f8_5 * 16.0) * 0.5; } } if ((printer->windowState == MSG_WINDOW_STATE_B || printer->windowState == MSG_WINDOW_STATE_C) && (printer->style == MSG_STYLE_RIGHT || printer->style == MSG_STYLE_LEFT || printer->style == MSG_STYLE_CENTER || printer->style == MSG_STYLE_TATTLE)) { switch (palette) { case MSG_PAL_WHITE: case MSG_PAL_RED: case MSG_PAL_10: case MSG_PAL_11: case MSG_PAL_12: case MSG_PAL_13: case MSG_PAL_14: break; case MSG_PAL_STANDARD: palette = MSG_PAL_40; break; case MSG_PAL_20: palette = MSG_PAL_41; break; case MSG_PAL_22: palette = MSG_PAL_42; break; case MSG_PAL_23: palette = MSG_PAL_43; break; case MSG_PAL_25: palette = MSG_PAL_44; break; default: palette = MSG_PAL_40; break; } } if (palette != sp9E) { sp9E = palette; msg_drawState->printModeFlags |= MSG_PRINT_FLAG_10; } if ((msg_drawState->effectFlags & MSG_FX_FLAG_DROP_SHADOW) && (phi_s2_5 == 0xFF)) { gDPPipeSync(gMainGfxPos++); gDPSetRenderMode(gMainGfxPos++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetCombineMode(gMainGfxPos++, PM_CC_07, PM_CC_07); gDPSetPrimColor(gMainGfxPos++, 0, 0, 40, 40, 40, 72); msg_draw_char(printer, msg_drawState, msg_drawState->printBuffer[msg_drawState->drawBufferPos], palette, charPosX + 2, charPosY + 2); gDPPipeSync(gMainGfxPos++); gDPSetRenderMode(gMainGfxPos++, G_RM_TEX_EDGE, G_RM_TEX_EDGE2); gDPSetCombineMode(gMainGfxPos++, G_CC_DECALRGBA, G_CC_DECALRGBA); } if (msg_drawState->effectFlags & MSG_FX_FLAG_BLUR) { for (i = 0; i < 5; i++) { phi_s0_7 = charPosX; phi_s1_8 = charPosY; if (spB8 != 2) { phi_s0_7 += (rand_int(10000) % 3) - 1; } if (spB8 != 1) { phi_s1_8 += (rand_int(10000) % 3) - 1; } msg_draw_char(printer, msg_drawState, msg_drawState->printBuffer[msg_drawState->drawBufferPos], palette, phi_s0_7, phi_s1_8); } } else { msg_draw_char(printer, msg_drawState, msg_drawState->printBuffer[msg_drawState->drawBufferPos], palette, charPosX, charPosY); } } } if (msg_drawState->printModeFlags & MSG_PRINT_FLAG_2) { msg_drawState->printModeFlags &= ~MSG_PRINT_FLAG_2; } msg_drawState->visiblePrintedCount += 1; msg_drawState->nextPos[0] += msg_get_draw_char_width(msg_drawState->printBuffer[msg_drawState->drawBufferPos], msg_drawState->font, msg_drawState->fontVariant, msg_drawState->msgScale.x, msg_drawState->curPosX, msg_drawState->printModeFlags); msg_drawState->drawBufferPos++; break; } } varImgHasBorder = FALSE; if (printer->varImageScreenPos.x != 0) { s16 varImgFinalAlpha; varImgFinalAlpha = printer->varImgFinalAlpha; msgVarImage = &(*gMsgVarImages)[printer->curImageIndex]; switch (printer->varImgHasBorder) { case 0: case 1: if (printer->varImgHasBorder) { varImgHasBorder = TRUE; } switch (printer->varImageDisplayState) { case 0: printer->varImageFadeTimer++; varImgFinalAlpha = printer->varImageFadeTimer * printer->varImgAlphaFadeStep; if (printer->varImgFinalAlpha <= varImgFinalAlpha) { varImgFinalAlpha = printer->varImgFinalAlpha; printer->varImageFadeTimer = 0; printer->varImageDisplayState = 1; } break; case 1: varImgFinalAlpha = (u8)(((f32) spAE / 255.0) * (f32) printer->varImgFinalAlpha); break; case 2: printer->varImageFadeTimer++; varImgFinalAlpha = printer->varImgFinalAlpha - printer->varImgAlphaFadeStep * printer->varImageFadeTimer; if (varImgFinalAlpha < 1) { printer->varImageScreenPos.x = 0; } break; } break; case 2: varImgFinalAlpha = (u8)(((f32) spAE / 255.0) * (f32) printer->varImgFinalAlpha); break; } if (varImgFinalAlpha > 0) { if (varImgHasBorder) { draw_box(0, WINDOW_STYLE_15, printer->varImageScreenPos.x - 7, printer->varImageScreenPos.y - 7, 0, msgVarImage->width + 15, msgVarImage->height + 14, varImgFinalAlpha, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NULL, 0, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL); } draw_ci_image_with_clipping(msgVarImage->raster, msgVarImage->width, msgVarImage->height, msgVarImage->format, msgVarImage->bitDepth, msgVarImage->palette, printer->varImageScreenPos.x, printer->varImageScreenPos.y, 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, varImgFinalAlpha); } } gDPPipeSync(gMainGfxPos++); D_80151338 = gMainGfxPos; } #endif void msg_reset_gfx_state(void) { gDPPipeSync(gMainGfxPos++); gSPDisplayList(gMainGfxPos++, D_8014C500); } #if VERSION_IQUE INCLUDE_ASM(s32, "msg", msg_draw_char); #else void msg_draw_char(MessagePrintState* printer, MessageDrawState* drawState, s32 charIndex, s32 palette, s32 posX, s32 posY) { MessageCharset* messageCharset = MsgCharsets[drawState->font]; s32 fontVariant = drawState->fontVariant; s32 clipUly = drawState->clipY[0]; s32 clipLry = drawState->clipY[1]; s32 clipUlx = drawState->clipX[0]; s32 clipLrx = drawState->clipX[1]; s32 rightPosX = posX + (s32)(drawState->charScale.x * messageCharset->texSize.x); s32 rightPosY = posY + (s32)(drawState->charScale.y * messageCharset->texSize.y); f32 clipOffset; s32 texOffsetX; s32 texOffsetY; s32 ulx, uly, lrx, lry; s32 dsdx, dtdy; if (posX >= clipLrx || posY >= clipLry || rightPosX <= clipUlx || rightPosY <= clipUly) { return; } if (posX < clipUlx) { clipOffset = abs(posX - clipUlx) / drawState->charScale.x; texOffsetX = (f32)((clipOffset + 0.5) * 32.0); ulx = clipUlx; } else { texOffsetX = 0; ulx = posX; } if (posY < clipUly) { if (!(printer->stateFlags & MSG_STATE_FLAG_400) || posY < 0) { clipOffset = abs(posY - clipUly) / drawState->charScale.y; texOffsetY = clipOffset * 32.0f; uly = clipUly; } else { texOffsetY = 0; uly = posY; } } else { texOffsetY = 0; uly = posY; } lrx = rightPosX; if (lrx >= clipLrx) { lrx = clipLrx; } lry = rightPosY; if (lry >= clipLry) { lry = clipLry; } dsdx = 1.0f / drawState->charScale.x * 1024.0f; dtdy = 1.0f / drawState->charScale.y * 1024.0f; if (drawState->printModeFlags & (MSG_PRINT_FLAG_10 | MSG_PRINT_FLAG_1)) { drawState->printModeFlags &= ~(MSG_PRINT_FLAG_10 | MSG_PRINT_FLAG_1); gDPLoadTLUT_pal16(gMainGfxPos++, 0, D_802F4560[palette]); } if (messageCharset->texSize.x >= 16 && messageCharset->texSize.x % 16 == 0) { gDPLoadTextureBlock_4b(gMainGfxPos++, messageCharset->rasters[fontVariant].raster + messageCharset->charRasterSize * charIndex, G_IM_FMT_CI, messageCharset->texSize.x, messageCharset->texSize.y, 0, G_TX_WRAP, G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); } else { gDPLoadTextureTile_4b(gMainGfxPos++, messageCharset->rasters[fontVariant].raster + messageCharset->charRasterSize * charIndex, G_IM_FMT_CI, messageCharset->texSize.x, messageCharset->texSize.y, 0, 0, messageCharset->texSize.x - 1, messageCharset->texSize.y - 1, 0, G_TX_WRAP, G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); } gSPTextureRectangle(gMainGfxPos++, ulx * 4, uly * 4, lrx * 4, lry * 4, G_TX_RENDERTILE, texOffsetX, texOffsetY, dsdx, dtdy); } #endif void msg_draw_prim_rect(u8 r, u8 g, u8 b, u8 a, u16 posX, u16 posY, u16 sizeX, u16 sizeY) { u16 lrX = posX + sizeX; u16 lrY = posY + sizeY; appendGfx_msg_prim_rect(r, g, b, a, posX, posY, lrX, lrY); } void appendGfx_msg_prim_rect(u8 r, u8 g, u8 b, u8 a, u16 ulX, u16 ulY, u16 lrX, u16 lrY) { gDPPipeSync(gMainGfxPos++); if (a == 255) { gDPSetCombineMode(gMainGfxPos++, PM_CC_08, PM_CC_08); } else { gDPSetRenderMode(gMainGfxPos++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetCombineMode(gMainGfxPos++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); } gDPSetPrimColor(gMainGfxPos++, 0, 0, r, g, b, a); gDPFillRectangle(gMainGfxPos++, ulX, ulY, lrX, lrY); gDPPipeSync(gMainGfxPos++); gDPSetRenderMode(gMainGfxPos++, G_RM_TEX_EDGE, G_RM_TEX_EDGE2); switch (msg_drawState->unk_29) { case 0: gDPSetCombineMode(gMainGfxPos++, G_CC_DECALRGBA, G_CC_DECALRGBA); break; case 1: gDPSetCombineMode(gMainGfxPos++, G_CC_MODULATEIDECALA_PRIM, G_CC_MODULATEIDECALA_PRIM); break; default: gDPSetCombineMode(gMainGfxPos++, G_CC_DECALRGBA, G_CC_DECALRGBA); break; } } void msg_draw_speech_bubble( MessagePrintState* printer, s16 posX, s16 posY, s16 straightWidth, s16 curveWidth, s16 height, f32 scaleX, f32 scaleY, u8 opacity, s32 arg9) { Matrix4f sp20, sp60; s16 temp_v0; s16 temp_v0_2; s32 negHeight; if (opacity == 255 && scaleX == 1.0 && scaleY == 1.0) { msg_draw_prim_rect(32, 128, 240, 0, posX - 1, posY + 1, curveWidth + (straightWidth + curveWidth) + 2, height - 2); } negHeight = -height; gMsgSpeechBoxLQuad[0].v.ob[0] = 1; gMsgSpeechBoxLQuad[2].v.ob[0] = 1; gMsgSpeechBoxLQuad[1].v.ob[0] = curveWidth; gMsgSpeechBoxLQuad[3].v.ob[0] = curveWidth; gMsgSpeechBoxLQuad[2].v.ob[1] = negHeight; gMsgSpeechBoxLQuad[3].v.ob[1] = negHeight; temp_v0 = curveWidth + straightWidth; gMsgSpeechBoxMQuad[0].v.ob[0] = curveWidth; gMsgSpeechBoxMQuad[2].v.ob[0] = curveWidth; gMsgSpeechBoxMQuad[1].v.ob[0] = temp_v0; gMsgSpeechBoxMQuad[3].v.ob[0] = temp_v0; gMsgSpeechBoxMQuad[2].v.ob[1] = negHeight; gMsgSpeechBoxMQuad[3].v.ob[1] = negHeight; temp_v0_2 = curveWidth + temp_v0; gMsgSpeechBoxRQuad[0].v.ob[0] = temp_v0; gMsgSpeechBoxRQuad[2].v.ob[0] = temp_v0; gMsgSpeechBoxRQuad[1].v.ob[0] = temp_v0_2; gMsgSpeechBoxRQuad[3].v.ob[0] = temp_v0_2; gMsgSpeechBoxRQuad[2].v.ob[1] = negHeight; gMsgSpeechBoxRQuad[3].v.ob[1] = negHeight; guTranslateF(sp20, posX, -posY, 0.0f); if (scaleX != 1.0 || scaleY != 1.0) { guScaleF(sp60, scaleX, scaleY, 1.0f); guMtxCatF(sp60, sp20, sp20); } guMtxF2L(sp20, &gDisplayContext->matrixStack[gMatrixListPos]); gSPMatrix(gMainGfxPos++, VIRTUAL_TO_PHYSICAL(&gDisplayContext->matrixStack[gMatrixListPos++]), G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gDPPipeSync(gMainGfxPos++); gDPSetCycleType(gMainGfxPos++, G_CYC_1CYCLE); gSPClearGeometryMode(gMainGfxPos++, G_CULL_BOTH | G_LIGHTING); gSPSetGeometryMode(gMainGfxPos++, G_SHADE | G_SHADING_SMOOTH); gDPSetColorDither(gMainGfxPos++, G_CD_DISABLE); gSPTexture(gMainGfxPos++, -1, -1, 0, G_TX_RENDERTILE, G_ON); gDPSetTexturePersp(gMainGfxPos++, G_TP_PERSP); if (printer->maxLinesPerPage == 3) { gDPSetTextureFilter(gMainGfxPos++, G_TF_POINT); } else { gDPSetTextureFilter(gMainGfxPos++, G_TF_BILERP); } if (opacity >= 255) { gDPSetRenderMode(gMainGfxPos++, AA_EN | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM), AA_EN | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)); gDPSetCombineMode(gMainGfxPos++, G_CC_DECALRGBA, G_CC_DECALRGBA); } else { gDPSetRenderMode(gMainGfxPos++, IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA), IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); gDPSetCombineMode(gMainGfxPos++, PM_CC_02, PM_CC_02); gDPSetPrimColor(gMainGfxPos++, 0, 0, 32, 32, 32, opacity); } gDPSetTextureLUT(gMainGfxPos++, G_TT_RGBA16); gDPSetTextureImage(gMainGfxPos++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, ui_msg_palettes[msg_drawState->framePalette]); gDPTileSync(gMainGfxPos++); gDPSetTile(gMainGfxPos++, G_IM_FMT_RGBA, G_IM_SIZ_4b, 0, 0x0100, G_TX_LOADTILE, 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); gDPLoadSync(gMainGfxPos++); gDPLoadTLUTCmd(gMainGfxPos++, G_TX_LOADTILE, 15); gDPPipeSync(gMainGfxPos++); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_bubble_left_png, G_IM_FMT_CI, 32, 0, 0, 0, 31, 63, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 5, 6, G_TX_NOLOD, G_TX_NOLOD); gSPVertex(gMainGfxPos++, gMsgSpeechBoxLQuad, 4, 0); gSP2Triangles(gMainGfxPos++, 0, 2, 1, 0, 1, 2, 3, 0); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_bubble_mid_png, G_IM_FMT_CI, 8, 0, 0, 0, 7, 63, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 3, 6, G_TX_NOLOD, G_TX_NOLOD); gSPVertex(gMainGfxPos++, gMsgSpeechBoxMQuad, 4, 0); gSP2Triangles(gMainGfxPos++, 0, 2, 1, 0, 1, 2, 3, 0); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_bubble_right_png, G_IM_FMT_CI, 32, 0, 0, 0, 31, 63, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 5, 6, G_TX_NOLOD, G_TX_NOLOD); gSPVertex(gMainGfxPos++, gMsgSpeechBoxRQuad, 4, 0); gSP2Triangles(gMainGfxPos++, 0, 2, 1, 0, 1, 2, 3, 0); gDPPipeSync(gMainGfxPos++); } void msg_draw_speech_arrow(MessagePrintState* printer) { s16 targetX, targetY; f32 windowXpart; s32 arrowLength; Vtx* quad; s32 angle; f32 cosAngle, sinAngle; Matrix4f sp10; s16 x1, x2, x3, x4; s32 y1, y2; u8 pointRightSide = FALSE; s16 windowX = printer->windowOffsetPos.x + printer->windowBasePos.x; s16 windowY = printer->windowOffsetPos.y + printer->windowBasePos.y; if (printer->openStartPos.x == 0) { return; } if (printer->style == MSG_STYLE_RIGHT || printer->style == MSG_STYLE_LEFT || printer->style == MSG_STYLE_CENTER || printer->maxLinesPerPage == 3) { targetY = windowY + printer->windowSize.y - 4; } else { targetY = windowY + printer->windowSize.y - 3; } if (printer->style == MSG_STYLE_LEFT) { pointRightSide = FALSE; } else if (printer->style == MSG_STYLE_CENTER || printer->openStartPos.x >= 160) { pointRightSide = TRUE; } if (pointRightSide) { targetX = windowX + (f32)printer->windowSize.x * 0.7; if (printer->openStartPos.x < targetX) { for (windowXpart = 0.7f; windowXpart >= 0.67; windowXpart -= 0.005) { targetX = windowX + printer->windowSize.x * windowXpart; angle = atan2(printer->openStartPos.x, printer->openStartPos.y, targetX, targetY); if (abs(angle) < 45) { break; } } } } else { targetX = windowX + (f32)printer->windowSize.x * 0.3; if (printer->openStartPos.x > targetX) { for (windowXpart = 0.3f; windowXpart <= 0.38; windowXpart += 0.005) { targetX = windowX + printer->windowSize.x * windowXpart; angle = atan2(printer->openStartPos.x, printer->openStartPos.y, targetX, targetY); if (abs(angle) < 45) { break; } } } } x1 = targetX - 9; x2 = targetX + 9; x3 = targetX; arrowLength = dist2D(printer->initOpenPos.x, printer->initOpenPos.y, targetX, targetY); if (arrowLength < 10) { return; } if (arrowLength > 25) { arrowLength = 25; } // alternate quads between frames if (gCurrentDisplayContextIndex != 0) { quad = gMsgArrowQuad1; } else { quad = gMsgArrowQuad2; } angle = atan2(targetX, targetY, printer->initOpenPos.x, printer->initOpenPos.y); angle -= 180; if (abs(angle) >= 75) { return; } cosAngle = cosine(angle); sinAngle = cosine(angle + 90); x3 = x3 - arrowLength * cosAngle; x4 = x3 + 1; y1 = -targetY; y2 = -(s16)(targetY + arrowLength * sinAngle); quad[0].v.ob[0] = x1; quad[0].v.ob[1] = y1; quad[1].v.ob[0] = x2; quad[1].v.ob[1] = y1; quad[2].v.ob[0] = x3; quad[2].v.ob[1] = y2; quad[3].v.ob[0] = x4; quad[3].v.ob[1] = y2; gDPPipeSync(gMainGfxPos++); gDPSetRenderMode(gMainGfxPos++, G_RM_OPA_SURF, G_RM_OPA_SURF2); gDPSetCombineMode(gMainGfxPos++, PM_CC_0F, PM_CC_0F); gDPSetTextureFilter(gMainGfxPos++, G_TF_BILERP); gDPSetPrimColor(gMainGfxPos++, 0, 0, 32, 32, 32, 255); gDPLoadTextureTile_4b(gMainGfxPos++, ui_msg_arrow_png, G_IM_FMT_CI, 16, 0, 0, 0, 15, 15, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, 4, G_TX_NOLOD, G_TX_NOLOD); guTranslateF(sp10, 0.0f, 0.0f, 0.0f); guMtxF2L(sp10, &gDisplayContext->matrixStack[gMatrixListPos]); gSPMatrix(gMainGfxPos++, VIRTUAL_TO_PHYSICAL(&gDisplayContext->matrixStack[gMatrixListPos++]), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPVertex(gMainGfxPos++, quad, 4, 0); gSP2Triangles(gMainGfxPos++, 0, 2, 1, 0, 1, 2, 3, 0); } void msg_draw_frame(s32 posX, s32 posY, s32 sizeX, s32 sizeY, s32 style, s32 palette, s32 fading, s32 bgAlpha, s32 frameAlpha) { s32 i; s32 frameType; s32 textures[16]; s32 r, g, b; Rect quads[16]; if (sizeX < 16 || sizeY < 16) { return; } if (fading != 0 && bgAlpha == 0 && frameAlpha == 0) { return; } gDPPipeSync(gMainGfxPos++); gDPSetCycleType(gMainGfxPos++, G_CYC_1CYCLE); gDPSetTexturePersp(gMainGfxPos++, G_TP_NONE); gDPSetTextureLOD(gMainGfxPos++, G_TL_TILE); gDPSetTextureLUT(gMainGfxPos++, G_TT_NONE); gDPSetColorDither(gMainGfxPos++, G_CD_DISABLE); gDPSetAlphaDither(gMainGfxPos++, G_AD_DISABLE); gDPSetTextureFilter(gMainGfxPos++, G_TF_POINT); if (fading == 0 || bgAlpha != 0) { do {} while (0); switch (style) { case MSG_STYLE_CHOICE: r = ((((u16*)(ui_msg_palettes[0]))[4] >> 11) & 0x1F) * 8; g = ((((u16*)(ui_msg_palettes[0]))[4] >> 6) & 0x1F) * 8; b = ((((u16*)(ui_msg_palettes[0]))[4] >> 1) & 0x1F) * 8; gDPPipeSync(gMainGfxPos++); if (fading != 0 && bgAlpha < 255) { gDPSetRenderMode(gMainGfxPos++, IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA), IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); } else { gDPSetRenderMode(gMainGfxPos++, G_RM_OPA_SURF, G_RM_OPA_SURF2); } gDPSetCombineMode(gMainGfxPos++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); gDPSetPrimColor(gMainGfxPos++, 0, 0, r, g, b, bgAlpha); if (posX + sizeX - 8 > 0) { gDPScisFillRectangle(gMainGfxPos++, posX + 8, posY + 8, posX + sizeX - 8, posY + sizeY - 8); } break; case MSG_STYLE_INSPECT: gDPPipeSync(gMainGfxPos++); gDPSetTextureFilter(gMainGfxPos++, G_TF_AVERAGE); gDPSetRenderMode(gMainGfxPos++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetCombineMode(gMainGfxPos++, PM_CC_10, PM_CC_10); if (fading == 0 || bgAlpha == 255) { gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, 216); } else { if (bgAlpha > 216) { bgAlpha = 216; } gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, bgAlpha); } gDPLoadTextureBlock_4b(gMainGfxPos++, ui_msg_background_png, G_IM_FMT_I, 64, 64, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 6, 6, G_TX_NOLOD, G_TX_NOLOD); if (style == MSG_STYLE_INSPECT) { gSPScisTextureRectangle(gMainGfxPos++, (posX + 3) * 4, (posY + 3) * 4, (posX + sizeX - 3) * 4, (posY + sizeY - 3) * 4, G_TX_RENDERTILE, gMsgBGScrollAmtX, gMsgBGScrollAmtY, 0x400, 0x400); } else { gSPScisTextureRectangle(gMainGfxPos++, (posX + 5) * 4, (posY + 5) * 4, (posX + sizeX - 5) * 4, (posY + sizeY - 5) * 4, G_TX_RENDERTILE, gMsgBGScrollAmtX, gMsgBGScrollAmtY, 0x400, 0x400); } break; } } if (sizeX >= 32) { quads[2].ulx = (posX + 16) * 4; quads[2].uly = posY * 4; quads[2].lrx = (posX + sizeX - 16) * 4; quads[2].lry = (posY + 8) * 4; quads[13].ulx = (posX + 16) * 4; quads[13].uly = (posY + sizeY - 8) * 4; quads[13].lrx = (posX + sizeX - 16) * 4; quads[13].lry = (posY + sizeY) * 4; } else if (sizeX > 16 && sizeX < 24) { quads[2].ulx = (posX + 8) * 4; quads[2].uly = posY * 4; quads[2].lrx = (posX + sizeX - 8) * 4; quads[2].lry = (posY + 8) * 4; quads[13].ulx = (posX + 8) * 4; quads[13].uly = (posY + sizeY - 8) * 4; quads[13].lrx = (posX + sizeX - 8) * 4; quads[13].lry = (posY + sizeY) * 4; } else { quads[2].ulx = 10000; quads[13].ulx = 10000; } if (sizeY >= 32) { quads[7].ulx = posX * 4; quads[7].uly = (posY + 16) * 4; quads[7].lrx = (posX + 8) * 4; quads[7].lry = (posY + sizeY - 16) * 4; quads[8].ulx = (posX + sizeX - 8) * 4; quads[8].uly = (posY + 16) * 4; quads[8].lrx = (posX + sizeX) * 4; quads[8].lry = (posY + sizeY - 16) * 4; } else if (sizeY > 16 && sizeY < 24) { quads[7].ulx = posX * 4; quads[7].uly = (posY + 8) * 4; quads[7].lrx = (posX + 8) * 4; quads[7].lry = (posY + sizeY - 8) * 4; quads[8].ulx = (posX + sizeX - 8) * 4; quads[8].uly = (posY + 8) * 4; quads[8].lrx = (posX + sizeX) * 4; quads[8].lry = (posY + sizeY - 8) * 4; } else { quads[7].ulx = 10000; quads[8].ulx = 10000; } if (sizeX >= 24) { quads[1].ulx = (posX + 8) * 4; quads[1].uly = posY * 4; quads[1].lrx = (posX + 16) * 4; quads[1].lry = (posY + 8) * 4; quads[3].ulx = (posX + sizeX - 16) * 4; quads[3].uly = posY * 4; quads[3].lrx = (posX + sizeX - 8) * 4; quads[3].lry = (posY + 8) * 4; quads[12].ulx = (posX + 8) * 4; quads[12].uly = (posY + sizeY - 8) * 4; quads[12].lrx = (posX + 16) * 4; quads[12].lry = (posY + sizeY) * 4; quads[14].ulx = (posX + sizeX - 16) * 4; quads[14].uly = (posY + sizeY - 8) * 4; quads[14].lrx = (posX + sizeX - 8) * 4; quads[14].lry = (posY + sizeY) * 4; } else { quads[1].ulx = 10000; quads[3].ulx = 10000; quads[12].ulx = 10000; quads[14].ulx = 10000; } if (sizeY >= 24) { quads[5].ulx = posX * 4; quads[5].uly = (posY + 8) * 4; quads[5].lrx = (posX + 8) * 4; quads[5].lry = (posY + 16) * 4; quads[6].ulx = (posX + sizeX - 8) * 4; quads[6].uly = (posY + 8) * 4; quads[6].lrx = (posX + sizeX) * 4; quads[6].lry = (posY + 16) * 4; quads[9].ulx = posX * 4; quads[9].uly = (posY + sizeY - 16) * 4; quads[9].lrx = (posX + 8) * 4; quads[9].lry = (posY + sizeY - 8) * 4; quads[10].ulx = (posX + sizeX - 8) * 4; quads[10].uly = (posY + sizeY - 16) * 4; quads[10].lrx = (posX + sizeX) * 4; quads[10].lry = (posY + sizeY - 8) * 4; } else { quads[5].ulx = 10000; quads[6].ulx = 10000; quads[9].ulx = 10000; quads[10].ulx = 10000; } quads[0].ulx = posX * 4; quads[0].uly = posY * 4; quads[0].lrx = (posX + 8) * 4; quads[0].lry = (posY + 8) * 4; quads[4].ulx = (posX + sizeX - 8) * 4; quads[4].uly = posY * 4; quads[4].lrx = (posX + sizeX) * 4; quads[4].lry = (posY + 8) * 4; quads[11].ulx = posX * 4; quads[11].uly = (posY + sizeY - 8) * 4; quads[11].lrx = (posX + 8) * 4; quads[11].lry = (posY + sizeY) * 4; quads[15].ulx = (posX + sizeX - 8) * 4; quads[15].uly = (posY + sizeY - 8) * 4; quads[15].lrx = (posX + sizeX) * 4; quads[15].lry = (posY + sizeY) * 4; switch (style) { case MSG_STYLE_CHOICE: frameType = 0; break; case MSG_STYLE_INSPECT: frameType = 1; break; default: frameType = 0; break; } for (i = 0; i < ARRAY_COUNT(textures); i++) { textures[i] = gMessageBoxFrameParts[frameType][i]; } if (fading == 0) { frameAlpha = 255; } gDPPipeSync(gMainGfxPos++); gDPSetRenderMode(gMainGfxPos++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetCombineMode(gMainGfxPos++, PM_CC_02, PM_CC_02); gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, frameAlpha); gDPSetTextureLUT(gMainGfxPos++, G_TT_RGBA16); gDPLoadTLUT_pal16(gMainGfxPos++, 0, ui_msg_palettes[palette]); for (i = 0; i < ARRAY_COUNT(textures); i++) { if (textures[i] != NULL && quads[i].ulx < 10000) { gDPLoadTextureTile_4b(gMainGfxPos++, textures[i], G_IM_FMT_CI, 8, 8, 0, 0, 7, 7, 0, G_TX_WRAP, G_TX_WRAP, 3, 3, G_TX_NOLOD, G_TX_NOLOD); gSPScisTextureRectangle(gMainGfxPos++, quads[i].ulx, quads[i].uly, quads[i].lrx, quads[i].lry, G_TX_RENDERTILE, 0, 0, 0x400, 0x400); } } gDPPipeSync(gMainGfxPos++); gDPSetTextureLUT(gMainGfxPos++, G_TT_NONE); } void msg_get_glyph(s32 font, s32 variation, s32 charIndex, s32 palette, MesasgeFontGlyphData* out) { out->raster = &MsgCharsets[font]->rasters[variation].raster[(u16)MsgCharsets[font]->charRasterSize * charIndex]; out->palette = D_802F4560[palette]; out->texSize.x = MsgCharsets[font]->texSize.x; out->texSize.y = MsgCharsets[font]->texSize.y; out->charWidth = msg_get_draw_char_width(charIndex, font, variation, 1.0f, 0, 0); out->charHeight = out->texSize.y; }