diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp index 00868a91d..d929b5ea3 100644 --- a/libultraship/libultraship/Window.cpp +++ b/libultraship/libultraship/Window.cpp @@ -279,21 +279,22 @@ namespace Ship { WmApi->set_keyboard_callbacks(Window::KeyDown, Window::KeyUp, Window::AllKeysUp); } - void task1(const char textToRead[]) + void task1(const std::string & textToRead) { const int w = 512; int* wp = const_cast (&w); - *wp = strlen(textToRead); + *wp = strlen(textToRead.c_str()); wchar_t wtext[w]; - mbstowcs(wtext, textToRead, strlen(textToRead) + 1); + mbstowcs(wtext, textToRead.c_str(), strlen(textToRead.c_str()) + 1); pVoice->Speak(wtext, SPF_IS_XML | SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL); } void Window::ReadText(const char textToRead[]) { - std::thread t1(task1, textToRead); + std::string textCopy(textToRead); + std::thread t1(task1, textCopy); t1.detach(); } diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index f932d3406..8524d6d60 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -118,6 +118,11 @@ s16 sOcarinaNoteCEnvR; s16 sOcarinaNoteCEnvB; s16 sOcarinaNoteCEnvG; +static u8 ttsHasNewMessage; +static u8 ttsHasMessage; +static s8 ttsCurrentChoice; +static u8 ttsMessageBuf[256]; + void Message_ResetOcarinaNoteState(void) { R_OCARINA_NOTES_YPOS(0) = 189; R_OCARINA_NOTES_YPOS(1) = 184; @@ -3004,6 +3009,104 @@ void Message_Draw(GlobalContext* globalCtx) { CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_message_PAL.c", 3582); } +void Message_TTS_Decode(u8* srcBuf, u8* dstBuf, u32 srcOffset, u32 size) { + u32 dstIdx = 0; + + for (u32 i = 0; i < size; i++) { + u8 currChar = srcBuf[i + srcOffset]; + + if (currChar < ' ') { + switch (currChar) { + case CTRL_NEWLINE: + dstBuf[dstIdx++] = ' '; + break; + case MESSAGE_COLOR: + case MESSAGE_SHIFT: + case MESSAGE_TEXT_SPEED: + case MESSAGE_BOX_BREAK_DELAYED: + case MESSAGE_FADE: + case MESSAGE_ITEM_ICON: + i++; + break; + case MESSAGE_FADE2: + case MESSAGE_SFX: + i += 2; + break; + default: + break; + } + } else { + dstBuf[dstIdx++] = currChar; + } + } + + dstBuf[dstIdx] = 0; +} + +void Message_TTS_Update(GlobalContext* globalCtx) { + MessageContext* msgCtx = &globalCtx->msgCtx; + + if (msgCtx->msgMode == MSGMODE_TEXT_NEXT_MSG || msgCtx->msgMode == MSGMODE_DISPLAY_SONG_PLAYED_TEXT_BEGIN || + (msgCtx->msgMode == MSGMODE_TEXT_CONTINUING && msgCtx->stateTimer == 1)) { + ttsHasNewMessage = 1; + } else if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING || msgCtx->msgMode == MSGMODE_OCARINA_STARTING || + msgCtx->msgMode == MSGMODE_OCARINA_PLAYING || msgCtx->msgMode == MSGMODE_TEXT_AWAIT_NEXT || + msgCtx->msgMode == MSGMODE_TEXT_DONE || msgCtx->msgMode == MSGMODE_DISPLAY_SONG_PLAYED_TEXT || + msgCtx->msgMode == MSGMODE_TEXT_DELAYED_BREAK) { + if (ttsHasNewMessage == 1) { + ttsHasNewMessage = 0; + ttsHasMessage = 1; + ttsCurrentChoice = 0; + + u32 size = msgCtx->decodedTextLen; + Message_TTS_Decode(msgCtx->msgBufDecoded, ttsMessageBuf, 0, size); + OTRTextToSpeechCallback(ttsMessageBuf); + } else if (msgCtx->msgMode == MSGMODE_TEXT_DONE && msgCtx->choiceNum > 0 && + msgCtx->choiceIndex != ttsCurrentChoice) { + ttsCurrentChoice = msgCtx->choiceIndex; + u32 startOffset = 0; + u32 endOffset = 0; + while (startOffset < msgCtx->decodedTextLen) { + if (msgCtx->msgBufDecoded[startOffset] == MESSAGE_TWO_CHOICE || + msgCtx->msgBufDecoded[startOffset] == MESSAGE_THREE_CHOICE) { + startOffset++; + break; + } + startOffset++; + } + if (startOffset < msgCtx->decodedTextLen) { + u8 i = msgCtx->choiceIndex; + while (i-- > 0) { + while (startOffset < msgCtx->decodedTextLen) { + if (msgCtx->msgBufDecoded[startOffset] == MESSAGE_NEWLINE) { + startOffset++; + break; + } + startOffset++; + } + } + endOffset = startOffset; + while (endOffset < msgCtx->decodedTextLen) { + if (msgCtx->msgBufDecoded[endOffset] == MESSAGE_NEWLINE) { + break; + } + endOffset++; + } + + if (startOffset < msgCtx->decodedTextLen && startOffset != endOffset) { + u32 size = endOffset - startOffset; + Message_TTS_Decode(msgCtx->msgBufDecoded, ttsMessageBuf, startOffset, size); + OTRTextToSpeechCallback(ttsMessageBuf); + } + } + } + } else if (ttsHasMessage == 1) { + ttsHasMessage = 0; + ttsHasNewMessage = 0; + OTRTextToSpeechCallback(""); // cancel current speech + } +} + void Message_Update(GlobalContext* globalCtx) { static s16 sTextboxXPositions[] = { 34, 34, 34, 34, 34, 34, @@ -3067,6 +3170,10 @@ void Message_Update(GlobalContext* globalCtx) { return; } + if (CVar_GetS32("gMessageTTS", 0) != 0) { + Message_TTS_Update(globalCtx); + } + bool isB_Held = CVar_GetS32("gFastText", 0) != 0 ? CHECK_BTN_ALL(input->cur.button, BTN_B) && !sTextboxSkipped : CHECK_BTN_ALL(input->press.button, BTN_B);