[Scummvm-git-logs] scummvm master -> 5a93dc22750916bed7d752fcbad853b16baa5dba
sev-
sev at scummvm.org
Sun Mar 14 17:52:39 UTC 2021
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
dc5783c910 COMMON: Add String::forEachLine and convertBiDiStringByLines
5a93dc2275 AGI: Add Hebrew support
Commit: dc5783c910428629a9476856c7a9e257af11da05
https://github.com/scummvm/scummvm/commit/dc5783c910428629a9476856c7a9e257af11da05
Author: Zvika Haramaty (haramaty.zvika at gmail.com)
Date: 2021-03-14T18:52:36+01:00
Commit Message:
COMMON: Add String::forEachLine and convertBiDiStringByLines
`convertBiDiStringByLines` calls the BiDi algo for each line in isolation,
and returns a joined result.
That's needed to support BiDi in AGI, and might be needed for other engines
in the future.
In order to do that, a new utility function was added:
`String::forEachLine` which gets a function as input, and its arg(s) (if it has any),
and calls the function on each line, and returns a new string which is all
concatenation of all the lines results (with '\n' added between them).
Changed paths:
common/str.cpp
common/str.h
common/unicode-bidi.cpp
common/unicode-bidi.h
diff --git a/common/str.cpp b/common/str.cpp
index e1171a9511..98bdac2a14 100644
--- a/common/str.cpp
+++ b/common/str.cpp
@@ -410,6 +410,27 @@ String String::substr(size_t pos, size_t len) const {
return String(_str + pos, MIN((size_t)_size - pos, len));
}
+String String::forEachLine(String(*func)(const String, va_list args), ...) const {
+ String result = "";
+ size_t index = findFirstOf('\n', 0);
+ size_t prev_index = 0;
+ va_list args;
+ va_start(args, func);
+ while (index != -1) {
+ String textLine = substr(prev_index, index - prev_index);
+ textLine = (*func)(textLine, args);
+ result = result + textLine + '\n';
+ prev_index = index + 1;
+ index = findFirstOf('\n', index + 1);
+ }
+
+ String textLine = substr(prev_index);
+ textLine = (*func)(textLine, args);
+ result = result + textLine;
+ va_end(args);
+ return result;
+}
+
#pragma mark -
bool operator==(const char* y, const String &x) {
diff --git a/common/str.h b/common/str.h
index ff8a0b3dae..ca0a3e886f 100644
--- a/common/str.h
+++ b/common/str.h
@@ -242,6 +242,9 @@ public:
/** Return a substring of this string */
String substr(size_t pos = 0, size_t len = npos) const;
+ /** Calls func on each line of the string, and returns a joined string */
+ String forEachLine(String(*func)(const String, va_list args), ...) const;
+
/** Python-like method **/
U32String decode(CodePage page = kUtf8) const;
diff --git a/common/unicode-bidi.cpp b/common/unicode-bidi.cpp
index 44f8ca2cc1..b03b03d72a 100644
--- a/common/unicode-bidi.cpp
+++ b/common/unicode-bidi.cpp
@@ -38,6 +38,12 @@ UnicodeBiDiText::UnicodeBiDiText(const Common::String &str, const Common::CodePa
initWithU32String(str.decode(page));
}
+UnicodeBiDiText::UnicodeBiDiText(const Common::String &str, const Common::CodePage page, uint *pbase_dir) : logical(str), _log_to_vis_index(NULL), _vis_to_log_index(NULL) {
+ _pbase_dir = *pbase_dir;
+ initWithU32String(str.decode(page));
+ *pbase_dir = _pbase_dir;
+}
+
UnicodeBiDiText::~UnicodeBiDiText() {
delete[] _log_to_vis_index;
delete[] _vis_to_log_index;
@@ -64,13 +70,12 @@ void UnicodeBiDiText::initWithU32String(const U32String &input) {
FriBidiChar *visual_str = new FriBidiChar[buff_length * sizeof(FriBidiChar)];
_log_to_vis_index = new uint32[input_size];
_vis_to_log_index = new uint32[input_size];
- FriBidiParType pbase_dir = FRIBIDI_PAR_ON;
if (!fribidi_log2vis(
/* input */
(const FriBidiChar *)input.c_str(),
input_size,
- &pbase_dir,
+ &_pbase_dir,
/* output */
visual_str,
(FriBidiStrIndex *)_log_to_vis_index, // position_L_to_V_list,
@@ -99,6 +104,17 @@ void UnicodeBiDiText::initWithU32String(const U32String &input) {
}
+Common::String bidiByLineHelper(Common::String line, va_list args) {
+ Common::CodePage page = va_arg(args, Common::CodePage);
+ uint32 *pbase_dir = va_arg(args, uint32*);
+ return UnicodeBiDiText(line, page, pbase_dir).visual.encode(page);
+}
+
+String convertBiDiStringByLines(const String &input, const Common::CodePage page) {
+ uint32 pbase_dir = SCUMMVM_FRIBIDI_PAR_ON;
+ return input.forEachLine(bidiByLineHelper, page, &pbase_dir);
+}
+
String convertBiDiString(const String &input, const Common::Language lang) {
if (lang != Common::HE_ISR) //TODO: modify when we'll support other RTL languages, such as Arabic and Farsi
return input;
diff --git a/common/unicode-bidi.h b/common/unicode-bidi.h
index 6c7465489c..a24fad16ca 100644
--- a/common/unicode-bidi.h
+++ b/common/unicode-bidi.h
@@ -27,6 +27,21 @@
#include "common/ustr.h"
#include "common/language.h"
+
+// SCUMMVM_FRIBIDI_PAR_ON: automatically check the text's direction
+// SCUMMVM_FRIBIDI_PAR_LTR, SCUMMVM_FRIBIDI_PAR_RTL: enforce LTR or RTL direction
+// if not USE_FRIBIDI, these defines values don't matter
+#ifdef USE_FRIBIDI
+#define SCUMMVM_FRIBIDI_PAR_ON FRIBIDI_PAR_ON
+#define SCUMMVM_FRIBIDI_PAR_LTR FRIBIDI_PAR_LTR
+#define SCUMMVM_FRIBIDI_PAR_RTL FRIBIDI_PAR_RTL
+#else
+#define SCUMMVM_FRIBIDI_PAR_ON 0
+#define SCUMMVM_FRIBIDI_PAR_LTR 0
+#define SCUMMVM_FRIBIDI_PAR_RTL 0
+#endif
+
+
namespace Common {
class UnicodeBiDiText {
@@ -34,12 +49,15 @@ private:
uint32 *_log_to_vis_index; // from fribidi conversion
uint32 *_vis_to_log_index; // from fribidi conversion
void initWithU32String(const Common::U32String &str);
+ Common::String bidiByLine(Common::String line, va_list args);
public:
const Common::U32String logical; // original string, ordered logically
Common::U32String visual; // from fribidi conversion, ordered visually
+ uint32 _pbase_dir;
UnicodeBiDiText(const Common::U32String &str);
UnicodeBiDiText(const Common::String &str, const Common::CodePage page);
+ UnicodeBiDiText(const Common::String &str, const Common::CodePage page, uint *pbase_dir);
~UnicodeBiDiText();
/**
@@ -57,6 +75,9 @@ UnicodeBiDiText convertBiDiU32String(const U32String &input);
String convertBiDiString(const String &input, const Common::Language lang);
String convertBiDiString(const String &input, const Common::CodePage page);
+// calls convertBiDiString for each line in isolation
+String convertBiDiStringByLines(const String &input, const Common::CodePage page);
+
} // End of namespace Common
#endif
Commit: 5a93dc22750916bed7d752fcbad853b16baa5dba
https://github.com/scummvm/scummvm/commit/5a93dc22750916bed7d752fcbad853b16baa5dba
Author: Zvika Haramaty (haramaty.zvika at gmail.com)
Date: 2021-03-14T18:52:36+01:00
Commit Message:
AGI: Add Hebrew support
Changed paths:
engines/agi/agi.h
engines/agi/detection_tables.h
engines/agi/inv.cpp
engines/agi/keyboard.cpp
engines/agi/loader_v2.cpp
engines/agi/menu.cpp
engines/agi/metaengine.cpp
engines/agi/saveload.cpp
engines/agi/systemui.cpp
engines/agi/text.cpp
engines/agi/text.h
engines/agi/words.cpp
engines/agi/words.h
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index f6d4b10ca4..504f52e5f8 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -734,6 +734,7 @@ public:
uint16 getVersion() const;
uint16 getGameType() const;
Common::Language getLanguage() const;
+ bool isLanguageRTL() const;
Common::Platform getPlatform() const;
const char *getGameMD5() const;
void initFeatures();
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index 068403aa0d..6b6f71195e 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -545,6 +545,9 @@ static const AGIGameDescription gameDescriptions[] = {
// not sure about disk format -- dsymonds
GAME("pq1", "2.0G 1987-12-03", "d194e5d88363095f55d5096b8e32fbbb", 0x2917, GID_PQ1),
+ // Police Quest 1 (PC) 2.0G 12/3/87; with Hebrew translation
+ GAME_LVFPN("pq1", "2.0G 1987-12-03", "PQ1.WAG", "59e1b2fb6d025968b8ed7388f107c7b5", -1, Common::HE_ISR, 0x2917, 0, GID_PQ1, Common::kPlatformDOS, GType_V2, GAMEOPTIONS_DEFAULT),
+
// Police Quest 1 (CoCo3 360k) [AGI 2.023]
GAME_PS("pq1", "", "28a077041f75aab78f66804800940085", 375, 0x2440, GID_PQ1, Common::kPlatformCoCo3),
diff --git a/engines/agi/inv.cpp b/engines/agi/inv.cpp
index 834fa9badc..4df55527a1 100644
--- a/engines/agi/inv.cpp
+++ b/engines/agi/inv.cpp
@@ -65,9 +65,20 @@ void InventoryMgr::getPlayerInventory() {
inventoryEntry.name = _vm->objectName(objectNr);
inventoryEntry.row = curRow;
inventoryEntry.column = curColumn;
- if (inventoryEntry.column > 1) {
- // right side, adjust column accordingly
- inventoryEntry.column -= strlen(inventoryEntry.name);
+ if (!_vm->isLanguageRTL()) {
+ if (inventoryEntry.column > 1) {
+ // right side, adjust column accordingly
+ inventoryEntry.column -= Common::strnlen(inventoryEntry.name, FONT_COLUMN_CHARACTERS);
+ }
+ } else {
+ // mirror the sides
+ if (inventoryEntry.column == 1) {
+ // right side, adjust column accordingly
+ inventoryEntry.column = FONT_COLUMN_CHARACTERS - 1 - Common::strnlen(inventoryEntry.name, FONT_COLUMN_CHARACTERS);
+ } else {
+ // left side, adjust column accordingly
+ inventoryEntry.column = 1;
+ }
}
_array.push_back(inventoryEntry);
@@ -187,10 +198,16 @@ void InventoryMgr::keyPress(uint16 newKey) {
changeActiveItem(+2);
break;
case AGI_KEY_LEFT:
- changeActiveItem(-1);
+ if (!_vm->isLanguageRTL())
+ changeActiveItem(-1);
+ else
+ changeActiveItem(+1);
break;
case AGI_KEY_RIGHT:
- changeActiveItem(+1);
+ if (!_vm->isLanguageRTL())
+ changeActiveItem(+1);
+ else
+ changeActiveItem(-1);
break;
default:
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 0f86438907..d1ad572c73 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -141,6 +141,11 @@ void AgiEngine::processScummVMEvents() {
}
}
+ if (_game._vm->getLanguage() == Common::HE_ISR && key >= 0x05d0 && key <= 0x05ea) {
+ // convert to WIN-1255
+ key = key - 0x05d0 + 0xe0;
+ }
+
if ((key) && (key <= 0xFF)) {
// No special key, directly accept it
// Is ISO-8859-1, we need lower 128 characters only, which is plain ASCII, so no mapping required
diff --git a/engines/agi/loader_v2.cpp b/engines/agi/loader_v2.cpp
index ddc8df3f2d..fed17ac11a 100644
--- a/engines/agi/loader_v2.cpp
+++ b/engines/agi/loader_v2.cpp
@@ -276,7 +276,10 @@ int AgiLoader_v2::loadObjects(const char *fname) {
}
int AgiLoader_v2::loadWords(const char *fname) {
- return _vm->_words->loadDictionary(fname);
+ if (_vm->getLanguage() != Common::HE_ISR)
+ return _vm->_words->loadDictionary(fname);
+ else
+ return _vm->_words->loadExtendedDictionary(fname);
}
} // End of namespace Agi
diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp
index 1d5366da5a..743de33045 100644
--- a/engines/agi/menu.cpp
+++ b/engines/agi/menu.cpp
@@ -41,7 +41,10 @@ GfxMenu::GfxMenu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture, TextMgr *text)
_delayedExecuteViaKeyboard = false;
_delayedExecuteViaMouse = false;
- _setupMenuColumn = 1;
+ if (!_vm->isLanguageRTL())
+ _setupMenuColumn = 1;
+ else
+ _setupMenuColumn = FONT_COLUMN_CHARACTERS - 2;
_setupMenuItemColumn = 1;
_lastSelectedMenuNr = 0;
@@ -82,26 +85,33 @@ void GfxMenu::addMenu(const char *menuText) {
menuEntry->textLen = menuEntry->text.size();
- // Cut menu name in case menu bar is full
- // Happens in at least the fan game Get Outta Space Quest
- // Original interpreter had graphical issues in this case
- // TODO: this whole code needs to get reworked anyway to support different types of menu bars depending on platform
- curColumnEnd += menuEntry->textLen;
- while ((menuEntry->textLen) && (curColumnEnd > 40)) {
- menuEntry->text.deleteLastChar();
- menuEntry->textLen--;
- curColumnEnd--;
+ if (!_vm->isLanguageRTL()) {
+ // Cut menu name in case menu bar is full
+ // Happens in at least the fan game Get Outta Space Quest
+ // Original interpreter had graphical issues in this case
+ // TODO: this whole code needs to get reworked anyway to support different types of menu bars depending on platform
+ curColumnEnd += menuEntry->textLen;
+ while ((menuEntry->textLen) && (curColumnEnd > 40)) {
+ menuEntry->text.deleteLastChar();
+ menuEntry->textLen--;
+ curColumnEnd--;
+ }
}
menuEntry->row = 0;
menuEntry->column = _setupMenuColumn;
+ if (_vm->isLanguageRTL())
+ menuEntry->column -= menuEntry->textLen;
menuEntry->itemCount = 0;
menuEntry->firstItemNr = _itemArray.size();
menuEntry->selectedItemNr = menuEntry->firstItemNr;
menuEntry->maxItemTextLen = 0;
_array.push_back(menuEntry);
- _setupMenuColumn += menuEntry->textLen + 1;
+ if (!_vm->isLanguageRTL())
+ _setupMenuColumn += menuEntry->textLen + 1;
+ else
+ _setupMenuColumn -= menuEntry->textLen + 1;
}
void GfxMenu::addMenuItem(const char *menuItemText, uint16 controllerSlot) {
@@ -132,11 +142,17 @@ void GfxMenu::addMenuItem(const char *menuItemText, uint16 controllerSlot) {
}
if (curMenuEntry->itemCount == 0) {
- // for first menu item of menu calculated column
- if (menuItemEntry->textLen + curMenuEntry->column < (FONT_COLUMN_CHARACTERS - 1)) {
- _setupMenuItemColumn = curMenuEntry->column;
+ if (!_vm->isLanguageRTL()) {
+ // for first menu item of menu calculated column
+ if (menuItemEntry->textLen + curMenuEntry->column < (FONT_COLUMN_CHARACTERS - 1)) {
+ _setupMenuItemColumn = curMenuEntry->column;
+ } else {
+ _setupMenuItemColumn = (FONT_COLUMN_CHARACTERS - 1) - menuItemEntry->textLen;
+ }
} else {
- _setupMenuItemColumn = (FONT_COLUMN_CHARACTERS - 1) - menuItemEntry->textLen;
+ _setupMenuItemColumn = curMenuEntry->column + curMenuEntry->textLen - menuItemEntry->textLen;
+ if (_setupMenuItemColumn < 2)
+ _setupMenuItemColumn = 2;
}
}
@@ -520,10 +536,16 @@ void GfxMenu::keyPress(uint16 newKey) {
break;
case AGI_KEY_LEFT:
- newMenuNr--;
+ if (!_vm->isLanguageRTL())
+ newMenuNr--;
+ else
+ newMenuNr++;
break;
case AGI_KEY_RIGHT:
- newMenuNr++;
+ if (!_vm->isLanguageRTL())
+ newMenuNr++;
+ else
+ newMenuNr--;
break;
case AGI_KEY_HOME:
// select first menu
diff --git a/engines/agi/metaengine.cpp b/engines/agi/metaengine.cpp
index d91099f85c..a1d9b5c162 100644
--- a/engines/agi/metaengine.cpp
+++ b/engines/agi/metaengine.cpp
@@ -55,7 +55,16 @@ Common::Platform AgiBase::getPlatform() const {
}
Common::Language AgiBase::getLanguage() const {
- return _gameDescription->desc.language;
+ if (_gameDescription->desc.language != Common::UNK_LANG)
+ return _gameDescription->desc.language;
+ else if (ConfMan.hasKey("language"))
+ return Common::parseLanguage(ConfMan.get("language"));
+ else
+ return Common::UNK_LANG;
+}
+
+bool AgiBase::isLanguageRTL() const {
+ return getLanguage() == Common::HE_ISR;
}
uint16 AgiBase::getVersion() const {
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index c781f00d7c..cca2c8b0e6 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -85,11 +85,20 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
out->writeUint32BE(AGIflag);
+ const char *descriptionStringC;
+ Common::U32String hebDesc;
+ if (_game._vm->getLanguage() != Common::HE_ISR) {
+ descriptionStringC = descriptionString.c_str();
+ } else {
+ hebDesc = descriptionString.substr(0, SAVEDGAME_DESCRIPTION_LEN / 2 - 3).decode(Common::kWindows1255);
+ descriptionStringC = hebDesc.encode(Common::kUtf8).c_str();
+ }
+
// Write description of saved game, limited to SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL
char description[SAVEDGAME_DESCRIPTION_LEN + 1];
memset(description, 0, sizeof(description));
- strncpy(description, descriptionString.c_str(), SAVEDGAME_DESCRIPTION_LEN);
+ Common::strlcpy(description, descriptionStringC, SAVEDGAME_DESCRIPTION_LEN);
assert(SAVEDGAME_DESCRIPTION_LEN + 1 == 31); // safety
out->write(description, 31);
@@ -927,6 +936,10 @@ bool AgiEngine::getSavegameInformation(int16 slotId, Common::String &saveDescrip
saveDescription += saveGameDescription;
saveIsValid = true;
+ if (_game._vm->getLanguage() == Common::HE_ISR) {
+ saveDescription = saveDescription.decode(Common::kUtf8).encode(Common::kWindows1255);
+ }
+
delete in;
return true;
}
diff --git a/engines/agi/systemui.cpp b/engines/agi/systemui.cpp
index f2304ea623..0eb54752b9 100644
--- a/engines/agi/systemui.cpp
+++ b/engines/agi/systemui.cpp
@@ -102,6 +102,26 @@ SystemUI::SystemUI(AgiEngine *vm, GfxMgr *gfx, TextMgr *text) {
_textRestoreGameError = "\x8E\xE8\xA8\xA1\xAA\xA0 \xA2 \xA7\xA0\xAF\xA8\xE1\xA0\xAD\xAD\xAE\xA9 \xA8\xA3\xE0\xA5.\nENTER - \xA2\xEB\xE5\xAE\xA4.";
_textRestoreGameVerify = "\x83\xAE\xE2\xAE\xA2 \xAA \xE1\xE7\xA8\xE2\xEB\xA2\xA0\xAD\xA8\xEE \xA8\xA3\xE0\xEB\x2C\n\xAE\xAF\xA8\xE1\xA0\xAD\xAD\xAE\xA9 \xAA\xA0\xAA.\n\n%s\n\n\xA8\xA7 \xE4\xA0\xA9\xAB\xA0:\n%s\n\n\x84\xAB\xEF \xAF\xE0\xAE\xA4\xAE\xAB\xA6\xA5\xAD\xA8\xEF \xAD\xA0\xA6\xAC\xA8\xE2\xA5 ENTER.\nESC - \xAE\xE2\xAC\xA5\xAD\xA0.";
break;
+ case Common::HE_ISR:
+ _textStatusScore = "\xf0\xe9\xf7\xe5\xe3: %v3 \xee\xfa\xe5\xea %v7";
+ _textStatusSoundOn = "\xf6\xec\xe9\xec: \xf4\xe5\xf2\xec";
+ _textStatusSoundOff = "\xf6\xec\xe9\xec: \xeb\xe1\xe5\xe9";
+ _textEnterCommand = "\xe4\xeb\xf0\xe9\xf1\xe5 \xf7\xec\xe8\n\n";
+ _textPause = " \xe4\xee\xf9\xe7\xf7 \xee\xe5\xf9\xe4\xe4.\n\xec\xe7\xf6\xe5 \xf2\xec ENTER \xeb\xe3\xe9 \xec\xe4\xee\xf9\xe9\xea.";
+ _textRestart = "\xec\xe7\xf6\xe5 \xf2\xec ENTER \xeb\xe3\xe9 \xec\xe4\xfa\xe7\xe9\xec \xee\xe7\xe3\xf9\n\xe0\xfa \xe4\xee\xf9\xe7\xf7.\n\n\xec\xe7\xf6\xe5 \xf2\xec ESC \xeb\xe3\xe9 \xec\xe4\xee\xf9\xe9\xea\n\xe0\xfa \xe4\xee\xf9\xe7\xf7 \xe4\xf0\xe5\xeb\xe7\xe9.";
+ _textQuit = "\xec\xe7\xf6\xe5 \xf2\xec ENTER \xec\xe9\xf6\xe9\xe0\xe4.\n\xec\xe7\xf6\xe5 \xf2\xec ESC \xeb\xe3\xe9 \xec\xe4\xee\xf9\xe9\xea \xec\xf9\xe7\xf7.";
+ _textInventoryYouAreCarrying = "\xe0\xfa\xe4 \xf0\xe5\xf9\xe0:";
+ _textInventoryNothing = "\xec\xe0 \xeb\xec\xe5\xed";
+ _textInventorySelectItems = "\xec\xe7\xf6\xe5 \xf2\xec ENTER \xeb\xe3\xe9 \xec\xe1\xe7\xe5\xf8, ESC \xeb\xe3\xe9 \xec\xe1\xe8\xec";
+ _textInventoryReturnToGame = "\xec\xe7\xf6\xe5 \xf2\xec \xee\xf7\xf9 \xeb\xec\xf9\xe4\xe5 \xeb\xe3\xe9 \xec\xe7\xe6\xe5\xf8 \xec\xee\xf9\xe7\xf7";
+ _textSaveGameSelectSlot = "\xe4\xf9\xfa\xee\xf9\xe5 \xe1\xee\xf7\xf9\xe9 \xe4\xe7\xe9\xf6\xe9\xed \xf2\xec \xee\xf0\xfa \xec\xe1\xe7\xe5\xf8 \xee\xf9\xe1\xf6\xfa \xf9\xe1\xe4 \xfa\xf8\xf6\xe5 \xec\xf9\xee\xe5\xf8 \xe0\xfa \xe4\xee\xf9\xe7\xf7. \xec\xe7\xf6\xe5 \xf2\xec ENTER \xec\xf9\xee\xe9\xf8\xfa \xee\xf9\xe7\xf7 \xe1\xee\xf9\xe1\xf6\xfa, ESC \xec\xe1\xe9\xe8\xe5\xec.";
+ _textSaveGameEnterDescription = "\xe0\xe9\xea \xfa\xf8\xf6\xe5 \xec\xfa\xe0\xf8 \xe0\xfa \xe4\xee\xf9\xe7\xf7 \xe4\xf9\xee\xe5\xf8 \xe4\xe6\xe4?\n\n";
+ _textSaveGameVerify = "\xe1\xe7\xf8\xfa \xec\xf9\xee\xe5\xf8 \xe0\xfa \xe4\xee\xf9\xe7\xf7\n\xf2\xed \xe4\xfa\xe9\xe0\xe5\xf8:\n\n%s\n\n\xe1\xf7\xe5\xe1\xf5:\n%s\n\n\xec\xe7\xf6\xe5 \xf2\xec ENTER \xec\xe4\xee\xf9\xea.\n\xec\xe7\xf6\xe5 \xf2\xec ESC \xec\xe1\xe9\xe8\xe5\xec.";
+ _textRestoreGameNoSlots = "\xe0\xe9\xef \xee\xf9\xe7\xf7\xe9\xed\n\xec\xf9\xe7\xe6\xf8\n\n \xe1\xf1\xf4\xf8\xe9\xe9\xfa \xe4\xee\xf9\xe7\xf7\xe9\xed \xe4\xf9\xee\xe5\xf8\xe9\xed \xf9\xec ScummVM\n\n\xec\xe7\xf6\xe5 \xf2\xec ENTER \xeb\xe3\xe9 \xec\xe4\xee\xf9\xe9\xea.";
+ _textRestoreGameSelectSlot = "\xe4\xf9\xfa\xee\xf9\xe5 \xe1\xee\xf7\xf9\xe9 \xe4\xe7\xe9\xf6\xe9\xed \xf2\xec \xee\xf0\xfa \xec\xe1\xe7\xe5\xf8 \xe0\xfa \xe4\xee\xf9\xe7\xf7 \xf9\xfa\xf8\xf6\xe5 \xec\xf9\xe7\xe6\xf8. \xec\xe7\xf6\xe5 \xf2\xec ENTER \xec\xf9\xe7\xe6\xe5\xf8 \xe4\xee\xf9\xe7\xf7, ESC \xec\xe1\xe9\xe8\xe5\xec.";
+ _textRestoreGameError = "\xf9\xe2\xe9\xe0\xe4 \xe1\xf0\xe9\xf1\xe9\xe5\xef \xec\xf9\xe7\xe6\xe5\xf8 \xee\xf9\xe7\xf7.\n\xec\xe7\xf6\xe5 \xf2\xec ENTER \xec\xe9\xf6\xe9\xe0\xe4.";
+ _textRestoreGameVerify = "\xe1\xe7\xf8\xfa \xec\xf9\xe7\xe6\xf8 \xe0\xfa \xe4\xee\xf9\xe7\xf7\n\xf2\xed \xe4\xfa\xe9\xe0\xe5\xf8:\n\n%s\n\n\xee\xe4\xf7\xe5\xe1\xf5:\n%s\n\n\xec\xe7\xf6\xe5 \xf2\xec ENTER \xec\xe4\xee\xf9\xea.\n\xec\xe7\xf6\xe5 \xf2\xec ESC \xec\xe1\xe9\xe8\xe5\xec.";
+ break;
default:
break;
}
@@ -723,8 +743,13 @@ void SystemUI::drawSavedGameSlots() {
_text->charAttrib_Set(0, 15);
for (slotNr = 0; slotNr < slotsToDrawCount; slotNr++) {
- _text->displayTextInsideWindow("-", 5 + slotNr, 1);
- _text->displayTextInsideWindow(_savedGameArray[_savedGameUpmostSlotNr + slotNr].displayText, 5 + slotNr, 3);
+ if (!_vm->isLanguageRTL()) {
+ _text->displayTextInsideWindow("-", 5 + slotNr, 1);
+ _text->displayTextInsideWindow(_savedGameArray[_savedGameUpmostSlotNr + slotNr].displayText, 5 + slotNr, 3);
+ } else {
+ _text->displayTextInsideWindow(_savedGameArray[_savedGameUpmostSlotNr + slotNr].displayText, 5 + slotNr, 0);
+ _text->displayTextInsideWindow("-", 5 + slotNr, 32);
+ }
}
_text->charAttrib_Pop();
}
@@ -734,10 +759,19 @@ void SystemUI::drawSavedGameSlotSelector(bool active) {
_text->charAttrib_Push();
_text->charAttrib_Set(0, 15);
+ int16 column;
+ const char *arrow;
+ if (!_vm->isLanguageRTL()) {
+ column = 0;
+ arrow = "\x1a";
+ } else {
+ column = 33;
+ arrow = "\x1b";
+ }
if (active) {
- _text->displayTextInsideWindow("\x1a", windowRow, 0);
+ _text->displayTextInsideWindow(arrow, windowRow, column);
} else {
- _text->displayTextInsideWindow(" ", windowRow, 0);
+ _text->displayTextInsideWindow(" ", windowRow, column);
}
_text->charAttrib_Pop();
}
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index bfc4ff4519..5e332ab8da 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -21,6 +21,7 @@
*/
#include "common/config-manager.h"
+#include "common/unicode-bidi.h"
#include "agi/agi.h"
#include "agi/sprite.h" // for commit_both()
#include "agi/graphics.h"
@@ -274,7 +275,27 @@ void TextMgr::displayTextInsideWindow(const char *textPtr, int16 windowRow, int1
charPos_Pop();
}
+Common::String rightAlign(Common::String line, va_list args) {
+ uint width = va_arg(args, uint);
+
+ while (line.size() < width)
+ line = " " + line;
+ return line;
+}
+
void TextMgr::displayText(const char *textPtr, bool disabledLook) {
+ Common::String textString;
+ if (_vm->isLanguageRTL()) {
+ textString = textPtr;
+ if (_vm->getLanguage() == Common::HE_ISR)
+ textString = Common::convertBiDiStringByLines(textString, Common::kWindows1255);
+
+ if (textString.contains('\n'))
+ textString = textString.forEachLine(rightAlign, (uint)_messageState.textSize_Width);
+
+ textPtr = textString.c_str();
+ }
+
const char *curTextPtr = textPtr;
byte curCharacter = 0;
@@ -563,11 +584,17 @@ void TextMgr::statusDraw() {
clearLine(_statusRow, 15);
charAttrib_Set(0, 15);
- charPos_Set(_statusRow, 1);
statusTextPtr = stringPrintf(_systemUI->getStatusTextScore());
+ if (!_vm->isLanguageRTL())
+ charPos_Set(_statusRow, 1);
+ else
+ charPos_Set(_statusRow, FONT_COLUMN_CHARACTERS - Common::strnlen(statusTextPtr, FONT_COLUMN_CHARACTERS) - 1);
displayText(statusTextPtr);
- charPos_Set(_statusRow, 30);
+ if (!_vm->isLanguageRTL())
+ charPos_Set(_statusRow, 30);
+ else
+ charPos_Set(_statusRow, 1);
if (_vm->getFlag(VM_FLAG_SOUND_ON)) {
statusTextPtr = stringPrintf(_systemUI->getStatusTextSoundOn());
} else {
@@ -684,6 +711,7 @@ void TextMgr::promptKeyPress(uint16 newKey) {
// but as soon as invalid characters were used in graphics mode they weren't properly shown
switch (_vm->getLanguage()) {
case Common::RU_RUS:
+ case Common::HE_ISR:
if (newKey >= 0x20)
acceptableInput = true;
break;
@@ -721,6 +749,8 @@ void TextMgr::promptKeyPress(uint16 newKey) {
_promptCursorPos--;
_prompt[_promptCursorPos] = 0;
displayCharacter(newKey);
+ if (_vm->isLanguageRTL())
+ promptRedraw();
promptRememberForAutoComplete();
}
@@ -750,6 +780,8 @@ void TextMgr::promptKeyPress(uint16 newKey) {
_promptCursorPos++;
_prompt[_promptCursorPos] = 0;
displayCharacter(newKey);
+ if (_vm->isLanguageRTL())
+ promptRedraw();
promptRememberForAutoComplete();
}
@@ -810,9 +842,17 @@ void TextMgr::promptRedraw() {
textPtr = stringPrintf(textPtr);
textPtr = stringWordWrap(textPtr, 40);
- displayText(textPtr);
- displayText((char *)&_prompt);
- inputEditOff();
+ if (!_vm->isLanguageRTL()) {
+ displayText(textPtr);
+ displayText((char *)&_prompt);
+ inputEditOff();
+ } else {
+ charPos_Set(_promptRow, FONT_COLUMN_CHARACTERS - 2 - Common::strnlen((const char *)_prompt, FONT_COLUMN_CHARACTERS));
+ inputEditOff();
+ displayText((char *)&_prompt);
+ displayText(textPtr);
+ charPos_Set(_promptRow, FONT_COLUMN_CHARACTERS - 1);
+ }
}
}
@@ -889,9 +929,21 @@ void TextMgr::stringEdit(int16 stringMaxLen) {
// Caller can set the input string
_inputStringCursorPos = 0;
- while (_inputStringCursorPos < inputStringLen) {
- displayCharacter(_inputString[_inputStringCursorPos]);
- _inputStringCursorPos++;
+ if (!_vm->isLanguageRTL()) {
+ while (_inputStringCursorPos < inputStringLen) {
+ displayCharacter(_inputString[_inputStringCursorPos]);
+ _inputStringCursorPos++;
+ }
+ } else {
+ while (_inputStringCursorPos < inputStringLen)
+ _inputStringCursorPos++;
+ if (stringMaxLen == 30)
+ // called from askForSaveGameDescription
+ charPos_Set(_textPos.row, 34 - _inputStringCursorPos);
+ else
+ charPos_Set(_textPos.row, stringMaxLen + 2 - _inputStringCursorPos);
+ inputEditOff();
+ displayText((const char *)_inputString);
}
// should never happen unless there is a coding glitch
@@ -900,7 +952,8 @@ void TextMgr::stringEdit(int16 stringMaxLen) {
_inputStringMaxLen = stringMaxLen;
_inputStringEntered = false;
- inputEditOff();
+ if (!_vm->isLanguageRTL())
+ inputEditOff();
do {
_vm->processAGIEvents();
@@ -932,6 +985,13 @@ void TextMgr::stringKeyPress(uint16 newKey) {
_inputStringCursorPos--;
_inputString[_inputStringCursorPos] = 0;
displayCharacter(newKey);
+ if (_vm->isLanguageRTL()) {
+ for (int i = 0; i < _inputStringCursorPos; i++)
+ displayCharacter(0x08);
+ displayCharacter(' ');
+ inputEditOff();
+ displayText((const char *)_inputString);
+ }
stringRememberForAutoComplete();
}
@@ -965,6 +1025,7 @@ void TextMgr::stringKeyPress(uint16 newKey) {
// but as soon as invalid characters were used in graphics mode they weren't properly shown
switch (_vm->getLanguage()) {
case Common::RU_RUS:
+ case Common::HE_ISR:
if (newKey >= 0x20)
acceptableInput = true;
break;
@@ -981,7 +1042,14 @@ void TextMgr::stringKeyPress(uint16 newKey) {
_inputString[_inputStringCursorPos] = newKey;
_inputStringCursorPos++;
_inputString[_inputStringCursorPos] = 0;
- displayCharacter(newKey);
+ if (!_vm->isLanguageRTL()) {
+ displayCharacter(newKey);
+ } else {
+ for(int i = 0; i < _inputStringCursorPos ; i++)
+ displayCharacter(0x08);
+ inputEditOff();
+ displayText((const char *)_inputString);
+ }
stringRememberForAutoComplete();
}
diff --git a/engines/agi/text.h b/engines/agi/text.h
index f0aeab7762..5ad6b5afa7 100644
--- a/engines/agi/text.h
+++ b/engines/agi/text.h
@@ -212,6 +212,8 @@ public:
char *stringWordWrap(const char *originalText, int16 maxWidth, int16 *calculatedWidthPtr = nullptr, int16 *calculatedHeightPtr = nullptr);
};
+Common::String rightAlign(Common::String line, va_list args);
+
} // End of namespace Agi
#endif /* AGI_TEXT_H */
diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index 2e34e1c410..92e6dcd138 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -123,6 +123,32 @@ int Words::loadDictionary(const char *fname) {
return errOK;
}
+int Words::loadExtendedDictionary(const char *sierraFname) {
+ Common::String fnameStr = Common::String(sierraFname) + ".extended";
+ const char *fname = fnameStr.c_str();
+
+ Common::File fp;
+
+ if (!fp.open(fname)) {
+ warning("loadWords: can't open %s", fname);
+ return errOK; // err_BadFileOpen
+ }
+ debug(0, "Loading dictionary: %s", fname);
+
+ // skip the header
+ fp.readString('\n');
+
+ while (!fp.eos() && !fp.err()) {
+ WordEntry *newWord = new WordEntry;
+ newWord->word = fp.readString();
+ newWord->id = atoi(fp.readString('\n').c_str());
+ if(!newWord->word.empty())
+ _dictionaryWords[(byte)newWord->word[0] - 'a'].push_back(newWord);
+ }
+
+ return errOK;
+}
+
void Words::unloadDictionary() {
for (int16 firstCharNr = 0; firstCharNr < 26; firstCharNr++) {
Common::Array<WordEntry *> &dictionary = _dictionaryWords[firstCharNr];
@@ -226,7 +252,9 @@ int16 Words::findWordInDictionary(const Common::String &userInputLowcased, uint1
foundWordLen = 0;
- if ((firstChar >= 'a') && (firstChar <= 'z')) {
+ const byte lastCharInAbc = _vm->getLanguage() == Common::HE_ISR ? 0xfa : 'z';
+
+ if ((firstChar >= 'a') && (firstChar <= lastCharInAbc)) {
// word has to start with a letter
if (((userInputPos + 1) < userInputLen) && (userInputLowcased[userInputPos + 1] == ' ')) {
// current word is 1 char only?
diff --git a/engines/agi/words.h b/engines/agi/words.h
index 96dafae275..d067b6fade 100644
--- a/engines/agi/words.h
+++ b/engines/agi/words.h
@@ -42,7 +42,8 @@ private:
AgiEngine *_vm;
// Dictionary
- Common::Array<WordEntry *> _dictionaryWords[26];
+ // 158 = 255 - 'a' ; that's allows us to support extended character set, and does no harm for regular English games
+ Common::Array<WordEntry *> _dictionaryWords[158];
WordEntry _egoWords[MAX_WORDS];
uint16 _egoWordCount;
@@ -54,6 +55,8 @@ public:
int loadDictionary_v1(Common::File &f);
int loadDictionary(const char *fname);
+ // used for fan made translations requiring extended char set
+ int loadExtendedDictionary(const char *fname);
void unloadDictionary();
void clearEgoWords();
More information about the Scummvm-git-logs
mailing list