Logo Search packages:      
Sourcecode: scummvm version File versions

script_v2.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 * Copyright (C) 2001-2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/script_v2.cpp,v 2.255 2004/10/22 10:25:55 eriktorbjorn Exp $
 *
 */

#include "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/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;
      _string[textSlot].right = 320;
      _string[textSlot].center = false;
      _string[textSlot].overhead = false;

      if (_gameId == GID_MANIAC) {
            // Demos don't set subtitle color before display first subtitle.
            if (_demoMode && _actorToPrintStrFor == 0xFF)
                  _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);

      _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 (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:
            warning("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)
                  lock(type, resid);
            else
                  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 ((_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 (_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))
            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) && (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
            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[2].topline;
      _string[2].xpos = 0;
      if (_version == 1)
            _string[2].color = 16;
      else 
            _string[2].color = 13;

      char *ptr = sentence;
      int n = 0;

      // Maximum length: 40 printable characters
      while (*ptr) {
            if (*ptr != '@')
                  n++;
            if (n > 40) {
                  *ptr = 0;
                  break;
            }
            ptr++;
      }

      sentenceline.top = virtscr[2].topline;
      sentenceline.bottom = virtscr[2].topline + 8;
      sentenceline.left = 0;
      sentenceline.right = 319;
      restoreBG(sentenceline);

      drawString(2, (byte*)sentence);
}

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;
      a = derefActor(getVarOrDirectByte(PARAM_1), "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() {
      getResultPos();
      int x = getVarOrDirectByte(PARAM_1) * 8;
      int y = getVarOrDirectByte(PARAM_2) * 2;
      setResult(findObject(x, y));
}

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) {
                  // 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 = 1;
}

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 = 1;

      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 = 1;
      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) {
            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(0x80);
      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);
}

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
            _userState = state & (32 | 64 | 128);
      }

      if (state & 1) {                                // Freeze
            if (state & 8)
                  freezeScripts(0);
            else
                  unfreezeScripts();
      }

      if (state & 2) {                                // Cursor Show/Hide
            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[2].topline;
      rect.bottom = virtscr[2].topline + 8 * 88;
      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 (_features & GF_NES) {
            warning("stub: o2_switchCostumeSet()");
            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;
}

#undef PARAM_1
#undef PARAM_2
#undef PARAM_3

} // End of namespace Scumm

Generated by  Doxygen 1.6.0   Back to index