[Scummvm-git-logs] scummvm master -> 03099dfa9e98cbedd12dbfc58b59259dbe5b9f21
athrxx
noreply at scummvm.org
Thu Mar 26 16:26:08 UTC 2026
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
f49d5ca984 KYRA: Add Korean fan translation support for Hand of Fate
03099dfa9e KYRA: Remove redundant KO_KOR lang overrides in HoF
Commit: f49d5ca984584ed6a88a87fe1ad5c2d8c8ccf433
https://github.com/scummvm/scummvm/commit/f49d5ca984584ed6a88a87fe1ad5c2d8c8ccf433
Author: Seokjun Kim (colus001 at me.com)
Date: 2026-03-26T17:26:00+01:00
Commit Message:
KYRA: Add Korean fan translation support for Hand of Fate
Changed paths:
A devtools/create_kyradat/resources/hof_dos_cd_korean.h
devtools/create_kyradat/games.cpp
devtools/create_kyradat/resources.cpp
dists/engine-data/kyra.dat
engines/kyra/detection_tables.h
engines/kyra/engine/kyra_hof.cpp
engines/kyra/engine/kyra_v2.cpp
engines/kyra/engine/scene_hof.cpp
engines/kyra/graphics/screen.cpp
engines/kyra/graphics/screen.h
engines/kyra/graphics/screen_hof.cpp
engines/kyra/gui/gui_hof.cpp
engines/kyra/resource/staticres.cpp
engines/kyra/sequence/sequences_hof.cpp
engines/kyra/text/text_hof.cpp
diff --git a/devtools/create_kyradat/games.cpp b/devtools/create_kyradat/games.cpp
index c5b09b6842b..52b7e4994e6 100644
--- a/devtools/create_kyradat/games.cpp
+++ b/devtools/create_kyradat/games.cpp
@@ -96,6 +96,7 @@ const Game kyra2Games[] = {
{ kKyra2, kPlatformDOS, kTalkieVersion, ES_ESP },
{ kKyra2, kPlatformDOS, kTalkieVersion, HE_ISR },
{ kKyra2, kPlatformDOS, kTalkieVersion, CS_CZE },
+ { kKyra2, kPlatformDOS, kTalkieVersion, KO_KOR },
{ kKyra2, kPlatformFMTowns, kNoSpecial, EN_ANY },
{ kKyra2, kPlatformFMTowns, kNoSpecial, JA_JPN },
diff --git a/devtools/create_kyradat/resources.cpp b/devtools/create_kyradat/resources.cpp
index b81fbd3b492..0659d41f6c1 100644
--- a/devtools/create_kyradat/resources.cpp
+++ b/devtools/create_kyradat/resources.cpp
@@ -98,6 +98,7 @@
#include "resources/hof_dos_cd_spanish.h"
#include "resources/hof_dos_cd_hebrew.h"
#include "resources/hof_dos_cd_czech.h"
+#include "resources/hof_dos_cd_korean.h"
#include "resources/hof_fmtowns.h"
#include "resources/hof_fmtowns_english.h"
@@ -1374,6 +1375,8 @@ static const ResourceProvider resourceProviders[] = {
{ k2SeqplayTlkFiles, kKyra2, kPlatformDOS, kTalkieVersion, ES_ESP, &k2SeqplayTlkFilesDOSCDSpanishProvider },
{ k2SeqplayStrings, kKyra2, kPlatformDOS, kTalkieVersion, CS_CZE, &k2SeqplayStringsDOSCDCzechProvider },
{ k2SeqplayTlkFiles, kKyra2, kPlatformDOS, kTalkieVersion, CS_CZE, &k2SeqplayTlkFilesDOSCDCzechProvider },
+ { k2SeqplayStrings, kKyra2, kPlatformDOS, kTalkieVersion, KO_KOR, &k2SeqplayStringsDOSCDKoreanProvider },
+ { k2SeqplayTlkFiles, kKyra2, kPlatformDOS, kTalkieVersion, KO_KOR, &k2SeqplayTlkFilesDOSCDKoreanProvider },
{ k2SeqplayPakFiles, kKyra2, kPlatformFMTowns, kNoSpecial, UNK_LANG, &k2SeqplayPakFilesFMTownsProvider },
{ k2SeqplayStrings, kKyra2, kPlatformFMTowns, kNoSpecial, EN_ANY, &k2SeqplayStringsFMTownsEnglishProvider },
{ k2SeqplaySfxFiles, kKyra2, kPlatformFMTowns, kNoSpecial, UNK_LANG, &k2SeqplaySfxFilesFMTownsProvider },
diff --git a/devtools/create_kyradat/resources/hof_dos_cd_korean.h b/devtools/create_kyradat/resources/hof_dos_cd_korean.h
new file mode 100644
index 00000000000..81fe3343ba1
--- /dev/null
+++ b/devtools/create_kyradat/resources/hof_dos_cd_korean.h
@@ -0,0 +1,127 @@
+static const char *const k2SeqplayStringsDOSCDKorean[104] = {
+ "\xC5\xB0\xB6\xF5\xB5\xF0\xBE\xC6\xB0\xA1 \xBB\xE7\xB6\xF3\xC1\xF6\xB0\xED \xC0\xD6\xB4\xD9!", // "í¤ëëìê° ì¬ë¼ì§ê³ ìë¤!"
+ "\xB9\xD9\xC0\xA7 \xC7\xCF\xB3\xAA\xC7\xCF\xB3\xAA...", // "ë°ì íëíë..."
+ "...\xB1\xD7\xB8\xAE\xB0\xED \xB3\xAA\xB9\xAB \xC7\xD1 \xB1\xD7\xB7\xE7 \xC7\xD1 \xB1\xD7\xB7\xE7.", // "...ê·¸ë¦¬ê³ ë무 í 그루 í 그루."
+ "\xC5\xB0\xB6\xF5\xB5\xF0\xBE\xC6\xB0\xA1 \xBC\xD2\xB8\xEA\xC7\xCF\xB0\xED \xC0\xD6\xB4\xD9!", // "í¤ëëìê° ì멸íê³ ìë¤!"
+ "\xBF\xD5\xB1\xC3 \xB8\xB6\xB9\xFD\xBB\xE7\xB5\xE9\xC0\xCC \xB4\xE7\xC8\xB2\xC7\xCF\xB0\xED \xC0\xD6\xB4\xD9.", // "ìê¶ ë§ë²ì¬ë¤ì´ ë¹í©íê³ ìë¤."
+ "\xB8\xF0\xB5\xE7 \xC2\xFC\xB0\xED\xB9\xAE\xC7\xE5\xC0\xBB \xB4\xD9 \xC3\xA3\xBE\xC6\xBA\xC3\xB4\xD9.", // "모ë ì°¸ê³ ë¬¸íì ë¤ ì°¾ìë´¤ë¤."
+ "\xB8\xB6\xB8\xA3\xC4\xDA\xBF\xCD \xB1\xD7\xC0\xC7 \xBB\xF5 \xBD\xC3\xC1\xBE\xB5\xB5 \xC8\xB8\xC0\xC7\xBF\xA1 \xC2\xFC\xBC\xAE\xC0\xCC \xC7\xE3\xB6\xF4\xB5\xC7\xBE\xFA\xB4\xD9.", // "ë§ë¥´ì½ì ê·¸ì ì ìì¢
ë íìì ì°¸ìì´ íë½ëìë¤."
+ "\xB4\xD9\xC7\xE0\xC8\xF7 \xBF\xEE\xB8\xED\xC0\xC7 \xBC\xD5\xC0\xBA \xC0\xCC\xB7\xB1 \xB9\xAE\xC1\xA6\xBF\xA1 \xB0\xE6\xC7\xE8\xC0\xCC \xC0\xD6\xBE\xFA\xB4\xD9.", // "ë¤íí ì´ëª
ì ìì ì´ë° 문ì ì ê²½íì´ ììë¤."
+ "\xB1\xD7\xB8\xAE\xB0\xED \xB8\xB6\xC4\xA7\xB3\xBB \xB0\xE8\xC8\xB9\xC0\xCC \xBD\xC2\xC0\xCE\xB5\xC7\xBE\xFA\xB4\xD9...", // "ê·¸ë¦¬ê³ ë§ì¹¨ë´ ê³íì´ ì¹ì¸ëìë¤..."
+ "...\xB8\xB6\xB9\xFD\xC0\xC7 \xB4\xE9\xB5\xB9\xC0\xBB...", // "...ë§ë²ì ë»ëì..."
+ "...\xBC\xBC\xBB\xF3\xC0\xC7 \xC1\xDF\xBD\xC9\xBF\xA1\xBC\xAD \xC3\xA3\xBE\xC6\xBF\xCD\xBE\xDF \xC7\xDF\xB4\xD9.", // "...ì¸ìì ì¤ì¬ìì ì°¾ììì¼ íë¤."
+ "\xC5\xB0\xB6\xF5\xB5\xF0\xBE\xC6 \xB8\xB6\xB9\xFD\xBB\xE7 \xC1\xDF \xB0\xA1\xC0\xE5 \xC0\xFE\xC0\xBA \xC0\xDC\xC6\xBC\xBE\xC6\xB0\xA1 \xB5\xB9\xC0\xBB \xC3\xA3\xB4\xC2 \xC0\xD3\xB9\xAB\xBF\xA1 \xBC\xB1\xC5\xC3\xB5\xC7\xBE\xFA\xB4\xD9.", // "í¤ëëì ë§ë²ì¬ ì¤ ê°ì¥ ì ì ìí°ìê° ëì ì°¾ë ì무ì ì íëìë¤."
+ "\xBF\xEE\xB8\xED\xC0\xC7 \xBC\xD5\xC0\xBB \xC7\xC3\xB7\xB9\xC0\xCC\xC7\xD8 \xC1\xD6\xBC\xC5\xBC\xAD \xB0\xA8\xBB\xE7\xC7\xD5\xB4\xCF\xB4\xD9.", // "ì´ëª
ì ìì íë ì´í´ 주ì
ì ê°ì¬í©ëë¤."
+ "\xC0\xCC \xC1\xA4\xB5\xB5 \xBA\xED\xB7\xE7\xBA\xA3\xB8\xAE\xB8\xE9 \xBC\xBC\xBB\xF3\xC0\xC7 \xC1\xDF\xBD\xC9\xC0\xB8\xB7\xCE \xB0\xA1\xB4\xC2 \xC6\xF7\xC5\xD0\xC0\xBB \xBF\xAD \xBC\xF6 \xC0\xD6\xC0\xBB \xB0\xC5\xBE\xDF.", // "ì´ ì ë ë¸ë£¨ë² 리면 ì¸ìì ì¤ì¬ì¼ë¡ ê°ë í¬í¸ì ì´ ì ìì ê±°ì¼."
+ " DUMMY STRING... ",
+ " DUMMY STRING... ",
+ "\xC0\xCC\xB7\xB1! \xB3\xBB \xC0\xE5\xBA\xF1\xB0\xA1 \xB4\xD9 \xB5\xB5\xB5\xCF\xB8\xC2\xBE\xD2\xBE\xEE!", // "ì´ë°! ë´ ì¥ë¹ê° ë¤ ëëë§ìì´!"
+ " DUMMY STRING... ",
+ "\xB3\xBB\xB0\xA1 \xC0\xFA \xBE\xC6\xB7\xA1\xB1\xEE\xC1\xF6 \xB0\xC9\xBE\xEE\xB0\xA5 \xB0\xC5\xB6\xF3\xB0\xED \xBB\xFD\xB0\xA2\xC7\xCF\xB8\xE9, \xB9\xCC\xC4\xA5 \xB0\xC5\xBE\xDF!", // "ë´ê° ì ìëê¹ì§ 걸ì´ê° ê±°ë¼ê³ ìê°íë©´, ë¯¸ì¹ ê±°ì¼!"
+ " DUMMY STRING... ",
+ " DUMMY STRING... ",
+ "\xBC\xAD\xB5\xD1\xB7\xAF \xC6\xC4\xBF\xEE!", // "ìëë¬ íì´!"
+ "\xBE\xDF, \xC5\xAB\xC0\xCF \xB3\xAF \xBB\xB7\xC7\xDF\xB3\xD7!", // "ì¼, í°ì¼ ë ë»íë¤!"
+ "\xB8\xC2\xBE\xC6. \xB3\xAA\xB4\xC2 \xB4\xD9\xBD\xC5 \xBB\xE7\xB3\xC9\xC0\xBA \xBE\xC8 \xB0\xA5 \xB0\xC5\xBE\xDF!", // "ë§ì. ëë ë¤ì ì¬ë¥ì ì ê° ê±°ì¼!"
+ "\xB0\xB3\xB1\xBC\xB0\xB3\xB1\xBC.", // "ê°êµ´ê°êµ´."
+ "\xB8\xEE \xB9\xF8\xC0\xBB \xB8\xBB\xC7\xD8\xBE\xDF \xBE\xCB\xBE\xC6\xB5\xE9\xBE\xEE? \xB3\xCA\xB4\xC2 \xB5\xCE\xB2\xA8\xBA\xF1\xB6\xF3\xB0\xED.", // "ëª ë²ì ë§í´ì¼ ììë¤ì´? ëë ë꺼ë¹ë¼ê³ ."
+ "\xC0\xCC\xB7\xB1! \xC4\xA1\xC1\xEE\xB0\xA1 \xB4\xD9 \xB6\xB3\xBE\xEE\xC1\xB3\xBE\xEE!", // "ì´ë°! ì¹ì¦ê° ë¤ ë¨ì´ì¡ì´!"
+ "\xC0\xCC \xB1\xCD\xC1\xF6\xB8\xA6 \xBD\xE1\xBA\xB8\xC0\xDA. \xC1\xD6\xC8\xB2\xBB\xF6\xC0\xCC\xB3\xD7.", // "ì´ ê·ì§ë¥¼ ì¨ë³´ì. 주í©ìì´ë¤."
+ "\xBE\xF6\xB8\xB6, \xB3\xAA\xB4\xC2 \xBE\xF0\xC1\xA6 \xB4\xE3\xC0\xEF\xC0\xCC\xB5\xA2\xB1\xBC\xC0\xBB \xB9\xDE\xBE\xC6\xBF\xE4?", // "ìë§, ëë ì¸ì ë´ìì´ë©êµ´ì ë°ìì?"
+ "\xC0\xFA\xB8\xAE \xBA\xF1\xC4\xD1, \xBD\xB5!", // "ì 리 ë¹ì¼, ì!"
+ "\xB3\xD7\xB0\xA1 \xC0\xDA\xB8\xA3\xB0\xED, \xB3\xBB\xB0\xA1 \xB0\xED\xB8\xA6\xB0\xD4.", // "ë¤ê° ìë¥´ê³ , ë´ê° ê³ ë¥¼ê²."
+ "\xBE\xC6\xB4\xCF. \xB3\xD7\xB0\xA1 \xC0\xDA\xB8\xA3\xB0\xED \xB3\xBB\xB0\xA1 \xB0\xED\xB8\xA6\xB0\xD4.", // "ìë. ë¤ê° ìë¥´ê³ ë´ê° ê³ ë¥¼ê²."
+ "\xBE\xC6\xC1\xF7\xB5\xB5 \xBE\xE2\xC6\xC5\xC7\xD1 \xB8\xF0\xB9\xE6\xC0\xDB\xC0\xCC\xB6\xF3\xB0\xED \xBB\xFD\xB0\xA2\xC7\xD8.", // "ìì§ë ìíí 모방ìì´ë¼ê³ ìê°í´."
+ "\xBE\xEE\xC8\xDE, \xB3\xCD \xBE\xFB\xB5\xA2\xC0\xCC\xB0\xA1 \xB9\xB0\xB7\xC1\xB5\xB5 5\xC0\xBD\xBA\xB8\xB0\xDD\xC0\xCC \xB9\xBA\xC1\xF6 \xB8\xF8 \xBE\xCB\xBE\xC6\xB5\xE9\xC0\xBB \xB0\xC5\xBE\xDF!", // "ì´í´, ë ìë©ì´ê° ë¬¼ë ¤ë 5ìë³´ê²©ì´ ëì§ ëª» ììë¤ì ê±°ì¼!"
+ "Executive Producer",
+ "Brett W. Sperry",
+ "Direction & Design",
+ "Rick Gush",
+ "Lead Programmer",
+ "Michael Legg",
+ "Art Management",
+ "Louis Castle",
+ "Joseph B. Hewitt IV",
+ "Lead Artist",
+ "Rick Parks",
+ "Additional Coding by",
+ "Philip W. Gorrow",
+ "Mike Grayford",
+ "Mark McCubbin",
+ "Artists",
+ "Cameron Chun",
+ "Cary Averett",
+ "Cindy Chinn",
+ "Elie Arabian",
+ "Fei Cheng",
+ "Ferby Miguel",
+ "Frank Mendeola",
+ "Jack Martin",
+ "Jerry Moore",
+ "DUMMY STRING... ",
+ "Judith Peterson",
+ "Larry Miller",
+ "Lenny Lee",
+ "Louise Sandoval",
+ "Ren Olsen",
+ "Music & Sounds by",
+ "Paul Mudra",
+ "Frank Klepacki",
+ "Dwight Okahara",
+ "Pat Collins",
+ "Quality Assurance by",
+ "Glenn Sperry",
+ "Michael Lightner",
+ "William Foster",
+ "Jesse Clemit",
+ "Jeff Fillhaber",
+ "Manual, Package Design",
+ "& Fulfillment",
+ "Eydie Laramore",
+ "Lisa Marcinko",
+ "Lauren Rifkin",
+ "\xC3\xE0\xC7\xCF\xC7\xD5\xB4\xCF\xB4\xD9!", // "ì¶íí©ëë¤!"
+ "\xBF\xEE\xB8\xED\xC0\xC7 \xBC\xD5\xC0\xBB \xC7\xC3\xB7\xB9\xC0\xCC\xC7\xD8 \xC1\xD6\xBC\xC5\xBC\xAD \xB0\xA8\xBB\xE7\xC7\xD5\xB4\xCF\xB4\xD9!", // "ì´ëª
ì ìì íë ì´í´ 주ì
ì ê°ì¬í©ëë¤!"
+ "Guest Coding",
+ "Producer Liaison",
+ "Scott Duckett",
+ "Irvine Testers",
+ "Chris McFarland",
+ "Paul Moore",
+ "Chad Soares",
+ "Jared Brinkley",
+ "Jon Willliams",
+ "Chris Toft",
+ "Joe Kucan's Hair by",
+ "Theodore A. Morris",
+ "\xB0\xD4\xC0\xD3 \xBA\xD2\xB7\xAF\xBF\xC0\xB1\xE2", // "ê²ì ë¶ë¬ì¤ê¸°"
+ "\xC0\xCE\xC6\xAE\xB7\xCE \xBA\xB8\xB1\xE2", // "ì¸í¸ë¡ 보기"
+ "\xBB\xF5 \xB0\xD4\xC0\xD3 \xBD\xC3\xC0\xDB", // "ì ê²ì ìì"
+ "\xB0\xD4\xC0\xD3 \xC1\xBE\xB7\xE1", // "ê²ì ì¢
ë£"
+ "Special Thanks to",
+ "Sake Joe Bostic-san",
+ "Tim Fritz",
+ "Kenny Dunne",
+ "\xBF\xEE\xB8\xED\xC0\xC7 \xBC\xD5\xC0\xBB \xC7\xC3\xB7\xB9\xC0\xCC\xC7\xD8 \xC1\xD6\xBC\xC5\xBC\xAD \xB0\xA8\xBB\xE7\xC7\xD5\xB4\xCF\xB4\xD9.\n" // "ì´ëª
ì ìì íë ì´í´ 주ì
ì ê°ì¬í©ëë¤.\n"
+};
+
+static const StringListProvider k2SeqplayStringsDOSCDKoreanProvider = { ARRAYSIZE(k2SeqplayStringsDOSCDKorean), k2SeqplayStringsDOSCDKorean };
+
+static const char *const k2SeqplayTlkFilesDOSCDKorean[14] = {
+ "EINTRO1",
+ "EINTRO2",
+ "EINTRO3",
+ "EINTRO4",
+ "EINTRO5",
+ "EINTRO6",
+ "EINTRO7",
+ "EINTRO8",
+ "EINTRO9",
+ "EINTRO10",
+ "EINTRO11",
+ "EINTRO12",
+ "EGLOW",
+ ""
+};
+
+static const StringListProvider k2SeqplayTlkFilesDOSCDKoreanProvider = { ARRAYSIZE(k2SeqplayTlkFilesDOSCDKorean), k2SeqplayTlkFilesDOSCDKorean };
diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat
index 7f4813135e3..2edacd78311 100644
Binary files a/dists/engine-data/kyra.dat and b/dists/engine-data/kyra.dat differ
diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index ce17c343824..a3486bab5b6 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -729,6 +729,42 @@ const KYRAGameDescription adGameDescs[] = {
KYRA2_FLOPPY_FAN_FLAGS(Common::RU_RUS, Common::EN_ANY)
},
+ { // Korean fan translation (based on FM-TOWNS).
+ // Detection language is KO_KOR so the entry is distinguishable from the
+ // base EN_ANY FM-Towns entries (all share the same WSCORE.PAK hash).
+ // kyra.dat does not carry KO_KOR data; loadStaticResourceFile() falls
+ // back to replacedLang (EN_ANY) automatically for fan translations.
+ {
+ "kyra2",
+ nullptr,
+ AD_ENTRY2s("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685", AD_NO_SIZE,
+ "KOREAN.FNT", "6b32ad695188e82b770a7739ffeb57db", 42300),
+ Common::KO_KOR,
+ Common::kPlatformFMTowns,
+ ADGF_NO_FLAGS,
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_RENDERFMTOWNS)
+ },
+ FLAGS_FAN(Common::KO_KOR, Common::EN_ANY, false, false, false, false, false, false, false, false, false, Kyra::GI_KYRA2)
+ },
+
+ { // Korean fan translation (based on DOS CD), English voice + Korean subtitles.
+ // Detection language is KO_KOR so the entry is distinguishable from the
+ // base EN_ANY CD entry (both share the same FATE.PAK hash). kyra.dat does
+ // not carry KO_KOR data; loadStaticResourceFile() falls back to
+ // replacedLang (EN_ANY) automatically for fan translations.
+ {
+ "kyra2",
+ "CD",
+ AD_ENTRY2s("FATE.PAK", "28cbad1c5bf06b2d3825ae57d760d032", AD_NO_SIZE,
+ "KOREAN.FNT", "6b32ad695188e82b770a7739ffeb57db", 42300),
+ Common::KO_KOR,
+ Common::kPlatformDOS,
+ ADGF_DROPLANGUAGE | ADGF_CD,
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
+ },
+ KYRA2_CD_FAN_FLAGS(Common::KO_KOR, Common::EN_ANY)
+ },
+
{ // CD version
{
"kyra2",
diff --git a/engines/kyra/engine/kyra_hof.cpp b/engines/kyra/engine/kyra_hof.cpp
index 130b4f358fc..e0eabfcdde9 100644
--- a/engines/kyra/engine/kyra_hof.cpp
+++ b/engines/kyra/engine/kyra_hof.cpp
@@ -192,13 +192,11 @@ Common::Error KyraEngine_HoF::init() {
KyraEngine_v1::init();
initStaticResource();
- _text = new TextDisplayer_HoF(this, _screen);
- assert(_text);
- _gui = new GUI_HoF(this);
- assert(_gui);
- _gui->initStaticData();
- _tim = new TIMInterpreter(this, _screen, _system);
- assert(_tim);
+ // Korean fan translation: kyra.dat was loaded with EN_ANY, now switch to KO_KOR
+ // so that file extensions and text handling all use Korean paths.
+ // Font loading must happen before initStaticData() which calls getFontHeight().
+ if (_flags.fanLang == Common::KO_KOR)
+ _flags.lang = Common::KO_KOR;
if (_flags.isDemo && !_flags.isTalkie) {
_screen->loadFont(_screen->FID_8_FNT, "FONT9P.FNT");
@@ -210,8 +208,22 @@ Common::Error KyraEngine_HoF::init() {
_screen->loadFont(_screen->FID_8_FNT, "8FAT.FNT");
_screen->loadFont(_screen->FID_BOOKFONT_FNT, "BOOKFONT.FNT");
}
+
+ if (_flags.lang == Common::KO_KOR) {
+ _screen->loadFont(Screen::FID_KOREAN_FNT, "KOREAN.FNT");
+ _defaultFont = Screen::FID_KOREAN_FNT;
+ _bookFont = Screen::FID_KOREAN_FNT;
+ }
_screen->setFont(_defaultFont);
+ _text = new TextDisplayer_HoF(this, _screen);
+ assert(_text);
+ _gui = new GUI_HoF(this);
+ assert(_gui);
+ _gui->initStaticData();
+ _tim = new TIMInterpreter(this, _screen, _system);
+ assert(_tim);
+
_screen->setAnimBlockPtr(3504);
_screen->setScreenDim(0);
@@ -294,6 +306,9 @@ void KyraEngine_HoF::startup() {
_trackMap = _dosTrackMap;
_trackMapSize = _dosTrackMapSize;
+ // Restore the default font after intro sequences may have changed it
+ _screen->setFont(_defaultFont);
+
allocAnimObjects(1, 10, 30);
_screen->_curPage = 0;
@@ -826,7 +841,7 @@ uint8 *KyraEngine_HoF::getTableEntry(uint8 *buffer, int id) {
Common::String KyraEngine_HoF::getTableString(int id, uint8 *buffer, bool decode) {
Common::String string((char *)getTableEntry(buffer, id));
- if (decode && _flags.lang != Common::JA_JPN) {
+ if (decode && _flags.lang != Common::JA_JPN && _flags.lang != Common::KO_KOR) {
string = Util::decodeString2(Util::decodeString1(string));
}
@@ -881,7 +896,7 @@ void KyraEngine_HoF::showChapterMessage(int id, int16 palIndex) {
void KyraEngine_HoF::updateCommandLineEx(int str1, int str2, int16 palIndex) {
Common::String str = getTableString(str1, _cCodeBuffer, true);
- if (_flags.lang != Common::ZH_TWN && _flags.lang != Common::JA_JPN && _flags.lang != Common::HE_ISR) {
+ if (_flags.lang != Common::ZH_TWN && _flags.lang != Common::JA_JPN && _flags.lang != Common::KO_KOR && _flags.lang != Common::HE_ISR) {
if (uint32 i = (uint32)str.findFirstOf(' ') + 1) {
str.erase(0, i);
str.setChar(toupper(str[0]), 0);
@@ -889,7 +904,7 @@ void KyraEngine_HoF::updateCommandLineEx(int str1, int str2, int16 palIndex) {
}
if (str2 > 0) {
- if (_flags.lang != Common::ZH_TWN && _flags.lang != Common::JA_JPN && _flags.lang != Common::HE_ISR)
+ if (_flags.lang != Common::ZH_TWN && _flags.lang != Common::JA_JPN && _flags.lang != Common::KO_KOR && _flags.lang != Common::HE_ISR)
str += " ";
if (_flags.lang == Common::HE_ISR)
str = getTableString(str2, _cCodeBuffer, 1) + " " + str + ".";
@@ -1008,6 +1023,12 @@ void KyraEngine_HoF::loadNPCScript() {
filename[5] = 'J';
break;
+ case 5:
+ // Korean fan translation: no Korean NPC script exists, fall back
+ // to the English one (_NPCE.EMC) which is present on DOS CD.
+ filename[5] = 'E';
+ break;
+
default:
break;
};
@@ -1928,15 +1949,27 @@ void KyraEngine_HoF::writeSettings() {
_flags.lang = Common::JA_JPN;
break;
+ case 5:
+ _flags.lang = Common::KO_KOR;
+ break;
+
case 0:
default:
_flags.lang = _langIntern ? Common::ZH_TWN : Common::EN_ANY;
}
- if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG)
+ if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG
+ && _flags.fanLang != Common::KO_KOR)
_flags.lang = _flags.fanLang;
- ConfMan.set("language", Common::getLanguageCode(_flags.lang));
+ // Korean fan translation: the detection entry now uses KO_KOR as the
+ // detection language with ADGF_DROPLANGUAGE, so we must write "ko" to
+ // config. Writing "en" would cause the Advanced Detector to prefer the
+ // base EN_ANY CD entry on next launch, reverting to English.
+ if (_flags.fanLang == Common::KO_KOR)
+ ConfMan.set("language", Common::getLanguageCode(Common::KO_KOR));
+ else
+ ConfMan.set("language", Common::getLanguageCode(_flags.lang));
KyraEngine_v1::writeSettings();
}
diff --git a/engines/kyra/engine/kyra_v2.cpp b/engines/kyra/engine/kyra_v2.cpp
index 24bc86317d3..d84d9649bf7 100644
--- a/engines/kyra/engine/kyra_v2.cpp
+++ b/engines/kyra/engine/kyra_v2.cpp
@@ -79,8 +79,14 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi
_lang = 0;
_scriptLang = 0;
Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
- if (lang == _flags.fanLang && _flags.replacedLang != Common::UNK_LANG)
- lang = _flags.replacedLang;
+
+ // Korean fan translation: always use KO_KOR regardless of config value,
+ // so that _lang is set to 5 and Korean file extensions are selected.
+ if (_flags.fanLang == Common::KO_KOR) {
+ lang = Common::KO_KOR;
+ } else if (lang == _flags.fanLang && _flags.replacedLang != Common::UNK_LANG) {
+ lang = _flags.replacedLang;
+ }
if (_flags.extraLang == Common::ZH_TWN)
_langIntern = 1;
@@ -115,6 +121,10 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi
_lang = 4;
break;
+ case Common::KO_KOR:
+ _lang = 5;
+ break;
+
default:
warning("unsupported language, switching back to English");
_lang = 0;
diff --git a/engines/kyra/engine/scene_hof.cpp b/engines/kyra/engine/scene_hof.cpp
index c17bc406580..cc472daf104 100644
--- a/engines/kyra/engine/scene_hof.cpp
+++ b/engines/kyra/engine/scene_hof.cpp
@@ -427,7 +427,17 @@ void KyraEngine_HoF::startSceneScript(int unk1) {
_sceneCommentString = "Undefined scene comment string!";
_emc->init(&_sceneScriptState, &_sceneScriptData);
- filename = Common::String(_sceneList[sceneId].filename1) + "." + _scriptLangExt[(_flags.platform == Common::kPlatformDOS && !_flags.isTalkie) ? 0 : _lang];
+ // Korean fan translation uses .KMC scripts (Korean-patched EMC files).
+ // Fall back to .EMC if .KMC is not available. Other langs clamp to valid range.
+ if (_flags.lang == Common::KO_KOR) {
+ filename = Common::String(_sceneList[sceneId].filename1) + ".KMC";
+ if (!_res->exists(filename.c_str())) {
+ filename = Common::String(_sceneList[sceneId].filename1) + ".EMC";
+ }
+ } else {
+ int scriptLangIdx = (_flags.platform == Common::kPlatformDOS && !_flags.isTalkie) ? 0 : (_lang > 3 ? 0 : _lang);
+ filename = Common::String(_sceneList[sceneId].filename1) + "." + _scriptLangExt[scriptLangIdx];
+ }
_res->exists(filename.c_str(), true);
_emc->load(filename.c_str(), &_sceneScriptData, &_opcodes);
runSceneScript7();
diff --git a/engines/kyra/graphics/screen.cpp b/engines/kyra/graphics/screen.cpp
index 1be63111966..0f80c637685 100644
--- a/engines/kyra/graphics/screen.cpp
+++ b/engines/kyra/graphics/screen.cpp
@@ -1426,8 +1426,22 @@ bool Screen::loadFont(FontId fontId, const char *filename) {
fnt->load(str);
}
} else if (fontId == FID_KOREAN_FNT) {
- const uint16 *lookupTable = _vm->staticres()->loadRawDataBe16(k1TwoByteFontLookupTable, temp);
- fnt = new JohabFontLoK(_fonts[FID_8_FNT], lookupTable, temp);
+ if (_vm->game() == GI_KYRA2) {
+ Common::Array<Font*> *fa = new Common::Array<Font*>;
+ fa->push_back(new KoreanOneByteFontHOF(SCREEN_W));
+ fa->push_back(new KoreanTwoByteFontHOF(SCREEN_W));
+ fnt = new MultiSubsetFont(fa);
+ // Load 1-byte (ASCII) font from ENGLISH.FNT first, then
+ // the main KOREAN.FNT call below will load the 2-byte glyphs.
+ Common::SeekableReadStream *engFile = _vm->resource()->createReadStream("ENGLISH.FNT");
+ if (engFile) {
+ fnt->load(*engFile);
+ delete engFile;
+ }
+ } else {
+ const uint16 *lookupTable = _vm->staticres()->loadRawDataBe16(k1TwoByteFontLookupTable, temp);
+ fnt = new JohabFontLoK(_fonts[FID_8_FNT], lookupTable, temp);
+ }
} else {
fnt = new DOSFont();
}
diff --git a/engines/kyra/graphics/screen.h b/engines/kyra/graphics/screen.h
index fa9bcd794ab..c1bc073210c 100644
--- a/engines/kyra/graphics/screen.h
+++ b/engines/kyra/graphics/screen.h
@@ -410,6 +410,26 @@ private:
void processColorMap() override;
};
+class KoreanOneByteFontHOF final : public ChineseFont {
+public:
+ KoreanOneByteFontHOF(int pitch) : ChineseFont(pitch, 8, 9, 8, 10, 0, 0) {}
+ Type getType() const override { return kJohab; }
+private:
+ bool hasGlyphForCharacter(uint16 c) const override { return !(c & 0x80); }
+ uint32 getFontOffset(uint16 c) const override { return (c & 0x7F) * 9; }
+ void processColorMap() override;
+};
+
+class KoreanTwoByteFontHOF final : public ChineseFont {
+public:
+ KoreanTwoByteFontHOF(int pitch) : ChineseFont(pitch, 10, 9, 10, 10, 0, 0) {}
+ Type getType() const override { return kJohab; }
+private:
+ bool hasGlyphForCharacter(uint16 c) const override { return (c & 0x80); }
+ uint32 getFontOffset(uint16 c) const override;
+ void processColorMap() override;
+};
+
class MultiSubsetFont final : public Font {
public:
MultiSubsetFont(Common::Array<Font*> *subsets) : Font(), _subsets(subsets) {}
diff --git a/engines/kyra/graphics/screen_hof.cpp b/engines/kyra/graphics/screen_hof.cpp
index 1fa7d0db6c6..e592cd4b38a 100644
--- a/engines/kyra/graphics/screen_hof.cpp
+++ b/engines/kyra/graphics/screen_hof.cpp
@@ -109,4 +109,29 @@ void ChineseTwoByteFontHOF::processColorMap() {
_pixelColorShading = !(_colorMap[1] == 207 || _colorMap[1] > 240);
}
+void KoreanOneByteFontHOF::processColorMap() {
+ _textColor[0] = _colorMap[1];
+ _textColor[1] = _colorMap[0] | (_colorMap[0] << 8);
+ _pixelColorShading = false;
+}
+
+uint32 KoreanTwoByteFontHOF::getFontOffset(uint16 c) const {
+ // fetchChar() stores: first byte (EUC-KR high) in low 8 bits,
+ // second byte (EUC-KR low) in high 8 bits. So:
+ // c & 0xFF = first byte (high byte of EUC-KR, 0xB0-0xC8)
+ // c >> 8 = second byte (low byte of EUC-KR, 0xA1-0xFE)
+ uint8 high = c & 0xFF;
+ uint8 low = (c >> 8) & 0xFF;
+ if (high < 0xB0 || high > 0xC8 || low < 0xA1 || low > 0xFE)
+ return 0;
+ uint32 index = (high - 0xB0) * 94 + (low - 0xA1);
+ return index * 18; // 10x9 pixels, 2 bytes/row, 9 rows = 18 bytes/glyph
+}
+
+void KoreanTwoByteFontHOF::processColorMap() {
+ _textColor[0] = _colorMap[1];
+ _textColor[1] = _colorMap[0] | (_colorMap[0] << 8);
+ _pixelColorShading = false;
+}
+
} // End of namespace Kyra
diff --git a/engines/kyra/gui/gui_hof.cpp b/engines/kyra/gui/gui_hof.cpp
index 0a3a316c751..11dd36eb038 100644
--- a/engines/kyra/gui/gui_hof.cpp
+++ b/engines/kyra/gui/gui_hof.cpp
@@ -1021,6 +1021,9 @@ int GUI_HoF::gameOptionsTalkie(Button *caller) {
int GUI_HoF::changeLanguage(Button *caller) {
updateMenuButton(caller);
+ // Korean fan translation: language is fixed to Korean, do not cycle.
+ if (_vm->gameFlags().fanLang == Common::KO_KOR)
+ return 0;
++_vm->_lang;
_vm->_lang %= _vm->_numLang;
setupOptionsButtons();
@@ -1052,6 +1055,11 @@ void GUI_HoF::setupOptionsButtons() {
_gameOptions.item[1].itemId = 33;
break;
+ case 5:
+ // Korean fan translation: string 51 in OPTIONS.KOR = "íêµì´"
+ _gameOptions.item[1].itemId = 51;
+ break;
+
default:
break;
}
diff --git a/engines/kyra/resource/staticres.cpp b/engines/kyra/resource/staticres.cpp
index 97df8d5e90a..b51c909c574 100644
--- a/engines/kyra/resource/staticres.cpp
+++ b/engines/kyra/resource/staticres.cpp
@@ -157,7 +157,33 @@ bool StaticResource::loadStaticResourceFile() {
if (!res->loadPakFile(staticDataFilename(), *i))
continue;
- if ((setLanguage(_vm->gameFlags().lang) && prefetchId(-1))) {
+ // Fan translations (e.g. Korean) may provide only a subset of
+ // resources in kyra.dat (e.g. intro strings). Load the base
+ // (replaced) language first, then merge fan language entries on
+ // top â only replacing IDs that the fan language provides.
+ if (_vm->gameFlags().fanLang != Common::UNK_LANG &&
+ _vm->gameFlags().replacedLang != Common::UNK_LANG) {
+ if ((setLanguage(_vm->gameFlags().replacedLang) && prefetchId(-1))) {
+ foundWorkingKyraDat = true;
+ // Merge: load the fan language ID map WITHOUT clearing
+ // existing _dataTable entries, then reload only the
+ // IDs that changed.
+ Common::SeekableReadStream *fanMap = loadIdMap(_vm->gameFlags().fanLang);
+ if (fanMap) {
+ int numIDs = fanMap->readUint16BE();
+ while (numIDs--) {
+ uint16 id2 = fanMap->readUint16BE();
+ uint8 type = fanMap->readByte();
+ uint32 filename = fanMap->readUint32BE();
+ _dataTable[id2] = DataDescriptor(filename, type);
+ unloadId(id2);
+ prefetchId(id2);
+ }
+ delete fanMap;
+ }
+ break;
+ }
+ } else if ((setLanguage(_vm->gameFlags().lang) && prefetchId(-1))) {
foundWorkingKyraDat = true;
break;
}
@@ -1455,7 +1481,8 @@ const char *const KyraEngine_HoF::_languageExtension[] = {
"ITA", Italian and Spanish were never included
"SPA"*/
"JPN",
- "POL"
+ "POL",
+ "KOR"
};
const char *const KyraEngine_HoF::_scriptLangExt[] = {
diff --git a/engines/kyra/sequence/sequences_hof.cpp b/engines/kyra/sequence/sequences_hof.cpp
index 495f29eeff4..160f51d5990 100644
--- a/engines/kyra/sequence/sequences_hof.cpp
+++ b/engines/kyra/sequence/sequences_hof.cpp
@@ -389,7 +389,7 @@ SeqPlayer_HOF::SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *syst
memset(_hofDemoItemShapes, 0, sizeof(_hofDemoItemShapes));
- _defaultFont = (_vm->gameFlags().lang == Common::ZH_TWN) ? Screen::FID_CHINESE_FNT : ((_vm->gameFlags().lang == Common::JA_JPN) ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
+ _defaultFont = (_vm->gameFlags().lang == Common::ZH_TWN) ? Screen::FID_CHINESE_FNT : ((_vm->gameFlags().lang == Common::JA_JPN) ? Screen::FID_SJIS_FNT : ((_vm->gameFlags().lang == Common::KO_KOR) ? Screen::FID_KOREAN_FNT : Screen::FID_GOLDFONT_FNT));
_creditsFont = (_vm->gameFlags().lang == Common::ZH_TWN) ? Screen::FID_CHINESE_FNT : Screen::FID_8_FNT;
_creditsFont2 = (_vm->gameFlags().lang == Common::ZH_TWN) ? Screen::FID_GOLDFONT_FNT : Screen::FID_8_FNT;
@@ -463,7 +463,9 @@ SeqPlayer_HOF::SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *syst
int8 ls = 0;
Screen::FontId fid = Screen::FID_8_FNT;
- if (_vm->gameFlags().lang == Common::JA_JPN) {
+ if (_vm->gameFlags().lang == Common::KO_KOR) {
+ fid = Screen::FID_KOREAN_FNT;
+ } else if (_vm->gameFlags().lang == Common::JA_JPN) {
fid = Screen::FID_SJIS_FNT;
ls = 1;
} else if (_vm->gameFlags().lang == Common::ZH_TWN) {
@@ -504,7 +506,7 @@ SeqPlayer_HOF::~SeqPlayer_HOF() {
delete _menu;
if (_vm->game() != GI_LOL)
- _screen->setFont(_vm->gameFlags().lang == Common::ZH_TWN ? Screen::FID_CHINESE_FNT : (_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT));
+ _screen->setFont(_vm->gameFlags().lang == Common::ZH_TWN ? Screen::FID_CHINESE_FNT : (_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : (_vm->gameFlags().lang == Common::KO_KOR ? Screen::FID_KOREAN_FNT : Screen::FID_8_FNT)));
}
int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
diff --git a/engines/kyra/text/text_hof.cpp b/engines/kyra/text/text_hof.cpp
index 34a3197eddc..8056b97049b 100644
--- a/engines/kyra/text/text_hof.cpp
+++ b/engines/kyra/text/text_hof.cpp
@@ -86,6 +86,12 @@ char *TextDisplayer_HoF::preprocessString(const char *str) {
if (_vm->gameFlags().lang == Common::ZH_TWN)
return _talkBuffer;
+ // Korean fan translation: delegate to base class which already handles
+ // 2-byte character width measurement with FID_KOREAN_FNT and has
+ // correct maxTextWidth limits for Korean text.
+ if (_vm->gameFlags().lang == Common::KO_KOR)
+ return TextDisplayer::preprocessString(_talkBuffer);
+
char *p = _talkBuffer;
while (*p) {
if (*p == '\r')
@@ -424,7 +430,7 @@ void KyraEngine_HoF::randomSceneChat() {
void KyraEngine_HoF::updateDlgBuffer() {
static const char suffixTalkie[] = "EFG";
- static const char suffixTowns[] = "G J";
+ static const char suffixTowns[] = "G J K";
if (_currentChapter == _npcTalkChpIndex && _mainCharacter.dlgIndex == _npcTalkDlgIndex)
return;
@@ -434,11 +440,18 @@ void KyraEngine_HoF::updateDlgBuffer() {
Common::String filename = Common::String::format("CH%.02d-S%.02d.DL", _currentChapter, _npcTalkDlgIndex);
- const char *suffix = _flags.isTalkie ? suffixTalkie : suffixTowns;
- if (_flags.platform != Common::kPlatformDOS || _flags.isTalkie)
- filename += suffix[_lang];
- else
- filename += 'G';
+ // Korean fan translation always uses .DLK regardless of talkie/platform.
+ // suffixTalkie[] = "EFG" only covers _lang 0-2; _lang=5 (KO_KOR) would
+ // be an out-of-bounds read, so we handle it explicitly before the lookup.
+ if (_flags.lang == Common::KO_KOR) {
+ filename += 'K';
+ } else {
+ const char *suffix = _flags.isTalkie ? suffixTalkie : suffixTowns;
+ if (_flags.platform != Common::kPlatformDOS || _flags.isTalkie)
+ filename += suffix[_lang];
+ else
+ filename += 'G';
+ }
delete[] _dlgBuffer;
_dlgBuffer = _res->fileData(filename.c_str(), nullptr);
Commit: 03099dfa9e98cbedd12dbfc58b59259dbe5b9f21
https://github.com/scummvm/scummvm/commit/03099dfa9e98cbedd12dbfc58b59259dbe5b9f21
Author: Seokjun Kim (colus001 at me.com)
Date: 2026-03-26T17:26:00+01:00
Commit Message:
KYRA: Remove redundant KO_KOR lang overrides in HoF
Changed paths:
engines/kyra/engine/kyra_hof.cpp
diff --git a/engines/kyra/engine/kyra_hof.cpp b/engines/kyra/engine/kyra_hof.cpp
index e0eabfcdde9..92c6dc83bd9 100644
--- a/engines/kyra/engine/kyra_hof.cpp
+++ b/engines/kyra/engine/kyra_hof.cpp
@@ -192,12 +192,6 @@ Common::Error KyraEngine_HoF::init() {
KyraEngine_v1::init();
initStaticResource();
- // Korean fan translation: kyra.dat was loaded with EN_ANY, now switch to KO_KOR
- // so that file extensions and text handling all use Korean paths.
- // Font loading must happen before initStaticData() which calls getFontHeight().
- if (_flags.fanLang == Common::KO_KOR)
- _flags.lang = Common::KO_KOR;
-
if (_flags.isDemo && !_flags.isTalkie) {
_screen->loadFont(_screen->FID_8_FNT, "FONT9P.FNT");
} else if (_flags.lang == Common::ZH_TWN) {
@@ -1958,18 +1952,10 @@ void KyraEngine_HoF::writeSettings() {
_flags.lang = _langIntern ? Common::ZH_TWN : Common::EN_ANY;
}
- if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG
- && _flags.fanLang != Common::KO_KOR)
+ if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG)
_flags.lang = _flags.fanLang;
- // Korean fan translation: the detection entry now uses KO_KOR as the
- // detection language with ADGF_DROPLANGUAGE, so we must write "ko" to
- // config. Writing "en" would cause the Advanced Detector to prefer the
- // base EN_ANY CD entry on next launch, reverting to English.
- if (_flags.fanLang == Common::KO_KOR)
- ConfMan.set("language", Common::getLanguageCode(Common::KO_KOR));
- else
- ConfMan.set("language", Common::getLanguageCode(_flags.lang));
+ ConfMan.set("language", Common::getLanguageCode(_flags.lang));
KyraEngine_v1::writeSettings();
}
More information about the Scummvm-git-logs
mailing list