aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/kevent.cpp71
-rw-r--r--engines/sci/engine/kmisc.cpp59
-rw-r--r--engines/sci/engine/savegame.cpp41
-rw-r--r--engines/sci/engine/vm.cpp173
-rw-r--r--engines/sci/engine/vm_types.h26
-rw-r--r--engines/sci/event.cpp20
-rw-r--r--engines/sci/event.h3
-rw-r--r--engines/sci/graphics/frameout.cpp11
-rw-r--r--engines/sci/graphics/frameout.h3
9 files changed, 214 insertions, 193 deletions
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index 58de38bd8e..e5a9931605 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -38,8 +38,6 @@
namespace Sci {
-#define SCI_VARIABLE_GAME_SPEED 3
-
reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
int mask = argv[0].toUint16();
reg_t obj = argv[1];
@@ -188,57 +186,42 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+struct KeyDirMapping {
+ uint16 key;
+ uint16 direction;
+};
+
+const KeyDirMapping keyToDirMap[] = {
+ { SCI_KEY_HOME, 8 }, { SCI_KEY_UP, 1 }, { SCI_KEY_PGUP, 2 },
+ { SCI_KEY_LEFT, 7 }, { SCI_KEY_CENTER, 0 }, { SCI_KEY_RIGHT, 3 },
+ { SCI_KEY_END, 6 }, { SCI_KEY_DOWN, 5 }, { SCI_KEY_PGDOWN, 4 },
+};
+
reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
SegManager *segMan = s->_segMan;
if (readSelectorValue(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard
- int mover = -1;
- switch (readSelectorValue(segMan, obj, SELECTOR(message))) {
- case SCI_KEY_HOME:
- mover = 8;
- break;
- case SCI_KEY_UP:
- mover = 1;
- break;
- case SCI_KEY_PGUP:
- mover = 2;
- break;
- case SCI_KEY_LEFT:
- mover = 7;
- break;
- case SCI_KEY_CENTER:
- case 76:
- mover = 0;
- break;
- case SCI_KEY_RIGHT:
- mover = 3;
- break;
- case SCI_KEY_END:
- mover = 6;
- break;
- case SCI_KEY_DOWN:
- mover = 5;
- break;
- case SCI_KEY_PGDOWN:
- mover = 4;
- break;
- default:
- break;
+ uint16 message = readSelectorValue(segMan, obj, SELECTOR(message));
+ uint16 eventType = SCI_EVENT_DIRECTION;
+ // Check if the game is using cursor views. These games allowed control
+ // of the mouse cursor via the keyboard controls (the so called
+ // "PseudoMouse" functionality in script 933).
+ if (g_sci->_features->detectSetCursorType() == SCI_VERSION_1_1)
+ eventType |= SCI_EVENT_KEYBOARD;
+
+ for (int i = 0; i < 9; i++) {
+ if (keyToDirMap[i].key == message) {
+ writeSelectorValue(segMan, obj, SELECTOR(type), eventType);
+ writeSelectorValue(segMan, obj, SELECTOR(message), keyToDirMap[i].direction);
+ return TRUE_REG; // direction mapped
+ }
}
- if (mover >= 0) {
- if (g_sci->getEventManager()->getUsesNewKeyboardDirectionType())
- writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD | SCI_EVENT_DIRECTION);
- else
- writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_DIRECTION);
- writeSelectorValue(segMan, obj, SELECTOR(message), mover);
- return make_reg(0, 1);
- } else
- return NULL_REG;
+ return NULL_REG; // unknown direction
}
- return s->r_acc;
+ return s->r_acc; // no keyboard event to map, leave accumulator unchanged
}
reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv) {
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 6e961f72f3..f95b1dd0f8 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -362,20 +362,29 @@ reg_t kIconBar(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
switch (argv[0].toUint16()) {
- case 0:
- // Add the icons
+ case 0: // InitIconBar
for (int i = 0; i < argv[1].toUint16(); i++)
g_sci->_gfxMacIconBar->addIcon(argv[i + 2]);
g_sci->_gfxMacIconBar->drawIcons();
+
+ // TODO: Should return icon bar handle
+ // Said handle is then used by DisposeIconBar
+ break;
+ case 1: // DisposeIconBar
+ warning("kIconBar(Dispose)");
+ break;
+ case 2: // EnableIconBar (0xffff = all)
+ warning("kIconBar(Enable, %d)", argv[1].toUint16());
+ break;
+ case 3: // DisableIconBar (0xffff = all)
+ warning("kIconBar(Disable, %d)", argv[1].toUint16());
break;
- case 2:
- case 3:
- case 4:
- // TODO: Other calls seem to handle selecting/deselecting them
+ case 4: // SetIconBarIcon
+ warning("kIconBar(SetIcon, %d, %d)", argv[1].toUint16(), argv[2].toUint16());
break;
default:
- warning("Unknown kIconBar subop %d", argv[0].toUint16());
+ error("Unknown kIconBar(%d)", argv[0].toUint16());
}
return NULL_REG;
@@ -389,23 +398,28 @@ reg_t kMacPlatform(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case 0:
- // Set Mac cursor remap
- g_sci->_gfxCursor->setMacCursorRemapList(argc - 1, argv + 1);
+ // Subop 0 has changed a few times
+ // In SCI1, its usage is still unknown
+ // In SCI1.1, it's NOP
+ // In SCI32, it's used for remapping cursor ID's
+ if (getSciVersion() >= SCI_VERSION_2_1) // Set Mac cursor remap
+ g_sci->_gfxCursor->setMacCursorRemapList(argc - 1, argv + 1);
+ else if (getSciVersion() != SCI_VERSION_1_1)
+ warning("Unknown SCI1 kMacPlatform(0) call");
break;
- case 1:
- // Unknown
- break;
- case 2:
- // Unknown
- break;
- case 3:
- // Unknown
- break;
- case 4:
- // Handle icon bar code
+ case 4: // Handle icon bar code
return kIconBar(s, argc - 1, argv + 1);
+ case 7: // Unknown, but always return -1
+ return SIGNAL_REG;
+ case 1: // Unknown, calls QuickDraw region functions (KQ5, QFG1VGA)
+ case 2: // Unknown, "UseNextWaitEvent" (Various)
+ case 3: // Unknown, "ProcessOpenDocuments" (Various)
+ case 5: // Unknown, plays a sound (KQ7)
+ case 6: // Unknown, menu-related (Unused?)
+ warning("Unhandled kMacPlatform(%d)", argv[0].toUint16());
+ break;
default:
- warning("Unknown kMacPlatform subop %d", argv[0].toUint16());
+ error("Unknown kMacPlatform(%d)", argv[0].toUint16());
}
return s->r_acc;
@@ -455,7 +469,8 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) {
warning("STUB: kPlatform(CDCheck)");
break;
case kPlatformUnk0:
- if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1 && argc > 1)
+ // For Mac versions, kPlatform(0) with other args has more functionality
+ if (g_sci->getPlatform() == Common::kPlatformMacintosh && argc > 1)
return kMacPlatform(s, argc - 1, argv + 1);
// Otherwise, fall through
case kPlatformGetPlatform:
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index a59d4c000b..ab355cebb4 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -47,6 +47,10 @@
#include "sci/sound/audio.h"
#include "sci/sound/music.h"
+#ifdef ENABLE_SCI32
+#include "sci/graphics/frameout.h"
+#endif
+
namespace Sci {
@@ -130,6 +134,13 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
// Reset _scriptSegMap, to be restored below
_scriptSegMap.clear();
+
+#ifdef ENABLE_SCI32
+ // Clear any planes/screen items currently showing so they
+ // don't show up after the load.
+ if (getSciVersion() >= SCI_VERSION_2)
+ g_sci->_gfxFrameout->clear();
+#endif
}
s.skip(4, VER(14), VER(18)); // OBSOLETE: Used to be _exportsAreWide
@@ -144,17 +155,15 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
SegmentType type = (s.isSaving() && mobj) ? mobj->getType() : SEG_TYPE_INVALID;
s.syncAsUint32LE(type);
- // If we were saving and mobj == 0, or if we are loading and this is an
- // entry marked as empty -> skip to next
- if (type == SEG_TYPE_INVALID)
+ if (type == SEG_TYPE_HUNK) {
+ // Don't save or load HunkTable segments
continue;
-
- // Don't save or load HunkTable segments
- if (type == SEG_TYPE_HUNK)
+ } else if (type == SEG_TYPE_INVALID) {
+ // If we were saving and mobj == 0, or if we are loading and this is an
+ // entry marked as empty -> skip to next
continue;
-
- // Don't save or load the obsolete system string segments
- if (type == 5) {
+ } else if (type == 5) {
+ // Don't save or load the obsolete system string segments
if (s.isSaving()) {
continue;
} else {
@@ -168,6 +177,14 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
_heap[i] = NULL; // set as freed
continue;
}
+#ifdef ENABLE_SCI32
+ } else if (type == SEG_TYPE_ARRAY) {
+ // Set the correct segment for SCI32 arrays
+ _arraysSegId = i;
+ } else if (type == SEG_TYPE_STRING) {
+ // Set the correct segment for SCI32 strings
+ _stringSegId = i;
+#endif
}
if (s.isLoading())
@@ -178,8 +195,7 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
// Let the object sync custom data
mobj->saveLoadWithSerializer(s);
-
- if (type == SEG_TYPE_SCRIPT && s.getVersion() >= 28) {
+ if (type == SEG_TYPE_SCRIPT) {
Script *scr = (Script *)mobj;
// If we are loading a script, perform some extra steps
@@ -196,7 +212,8 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
}
// Sync the script's string heap
- scr->syncStringHeap(s);
+ if (s.getVersion() >= 28)
+ scr->syncStringHeap(s);
}
}
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 6d11a1ad8a..9c7f52d28e 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -131,21 +131,6 @@ static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) {
return 0;
}
-static int validate_arithmetic(reg_t reg) {
- if (reg.segment) {
- // The results of this are likely unpredictable... It most likely means that a kernel function is returning something wrong.
- // If such an error occurs, we usually need to find the last kernel function called and check its return value.
- error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]. Address: %04x:%04x", reg.segment, PRINT_REG(reg));
- return 0;
- }
-
- return reg.offset;
-}
-
-static int signed_validate_arithmetic(reg_t reg) {
- return (int16)validate_arithmetic(reg);
-}
-
static bool validate_variable(reg_t *r, reg_t *stack_base, int type, int max, int index) {
const char *names[4] = {"global", "local", "temp", "param"};
@@ -176,20 +161,6 @@ static bool validate_variable(reg_t *r, reg_t *stack_base, int type, int max, in
return true;
}
-static bool validate_unsignedInteger(reg_t reg, uint16 &integer) {
- if (reg.segment)
- return false;
- integer = reg.offset;
- return true;
-}
-
-static bool validate_signedInteger(reg_t reg, int16 &integer) {
- if (reg.segment)
- return false;
- integer = (int16)reg.offset;
- return true;
-}
-
extern const char *opcodeNames[]; // from scriptdebug.cpp
static reg_t arithmetic_lookForWorkaround(const byte opcode, const SciWorkaroundEntry *workaroundList, reg_t value1, reg_t value2) {
@@ -427,12 +398,12 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
int activeBreakpointTypes = g_sci->_debugState._activeBreakpointTypes;
while (framesize > 0) {
- selector = validate_arithmetic(*argp++);
- argc = validate_arithmetic(*argp);
+ selector = argp->requireUint16();
+ argp++;
+ argc = argp->requireUint16();
- if (argc > 0x800) { // More arguments than the stack could possibly accomodate for
+ if (argc > 0x800) // More arguments than the stack could possibly accomodate for
error("send_selector(): More than 0x800 arguments to function call");
- }
#ifdef VM_DEBUG_SEND
debugN("Send to %04x:%04x (%s), selector %04x (%s):", PRINT_REG(send_obj),
@@ -1014,8 +985,8 @@ void run_vm(EngineState *s) {
case op_bnot: { // 0x00 (00)
// Binary not
- int16 value;
- if (validate_signedInteger(s->r_acc, value))
+ int16 value = s->r_acc.toSint16();
+ if (s->r_acc.isNumber())
s->r_acc = make_reg(0, 0xffff ^ value);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, NULL_REG);
@@ -1087,8 +1058,9 @@ void run_vm(EngineState *s) {
case op_mul: { // 0x03 (03)
r_temp = POP32();
- int16 value1, value2;
- if (validate_signedInteger(s->r_acc, value1) && validate_signedInteger(r_temp, value2))
+ int16 value1 = s->r_acc.toSint16();
+ int16 value2 = r_temp.toSint16();
+ if (s->r_acc.isNumber() && r_temp.isNumber())
s->r_acc = make_reg(0, value1 * value2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeMulWorkarounds, s->r_acc, r_temp);
@@ -1097,8 +1069,9 @@ void run_vm(EngineState *s) {
case op_div: { // 0x04 (04)
r_temp = POP32();
- int16 divisor, dividend;
- if (validate_signedInteger(s->r_acc, divisor) && validate_signedInteger(r_temp, dividend))
+ int16 divisor = s->r_acc.toSint16();
+ int16 dividend = r_temp.toSint16();
+ if (s->r_acc.isNumber() && r_temp.isNumber())
s->r_acc = make_reg(0, (divisor != 0 ? dividend / divisor : 0));
else
s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeDivWorkarounds, s->r_acc, r_temp);
@@ -1109,8 +1082,9 @@ void run_vm(EngineState *s) {
r_temp = POP32();
if (getSciVersion() <= SCI_VERSION_0_LATE) {
- uint16 modulo, value;
- if (validate_unsignedInteger(s->r_acc, modulo) && validate_unsignedInteger(r_temp, value))
+ uint16 modulo = s->r_acc.toUint16();
+ uint16 value = r_temp.toUint16();
+ if (s->r_acc.isNumber() && r_temp.isNumber())
s->r_acc = make_reg(0, (modulo != 0 ? value % modulo : 0));
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp);
@@ -1121,8 +1095,10 @@ void run_vm(EngineState *s) {
// for simplicity's sake and use the new code for SCI01 and newer
// games. Fixes the battlecruiser mini game in SQ5 (room 850),
// bug #3035755
- int16 modulo, value, result;
- if (validate_signedInteger(s->r_acc, modulo) && validate_signedInteger(r_temp, value)) {
+ int16 modulo = s->r_acc.toSint16();
+ int16 value = r_temp.toSint16();
+ int16 result;
+ if (s->r_acc.isNumber() && r_temp.isNumber()) {
modulo = ABS(modulo);
result = (modulo != 0 ? value % modulo : 0);
if (result < 0)
@@ -1137,8 +1113,9 @@ void run_vm(EngineState *s) {
case op_shr: { // 0x06 (06)
// Shift right logical
r_temp = POP32();
- uint16 value, shiftCount;
- if (validate_unsignedInteger(r_temp, value) && validate_unsignedInteger(s->r_acc, shiftCount))
+ uint16 value = r_temp.toUint16();
+ uint16 shiftCount = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, value >> shiftCount);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
@@ -1148,8 +1125,9 @@ void run_vm(EngineState *s) {
case op_shl: { // 0x07 (07)
// Shift left logical
r_temp = POP32();
- uint16 value, shiftCount;
- if (validate_unsignedInteger(r_temp, value) && validate_unsignedInteger(s->r_acc, shiftCount))
+ uint16 value = r_temp.toUint16();
+ uint16 shiftCount = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, value << shiftCount);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
@@ -1158,8 +1136,9 @@ void run_vm(EngineState *s) {
case op_xor: { // 0x08 (08)
r_temp = POP32();
- uint16 value1, value2;
- if (validate_unsignedInteger(r_temp, value1) && validate_unsignedInteger(s->r_acc, value2))
+ uint16 value1 = r_temp.toUint16();
+ uint16 value2 = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, value1 ^ value2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
@@ -1168,8 +1147,9 @@ void run_vm(EngineState *s) {
case op_and: { // 0x09 (09)
r_temp = POP32();
- uint16 value1, value2;
- if (validate_unsignedInteger(r_temp, value1) && validate_unsignedInteger(s->r_acc, value2))
+ uint16 value1 = r_temp.toUint16();
+ uint16 value2 = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, value1 & value2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeAndWorkarounds, r_temp, s->r_acc);
@@ -1178,8 +1158,9 @@ void run_vm(EngineState *s) {
case op_or: { // 0x0a (10)
r_temp = POP32();
- uint16 value1, value2;
- if (validate_unsignedInteger(r_temp, value1) && validate_unsignedInteger(s->r_acc, value2))
+ uint16 value1 = r_temp.toUint16();
+ uint16 value2 = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, value1 | value2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeOrWorkarounds, r_temp, s->r_acc);
@@ -1187,8 +1168,8 @@ void run_vm(EngineState *s) {
}
case op_neg: { // 0x0b (11)
- int16 value;
- if (validate_signedInteger(s->r_acc, value))
+ int16 value = s->r_acc.toSint16();
+ if (s->r_acc.isNumber())
s->r_acc = make_reg(0, -value);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, NULL_REG);
@@ -1232,8 +1213,9 @@ void run_vm(EngineState *s) {
// Happens in SQ1, room 28, when throwing the water at Orat
s->r_acc = make_reg(0, 1);
} else {
- int16 compare1, compare2;
- if (validate_signedInteger(r_temp, compare1) && validate_signedInteger(s->r_acc, compare2))
+ int16 compare1 = r_temp.toSint16();
+ int16 compare2 = s->r_acc.toSint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, compare1 > compare2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
@@ -1249,8 +1231,9 @@ void run_vm(EngineState *s) {
warning("[VM] Comparing pointers in different segments (%04x:%04x vs. %04x:%04x)", PRINT_REG(r_temp), PRINT_REG(s->r_acc));
s->r_acc = make_reg(0, (r_temp.segment == s->r_acc.segment) && r_temp.offset >= s->r_acc.offset);
} else {
- int16 compare1, compare2;
- if (validate_signedInteger(r_temp, compare1) && validate_signedInteger(s->r_acc, compare2))
+ int16 compare1 = r_temp.toSint16();
+ int16 compare2 = s->r_acc.toSint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, compare1 >= compare2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeGeWorkarounds, r_temp, s->r_acc);
@@ -1272,8 +1255,9 @@ void run_vm(EngineState *s) {
// Happens in SQ1, room 58, when giving id-card to robot
s->r_acc = make_reg(0, 1);
} else {
- int16 compare1, compare2;
- if (validate_signedInteger(r_temp, compare1) && validate_signedInteger(s->r_acc, compare2))
+ int16 compare1 = r_temp.toSint16();
+ int16 compare2 = s->r_acc.toSint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, compare1 < compare2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
@@ -1289,8 +1273,9 @@ void run_vm(EngineState *s) {
warning("[VM] Comparing pointers in different segments (%04x:%04x vs. %04x:%04x)", PRINT_REG(r_temp), PRINT_REG(s->r_acc));
s->r_acc = make_reg(0, (r_temp.segment == s->r_acc.segment) && r_temp.offset <= s->r_acc.offset);
} else {
- int16 compare1, compare2;
- if (validate_signedInteger(r_temp, compare1) && validate_signedInteger(s->r_acc, compare2))
+ int16 compare1 = r_temp.toSint16();
+ int16 compare2 = s->r_acc.toSint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, compare1 <= compare2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeLeWorkarounds, r_temp, s->r_acc);
@@ -1317,8 +1302,9 @@ void run_vm(EngineState *s) {
else if (r_temp.segment && s->r_acc.segment)
s->r_acc = make_reg(0, (r_temp.segment == s->r_acc.segment) && r_temp.offset > s->r_acc.offset);
else {
- uint16 compare1, compare2;
- if (validate_unsignedInteger(r_temp, compare1) && validate_unsignedInteger(s->r_acc, compare2))
+ uint16 compare1 = r_temp.toUint16();
+ uint16 compare2 = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, compare1 > compare2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
@@ -1336,8 +1322,9 @@ void run_vm(EngineState *s) {
else if (r_temp.segment && s->r_acc.segment)
s->r_acc = make_reg(0, (r_temp.segment == s->r_acc.segment) && r_temp.offset >= s->r_acc.offset);
else {
- uint16 compare1, compare2;
- if (validate_unsignedInteger(r_temp, compare1) && validate_unsignedInteger(s->r_acc, compare2))
+ uint16 compare1 = r_temp.toUint16();
+ uint16 compare2 = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, compare1 >= compare2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
@@ -1356,8 +1343,9 @@ void run_vm(EngineState *s) {
else if (r_temp.segment && s->r_acc.segment)
s->r_acc = make_reg(0, (r_temp.segment == s->r_acc.segment) && r_temp.offset < s->r_acc.offset);
else {
- uint16 compare1, compare2;
- if (validate_unsignedInteger(r_temp, compare1) && validate_unsignedInteger(s->r_acc, compare2))
+ uint16 compare1 = r_temp.toUint16();
+ uint16 compare2 = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, compare1 < compare2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeUltWorkarounds, r_temp, s->r_acc);
@@ -1375,8 +1363,9 @@ void run_vm(EngineState *s) {
else if (r_temp.segment && s->r_acc.segment)
s->r_acc = make_reg(0, (r_temp.segment == s->r_acc.segment) && r_temp.offset <= s->r_acc.offset);
else {
- uint16 compare1, compare2;
- if (validate_unsignedInteger(r_temp, compare1) && validate_unsignedInteger(s->r_acc, compare2))
+ uint16 compare1 = r_temp.toUint16();
+ uint16 compare2 = s->r_acc.toUint16();
+ if (r_temp.isNumber() && s->r_acc.isNumber())
s->r_acc = make_reg(0, compare1 <= compare2);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
@@ -1446,7 +1435,7 @@ void run_vm(EngineState *s) {
xs_new = add_exec_stack_entry(s->_executionStack, make_reg(s->xs->addr.pc.segment,
localCallOffset),
s->xs->sp, s->xs->objp,
- (validate_arithmetic(*call_base)) + s->restAdjust,
+ (call_base->requireUint16()) + s->restAdjust,
call_base, NULL_SELECTOR, -1, localCallOffset, s->xs->objp,
s->_executionStack.size()-1, s->xs->local_segment);
s->restAdjust = 0; // Used up the &rest adjustment
@@ -1466,7 +1455,7 @@ void run_vm(EngineState *s) {
if (!oldScriptHeader)
s->xs->sp -= s->restAdjust;
- int argc = validate_arithmetic(s->xs->sp[0]);
+ int argc = s->xs->sp[0].requireUint16();
if (!oldScriptHeader)
argc += s->restAdjust;
@@ -1663,7 +1652,7 @@ void run_vm(EngineState *s) {
r_temp.offset = s->variables[var_number] - s->variablesBase[var_number];
if (temp & 0x08) // Add accumulator offset if requested
- r_temp.offset += signed_validate_arithmetic(s->r_acc);
+ r_temp.offset += s->r_acc.requireSint16();
r_temp.offset += opparams[1]; // Add index
r_temp.offset *= 2; // variables are 16 bit
@@ -1710,8 +1699,8 @@ void run_vm(EngineState *s) {
case op_ipToa: { // 0x35 (53)
// Increment Property and copy To Accumulator
reg_t &opProperty = validate_property(s, obj, opparams[0]);
- uint16 valueProperty;
- if (validate_unsignedInteger(opProperty, valueProperty))
+ uint16 valueProperty = opProperty.toUint16();
+ if (opProperty.isNumber())
s->r_acc = make_reg(0, valueProperty + 1);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, opProperty, NULL_REG);
@@ -1722,8 +1711,8 @@ void run_vm(EngineState *s) {
case op_dpToa: { // 0x36 (54)
// Decrement Property and copy To Accumulator
reg_t &opProperty = validate_property(s, obj, opparams[0]);
- uint16 valueProperty;
- if (validate_unsignedInteger(opProperty, valueProperty))
+ uint16 valueProperty = opProperty.toUint16();
+ if (opProperty.isNumber())
s->r_acc = make_reg(0, valueProperty - 1);
else
s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeDptoaWorkarounds, opProperty, NULL_REG);
@@ -1734,8 +1723,8 @@ void run_vm(EngineState *s) {
case op_ipTos: { // 0x37 (55)
// Increment Property and push to Stack
reg_t &opProperty = validate_property(s, obj, opparams[0]);
- uint16 valueProperty;
- if (validate_unsignedInteger(opProperty, valueProperty))
+ uint16 valueProperty = opProperty.toUint16();
+ if (opProperty.isNumber())
valueProperty++;
else
valueProperty = arithmetic_lookForWorkaround(opcode, NULL, opProperty, NULL_REG).offset;
@@ -1747,8 +1736,8 @@ void run_vm(EngineState *s) {
case op_dpTos: { // 0x38 (56)
// Decrement Property and push to Stack
reg_t &opProperty = validate_property(s, obj, opparams[0]);
- uint16 valueProperty;
- if (validate_unsignedInteger(opProperty, valueProperty))
+ uint16 valueProperty = opProperty.toUint16();
+ if (opProperty.isNumber())
valueProperty--;
else
valueProperty = arithmetic_lookForWorkaround(opcode, NULL, opProperty, NULL_REG).offset;
@@ -1871,8 +1860,8 @@ void run_vm(EngineState *s) {
// Load global, local, temp or param variable into the accumulator,
// using the accumulator as an additional index
var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
- int16 value;
- if (!validate_signedInteger(s->r_acc, value))
+ int16 value = s->r_acc.toSint16();
+ if (!s->r_acc.isNumber())
value = arithmetic_lookForWorkaround(opcode, opcodeLaiWorkarounds, s->r_acc, NULL_REG).offset;
var_number = opparams[0] + value;
s->r_acc = READ_VAR(var_type, var_number);
@@ -1886,8 +1875,8 @@ void run_vm(EngineState *s) {
// Load global, local, temp or param variable into the stack,
// using the accumulator as an additional index
var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
- int16 value;
- if (!validate_signedInteger(s->r_acc, value))
+ int16 value = s->r_acc.toSint16();
+ if (!s->r_acc.isNumber())
value = arithmetic_lookForWorkaround(opcode, opcodeLsiWorkarounds, s->r_acc, NULL_REG).offset;
var_number = opparams[0] + value;
PUSH32(READ_VAR(var_type, var_number));
@@ -1925,7 +1914,7 @@ void run_vm(EngineState *s) {
// of sense otherwise, with acc being used for two things
// simultaneously...
var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
- var_number = opparams[0] + signed_validate_arithmetic(s->r_acc);
+ var_number = opparams[0] + s->r_acc.requireSint16();
s->r_acc = POP32();
WRITE_VAR(var_type, var_number, s->r_acc);
break;
@@ -1937,7 +1926,7 @@ void run_vm(EngineState *s) {
// Save the stack into the global, local, temp or param variable,
// using the accumulator as an additional index
var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
- var_number = opparams[0] + signed_validate_arithmetic(s->r_acc);
+ var_number = opparams[0] + s->r_acc.requireSint16();
WRITE_VAR(var_type, var_number, POP32());
break;
@@ -1983,7 +1972,7 @@ void run_vm(EngineState *s) {
// Increment the global, local, temp or param variable and save it
// to the accumulator, using the accumulator as an additional index
var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
- var_number = opparams[0] + signed_validate_arithmetic(s->r_acc);
+ var_number = opparams[0] + s->r_acc.requireSint16();
r_temp = READ_VAR(var_type, var_number);
if (r_temp.segment) {
// Pointer arithmetics!
@@ -2000,7 +1989,7 @@ void run_vm(EngineState *s) {
// Increment the global, local, temp or param variable and save it
// to the stack, using the accumulator as an additional index
var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
- var_number = opparams[0] + signed_validate_arithmetic(s->r_acc);
+ var_number = opparams[0] + s->r_acc.requireSint16();
r_temp = READ_VAR(var_type, var_number);
if (r_temp.segment) {
// Pointer arithmetics!
@@ -2053,7 +2042,7 @@ void run_vm(EngineState *s) {
// Decrement the global, local, temp or param variable and save it
// to the accumulator, using the accumulator as an additional index
var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
- var_number = opparams[0] + signed_validate_arithmetic(s->r_acc);
+ var_number = opparams[0] + s->r_acc.requireSint16();
r_temp = READ_VAR(var_type, var_number);
if (r_temp.segment) {
// Pointer arithmetics!
@@ -2070,7 +2059,7 @@ void run_vm(EngineState *s) {
// Decrement the global, local, temp or param variable and save it
// to the stack, using the accumulator as an additional index
var_type = opcode & 0x3; // Gets the variable type: g, l, t or p
- var_number = opparams[0] + signed_validate_arithmetic(s->r_acc);
+ var_number = opparams[0] + s->r_acc.requireSint16();
r_temp = READ_VAR(var_type, var_number);
if (r_temp.segment) {
// Pointer arithmetics!
diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h
index edf35a122a..cc1f9b2685 100644
--- a/engines/sci/engine/vm_types.h
+++ b/engines/sci/engine/vm_types.h
@@ -56,6 +56,32 @@ struct reg_t {
int16 toSint16() const {
return (int16) offset;
}
+
+ uint16 requireUint16() const {
+ if (isNumber())
+ return toUint16();
+ else
+ // The results of this are likely unpredictable... It most likely
+ // means that a kernel function is returning something wrong. If
+ // such an error occurs, we usually need to find the last kernel
+ // function called and check its return value.
+ error("[VM] Attempt to read unsigned arithmetic value from non-zero segment %04x. Offset: %04x", segment, offset);
+ }
+
+ int16 requireSint16() const {
+ if (isNumber())
+ return toSint16();
+ else
+ // The results of this are likely unpredictable... It most likely
+ // means that a kernel function is returning something wrong. If
+ // such an error occurs, we usually need to find the last kernel
+ // function called and check its return value.
+ error("[VM] Attempt to read signed arithmetic value from non-zero segment %04x. Offset: %04x", segment, offset);
+ }
+
+ bool isNumber() const {
+ return !segment;
+ }
};
static inline reg_t make_reg(SegmentId segment, uint16 offset) {
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 0c17db6028..d607a5314f 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -36,31 +36,11 @@
namespace Sci {
EventManager::EventManager(bool fontIsExtended) : _fontIsExtended(fontIsExtended), _modifierStates(0) {
-
- if (getSciVersion() >= SCI_VERSION_1_MIDDLE) {
- _usesNewKeyboardDirectionType = true;
- } else if (getSciVersion() <= SCI_VERSION_01) {
- _usesNewKeyboardDirectionType = false;
- } else {
- // they changed this somewhere inbetween SCI1EGA/EARLY
- _usesNewKeyboardDirectionType = false;
-
- // We are looking if script 933 exists, that one has the PseudoMouse class in it that handles it
- // The good thing is that PseudoMouse seems to only exists in games that use the new method
- if (g_sci->getResMan()->testResource(ResourceId(kResourceTypeScript, 933)))
- _usesNewKeyboardDirectionType = true;
- // Checking the keyboard driver size in here would also be a valid method, but the driver is only available
- // in PC versions of the game
- }
}
EventManager::~EventManager() {
}
-bool EventManager::getUsesNewKeyboardDirectionType() {
- return _usesNewKeyboardDirectionType;
-}
-
struct ScancodeRow {
int offset;
const char *keys;
diff --git a/engines/sci/event.h b/engines/sci/event.h
index fade7dd337..7c83476294 100644
--- a/engines/sci/event.h
+++ b/engines/sci/event.h
@@ -116,7 +116,6 @@ public:
void updateScreen();
SciEvent getSciEvent(unsigned int mask);
- bool getUsesNewKeyboardDirectionType();
private:
SciEvent getScummVMEvent();
@@ -124,8 +123,6 @@ private:
const bool _fontIsExtended;
int _modifierStates;
Common::List<SciEvent> _events;
-
- bool _usesNewKeyboardDirectionType;
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 5b690f289a..ab4a2c9c1a 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -58,6 +58,12 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
GfxFrameout::~GfxFrameout() {
}
+void GfxFrameout::clear() {
+ _screenItems.clear();
+ _planes.clear();
+ _planePictures.clear();
+}
+
void GfxFrameout::kernelAddPlane(reg_t object) {
PlaneEntry newPlane;
@@ -584,6 +590,11 @@ void GfxFrameout::kernelFrameout() {
uint16 startX = itemEntry->x + it->planeRect.left;
uint16 curY = itemEntry->y + it->planeRect.top;
const char *txt = text.c_str();
+ // HACK. The plane sometimes doesn't contain the correct width. This
+ // hack breaks the dialog options when speaking with Grace, but it's
+ // the best we got up to now.
+ // TODO: Remove this, and figure out why the plane in question isn't
+ // initialized correctly (its width is 0).
uint16 w = it->planeRect.width() >= 20 ? it->planeRect.width() : _screen->getWidth() - 10;
int16 charCount;
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 93d61ba22e..347ecb9424 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -28,6 +28,8 @@
namespace Sci {
+class GfxPicture;
+
struct PlaneEntry {
reg_t object;
uint16 priority;
@@ -99,6 +101,7 @@ public:
void addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX);
void deletePlanePictures(reg_t object);
+ void clear();
private:
SegManager *_segMan;