[Scummvm-git-logs] scummvm master -> fb5071e8495dd715165406fd14526814508256b7

sev- noreply at scummvm.org
Sat Apr 29 11:38:08 UTC 2023


This automated email contains information about 45 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
3e929bd857 KYRA: Fix NPE on other languages
25947e92b9 KYRA: Remove empty rows in saveLoadStrings
b5f4192744 KYRA: Fix segmentation fault on _transferStringsScummVM with unknown language
cf8e0fde0e KYRA: Fix off-by-one error for empty string error for Sega CD version
809bbc6775 KYRA: Fix crash on unknown lang with errorSlotNoNameString
bc80106e04 GRAPHICS: Bring on-par Surface and raw draw for big5 font
95bbb7c3d5 GRAPHICS: New method hasGlyphForBig5Char in big5font
b43be897c7 GRAPHICS: sanity check for big5 font file
eb2c55fe04 COMMON: Move DOS font from AGI to common
87ce98a749 KYRA: Add resources for EOB2 Chinese
3904b79aa5 KYRA: Handle "taken" in Chinese EOB2.
73b55dae93 KYRA: Change eob2 Chinese from ZH_ANY to more accurate ZH_TWN
e5ddd3bc5b KYRA: Enable Chinese EOB2
071ee78bc7 KYRA: Support compression used in Chinese eob2
2703a5c652 KYRA: Support big5 font used in eob2
8083992529 KYRA: Support word-wrapping in Chinese RPG
1e6b5eeae4 KYRA: Add 2x height-scaled font for Chinese eob2
691d25fc7f KYRA: Add explicit check for >= 0x80 chars
6a00f7a418 KYRA: Fix handling of importing EOB2 original saves containing Chinese chars
e1f706b56d KYRA: Use Chinese font in Intro and Finale of Chinese EoB2
094f6aea29 KYRA: Mark Chinese EoB2 as talkie
6ae55d93a4 KYRA: Play voices in Intro and Finale of Chinese EoB2
e7afc8ab2e KYRA: Support logo from T1.CPS
5d3293e4c5 KYRA: Fix EOB2 Chinese main menu position and line spacing
a666b2deca KYRA: Add Chinese version of saveLoadStrings
4f0169e104 KYRA: Use Chinese font in several places in Chinese EOB2
0c8b668c4c KYRA: Add button defs for EOB2 Chinese
1bf7a7d448 KYRA: Translate Camp button in Chinese EOB2
678ec94ab0 KYRA: Change rendering of spell menu in Chinese EOB2
832bcda774 KYRA: Resize console for Chinese EOB2 the same way as original
28e87b295d KYRA: Add string for own healing in Chinese EOB2
5680cb0838 KYRA: Adjust layout in Chinese EOB2 save/load dialog
1e7f405f0d KYRA: Add _screenDimTable for Chinese EOB2
a569b7c5b2 KYRA: Add OK string for menu dialogues in Chinese EOB2
c5f8d354f7 KYRA: Adjust layout of GUI_EoB::messageDialogue for Chinese EOB2
571f8d1595 KYRA: Adjust font height for console in Chinese EOB2.
8c0295bb66 KYRA: Add errorSlotNoNameString for Chinese EOB2
d091774ab2 KYRA: Support 2-column simplemenu
e64898ad33 KYRA: Increase x-resolution of button position
286e7e4b2e KYRA: Change chargen layout in Chinese EOB2 to match original
52b9c91040 KYRA: Clean field before drawing modify menu
47e981fa8d KYRA: Always use drawButton to page 0 rather than 2
a2fb72cf12 KYRA: Change height of text input to 15 for Chinese EOB2
3b9349fd10 KYRA: Change layout of text input for Chinese EOB2
fb5071e849 KYRA: Remove pageNum argument in drawButton


Commit: 3e929bd8578efae1b688cf586f2277f2d0d2a330
    https://github.com/scummvm/scummvm/commit/3e929bd8578efae1b688cf586f2277f2d0d2a330
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Fix NPE on other languages

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index 8f44dd0b1a9..1d162e03bb5 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -581,8 +581,8 @@ void EoBCoreEngine::initStaticResource() {
 		}
 		break;
 	default:
-		_saveLoadStrings = saveLoadStrings[5];
-		_errorSlotEmptyString = errorSlotEmptyString[7];
+		_saveLoadStrings = saveLoadStrings[0];
+		_errorSlotEmptyString = errorSlotEmptyString[0];
 		break;
 	}
 


Commit: 25947e92b944fa16060a1569b0cbfb33868223a5
    https://github.com/scummvm/scummvm/commit/25947e92b944fa16060a1569b0cbfb33868223a5
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Remove empty rows in saveLoadStrings

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index 1d162e03bb5..cc92ba44019 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -530,8 +530,6 @@ void EoBCoreEngine::initStaticResource() {
 		{   "Abbr.",    "Leerer Slot",		"Speichern",    "  Laden"       },
 		{	" < < ",	"Posizione Vuota",	"Salva",		"Carica"	    },
 		{	"Anular",	"Sin Uso",			"Grabar",		"Cargar"	    },
-		{   0,          0,					0,					0			},
-		{	0,          0,					0,					0			},
 		{   "Cancel",   "\x82""d""\x82\x8d\x82\x90\x82\x94\x82\x99\x81""@""\x82\x92\x82\x85\x82\x87\x82\x89\x82\x8f\x82\x8e",		"Select save area",    "Select load data"     },
 		{   "\x82\xe2\x82\xdf\x82\xe9",   "\x8b\xf3\x82\xab\x97\xcc\x88\xe6",	"\x82\xc7\x82\xb1\x82\xc9\x83""Z""\x81""|""\x83""u""\x82\xb5\x82\xdc\x82\xb7\x82\xa9\x81""H",	"\x82\xc7\x82\xea\x82\xf0\x83\x8d\x81""|""\x83""h""\x82\xb5\x82\xdc\x82\xb7\x82\xa9\x81""H"    }
 	};
@@ -549,7 +547,7 @@ void EoBCoreEngine::initStaticResource() {
 	switch (_flags.lang) {
 	case Common::EN_ANY: {
 		if (_flags.platform == Common::kPlatformSegaCD) {
-			_saveLoadStrings = saveLoadStrings[6];
+			_saveLoadStrings = saveLoadStrings[4];
 			_errorSlotEmptyString = errorSlotEmptyString[5];
 		} else {
 			_saveLoadStrings = saveLoadStrings[0];
@@ -571,7 +569,7 @@ void EoBCoreEngine::initStaticResource() {
 		break;
 	case Common::JA_JPN:
 		if (_flags.platform == Common::kPlatformSegaCD) {
-			_saveLoadStrings = saveLoadStrings[7];
+			_saveLoadStrings = saveLoadStrings[5];
 			_errorSlotEmptyString = errorSlotEmptyString[6];
 		} else {
 			// EOB II FM-Towns uses English here.


Commit: b5f4192744d93ad25024a6eec5bda1c8044dfce0
    https://github.com/scummvm/scummvm/commit/b5f4192744d93ad25024a6eec5bda1c8044dfce0
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Fix segmentation fault on _transferStringsScummVM with unknown language

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index cc92ba44019..78fe74285fb 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -1764,13 +1764,11 @@ void DarkMoonEngine::initStaticResource() {
 			"Escoge Fichero",
 			"\r\r   Un momento\r   por favor..."
 		},
-		{
-			0, 0, 0, 0
-		}
 	};
 
 	switch(_flags.lang) {
 		case Common::EN_ANY:
+		default:
 			_errorSlotNoNameString = errorSlotNoNameString[0];
 			_transferStringsScummVM = transferStringsScummVM[0];
 			break;
@@ -1782,9 +1780,6 @@ void DarkMoonEngine::initStaticResource() {
 			_errorSlotNoNameString = errorSlotNoNameString[2];
 			_transferStringsScummVM = transferStringsScummVM[2];
 			break;
-		default:
-			_errorSlotNoNameString = errorSlotNoNameString[3];
-			_transferStringsScummVM = transferStringsScummVM[3];
 	}
 
 }


Commit: cf8e0fde0e15d5e0dd30d4bdac1b411d6a4cd33b
    https://github.com/scummvm/scummvm/commit/cf8e0fde0e15d5e0dd30d4bdac1b411d6a4cd33b
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Fix off-by-one error for empty string error for Sega CD version

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index 78fe74285fb..49f38e8b311 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -548,7 +548,7 @@ void EoBCoreEngine::initStaticResource() {
 	case Common::EN_ANY: {
 		if (_flags.platform == Common::kPlatformSegaCD) {
 			_saveLoadStrings = saveLoadStrings[4];
-			_errorSlotEmptyString = errorSlotEmptyString[5];
+			_errorSlotEmptyString = errorSlotEmptyString[4];
 		} else {
 			_saveLoadStrings = saveLoadStrings[0];
 			_errorSlotEmptyString = errorSlotEmptyString[0];
@@ -570,7 +570,7 @@ void EoBCoreEngine::initStaticResource() {
 	case Common::JA_JPN:
 		if (_flags.platform == Common::kPlatformSegaCD) {
 			_saveLoadStrings = saveLoadStrings[5];
-			_errorSlotEmptyString = errorSlotEmptyString[6];
+			_errorSlotEmptyString = errorSlotEmptyString[5];
 		} else {
 			// EOB II FM-Towns uses English here.
 			// Only the empty slot warning is in Japanese.


Commit: 809bbc6775f06f6f8117829d353e0992bc6614b7
    https://github.com/scummvm/scummvm/commit/809bbc6775f06f6f8117829d353e0992bc6614b7
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Fix crash on unknown lang with errorSlotNoNameString

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index 49f38e8b311..29254c30435 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -1439,6 +1439,7 @@ void EoBEngine::initStaticResource() {
 
 	switch (_flags.lang) {
 	case Common::EN_ANY:
+	default:
 		_errorSlotNoNameString = errorSlotNoNameString[0];
 		break;
 	case Common::DE_DEU:
@@ -1450,8 +1451,6 @@ void EoBEngine::initStaticResource() {
 	case Common::JA_JPN:
 		_errorSlotNoNameString = errorSlotNoNameString[3];
 		break;
-	default:
-		_errorSlotNoNameString = errorSlotNoNameString[ARRAYSIZE(errorSlotNoNameString) - 1];
 	}
 }
 


Commit: bc80106e043c3f3a9e196e01037d70d69fc99ab2
    https://github.com/scummvm/scummvm/commit/bc80106e043c3f3a9e196e01037d70d69fc99ab2
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
GRAPHICS: Bring on-par Surface and raw draw for big5 font

Changed paths:
    graphics/big5.cpp
    graphics/big5.h


diff --git a/graphics/big5.cpp b/graphics/big5.cpp
index dc8aeb4c76f..15513505407 100644
--- a/graphics/big5.cpp
+++ b/graphics/big5.cpp
@@ -109,22 +109,22 @@ template <class T> bool Big5Font::drawReal(byte *dest, uint16 textChar, int maxX
 	return true;
 }
 
-bool Big5Font::drawBig5Char(byte *dest, uint16 ch, int maxX, int maxY, uint32 destPitch, byte color, byte outlineColor) const {
-	return drawReal<uint8>(dest, ch, maxX, maxY, destPitch, color, outlineColor, true);
-}
-
-bool Big5Font::drawBig5Char(Graphics::Surface *surf, uint16 ch, const Common::Point &pt, uint32 color) const {
-	switch(surf->format.bytesPerPixel) {
+bool Big5Font::drawBig5Char(byte *dest, uint16 ch, int maxX, int maxY, uint32 destPitch, byte color, byte outlineColor, bool outline, int bpp) const {
+	switch(bpp) {
 	case 4:
-		return drawReal<uint32>((byte*)surf->getBasePtr(pt.x, pt.y), ch, surf->w - pt.x, surf->h - pt.y, surf->pitch, color, 0, false);
+		return drawReal<uint32>(dest, ch, maxX, maxY, destPitch, color, outlineColor, outline);
 	case 2:
-		return drawReal<uint16>((byte*)surf->getBasePtr(pt.x, pt.y), ch, surf->w - pt.x, surf->h - pt.y, surf->pitch, color, 0, false);
+		return drawReal<uint16>(dest, ch, maxX, maxY, destPitch, color, outlineColor, outline);
 	case 1:
-		return drawReal<uint8>((byte*)surf->getBasePtr(pt.x, pt.y), ch, surf->w - pt.x, surf->h - pt.y, surf->pitch, color, 0, false);
+		return drawReal<uint8>(dest, ch, maxX, maxY, destPitch, color, outlineColor, outline);
 	default:
-		error("Big5 font for bpp=%d is not supported", surf->format.bytesPerPixel);
+		error("Big5 font for bpp=%d is not supported", bpp);
 	}
 
 }
 
+bool Big5Font::drawBig5Char(Graphics::Surface *surf, uint16 ch, const Common::Point &pt, uint32 color, byte outlineColor, bool outline) const {
+	return drawBig5Char((byte*)surf->getBasePtr(pt.x, pt.y), ch, surf->w - pt.x, surf->h - pt.y, surf->pitch, color, outlineColor, outline, surf->format.bytesPerPixel);
+}
+
 }
diff --git a/graphics/big5.h b/graphics/big5.h
index 1aa73876dc6..fe68be27101 100644
--- a/graphics/big5.h
+++ b/graphics/big5.h
@@ -34,8 +34,8 @@ public:
 	Big5Font();
 	~Big5Font();
 	void loadPrefixedRaw(Common::ReadStream &input, int height);
-	bool drawBig5Char(byte *dest, uint16 ch, int maxX, int maxY, uint32 destPitch, byte color, byte outlineColor) const;
-	bool drawBig5Char(Graphics::Surface *surf, uint16 ch, const Common::Point &pt, uint32 color) const;
+	bool drawBig5Char(byte *dest, uint16 ch, int maxX, int maxY, uint32 destPitch, byte color, byte outlineColor, bool outline = true, int bpp = 8) const;
+	bool drawBig5Char(Graphics::Surface *surf, uint16 ch, const Common::Point &pt, uint32 color, byte outlineColor = 0, bool outline = false) const;
 
 	int getFontHeight() const { return _chineseTraditionalHeight; }
 


Commit: 95bbb7c3d5af6b1b6a64346beb7bef0aca1e7246
    https://github.com/scummvm/scummvm/commit/95bbb7c3d5af6b1b6a64346beb7bef0aca1e7246
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
GRAPHICS: New method hasGlyphForBig5Char in big5font

Changed paths:
    graphics/big5.h


diff --git a/graphics/big5.h b/graphics/big5.h
index fe68be27101..248dad72c5b 100644
--- a/graphics/big5.h
+++ b/graphics/big5.h
@@ -36,6 +36,7 @@ public:
 	void loadPrefixedRaw(Common::ReadStream &input, int height);
 	bool drawBig5Char(byte *dest, uint16 ch, int maxX, int maxY, uint32 destPitch, byte color, byte outlineColor, bool outline = true, int bpp = 8) const;
 	bool drawBig5Char(Graphics::Surface *surf, uint16 ch, const Common::Point &pt, uint32 color, byte outlineColor = 0, bool outline = false) const;
+	bool hasGlyphForBig5Char(uint16 textChar) const { return (textChar & 0x8000) && _chineseTraditionalIndex[textChar & 0x7fff] >= 0; }
 
 	int getFontHeight() const { return _chineseTraditionalHeight; }
 


Commit: b43be897c763eea4921067a3eb37cc3bcc7ca7eb
    https://github.com/scummvm/scummvm/commit/b43be897c763eea4921067a3eb37cc3bcc7ca7eb
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
GRAPHICS: sanity check for big5 font file

Changed paths:
    graphics/big5.cpp


diff --git a/graphics/big5.cpp b/graphics/big5.cpp
index 15513505407..95ef5e288a6 100644
--- a/graphics/big5.cpp
+++ b/graphics/big5.cpp
@@ -76,8 +76,12 @@ void Big5Font::loadPrefixedRaw(Common::ReadStream &input, int height) {
 		// Big-endian because it's not really a u16 but a big5 sequence.
 		uint16 ch = input.readUint16BE();
 		ChineseTraditionalGlyph glyph;
+		if (input.eos())
+			break;
 		if (ch == 0xffff)
 			break;
+		if (!(ch & 0x8000))
+			continue;
 		memset(&glyph.bitmap, 0, sizeof(glyph.bitmap));
 		memset(&glyph.outline, 0, sizeof(glyph.outline));
 		input.read(&glyph.bitmap, (kChineseTraditionalWidth / 8) * _chineseTraditionalHeight);


Commit: eb2c55fe04c9ad3f060fa4e1e4f1dd70f1a13826
    https://github.com/scummvm/scummvm/commit/eb2c55fe04c9ad3f060fa4e1e4f1dd70f1a13826
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
COMMON: Move DOS font from AGI to common

It's useful for Chinese EOB2 as well

Changed paths:
  A graphics/fonts/dosfont.cpp
  A graphics/fonts/dosfont.h
    engines/agi/font.cpp
    graphics/module.mk


diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
index c2f94022c2a..6a7f8fe8426 100644
--- a/engines/agi/font.cpp
+++ b/engines/agi/font.cpp
@@ -24,6 +24,7 @@
 #include "gui/gui-manager.h"
 #include "gui/message.h"
 #include "graphics/fonts/amigafont.h"
+#include "graphics/fonts/dosfont.h"
 
 #include "agi/agi.h"
 #include "agi/font.h"
@@ -50,412 +51,6 @@ static const uint8 fontData_ArrowRightCharacter[8] = {
 	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
 };
 
-// 8x8 font patterns
-
-// this is basically the standard PC BIOS font, taken from Dos-Box, with a few modifications
-static const uint8 fontData_PCBIOS[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
-	0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
-	0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
-	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
-	0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
-	0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
-	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
-	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
-	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
-	0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
-	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
-	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
-	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00, // 0x0D changed
-	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C, // 0x0E changed
-	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, // 0x0F changed
-	//0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, // 0x0D original
-	//0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, // 0x0E original
-	//0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, // 0x0F original
-	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
-	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x12 changed
-	//0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, // 0x12 original
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
-	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00, // 0x14 changed
-	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, // 0x14 changed
-	//0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, // 0x14 original
-	//0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78, // 0x15 original
-	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E, // 0x17 changed
-	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 changed
-	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x19 changed
-	//0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, // 0x17 original
-	//0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 original
-	//0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, // 0x19 original
-	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
-	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
-	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, // 0x1D changed
-	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, // 0x1E changed
-	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, // 0x1F changed
-	//0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, // 0x1D original
-	//0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, // 0x1E original
-	//0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, // 0x1F original
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
-	0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
-	0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
-	0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
-	0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
-	0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
-	0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
-	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
-	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
-	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
-	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
-	0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
-	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
-	0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
-	0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
-	0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
-	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
-	0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
-	0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
-	0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
-	0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
-	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
-	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
-	0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
-	0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
-	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
-	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
-	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
-	0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
-	0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
-	0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
-	0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
-	0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
-	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
-	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
-	0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
-	0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
-	0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
-	0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
-	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
-	0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
-	0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
-	0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
-	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
-	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
-	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
-	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
-	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
-	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
-	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
-	0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
-	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
-	0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
-	0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
-	0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
-	0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
-	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
-	0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
-	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
-	0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
-	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
-	0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78, // 0x80
-	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
-	0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
-	0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
-	0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
-	0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
-	0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38,
-	0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
-	0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
-	0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
-	0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00,
-	0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00,
-	0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00,
-	0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
-	0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
-	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00,
-	0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
-	0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18,
-	0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00,
-	0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30,
-	0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7,
-	0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70,
-	0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
-	0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
-	0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00,
-	0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00,
-	0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00,
-	0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00,
-	0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00,
-	0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F,
-	0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03,
-	0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
-	0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
-	0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
-	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
-	0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36,
-	0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36,
-	0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
-	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00,
-	0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0,
-	0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
-	0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00,
-	0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00,
-	0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00,
-	0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0,
-	0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC,
-	0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00,
-	0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00,
-	0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00,
-	0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0,
-	0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00,
-	0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00,
-	0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
-	0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00,
-	0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00,
-	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
-	0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00,
-	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
-	0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-	0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C,
-	0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
-	0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-// Extended set (0x80-0xFF) for Russian versions of games
-static const uint8 fontData_ExtendedRussian[] = {
-	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
-	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
-	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
-	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
-	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
-	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
-	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
-	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
-	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
-	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
-	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
-	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
-	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
-	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
-	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
-	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
-	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
-	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
-	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
-	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
-	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
-	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
-	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
-	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
-	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
-	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
-	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
-	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
-	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
-};
-
 void GfxFont::init() {
 	if (ConfMan.getBool("herculesfont")) {
 		// User wants, that we use Hercules hires font, try to load it
@@ -519,7 +114,7 @@ void GfxFont::init() {
 		if (!_fontData) {
 			// no font assigned?
 			// use regular PC-BIOS font (taken from Dos-Box with a few modifications)
-			_fontData = fontData_PCBIOS;
+			_fontData = Graphics::DosFont::fontData_PCBIOS;
 			debug("AGI: Using PC-BIOS font");
 		}
 	}
@@ -559,7 +154,7 @@ void GfxFont::overwriteExtendedWithRussianSet() {
 		_fontData = _fontDataAllocated;
 	}
 	// Overwrite extended set with Russian characters
-	memcpy(_fontDataAllocated + (128 * 8), fontData_ExtendedRussian, 128 * 8);
+	memcpy(_fontDataAllocated + (128 * 8), Graphics::DosFont::fontData_ExtendedRussian, 128 * 8);
 
 	debug("AGI: Using Russian extended font set");
 }
@@ -647,7 +242,7 @@ void GfxFont::loadFontAmigaPseudoTopaz() {
 	_fontDataAllocated = fontData;
 
 	// copy first 32 PC-BIOS characters over
-	memcpy(fontData, fontData_PCBIOS, FONT_DISPLAY_WIDTH * 32);
+	memcpy(fontData, Graphics::DosFont::fontData_PCBIOS, FONT_DISPLAY_WIDTH * 32);
 	fontData += FONT_DISPLAY_WIDTH * 32;
 
 	Graphics::AmigaFont topaz;
diff --git a/graphics/fonts/dosfont.cpp b/graphics/fonts/dosfont.cpp
new file mode 100644
index 00000000000..a0bce224a5b
--- /dev/null
+++ b/graphics/fonts/dosfont.cpp
@@ -0,0 +1,430 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "graphics/fonts/dosfont.h"
+
+namespace Graphics {
+// 8x8 font patterns
+
+// this is basically the standard PC BIOS font, taken from Dos-Box, with a few modifications
+const uint8 DosFont::fontData_PCBIOS[256 * 8] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
+	0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
+	0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+	0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
+	0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
+	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
+	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
+	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
+	0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
+	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
+	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
+	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00, // 0x0D changed
+	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C, // 0x0E changed
+	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, // 0x0F changed
+	//0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, // 0x0D original
+	//0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, // 0x0E original
+	//0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, // 0x0F original
+	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
+	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
+	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x12 changed
+	//0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, // 0x12 original
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00, // 0x14 changed
+	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, // 0x14 changed
+	//0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, // 0x14 original
+	//0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78, // 0x15 original
+	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
+	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E, // 0x17 changed
+	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 changed
+	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x19 changed
+	//0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, // 0x17 original
+	//0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 original
+	//0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, // 0x19 original
+	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
+	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
+	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, // 0x1D changed
+	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, // 0x1E changed
+	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, // 0x1F changed
+	//0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, // 0x1D original
+	//0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, // 0x1E original
+	//0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, // 0x1F original
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
+	0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+	0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
+	0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
+	0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
+	0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
+	0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
+	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+	0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
+	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
+	0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
+	0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
+	0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
+	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
+	0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
+	0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
+	0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
+	0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
+	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+	0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
+	0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
+	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
+	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
+	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
+	0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
+	0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
+	0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
+	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
+	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
+	0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
+	0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
+	0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
+	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
+	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
+	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
+	0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
+	0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
+	0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
+	0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+	0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
+	0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
+	0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
+	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
+	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
+	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
+	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
+	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
+	0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
+	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
+	0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+	0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
+	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
+	0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
+	0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
+	0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+	0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
+	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
+	0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
+	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+	0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
+	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
+	0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78, // 0x80
+	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+	0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
+	0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+	0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+	0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+	0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38,
+	0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+	0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
+	0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+	0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+	0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00,
+	0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00,
+	0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00,
+	0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+	0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00,
+	0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+	0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18,
+	0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00,
+	0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30,
+	0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7,
+	0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70,
+	0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+	0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+	0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00,
+	0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00,
+	0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00,
+	0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00,
+	0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
+	0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00,
+	0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F,
+	0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03,
+	0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
+	0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
+	0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+	0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36,
+	0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36,
+	0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00,
+	0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0,
+	0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
+	0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00,
+	0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00,
+	0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00,
+	0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0,
+	0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC,
+	0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00,
+	0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00,
+	0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00,
+	0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0,
+	0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00,
+	0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+	0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00,
+	0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
+	0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00,
+	0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00,
+	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
+	0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00,
+	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
+	0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+	0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C,
+	0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
+	0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// Extended set (0x80-0xFF) for Russian versions of games
+const uint8 DosFont::fontData_ExtendedRussian[128 * 8] = {
+	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
+	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
+	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
+	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
+	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
+	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
+	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
+	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
+	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
+	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
+	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
+	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
+	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
+	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
+	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
+	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
+	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
+	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
+	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
+	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
+	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
+	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
+	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
+	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
+	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
+	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
+	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
+	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
+	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
+	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
+	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
+	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
+	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
+	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
+	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
+	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
+	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
+	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
+	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
+};
+}  // end of namespace Graphics
diff --git a/graphics/fonts/dosfont.h b/graphics/fonts/dosfont.h
new file mode 100644
index 00000000000..faf545dd908
--- /dev/null
+++ b/graphics/fonts/dosfont.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef GRAPHICS_FONTS_DOSFONT_H
+#define GRAPHICS_FONTS_DOSFONT_H
+
+#include <graphics/font.h>
+
+namespace Graphics {
+
+// For now just a holder for static data. May become a child of Font if needed.
+class DosFont {
+public:
+// 8x8 font patterns
+
+// this is basically the standard PC BIOS font, taken from Dos-Box, with a few modifications
+static const uint8 fontData_PCBIOS[256 * 8];
+static const uint8 fontData_ExtendedRussian[128 * 8];
+};
+
+}
+
+#endif
diff --git a/graphics/module.mk b/graphics/module.mk
index 196be8a5265..8bc02ee268e 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS := \
 	fonts/amigafont.o \
 	fonts/bdf.o \
 	fonts/consolefont.o \
+	fonts/dosfont.o \
 	fonts/freetype.o \
 	fonts/macfont.o \
 	fonts/newfont_big.o \


Commit: 87ce98a74981a32fb3fc029123fc8a5e3fbbf972
    https://github.com/scummvm/scummvm/commit/87ce98a74981a32fb3fc029123fc8a5e3fbbf972
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add resources for EOB2 Chinese

Changed paths:
  A devtools/create_kyradat/resources/eob2_dos_chinese.h
    devtools/create_kyradat/games.cpp
    devtools/create_kyradat/resources.cpp
    dists/engine-data/kyra.dat


diff --git a/devtools/create_kyradat/games.cpp b/devtools/create_kyradat/games.cpp
index 24a3ac0e963..649d584e1b1 100644
--- a/devtools/create_kyradat/games.cpp
+++ b/devtools/create_kyradat/games.cpp
@@ -136,6 +136,7 @@ const Game eob1Games[] = {
 
 const Game eob2Games[] = {
 	{ kEoB2, kPlatformDOS, kNoSpecial, EN_ANY },
+	{ kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN },
 	{ kEoB2, kPlatformDOS, kNoSpecial, DE_DEU },
 	{ kEoB2, kPlatformDOS, kNoSpecial, ES_ESP },
 
@@ -4624,6 +4625,7 @@ const GameNeed gameNeedTable[] = {
 	{ kEoB1, kPlatformSegaCD, kNoSpecial, eob1SegaCDNeed },
 
 	{ kEoB2, kPlatformDOS, kNoSpecial, eob2FloppyNeed },
+	{ kEoB2, kPlatformDOS, kTalkieVersion, eob2FloppyNeed },
 	{ kEoB2, kPlatformAmiga, kNoSpecial, eob2AmigaNeed },
 	//{ kEoB2, kPlatformPC98, kNoSpecial, eob2PC98Need },
 	{ kEoB2, kPlatformFMTowns, kNoSpecial, eob2FMTownsNeed },
diff --git a/devtools/create_kyradat/resources.cpp b/devtools/create_kyradat/resources.cpp
index 2d556ab9b72..179ff4d2913 100644
--- a/devtools/create_kyradat/resources.cpp
+++ b/devtools/create_kyradat/resources.cpp
@@ -133,6 +133,7 @@
 
 // Eye of the Beholder: The Legend of Darkmoon
 #include "resources/eob2_dos.h"
+#include "resources/eob2_dos_chinese.h"
 #include "resources/eob2_dos_english.h"
 #include "resources/eob2_dos_german.h"
 #include "resources/eob2_dos_spanish.h"
@@ -3448,6 +3449,296 @@ static const ResourceProvider resourceProviders[] = {
 	{ kRpgCommonDscBlockMap, kEoB2, kPlatformDOS, kNoSpecial, UNK_LANG, &kEoB2DscBlockMapDOSProvider },
 	{ kRpgCommonDscDimMap, kEoB2, kPlatformDOS, kNoSpecial, UNK_LANG, &kEoB2DscDimMapDOSProvider },
 	{ kRpgCommonDscBlockIndex, kEoB2, kPlatformDOS, kNoSpecial, UNK_LANG, &kEoB2DscBlockIndexDOSProvider },
+	{ kEoBBaseNpcPresetsNames, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2NpcPresetsNamesDOSChineseProvider },
+	{ kEoBBaseChargenStrings1, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ChargenStrings1DOSChineseProvider },
+	{ kEoBBaseChargenStrings2, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ChargenStrings2DOSChineseProvider },
+	{ kEoBBaseChargenStatStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ChargenStatStringsDOSChineseProvider },
+	{ kEoBBaseChargenRaceSexStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ChargenRaceSexStringsDOSChineseProvider },
+	{ kEoBBaseChargenClassStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ChargenClassStringsDOSChineseProvider },
+	{ kEoBBaseChargenAlignmentStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ChargenAlignmentStringsDOSChineseProvider },
+	{ kEoBBaseChargenEnterGameStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ChargenEnterGameStringsDOSChineseProvider },
+	{ kEoBBasePryDoorStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2PryDoorStringsDOSChineseProvider },
+	{ kEoBBaseWarningStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2WarningStringsDOSChineseProvider },
+	{ kEoBBaseItemSuffixStringsRings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ItemSuffixStringsRingsDOSChineseProvider },
+	{ kEoBBaseItemSuffixStringsPotions, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ItemSuffixStringsPotionsDOSChineseProvider },
+	{ kEoBBaseItemSuffixStringsWands, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ItemSuffixStringsWandsDOSChineseProvider },
+	{ kEoBBaseRipItemStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2RipItemStringsDOSChineseProvider },
+	{ kEoBBaseCursedString, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CursedStringDOSChineseProvider },
+	{ kEoBBaseMagicObjectStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicObjectStringsDOSChineseProvider },
+	{ kEoBBaseMagicObjectString5, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicObjectString5DOSChineseProvider },
+	{ kEoBBasePatternSuffix, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2PatternSuffixDOSChineseProvider },
+	{ kEoBBasePatternGrFix1, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2PatternGrFix1DOSChineseProvider },
+	{ kEoBBasePatternGrFix2, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2PatternGrFix2DOSChineseProvider },
+	{ kEoBBaseValidateArmorString, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ValidateArmorStringDOSChineseProvider },
+	{ kEoBBaseValidateCursedString, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ValidateCursedStringDOSChineseProvider },
+	{ kEoBBaseValidateNoDropString, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ValidateNoDropStringDOSChineseProvider },
+	{ kEoBBasePotionStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2PotionStringsDOSChineseProvider },
+	{ kEoBBaseWandStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2WandStringsDOSChineseProvider },
+	{ kEoBBaseItemMisuseStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ItemMisuseStringsDOSChineseProvider },
+	{ kEoBBaseTakenStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2TakenStringsDOSChineseProvider },
+	{ kEoBBasePotionEffectStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2PotionEffectStringsDOSChineseProvider },
+	{ kEoBBaseYesNoStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2YesNoStringsDOSChineseProvider },
+	{ kRpgCommonMoreStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MoreStringsDOSChineseProvider },
+	{ kEoBBaseNpcMaxStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2NpcMaxStringsDOSChineseProvider },
+	{ kEoBBaseOkStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2OkStringsDOSChineseProvider },
+	{ kEoBBaseNpcJoinStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2NpcJoinStringsDOSChineseProvider },
+	{ kEoBBaseCancelStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CancelStringsDOSChineseProvider },
+	{ kEoBBaseAbortStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2AbortStringsDOSChineseProvider },
+	{ kEoBBaseMenuStringsMain, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsMainDOSChineseProvider },
+	{ kEoBBaseMenuStringsSaveLoad, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsSaveLoadDOSChineseProvider },
+	{ kEoBBaseMenuStringsOnOff, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsOnOffDOSChineseProvider },
+	{ kEoBBaseMenuStringsSpells, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsSpellsDOSChineseProvider },
+	{ kEoBBaseMenuStringsRest, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsRestDOSChineseProvider },
+	{ kEoBBaseMenuStringsDrop, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsDropDOSChineseProvider },
+	{ kEoBBaseMenuStringsExit, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsExitDOSChineseProvider },
+	{ kEoBBaseMenuStringsStarve, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsStarveDOSChineseProvider },
+	{ kEoBBaseMenuStringsScribe, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsScribeDOSChineseProvider },
+	{ kEoBBaseMenuStringsDrop2, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsDrop2DOSChineseProvider },
+	{ kEoBBaseMenuStringsHead, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsHeadDOSChineseProvider },
+	{ kEoBBaseMenuStringsPoison, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsPoisonDOSChineseProvider },
+	{ kEoBBaseMenuStringsMgc, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsMgcDOSChineseProvider },
+	{ kEoBBaseMenuStringsPrefs, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsPrefsDOSChineseProvider },
+	{ kEoBBaseMenuStringsRest2, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsRest2DOSChineseProvider },
+	{ kEoBBaseMenuStringsRest3, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsRest3DOSChineseProvider },
+	{ kEoBBaseMenuStringsRest4, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsRest4DOSChineseProvider },
+	{ kEoBBaseMenuStringsDefeat, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsDefeatDOSChineseProvider },
+	{ kEoBBaseMenuStringsTransfer, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsTransferDOSChineseProvider },
+	{ kEoBBaseMenuStringsSpec, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuStringsSpecDOSChineseProvider },
+	{ kEoBBaseMenuYesNoStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MenuYesNoStringsDOSChineseProvider },
+	{ kEoBBaseCharGuiStringsHp, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharGuiStringsHpDOSChineseProvider },
+	{ kEoBBaseCharGuiStringsWp2, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharGuiStringsWp2DOSChineseProvider },
+	{ kEoBBaseCharGuiStringsWr, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharGuiStringsWrDOSChineseProvider },
+	{ kEoBBaseCharGuiStringsSt2, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharGuiStringsSt2DOSChineseProvider },
+	{ kEoBBaseCharGuiStringsIn, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharGuiStringsInDOSChineseProvider },
+	{ kEoBBaseCharStatusStrings7, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharStatusStrings7DOSChineseProvider },
+	{ kEoBBaseCharStatusStrings82, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharStatusStrings82DOSChineseProvider },
+	{ kEoBBaseCharStatusStrings9, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharStatusStrings9DOSChineseProvider },
+	{ kEoBBaseCharStatusStrings12, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharStatusStrings12DOSChineseProvider },
+	{ kEoBBaseCharStatusStrings132, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CharStatusStrings132DOSChineseProvider },
+	{ kEoBBaseLevelGainStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2LevelGainStringsDOSChineseProvider },
+	{ kEoBBaseBookNumbers, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2BookNumbersDOSChineseProvider },
+	{ kEoBBaseMageSpellsList, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MageSpellsListDOSChineseProvider },
+	{ kEoBBaseClericSpellsList, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ClericSpellsListDOSChineseProvider },
+	{ kEoBBaseSpellNames, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2SpellNamesDOSChineseProvider },
+	{ kEoBBaseMagicStrings1, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicStrings1DOSChineseProvider },
+	{ kEoBBaseMagicStrings2, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicStrings2DOSChineseProvider },
+	{ kEoBBaseMagicStrings3, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicStrings3DOSChineseProvider },
+	{ kEoBBaseMagicStrings4, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicStrings4DOSChineseProvider },
+	{ kEoBBaseMagicStrings6, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicStrings6DOSChineseProvider },
+	{ kEoBBaseMagicStrings7, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicStrings7DOSChineseProvider },
+	{ kEoBBaseMagicStrings8, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MagicStrings8DOSChineseProvider },
+	{ kEoBBaseManDef, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ManDefDOSChineseProvider },
+	{ kEoBBaseManWord, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ManWordDOSChineseProvider },
+	{ kEoBBaseManPrompt, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2ManPromptDOSChineseProvider },
+	{ kEoB2MainMenuStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MainMenuStringsDOSChineseProvider },
+	{ kEoB2TransferStrings1, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2TransferStrings1DOSChineseProvider },
+	{ kEoB2TransferStrings2, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2TransferStrings2DOSChineseProvider },
+	{ kEoB2TransferLabels, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2TransferLabelsDOSChineseProvider },
+	{ kEoB2IntroStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2IntroStringsDOSChineseProvider },
+	{ kEoB2IntroCPSFiles, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2IntroCPSFilesDOSChineseProvider },
+	{ kEoB2FinaleStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2FinaleStringsDOSChineseProvider },
+	{ kEoB2CreditsData, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2CreditsDataDOSEnglishProvider },
+	{ kEoB2FinaleCPSFiles, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2FinaleCPSFilesDOSChineseProvider },
+	{ kEoBBaseMonsterDistAttStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MonsterDistAttStringsDOSChineseProvider },
+	{ kEoB2Npc1Strings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2Npc1StringsDOSChineseProvider },
+	{ kEoB2Npc2Strings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2Npc2StringsDOSChineseProvider },
+	{ kEoB2MonsterDustStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2MonsterDustStringsDOSChineseProvider },
+	{ kEoB2KheldranStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2KheldranStringsDOSChineseProvider },
+	{ kEoB2HornStrings, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2HornStringsDOSChineseProvider },
+	{ kEoB2IntroAnimData40, kEoB2, kPlatformDOS, kTalkieVersion, ZH_TWN, &kEoB2IntroAnimData40DOSChineseProvider },
+	{ kEoBBaseChargenStartLevels, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ChargenStartLevelsDOSProvider },
+	{ kEoBBaseChargenClassMinStats, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ChargenClassMinStatsDOSProvider },
+	{ kEoBBaseChargenRaceMinStats, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ChargenRaceMinStatsDOSProvider },
+	{ kEoBBaseChargenRaceMaxStats, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ChargenRaceMaxStatsDOSProvider },
+	{ kEoBBaseSaveThrowTable1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SaveThrowTable1DOSProvider },
+	{ kEoBBaseSaveThrowTable2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SaveThrowTable2DOSProvider },
+	{ kEoBBaseSaveThrowTable3, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SaveThrowTable3DOSProvider },
+	{ kEoBBaseSaveThrowTable4, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SaveThrowTable4DOSProvider },
+	{ kEoBBaseSaveThrwLvlIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SaveThrwLvlIndexDOSProvider },
+	{ kEoBBaseSaveThrwModDiv, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SaveThrwModDivDOSProvider },
+	{ kEoBBaseSaveThrwModExt, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SaveThrwModExtDOSProvider },
+	{ kEoBBaseEnchantedString, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2EnchantedStringDOSProvider },
+	{ kEoBBaseMenuStringsSpellNo, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MenuStringsSpellNoDOSProvider },
+	{ kEoBBaseSpellLevelsMage, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SpellLevelsMageDOSProvider },
+	{ kEoBBaseSpellLevelsCleric, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SpellLevelsClericDOSProvider },
+	{ kEoBBaseNumSpellsCleric, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2NumSpellsClericDOSProvider },
+	{ kEoBBaseNumSpellsWisAdj, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2NumSpellsWisAdjDOSProvider },
+	{ kEoBBaseNumSpellsPal, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2NumSpellsPalDOSProvider },
+	{ kEoBBaseNumSpellsMage, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2NumSpellsMageDOSProvider },
+	{ kEoBBaseExperienceTable0, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExperienceTable0DOSProvider },
+	{ kEoBBaseExperienceTable1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExperienceTable1DOSProvider },
+	{ kEoBBaseExperienceTable2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExperienceTable2DOSProvider },
+	{ kEoBBaseExperienceTable3, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExperienceTable3DOSProvider },
+	{ kEoBBaseExperienceTable4, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExperienceTable4DOSProvider },
+	{ kEoBBaseExpObjectTlMode, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExpObjectTlModeDOSProvider },
+	{ kEoBBaseExpObjectTblIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExpObjectTblIndexDOSProvider },
+	{ kEoBBaseExpObjectShpStart, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExpObjectShpStartDOSProvider },
+	{ kEoBBaseExpObjectTbl1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExpObjectTbl1DOSProvider },
+	{ kEoBBaseExpObjectTbl2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExpObjectTbl2DOSProvider },
+	{ kEoBBaseExpObjectTbl3, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExpObjectTbl3DOSProvider },
+	{ kEoBBaseExpObjectY, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ExpObjectYDOSProvider },
+	{ kEoBBaseSparkDefSteps, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkDefStepsDOSProvider },
+	{ kEoBBaseSparkDefSubSteps, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkDefSubStepsDOSProvider },
+	{ kEoBBaseSparkDefShift, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkDefShiftDOSProvider },
+	{ kEoBBaseSparkDefAdd, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkDefAddDOSProvider },
+	{ kEoBBaseSparkDefX, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkDefXDOSProvider },
+	{ kEoBBaseSparkDefY, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkDefYDOSProvider },
+	{ kEoBBaseSparkOfFlags1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkOfFlags1DOSProvider },
+	{ kEoBBaseSparkOfFlags2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkOfFlags2DOSProvider },
+	{ kEoBBaseSparkOfShift, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkOfShiftDOSProvider },
+	{ kEoBBaseSparkOfX, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkOfXDOSProvider },
+	{ kEoBBaseSparkOfY, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SparkOfYDOSProvider },
+	{ kEoBBaseSpellProperties, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SpellPropertiesDOSProvider },
+	{ kEoBBaseMagicFlightProps, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MagicFlightPropsDOSProvider },
+	{ kEoBBaseTurnUndeadEffect, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2TurnUndeadEffectDOSProvider },
+	{ kEoBBaseBurningHandsDest, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2BurningHandsDestDOSProvider },
+	{ kEoBBaseConeOfColdDest1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ConeOfColdDest1DOSProvider },
+	{ kEoBBaseConeOfColdDest2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ConeOfColdDest2DOSProvider },
+	{ kEoBBaseConeOfColdDest3, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ConeOfColdDest3DOSProvider },
+	{ kEoBBaseConeOfColdDest4, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ConeOfColdDest4DOSProvider },
+	{ kEoBBaseConeOfColdGfxTbl, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ConeOfColdGfxTblDOSProvider },
+	{ kRpgCommonDscDoorShapeIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorShapeIndexDOSProvider },
+	{ kEoBBaseWllFlagPreset, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2WllFlagPresetDOSProvider },
+	{ kEoBBaseDscShapeCoords, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscShapeCoordsDOSProvider },
+	{ kRpgCommonDscDoorScaleOffs, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorScaleOffsDOSProvider },
+	{ kEoBBaseDscDoorScaleMult1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorScaleMult1DOSProvider },
+	{ kEoBBaseDscDoorScaleMult2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorScaleMult2DOSProvider },
+	{ kEoBBaseDscDoorScaleMult3, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorScaleMult3DOSProvider },
+	{ kEoBBaseDscDoorType5Offs, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorType5OffsDOSProvider },
+	{ kEoBBaseDscDoorY1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorY1DOSProvider },
+	{ kRpgCommonDscDoorY2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorY2DOSProvider },
+	{ kRpgCommonDscDoorFrameY1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorFrameY1DOSProvider },
+	{ kRpgCommonDscDoorFrameY2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDoorFrameY2DOSProvider },
+	{ kEoBBaseDscItemPosIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscItemPosIndexDOSProvider },
+	{ kEoBBaseDscItemShpX, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscItemShpXDOSProvider },
+	{ kEoBBaseDscItemScaleIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscItemScaleIndexDOSProvider },
+	{ kEoBBaseDscItemTileIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscItemTileIndexDOSProvider },
+	{ kEoBBaseDscItemShapeMap, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscItemShapeMapDOSProvider },
+	{ kEoBBaseDscTelptrShpCoords, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscTelptrShpCoordsDOSProvider },
+	{ kEoBBasePortalSeqData, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2PortalSeqDataDOSProvider },
+	{ kEoBBaseDscMonsterFrmOffsTbl1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscMonsterFrmOffsTbl1DOSProvider },
+	{ kEoBBaseDscMonsterFrmOffsTbl2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscMonsterFrmOffsTbl2DOSProvider },
+	{ kEoBBaseInvSlotX, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2InvSlotXDOSProvider },
+	{ kEoBBaseInvSlotY, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2InvSlotYDOSProvider },
+	{ kEoBBaseSlotValidationFlags, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SlotValidationFlagsDOSProvider },
+	{ kEoBBaseProjectileWeaponTypes, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ProjectileWeaponTypesDOSProvider },
+	{ kEoBBaseWandTypes, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2WandTypesDOSProvider },
+	{ kEoBBaseDrawObjPosIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DrawObjPosIndexDOSProvider },
+	{ kEoBBaseFlightObjFlipIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FlightObjFlipIndexDOSProvider },
+	{ kEoBBaseFlightObjShpMap, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FlightObjShpMapDOSProvider },
+	{ kEoBBaseFlightObjSclIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FlightObjSclIndexDOSProvider },
+	{ kEoB2TransferPortraitFrames, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2TransferPortraitFramesDOSProvider },
+	{ kEoB2TransferConvertTable, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2TransferConvertTableDOSProvider },
+	{ kEoB2TransferItemTable, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2TransferItemTableDOSProvider },
+	{ kEoB2TransferExpTable, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2TransferExpTableDOSProvider },
+	{ kEoB2IntroAnimData00, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData00DOSProvider },
+	{ kEoB2IntroAnimData01, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData01DOSProvider },
+	{ kEoB2IntroAnimData02, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData02DOSProvider },
+	{ kEoB2IntroAnimData03, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData03DOSProvider },
+	{ kEoB2IntroAnimData04, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData04DOSProvider },
+	{ kEoB2IntroAnimData05, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData05DOSProvider },
+	{ kEoB2IntroAnimData06, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData06DOSProvider },
+	{ kEoB2IntroAnimData07, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData07DOSProvider },
+	{ kEoB2IntroAnimData08, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData08DOSProvider },
+	{ kEoB2IntroAnimData09, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData09DOSProvider },
+	{ kEoB2IntroAnimData10, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData10DOSProvider },
+	{ kEoB2IntroAnimData11, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData11DOSProvider },
+	{ kEoB2IntroAnimData12, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData12DOSProvider },
+	{ kEoB2IntroAnimData13, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData13DOSProvider },
+	{ kEoB2IntroAnimData14, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData14DOSProvider },
+	{ kEoB2IntroAnimData15, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData15DOSProvider },
+	{ kEoB2IntroAnimData16, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData16DOSProvider },
+	{ kEoB2IntroAnimData17, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData17DOSProvider },
+	{ kEoB2IntroAnimData18, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData18DOSProvider },
+	{ kEoB2IntroAnimData19, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData19DOSProvider },
+	{ kEoB2IntroAnimData20, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData20DOSProvider },
+	{ kEoB2IntroAnimData21, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData21DOSProvider },
+	{ kEoB2IntroAnimData22, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData22DOSProvider },
+	{ kEoB2IntroAnimData23, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData23DOSProvider },
+	{ kEoB2IntroAnimData24, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData24DOSProvider },
+	{ kEoB2IntroAnimData25, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData25DOSProvider },
+	{ kEoB2IntroAnimData26, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData26DOSProvider },
+	{ kEoB2IntroAnimData27, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData27DOSProvider },
+	{ kEoB2IntroAnimData28, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData28DOSProvider },
+	{ kEoB2IntroAnimData29, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData29DOSProvider },
+	{ kEoB2IntroAnimData30, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData30DOSProvider },
+	{ kEoB2IntroAnimData31, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData31DOSProvider },
+	{ kEoB2IntroAnimData32, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData32DOSProvider },
+	{ kEoB2IntroAnimData33, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData33DOSProvider },
+	{ kEoB2IntroAnimData34, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData34DOSProvider },
+	{ kEoB2IntroAnimData35, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData35DOSProvider },
+	{ kEoB2IntroAnimData36, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData36DOSProvider },
+	{ kEoB2IntroAnimData37, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData37DOSProvider },
+	{ kEoB2IntroAnimData38, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData38DOSProvider },
+	{ kEoB2IntroAnimData39, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData39DOSProvider },
+	{ kEoB2IntroAnimData41, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData41DOSProvider },
+	{ kEoB2IntroAnimData42, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData42DOSProvider },
+	{ kEoB2IntroAnimData43, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroAnimData43DOSProvider },
+	{ kEoB2IntroShapes00, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroShapes00DOSProvider },
+	{ kEoB2IntroShapes01, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroShapes01DOSProvider },
+	{ kEoB2IntroShapes04, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroShapes04DOSProvider },
+	{ kEoB2IntroShapes07, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2IntroShapes07DOSProvider },
+	{ kEoB2FinaleAnimData00, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData00DOSProvider },
+	{ kEoB2FinaleAnimData01, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData01DOSProvider },
+	{ kEoB2FinaleAnimData02, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData02DOSProvider },
+	{ kEoB2FinaleAnimData03, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData03DOSProvider },
+	{ kEoB2FinaleAnimData04, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData04DOSProvider },
+	{ kEoB2FinaleAnimData05, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData05DOSProvider },
+	{ kEoB2FinaleAnimData06, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData06DOSProvider },
+	{ kEoB2FinaleAnimData07, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData07DOSProvider },
+	{ kEoB2FinaleAnimData08, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData08DOSProvider },
+	{ kEoB2FinaleAnimData09, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData09DOSProvider },
+	{ kEoB2FinaleAnimData10, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData10DOSProvider },
+	{ kEoB2FinaleAnimData11, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData11DOSProvider },
+	{ kEoB2FinaleAnimData12, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData12DOSProvider },
+	{ kEoB2FinaleAnimData13, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData13DOSProvider },
+	{ kEoB2FinaleAnimData14, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData14DOSProvider },
+	{ kEoB2FinaleAnimData15, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData15DOSProvider },
+	{ kEoB2FinaleAnimData16, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData16DOSProvider },
+	{ kEoB2FinaleAnimData17, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData17DOSProvider },
+	{ kEoB2FinaleAnimData18, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData18DOSProvider },
+	{ kEoB2FinaleAnimData19, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData19DOSProvider },
+	{ kEoB2FinaleAnimData20, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleAnimData20DOSProvider },
+	{ kEoB2FinaleShapes00, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleShapes00DOSProvider },
+	{ kEoB2FinaleShapes03, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleShapes03DOSProvider },
+	{ kEoB2FinaleShapes07, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleShapes07DOSProvider },
+	{ kEoB2FinaleShapes09, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleShapes09DOSProvider },
+	{ kEoB2FinaleShapes10, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FinaleShapes10DOSProvider },
+	{ kEoB2NpcShapeData, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2NpcShapeDataDOSProvider },
+	{ kEoBBaseClassModifierFlags, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2ClassModifierFlagsDOSProvider },
+	{ kEoBBaseMonsterStepTable02, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterStepTable02DOSProvider },
+	{ kEoBBaseMonsterStepTable1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterStepTable1DOSProvider },
+	{ kEoBBaseMonsterStepTable2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterStepTable2DOSProvider },
+	{ kEoBBaseMonsterStepTable3, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterStepTable3DOSProvider },
+	{ kEoBBaseMonsterCloseAttPosTable1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterCloseAttPosTable1DOSProvider },
+	{ kEoBBaseMonsterCloseAttPosTable22, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterCloseAttPosTable22DOSProvider },
+	{ kEoBBaseMonsterCloseAttUnkTable, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterCloseAttUnkTableDOSProvider },
+	{ kEoBBaseMonsterCloseAttChkTable1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterCloseAttChkTable1DOSProvider },
+	{ kEoBBaseMonsterCloseAttChkTable2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterCloseAttChkTable2DOSProvider },
+	{ kEoBBaseMonsterCloseAttDstTable1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterCloseAttDstTable1DOSProvider },
+	{ kEoBBaseMonsterCloseAttDstTable2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterCloseAttDstTable2DOSProvider },
+	{ kEoBBaseMonsterProximityTable, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterProximityTableDOSProvider },
+	{ kEoBBaseFindBlockMonstersTable, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2FindBlockMonstersTableDOSProvider },
+	{ kEoBBaseMonsterDirChangeTable, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2MonsterDirChangeTableDOSProvider },
+	{ kEoBBaseEncodeMonsterDefs, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2EncodeMonsterDefsDOSProvider },
+	{ kEoBBaseNpcPresets, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2NpcPresetsDOSProvider },
+	{ kEoBBaseSoundFilesIntro, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SoundFilesIntroDOSProvider },
+	{ kEoBBaseSoundFilesFinale, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2SoundFilesFinaleDOSProvider },
+	{ kEoB2DreamSteps, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DreamStepsDOSProvider },
+	{ kEoB2HornSounds, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2HornSoundsDOSProvider },
+	{ kEoB2WallOfForceDsX, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2WallOfForceDsXDOSProvider },
+	{ kEoB2WallOfForceDsY, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2WallOfForceDsYDOSProvider },
+	{ kEoB2WallOfForceNumW, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2WallOfForceNumWDOSProvider },
+	{ kEoB2WallOfForceNumH, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2WallOfForceNumHDOSProvider },
+	{ kEoB2WallOfForceShpId, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2WallOfForceShpIdDOSProvider },
+	{ kRpgCommonDscShapeIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscShapeIndexDOSProvider },
+	{ kRpgCommonDscX, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscXDOSProvider },
+	{ kRpgCommonDscTileIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscTileIndexDOSProvider },
+	{ kRpgCommonDscDimData1, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDimData1DOSProvider },
+	{ kRpgCommonDscDimData2, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDimData2DOSProvider },
+	{ kRpgCommonDscBlockMap, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscBlockMapDOSProvider },
+	{ kRpgCommonDscDimMap, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscDimMapDOSProvider },
+	{ kRpgCommonDscBlockIndex, kEoB2, kPlatformDOS, kTalkieVersion, UNK_LANG, &kEoB2DscBlockIndexDOSProvider },
 	{ kEoBBaseNpcPresetsNames, kEoB2, kPlatformDOS, kNoSpecial, DE_DEU, &kEoB2NpcPresetsNamesDOSGermanProvider },
 	{ kEoBBaseChargenStrings1, kEoB2, kPlatformDOS, kNoSpecial, DE_DEU, &kEoB2ChargenStrings1DOSGermanProvider },
 	{ kEoBBaseChargenStrings2, kEoB2, kPlatformDOS, kNoSpecial, DE_DEU, &kEoB2ChargenStrings2DOSGermanProvider },
diff --git a/devtools/create_kyradat/resources/eob2_dos_chinese.h b/devtools/create_kyradat/resources/eob2_dos_chinese.h
new file mode 100644
index 00000000000..fb971cedcfb
--- /dev/null
+++ b/devtools/create_kyradat/resources/eob2_dos_chinese.h
@@ -0,0 +1,1085 @@
+static const char *const kEoB2ChargenStrings1DOSChinese[9] = {
+	"\xaa\xba\xab\x5f\xc0\x49\xb6\xa4\xa5\xee\xa4\x77\xab\xd8\xa5\xdf\xa7\xb9\xb2\xa6\x2c\xbd\xd0\xb1\x4e\xab\xfc\xbc\xd0\xb2\xbe\xa8\xec\x5b\x50\x4c\x41\x59\x5d\xab\xf6\xa4\x55\xa5\xaa\xc1\xe4\x2c\xa9\xce\xab\xf6\x5b\x50\x5d\xc1\xe4\x2c\xb6\x7d\xa9\x6c\xb1\x7a\xaa\xba\xab\x5f\xc0\x49\xae\xc8\xb5\x7b", /* "的冒險隊伍已建立完畢,請將指標移到[PLAY]按下左鍵,或按[P]鍵,開始您的冒險旅程"; */
+	"          ",
+	"\xa8\xbe\x3a\r\xa9\x52\x3a\r\xaf\xc5\x3a", /* "防:\r命:\r級:"; */
+	"%s\r%d\r%d\r%d\r%d\r%d",
+	"%d\r%d",
+	"%d",
+	"%d/%d",
+	"%d/%d/%d",
+	"\xbd\xd0\xa5\xfd\xbf\xef\xbe\xdc\xa4\x40\xad\xd3\xa9\xf1\xb8\x6d\r\xa4\x48\xaa\xab\xb9\xcf\xa4\xf9\xaa\xba\xa4\xe8\xae\xd8\x2e", /* "請先選擇一個放置\r人物圖片的方框."; */
+};
+
+static const StringListProvider kEoB2ChargenStrings1DOSChineseProvider = { ARRAYSIZE(kEoB2ChargenStrings1DOSChinese), kEoB2ChargenStrings1DOSChinese };
+
+static const char *const kEoB2ChargenStrings2DOSChinese[12] = {
+	"%s",
+	"%d",
+	"%s",
+	"%d",
+	"%d",
+	"%d",
+	"%s",
+	"%d",
+	"\xbf\xef\xbe\xdc\xba\xd8\xb1\xda\x3a", /* "選擇種族:"; */
+	"\xbf\xef\xc2\xbe\xb7\x7e", /* "選職業"; */
+	"\xbf\xef\xbe\xdc\xb0\x7d\xc0\xe7\x3a", /* "選擇陣營:"; */
+	"\xbf\xe9\xa4\x4a\xa9\x6d\xa6\x57\x3a", /* "輸入姓名:"; */
+};
+
+static const StringListProvider kEoB2ChargenStrings2DOSChineseProvider = { ARRAYSIZE(kEoB2ChargenStrings2DOSChinese), kEoB2ChargenStrings2DOSChinese };
+
+static const char *const kEoB2ChargenStatStringsDOSChinese[12] = {
+	"\xa4\x4f\x3a", /* "力:"; */
+	"\xb4\xbc\x3a", /* "智:"; */
+	"\xbe\xc7\x3a", /* "å­¸:"; */
+	"\xb1\xd3\x3a", /* "敏:"; */
+	"\xc5\xe9\x3a", /* "é«”:"; */
+	"\xbe\x79\x3a", /* "é­…:"; */
+	"\xa4\x4f\xb6\x71\x3a", /* "力量:"; */
+	"\xb4\xbc\xaf\xe0\x3a", /* "智能:"; */
+	"\xbe\xc7\xb0\xdd\x3a", /* "學問:"; */
+	"\xb1\xd3\xb1\xb6\x3a", /* "敏捷:"; */
+	"\xc5\xe9\xbd\xe8\x3a", /* "體質:"; */
+	"\xbe\x79\xa4\x4f\x3a", /* "魅力:"; */
+};
+
+static const StringListProvider kEoB2ChargenStatStringsDOSChineseProvider = { ARRAYSIZE(kEoB2ChargenStatStringsDOSChinese), kEoB2ChargenStatStringsDOSChinese }; // Likely OK
+
+static const char *const kEoB2ChargenRaceSexStringsDOSChinese[12] = {
+	"\xa8\x6b\xa9\xca\xa4\x48\xc3\xfe", /* "男性人類"; */
+	"\xa4\x6b\xa9\xca\xa4\x48\xc3\xfe", /* "女性人類"; */
+	"\xa8\x6b\xa9\xca\xba\xeb\xc6\x46", /* "男性精靈"; */
+	"\xa4\x6b\xa9\xca\xba\xeb\xc6\x46", /* "女性精靈"; */
+	"\xa8\x6b\xa5\x62\xba\xeb\xc6\x46", /* "男半精靈"; */
+	"\xa4\x6b\xa5\x62\xba\xeb\xc6\x46", /* "女半精靈"; */
+	"\xa8\x6b\xa9\xca\xb8\x47\xa4\x48", /* "男性矮人"; */
+	"\xa4\x6b\xa9\xca\xb8\x47\xa4\x48", /* "女性矮人"; */
+	"\xa8\x6b\xa9\xca\xa8\xdc\xbe\xa7", /* "男性侏儒"; */
+	"\xa4\x6b\xa9\xca\xa8\xdc\xbe\xa7", /* "女性侏儒"; */
+	"\xa8\x6b\xa5\x62\xa8\xad\xa4\x48", /* "男半身人"; */
+	"\xa4\x6b\xa5\x62\xa8\xad\xa4\x48", /* "女半身人"; */
+};
+
+static const StringListProvider kEoB2ChargenRaceSexStringsDOSChineseProvider = { ARRAYSIZE(kEoB2ChargenRaceSexStringsDOSChinese), kEoB2ChargenRaceSexStringsDOSChinese };
+
+static const char *const kEoB2ChargenClassStringsDOSChinese[21] = {
+	"\xbe\xd4\xa4\x68", /* "戰士"; */
+	"\xb9\x43\xab\x4c", /* "遊俠"; */
+	"\xaa\x5a\xa4\x68", /* "武士"; */
+	"\xa7\xc5\xae\x76", /* "巫師"; */
+	"\xaa\xaa\xae\x76", /* "牧師"; */
+	"\xa4\x70\xb0\xbd", /* "小偷"; */
+	"\xbe\xd4\xa4\x68\x2f\xaa\xaa\xae\x76", /* "戰士/牧師"; */
+	"\xbe\xd4\xa4\x68\x2f\xa4\x70\xb0\xbd", /* "戰士/小偷"; */
+	"\xbe\xd4\xa4\x68\x2f\xa7\xc5\xae\x76", /* "戰士/巫師"; */
+	"\xbe\xd4\xa4\x68\x2f\xa7\xc5\xae\x76\x2f\xa4\x70\xb0\xbd", /* "戰士/巫師/小偷"; */
+	"\xa4\x70\xb0\xbd\x2f\xa7\xc5\xae\x76", /* "小偷/巫師"; */
+	"\xaa\xaa\xae\x76\x2f\xa4\x70\xb0\xbd", /* "牧師/小偷"; */
+	"\xbe\xd4\xa4\x68\x2f\xaa\xaa\xae\x76\x2f\xa7\xc5\xae\x76", /* "戰士/牧師/巫師"; */
+	"\xb9\x43\xab\x4c\x2f\xaa\xaa\xae\x76", /* "遊俠/牧師"; */
+	"\xaa\xaa\xae\x76\x2f\xa7\xc5\xae\x76", /* "牧師/巫師"; */
+	"\xbe\xd4\xa4\x68", /* "戰士"; */
+	"\xa7\xc5\xae\x76", /* "巫師"; */
+	"\xaa\xaa\xae\x76", /* "牧師"; */
+	"\xa4\x70\xb0\xbd", /* "小偷"; */
+	"\xaa\x5a\xa4\x68", /* "武士"; */
+	"\xb9\x43\xab\x4c", /* "遊俠"; */
+};
+
+static const StringListProvider kEoB2ChargenClassStringsDOSChineseProvider = { ARRAYSIZE(kEoB2ChargenClassStringsDOSChinese), kEoB2ChargenClassStringsDOSChinese };
+
+static const char *const kEoB2ChargenAlignmentStringsDOSChinese[9] = {
+	"\xb5\xb4\xb9\xef\xb5\xbd\xa8\x7d", /* "絕對善良"; */
+	"\xb5\xbd\xa8\x7d\xa5\xbb\xa9\xca", /* "善良本性"; */
+	"\xa6\xfd\xa8\x44\xa6\x77\xa4\xdf", /* "但求安心"; */
+	"\xc4\x59\xa6\x75\xa4\xa4\xa5\xdf", /* "嚴守中立"; */
+	"\xa4\xa4\xa5\xdf\xa5\xbb\xa6\xec", /* "中立本位"; */
+	"\xc0\x48\xbe\xf7\xc0\xb3\xc5\xdc", /* "隨機應變"; */
+	"\xa7\xb9\xa5\xfe\xa8\xb8\xb4\x63", /* "完全邪惡"; */
+	"\xa8\xb8\xb4\x63\xa5\xbb\xa9\xca", /* "邪惡本性"; */
+	"\xc0\x48\xbf\xb3\xac\xb0\xb4\x63", /* "隨興為惡"; */
+};
+
+static const StringListProvider kEoB2ChargenAlignmentStringsDOSChineseProvider = { ARRAYSIZE(kEoB2ChargenAlignmentStringsDOSChinese), kEoB2ChargenAlignmentStringsDOSChinese };
+
+static const char *const kEoB2ChargenEnterGameStringsDOSChinese[1] = {
+	"\xb8\xfc\xa4\x4a\xb9\x43\xc0\xb8\xa4\xa4\x21\xbd\xd0\xb5\x79\xb5\xa5\x2e\x2e\x2e", /* "載入遊戲中!請稍等..."; */
+};
+
+static const StringListProvider kEoB2ChargenEnterGameStringsDOSChineseProvider = { ARRAYSIZE(kEoB2ChargenEnterGameStringsDOSChinese), kEoB2ChargenEnterGameStringsDOSChinese };
+
+static const char *const kEoB2PryDoorStringsDOSChinese[8] = {
+	"\r",
+	"\xb1\x7a\xaa\xba\xa4\x4f\xb6\x71\xa4\xa3\xb0\xf7\xbc\xb2\xb6\x7d\xb3\x6f\xb9\x44\xaa\xf9\x2e\r", /* "您的力量不夠撞開這道門."; */
+	"\x06\x04\xb1\x7a\xa5\xce\xa4\x4f\xbc\xb2\xaa\xf9\x2e\r", /* "\x06\x04您用力撞門."; */
+	"\x06\x06\xb1\x7a\xb9\xc1\xb8\xd5\xb1\x4e\xaa\xf9\xbc\xb2\xb6\x7d\x2c\xa6\xfd\xac\x4f\xb1\x7a\xa5\xa2\xb1\xd1\xa4\x46\x2e\r", /* "\x06\x06您嘗試將門撞開,但是您失敗了."; */
+	"\xb1\x7a\xa4\xa3\xaf\xe0\xb1\x4e\xb3\x6f\xb6\xb5\xaa\xab\xab\x7e\xa9\xf1\xb8\x6d\xa9\xf3\xa6\xb9\xb3\x42\x2e\r", /* "您不能將這項物品放置於此處."; */
+	"\xb3\x6f\xaa\xab\xab\x7e\xa4\xd3\xa4\x6a\xa4\x46\x2c\xb1\x7a\xa9\xf1\xa4\xa3\xb6\x69\xa5\x68\x2e\r", /* "這物品太大了,您放不進去."; */
+	"\xa8\x53\xa6\xb3\xa4\x48\xaf\xe0\xb0\xf7\xb1\x4e\xb3\x6f\xb9\x44\xaa\xf9\xa5\xb4\xb6\x7d\x2e\r", /* "沒有人能夠將這道門打開."; */
+	"\r"
+};
+
+static const StringListProvider kEoB2PryDoorStringsDOSChineseProvider = { ARRAYSIZE(kEoB2PryDoorStringsDOSChinese), kEoB2PryDoorStringsDOSChinese };
+
+static const char *const kEoB2WarningStringsDOSChinese[4] = {
+	"\xb1\x7a\xb5\x4c\xaa\x6b\xa8\xab\xb9\x4c\xa5\x68\x2e\r", /* "您無法走過去."; */
+	"%s\xa4\x77\xb8\x67\xb5\x4c\xaa\x6b\xa6\x59\xaa\x46\xa6\xe8\xa4\x46\x21\r", /* "%s已經無法吃東西了!"; */
+	"\xb3\x6f\xad\xb9\xaa\xab\xa4\x77\xb8\x67\xbb\x47\xc3\x61\xa4\x46\x21\xb1\x7a\xa4\xa3\xad\x6e\xa6\x59\x21\r", /* "這食物已經腐壞了!您不要吃!"; */
+	"\xb1\x7a\xa5\x75\xaf\xe0\xb0\xf7\xa6\x59\xad\xb9\xaa\xab\x21\r", /* "您只能夠吃食物!"; */
+};
+
+static const StringListProvider kEoB2WarningStringsDOSChineseProvider = { ARRAYSIZE(kEoB2WarningStringsDOSChinese), kEoB2WarningStringsDOSChinese };
+
+static const char *const kEoB2ItemSuffixStringsRingsDOSChinese[4] = {
+	"\xaf\xc2\xba\xe9\xb8\xcb\xb9\xa2\xac\xfc\xc6\x5b\xa5\xce", /* "純粹裝飾美觀用"; */
+	"\xbc\x57\xb1\x6a\xa7\xc5\xae\x76\xb0\x4f\xbe\xd0\xaa\x6b\xb3\x4e", /* "增強巫師記憶法術"; */
+	"\xab\x4f\xab\xf9\xa4\xb8\xae\xf0\xa4\xa3\xb7\x7c\xc4\xc8\xb4\xf7", /* "保持元氣不會饑渴"; */
+	"\xbc\x59\xb8\xa8\xb3\xb4\xa7\x7c\xa4\xa3\xb7\x7c\xa8\xfc\xb6\xcb", /* "墜落陷坑不會受傷"; */
+};
+
+static const StringListProvider kEoB2ItemSuffixStringsRingsDOSChineseProvider = { ARRAYSIZE(kEoB2ItemSuffixStringsRingsDOSChinese), kEoB2ItemSuffixStringsRingsDOSChinese };
+
+
+static const char *const kEoB2ItemSuffixStringsPotionsDOSChinese[8] = {
+	"\xbc\x57\xa5\x5b\xa4\x4f\xb6\x71", /* "增加力量"; */
+	"\xa4\x40\xaf\xeb\xaa\x76\xc0\xf8", /* "一般治療"; */
+	"\xbc\x57\xb1\x6a\xa5\xcd\xa9\x52\xa4\x4f", /* "增強生命力"; */
+	"\xa6\xb3\xac\x72", /* "有毒"; */
+	"\xab\xec\xb4\x5f\xa4\xb8\xae\xf0", /* "恢復元氣"; */
+	"\xbc\x57\xa5\x5b\xac\xa1\xa4\x4f\xb3\x74\xab\xd7", /* "增加活力速度"; */
+	"\xc1\xf4\xa7\xce\xa5\xce", /* "隱形用"; */
+	"\xb8\xd1\xac\x72\xa5\xce", /* "解毒用"; */
+};
+
+static const StringListProvider kEoB2ItemSuffixStringsPotionsDOSChineseProvider = { ARRAYSIZE(kEoB2ItemSuffixStringsPotionsDOSChinese), kEoB2ItemSuffixStringsPotionsDOSChinese };
+
+static const char *const kEoB2ItemSuffixStringsWandsDOSChinese[8] = {
+	"\xb7\x7c\xc2\x48\xa4\xe2", /* "會黏手"; */
+	"\xac\x49\xae\x69\xb9\x70\xb9\x71\xb3\x4e", /* "施展雷電術"; */
+	"\xac\x49\xae\x69\xa7\x4e\xc0\x40\xb3\x4e", /* "施展冷錐術"; */
+	"\xaa\x76\xc0\xf8\xad\xab\xb6\xcb", /* "治療重傷"; */
+	"\xac\x49\xae\x69\xa4\xf5\xb2\x79\xb3\x4e", /* "施展火球術"; */
+	"\xac\x50\xa4\xf5\xc4\x5f\xa7\xfa", /* "星火寶杖"; */
+	"\xac\x49\xae\x69\xc5\x5d\xaa\x6b\xad\xb8\xbc\x75", /* "施展魔法飛彈"; */
+	"\xac\x49\xae\x69\xb8\xd1\xa9\x47\xb3\x4e", /* "施展解咒術"; */
+};
+
+static const StringListProvider kEoB2ItemSuffixStringsWandsDOSChineseProvider = { ARRAYSIZE(kEoB2ItemSuffixStringsWandsDOSChinese), kEoB2ItemSuffixStringsWandsDOSChinese };
+
+static const char *const kEoB2RipItemStringsDOSChinese[3] = {
+	"\x25\x73\xbf\xf2\xa5\xa2\xa4\x46\xa6\x6f\xaa\xba", /* "%s遺失了她的"; */
+	"\x25\x73\xbf\xf2\xa5\xa2\xa4\x46\xa5\x4c\xaa\xba", /* "%s遺失了他的"; */
+	".\r"
+};
+
+static const StringListProvider kEoB2RipItemStringsDOSChineseProvider = { ARRAYSIZE(kEoB2RipItemStringsDOSChinese), kEoB2RipItemStringsDOSChinese };
+
+static const char *const kEoB2CursedStringDOSChinese[1] = {
+	"\xb3\x51\xb6\x41\xa9\x47\xaa\xba\x25\x64\x25\x73", /* "被詛咒的%d%s"; */
+};
+
+static const StringListProvider kEoB2CursedStringDOSChineseProvider = { ARRAYSIZE(kEoB2CursedStringDOSChinese), kEoB2CursedStringDOSChinese };
+
+static const char *const kEoB2MagicObjectStringsDOSChinese[5] = {
+	"\xa7\xc5\xae\x76", /* "巫師"; */
+	"\xaa\xaa\xae\x76", /* "牧師"; */
+	"\xa7\xd9\xab\xfc", /* "戒指"; */
+	"\xc3\xc4\xa4\xf4", /* "藥水"; */
+	"\xc5\x5d\xa7\xfa", /* "魔杖"; */
+};
+
+static const StringListProvider kEoB2MagicObjectStringsDOSChineseProvider = { ARRAYSIZE(kEoB2MagicObjectStringsDOSChinese), kEoB2MagicObjectStringsDOSChinese };
+
+static const char *const kEoB2MagicObjectString5DOSChinese[1] = {
+	"Stick"
+};
+
+static const StringListProvider kEoB2MagicObjectString5DOSChineseProvider = { ARRAYSIZE(kEoB2MagicObjectString5DOSChinese), kEoB2MagicObjectString5DOSChinese };
+
+static const char *const kEoB2PatternSuffixDOSChinese[1] = {
+	"%s of %s"
+};
+
+static const StringListProvider kEoB2PatternSuffixDOSChineseProvider = { ARRAYSIZE(kEoB2PatternSuffixDOSChinese), kEoB2PatternSuffixDOSChinese }; 
+
+static const char *const kEoB2PatternGrFix1DOSChinese[1] = {
+	"%s of %s"
+};
+
+static const StringListProvider kEoB2PatternGrFix1DOSChineseProvider = { ARRAYSIZE(kEoB2PatternGrFix1DOSChinese), kEoB2PatternGrFix1DOSChinese };
+
+static const char *const kEoB2PatternGrFix2DOSChinese[1] = {
+	"%s of %s"
+};
+
+static const StringListProvider kEoB2PatternGrFix2DOSChineseProvider = { ARRAYSIZE(kEoB2PatternGrFix2DOSChinese), kEoB2PatternGrFix2DOSChinese };
+
+static const char *const kEoB2ValidateArmorStringDOSChinese[1] = {
+	"%s can't wear that type of armor.\r"
+};
+
+static const StringListProvider kEoB2ValidateArmorStringDOSChineseProvider = { ARRAYSIZE(kEoB2ValidateArmorStringDOSChinese), kEoB2ValidateArmorStringDOSChinese };
+
+static const char *const kEoB2ValidateCursedStringDOSChinese[1] = {
+	"%s cannot release the weapon!  It is cursed!\r"
+};
+
+static const StringListProvider kEoB2ValidateCursedStringDOSChineseProvider = { ARRAYSIZE(kEoB2ValidateCursedStringDOSChinese), kEoB2ValidateCursedStringDOSChinese };
+
+static const char *const kEoB2ValidateNoDropStringDOSChinese[1] = {
+	"\xb1\x7a\xa4\xa3\xaf\xe0\xb1\x4e\xb3\x6f\xb6\xb5\xaa\xab\xab\x7e\xa9\xf1\xb8\x6d\xa6\x62\xa8\xba\xad\xd3\xa6\xec\xb8\x6d\x2e\r", /* "您不能將這項物品放置在那."; */
+};
+
+static const StringListProvider kEoB2ValidateNoDropStringDOSChineseProvider = { ARRAYSIZE(kEoB2ValidateNoDropStringDOSChinese), kEoB2ValidateNoDropStringDOSChinese };
+
+static const char *const kEoB2PotionStringsDOSChinese[2] = {
+	"\xa4\xa4\xac\x72\xa4\x46", /* "中毒了"; */
+	"\x25\x73\xb7\x50\xc4\xb1\x25\x73\x21\x0d", /* "%s感覺%s!\r"; */
+};
+
+static const StringListProvider kEoB2PotionStringsDOSChineseProvider = { ARRAYSIZE(kEoB2PotionStringsDOSChinese), kEoB2PotionStringsDOSChinese };
+
+static const char *const kEoB2WandStringsDOSChinese[1] = {
+	"\xb3\x6f\xa4\xec\xa7\xfa\xa5\x7e\xc6\x5b\xa4\x57\xac\xdd\xa8\xd3\x2c\xa8\xc3\xa8\x53\xa6\xb3\xa4\xb0\xbb\xf2\xc5\x5d\xa4\x4f\r", /* "這木杖外觀上看來,並沒有什麼魔力"; */
+};
+
+static const StringListProvider kEoB2WandStringsDOSChineseProvider = { ARRAYSIZE(kEoB2WandStringsDOSChinese), kEoB2WandStringsDOSChinese };
+
+static const char *const kEoB2ItemMisuseStringsDOSChinese[3] = {
+	"%s can not use this item.\r",
+	"This item automatically used when worn.\r",
+	"This item is not used in this way.\r"
+};
+
+static const StringListProvider kEoB2ItemMisuseStringsDOSChineseProvider = { ARRAYSIZE(kEoB2ItemMisuseStringsDOSChinese), kEoB2ItemMisuseStringsDOSChinese };
+
+static const char *const kEoB2TakenStringsDOSChinese[1] = {
+	" taken.\r"
+};
+
+static const StringListProvider kEoB2TakenStringsDOSChineseProvider = { ARRAYSIZE(kEoB2TakenStringsDOSChinese), kEoB2TakenStringsDOSChinese };
+
+static const char *const kEoB2PotionEffectStringsDOSChinese[8] = {
+	"\xab\x44\xb1\x60\xb1\x6a\xa7\xa7", /* "非常強壯"; */
+	"\xa4\xf1\xb8\xfb\xa6\x6e\xa4\x46", /* "比較好了"; */
+	"\xab\x44\xb1\x60\xa6\x6e", /* "非常好"; */
+	"\xa8\xec\xab\xdc\xa4\xa3\xb5\xce\xaa\x41", /* "到很不舒服"; */
+	"\xa8\x7b\xa4\x6c\xab\xdc\xb9\xa1\xba\xa1", /* "肚子很飽滿"; */
+	"\xa7\xf3\xa7\xd6\xa9\x4d\xb1\xd3\xb1\xb6", /* "更快和敏捷"; */
+	"\xc5\xdc\xa6\xa8\xc1\xf4\xa7\xce\xa4\x46", /* "變成隱形了"; */
+	"\xac\x72\xa9\xca\xa4\x77\xb8\x67\xae\xf8\xa5\xa2\xa4\x46", /* "毒性已經消失了"; */
+};
+
+static const StringListProvider kEoB2PotionEffectStringsDOSChineseProvider = { ARRAYSIZE(kEoB2PotionEffectStringsDOSChinese), kEoB2PotionEffectStringsDOSChinese };
+
+static const char *const kEoB2YesNoStringsDOSChinese[2] = {
+	"yes",
+	"no"
+};
+
+static const StringListProvider kEoB2YesNoStringsDOSChineseProvider = { ARRAYSIZE(kEoB2YesNoStringsDOSChinese), kEoB2YesNoStringsDOSChinese };
+
+static const char *const kEoB2MoreStringsDOSChinese[1] = {
+	"MORE"
+};
+
+static const StringListProvider kEoB2MoreStringsDOSChineseProvider = { ARRAYSIZE(kEoB2MoreStringsDOSChinese), kEoB2MoreStringsDOSChinese };
+
+static const char *const kEoB2NpcMaxStringsDOSChinese[1] = {
+	"\xb1\x7a\xaa\xba\xb6\xa4\xa5\xee\xa4\xa4\xb3\xcc\xa6\x68\xa5\x75\xaf\xe0\xa6\xb3\xa4\xbb\xa6\xec\xb6\xa4\xad\xfb\x2c\xbd\xd0\xbf\xef\xbe\xdc\xa4\x40\xa6\xec\xb1\x7a\xad\x6e\xb8\xd1\xb9\xb5\xaa\xba\xb6\xa4\xad\xfb", /* "您的隊伍中最多只能有六位隊員,請選擇一位您要解僱的隊員"; */
+};
+
+static const StringListProvider kEoB2NpcMaxStringsDOSChineseProvider = { ARRAYSIZE(kEoB2NpcMaxStringsDOSChinese), kEoB2NpcMaxStringsDOSChinese };
+
+static const char *const kEoB2OkStringsDOSChinese[1] = {
+	"OK"
+};
+
+static const StringListProvider kEoB2OkStringsDOSChineseProvider = { ARRAYSIZE(kEoB2OkStringsDOSChinese), kEoB2OkStringsDOSChinese };
+
+static const char *const kEoB2NpcJoinStringsDOSChinese[1] = {
+	"%s\xa5\x5b\xa4\x4a\xab\x5f\xc0\x49\xb6\xa4\xa5\xee\xa4\xba\x2e\r", /* "%s加入冒險隊伍內."; */
+};
+
+static const StringListProvider kEoB2NpcJoinStringsDOSChineseProvider = { ARRAYSIZE(kEoB2NpcJoinStringsDOSChinese), kEoB2NpcJoinStringsDOSChinese };
+
+static const char *const kEoB2CancelStringsDOSChinese[1] = {
+	"CANCEL"
+};
+
+static const StringListProvider kEoB2CancelStringsDOSChineseProvider = { ARRAYSIZE(kEoB2CancelStringsDOSChinese), kEoB2CancelStringsDOSChinese };
+
+static const char *const kEoB2AbortStringsDOSChinese[1] = {
+	"ABORT"
+};
+
+static const StringListProvider kEoB2AbortStringsDOSChineseProvider = { ARRAYSIZE(kEoB2AbortStringsDOSChinese), kEoB2AbortStringsDOSChinese };
+
+static const char *const kEoB2MenuStringsMainDOSChinese[8] = {
+	"\xbd\xd0\x20\xbf\xef\x20\xbe\xdc\x20\xb6\xb5\x20\xa5\xd8\x3a", /* "請 選 擇 項 目:"; */
+	"\xc5\xfd\x20\xb6\xa4\x20\xa5\xee\x20\xa5\xf0\x20\xae\xa7", /* "讓 隊 伍 休 息"; */
+	"\xb0\x4f\x20\x20\xbe\xd0\x20\x20\xaa\x6b\x20\x20\xb3\x4e", /* "記  憶  法  術"; */
+	"\xac\xe8\x20\x20\xa8\x44\x20\x20\xaa\x6b\x20\x20\xb3\x4e", /* "祈  求  法  術"; */
+	"\xa7\xdb\x20\x20\xbc\x67\x20\x20\xaa\x6b\x20\x20\xb3\x4e", /* "抄  寫  法  術"; */
+	"\xa5\x5c\x20\x20\xaf\xe0\x20\x20\xb3\x5d\x20\x20\xa9\x77", /* "功  能  設  定"; */
+	"\xb9\x43\x20\x20\xc0\xb8\x20\x20\xbf\xef\x20\x20\xb6\xb5", /* "遊  戲  選  項"; */
+	"\xc2\xf7\xb6\x7d", /* "離開"; */
+};
+
+static const StringListProvider kEoB2MenuStringsMainDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsMainDOSChinese), kEoB2MenuStringsMainDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsSaveLoadDOSChinese[8] = {
+	"\xb8\xfc\xa4\x4a\xb9\x43\xc0\xb8\xb6\x69\xab\xd7", /* "載入遊戲進度"; "Load Game" */
+	"\xc0\x78\xa6\x73\xb9\x43\xc0\xb8\xb6\x69\xab\xd7", /* "儲存遊戲進度"; "Save Game" */
+	"\xbb\xba\x20\xb4\xb2\x20\xb6\xa4\x20\xad\xfb", /* "遣 散 隊 員"; "Drop Character" */
+	"\xb5\xb2\x20\xa7\xf4\x20\xb9\x43\x20\xc0\xb8", /* "結 束 遊 戲"; "Quit Game" */
+	"\xb9\x43\x20\x20\xc0\xb8\x20\x20\xbf\xef\x20\x20\xb6\xb5\x3a", /* "遊  戲  選  項:"; "Game Options:" */
+	"\x0d\x20\x20\x20\xa6\x73\x20\xc0\xc9\x20\xa7\xb9\x20\xb2\xa6\x2e", /* "\r   存 檔 完 畢."; "\r   Game saved." */
+	"\x0d\x20\x20\x20\xa6\x73\x20\xc0\xc9\x20\xa5\xa2\x20\xb1\xd1\x2e", /* "\r   存 檔 失 敗."; "Attempts to save your\rgame have failed!", */
+	"\xb5\x4c\xaa\x6b\xb8\xfc\xa4\x4a\xc0\xc9\xae\xd7\x2c\xa5\x69\xaf\xe0\x0d\xc0\xc9\xae\xd7\xa4\x77\xb8\x67\xb7\x6c\xc3\x61", /* "無法載入檔案,可能\r檔案已經損壞"; "Cannot load your\rsave game.  The\rfile may be corrupt!" */
+};
+
+static const StringListProvider kEoB2MenuStringsSaveLoadDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsSaveLoadDOSChinese), kEoB2MenuStringsSaveLoadDOSChinese }; // Likely ok
+
+static const char *const kEoB2MenuStringsOnOffDOSChinese[2] = {
+	"\xb6\x7d", /* "é–‹"; */
+	"\xc3\xf6", /* "關"; */
+};
+
+static const StringListProvider kEoB2MenuStringsOnOffDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsOnOffDOSChinese), kEoB2MenuStringsOnOffDOSChinese };
+
+static const char *const kEoB2MenuStringsSpellsDOSChinese[17] = {
+	"\x0d\x0d\xb1\x71\xb1\x7a\xaa\xba\xb6\xa4\xa5\xee\xa4\xa4\xbf\xef\xbe\xdc\xa4\x40\x0d\xad\xd3\xbe\x41\xb7\xed\xaa\xba\xb6\xa4\xad\xfb\xa8\xd3\xbe\xc7\xb2\xdf\x0d\xaa\x6b\xb3\x4e\x2e", /* "\r\r從您的隊伍中選擇一\r個適當的隊員來學習\r法術."; */
+	"\x0d\xb1\x7a\xaa\xba\xaa\x5a\xa4\x68\xb5\xa5\xaf\xc5\xa4\xd3\xa7\x43\x2c\x0d\xb5\x4c\xaa\x6b\xa8\xcf\xa5\xce\xaa\x6b\xb3\x4e\x2e", /* "\r您的武士等級太低,\r無法使用法術."; */
+	"\x0d\xa8\x53\xa6\xb3\xaa\x6b\xb3\x4e\xb1\xb2\xb6\x62", /* "\r沒有法術捲軸"; */
+	"\x0d\x0d\xbd\xd0\xb1\x71\xb1\x7a\xaa\xba\xab\x5f\xc0\x49\xb6\xa4\xa5\xee\xa4\xa4\xbf\xef\x0d\xa5\x58\xa4\x40\xad\xd3\xb6\xa4\xad\xfb\xa8\xd3\xac\xe8\xa8\x44\xaa\x6b\xb3\x4e\x2e", /* "\r\r請從您的冒險隊伍中選\r出一個隊員來祈求法術."; */
+	"\x0d\xa8\x53\xa6\xb3\xa5\xf4\xa6\xf3\xa4\x40\xa6\xec\xb6\xa4\xad\xfb\x0d\xa5\x69\xa5\x48\xac\xe8\xa8\x44\xb7\x73\xaa\xba\xaa\x6b\xb3\x4e\x2e", /* "\r沒有任何一位隊員\r可以祈求新的法術."; */
+	"\x0d\xa8\x53\xa6\xb3\xa5\xf4\xa6\xf3\xa4\x40\xa6\xec\xb6\xa4\xad\xfb\x0d\xa5\x69\xa5\x48\xbe\xc7\xb2\xdf\xb7\x73\xaa\xba\xaa\x6b\xb3\x4e\x2e", /* "\r沒有任何一位隊員\r可以學習新的法術."; */
+	"\xa5\xa2\xa5\x68\xaa\xbe\xc4\xb1\xa9\xce\xa4\x77\xa6\xba\xa4\x60\xaa\xba\x0d\xa7\xc5\xae\x76\xa4\xa3\xaf\xe0\xbe\xc7\xb2\xdf\xaa\x6b\xb3\x4e\x2e", /* "失去知覺或已死亡的\r巫師不能學習法術."; */
+	"\xa5\xa2\xa5\x68\xaa\xbe\xc4\xb1\xa9\xce\xa4\x77\xa6\xba\xa4\x60\xaa\xba\x0d\xaa\xaa\xae\x76\xa4\xa3\xaf\xe0\xac\xe8\xa8\x44\xaa\x6b\xb3\x4e\x2e", /* "失去知覺或已死亡的\r牧師不能祈求法術."; */
+	"1",
+	"2",
+	"3",
+	"4",
+	"5",
+	"\xb2\x4d\xb0\xa3", /* "清除"; */
+	"\xa5\x69\xa5\xce\xaa\xba\xaa\x6b\xb3\x4e\x3a", /* "可用的法術:"; */
+	"\xac\x4f", /* "是"; */
+	"\xa4\xa3", /* "不"; */
+};
+
+static const StringListProvider kEoB2MenuStringsSpellsDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsSpellsDOSChinese), kEoB2MenuStringsSpellsDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsRestDOSChinese[5] = {
+	"\xa7\x41\xaa\xba\xaa\x76\xc0\xf8\xaa\xcc\xad\x6e\xc2\xe5\xaa\x76\x0d\xb6\xa4\xad\xfb\xb6\xdc\x3f\x20\x20\x20\x20\x20\x20\x20\x20", /* "你的治療者要醫治\r隊員嗎?        "; */
+	"\xa6\xb9\xb3\x42\xa6\xfc\xa5\x47\xa6\xb3\xa6\x4d\xc0\x49\xa6\x73\xa6\x62\x21\x0d\xb1\x7a\xad\x6e\xa6\x62\xa6\xb9\xa5\xf0\xae\xa7\xc0\xf8\xbe\x69\xb6\xdc\x3f", /* "此處似乎有危險存在!\r您要在此休息療養嗎?"; */
+	"\x20\x20\xb6\xa4\xa5\xee\xa5\xf0\xae\xa7\xa4\xa4\x2e", /* "  隊伍休息中."; */
+	"\x0d\xa5\xfe\xb3\xa1\xaa\xba\xb6\xa4\xad\xfb\xa4\x77\xb8\x67\xb1\x6f\xa8\xec\x0d\xa4\x46\xa5\x52\xa5\xf7\xaa\xba\xa5\xf0\xae\xa7", /* "\r全部的隊員已經得到\r了充份的休息"; */
+	"\xb1\x7a\xaa\xba\xb6\xa4\xa5\xee\xbb\xdd\xad\x6e\xa5\xf0\xae\xa7\x0d\xae\xc9\xb6\xa1\x2c\xa5\x48\xab\x4b\xbe\xc7\xb2\xdf\xaa\x6b\xb3\x4e", /* "您的隊伍需要休息\r時間,以便學習法術"; */
+};
+
+static const StringListProvider kEoB2MenuStringsRestDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsRestDOSChinese), kEoB2MenuStringsRestDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsDropDOSChinese[1] = {
+	"\xaa\x60\xb7\x4e\x21\xb1\x7a\xaa\xba\xb6\xa4\xad\xfb\xc1\x60\xa6\x40\x0d\xa4\xa3\xb1\x6f\xa4\xd6\xa9\xf3\xa5\x7c\xa4\x48", /* "注意!您的隊員總共\r不得少於四人"; */
+};
+
+static const StringListProvider kEoB2MenuStringsDropDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsDropDOSChinese), kEoB2MenuStringsDropDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsExitDOSChinese[1] = {
+	"\x0d\xb1\x7a\xbd\x54\xa9\x77\xad\x6e\xb5\xb2\xa7\xf4\xb9\x43\xc0\xb8\x3f", /* "\r您確定要結束遊戲?"; */
+};
+
+static const StringListProvider kEoB2MenuStringsExitDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsExitDOSChinese), kEoB2MenuStringsExitDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsStarveDOSChinese[1] = {
+	"\xb1\x7a\xaa\xba\xb6\xa4\xad\xfb\xa5\xbf\xb3\x42\xa9\xf3\xc4\xc8\xbe\x6a\x0d\xa4\xa4\x2e\xb1\x7a\xad\x6e\xc4\x7e\xc4\xf2\xa5\xf0\xae\xa7\xb6\xdc\x3f", /* "您的隊員正處於饑餓\r中.您要繼續休息嗎?"; */
+};
+
+static const StringListProvider kEoB2MenuStringsStarveDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsStarveDOSChinese), kEoB2MenuStringsStarveDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsScribeDOSChinese[5] = {
+	"\xbd\xd0\xbf\xef\xbe\xdc\xb1\x7a\xad\x6e\xa7\xdb\xbc\x67\xaa\xba\xb1\xb2\xb6\x62", /* "請選擇您要抄寫的捲軸"; */
+	"\xbd\xd0\xb1\x71\xb6\xa4\xad\xfb\xa4\xa4\xbf\xef\xa5\x58\xa4\x40\xad\xd3\x0d\xa7\xc5\xae\x76\xa8\xd3\xa7\xdb\xbc\x67\xaa\x6b\xb3\x4e\x2e", /* "請從隊員中選出一個\r巫師來抄寫法術."; */
+	"\xb1\x7a\xa8\x53\xa6\xb3\xa5\xf4\xa6\xf3\xc5\x5d\xaa\x6b\xb1\xb2\xb6\x62\x0d\xa5\x69\xa5\x48\xa5\xce\xa8\xd3\xa7\xdb\xbc\x67\xaa\x6b\xb3\x4e\x2e", /* "您沒有任何魔法捲軸\r可以用來抄寫法術."; */
+	"\xb1\x7a\xa8\xc3\xa8\x53\xa6\xb3\xb3\x6f\xa6\xec\xa7\xc5\xae\x76\x0d\xa5\xbc\xbe\xc7\xb9\x4c\xaa\xba\xc5\x5d\xaa\x6b\xb1\xb2\xb6\x62\x2e", /* "您並沒有這位巫師\r未學過的魔法捲軸."; */
+	"\xb1\x7a\xa8\xc3\xa8\x53\xa6\xb3\xa7\xc5\xae\x76\xa5\x69\xa5\x48\x0d\xa7\xdb\xbc\x67\xc5\x5d\xaa\x6b\xb1\xb2\xb6\x62", /* "您並沒有巫師可以\r抄寫魔法捲軸"; */
+};
+
+static const StringListProvider kEoB2MenuStringsScribeDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsScribeDOSChinese), kEoB2MenuStringsScribeDOSChinese };  // Likely OK
+
+static const char *const kEoB2MenuStringsDrop2DOSChinese[3] = {
+	"\x0d\x0d\x0d\xbd\xd0\xbf\xef\xbe\xdc\xb1\x7a\xb7\x51\xbb\xba\xb4\xb2\xaa\xba\xb6\xa4\xad\xfb\x2e", /* "\r\r\r請選擇您想遣散的隊員."; */
+	"\x0d\x20\xb1\x7a\xa5\xb2\xb6\xb7\xbf\xe9\xa4\x4a\xc0\xc9\xae\xd7\xa6\x57\xba\xd9", /* "\r 您必須輸入檔案名稱"; */
+	"\xb1\x7a\xbd\x54\xa9\x77\xb7\x73\xa6\x73\xa9\xf1\xaa\xba\xc0\xc9\xae\xd7\x0d\xad\x6e\xa8\xfa\xa5\x4e\xb3\x6f\xad\xd3\xc2\xc2\xc0\xc9\xae\xd7\x3f", /* "您確定新存放的檔案\r要取代這個舊檔案?"; */
+};
+
+static const StringListProvider kEoB2MenuStringsDrop2DOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsDrop2DOSChinese), kEoB2MenuStringsDrop2DOSChinese };  // Likely OK
+
+static const char *const kEoB2MenuStringsHeadDOSChinese[3] = {
+	"\xb2\xcf\xc0\xe7\x3a", /* "紮營:"; */
+	"\xa5\x5c\x20\x20\xaf\xe0\x20\x20\xb3\x5d\x20\x20\xa9\x77\x3a", /* "功  能  設  定:"; */
+	"\xb9\x43\x20\x20\xc0\xb8\x20\x20\xbf\xef\x20\x20\xb6\xb5\x3a", /* "遊  戲  選  項:"; */
+};
+
+static const StringListProvider kEoB2MenuStringsHeadDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsHeadDOSChinese), kEoB2MenuStringsHeadDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsPoisonDOSChinese[1] = {
+	"\xa6\xb3\xb6\xa4\xad\xfb\xa4\xa4\xac\x72\xa4\x46\xc0\x48\xae\xc9\xa5\x69\x0d\xaf\xe0\xb1\xbe\xb1\xbc\x21\xc1\xd9\xad\x6e\xa5\xf0\xae\xa7\xb6\xdc\x3f", /* "有隊員中毒了隨時可\r能掛掉!還要休息嗎?"; */
+};
+
+static const StringListProvider kEoB2MenuStringsPoisonDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsPoisonDOSChinese), kEoB2MenuStringsPoisonDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsMgcDOSChinese[2] = {
+	"%-8s %1d",
+	"\xa5\x69\xa5\xce\xc2\x49\xbc\xc6\x3a\x25\x64", /* "可用點數:%d"; */
+};
+
+static const StringListProvider kEoB2MenuStringsMgcDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsMgcDOSChinese), kEoB2MenuStringsMgcDOSChinese };
+
+static const char *const kEoB2MenuStringsPrefsDOSChinese[4] = {
+	"Tunes are %-3s",
+	"\xad\x49\xb4\xba\xad\xb5\xae\xc4\x25\x2d\x31\x73", /* "背景音效%-1s"; */
+	"\xb1\xf8\xaa\xac\xb9\xcf\xaa\xed\x25\x2d\x31\x73", /* "條狀圖表%-1s"; */
+	"Mouse is %-3s"
+};
+
+static const StringListProvider kEoB2MenuStringsPrefsDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsPrefsDOSChinese), kEoB2MenuStringsPrefsDOSChinese };
+
+static const char *const kEoB2MenuStringsRest2DOSChinese[5] = {
+	"\x25\x73\xbe\xc7\xb7\x7c\xa4\x46\x25\x73\x2e\x0d", /* "%s學會了%s.\r"; */	
+	"\x25\x73\xa4\x77\xb0\x4f\xbe\xd0\xa6\xed\x25\x73\xaa\xba\xaa\x6b\xb3\x4e\x2e\x0d", /* "%s已記憶住%s的法術.\r"; */
+	"\x25\x73\xac\x49\xae\x69\xaa\x76\xc0\xf8\xb3\x4e\xa8\xd3\xaa\x76\xc0\xf8\x25\x73\xaa\xba\xb6\xcb\xb6\xd5\x2e", /* "%s施展治療術來治療%s的傷勢."; */
+	"\xa4\x77\xa5\xf0\xae\xa7\xaa\xba\xae\xc9\xb6\xa1\x3a\x20\x25\x2d\x34\x64", /* "已休息的時間: %-4d"; */
+	"\r%s\r"
+};
+
+static const StringListProvider kEoB2MenuStringsRest2DOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsRest2DOSChinese), kEoB2MenuStringsRest2DOSChinese };
+
+static const char *const kEoB2MenuStringsRest3DOSChinese[1] = {
+	"\x06\x06\xb1\x7a\xc4\xb1\xb1\x6f\xa6\x62\xb3\x6f\xb8\xcc\xa5\xf0\xae\xa7\x2c\xa8\xc3\xa4\xa3\xac\x4f\xab\xdc\xa6\x77\xa5\xfe\x2e", /* "\x06\x06您覺得在這裡休息,並不是很安全."; */
+};
+
+static const StringListProvider kEoB2MenuStringsRest3DOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsRest3DOSChinese), kEoB2MenuStringsRest3DOSChinese };
+
+static const char *const kEoB2MenuStringsRest4DOSChinese[1] = {
+	"\x06\x06\xb1\x7a\xa7\x4f\xa5\xf0\xae\xa7\xa4\x46\x2c\xa9\xc7\xaa\xab\xa8\xd3\xa4\x46\x21", /* "\x06\x06您別休息了,怪物來了!"; */
+};
+
+static const StringListProvider kEoB2MenuStringsRest4DOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsRest4DOSChinese), kEoB2MenuStringsRest4DOSChinese };
+
+static const char *const kEoB2MenuStringsDefeatDOSChinese[1] = {
+	"\xb1\x7a\xaa\xba\xbe\xe3\xad\xd3\xab\x5f\xc0\x49\xb6\xa4\xa5\xee\xa4\x77\x0d\xa5\xfe\xad\x78\xb0\x7d\xa4\x60\x21\xb1\x7a\xad\x6e\xb8\xfc\xa4\x4a\xa5\x48\x0d\xab\x65\xa9\xd2\xc0\x78\xa6\x73\xaa\xba\xb6\x69\xab\xd7\xc0\xc9\xb6\xdc\x3f", /* "您的整個冒險隊伍已\r全軍陣亡!您要載入以\r前所儲存的進度檔嗎?"; */
+};
+
+static const StringListProvider kEoB2MenuStringsDefeatDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsDefeatDOSChinese), kEoB2MenuStringsDefeatDOSChinese }; // Likely OK
+
+static const char *const kEoB2MenuStringsTransferDOSChinese[5] = {
+	"\xa6\x62\xb6\x7d\xa9\x6c\xb9\x43\xc0\xb8\xa5\x48\xab\x65\x2c\xb1\x7a\xa5\xb2\xb6\xb7\x0d\xa5\xfd\xb3\x5d\xa9\x77\xa6\x6e\xa5\x7c\xa6\xec\xb6\xa4\xad\xfb\x21", /* "在開始遊戲以前,您必須\r先設定好四位隊員!"; */
+	"\xa6\x62\xc1\xf4\xa4\xeb\xb6\xc7\xa9\x5f\xa4\xa4\x2c\xb1\x7a\xb3\xcc\xa6\x68\x0d\xa5\x75\xaf\xe0\xb6\xc7\xb0\x65\xa5\x7c\xa6\xec\xb6\xa4\xad\xfb\x21", /* "在隱月傳奇中,您最多\r只能傳送四位隊員!"; */
+	"\xa6\x62\xa5\xbb\xb9\x43\xc0\xb8\xa4\xa4\xb5\x4c\xa5\xce\xa9\xce\xa4\xa3\xaf\xe0\x0d\xa8\xcf\xa5\xce\xaa\xba\xaa\xab\xab\x7e\x2c\xb3\xa3\xb7\x7c\xb3\x51\x0d\xb2\x4d\xb0\xa3\xb1\xbc\x2e", /* "在本遊戲中無用或不能\r使用的物品,都會被\r清除掉."; */
+	"\x20\x0d\x20\xb1\x7a\xaa\xba\xab\x5f\xc0\x49\xb6\xa4\xa5\xee\xb8\xcc\x20\x0d\x20\xa8\x53\xa6\xb3\xa7\xc5\xae\x76\x2e", /* " \r 您的冒險隊伍裡 \r 沒有巫師."; */
+	"\x20\x0d\xa6\x62\xb1\x7a\xaa\xba\xb6\xa4\xa5\xee\xa4\xa4\xa8\xc3\xa8\x53\xa6\xb3\x0d\xaa\xaa\xae\x76\xa9\xce\xaa\x5a\xa4\x68", /* " \r在您的隊伍中並沒有\r牧師或武士"; */
+};
+
+static const StringListProvider kEoB2MenuStringsTransferDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsTransferDOSChinese), kEoB2MenuStringsTransferDOSChinese }; // Likely ok
+
+static const char *const kEoB2MenuStringsSpecDOSChinese[2] = {
+	"\xb7\xed\xb1\x7a\xa4\x40\xc4\xb1\xbf\xf4\xa8\xd3\x2c\xb1\x7a\xb5\x6f\xb2\x7b\x0d\xad\x5e\xc2\xc4\xba\xb8\xa8\xba\xad\xd3\xa4\x70\xb8\xe9\xa4\x77\xb8\x67\x0d\xc2\xf7\xb6\x7d\xa4\x46\x21", /* "當您一覺醒來,您發現\r英薩爾那個小賊已經\r離開了!"; */
+	"\xb1\x7a\xa8\xb3\xb3\x74\xa6\x61\xc0\xcb\xb5\xf8\xa4\x46\xa4\x40\xa4\x55\x0d\xa9\xd2\xa6\xb3\xaa\xab\xab\x7e\x2c\xb5\x6f\xb2\x7b\xb8\xcb\xb3\xc6\xb3\xa3\x0d\xa4\xa3\xa8\xa3\xa4\x46\x21", /* "您迅速地檢視了一下\r所有物品,發現裝備都\r不見了!"; */
+};
+
+static const StringListProvider kEoB2MenuStringsSpecDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsSpecDOSChinese), kEoB2MenuStringsSpecDOSChinese };
+
+static const char *const kEoB2MenuYesNoStringsDOSChinese[2] = {
+	"Yes",
+	"No"
+};
+
+static const StringListProvider kEoB2MenuYesNoStringsDOSChineseProvider = { ARRAYSIZE(kEoB2MenuYesNoStringsDOSChinese), kEoB2MenuYesNoStringsDOSChinese };
+
+static const char *const kEoB2CharGuiStringsHpDOSChinese[2] = {
+	"HP",
+	"%3d of %-3d"
+};
+
+static const StringListProvider kEoB2CharGuiStringsHpDOSChineseProvider = { ARRAYSIZE(kEoB2CharGuiStringsHpDOSChinese), kEoB2CharGuiStringsHpDOSChinese };
+
+static const char *const kEoB2CharGuiStringsWp2DOSChinese[3] = {
+	"\xa7\xf0\xc0\xbb\xa5\xa2\xbb\x7e", /* "攻擊失誤"; */
+	"\xad\x4a\xb6\xc3\xac\xe5\xbc\x41", /* "胡亂砍劈"; */
+	"\xb2\x72\xaf\x50\xa4\x40\xc0\xbb", /* "猛烈一擊"; */
+};
+
+static const StringListProvider kEoB2CharGuiStringsWp2DOSChineseProvider = { ARRAYSIZE(kEoB2CharGuiStringsWp2DOSChinese), kEoB2CharGuiStringsWp2DOSChinese };
+
+static const char *const kEoB2CharGuiStringsWrDOSChinese[4] = {
+	"\xb5\x4c\xaa\x6b\xa7\xf0\xc0\xbb", /* "無法攻擊"; */
+	"",
+	"NO",
+	"AMMO"
+};
+
+static const StringListProvider kEoB2CharGuiStringsWrDOSChineseProvider = { ARRAYSIZE(kEoB2CharGuiStringsWrDOSChinese), kEoB2CharGuiStringsWrDOSChinese };
+
+static const char *const kEoB2CharGuiStringsSt2DOSChinese[7] = {
+	"Swapping",
+	"\xa5\xfa\xba\x61\xb0\x7d\xa4\x60", /* "光榮陣亡"; */
+	"\xa9\xfc\xb0\x67\xa4\xa3\xbf\xf4", /* "昏迷不醒"; */
+	"\xba\x43\xa9\xca\xa4\xa4\xac\x72", /* "慢性中毒"; */
+	"\xa8\xad\xac\x56\xbc\x40\xac\x72", /* "身染劇毒"; */
+	"\xa5\xfe\xa8\xad\xb7\xf2\xb7\xf4", /* "全身痲痺"; */
+	"\xc5\xdc\xa6\xa8\xa4\xc6\xa5\xdb", /* "變成化石"; */
+};
+
+static const StringListProvider kEoB2CharGuiStringsSt2DOSChineseProvider = { ARRAYSIZE(kEoB2CharGuiStringsSt2DOSChinese), kEoB2CharGuiStringsSt2DOSChinese };
+
+static const char *const kEoB2CharGuiStringsInDOSChinese[4] = {
+	"\xb6\xa4\xad\xfb\xb8\xea\xae\xc6", /* "隊員資料"; */
+	"\xa8\xbe\xc5\x40\xa4\x4f\x3a", /* "防護力:"; */
+	"\xb8\x67\xc5\xe7", /* "ç¶“é©—"; */
+	"\xb5\xa5\xaf\xc5", /* "等級"; */
+};
+
+static const StringListProvider kEoB2CharGuiStringsInDOSChineseProvider = { ARRAYSIZE(kEoB2CharGuiStringsInDOSChinese), kEoB2CharGuiStringsInDOSChinese };
+
+static const char *const kEoB2CharStatusStrings7DOSChinese[1] = {
+	"\x25\x73\xa4\xa3\xa6\x41\xa6\xb3\xa5\xa8\xa4\x6a\xaa\xba\xa4\x4f\xb6\x71\xa4\x46\x2e\r", /* "%s不再有巨大的力量了.\r"; */
+};
+
+static const StringListProvider kEoB2CharStatusStrings7DOSChineseProvider = { ARRAYSIZE(kEoB2CharStatusStrings7DOSChinese), kEoB2CharStatusStrings7DOSChinese };
+
+static const char *const kEoB2CharStatusStrings82DOSChinese[1] = {
+	"\x06\x06\x25\x73\xb7\x50\xc4\xb1\xac\x72\xa9\xca\xa5\xbf\xb3\x76\xba\xa5\xb5\x6f\xa7\x40\xa4\xa4\x21\x0d", /* "\x06\x06%s感覺毒性正逐漸發作中!\r"; */
+};
+
+static const StringListProvider kEoB2CharStatusStrings82DOSChineseProvider = { ARRAYSIZE(kEoB2CharStatusStrings82DOSChinese), kEoB2CharStatusStrings82DOSChinese };
+
+static const char *const kEoB2CharStatusStrings9DOSChinese[1] = {
+	"\x06\x04\x25\x73\xa4\x77\xa4\xa3\xa6\x41\xb7\xf2\xb7\xf4\xa4\x46\x21\r", /* "\x06\x04%s已不再痲痺了!\r"; */
+};
+
+static const StringListProvider kEoB2CharStatusStrings9DOSChineseProvider = { ARRAYSIZE(kEoB2CharStatusStrings9DOSChinese), kEoB2CharStatusStrings9DOSChinese };
+
+static const char *const kEoB2CharStatusStrings12DOSChinese[1] = {
+	"\x25\x73\xaa\xba\xb3\x74\xab\xd7\xba\x43\xa4\x55\xa8\xd3\xa4\x46\x2e\r", /* "%s的速度慢下來了.\r"; */
+};
+
+static const StringListProvider kEoB2CharStatusStrings12DOSChineseProvider = { ARRAYSIZE(kEoB2CharStatusStrings12DOSChinese), kEoB2CharStatusStrings12DOSChinese };
+
+static const char *const kEoB2CharStatusStrings132DOSChinese[1] = {
+	"\x06\x06""%s is %s!\r"
+};
+
+static const StringListProvider kEoB2CharStatusStrings132DOSChineseProvider = { ARRAYSIZE(kEoB2CharStatusStrings132DOSChinese), kEoB2CharStatusStrings132DOSChinese };
+
+static const char *const kEoB2LevelGainStringsDOSChinese[1] = {
+	"\x06\x06\x25\x73\xaa\xba\xb5\xa5\xaf\xc5\xb4\xa3\xa4\xc9\xa4\x46\xa4\x40\xaf\xc5\x2e\x06\x0f\r", /* "\x06\x06%s的等級提升了一級.\x06\x0f\r"; */
+};
+
+static const StringListProvider kEoB2LevelGainStringsDOSChineseProvider = { ARRAYSIZE(kEoB2LevelGainStringsDOSChinese), kEoB2LevelGainStringsDOSChinese };
+
+static const char *const kEoB2BookNumbersDOSChinese[5] = {
+	"\xb2\xc4\xa4\x40\xaf\xc5", /* "第一級"; */
+	"\xb2\xc4\xa4\x47\xaf\xc5", /* "第二級"; */
+	"\xb2\xc4\xa4\x54\xaf\xc5", /* "第三級"; */
+	"\xb2\xc4\xa5\x7c\xaf\xc5", /* "第四級"; */
+	"\xb2\xc4\xa4\xad\xaf\xc5", /* "第五級"; */
+};
+
+static const StringListProvider kEoB2BookNumbersDOSChineseProvider = { ARRAYSIZE(kEoB2BookNumbersDOSChinese), kEoB2BookNumbersDOSChinese };
+
+static const char *const kEoB2MageSpellsListDOSChinese[33] = {
+	"",
+	"\xc5\x5d\xab\x60\xb3\x4e", /* "魔冑術"; */
+	"\xbf\x55\xbf\x4e\xa4\xa7\xa4\xe2", /* "燃燒之手"; */
+	"\xb0\xbb\xb4\xfa\xc5\x5d\xaa\x6b", /* "偵測魔法"; */
+	"\xc5\x5d\xaa\x6b\xad\xb8\xbc\x75", /* "魔法飛彈"; */
+	"\xc5\x5d\xac\xde\xb3\x4e", /* "魔盾術"; */
+	"\xb9\x71\xc0\xbb\xa4\xe2\xa4\x4d", /* "電擊手刀"; */
+	"\xc2\x61\xc4\x67\xa4\xc6\xa8\xad", /* "朦朧化身"; */
+	"\xb0\xbb\xb4\xfa\xc1\xf4\xa7\xce", /* "偵測隱形"; */
+	"\xbf\xeb\xc3\xd1\xaa\xab\xab\x7e", /* "辨識物品"; */
+	"\xc1\xf4\xa7\xce\xb3\x4e", /* "隱形術"; */
+	"\xbb\xc4\xb2\x47\xa4\xa7\xbd\x62", /* "酸液之箭"; */
+	"\xb8\xd1\xa9\x47\xb3\x4e", /* "解咒術"; */
+	"\xa4\xf5\xb2\x79\xb3\x4e", /* "火球術"; */
+	"\xa8\xb3\xb1\xb6\xb3\x4e", /* "迅捷術"; */
+	"\xa9\x77\xa8\xad\xb3\x4e", /* "定身術"; */
+	"\xa4\x51\xa7\x60\xc1\xf4\xa7\xce", /* "十呎隱形"; */
+	"\xb9\x70\xb9\x71\xb3\x4e", /* "雷電術"; */
+	"\xa7\x6c\xa6\xe5\xb0\xad\xa4\xf6", /* "吸血鬼爪"; */
+	"\xae\xa3\xc4\xdf\xb3\x4e", /* "恐懼術"; */
+	"\xb4\x48\xa6\x42\xad\xb7\xbc\xc9", /* "寒冰風暴"; */
+	"\xb1\x6a\xa4\x4f\xc1\xf4\xa7\xce", /* "強力隱形"; */
+	"\xb8\xd1\xb0\xa3\xb6\x41\xa9\x47", /* "解除詛咒"; */
+	"\xa7\x4e\xc0\x40\xb3\x4e", /* "冷錐術"; */
+	"\xa9\xc7\xaa\xab\xa9\x77\xa8\xad", /* "怪物定身"; */
+	"\xa4\x4f\xc0\xf0\xb3\x4e", /* "力牆術"; */
+	"\xa4\xc0\xb8\xd1\xb3\x4e", /* "分解術"; */
+	"\xa5\xdb\xa4\xc6\xb3\x4e", /* "石化術"; */
+	"\xb8\xd1\xb0\xa3\xa5\xdb\xa4\xc6", /* "解除石化"; */
+	"\xb3\x7a\xb5\xf8\xb3\x4e", /* "透視術"; */
+	"\xa6\xba\xa4\x60\xa4\xa7\xab\xfc", /* "死亡之指"; */
+	"\xb1\x6a\xa4\x4f\xc5\x5d\xa9\x47", /* "強力魔咒"; */
+	"\xb6\x57\xaf\xc5\xae\xb1\xc0\x59", /* "超級拳頭"; */
+};
+
+static const StringListProvider kEoB2MageSpellsListDOSChineseProvider = { ARRAYSIZE(kEoB2MageSpellsListDOSChinese), kEoB2MageSpellsListDOSChinese };
+
+static const char *const kEoB2ClericSpellsListDOSChinese[30] = {
+	"",
+	"\xaf\xac\xba\xd6\xb3\x4e", /* "祝福術"; */
+	"\xbb\xb4\xab\xd7\xb6\xcb\xae\x60", /* "輕度傷害"; */
+	"\xaa\x76\xc0\xf8\xbb\xb4\xb6\xcb", /* "治療輕傷"; */
+	"\xb0\xbb\xb4\xfa\xc5\x5d\xaa\x6b", /* "偵測魔法"; */
+	"\xa6\xca\xa8\xb8\xa4\xa3\xab\x49", /* "百邪不侵"; */
+	"\xb1\x6a\xa4\xc6\xa5\xcd\xa9\x52", /* "強化生命"; */
+	"\xa4\xf5\xb5\x4b\xa4\xa7\xa4\x62", /* "火焰之刃"; */
+	"\xa9\x77\xa8\xad\xb3\x4e", /* "定身術"; */
+	"\xb4\xee\xbd\x77\xac\x72\xa9\xca", /* "減緩毒性"; */
+	"\xbb\x73\xb3\x79\xad\xb9\xaa\xab", /* "製造食物"; */
+	"\xb8\xd1\xa9\x47\xb3\x4e", /* "解咒術"; */
+	"\xc5\x5d\xaa\x6b\xa4\xa7\xb3\x54", /* "魔法之袍"; */
+	"\xac\xe8\xc3\xab\xb3\x4e", /* "祈禱術"; */
+	"\xb8\xd1\xb0\xa3\xb7\xf2\xde\xcd", /* "解除痲痹"; */
+	"\xad\xab\xab\xd7\xb6\xcb\xae\x60", /* "重度傷害"; */
+	"\xaa\x76\xc0\xf8\xad\xab\xb6\xcb", /* "治療重傷"; */
+	"\xa4\xa4\xa9\x4d\xac\x72\xaf\xc0", /* "中和毒素"; */
+	"\xb9\x40\xa8\xb8\xa4\x51\xa7\x60", /* "辟邪十呎"; */
+	"\xad\x50\xa9\x52\xb6\xcb\xae\x60", /* "致命傷害"; */
+	"\xaa\x76\xc0\xf8\xad\x50\xa9\x52", /* "治療致命"; */
+	"\xa4\xd1\xa4\xf5\xb5\x49\xa8\xad", /* "天火焚身"; */
+	"\xb4\x5f\xac\xa1\xb3\x4e", /* "復活術"; */
+	"\xb9\xdc\xa9\x52\xb3\x4e", /* "奪命術"; */
+	"\xb3\x7a\xb5\xf8\xb3\x4e", /* "透視術"; */
+	"\xb6\xcb\xae\x60\xb3\x4e", /* "傷害術"; */
+	"\xa7\xb9\xa5\xfe\xc2\xe5\xc0\xf8", /* "完全醫療"; */
+	"\xa6\x41\xb3\x79\xa5\xcd\xa9\x52", /* "再造生命"; */
+	"\xb6\xc7\xa5\x5c\xa4\x6a\xaa\x6b", /* "傳功大法"; */
+	"\xb6\x57\xb4\xe7\xa4\x60\xbb\xee", /* "超渡亡魂"; */
+};
+
+static const StringListProvider kEoB2ClericSpellsListDOSChineseProvider = { ARRAYSIZE(kEoB2ClericSpellsListDOSChinese), kEoB2ClericSpellsListDOSChinese };
+
+static const char *const kEoB2SpellNamesDOSChinese[68] = {
+	"\xc5\x5d\xab\x60\xb3\x4e", /* "魔冑術"; "armor" */
+	"\xbf\x55\xbf\x4e\xa4\xa7\xa4\xe2", /* "燃燒之手"; "burning hands" */
+	"\xb0\xbb\xb4\xfa\xc5\x5d\xaa\x6b", /* "偵測魔法"; "detect magic" */
+	"\xc5\x5d\xaa\x6b\xad\xb8\xbc\x75", /* "魔法飛彈"; "magic missile" */
+	"\xc5\x5d\xac\xde\xb3\x4e", /* "魔盾術"; "shield" */
+	"\xb9\x71\xc0\xbb\xa4\xe2\xa4\x4d", /* "電擊手刀"; "shocking grasp" */
+	"\xc2\x61\xc4\x67\xa4\xc6\xa8\xad", /* "朦朧化身"; "blur" */
+	"\xb0\xbb\xb4\xfa\xc1\xf4\xa7\xce", /* "偵測隱形"; "detect invisibility" */
+	"\xbf\xeb\xc3\xd1\xaa\xab\xab\x7e", /* "辨識物品"; "improved identify" */
+	"\xc1\xf4\xa7\xce\xb3\x4e", /* "隱形術"; "invisibility" */
+	"\xbb\xc4\xb2\x47\xa4\xa7\xbd\x62", /* "酸液之箭"; "melf's acid arrow" */
+	"\xb8\xd1\xa9\x47\xb3\x4e", /* "解咒術"; "dispel magic" */
+	"\xa4\xf5\xb2\x79\xb3\x4e", /* "火球術"; "fireball" */
+	"\xa8\xb3\xb1\xb6\xb3\x4e", /* "迅捷術"; "haste" */
+	"\xa9\x77\xa8\xad\xb3\x4e", /* "定身術"; "Hold Person" */
+	"\x31\x30\xa7\x60\xc1\xf4\xa7\xce", /* "10呎隱形"; "invisibility 10' radius" */
+	"\xb9\x70\xb9\x71\xb3\x4e", /* "雷電術"; "lightning bolt" */
+	"\xa7\x6c\xa6\xe5\xb0\xad\xa4\xf6", /* "吸血鬼爪"; "vampiric touch" */
+	"\xae\xa3\xc4\xdf\xb3\x4e", /* "恐懼術"; "fear" */
+	"\xb4\x48\xa6\x42\xad\xb7\xbc\xc9", /* "寒冰風暴"; "ice storm" */
+	"\xb1\x6a\xa4\x4f\xc1\xf4\xa7\xce", /* "強力隱形"; "improved invisibility" */
+	"\xb8\xd1\xb0\xa3\xb6\x41\xa9\x47", /* "解除詛咒"; "remove curse" */
+	"\xa7\x4e\xc0\x40\xb3\x4e", /* "冷錐術"; "cone of cold" */
+	"\xa9\xc7\xaa\xab\xa9\x77\xa8\xad", /* "怪物定身"; "hold monster" */
+	"\xa4\x4f\xc0\xf0\xb3\x4e", /* "力牆術"; "wall of force" */
+	"\xa4\xc0\xb8\xd1\xb3\x4e", /* "分解術"; "disintegrate" */
+	"\xa5\xdb\xa4\xc6\xb3\x4e", /* "石化術"; "flesh to stone" */
+	"\xb8\xd1\xb0\xa3\xa5\xdb\xa4\xc6", /* "解除石化"; "stone to flesh" */
+	"\xb3\x7a\xb5\xf8\xb3\x4e", /* "透視術"; "true seeing" */
+	"\xa6\xba\xa4\x60\xa4\xa7\xab\xfc", /* "死亡之指"; "finger of death" */
+	"\xb1\x6a\xa4\x4f\xc5\x5d\xa9\x47", /* "強力魔咒"; "power word stun" */
+	"\xb6\x57\xaf\xc5\xad\xab\xae\xb1", /* "超級重拳"; "bigby's clenched fist" */
+	"\xaf\xac\xba\xd6\xb3\x4e", /* "祝福術";  "bless"*/
+	"\xbb\xb4\xab\xd7\xb6\xcb\xae\x60", /* "輕度傷害"; "cause light wounds" */
+	"\xaa\x76\xc0\xf8\xbb\xb4\xb6\xcb", /* "治療輕傷"; "cure light wounds" */
+	"\xb0\xbb\xb4\xfa\xc5\x5d\xaa\x6b", /* "偵測魔法"; "detect magic" */
+	"\xa6\xca\xa8\xb8\xa4\xa3\xab\x49", /* "百邪不侵"; "protection from evil" */
+	"\xb1\x6a\xa4\xc6\xa5\xcd\xa9\x52", /* "強化生命"; "aid" */
+	"\xa4\xf5\xb5\x4b\xa4\xa7\xa4\x62", /* "火焰之刃"; "flame blade" */
+	"\xa9\x77\xa8\xad\xb3\x4e", /* "定身術"; "hold person" */
+	"\xb4\xee\xbd\x77\xac\x72\xa9\xca", /* "減緩毒性"; "slow poison" */
+	"\xb3\x79\xad\xb9\xaa\xab\xa9\x4d\xa4\xf4", /* "造食物和水"; "create food" */
+	"\xb8\xd1\xa9\x47\xb3\x4e", /* "解咒術"; "dispel magic" */
+	"\xc5\x5d\xaa\x6b\xa4\xa7\xb3\x54", /* "魔法之袍"; "magical vestment" */
+	"\xac\xe8\xc3\xab\xb3\x4e", /* "祈禱術"; "prayer" */
+	"\xb8\xd1\xb0\xa3\xb7\xf2\xde\xcd", /* "解除痲痹"; "remove paralysis" */
+	"\xad\xab\xab\xd7\xb6\xcb\xae\x60", /* "重度傷害"; "cause serious wounds" */
+	"\xaa\x76\xc0\xf8\xad\xab\xb6\xcb", /* "治療重傷"; "cure serious wounds" */
+	"\xa4\xa4\xa9\x4d\xac\x72\xaf\xc0", /* "中和毒素"; "neutralize poison" */
+	"\xb9\x40\xa8\xb8\xa4\x51\xa7\x60", /* "辟邪十呎"; "protection from evil 10' radius" */
+	"\xad\x50\xa9\x52\xb6\xcb\xae\x60", /* "致命傷害"; "cause critical wounds" */
+	"\xaa\x76\xc0\xf8\xad\x50\xa9\x52", /* "治療致命"; "cure critical wounds" */
+	"\xa4\xd1\xa4\xf5\xb5\x49\xa8\xad", /* "天火焚身"; "flame strike" */
+	"\xb4\x5f\xac\xa1\xb3\x4e", /* "復活術"; "raise dead" */
+	"\xb9\xdc\xa9\x52\xb3\x4e", /* "奪命術"; "slay living" */
+	"\xb3\x7a\xb5\xf8\xb3\x4e", /* "透視術"; "true seeing" */
+	"\xb6\xcb\xae\x60\xb3\x4e", /* "傷害術"; "harm" */
+	"\xa7\xb9\xa5\xfe\xc2\xe5\xc0\xf8", /* "完全醫療"; "heal" */
+	"\xa6\x41\xb3\x79\xa5\xcd\xa9\x52", /* "再造生命"; "ressurection" */
+	"\xb6\xc7\xa5\xa4\x6a\xaa\x6b", /* "傳奶j法"; "lay on hands" */
+	"\xb6\x57\xb4\xe7\xa4\x60\xbb\xee", /* "超渡亡魂"; "turn undead" */
+	"",
+	"\xc0\x73\xae\xf0\xc5\x40\xb8\x6e", /* "龍氣護罩"; "mystic defense" */
+	"",
+	"",
+	"",
+	"",
+	""
+};
+
+static const StringListProvider kEoB2SpellNamesDOSChineseProvider = { ARRAYSIZE(kEoB2SpellNamesDOSChinese), kEoB2SpellNamesDOSChinese };
+
+static const char *const kEoB2MagicStrings1DOSChinese[6] = {
+	"\xa9\xf1\xb1\xf3", /* "放棄"; */
+	"\xa9\xf1\xb1\xf3", /* "放棄"; */
+	"\xb1\x7a\xa5\xb2\xb6\xb7\xaa\xc5\xb5\xdb\xa4\x40\xb0\xa6\xa4\xe2\x2c\xa4\x7e\xaf\xe0\xac\x49\xae\x69\xb3\x6f\xb6\xb5\xaa\x6b\xb3\x4e\x2e", /* "您必須空著一隻手,才能施展這項法術."; */
+	"\xb1\x7a\xa6\xdb\xa4\x76\xa4\xa3\xaf\xe0\xa6\x50\xae\xc9\xa8\xcf\xa5\xce\xb3\x6f\xaa\x6b\xb3\x4e\xa8\xe2\xa6\xb8\x2e", /* "您自己不能同時使用這法術兩次."; */
+	"%s\xac\x49\xae\x69\xa4\x46%s\x2e", /* "%s施展了%s."; */
+	"\xac\x49\xaa\x6b\xa7\xb9\xb2\xa6", /* "施法完畢"; */
+};
+
+static const StringListProvider kEoB2MagicStrings1DOSChineseProvider = { ARRAYSIZE(kEoB2MagicStrings1DOSChinese), kEoB2MagicStrings1DOSChinese };
+
+static const char *const kEoB2MagicStrings2DOSChinese[5] = {
+	"\xac\x49\xaa\x6b\xa5\xa2\xb1\xd1\x21\r", /* "施法失敗!\r"; */
+	"\x25\x73\xa4\x77\xb8\x67\xb3\x51\xa4\xc0\xb8\xd1\xa4\x46\x21\r", /* "%s已經被分解了!\r"; */
+	"\x06\x06\xb6\xa4\xa5\xee\xa4\x77\xb3\x51\xa6\xba\xa4\x60\xa4\xa7\xb3\x4e\xa9\xd2\xc0\xbb\xa4\xa4\x21\r", /* "\x06\x06隊伍已被死亡之術所擊中!\r"; */
+	"\x06\x06\x25\x73\xa4\x77\xb8\x67\xb3\x51\xad\xab\xab\xd7\xb6\xcb\xae\x60\xaa\x6b\xb3\x4e\xa9\xd2\xb6\xcb\x2e\r", /* "\x06\x06%s已經被重度傷害法術所傷.\r"; */
+	"\xb3\x51\xa5\xdb\xa4\xc6", /* "被石化"; */
+};
+
+static const StringListProvider kEoB2MagicStrings2DOSChineseProvider = { ARRAYSIZE(kEoB2MagicStrings2DOSChinese), kEoB2MagicStrings2DOSChinese };
+
+static const char *const kEoB2MagicStrings3DOSChinese[5] = {
+	"\xa6\x56\xa8\xba\xa4\x40\xad\xd3\xb6\xa4\xad\xfb\xac\x49\xae\x69\xa6\xb9\xb6\xb5\xaa\x6b\xb3\x4e\x3f", /* "向那一個隊員施展此項法術?"; */
+	"\r\xa9\xf1\xb1\xf3\xac\x49\xae\x69\xaa\x6b\xb3\x4e\x2e\r", /* "\r放棄施展法術.\r"; */
+	"\x25\x73\xaa\xba\x25\x73\xae\xc4\xa4\x4f\xae\xc9\xb6\xa1\xa4\x77\xb9\x4c\x21\r", /* "%s的%s效力時間已過!\r"; */
+	"\x25\x73\xa8\x53\xa6\xb3\xc0\xbb\xa4\xa4\xb3\x6f\xa9\xc7\xaa\xab\x2e\r", /* "%s沒有擊中這怪物.\r"; */
+	"\x25\x73\xbb\xdd\xad\x6e\xa6\xb3\xb8\xfb\xb0\xaa\xaa\xba\xb5\xa5\xaf\xc5\xa4\x7e\xaf\xe0\xc0\xbb\xa4\xa4\xa5\xd8\xbc\xd0\x21\r", /* "%s需要有較高的等級才能擊中目標!\r"; */
+};
+
+static const StringListProvider kEoB2MagicStrings3DOSChineseProvider = { ARRAYSIZE(kEoB2MagicStrings3DOSChinese), kEoB2MagicStrings3DOSChinese };
+
+static const char *const kEoB2MagicStrings4DOSChinese[1] = {
+	"\xab\x7a\x21\xa8\x53\xa6\xb3\xa5\x5c\xae\xc4\x21\x0d", /* "哇!沒有功效!\r"; */
+};
+
+static const StringListProvider kEoB2MagicStrings4DOSChineseProvider = { ARRAYSIZE(kEoB2MagicStrings4DOSChinese), kEoB2MagicStrings4DOSChinese };
+
+static const char *const kEoB2MagicStrings6DOSChinese[1] = {
+	"\x25\x73\xa4\x77\xa6\xb3\xa4\x40\xad\xd3\xc5\x40\xa5\xd2\xaa\xba\xa8\xbe\xbf\x6d\xb2\x76\xb6\x57\xb9\x4c\x20\x36\x20\xc2\x49\x2e", /* "%s已有一個護甲的防禦率超過 6 點."; */
+};
+
+static const StringListProvider kEoB2MagicStrings6DOSChineseProvider = { ARRAYSIZE(kEoB2MagicStrings6DOSChinese), kEoB2MagicStrings6DOSChinese };
+
+static const char *const kEoB2MagicStrings7DOSChinese[2] = {
+	"\x25\x73\xa4\x77\xa6\x62\xb3\x6f\x25\x73\xaa\xba\xae\xc4\xa4\x4f\xa4\xa7\xa4\xba\x2e\r", /* "%s已在這%s的效力之內.\r"; */
+	"\xbe\xe3\xa4\xe4\xb6\xa4\xa5\xee\xa4\x77\xb8\x67\xa6\x62\xb3\x6f\x25\x73\xaa\xba\xae\xc4\xa4\x4f\xa4\xa7\xa4\xba\x2e\r", /* "整支隊伍已經在這%s的效力之內.\r"; */
+};
+
+static const StringListProvider kEoB2MagicStrings7DOSChineseProvider = { ARRAYSIZE(kEoB2MagicStrings7DOSChinese), kEoB2MagicStrings7DOSChinese };
+
+static const char *const kEoB2MagicStrings8DOSChinese[6] = {
+	"\xac\x49\xaa\x6b\xa5\xa2\xb1\xd1\x21\r", /* "施法失敗!\r"; */
+	"\xb3\x51\xb7\xf2\xb7\xf4", /* "被痲痺"; */
+	"\xac\x49\xaa\x6b\xa5\xa2\xb1\xd1\x21\r", /* "施法失敗!\r"; */
+	"\xac\x49\xaa\x6b\xa5\xa2\xb1\xd1\x21\r", /* "施法失敗!\r"; */
+	"\xa8\x53\xa6\xb3\xa9\xc7\xaa\xab\xa9\xce\xbc\xc4\xa4\x48\xb1\xb5\xaa\xf1\x21\r", /* "沒有怪物或敵人接近!\r"; */
+	"\x25\x73\xa4\x77\xa6\x62\xb1\x6a\xa4\xc6\xa5\xcd\xa9\x52\xb3\x4e\xaa\xba\xae\xc4\xa4\x4f\xbd\x64\xb3\xf2\xa4\xa7\xa4\xba\x2e\r", /* "%s已在強化生命術的效力範圍之內.\r"; */
+};
+
+static const StringListProvider kEoB2MagicStrings8DOSChineseProvider = { ARRAYSIZE(kEoB2MagicStrings8DOSChinese), kEoB2MagicStrings8DOSChinese };
+
+static const byte kEoB2ManDefDOSChinese[200] = {
+	0x09, 0x03, 0x04, 0x00, 0x09, 0x0D, 0x02, 0x00,
+	0x09, 0x07, 0x07, 0x00, 0x14, 0x06, 0x05, 0x00,
+	0x14, 0x10, 0x06, 0x00, 0x14, 0x1C, 0x03, 0x00,
+	0x1A, 0x04, 0x06, 0x00, 0x1A, 0x0A, 0x05, 0x00,
+	0x1A, 0x0C, 0x05, 0x00, 0x15, 0x03, 0x04, 0x00,
+	0x15, 0x05, 0x05, 0x00, 0x15, 0x0F, 0x02, 0x00,
+	0x15, 0x14, 0x03, 0x00, 0x15, 0x1B, 0x02, 0x00,
+	0x15, 0x1D, 0x03, 0x00, 0x23, 0x01, 0x03, 0x00,
+	0x23, 0x03, 0x03, 0x00, 0x23, 0x08, 0x03, 0x00,
+	0x23, 0x19, 0x02, 0x00, 0x23, 0x1F, 0x04, 0x00,
+	0x23, 0x26, 0x04, 0x00, 0x26, 0x03, 0x02, 0x00,
+	0x26, 0x05, 0x06, 0x00, 0x26, 0x12, 0x03, 0x00,
+	0x26, 0x18, 0x01, 0x00, 0x26, 0x1E, 0x01, 0x00,
+	0x26, 0x21, 0x04, 0x00, 0x17, 0x01, 0x03, 0x00,
+	0x17, 0x03, 0x06, 0x00, 0x17, 0x06, 0x02, 0x00,
+	0x17, 0x0F, 0x05, 0x00, 0x17, 0x1B, 0x01, 0x00,
+	0x17, 0x21, 0x06, 0x00, 0x12, 0x03, 0x02, 0x00,
+	0x12, 0x05, 0x04, 0x00, 0x12, 0x09, 0x02, 0x00,
+	0x12, 0x0B, 0x04, 0x00, 0x12, 0x0D, 0x06, 0x00,
+	0x12, 0x0F, 0x03, 0x00, 0x12, 0x11, 0x05, 0x00,
+	0x12, 0x12, 0x02, 0x00, 0x1F, 0x02, 0x04, 0x00,
+	0x1F, 0x02, 0x07, 0x00, 0x1F, 0x04, 0x03, 0x00,
+	0x1F, 0x06, 0x03, 0x00, 0x1F, 0x09, 0x03, 0x00,
+	0x1F, 0x0A, 0x01, 0x00, 0x1C, 0x03, 0x03, 0x00,
+	0x1C, 0x04, 0x02, 0x00, 0x1C, 0x05, 0x06, 0x00
+};
+
+static const ByteProvider kEoB2ManDefDOSChineseProvider = { ARRAYSIZE(kEoB2ManDefDOSChinese), kEoB2ManDefDOSChinese };
+
+static const char *const kEoB2ManWordDOSChinese[51] = {
+	"cursor",
+	"majority",
+	"right",
+	"unusable",
+	"greyed",
+	"thrown",
+	"spellcasters",
+	"button",
+	"characters",
+	"carefree",
+	"practical",
+	"inherit",
+	"while",
+	"combinations",
+	"charm",
+	"individuals",
+	"gestures",
+	"pummel",
+	"paladins",
+	"skill",
+	"advancement",
+	"also",
+	"counters",
+	"knowledge",
+	"greater",
+	"assume",
+	"several",
+	"laying",
+	"reach",
+	"swiftly",
+	"allows",
+	"limited",
+	"jack",
+	"thrown",
+	"weapons",
+	"note",
+	"certain",
+	"damage",
+	"done",
+	"bonus",
+	"may",
+	"over",
+	"box",
+	"put",
+	"portrait",
+	"backpack",
+	"inside",
+	"causes",
+	"until",
+	"outright",
+	""
+};
+
+static const StringListProvider kEoB2ManWordDOSChineseProvider = { ARRAYSIZE(kEoB2ManWordDOSChinese), kEoB2ManWordDOSChinese };
+
+static const char *const kEoB2ManPromptDOSChinese[1] = {
+	"\r\r\r\rOn the page with this symbol...\r\rFind line %d\rEnter word %d\r"
+};
+
+static const StringListProvider kEoB2ManPromptDOSChineseProvider = { ARRAYSIZE(kEoB2ManPromptDOSChinese), kEoB2ManPromptDOSChinese };
+
+static const char *const kEoB2MainMenuStringsDOSChinese[5] = {
+	"\xb8\xfc\x20\xa4\x4a\x20\xc2\xc2\x20\xc0\xc9", /* "載 入 舊 檔"; */
+	"\xad\xab\xb7\x73\xab\xd8\xa5\xdf\xb7\x73\xb6\xa4\xad\xfb", /* "重新建立新隊員"; */
+	"\xc2\xe0\xb4\xab\xb2\xc4\xa4\x40\xa5\x4e\xaa\xba\xa4\x48\xaa\xab\xb8\xea\xae\xc6", /* "轉換第一代的人物資料"; */
+	"\xc6\x5b\xac\xdd\xa4\xf9\xc0\x59\xac\x47\xa8\xc6\xa4\xb6\xb2\xd0", /* "觀看片頭故事介紹"; */
+	"\xb5\xb2\x20\xa7\xf4\x20\xb9\x43\x20\xc0\xb8", /* "結 束 遊 戲"; */
+};
+
+static const StringListProvider kEoB2MainMenuStringsDOSChineseProvider = { ARRAYSIZE(kEoB2MainMenuStringsDOSChinese), kEoB2MainMenuStringsDOSChinese };
+
+static const char *const kEoB2TransferStrings1DOSChinese[2] = {
+	"\xb5\xa5\xaf\xc5\x3a\x25\x64", /* "等級:%d"; */
+	" / %d"
+};
+
+static const StringListProvider kEoB2TransferStrings1DOSChineseProvider = { ARRAYSIZE(kEoB2TransferStrings1DOSChinese), kEoB2TransferStrings1DOSChinese };
+
+static const char *const kEoB2TransferStrings2DOSChinese[2] = {
+	"\xa6\x62\xb1\x7a\xaa\xba\xb6\xa4\xa5\xee\xa4\xa4\x2c\xb1\x7a\xb3\xcc\xa6\x68\xa5\x75\xaf\xe0\xbf\xef\xa5\x7c\xa6\xec\xa4\x48\xaa\xab\xc2\xe0\xb4\xab", /* ",您最多只能選四位人物轉換"; */
+	"Select OK when you are finished choosing your party."
+};
+
+static const StringListProvider kEoB2TransferStrings2DOSChineseProvider = { ARRAYSIZE(kEoB2TransferStrings2DOSChinese), kEoB2TransferStrings2DOSChinese };
+
+static const char *const kEoB2TransferLabelsDOSChinese[2] = {
+	"CANCEL",
+	"OK"
+};
+
+static const StringListProvider kEoB2TransferLabelsDOSChineseProvider = { ARRAYSIZE(kEoB2TransferLabelsDOSChinese), kEoB2TransferLabelsDOSChinese };
+
+static const char *const kEoB2IntroStringsDOSChinese[20] = {
+	"\xa6\x62\xa4\x40\xad\xd3\xad\xb7\xab\x42\xa5\xe6\xa5\x5b\xaa\xba\xb2\x4d\xb1\xe1", /* "在一個風雨交加的清晨"; "In a storm early morning" */
+	"\xa7\x41\xa6\xac\xa8\xec\xa4\x46\xa4\x40\xb1\x69\xab\x4b\xa8\xe7", /* "你收到了一張便函"; "You have received a note" */
+	"\xa5\xa6\xac\x4f\xa7\x41\xaa\xba\xa6\x6e\xa4\xcd\r\xc4\xb3\xaa\xf8\xab\xb4\xba\xb8\xaf\x5a\xbc\x67\xa8\xd3\xaa\xba.", /* "它是你的好友\r議長契爾班寫來的."; "It's from your friend Chancellor Khelben." */
+	"\xab\x4b\xa8\xe7\xa4\x57\xaa\xba\xa4\xba\xae\x65\xa8\xc3\xa4\xa3\xac\x4f\xab\xdc\xb2\x4d\xb7\xa1,\r\xa6\xfd\xac\x4f\xa6\xfc\xa5\x47\xac\xdb\xb7\xed\xba\xf2\xab\xe6.", /* "便函上的內容並不是很清楚,\r但是似乎相當緊急."; "The content on the note is not very clear, but seems fairly urgent." */
+	"\xab\xb4\xba\xb8\xaf\x5a\xad\x6e\xb0\xb5\xa4\xb0\xbb\xf2\xa9\x4f\x3f", /* "契爾班要做什麼呢?"; "What is Khelben going to do?" */
+	"\xc5\x77\xaa\xef,\xbd\xd0\xb6\x69.", /* "歡迎,請進."; "Welcome, please come in." */
+	"\xab\xb4\xba\xb8\xaf\x5a\xa5\x44\xa4\x48\xa4\x77\xb8\x67\xa6\x62\xa5\x4c\xaa\xba\xae\xd1\xa9\xd0\xb5\xa5\xb1\x7a\xa4\x46.", /* "契爾班主人已經在他的書房等您了."; "Master Khelben is already waiting for you in his study." */
+	"\xc1\xc2\xc1\xc2\xa7\x41\xb3\x6f\xbb\xf2\xa7\xd6\xaa\xba\xbb\xb0\xa8\xd3.", /* "謝謝你這麼快的趕來."; "Thank you for rushing. Come." */
+	"\xa6\x6e\xa5\x53\xa7\xcc,\xa7\xda\xb2\x7b\xa6\x62\xa6\xb3\xa4\x46\xb3\xc2\xb7\xd0.", /* "好兄弟,我現在有了麻煩."; "Dude, I'm in trouble now." */
+	"\xbb\xb7\xa5\x6a\xaa\xba\xa7\xaf\xc5\x5d\xa4\x77\xb8\x67\xa4\x4a\xab\x49\xa4\x46\xc1\xf4\xa4\xeb\xaf\xab\xbc\x71.", /* "遠古的妖魔已經入侵了隱月神廟."; "Ancient demons have invaded the Temple of the Hidden Moon." */
+	"\xa7\xda\xb1\x6a\xaf\x50\xaa\xba\xb7\x50\xc4\xb1\xa8\xec,\r\xa5\xbb\xab\xb0\xa5\xab\xaa\xba\xa6\x77\xa5\xfe\xa4\x77\xa6\xb3\xab\xdc\xa4\x6a\xaa\xba\xab\xc2\xaf\xd9.", /* "我強烈的感覺到,\r本城市的安全已有很大的威脅."; "I strongly feel that  the security of this city has been seriously threatened."; */
+	"\xa7\xda\xbb\xdd\xad\x6e\xa7\x41\xaa\xba\xc0\xb0\xa6\xa3.", /* "我需要你的幫忙."; "I need your help." */
+	"\xa4\x54\xa4\xd1\xab\x65,\xa7\xda\xac\xa3\xa4\x46\xa5\x7c\xad\xd3\xa4\x48\xab\x65\xa5\x68\xbd\xd5\xac\x64.", /* "三天前,我派了四個人前去調查."; "Three days ago, I sent four people to investigate." */
+	"\xa6\xfd\xac\x4f\xa6\xdc\xa4\xb5\xa6\x6f\xad\xcc\xad\xb5\xab\x48\xa5\xfe\xb5\x4c.", /* "但是至今她們音信全無."; "but so far They haven't heard from them at all." */
+	"\xa7\xda\xb7\x50\xc4\xb1\xa8\xec\xa6\x6f\xad\xcc\xa5\xbf\xa8\xad\xb3\xb4\xc0\x49\xb9\xd2\xa4\xa4.", /* "我感覺到她們正身陷險境中."; "I feel they are in danger." */
+	"\xae\xb3\xb5\xdb\xb3\x6f\xad\xd3\xaa\xf7\xb9\xf4.", /* "拿著這個金幣."; Hold this coin."; */
+	"\xa7\xda\xb1\x4e\xa8\xcf\xa5\xce\xa5\xa6\xbb\x50\xa7\x41\xc1\x70\xb5\xb8.", /* "我將使用它與你聯絡."; "I will use it with you connection."; */
+	"\xa8\xc6\xa4\xa3\xa9\x79\xbf\xf0,\xa7\x41\xa5\xb2\xb6\xb7\xbb\xb0\xa7\xd6\xb0\xca\xa8\xad.", /* "事不宜遲,你必須趕快動身."; "Without further delay, you must leave quickly."; */
+	"\xa7\xda\xb2\x7b\xa6\x62\xb1\x4e\xa7\x41\xad\xcc\xb6\xc7\xb0\x65\xa8\xec\xb1\xb5\xaa\xf1\xaf\xab\xbc\x71\xaa\xba\xaa\xfe\xaa\xf1.", /* "我現在將你們傳送到接近神廟的附近."; "I will now teleport you closer to the temple." */
+	"\xc4\x40\xa6\x6e\xb9\x42\xa6\xf1\xc0\x48\xb5\xdb\xa7\x41\xad\xcc.", /* "願好運伴隨著你們."; "May good luck be with you."; */
+};
+
+static const StringListProvider kEoB2IntroStringsDOSChineseProvider = { ARRAYSIZE(kEoB2IntroStringsDOSChinese), kEoB2IntroStringsDOSChinese }; // OK
+
+static const char *const kEoB2IntroCPSFilesDOSChinese[13] = {
+	"STREET1.CPS",
+	"STREET2.CPS",
+	"DOORWAY1.CPS",
+	"DOORWAY2.CPS",
+	"WESTWOOD.CPS",
+	"WINDING.CPS",
+	"KHELBAN2.CPS",
+	"KHELBAN1.CPS",
+	"KHELBAN3.CPS",
+	"KHELBAN4.CPS",
+	"COIN.CPS",
+	"KHELBAN5.CPS",
+	"KHELBAN6.CPS"
+};
+
+static const StringListProvider kEoB2IntroCPSFilesDOSChineseProvider = { ARRAYSIZE(kEoB2IntroCPSFilesDOSChinese), kEoB2IntroCPSFilesDOSChinese }; // OK
+
+static const char *const kEoB2FinaleStringsDOSChinese[20] = {
+	"\xb3\xcc\xab\xe1\xb3\xd3\xa7\x51\xaa\xba\xae\xc9\xa8\xe8\xb2\xd7\xa9\xf3\xa8\xd3\xa8\xec\x2c\xb1\x4d\xae\xa6\xb3\x51\xc0\xbb\xb1\xd1\xa4\x46\x2e", /* "最後勝利的時刻終於來到,專恩被擊敗了."; "The moment of final victory has finally come, Boen is defeated." */
+	"\xac\xf0\xb5\x4d\x2c\xb1\x7a\xaa\xba\xa6\x6e\xa4\xcd\xab\xb4\xba\xb8\xaf\x5a\xa5\x58\xb2\x7b\xa4\x46\x2e", /* "突然,您的好友契爾班出現了."; "Suddenly, your friend Khelben appeared." */
+	"\xae\xa5\xb3\xdf\xa7\x41\x2c\xa7\xda\xc0\xf2\xb1\x6f\xb3\xd3\xa7\x51\xaa\xba\xa6\xd1\xa4\xcd\x2e", /* "恭喜你,我獲得勝利的老友."; "Congratulations, my victorious old friend." */
+	"\xa7\x41\xa4\x77\xb8\x67\xc0\xbb\xb1\xd1\xa4\x46\xc5\x5d\xc0\x73\xb1\x4d\xae\xa6\x21", /* "你已經擊敗了魔龍專恩!"; "You have Defeated the dragon Boen!" */
+	"\xa7\xda\xa8\xc3\xa4\xa3\xaa\xbe\xb9\x44\x2c\xb1\x4d\xae\xa6\xad\xec\xa8\xd3\xac\x4f\xa4\x40\xb1\xf8\xb4\x63\xc0\x73\x2e", /* "我並不知道,專恩原來是一條惡龍."; "I don't know, Zhuanen turned out to be a dragon." */
+	"\xa8\x65\xa4\x77\xb8\x67\xa5\xcd\xa6\x73\xa6\xb3\xb6\x57\xb9\x4c\x33\x30\x30\xa6\x7e\xa4\x46\x21", /* "牠已經生存有超過300年了!"; "It's been around for over 300 years!" */
+	"\xa8\x65\xaa\xba\xa4\x4f\xb6\x71\xa4\x77\xc0\x48\xad\xb7\xa6\xd3\xa5\x68\x2e", /* "牠的力量已隨風而去."; "Its power has gone with the wind."; */
+	"\xa6\xfd\xc1\xf4\xa4\xeb\xaf\xab\xbc\x71\xa8\xcc\xc2\xc2\xac\x4f\xa5\xa8\xa4\x6a\xa8\xb8\xb4\x63\xa4\x4f\xb6\x71\xaa\xba\xb7\xbd\xc0\x59\x2e", /* "但隱月神廟依舊是巨大邪惡力量的源頭."; "But the Darkmoon temple is still the source of great evil power." */
+	"\xa8\xc3\xa5\x42\xa8\x65\xaa\xba\xb3\x5c\xa6\x68\xa4\xf6\xa4\xfa\xa8\xcc\xb5\x4d\xa6\x73\xa6\x62\x2e", /* "並且牠的許多爪牙依然存在."; "And many of its minions still exist." */
+	"\xb2\x7b\xa6\x62\xa7\xda\xad\xcc\xa5\xb2\xb6\xb7\xbb\xb0\xa7\xd6\xc2\xf7\xb6\x7d\xa6\xb9\xb3\x42\x2e", /* "現在我們必須趕快離開此處."; "We must get out of here now." */
+	"\xb3\x6f\xbc\xcb\xa7\xda\xa4\x7e\xaf\xe0\xb1\x4e\xa6\xb9\xbc\x71\xba\x52\xb7\xb4\xa6\x69\xac\xb0\xa5\xad\xa6\x61\x2e", /* "這樣我才能將此廟摧毀夷為平地."; "So I can destroy this temple and raze it to the ground." */
+	"\xb8\xf2\xa7\xda\xa8\xd3\x2e", /* "跟我來."; "Follow me." */
+	"\xb1\x6a\xa4\x6a\xaa\xba\xaa\x6b\xa4\x4f\xa4\x77\xb7\xc7\xb3\xc6\xa6\x6e\xb9\xef\xaf\xab\xbc\x71\xb0\xb5\xb7\xb4\xb7\xc0\xa9\xca\xa7\xf0\xc0\xbb\x2e", /* "強大的法力已準備好對神廟做毀滅性攻擊."; "The powerful mana is ready to do a devastating attack on the temple." */
+	"\xaf\xab\xbc\x71\xaa\xba\xc5\x5d\xa4\x4f\xaf\x75\xac\x4f\xab\x44\xb1\x60\xaa\xba\xb1\x6a\xae\xab\x2e", /* "神廟的魔力真是非常的強悍."; "The magic of the temple is really powerful." */
+	"\xa5\xa6\xb5\xb4\xa4\xa3\xa5\x69\xa5\x48\xc4\x7e\xc4\xf2\xa6\x73\xa6\x62\x21", /* "它絕不可以繼續存在!"; "It must not continue to exist !"; */
+	"\xaf\xab\xbc\x71\xb2\xd7\xa9\xf3\xa4\xc6\xac\xb0\xaf\x51\xa6\xb3\xa4\x46\x2e", /* "神廟終於化為烏有了."; "The temple finally disappeared up." */
+	"\xa7\xda\xaa\xba\xa6\x6e\xaa\x42\xa4\xcd\x2c\xa7\xda\xad\xcc\xaa\xba\xa5\xf4\xb0\xc8\xa4\x77\xa7\xb9\xa6\xa8\xa4\x46\x2e", /* "我的好朋友,我們的任務已完成了."; "My good friend, our task has been completed." */
+	"\xc1\xc2\xc1\xc2\xa7\x41\x2e", /* "謝謝你."; "Thank you." */
+	"\xa7\x41\xb1\x4e\xc0\xf2\xb1\x6f\xa7\xda\xad\xcc\xb3\xcc\xb2\x60\xaa\xba\xb7\x71\xb7\x4e\xa9\x4d\xb4\x4c\xb1\x52\x2e", /* "你將獲得我們最深的敬意和尊崇."; "You will receive our deepest respect and honor." */
+	"\xa7\xda\xad\xcc\xb1\x4e\xa5\xc3\xbb\xb7\xb0\x4f\xb1\x6f\xa7\x41\xad\x5e\xab\x69\xa5\xc7\xc3\xf8\xaa\xba\xa8\xc6\xc2\xdd\x2e", /* "我們將永遠記得你英勇犯難的事蹟."; "We will always remember your heroic deeds." */
+};
+
+static const StringListProvider kEoB2FinaleStringsDOSChineseProvider = { ARRAYSIZE(kEoB2FinaleStringsDOSChinese), kEoB2FinaleStringsDOSChinese }; // Likely ok, play finale to check
+
+static const char *const kEoB2FinaleCPSFilesDOSChinese[13] = {
+	"DRAGON1.CPS",
+	"DRAGON2.CPS",
+	"HURRY1.CPS",
+	"HURRY2.CPS",
+	"DESTROY0.CPS",
+	"DESTROY1.CPS",
+	"DESTROY2.CPS",
+	"MAGIC.CPS",
+	"DESTROY3.CPS",
+	"CREDITS2.CPS",
+	"CREDITS3.CPS",
+	"HEROES.CPS",
+	"THANKS.CPS"
+};
+
+static const StringListProvider kEoB2FinaleCPSFilesDOSChineseProvider = { ARRAYSIZE(kEoB2FinaleCPSFilesDOSChinese), kEoB2FinaleCPSFilesDOSChinese };  // Likely ok, play finale to check
+
+static const char *const kEoB2MonsterDistAttStringsDOSChinese[5] = {
+	"\xb6\xa4\xa5\xee\xb3\x51\xa4\xdf\xc6\x46\xae\xa3\xc4\xdf\xb3\x4e\xa9\xd2\xc0\xbb\xa4\xa4\x21\r", /* "隊伍被心靈恐懼術所擊中!\r"; */
+	"\xb3\x51\xb7\xf2\xb7\xf4\xb0\xca\xbc\x75\xa4\xa3\xb1\x6f", /* "被痲痺動彈不得"; */
+	"\xa4\xa4\xac\x72\xa4\x46", /* "中毒了"; */
+	"\xb7\xf2\xb7\xf4\xa4\x46", /* "痲痺了"; */
+	"\xb3\x51\xa5\xdb\xa4\xc6\xa4\x46", /* "被石化了"; */
+};
+
+static const StringListProvider kEoB2MonsterDistAttStringsDOSChineseProvider = { ARRAYSIZE(kEoB2MonsterDistAttStringsDOSChinese), kEoB2MonsterDistAttStringsDOSChinese };
+
+static const char *const kEoB2Npc1StringsDOSChinese[2] = {
+	"\xa5\xe6\x20\xbd\xcd", /* "交 談"; */
+	"\xc2\xf7\x20\xb6\x7d", /* "離 開"; */
+};
+
+static const StringListProvider kEoB2Npc1StringsDOSChineseProvider = { ARRAYSIZE(kEoB2Npc1StringsDOSChinese), kEoB2Npc1StringsDOSChinese };
+
+static const char *const kEoB2Npc2StringsDOSChinese[2] = {
+	"\xc4\xc0\xa9\xf1\xa5\x4c", /* "釋放他"; */
+	"\xc2\xf7\x20\xb6\x7d", /* "離 開"; */
+};
+
+static const StringListProvider kEoB2Npc2StringsDOSChineseProvider = { ARRAYSIZE(kEoB2Npc2StringsDOSChinese), kEoB2Npc2StringsDOSChinese };
+
+static const char *const kEoB2MonsterDustStringsDOSChinese[1] = {
+	"\xb3\x6f\xa9\xc7\xaa\xab\xa4\x77\xb3\x51\xc0\xbb\xa6\xa8\xaf\xbb\xa8\xad\xb8\x48\xb0\xa9\xa4\x46\x21\r", /* "這怪物已被擊成粉身碎骨了!\r"; */
+};
+
+static const StringListProvider kEoB2MonsterDustStringsDOSChineseProvider = { ARRAYSIZE(kEoB2MonsterDustStringsDOSChinese), kEoB2MonsterDustStringsDOSChinese };
+
+static const char *const kEoB2KheldranStringsDOSChinese[1] = {
+	"\x20\x20\xa6\x70\xa6\xb9\xaf\xc2\xaf\x75\xaa\xba\xa4\x70\xa4\x6c\x21", /* "  如此純真的小子!"; */
+};
+
+static const StringListProvider kEoB2KheldranStringsDOSChineseProvider = { ARRAYSIZE(kEoB2KheldranStringsDOSChinese), kEoB2KheldranStringsDOSChinese }; 
+
+static const char *const kEoB2HornStringsDOSChinese[4] = {
+	"\xb1\x71\xb8\xb9\xa8\xa4\xa4\xa4\xb6\xc7\xa5\x58\xb6\xaf\xa7\x71\xaa\xba\xc1\x6e\xad\xb5\x2e\r", /* "從號角中傳出雄吼的聲音.\r"; */
+	"\xb1\x71\xb8\xb9\xa8\xa4\xa4\xa4\xb6\xc7\xa5\x58\xaa\xc5\xac\x7d\xaa\xba\xc1\x6e\xad\xb5\x2e\r", /* "從號角中傳出空洞的聲音.\r"; */
+	"\xb1\x71\xb8\xb9\xa8\xa4\xa4\xa4\xb6\xc7\xa5\x58\xae\xae\xa6\xd5\xaa\xba\xc1\x6e\xad\xb5\x2e\r", /* "從號角中傳出悅耳的聲音.\r"; */
+	"\xb1\x71\xb8\xb9\xa8\xa4\xa4\xa4\xb6\xc7\xa5\x58\xa9\xc7\xb2\xa7\xaa\xba\xc1\x6e\xad\xb5\x2e\r", /* "從號角中傳出怪異的聲音.\r"; */
+};
+
+static const StringListProvider kEoB2HornStringsDOSChineseProvider = { ARRAYSIZE(kEoB2HornStringsDOSChinese), kEoB2HornStringsDOSChinese };
+
+static const char *const kEoB2NpcPresetsNamesDOSChinese[6] = {
+	"\xad\x5e\xc2\xc4\xba\xb8", /* "英薩爾"; "Insal" */
+	"\xa5\x64\xc4\xf5\xbc\x77\xdb\x69", /* "卡蘭德菈"; "Calandra" */
+	"\\xa5\xf0\xae\xa6", /* "休恩"; "Shorn" */
+	"\xb8\x74\xb7\xe7\xba\xb8", /* "聖瑞爾"; "San-raal" */
+	"\xc3\xd3\xae\xe6\xa6\xd5", /* "譚格耳"; "Tanglor" */
+	"\xa6\x77\xbb\x5f\xba\xb8", /* "安蓓爾"; "Amber" */
+};
+
+static const StringListProvider kEoB2NpcPresetsNamesDOSChineseProvider = { ARRAYSIZE(kEoB2NpcPresetsNamesDOSChinese), kEoB2NpcPresetsNamesDOSChinese };
+
+static const DarkMoonAnimCommand kEoB2IntroAnimData40DOSChinese[] = {
+	{ 101,    0,  21, 20,   1,   1,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   1,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   2,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   3,   0,   0,   0,   0 },
+	{ 0x06,  11,   0,  0,   0,   0,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   4,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   5,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,  18,   6,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,  90,   6,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   5,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   4,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   3,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   2,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   1,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   1,   0,   0,   0,   0 },
+	{ 101,    0,  21, 20,   1,   0,   0,   0,   0,   0 },
+	{ 0xFF,   0,   0,  0,   0,   0,   0,   0,   0,   0 }
+};
+
+static const DarkMoonAnimCommandProvider kEoB2IntroAnimData40DOSChineseProvider = { ARRAYSIZE(kEoB2IntroAnimData40DOSChinese), kEoB2IntroAnimData40DOSChinese }; // OK
diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat
index 6762f3811e4..0b19ec4154a 100644
Binary files a/dists/engine-data/kyra.dat and b/dists/engine-data/kyra.dat differ


Commit: 3904b79aa5ae006f1033994b0edc616a4c0ca4ee
    https://github.com/scummvm/scummvm/commit/3904b79aa5ae006f1033994b0edc616a4c0ca4ee
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Handle "taken" in Chinese EOB2.

Changed paths:
    devtools/create_kyradat/resources/eob2_dos_chinese.h
    engines/kyra/engine/eobcommon.cpp


diff --git a/devtools/create_kyradat/resources/eob2_dos_chinese.h b/devtools/create_kyradat/resources/eob2_dos_chinese.h
index fb971cedcfb..feb5b480362 100644
--- a/devtools/create_kyradat/resources/eob2_dos_chinese.h
+++ b/devtools/create_kyradat/resources/eob2_dos_chinese.h
@@ -255,7 +255,7 @@ static const char *const kEoB2ItemMisuseStringsDOSChinese[3] = {
 static const StringListProvider kEoB2ItemMisuseStringsDOSChineseProvider = { ARRAYSIZE(kEoB2ItemMisuseStringsDOSChinese), kEoB2ItemMisuseStringsDOSChinese };
 
 static const char *const kEoB2TakenStringsDOSChinese[1] = {
-	" taken.\r"
+	"\xae\xb3\xa8\xfa", /* "拿取"; */
 };
 
 static const StringListProvider kEoB2TakenStringsDOSChineseProvider = { ARRAYSIZE(kEoB2TakenStringsDOSChinese), kEoB2TakenStringsDOSChinese };
diff --git a/engines/kyra/engine/eobcommon.cpp b/engines/kyra/engine/eobcommon.cpp
index 488726c5791..ea10d636664 100644
--- a/engines/kyra/engine/eobcommon.cpp
+++ b/engines/kyra/engine/eobcommon.cpp
@@ -963,8 +963,14 @@ void EoBCoreEngine::setHandItem(Item itemIndex) {
 	}
 
 	if (_screen->curDimIndex() == 7 && itemIndex) {
-		printFullItemName(itemIndex);
-		_txt->printMessage(_takenStrings[0]);
+		if (_flags.lang == Common::Language::ZH_TWN) {
+			_txt->printMessage(_takenStrings[0]);
+			printFullItemName(itemIndex);
+			_txt->printMessage("\r");
+		} else {
+			printFullItemName(itemIndex);
+			_txt->printMessage(_takenStrings[0]);
+		}
 	}
 
 	_itemInHand = itemIndex;


Commit: 73b55dae93780c086f98c80c127d68ba857df130
    https://github.com/scummvm/scummvm/commit/73b55dae93780c086f98c80c127d68ba857df130
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Change eob2 Chinese from ZH_ANY to more accurate ZH_TWN

Changed paths:
    engines/kyra/detection_tables.h


diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index 564bbc384ec..b1fb0f4a19c 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -2055,7 +2055,7 @@ const KYRAGameDescription adGameDescs[] = {
 			"eob2",
 			msg_missingLangResources, // Reason for being unsupported
 			AD_ENTRY1s("LEVEL15.INF", "f972f628d21bae404a7d52bb287c0012", -1),
-			Common::ZH_ANY,
+			Common::ZH_TWN,
 			Common::kPlatformDOS,
 			ADGF_UNSUPPORTED,
 			GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)


Commit: e5ddd3bc5b9208b16afd719251b90959a013a2bb
    https://github.com/scummvm/scummvm/commit/e5ddd3bc5b9208b16afd719251b90959a013a2bb
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Enable Chinese EOB2

Changed paths:
    engines/kyra/detection_tables.h


diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index b1fb0f4a19c..0fe4aabfd88 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -2053,11 +2053,11 @@ const KYRAGameDescription adGameDescs[] = {
 	{
 		{
 			"eob2",
-			msg_missingLangResources, // Reason for being unsupported
+			0,
 			AD_ENTRY1s("LEVEL15.INF", "f972f628d21bae404a7d52bb287c0012", -1),
 			Common::ZH_TWN,
 			Common::kPlatformDOS,
-			ADGF_UNSUPPORTED,
+			ADGF_NO_FLAGS,
 			GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
 		},
 		EOB2_FLAGS


Commit: 071ee78bc777c80ab5121e5c6163ce257e8252f1
    https://github.com/scummvm/scummvm/commit/071ee78bc777c80ab5121e5c6163ce257e8252f1
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Support compression used in Chinese eob2

Changed paths:
    engines/kyra/engine/scene_eob.cpp
    engines/kyra/graphics/screen_eob.cpp
    engines/kyra/graphics/screen_eob.h


diff --git a/engines/kyra/engine/scene_eob.cpp b/engines/kyra/engine/scene_eob.cpp
index bd82a424537..eb48b7ac3d5 100644
--- a/engines/kyra/engine/scene_eob.cpp
+++ b/engines/kyra/engine/scene_eob.cpp
@@ -125,6 +125,11 @@ void EoBCoreEngine::readLevelFileData(int level) {
 	if (!s)
 		error("Failed to load level file LEVEL%d.INF/DRO/ELO/JOT", level);
 
+	if (_flags.gameID == GI_EOB2 && _flags.lang == Common::Language::ZH_TWN) {
+		_screen->loadChineseEOB2LZBitmap(s, 5, 15000);
+		return;
+	}
+
 	if (s->readUint16LE() + 2 == s->size()) {
 		// check for valid compression type
 		if (s->readUint16LE() <= 4) {
diff --git a/engines/kyra/graphics/screen_eob.cpp b/engines/kyra/graphics/screen_eob.cpp
index 219fc43f30c..f7339f5348d 100644
--- a/engines/kyra/graphics/screen_eob.cpp
+++ b/engines/kyra/graphics/screen_eob.cpp
@@ -42,6 +42,39 @@
 #define VORTEX_ANIM_DURATION 750
 
 namespace Kyra {
+namespace {
+void naive_memcpy(byte *dest, const byte *src, int len) {
+	while(len--)
+		*dest++ = *src++;
+}
+
+struct eob2ChineseLZInStream {
+	Common::SeekableReadStream *srcStream;
+	int numBits;
+	uint16 bits;
+
+	int getBit() {
+		if (numBits == 0) {
+			numBits = 16;
+			bits = getShort();
+		}
+		numBits--;
+		int val = bits & 1;
+		bits >>= 1;
+		return val;
+	}
+
+	byte getByte() {
+		return srcStream->readByte();
+	}
+
+	uint16 getShort() {
+		return srcStream->readUint16LE();
+	}
+
+	eob2ChineseLZInStream(Common::SeekableReadStream *src) : srcStream(src), numBits(0), bits(0) {}
+};
+}
 
 Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _screenDimTable, _screenDimTableCount), _cursorColorKey16Bit(0x8000) {
 	_dsBackgroundFading = false;
@@ -284,7 +317,75 @@ void Screen_EoB::loadShapeSetBitmap(const char *file, int tempPage, int destPage
 	_curPage = 2;
 }
 
+void Screen_EoB::eob2ChineseLZUncompress(byte *dest, uint32 destSize, Common::SeekableReadStream *src) {
+	src->skip(6);
+	eob2ChineseLZInStream in(src);
+	int lzOffset, lzLen;
+	byte *destPtr = dest;
+	byte *destEnd = dest + destSize;
+
+	while (1) {
+		if (in.getBit()) {
+			assert(destPtr < destEnd);
+			*destPtr++ = in.getByte();
+			continue;
+		}
+
+		if (!in.getBit()) {
+			lzLen = in.getBit() << 1;
+			lzLen |= in.getBit();
+			lzOffset = 0x100 - in.getByte();
+		} else {
+			uint16 lzPair = in.getShort();
+			lzOffset = 0x2000 - (lzPair >> 3);
+			lzLen = lzPair & 7;
+			if (lzLen == 0) {
+				lzLen = in.getByte();
+				if (lzLen == 0) {
+					return;
+				}
+			}
+		}
+		lzLen += 2;
+		assert(destPtr < destEnd);
+		assert(destPtr + lzLen < destEnd);
+		assert(destPtr - lzOffset >= dest);
+		naive_memcpy(destPtr, destPtr - lzOffset, lzLen);
+		destPtr += lzLen;
+	}
+}
+
+void Screen_EoB::loadChineseEOB2LZBitmap(Common::SeekableReadStream *s, int pageNum, uint32 size) {
+	eob2ChineseLZUncompress(_pagePtrs[pageNum], size, s);
+}
+
 void Screen_EoB::loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip) {
+	if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN && scumm_stricmp(filename, "menu.cps") == 0) {
+		uint32 palSize;
+		uint8 *palData = _vm->resource()->fileData("menu.col", &palSize);
+		if (!palData) {
+			warning("couldn't load bitmap: '%s'", filename);
+			return;
+		}
+		loadPalette(palData, *pal, palSize);
+		delete[] palData;
+
+		Common::ScopedPtr<Common::SeekableReadStream> srcStream(_vm->resource()->createReadStream(filename));
+
+		if (!srcStream) {
+			warning("couldn't load bitmap: '%s'", filename);
+			return;
+		}
+
+		uint8 *dstData = getPagePtr(dstPage);
+		memset(dstData, 0, _screenPageSize);
+		if (dstPage == 0 || tempPage == 0)
+			_forceFullUpdate = true;
+
+		eob2ChineseLZUncompress(dstData, _screenPageSize, srcStream.get());
+		return;
+	}
+
 	if (!scumm_stricmp(filename + strlen(filename) - 3, "BIN")) {
 		Common::SeekableReadStream *str = _vm->resource()->createReadStream(filename);
 		if (!str)
diff --git a/engines/kyra/graphics/screen_eob.h b/engines/kyra/graphics/screen_eob.h
index 00c727d019c..e88de780358 100644
--- a/engines/kyra/graphics/screen_eob.h
+++ b/engines/kyra/graphics/screen_eob.h
@@ -67,6 +67,8 @@ public:
 
 	void printShadedText(const char *string, int x, int y, int col1, int col2, int shadowCol, int pitch = -1);
 
+	static void eob2ChineseLZUncompress(byte *dest, uint32 destSize, Common::SeekableReadStream *src);
+	void loadChineseEOB2LZBitmap(Common::SeekableReadStream *s, int pageNum, uint32 size);
 	void loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip = false) override;
 	void loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage);
 	void loadShapeSetBitmap(const char *file, int tempPage, int destPage);


Commit: 2703a5c65295dba2dbb7dfd26951fca0de7ce01c
    https://github.com/scummvm/scummvm/commit/2703a5c65295dba2dbb7dfd26951fca0de7ce01c
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Support big5 font used in eob2

Changed paths:
    engines/kyra/graphics/screen_eob.cpp
    engines/kyra/graphics/screen_eob.h


diff --git a/engines/kyra/graphics/screen_eob.cpp b/engines/kyra/graphics/screen_eob.cpp
index f7339f5348d..49497b23d70 100644
--- a/engines/kyra/graphics/screen_eob.cpp
+++ b/engines/kyra/graphics/screen_eob.cpp
@@ -181,6 +181,14 @@ bool Screen_EoB::init() {
 		}
 		_cpsFilePattern += cpsExt[ci];
 
+		if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) {
+			Common::File f;
+			if (!f.open("ceob.pat"))
+				return false;
+			_big5.reset(new Graphics::Big5Font());
+			_big5->loadPrefixedRaw(f, 14);
+		}
+
 		return true;
 	}
 	return false;
@@ -1665,6 +1673,8 @@ bool Screen_EoB::loadFont(FontId fontId, const char *filename) {
 	bool ret = false;
 	if (fnt) {
 		ret = fnt->load(*file);
+		if (_big5)
+			fnt = new ChineseTwoByteFontEoB(_big5, fnt);
 		fnt->setColorMap(_textColorsMap);
 	}
 
@@ -2143,6 +2153,34 @@ void OldDOSFont::unload() {
 	_bitmapOffsets = 0;
 }
 
+uint16 ChineseTwoByteFontEoB::translateBig5(uint16 in) const {
+	if (in < 0x80)
+		return in;
+	in = ((in & 0xff00) >> 8) | ((in & 0xff) << 8);
+	if (_big5->hasGlyphForBig5Char(in))
+		return in;
+	return '?';
+}
+
+int ChineseTwoByteFontEoB::getCharWidth(uint16 c) const {
+	uint16 t = translateBig5(c);
+	return (t < 0x80) ? _singleByte->getCharWidth(t) : _big5->kChineseTraditionalWidth;
+}
+
+int ChineseTwoByteFontEoB::getCharHeight(uint16 c) const {
+	uint16 t = translateBig5(c);
+	return (t < 0x80) ? _singleByte->getCharHeight(t) : _big5->getFontHeight() + 1;
+}
+
+void ChineseTwoByteFontEoB::drawChar(uint16 c, byte *dst, int pitch, int bpp) const {
+	uint16 t = translateBig5(c);
+	if (t < 0x80)
+		_singleByte->drawChar(t, dst, pitch, bpp);
+	else
+		_big5->drawBig5Char(dst, t,
+				    _big5->kChineseTraditionalWidth, _big5->getFontHeight(), pitch, _colorMap[1], _colorMap[0], _border, bpp);
+}
+
 } // End of namespace Kyra
 
 #endif // ENABLE_EOB
diff --git a/engines/kyra/graphics/screen_eob.h b/engines/kyra/graphics/screen_eob.h
index e88de780358..1f3f83bd2e3 100644
--- a/engines/kyra/graphics/screen_eob.h
+++ b/engines/kyra/graphics/screen_eob.h
@@ -24,6 +24,8 @@
 
 #ifdef ENABLE_EOB
 
+#include "graphics/big5.h"
+
 #include "kyra/graphics/screen.h"
 
 namespace Kyra {
@@ -221,6 +223,34 @@ private:
 	uint16 *_segaCustomPalettes;
 	uint8 *_defaultRenderBuffer;
 	int _defaultRenderBufferSize;
+
+	Common::SharedPtr<Graphics::Big5Font> _big5;
+};
+
+class ChineseTwoByteFontEoB final : public Font {
+public:
+	ChineseTwoByteFontEoB(Common::SharedPtr<Graphics::Big5Font> big5, Font *singleByte) : _big5(big5), _singleByte(singleByte), _border(false), _colorMap(nullptr) {}
+
+	virtual Type getType() const override { return kBIG5; }
+
+	bool load(Common::SeekableReadStream &data) override {
+		return _singleByte->load(data);
+	}
+
+	void setStyles(int styles) override { _border = (styles & kStyleBorder); _singleByte->setStyles(styles); }
+	int getHeight() const override { return MAX(_big5->getFontHeight() + 1, _singleByte->getHeight()); }
+	int getWidth() const override { return MAX(_big5->kChineseTraditionalWidth + 2, _singleByte->getWidth()); }
+	void setColorMap(const uint8 *src) override { _colorMap = src; _singleByte->setColorMap(src); }
+	int getCharWidth(uint16 c) const override;
+	int getCharHeight(uint16 c) const override;
+	void drawChar(uint16 c, byte *dst, int pitch, int bpp) const override;
+
+private:
+	uint16 translateBig5(uint16 in) const;
+	Common::SharedPtr<Graphics::Big5Font> _big5;
+	Common::ScopedPtr<Font> _singleByte;
+	bool _border;
+	const uint8 *_colorMap;
 };
 
 /**


Commit: 808399252974fdde2e67c7d8ce7b8005f7d5b06b
    https://github.com/scummvm/scummvm/commit/808399252974fdde2e67c7d8ce7b8005f7d5b06b
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Support word-wrapping in Chinese RPG

Changed paths:
    engines/kyra/text/text_rpg.cpp
    engines/kyra/text/text_rpg.h


diff --git a/engines/kyra/text/text_rpg.cpp b/engines/kyra/text/text_rpg.cpp
index f05fb510a5c..ccc88377e77 100644
--- a/engines/kyra/text/text_rpg.cpp
+++ b/engines/kyra/text/text_rpg.cpp
@@ -36,7 +36,7 @@ TextDisplayer_rpg::TextDisplayer_rpg(KyraRpgEngine *engine, Screen *scr) : _vm(e
 	_lineCount(0), _printFlag(false), _lineWidth(0), _numCharsTotal(0), _allowPageBreak(true),
 	_numCharsLeft(0), _numCharsPrinted(0), _sjisTextModeLineBreak(false), _waitButtonMode(1),
 	_pc98TextMode(engine->gameFlags().use16ColorMode && engine->game() == GI_LOL),
-	_waitButtonFont(Screen::FID_6_FNT) {
+	_waitButtonFont(Screen::FID_6_FNT), _isChinese(_vm->gameFlags().lang == Common::Language::ZH_TWN || _vm->gameFlags().lang == Common::Language::ZH_CHN) {
 
 	static const uint8 amigaColorMap[16] = {
 		0x00, 0x06, 0x1d, 0x1b, 0x1a, 0x17, 0x18, 0x0e, 0x19, 0x1c, 0x1c, 0x1e, 0x13, 0x0a, 0x11, 0x1f
@@ -188,6 +188,22 @@ void TextDisplayer_rpg::displayText(char *str, ...) {
 			}
 		}
 
+		if (_isChinese) {
+			uint8 cu = (uint8) c;
+			if (cu & 0x80) {
+				if ((_textDimData[sdx].column + _lineWidth + Graphics::Big5Font::kChineseTraditionalWidth) > (sd->w << 3))
+					printLine(_currentLine);
+
+				_currentLine[_numCharsLeft++] = c;
+				_currentLine[_numCharsLeft++] = parseCommand();
+				_currentLine[_numCharsLeft] = '\0';
+
+				_lineWidth += Graphics::Big5Font::kChineseTraditionalWidth;
+				c = parseCommand();
+				continue;
+			}
+		}
+
 		uint16 dv = _textDimData[sdx].column / (_screen->getFontWidth() + _screen->_charSpacing);
 
 		switch (c - 1) {
@@ -397,6 +413,13 @@ void TextDisplayer_rpg::printLine(char *str) {
 			}
 		}
 
+		if (_isChinese) {
+			for (int i = 0; i < s; ++i) {
+				if (str[i] & 0x80)
+					twoByteCharOffs = 16;
+			}
+		}
+
 		if ((lw + _textDimData[sdx].column) >= w) {
 			if ((lines - 1) <= _lineCount && _allowPageBreak)
 				// cut off line to leave space for "MORE" button
@@ -414,7 +437,10 @@ void TextDisplayer_rpg::printLine(char *str) {
 
 				for (strPos = 0; strPos < s; ++strPos) {
 					uint8 cu = (uint8) str[strPos];
-					if (cu >= 0xE0 || (cu > 0x80 && cu < 0xA0)) {
+					if (_isChinese && (cu & 0x80)) {
+						lw += twoByteCharOffs;
+						strPos++;
+					} else if (cu >= 0xE0 || (cu > 0x80 && cu < 0xA0)) {
 						lw += sjisOffs;
 						strPos++;
 					} else {
diff --git a/engines/kyra/text/text_rpg.h b/engines/kyra/text/text_rpg.h
index c6a8a9e7212..42ca83c4a13 100644
--- a/engines/kyra/text/text_rpg.h
+++ b/engines/kyra/text/text_rpg.h
@@ -114,6 +114,8 @@ private:
 	Screen::FontId _waitButtonFont;
 
 	uint8 _colorMap[256];
+
+	bool _isChinese;
 };
 
 } // End of namespace Kyra


Commit: 1e6b5eeae441cb24af5651c773f5582e05a2bd9e
    https://github.com/scummvm/scummvm/commit/1e6b5eeae441cb24af5651c773f5582e05a2bd9e
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add 2x height-scaled font for Chinese eob2

This takes BIOS font and height-stretches it 2x just like the original

Changed paths:
    engines/kyra/engine/eobcommon.cpp
    engines/kyra/graphics/screen_eob.cpp
    engines/kyra/graphics/screen_eob.h


diff --git a/engines/kyra/engine/eobcommon.cpp b/engines/kyra/engine/eobcommon.cpp
index ea10d636664..198f191a353 100644
--- a/engines/kyra/engine/eobcommon.cpp
+++ b/engines/kyra/engine/eobcommon.cpp
@@ -591,6 +591,11 @@ void EoBCoreEngine::loadFonts() {
 		_screen->setFontStyles(Screen::FID_8_FNT, Font::kStyleNone);
 		_invFont1 = _invFont2 = _conFont = Screen::FID_8_FNT;
 	}
+
+	if (_flags.lang == Common::ZH_TWN) {
+		_screen->loadFont(Screen::FID_CHINESE_FNT, "FONT8.FNT");
+		_conFont = Screen::FID_CHINESE_FNT;
+	}
 }
 
 Common::Error EoBCoreEngine::go() {
diff --git a/engines/kyra/graphics/screen_eob.cpp b/engines/kyra/graphics/screen_eob.cpp
index 49497b23d70..baea4ae0e37 100644
--- a/engines/kyra/graphics/screen_eob.cpp
+++ b/engines/kyra/graphics/screen_eob.cpp
@@ -37,6 +37,7 @@
 #include "graphics/cursorman.h"
 #include "graphics/palette.h"
 #include "graphics/sjis.h"
+#include "graphics/fonts/dosfont.h"
 
 #define EXPLOSION_ANIM_DURATION 750
 #define VORTEX_ANIM_DURATION 750
@@ -1659,6 +1660,13 @@ bool Screen_EoB::loadFont(FontId fontId, const char *filename) {
 	} else if (_isSegaCD) {
 		fnt = new SegaCDFont(_vm->gameFlags().lang, _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable1, temp), _vm->staticres()->loadRawDataBe16(kEoB1Ascii2SjisTable2, temp),
 			_vm->staticres()->loadRawData(kEoB1CharWidthTable1, temp), _vm->staticres()->loadRawData(kEoB1CharWidthTable2, temp), _vm->staticres()->loadRawData(kEoB1CharWidthTable3, temp));
+	} else if (fontId == FID_CHINESE_FNT && _vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::ZH_TWN) {
+		// We wrap all fonts in Big5 support but FID_CHINESE additionally attempts to match height
+		OldDOSFont *ofnt = new OldDOSFont(_useHiResEGADithering ? Common::kRenderVGA : _renderMode, 12);
+		ofnt->loadPCBIOSTall();
+		fnt = new ChineseTwoByteFontEoB(_big5, ofnt);
+		fnt->setColorMap(_textColorsMap);
+		return true;
 	} else {
 		// We use normal VGA rendering in EOB II, since we do the complete EGA dithering in updateScreen().
 		fnt = new OldDOSFont(_useHiResEGADithering ? Common::kRenderVGA : _renderMode, 12);
@@ -1937,6 +1945,34 @@ OldDOSFont::~OldDOSFont() {
 	}
 }
 
+bool OldDOSFont::loadPCBIOSTall() {
+	unload();
+
+	_numGlyphs = 128;
+	_width = 8;
+	const int originalBytesPerGlyph = 8;
+	const int originalHeight = 8;
+	const int bytesPerGlyph = 15;
+	_height = originalHeight * 2 - 1;
+	_data = new uint8[_numGlyphs * bytesPerGlyph + _numGlyphs * sizeof(uint16)];
+	assert(_data);
+
+	_bitmapOffsets = (uint16 *)_data;
+
+	for (int i = 0; i < _numGlyphs; ++i) {
+		_bitmapOffsets[i] = _numGlyphs * sizeof(uint16) + i * bytesPerGlyph;
+		byte *optr = _data + _bitmapOffsets[i];
+		const byte *iptr = Graphics::DosFont::fontData_PCBIOS + i * originalBytesPerGlyph;
+		*optr++ = *iptr++;
+		for (int j = 1; j < originalHeight; j++) {
+			*optr++ = *iptr;
+			*optr++ = *iptr++;
+		}
+	}
+
+	return true;
+}
+
 bool OldDOSFont::load(Common::SeekableReadStream &file) {
 	unload();
 
diff --git a/engines/kyra/graphics/screen_eob.h b/engines/kyra/graphics/screen_eob.h
index 1f3f83bd2e3..070b78c58c1 100644
--- a/engines/kyra/graphics/screen_eob.h
+++ b/engines/kyra/graphics/screen_eob.h
@@ -238,7 +238,7 @@ public:
 	}
 
 	void setStyles(int styles) override { _border = (styles & kStyleBorder); _singleByte->setStyles(styles); }
-	int getHeight() const override { return MAX(_big5->getFontHeight() + 1, _singleByte->getHeight()); }
+	int getHeight() const override { return MAX(_big5->getFontHeight(), _singleByte->getHeight()); }
 	int getWidth() const override { return MAX(_big5->kChineseTraditionalWidth + 2, _singleByte->getWidth()); }
 	void setColorMap(const uint8 *src) override { _colorMap = src; _singleByte->setColorMap(src); }
 	int getCharWidth(uint16 c) const override;
@@ -264,6 +264,7 @@ public:
 	~OldDOSFont() override;
 
 	bool load(Common::SeekableReadStream &file) override;
+	bool loadPCBIOSTall();
 	Type getType() const override { return kASCII; }
 	int getHeight() const override { return _height; }
 	int getWidth() const override { return _width; }


Commit: 691d25fc7f5da7d0ea868ba64197e0dd5e6a6435
    https://github.com/scummvm/scummvm/commit/691d25fc7f5da7d0ea868ba64197e0dd5e6a6435
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add explicit check for >= 0x80 chars

Signedness of char is platform-dependent.

Changed paths:
    engines/kyra/gui/gui_eob.cpp


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index a9bc6405432..c516f0cfd52 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -4604,7 +4604,7 @@ void GUI_EoB::setupSaveMenuSlots() {
 						// have a special 1-byte encoding that must be kept. It is easy to distinguish between GMM descriptions and ingame descriptions due to the '\r' characters
 						// that the auto-generated strings always and the GMM strings never have.
 						for (uint ii = 0; ii < strlen(_saveSlotStringsTemp[i]); ++ii) {
-							if (_saveSlotStringsTemp[i][ii] < 32 && _saveSlotStringsTemp[i][ii] != '\r') // due to the signed char type this will also clean up everything >= 0x80
+						  if ((_saveSlotStringsTemp[i][ii] & 0x80) || (_saveSlotStringsTemp[i][ii] < 32 && _saveSlotStringsTemp[i][ii] != '\r'))
 								_saveSlotStringsTemp[i][ii] = ' ';
 						}
 				}


Commit: 6a00f7a4180ea2abb774dfcce27394c4258141b4
    https://github.com/scummvm/scummvm/commit/6a00f7a4180ea2abb774dfcce27394c4258141b4
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Fix handling of importing EOB2 original saves containing Chinese chars

Changed paths:
    engines/kyra/gui/gui.cpp
    engines/kyra/gui/gui_eob.cpp
    engines/kyra/gui/saveload_eob.cpp


diff --git a/engines/kyra/gui/gui.cpp b/engines/kyra/gui/gui.cpp
index bdc232c360f..ba74570a42f 100644
--- a/engines/kyra/gui/gui.cpp
+++ b/engines/kyra/gui/gui.cpp
@@ -120,7 +120,8 @@ void GUI::updateSaveSlotsList(Common::String targetName, bool force) {
 				// Ingame auto-generated Japanese EOB SegaCD savegame descriptions have a special 1-byte encoding that
 				// does not survive this conversion. And the rest of the characters in these descriptions do not require it.
 				if (!(_vm->gameFlags().platform == Common::kPlatformSegaCD && _vm->gameFlags().lang == Common::JA_JPN && Common::String(*listEntry).contains('\r')))
-					Util::convertString_GUItoKYRA(*listEntry, buffSize);
+					Util::convertString_GUItoKYRA(*listEntry, buffSize,
+								      _vm->gameFlags().lang == Common::ZH_TWN ? Common::CodePage::kBig5 : Common::CodePage::kDos850);
 				delete in;
 			} else {
 				*listEntry = nullptr;
diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index c516f0cfd52..b1e45840edd 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -4598,7 +4598,7 @@ void GUI_EoB::setupSaveMenuSlots() {
 				Common::strlcpy(_saveSlotStringsTemp[i], _savegameList[i + _savegameOffset], 25);
 
 				if (!(_vm->gameFlags().lang == Common::JA_JPN && _vm->gameFlags().platform == Common::kPlatformSegaCD &&
-					Common::String(_saveSlotStringsTemp[i]).contains('\r')) && (_vm->gameFlags().lang == Common::JA_JPN || _vm->gameFlags().lang == Common::ZH_TWN || _vm->gameFlags().platform == Common::kPlatformSegaCD)) {
+				      Common::String(_saveSlotStringsTemp[i]).contains('\r')) && (_vm->gameFlags().lang == Common::JA_JPN || (_vm->gameFlags().lang == Common::ZH_TWN && _vm->game() != GI_EOB2) || _vm->gameFlags().platform == Common::kPlatformSegaCD)) {
 						// Strip special characters from GMM save dialog which might get misinterpreted as SJIS
 						// Special case for Japanese SegaCD: Only the save descriptions from GMM should be stripped. The auto-generated descriptions from the ingame save dialog
 						// have a special 1-byte encoding that must be kept. It is easy to distinguish between GMM descriptions and ingame descriptions due to the '\r' characters
diff --git a/engines/kyra/gui/saveload_eob.cpp b/engines/kyra/gui/saveload_eob.cpp
index ad16a4f3144..923fcfbe6b3 100644
--- a/engines/kyra/gui/saveload_eob.cpp
+++ b/engines/kyra/gui/saveload_eob.cpp
@@ -586,15 +586,16 @@ bool EoBCoreEngine::importOriginalSaveFile(int destSlot, const char *sourceFile)
 			Common::String temp = Common::String::format(pattern, i);
 			Common::SeekableReadStream *fs = _res->createReadStream(temp);
 			if (fs) {
-				Common::String dsc;
+				Common::U32String dsc;
 				if (_flags.gameID == GI_EOB2) {
 					char descStr[20];
 					fs->read(descStr, 20);
-					dsc = Common::String::format("(\"%s\")", descStr).c_str();
+					dsc = Common::U32String(descStr, _flags.lang == Common::ZH_TWN ? Common::CodePage::kBig5 : Common::CodePage::kLatin1);
+					dsc = "(\"" + dsc + "\")";
 				}
 
 				delete fs;
-				::GUI::MessageDialog dialog(Common::U32String::format(_("The following original saved game file has been found in your game path:\n\n%s %s\n\nDo you wish to use this saved game file with ScummVM?\n\n"), temp.c_str(), dsc.c_str()), _("Yes"), _("No"));
+				::GUI::MessageDialog dialog(Common::U32String::format(_("The following original saved game file has been found in your game path:\n\n%s %S\n\nDo you wish to use this saved game file with ScummVM?\n\n"), temp.c_str(), dsc.c_str()), _("Yes"), _("No"));
 				if (dialog.runModal() == ::GUI::kMessageOK)
 					origFiles.push_back(temp);
 			}
@@ -707,7 +708,10 @@ Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) {
 	} else {
 		char tempStr[30];
 		in.read(tempStr, sourcePlatform == Common::kPlatformFMTowns ? 30 : 20);
-		desc = tempStr;
+		if (_flags.lang == Common::ZH_TWN) {
+			desc = Common::U32String(tempStr, Common::CodePage::kBig5).encode(Common::CodePage::kUtf8);
+		} else
+			desc = tempStr;
 	}
 
 	for (int i = 0; i < 6; i++) {


Commit: e1f706b56d5c1bc3802c7d604efc098373fce7c6
    https://github.com/scummvm/scummvm/commit/e1f706b56d5c1bc3802c7d604efc098373fce7c6
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Use Chinese font in Intro and Finale of Chinese EoB2

Changed paths:
    engines/kyra/sequence/sequences_darkmoon.cpp


diff --git a/engines/kyra/sequence/sequences_darkmoon.cpp b/engines/kyra/sequence/sequences_darkmoon.cpp
index 824283c23f3..018aa5b91e8 100644
--- a/engines/kyra/sequence/sequences_darkmoon.cpp
+++ b/engines/kyra/sequence/sequences_darkmoon.cpp
@@ -1615,7 +1615,8 @@ void DarkmoonSequenceHelper::init(DarkmoonSequenceHelper::Mode mode) {
 	memset(_textColor, 0, 3);
 
 	_screen->setScreenPalette(*_palettes[0]);
-	_prevFont = _screen->setFont(_vm->gameFlags().platform == Common::kPlatformFMTowns ? Screen::FID_SJIS_LARGE_FNT : Screen::FID_8_FNT);
+	_prevFont = _screen->setFont(_vm->gameFlags().lang == Common::Language::ZH_TWN ? Screen::FID_CHINESE_FNT :
+				     _vm->gameFlags().platform == Common::kPlatformFMTowns ? Screen::FID_SJIS_LARGE_FNT : Screen::FID_8_FNT);
 	_screen->hideMouse();
 
 	_vm->delay(150);


Commit: 094f6aea293b5b60480e3ba86f1ead992565f852
    https://github.com/scummvm/scummvm/commit/094f6aea293b5b60480e3ba86f1ead992565f852
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Mark Chinese EoB2 as talkie

Changed paths:
    engines/kyra/detection_tables.h


diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index 0fe4aabfd88..665ae4b128a 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -69,6 +69,7 @@ namespace {
 #define EOB_PC98_FLAGS FLAGS(false, false, false, false, true, true, false, false, false, Kyra::GI_EOB1)
 #define EOB2_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_EOB2)
 #define EOB2_FMTOWNS_FLAGS FLAGS(false, false, false, false, true, false, true, false, false, Kyra::GI_EOB2)
+#define EOB2_TALKIE_FLAGS FLAGS(false, false, true, false, false, false, false, false, false, Kyra::GI_EOB2)
 
 static const char msg_missingLangResources[]			= _s("Missing language specific game code and/or resources.");
 static const char msg_fanTrans_missingLangResources[]	= _s("Missing language specific game code and/or resources for this fan translation.");
@@ -2060,7 +2061,7 @@ const KYRAGameDescription adGameDescs[] = {
 			ADGF_NO_FLAGS,
 			GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
 		},
-		EOB2_FLAGS
+		EOB2_TALKIE_FLAGS
 	},
 
 	{


Commit: 6ae55d93a4ecae0417eef6d3b8e283cc5bfcf087
    https://github.com/scummvm/scummvm/commit/6ae55d93a4ecae0417eef6d3b8e283cc5bfcf087
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Play voices in Intro and Finale of Chinese EoB2

Changed paths:
    engines/kyra/detection_tables.h
    engines/kyra/sequence/sequences_darkmoon.cpp


diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index 665ae4b128a..3667fa1b4d7 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -2059,7 +2059,7 @@ const KYRAGameDescription adGameDescs[] = {
 			Common::ZH_TWN,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
+			GUIO6(GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
 		},
 		EOB2_TALKIE_FLAGS
 	},
diff --git a/engines/kyra/sequence/sequences_darkmoon.cpp b/engines/kyra/sequence/sequences_darkmoon.cpp
index 018aa5b91e8..d845603100b 100644
--- a/engines/kyra/sequence/sequences_darkmoon.cpp
+++ b/engines/kyra/sequence/sequences_darkmoon.cpp
@@ -70,8 +70,9 @@ private:
 	Screen_EoB *_screen;
 
 	struct Config {
-		Config(const char *const *str, const char *const *cpsfiles, const uint8 **cpsdata, const char *const *pal, const DarkMoonShapeDef **shp, const DarkMoonAnimCommand **anim, bool loadScenePalette, bool paletteFading, bool animCmdRestorePalette, bool shapeBackgroundFading, int animPalOffset, int animType1ShapeDim, bool animCmd5SetPalette, int animCmd5ExtraPage) : strings(str), cpsFiles(cpsfiles), cpsData(cpsdata), palFiles(pal), shapeDefs(shp), animData(anim), loadScenePal(loadScenePalette), palFading(paletteFading), animCmdRestorePal(animCmdRestorePalette), shpBackgroundFading(shapeBackgroundFading), animPalOffs(animPalOffset), animCmd1ShapeFrame(animType1ShapeDim), animCmd5SetPal(animCmd5SetPalette), animCmd5AltPage(animCmd5ExtraPage) {}
+		Config(const char *const *str, const char *const *cpsfiles, const char *vocPat, const uint8 **cpsdata, const char *const *pal, const DarkMoonShapeDef **shp, const DarkMoonAnimCommand **anim, bool loadScenePalette, bool paletteFading, bool animCmdRestorePalette, bool shapeBackgroundFading, int animPalOffset, int animType1ShapeDim, bool animCmd5SetPalette, int animCmd5ExtraPage) : strings(str), voicePattern(vocPat), cpsFiles(cpsfiles), cpsData(cpsdata), palFiles(pal), shapeDefs(shp), animData(anim), loadScenePal(loadScenePalette), palFading(paletteFading), animCmdRestorePal(animCmdRestorePalette), shpBackgroundFading(shapeBackgroundFading), animPalOffs(animPalOffset), animCmd1ShapeFrame(animType1ShapeDim), animCmd5SetPal(animCmd5SetPalette), animCmd5AltPage(animCmd5ExtraPage) {}
 		const char *const *strings;
+		const char *voicePattern;
 		const char *const *cpsFiles;
 		const uint8 **cpsData;
 		const char *const *palFiles;
@@ -1149,6 +1150,8 @@ DarkmoonSequenceHelper::~DarkmoonSequenceHelper() {
 	delete[] _config->cpsData;
 	delete _config;
 
+	_vm->_sound->voiceStop(&_vm->_speechHandle);
+
 	_screen->enableHiColorMode(true);
 	_screen->clearCurPage();
 	_screen->setFont(_prevFont);
@@ -1422,6 +1425,11 @@ void DarkmoonSequenceHelper::printText(int index, int color) {
 	}
 
 	Common::String str = _config->strings[index];
+
+	if (_config->voicePattern) {
+		_vm->_sound->voicePlay(Common::String::format(_config->voicePattern, index + 1).c_str(), &_vm->_speechHandle);
+	}
+
 	const ScreenDim *dm = _screen->_curDim;
 	int fontHeight = (_vm->gameFlags().platform == Common::kPlatformPC98) ? (_screen->getFontHeight() << 1) : (_screen->getFontHeight() + 1);
 	int xAlignFactor = (_vm->gameFlags().platform == Common::kPlatformPC98) ? 2 : 1;
@@ -1488,6 +1496,7 @@ void DarkmoonSequenceHelper::init(DarkmoonSequenceHelper::Mode mode) {
 		_config = new Config(
 			_vm->staticres()->loadStrings(kEoB2IntroStrings, size),
 			_vm->staticres()->loadStrings(kEoB2IntroCPSFiles, size),
+			_vm->_flags.isTalkie ? "EOB%d" : nullptr,
 			new const uint8*[16],
 			_vm->_flags.platform == Common::kPlatformAmiga ? 0 : (_vm->_configRenderMode == Common::kRenderEGA ? _palFilesIntroEGA : _palFilesIntroVGA),
 			new const DarkMoonShapeDef*[16],
@@ -1521,6 +1530,7 @@ void DarkmoonSequenceHelper::init(DarkmoonSequenceHelper::Mode mode) {
 		_config = new Config(
 			_vm->staticres()->loadStrings(kEoB2FinaleStrings, size),
 			_vm->staticres()->loadStrings(kEoB2FinaleCPSFiles, size),
+			_vm->_flags.isTalkie ? "EOBF%d" : nullptr,
 			new const uint8*[13],
 			_vm->_flags.platform == Common::kPlatformAmiga ? _palFilesFinaleAmiga : (_vm->_configRenderMode == Common::kRenderEGA ? _palFilesFinaleEGA : _palFilesFinaleVGA),
 			new const DarkMoonShapeDef*[13],


Commit: e7afc8ab2e3ab6823765b309a28eda67f96aa33a
    https://github.com/scummvm/scummvm/commit/e7afc8ab2e3ab6823765b309a28eda67f96aa33a
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Support logo from T1.CPS

Changed paths:
    engines/kyra/graphics/screen_eob.cpp
    engines/kyra/graphics/screen_eob.h
    engines/kyra/sequence/sequences_darkmoon.cpp


diff --git a/engines/kyra/graphics/screen_eob.cpp b/engines/kyra/graphics/screen_eob.cpp
index baea4ae0e37..0098a5ee37f 100644
--- a/engines/kyra/graphics/screen_eob.cpp
+++ b/engines/kyra/graphics/screen_eob.cpp
@@ -762,6 +762,65 @@ uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool enco
 	return shp;
 }
 
+void Screen_EoB::drawT1Shape(uint8 pageNum, const byte *t1data, int x, int y, int sd) {
+	const byte *src = t1data;
+	int width = READ_LE_UINT16(t1data);
+	int height = READ_LE_UINT16(t1data + 2);
+	src += 4;
+
+	const ScreenDim *dm = getScreenDim(sd);
+	setShapeFrame(dm->sx, dm->sy, dm->sx + dm->w, dm->sy + dm->h);
+	int fx = dm->sx << 3;
+	int fy = dm->sy;
+	int fw = dm->w << 3;
+	int fh = dm->h;
+
+	int rX = fx + x;
+	int rY = fy + y;
+	int rW = (fx + fw) - rX;
+	int rH = (fy + fh) - rY;
+	int dX = 0, dY = 0;
+
+	if (rX < 0) {
+		dX = -rX;
+		rX = 0;
+	}
+
+	if (rY < 0) {
+		dY = -rY;
+		rY = 0;
+	}
+
+	if (dX >= width || dY >= height)
+		return;
+
+	if (rW > width - dX)
+		rW = width - dX;
+	if (rH > height - rY)
+		rH = height - dY;
+	if (rW <= 0 || rH <= 0)
+		return;
+
+	if (pageNum == 0 || pageNum == 1)
+		addDirtyRect(rX, rY, rW, rH);
+
+	int dH = rH;
+	uint8 *dstL = getPagePtr(pageNum) + rY * _bytesPerPixel * SCREEN_W;
+	src += dY * width;
+
+	while (dH--) {
+		const uint8 *src2 = src + dX;
+		uint8 *dst = dstL + rX * _bytesPerPixel;
+
+		for (int i = 0; i < rW; i++, src2++, dst += _bytesPerPixel)
+			if (*src2)
+				drawShapeSetPixel(dst, *src2);
+
+		dstL += SCREEN_W * _bytesPerPixel;
+		src += width;
+	}
+}
+
 void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...) {
 	uint8 *dst = getPagePtr(pageNum);
 	const uint8 *src = shapeData;
diff --git a/engines/kyra/graphics/screen_eob.h b/engines/kyra/graphics/screen_eob.h
index 070b78c58c1..b9f70a3f3b2 100644
--- a/engines/kyra/graphics/screen_eob.h
+++ b/engines/kyra/graphics/screen_eob.h
@@ -82,6 +82,7 @@ public:
 
 	uint8 *encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool encode8bit = false, const uint8 *cgaMapping = 0);
 	void drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd = -1, int flags = 0, ...) override;
+	void drawT1Shape(uint8 pageNum, const byte *t1data, int x, int y, int sd);
 	const uint8 *scaleShape(const uint8 *shapeData, int blockDistance);
 	const uint8 *scaleShapeStep(const uint8 *shp);
 	const uint8 *generateShapeOverlay(const uint8 *shp, const uint8 *fadingTable);
diff --git a/engines/kyra/sequence/sequences_darkmoon.cpp b/engines/kyra/sequence/sequences_darkmoon.cpp
index d845603100b..b30be2b126e 100644
--- a/engines/kyra/sequence/sequences_darkmoon.cpp
+++ b/engines/kyra/sequence/sequences_darkmoon.cpp
@@ -92,6 +92,7 @@ private:
 
 	Palette *_palettes[13];
 	uint8 *_fadingTables[7];
+	byte *_t1cps;
 
 	const uint8 **_shapes;
 
@@ -1126,7 +1127,7 @@ void DarkMoonEngine::seq_playCredits(DarkmoonSequenceHelper *sq, const uint8 *da
 		delete[] items[i].str;
 }
 
-DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, DarkmoonSequenceHelper::Mode mode) : _system(system), _vm(vm), _screen(screen), _fadePalIndex(0) {
+DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, DarkmoonSequenceHelper::Mode mode) : _system(system), _vm(vm), _screen(screen), _fadePalIndex(0), _t1cps(nullptr) {
 	init(mode);
 }
 
@@ -1145,6 +1146,8 @@ DarkmoonSequenceHelper::~DarkmoonSequenceHelper() {
 		delete[] _shapes[i];
 	delete[] _shapes;
 
+	delete[] _t1cps;
+
 	delete[] _config->animData;
 	delete[] _config->shapeDefs;
 	delete[] _config->cpsData;
@@ -1323,15 +1326,35 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) {
 
 		case 3:
 		case 4:
+		case 101: { // ScummVM extension
+			int isT1 = s->command == 101;
+			int shapeWidth = 0, shapeHeight = 0;
 			// fade shape in or out or restore background
 			if (!_config->shpBackgroundFading)
 				break;
 
+			if (isT1 && !_t1cps) {
+				_t1cps = new byte[64000];
+				memset(_t1cps, 0, 4);
+				Common::ScopedPtr<Common::SeekableReadStream> srcStream(_vm->resource()->createReadStream("T1.CPS"));
+				if (srcStream)
+					Screen_EoB::eob2ChineseLZUncompress(_t1cps, 64000, srcStream.get());
+			}
+			if (isT1) {
+				shapeWidth = READ_LE_UINT16(_t1cps);
+				shapeHeight = READ_LE_UINT16(_t1cps + 2);
+			} else {
+				shapeWidth = (_shapes[s->obj][2] + 1) << 3;
+				shapeHeight = _shapes[s->obj][3];
+			}
+
 			if (_vm->_configRenderMode == Common::kRenderEGA) {
-				if (palIndex)
+				if (palIndex && isT1)
+					_screen->drawT1Shape(0, _t1cps, s->x1, y, 0);
+				else if (palIndex)
 					_screen->drawShape(0, _shapes[s->obj], s->x1, y, 0);
 				else
-					_screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 0, Screen::CR_NO_P_CHECK);
+					_screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, shapeWidth, shapeHeight, 2, 0, Screen::CR_NO_P_CHECK);
 				_screen->updateScreen();
 				delay(s->delay /** 7*/);
 			} else if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
@@ -1343,7 +1366,7 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) {
 					_screen->drawShape(4, _shapes[obj], s->x1 & 7, 0, 0);
 					_screen->copyRegion(0, 0, s->x1, s->y1, (_shapes[obj][2] + 1) << 3, _shapes[obj][3], 4, 0, Screen::CR_NO_P_CHECK);
 				} else {
-					_screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 0, Screen::CR_NO_P_CHECK);
+					_screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, shapeWidth, shapeHeight, 2, 0, Screen::CR_NO_P_CHECK);
 				}
 				_screen->updateScreen();
 
@@ -1357,11 +1380,14 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) {
 				if (palIndex) {
 					_screen->setFadeTable(_fadingTables[palIndex - 1]);
 
-					_screen->copyRegion(s->x1 - 8, s->y1 - 8, 0, 0, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 4, Screen::CR_NO_P_CHECK);
-					_screen->drawShape(4, _shapes[s->obj], s->x1 & 7, 0, 0);
-					_screen->copyRegion(0, 0, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 4, 0, Screen::CR_NO_P_CHECK);
+					_screen->copyRegion(s->x1 - 8, s->y1 - 8, 0, 0, shapeWidth, shapeHeight, 2, 4, Screen::CR_NO_P_CHECK);
+					if (isT1)
+						_screen->drawT1Shape(4, _t1cps, 0, 0, 0);
+					else
+						_screen->drawShape(4, _shapes[s->obj], s->x1 & 7, 0, 0);
+					_screen->copyRegion(0, 0, s->x1, s->y1, shapeWidth, shapeHeight, 4, 0, Screen::CR_NO_P_CHECK);
 				} else {
-					_screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 0, Screen::CR_NO_P_CHECK);
+					_screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, shapeWidth, shapeHeight, 2, 0, Screen::CR_NO_P_CHECK);
 				}
 				_screen->updateScreen();
 
@@ -1370,6 +1396,7 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) {
 				_screen->setShapeFadingLevel(0);
 			}
 			break;
+		}
 
 		case 5:
 			// copy region


Commit: 5d3293e4c566ce4defca14a619dd0272cf59fad6
    https://github.com/scummvm/scummvm/commit/5d3293e4c566ce4defca14a619dd0272cf59fad6
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Fix EOB2 Chinese main menu position and line spacing

Changed paths:
    engines/kyra/sequence/sequences_darkmoon.cpp


diff --git a/engines/kyra/sequence/sequences_darkmoon.cpp b/engines/kyra/sequence/sequences_darkmoon.cpp
index b30be2b126e..4b918926803 100644
--- a/engines/kyra/sequence/sequences_darkmoon.cpp
+++ b/engines/kyra/sequence/sequences_darkmoon.cpp
@@ -203,6 +203,12 @@ int DarkMoonEngine::mainMenu() {
 
 int DarkMoonEngine::mainMenuLoop() {
 	int sel = -1;
+
+	if (_flags.lang == Common::Language::ZH_TWN) {
+		_screen->modifyScreenDim(6, 10, 72, 21, 40);
+		_screen->setFont(Screen::FID_CHINESE_FNT);
+	}
+
 	do {
 		_screen->setScreenDim(6);
 		_gui->simpleMenu_setup(6, 0, _mainMenuStrings, -1, 0, 0, _configRenderMode == Common::kRenderCGA ? 1 : guiSettings()->colors.guiColorWhite, guiSettings()->colors.guiColorLightRed, guiSettings()->colors.guiColorBlack);


Commit: a666b2deca033192e5dbbfb3aa9ae221cafde9ac
    https://github.com/scummvm/scummvm/commit/a666b2deca033192e5dbbfb3aa9ae221cafde9ac
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add Chinese version of saveLoadStrings

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index 29254c30435..2f0d15d0c5d 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -531,7 +531,8 @@ void EoBCoreEngine::initStaticResource() {
 		{	" < < ",	"Posizione Vuota",	"Salva",		"Carica"	    },
 		{	"Anular",	"Sin Uso",			"Grabar",		"Cargar"	    },
 		{   "Cancel",   "\x82""d""\x82\x8d\x82\x90\x82\x94\x82\x99\x81""@""\x82\x92\x82\x85\x82\x87\x82\x89\x82\x8f\x82\x8e",		"Select save area",    "Select load data"     },
-		{   "\x82\xe2\x82\xdf\x82\xe9",   "\x8b\xf3\x82\xab\x97\xcc\x88\xe6",	"\x82\xc7\x82\xb1\x82\xc9\x83""Z""\x81""|""\x83""u""\x82\xb5\x82\xdc\x82\xb7\x82\xa9\x81""H",	"\x82\xc7\x82\xea\x82\xf0\x83\x8d\x81""|""\x83""h""\x82\xb5\x82\xdc\x82\xb7\x82\xa9\x81""H"    }
+		{   "\x82\xe2\x82\xdf\x82\xe9",   "\x8b\xf3\x82\xab\x97\xcc\x88\xe6",	"\x82\xc7\x82\xb1\x82\xc9\x83""Z""\x81""|""\x83""u""\x82\xb5\x82\xdc\x82\xb7\x82\xa9\x81""H",	"\x82\xc7\x82\xea\x82\xf0\x83\x8d\x81""|""\x83""h""\x82\xb5\x82\xdc\x82\xb7\x82\xa9\x81""H"    },
+		{   "\xa8\xfa\xae\xf8" /* "取消"; */, "\xa9\x7c\xa5\xbc\xa8\xcf\xa5\xce" /* "尚未使用"; */, "\xa6\x73\xa9\xf1\xb6\x69\xab\xd7" /* "存放進度"; */, "\xb8\xfc\xa4\x4a\xb6\x69\xab\xd7" /* "載入進度"; */  },
 	};
 
 	static const char *const errorSlotEmptyString[8] = {
@@ -541,6 +542,7 @@ void EoBCoreEngine::initStaticResource() {
 		"No hay partidas\rgrabadas!",
 		"\r ""\x82\xBB\x82\xCC\x83""X""\x83\x8D\x83""b""\x83""g""\x82\xC9\x82\xCD\x83""Q""\x81""[""\x83\x80\x82\xAA\x83""Z""\x81""[""\x83""u\r ""\x82\xB3\x82\xEA\x82\xC4\x82\xA2\x82\xDC\x82\xB9\x82\xF1\x81""B",
 		"\x8b\xf3\x82\xab\x97\xcc\x88\xe6",
+		"\xb3\x6f\xad\xd3\xa6\xec\xb8\x6d\xa9\x7c\xa5\xbc\xc0\x78\xa6\x73\x0d\xb8\xea\xae\xc6\xc0\xc9\x2c\xbd\xd0\xad\xab\xb7\x73\xbf\xef\xbe\xdc", /* "這個位置尚未\r資料檔,請重新選擇"; */
 		0
 	};
 
@@ -578,6 +580,11 @@ void EoBCoreEngine::initStaticResource() {
 			_errorSlotEmptyString = errorSlotEmptyString[4];
 		}
 		break;
+	case Common::ZH_TWN:
+		_saveLoadStrings = saveLoadStrings[6];
+		_errorSlotEmptyString = errorSlotEmptyString[6];
+		break;
+
 	default:
 		_saveLoadStrings = saveLoadStrings[0];
 		_errorSlotEmptyString = errorSlotEmptyString[0];


Commit: 4f0169e10470f5a4bdb19a1afbb6652b48c72a02
    https://github.com/scummvm/scummvm/commit/4f0169e10470f5a4bdb19a1afbb6652b48c72a02
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Use Chinese font in several places in Chinese EOB2

Changed paths:
    engines/kyra/gui/gui_eob.cpp


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index b1e45840edd..9bde9009e7c 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -2197,7 +2197,7 @@ void GUI_EoB::simpleMenu_flashSelection(const char *str, int x, int y, int color
 }
 
 void GUI_EoB::runCampMenu() {
-	Screen::FontId of = _screen->setFont(_vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+	Screen::FontId of = _screen->setFont(_vm->_flags.lang == Common::Language::ZH_TWN ? Screen::FID_CHINESE_FNT : _vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
 
 	Button *highlightButton = 0;
 	Button *prevHighlightButton = 0;
@@ -2527,7 +2527,7 @@ bool GUI_EoB::runLoadMenu(int x, int y, bool fromMainMenu) {
 
 bool GUI_EoB::confirmDialogue2(int dim, int id, int deflt) {
 	int od = _screen->curDimIndex();
-	Screen::FontId of = _screen->setFont(_vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+	Screen::FontId of = _screen->setFont(_vm->_flags.lang == Common::Language::ZH_TWN ? Screen::FontId::FID_CHINESE_FNT : _vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
 	_screen->setScreenDim(dim);
 
 	drawTextBox(dim, id);
@@ -2596,7 +2596,7 @@ bool GUI_EoB::confirmDialogue2(int dim, int id, int deflt) {
 void GUI_EoB::messageDialogue(int dim, int id, int buttonTextCol) {
 	int od = _screen->curDimIndex();
 	_screen->setScreenDim(dim);
-	Screen::FontId of = _screen->setFont(_vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+	Screen::FontId of = _screen->setFont(_vm->_flags.lang == Common::Language::ZH_TWN ? Screen::FontId::FID_CHINESE_FNT : _vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
 
 	drawTextBox(dim, id);
 	const ScreenDim *dm = _screen->getScreenDim(dim);
@@ -4067,7 +4067,7 @@ void GUI_EoB::printScribeScrollSpellString(const int16 *menuItems, int id, bool
 
 bool GUI_EoB::confirmDialogue(int id) {
 	int od = _screen->curDimIndex();
-	Screen::FontId of = _screen->setFont(_vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+	Screen::FontId of = _screen->setFont(_vm->_flags.lang == Common::Language::ZH_TWN ? Screen::FontId::FID_CHINESE_FNT : _vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
 
 	Button *buttonList = initMenu(5);
 
@@ -4290,7 +4290,7 @@ int GUI_EoB::selectCharacterDialogue(int id) {
 void GUI_EoB::displayTextBox(int id, int, bool) {
 	int op = _screen->setCurPage(2);
 	int od = _screen->curDimIndex();
-	Screen::FontId of = _screen->setFont(_vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+	Screen::FontId of = _screen->setFont(_vm->_flags.lang == Common::Language::ZH_TWN ? Screen::FontId::FID_CHINESE_FNT : _vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
 	_screen->setClearScreenDim(11);
 	const ScreenDim *dm = _screen->getScreenDim(11);
 
@@ -4328,6 +4328,8 @@ Button *GUI_EoB::initMenu(int id) {
 	}
 
 	if (m->titleStrId != -1) {
+		if (_vm->gameFlags().lang == Common::Language::ZH_TWN)
+			_screen->setFont(Screen::FID_CHINESE_FNT);
 		if (_vm->gameFlags().platform == Common::kPlatformSegaCD)
 			displayTextBox(m->titleStrId, 0x55, false);
 		else
@@ -4422,7 +4424,7 @@ void GUI_EoB::drawTextBox(int dim, int id) {
 	int od = _screen->curDimIndex();
 	_screen->setScreenDim(dim);
 	const ScreenDim *dm = _screen->getScreenDim(dim);
-	Screen::FontId of = _screen->setFont(_vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+	Screen::FontId of = _screen->setFont(_vm->_flags.lang == Common::Language::ZH_TWN ? Screen::FontId::FID_CHINESE_FNT : _vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
 
 	if (dm->w <= 22 && dm->h <= 84)
 		_screen->copyRegion(dm->sx << 3, dm->sy, 0, dm->h, dm->w << 3, dm->h, 0, 2, Screen::CR_NO_P_CHECK);
@@ -4641,7 +4643,7 @@ void GUI_EoB::sortSaveSlots() {
 }
 
 void GUI_EoB::restParty_updateRestTime(int hours, bool init) {
-	Screen::FontId of = _screen->setFont(_vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+	Screen::FontId of = _screen->setFont(_vm->_flags.lang == Common::Language::ZH_TWN ? Screen::FontId::FID_CHINESE_FNT : _vm->_flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
 	int od = _screen->curDimIndex();
 	_screen->setScreenDim(10);
 


Commit: 0c8b668c4c2879d6f24c420dfb0ba3c018612826
    https://github.com/scummvm/scummvm/commit/0c8b668c4c2879d6f24c420dfb0ba3c018612826
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add button defs for EOB2 Chinese

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index 2f0d15d0c5d..ea258dbffbc 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -904,6 +904,73 @@ void EoBCoreEngine::initMenus() {
 		{  8,  128, 122,  40,  14,  19,  7  }
 	};
 
+	static const EoBMenuButtonDef buttonDefsChineseEOB2[] = {
+		// Camp menu
+		{  2,   42,   4, 128,  19,  20,  3  },
+		{  3,   42,  24, 128,  19,  52,  3  },
+		{  4,   42,  44, 128,  19,  26,  3  },
+		{  5,   42,  64, 128,  19,  32,  3  },
+		{  6,   42,  84, 128,  19,   0,  3  },
+		{  7,   42, 104, 128,  19,  35,  3  },
+		{  8,  128, 123,  40,  19,  19,  3  },
+
+		{  9,   12,  20, 158,  17,  39,  3  },
+		{  10,  12,  37, 158,  17,  32,  3  },
+		{  11,  12,  54, 158,  17,  33,  3  },
+		{  12,  12,  71, 158,  17,  17,  3  },
+		{  8,  128, 122,  40,  19,  19,  7  },
+		{  18,  12,  20, 158,  17,  32,  3  },
+		{  19,  12,  37, 158,  17,  50,  3  },
+		{  8,  128, 122,  40,  19,  19,  7  },
+		{  8,  128, 122,  40,  19,  19,  5  },
+		{  0,  184,   0,  64,  48, 112,  0  },
+		{  0,  256,   0,  64,  48, 113,  0  },
+		{  0,  184,  56,  64,  48, 114,  0  },
+		{  0,  256,  56,  64,  48, 115,  0  },
+		{  0,  184, 112,  64,  48, 116,  0  },
+		{  0,  256, 112,  64,  48, 117,  0  },
+
+		// OK/Cancel buttons in spell menu
+		{  36,   8, 122,  40,  19,  48,  5  },
+		{  8,  128, 122,  40,  19,  19,  5  },
+
+		// Spell window bounds
+		{  0,    0,  50, 168,  72,  61,  0  },
+
+		// Spell number buttons 1-6
+		{  31,  11,  20,  18,  18,   2,  5  },
+		{  32,  38,  20,  18,  18,   3,  5  },
+		{  33,  65,  20,  18,  18,   4,  5  },
+		{  34,  92,  20,  18,  18,   5,  5  },
+		{  35, 119,  20,  18,  18,   6,  5  },
+		{  60, 146,  20,  18,  18,   7,  5  },
+
+		{  61, 150,  16,  20,  18,   8,  5  },
+		{  38,  16,  57,  32,  17,  22,  7  },
+		{  39, 128,  57,  32,  17,  51,  7  },
+		{  8,  128, 126,  40,  17,  19,  7  },
+		{  0,    0,  50, 168,  72,  61,  0  },
+		// EOB 1 memorize/pray menu:
+		{  36,   8, 126,  48,  17,  48,  5  },
+		{  8,  128, 126,  40,  17,  19,  5  },
+		{  0,    0,  50, 168,  72,  61,  0  },
+		{  31,   8,  16,  24,  20,   2,  5  },
+		{  32,  40,  16,  24,  20,   3,  5  },
+		{  33,  72,  16,  24,  20,   4,  5  },
+		{  34, 104,  16,  24,  20,   5,  5  },
+		{  35, 136,  16,  24,  20,   6,  5  },
+		// FM-Towns options menu
+		{  18,  12,  20, 158,  17,  32,  3  },
+		{  19,  12,  37, 158,  17,  50,  3  },
+		{  20,  12,  54, 158,  17,  21,  3  },
+		{  8,  128, 122,  40,  17,  19,  7  },
+		// PC-98 options menu
+		{  17,  12,  20, 158,  17,  32,  3  },
+		{  18,  12,  37, 158,  17,  50,  3  },
+		{  19,  12,  54, 158,  17,  21,  3  },
+		{  8,  128, 122,  40,  17,  19,  7  }
+	};
+
 	static const EoBMenuButtonDef buttonDefsSegaCD[] = {
 		{   0,   8,  40,  80,  16,  20,  3  },
 		{   0,  88,  40,  80,  16,  52,  3  },
@@ -947,7 +1014,12 @@ void EoBCoreEngine::initMenus() {
 		{   0,  24,  80,  80,  48,   0,  3  }
 	};
 
-	_menuButtonDefs = (_flags.platform == Common::kPlatformSegaCD) ? buttonDefsSegaCD : buttonDefsDefault;
+	if (_flags.lang == Common::Language::ZH_TWN)
+		_menuButtonDefs = buttonDefsChineseEOB2;
+	else if (_flags.platform == Common::kPlatformSegaCD)
+		_menuButtonDefs = buttonDefsSegaCD;
+	else
+		_menuButtonDefs = buttonDefsDefault;
 
 	static const EoBMenuDef menuDefsDefault[7] = {
 		{  1, 10,  0, 7,  9 },


Commit: 1bf7a7d448d8ad21af60c787bf5687ea5804b8d2
    https://github.com/scummvm/scummvm/commit/1bf7a7d448d8ad21af60c787bf5687ea5804b8d2
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Translate Camp button in Chinese EOB2

This is to match original

Changed paths:
    engines/kyra/gui/gui_eob.cpp


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index 9bde9009e7c..132019e441d 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -49,6 +49,12 @@ Button *EoBCoreEngine::gui_getButton(Button *buttonList, int index) {
 void EoBCoreEngine::gui_drawPlayField(bool refresh) {
 	_screen->loadEoBBitmap("PLAYFLD", _cgaMappingDeco, 5, 3, 2);
 	int cp = _screen->setCurPage(2);
+	if (_flags.lang == Common::Language::ZH_TWN) {
+		Screen::FontId of = _screen->setFont(Screen::FID_CHINESE_FNT);
+		_screen->fillRect(290, 180, 318, 194, guiSettings()->colors.fill);
+		_screen->printShadedText("\xbf\xef?" /* 選? */, 292, 181, guiSettings()->colors.guiColorYellow, guiSettings()->colors.fill, guiSettings()->colors.guiColorBlack, -1);
+		_screen->setFont(of);
+	}
 	gui_drawCompass(true);
 
 	if (refresh && !_sceneDrawPage2)


Commit: 678ec94ab036de0862083eef54f72a8bffa84a74
    https://github.com/scummvm/scummvm/commit/678ec94ab036de0862083eef54f72a8bffa84a74
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Change rendering of spell menu in Chinese EOB2

Changed paths:
    engines/kyra/gui/gui_eob.cpp
    engines/kyra/gui/gui_eob.h
    engines/kyra/gui/gui_eob_segacd.cpp
    engines/kyra/gui/gui_eob_segacd.h


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index 132019e441d..ff52b719453 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -3449,8 +3449,6 @@ void GUI_EoB::runMemorizePrayMenu(int charIndex, int spellType) {
 	int newHighLightButton = 0;
 	int newHighLightText = 0;
 	int buttonStart = (_vm->gameFlags().platform == Common::kPlatformSegaCD) ? 0x801B : 0x8017;
-	int listY = (_vm->gameFlags().platform == Common::kPlatformSegaCD) ? 80 : 50;
-	int listEntryH = (_vm->gameFlags().platform == Common::kPlatformSegaCD) ? 8 : 9;
 	bool updateDesc = true;
 	bool updateList = true;
 	bool highLightClicked = (_vm->gameFlags().platform == Common::kPlatformSegaCD);
@@ -3499,7 +3497,7 @@ void GUI_EoB::runMemorizePrayMenu(int charIndex, int spellType) {
 				_screen->sega_getRenderer()->render(0, 1, 8, 20, 2);
 			} else {
 				_screen->set16bitShadingLevel(4);
-				_screen->printShadedText(Common::String::format(_vm->_menuStringsMgc[1], np[lastHighLightButton] - numAssignedSpellsPerBookPage[lastHighLightButton], np[lastHighLightButton]).c_str(), 8, 38, _vm->guiSettings()->colors.guiColorLightBlue, _vm->guiSettings()->colors.fill, _vm->guiSettings()->colors.guiColorBlack);
+				_screen->printShadedText(Common::String::format(_vm->_menuStringsMgc[1], np[lastHighLightButton] - numAssignedSpellsPerBookPage[lastHighLightButton], np[lastHighLightButton]).c_str(), _vm->_flags.lang == Common::Language::ZH_TWN ? 4 : 8, _vm->_flags.lang == Common::Language::ZH_TWN ? 40 : 38, _vm->guiSettings()->colors.guiColorLightBlue, _vm->guiSettings()->colors.fill, _vm->guiSettings()->colors.guiColorBlack);
 				_screen->set16bitShadingLevel(0);
 			}
 		}
@@ -3526,9 +3524,9 @@ void GUI_EoB::runMemorizePrayMenu(int charIndex, int spellType) {
 		} else if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE]) {
 			inputFlag = buttonStart + 1;
 		} else {
-			Common::Point p = _vm->getMousePos();
-			if (_vm->posWithinRect(p.x, p.y, 8, listY, 168, listY + 72)) {
-				newHighLightText = (p.y - listY) / listEntryH;
+			int entry = mapPointToEntry(_vm->getMousePos());
+			if (entry >= 0) {
+				newHighLightText = entry;
 				if (menuSpellMap[lastHighLightButton * 11] - 1 < newHighLightText)
 					newHighLightText = menuSpellMap[lastHighLightButton * 11] - 1;
 			}
@@ -4401,7 +4399,10 @@ void GUI_EoB::drawMenuButton(Button *b, bool clicked, bool highlight, bool noFil
 
 		if (d->flags & 4) {
 			xOffs = ((b->width - _screen->getTextWidth(s)) >> 1) + 1;
-			yOffs = (b->height - 7) >> 1;
+			if (_vm->_flags.lang == Common::Language::ZH_TWN)
+				yOffs = (b->height - 14) >> 1;
+			else
+				yOffs = (b->height - 7) >> 1;
 		}
 
 		int col1 = (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : _vm->guiSettings()->colors.guiColorWhite;
@@ -4477,14 +4478,32 @@ void GUI_EoB::drawSaveSlotButton(int slot, int redrawBox, bool highlight) {
 	_vm->screen()->setFont(fnt);
 }
 
+int GUI_EoB::mapPointToEntry(const Common::Point &p) const {
+	if (_vm->_flags.lang == Common::ZH_TWN) {
+		if (_vm->posWithinRect(p.x, p.y, 4, 58, 168, 122))
+			return (p.y - 58) / 16 + (p.x >= 84) * 4;
+		return -1;
+	}
+	if (_vm->posWithinRect(p.x, p.y, 8, 50, 168, 122))
+		return (p.y - 50) / 9;
+
+	return -1;
+}
+
 void GUI_EoB::memorizePrayMenuPrintString(int spellId, int bookPageIndex, int spellType, bool noFill, bool highLight) {
 	if (bookPageIndex < 0)
 		return;
 
-	int y = bookPageIndex * 9 + 50;
+	int x = _vm->_flags.lang == Common::ZH_TWN ? 4 + (bookPageIndex / 4) * 80 : 8;
+	int y = _vm->_flags.lang == Common::ZH_TWN ? (bookPageIndex % 4) * 16 + 58 : bookPageIndex * 9 + 50;
+	int w = _vm->_flags.lang == Common::ZH_TWN ? 80 : 160;
+	int h = _vm->_flags.lang == Common::ZH_TWN ? 15 : 8;
 	int col1 = (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : _vm->guiSettings()->colors.guiColorWhite;
 	_screen->set16bitShadingLevel(4);
 
+	if (!spellId || _vm->_flags.lang == Common::ZH_TWN)
+		_screen->fillRect(x, y, x + w, y + h,  _vm->guiSettings()->colors.fill);
+
 	if (spellId) {
 		Common::String s;
 		if (_vm->_flags.lang == Common::JA_JPN) {
@@ -4497,11 +4516,9 @@ void GUI_EoB::memorizePrayMenuPrintString(int spellId, int bookPageIndex, int sp
 		}
 
 		if (noFill)
-			_screen->printText(s.c_str(), 8, y, highLight ? _vm->guiSettings()->colors.guiColorLightRed : col1, 0);
+			_screen->printText(s.c_str(), x, y, highLight ? _vm->guiSettings()->colors.guiColorLightRed : col1, 0);
 		else
-			_screen->printShadedText(s.c_str(), 8, y, highLight ? _vm->guiSettings()->colors.guiColorLightRed : col1, _vm->guiSettings()->colors.fill, _vm->guiSettings()->colors.guiColorBlack);
-	} else {
-		_screen->fillRect(6, y, 168, y + 8,  _vm->guiSettings()->colors.fill);
+			_screen->printShadedText(s.c_str(), x, y, highLight ? _vm->guiSettings()->colors.guiColorLightRed : col1, _vm->guiSettings()->colors.fill, _vm->guiSettings()->colors.guiColorBlack);
 	}
 
 	_screen->set16bitShadingLevel(0);
diff --git a/engines/kyra/gui/gui_eob.h b/engines/kyra/gui/gui_eob.h
index 44f3290fe2b..8a6b2be6998 100644
--- a/engines/kyra/gui/gui_eob.h
+++ b/engines/kyra/gui/gui_eob.h
@@ -81,6 +81,7 @@ protected:
 	const char *getMenuString(int id);
 	Button *initMenu(int id);
 	void releaseButtons(Button *list);
+	virtual int mapPointToEntry(const Common::Point &p) const;
 
 	int8 *_numAssignedSpellsOfType;
 	char** _saveSlotStringsTemp;
diff --git a/engines/kyra/gui/gui_eob_segacd.cpp b/engines/kyra/gui/gui_eob_segacd.cpp
index 0a4d3aee199..bf97990c780 100644
--- a/engines/kyra/gui/gui_eob_segacd.cpp
+++ b/engines/kyra/gui/gui_eob_segacd.cpp
@@ -911,6 +911,13 @@ int GUI_EoB_SegaCD::getHighlightSlot() {
 	return res;
 }
 
+int GUI_EoB_SegaCD::mapPointToEntry(const Common::Point &p) const {
+	if (_vm->posWithinRect(p.x, p.y, 8, 80, 168, 152))
+		return (p.y - 80) / 8;
+
+	return -1;
+}
+
 void GUI_EoB_SegaCD::memorizePrayMenuPrintString(int spellId, int bookPageIndex, int spellType, bool noFill, bool highLight) {
 	if (bookPageIndex < 0)
 		return;
diff --git a/engines/kyra/gui/gui_eob_segacd.h b/engines/kyra/gui/gui_eob_segacd.h
index 0efb488db96..b3404a30028 100644
--- a/engines/kyra/gui/gui_eob_segacd.h
+++ b/engines/kyra/gui/gui_eob_segacd.h
@@ -35,6 +35,9 @@ public:
 	GUI_EoB_SegaCD(EoBEngine *vm);
 	~GUI_EoB_SegaCD() override;
 
+protected:
+	int mapPointToEntry(const Common::Point &p) const override;
+
 private:
 	void drawCampMenu() override;
 	void initMemorizePrayMenu(int spellType) override;


Commit: 832bcda774013a9868292a9ff28ab7f84b568831
    https://github.com/scummvm/scummvm/commit/832bcda774013a9868292a9ff28ab7f84b568831
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Resize console for Chinese EOB2 the same way as original

Changed paths:
    engines/kyra/gui/gui_eob.cpp


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index ff52b719453..b2b7f96c437 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -54,6 +54,9 @@ void EoBCoreEngine::gui_drawPlayField(bool refresh) {
 		_screen->fillRect(290, 180, 318, 194, guiSettings()->colors.fill);
 		_screen->printShadedText("\xbf\xef?" /* 選? */, 292, 181, guiSettings()->colors.guiColorYellow, guiSettings()->colors.fill, guiSettings()->colors.guiColorBlack, -1);
 		_screen->setFont(of);
+
+		_screen->fillRect(3, 170, 290, 198, guiSettings()->colors.fill);
+		_screen->fillRect(4, 171, 289, 197, guiSettings()->colors.guiColorBlack);
 	}
 	gui_drawCompass(true);
 


Commit: 28e87b295dce37c5445b2901f1c0d21d64a78725
    https://github.com/scummvm/scummvm/commit/28e87b295dce37c5445b2901f1c0d21d64a78725
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add string for own healing in Chinese EOB2

Changed paths:
    devtools/create_kyradat/resources/eob2_dos_chinese.h
    dists/engine-data/kyra.dat
    engines/kyra/gui/gui_eob.cpp


diff --git a/devtools/create_kyradat/resources/eob2_dos_chinese.h b/devtools/create_kyradat/resources/eob2_dos_chinese.h
index feb5b480362..37c614494fd 100644
--- a/devtools/create_kyradat/resources/eob2_dos_chinese.h
+++ b/devtools/create_kyradat/resources/eob2_dos_chinese.h
@@ -447,12 +447,13 @@ static const char *const kEoB2MenuStringsPrefsDOSChinese[4] = {
 
 static const StringListProvider kEoB2MenuStringsPrefsDOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsPrefsDOSChinese), kEoB2MenuStringsPrefsDOSChinese };
 
-static const char *const kEoB2MenuStringsRest2DOSChinese[5] = {
+static const char *const kEoB2MenuStringsRest2DOSChinese[6] = {
 	"\x25\x73\xbe\xc7\xb7\x7c\xa4\x46\x25\x73\x2e\x0d", /* "%s學會了%s.\r"; */	
 	"\x25\x73\xa4\x77\xb0\x4f\xbe\xd0\xa6\xed\x25\x73\xaa\xba\xaa\x6b\xb3\x4e\x2e\x0d", /* "%s已記憶住%s的法術.\r"; */
 	"\x25\x73\xac\x49\xae\x69\xaa\x76\xc0\xf8\xb3\x4e\xa8\xd3\xaa\x76\xc0\xf8\x25\x73\xaa\xba\xb6\xcb\xb6\xd5\x2e", /* "%s施展治療術來治療%s的傷勢."; */
 	"\xa4\x77\xa5\xf0\xae\xa7\xaa\xba\xae\xc9\xb6\xa1\x3a\x20\x25\x2d\x34\x64", /* "已休息的時間: %-4d"; */
-	"\r%s\r"
+	"\r%s\r",
+	"\x25\x73\xac\x49\xae\x69\xaa\x76\xc0\xf8\xb3\x4e\xa8\xd3\xaa\x76\xc0\xf8\xa6\xdb\xa4\x76\xaa\xba\xb6\xcb\xb6\xd5\x2e", /* "%s施展治療術來治療自己的傷勢."; */
 };
 
 static const StringListProvider kEoB2MenuStringsRest2DOSChineseProvider = { ARRAYSIZE(kEoB2MenuStringsRest2DOSChinese), kEoB2MenuStringsRest2DOSChinese };
diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat
index 0b19ec4154a..e1859eb636e 100644
Binary files a/dists/engine-data/kyra.dat and b/dists/engine-data/kyra.dat differ
diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index b2b7f96c437..87cea05b2a4 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -3934,7 +3934,10 @@ bool GUI_EoB::restParty() {
 					crs[i] = 0;
 					injured--;
 
-					_vm->_txt->printMessage(Common::String::format(_vm->_menuStringsRest2[2], _vm->_characters[i].name, _vm->_characters[injured].name).c_str());
+					if (_vm->_flags.lang == Common::Language::ZH_TWN && i == injured)
+						_vm->_txt->printMessage(Common::String::format(_vm->_menuStringsRest2[5], _vm->_characters[injured].name).c_str());
+					else
+						_vm->_txt->printMessage(Common::String::format(_vm->_menuStringsRest2[2], _vm->_characters[i].name, _vm->_characters[injured].name).c_str());
 
 					_vm->delay(80);
 


Commit: 5680cb08382322f89cff4f20374c8472e27bef8b
    https://github.com/scummvm/scummvm/commit/5680cb08382322f89cff4f20374c8472e27bef8b
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Adjust layout in Chinese EOB2 save/load dialog

Compared with the original in order to look as same as possible

Changed paths:
    engines/kyra/gui/gui_eob.cpp


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index 87cea05b2a4..60814281df9 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -3341,7 +3341,8 @@ void GUI_EoB::drawSaveSlotDialog(int x, int y, int id) {
 	_screen->setCurPage(2);
 	drawMenuButtonBox(0, 0, 176, 144, false, false);
 	const char* title = (id < 2) ? _vm->_saveLoadStrings[2 + id] : _vm->_transferStringsScummVM[id - 1];
-	_screen->printShadedText(title, 52, 5, (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+	_screen->printShadedText(title, 52, _vm->_flags.lang == Common::Language::ZH_TWN ? 3 : 5,
+				 (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
 	_screen->copyRegion(0, 0, x, y, 176, 144, 2, 0, Screen::CR_NO_P_CHECK);
 	_screen->fillRect(0, 0, 175, 143, 0, 2);
 	_screen->setCurPage(0);
@@ -4342,6 +4343,8 @@ Button *GUI_EoB::initMenu(int id) {
 			_screen->setFont(Screen::FID_CHINESE_FNT);
 		if (_vm->gameFlags().platform == Common::kPlatformSegaCD)
 			displayTextBox(m->titleStrId, 0x55, false);
+		else if (_vm->_flags.lang == Common::Language::ZH_TWN)
+			_screen->printShadedText(getMenuString(m->titleStrId), 3, 3, m->titleCol, 0, _vm->guiSettings()->colors.guiColorBlack);
 		else
 			_screen->printShadedText(getMenuString(m->titleStrId), 5, 5, m->titleCol, 0, _vm->guiSettings()->colors.guiColorBlack);
 		_screen->setTextMarginRight(Screen::SCREEN_W);
@@ -4401,7 +4404,7 @@ void GUI_EoB::drawMenuButton(Button *b, bool clicked, bool highlight, bool noFil
 		const char *s = getMenuString(d->labelId);
 
 		int xOffs = 4;
-		int yOffs = 3;
+		int yOffs = _vm->_flags.lang == Common::Language::ZH_TWN ? 2 : 3;
 
 		if (d->flags & 4) {
 			xOffs = ((b->width - _screen->getTextWidth(s)) >> 1) + 1;
@@ -4459,7 +4462,7 @@ void GUI_EoB::drawSaveSlotButton(int slot, int redrawBox, bool highlight) {
 		return;
 
 	int x = _saveSlotX + 4;
-	int y = _saveSlotY + slot * 17 + 20;
+	int y = _vm->_flags.lang == Common::Language::ZH_TWN ? _saveSlotY + slot * 18 + 18 : _saveSlotY + slot * 17 + 20;
 	int w = 167;
 	char slotString[26];
 	memset(slotString, 0, 26);
@@ -4467,12 +4470,12 @@ void GUI_EoB::drawSaveSlotButton(int slot, int redrawBox, bool highlight) {
 
 	if (slot >= 6) {
 		x = _saveSlotX + 118;
-		y = _saveSlotY + 126;
+		y = _vm->_flags.lang == Common::Language::ZH_TWN ? _saveSlotY + 125 : _saveSlotY + 126;
 		w = 53;
 	}
 
 	if (redrawBox)
-		drawMenuButtonBox(x, y, w, 14, (redrawBox - 1) ? true : false, false);
+		drawMenuButtonBox(x, y, w, _vm->_flags.lang == Common::Language::ZH_TWN ? 18 : 14, (redrawBox - 1) ? true : false, false);
 
 	Screen::FontId fnt = _screen->_currentFont;
 	if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
@@ -4480,7 +4483,9 @@ void GUI_EoB::drawSaveSlotButton(int slot, int redrawBox, bool highlight) {
 		y++;
 	}
 
-	_screen->printShadedText(slotString, x + 4, y + 3, highlight ? _vm->guiSettings()->colors.guiColorLightRed : (_vm->_configRenderMode == Common::kRenderCGA ? 1 : _vm->guiSettings()->colors.guiColorWhite), 0, _vm->guiSettings()->colors.guiColorBlack);
+	_screen->printShadedText(slotString, x + 4,
+				 _vm->_flags.lang == Common::Language::ZH_TWN ? y + 2 : y + 3,
+				 highlight ? _vm->guiSettings()->colors.guiColorLightRed : (_vm->_configRenderMode == Common::kRenderCGA ? 1 : _vm->guiSettings()->colors.guiColorWhite), 0, _vm->guiSettings()->colors.guiColorBlack);
 	_vm->screen()->setFont(fnt);
 }
 


Commit: 1e7f405f0d5819c6caf2fb838019069d2db259b4
    https://github.com/scummvm/scummvm/commit/1e7f405f0d5819c6caf2fb838019069d2db259b4
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add _screenDimTable for Chinese EOB2

Changed paths:
    engines/kyra/graphics/screen_eob.cpp
    engines/kyra/graphics/screen_eob.h
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/graphics/screen_eob.cpp b/engines/kyra/graphics/screen_eob.cpp
index 0098a5ee37f..39bdb50c0ea 100644
--- a/engines/kyra/graphics/screen_eob.cpp
+++ b/engines/kyra/graphics/screen_eob.cpp
@@ -77,7 +77,7 @@ struct eob2ChineseLZInStream {
 };
 }
 
-Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _screenDimTable, _screenDimTableCount), _cursorColorKey16Bit(0x8000) {
+Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, vm->gameFlags().lang == Common::Language::ZH_TWN ? _screenDimTableZH : _screenDimTableIntl, _screenDimTableCount), _cursorColorKey16Bit(0x8000) {
 	_dsBackgroundFading = false;
 	_dsShapeFadingLevel = 0;
 	_dsBackgroundFadingXOffs = 0;
diff --git a/engines/kyra/graphics/screen_eob.h b/engines/kyra/graphics/screen_eob.h
index b9f70a3f3b2..00c618e8527 100644
--- a/engines/kyra/graphics/screen_eob.h
+++ b/engines/kyra/graphics/screen_eob.h
@@ -202,7 +202,8 @@ private:
 	const uint16 _cursorColorKey16Bit;
 
 	static const uint8 _egaMatchTable[];
-	static const ScreenDim _screenDimTable[];
+	static const ScreenDim _screenDimTableIntl[];
+	static const ScreenDim _screenDimTableZH[];
 	static const int _screenDimTableCount;
 
 	// SegaCD specific
diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index ea258dbffbc..388fb153b72 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -147,7 +147,7 @@ void StaticResource::freeEoBNpcData(void *&ptr, int &size) {
 	size = 0;
 }
 
-const ScreenDim Screen_EoB::_screenDimTable[] = {
+const ScreenDim Screen_EoB::_screenDimTableIntl[] = {
 	{ 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 },
 	{ 0x08, 0x48, 0x18, 0x38, 0x0E, 0x0C, 0x00, 0x00 },
 	{ 0x13, 0x40, 0x14, 0x80, 0x06, 0x0C, 0x00, 0x00 },
@@ -179,7 +179,39 @@ const ScreenDim Screen_EoB::_screenDimTable[] = {
 	{ 0x0A, 0xA8, 0x15, 0x18, 0x0F, 0x0C, 0x00, 0x00 }
 };
 
-const int Screen_EoB::_screenDimTableCount = ARRAYSIZE(Screen_EoB::_screenDimTable);
+const ScreenDim Screen_EoB::_screenDimTableZH[] = {
+	{ 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 },
+	{ 0x08, 0x48, 0x18, 0x38, 0x0E, 0x0C, 0x00, 0x00 },
+	{ 0x13, 0x40, 0x14, 0x80, 0x06, 0x0C, 0x00, 0x00 },
+	{ 0x1D, 0x78, 0x08, 0x40, 0x0F, 0x0D, 0x00, 0x00 },
+	{ 0x02, 0x18, 0x14, 0x78, 0x0F, 0x02, 0x03, 0x00 },
+	{ 0x00, 0x00, 0x16, 0x78, 0x0F, 0x0D, 0x00, 0x00 },
+	{ 0x0A, 0x6C, 0x15, 0x28, 0x0F, 0x00, 0x00, 0x00 },
+	{ 0x01, 0xAB, 0x23, 0x1C, 0x0F, 0x0C, 0x00, 0x00 },
+	{ 0x02, 0x18, 0x14, 0x00, 0x0F, 0x02, 0x03, 0x00 },
+	{ 0x01, 0x7D, 0x26, 0x40, 0x0F, 0x00, 0x03, 0x00 },
+	{ 0x00, 0x00, 0x16, 0x90, 0x0F, 0x02, 0x00, 0x00 },
+	{ 0x01, 0x14, 0x14, 0x38, 0x0F, 0x02, 0x00, 0x00 },
+	{ 0x01, 0x04, 0x14, 0x9C, 0x0F, 0x02, 0x00, 0x00 },
+	{ 0x01, 0x19, 0x26, 0x64, 0x0F, 0x02, 0x00, 0x00 },
+	{ 0x01, 0x14, 0x14, 0x58, 0x0F, 0x02, 0x00, 0x00 },
+	{ 0x02, 0x06, 0x23, 0x78, 0x0F, 0x02, 0x00, 0x00 },
+	{ 0x09, 0x14, 0x16, 0x38, 0x0F, 0x02, 0x00, 0x00 },
+	{ 0x01, 0x96, 0x26, 0x31, 0x0F, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x08, 0x26, 0x80, 0x0C, 0x0F, 0x00, 0x00 },
+	{ 0x01, 0x10, 0x26, 0x14, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x00, 0x10, 0x10, 0x0C, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x00, 0x10, 0x17, 0x00, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x00, 0x10, 0x10, 0x00, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x00, 0x10, 0x07, 0x04, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x00, 0x00, 0x11, 0x05, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x00, 0x00, 0x15, 0x05, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x00, 0x00, 0x11, 0x08, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x00, 0x00, 0x15, 0x03, 0x00, 0x0F, 0x06, 0x00 },
+	{ 0x0A, 0xA8, 0x15, 0x18, 0x0F, 0x0C, 0x00, 0x00 }
+};
+
+const int Screen_EoB::_screenDimTableCount = ARRAYSIZE(Screen_EoB::_screenDimTableIntl);
 
 const uint8 EoBCoreEngine::_hpIncrPerLevel[] = { 10, 4, 8, 6, 10, 10, 9, 10, 9, 10, 9, 9, 3, 1, 2, 2, 3, 3 };
 


Commit: a569b7c5b283826c7702cace14ce3165e409e201
    https://github.com/scummvm/scummvm/commit/a569b7c5b283826c7702cace14ce3165e409e201
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add OK string for menu dialogues in Chinese EOB2

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index 388fb153b72..29303a024ce 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -578,6 +578,8 @@ void EoBCoreEngine::initStaticResource() {
 		0
 	};
 
+	_menuOkString = "OK";
+
 	switch (_flags.lang) {
 	case Common::EN_ANY: {
 		if (_flags.platform == Common::kPlatformSegaCD) {
@@ -615,6 +617,7 @@ void EoBCoreEngine::initStaticResource() {
 	case Common::ZH_TWN:
 		_saveLoadStrings = saveLoadStrings[6];
 		_errorSlotEmptyString = errorSlotEmptyString[6];
+		_menuOkString = "\xa7\xb9\xb2\xa6"; /* "完畢" */
 		break;
 
 	default:
@@ -622,8 +625,6 @@ void EoBCoreEngine::initStaticResource() {
 		_errorSlotEmptyString = errorSlotEmptyString[0];
 		break;
 	}
-
-	_menuOkString = "OK";
 }
 
 void EoBCoreEngine::initButtonData() {


Commit: c5f8d354f7355232a7eff61e6e24767635bb070e
    https://github.com/scummvm/scummvm/commit/c5f8d354f7355232a7eff61e6e24767635bb070e
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Adjust layout of GUI_EoB::messageDialogue for Chinese EOB2

Changed paths:
    engines/kyra/gui/gui_eob.cpp


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index 60814281df9..66a27049ffd 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -2614,8 +2614,13 @@ void GUI_EoB::messageDialogue(int dim, int id, int buttonTextCol) {
 	int by = dm->sy + dm->h - 19;
 	int bw = _screen->getTextWidth(_vm->_menuOkString) + 7;
 
-	drawMenuButtonBox(bx, by, bw, 14, false, false);
-	_screen->printShadedText(_vm->_menuOkString, bx + 4, by + 3, buttonTextCol, 0, _vm->guiSettings()->colors.guiColorBlack);
+	if (_vm->_flags.lang == Common::Language::ZH_TWN) {
+		drawMenuButtonBox(bx, by, bw, 16, false, false);
+		_screen->printShadedText(_vm->_menuOkString, bx + 4, by + 1, buttonTextCol, 0, _vm->guiSettings()->colors.guiColorBlack);
+	} else {
+		drawMenuButtonBox(bx, by, bw, 14, false, false);
+		_screen->printShadedText(_vm->_menuOkString, bx + 4, by + 3, buttonTextCol, 0, _vm->guiSettings()->colors.guiColorBlack);
+	}
 	_screen->updateScreen();
 
 	for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {


Commit: 571f8d1595600490706f64a764f6c720550fe5b5
    https://github.com/scummvm/scummvm/commit/571f8d1595600490706f64a764f6c720550fe5b5
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Adjust font height for console in Chinese EOB2.

This is more in line with the original

Changed paths:
    engines/kyra/text/text_rpg.cpp


diff --git a/engines/kyra/text/text_rpg.cpp b/engines/kyra/text/text_rpg.cpp
index ccc88377e77..576d47b2319 100644
--- a/engines/kyra/text/text_rpg.cpp
+++ b/engines/kyra/text/text_rpg.cpp
@@ -340,7 +340,13 @@ void TextDisplayer_rpg::printLine(char *str) {
 	bool sjisTextMode = _pc98TextMode && (sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15) ? true : false;
 	int sjisOffs = (sjisTextMode || _vm->game() != GI_LOL) ? 8 : 9;
 
-	int fh = (_screen->_currentFont == Screen::FID_SJIS_TEXTMODE_FNT) ? 9 : (_screen->getFontHeight() + _screen->_lineSpacing);
+	int fh;
+	if (_screen->_currentFont == Screen::FID_CHINESE_FNT && _vm->_flags.lang == Common::Language::ZH_TWN && _vm->_flags.gameID == GI_EOB2)
+		fh = 14;
+	else if (_screen->_currentFont == Screen::FID_SJIS_TEXTMODE_FNT)
+		fh = 9;
+	else
+		fh = _screen->getFontHeight() + _screen->_lineSpacing;
 	int lines = (sd->h - _screen->_lineSpacing) / fh;
 
 	while (_textDimData[sdx].line >= lines) {


Commit: 8c0295bb6683c25dd29b989289213bac12d4cedc
    https://github.com/scummvm/scummvm/commit/8c0295bb6683c25dd29b989289213bac12d4cedc
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Add errorSlotNoNameString for Chinese EOB2

Changed paths:
    engines/kyra/resource/staticres_eob.cpp


diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
index 29303a024ce..3ef199dd230 100644
--- a/engines/kyra/resource/staticres_eob.cpp
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -1845,10 +1845,11 @@ void DarkMoonEngine::initStaticResource() {
 	_amigaSoundIndex2 = _staticres->loadRawData(kEoB2SoundIndex2, temp);
 	_amigaSoundPatch = _staticres->loadRawData(kEoB2MonsterSoundPatchData, _amigaSoundPatchSize);
 
-	static const char *const errorSlotNoNameString[4] = {
+	static const char *const errorSlotNoNameString[5] = {
 		" You must specify\r a name for your\r save game!",
 		" Spielst[nde m]ssen\r einen Namen haben!",
 		" Debes poner\run nombre al\rfichero!",
+		" \xb1\x7a\xa5\xb2\xb6\xb7\xbf\xe9\xa4\x4a\xc0\xc9\xae\xd7\xa6\x57\xba\xd9", /* " 您必須輸入檔案名稱" */
 		0
 	};
 
@@ -1891,6 +1892,10 @@ void DarkMoonEngine::initStaticResource() {
 			_errorSlotNoNameString = errorSlotNoNameString[2];
 			_transferStringsScummVM = transferStringsScummVM[2];
 			break;
+		case Common::ZH_TWN:
+			_errorSlotNoNameString = errorSlotNoNameString[3];
+			_transferStringsScummVM = transferStringsScummVM[0];
+			break;
 	}
 
 }


Commit: d091774ab2abea46ae80b9b9eebdb42371f15ba5
    https://github.com/scummvm/scummvm/commit/d091774ab2abea46ae80b9b9eebdb42371f15ba5
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Support 2-column simplemenu

It's needed for EOB2 Chinese chargen to keep all the possibilities on
the screen

Changed paths:
    engines/kyra/gui/gui_eob.cpp
    engines/kyra/gui/gui_eob.h


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index 66a27049ffd..62b1986b930 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -2081,24 +2081,73 @@ int GUI_EoB::processButtonList(Kyra::Button *buttonList, uint16 inputFlags, int8
 	return result;
 }
 
+Common::Point GUI_EoB::simpleMenu_getTextPoint(int num, int *col) {
+	int column = 0;
+        int line = num;
+        int tx = 0;
+        for (; line >= _menuLines[column] && column + 1 < _menuColumns; line -= _menuLines[column], column++)
+                tx += _menuColumnWidth[column];
+        int ty = (line + _menuColumnOffset[column]) * (_menuLineSpacing + _screen->getCharHeight(' '));
+	if (col)
+		*col = column;
+	return Common::Point(tx, ty);
+}
+
+void GUI_EoB::simpleMenu_printButton(int sd, int num, const char *title, bool isHighlight, bool isInitial) {
+	int column;
+	Common::Point tPoint = simpleMenu_getTextPoint(num, &column);
+        if (_vm->gameFlags().platform == Common::kPlatformSegaCD) {
+                _vm->_txt->printShadedText(title, 4 + tPoint.x, (sd == 8 ? 2 : 20) + tPoint.y, isHighlight ? _menuHighlightColor : _menuTextColor, _menuShadowColor);
+        } else {
+		Common::Point p = tPoint + _menuPoint;
+                _screen->printShadedText(title, p.x, p.y, _menuTextColor, 0, _menuShadowColor);
+                if (isHighlight)
+                        _screen->printText(title, p.x, p.y, _menuHighlightColor, 0);
+		if (num < ARRAYSIZE(_menuOverflow) && isInitial)
+			_menuOverflow[num] = _screen->getTextWidth(title) > _menuColumnWidth[column];
+        }
+}
+
 void GUI_EoB::simpleMenu_setup(int sd, int maxItem, const char *const *strings, int32 menuItemsMask, int itemOffset, int lineSpacing, int textColor, int highlightColor, int shadowColor) {
 	simpleMenu_initMenuItemsMask(sd, maxItem, menuItemsMask, itemOffset);
 
 	const ScreenDim *dm = _screen->getScreenDim(19 + sd);
-	int x = (_screen->_curDim->sx + dm->sx) << 3;
-	int y = _screen->_curDim->sy + dm->sy;
+        _menuPoint = Common::Point((_screen->_curDim->sx + dm->sx) << 3, _screen->_curDim->sy + dm->sy);
 
 	int v = simpleMenu_getMenuItem(_menuCur, menuItemsMask, itemOffset);
-
-	for (int i = 0; i < _menuNumItems; i++) {
-		int item = simpleMenu_getMenuItem(i, menuItemsMask, itemOffset);
-		int ty = i * (lineSpacing + _screen->getCharHeight(' '));
-		if (_vm->gameFlags().platform == Common::kPlatformSegaCD) {
-			_vm->_txt->printShadedText(strings[item], 4, (sd == 8 ? 2 : 20) + ty, item == v ? highlightColor : textColor, shadowColor);
-		} else {
-			_screen->printShadedText(strings[item], x, y + ty, textColor, 0, shadowColor);
-			if (item == v)
-				_screen->printText(strings[item], x, y + ty, highlightColor, 0);
+	_menuColumns = 1;
+	_menuLines[0] = _menuNumItems;
+	_menuLines[1] = 0;
+	_menuColumnWidth[0] = dm->w * _screen->getCharWidth('W');
+	_menuColumnWidth[1] = 0;
+	_menuColumnOffset[0] = 0;
+	_menuColumnOffset[1] = 0;
+
+	memset(_menuOverflow, 0, sizeof(_menuOverflow));
+
+	if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) {
+		switch (sd) {
+		case 1:
+		case 3:
+			_menuPoint.x = (_screen->_curDim->sx << 3) - 7;
+			if (_menuNumItems >= 6) {
+				_menuLines[0] = 6;
+				_menuLines[1] = _menuNumItems - 6;
+				_menuColumnWidth[0] = _menuColumnWidth[1] = 75;
+				_menuColumns = 2;
+			}
+			break;
+		case 2:
+			_menuPoint.x = (_screen->_curDim->sx << 3) - 7;
+			if (_menuNumItems >= 7) {
+				_menuLines[0] = 7;
+				_menuColumnOffset[1] = -1;
+				_menuLines[1] = _menuNumItems - 7;
+				_menuColumnWidth[0] = 48;
+				_menuColumnWidth[1] = 135;
+				_menuColumns = 2;
+			}
+			break;
 		}
 	}
 
@@ -2107,65 +2156,113 @@ void GUI_EoB::simpleMenu_setup(int sd, int maxItem, const char *const *strings,
 	_menuTextColor = textColor;
 	_menuHighlightColor = highlightColor;
 	_menuShadowColor = shadowColor;
+
+	for (int i = 0; i < _menuNumItems; i++) {
+		int item = simpleMenu_getMenuItem(i, menuItemsMask, itemOffset);
+                simpleMenu_printButton(sd, i, strings[item], item == v, true);
+	}
+
 	_vm->removeInputTop();
 }
 
-int GUI_EoB::simpleMenu_process(int sd, const char *const *strings, void *b, int32 menuItemsMask, int itemOffset) {
+int GUI_EoB::simpleMenu_getMouseItem(int sd) {
 	const ScreenDim *dm = _screen->getScreenDim(19 + sd);
-	int h = _menuNumItems - 1;
+	Common::Point mousePos = _vm->getMousePos();
+	int xrel = mousePos.x - _menuPoint.x;
+	int y1 = _screen->_curDim->sy + dm->sy - (_menuLineSpacing >> 1);
+	int lineH = (_menuLineSpacing + _screen->getCharHeight(' '));
+	int yrel = mousePos.y - y1;
+	int column;
+	int columnItems = 0;
+
+	if (xrel < 0)
+		return -1;
+
+	for (column = 0; column < _menuColumns; column++) {
+		if (xrel < _menuColumnWidth[column])
+			break;
+		xrel -= _menuColumnWidth[column];
+		columnItems += _menuLines[column];
+	}
+
+	if (column == _menuColumns)
+		return -1;
+	
+	int yrelcol = yrel - _menuColumnOffset[column] * lineH;
+
+	if (yrelcol >= 0 && yrelcol < _menuLines[column] * lineH)
+		return yrelcol / lineH + columnItems;
+
+	// Try previous column if it's wide
+	if (column == 0)
+		return -1;
+
+	column--;
+	columnItems -= _menuLines[column];
+	yrelcol = yrel - _menuColumnOffset[column] * lineH;
+	if (yrelcol >= 0 && yrelcol < _menuLines[column] * lineH) {
+		int candidate = yrelcol / lineH + columnItems;
+		if (candidate < ARRAYSIZE(_menuOverflow) && _menuOverflow[candidate])
+			return candidate;
+	}
+
+	return -1;
+}
+
+int GUI_EoB::simpleMenu_process(int sd, const char *const *strings, void *b, int32 menuItemsMask, int itemOffset) {
 	int currentItem = _menuCur % _menuNumItems;
 	int newItem = currentItem;
 	int result = -1;
-	int lineH = (_menuLineSpacing + _screen->getCharHeight(' '));
-	int lineS1 = _menuLineSpacing >> 1;
-	int x = (_screen->_curDim->sx + dm->sx) << 3;
-	int y = _screen->_curDim->sy + dm->sy;
 
 	int inFlag = _vm->checkInput(0, false, 0) & 0x8FF;
 	_vm->removeInputTop();
-	Common::Point mousePos = _vm->getMousePos();
 
-	int x1 = (_screen->_curDim->sx << 3) + (dm->sx * _screen->getCharWidth('W'));
-	int y1 = _screen->_curDim->sy + dm->sy - lineS1;
-	int x2 = x1 + (dm->w * _screen->getCharWidth('W')) - 1;
-	int y2 = y1 + _menuNumItems * lineH - 1;
-	if (_vm->posWithinRect(mousePos.x, mousePos.y, x1, y1, x2, y2))
-		newItem = (mousePos.y - y1) / lineH;
+	int mouseItem = simpleMenu_getMouseItem(sd);
+
+	if (mouseItem >= 0)
+		newItem = mouseItem;
 
 	if (inFlag == 199 || inFlag == 201) {
-		if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, x1, y1, x2, y2))
-			result = newItem = (_vm->_mouseY - y1) / lineH;
+		if (mouseItem >= 0)
+			result = newItem = mouseItem;
 	} else if (inFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inFlag == _vm->_keyMap[Common::KEYCODE_KP5]) {
 		result = newItem;
 	} else if (inFlag == _vm->_keyMap[Common::KEYCODE_HOME] || inFlag == _vm->_keyMap[Common::KEYCODE_KP7] || inFlag == _vm->_keyMap[Common::KEYCODE_PAGEUP] || inFlag == _vm->_keyMap[Common::KEYCODE_KP9]) {
 		newItem = 0;
 	} else if (inFlag == _vm->_keyMap[Common::KEYCODE_END] || inFlag == _vm->_keyMap[Common::KEYCODE_KP1] || inFlag == _vm->_keyMap[Common::KEYCODE_PAGEDOWN] || inFlag == _vm->_keyMap[Common::KEYCODE_KP3]) {
-		newItem = h;
+		newItem = _menuNumItems - 1;
 	} else if (inFlag == _vm->_keyMap[Common::KEYCODE_UP] || inFlag == _vm->_keyMap[Common::KEYCODE_KP8]) {
 		if (--newItem < 0)
-			newItem = h;
+			newItem = _menuNumItems - 1;
 	} else if (inFlag == _vm->_keyMap[Common::KEYCODE_DOWN] || inFlag == _vm->_keyMap[Common::KEYCODE_KP2]) {
-		if (++newItem > h)
+		if (++newItem > _menuNumItems - 1)
 			newItem = 0;
+	} else if (inFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inFlag == _vm->_keyMap[Common::KEYCODE_KP4]) {
+		newItem -= _menuLines[0];
+		if (newItem < 0)
+			newItem = 0;
+	} else if (inFlag == _vm->_keyMap[Common::KEYCODE_RIGHT] || inFlag == _vm->_keyMap[Common::KEYCODE_KP6]) {
+		newItem += _menuLines[0];
+		if (newItem > _menuNumItems - 1)
+			newItem = _menuNumItems - 1;
 	} else {
 		_menuLastInFlags = inFlag;
 	}
 
 	if (newItem != currentItem) {
+                simpleMenu_printButton(sd, currentItem, strings[simpleMenu_getMenuItem(currentItem, menuItemsMask, itemOffset)], false, false);
+                simpleMenu_printButton(sd, newItem, strings[simpleMenu_getMenuItem(newItem, menuItemsMask, itemOffset)], true, false);
 		if (_vm->gameFlags().platform == Common::kPlatformSegaCD) {
-			_vm->_txt->printShadedText(strings[simpleMenu_getMenuItem(currentItem, menuItemsMask, itemOffset)], 4, (sd == 8 ? 2 : 20) + currentItem * lineH, _menuTextColor, _menuShadowColor);
-			_vm->_txt->printShadedText(strings[simpleMenu_getMenuItem(newItem, menuItemsMask, itemOffset)], 4, (sd == 8 ? 2 : 20) + newItem * lineH, _menuHighlightColor, _menuShadowColor);
 			_screen->sega_getRenderer()->render(0, 6, 20, 26, 5);
-		} else {
-			_screen->printText(strings[simpleMenu_getMenuItem(currentItem, menuItemsMask, itemOffset)], x, y + currentItem * lineH, _menuTextColor, 0);
-			_screen->printText(strings[simpleMenu_getMenuItem(newItem, menuItemsMask, itemOffset)], x, y + newItem * lineH, _menuHighlightColor, 0);
 		}
 		_screen->updateScreen();
 	}
 
 	if (result != -1) {
 		result = simpleMenu_getMenuItem(result, menuItemsMask, itemOffset);
-		simpleMenu_flashSelection(strings[result], x, y + newItem * lineH, _vm->guiSettings()->colors.guiColorWhite, _menuHighlightColor, 0);
+		Common::Point tPoint = simpleMenu_getTextPoint(newItem);
+		Common::Point p = _menuPoint + tPoint;
+		simpleMenu_flashSelection(strings[result], p.x, p.y, _vm->guiSettings()->colors.guiColorWhite, _menuHighlightColor, 0);
 	}
 
 	_menuCur = newItem;
diff --git a/engines/kyra/gui/gui_eob.h b/engines/kyra/gui/gui_eob.h
index 8a6b2be6998..b9cce3bbee6 100644
--- a/engines/kyra/gui/gui_eob.h
+++ b/engines/kyra/gui/gui_eob.h
@@ -98,6 +98,9 @@ private:
 	int simpleMenu_getMenuItem(int index, int32 menuItemsMask, int itemOffset);
 	void simpleMenu_flashSelection(const char *str, int x, int y, int color1, int color2, int color3);
 	void simpleMenu_initMenuItemsMask(int menuId, int maxItem, int32 menuItemsMask, int unk);
+	void simpleMenu_printButton(int sd, int num, const char *title, bool isHighlight, bool isInitial);
+	Common::Point simpleMenu_getTextPoint(int num, int *col = nullptr);
+	int simpleMenu_getMouseItem(int sd);
 
 	bool runSaveMenu(int x, int y);
 	int selectSaveSlotDialog(int x, int y, int id);
@@ -150,6 +153,12 @@ private:
 	int _menuTextColor;
 	int _menuHighlightColor;
 	int _menuShadowColor;
+	int _menuLines[2];
+	int _menuColumnWidth[2];
+	int _menuColumnOffset[2];
+	bool _menuOverflow[20];
+	int _menuColumns;
+	Common::Point _menuPoint;
 
 	uint8 _numPages;
 	uint8 _numVisPages;


Commit: e64898ad33aa08f3c6ca065533cd3955ce090149
    https://github.com/scummvm/scummvm/commit/e64898ad33aa08f3c6ca065533cd3955ce090149
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Increase x-resolution of button position

Currently buttons have to be 8-aligned on x axis. In Chinese version it's
only 4-aligned. Change code no to require any alignment.

Changed paths:
    engines/kyra/engine/chargen.cpp
    engines/kyra/engine/eobcommon.h


diff --git a/engines/kyra/engine/chargen.cpp b/engines/kyra/engine/chargen.cpp
index 130e01cacfc..8e3c6c6fc22 100644
--- a/engines/kyra/engine/chargen.cpp
+++ b/engines/kyra/engine/chargen.cpp
@@ -50,7 +50,7 @@ private:
 	bool createCustomParty(const uint8 ***faceShapes);
 	void createDefaultParty();
 	void initButtonsFromList(int first, int numButtons);
-	void initButton(int index, int x, int y, int w, int h, int keyCode);
+	void initButton(int index, const EoBChargenButtonDef *e);
 	void checkForCompleteParty();
 	void drawButton(int index, int buttonState, int pageNum);
 	void processButtonClick(int index);
@@ -176,7 +176,7 @@ CharacterGenerator::CharacterGenerator(EoBCoreEngine *vm, Screen_EoB *screen) :
 		// Adjust modify menu buttons for SegaCD
 		for (int i = 31; i < 38; ++i)
 			chargenButtonDefs[i].y += 8;
-		chargenButtonDefs[37].x--;
+		chargenButtonDefs[37].x -= 8;
 	}
 
 	_chargenButtonDefs = chargenButtonDefs;
@@ -432,13 +432,13 @@ void CharacterGenerator::initButtonsFromList(int first, int numButtons) {
 
 	for (int i = 0; i < numButtons; i++) {
 		const EoBChargenButtonDef *e = &_chargenButtonDefs[first + i];
-		initButton(i, e->x, e->y, e->w, e->h, e->keyCode);
+		initButton(i, e);
 	}
 
 	_vm->gui_notifyButtonListChanged();
 }
 
-void CharacterGenerator::initButton(int index, int x, int y, int w, int h, int keyCode) {
+void CharacterGenerator::initButton(int index, const EoBChargenButtonDef *e) {
 	Button *b = 0;
 	int cnt = 1;
 
@@ -463,12 +463,12 @@ void CharacterGenerator::initButton(int index, int x, int y, int w, int h, int k
 	b->data3Val2 = 8;
 
 	b->index = index + 1;
-	b->x = x << 3;
-	b->y = y;
-	b->width = w;
-	b->height = h;
-	b->keyCode = keyCode;
-	b->keyCode2 = keyCode | 0x100;
+	b->x = e->x;
+	b->y = e->y;
+	b->width = e->w;
+	b->height = e->h;
+	b->keyCode = e->keyCode;
+	b->keyCode2 = e->keyCode | 0x100;
 }
 
 void CharacterGenerator::checkForCompleteParty() {
@@ -1619,47 +1619,47 @@ void CharacterGenerator::finish() {
 }
 
 const EoBChargenButtonDef CharacterGenerator::_chargenButtonDefsDOS[] = {
-	{ 0x01, 0x37, 0x31, 0x32, 0x70 },
-	{ 0x09, 0x37, 0x31, 0x32, 0x71 },
-	{ 0x01, 0x77, 0x31, 0x32, 0x72 },
-	{ 0x09, 0x77, 0x31, 0x32, 0x73 },
-	{ 0x03, 0xB5, 0x53, 0x10, 0x1A },
-	{ 0x21, 0xAC, 0x26, 0x10, 0x19 },
-	{ 0x1C, 0xAC, 0x26, 0x10, 0x21 },
-	{ 0x21, 0xAC, 0x26, 0x10, 0x32 },
-	{ 0x13, 0x50, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x58, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x60, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x68, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x70, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x78, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x80, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x88, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x90, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0x98, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0xA0, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0xA8, 0x9A, 0x08, 0x00 },
-	{ 0x13, 0xB0, 0x9A, 0x08, 0x00 },
-	{ 0x12, 0x42, 0x20, 0x10, 0x00 },
-	{ 0x12, 0x52, 0x20, 0x10, 0x00 },
-	{ 0x16, 0x42, 0x20, 0x20, 0x00 },
-	{ 0x1A, 0x42, 0x20, 0x20, 0x00 },
-	{ 0x1E, 0x42, 0x20, 0x20, 0x00 },
-	{ 0x22, 0x42, 0x20, 0x20, 0x00 },
-	{ 0x1C, 0x9C, 0x26, 0x10, 0x14 },
-	{ 0x21, 0x9C, 0x26, 0x10, 0x34 },
-	{ 0x1C, 0xAC, 0x26, 0x10, 0x22 },
-	{ 0x21, 0xAC, 0x26, 0x10, 0x26 },
-	{ 0x12, 0x80, 0x35, 0x08, 0x00 },
-	{ 0x12, 0x88, 0x35, 0x08, 0x00 },
-	{ 0x12, 0x90, 0x35, 0x08, 0x00 },
-	{ 0x12, 0x98, 0x35, 0x08, 0x00 },
-	{ 0x12, 0xA0, 0x35, 0x08, 0x00 },
-	{ 0x12, 0xA8, 0x35, 0x08, 0x00 },
-	{ 0x1D, 0x88, 0x35, 0x08, 0x00 },
-	{ 0x1B, 0xAC, 0x15, 0x10, 0x0D },
-	{ 0x1E, 0xAC, 0x15, 0x10, 0x0C },
-	{ 0x21, 0xAC, 0x25, 0x10, 0x19 }
+	{ 0x01 << 3, 0x37, 0x31, 0x32, 0x70 },
+	{ 0x09 << 3, 0x37, 0x31, 0x32, 0x71 },
+	{ 0x01 << 3, 0x77, 0x31, 0x32, 0x72 },
+	{ 0x09 << 3, 0x77, 0x31, 0x32, 0x73 },
+	{ 0x03 << 3, 0xB5, 0x53, 0x10, 0x1A },
+	{ 0x21 << 3, 0xAC, 0x26, 0x10, 0x19 },
+	{ 0x1C << 3, 0xAC, 0x26, 0x10, 0x21 },
+	{ 0x21 << 3, 0xAC, 0x26, 0x10, 0x32 },
+	{ 0x13 << 3, 0x50, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x58, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x60, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x68, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x70, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x78, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x80, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x88, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x90, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x98, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0xA0, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0xA8, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0xB0, 0x9A, 0x08, 0x00 },
+	{ 0x12 << 3, 0x42, 0x20, 0x10, 0x00 },
+	{ 0x12 << 3, 0x52, 0x20, 0x10, 0x00 },
+	{ 0x16 << 3, 0x42, 0x20, 0x20, 0x00 },
+	{ 0x1A << 3, 0x42, 0x20, 0x20, 0x00 },
+	{ 0x1E << 3, 0x42, 0x20, 0x20, 0x00 },
+	{ 0x22 << 3, 0x42, 0x20, 0x20, 0x00 },
+	{ 0x1C << 3, 0x9C, 0x26, 0x10, 0x14 },
+	{ 0x21 << 3, 0x9C, 0x26, 0x10, 0x34 },
+	{ 0x1C << 3, 0xAC, 0x26, 0x10, 0x22 },
+	{ 0x21 << 3, 0xAC, 0x26, 0x10, 0x26 },
+	{ 0x12 << 3, 0x80, 0x35, 0x08, 0x00 },
+	{ 0x12 << 3, 0x88, 0x35, 0x08, 0x00 },
+	{ 0x12 << 3, 0x90, 0x35, 0x08, 0x00 },
+	{ 0x12 << 3, 0x98, 0x35, 0x08, 0x00 },
+	{ 0x12 << 3, 0xA0, 0x35, 0x08, 0x00 },
+	{ 0x12 << 3, 0xA8, 0x35, 0x08, 0x00 },
+	{ 0x1D << 3, 0x88, 0x35, 0x08, 0x00 },
+	{ 0x1B << 3, 0xAC, 0x15, 0x10, 0x0D },
+	{ 0x1E << 3, 0xAC, 0x15, 0x10, 0x0C },
+	{ 0x21 << 3, 0xAC, 0x25, 0x10, 0x19 }
 };
 
 const uint16 CharacterGenerator::_chargenButtonKeyCodesFMTOWNS[] = {
diff --git a/engines/kyra/engine/eobcommon.h b/engines/kyra/engine/eobcommon.h
index d625a3178cb..df416df4feb 100644
--- a/engines/kyra/engine/eobcommon.h
+++ b/engines/kyra/engine/eobcommon.h
@@ -69,7 +69,7 @@ struct EoBRect8 {
 };
 
 struct EoBChargenButtonDef {
-	uint8 x;
+	uint16 x;
 	uint8 y;
 	uint8 w;
 	uint8 h;


Commit: 286e7e4b2e030a0b4eaef361260bf4119e39bbd7
    https://github.com/scummvm/scummvm/commit/286e7e4b2e030a0b4eaef361260bf4119e39bbd7
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Change chargen layout in Chinese EOB2 to match original

Changed paths:
    engines/kyra/engine/chargen.cpp


diff --git a/engines/kyra/engine/chargen.cpp b/engines/kyra/engine/chargen.cpp
index 8e3c6c6fc22..d1aa677502d 100644
--- a/engines/kyra/engine/chargen.cpp
+++ b/engines/kyra/engine/chargen.cpp
@@ -109,6 +109,7 @@ private:
 	const EoBChargenButtonDef *_chargenButtonDefs;
 
 	static const EoBChargenButtonDef _chargenButtonDefsDOS[];
+	static const EoBChargenButtonDef _chargenButtonDefsDOSChinese[];
 	static const uint16 _chargenButtonKeyCodesFMTOWNS[];
 	static const CreatePartyModButton _chargenModButtons[];
 	static const EoBRect8 _chargenButtonBodyCoords[];
@@ -123,6 +124,9 @@ private:
 
 	static const int16 _raceModifiers[];
 
+	static const char *_chineseStrings[17];
+	static const int _chineseButtonMapping[17];
+
 	EoBCharacter *_characters;
 	const uint8 **_faceShapes;
 
@@ -161,8 +165,8 @@ CharacterGenerator::CharacterGenerator(EoBCoreEngine *vm, Screen_EoB *screen) :
 	_chargenDefaultNames = _vm->staticres()->loadStrings(kEoB1DefaultPartyNames, temp);
 	_chargenDefaultStats = _vm->staticres()->loadRawData(kEoB1DefaultPartyStats, temp);
 
-	EoBChargenButtonDef *chargenButtonDefs = new EoBChargenButtonDef[41];
-	memcpy(chargenButtonDefs, _chargenButtonDefsDOS, 41 * sizeof(EoBChargenButtonDef));
+	EoBChargenButtonDef *chargenButtonDefs = new EoBChargenButtonDef[42];
+	memcpy(chargenButtonDefs, (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) ? _chargenButtonDefsDOSChinese : _chargenButtonDefsDOS, 42 * sizeof(EoBChargenButtonDef));
 
 	if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
 		const uint16 *c = _chargenButtonKeyCodesFMTOWNS;
@@ -540,12 +544,41 @@ void CharacterGenerator::drawButton(int index, int buttonState, int pageNum) {
 		return;
 	}
 
-	const CreatePartyModButton *c = &_chargenModButtons[index];
-	const EoBRect8 *p = &_chargenButtonBodyCoords[c->bodyIndex + buttonState];
+	if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN && _chineseStrings[index]) {
+		int mappedIdx = _chineseButtonMapping[index];
+		int destX = _chargenButtonDefs[mappedIdx].x;
+		int destY = _chargenButtonDefs[mappedIdx].y;
+		int w = _chargenButtonDefs[mappedIdx].w;
+		int h = _chargenButtonDefs[mappedIdx].h;
+
+		int x2 = destX;
+		int y2 = destY;
+
+		if (pageNum == 2) {
+			x2 = destX - 144;
+			y2 = destY - 64;
+		}
+		int page = _screen->_curPage;
+
+		_screen->_curPage = pageNum;
+		_screen->set16bitShadingLevel(4);
+		_vm->gui_drawBox(x2, y2, w, h, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, -1);
+		_vm->gui_drawBox(x2 + 1, y2 + 1, w - 2, h - 2, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill);
+		_screen->set16bitShadingLevel(0);
+		_screen->printShadedText(_chineseStrings[index], x2 + 2, y2 + 2, buttonState ? _vm->guiSettings()->colors.guiColorLightRed : _vm->guiSettings()->colors.guiColorWhite,
+					 0, _vm->guiSettings()->colors.guiColorBlack);
+		_screen->_curPage = page;
+		if (pageNum == 0 || pageNum == 1)
+			_screen->updateScreen();
+		return;
+	}
 
 	int x2 = 20;
 	int y2 = 0;
 
+	const CreatePartyModButton *c = &_chargenModButtons[index];
+	const EoBRect8 *p = &_chargenButtonBodyCoords[c->bodyIndex + buttonState];
+
 	if (pageNum) {
 		x2 = c->destX + 2;
 		y2 = c->destY - 64;
@@ -700,7 +733,8 @@ int CharacterGenerator::raceSexMenu() {
 		_screen->sega_getRenderer()->fillRectWithTiles(0, 18, 8, 20, 16, 0);
 		_vm->_txt->printShadedText(_chargenStrings2[8], 0, 0, -1, 0x99);
 	} else {
-		_screen->printShadedText(_chargenStrings2[8], 147, 67, _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
+		_screen->printShadedText(_chargenStrings2[8], 147, (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) ? 65 : 67,
+					 _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
 	}
 	_vm->removeInputTop();
 
@@ -738,8 +772,12 @@ int CharacterGenerator::classMenu(int raceSex) {
 		_screen->sega_loadTextBackground(_wndBackgrnd, 10240);
 		_screen->sega_getRenderer()->fillRectWithTiles(0, 18, 8, 20, 16, 0);
 		_vm->_txt->printShadedText(_chargenStrings2[9], 0, 0, -1, 0x99);
+	} else if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) {
+		_screen->printShadedText(_chargenStrings2[9], 145, 65,
+					 _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
 	} else {
-		_screen->printShadedText(_chargenStrings2[9], 147, 67, _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
+		_screen->printShadedText(_chargenStrings2[9], 147, 67,
+					 _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
 	}
 	drawButton(5, 0, 0);
 
@@ -759,7 +797,8 @@ int CharacterGenerator::classMenu(int raceSex) {
 
 		if (in == _vm->_keyMap[Common::KEYCODE_ESCAPE] || _vm->_gui->_menuLastInFlags == _vm->_keyMap[Common::KEYCODE_ESCAPE] || _vm->_gui->_menuLastInFlags == _vm->_keyMap[Common::KEYCODE_b]) {
 			res = _vm->_keyMap[Common::KEYCODE_ESCAPE];
-		} else if (_vm->posWithinRect(mp.x, mp.y, 264, 171, 303, 187)) {
+		} else if (_vm->posWithinRect(mp.x, mp.y, _chargenButtonDefs[41].x, _chargenButtonDefs[41].y,
+					      _chargenButtonDefs[41].x + _chargenButtonDefs[41].w, _chargenButtonDefs[41].y + _chargenButtonDefs[41].h)) {
 			if (in == 199 || in == 201)
 				res = _vm->_keyMap[Common::KEYCODE_ESCAPE];
 			else
@@ -798,7 +837,9 @@ int CharacterGenerator::alignmentMenu(int cClass) {
 		_screen->sega_getRenderer()->fillRectWithTiles(0, 18, 8, 20, 16, 0);
 		_vm->_txt->printShadedText(_chargenStrings2[10], 0, 0, -1, 0x99);
 	} else {
-		_screen->printShadedText(_chargenStrings2[10], 147, 67, _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
+		_screen->printShadedText(_chargenStrings2[10], 147,
+					 (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) ? 65 : 67,
+					 _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
 	}
 
 	drawButton(5, 0, 0);
@@ -819,7 +860,8 @@ int CharacterGenerator::alignmentMenu(int cClass) {
 
 		if (in == _vm->_keyMap[Common::KEYCODE_ESCAPE] || _vm->_gui->_menuLastInFlags == _vm->_keyMap[Common::KEYCODE_ESCAPE] || _vm->_gui->_menuLastInFlags == _vm->_keyMap[Common::KEYCODE_b]) {
 			res = _vm->_keyMap[Common::KEYCODE_ESCAPE];
-		} else if (_vm->posWithinRect(mp.x, mp.y, 264, 171, 303, 187)) {
+		} else if (_vm->posWithinRect(mp.x, mp.y, _chargenButtonDefs[41].x, _chargenButtonDefs[41].y,
+					      _chargenButtonDefs[41].x + _chargenButtonDefs[41].w, _chargenButtonDefs[41].y + _chargenButtonDefs[41].h)) {
 			if (in == 199 || in == 201)
 				res = _vm->_keyMap[Common::KEYCODE_ESCAPE];
 			else
@@ -1135,7 +1177,7 @@ void CharacterGenerator::printStats(int index, int mode) {
 		_screen->copyRegion(0, 0, 160, 0, 160, 128, 2, 2, Screen::CR_NO_P_CHECK);
 		_screen->_curPage = 2;
 		if (mode != 4)
-			_screen->drawShape(2, c->faceShape, 224, 2, 0);
+			_screen->drawShape(2, c->faceShape, (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) ? 289 : 224, 2, 0);
 	}
 
 	Common::String str1 = Common::String::format(_chargenStrings1[3], _vm->getCharStrength(c->strengthCur, c->strengthExtCur, _vm->gameFlags().platform == Common::kPlatformSegaCD).c_str(), c->intelligenceCur, c->wisdomCur, c->dexterityCur, c->constitutionCur, c->charismaCur);
@@ -1151,17 +1193,52 @@ void CharacterGenerator::printStats(int index, int mode) {
 		_vm->_txt->printShadedText(str2.c_str(), 112, 72);
 		_vm->_txt->printShadedText(str3.c_str(), 120, 88);
 	} else {
-		_screen->printShadedText(c->name, 160 + ((160 - _screen->getTextWidth(c->name)) / 2), 35, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
-		_screen->printShadedText(_chargenRaceSexStrings[c->raceSex], 160 + ((160 - _screen->getTextWidth(_chargenRaceSexStrings[c->raceSex])) / 2), 45, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
-		_screen->printShadedText(_chargenClassStrings[c->cClass], 160 + ((160 - _screen->getTextWidth(_chargenClassStrings[c->cClass])) / 2), 54, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+		_screen->printShadedText(c->name,
+					 160 + ((160 - _screen->getTextWidth(c->name)) / 2),
+					 35, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+		if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) {
+			_screen->printShadedText(_chargenRaceSexStrings[c->raceSex], 165, 34, _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(_chargenClassStrings[c->cClass], 165, 49, _vm->guiSettings()->colors.guiColorLightRed, 0, _vm->guiSettings()->colors.guiColorBlack);
+
+			for (int i = 0; i < 6; i++)
+				_screen->printShadedText(_chargenStatStrings[i], 165 + (i / 3) * 75, 64 + 16 * (i % 3), _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText("\xa8\xbe:" /* "防:"; */, 165, 64 + 16 * 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText("\xa9\x52:" /* "命:"; */, 165 + 45, 64 + 16 * 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText("\xaf\xc5:" /* "ç´š:"; */, 165 + 91, 64 + 16 * 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+
+			Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+			_screen->printShadedText(_vm->getCharStrength(c->strengthCur, c->strengthExtCur, _vm->gameFlags().platform == Common::kPlatformSegaCD).c_str(),
+						 165 + 25, 64 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(Common::String::format("%d", c->intelligenceCur).c_str(),
+						 165 + 25, 64 + 16 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(Common::String::format("%d", c->wisdomCur).c_str(),
+						 165 + 25, 64 + 16 * 2 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(Common::String::format("%d", c->dexterityCur).c_str(),
+						 165 + 75 + 25, 64 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(Common::String::format("%d", c->constitutionCur).c_str(),
+						 165 + 75 + 25, 64 + 16 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(Common::String::format("%d", c->charismaCur).c_str(),
+						 165 + 75 + 25, 64 + 16 * 2 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+
+			_screen->printShadedText(str3.c_str(),
+						 165 + 25, 64 + 16 * 3 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(Common::String::format("%d", c->hitPointsMax).c_str(),
+						 165 + 45 + 25, 64 + 16 * 3 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(Common::String::format("%d", c->armorClass).c_str(),
+						 165 + 91 + 25, 64 + 16 * 3 + 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->setFont(of);
+		} else {
+			_screen->printShadedText(_chargenRaceSexStrings[c->raceSex], 160 + ((160 - _screen->getTextWidth(_chargenRaceSexStrings[c->raceSex])) / 2), 45, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(_chargenClassStrings[c->cClass], 160 + ((160 - _screen->getTextWidth(_chargenClassStrings[c->cClass])) / 2), 54, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
 
-		for (int i = 0; i < 6; i++)
-			_screen->printShadedText(_chargenStatStrings[i], 163, (i + 8) << 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			for (int i = 0; i < 6; i++)
+				_screen->printShadedText(_chargenStatStrings[i], 163, (i + 8) << 3, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(_chargenStrings1[2], 248, 64, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
 
-		_screen->printShadedText(_chargenStrings1[2], 248, 64, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
-		_screen->printShadedText(str1.c_str(), 192, 64, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
-		_screen->printShadedText(str2.c_str(), 280, 64, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
-		_screen->printShadedText(str3.c_str(), 280, 80, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(str1.c_str(), 192, 64, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(str2.c_str(), 280, 64, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			_screen->printShadedText(str3.c_str(), 280, 80, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+		}
 	}
 
 	switch (mode) {
@@ -1235,10 +1312,17 @@ int CharacterGenerator::modifyStat(int index, int8 *stat1, int8 *stat2) {
 	printStats(_activeBox, 3);
 	_vm->removeInputTop();
 
+	Screen::FontId of = _screen->_currentFont;
+
 	if (_vm->_flags.platform == Common::kPlatformSegaCD) {
 		Common::String statStr = index ? Common::String::format("%02d", *s1) : _vm->getCharStrength(*s1, *s2, true);
 		_vm->_txt->printShadedText(statStr.c_str(), b->x - 112, b->y - 64, 0x55);
 		_screen->sega_getRenderer()->render(0, (b->x + 32) >> 3, b->y >> 3, 5, 1);
+	} else if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) {
+		_screen->setFont(Screen::FID_8_FNT);
+		Common::String statStr = index ? Common::String::format("%d", *s1) : _vm->getCharStrength(*s1, *s2);
+		_screen->copyRegion(b->x - 115, b->y - 63, b->x + 29, b->y + 1, index == 6 ? 20 : 40, 14, 2, 0, Screen::CR_NO_P_CHECK);
+		_screen->printShadedText(statStr.c_str(), b->x + 29, b->y + 1, _vm->guiSettings()->colors.guiColorLightRed, 0, _vm->guiSettings()->colors.guiColorBlack);
 	} else {
 		Common::String statStr = index ? Common::String::format("%d", *s1) : _vm->getCharStrength(*s1, *s2);
 		_screen->copyRegion(b->x - 112, b->y - 64, b->x + 32, b->y, 40, b->height, 2, 0, Screen::CR_NO_P_CHECK);
@@ -1339,6 +1423,20 @@ int CharacterGenerator::modifyStat(int index, int8 *stat1, int8 *stat2) {
 			printStats(_activeBox, 3);
 			_vm->_txt->printShadedText(statStr.c_str(), b->x - 112, b->y - 64, 0x55);
 			_screen->sega_getRenderer()->render(0, (b->x + 32) >> 3, b->y >> 3, 5, 1);
+		} else if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) {
+			Common::String statStr = index ? Common::String::format("%d", *s1) : _vm->getCharStrength(*s1, *s2);
+			_screen->copyRegion(b->x - 115, b->y - 63, b->x + 29, b->y + 1, index == 6 ? 20 : 40, 14, 2, 0, Screen::CR_NO_P_CHECK);
+			_screen->printShadedText(statStr.c_str(), b->x + 29, b->y + 1, _vm->guiSettings()->colors.guiColorLightRed, 0, _vm->guiSettings()->colors.guiColorBlack);
+
+			if (hpChanged) {
+				statStr = Common::String::format("%d", c->hitPointsCur);
+				_screen->copyRegion(75, 115, 219, 179, 20, 8, 2, 0, Screen::CR_NO_P_CHECK);
+				_screen->printShadedText(statStr.c_str(), 219, 179, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			} else if (acChanged) {
+				statStr = Common::String::format("%d", c->armorClass);
+				_screen->copyRegion(121, 115, 265, 179, 20, 8, 2, 0, Screen::CR_NO_P_CHECK);
+				_screen->printShadedText(statStr.c_str(), 265, 179, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorBlack);
+			}
 		} else {
 			Common::String statStr = index ? Common::String::format("%d", *s1) : _vm->getCharStrength(*s1, *s2);
 			_screen->copyRegion(b->x - 112, b->y - 64, b->x + 32, b->y, 40, b->height, 2, 0, Screen::CR_NO_P_CHECK);
@@ -1367,6 +1465,8 @@ int CharacterGenerator::modifyStat(int index, int8 *stat1, int8 *stat2) {
 		}
 	}
 
+	_screen->setFont(of);
+
 	return ci;
 }
 
@@ -1618,6 +1718,92 @@ void CharacterGenerator::finish() {
 	}
 }
 
+// TODO: Move to kyra.dat
+const char *CharacterGenerator::_chineseStrings[17] = {
+	nullptr, /* Unused */
+	nullptr, /* Unused */
+	nullptr, /* Unused */
+	nullptr, /* Unused */
+	"\xbb\xeb\xa4\x6c", /* "骰子"; */
+	"\xb0\x68\xa6\x5e", /* "退回" */
+	"\xb1\xb5\xa8\xfc", /* "接受"; */
+	"\xad\xd7\xa7\xef", /* "修改"; */
+	"\xb3\x79\xab\xac", /* "造型"; */
+	"\xa7\xb9\xb2\xa6", /* "完畢"; */
+	"\xa4\x51", /* "十"; */
+	"\xa4\x40", /* "一"; */
+	nullptr, /* Arrow */
+	nullptr, /* Arrow */
+	nullptr, /* Inactive play */
+	nullptr, /* Active play */
+	"\xa7\x52\xb0\xa3", /* "刪除"; */
+};
+
+const int CharacterGenerator::_chineseButtonMapping[17] = {
+	-1,
+	-1,
+	-1,
+	-1,
+	27,
+	41,
+	30,
+	28,
+	29,
+	40,
+	38,
+	39,
+	-1,
+	-1,
+	-1,
+	-1,
+	6,
+};
+
+const EoBChargenButtonDef CharacterGenerator::_chargenButtonDefsDOSChinese[] = {
+	{ 0x01 << 3, 0x37, 0x31, 0x32, 0x70 },
+	{ 0x09 << 3, 0x37, 0x31, 0x32, 0x71 },
+	{ 0x01 << 3, 0x77, 0x31, 0x32, 0x72 },
+	{ 0x09 << 3, 0x77, 0x31, 0x32, 0x73 },
+	{ 0x03 << 3, 0xB5, 0x53, 0x10, 0x1A },
+	{ 190, 64, 35, 18, 0x19 },
+	{ 144, 64, 35, 18, 0x21 },
+	{ 0x21 << 3, 0xAC, 0x26, 0x10, 0x32 },
+	{ 0x13 << 3, 0x50, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x58, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x60, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x68, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x70, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x78, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x80, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x88, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x90, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0x98, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0xA0, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0xA8, 0x9A, 0x08, 0x00 },
+	{ 0x13 << 3, 0xB0, 0x9A, 0x08, 0x00 },
+	{ 0x12 << 3, 0x42, 0x20, 0x10, 0x00 },
+	{ 0x12 << 3, 0x52, 0x20, 0x10, 0x00 },
+	{ 0x16 << 3, 0x42, 0x20, 0x20, 0x00 },
+	{ 0x1A << 3, 0x42, 0x20, 0x20, 0x00 },
+	{ 0x1E << 3, 0x42, 0x20, 0x20, 0x00 },
+	{ 0x22 << 3, 0x42, 0x20, 0x20, 0x00 },
+	{ 144,  64, 35, 18, 0x14 },
+	{ 183,  64, 35, 18, 0x34 },
+	{ 144,  80, 35, 18, 0x22 },
+	{ 183,  80, 35, 18, 0x26 },
+	{ 145, 130, 43, 16, 0x00 },
+	{ 145, 146, 43, 16, 0x00 },
+	{ 145, 162, 43, 16, 0x00 },
+	{ 220, 130, 43, 16, 0x00 },
+	{ 220, 146, 43, 16, 0x00 },
+	{ 220, 162, 43, 16, 0x00 },
+	{ 190, 178, 43, 16, 0x00 },
+	{ 144,  64, 19, 18, 0x0D },
+	{ 167,  64, 19, 18, 0x0C },
+	{ 190,  64, 35, 18, 0x19 },
+	{ 267, 171, 35, 18, 0x00 },
+};
+
 const EoBChargenButtonDef CharacterGenerator::_chargenButtonDefsDOS[] = {
 	{ 0x01 << 3, 0x37, 0x31, 0x32, 0x70 },
 	{ 0x09 << 3, 0x37, 0x31, 0x32, 0x71 },
@@ -1659,7 +1845,8 @@ const EoBChargenButtonDef CharacterGenerator::_chargenButtonDefsDOS[] = {
 	{ 0x1D << 3, 0x88, 0x35, 0x08, 0x00 },
 	{ 0x1B << 3, 0xAC, 0x15, 0x10, 0x0D },
 	{ 0x1E << 3, 0xAC, 0x15, 0x10, 0x0C },
-	{ 0x21 << 3, 0xAC, 0x25, 0x10, 0x19 }
+	{ 0x21 << 3, 0xAC, 0x25, 0x10, 0x19 },
+	{ 264      ,  171,   39,   16, 0    },
 };
 
 const uint16 CharacterGenerator::_chargenButtonKeyCodesFMTOWNS[] = {


Commit: 52b9c910402c7e1dd2ee7dc3e3366e7c38aa47bd
    https://github.com/scummvm/scummvm/commit/52b9c910402c7e1dd2ee7dc3e3366e7c38aa47bd
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Clean field before drawing modify menu

Changed paths:
    engines/kyra/engine/chargen.cpp


diff --git a/engines/kyra/engine/chargen.cpp b/engines/kyra/engine/chargen.cpp
index d1aa677502d..7c8d03980b7 100644
--- a/engines/kyra/engine/chargen.cpp
+++ b/engines/kyra/engine/chargen.cpp
@@ -969,6 +969,7 @@ void CharacterGenerator::generateStats(int index) {
 
 void CharacterGenerator::modifyMenu() {
 	_vm->removeInputTop();
+	_screen->copyRegion(0, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
 	printStats(_activeBox, 3);
 
 	EoBCharacter *c = &_characters[_activeBox];


Commit: 47e981fa8d58d25cf1e1dd0e359253a253de4d06
    https://github.com/scummvm/scummvm/commit/47e981fa8d58d25cf1e1dd0e359253a253de4d06
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Always use drawButton to page 0 rather than 2

This makes it needed for cleaning of the field when buttons are
moved as needed for Chinese EOB2

Changed paths:
    engines/kyra/engine/chargen.cpp


diff --git a/engines/kyra/engine/chargen.cpp b/engines/kyra/engine/chargen.cpp
index 7c8d03980b7..a50871a3bda 100644
--- a/engines/kyra/engine/chargen.cpp
+++ b/engines/kyra/engine/chargen.cpp
@@ -1242,36 +1242,36 @@ void CharacterGenerator::printStats(int index, int mode) {
 		}
 	}
 
+	if (_vm->_flags.platform == Common::kPlatformSegaCD) {
+		_screen->sega_getRenderer()->render(0, 18, 8, 20, 16);
+		if (mode != 4)
+			_screen->drawShape(0, c->faceShape, 208, 66, 0);
+	} else
+		_screen->copyRegion(160, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
+
 	switch (mode) {
 	case 1:
-		drawButton(4, 0, 2);
-		drawButton(7, 0, 2);
-		drawButton(8, 0, 2);
-		drawButton(6, 0, 2);
+		drawButton(4, 0, 0);
+		drawButton(7, 0, 0);
+		drawButton(8, 0, 0);
+		drawButton(6, 0, 0);
 		break;
 
 	case 2:
-		drawButton(16, 0, 2);
-		drawButton(9, 0, 2);
+		drawButton(16, 0, 0);
+		drawButton(9, 0, 0);
 		break;
 
 	case 3:
-		drawButton(10, 0, 2);
-		drawButton(11, 0, 2);
-		drawButton(9, 0, 2);
+		drawButton(10, 0, 0);
+		drawButton(11, 0, 0);
+		drawButton(9, 0, 0);
 		break;
 
 	default:
 		break;
 	}
 
-	if (_vm->_flags.platform == Common::kPlatformSegaCD) {
-		_screen->sega_getRenderer()->render(0, 18, 8, 20, 16);
-		if (mode != 4)
-			_screen->drawShape(0, c->faceShape, 208, 66, 0);
-	} else
-		_screen->copyRegion(160, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
-
 	if (mode != 3)
 		_screen->updateScreen();
 


Commit: a2fb72cf12adc9f12fab6fb8f9773351e1c83039
    https://github.com/scummvm/scummvm/commit/a2fb72cf12adc9f12fab6fb8f9773351e1c83039
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Change height of text input to 15 for Chinese EOB2

Changed paths:
    engines/kyra/gui/gui_eob.cpp


diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index 62b1986b930..1f516c38a1f 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -2824,6 +2824,7 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo
 	uint8 *segaCharBuf = new uint8[destMaxLen << 5]();
 
 	int len = strlen(dest);
+	int height = (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN) ? 15 : 9;
 	if (len > destMaxLen) {
 		len = destMaxLen;
 		dest[destMaxLen] = 0;
@@ -2833,7 +2834,7 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo
 	if (len >= destMaxLen)
 		pos--;
 
-	_screen->copyRegion((x - 1) << 3, y, 0, 191, (destMaxLen + 2) << 3, 9, 0, 2, Screen::CR_NO_P_CHECK);
+	_screen->copyRegion((x - 1) << 3, y, 0, 200 - height, (destMaxLen + 2) << 3, height, 0, 2, Screen::CR_NO_P_CHECK);
 	if (_vm->gameFlags().platform == Common::kPlatformFMTowns)
 		_screen->copyRegion(0, 0, 160, 0, 160, 128, 2, 2, Screen::CR_NO_P_CHECK);
 	_screen->printShadedText(dest, x << 3, y, textColor1, textColor2, _vm->guiSettings()->colors.guiColorBlack);
@@ -2862,10 +2863,10 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo
 					_screen->sega_getRenderer()->render(0, x + pos, y >> 3, 1, 1);
 					_screen->sega_setTextBuffer(0, 0);
 				} else if (cursorState) {
-					_screen->copyRegion((pos + 1) << 3, 191, (x + pos) << 3, y, 8, 9, 2, 0, Screen::CR_NO_P_CHECK);
+					_screen->copyRegion((pos + 1) << 3, 200 - height, (x + pos) << 3, y, 8, height, 2, 0, Screen::CR_NO_P_CHECK);
 					_screen->printShadedText(sufx, (x + pos) << 3, y, textColor1, textColor2, _vm->guiSettings()->colors.guiColorBlack);
 				} else {
-					_screen->fillRect((x + pos) << 3, y, ((x + pos) << 3) + 7, y + 7, cursorColor);
+					_screen->fillRect((x + pos) << 3, y, ((x + pos) << 3) + 7, y + height - 2, cursorColor);
 					_screen->printText(sufx, (x + pos) << 3, y, textColor1, cursorColor);
 				}
 
@@ -2989,7 +2990,7 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo
 			_screen->sega_getRenderer()->render(0, x, y >> 3, destMaxLen, 1);
 			_screen->sega_setTextBuffer(0, 0);
 		} else {
-			_screen->copyRegion(0, 191, (x - 1) << 3, y, (destMaxLen + 2) << 3, 9, 2, 0, Screen::CR_NO_P_CHECK);
+			_screen->copyRegion(0, 200 - height, (x - 1) << 3, y, (destMaxLen + 2) << 3, height, 2, 0, Screen::CR_NO_P_CHECK);
 			_screen->printShadedText(dest, x << 3, y, textColor1, textColor2, _vm->guiSettings()->colors.guiColorBlack);
 		}
 


Commit: 3b9349fd100bf03a2bdfba337037fc4d03f49954
    https://github.com/scummvm/scummvm/commit/3b9349fd100bf03a2bdfba337037fc4d03f49954
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Change layout of text input for Chinese EOB2

Changed paths:
    engines/kyra/engine/chargen.cpp


diff --git a/engines/kyra/engine/chargen.cpp b/engines/kyra/engine/chargen.cpp
index a50871a3bda..549fd0c8005 100644
--- a/engines/kyra/engine/chargen.cpp
+++ b/engines/kyra/engine/chargen.cpp
@@ -714,9 +714,16 @@ void CharacterGenerator::createPartyMember() {
 				if (!_vm->shouldQuit())
 					_vm->_gui->getTextInput(_characters[_activeBox].name, (_chargenBoxX[_activeBox] >> 3) - 1, _chargenBoxY[_activeBox] + 41, 7, 0xFF, 0x00, 0xFF);
 			} else {
+				if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN)
+					_screen->copyRegion(5, 33, 149, 97, 64, 21, 2, 0, Screen::CR_NO_P_CHECK);
 				_screen->printShadedText(_chargenStrings2[11], 149, 100, _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
 				if (!_vm->shouldQuit()) {
-					_vm->_gui->getTextInput(_characters[_activeBox].name, 24, 100, 10, _vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorDarkRed);
+					if (_vm->game() == GI_EOB2 && _vm->gameFlags().lang == Common::Language::ZH_TWN)
+						_vm->_gui->getTextInput(_characters[_activeBox].name, 28, 100, 9,
+									_vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorDarkRed);
+					else
+						_vm->_gui->getTextInput(_characters[_activeBox].name, 24, 100, 10,
+									_vm->guiSettings()->colors.guiColorWhite, 0, _vm->guiSettings()->colors.guiColorDarkRed);
 					processNameInput(_activeBox, _vm->guiSettings()->colors.guiColorBlue);
 				}
 			}


Commit: fb5071e8495dd715165406fd14526814508256b7
    https://github.com/scummvm/scummvm/commit/fb5071e8495dd715165406fd14526814508256b7
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-04-29T13:37:45+02:00

Commit Message:
KYRA: Remove pageNum argument in drawButton

It's now always zero and hence is redundant

Changed paths:
    engines/kyra/engine/chargen.cpp


diff --git a/engines/kyra/engine/chargen.cpp b/engines/kyra/engine/chargen.cpp
index 549fd0c8005..623b783d0e2 100644
--- a/engines/kyra/engine/chargen.cpp
+++ b/engines/kyra/engine/chargen.cpp
@@ -52,7 +52,7 @@ private:
 	void initButtonsFromList(int first, int numButtons);
 	void initButton(int index, const EoBChargenButtonDef *e);
 	void checkForCompleteParty();
-	void drawButton(int index, int buttonState, int pageNum);
+	void drawButton(int index, int buttonState);
 	void processButtonClick(int index);
 	int viewDeleteCharacter();
 	void createPartyMember();
@@ -507,9 +507,9 @@ void CharacterGenerator::checkForCompleteParty() {
 			_screen->setCurPage(0);
 			_screen->copyRegion(168, 61, 152, 125, 136, 40, 2, 0, Screen::CR_NO_P_CHECK);
 		}
-		drawButton(15, 0, 0);
+		drawButton(15, 0);
 	} else {
-		drawButton(14, 0, 0);
+		drawButton(14, 0);
 	}
 
 	if (_vm->gameFlags().platform == Common::kPlatformSegaCD) {
@@ -520,7 +520,7 @@ void CharacterGenerator::checkForCompleteParty() {
 	_screen->updateScreen();
 }
 
-void CharacterGenerator::drawButton(int index, int buttonState, int pageNum) {
+void CharacterGenerator::drawButton(int index, int buttonState) {
 	if (index >= 17)
 		return;
 
@@ -554,13 +554,9 @@ void CharacterGenerator::drawButton(int index, int buttonState, int pageNum) {
 		int x2 = destX;
 		int y2 = destY;
 
-		if (pageNum == 2) {
-			x2 = destX - 144;
-			y2 = destY - 64;
-		}
 		int page = _screen->_curPage;
 
-		_screen->_curPage = pageNum;
+		_screen->_curPage = 0;
 		_screen->set16bitShadingLevel(4);
 		_vm->gui_drawBox(x2, y2, w, h, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, -1);
 		_vm->gui_drawBox(x2 + 1, y2 + 1, w - 2, h - 2, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill);
@@ -568,8 +564,7 @@ void CharacterGenerator::drawButton(int index, int buttonState, int pageNum) {
 		_screen->printShadedText(_chineseStrings[index], x2 + 2, y2 + 2, buttonState ? _vm->guiSettings()->colors.guiColorLightRed : _vm->guiSettings()->colors.guiColorWhite,
 					 0, _vm->guiSettings()->colors.guiColorBlack);
 		_screen->_curPage = page;
-		if (pageNum == 0 || pageNum == 1)
-			_screen->updateScreen();
+		_screen->updateScreen();
 		return;
 	}
 
@@ -579,28 +574,20 @@ void CharacterGenerator::drawButton(int index, int buttonState, int pageNum) {
 	const CreatePartyModButton *c = &_chargenModButtons[index];
 	const EoBRect8 *p = &_chargenButtonBodyCoords[c->bodyIndex + buttonState];
 
-	if (pageNum) {
-		x2 = c->destX + 2;
-		y2 = c->destY - 64;
-	}
-
 	_screen->copyRegion(p->x << 3, p->y, x2 << 3, y2, p->w << 3, p->h, 2, 2, Screen::CR_NO_P_CHECK);
 	if (c->labelW)
 		_screen->drawShape(2, _chargenButtonLabels[index], (x2 << 3) + c->labelX, y2 + c->labelY, 0);
 
-	if (pageNum == 2)
-		return;
-
 	_screen->copyRegion(160, 0, c->destX << 3, c->destY, p->w << 3, p->h, 2, 0, Screen::CR_NO_P_CHECK);
 	_screen->updateScreen();
 }
 
 void CharacterGenerator::processButtonClick(int index) {
-	drawButton(index, 1, 0);
+	drawButton(index, 1);
 	if (!(_vm->game() == GI_EOB1 && _vm->_flags.platform == Common::kPlatformPC98))
 		_vm->snd_playSoundEffect(76);
 	_vm->_system->delayMillis(80);
-	drawButton(index, 0, 0);
+	drawButton(index, 0);
 }
 
 int CharacterGenerator::viewDeleteCharacter() {
@@ -786,7 +773,7 @@ int CharacterGenerator::classMenu(int raceSex) {
 		_screen->printShadedText(_chargenStrings2[9], 147, 67,
 					 _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
 	}
-	drawButton(5, 0, 0);
+	drawButton(5, 0);
 
 	itemsMask &= _classMenuMasks[raceSex / 2];
 	_vm->_gui->simpleMenu_setup(2, 15, _chargenClassStrings, itemsMask, 0, 0, _menuColor1, _menuColor2, _menuColor3);
@@ -849,7 +836,7 @@ int CharacterGenerator::alignmentMenu(int cClass) {
 					 _vm->guiSettings()->colors.guiColorLightBlue, 0, _vm->guiSettings()->colors.guiColorBlack);
 	}
 
-	drawButton(5, 0, 0);
+	drawButton(5, 0);
 
 	itemsMask &= _alignmentMenuMasks[cClass];
 	_vm->_gui->simpleMenu_setup(3, 9, _chargenAlignmentStrings, itemsMask, 0, 0, _menuColor1, _menuColor2, _menuColor3);
@@ -1076,8 +1063,8 @@ void CharacterGenerator::faceSelectMenu() {
 	int8 shp = charSex ? 26 : 0;
 
 	printStats(_activeBox, 4);
-	drawButton(12, 0, 0);
-	drawButton(13, 0, 0);
+	drawButton(12, 0);
+	drawButton(13, 0);
 	_vm->_gui->updateBoxFrameHighLight(-1);
 
 	shp = getNextFreeFaceShape(shp, charSex, 1, _chargenSelectedPortraits);
@@ -1172,7 +1159,7 @@ void CharacterGenerator::processFaceMenuSelection(int index) {
 	if (index <= 48)
 		_screen->drawShape(0, _characters[_activeBox].faceShape, _chargenBoxX[_activeBox], _chargenBoxY[_activeBox] + 1, 0);
 	else
-		drawButton(index - 50, 0, 0);
+		drawButton(index - 50, 0);
 }
 
 void CharacterGenerator::printStats(int index, int mode) {
@@ -1258,21 +1245,21 @@ void CharacterGenerator::printStats(int index, int mode) {
 
 	switch (mode) {
 	case 1:
-		drawButton(4, 0, 0);
-		drawButton(7, 0, 0);
-		drawButton(8, 0, 0);
-		drawButton(6, 0, 0);
+		drawButton(4, 0);
+		drawButton(7, 0);
+		drawButton(8, 0);
+		drawButton(6, 0);
 		break;
 
 	case 2:
-		drawButton(16, 0, 0);
-		drawButton(9, 0, 0);
+		drawButton(16, 0);
+		drawButton(9, 0);
 		break;
 
 	case 3:
-		drawButton(10, 0, 0);
-		drawButton(11, 0, 0);
-		drawButton(9, 0, 0);
+		drawButton(10, 0);
+		drawButton(11, 0);
+		drawButton(9, 0);
 		break;
 
 	default:




More information about the Scummvm-git-logs mailing list