diff options
Diffstat (limited to 'engines/scumm/script_v2.cpp')
-rw-r--r-- | engines/scumm/script_v2.cpp | 1629 |
1 files changed, 1629 insertions, 0 deletions
diff --git a/engines/scumm/script_v2.cpp b/engines/scumm/script_v2.cpp new file mode 100644 index 0000000000..880628f53e --- /dev/null +++ b/engines/scumm/script_v2.cpp @@ -0,0 +1,1629 @@ +/* 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 "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/intern.h" +#include "scumm/object.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/util.h" +#include "scumm/verbs.h" + +namespace Scumm { + +#define OPCODE(x) _OPCODE(ScummEngine_v2, x) + +void ScummEngine_v2::setupOpcodes() { + static const OpcodeEntryV2 opcodes[256] = { + /* 00 */ + OPCODE(o5_stopObjectCode), + OPCODE(o2_putActor), + OPCODE(o5_startMusic), + OPCODE(o5_getActorRoom), + /* 04 */ + OPCODE(o2_isGreaterEqual), + OPCODE(o2_drawObject), + OPCODE(o2_getActorElevation), + OPCODE(o2_setState08), + /* 08 */ + OPCODE(o5_isNotEqual), + OPCODE(o5_faceActor), + OPCODE(o2_assignVarWordIndirect), + OPCODE(o2_setObjPreposition), + /* 0C */ + OPCODE(o2_resourceRoutines), + OPCODE(o5_walkActorToActor), + OPCODE(o2_putActorAtObject), + OPCODE(o2_ifNotState08), + /* 10 */ + OPCODE(o5_getObjectOwner), + OPCODE(o2_animateActor), + OPCODE(o2_panCameraTo), + OPCODE(o2_actorOps), + /* 14 */ + OPCODE(o5_print), + OPCODE(o2_actorFromPos), + OPCODE(o5_getRandomNr), + OPCODE(o2_clearState02), + /* 18 */ + OPCODE(o5_jumpRelative), + OPCODE(o2_doSentence), + OPCODE(o5_move), + OPCODE(o2_setBitVar), + /* 1C */ + OPCODE(o5_startSound), + OPCODE(o2_ifClassOfIs), + OPCODE(o2_walkActorTo), + OPCODE(o2_ifState02), + /* 20 */ + OPCODE(o5_stopMusic), + OPCODE(o2_putActor), + OPCODE(o5_saveLoadGame), + OPCODE(o2_getActorY), + /* 24 */ + OPCODE(o2_loadRoomWithEgo), + OPCODE(o2_drawObject), + OPCODE(o5_setVarRange), + OPCODE(o2_setState04), + /* 28 */ + OPCODE(o5_equalZero), + OPCODE(o2_setOwnerOf), + OPCODE(o2_addIndirect), + OPCODE(o5_delayVariable), + /* 2C */ + OPCODE(o2_assignVarByte), + OPCODE(o5_putActorInRoom), + OPCODE(o2_delay), + OPCODE(o2_ifNotState04), + /* 30 */ + OPCODE(o2_setBoxFlags), + OPCODE(o2_getBitVar), + OPCODE(o2_setCameraAt), + OPCODE(o2_roomOps), + /* 34 */ + OPCODE(o5_getDist), + OPCODE(o2_findObject), + OPCODE(o2_walkActorToObject), + OPCODE(o2_setState01), + /* 38 */ + OPCODE(o2_isLessEqual), + OPCODE(o2_doSentence), + OPCODE(o2_subtract), + OPCODE(o2_waitForActor), + /* 3C */ + OPCODE(o5_stopSound), + OPCODE(o2_setActorElevation), + OPCODE(o2_walkActorTo), + OPCODE(o2_ifNotState01), + /* 40 */ + OPCODE(o2_cutscene), + OPCODE(o2_putActor), + OPCODE(o2_startScript), + OPCODE(o2_getActorX), + /* 44 */ + OPCODE(o2_isLess), + OPCODE(o2_drawObject), + OPCODE(o5_increment), + OPCODE(o2_clearState08), + /* 48 */ + OPCODE(o5_isEqual), + OPCODE(o5_faceActor), + OPCODE(o2_chainScript), + OPCODE(o2_setObjPreposition), + /* 4C */ + OPCODE(o2_waitForSentence), + OPCODE(o5_walkActorToActor), + OPCODE(o2_putActorAtObject), + OPCODE(o2_ifState08), + /* 50 */ + OPCODE(o2_pickupObject), + OPCODE(o2_animateActor), + OPCODE(o5_actorFollowCamera), + OPCODE(o2_actorOps), + /* 54 */ + OPCODE(o5_setObjectName), + OPCODE(o2_actorFromPos), + OPCODE(o5_getActorMoving), + OPCODE(o2_setState02), + /* 58 */ + OPCODE(o2_beginOverride), + OPCODE(o2_doSentence), + OPCODE(o2_add), + OPCODE(o2_setBitVar), + /* 5C */ + OPCODE(o2_dummy), + OPCODE(o2_ifClassOfIs), + OPCODE(o2_walkActorTo), + OPCODE(o2_ifNotState02), + /* 60 */ + OPCODE(o2_cursorCommand), + OPCODE(o2_putActor), + OPCODE(o2_stopScript), + OPCODE(o5_getActorFacing), + /* 64 */ + OPCODE(o2_loadRoomWithEgo), + OPCODE(o2_drawObject), + OPCODE(o5_getClosestObjActor), + OPCODE(o2_clearState04), + /* 68 */ + OPCODE(o5_isScriptRunning), + OPCODE(o2_setOwnerOf), + OPCODE(o2_subIndirect), + OPCODE(o2_dummy), + /* 6C */ + OPCODE(o2_getObjPreposition), + OPCODE(o5_putActorInRoom), + OPCODE(o2_dummy), + OPCODE(o2_ifState04), + /* 70 */ + OPCODE(o2_lights), + OPCODE(o5_getActorCostume), + OPCODE(o5_loadRoom), + OPCODE(o2_roomOps), + /* 74 */ + OPCODE(o5_getDist), + OPCODE(o2_findObject), + OPCODE(o2_walkActorToObject), + OPCODE(o2_clearState01), + /* 78 */ + OPCODE(o2_isGreater), + OPCODE(o2_doSentence), + OPCODE(o2_verbOps), + OPCODE(o2_getActorWalkBox), + /* 7C */ + OPCODE(o5_isSoundRunning), + OPCODE(o2_setActorElevation), + OPCODE(o2_walkActorTo), + OPCODE(o2_ifState01), + /* 80 */ + OPCODE(o5_breakHere), + OPCODE(o2_putActor), + OPCODE(o5_startMusic), + OPCODE(o5_getActorRoom), + /* 84 */ + OPCODE(o2_isGreaterEqual), + OPCODE(o2_drawObject), + OPCODE(o2_getActorElevation), + OPCODE(o2_setState08), + /* 88 */ + OPCODE(o5_isNotEqual), + OPCODE(o5_faceActor), + OPCODE(o2_assignVarWordIndirect), + OPCODE(o2_setObjPreposition), + /* 8C */ + OPCODE(o2_resourceRoutines), + OPCODE(o5_walkActorToActor), + OPCODE(o2_putActorAtObject), + OPCODE(o2_ifNotState08), + /* 90 */ + OPCODE(o5_getObjectOwner), + OPCODE(o2_animateActor), + OPCODE(o2_panCameraTo), + OPCODE(o2_actorOps), + /* 94 */ + OPCODE(o5_print), + OPCODE(o2_actorFromPos), + OPCODE(o5_getRandomNr), + OPCODE(o2_clearState02), + /* 98 */ + OPCODE(o2_restart), + OPCODE(o2_doSentence), + OPCODE(o5_move), + OPCODE(o2_setBitVar), + /* 9C */ + OPCODE(o5_startSound), + OPCODE(o2_ifClassOfIs), + OPCODE(o2_walkActorTo), + OPCODE(o2_ifState02), + /* A0 */ + OPCODE(o5_stopObjectCode), + OPCODE(o2_putActor), + OPCODE(o5_saveLoadGame), + OPCODE(o2_getActorY), + /* A4 */ + OPCODE(o2_loadRoomWithEgo), + OPCODE(o2_drawObject), + OPCODE(o5_setVarRange), + OPCODE(o2_setState04), + /* A8 */ + OPCODE(o5_notEqualZero), + OPCODE(o2_setOwnerOf), + OPCODE(o2_addIndirect), + OPCODE(o2_switchCostumeSet), + /* AC */ + OPCODE(o2_drawSentence), + OPCODE(o5_putActorInRoom), + OPCODE(o2_waitForMessage), + OPCODE(o2_ifNotState04), + /* B0 */ + OPCODE(o2_setBoxFlags), + OPCODE(o2_getBitVar), + OPCODE(o2_setCameraAt), + OPCODE(o2_roomOps), + /* B4 */ + OPCODE(o5_getDist), + OPCODE(o2_findObject), + OPCODE(o2_walkActorToObject), + OPCODE(o2_setState01), + /* B8 */ + OPCODE(o2_isLessEqual), + OPCODE(o2_doSentence), + OPCODE(o2_subtract), + OPCODE(o2_waitForActor), + /* BC */ + OPCODE(o5_stopSound), + OPCODE(o2_setActorElevation), + OPCODE(o2_walkActorTo), + OPCODE(o2_ifNotState01), + /* C0 */ + OPCODE(o2_endCutscene), + OPCODE(o2_putActor), + OPCODE(o2_startScript), + OPCODE(o2_getActorX), + /* C4 */ + OPCODE(o2_isLess), + OPCODE(o2_drawObject), + OPCODE(o5_decrement), + OPCODE(o2_clearState08), + /* C8 */ + OPCODE(o5_isEqual), + OPCODE(o5_faceActor), + OPCODE(o2_chainScript), + OPCODE(o2_setObjPreposition), + /* CC */ + OPCODE(o5_pseudoRoom), + OPCODE(o5_walkActorToActor), + OPCODE(o2_putActorAtObject), + OPCODE(o2_ifState08), + /* D0 */ + OPCODE(o2_pickupObject), + OPCODE(o2_animateActor), + OPCODE(o5_actorFollowCamera), + OPCODE(o2_actorOps), + /* D4 */ + OPCODE(o5_setObjectName), + OPCODE(o2_actorFromPos), + OPCODE(o5_getActorMoving), + OPCODE(o2_setState02), + /* D8 */ + OPCODE(o5_printEgo), + OPCODE(o2_doSentence), + OPCODE(o2_add), + OPCODE(o2_setBitVar), + /* DC */ + OPCODE(o2_dummy), + OPCODE(o2_ifClassOfIs), + OPCODE(o2_walkActorTo), + OPCODE(o2_ifNotState02), + /* E0 */ + OPCODE(o2_cursorCommand), + OPCODE(o2_putActor), + OPCODE(o2_stopScript), + OPCODE(o5_getActorFacing), + /* E4 */ + OPCODE(o2_loadRoomWithEgo), + OPCODE(o2_drawObject), + OPCODE(o5_getClosestObjActor), + OPCODE(o2_clearState04), + /* E8 */ + OPCODE(o5_isScriptRunning), + OPCODE(o2_setOwnerOf), + OPCODE(o2_subIndirect), + OPCODE(o2_dummy), + /* EC */ + OPCODE(o2_getObjPreposition), + OPCODE(o5_putActorInRoom), + OPCODE(o2_dummy), + OPCODE(o2_ifState04), + /* F0 */ + OPCODE(o2_lights), + OPCODE(o5_getActorCostume), + OPCODE(o5_loadRoom), + OPCODE(o2_roomOps), + /* F4 */ + OPCODE(o5_getDist), + OPCODE(o2_findObject), + OPCODE(o2_walkActorToObject), + OPCODE(o2_clearState01), + /* F8 */ + OPCODE(o2_isGreater), + OPCODE(o2_doSentence), + OPCODE(o2_verbOps), + OPCODE(o2_getActorWalkBox), + /* FC */ + OPCODE(o5_isSoundRunning), + OPCODE(o2_setActorElevation), + OPCODE(o2_walkActorTo), + OPCODE(o2_ifState01) + }; + + _opcodesV2 = opcodes; +} + +#define SENTENCE_SCRIPT 2 + +#define PARAM_1 0x80 +#define PARAM_2 0x40 +#define PARAM_3 0x20 + +void ScummEngine_v2::executeOpcode(byte i) { + OpcodeProcV2 op = _opcodesV2[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v2::getOpcodeDesc(byte i) { + return _opcodesV2[i].desc; +} + +int ScummEngine_v2::getVar() { + return readVar(fetchScriptByte()); +} + +void ScummEngine_v2::decodeParseString() { + byte buffer[512]; + byte *ptr = buffer; + byte c; + bool insertSpace = false; + + while ((c = fetchScriptByte())) { + + insertSpace = (c & 0x80) != 0; + c &= 0x7f; + + if (c < 8) { + // Special codes as seen in CHARSET_1 etc. My guess is that they + // have a similar function as the corresponding embedded stuff in modern + // games. Hence for now we convert them to the modern format. + // This might allow us to reuse the existing code. + *ptr++ = 0xFF; + *ptr++ = c; + if (c > 3) { + *ptr++ = fetchScriptByte(); + *ptr++ = 0; + } + } else + *ptr++ = c; + + if (insertSpace) + *ptr++ = ' '; + + } + *ptr = 0; + + int textSlot = 0; + _string[textSlot].xpos = 0; + _string[textSlot].ypos = 0; + if (_platform == Common::kPlatformNES) + _string[textSlot].right = 256; + else + _string[textSlot].right = 320; + _string[textSlot].center = false; + _string[textSlot].overhead = false; + + if (_gameId == GID_MANIAC && _actorToPrintStrFor == 0xFF) { + if (_platform == Common::kPlatformC64) { + _string[textSlot].color = 14; + } else if (_demoMode) { + _string[textSlot].color = (_version == 2) ? 15 : 1; + } + } + + actorTalk(buffer); +} + +int ScummEngine_v2::readVar(uint var) { + if (var >= 14 && var <= 16) + var = _scummVars[var]; + + checkRange(_numVariables - 1, 0, var, "Variable %d out of range(r)"); + debugC(DEBUG_VARS, "readvar(%d) = %d", var, _scummVars[var]); + return _scummVars[var]; +} + +void ScummEngine_v2::writeVar(uint var, int value) { + checkRange(_numVariables - 1, 0, var, "Variable %d out of range(r)"); + debugC(DEBUG_VARS, "writeVar(%d) = %d", var, value); + + if (VAR_CUTSCENEEXIT_KEY != 0xFF && var == VAR_CUTSCENEEXIT_KEY) { + // Remap the cutscene exit key in earlier games + if (value == 4 || value == 13 || value == 64) + value = 27; + } + + _scummVars[var] = value; + + // HACK: Ender's hack around a bug in Maniac. If you take the last dime from + // Weird Ed's piggybank, this disables the New Kid option and runs the Jail + // cutscene. Script 116 sets var[175] to 1, which disables New Kid in + // script 164. Unfortunatly, when New Kid is reenabled (var[175] = 0) in + // script 89, script 164 isn't reran to redraw it. Why? Dunno. Hack? Yes. + if ((var == 175) && (_gameId == GID_MANIAC) && (vm.slot[_currentScript].number == 89)) + runScript(164, 0, 0, 0); +} + +void ScummEngine_v2::getResultPosIndirect() { + _resultVarNumber = _scummVars[fetchScriptByte()]; +} + +void ScummEngine_v2::getResultPos() { + _resultVarNumber = fetchScriptByte(); +} + +void ScummEngine_v2::setStateCommon(byte type) { + int obj = getVarOrDirectWord(PARAM_1); + putState(obj, getState(obj) | type); +} + +void ScummEngine_v2::clearStateCommon(byte type) { + int obj = getVarOrDirectWord(PARAM_1); + putState(obj, getState(obj) & ~type); +} + +void ScummEngine_v2::o2_setState08() { + int obj = getVarOrDirectWord(PARAM_1); + putState(obj, getState(obj) | 0x08); + markObjectRectAsDirty(obj); + clearDrawObjectQueue(); +} + +void ScummEngine_v2::o2_clearState08() { + int obj = getVarOrDirectWord(PARAM_1); + putState(obj, getState(obj) & ~0x08); + markObjectRectAsDirty(obj); + clearDrawObjectQueue(); +} + +void ScummEngine_v2::o2_setState04() { + setStateCommon(0x04); +} + +void ScummEngine_v2::o2_clearState04() { + clearStateCommon(0x04); +} + +void ScummEngine_v2::o2_setState02() { + setStateCommon(0x02); +} + +void ScummEngine_v2::o2_clearState02() { + clearStateCommon(0x02); +} + +void ScummEngine_v2::o2_setState01() { + setStateCommon(0x01); +} + +void ScummEngine_v2::o2_clearState01() { + clearStateCommon(0x01); +} + +void ScummEngine_v2::o2_assignVarWordIndirect() { + getResultPosIndirect(); + setResult(getVarOrDirectWord(PARAM_1)); +} + +void ScummEngine_v2::o2_assignVarByte() { + getResultPos(); + setResult(fetchScriptByte()); +} + +void ScummEngine_v2::o2_setObjPreposition() { + int obj = getVarOrDirectWord(PARAM_1); + int unk = fetchScriptByte(); + + if (_platform == Common::kPlatformNES) + return; + + if (whereIsObject(obj) != WIO_NOT_FOUND) { + // FIXME: this might not work properly the moment we save and restore the game. + byte *ptr = getOBCDFromObject(obj) + 12; + *ptr &= 0x1F; + *ptr |= unk << 5; + } +} + +void ScummEngine_v2::o2_getObjPreposition() { + getResultPos(); + int obj = getVarOrDirectWord(PARAM_1); + + if (whereIsObject(obj) != WIO_NOT_FOUND) { + byte *ptr = getOBCDFromObject(obj) + 12; + setResult(*ptr >> 5); + } else { + setResult(0xFF); + } +} + +void ScummEngine_v2::o2_setBitVar() { + int var = fetchScriptWord(); + byte a = getVarOrDirectByte(PARAM_1); + + int bit_var = var + a; + int bit_offset = bit_var & 0x0f; + bit_var >>= 4; + + if (getVarOrDirectByte(PARAM_2)) + _scummVars[bit_var] |= (1 << bit_offset); + else + _scummVars[bit_var] &= ~(1 << bit_offset); + +} + +void ScummEngine_v2::o2_getBitVar() { + getResultPos(); + int var = fetchScriptWord(); + byte a = getVarOrDirectByte(PARAM_1); + + int bit_var = var + a; + int bit_offset = bit_var & 0x0f; + bit_var >>= 4; + + setResult((_scummVars[bit_var] & (1 << bit_offset)) ? 1 : 0); +} + +void ScummEngine_v2::ifStateCommon(byte type) { + int obj = getVarOrDirectWord(PARAM_1); + + if ((getState(obj) & type) == 0) + o5_jumpRelative(); + else + ignoreScriptWord(); +} + +void ScummEngine_v2::ifNotStateCommon(byte type) { + int obj = getVarOrDirectWord(PARAM_1); + + if ((getState(obj) & type) != 0) + o5_jumpRelative(); + else + ignoreScriptWord(); +} + +void ScummEngine_v2::o2_ifState08() { + ifStateCommon(0x08); +} + +void ScummEngine_v2::o2_ifNotState08() { + ifNotStateCommon(0x08); +} + +void ScummEngine_v2::o2_ifState04() { + ifStateCommon(0x04); +} + +void ScummEngine_v2::o2_ifNotState04() { + ifNotStateCommon(0x04); +} + +void ScummEngine_v2::o2_ifState02() { + ifStateCommon(0x02); +} + +void ScummEngine_v2::o2_ifNotState02() { + ifNotStateCommon(0x02); +} + +void ScummEngine_v2::o2_ifState01() { + ifStateCommon(0x01); +} + +void ScummEngine_v2::o2_ifNotState01() { + ifNotStateCommon(0x01); +} + +void ScummEngine_v2::o2_addIndirect() { + int a; + getResultPosIndirect(); + a = getVarOrDirectWord(PARAM_1); + _scummVars[_resultVarNumber] += a; +} + +void ScummEngine_v2::o2_subIndirect() { + int a; + getResultPosIndirect(); + a = getVarOrDirectWord(PARAM_1); + _scummVars[_resultVarNumber] -= a; +} + +void ScummEngine_v2::o2_add() { + int a; + getResultPos(); + a = getVarOrDirectWord(PARAM_1); + _scummVars[_resultVarNumber] += a; +} + +void ScummEngine_v2::o2_subtract() { + int a; + getResultPos(); + a = getVarOrDirectWord(PARAM_1); + _scummVars[_resultVarNumber] -= a; +} + +void ScummEngine_v2::o2_waitForActor() { + Actor *a = derefActor(getVarOrDirectByte(PARAM_1), "o2_waitForActor"); + if (a->_moving) { + _scriptPointer -= 2; + o5_breakHere(); + } +} + +void ScummEngine_v2::o2_waitForMessage() { + + if (VAR(VAR_HAVE_MSG)) { + _scriptPointer--; + o5_breakHere(); + } +} + +void ScummEngine_v2::o2_waitForSentence() { + if (!_sentenceNum && !isScriptInUse(SENTENCE_SCRIPT)) + return; + + _scriptPointer--; + o5_breakHere(); +} + +void ScummEngine_v2::o2_actorOps() { + int act = getVarOrDirectByte(PARAM_1); + int arg = getVarOrDirectByte(PARAM_2); + Actor *a; + int i; + + _opcode = fetchScriptByte(); + if (act == 0 && _opcode == 5) { + // This case happens in the Zak/MM bootscripts, to set the default talk color (9). + _string[0].color = arg; + return; + } + + a = derefActor(act, "actorOps"); + + switch (_opcode) { + case 1: // SO_SOUND + a->_sound[0] = arg; + break; + case 2: // SO_PALETTE + if (_version == 1) + i = act; + else + i = fetchScriptByte(); + + a->setPalette(i, arg); + break; + case 3: // SO_ACTOR_NAME + loadPtrToResource(rtActorName, a->_number, NULL); + break; + case 4: // SO_COSTUME + a->setActorCostume(arg); + break; + case 5: // SO_TALK_COLOR + if (_gameId == GID_MANIAC && _version == 2 && _demoMode && arg == 1) + a->_talkColor = 15; + else + a->_talkColor = arg; + break; + default: + error("o2_actorOps: opcode %d not yet supported", _opcode); + } +} + +void ScummEngine_v2::o2_restart() { + restart(); +} + +void ScummEngine_v2::o2_drawObject() { + int obj, idx, i; + ObjectData *od; + uint16 x, y, w, h; + int xpos, ypos; + + obj = getVarOrDirectWord(PARAM_1); + xpos = getVarOrDirectByte(PARAM_2); + ypos = getVarOrDirectByte(PARAM_3); + + idx = getObjectIndex(obj); + if (idx == -1) + return; + + od = &_objs[idx]; + if (xpos != 0xFF) { + od->walk_x += (xpos * 8) - od->x_pos; + od->x_pos = xpos * 8; + od->walk_y += (ypos * 8) - od->y_pos; + od->y_pos = ypos * 8; + } + addObjectToDrawQue(idx); + + x = od->x_pos; + y = od->y_pos; + w = od->width; + h = od->height; + + i = _numLocalObjects; + while (i--) { + if (_objs[i].obj_nr && _objs[i].x_pos == x && _objs[i].y_pos == y && _objs[i].width == w && _objs[i].height == h) + putState(_objs[i].obj_nr, getState(_objs[i].obj_nr) & ~0x08); + } + + putState(obj, getState(od->obj_nr) | 0x08); +} + +void ScummEngine_v2::o2_resourceRoutines() { + const ResTypes resTypes[] = { + rtNumTypes, // Invalid + rtNumTypes, // Invalid + rtCostume, + rtRoom, + rtNumTypes, // Invalid + rtScript, + rtSound + }; + int resid = getVarOrDirectByte(PARAM_1); + int opcode = fetchScriptByte(); + + ResTypes type = rtNumTypes; + if (0 <= (opcode >> 4) && (opcode >> 4) < (int)ARRAYSIZE(resTypes)) + type = resTypes[opcode >> 4]; + + if ((opcode & 0x0f) == 0 || type == rtNumTypes) + return; + + // HACK V2 Maniac Mansion tries to load an invalid sound resource in demo script. + if (_gameId == GID_MANIAC && _version == 2 && vm.slot[_currentScript].number == 9 && type == rtSound && resid == 1) + return; + + if ((opcode & 0x0f) == 1) { + ensureResourceLoaded(type, resid); + } else { + if (opcode & 1) + res.lock(type, resid); + else + res.unlock(type, resid); + } +} + +void ScummEngine_v2::o2_verbOps() { + int verb = fetchScriptByte(); + int slot, state; + + switch (verb) { + case 0: // SO_DELETE_VERBS + slot = getVarOrDirectByte(PARAM_1) + 1; + assert(0 < slot && slot < _numVerbs); + + //printf("o2_verbOps delete slot = %d\n", slot); + killVerb(slot); + break; + + case 0xFF: // Verb On/Off + verb = fetchScriptByte(); + state = fetchScriptByte(); + slot = getVerbSlot(verb, 0); + + //printf("o2_verbOps Verb On/Off: verb = %d, slot = %d, state = %d\n", verb, slot, state); + + _verbs[slot].curmode = state; + + break; + + default: { // New Verb + int x = fetchScriptByte() * 8; + int y = fetchScriptByte() * 8; + slot = getVarOrDirectByte(PARAM_1) + 1; + int prep = fetchScriptByte(); // Only used in V1? + // V1 Maniac verbs are relative to the 'verb area' - under the sentence + if (_platform == Common::kPlatformNES) + x += 8; + else if ((_gameId == GID_MANIAC) && (_version == 1)) + y += 8; + + //printf("o2_verbOps: verb = %d, slot = %d, x = %d, y = %d, unk = %d, name = %s\n", + // verb, slot, x, y, prep, _scriptPointer); + + VerbSlot *vs; + assert(0 < slot && slot < _numVerbs); + + vs = &_verbs[slot]; + vs->verbid = verb; + if (_platform == Common::kPlatformNES) { + vs->color = 1; + vs->hicolor = 1; + vs->dimcolor = 1; + } else if (_version == 1) { + vs->color = (_gameId == GID_MANIAC && _demoMode) ? 16 : 5; + vs->hicolor = 7; + vs->dimcolor = 11; + } else { + vs->color = (_gameId == GID_MANIAC && _demoMode) ? 13 : 2; + vs->hicolor = 14; + vs->dimcolor = 8; + } + vs->type = kTextVerbType; + vs->charset_nr = _string[0]._default.charset; + vs->curmode = 1; + vs->saveid = 0; + vs->key = 0; + vs->center = 0; + vs->imgindex = 0; + vs->prep = prep; + + vs->curRect.left = x; + vs->curRect.top = y; + + // FIXME: again, this map depends on the language of the game. + // E.g. a german keyboard has 'z' and 'y' swapped, while a french + // keyboard starts with "awert", etc. + const char keyboard[] = { + 'q','w','e','r','t', + 'a','s','d','f','g', + 'z','x','c','v','b' + }; + if (1 <= slot && slot <= ARRAYSIZE(keyboard)) + vs->key = keyboard[slot - 1]; + + // It follows the verb name + loadPtrToResource(rtVerb, slot, NULL); + } + break; + } + + // Force redraw of the modified verb slot + drawVerb(slot, 0); + verbMouseOver(0); +} + +void ScummEngine_v2::o2_doSentence() { + int a; + SentenceTab *st; + + a = getVarOrDirectByte(PARAM_1); + if (a == 0xFC) { + _sentenceNum = 0; + stopScript(SENTENCE_SCRIPT); + return; + } + if (a == 0xFB) { + resetSentence(); + return; + } + + st = &_sentence[_sentenceNum++]; + + st->verb = a; + st->objectA = getVarOrDirectWord(PARAM_2); + st->objectB = getVarOrDirectWord(PARAM_3); + st->preposition = (st->objectB != 0); + st->freezeCount = 0; + + // Execute or print the sentence + _opcode = fetchScriptByte(); + switch (_opcode) { + case 0: + // Do nothing (besides setting up the sentence above) + break; + case 1: + // Execute the sentence + _sentenceNum--; + + if (st->verb == 254) { + ScummEngine::stopObjectScript(st->objectA); + } else { + bool isBackgroundScript; + bool isSpecialVerb; + if (st->verb != 253 && st->verb != 250) { + VAR(VAR_ACTIVE_VERB) = st->verb; + VAR(VAR_ACTIVE_OBJECT1) = st->objectA; + VAR(VAR_ACTIVE_OBJECT2) = st->objectB; + + isBackgroundScript = false; + isSpecialVerb = false; + } else { + isBackgroundScript = (st->verb == 250); + isSpecialVerb = true; + st->verb = 253; + } + + // Check if an object script for this object is already running. If + // so, reuse its script slot. Note that we abuse two script flags: + // freezeResistant and recursive. We use them to track two + // script flags used in V1/V2 games. The main reason we do it this + // ugly evil way is to avoid having to introduce yet another save + // game revision. + int slot = -1; + ScriptSlot *ss; + int i; + + ss = vm.slot; + for (i = 0; i < NUM_SCRIPT_SLOT; i++, ss++) { + if (st->objectA == ss->number && + ss->freezeResistant == isBackgroundScript && + ss->recursive == isSpecialVerb && + (ss->where == WIO_ROOM || ss->where == WIO_INVENTORY || ss->where == WIO_FLOBJECT)) { + slot = i; + break; + } + } + + runObjectScript(st->objectA, st->verb, isBackgroundScript, isSpecialVerb, NULL, slot); + } + break; + case 2: + // Print the sentence + _sentenceNum--; + + VAR(VAR_SENTENCE_VERB) = st->verb; + VAR(VAR_SENTENCE_OBJECT1) = st->objectA; + VAR(VAR_SENTENCE_OBJECT2) = st->objectB; + + o2_drawSentence(); + break; + default: + error("o2_doSentence: unknown subopcode %d", _opcode); + } +} + +void ScummEngine_v2::o2_drawSentence() { + Common::Rect sentenceline; + static char sentence[256]; + const byte *temp; + int slot = getVerbSlot(VAR(VAR_SENTENCE_VERB), 0); + + if (!((_userState & 32) || (_platform == Common::kPlatformNES && _userState & 0xe0))) + return; + + if (getResourceAddress(rtVerb, slot)) + strcpy(sentence, (char*)getResourceAddress(rtVerb, slot)); + else + return; + + if (VAR(VAR_SENTENCE_OBJECT1) > 0) { + temp = getObjOrActorName(VAR(VAR_SENTENCE_OBJECT1)); + if (temp) { + strcat(sentence, " "); + strcat(sentence, (const char*)temp); + } + + // For V1 games, the engine must compute the preposition. + // In all other Scumm versions, this is done by the sentence script. + if ((_gameId == GID_MANIAC && _version == 1 && !(_platform == Common::kPlatformNES)) && (VAR(VAR_SENTENCE_PREPOSITION) == 0)) { + if (_verbs[slot].prep == 0xFF) { + byte *ptr = getOBCDFromObject(VAR(VAR_SENTENCE_OBJECT1)); + assert(ptr); + VAR(VAR_SENTENCE_PREPOSITION) = (*(ptr + 12) >> 5); + } else + VAR(VAR_SENTENCE_PREPOSITION) = _verbs[slot].prep; + } + } + + if (0 < VAR(VAR_SENTENCE_PREPOSITION) && VAR(VAR_SENTENCE_PREPOSITION) <= 4) { + // The prepositions, like the fonts, were hard code in the engine. Thus + // we have to do that, too, and provde localized versions for all the + // languages MM/Zak are available in. + // + // The order here matches the one defined in gameDetector.h + const char *prepositions[][5] = { + { " ", " in", " with", " on", " to" }, // English + { " ", " mit", " mit", " mit", " zu" }, // German + { " ", " dans", " avec", " sur", " <" }, // French + { " ", " in", " con", " su", " a" }, // Italian + { " ", " in", " with", " on", " to" }, // Portugese + { " ", " en", " con", " en", " a" }, // Spanish + { " ", " in", " with", " on", " to" }, // Japanese + { " ", " in", " with", " on", " to" }, // Chinese + { " ", " in", " with", " on", " to" } // Korean + }; + int lang = (_language <= 8) ? _language : 0; // Default to english + if (_platform == Common::kPlatformNES) { + strcat(sentence, (const char *)(getResourceAddress(rtCostume, 78) + VAR(VAR_SENTENCE_PREPOSITION) * 8 + 2)); + } else + strcat(sentence, prepositions[lang][VAR(VAR_SENTENCE_PREPOSITION)]); + } + + if (VAR(VAR_SENTENCE_OBJECT2) > 0) { + temp = getObjOrActorName(VAR(VAR_SENTENCE_OBJECT2)); + if (temp) { + strcat(sentence, " "); + strcat(sentence, (const char*)temp); + } + } + + _string[2].charset = 1; + _string[2].ypos = virtscr[kVerbVirtScreen].topline; + _string[2].xpos = 0; + if (_platform == Common::kPlatformNES) { + _string[2].xpos = 16; + _string[2].color = 0; + } else if (_version == 1) + _string[2].color = 16; + else + _string[2].color = 13; + + byte string[80]; + char *ptr = sentence; + int i = 0, len = 0; + + // Maximum length of printable characters + int maxChars = (_platform == Common::kPlatformNES) ? 60: 40; + while (*ptr) { + if (*ptr != '@') + len++; + if (len > maxChars) { + break; + } + + string[i++] = *ptr++; + + if (_platform == Common::kPlatformNES && len == 30) { + string[i++] = 0xFF; + string[i++] = 8; + } + } + string[i] = 0; + + if (_platform == Common::kPlatformNES) { + sentenceline.top = virtscr[kVerbVirtScreen].topline; + sentenceline.bottom = virtscr[kVerbVirtScreen].topline + 16; + sentenceline.left = 16; + sentenceline.right = 255; + } else { + sentenceline.top = virtscr[kVerbVirtScreen].topline; + sentenceline.bottom = virtscr[kVerbVirtScreen].topline + 8; + sentenceline.left = 0; + sentenceline.right = 319; + } + restoreBG(sentenceline); + + drawString(2, (byte*)string); +} + +void ScummEngine_v2::o2_ifClassOfIs() { + int obj = getVarOrDirectWord(PARAM_1); + int clsop = getVarOrDirectByte(PARAM_2); + byte *obcd = getOBCDFromObject(obj); + + if (obcd == 0) { + o5_jumpRelative(); + return; + } + + byte cls = *(obcd + 6); + if ((cls & clsop) != clsop) { + o5_jumpRelative(); + return; + } + ignoreScriptWord(); +} + +void ScummEngine_v2::o2_walkActorTo() { + int x, y; + Actor *a; + + int act = getVarOrDirectByte(PARAM_1); + + // WORKAROUND bug #1252606 + if (_gameId == GID_ZAK && _version == 1 && vm.slot[_currentScript].number == 115 && act == 249) { + act = VAR(VAR_EGO); + } + + a = derefActor(act, "o2_walkActorTo"); + + x = getVarOrDirectByte(PARAM_2) * 8; + y = getVarOrDirectByte(PARAM_3) * 2; + + a->startWalkActor(x, y, -1); +} + +void ScummEngine_v2::o2_putActor() { + int act = getVarOrDirectByte(PARAM_1); + int x, y; + Actor *a; + + a = derefActor(act, "o2_putActor"); + + x = getVarOrDirectByte(PARAM_2) * 8; + y = getVarOrDirectByte(PARAM_3) * 2; + + a->putActor(x, y, a->_room); +} + +void ScummEngine_v2::o2_startScript() { + int script = getVarOrDirectByte(PARAM_1); + + if (!_copyProtection) { + // The enhanced version of Zak McKracken included in the + // SelectWare Classic Collection bundle used CD check instead + // of the usual key code check at airports. + if ((_gameId == GID_ZAK) && (script == 15) && (_roomResource == 45)) + return; + } + + runScript(script, 0, 0, 0); +} + +void ScummEngine_v2::o2_stopScript() { + int script; + + script = getVarOrDirectByte(PARAM_1); + + if ((_gameId == GID_ZAK) && (_roomResource == 7) && (vm.slot[_currentScript].number == 10001)) { + // FIXME: Nasty hack for bug #771499 + // Don't let the exit script for room 7 stop the buy script (24), + // switching to the number selection keypad (script 15) + if ((script == 24) && isScriptRunning(15)) + return; + } + + if (script == 0) + script = vm.slot[_currentScript].number; + + if (_currentScript != 0 && vm.slot[_currentScript].number == script) + stopObjectCode(); + else + stopScript(script); +} + +void ScummEngine_v2::o2_panCameraTo() { + panCameraTo(getVarOrDirectByte(PARAM_1) * 8, 0); +} + +void ScummEngine_v2::o2_walkActorToObject() { + int obj; + Actor *a; + + a = derefActor(getVarOrDirectByte(PARAM_1), "o2_walkActorToObject"); + obj = getVarOrDirectWord(PARAM_2); + if (whereIsObject(obj) != WIO_NOT_FOUND) { + int x, y, dir; + getObjectXYPos(obj, x, y, dir); + a->startWalkActor(x, y, dir); + } +} + +void ScummEngine_v2::o2_putActorAtObject() { + int obj, x, y; + Actor *a; + + a = derefActor(getVarOrDirectByte(PARAM_1), "o2_putActorAtObject"); + + obj = getVarOrDirectWord(PARAM_2); + if (whereIsObject(obj) != WIO_NOT_FOUND) + getObjectXYPos(obj, x, y); + else { + x = 240; + y = 120; + } + + a->putActor(x, y, a->_room); +} + +void ScummEngine_v2::o2_getActorElevation() { + getResultPos(); + int act = getVarOrDirectByte(PARAM_1); + Actor *a = derefActor(act, "o2_getActorElevation"); + setResult(a->getElevation() / 2); +} + +void ScummEngine_v2::o2_setActorElevation() { + int act = getVarOrDirectByte(PARAM_1); + int elevation = (int8)getVarOrDirectByte(PARAM_2); + + Actor *a = derefActor(act, "o2_setActorElevation"); + a->setElevation(elevation * 2); +} + +void ScummEngine_v2::o2_animateActor() { + int act = getVarOrDirectByte(PARAM_1); + int anim = getVarOrDirectByte(PARAM_2); + + Actor *a = derefActor(act, "o2_animateActor"); + a->animateActor(anim); +} + +void ScummEngine_v2::o2_actorFromPos() { + int x, y; + getResultPos(); + x = getVarOrDirectByte(PARAM_1) * 8; + y = getVarOrDirectByte(PARAM_2) * 2; + setResult(getActorFromPos(x, y)); +} + +void ScummEngine_v2::o2_findObject() { + int obj; + getResultPos(); + int x = getVarOrDirectByte(PARAM_1) * 8; + int y = getVarOrDirectByte(PARAM_2) * 2; + obj = findObject(x, y); + if (obj == 0 && (_platform == Common::kPlatformNES) && (_userState & 0x40)) { + if (_mouseOverBoxV2 >= 0 && _mouseOverBoxV2 < 4) + obj = findInventory(VAR(VAR_EGO), _mouseOverBoxV2 + _inventoryOffset + 1); + } + setResult(obj); +} + +void ScummEngine_v2::o2_getActorX() { + int a; + getResultPos(); + + a = getVarOrDirectByte(PARAM_1); + setResult(getObjX(a) / 8); +} + +void ScummEngine_v2::o2_getActorY() { + int a; + getResultPos(); + + a = getVarOrDirectByte(PARAM_1); + setResult(getObjY(a) / 2); +} + +void ScummEngine_v2::o2_isGreater() { + uint16 a = getVar(); + uint16 b = getVarOrDirectWord(PARAM_1); + if (b > a) + ignoreScriptWord(); + else + o5_jumpRelative(); +} + +void ScummEngine_v2::o2_isGreaterEqual() { + uint16 a = getVar(); + uint16 b = getVarOrDirectWord(PARAM_1); + if (b >= a) + ignoreScriptWord(); + else + o5_jumpRelative(); +} + +void ScummEngine_v2::o2_isLess() { + uint16 a = getVar(); + uint16 b = getVarOrDirectWord(PARAM_1); + + if (b < a) + ignoreScriptWord(); + else + o5_jumpRelative(); +} + +void ScummEngine_v2::o2_isLessEqual() { + uint16 a = getVar(); + uint16 b = getVarOrDirectWord(PARAM_1); + if (b <= a) + ignoreScriptWord(); + else + o5_jumpRelative(); +} + +void ScummEngine_v2::o2_lights() { + int a, b, c; + + a = getVarOrDirectByte(PARAM_1); + b = fetchScriptByte(); + c = fetchScriptByte(); + + if (c == 0) { + if (_gameId == GID_MANIAC && _version == 1 && !(_platform == Common::kPlatformNES)) { + // Convert older light mode values into + // equivalent values.of later games + // 0 Darkness + // 1 Flashlight + // 2 Lighted area + if (a == 2) + VAR(VAR_CURRENT_LIGHTS) = 11; + else if (a == 1) + VAR(VAR_CURRENT_LIGHTS) = 4; + else + VAR(VAR_CURRENT_LIGHTS) = 0; + } else + VAR(VAR_CURRENT_LIGHTS) = a; + } else if (c == 1) { + _flashlight.xStrips = a; + _flashlight.yStrips = b; + } + _fullRedraw = true; +} + +void ScummEngine_v2::o2_loadRoomWithEgo() { + Actor *a; + int obj, room, x, y, x2, y2, dir; + + obj = getVarOrDirectWord(PARAM_1); + room = getVarOrDirectByte(PARAM_2); + + a = derefActor(VAR(VAR_EGO), "o2_loadRoomWithEgo"); + + a->putActor(0, 0, room); + _egoPositioned = false; + + x = (int8)fetchScriptByte() * 8; + y = (int8)fetchScriptByte() * 2; + + startScene(a->_room, a, obj); + + getObjectXYPos(obj, x2, y2, dir); + a->putActor(x2, y2, _currentRoom); + a->setDirection(dir + 180); + + camera._dest.x = camera._cur.x = a->_pos.x; + setCameraAt(a->_pos.x, a->_pos.y); + setCameraFollows(a); + + _fullRedraw = true; + + resetSentence(); + + if (x >= 0 && y >= 0) { + a->startWalkActor(x, y, -1); + } + runScript(5, 0, 0, 0); +} + +void ScummEngine_v2::o2_setOwnerOf() { + int obj, owner; + + obj = getVarOrDirectWord(PARAM_1); + owner = getVarOrDirectByte(PARAM_2); + + setOwnerOf(obj, owner); +} + +void ScummEngine_v2::o2_delay() { + int delay = fetchScriptByte(); + delay |= fetchScriptByte() << 8; + delay |= fetchScriptByte() << 16; + delay = 0xFFFFFF - delay; + + vm.slot[_currentScript].delay = delay; + vm.slot[_currentScript].status = ssPaused; + o5_breakHere(); +} + +void ScummEngine_v2::o2_setBoxFlags() { + int a, b; + + a = getVarOrDirectByte(PARAM_1); + b = fetchScriptByte(); + setBoxFlags(a, b); +} + +void ScummEngine_v2::o2_setCameraAt() { + setCameraAtEx(getVarOrDirectByte(PARAM_1) * 8); +} + +void ScummEngine_v2::o2_roomOps() { + int a = getVarOrDirectByte(PARAM_1); + int b = getVarOrDirectByte(PARAM_2); + + _opcode = fetchScriptByte(); + switch (_opcode & 0x1F) { + case 1: // SO_ROOM_SCROLL + a *= 8; + b *= 8; + 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 2: // SO_ROOM_COLOR + if (_version == 1) { + // V1 zak needs to know when room color is changed + _roomPalette[0] = 255; + _roomPalette[1] = a; + _roomPalette[2] = b; + } else { + _roomPalette[b] = a; + } + _fullRedraw = true; + break; + } +} + +void ScummEngine_v2::o2_cutscene() { + vm.cutSceneData[0] = _userState | (_userPut ? 16 : 0); + vm.cutSceneData[1] = (int16)VAR(VAR_CURSORSTATE); + vm.cutSceneData[2] = _currentRoom; + vm.cutSceneData[3] = camera._mode; + + VAR(VAR_CURSORSTATE) = 200; + + // FIXME allows quotes script (173) to start during introudction of + // demo mode of V1 Maniac Mansion. setUserState was halting script + // 173 before it started. + if (!(_gameId == GID_MANIAC && _demoMode)) + // Hide inventory, freeze scripts, hide cursor + setUserState(15); + + _sentenceNum = 0; + stopScript(SENTENCE_SCRIPT); + resetSentence(); + + vm.cutScenePtr[0] = 0; +} + +void ScummEngine_v2::o2_endCutscene() { + vm.cutSceneStackPointer = 0; + + VAR(VAR_OVERRIDE) = 0; + vm.cutSceneScript[0] = 0; + vm.cutScenePtr[0] = 0; + + VAR(VAR_CURSORSTATE) = vm.cutSceneData[1]; + + // Reset user state to values before cutscene + setUserState(vm.cutSceneData[0] | 7); + + if ((_gameId == GID_MANIAC) && !(_platform == Common::kPlatformNES)) { + camera._mode = (byte) vm.cutSceneData[3]; + if (camera._mode == kFollowActorCameraMode) { + actorFollowCamera(VAR(VAR_EGO)); + } else if (vm.cutSceneData[2] != _currentRoom) { + startScene(vm.cutSceneData[2], 0, 0); + } + } else { + actorFollowCamera(VAR(VAR_EGO)); + } +} + +void ScummEngine_v2::o2_beginOverride() { + vm.cutScenePtr[0] = _scriptPointer - _scriptOrgPointer; + vm.cutSceneScript[0] = _currentScript; + + // Skip the jump instruction following the override instruction + fetchScriptByte(); + fetchScriptWord(); +} + +void ScummEngine_v2::o2_chainScript() { + int data = getVarOrDirectByte(PARAM_1); + stopScript(vm.slot[_currentScript].number); + _currentScript = 0xFF; + runScript(data, 0, 0, 0); +} + +void ScummEngine_v2::o2_pickupObject() { + int obj = getVarOrDirectWord(PARAM_1); + + if (obj < 1) { + error("pickupObject received invalid index %d (script %d)", obj, vm.slot[_currentScript].number); + } + + if (getObjectIndex(obj) == -1) + return; + + if (whereIsObject(obj) == WIO_INVENTORY) /* Don't take an */ + return; /* object twice */ + + addObjectToInventory(obj, _roomResource); + markObjectRectAsDirty(obj); + putOwner(obj, VAR(VAR_EGO)); + putState(obj, getState(obj) | 0xA); + clearDrawObjectQueue(); + + runInventoryScript(1); + if (_platform == Common::kPlatformNES) + _sound->addSoundToQueue(51); // play 'pickup' sound +} + +void ScummEngine_v2::o2_cursorCommand() { // TODO: Define the magic numbers + uint16 cmd = getVarOrDirectWord(PARAM_1); + byte state = cmd >> 8; + + if (cmd & 0xFF) { + VAR(VAR_CURSORSTATE) = cmd & 0xFF; + } + + setUserState(state); +} + +void ScummEngine_v2::setUserState(byte state) { + if (state & 4) { // Userface + if (_platform == Common::kPlatformNES) + _userState = (_userState & ~0xE0) | (state & 0xE0); + else + _userState = state & (32 | 64 | 128); + } + + if (state & 1) { // Freeze + if (state & 8) + freezeScripts(0); + else + unfreezeScripts(); + } + + if (state & 2) { // Cursor Show/Hide + if (_platform == Common::kPlatformNES) + _userState = (_userState & ~0x10) | (state & 0x10); + if (state & 16) { + _userPut = 1; + _cursor.state = 1; + } else { + _userPut = 0; + _cursor.state = 0; + } + } + + // Hide all verbs and inventory + Common::Rect rect; + rect.top = virtscr[kVerbVirtScreen].topline; + rect.bottom = virtscr[kVerbVirtScreen].topline + 8 * 88; + if (_platform == Common::kPlatformNES) { + rect.left = 16; + rect.right = 255; + } else { + rect.left = 0; + rect.right = 319; + } + restoreBG(rect); + + // Draw all verbs and inventory + redrawVerbs(); + runInventoryScript(1); +} + +void ScummEngine_v2::o2_getActorWalkBox() { + Actor *a; + getResultPos(); + a = derefActor(getVarOrDirectByte(PARAM_1), "o2_getActorWalkbox"); + setResult(a->_walkbox); +} + +void ScummEngine_v2::o2_dummy() { + // Opcode 238 is used in maniac and zak but has no purpose + if (_opcode != 238) + warning("o2_dummy invoked (opcode %d)", _opcode); +} + +void ScummEngine_v2::o2_switchCostumeSet() { + // NES version of maniac uses this to switch between the two + // groups of costumes it has + if (_platform == Common::kPlatformNES) + NES_loadCostumeSet(fetchScriptByte()); + else if (_platform == Common::kPlatformC64) + fetchScriptByte(); + else + o2_dummy(); +} + +void ScummEngine_v2::resetSentence() { + VAR(VAR_SENTENCE_VERB) = VAR(VAR_BACKUP_VERB); + VAR(VAR_SENTENCE_OBJECT1) = 0; + VAR(VAR_SENTENCE_OBJECT2) = 0; + VAR(VAR_SENTENCE_PREPOSITION) = 0; +} + +void ScummEngine_v2::runInventoryScript(int i) { + redrawV2Inventory(); +} + +#undef PARAM_1 +#undef PARAM_2 +#undef PARAM_3 + +} // End of namespace Scumm |