diff options
author | Johannes Schickel | 2011-02-15 23:40:06 +0100 |
---|---|---|
committer | Johannes Schickel | 2011-02-15 23:42:50 +0100 |
commit | a02454644af514c4f50b861cc718e2951d4c46dd (patch) | |
tree | e6385482a68f330f412e87aa33b049b4f5912911 /engines/sci/engine | |
parent | 01d511bf1b6df74254a2f6bd3007e884cd0c0dde (diff) | |
parent | 369db4fdfd5dac16858505f91cb37f4ae386fe80 (diff) | |
download | scummvm-rg350-a02454644af514c4f50b861cc718e2951d4c46dd.tar.gz scummvm-rg350-a02454644af514c4f50b861cc718e2951d4c46dd.tar.bz2 scummvm-rg350-a02454644af514c4f50b861cc718e2951d4c46dd.zip |
Merge branch 'master' into osystem-palette
Conflicts:
backends/platform/wii/osystem_gfx.cpp
Diffstat (limited to 'engines/sci/engine')
-rw-r--r-- | engines/sci/engine/kevent.cpp | 71 | ||||
-rw-r--r-- | engines/sci/engine/kmisc.cpp | 59 | ||||
-rw-r--r-- | engines/sci/engine/savegame.cpp | 41 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 173 | ||||
-rw-r--r-- | engines/sci/engine/vm_types.h | 26 |
5 files changed, 200 insertions, 170 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) { |