diff --git a/soh/assets/custom/fonts/NotoSansJP-Regular.ttf b/soh/assets/custom/fonts/NotoSansJP-Regular.ttf new file mode 100644 index 000000000..7c15c5959 Binary files /dev/null and b/soh/assets/custom/fonts/NotoSansJP-Regular.ttf differ diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 5f9073055..180b045aa 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -4,6 +4,7 @@ #include "soh/OTRGlobals.h" #include "soh/SohGui/UIWidgets.hpp" #include "soh/SohGui/SohGui.hpp" +#include "soh/SaveManager.h" #include #include @@ -27,6 +28,11 @@ extern PlayState* gPlayState; #include "textures/parameter_static/parameter_static.h" } +#include "message_data_static.h" +extern "C" MessageTableEntry* sGerMessageEntryTablePtr; +extern "C" MessageTableEntry* sFraMessageEntryTablePtr; +extern "C" MessageTableEntry* sJpnMessageEntryTablePtr; + // Maps entries in the GS flag array to the area name it represents std::vector gsMapping = { "Deku Tree", @@ -106,6 +112,48 @@ char z2ASCII(int code) { return char(ret); } +std::string decodeNTSCPlayerNameChar(int code) { + const std::string charmap[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", // 10 + "あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ", // 20 + "さ", "し", "す", "せ", "そ", "た", "ち", "つ", "て", "と", // 30 + "な", "に", "ぬ", "ね", "の", "は", "ひ", "ふ", "へ", "ほ", // 40 + "ま", "み", "む", "め", "も", "や", "ゆ", "よ", "ら", "り", // 50 + "る", "れ", "ろ", "わ", "を", "ん", "ぁ", "ぃ", "ぅ", "ぇ", // 60 + "ぉ", "っ", "ゃ", "ゅ", "ょ", "が", "ぎ", "ぐ", "げ", "ご", // 70 + "ざ", "じ", "ず", "ぜ", "ぞ", "だ", "ぢ", "づ", "で", "ど", // 80 + "ば", "び", "ぶ", "べ", "ぼ", "ぱ", "ぴ", "ぷ", "ぺ", "ぽ", // 90 + "ア", "イ", "ウ", "エ", "オ", "カ", "キ", "ク", "ケ", "コ", // 100 + "サ", "シ", "ス", "セ", "ソ", "タ", "チ", "ツ", "テ", "ト", // 110 + "ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "ヒ", "フ", "ヘ", "ホ", // 120 + "マ", "ミ", "ム", "メ", "モ", "ヤ", "ユ", "ヨ", "ラ", "リ", // 130 + "ル", "レ", "ロ", "ワ", "ヲ", "ン", "ァ", "ィ", "ゥ", "ェ", // 140 + "ォ", "ッ", "ャ", "ュ", "ョ", "ガ", "ギ", "グ", "ゲ", "ゴ", // 150 + "ザ", "ジ", "ズ", "ゼ", "ゾ", "ダ", "ヂ", "ヅ", "デ", "ド", // 160 + "バ", "ビ", "ブ", "ベ", "ボ", "パ", "ピ", "プ", "ペ", "ポ", // 170 + "ヴ", + }; + std::string ret; + + if (code < 171) { // Digits and Japanese + ret = charmap[code]; + } else if (code >= 171 && code < 197) { // Uppercase letters + ret.assign(1, (char)(code - 171 + 65)); + } else if (code >= 197 && code < 223) { // Lowercase letters + ret.assign(1, (char)(code - 197 + 97)); + } else if (code == 223) { // Space + ret = " "; + } else if (code == 228) { // - + ret = "-"; + } else if (code == 234) { // . + ret = "."; + } else { + ret = "?"; + } + + return ret; +} + enum MagicLevel { MAGIC_LEVEL_NONE, MAGIC_LEVEL_SINGLE, MAGIC_LEVEL_DOUBLE }; std::unordered_map magicLevelMap = { @@ -144,6 +192,17 @@ std::unordered_map fileNumMap = { { 2, "File 3" }, }; +std::unordered_map filenameLanguageMap = { + { NAME_LANGUAGE_PAL, "PAL" }, + { NAME_LANGUAGE_NTSC_JPN, "NTSC JPN" }, + { NAME_LANGUAGE_NTSC_ENG, "NTSC ENG" }, +}; + +std::unordered_map filenameLanguageMapNTSCOnly = { + { NAME_LANGUAGE_NTSC_JPN, "NTSC JPN" }, + { NAME_LANGUAGE_NTSC_ENG, "NTSC ENG" }, +}; + void DrawInfoTab() { if (gSaveContext.gameMode == GAMEMODE_TITLE_SCREEN) { ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Title Screen"); @@ -160,15 +219,30 @@ void DrawInfoTab() { // TODO Needs a better method for name changing but for now this will work. std::string name; ImU16 one = 1; - for (int i = 0; i < 8; i++) { - char letter = z2ASCII(gSaveContext.playerName[i]); - name += letter; + + if (gSaveContext.ship.filenameLanguage == NAME_LANGUAGE_PAL) { + for (int i = 0; i < 8; i++) { + char letter = z2ASCII(gSaveContext.playerName[i]); + name += letter; + } + name += '\0'; + } else { + for (int i = 0; i < 8; i++) { + name += decodeNTSCPlayerNameChar(gSaveContext.playerName[i]); + } + name += '\0'; } - name += '\0'; ImGui::PushItemWidth(ImGui::GetFontSize() * 6); - ImGui::Text("Name: %s", name.c_str()); + if (gSaveContext.ship.filenameLanguage == NAME_LANGUAGE_PAL) { + ImGui::Text("Name: %s", name.c_str()); + } else { + ImGui::PushFont(OTRGlobals::Instance->fontJapanese); + ImGui::Text("Name: %s", name.c_str()); + ImGui::PopFont(); + } + Tooltip("Player Name"); std::string nameID; for (int i = 0; i < 8; i++) { @@ -181,6 +255,25 @@ void DrawInfoTab() { PopStyleInput(); } + // Filename encoding + const bool hasPAL = (sGerMessageEntryTablePtr != nullptr) && (sFraMessageEntryTablePtr != nullptr); + const bool hasNTSC = (sJpnMessageEntryTablePtr != nullptr); + if (hasPAL && hasNTSC) { + // Full + Combobox("Player Name Language", &gSaveContext.ship.filenameLanguage, filenameLanguageMap, + comboboxOptionsBase.Tooltip("Encoding used for Player Name")); + } else if (hasNTSC && (gSaveContext.ship.filenameLanguage != NAME_LANGUAGE_PAL)) { + // NTSC only + Combobox("Player Name Language", &gSaveContext.ship.filenameLanguage, filenameLanguageMapNTSCOnly, + comboboxOptionsBase.Tooltip("Encoding used for Player Name")); + } else { + // PAL only (read only) + ImGui::BeginDisabled(); + Combobox("Player Name Language", &gSaveContext.ship.filenameLanguage, filenameLanguageMap, + comboboxOptionsBase.Tooltip("Encoding used for Player Name")); + ImGui::EndDisabled(); + } + // Use an intermediary to keep the health from updating (and potentially killing the player) // until it is done being edited int16_t healthIntermediary = gSaveContext.healthCapacity; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 9637c0ff1..d05569e4f 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -435,13 +435,14 @@ void OTRGlobals::Initialize() { previousImGuiScaleIndex = -1; previousImGuiScale = defaultImGuiScale; - fontMonoSmall = CreateFontWithSize(14.0f, "fonts/Inconsolata-Regular.ttf"); - fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf"); - fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf"); - fontMonoLargest = CreateFontWithSize(24.0f, "fonts/Inconsolata-Regular.ttf"); - fontStandard = CreateFontWithSize(16.0f, "fonts/Montserrat-Regular.ttf"); - fontStandardLarger = CreateFontWithSize(20.0f, "fonts/Montserrat-Regular.ttf"); - fontStandardLargest = CreateFontWithSize(24.0f, "fonts/Montserrat-Regular.ttf"); + fontMonoSmall = CreateFontWithSize(14.0f, "fonts/Inconsolata-Regular.ttf", false); + fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf", false); + fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf", false); + fontMonoLargest = CreateFontWithSize(24.0f, "fonts/Inconsolata-Regular.ttf", false); + fontStandard = CreateFontWithSize(16.0f, "fonts/Montserrat-Regular.ttf", false); + fontStandardLarger = CreateFontWithSize(20.0f, "fonts/Montserrat-Regular.ttf", false); + fontStandardLargest = CreateFontWithSize(24.0f, "fonts/Montserrat-Regular.ttf", false); + fontJapanese = CreateFontWithSize(24.0f, "fonts/NotoSansJP-Regular.ttf", true); ImGui::GetIO().FontDefault = fontStandardLarger; ScaleImGui(); @@ -1687,7 +1688,7 @@ extern "C" SoundFontSample* ReadCustomSample(const char* path) { */ } -ImFont* OTRGlobals::CreateFontWithSize(float size, std::string fontPath) { +ImFont* OTRGlobals::CreateFontWithSize(float size, std::string fontPath, bool isJapaneseFont) { auto mImGuiIo = &ImGui::GetIO(); ImFont* font; if (fontPath == "") { @@ -1706,7 +1707,8 @@ ImFont* OTRGlobals::CreateFontWithSize(float size, std::string fontPath) { Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fontPath, false, initData)); ImFontConfig fontConf; fontConf.FontDataOwnedByAtlas = false; - font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontData->Data, fontData->DataSize, size, &fontConf); + const ImWchar* glyph_ranges = isJapaneseFont ? mImGuiIo->Fonts->GetGlyphRangesJapanese() : nullptr; + font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontData->Data, fontData->DataSize, size, &fontConf, glyph_ranges); } // FontAwesome fonts need to have their sizes reduced by 2.0f/3.0f in order to align correctly float iconFontSize = size * 2.0f / 3.0f; diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 42bb1a748..e6fbb4181 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -66,6 +66,7 @@ class OTRGlobals { ImFont* fontMono; ImFont* fontMonoLarger; ImFont* fontMonoLargest; + ImFont* fontJapanese; OTRGlobals(); ~OTRGlobals(); @@ -82,7 +83,7 @@ class OTRGlobals { bool hasMasterQuest; bool hasOriginal; ImFont* CreateDefaultFontWithSize(float size); - ImFont* CreateFontWithSize(float size, std::string fontPath); + ImFont* CreateFontWithSize(float size, std::string fontPath, bool isJapaneseFont); }; #endif