aboutsummaryrefslogtreecommitdiff
path: root/engines/toltecs/script.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/toltecs/script.cpp')
-rw-r--r--engines/toltecs/script.cpp155
1 files changed, 58 insertions, 97 deletions
diff --git a/engines/toltecs/script.cpp b/engines/toltecs/script.cpp
index 5e8617bc43..07d74ac369 100644
--- a/engines/toltecs/script.cpp
+++ b/engines/toltecs/script.cpp
@@ -40,6 +40,22 @@
namespace Toltecs {
+static const VarType varTypes[] = {
+ vtByte, vtWord, vtWord, vtByte, vtWord, // 0 - 4
+ vtWord, vtWord, vtWord, vtWord, vtWord, // 5 - 9
+ vtWord, vtWord, vtByte, vtWord, vtWord, // 10 - 14
+ vtWord, vtWord, vtWord, vtWord, vtWord, // 15 - 19
+ vtWord, vtWord // 20 - 21
+};
+
+static const char *varNames[] = {
+ "mouseDisabled", "mouseY", "mouseX", "mouseButton", "verbLineY", // 0 - 4
+ "verbLineX", "verbLineWidth", "verbLineCount", "verbLineNum", "talkTextItemNum", // 5 - 9
+ "talkTextY", "talkTextX", "talkTextFontColor", "cameraY", "cameraX", // 10 - 14
+ "walkSpeedY", "walkSpeedX", "flag01", "sceneResIndex", "guiHeight", // 15 - 19
+ "sceneHeight", "sceneWidth" // 20 - 21
+};
+
ScriptInterpreter::ScriptInterpreter(ToltecsEngine *vm) : _vm(vm) {
_stack = new byte[kScriptStackSize];
@@ -154,6 +170,17 @@ void ScriptInterpreter::setupScriptFunctions() {
}
void ScriptInterpreter::loadScript(uint resIndex, uint slotIndex) {
+ if (_slots[slotIndex].resIndex && _slots[slotIndex].resIndex != resIndex && _vm->_screen->isTalkTextActive(slotIndex)) {
+ // WORKAROUND: This happens when examining the assembled
+ // pickaxe. It could lead to random characters being printed,
+ // or possibly even crashes, when subtitles are enabled.
+ //
+ // According to johndoe and he said there may be some bug or
+ // missing feature that causes this situation to happen at all,
+ // but he was ok with this workaround for now.
+ warning("Possible script bug: Loading script %d into slot %d that has an active talk text, probably for script %d", resIndex, slotIndex, _slots[slotIndex].resIndex);
+ _vm->_screen->finishTalkTextItem(slotIndex);
+ }
delete[] _slots[slotIndex].data;
@@ -162,7 +189,6 @@ void ScriptInterpreter::loadScript(uint resIndex, uint slotIndex) {
_slots[slotIndex].size = scriptResource->size;
_slots[slotIndex].data = new byte[_slots[slotIndex].size];
memcpy(_slots[slotIndex].data, scriptResource->data, _slots[slotIndex].size);
-
}
void ScriptInterpreter::setMainScript(uint slotIndex) {
@@ -228,10 +254,9 @@ int16 ScriptInterpreter::readInt16() {
}
void ScriptInterpreter::execOpcode(byte opcode) {
-
int16 ofs;
- debug(1, "opcode = %d", opcode);
+ debug(2, "opcode = %d", opcode);
switch (opcode) {
case 0:
@@ -239,35 +264,32 @@ void ScriptInterpreter::execOpcode(byte opcode) {
// ok
_subCode = _code;
byte length = readByte();
- debug(1, "length = %d", length);
+ if (length == 0) {
+ warning("Possible script bug detected - opcode length is 0 when calling script function");
+ return;
+ }
+ debug(2, "length = %d", length);
uint16 index = readInt16();
- debug(1, "callScriptFunction %d", index);
execScriptFunction(index);
_code += length - 2;
break;
}
case 1:
- // ok
_regs.reg0 = readInt16();
break;
case 2:
- // ok
_regs.reg1 = readInt16();
break;
case 3:
- // ok
_regs.reg3 = readInt16();
break;
case 4:
- // ok
_regs.reg5 = _regs.reg0;
break;
case 5:
- // ok
_regs.reg3 = _regs.reg0;
break;
case 6:
- // ok
_regs.reg1 = _regs.reg0;
break;
case 7:
@@ -468,72 +490,14 @@ void ScriptInterpreter::execOpcode(byte opcode) {
}
void ScriptInterpreter::execScriptFunction(uint16 index) {
- debug(4, "execScriptFunction(%d)", index);
if (index >= _scriptFuncs.size())
error("ScriptInterpreter::execScriptFunction() Invalid script function index %d", index);
- debug(4, "%s", _scriptFuncNames[index]);
+ debug(1, "execScriptFunction %s (%d)", _scriptFuncNames[index], index);
(*_scriptFuncs[index])();
}
-VarType ScriptInterpreter::getGameVarType(uint variable) {
- switch (variable) {
- case 0: return vtByte;
- case 1: return vtWord;
- case 2: return vtWord;
- case 3: return vtByte;
- case 4: return vtWord;
- case 5: return vtWord;
- case 6: return vtWord;
- case 7: return vtWord;
- case 8: return vtWord;
- case 9: return vtWord;
- case 10: return vtWord;
- case 11: return vtWord;
- case 12: return vtByte;
- case 13: return vtWord;
- case 14: return vtWord;
- case 15: return vtWord;
- case 16: return vtWord;
- case 17: return vtWord;
- case 18: return vtWord;
- case 19: return vtWord;
- case 20: return vtWord;
- case 21: return vtWord;
- default:
- error("Invalid game variable");
- }
-}
-
-const char *getVarName(uint variable) {
- switch (variable) {
- case 0: return "mouseDisabled";
- case 1: return "mouseY";
- case 2: return "mouseX";
- case 3: return "mouseButton";
- case 4: return "verbLineY";
- case 5: return "verbLineX";
- case 6: return "verbLineWidth";
- case 7: return "verbLineCount";
- case 8: return "verbLineNum";
- case 9: return "talkTextItemNum";
- case 10: return "talkTextY";
- case 11: return "talkTextX";
- case 12: return "talkTextFontColor";
- case 13: return "cameraY";
- case 14: return "cameraX";
- case 15: return "walkSpeedY";
- case 16: return "walkSpeedX";
- case 17: return "flag01";
- case 18: return "sceneResIndex";
- case 19: return "guiHeight";
- case 20: return "sceneHeight";
- case 21: return "sceneWidth";
- }
- return "(invalid)";
-}
-
int16 ScriptInterpreter::getGameVar(uint variable) {
- debug(0, "ScriptInterpreter::getGameVar(%d{%s})", variable, getVarName(variable));
+ debug(2, "ScriptInterpreter::getGameVar(%d{%s})", variable, varNames[variable]);
switch (variable) {
case 0: return _vm->_mouseDisabled;
@@ -559,13 +523,13 @@ int16 ScriptInterpreter::getGameVar(uint variable) {
case 20: return _vm->_sceneHeight;
case 21: return _vm->_sceneWidth;
default:
- warning("Getting unimplemented game variable %s (%d)", getVarName(variable), variable);
+ warning("Getting unimplemented game variable %s (%d)", varNames[variable], variable);
return 0;
}
}
void ScriptInterpreter::setGameVar(uint variable, int16 value) {
- debug(0, "ScriptInterpreter::setGameVar(%d{%s}, %d)", variable, getVarName(variable), value);
+ debug(2, "ScriptInterpreter::setGameVar(%d{%s}, %d)", variable, varNames[variable], value);
switch (variable) {
case 0:
@@ -632,10 +596,9 @@ void ScriptInterpreter::setGameVar(uint variable, int16 value) {
case 1:
case 2:
default:
- warning("Setting unimplemented game variable %s (%d) to %d", getVarName(variable), variable, value);
+ warning("Setting unimplemented game variable %s (%d) to %d", varNames[variable], variable, value);
break;
}
-
}
byte ScriptInterpreter::arg8(int16 offset) {
@@ -657,32 +620,31 @@ int16 ScriptInterpreter::popInt16() {
}
void ScriptInterpreter::localWrite8(int16 offset, byte value) {
- //debug(1, "localWrite8(%d, %d)", offset, value);
+ //debug(2, "localWrite8(%d, %d)", offset, value);
_localData[offset] = value;
}
byte ScriptInterpreter::localRead8(int16 offset) {
- //debug(1, "localRead8(%d) -> %d", offset, _localData[offset]);
+ //debug(2, "localRead8(%d) -> %d", offset, _localData[offset]);
return _localData[offset];
}
void ScriptInterpreter::localWrite16(int16 offset, int16 value) {
- //debug(1, "localWrite16(%d, %d)", offset, value);
+ //debug(2, "localWrite16(%d, %d)", offset, value);
WRITE_LE_UINT16(&_localData[offset], value);
}
int16 ScriptInterpreter::localRead16(int16 offset) {
- //debug(1, "localRead16(%d) -> %d", offset, (int16)READ_LE_UINT16(&_localData[offset]));
+ //debug(2, "localRead16(%d) -> %d", offset, (int16)READ_LE_UINT16(&_localData[offset]));
return (int16)READ_LE_UINT16(&_localData[offset]);
}
byte *ScriptInterpreter::localPtr(int16 offset) {
- //debug(1, "localPtr(%d)", offset);
+ //debug(2, "localPtr(%d)", offset);
return &_localData[offset];
}
void ScriptInterpreter::saveState(Common::WriteStream *out) {
-
// Save registers
out->writeUint16LE(_regs.reg0);
out->writeUint16LE(_regs.reg1);
@@ -708,11 +670,9 @@ void ScriptInterpreter::saveState(Common::WriteStream *out) {
// Save IP
out->writeUint16LE((int16)(_code - getSlotData(_regs.reg4)));
-
}
void ScriptInterpreter::loadState(Common::ReadStream *in) {
-
// Load registers
_regs.reg0 = in->readUint16LE();
_regs.reg1 = in->readUint16LE();
@@ -741,7 +701,6 @@ void ScriptInterpreter::loadState(Common::ReadStream *in) {
// Load IP
_code = getSlotData(_regs.reg4) + in->readUint16LE();
-
}
void ScriptInterpreter::sfNop() {
@@ -755,7 +714,9 @@ void ScriptInterpreter::sfGetGameVar() {
void ScriptInterpreter::sfSetGameVar() {
int16 varIndex = arg16(3);
- VarType varType = getGameVarType(varIndex);
+ assert(varIndex <= 21);
+
+ VarType varType = varTypes[varIndex];
int16 value = 0;
if (varType == vtByte)
value = arg8(5);
@@ -810,8 +771,7 @@ void ScriptInterpreter::sfSetDeltaAnimPalette() {
}
void ScriptInterpreter::sfSetUnkPaletteEffect() {
- // TODO
- debug("ScriptInterpreter::sfSetUnkPaletteEffect");
+ error("ScriptInterpreter::sfSetUnkPaletteEffect called"); // unused
}
void ScriptInterpreter::sfBuildColorTransTable() {
@@ -992,7 +952,8 @@ void ScriptInterpreter::sfStopShakeScreen() {
void ScriptInterpreter::sfStartSequence() {
int16 sequenceResIndex = arg16(3);
- //debug("ScriptInterpreter::sfStartSequence(%d)", sequenceResIndex);
+ debug(1, "ScriptInterpreter::sfStartSequence(%d)", sequenceResIndex);
+
if (sequenceResIndex >= 0) {
//_vm->_arc->dump(sequenceResIndex, "music"); // DEBUG: Dump music so we know what's in there
@@ -1001,7 +962,6 @@ void ScriptInterpreter::sfStartSequence() {
}
void ScriptInterpreter::sfEndSequence() {
- //debug("ScriptInterpreter::sfEndSequence");
_vm->_music->stopSequence();
}
@@ -1029,9 +989,8 @@ void ScriptInterpreter::sfHandleInput() {
if (_vm->_rightButtonDown) {
keyCode = 1;
} else {
- /* Convert keyboard scancode to IBM PC scancode
- Only scancodes known to be used (so far) are converted
- */
+ // Convert keyboard scancode to IBM PC scancode.
+ // Only scancodes known to be used (so far) are converted.
switch (_vm->_keyState.keycode) {
case Common::KEYCODE_ESCAPE:
keyCode = 1;
@@ -1050,11 +1009,13 @@ void ScriptInterpreter::sfRunOptionsScreen() {
_vm->showMenu(kMenuIdMain);
}
-/* NOTE: The opcodes sfPrecacheSprites, sfPrecacheSounds1, sfPrecacheSounds2 and
- sfDeletePrecachedFiles were used by the original engine to handle precaching
- of data so the game doesn't stall while playing (due to the slow speed of
- CD-Drives back then). This is not needed in ScummVM since all supported
- systems are fast enough to load data in-game. */
+/**
+ * NOTE: The opcodes sfPrecacheSprites, sfPrecacheSounds1, sfPrecacheSounds2 and
+ * sfDeletePrecachedFiles were used by the original engine to handle precaching
+ * of data so the game doesn't stall while playing (due to the slow speed of
+ * CD-Drives back then). This is not needed in ScummVM since all supported
+ * systems are fast enough to load data in-game.
+ */
void ScriptInterpreter::sfPrecacheSprites() {
// See note above