aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/script_v6.cpp
diff options
context:
space:
mode:
authorMax Horn2006-02-11 22:45:04 +0000
committerMax Horn2006-02-11 22:45:04 +0000
commit26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch)
tree26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/scumm/script_v6.cpp
parent2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff)
downloadscummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/scumm/script_v6.cpp')
-rw-r--r--engines/scumm/script_v6.cpp3183
1 files changed, 3183 insertions, 0 deletions
diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp
new file mode 100644
index 0000000000..77709eed21
--- /dev/null
+++ b/engines/scumm/script_v6.cpp
@@ -0,0 +1,3183 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "common/config-manager.h"
+
+#include "scumm/actor.h"
+#include "scumm/charset.h"
+#include "scumm/imuse.h"
+#include "scumm/imuse_digi/dimuse.h"
+#include "scumm/insane/insane.h"
+#include "scumm/intern.h"
+#include "scumm/object.h"
+#include "scumm/resource.h"
+#include "scumm/scumm.h"
+#include "scumm/smush/smush_player.h"
+#include "scumm/sound.h"
+#include "scumm/util.h"
+#include "scumm/verbs.h"
+
+#include "sound/mididrv.h"
+#include "sound/mixer.h"
+
+namespace Scumm {
+
+#define OPCODE(x) _OPCODE(ScummEngine_v6, x)
+
+void ScummEngine_v6::setupOpcodes() {
+ static const OpcodeEntryV6 opcodes[256] = {
+ /* 00 */
+ OPCODE(o6_pushByte),
+ OPCODE(o6_pushWord),
+ OPCODE(o6_pushByteVar),
+ OPCODE(o6_pushWordVar),
+ /* 04 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayRead),
+ OPCODE(o6_wordArrayRead),
+ /* 08 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayIndexedRead),
+ OPCODE(o6_wordArrayIndexedRead),
+ /* 0C */
+ OPCODE(o6_dup),
+ OPCODE(o6_not),
+ OPCODE(o6_eq),
+ OPCODE(o6_neq),
+ /* 10 */
+ OPCODE(o6_gt),
+ OPCODE(o6_lt),
+ OPCODE(o6_le),
+ OPCODE(o6_ge),
+ /* 14 */
+ OPCODE(o6_add),
+ OPCODE(o6_sub),
+ OPCODE(o6_mul),
+ OPCODE(o6_div),
+ /* 18 */
+ OPCODE(o6_land),
+ OPCODE(o6_lor),
+ OPCODE(o6_pop),
+ OPCODE(o6_invalid),
+ /* 1C */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 20 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 24 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 28 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 2C */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 30 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 34 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 38 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 3C */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 40 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_writeByteVar),
+ OPCODE(o6_writeWordVar),
+ /* 44 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayWrite),
+ OPCODE(o6_wordArrayWrite),
+ /* 48 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayIndexedWrite),
+ OPCODE(o6_wordArrayIndexedWrite),
+ /* 4C */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteVarInc),
+ OPCODE(o6_wordVarInc),
+ /* 50 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayInc),
+ OPCODE(o6_wordArrayInc),
+ /* 54 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteVarDec),
+ OPCODE(o6_wordVarDec),
+ /* 58 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayDec),
+ OPCODE(o6_wordArrayDec),
+ /* 5C */
+ OPCODE(o6_if),
+ OPCODE(o6_ifNot),
+ OPCODE(o6_startScript),
+ OPCODE(o6_startScriptQuick),
+ /* 60 */
+ OPCODE(o6_startObject),
+ OPCODE(o6_drawObject),
+ OPCODE(o6_drawObjectAt),
+ OPCODE(o6_drawBlastObject),
+ /* 64 */
+ OPCODE(o6_setBlastObjectWindow),
+ OPCODE(o6_stopObjectCode),
+ OPCODE(o6_stopObjectCode),
+ OPCODE(o6_endCutscene),
+ /* 68 */
+ OPCODE(o6_cutscene),
+ OPCODE(o6_stopMusic),
+ OPCODE(o6_freezeUnfreeze),
+ OPCODE(o6_cursorCommand),
+ /* 6C */
+ OPCODE(o6_breakHere),
+ OPCODE(o6_ifClassOfIs),
+ OPCODE(o6_setClass),
+ OPCODE(o6_getState),
+ /* 70 */
+ OPCODE(o6_setState),
+ OPCODE(o6_setOwner),
+ OPCODE(o6_getOwner),
+ OPCODE(o6_jump),
+ /* 74 */
+ OPCODE(o6_startSound),
+ OPCODE(o6_stopSound),
+ OPCODE(o6_startMusic),
+ OPCODE(o6_stopObjectScript),
+ /* 78 */
+ OPCODE(o6_panCameraTo),
+ OPCODE(o6_actorFollowCamera),
+ OPCODE(o6_setCameraAt),
+ OPCODE(o6_loadRoom),
+ /* 7C */
+ OPCODE(o6_stopScript),
+ OPCODE(o6_walkActorToObj),
+ OPCODE(o6_walkActorTo),
+ OPCODE(o6_putActorAtXY),
+ /* 80 */
+ OPCODE(o6_putActorAtObject),
+ OPCODE(o6_faceActor),
+ OPCODE(o6_animateActor),
+ OPCODE(o6_doSentence),
+ /* 84 */
+ OPCODE(o6_pickupObject),
+ OPCODE(o6_loadRoomWithEgo),
+ OPCODE(o6_invalid),
+ OPCODE(o6_getRandomNumber),
+ /* 88 */
+ OPCODE(o6_getRandomNumberRange),
+ OPCODE(o6_invalid),
+ OPCODE(o6_getActorMoving),
+ OPCODE(o6_isScriptRunning),
+ /* 8C */
+ OPCODE(o6_getActorRoom),
+ OPCODE(o6_getObjectX),
+ OPCODE(o6_getObjectY),
+ OPCODE(o6_getObjectOldDir),
+ /* 90 */
+ OPCODE(o6_getActorWalkBox),
+ OPCODE(o6_getActorCostume),
+ OPCODE(o6_findInventory),
+ OPCODE(o6_getInventoryCount),
+ /* 94 */
+ OPCODE(o6_getVerbFromXY),
+ OPCODE(o6_beginOverride),
+ OPCODE(o6_endOverride),
+ OPCODE(o6_setObjectName),
+ /* 98 */
+ OPCODE(o6_isSoundRunning),
+ OPCODE(o6_setBoxFlags),
+ OPCODE(o6_createBoxMatrix),
+ OPCODE(o6_resourceRoutines),
+ /* 9C */
+ OPCODE(o6_roomOps),
+ OPCODE(o6_actorOps),
+ OPCODE(o6_verbOps),
+ OPCODE(o6_getActorFromXY),
+ /* A0 */
+ OPCODE(o6_findObject),
+ OPCODE(o6_pseudoRoom),
+ OPCODE(o6_getActorElevation),
+ OPCODE(o6_getVerbEntrypoint),
+ /* A4 */
+ OPCODE(o6_arrayOps),
+ OPCODE(o6_saveRestoreVerbs),
+ OPCODE(o6_drawBox),
+ OPCODE(o6_pop),
+ /* A8 */
+ OPCODE(o6_getActorWidth),
+ OPCODE(o6_wait),
+ OPCODE(o6_getActorScaleX),
+ OPCODE(o6_getActorAnimCounter1),
+ /* AC */
+ OPCODE(o6_soundKludge),
+ OPCODE(o6_isAnyOf),
+ OPCODE(o6_systemOps),
+ OPCODE(o6_isActorInBox),
+ /* B0 */
+ OPCODE(o6_delay),
+ OPCODE(o6_delaySeconds),
+ OPCODE(o6_delayMinutes),
+ OPCODE(o6_stopSentence),
+ /* B4 */
+ OPCODE(o6_printLine),
+ OPCODE(o6_printText),
+ OPCODE(o6_printDebug),
+ OPCODE(o6_printSystem),
+ /* B8 */
+ OPCODE(o6_printActor),
+ OPCODE(o6_printEgo),
+ OPCODE(o6_talkActor),
+ OPCODE(o6_talkEgo),
+ /* BC */
+ OPCODE(o6_dimArray),
+ OPCODE(o6_dummy),
+ OPCODE(o6_startObjectQuick),
+ OPCODE(o6_startScriptQuick2),
+ /* C0 */
+ OPCODE(o6_dim2dimArray),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* C4 */
+ OPCODE(o6_abs),
+ OPCODE(o6_distObjectObject),
+ OPCODE(o6_distObjectPt),
+ OPCODE(o6_distPtPt),
+ /* C8 */
+ OPCODE(o6_kernelGetFunctions),
+ OPCODE(o6_kernelSetFunctions),
+ OPCODE(o6_delayFrames),
+ OPCODE(o6_pickOneOf),
+ /* CC */
+ OPCODE(o6_pickOneOfDefault),
+ OPCODE(o6_stampObject),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* D0 */
+ OPCODE(o6_getDateTime),
+ OPCODE(o6_stopTalking),
+ OPCODE(o6_getAnimateVariable),
+ OPCODE(o6_invalid),
+ /* D4 */
+ OPCODE(o6_shuffle),
+ OPCODE(o6_jumpToScript),
+ OPCODE(o6_band),
+ OPCODE(o6_bor),
+ /* D8 */
+ OPCODE(o6_isRoomScriptRunning),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* DC */
+ OPCODE(o6_invalid),
+ OPCODE(o6_findAllObjects),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* E0 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_getPixel),
+ OPCODE(o6_invalid),
+ OPCODE(o6_pickVarRandom),
+ /* E4 */
+ OPCODE(o6_setBoxSet),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* E8 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* EC */
+ OPCODE(o6_getActorLayer),
+ OPCODE(o6_getObjectNewDir),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* F0 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* F4 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* F8 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* FC */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ };
+
+ _opcodesV6 = opcodes;
+}
+
+void ScummEngine_v6::executeOpcode(byte i) {
+ OpcodeProcV6 op = _opcodesV6[i].proc;
+ (this->*op) ();
+}
+
+const char *ScummEngine_v6::getOpcodeDesc(byte i) {
+ return _opcodesV6[i].desc;
+}
+
+int ScummEngine_v6::popRoomAndObj(int *room) {
+ int obj;
+
+ if (_version >= 7) {
+ obj = pop();
+ *room = getObjectRoom(obj);
+ } else {
+ *room = pop();
+ obj = pop();
+ }
+
+ return obj;
+}
+
+ScummEngine_v6::ArrayHeader *ScummEngine_v6::defineArray(int array, int type, int dim2, int dim1) {
+ int id;
+ int size;
+ ArrayHeader *ah;
+
+ assert(0 <= type && type <= 5);
+
+
+ if (_heversion >= 61) {
+ if (type == kBitArray || type == kNibbleArray)
+ type = kByteArray;
+ } else {
+ // NOTE: The following code turns all arrays except string arrays into
+ // integer arrays. There seems to be no reason for this, and it wastes
+ // space. However, we can't just remove this either, as that would
+ // break savegame compatibility. So do not touch this unless you are
+ // also adding code which updated old savegames, too. And of course
+ // readArray() and writeArray() would have to be updated, too...
+ if (type != kStringArray)
+ type = kIntArray;
+ }
+
+ nukeArray(array);
+
+ id = findFreeArrayId();
+
+ if (_version == 8) {
+ if (array & 0x40000000) {
+ }
+
+ if (array & 0x80000000) {
+ error("Can't define bit variable as array pointer");
+ }
+
+ size = (type == kIntArray) ? 4 : 1;
+ } else {
+ if (array & 0x4000) {
+ }
+
+ if (array & 0x8000) {
+ error("Can't define bit variable as array pointer");
+ }
+
+ size = (type == kIntArray) ? 2 : 1;
+ }
+
+ writeVar(array, id);
+
+ size *= dim2 + 1;
+ size *= dim1 + 1;
+
+ ah = (ArrayHeader *)res.createResource(rtString, id, size + sizeof(ArrayHeader));
+
+ ah->type = TO_LE_16(type);
+ ah->dim1 = TO_LE_16(dim1 + 1);
+ ah->dim2 = TO_LE_16(dim2 + 1);
+
+ return ah;
+}
+
+void ScummEngine_v6::nukeArray(int a) {
+ int data;
+
+ data = readVar(a);
+
+ if (_heversion >= 80)
+ data &= ~0x33539000;
+
+ if (data)
+ res.nukeResource(rtString, data);
+ if (_heversion >= 60)
+ _arraySlot[data] = 0;
+
+ writeVar(a, 0);
+}
+
+int ScummEngine_v6::findFreeArrayId() {
+ byte **addr = res.address[rtString];
+ int i;
+
+ for (i = 1; i < _numArray; i++) {
+ if (!addr[i])
+ return i;
+ }
+ error("Out of array pointers, %d max", _numArray);
+ return -1;
+}
+
+#define SWAP16(x) x = SWAP_BYTES_16(x)
+
+ScummEngine_v6::ArrayHeader *ScummEngine_v6::getArray(int array) {
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
+ if (!ah)
+ return 0;
+
+ // Workaround for a long standing bug where we save array headers in native
+ // endianness, instead of a fixed endianness. We try to detect savegames
+ // which were created on a big endian system and convert them to little
+ // endian.
+ if ((FROM_LE_16(ah->dim1) & 0xF000) || (FROM_LE_16(ah->dim2) & 0xF000) || (FROM_LE_16(ah->type) & 0xFF00)) {
+ SWAP16(ah->dim1);
+ SWAP16(ah->dim2);
+ SWAP16(ah->type);
+ }
+
+ return ah;
+}
+
+int ScummEngine_v6::readArray(int array, int idx, int base) {
+ ArrayHeader *ah = getArray(array);
+
+ if (ah == NULL || ah->data == NULL)
+ error("readArray: invalid array %d (%d)", array, readVar(array));
+
+ // WORKAROUND bug #645711. This is clearly a script bug, as this script
+ // excerpt shows nicely:
+ // ...
+ // [03A7] (5D) if (isAnyOf(array-447[localvar13][localvar14],[0,4])) {
+ // [03BD] (5D) if ((localvar13 != -1) && (localvar14 != -1)) {
+ // [03CF] (B6) printDebug.begin()
+ // ...
+ if (_gameId == GID_FT && array == 447 && _currentRoom == 95 && vm.slot[_currentScript].number == 2010 && idx == -1 && base == -1) {
+ return 0;
+ }
+
+ const int offset = base + idx * FROM_LE_16(ah->dim1);
+
+ if (offset < 0 || offset >= FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2)) {
+ error("readArray: array %d out of bounds: [%d,%d] exceeds [%d,%d]",
+ array, base, idx, FROM_LE_16(ah->dim1), FROM_LE_16(ah->dim2));
+ }
+
+ int val;
+ if (FROM_LE_16(ah->type) != kIntArray) {
+ val = ah->data[offset];
+ } else if (_version == 8) {
+ val = (int32)READ_LE_UINT32(ah->data + offset * 4);
+ } else {
+ val = (int16)READ_LE_UINT16(ah->data + offset * 2);
+ }
+ return val;
+}
+
+void ScummEngine_v6::writeArray(int array, int idx, int base, int value) {
+ ArrayHeader *ah = getArray(array);
+ if (!ah)
+ return;
+
+ const int offset = base + idx * FROM_LE_16(ah->dim1);
+
+ if (offset < 0 || offset >= FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2)) {
+ error("writeArray: array %d out of bounds: [%d,%d] exceeds [%d,%d]",
+ array, base, idx, FROM_LE_16(ah->dim1), FROM_LE_16(ah->dim2));
+ }
+
+ if (FROM_LE_16(ah->type) != kIntArray) {
+ ah->data[offset] = value;
+ } else if (_version == 8) {
+ WRITE_LE_UINT32(ah->data + offset * 4, value);
+ } else {
+ WRITE_LE_UINT16(ah->data + offset * 2, value);
+ }
+}
+
+void ScummEngine_v6::readArrayFromIndexFile() {
+ int num;
+ int a, b, c;
+
+ while ((num = _fileHandle->readUint16LE()) != 0) {
+ a = _fileHandle->readUint16LE();
+ b = _fileHandle->readUint16LE();
+ c = _fileHandle->readUint16LE();
+ if (c == kBitArray)
+ defineArray(num, kBitArray, a, b);
+ else
+ defineArray(num, kIntArray, a, b);
+ }
+}
+
+int ScummEngine_v6::getStackList(int *args, uint maxnum) {
+ uint num, i;
+
+ for (i = 0; i < maxnum; i++)
+ args[i] = 0;
+
+ num = pop();
+
+ if (num > maxnum)
+ error("Too many items %d in stack list, max %d", num, maxnum);
+
+ i = num;
+ while (i--) {
+ args[i] = pop();
+ }
+
+ return num;
+}
+
+void ScummEngine_v6::o6_pushByte() {
+ push(fetchScriptByte());
+}
+
+void ScummEngine_v6::o6_pushWord() {
+ push(fetchScriptWordSigned());
+}
+
+void ScummEngine_v6::o6_pushByteVar() {
+ push(readVar(fetchScriptByte()));
+}
+
+void ScummEngine_v6::o6_pushWordVar() {
+ push(readVar(fetchScriptWord()));
+}
+
+void ScummEngine_v6::o6_invalid() {
+ error("Invalid opcode '%x' at %x", _opcode, _scriptPointer - _scriptOrgPointer);
+}
+
+void ScummEngine_v6::o6_byteArrayRead() {
+ int base = pop();
+ push(readArray(fetchScriptByte(), 0, base));
+}
+
+void ScummEngine_v6::o6_wordArrayRead() {
+ int base = pop();
+ push(readArray(fetchScriptWord(), 0, base));
+}
+
+void ScummEngine_v6::o6_byteArrayIndexedRead() {
+ int base = pop();
+ int idx = pop();
+ push(readArray(fetchScriptByte(), idx, base));
+}
+
+void ScummEngine_v6::o6_wordArrayIndexedRead() {
+ int base = pop();
+ int idx = pop();
+ push(readArray(fetchScriptWord(), idx, base));
+}
+
+void ScummEngine_v6::o6_dup() {
+ int a = pop();
+ push(a);
+ push(a);
+}
+
+void ScummEngine_v6::o6_not() {
+ push(pop() == 0);
+}
+
+void ScummEngine_v6::o6_eq() {
+ push(pop() == pop());
+}
+
+void ScummEngine_v6::o6_neq() {
+ push(pop() != pop());
+}
+
+void ScummEngine_v6::o6_gt() {
+ int a = pop();
+ push(pop() > a);
+}
+
+void ScummEngine_v6::o6_lt() {
+ int a = pop();
+ push(pop() < a);
+}
+
+void ScummEngine_v6::o6_le() {
+ int a = pop();
+ push(pop() <= a);
+}
+
+void ScummEngine_v6::o6_ge() {
+ int a = pop();
+ push(pop() >= a);
+}
+
+void ScummEngine_v6::o6_add() {
+ int a = pop();
+ push(pop() + a);
+}
+
+void ScummEngine_v6::o6_sub() {
+ int a = pop();
+ push(pop() - a);
+}
+
+void ScummEngine_v6::o6_mul() {
+ int a = pop();
+ push(pop() * a);
+}
+
+void ScummEngine_v6::o6_div() {
+ int a = pop();
+ if (a == 0)
+ error("division by zero");
+ push(pop() / a);
+}
+
+void ScummEngine_v6::o6_land() {
+ int a = pop();
+ push(pop() && a);
+}
+
+void ScummEngine_v6::o6_lor() {
+ int a = pop();
+ push(pop() || a);
+}
+
+void ScummEngine_v6::o6_bor() {
+ int a = pop();
+ push(pop() | a);
+}
+
+void ScummEngine_v6::o6_band() {
+ int a = pop();
+ push(pop() & a);
+}
+
+void ScummEngine_v6::o6_pop() {
+ pop();
+}
+
+void ScummEngine_v6::o6_writeByteVar() {
+ writeVar(fetchScriptByte(), pop());
+}
+
+void ScummEngine_v6::o6_writeWordVar() {
+ writeVar(fetchScriptWord(), pop());
+}
+
+void ScummEngine_v6::o6_byteArrayWrite() {
+ int a = pop();
+ writeArray(fetchScriptByte(), 0, pop(), a);
+}
+
+void ScummEngine_v6::o6_wordArrayWrite() {
+ int a = pop();
+ writeArray(fetchScriptWord(), 0, pop(), a);
+}
+
+void ScummEngine_v6::o6_byteArrayIndexedWrite() {
+ int val = pop();
+ int base = pop();
+ writeArray(fetchScriptByte(), pop(), base, val);
+}
+
+void ScummEngine_v6::o6_wordArrayIndexedWrite() {
+ int val = pop();
+ int base = pop();
+ writeArray(fetchScriptWord(), pop(), base, val);
+}
+
+void ScummEngine_v6::o6_byteVarInc() {
+ int var = fetchScriptByte();
+ writeVar(var, readVar(var) + 1);
+}
+
+void ScummEngine_v6::o6_wordVarInc() {
+ int var = fetchScriptWord();
+ writeVar(var, readVar(var) + 1);
+}
+
+void ScummEngine_v6::o6_byteArrayInc() {
+ int var = fetchScriptByte();
+ int base = pop();
+ writeArray(var, 0, base, readArray(var, 0, base) + 1);
+}
+
+void ScummEngine_v6::o6_wordArrayInc() {
+ int var = fetchScriptWord();
+ int base = pop();
+ writeArray(var, 0, base, readArray(var, 0, base) + 1);
+}
+
+void ScummEngine_v6::o6_byteVarDec() {
+ int var = fetchScriptByte();
+ writeVar(var, readVar(var) - 1);
+}
+
+void ScummEngine_v6::o6_wordVarDec() {
+ int var = fetchScriptWord();
+ writeVar(var, readVar(var) - 1);
+}
+
+void ScummEngine_v6::o6_byteArrayDec() {
+ int var = fetchScriptByte();
+ int base = pop();
+ writeArray(var, 0, base, readArray(var, 0, base) - 1);
+}
+
+void ScummEngine_v6::o6_wordArrayDec() {
+ int var = fetchScriptWord();
+ int base = pop();
+ writeArray(var, 0, base, readArray(var, 0, base) - 1);
+}
+
+void ScummEngine_v6::o6_if() {
+ if (pop())
+ o6_jump();
+ else
+ fetchScriptWord();
+}
+
+void ScummEngine_v6::o6_ifNot() {
+ if (!pop())
+ o6_jump();
+ else
+ fetchScriptWord();
+}
+
+void ScummEngine_v6::o6_jump() {
+ int offset = fetchScriptWordSigned();
+ _scriptPointer += offset;
+}
+
+void ScummEngine_v6::o6_startScript() {
+ int args[25];
+ int script, flags;
+
+ getStackList(args, ARRAYSIZE(args));
+ script = pop();
+ flags = pop();
+
+ // WORKAROUND bug #556558: At Dino Bungee National Memorial, the buttons for
+ // the Wally and Rex dinosaurs will always restart their speech, instead of
+ // stopping and starting their speech. This was a script bug in the original
+ // game.
+ if (_gameId == GID_SAMNMAX && _roomResource == 59 &&
+ vm.slot[_currentScript].number == 201 && script == 48) {
+ o6_breakHere();
+ }
+
+ // WORKAROUND bug #903223: In Puerto Pollo, if you have Guybrush examine
+ // the church clock, he'll read out the current time. Nice touch, only that
+ // it sounds crap in the german version (and maybe others, too). It seems
+ // the original engine of the german version played just a simple fixed
+ // text in this spot, for the above reason. Since the data files are
+ // unchanged, it must have been an engine hack job. No idea how they did
+ // it exactly, but this here is how we do it :-)
+ if (_gameId == GID_CMI && script == 204 &&
+ _currentRoom == 15 && vm.slot[_currentScript].number == 421 &&
+ _language == Common::DE_DEU) {
+
+ _actorToPrintStrFor = 1;
+ _string[0].loadDefault();
+ actorTalk((const byte *)"/VDSO325/Whoa! Look at the time. Gotta scoot.");
+
+ return;
+ }
+
+ runScript(script, (flags & 1) != 0, (flags & 2) != 0, args);
+}
+
+void ScummEngine_v6::o6_jumpToScript() {
+ int args[25];
+ int script, flags;
+
+ getStackList(args, ARRAYSIZE(args));
+ script = pop();
+ flags = pop();
+ stopObjectCode();
+ runScript(script, (flags & 1) != 0, (flags & 2) != 0, args);
+}
+
+void ScummEngine_v6::o6_startScriptQuick() {
+ int args[25];
+ int script;
+ getStackList(args, ARRAYSIZE(args));
+ script = pop();
+ runScript(script, 0, 0, args);
+}
+
+void ScummEngine_v6::o6_startScriptQuick2() {
+ int args[25];
+ int script;
+ getStackList(args, ARRAYSIZE(args));
+ script = pop();
+ runScript(script, 0, 1, args);
+}
+
+void ScummEngine_v6::o6_startObject() {
+ int args[25];
+ int script, entryp;
+ int flags;
+ getStackList(args, ARRAYSIZE(args));
+ entryp = pop();
+ script = pop();
+ flags = pop();
+ runObjectScript(script, entryp, (flags & 1) != 0, (flags & 2) != 0, args);
+}
+
+void ScummEngine_v6::o6_startObjectQuick() {
+ int args[25];
+ int script, entryp;
+ getStackList(args, ARRAYSIZE(args));
+ entryp = pop();
+ script = pop();
+ runObjectScript(script, entryp, 0, 1, args);
+}
+
+void ScummEngine_v6::o6_drawObject() {
+ int state = pop();
+ int obj = pop();
+
+ // This is based on disassembly
+ if (state == 0)
+ state = 1;
+
+ setObjectState(obj, state, -1, -1);
+}
+
+void ScummEngine_v6::o6_drawObjectAt() {
+ int y = pop();
+ int x = pop();
+ int obj = pop();
+ setObjectState(obj, 1, x, y);
+}
+
+void ScummEngine_v6::o6_stopObjectCode() {
+ stopObjectCode();
+}
+
+void ScummEngine_v6::o6_endCutscene() {
+ endCutscene();
+}
+
+void ScummEngine_v6::o6_cutscene() {
+ int args[25];
+ getStackList(args, ARRAYSIZE(args));
+ beginCutscene(args);
+}
+
+void ScummEngine_v6::o6_stopMusic() {
+ _sound->stopAllSounds();
+}
+
+void ScummEngine_v6::o6_freezeUnfreeze() {
+ int a = pop();
+
+ if (a)
+ freezeScripts(a);
+ else
+ unfreezeScripts();
+}
+
+void ScummEngine_v6::o6_cursorCommand() {
+ int a, i;
+ int args[16];
+
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 0x90: // SO_CURSOR_ON Turn cursor on
+ _cursor.state = 1;
+ verbMouseOver(0);
+ break;
+ case 0x91: // SO_CURSOR_OFF Turn cursor off
+ _cursor.state = 0;
+ verbMouseOver(0);
+ break;
+ case 0x92: // SO_USERPUT_ON
+ _userPut = 1;
+ break;
+ case 0x93: // SO_USERPUT_OFF
+ _userPut = 0;
+ break;
+ case 0x94: // SO_CURSOR_SOFT_ON Turn soft cursor on
+ _cursor.state++;
+ if (_cursor.state > 1)
+ error("Cursor state greater than 1 in script");
+ verbMouseOver(0);
+ break;
+ case 0x95: // SO_CURSOR_SOFT_OFF Turn soft cursor off
+ _cursor.state--;
+ verbMouseOver(0);
+ break;
+ case 0x96: // SO_USERPUT_SOFT_ON
+ _userPut++;
+ break;
+ case 0x97: // SO_USERPUT_SOFT_OFF
+ _userPut--;
+ break;
+ case 0x99: // SO_CURSOR_IMAGE Set cursor image
+ {
+ int room, obj;
+ if (_heversion >= 70) {
+ obj = pop();
+ room = getObjectRoom(obj);
+ } else {
+ obj = popRoomAndObj(&room);
+ }
+ setCursorFromImg(obj, room, 1);
+ break;
+ }
+ case 0x9A: // SO_CURSOR_HOTSPOT Set cursor hotspot
+ a = pop();
+ setCursorHotspot(pop(), a);
+ break;
+ case 0x9C: // SO_CHARSET_SET
+ initCharset(pop());
+ break;
+ case 0x9D: // SO_CHARSET_COLOR
+ getStackList(args, ARRAYSIZE(args));
+ for (i = 0; i < 16; i++)
+ _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i];
+ break;
+ case 0xD6: // SO_CURSOR_TRANSPARENT Set cursor transparent color
+ setCursorTransparency(pop());
+ break;
+ default:
+ error("o6_cursorCommand: default case %x", subOp);
+ }
+
+ VAR(VAR_CURSORSTATE) = _cursor.state;
+ VAR(VAR_USERPUT) = _userPut;
+}
+
+void ScummEngine_v6::o6_breakHere() {
+ updateScriptPtr();
+ _currentScript = 0xFF;
+}
+
+void ScummEngine_v6::o6_ifClassOfIs() {
+ int args[16];
+ int num, obj, cls;
+ bool b;
+ int cond = 1;
+
+ num = getStackList(args, ARRAYSIZE(args));
+ obj = pop();
+
+ if (_heversion >= 80 && num == 0) {
+ push(_classData[obj]);
+ return;
+ }
+
+ while (--num >= 0) {
+ cls = args[num];
+ b = getClass(obj, cls);
+ if ((cls & 0x80 && !b) || (!(cls & 0x80) && b))
+ cond = 0;
+ }
+ push(cond);
+}
+
+void ScummEngine_v6::o6_setClass() {
+ int args[16];
+ int num, obj, cls;
+
+ num = getStackList(args, ARRAYSIZE(args));
+ obj = pop();
+
+ while (--num >= 0) {
+ cls = args[num];
+ if (cls == 0)
+ _classData[num] = 0;
+ else if (cls & 0x80)
+ putClass(obj, cls, 1);
+ else
+ putClass(obj, cls, 0);
+ }
+}
+
+void ScummEngine_v6::o6_getState() {
+ push(getState(pop()));
+}
+
+void ScummEngine_v6::o6_setState() {
+ int state = pop();
+ int obj = pop();
+
+ putState(obj, state);
+ markObjectRectAsDirty(obj);
+ if (_bgNeedsRedraw)
+ clearDrawObjectQueue();
+}
+
+void ScummEngine_v6::o6_setOwner() {
+ int owner = pop();
+ int obj = pop();
+ setOwnerOf(obj, owner);
+}
+
+void ScummEngine_v6::o6_getOwner() {
+ push(getOwner(pop()));
+}
+
+void ScummEngine_v6::o6_startSound() {
+ int offset = 0;
+
+ // In Fatty Bear's Birthday Surprise the piano uses offsets 1 - 23 to
+ // indicate which note to play, but only when using the standard piano
+ // sound. See also o60_soundOps()
+ if (_heversion >= 60 && (_gameId != GID_PUTTDEMO))
+ offset = pop();
+
+#ifndef DISABLE_SCUMM_7_8
+ if (_features & GF_DIGI_IMUSE)
+ _imuseDigital->startSfx(pop(), 64);
+ else
+#endif
+ _sound->addSoundToQueue(pop(), offset);
+}
+
+void ScummEngine_v6::o6_stopSound() {
+ _sound->stopSound(pop());
+}
+
+void ScummEngine_v6::o6_startMusic() {
+ if (_features & GF_DIGI_IMUSE)
+ error("o6_startMusic() It shouldn't be called here for imuse digital");
+
+ _sound->addSoundToQueue(pop());
+}
+
+void ScummEngine_v6::o6_stopObjectScript() {
+ stopObjectScript(pop());
+}
+
+void ScummEngine_v6::o6_panCameraTo() {
+ if (_version >= 7) {
+ int y = pop();
+ int x = pop();
+ panCameraTo(x, y);
+ } else {
+ panCameraTo(pop(), 0);
+ }
+}
+
+void ScummEngine_v6::o6_actorFollowCamera() {
+ if (_version >= 7)
+ setCameraFollows(derefActor(pop(), "actorFollowCamera"));
+ else
+ actorFollowCamera(pop());
+}
+
+void ScummEngine_v6::o6_setCameraAt() {
+ if (_version >= 7) {
+ int x, y;
+
+ camera._follows = 0;
+ VAR(VAR_CAMERA_FOLLOWED_ACTOR) = 0;
+
+ y = pop();
+ x = pop();
+
+ setCameraAt(x, y);
+ } else {
+ setCameraAtEx(pop());
+ }
+}
+
+void ScummEngine_v6::o6_loadRoom() {
+ int room = pop();
+ startScene(room, 0, 0);
+ if (_heversion >= 61) {
+ setCameraAt(camera._cur.x, 0);
+ }
+ _fullRedraw = true;
+}
+
+void ScummEngine_v6::o6_stopScript() {
+ int script = pop();
+ if (script == 0)
+ stopObjectCode();
+ else
+ stopScript(script);
+}
+
+void ScummEngine_v6::o6_walkActorToObj() {
+ int act, obj, dist;
+ Actor *a, *a2;
+ int x, y;
+
+ dist = pop();
+ obj = pop();
+ act = pop();
+ a = derefActor(act, "o6_walkActorToObj");
+
+ if (obj >= _numActors) {
+ int wio = whereIsObject(obj);
+
+ if (wio != WIO_FLOBJECT && wio != WIO_ROOM)
+ return;
+
+ int dir;
+ getObjectXYPos(obj, x, y, dir);
+ a->startWalkActor(x, y, dir);
+ } else {
+ a2 = derefActorSafe(obj, "o6_walkActorToObj(2)");
+ if (_gameId == GID_SAMNMAX && a2 == 0) {
+ // WORKAROUND bug #742676 SAM: Fish Farm. Note quite sure why it
+ // happens, whether it's normal or due to a bug in the ScummVM code.
+ debug(0, "o6_walkActorToObj: invalid actor %d", obj);
+ return;
+ }
+ if (!a->isInCurrentRoom() || !a2->isInCurrentRoom())
+ return;
+ if (dist == 0) {
+ dist = a2->_scalex * a2->_width / 0xFF;
+ dist += dist / 2;
+ }
+ x = a2->_pos.x;
+ y = a2->_pos.y;
+ if (x < a->_pos.x)
+ x += dist;
+ else
+ x -= dist;
+ a->startWalkActor(x, y, -1);
+ }
+}
+
+void ScummEngine_v6::o6_walkActorTo() {
+ int x, y;
+ y = pop();
+ x = pop();
+ Actor *a = derefActor(pop(), "o6_walkActorTo");
+ a->startWalkActor(x, y, -1);
+}
+
+void ScummEngine_v6::o6_putActorAtXY() {
+ int room, x, y, act;
+ Actor *a;
+
+ room = pop();
+ y = pop();
+ x = pop();
+ act = pop();
+ a = derefActor(act, "o6_putActorAtXY");
+
+ if (room == 0xFF || room == 0x7FFFFFFF) {
+ room = a->_room;
+ } else {
+ if (a->_visible && _currentRoom != room && getTalkingActor() == a->_number) {
+ stopTalk();
+ }
+ if (room != 0)
+ a->_room = room;
+ }
+ a->putActor(x, y, room);
+}
+
+
+void ScummEngine_v6::o6_putActorAtObject() {
+ int room, obj, x, y;
+ Actor *a;
+
+ obj = popRoomAndObj(&room);
+
+ a = derefActor(pop(), "o6_putActorAtObject");
+ if (whereIsObject(obj) != WIO_NOT_FOUND) {
+ getObjectXYPos(obj, x, y);
+ } else {
+ x = 160;
+ y = 120;
+ }
+ if (room == 0xFF)
+ room = a->_room;
+ a->putActor(x, y, room);
+}
+
+void ScummEngine_v6::o6_faceActor() {
+ int obj = pop();
+ Actor *a = derefActor(pop(), "o6_faceActor");
+ a->faceToObject(obj);
+}
+
+void ScummEngine_v6::o6_animateActor() {
+ int anim = pop();
+ int act = pop();
+ if (_gameId == GID_TENTACLE && _roomResource == 57 &&
+ vm.slot[_currentScript].number == 19 && act == 593) {
+ // WORKAROUND bug #743363: This very odd case (animateActor(593,250))
+ // occurs in DOTT, in the cutscene after George cuts down the "cherry
+ // tree" and the tree Laverne is trapped in vanishes...
+ // Not sure if this means animateActor somehow also must work for objects
+ // (593 is the time machine in room 57), or if this is simply a script bug.
+ act = 6;
+ }
+ if (_gameId == GID_SAMNMAX && _roomResource == 35 &&
+ vm.slot[_currentScript].number == 202 && act == 4 && anim == 14) {
+ // WORKAROUND bug #1223621 (Animation glitch at World of Fish).
+ // Before starting animation 14 of the fisherman, make sure he isn't
+ // talking anymore. This appears to be a bug in the original game as well.
+ if (getTalkingActor() == 4) {
+ stopTalk();
+ }
+ }
+ Actor *a = derefActor(act, "o6_animateActor");
+ a->animateActor(anim);
+}
+
+void ScummEngine_v6::o6_doSentence() {
+ int verb, objectA, objectB, dummy = 0;
+
+ objectB = pop();
+ if (_version < 8)
+ dummy = pop(); // dummy pop (in Sam&Max, seems to be always 0 or 130)
+ objectA = pop();
+ verb = pop();
+
+ doSentence(verb, objectA, objectB);
+}
+
+void ScummEngine_v6::o6_pickupObject() {
+ int obj, room;
+ int i;
+
+ obj = popRoomAndObj(&room);
+ if (room == 0)
+ room = _roomResource;
+
+ for (i = 0; i < _numInventory; i++) {
+ if (_inventory[i] == (uint16)obj) {
+ putOwner(obj, VAR(VAR_EGO));
+ runInventoryScript(obj);
+ return;
+ }
+ }
+
+ addObjectToInventory(obj, room);
+ putOwner(obj, VAR(VAR_EGO));
+ putClass(obj, kObjectClassUntouchable, 1);
+ putState(obj, 1);
+ markObjectRectAsDirty(obj);
+ clearDrawObjectQueue();
+ runInventoryScript(obj);
+}
+
+void ScummEngine_v6::o6_loadRoomWithEgo() {
+ Actor *a;
+ int obj, room, x, y;
+
+ y = pop();
+ x = pop();
+
+ obj = popRoomAndObj(&room);
+
+ a = derefActor(VAR(VAR_EGO), "o6_loadRoomWithEgo");
+ a->putActor(0, 0, room);
+ _egoPositioned = false;
+
+ VAR(VAR_WALKTO_OBJ) = obj;
+ startScene(a->_room, a, obj);
+ VAR(VAR_WALKTO_OBJ) = 0;
+
+ if (_version == 6) {
+ camera._cur.x = camera._dest.x = a->_pos.x;
+ setCameraFollows(a);
+ }
+
+ _fullRedraw = true;
+
+ if (x != -1 && x != 0x7FFFFFFF) {
+ a->startWalkActor(x, y, -1);
+ }
+}
+
+void ScummEngine_v6::o6_getRandomNumber() {
+ int rnd;
+ rnd = _rnd.getRandomNumber(pop());
+ if (VAR_RANDOM_NR != 0xFF)
+ VAR(VAR_RANDOM_NR) = rnd;
+ push(rnd);
+}
+
+void ScummEngine_v6::o6_getRandomNumberRange() {
+ int max = pop();
+ int min = pop();
+ int rnd = _rnd.getRandomNumberRng(min, max);
+ if (VAR_RANDOM_NR != 0xFF)
+ VAR(VAR_RANDOM_NR) = rnd;
+ push(rnd);
+}
+
+void ScummEngine_v6::o6_isScriptRunning() {
+ push(isScriptRunning(pop()));
+}
+
+void ScummEngine_v6::o6_isRoomScriptRunning() {
+ push(isRoomScriptRunning(pop()));
+}
+
+void ScummEngine_v6::o6_getActorMoving() {
+ Actor *a = derefActor(pop(), "o6_getActorMoving");
+ push(a->_moving);
+}
+
+void ScummEngine_v6::o6_getActorRoom() {
+ int act = pop();
+
+ if (act == 0) {
+ // This case occurs at the very least in COMI. That's because in COMI's script 28,
+ // there is a check which looks as follows:
+ // if (((VAR_TALK_ACTOR != 0) && (VAR_HAVE_MSG == 1)) &&
+ // (getActorRoom(VAR_TALK_ACTOR) == VAR_ROOM))
+ // Due to the way this is represented in bytecode, the engine cannot
+ // short circuit. Hence, even though this would be perfectly fine code
+ // in C/C++, here it can (and does) lead to getActorRoom(0) being
+ // invoked. We silently ignore this.
+ push(0);
+ return;
+ }
+
+ if (act == 255) {
+ // This case also occurs in COMI...
+ push(0);
+ return;
+ }
+
+ Actor *a = derefActor(act, "o6_getActorRoom");
+ push(a->_room);
+}
+
+void ScummEngine_v6::o6_getActorWalkBox() {
+ Actor *a = derefActor(pop(), "o6_getActorWalkBox");
+ push(a->_ignoreBoxes ? 0 : a->_walkbox);
+}
+
+void ScummEngine_v6::o6_getActorCostume() {
+ Actor *a = derefActor(pop(), "o6_getActorCostume");
+ push(a->_costume);
+}
+
+void ScummEngine_v6::o6_getActorElevation() {
+ Actor *a = derefActor(pop(), "o6_getActorElevation");
+ push(a->getElevation());
+}
+
+void ScummEngine_v6::o6_getActorWidth() {
+ Actor *a = derefActor(pop(), "o6_getActorWidth");
+ push(a->_width);
+}
+
+void ScummEngine_v6::o6_getActorScaleX() {
+ Actor *a = derefActor(pop(), "o6_getActorScale");
+ push(a->_scalex);
+}
+
+void ScummEngine_v6::o6_getActorAnimCounter1() {
+ Actor *a = derefActor(pop(), "o6_getActorAnimCounter");
+ push(a->_cost.animCounter);
+}
+
+void ScummEngine_v6::o6_getAnimateVariable() {
+ int var = pop();
+ Actor *a = derefActor(pop(), "o6_getAnimateVariable");
+ push(a->getAnimVar(var));
+}
+
+void ScummEngine_v6::o6_isActorInBox() {
+ int box = pop();
+ Actor *a = derefActor(pop(), "o6_isActorInBox");
+ push(checkXYInBoxBounds(box, a->_pos.x, a->_pos.y));
+}
+
+void ScummEngine_v6::o6_getActorLayer() {
+ Actor *a = derefActor(pop(), "getActorLayer");
+ push(a->_layer);
+}
+
+void ScummEngine_v6::o6_getObjectX() {
+ push(getObjX(pop()));
+}
+
+void ScummEngine_v6::o6_getObjectY() {
+ push(getObjY(pop()));
+}
+
+void ScummEngine_v6::o6_getObjectOldDir() {
+ push(getObjOldDir(pop()));
+}
+
+void ScummEngine_v6::o6_getObjectNewDir() {
+ push(getObjNewDir(pop()));
+}
+
+void ScummEngine_v6::o6_findInventory() {
+ int idx = pop();
+ int owner = pop();
+ push(findInventory(owner, idx));
+}
+
+void ScummEngine_v6::o6_getInventoryCount() {
+ push(getInventoryCount(pop()));
+}
+
+void ScummEngine_v6::o6_getVerbFromXY() {
+ int y = pop();
+ int x = pop();
+ int over = findVerbAtPos(x, y);
+ if (over)
+ over = _verbs[over].verbid;
+ push(over);
+}
+
+void ScummEngine_v6::o6_beginOverride() {
+ beginOverride();
+}
+
+void ScummEngine_v6::o6_endOverride() {
+ endOverride();
+}
+
+void ScummEngine_v6::o6_setObjectName() {
+ int obj = pop();
+ setObjectName(obj);
+}
+
+void ScummEngine_v6::o6_isSoundRunning() {
+ int snd = pop();
+
+ if (snd)
+ snd = _sound->isSoundRunning(snd);
+
+ push(snd);
+}
+
+void ScummEngine_v6::o6_setBoxFlags() {
+ int table[65];
+ int num, value;
+
+ value = pop();
+ num = getStackList(table, ARRAYSIZE(table));
+
+ while (--num >= 0) {
+ setBoxFlags(table[num], value);
+ }
+}
+
+void ScummEngine_v6::o6_createBoxMatrix() {
+ createBoxMatrix();
+
+ if ((_gameId == GID_DIG) || (_gameId == GID_CMI))
+ putActors();
+}
+
+void ScummEngine_v6::o6_resourceRoutines() {
+ int resid;
+
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 100: // SO_LOAD_SCRIPT
+ resid = pop();
+ if (_version >= 7)
+ if (resid >= _numGlobalScripts)
+ break;
+ ensureResourceLoaded(rtScript, resid);
+ break;
+ case 101: // SO_LOAD_SOUND
+ resid = pop();
+ ensureResourceLoaded(rtSound, resid);
+ break;
+ case 102: // SO_LOAD_COSTUME
+ resid = pop();
+ ensureResourceLoaded(rtCostume, resid);
+ break;
+ case 103: // SO_LOAD_ROOM
+ resid = pop();
+ ensureResourceLoaded(rtRoom, resid);
+ break;
+ case 104: // SO_NUKE_SCRIPT
+ resid = pop();
+ if (_version >= 7)
+ if (resid >= _numGlobalScripts)
+ break;
+ res.setResourceCounter(rtScript, resid, 0x7F);
+ break;
+ case 105: // SO_NUKE_SOUND
+ resid = pop();
+ res.setResourceCounter(rtSound, resid, 0x7F);
+ break;
+ case 106: // SO_NUKE_COSTUME
+ resid = pop();
+ res.setResourceCounter(rtCostume, resid, 0x7F);
+ break;
+ case 107: // SO_NUKE_ROOM
+ resid = pop();
+ res.setResourceCounter(rtRoom, resid, 0x7F);
+ break;
+ case 108: // SO_LOCK_SCRIPT
+ resid = pop();
+ if (resid >= _numGlobalScripts)
+ break;
+ res.lock(rtScript, resid);
+ break;
+ case 109: // SO_LOCK_SOUND
+ resid = pop();
+ res.lock(rtSound, resid);
+ break;
+ case 110: // SO_LOCK_COSTUME
+ resid = pop();
+ res.lock(rtCostume, resid);
+ break;
+ case 111: // SO_LOCK_ROOM
+ resid = pop();
+ if (resid > 0x7F)
+ resid = _resourceMapper[resid & 0x7F];
+ res.lock(rtRoom, resid);
+ break;
+ case 112: // SO_UNLOCK_SCRIPT
+ resid = pop();
+ if (resid >= _numGlobalScripts)
+ break;
+ res.unlock(rtScript, resid);
+ break;
+ case 113: // SO_UNLOCK_SOUND
+ resid = pop();
+ res.unlock(rtSound, resid);
+ break;
+ case 114: // SO_UNLOCK_COSTUME
+ resid = pop();
+ res.unlock(rtCostume, resid);
+ break;
+ case 115: // SO_UNLOCK_ROOM
+ resid = pop();
+ if (resid > 0x7F)
+ resid = _resourceMapper[resid & 0x7F];
+ res.unlock(rtRoom, resid);
+ break;
+ case 116: // SO_CLEAR_HEAP
+ /* this is actually a scumm message */
+ error("clear heap not working yet");
+ break;
+ case 117: // SO_LOAD_CHARSET
+ resid = pop();
+ loadCharset(resid);
+ break;
+ case 118: // SO_NUKE_CHARSET
+ resid = pop();
+ nukeCharset(resid);
+ break;
+ case 119: // SO_LOAD_OBJECT
+ {
+ int room, obj = popRoomAndObj(&room);
+ loadFlObject(obj, room);
+ break;
+ }
+ default:
+ error("o6_resourceRoutines: default case %d", subOp);
+ }
+}
+
+
+void ScummEngine_v6::o6_roomOps() {
+ int a, b, c, d, e;
+
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 172: // SO_ROOM_SCROLL
+ b = pop();
+ a = pop();
+ if (a < (_screenWidth / 2))
+ a = (_screenWidth / 2);
+ if (b < (_screenWidth / 2))
+ b = (_screenWidth / 2);
+ if (a > _roomWidth - (_screenWidth / 2))
+ a = _roomWidth - (_screenWidth / 2);
+ if (b > _roomWidth - (_screenWidth / 2))
+ b = _roomWidth - (_screenWidth / 2);
+ VAR(VAR_CAMERA_MIN_X) = a;
+ VAR(VAR_CAMERA_MAX_X) = b;
+ break;
+
+ case 174: // SO_ROOM_SCREEN
+ b = pop();
+ a = pop();
+ initScreens(a, b);
+ break;
+
+ case 175: // SO_ROOM_PALETTE
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ setPalColor(d, a, b, c);
+ break;
+
+ case 176: // SO_ROOM_SHAKE_ON
+ setShake(1);
+ break;
+
+ case 177: // SO_ROOM_SHAKE_OFF
+ setShake(0);
+ break;
+
+ case 179: // SO_ROOM_INTENSITY
+ c = pop();
+ b = pop();
+ a = pop();
+ darkenPalette(a, a, a, b, c);
+ break;
+
+ case 180: // SO_ROOM_SAVEGAME
+ _saveTemporaryState = true;
+ _saveLoadSlot = pop();
+ _saveLoadFlag = pop();
+ if (_gameId == GID_TENTACLE)
+ _saveSound = (_saveLoadSlot != 0);
+ break;
+
+ case 181: // SO_ROOM_FADE
+ a = pop();
+ if (a) {
+ _switchRoomEffect = (byte)(a & 0xFF);
+ _switchRoomEffect2 = (byte)(a >> 8);
+ } else {
+ fadeIn(_newEffect);
+ }
+ break;
+
+ case 182: // SO_RGB_ROOM_INTENSITY
+ e = pop();
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ darkenPalette(a, b, c, d, e);
+ break;
+
+ case 183: // SO_ROOM_SHADOW
+ e = pop();
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ setupShadowPalette(a, b, c, d, e, 0, 256);
+ break;
+
+ case 184: // SO_SAVE_STRING
+ error("save string not implemented");
+ break;
+
+ case 185: // SO_LOAD_STRING
+ error("load string not implemented");
+ break;
+
+ case 186: // SO_ROOM_TRANSFORM
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ palManipulateInit(a, b, c, d);
+ break;
+
+ case 187: // SO_CYCLE_SPEED
+ b = pop();
+ a = pop();
+ checkRange(16, 1, a, "o6_roomOps: 187: color cycle out of range (%d)");
+ _colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0;
+ break;
+
+ case 213: // SO_ROOM_NEW_PALETTE
+ a = pop();
+
+ // This opcode is used when turning off noir mode in Sam & Max,
+ // but since our implementation of this feature doesn't change
+ // the original palette there's no need to reload it. Doing it
+ // this way, we avoid some graphics glitches that the original
+ // interpreter had.
+
+ if (_gameId == GID_SAMNMAX && vm.slot[_currentScript].number == 64)
+ setDirtyColors(0, 255);
+ else
+ setPalette(a);
+ break;
+ default:
+ error("o6_roomOps: default case %d", subOp);
+ }
+}
+
+void ScummEngine_v6::o6_actorOps() {
+ Actor *a;
+ int i, j, k;
+ int args[8];
+
+ byte subOp = fetchScriptByte();
+ if (subOp == 197) {
+ _curActor = pop();
+ return;
+ }
+
+ a = derefActorSafe(_curActor, "o6_actorOps");
+ if (!a)
+ return;
+
+ switch (subOp) {
+ case 76: // SO_COSTUME
+ a->setActorCostume(pop());
+ break;
+ case 77: // SO_STEP_DIST
+ j = pop();
+ i = pop();
+ a->setActorWalkSpeed(i, j);
+ break;
+ case 78: // SO_SOUND
+ k = getStackList(args, ARRAYSIZE(args));
+ for (i = 0; i < k; i++)
+ a->_sound[i] = args[i];
+ break;
+ case 79: // SO_WALK_ANIMATION
+ a->_walkFrame = pop();
+ break;
+ case 80: // SO_TALK_ANIMATION
+ a->_talkStopFrame = pop();
+ a->_talkStartFrame = pop();
+ break;
+ case 81: // SO_STAND_ANIMATION
+ a->_standFrame = pop();
+ break;
+ case 82: // SO_ANIMATION
+ // dummy case in scumm6
+ pop();
+ pop();
+ pop();
+ break;
+ case 83: // SO_DEFAULT
+ a->initActor(0);
+ break;
+ case 84: // SO_ELEVATION
+ a->setElevation(pop());
+ break;
+ case 85: // SO_ANIMATION_DEFAULT
+ a->_initFrame = 1;
+ a->_walkFrame = 2;
+ a->_standFrame = 3;
+ a->_talkStartFrame = 4;
+ a->_talkStopFrame = 5;
+ break;
+ case 86: // SO_PALETTE
+ j = pop();
+ i = pop();
+ checkRange(255, 0, i, "Illegal palette slot %d");
+ a->setPalette(i, j);
+ break;
+ case 87: // SO_TALK_COLOR
+ a->_talkColor = pop();
+ break;
+ case 88: // SO_ACTOR_NAME
+ loadPtrToResource(rtActorName, a->_number, NULL);
+ break;
+ case 89: // SO_INIT_ANIMATION
+ a->_initFrame = pop();
+ break;
+ case 91: // SO_ACTOR_WIDTH
+ a->_width = pop();
+ break;
+ case 92: // SO_SCALE
+ i = pop();
+ a->setScale(i, i);
+ break;
+ case 93: // SO_NEVER_ZCLIP
+ a->_forceClip = 0;
+ break;
+ case 225: // SO_ALWAYS_ZCLIP
+ case 94: // SO_ALWAYS_ZCLIP
+ a->_forceClip = pop();
+ break;
+ case 95: // SO_IGNORE_BOXES
+ a->_ignoreBoxes = 1;
+ a->_forceClip = (_version >= 7) ? 100 : 0;
+ if (a->isInCurrentRoom())
+ a->putActor(a->_pos.x, a->_pos.y, a->_room);
+ break;
+ case 96: // SO_FOLLOW_BOXES
+ a->_ignoreBoxes = 0;
+ a->_forceClip = (_version >= 7) ? 100 : 0;
+ if (a->isInCurrentRoom())
+ a->putActor(a->_pos.x, a->_pos.y, a->_room);
+ break;
+ case 97: // SO_ANIMATION_SPEED
+ a->setAnimSpeed(pop());
+ break;
+ case 98: // SO_SHADOW
+ a->_shadowMode = pop();
+ break;
+ case 99: // SO_TEXT_OFFSET
+ a->_talkPosY = pop();
+ a->_talkPosX = pop();
+ break;
+ case 198: // SO_ACTOR_VARIABLE
+ i = pop();
+ a->setAnimVar(pop(), i);
+ break;
+ case 215: // SO_ACTOR_IGNORE_TURNS_ON
+ a->_ignoreTurns = true;
+ break;
+ case 216: // SO_ACTOR_IGNORE_TURNS_OFF
+ a->_ignoreTurns = false;
+ break;
+ case 217: // SO_ACTOR_NEW
+ a->initActor(2);
+ break;
+ case 227: // SO_ACTOR_DEPTH
+ a->_layer = pop();
+ break;
+ case 228: // SO_ACTOR_WALK_SCRIPT
+ a->_walkScript = pop();
+ break;
+ case 229: // SO_ACTOR_STOP
+ a->stopActorMoving();
+ a->startAnimActor(a->_standFrame);
+ break;
+ case 230: /* set direction */
+ a->_moving &= ~MF_TURN;
+ a->setDirection(pop());
+ break;
+ case 231: /* turn to direction */
+ a->turnToDirection(pop());
+ break;
+ case 233: // SO_ACTOR_WALK_PAUSE
+ a->_moving |= MF_FROZEN;
+ break;
+ case 234: // SO_ACTOR_WALK_RESUME
+ a->_moving &= ~MF_FROZEN;
+ break;
+ case 235: // SO_ACTOR_TALK_SCRIPT
+ a->_talkScript = pop();
+ break;
+ default:
+ error("o6_actorOps: default case %d", subOp);
+ }
+}
+
+void ScummEngine_v6::o6_verbOps() {
+ int slot, a, b;
+ VerbSlot *vs;
+
+ byte subOp = fetchScriptByte();
+ if (subOp == 196) {
+ _curVerb = pop();
+ _curVerbSlot = getVerbSlot(_curVerb, 0);
+ checkRange(_numVerbs - 1, 0, _curVerbSlot, "Illegal new verb slot %d");
+ return;
+ }
+ vs = &_verbs[_curVerbSlot];
+ slot = _curVerbSlot;
+ switch (subOp) {
+ case 124: // SO_VERB_IMAGE
+ a = pop();
+ if (_curVerbSlot) {
+ setVerbObject(_roomResource, a, slot);
+ vs->type = kImageVerbType;
+ if (_heversion >= 61)
+ vs->imgindex = a;
+ }
+ break;
+ case 125: // SO_VERB_NAME
+ loadPtrToResource(rtVerb, slot, NULL);
+ vs->type = kTextVerbType;
+ vs->imgindex = 0;
+ break;
+ case 126: // SO_VERB_COLOR
+ vs->color = pop();
+ break;
+ case 127: // SO_VERB_HICOLOR
+ vs->hicolor = pop();
+ break;
+ case 128: // SO_VERB_AT
+ vs->curRect.top = pop();
+ vs->curRect.left = pop();
+ break;
+ case 129: // SO_VERB_ON
+ vs->curmode = 1;
+ break;
+ case 130: // SO_VERB_OFF
+ vs->curmode = 0;
+ break;
+ case 131: // SO_VERB_DELETE
+ if (_heversion >= 60) {
+ slot = getVerbSlot(pop(), 0);
+ }
+ killVerb(slot);
+ break;
+ case 132: // SO_VERB_NEW
+ slot = getVerbSlot(_curVerb, 0);
+ if (slot == 0) {
+ for (slot = 1; slot < _numVerbs; slot++) {
+ if (_verbs[slot].verbid == 0)
+ break;
+ }
+ if (slot == _numVerbs)
+ error("Too many verbs");
+ _curVerbSlot = slot;
+ }
+ vs = &_verbs[slot];
+ vs->verbid = _curVerb;
+ vs->color = 2;
+ vs->hicolor = 0;
+ vs->dimcolor = 8;
+ vs->type = kTextVerbType;
+ vs->charset_nr = _string[0]._default.charset;
+ vs->curmode = 0;
+ vs->saveid = 0;
+ vs->key = 0;
+ vs->center = 0;
+ vs->imgindex = 0;
+ break;
+ case 133: // SO_VERB_DIMCOLOR
+ vs->dimcolor = pop();
+ break;
+ case 134: // SO_VERB_DIM
+ vs->curmode = 2;
+ break;
+ case 135: // SO_VERB_KEY
+ vs->key = pop();
+ break;
+ case 136: // SO_VERB_CENTER
+ vs->center = 1;
+ break;
+ case 137: // SO_VERB_NAME_STR
+ a = pop();
+ if (a == 0) {
+ loadPtrToResource(rtVerb, slot, (const byte *)"");
+ } else {
+ loadPtrToResource(rtVerb, slot, getStringAddress(a));
+ }
+ vs->type = kTextVerbType;
+ vs->imgindex = 0;
+ break;
+ case 139: // SO_VERB_IMAGE_IN_ROOM
+ b = pop();
+ a = pop();
+
+ if (slot && a != vs->imgindex) {
+ setVerbObject(b, a, slot);
+ vs->type = kImageVerbType;
+ vs->imgindex = a;
+ }
+ break;
+ case 140: // SO_VERB_BAKCOLOR
+ vs->bkcolor = pop();
+ break;
+ case 255:
+ drawVerb(slot, 0);
+ verbMouseOver(0);
+ break;
+ default:
+ error("o6_verbops: default case %d", subOp);
+ }
+}
+
+void ScummEngine_v6::o6_getActorFromXY() {
+ int y = pop();
+ int x = pop();
+ int r = getActorFromPos(x, y);
+ push(r);
+}
+
+void ScummEngine_v6::o6_findObject() {
+ int y = pop();
+ int x = pop();
+ int r = findObject(x, y);
+ push(r);
+}
+
+void ScummEngine_v6::o6_pseudoRoom() {
+ int list[100];
+ int num, a, value;
+
+ num = getStackList(list, ARRAYSIZE(list));
+ value = pop();
+
+ while (--num >= 0) {
+ a = list[num];
+ if (a > 0x7F)
+ _resourceMapper[a & 0x7F] = value;
+ }
+}
+
+void ScummEngine_v6::o6_getVerbEntrypoint() {
+ int e = pop();
+ int v = pop();
+ push(getVerbEntrypoint(v, e));
+}
+
+void ScummEngine_v6::o6_arrayOps() {
+ byte subOp = fetchScriptByte();
+ int array = fetchScriptWord();
+ int b, c, d, len;
+ ArrayHeader *ah;
+ int list[128];
+
+ switch (subOp) {
+ case 205: // SO_ASSIGN_STRING
+ b = pop();
+ len = resStrLen(_scriptPointer);
+ ah = defineArray(array, kStringArray, 0, len + 1);
+ copyScriptString(ah->data + b);
+ break;
+ case 208: // SO_ASSIGN_INT_LIST
+ b = pop();
+ c = pop();
+ d = readVar(array);
+ if (d == 0) {
+ defineArray(array, kIntArray, 0, b + c);
+ }
+ while (c--) {
+ writeArray(array, 0, b + c, pop());
+ }
+ break;
+ case 212: // SO_ASSIGN_2DIM_LIST
+ b = pop();
+ len = getStackList(list, ARRAYSIZE(list));
+ d = readVar(array);
+ if (d == 0)
+ error("Must DIM a two dimensional array before assigning");
+ c = pop();
+ while (--len >= 0) {
+ writeArray(array, c, b + len, list[len]);
+ }
+ break;
+ default:
+ error("o6_arrayOps: default case %d (array %d)", subOp, array);
+ }
+}
+
+void ScummEngine_v6::o6_saveRestoreVerbs() {
+ int a, b, c;
+ int slot, slot2;
+
+ c = pop();
+ b = pop();
+ a = pop();
+
+ byte subOp = fetchScriptByte();
+ if (_version == 8) {
+ subOp = (subOp - 141) + 0xB4;
+ }
+
+ switch (subOp) {
+ case 141: // SO_SAVE_VERBS
+ while (a <= b) {
+ slot = getVerbSlot(a, 0);
+ if (slot && _verbs[slot].saveid == 0) {
+ _verbs[slot].saveid = c;
+ drawVerb(slot, 0);
+ verbMouseOver(0);
+ }
+ a++;
+ }
+ break;
+ case 142: // SO_RESTORE_VERBS
+ while (a <= b) {
+ slot = getVerbSlot(a, c);
+ if (slot) {
+ slot2 = getVerbSlot(a, 0);
+ if (slot2)
+ killVerb(slot2);
+ slot = getVerbSlot(a, c);
+ _verbs[slot].saveid = 0;
+ drawVerb(slot, 0);
+ verbMouseOver(0);
+ }
+ a++;
+ }
+ break;
+ case 143: // SO_DELETE_VERBS
+ while (a <= b) {
+ slot = getVerbSlot(a, c);
+ if (slot)
+ killVerb(slot);
+ a++;
+ }
+ break;
+ default:
+ error("o6_saveRestoreVerbs: default case");
+ }
+}
+
+void ScummEngine_v6::o6_drawBox() {
+ int x, y, x2, y2, color;
+ color = pop();
+ y2 = pop();
+ x2 = pop();
+ y = pop();
+ x = pop();
+ drawBox(x, y, x2, y2, color);
+}
+
+void ScummEngine_v6::o6_wait() {
+ int actnum;
+ int offs = -2;
+ Actor *a;
+
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 168: // SO_WAIT_FOR_ACTOR Wait for actor
+ offs = fetchScriptWordSigned();
+ actnum = pop();
+ a = derefActor(actnum, "o6_wait:168");
+ if (a->isInCurrentRoom() && a->_moving)
+ break;
+ return;
+ case 169: // SO_WAIT_FOR_MESSAGE Wait for message
+ if (VAR(VAR_HAVE_MSG))
+ break;
+ return;
+ case 170: // SO_WAIT_FOR_CAMERA Wait for camera
+ if (_version >= 7) {
+ if (camera._dest != camera._cur)
+ break;
+ } else {
+ if (camera._cur.x / 8 != camera._dest.x / 8)
+ break;
+ }
+
+ return;
+ case 171: // SO_WAIT_FOR_SENTENCE
+ if (_sentenceNum) {
+ if (_sentence[_sentenceNum - 1].freezeCount && !isScriptInUse(VAR(VAR_SENTENCE_SCRIPT)))
+ return;
+ break;
+ }
+ if (!isScriptInUse(VAR(VAR_SENTENCE_SCRIPT)))
+ return;
+ break;
+ case 226: // SO_WAIT_FOR_ANIMATION
+ offs = fetchScriptWordSigned();
+ actnum = pop();
+ a = derefActor(actnum, "o6_wait:226");
+ if (a->isInCurrentRoom() && a->_needRedraw)
+ break;
+ return;
+ case 232: // SO_WAIT_FOR_TURN
+ // FIXME: This opcode is really odd. It's used a lot in The Dig.
+ // But sometimes it receives the actor ID as params, and sometimes an
+ // angle. However in (almost?) all cases, just before calling it, _curActor
+ // is set, so we can use it. I tried to add code that detects if an angle
+ // is passed, and if so, wait till that angle is reached, but that leads to hangs.
+ // It would be very good if somebody could disassmble the original code
+ // for this opcode so that we could figure out what's really going on here.
+ //
+ // For now, if the value passed in is divisible by 45, assume it is an
+ // angle, and use _curActor as the actor to wait for.
+ offs = fetchScriptWordSigned();
+ actnum = pop();
+ if (actnum % 45 == 0) {
+ actnum = _curActor;
+ }
+ a = derefActor(actnum, "o6_wait:232b");
+ if (a->isInCurrentRoom() && a->_moving & MF_TURN)
+ break;
+ return;
+ default:
+ error("o6_wait: default case 0x%x", subOp);
+ }
+
+ _scriptPointer += offs;
+ o6_breakHere();
+}
+
+void ScummEngine_v6::o6_soundKludge() {
+ int list[16];
+ int num = getStackList(list, ARRAYSIZE(list));
+
+ _sound->soundKludge(list, num);
+
+ // WORKAROUND for bug #1398195: The room-11-2016 script contains a
+ // slight bug causing it to busy-wait for a sound to finish. Even under
+ // the best of circumstances, this will cause the game to hang briefly.
+ // On platforms where threading is cooperative, it will cause the game
+ // to hang indefinitely. We identify the buggy part of the script by
+ // looking for a soundKludge() opcode immediately followed by a jump.
+
+ if (_gameId == GID_CMI && _roomResource == 11 && vm.slot[_currentScript].number == 2016 && *_scriptPointer == 0x66) {
+ debug(3, "Working around script bug in room-11-2016");
+ o6_breakHere();
+ }
+}
+
+void ScummEngine_v6::o6_isAnyOf() {
+ int list[100];
+ int num;
+ int32 val;
+
+ num = getStackList(list, ARRAYSIZE(list));
+ val = pop();
+
+ while (--num >= 0) {
+ if (list[num] == val) {
+ push(1);
+ return;
+ }
+ }
+
+ push(0);
+}
+
+void ScummEngine_v6::o6_systemOps() {
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 158: // SO_RESTART
+ restart();
+ break;
+ case 159: // SO_PAUSE
+ pauseGame();
+ break;
+ case 160: // SO_QUIT
+ shutDown();
+ break;
+ default:
+ error("o6_systemOps invalid case %d", subOp);
+ }
+}
+
+void ScummEngine_v6::o6_delay() {
+ uint32 delay = (uint16)pop();
+ vm.slot[_currentScript].delay = delay;
+ vm.slot[_currentScript].status = ssPaused;
+ o6_breakHere();
+}
+
+void ScummEngine_v6::o6_delaySeconds() {
+ uint32 delay = (uint32)pop();
+ delay = delay * 60;
+ vm.slot[_currentScript].delay = delay;
+ vm.slot[_currentScript].status = ssPaused;
+ o6_breakHere();
+}
+
+void ScummEngine_v6::o6_delayMinutes() {
+ uint32 delay = (uint16)pop() * 3600;
+ vm.slot[_currentScript].delay = delay;
+ vm.slot[_currentScript].status = ssPaused;
+ o6_breakHere();
+}
+
+void ScummEngine_v6::o6_stopSentence() {
+ _sentenceNum = 0;
+ stopScript(VAR(VAR_SENTENCE_SCRIPT));
+ clearClickedStatus();
+}
+
+void ScummEngine_v6::o6_printLine() {
+ _actorToPrintStrFor = 0xFF;
+ decodeParseString(0, 0);
+}
+
+void ScummEngine_v6::o6_printText() {
+ decodeParseString(1, 0);
+}
+
+void ScummEngine_v6::o6_printDebug() {
+ decodeParseString(2, 0);
+}
+
+void ScummEngine_v6::o6_printSystem() {
+ decodeParseString(3, 0);
+}
+
+void ScummEngine_v6::o6_printActor() {
+ decodeParseString(0, 1);
+}
+
+void ScummEngine_v6::o6_printEgo() {
+ push(VAR(VAR_EGO));
+ decodeParseString(0, 1);
+}
+
+void ScummEngine_v6::o6_talkActor() {
+ _actorToPrintStrFor = pop();
+
+ _string[0].loadDefault();
+ actorTalk(_scriptPointer);
+
+ _scriptPointer += resStrLen(_scriptPointer) + 1;
+}
+
+void ScummEngine_v6::o6_talkEgo() {
+ push(VAR(VAR_EGO));
+ o6_talkActor();
+}
+
+void ScummEngine_v6::o6_dimArray() {
+ int data;
+
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 199: // SO_INT_ARRAY
+ data = kIntArray;
+ break;
+ case 200: // SO_BIT_ARRAY
+ data = kBitArray;
+ break;
+ case 201: // SO_NIBBLE_ARRAY
+ data = kNibbleArray;
+ break;
+ case 202: // SO_BYTE_ARRAY
+ data = kByteArray;
+ break;
+ case 203: // SO_STRING_ARRAY
+ data = kStringArray;
+ break;
+ case 204: // SO_UNDIM_ARRAY
+ nukeArray(fetchScriptWord());
+ return;
+ default:
+ error("o6_dimArray: default case %d", subOp);
+ }
+
+ defineArray(fetchScriptWord(), data, 0, pop());
+}
+
+void ScummEngine_v6::o6_dummy() {
+ if (_heversion >= 60) {
+ stopObjectCode();
+ }
+}
+
+void ScummEngine_v6::o6_dim2dimArray() {
+ int a, b, data;
+
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 199: // SO_INT_ARRAY
+ data = kIntArray;
+ break;
+ case 200: // SO_BIT_ARRAY
+ data = kBitArray;
+ break;
+ case 201: // SO_NIBBLE_ARRAY
+ data = kNibbleArray;
+ break;
+ case 202: // SO_BYTE_ARRAY
+ data = kByteArray;
+ break;
+ case 203: // SO_STRING_ARRAY
+ data = kStringArray;
+ break;
+ default:
+ error("o6_dim2dimArray: default case %d", subOp);
+ }
+
+ b = pop();
+ a = pop();
+ defineArray(fetchScriptWord(), data, a, b);
+}
+
+void ScummEngine_v6::o6_abs() {
+ int a = pop();
+ push(ABS(a));
+}
+
+void ScummEngine_v6::o6_distObjectObject() {
+ int a, b;
+ b = pop();
+ a = pop();
+ push(getDistanceBetween(true, a, 0, true, b, 0));
+}
+
+void ScummEngine_v6::o6_distObjectPt() {
+ int a, b, c;
+ c = pop();
+ b = pop();
+ a = pop();
+ push(getDistanceBetween(true, a, 0, false, b, c));
+}
+
+void ScummEngine_v6::o6_distPtPt() {
+ int a, b, c, d;
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ push(getDistanceBetween(false, a, b, false, c, d));
+}
+
+void ScummEngine_v6::o6_drawBlastObject() {
+ int args[16];
+ int a, b, c, d, e;
+
+ getStackList(args, ARRAYSIZE(args));
+ e = pop();
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ enqueueObject(a, b, c, d, e, 0xFF, 0xFF, 1, 0);
+}
+
+// Set BOMP processing window
+void ScummEngine_v6::o6_setBlastObjectWindow() {
+ pop();
+ pop();
+ pop();
+ pop();
+
+ // None of the scripts of The Dig and Full Throttle use this opcode.
+ // Sam & Max only uses it at the beginning of the highway subgame. In
+ // the original interpreter pop'ed arguments are just ignored and the
+ // clipping blastObject window is defined with (0, 0, 320, 200)...
+ // which matches the screen dimensions and thus, doesn't require
+ // another clipping operation.
+ // So, we just handle this as no-op opcode.
+}
+
+void ScummEngine_v6::o6_kernelSetFunctions() {
+ int args[30];
+ int num;
+ Actor *a;
+
+ num = getStackList(args, ARRAYSIZE(args));
+
+ if (_version >= 7) {
+ switch (args[0]) {
+ case 4:
+ grabCursor(args[1], args[2], args[3], args[4]);
+ break;
+#ifndef DISABLE_SCUMM_7_8
+ case 6: {
+ if (_smushFrameRate == 0)
+ _smushFrameRate = 14;
+
+ // SMUSH movie playback
+ if (args[1] == 0) {
+ assert(getStringAddressVar(VAR_VIDEONAME));
+ if (strcmp((char *)getStringAddressVar(VAR_VIDEONAME), "sq3.san") == 0)
+ _smushFrameRate = 14;
+
+ SmushPlayer *sp = new SmushPlayer(this, _smushFrameRate);
+
+ // Correct incorrect smush filename in Macintosh FT demo
+ if ((_gameId == GID_FT) && (_features & GF_DEMO) && (_platform == Common::kPlatformMacintosh) &&
+ (strcmp((char *)getStringAddressVar(VAR_VIDEONAME), "jumpgorge.san") == 0))
+ sp->play("jumpgorg.san");
+ else
+ sp->play((char *)getStringAddressVar(VAR_VIDEONAME));
+ delete sp;
+ } else if (_gameId == GID_FT) {
+ const int insaneVarNum = ((_features & GF_DEMO) && (_platform == Common::kPlatformPC))
+ ? 232 : 233;
+
+ _insaneRunning = true;
+ _insane->setSmushParams(_smushFrameRate);
+ _insane->runScene(insaneVarNum);
+ _insaneRunning = false;
+ }
+ }
+ break;
+#endif
+ case 12:
+ setCursorFromImg(args[1], (uint) - 1, args[2]);
+ break;
+ case 13:
+ derefActor(args[1], "o6_kernelSetFunctions:13")->remapActorPalette(args[2], args[3], args[4], -1);
+ break;
+ case 14:
+ derefActor(args[1], "o6_kernelSetFunctions:14")->remapActorPalette(args[2], args[3], args[4], args[5]);
+ break;
+ case 15:
+ _smushFrameRate = args[1];
+ break;
+ case 16:
+ case 17:
+ enqueueText(getStringAddressVar(VAR_STRING2DRAW), args[3], args[4], args[2], args[1], (args[0] == 16));
+ break;
+ case 20:
+ // it's used for turn on/off 'RadioChatter' effect for voice in the dig, but i's not needed
+ break;
+ case 107:
+ a = derefActor(args[1], "o6_kernelSetFunctions: 107");
+ a->setScale((unsigned char)args[2], -1);
+ break;
+ case 108:
+ setupShadowPalette(args[1], args[2], args[3], args[4], args[5], args[6]);
+ break;
+ case 109:
+ setupShadowPalette(0, args[1], args[2], args[3], args[4], args[5]);
+ break;
+ case 114:
+ error("o6_kernelSetFunctions: stub114()");
+ break;
+ case 117:
+ freezeScripts(2);
+ break;
+ case 118:
+ enqueueObject(args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], 3);
+ break;
+ case 119:
+ enqueueObject(args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], 0);
+ break;
+ case 124:
+ _saveSound = args[1];
+ break;
+ case 215:
+ ConfMan.set("subtitles", args[1] != 0);
+ break;
+ default:
+ error("o6_kernelSetFunctions: default case %d (param count %d)", args[0], num);
+ break;
+ }
+ } else {
+ switch (args[0]) {
+ case 3:
+ // Dummy case
+ break;
+ case 4:
+ grabCursor(args[1], args[2], args[3], args[4]);
+ break;
+ case 5:
+ fadeOut(args[1]);
+ break;
+ case 6:
+ _fullRedraw = true;
+ redrawBGAreas();
+ setActorRedrawFlags();
+ processActors();
+ fadeIn(args[1]);
+ break;
+ case 8:
+ startManiac();
+ break;
+ case 9:
+ killAllScriptsExceptCurrent();
+ break;
+ case 104: /* samnmax */
+ nukeFlObjects(args[2], args[3]);
+ break;
+ case 107: /* set actor scale */
+ a = derefActor(args[1], "o6_kernelSetFunctions: 107");
+ a->setScale((unsigned char)args[2], -1);
+ break;
+ case 108: /* create proc_special_palette */
+ case 109:
+ // Case 108 and 109 share the same function
+ if (num != 6)
+ error("o6_kernelSetFunctions sub op %d: expected 6 params but got %d", args[0], num);
+ setupShadowPalette(args[3], args[4], args[5], args[1], args[2], 0, 256);
+ break;
+ case 110:
+ _charset->clearCharsetMask();
+ break;
+ case 111:
+ a = derefActor(args[1], "o6_kernelSetFunctions: 111");
+ a->_shadowMode = args[2] + args[3];
+ break;
+ case 112: /* palette shift? */
+ setupShadowPalette(args[3], args[4], args[5], args[1], args[2], args[6], args[7]);
+ break;
+ case 114:
+ // Sam & Max film noir mode
+ if (_gameId == GID_SAMNMAX) {
+ // At this point ScummVM will already have set
+ // variable 0x8000 to indicate that the game is
+ // in film noir mode. All we have to do here is
+ // to mark the palette as "dirty", because
+ // updatePalette() will desaturate the colors
+ // as they are uploaded to the backend.
+ //
+ // This actually works better than the original
+ // interpreter, where actors would sometimes
+ // still be drawn in color.
+ setDirtyColors(0, 255);
+ } else
+ error("stub o6_kernelSetFunctions_114()");
+ break;
+ case 117:
+ // Sam & Max uses this opcode in script-43, right
+ // before a screensaver is selected.
+ //
+ // Sam & Max uses variable 132 to specify the number of
+ // minutes of inactivity (no mouse movements) before
+ // starting the screensaver, so setting it to 0 will
+ // help in debugging.
+ freezeScripts(0x80);
+ break;
+ case 119:
+ enqueueObject(args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], 0);
+ break;
+ case 120:
+ swapPalColors(args[1], args[2]);
+ break;
+ case 122:
+ VAR(VAR_SOUNDRESULT) =
+ (short)_imuse->doCommand (num - 1, &args[1]);
+ break;
+ case 123:
+ copyPalColor(args[2], args[1]);
+ break;
+ case 124:
+ _saveSound = args[1];
+ break;
+ default:
+ error("o6_kernelSetFunctions: default case %d (param count %d)", args[0], num);
+ break;
+ }
+ }
+}
+
+void ScummEngine_v6::o6_kernelGetFunctions() {
+ int args[30];
+ int i;
+ int slot;
+ Actor *a;
+
+ getStackList(args, ARRAYSIZE(args));
+
+ switch (args[0]) {
+ case 113:
+ // This is used for the Sam & Max paint-by-numbers mini-game
+ // to find out what color to change. I think that what we have
+ // the virtual mouse coordinates, because that's what used
+ // everywhere else in the script.
+
+ {
+ VirtScreen *vs = &virtscr[0];
+ if (args[1] < 0 || args[1] >= vs->w || args[2] < 0 || args[2] >= vs->h) {
+ // FIXME: Until we know what to do in this case...
+ debug(0, "o6_kernelGetFunctions:113: asking for pixel (%d, %d) outside of %dx%d screen", args[1], args[2], vs->w, vs->h);
+ push(0);
+ } else
+ push(*((byte *)vs->pixels + args[1] + args[2] * vs->pitch));
+ }
+ break;
+ case 115:
+ push(getSpecialBox(args[1], args[2]));
+ break;
+ case 116:
+ push(checkXYInBoxBounds(args[3], args[1], args[2]));
+ break;
+ case 206:
+ push(remapPaletteColor(args[1], args[2], args[3], -1));
+ break;
+ case 207:
+ i = getObjectIndex(args[1]);
+ assert(i);
+ push(_objs[i].x_pos);
+ break;
+ case 208:
+ i = getObjectIndex(args[1]);
+ assert(i);
+ push(_objs[i].y_pos);
+ break;
+ case 209:
+ i = getObjectIndex(args[1]);
+ assert(i);
+ push(_objs[i].width);
+ break;
+ case 210:
+ i = getObjectIndex(args[1]);
+ assert(i);
+ push(_objs[i].height);
+ break;
+ case 211:
+ /*
+ 13 = thrust
+ 336 = thrust
+ 328 = thrust
+ 27 = abort
+ 97 = left
+ 331 = left
+ 115 = right
+ 333 = right
+ */
+
+ push(getKeyState(args[1]));
+ break;
+ case 212:
+ a = derefActor(args[1], "o6_kernelGetFunctions:212");
+ // This is used by walk scripts
+ push(a->_frame);
+ break;
+ case 213:
+ slot = getVerbSlot(args[1], 0);
+ push(_verbs[slot].curRect.left);
+ break;
+ case 214:
+ slot = getVerbSlot(args[1], 0);
+ push(_verbs[slot].curRect.top);
+ break;
+ case 215:
+ if ((_extraBoxFlags[args[1]] & 0x00FF) == 0x00C0) {
+ push(_extraBoxFlags[args[1]]);
+ } else {
+ push(getBoxFlags(args[1]));
+ }
+ break;
+ default:
+ error("o6_kernelGetFunctions: default case %d", args[0]);
+ }
+}
+
+// FIXME: check either some warning will trigger. I am not sure that those
+// keys are queried in scripts at all
+int ScummEngine::getKeyState(int key) {
+ switch (key) {
+ case 0x145:
+ warning("ScummEngine::getKeyState(%x) 'numlock' is probed", key);
+ return 0;
+ break;
+ case 0x164:
+ warning("ScummEngine::getKeyState(%x) 'left shift' is probed", key);
+ return 0;
+ break;
+ case 0x165:
+ warning("ScummEngine::getKeyState(%x) 'right shift' is probed", key);
+ return 0;
+ break;
+ case 0x166:
+ case 0x167:
+ warning("ScummEngine::getKeyState(%x) 'alt' is probed", key);
+ return 0;
+ break;
+ case 0x168:
+ warning("ScummEngine::getKeyState(%x) 'left ctrl' is probed", key);
+ return 0;
+ break;
+ case 0x202a:
+ warning("ScummEngine::getKeyState(%x) 'gray *' is probed", key);
+ return 0;
+ break;
+ case 0x202d:
+ warning("ScummEngine::getKeyState(%x) 'gray -' is probed", key);
+ return 0;
+ break;
+ case 0x147: // Home
+ return (_keyDownMap[0x107] || _keyDownMap[0x115]) ? 1 : 0;
+ break;
+ case 0x148: // Up
+ return (_keyDownMap[0x108] || _keyDownMap[0x111] ||
+ _keyDownMap[0x38]) ? 1 : 0;
+ break;
+ case 0x149: // PgUp
+ return (_keyDownMap[0x109] || _keyDownMap[0x118]) ? 1 : 0;
+ break;
+ case 0x14A: // Gray-
+ return (_keyDownMap[0x10d] || _keyDownMap[0x2d]) ? 1 : 0;
+ break;
+ case 0x14B: // Left
+ return (_keyDownMap[0x104] || _keyDownMap[0x114] ||
+ _keyDownMap[0x34]) ? 1 : 0;
+ break;
+ case 0x14C: // 5
+ return (_keyDownMap[0x105]) ? 1 : 0;
+ break;
+ case 0x14D: // Right
+ return (_keyDownMap[0x106] || _keyDownMap[0x113] ||
+ _keyDownMap[0x36]) ? 1 : 0;
+ break;
+ case 0x14E: // Gray+
+ return (_keyDownMap[0x10e] ||
+ (_keyDownMap[0x13d] && _keyDownMap[0x12f])) ? 1 : 0;
+ break;
+ case 0x14F: // End
+ return (_keyDownMap[0x101] || _keyDownMap[0x117]) ? 1 : 0;
+ break;
+ case 0x150: // Down
+ return (_keyDownMap[0x102] || _keyDownMap[0x112] ||
+ _keyDownMap[0x32]) ? 1 : 0;
+ break;
+ case 0x151: // PgDn
+ return (_keyDownMap[0x103] || _keyDownMap[0x119]) ? 1 : 0;
+ break;
+ case 0x152: // Ins
+ return (_keyDownMap[0x100] || _keyDownMap[0x115]) ? 1 : 0;
+ break;
+ case 0x153: // Del
+ return (_keyDownMap[0x10a] || _keyDownMap[0x7f]) ? 1 : 0;
+ break;
+ default:
+ break;
+ }
+
+ if (key >= 0x13b && key <= 0x144) { // F1-F10
+ key -= 0x13b - 0x11a;
+ } else if (key >= 0x154 && key <= 0x15d) { // Shift+F1-F10
+ key -= 0x154 - 0x11a; // map it to just F1-F10
+
+ warning("ScummEngine::getKeyState(%x) 'Shift-F%d' is probed", key, key-0x153);
+ } else if (key > 0x8000) { // Alt
+ key -= 0x8000;
+ key += 154; // see ScummEngine::parseEvents()
+ } else if (key > 0x4000) { // Ctrl
+ key -= 0x4000;
+ key -= 0x40;
+ } else if (key > 0x2000) { // Gray keys
+ key -= 0x2000;
+ warning("ScummEngine::getKeyState(%x) 'gray key' is probed", key);
+ }
+
+ return (_keyDownMap[key]) ? 1 : 0;
+}
+
+void ScummEngine_v6::o6_delayFrames() {
+ ScriptSlot *ss = &vm.slot[_currentScript];
+ if (ss->delayFrameCount == 0) {
+ ss->delayFrameCount = pop();
+ } else {
+ ss->delayFrameCount--;
+ }
+ if (ss->delayFrameCount) {
+ _scriptPointer--;
+ o6_breakHere();
+ }
+}
+
+void ScummEngine_v6::o6_pickOneOf() {
+ int args[100];
+ int i, num;
+
+ num = getStackList(args, ARRAYSIZE(args));
+ i = pop();
+ if (i < 0 || i > num)
+ error("o6_pickOneOf: %d out of range (0, %d)", i, num - 1);
+ push(args[i]);
+}
+
+void ScummEngine_v6::o6_pickOneOfDefault() {
+ int args[100];
+ int i, num, def;
+
+ def = pop();
+ num = getStackList(args, ARRAYSIZE(args));
+ i = pop();
+ if (i < 0 || i >= num)
+ i = def;
+ else
+ i = args[i];
+ push(i);
+}
+
+void ScummEngine_v6::o6_stampObject() {
+ int object, x, y, state;
+
+ state = pop();
+ y = pop();
+ x = pop();
+ object = pop();
+ if (_version >= 7 && object < 30) {
+ if (state == 0)
+ state = 255;
+
+ Actor *a = derefActor(object, "o6_stampObject");
+ a->_scalex = state;
+ a->_scaley = state;
+ a->putActor(x, y, _currentRoom);
+ a->_drawToBackBuf = true;
+ a->drawActorCostume();
+ a->_drawToBackBuf = false;
+ a->drawActorCostume();
+ return;
+ }
+
+ if (state == 0)
+ state = 1;
+
+ int objnum = getObjectIndex(object);
+ if (objnum == -1)
+ return;
+
+ if (x != -1) {
+ _objs[objnum].x_pos = x * 8;
+ _objs[objnum].y_pos = y * 8;
+ }
+
+ putState(object, state);
+ drawObject(objnum, 0);
+}
+
+void ScummEngine_v6::o6_stopTalking() {
+ stopTalk();
+}
+
+void ScummEngine_v6::o6_findAllObjects() {
+ int room = pop();
+ int i = 1;
+
+ if (room != _currentRoom)
+ error("o6_findAllObjects: current room is not %d", room);
+ writeVar(0, 0);
+ defineArray(0, kIntArray, 0, _numLocalObjects + 1);
+ writeArray(0, 0, 0, _numLocalObjects);
+
+ while (i < _numLocalObjects) {
+ writeArray(0, 0, i, _objs[i].obj_nr);
+ i++;
+ }
+
+ push(readVar(0));
+}
+
+void ScummEngine_v6::shuffleArray(int num, int minIdx, int maxIdx) {
+ int range = maxIdx - minIdx;
+ int count = range * 2;
+
+ // Shuffle the array 'num'
+ while (count--) {
+ // Determine two random elements...
+ int rand1 = _rnd.getRandomNumber(range) + minIdx;
+ int rand2 = _rnd.getRandomNumber(range) + minIdx;
+
+ // ...and swap them
+ int val1 = readArray(num, 0, rand1);
+ int val2 = readArray(num, 0, rand2);
+ writeArray(num, 0, rand1, val2);
+ writeArray(num, 0, rand2, val1);
+ }
+}
+
+void ScummEngine_v6::o6_shuffle() {
+ int b = pop();
+ int a = pop();
+ shuffleArray(fetchScriptWord(), a, b);
+}
+
+void ScummEngine_v6::o6_pickVarRandom() {
+ int num;
+ int args[100];
+ int dim1;
+
+ num = getStackList(args, ARRAYSIZE(args));
+ int value = fetchScriptWord();
+
+ if (readVar(value) == 0) {
+ defineArray(value, kIntArray, 0, num);
+ if (num > 0) {
+ int16 counter = 0;
+ do {
+ writeArray(value, 0, counter + 1, args[counter]);
+ } while (++counter < num);
+ }
+
+ shuffleArray(value, 1, num);
+ writeArray(value, 0, 0, 2);
+ push(readArray(value, 0, 1));
+ return;
+ }
+
+ num = readArray(value, 0, 0);
+
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(value));
+ dim1 = FROM_LE_16(ah->dim1) - 1;
+
+ if (dim1 < num) {
+ int16 var_2 = readArray(value, 0, num - 1);
+ shuffleArray(value, 1, dim1);
+ if (readArray(value, 0, 1) == var_2) {
+ num = 2;
+ } else {
+ num = 1;
+ }
+ }
+
+ writeArray(value, 0, 0, num + 1);
+ push(readArray(value, 0, num));
+}
+
+void ScummEngine_v6::o6_getDateTime() {
+ struct tm *t;
+ time_t now = time(NULL);
+
+ t = localtime(&now);
+
+ VAR(VAR_TIMEDATE_YEAR) = t->tm_year;
+ VAR(VAR_TIMEDATE_MONTH) = t->tm_mon;
+ VAR(VAR_TIMEDATE_DAY) = t->tm_mday;
+ VAR(VAR_TIMEDATE_HOUR) = t->tm_hour;
+ VAR(VAR_TIMEDATE_MINUTE) = t->tm_min;
+
+ if (_version == 8)
+ VAR(VAR_TIMEDATE_SECOND) = t->tm_sec;
+}
+
+void ScummEngine_v6::o6_getPixel() {
+ // This opcode is used to check fir ground area in the "Asteroid Lander"
+ // minigame in "The Dig"
+ int x, y;
+
+ if (_heversion == 61) {
+ x = pop();
+ y = pop();
+ } else {
+ y = pop();
+ x = pop();
+ }
+
+ VirtScreen *vs = findVirtScreen(y);
+
+ if (vs == NULL || x > _screenWidth - 1 || x < 0) {
+ push(-1);
+ return;
+ }
+
+ byte area = *vs->getPixels(x, y - vs->topline);
+ push(area);
+}
+
+void ScummEngine_v6::o6_setBoxSet() {
+ int arg = pop() - 1;
+
+ const byte *room = getResourceAddress(rtRoom, _roomResource);
+ const byte *boxd = NULL, *boxm = NULL;
+ int32 dboxSize, mboxSize;
+ int i;
+
+ ResourceIterator boxds(room, false);
+ for (i = 0; i < arg; i++)
+ boxd = boxds.findNext(MKID('BOXD'));
+
+ if (!boxd)
+ error("ScummEngine_v6::o6_setBoxSet: Can't find dboxes for set %d", arg);
+
+ dboxSize = READ_BE_UINT32(boxd + 4) - 8;
+ byte *matrix = res.createResource(rtMatrix, 2, dboxSize);
+
+ assert(matrix);
+ memcpy(matrix, boxd + 8, dboxSize);
+
+ ResourceIterator boxms(room, false);
+ for (i = 0; i < arg; i++)
+ boxm = boxms.findNext(MKID('BOXM'));
+
+ if (!boxm)
+ error("ScummEngine_v6::o6_setBoxSet: Can't find mboxes for set %d", arg);
+
+ mboxSize = READ_BE_UINT32(boxm + 4) - 8;
+ matrix = res.createResource(rtMatrix, 1, mboxSize);
+
+ assert(matrix);
+ memcpy(matrix, boxm + 8, mboxSize);
+
+ if (_version == 7)
+ putActors();
+}
+
+void ScummEngine_v6::decodeParseString(int m, int n) {
+ byte b = fetchScriptByte();
+
+ switch (b) {
+ case 65: // SO_AT
+ _string[m].ypos = pop();
+ _string[m].xpos = pop();
+ _string[m].overhead = false;
+ break;
+ case 66: // SO_COLOR
+ _string[m].color = pop();
+ break;
+ case 67: // SO_CLIPPED
+ _string[m].right = pop();
+ break;
+ case 69: // SO_CENTER
+ _string[m].center = true;
+ _string[m].overhead = false;
+ break;
+ case 71: // SO_LEFT
+ _string[m].center = false;
+ _string[m].overhead = false;
+ break;
+ case 72: // SO_OVERHEAD
+ _string[m].overhead = true;
+ _string[m].no_talk_anim = false;
+ break;
+ case 73: // SO_SAY_VOICE
+ error("decodeParseString: case 73");
+ break;
+ case 74: // SO_MUMBLE
+ _string[m].no_talk_anim = true;
+ break;
+ case 75: // SO_TEXTSTRING
+ printString(m, _scriptPointer);
+ _scriptPointer += resStrLen(_scriptPointer) + 1;
+ break;
+ case 0xFE:
+ _string[m].loadDefault();
+ if (n)
+ _actorToPrintStrFor = pop();
+ break;
+ case 0xFF:
+ _string[m].saveDefault();
+ break;
+ default:
+ error("decodeParseString: default case 0x%x", b);
+ }
+}
+
+} // End of namespace Scumm