[Scummvm-git-logs] scummvm master -> 9f10fbcfc1e70f733b04b26e5812514fd02fea80
bluegr
bluegr at gmail.com
Mon May 25 00:22:04 UTC 2020
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:
6ab0cb78e0 SCI: Improve vm_hooks ; Support Hebrew SQ3
9f10fbcfc1 SCI: Hebrew SQ3 - fixed rejects
Commit: 6ab0cb78e0c14da5bdc8ae2df43155304e15def8
https://github.com/scummvm/scummvm/commit/6ab0cb78e0c14da5bdc8ae2df43155304e15def8
Author: Zvika Haramaty (haramaty.zvika at gmail.com)
Date: 2020-05-25T03:21:59+03:00
Commit Message:
SCI: Improve vm_hooks ; Support Hebrew SQ3
- vm_hooks: fully support 'call*'
- make required changes to support Hebrew SQ3 (which is still a WIP
project)
Changed paths:
engines/sci/detection_tables.h
engines/sci/engine/script_patches.cpp
engines/sci/engine/vm.cpp
engines/sci/engine/vm_hooks.cpp
engines/sci/engine/vm_hooks.h
engines/sci/event.cpp
engines/sci/graphics/controls16.cpp
engines/sci/graphics/menu.cpp
engines/sci/graphics/text16.cpp
engines/sci/parser/vocabulary.cpp
engines/sci/parser/vocabulary.h
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 3388ecb970..2b333d47bc 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -4785,6 +4785,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO_STD16_UNDITHER },
+ // Space Quest 3 - Hebrew DOS (from the Space Quest Collection)
+ // Executable scanning reports "0.000.685", VERSION file reports "1.018"
+ // This translation is still a work in progress
+ { "sq3", "", {
+ {"resource.map", 0, "55e91aeef1705bce2a9b79172682f36d", 5730},
+ {"resource.001", 0, "8b55c4875298f45ea5696a5ee8f6a7fe", 490247},
+ {"resource.002", 0, "8b55c4875298f45ea5696a5ee8f6a7fe", 715777},
+ {"resource.003", 0, "8b55c4875298f45ea5696a5ee8f6a7fe", 703370},
+ {"PATCHES/font.000", 0, "6fab182f1c071d1ed47be27776964baf", 3334},
+ AD_LISTEND},
+ Common::HE_ISR, Common::kPlatformDOS, 0, GUIO_STD16_UNDITHER },
+
+
// Space Quest 3 - English DOS 6 x 360k Floppy (from misterhands, bug report Trac #10677 and goodoldgeorge, bug report Trac #10636)
// Executable scanning reports "0.000.685", VERSION file reports "1.018"
{"sq3", "", {
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 302c0a4634..2ab4e7cade 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -15842,6 +15842,42 @@ static const SciScriptPatcherEntry qfg4Signatures[] = {
#endif
+// Space Quest 3 has some strings hard coded in the scripts file
+// We need to patch them for the Hebrew translation
+
+// Replace "Enter input" prompt with Hebrew
+static const uint16 sq3HebrewEnterInputSignature[] = {
+ SIG_MAGICDWORD,
+ 0x45, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0,
+ SIG_END
+};
+
+static const uint16 sq3HebrewEnterInputPatch[] = {
+ 0xe4, 0xf7, 0xf9, 0x20, 0xf4, 0xf7, 0xe5, 0xe3, 0xe4, 0x3a, 0,
+ PATCH_END
+};
+
+// Replace "Space Quest ]I[" in status bar with Hebrew
+static const uint16 sq3HebrewStatusBarNameSignature[] = {
+ SIG_MAGICDWORD,
+ 0x53, 0x70, 0x61, 0x63, 0x65, 0x20, 0x51, 0x75, 0x65, 0x73, 0x74, 0x20, 0x0b, // "Space Quest " + special ]I[ char
+ SIG_END
+};
+
+static const uint16 sq3HebrewStatusBarNamePatch[] = {
+ 0xee, 0xf1, 0xf2, 0x20, 0xe1, 0xe7, 0xec, 0xec, 0x20, 0x0b, 0x20, 0x20, 0x20, // 'Space Quest' in Hebrew: 'Masa Bahalal ' + special ]I[ char
+ PATCH_END
+};
+
+// script, description, signature patch
+static const SciScriptPatcherEntry sq3Signatures[] = {
+ { false, 0, "Hebrew: Replace name in status bar", 1, sq3HebrewStatusBarNameSignature, sq3HebrewStatusBarNamePatch },
+ { false, 996, "Hebrew: Replace 'Enter input' prompt", 1, sq3HebrewEnterInputSignature, sq3HebrewEnterInputPatch },
+ SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+
+
// ===========================================================================
// script 298 of sq4/floppy has an issue. object "nest" uses another property
// which isn't included in property count. We return 0 in that case, so that
@@ -19140,6 +19176,9 @@ void ScriptPatcher::processScript(uint16 scriptNr, SciSpan<byte> scriptData) {
case GID_SQ1:
signatureTable = sq1vgaSignatures;
break;
+ case GID_SQ3:
+ signatureTable = sq3Signatures;
+ break;
case GID_SQ4:
signatureTable = sq4Signatures;
break;
@@ -19216,6 +19255,12 @@ void ScriptPatcher::processScript(uint16 scriptNr, SciSpan<byte> scriptData) {
enablePatch(signatureTable, "Floppy: fix peer bats, upper door (2/2)");
}
break;
+ case GID_SQ3:
+ if (g_sci->getLanguage() == Common::HE_ISR) {
+ enablePatch(signatureTable, "Hebrew: Replace name in status bar");
+ enablePatch(signatureTable, "Hebrew: Replace 'Enter input' prompt");
+ }
+ break;
case GID_SQ4:
// Enable the dress-purchase flag fixes for English Amiga only.
// One of these patches is applied to scripts that are the same as those
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index b7259d6140..99ba2ae177 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -664,7 +664,7 @@ void run_vm(EngineState *s) {
// Get opcode
byte extOpcode;
- if (!vmHooks.isActive())
+ if (!vmHooks.isActive(s))
s->xs->addr.pc.incOffset(readPMachineInstruction(scr->getBuf(s->xs->addr.pc.getOffset()), extOpcode, opparams));
else {
int offset = readPMachineInstruction(vmHooks.data(), extOpcode, opparams);
@@ -804,7 +804,7 @@ void run_vm(EngineState *s) {
case op_bt: // 0x17 (23)
// Branch relative if true
- if (!vmHooks.isActive()) {
+ if (!vmHooks.isActive(s)) {
if (s->r_acc.getOffset() || s->r_acc.getSegment())
s->xs->addr.pc.incOffset(opparams[0]);
@@ -819,7 +819,7 @@ void run_vm(EngineState *s) {
case op_bnt: // 0x18 (24)
// Branch relative if not true
- if (!vmHooks.isActive()) {
+ if (!vmHooks.isActive(s)) {
if (!(s->r_acc.getOffset() || s->r_acc.getSegment()))
s->xs->addr.pc.incOffset(opparams[0]);
@@ -833,7 +833,7 @@ void run_vm(EngineState *s) {
break;
case op_jmp: // 0x19 (25)
- if (!vmHooks.isActive()) {
+ if (!vmHooks.isActive(s)) {
s->xs->addr.pc.incOffset(opparams[0]);
if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize())
diff --git a/engines/sci/engine/vm_hooks.cpp b/engines/sci/engine/vm_hooks.cpp
index c4e2b46524..63608f4553 100644
--- a/engines/sci/engine/vm_hooks.cpp
+++ b/engines/sci/engine/vm_hooks.cpp
@@ -22,6 +22,7 @@
#include "common/hashmap.h"
#include "common/array.h"
+#include "common/language.h"
#include "sci/engine/vm_hooks.h"
#include "sci/engine/vm.h"
#include "sci/engine/state.h"
@@ -35,7 +36,8 @@ namespace Sci {
* This mechanism allows inserting new instructions, and not only replace existing code.
* Note that when using hooks, the regular PC is frozen, and doesn't advance.
* Therefore, 'jmp', 'bt' and 'bnt' are used to locally move around inside the patch.
- * call* opcodes can be used - but they should be last executed opcode, in order to successfully transfer control.
+ *
+ * (In the past there was a warning regarding 'call's - but they should work now)
*
******************************************************************************************************************/
@@ -68,6 +70,60 @@ static const byte qfg1_die_after_running_on_ice[] = {
0x47, 0x00, 0x01, 0x10 // calle proc0_1
};
+
+// SCI0 Hebrew translations need to modify and relocate the "Enter input:" prompt
+// currently SQ3 is the only Hebrew SCI0 game, but this patch (or similar) should work for the future games as well
+
+static const byte sci0_hebrew_input_prompt[] = {
+ // in (procedure (Print ...
+ // ...
+ // (#edit
+ // (++ paramCnt)
+ // adding:
+ // (hDText moveTo: 104 4)
+ // (= hDText (DText new:))
+ // (hDText
+ // text: ''
+ // moveTo: 4 4
+ // font: gDefaultFont
+ // setSize:
+ // )
+ // (hDialog add: hDText)
+ 0x38, 0x92, 0, // pushi #moveTo
+ 0x39, 2, // pushi 2
+ 0x38, 210, 0, // pushi 220 ;x
+ 0x39, 4, // pushi 4 ;y
+ 0x85, 1, // lat temp1
+ 0x4a, 8, // send 8
+ 0x38, 0x59, 0, // pushi #new
+ 0x39, 0, // pushi 0
+ 0x51, 0xd, // class DText
+ 0x4a, 4, // send 4
+ 0xa5, 1, // sat temp1
+ 0x39, 0x1a, // pushi #text
+ 0x39, 1, // pushi 1
+ 0x75, 25, // lofss '' ; that location has '\0'
+ 0x38, 146, 0, // pushi 146
+ 0x39, 2, // pushi 2
+ 0x39, 4, // pushi 4 ;x
+ 0x39, 14, // pushi 12 ;y
+ 0x39, 33, // pushi 33
+ 0x39, 1, // pushi 1
+ 0x89, 0x16, // lsg global22
+ 0x38, 144, 0, // pushi 144
+ 0x39, 0, // pushi 0
+ 0x85, 1, // lat temp1
+ 0x4a, 24, // send 24
+ 0x38, 0x64, 0, // pushi #add
+ 0x39, 1, // pushi 1
+ 0x8d, 1, // lst temp1
+ 0x85, 0, // lat temp0
+ 0x4a, 6, // send 6
+ 0x85, 5 // lat temp5
+};
+
+
+
/** Write here all games hooks
* From this we'll build _hooksMap, which contains only relevant hooks to current game
* The match is performed according to PC, script number, opcode (only opcode name, as seen in ScummVM debugger),
@@ -76,9 +132,11 @@ static const byte qfg1_die_after_running_on_ice[] = {
* - external function ID (and then selector is "")
* = in that case, if objName == "" it will be ignored, otherwise, it will be also used to match
*/
+
static const GeneralHookEntry allGamesHooks[] = {
- // GID, script, PC.offset, objName, selector, externID, opcode, hook array
- {GID_QFG1, {58, 0x144d}, {"egoRuns", "changeState", -1 , "push0", HOOKARRAY(qfg1_die_after_running_on_ice)}}
+ // GID, script, lang, PC.offset, objName, selector, externID, opcode, hook array
+ {GID_QFG1, Common::UNK_LANG, {58, 0x144d}, {"egoRuns", "changeState", -1 , "push0", HOOKARRAY(qfg1_die_after_running_on_ice)}},
+ {GID_SQ3, Common::HE_ISR, {255, 0x1103}, {"User", "", -1 , "pushi", HOOKARRAY(sci0_hebrew_input_prompt)}}
};
@@ -86,10 +144,12 @@ VmHooks::VmHooks() {
// build _hooksMap
for (uint i = 0; i < ARRAYSIZE(allGamesHooks); i++) {
if (allGamesHooks[i].gameId == g_sci->getGameId())
- _hooksMap.setVal(allGamesHooks[i].key, allGamesHooks[i].entry);
+ if (allGamesHooks[i].language == g_sci->getLanguage() || allGamesHooks[i].language == Common::UNK_LANG)
+ _hooksMap.setVal(allGamesHooks[i].key, allGamesHooks[i].entry);
}
_lastPc = NULL_REG;
+ _just_finished = false;
_location = 0;
}
@@ -120,12 +180,16 @@ bool hook_exec_match(Sci::EngineState *s, HookEntry entry) {
s->xs->debugExportId == entry.exportId && strcmp(entry.opcodeName, opcodeNames[opcode]) == 0;
}
-
void VmHooks::vm_hook_before_exec(Sci::EngineState *s) {
+ if (_just_finished) {
+ _just_finished = false;
+ _lastPc = NULL_REG;
+ return;
+ }
Script *scr = s->_segMan->getScript(s->xs->addr.pc.getSegment());
int scriptNumber = scr->getScriptNumber();
HookHashKey key = { scriptNumber, s->xs->addr.pc.getOffset() };
- if (_lastPc != s->xs->addr.pc && _hooksMap.contains(key)) {
+ if (_hookScriptData.empty() && _lastPc != s->xs->addr.pc && _hooksMap.contains(key)) {
_lastPc = s->xs->addr.pc;
HookEntry entry = _hooksMap[key];
if (hook_exec_match(s, entry)) {
@@ -143,8 +207,9 @@ byte *VmHooks::data() {
return _hookScriptData.data() + _location;
}
-bool VmHooks::isActive() {
- return !_hookScriptData.empty();
+bool VmHooks::isActive(Sci::EngineState *s) {
+ // if PC has changed, then we're temporary inactive - went to some other call, or send, etc.
+ return !_hookScriptData.empty() && _lastPc == s->xs->addr.pc;
}
void VmHooks::advance(int offset) {
@@ -155,6 +220,7 @@ void VmHooks::advance(int offset) {
error("VmHooks: requested to change offset after end of patch");
else if ((uint)newLocation == _hookScriptData.size()) {
_hookScriptData.clear();
+ _just_finished = true;
_location = 0;
} else
_location = newLocation;
diff --git a/engines/sci/engine/vm_hooks.h b/engines/sci/engine/vm_hooks.h
index 5c5e699d53..274a0d8816 100644
--- a/engines/sci/engine/vm_hooks.h
+++ b/engines/sci/engine/vm_hooks.h
@@ -61,6 +61,7 @@ struct HookEntry {
/** Used for allGamesHooks - from it we build the specific _hooksMap */
struct GeneralHookEntry {
SciGameId gameId;
+ Common::Language language; // language to be patched. UNK_LANG means to patch all languages
HookHashKey key;
HookEntry entry;
};
@@ -80,7 +81,7 @@ public:
byte *data();
- bool isActive();
+ bool isActive(Sci::EngineState *s);
void advance(int offset);
@@ -90,9 +91,12 @@ private:
Common::Array<byte> _hookScriptData;
- /** Used to avoid double patching in row */
+ /** Used to avoid double patching in row, and to support `call`ing */
reg_t _lastPc;
+ /** Used to avoid double patching in row */
+ bool _just_finished;
+
/** Location inside patch */
int _location;
};
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 65f563ea6f..cfbfdb3585 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -375,6 +375,10 @@ SciEvent EventManager::getScummVMEvent() {
input.character = 0x80 + i;
break;
}
+ } else if (g_sci->getLanguage() == Common::HE_ISR) {
+ if (input.character >= 0x05d0 && input.character <= 0x05ea)
+ // convert to WIN-1255
+ input.character = input.character - 0x05d0 + 0xe0;
}
}
diff --git a/engines/sci/graphics/controls16.cpp b/engines/sci/graphics/controls16.cpp
index 08906c03a0..ce50d59ba1 100644
--- a/engines/sci/graphics/controls16.cpp
+++ b/engines/sci/graphics/controls16.cpp
@@ -113,10 +113,16 @@ void GfxControls16::texteditCursorDraw(Common::Rect rect, const char *text, uint
for (i = 0; i < curPos; i++) {
textWidth += _text16->_font->getCharWidth((unsigned char)text[i]);
}
- _texteditCursorRect.left = rect.left + textWidth;
+ if (!g_sci->isLanguageRTL())
+ _texteditCursorRect.left = rect.left + textWidth;
+ else
+ _texteditCursorRect.right = rect.right - textWidth;
_texteditCursorRect.top = rect.top;
_texteditCursorRect.bottom = _texteditCursorRect.top + _text16->_font->getHeight();
- _texteditCursorRect.right = _texteditCursorRect.left + (text[curPos] == 0 ? 1 : _text16->_font->getCharWidth((unsigned char)text[curPos]));
+ if (!g_sci->isLanguageRTL())
+ _texteditCursorRect.right = _texteditCursorRect.left + (text[curPos] == 0 ? 1 : _text16->_font->getCharWidth((unsigned char)text[curPos]));
+ else
+ _texteditCursorRect.left = _texteditCursorRect.right - (text[curPos] == 0 ? 1 : _text16->_font->getCharWidth((unsigned char)text[curPos]));
_paint16->invertRect(_texteditCursorRect);
_paint16->bitsShow(_texteditCursorRect);
_texteditCursorVisible = true;
@@ -184,13 +190,25 @@ void GfxControls16::kernelTexteditChange(reg_t controlObject, reg_t eventObject)
cursorPos = textSize; textChanged = true;
break;
case kSciKeyLeft:
- if (cursorPos > 0) {
- cursorPos--; textChanged = true;
+ if (!g_sci->isLanguageRTL()) {
+ if (cursorPos > 0) {
+ cursorPos--; textChanged = true;
+ }
+ } else {
+ if (cursorPos + 1 <= textSize) {
+ cursorPos++; textChanged = true;
+ }
}
break;
case kSciKeyRight:
- if (cursorPos + 1 <= textSize) {
- cursorPos++; textChanged = true;
+ if (!g_sci->isLanguageRTL()) {
+ if (cursorPos + 1 <= textSize) {
+ cursorPos++; textChanged = true;
+ }
+ } else {
+ if (cursorPos > 0) {
+ cursorPos--; textChanged = true;
+ }
}
break;
case kSciKeyEtx:
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index b1ebbc71e5..d85f87e790 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -355,12 +355,24 @@ void GfxMenu::drawBar() {
_paint16->fillRect(_ports->_menuBarRect, 1, _screen->getColorWhite());
_paint16->fillRect(_ports->_menuLine, 1, 0);
_ports->penColor(0);
- _ports->moveTo(8, 1);
+ if (!g_sci->isLanguageRTL())
+ _ports->moveTo(8, 1);
+ else
+ _ports->moveTo(_screen->getWidth() - 8, 1);
listIterator = _list.begin();
while (listIterator != listEnd) {
listEntry = *listIterator;
+ int16 textWidth;
+ int16 textHeight;
+ if (g_sci->isLanguageRTL()) {
+ _text16->StringWidth(listEntry->textSplit.c_str(), _text16->GetFontId(), textWidth, textHeight);
+ _ports->_curPort->curLeft -= textWidth;
+ }
+ int16 origCurLeft = _ports->_curPort->curLeft;
_text16->DrawString(listEntry->textSplit.c_str());
+ if (g_sci->isLanguageRTL())
+ _ports->_curPort->curLeft = origCurLeft;
listIterator++;
}
@@ -584,19 +596,35 @@ void GfxMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) {
_menuRect.top = _ports->_menuBarRect.bottom;
menuTextRect.top = _ports->_menuBarRect.top;
menuTextRect.bottom = _ports->_menuBarRect.bottom;
- menuTextRect.left = menuTextRect.right = 7;
+ if (!g_sci->isLanguageRTL())
+ menuTextRect.left = menuTextRect.right = 7;
+ else
+ menuTextRect.left = menuTextRect.right = _ports->_menuBarRect.right - 7;
listIterator = _list.begin();
while (listIterator != listEnd) {
listEntry = *listIterator;
listNr++;
- menuTextRect.left = menuTextRect.right;
- menuTextRect.right += listEntry->textWidth;
- if (listNr == newMenuId)
- _menuRect.left = menuTextRect.left;
+ if (!g_sci->isLanguageRTL()) {
+ menuTextRect.left = menuTextRect.right;
+ menuTextRect.right += listEntry->textWidth;
+ if (listNr == newMenuId)
+ _menuRect.left = menuTextRect.left;
+ } else {
+ menuTextRect.right = menuTextRect.left;
+ menuTextRect.left -= listEntry->textWidth;
+ if (listNr == newMenuId)
+ _menuRect.right = menuTextRect.right;
+ }
if ((listNr == newMenuId) || (listNr == oldMenuId)) {
- menuTextRect.translate(1, 0);
- _paint16->invertRect(menuTextRect);
- menuTextRect.translate(-1, 0);
+ if (!g_sci->isLanguageRTL()) {
+ menuTextRect.translate(1, 0);
+ _paint16->invertRect(menuTextRect);
+ menuTextRect.translate(-1, 0);
+ } else {
+ menuTextRect.translate(-1, 0);
+ _paint16->invertRect(menuTextRect);
+ menuTextRect.translate(1, 0);
+ }
}
listIterator++;
@@ -614,16 +642,26 @@ void GfxMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) {
}
listItemIterator++;
}
- _menuRect.right = _menuRect.left + 16 + 4 + 2;
- _menuRect.right += maxTextWidth + maxTextRightAlignedWidth;
- if (!maxTextRightAlignedWidth)
- _menuRect.right -= 5;
+ if (!g_sci->isLanguageRTL()) {
+ _menuRect.right = _menuRect.left + 16 + 4 + 2;
+ _menuRect.right += maxTextWidth + maxTextRightAlignedWidth;
+ if (!maxTextRightAlignedWidth)
+ _menuRect.right -= 5;
+ } else {
+ _menuRect.left = _menuRect.right - (16 + 4 + 2);
+ _menuRect.left -= (maxTextWidth + maxTextRightAlignedWidth);
+ if (!maxTextRightAlignedWidth)
+ _menuRect.left += 5;
+ }
// If part of menu window is outside the screen, move it into the screen
// (this happens in multilingual sq3 and lsl3).
if (_menuRect.right > _screen->getWidth()) {
_menuRect.translate(-(_menuRect.right - _screen->getWidth()), 0);
}
+ if (_menuRect.left < 0) {
+ warning("GfxMenu::drawMenu: _menuRect.left < 0");
+ }
// Save background
_menuSaveHandle = _paint16->bitsSave(_menuRect, GFX_SCREEN_MASK_VISUAL);
@@ -633,7 +671,10 @@ void GfxMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) {
_menuRect.left++; _menuRect.right--; _menuRect.bottom--;
_paint16->fillRect(_menuRect, GFX_SCREEN_MASK_VISUAL, _screen->getColorWhite());
- _menuRect.left += 8;
+ if (!g_sci->isLanguageRTL())
+ _menuRect.left += 8;
+ else
+ _menuRect.right -= 8;
topPos = _menuRect.top + 1;
listItemIterator = _itemList.begin();
while (listItemIterator != listItemEnd) {
@@ -641,10 +682,17 @@ void GfxMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) {
if (listItemEntry->menuId == newMenuId) {
if (!listItemEntry->separatorLine) {
_ports->textGreyedOutput(!listItemEntry->enabled);
- _ports->moveTo(_menuRect.left, topPos);
- _text16->DrawString(listItemEntry->textSplit.c_str());
- _ports->moveTo(_menuRect.right - listItemEntry->textRightAlignedWidth - 5, topPos);
- _text16->DrawString(listItemEntry->textRightAligned.c_str());
+ if (!g_sci->isLanguageRTL()) {
+ _ports->moveTo(_menuRect.left, topPos);
+ _text16->DrawString(listItemEntry->textSplit.c_str());
+ _ports->moveTo(_menuRect.right - listItemEntry->textRightAlignedWidth - 5, topPos);
+ _text16->DrawString(listItemEntry->textRightAligned.c_str());
+ } else {
+ _ports->moveTo(_menuRect.left + 5, topPos);
+ _text16->DrawString(listItemEntry->textRightAligned.c_str());
+ _ports->moveTo(_menuRect.right - listItemEntry->textWidth, topPos);
+ _text16->DrawString(listItemEntry->textSplit.c_str());
+ }
} else {
// We dont 100% follow sierra here, we draw the line from left to right. Looks better
// BTW. SCI1.1 seems to put 2 pixels and then skip one, we don't do this at all (lsl6)
@@ -664,8 +712,16 @@ void GfxMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) {
// Draw the black line again
_paint16->fillRect(_ports->_menuLine, 1, 0);
- _menuRect.left -= 8;
- _menuRect.left--; _menuRect.right++; _menuRect.bottom++;
+ if (!g_sci->isLanguageRTL()) {
+ _menuRect.left -= 8;
+ _menuRect.left--;
+ _menuRect.right++;
+ } else {
+ _menuRect.right += 8;
+ _menuRect.right--;
+ _menuRect.left++;
+ }
+ _menuRect.bottom++;
_paint16->bitsShow(_menuRect);
}
@@ -701,15 +757,26 @@ uint16 GfxMenu::mouseFindMenuSelection(Common::Point mousePosition) {
GuiMenuEntry *listEntry;
GuiMenuList::iterator listIterator;
GuiMenuList::iterator listEnd = _list.end();
- uint16 curXstart = 8;
+ uint16 curXstart;
+ if (!g_sci->isLanguageRTL())
+ curXstart = 8;
+ else
+ curXstart = _screen->getWidth() - 8;
listIterator = _list.begin();
while (listIterator != listEnd) {
listEntry = *listIterator;
- if (mousePosition.x >= curXstart && mousePosition.x < curXstart + listEntry->textWidth) {
- return listEntry->id;
+ if (!g_sci->isLanguageRTL()) {
+ if (mousePosition.x >= curXstart && mousePosition.x < curXstart + listEntry->textWidth) {
+ return listEntry->id;
+ }
+ curXstart += listEntry->textWidth;
+ } else {
+ if (mousePosition.x <= curXstart && mousePosition.x > curXstart - listEntry->textWidth) {
+ return listEntry->id;
+ }
+ curXstart -= listEntry->textWidth;
}
- curXstart += listEntry->textWidth;
listIterator++;
}
return 0;
@@ -787,10 +854,22 @@ GuiMenuItemEntry *GfxMenu::interactiveWithKeyboard() {
}
break;
case kSciKeyLeft:
- newMenuId--; newItemId = 1;
+ if (!g_sci->isLanguageRTL()) {
+ newMenuId--;
+ newItemId = 1;
+ } else {
+ newMenuId++;
+ newItemId = 1;
+ }
break;
case kSciKeyRight:
- newMenuId++; newItemId = 1;
+ if (!g_sci->isLanguageRTL()) {
+ newMenuId++;
+ newItemId = 1;
+ } else {
+ newMenuId--;
+ newItemId = 1;
+ }
break;
case kSciKeyUp:
newItemId--;
@@ -952,7 +1031,14 @@ void GfxMenu::kernelDrawStatus(const char *text, int16 colorPen, int16 colorBack
_paint16->fillRect(_ports->_menuBarRect, 1, colorBack);
_ports->penColor(colorPen);
- _ports->moveTo(0, 1);
+ if (!g_sci->isLanguageRTL()) {
+ _ports->moveTo(0, 1);
+ } else {
+ int16 textWidth;
+ int16 textHeight;
+ _text16->StringWidth(text, _text16->GetFontId(), textWidth, textHeight);
+ _ports->moveTo(_screen->getWidth() - textWidth, 1);
+ }
_text16->DrawStatus(text);
_paint16->bitsShow(_ports->_menuBarRect);
// Also draw the line under the status bar. Normally, this is never drawn,
diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp
index 8aba5587f2..eccbf49806 100644
--- a/engines/sci/graphics/text16.cpp
+++ b/engines/sci/graphics/text16.cpp
@@ -22,6 +22,7 @@
#include "common/util.h"
#include "common/stack.h"
+#include "common/unicode-bidi.h"
#include "graphics/primitives.h"
#include "sci/sci.h"
@@ -559,22 +560,56 @@ void GfxText16::Box(const char *text, uint16 languageSplitter, bool show, const
break;
Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, true);
maxTextWidth = MAX<int16>(maxTextWidth, textWidth);
- switch (alignment) {
- case SCI_TEXT16_ALIGNMENT_RIGHT:
- offset = rect.width() - textWidth;
- break;
- case SCI_TEXT16_ALIGNMENT_CENTER:
- offset = (rect.width() - textWidth) / 2;
- break;
- case SCI_TEXT16_ALIGNMENT_LEFT:
- offset = 0;
- break;
+ if (!g_sci->isLanguageRTL()) {
+ switch (alignment) {
+ case SCI_TEXT16_ALIGNMENT_RIGHT:
+ offset = rect.width() - textWidth;
+ break;
+ case SCI_TEXT16_ALIGNMENT_CENTER:
+ offset = (rect.width() - textWidth) / 2;
+ break;
+ case SCI_TEXT16_ALIGNMENT_LEFT:
+ offset = 0;
+ break;
- default:
- warning("Invalid alignment %d used in TextBox()", alignment);
+ default:
+ warning("Invalid alignment %d used in TextBox()", alignment);
+ }
+ } else {
+ // language direction is from Right to Left
+ switch (alignment) {
+ case SCI_TEXT16_ALIGNMENT_LEFT:
+ offset = rect.width() - textWidth;
+ break;
+ case SCI_TEXT16_ALIGNMENT_CENTER:
+ offset = (rect.width() - textWidth) / 2;
+ break;
+ case SCI_TEXT16_ALIGNMENT_RIGHT:
+ offset = 0;
+ break;
+
+ default:
+ warning("Invalid alignment %d used in TextBox()", alignment);
+ }
+
+ // in the fonts, the characters have some spacing to the left, and no space to the right
+ // therefore, when we start drawing from the right, they "start from the border"
+ // e.g., in SQ3 Hebrew user's input prompt
+ // we can't make the Hebrew letters spacing in the right (in the font), because then mixed English-Hebrew text
+ // might have 2 letters stick together
+ // therefore, we shift here one pixel to the left, for the spacing
+ offset--;
}
_ports->moveTo(rect.left + offset, rect.top + hline);
+ Common::String textString;
+ if (g_sci->isLanguageRTL()) {
+ const char *curTextLineOrig = curTextLine;
+ Common::String textLogical = Common::String(curTextLineOrig, (uint32)charCount);
+ textString = Common::convertBiDiString(textLogical, g_sci->getLanguage()); //TODO: maybe move to Draw()?
+ curTextLine = textString.c_str();
+ }
+
if (show) {
Show(curTextLine, 0, charCount, fontId, previousPenColor);
} else {
@@ -618,8 +653,15 @@ void GfxText16::DrawString(const Common::String &text) {
// we need to have a separate status drawing code
// In KQ4 the IV char is actually 0xA, which would otherwise get considered as linebreak and not printed
-void GfxText16::DrawStatus(const Common::String &str) {
+void GfxText16::DrawStatus(const Common::String &strOrig) {
uint16 curChar, charWidth;
+
+ Common::String str;
+ if (!g_sci->isLanguageRTL())
+ str = strOrig;
+ else
+ str = Common::convertBiDiString(strOrig, g_sci->getLanguage());
+
const byte *text = (const byte *)str.c_str();
uint16 textLen = str.size();
Common::Rect rect;
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index 6699ed25b8..2c8739e272 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -116,7 +116,8 @@ bool Vocabulary::loadParserWords() {
}
// If all of them were empty, we are definitely seeing SCI01 vocab in disguise (e.g. pq2 japanese)
if (alphabetNr == 26) {
- warning("SCI0: Found SCI01 vocabulary in disguise");
+ if (g_sci->getLanguage() != Common::HE_ISR)
+ warning("SCI0: Found SCI01 vocabulary in disguise");
resourceType = kVocabularySCI1;
}
}
@@ -250,10 +251,38 @@ bool Vocabulary::loadSuffixes() {
_parserSuffixes.push_back(suffix);
}
+ appendSuffixes();
return true;
}
+void Vocabulary::appendSuffixes() {
+ if (g_sci->getLanguage() == Common::HE_ISR) {
+ for (int i = 0; i < 2; i++) {
+ int cls;
+ if (i == 0)
+ cls = VOCAB_CLASS_PREPOSITION << 4;
+ else
+ cls = VOCAB_CLASS_NOUN << 4;
+
+ suffix_t suffix1 = { cls, cls, 1, 0, "\xea", "" }; // get rid of Kaf Sofit
+ _parserSuffixes.push_back(suffix1);
+
+ suffix_t suffix2 = { cls, cls, 2, 0, "\xe9\xed", "" }; // get rid of Yud, Mem Sofit
+ _parserSuffixes.push_back(suffix2);
+
+ suffix_t suffix3 = { cls, cls, 2, 0, "\xe5\xfa", "" }; // get rid of Vav, Taf
+ _parserSuffixes.push_back(suffix3);
+
+ suffix_t suffix4 = { cls, cls, 3, 2, "\xe9\xe5\xfa", "\xe9\xfa" }; // Yud, Vav, Taf -> Yud, Taf
+ _parserSuffixes.push_back(suffix4);
+
+ suffix_t suffix5 = { cls, cls, 3, 2, "\xe0\xe5\xfa", "\xe0\xe4" }; // Alef, Vav, Taf -> Alef, He
+ _parserSuffixes.push_back(suffix5);
+ }
+ }
+}
+
void Vocabulary::freeSuffixes() {
Resource* resource = _resMan->findResource(ResourceId(kResourceTypeVocab, _resourceIdSuffixes), false);
if (resource)
@@ -482,6 +511,42 @@ void Vocabulary::lookupWord(ResultWordList& retval, const char *word, int word_l
}
}
+void Vocabulary::lookupWordPrefix(ResultWordListList &parent_retval, ResultWordList &retval, const char *word, int word_len) {
+ // currently, this is needed only for Hebrew translation
+ if (g_sci->getLanguage() != Common::HE_ISR)
+ return;
+
+ if (--word_len <= 0)
+ return;
+
+ if (lookupSpecificPrefix(parent_retval, retval, word, word_len, 0xe1, "1hebrew1prefix1bet")) // "Bet"
+ return;
+ if (lookupSpecificPrefix(parent_retval, retval, word, word_len, 0xe4, "the")) // "He Hayedia"
+ return;
+ if (lookupSpecificPrefix(parent_retval, retval, word, word_len, 0xec, "1hebrew1prefix1lamed")) // "Lamed"
+ return;
+ if (lookupSpecificPrefix(parent_retval, retval, word, word_len, 0xee, "1hebrew1prefix1mem")) // "Mem"
+ return;
+}
+
+bool Vocabulary::lookupSpecificPrefix(ResultWordListList &parent_retval, ResultWordList &retval, const char *word, int word_len, unsigned char prefix, const char *meaning) {
+ if (!_parserWords.contains(meaning)) {
+ warning("Vocabulary::lookupSpecificPrefix: _parserWords doesn't contains '%s'", meaning);
+ return false;
+ }
+ if ((unsigned char)word[0] == prefix) {
+ ResultWordList word_list;
+ lookupWord(word_list, word + 1, word_len);
+ if (!word_list.empty())
+ if (word_list.front()._class == VOCAB_CLASS_NOUN << 4 || word_list.front()._class == VOCAB_CLASS_PREPOSITION << 4) {
+ parent_retval.push_back(_parserWords[meaning]);
+ retval = word_list;
+ return true;
+ }
+ }
+ return false;
+}
+
void Vocabulary::debugDecipherSaidBlock(const SciSpan<const byte> &data) {
bool first = true;
uint16 nextItem;
@@ -585,10 +650,14 @@ bool Vocabulary::tokenizeString(ResultWordListList &retval, const char *sentence
lookupWord(lookup_result, currentWord, wordLen);
if (lookup_result.empty()) { // Not found?
- *error = (char *)calloc(wordLen + 1, 1);
- strncpy(*error, currentWord, wordLen); // Set the offending word
- retval.clear();
- return false; // And return with error
+ lookupWordPrefix(retval, lookup_result, currentWord, wordLen);
+
+ if (lookup_result.empty()) { // Still not found? {
+ *error = (char *)calloc(wordLen + 1, 1);
+ strncpy(*error, currentWord, wordLen); // Set the offending word
+ retval.clear();
+ return false; // And return with error
+ }
}
// Copy into list
diff --git a/engines/sci/parser/vocabulary.h b/engines/sci/parser/vocabulary.h
index 763c1fd189..bdfbe5bdca 100644
--- a/engines/sci/parser/vocabulary.h
+++ b/engines/sci/parser/vocabulary.h
@@ -208,6 +208,29 @@ public:
*/
void lookupWord(ResultWordList &retval, const char *word, int word_len);
+ /**
+ * Looks up a single word in the words list, taking into account suffixes, and updating parent_retval if finding matching prefix
+ * Note: there is no equivalent in Sierra SCI, added to support specific languages translations
+ * For other languages, does nothing
+ * @param parent_retval parent's function list of matches
+ * @param retval the list of matches
+ * @param word pointer to the word to look up
+ * @param word_len length of the word to look up
+ */
+ void lookupWordPrefix(ResultWordListList &parent_retval, ResultWordList &retval, const char *word, int word_len);
+
+ /**
+ * Helper function for lookupWordPrefix, checking specific prefix for match
+ * @param parent_retval lookupWordPrefix's parent's function list of matches
+ * @param retval lookupWordPrefix's list of matches
+ * @param word pointer to the word to look up
+ * @param word_len length of the word to look up
+ * @param prefix the prefix to look for in the word
+ * @param meaning the meaning of that prefix
+ * @return true on prefix match, false on prefix not matching
+ */
+ bool lookupSpecificPrefix(ResultWordListList &parent_retval, ResultWordList &retval, const char *word, int word_len, unsigned char prefix, const char *meaning);
+
/**
* Tokenizes a string and compiles it into word_ts.
@@ -324,6 +347,11 @@ private:
*/
bool loadSuffixes();
+ /**
+ * Appends required suffixes for specific languages
+ */
+ void appendSuffixes();
+
/**
* Frees all suffixes in the given list.
* @param suffixes: The suffixes to free
Commit: 9f10fbcfc1e70f733b04b26e5812514fd02fea80
https://github.com/scummvm/scummvm/commit/9f10fbcfc1e70f733b04b26e5812514fd02fea80
Author: Zvika (haramaty.zvika at gmail.com)
Date: 2020-05-25T03:21:59+03:00
Commit Message:
SCI: Hebrew SQ3 - fixed rejects
Changed paths:
engines/sci/engine/vm_hooks.cpp
engines/sci/engine/vm_hooks.h
engines/sci/graphics/menu.cpp
engines/sci/graphics/text16.cpp
engines/sci/parser/vocabulary.cpp
engines/sci/parser/vocabulary.h
diff --git a/engines/sci/engine/vm_hooks.cpp b/engines/sci/engine/vm_hooks.cpp
index 63608f4553..7a6476c719 100644
--- a/engines/sci/engine/vm_hooks.cpp
+++ b/engines/sci/engine/vm_hooks.cpp
@@ -37,8 +37,6 @@ namespace Sci {
* Note that when using hooks, the regular PC is frozen, and doesn't advance.
* Therefore, 'jmp', 'bt' and 'bnt' are used to locally move around inside the patch.
*
- * (In the past there was a warning regarding 'call's - but they should work now)
- *
******************************************************************************************************************/
diff --git a/engines/sci/engine/vm_hooks.h b/engines/sci/engine/vm_hooks.h
index 274a0d8816..a9b367c7e2 100644
--- a/engines/sci/engine/vm_hooks.h
+++ b/engines/sci/engine/vm_hooks.h
@@ -94,7 +94,7 @@ private:
/** Used to avoid double patching in row, and to support `call`ing */
reg_t _lastPc;
- /** Used to avoid double patching in row */
+ /** Raised after patch has ended, to avoid confusion with situation of returning from a `call` to the patch, and continue execution of original code */
bool _just_finished;
/** Location inside patch */
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index d85f87e790..eb87f81c25 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -616,15 +616,10 @@ void GfxMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) {
_menuRect.right = menuTextRect.right;
}
if ((listNr == newMenuId) || (listNr == oldMenuId)) {
- if (!g_sci->isLanguageRTL()) {
- menuTextRect.translate(1, 0);
- _paint16->invertRect(menuTextRect);
- menuTextRect.translate(-1, 0);
- } else {
- menuTextRect.translate(-1, 0);
- _paint16->invertRect(menuTextRect);
- menuTextRect.translate(1, 0);
- }
+ int multiplier = !g_sci->isLanguageRTL() ? 1 : -1;
+ menuTextRect.translate(1 * multiplier, 0);
+ _paint16->invertRect(menuTextRect);
+ menuTextRect.translate(-1 * multiplier, 0);
}
listIterator++;
@@ -834,6 +829,8 @@ GuiMenuItemEntry *GfxMenu::interactiveWithKeyboard() {
_paint16->bitsShow(_ports->_menuRect);
_paint16->bitsShow(_menuRect);
+ int multiplier = !g_sci->isLanguageRTL() ? 1 : -1;
+
while (true) {
curEvent = _event->getSciEvent(kSciEventAny);
@@ -854,22 +851,12 @@ GuiMenuItemEntry *GfxMenu::interactiveWithKeyboard() {
}
break;
case kSciKeyLeft:
- if (!g_sci->isLanguageRTL()) {
- newMenuId--;
- newItemId = 1;
- } else {
- newMenuId++;
- newItemId = 1;
- }
+ newMenuId -= 1 * multiplier;
+ newItemId = 1;
break;
case kSciKeyRight:
- if (!g_sci->isLanguageRTL()) {
- newMenuId++;
- newItemId = 1;
- } else {
- newMenuId--;
- newItemId = 1;
- }
+ newMenuId += 1 * multiplier;
+ newItemId = 1;
break;
case kSciKeyUp:
newItemId--;
diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp
index eccbf49806..1e88588be1 100644
--- a/engines/sci/graphics/text16.cpp
+++ b/engines/sci/graphics/text16.cpp
@@ -560,46 +560,37 @@ void GfxText16::Box(const char *text, uint16 languageSplitter, bool show, const
break;
Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, true);
maxTextWidth = MAX<int16>(maxTextWidth, textWidth);
- if (!g_sci->isLanguageRTL()) {
- switch (alignment) {
- case SCI_TEXT16_ALIGNMENT_RIGHT:
+ switch (alignment) {
+ case SCI_TEXT16_ALIGNMENT_RIGHT:
+ if (!g_sci->isLanguageRTL())
offset = rect.width() - textWidth;
- break;
- case SCI_TEXT16_ALIGNMENT_CENTER:
- offset = (rect.width() - textWidth) / 2;
- break;
- case SCI_TEXT16_ALIGNMENT_LEFT:
+ else
offset = 0;
- break;
-
- default:
- warning("Invalid alignment %d used in TextBox()", alignment);
- }
- } else {
- // language direction is from Right to Left
- switch (alignment) {
- case SCI_TEXT16_ALIGNMENT_LEFT:
- offset = rect.width() - textWidth;
- break;
- case SCI_TEXT16_ALIGNMENT_CENTER:
- offset = (rect.width() - textWidth) / 2;
- break;
- case SCI_TEXT16_ALIGNMENT_RIGHT:
+ break;
+ case SCI_TEXT16_ALIGNMENT_CENTER:
+ offset = (rect.width() - textWidth) / 2;
+ break;
+ case SCI_TEXT16_ALIGNMENT_LEFT:
+ if (!g_sci->isLanguageRTL())
offset = 0;
- break;
+ else
+ offset = rect.width() - textWidth;
+ break;
+
+ default:
+ warning("Invalid alignment %d used in TextBox()", alignment);
+ }
- default:
- warning("Invalid alignment %d used in TextBox()", alignment);
- }
- // in the fonts, the characters have some spacing to the left, and no space to the right
+ if (g_sci->isLanguageRTL())
+ // In the game fonts, characters have spacing on the left, and no spacing on the right,
// therefore, when we start drawing from the right, they "start from the border"
- // e.g., in SQ3 Hebrew user's input prompt
- // we can't make the Hebrew letters spacing in the right (in the font), because then mixed English-Hebrew text
- // might have 2 letters stick together
- // therefore, we shift here one pixel to the left, for the spacing
+ // e.g., in SQ3 Hebrew user's input prompt.
+ // We can't add spacing on the right of the Hebrew letters, because then characters in mixed
+ // English-Hebrew text might be stuck together.
+ // Therefore, we shift one pixel to the left, for proper spacing
offset--;
- }
+
_ports->moveTo(rect.left + offset, rect.top + hline);
Common::String textString;
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index 2c8739e272..7ff06dfd6f 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -265,20 +265,16 @@ void Vocabulary::appendSuffixes() {
else
cls = VOCAB_CLASS_NOUN << 4;
- suffix_t suffix1 = { cls, cls, 1, 0, "\xea", "" }; // get rid of Kaf Sofit
- _parserSuffixes.push_back(suffix1);
-
- suffix_t suffix2 = { cls, cls, 2, 0, "\xe9\xed", "" }; // get rid of Yud, Mem Sofit
- _parserSuffixes.push_back(suffix2);
-
- suffix_t suffix3 = { cls, cls, 2, 0, "\xe5\xfa", "" }; // get rid of Vav, Taf
- _parserSuffixes.push_back(suffix3);
-
- suffix_t suffix4 = { cls, cls, 3, 2, "\xe9\xe5\xfa", "\xe9\xfa" }; // Yud, Vav, Taf -> Yud, Taf
- _parserSuffixes.push_back(suffix4);
-
- suffix_t suffix5 = { cls, cls, 3, 2, "\xe0\xe5\xfa", "\xe0\xe4" }; // Alef, Vav, Taf -> Alef, He
- _parserSuffixes.push_back(suffix5);
+ suffix_t suffixes[] = {
+ {cls, cls, 1, 0, "\xea", ""}, // get rid of Kaf Sofit
+ {cls, cls, 2, 0, "\xe9\xed", ""}, // get rid of Yud, Mem Sofit
+ {cls, cls, 2, 0, "\xe5\xfa", ""}, // get rid of Vav, Taf
+ {cls, cls, 3, 2, "\xe9\xe5\xfa", "\xe9\xfa"}, // Yud, Vav, Taf -> Yud, Taf
+ {cls, cls, 3, 2, "\xe0\xe5\xfa", "\xe0\xe4"} // Alef, Vav, Taf -> Alef, He
+ };
+
+ for (int j = 0; j < ARRAYSIZE(suffixes); j++)
+ _parserSuffixes.push_back(suffixes[j]);
}
}
}
@@ -519,14 +515,16 @@ void Vocabulary::lookupWordPrefix(ResultWordListList &parent_retval, ResultWordL
if (--word_len <= 0)
return;
- if (lookupSpecificPrefix(parent_retval, retval, word, word_len, 0xe1, "1hebrew1prefix1bet")) // "Bet"
- return;
- if (lookupSpecificPrefix(parent_retval, retval, word, word_len, 0xe4, "the")) // "He Hayedia"
- return;
- if (lookupSpecificPrefix(parent_retval, retval, word, word_len, 0xec, "1hebrew1prefix1lamed")) // "Lamed"
- return;
- if (lookupSpecificPrefix(parent_retval, retval, word, word_len, 0xee, "1hebrew1prefix1mem")) // "Mem"
- return;
+ PrefixMeaning prefixes[] = {
+ {0xe1, "1hebrew1prefix1bet"}, // "Bet"
+ {0xe4, "the"}, // "He Hayedia"
+ {0xec, "1hebrew1prefix1lamed"}, // "Lamed"
+ {0xee, "1hebrew1prefix1mem"} // "Mem"
+ };
+
+ for (int i = 0; i < ARRAYSIZE(prefixes); i++)
+ if (lookupSpecificPrefix(parent_retval, retval, word, word_len, prefixes[i].prefix, prefixes[i].meaning))
+ return;
}
bool Vocabulary::lookupSpecificPrefix(ResultWordListList &parent_retval, ResultWordList &retval, const char *word, int word_len, unsigned char prefix, const char *meaning) {
@@ -652,7 +650,7 @@ bool Vocabulary::tokenizeString(ResultWordListList &retval, const char *sentence
if (lookup_result.empty()) { // Not found?
lookupWordPrefix(retval, lookup_result, currentWord, wordLen);
- if (lookup_result.empty()) { // Still not found? {
+ if (lookup_result.empty()) { // Still not found?
*error = (char *)calloc(wordLen + 1, 1);
strncpy(*error, currentWord, wordLen); // Set the offending word
retval.clear();
diff --git a/engines/sci/parser/vocabulary.h b/engines/sci/parser/vocabulary.h
index bdfbe5bdca..f4d13d698b 100644
--- a/engines/sci/parser/vocabulary.h
+++ b/engines/sci/parser/vocabulary.h
@@ -209,24 +209,24 @@ public:
void lookupWord(ResultWordList &retval, const char *word, int word_len);
/**
- * Looks up a single word in the words list, taking into account suffixes, and updating parent_retval if finding matching prefix
+ * Looks up a single word in the words list, taking into account suffixes, and updating parent_retval if a matching prefix is found
* Note: there is no equivalent in Sierra SCI, added to support specific languages translations
- * For other languages, does nothing
- * @param parent_retval parent's function list of matches
- * @param retval the list of matches
- * @param word pointer to the word to look up
- * @param word_len length of the word to look up
+ * For other languages, it does nothing
+ * @param parent_retval parent's function list of matches
+ * @param retval the list of matches
+ * @param word pointer to the word to look up
+ * @param word_len length of the word to look up
*/
void lookupWordPrefix(ResultWordListList &parent_retval, ResultWordList &retval, const char *word, int word_len);
/**
* Helper function for lookupWordPrefix, checking specific prefix for match
- * @param parent_retval lookupWordPrefix's parent's function list of matches
- * @param retval lookupWordPrefix's list of matches
- * @param word pointer to the word to look up
- * @param word_len length of the word to look up
- * @param prefix the prefix to look for in the word
- * @param meaning the meaning of that prefix
+ * @param parent_retval lookupWordPrefix's parent's function list of matches
+ * @param retval lookupWordPrefix's list of matches
+ * @param word pointer to the word to look up
+ * @param word_len length of the word to look up
+ * @param prefix the prefix to look for in the word
+ * @param meaning the meaning of that prefix
* @return true on prefix match, false on prefix not matching
*/
bool lookupSpecificPrefix(ResultWordListList &parent_retval, ResultWordList &retval, const char *word, int word_len, unsigned char prefix, const char *meaning);
@@ -399,6 +399,11 @@ private:
SynonymList _synonyms; /**< The list of synonyms */
Common::Array<Common::List<AltInput> > _altInputs;
+ struct PrefixMeaning {
+ unsigned char prefix;
+ const char *meaning;
+ };
+
int _pronounReference;
public:
More information about the Scummvm-git-logs
mailing list