aboutsummaryrefslogtreecommitdiff
path: root/engines/prince/script.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/prince/script.cpp')
-rw-r--r--engines/prince/script.cpp2071
1 files changed, 2071 insertions, 0 deletions
diff --git a/engines/prince/script.cpp b/engines/prince/script.cpp
new file mode 100644
index 0000000000..75d084f639
--- /dev/null
+++ b/engines/prince/script.cpp
@@ -0,0 +1,2071 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#include "prince/script.h"
+#include "prince/prince.h"
+#include "prince/flags.h"
+#include "prince/variatxt.h"
+#include "prince/font.h"
+#include "prince/hero.h"
+#include "prince/resource.h"
+#include "prince/animation.h"
+
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/archive.h"
+#include "common/memstream.h"
+
+namespace Prince {
+
+static const uint16 kNumOpcodes = 144;
+
+Room::Room() {}
+
+bool Room::loadRoom(byte *roomData) {
+ int roomSize = 64;
+ Common::MemoryReadStream roomStream(roomData, roomSize);
+
+ _mobs = roomStream.readSint32LE();
+ _backAnim = roomStream.readSint32LE();
+ _obj = roomStream.readSint32LE();
+ _nak = roomStream.readSint32LE();
+ _itemUse = roomStream.readSint32LE();
+ _itemGive = roomStream.readSint32LE();
+ _walkTo = roomStream.readSint32LE();
+ _examine = roomStream.readSint32LE();
+ _pickup = roomStream.readSint32LE();
+ _use = roomStream.readSint32LE();
+ _pushOpen = roomStream.readSint32LE();
+ _pullClose = roomStream.readSint32LE();
+ _talk = roomStream.readSint32LE();
+ _give = roomStream.readSint32LE();
+
+ return true;
+}
+
+int Room::getOptionOffset(int option) {
+ switch (option) {
+ case 0:
+ return _walkTo;
+ case 1:
+ return _examine;
+ case 2:
+ return _pickup;
+ case 3:
+ return _use;
+ case 4:
+ return _pushOpen;
+ case 5:
+ return _pullClose;
+ case 6:
+ return _talk;
+ case 7:
+ return _give;
+ default:
+ error("Wrong option - nr %d", option);
+ }
+}
+
+Script::Script(PrinceEngine *vm) : _vm(vm), _data(nullptr), _dataSize(0) {
+}
+
+Script::~Script() {
+ if (_data != nullptr) {
+ free(_data);
+ _dataSize = 0;
+ _data = nullptr;
+ }
+}
+
+bool Script::loadStream(Common::SeekableReadStream &stream) {
+ _dataSize = stream.size();
+ if (!_dataSize) {
+ return false;
+ }
+
+ _data = (byte *)malloc(_dataSize);
+
+ if (!_data) {
+ return false;
+ }
+
+ stream.read(_data, _dataSize);
+
+ Common::MemoryReadStream scriptDataStream(_data, _dataSize);
+ _scriptInfo.rooms = scriptDataStream.readSint32LE();
+ _scriptInfo.startGame = scriptDataStream.readSint32LE();
+ _scriptInfo.restoreGame = scriptDataStream.readSint32LE();
+ _scriptInfo.stdExamine = scriptDataStream.readSint32LE();
+ _scriptInfo.stdPickup = scriptDataStream.readSint32LE();
+ _scriptInfo.stdUse = scriptDataStream.readSint32LE();
+ _scriptInfo.stdOpen = scriptDataStream.readSint32LE();
+ _scriptInfo.stdClose = scriptDataStream.readSint32LE();
+ _scriptInfo.stdTalk = scriptDataStream.readSint32LE();
+ _scriptInfo.stdGive = scriptDataStream.readSint32LE();
+ _scriptInfo.usdCode = scriptDataStream.readSint32LE();
+ _scriptInfo.invObjExam = scriptDataStream.readSint32LE();
+ _scriptInfo.invObjUse = scriptDataStream.readSint32LE();
+ _scriptInfo.invObjUU = scriptDataStream.readSint32LE();
+ _scriptInfo.stdUseItem = scriptDataStream.readSint32LE();
+ _scriptInfo.lightSources = scriptDataStream.readSint32LE();
+ _scriptInfo.specRout = scriptDataStream.readSint32LE();
+ _scriptInfo.invObjGive = scriptDataStream.readSint32LE();
+ _scriptInfo.stdGiveItem = scriptDataStream.readSint32LE();
+ _scriptInfo.goTester = scriptDataStream.readSint32LE();
+
+ return true;
+}
+
+uint16 Script::readScript16(uint32 address) {
+ assert((_data + address + sizeof(uint16)) <= (_data + _dataSize));
+ uint16 data = READ_LE_UINT16(&_data[address]);
+ return data;
+}
+
+uint32 Script::readScript32(uint32 address) {
+ assert((_data + address + sizeof(uint32)) <= (_data + _dataSize));
+ uint32 data = READ_LE_UINT32(&_data[address]);
+ return data;
+}
+
+int16 Script::getLightX(int locationNr) {
+ return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8]);
+}
+
+int16 Script::getLightY(int locationNr) {
+ return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8 + 2]);
+}
+
+int32 Script::getShadowScale(int locationNr) {
+ return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8 + 4]);
+}
+
+uint32 Script::getStartGameOffset() {
+ return _scriptInfo.startGame;
+}
+
+uint32 Script::getLocationInitScript(int initRoomTableOffset, int roomNr) {
+ return (uint32)READ_LE_UINT32(&_data[initRoomTableOffset + roomNr * 4]);
+}
+
+byte Script::getMobVisible(int roomMobOffset, uint16 mob) {
+ return _data[roomMobOffset + mob];
+}
+
+void Script::setMobVisible(int roomMobOffset, uint16 mob, byte value) {
+ _data[roomMobOffset + mob] = value;
+}
+
+uint8 *Script::getRoomOffset(int locationNr) {
+ return &_data[_scriptInfo.rooms + locationNr * 64];
+}
+
+int32 Script::getOptionStandardOffset(int option) {
+ switch (option) {
+ case 1:
+ return _scriptInfo.stdExamine;
+ case 2:
+ return _scriptInfo.stdPickup;
+ case 3:
+ return _scriptInfo.stdUse;
+ case 4:
+ return _scriptInfo.stdOpen;
+ case 5:
+ return _scriptInfo.stdClose;
+ case 6:
+ return _scriptInfo.stdTalk;
+ case 7:
+ return _scriptInfo.stdGive;
+ default:
+ error("Wrong standard option - nr %d", option);
+ }
+}
+
+uint8 *Script::getHeroAnimName(int offset) {
+ return &_data[offset];
+}
+
+uint32 Script::getBackAnimId(int roomBackAnimOffset, int slot) {
+ uint32 animId = READ_LE_UINT32(&_data[roomBackAnimOffset + slot * 4]);
+ return animId;
+}
+
+void Script::setBackAnimId(int roomBackAnimOffset, int slot, int animId) {
+ WRITE_LE_UINT32(&_data[roomBackAnimOffset + slot * 4], animId);
+}
+
+byte Script::getObjId(int roomObjOffset, int slot) {
+ return _data[roomObjOffset + slot];
+}
+
+void Script::setObjId(int roomObjOffset, int slot, byte objectId) {
+ _data[roomObjOffset + slot] = objectId;
+}
+
+int Script::scanMobEvents(int mobMask, int dataEventOffset) {
+ debug("mobMask: %d", mobMask);
+ int i = 0;
+ int16 mob;
+ int32 code;
+ do {
+ mob = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 6]);
+ if (mob == mobMask) {
+ code = (int)READ_LE_UINT32(&_data[dataEventOffset + i * 6 + 2]);
+ debug("code: %d", code);
+ return code;
+ }
+ i++;
+ } while (mob != -1);
+ return -1;
+}
+
+int Script::scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask) {
+ debug("mobMask: %d", mobMask);
+ int i = 0;
+ int16 mob;
+ int16 item;
+ int32 code;
+ do {
+ mob = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 8]);
+ if (mob == mobMask) {
+ item = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 8 + 2]);
+ if (item == itemMask) {
+ code = (int)READ_LE_UINT32(&_data[dataEventOffset + i * 8 + 4]);
+ debug("itemMask: %d", item);
+ debug("code: %d", code);
+ return code;
+ }
+ }
+ i++;
+ } while (mob != -1);
+ return -1;
+}
+
+void Script::installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int roomBackAnimOffset) {
+
+ _vm->removeSingleBackAnim(slot); // free slot before loading
+
+ int offset = roomBackAnimOffset + slot * 4; // BackgroundAnim offset for selected slot number
+
+ BackgroundAnim newBackgroundAnim; // BackgroundAnim seq data and its array of Anim
+
+ int animOffset = READ_LE_UINT32(&_data[offset]); // pos of BackgroundAnim data in script
+ int anims = READ_LE_UINT32(&_data[animOffset + 8]); // amount of Anim in BackgroundAnim
+
+ if (anims == 0) {
+ anims = 1; // anims with 0 as amount in game data has just 1 animation
+ }
+
+ if (animOffset != 0) {
+ Common::MemoryReadStream stream(_data, _dataSize); // stream from script data
+ for (int i = 0; i < anims; i++) {
+ Anim newAnim;
+ stream.seek(animOffset + kStructSizeBAS + kStructSizeBASA * i);
+ // Anim BASA data
+ newAnim._basaData._num = stream.readUint16LE();
+ newAnim._basaData._start = stream.readUint16LE();
+ newAnim._basaData._end = stream.readUint16LE();
+
+ // Anim number in game files
+ int animNumber = newAnim._basaData._num;
+ const Common::String animName = Common::String::format("AN%02d", animNumber);
+ const Common::String shadowName = Common::String::format("AN%02dS", animNumber);
+ newAnim._animData = new Animation();
+ newAnim._shadowData = new Animation();
+ Resource::loadResource(newAnim._animData, animName.c_str(), true);
+ if (!Resource::loadResource(newAnim._shadowData, shadowName.c_str(), false)) {
+ delete newAnim._shadowData;
+ newAnim._shadowData = nullptr;
+ }
+
+ newAnim._usage = 0;
+ newAnim._state = 0; // enabled
+ if ((_vm->_animList[animNumber]._flags & 4)) {
+ newAnim._state = 1;
+ newAnim._frame = _vm->_animList[animNumber]._endPhase;
+ newAnim._showFrame = _vm->_animList[animNumber]._endPhase;
+ } else {
+ newAnim._frame = _vm->_animList[animNumber]._startPhase;
+ newAnim._showFrame = _vm->_animList[animNumber]._startPhase;
+ }
+ newAnim._flags = _vm->_animList[animNumber]._flags;
+ newAnim._lastFrame = _vm->_animList[animNumber]._endPhase;
+ newAnim._loopFrame = _vm->_animList[animNumber]._loopPhase;
+ newAnim._loopType = _vm->_animList[animNumber]._loopType;
+ newAnim._nextAnim = _vm->_animList[animNumber]._nextAnim;
+ newAnim._x = _vm->_animList[animNumber]._x;
+ newAnim._y = _vm->_animList[animNumber]._y;
+ newAnim._currFrame = 0;
+ newAnim._currX = _vm->_animList[animNumber]._x;
+ newAnim._currY = _vm->_animList[animNumber]._y;
+ newAnim._currW = 0;
+ newAnim._currH = 0;
+ newAnim._packFlag = 0;
+ newAnim._shadowBack = _vm->_animList[animNumber]._type;
+ newBackgroundAnim.backAnims.push_back(newAnim);
+ }
+
+ // Anim BAS data
+ stream.seek(animOffset);
+ newBackgroundAnim._seq._type = stream.readUint32LE();
+ newBackgroundAnim._seq._data = stream.readUint32LE();
+ newBackgroundAnim._seq._anims = stream.readUint32LE();
+ stream.skip(12);
+ newBackgroundAnim._seq._current = newBackgroundAnim.backAnims[0]._basaData._num;
+ newBackgroundAnim._seq._counter = 0;
+ newBackgroundAnim._seq._currRelative = 0;
+ newBackgroundAnim._seq._data2 = stream.readUint32LE();
+
+ int start = newBackgroundAnim.backAnims[0]._basaData._start; // BASA_Start of first frame
+ int end = newBackgroundAnim.backAnims[0]._basaData._end; // BASA_End of first frame
+
+ if (start != -1) {
+ newBackgroundAnim.backAnims[0]._frame = start;
+ newBackgroundAnim.backAnims[0]._showFrame = start;
+ newBackgroundAnim.backAnims[0]._loopFrame = start;
+ }
+
+ if (end != -1) {
+ newBackgroundAnim.backAnims[0]._lastFrame = end;
+ }
+
+ backAnimList[slot] = newBackgroundAnim;
+ }
+}
+
+void Script::installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int roomBackAnimOffset) {
+ for (int i = 0; i < _vm->kMaxBackAnims; i++) {
+ installSingleBackAnim(backAnimList, i, roomBackAnimOffset);
+ }
+}
+
+void Script::installObjects(int offset) {
+ for (int i = 0; i < _vm->kMaxObjects; i++) {
+ _vm->_objSlot[i] = _data[offset];
+ offset++;
+ }
+}
+
+bool Script::loadAllMasks(Common::Array<Mask> &maskList, int offset) {
+ Mask tempMask;
+ while (1) {
+ Common::MemoryReadStream maskStream(_data, _dataSize);
+ maskStream.seek(offset);
+ tempMask._state = maskStream.readUint16LE();
+ if (tempMask._state == -1) {
+ break;
+ }
+ tempMask._flags = maskStream.readUint16LE();
+ tempMask._x1 = maskStream.readUint16LE();
+ tempMask._y1 = maskStream.readUint16LE();
+ tempMask._x2 = maskStream.readUint16LE();
+ tempMask._y2 = maskStream.readUint16LE();
+ tempMask._z = maskStream.readUint16LE();
+ tempMask._number = maskStream.readUint16LE();
+
+ const Common::String msStreamName = Common::String::format("MS%02d", tempMask._number);
+ Common::SeekableReadStream *msStream = SearchMan.createReadStreamForMember(msStreamName);
+ if (!msStream) {
+ tempMask._width = 0;
+ tempMask._height = 0;
+ tempMask._data = nullptr;
+ debug("Can't load %s", msStreamName.c_str());
+ delete msStream;
+ } else {
+ uint32 dataSize = msStream->size();
+ if (dataSize != -1) {
+ tempMask._data = (byte *)malloc(dataSize);
+ if (msStream->read(tempMask._data, dataSize) != dataSize) {
+ free(tempMask._data);
+ delete msStream;
+ return false;
+ }
+ delete msStream;
+ }
+ tempMask._width = tempMask.getWidth();
+ tempMask._height = tempMask.getHeight();
+ }
+
+ maskList.push_back(tempMask);
+ offset += 16; // size of Mask (Nak) struct
+ }
+ return true;
+}
+
+InterpreterFlags::InterpreterFlags() {
+ resetAllFlags();
+}
+
+void InterpreterFlags::resetAllFlags() {
+ memset(_flags, 0, sizeof(_flags));
+}
+
+void InterpreterFlags::setFlagValue(Flags::Id flagId, int32 value) {
+ _flags[(uint32)flagId - kFlagMask] = value;
+}
+
+int32 InterpreterFlags::getFlagValue(Flags::Id flagId) {
+ return _flags[(uint32)flagId - kFlagMask];
+}
+
+Interpreter::Interpreter(PrinceEngine *vm, Script *script, InterpreterFlags *flags) :
+ _vm(vm), _script(script), _flags(flags),
+ _stacktop(0), _opcodeNF(false), _opcodeEnd(false),
+ _waitFlag(0), _result(true) {
+
+ // Initialize the script
+ _mode = "fg";
+ _fgOpcodePC = _script->getStartGameOffset();
+ _bgOpcodePC = 0;
+}
+
+void Interpreter::debugInterpreter(const char *s, ...) {
+ char buf[STRINGBUFLEN];
+ va_list va;
+ va_start(va, s);
+ vsnprintf(buf, STRINGBUFLEN, s, va);
+ va_end(va);
+
+ Common::String str = Common::String::format("@0x%08X: ", _lastInstruction);
+ str += Common::String::format("op %04d: ", _lastOpcode);
+ //debugC(10, DebugChannel::kScript, "PrinceEngine::Script %s %s", str.c_str(), buf);
+ if (!strcmp(_mode, "fg")) {
+ debug(10, "PrinceEngine::Script %s %s", str.c_str(), buf);
+ }
+ //debug("Prince::Script mode %s %s %s", _mode, str.c_str(), buf);
+}
+
+void Interpreter::stepBg() {
+ if (_bgOpcodePC) {
+ _mode = "bg";
+ _bgOpcodePC = step(_bgOpcodePC);
+ }
+}
+
+void Interpreter::stepFg() {
+ if (_fgOpcodePC) {
+ _mode = "fg";
+ _fgOpcodePC = step(_fgOpcodePC);
+ }
+}
+
+uint32 Interpreter::step(uint32 opcodePC) {
+ _currentInstruction = opcodePC;
+
+ while (!_opcodeNF) {
+ _lastInstruction = _currentInstruction;
+
+ // Get the current opcode
+ _lastOpcode = readScript16();
+
+ if (_lastOpcode > kNumOpcodes)
+ error(
+ "Trying to execute unknown opcode @0x%04X: %02d",
+ _currentInstruction,
+ _lastOpcode);
+
+ // Execute the current opcode
+ OpcodeFunc op = _opcodes[_lastOpcode];
+ (this->*op)();
+ if (_opcodeNF) {
+ _opcodeNF = 0;
+ break;
+ }
+ }
+
+ if (_opcodeEnd) {
+ _vm->quitGame();
+ }
+
+ return _currentInstruction;
+}
+
+void Interpreter::storeNewPC(int opcodePC) {
+ if (_flags->getFlagValue(Flags::GETACTION) == 1) {
+ _flags->setFlagValue(Flags::GETACTIONDATA, opcodePC);
+ opcodePC = _flags->getFlagValue(Flags::GETACTIONBACK);
+ }
+ _fgOpcodePC = opcodePC;
+}
+
+int Interpreter::getLastOPCode() {
+ return _lastOpcode;
+}
+
+int Interpreter::getFgOpcodePC() {
+ return _fgOpcodePC;
+}
+
+uint32 Interpreter::getCurrentString() {
+ return _currentString;
+}
+
+void Interpreter::setCurrentString(uint32 value) {
+ _currentString = value;
+}
+
+byte *Interpreter::getString() {
+ return _string;
+}
+
+void Interpreter::setString(byte *newString) {
+ _string = newString;
+}
+
+void Interpreter::increaseString() {
+ while (*_string) {
+ _string++;
+ }
+ _string++;
+}
+
+void Interpreter::setResult(byte value) {
+ _result = value;
+}
+
+void Interpreter::setBgOpcodePC(uint32 value) {
+ _bgOpcodePC = value;
+}
+
+void Interpreter::setFgOpcodePC(uint32 value) {
+ _fgOpcodePC = value;
+}
+
+uint16 Interpreter::readScript16() {
+ uint16 data = _script->readScript16(_currentInstruction);
+ _currentInstruction += sizeof(uint16);
+ return data;
+}
+
+uint32 Interpreter::readScript32() {
+ uint32 data = _script->readScript32(_currentInstruction);
+ _currentInstruction += sizeof(uint32);
+ return data;
+}
+
+int32 Interpreter::readScriptFlagValue() {
+ uint16 value = readScript16();
+ if (value & InterpreterFlags::kFlagMask) {
+ return _flags->getFlagValue((Flags::Id)value);
+ }
+ return value;
+}
+
+Flags::Id Interpreter::readScriptFlagId() {
+ return (Flags::Id)readScript16();
+}
+
+void Interpreter::O_WAITFOREVER() {
+ _vm->changeCursor(_vm->_currentPointerNumber);
+ _opcodeNF = 1;
+ _currentInstruction -= 2;
+ //debugInterpreter("O_WAITFOREVER");
+}
+
+void Interpreter::O_BLACKPALETTE() {
+ _vm->blackPalette();
+ debugInterpreter("O_BLACKPALETTE");
+}
+
+void Interpreter::O_SETUPPALETTE() {
+ _vm->setPalette(_vm->_roomBmp->getPalette());
+ debugInterpreter("O_SETUPPALETTE");
+}
+
+void Interpreter::O_INITROOM() {
+ int32 roomId = readScriptFlagValue();
+ _vm->loadLocation(roomId);
+ _opcodeNF = 1;
+ debugInterpreter("O_INITROOM %d", roomId);
+}
+
+void Interpreter::O_SETSAMPLE() {
+ int32 sampleId = readScriptFlagValue();
+ int32 sampleNameOffset = readScript32();
+ const char *sampleName = _script->getString(_currentInstruction + sampleNameOffset - 4);
+ _vm->loadSample(sampleId, sampleName);
+ debugInterpreter("O_SETSAMPLE %d %s", sampleId, sampleName);
+}
+
+void Interpreter::O_FREESAMPLE() {
+ int32 sampleId = readScriptFlagValue();
+ _vm->freeSample(sampleId);
+ debugInterpreter("O_FREESAMPLE sampleId: %d", sampleId);
+}
+
+void Interpreter::O_PLAYSAMPLE() {
+ int32 sampleId = readScriptFlagValue();
+ uint16 loopType = readScript16();
+ _vm->playSample(sampleId, loopType);
+ debugInterpreter("O_PLAYSAMPLE sampleId %d loopType %d", sampleId, loopType);
+}
+
+void Interpreter::O_PUTOBJECT() {
+ int32 roomId = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ int32 objectId = readScriptFlagValue();
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+ _vm->_script->setObjId(room->_obj, slot, objectId);
+ if (_vm->_locationNr == roomId) {
+ _vm->_objSlot[slot] = objectId;
+ }
+ delete room;
+ debugInterpreter("O_PUTOBJECT roomId %d, slot %d, objectId %d", roomId, slot, objectId);
+}
+
+void Interpreter::O_REMOBJECT() {
+ int32 roomId = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+ _vm->_script->setObjId(room->_obj, slot, 0xFF);
+ if (_vm->_locationNr == roomId) {
+ _vm->_objSlot[slot] = 0xFF;
+ }
+ delete room;
+ debugInterpreter("O_REMOBJECT roomId %d slot %d", roomId, slot);
+}
+
+void Interpreter::O_SHOWANIM() {
+ int32 slot = readScriptFlagValue();
+ int32 animId = readScriptFlagValue();
+ _vm->freeNormAnim(slot);
+ Anim &anim = _vm->_normAnimList[slot];
+ AnimListItem &animList = _vm->_animList[animId];
+ anim._currFrame = 0;
+ anim._packFlag = 0;
+ anim._state = 0;
+ anim._frame = animList._startPhase;
+ anim._showFrame = animList._startPhase;
+ anim._lastFrame = animList._endPhase;
+ anim._loopFrame = animList._loopPhase;
+ anim._x = animList._x;
+ anim._y = animList._y;
+ anim._loopType = animList._loopType;
+ anim._shadowBack = animList._type;
+ anim._flags = animList._flags;
+ anim._nextAnim = animList._nextAnim;
+ int fileNumber = animList._fileNumber;
+ const Common::String animName = Common::String::format("AN%02d", fileNumber);
+ const Common::String shadowName = Common::String::format("AN%02dS", fileNumber);
+ anim._animData = new Animation();
+ anim._shadowData = new Animation();
+ Resource::loadResource(anim._animData, animName.c_str(), true);
+ if (!Resource::loadResource(anim._shadowData, shadowName.c_str(), false)) {
+ delete anim._shadowData;
+ anim._shadowData = nullptr;
+ }
+
+ // WALKAROUND: fix for turning off bard's wife background animation
+ // in front of bard's house (location 7) after giving her poem (item 33)
+ // in script: GiveLetter (line 11082)
+ if (_currentInstruction == kGiveLetterScriptFix) {
+ _vm->_backAnimList[1].backAnims[0]._state = 1;
+ }
+
+ debugInterpreter("O_SHOWANIM slot %d, animId %d", slot, animId);
+}
+
+void Interpreter::O_CHECKANIMEND() {
+ int32 slot = readScriptFlagValue();
+ if (_vm->_normAnimList[slot]._frame != _vm->_normAnimList[slot]._lastFrame - 1) {
+ _currentInstruction -= 4;
+ _opcodeNF = 1;
+ }
+ debugInterpreter("O_CHECKANIMEND slot %d", slot);
+}
+
+void Interpreter::O_FREEANIM() {
+ int32 slot = readScriptFlagValue();
+ _vm->freeNormAnim(slot);
+ debugInterpreter("O_FREEANIM slot %d", slot);
+}
+
+void Interpreter::O_CHECKANIMFRAME() {
+ int32 slot = readScriptFlagValue();
+ int32 frameNumber = readScriptFlagValue();
+ if (_vm->_normAnimList[slot]._frame != frameNumber - 1) {
+ _currentInstruction -= 6;
+ _opcodeNF = 1;
+ }
+ debugInterpreter("O_CHECKANIMFRAME slot %d, frameNumber %d", slot, frameNumber);
+}
+
+void Interpreter::O_PUTBACKANIM() {
+ int32 roomId = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ int32 animId = readScript32();
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+ _vm->_script->setBackAnimId(room->_backAnim, slot, animId);
+ if (_vm->_locationNr == roomId) {
+ _vm->_script->installSingleBackAnim(_vm->_backAnimList, slot, room->_backAnim);
+ }
+ delete room;
+ debugInterpreter("O_PUTBACKANIM roomId %d, slot %d, animId %d", roomId, slot, animId);
+}
+
+void Interpreter::O_REMBACKANIM() {
+ int32 roomId = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ if (_vm->_locationNr == roomId) {
+ _vm->removeSingleBackAnim(slot);
+ }
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+ _vm->_script->setBackAnimId(room->_backAnim, slot, 0);
+ delete room;
+ debugInterpreter("O_REMBACKANIM roomId %d, slot %d", roomId, slot);
+}
+
+void Interpreter::O_CHECKBACKANIMFRAME() {
+ int32 slotId = readScriptFlagValue();
+ int32 frameId = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ if (_vm->_backAnimList[slotId].backAnims[currAnim]._frame != frameId - 1) {
+ _currentInstruction -= 6;
+ _opcodeNF = 1;
+ }
+ debugInterpreter("O_CHECKBACKANIMFRAME slotId %d, frameId %d", slotId, frameId);
+}
+
+// Not used in script
+void Interpreter::O_FREEALLSAMPLES() {
+ error("O_FREEALLSAMPLES");
+}
+
+void Interpreter::O_SETMUSIC() {
+ uint16 musicId = readScript16();
+ _vm->loadMusic(musicId);
+ debugInterpreter("O_SETMUSIC musicId %d", musicId);
+}
+
+void Interpreter::O_STOPMUSIC() {
+ _vm->stopMusic();
+ debugInterpreter("O_STOPMUSIC");
+}
+
+void Interpreter::O__WAIT() {
+ int32 pause = readScriptFlagValue();
+ debugInterpreter("O__WAIT pause %d", pause);
+ if (!_waitFlag) {
+ // set new wait flag value and continue
+ _waitFlag = pause;
+ _opcodeNF = 1;
+ _currentInstruction -= 4;
+ return;
+ }
+ _waitFlag--;
+ if (_waitFlag > 0) {
+ _opcodeNF = 1;
+ _currentInstruction -= 4;
+ return;
+ }
+}
+
+// Not used in script
+void Interpreter::O_UPDATEOFF() {
+ error("O_UPDATEOFF");
+}
+
+// Not used in script
+void Interpreter::O_UPDATEON() {
+ error("O_UPDATEON");
+}
+
+// Not used in script
+void Interpreter::O_UPDATE () {
+ error("O_UPDATE");
+}
+
+// Not used in script
+void Interpreter::O_CLS() {
+ error("O_CLS");
+}
+
+void Interpreter::O__CALL() {
+ int32 address = readScript32();
+ _stack[_stacktop] = _currentInstruction;
+ _stacktop++;
+ _currentInstruction += address - 4;
+ debugInterpreter("O__CALL 0x%04X", _currentInstruction);
+}
+
+void Interpreter::O_RETURN() {
+ if (_stacktop > 0) {
+ _stacktop--;
+ _currentInstruction = _stack[_stacktop];
+ debugInterpreter("O_RETURN 0x%04X", _currentInstruction);
+ } else {
+ error("O_RETURN: Stack is empty");
+ }
+}
+
+void Interpreter::O_GO() {
+ int32 opPC = readScript32();
+ _currentInstruction += opPC - 4;
+ debugInterpreter("O_GO 0x%04X", opPC);
+}
+
+void Interpreter::O_BACKANIMUPDATEOFF() {
+ int32 slotId = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ if (!_vm->_backAnimList[slotId].backAnims.empty()) {
+ _vm->_backAnimList[slotId].backAnims[currAnim]._state = 1;
+ }
+ debugInterpreter("O_BACKANIMUPDATEOFF slotId %d", slotId);
+}
+
+void Interpreter::O_BACKANIMUPDATEON() {
+ int32 slotId = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ if (!_vm->_backAnimList[slotId].backAnims.empty()) {
+ _vm->_backAnimList[slotId].backAnims[currAnim]._state = 0;
+ }
+ debugInterpreter("O_BACKANIMUPDATEON slotId %d", slotId);
+}
+
+void Interpreter::O_CHANGECURSOR() {
+ int32 cursorId = readScriptFlagValue();
+ _vm->changeCursor(cursorId);
+ debugInterpreter("O_CHANGECURSOR %x", cursorId);
+}
+
+// Not used in script
+void Interpreter::O_CHANGEANIMTYPE() {
+ error("O_CHANGEANIMTYPE");
+}
+
+void Interpreter::O__SETFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue((Flags::Id)(flagId), value);
+ debugInterpreter("O__SETFLAG 0x%04X (%s) = %d", flagId, Flags::getFlagName(flagId), value);
+}
+
+void Interpreter::O_COMPARE() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _result = _flags->getFlagValue(flagId) != value;
+ debugInterpreter("O_COMPARE flagId 0x%04X (%s), value %d == %d (%d)", flagId, Flags::getFlagName(flagId), value, _flags->getFlagValue(flagId), _result);
+}
+
+void Interpreter::O_JUMPZ() {
+ int32 offset = readScript32();
+ if (!_result) {
+ _currentInstruction += offset - 4;
+ }
+ debugInterpreter("O_JUMPZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset);
+}
+
+void Interpreter::O_JUMPNZ() {
+ int32 offset = readScript32();
+ if (_result) {
+ _currentInstruction += offset - 4;
+ }
+ debugInterpreter("O_JUMPNZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset);
+}
+
+void Interpreter::O_EXIT() {
+ int32 exitCode = readScriptFlagValue();
+ _opcodeEnd = true;
+ _opcodeNF = 1;
+ if (exitCode == 0x2EAD) {
+ _vm->scrollCredits();
+ }
+ debugInterpreter("O_EXIT exitCode %d", exitCode);
+}
+
+void Interpreter::O_ADDFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) + value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ }
+ else {
+ _result = 0;
+ }
+ debugInterpreter("O_ADDFLAG flagId %04x (%s), value %d", flagId, Flags::getFlagName(flagId), value);
+}
+
+void Interpreter::O_TALKANIM() {
+ int32 animNumber = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ _vm->doTalkAnim(animNumber, slot, kNormalAnimation);
+ debugInterpreter("O_TALKANIM animNumber %d, slot %d", animNumber, slot);
+}
+
+void Interpreter::O_SUBFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) - value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ }
+ else {
+ _result = 0;
+ }
+ debugInterpreter("O_SUBFLAG flagId %d, value %d", flagId, value);
+}
+
+void Interpreter::O_SETSTRING() {
+ int32 offset = readScript32();
+ _currentString = offset;
+ if (offset >= 80000) {
+ _string = _vm->_variaTxt->getString(offset - 80000);
+ debugInterpreter("GetVaria %s", _string);
+ }
+ else if (offset < 2000) {
+ _vm->_dialogData = &_vm->_dialogDat[offset * 4 - 4];
+ uint32 of = READ_LE_UINT32(_vm->_talkTxt + offset * 4);
+ const char *txt = (const char *)&_vm->_talkTxt[of];
+ _string = &_vm->_talkTxt[of];
+ debugInterpreter("TalkTxt %d %s", of, txt);
+ }
+ debugInterpreter("O_SETSTRING %04d", offset);
+}
+
+void Interpreter::O_ANDFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) & value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ } else {
+ _result = 0;
+ }
+ debugInterpreter("O_ANDFLAG flagId %d, value %d", flagId, value);
+}
+
+void Interpreter::O_GETMOBDATA() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 mobId = readScriptFlagValue();
+ int32 mobOffset = readScriptFlagValue();
+ int16 value = _vm->_mobList[mobId].getData((Mob::AttrId)mobOffset);
+ _flags->setFlagValue(flagId, value);
+ debugInterpreter("O_GETMOBDATA flagId %d, modId %d, mobOffset %d", flagId, mobId, mobOffset);
+}
+
+void Interpreter::O_ORFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) | value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ } else {
+ _result = 0;
+ }
+ debugInterpreter("O_ORFLAG flagId %d, value %d", flagId, value);
+}
+
+void Interpreter::O_SETMOBDATA() {
+ int32 mobId = readScriptFlagValue();
+ int32 mobOffset = readScriptFlagValue();
+ int32 value = readScriptFlagValue();
+ _vm->_mobList[mobId].setData((Mob::AttrId)mobOffset, value);
+ debugInterpreter("O_SETMOBDATA mobId %d, mobOffset %d, value %d", mobId, mobOffset, value);
+}
+
+void Interpreter::O_XORFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) ^ value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ } else {
+ _result = 0;
+ }
+ debugInterpreter("O_XORFLAG flagId %d, value %d", flagId, value);
+}
+
+void Interpreter::O_GETMOBTEXT() {
+ int32 mob = readScriptFlagValue();
+ _currentString = _vm->_locationNr * 100 + mob + 60001;
+ _string = (byte *)_vm->_mobList[mob]._examText.c_str();
+ debugInterpreter("O_GETMOBTEXT mob %d", mob);
+}
+
+void Interpreter::O_MOVEHERO() {
+ int32 heroId = readScriptFlagValue();
+ int32 x = readScriptFlagValue();
+ int32 y = readScriptFlagValue();
+ int32 dir = readScriptFlagValue();
+ _vm->moveRunHero(heroId, x, y, dir, false);
+ debugInterpreter("O_MOVEHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
+}
+
+void Interpreter::O_WALKHERO() {
+ int32 heroId = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else if (heroId == 1) {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ if (hero->_state != Hero::kHeroStateStay) {
+ _currentInstruction -= 4;
+ _opcodeNF = 1;
+ }
+ }
+ debugInterpreter("O_WALKHERO %d", heroId);
+}
+
+void Interpreter::O_SETHERO() {
+ int32 heroId = readScriptFlagValue();
+ int32 x = readScriptFlagValue();
+ int32 y = readScriptFlagValue();
+ int32 dir = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else if (heroId == 1) {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ hero->setPos(x, y);
+ hero->_lastDirection = dir;
+ hero->_visible = 1;
+ hero->countDrawPosition();
+ }
+ debugInterpreter("O_SETHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
+}
+
+void Interpreter::O_HEROOFF() {
+ int32 heroId = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else if (heroId == 1) {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ hero->setVisible(false);
+ }
+ debugInterpreter("O_HEROOFF %d", heroId);
+}
+
+void Interpreter::O_HEROON() {
+ int32 heroId = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else if (heroId == 1) {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ hero->setVisible(true);
+ }
+ debugInterpreter("O_HEROON %d", heroId);
+}
+
+void Interpreter::O_CLSTEXT() {
+ int32 slot = readScriptFlagValue();
+ _vm->_textSlots[slot]._str = nullptr;
+ _vm->_textSlots[slot]._time = 0;
+ debugInterpreter("O_CLSTEXT slot %d", slot);
+}
+
+void Interpreter::O_CALLTABLE() {
+ Flags::Id flagId = readScriptFlagId();
+ int roomNr = _flags->getFlagValue(flagId);
+ int32 tableOffset = readScript32();
+ int initLocationScript = _script->getLocationInitScript(tableOffset, roomNr);
+ if (initLocationScript) {
+ _stack[_stacktop] = _currentInstruction;
+ _stacktop++;
+ _currentInstruction = initLocationScript;
+ }
+ debugInterpreter("O_CALLTABLE loc %d", roomNr);
+}
+
+void Interpreter::O_CHANGEMOB() {
+ int32 mob = readScriptFlagValue();
+ int32 value = readScriptFlagValue();
+ value ^= 1;
+ _vm->_script->setMobVisible(_vm->_room->_mobs, mob, value);
+ _vm->_mobList[mob]._visible = value;
+ debugInterpreter("O_CHANGEMOB mob %d, value %d", mob, value);
+}
+
+void Interpreter::O_ADDINV() {
+ int32 hero = readScriptFlagValue();
+ int32 item = readScriptFlagValue();
+ _vm->addInv(hero, item, false);
+ debugInterpreter("O_ADDINV hero %d, item %d", hero, item);
+}
+
+void Interpreter::O_REMINV() {
+ int32 hero = readScriptFlagValue();
+ int32 item = readScriptFlagValue();
+ _vm->remInv(hero, item);
+ debugInterpreter("O_REMINV hero %d, item %d", hero, item);
+}
+
+// Not used in script
+void Interpreter::O_REPINV() {
+ error("O_REPINV");
+}
+
+// Not used in script
+void Interpreter::O_OBSOLETE_GETACTION() {
+ error("O_OBSOLETE_GETACTION");
+}
+
+// Not used in script
+void Interpreter::O_ADDWALKAREA() {
+ error("O_ADDWALKAREA");
+}
+
+// Not used in script
+void Interpreter::O_REMWALKAREA() {
+ error("O_REMWALKAREA");
+}
+
+ // Not used in script
+void Interpreter::O_RESTOREWALKAREA() {
+ error("O_RESTOREWALKAREA");
+}
+
+void Interpreter::O_WAITFRAME() {
+ _opcodeNF = true;
+ debugInterpreter("O_WAITFRAME");
+}
+
+void Interpreter::O_SETFRAME() {
+ int32 anim = readScriptFlagValue();
+ int32 frame = readScriptFlagValue();
+ _vm->_normAnimList[anim]._frame = frame;
+ debugInterpreter("O_SETFRAME anim %d, frame %d", anim, frame);
+}
+
+// Not used in script
+void Interpreter::O_RUNACTION() {
+ error("O_RUNACTION");
+}
+
+void Interpreter::O_COMPAREHI() {
+ Flags::Id flag = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ int32 flagValue = _flags->getFlagValue(flag);
+ if (flagValue > value) {
+ _result = 0;
+ } else {
+ _result = 1;
+ }
+ debugInterpreter("O_COMPAREHI flag %04x - (%s), value %d, flagValue %d, result %d", flag, Flags::getFlagName(flag), value, flagValue, _result);
+}
+
+void Interpreter::O_COMPARELO() {
+ Flags::Id flag = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ int32 flagValue = _flags->getFlagValue(flag);
+ if (flagValue < value) {
+ _result = 0;
+ } else {
+ _result = 1;
+ }
+ debugInterpreter("O_COMPARELO flag %04x - (%s), value %d, flagValue %d, result %d", flag, Flags::getFlagName(flag), value, flagValue, _result);
+}
+
+// Not used in script
+void Interpreter::O_PRELOADSET() {
+ error("O_PRELOADSET");
+}
+
+// Not used in script
+void Interpreter::O_FREEPRELOAD() {
+ error("O_FREEPRELOAD");
+}
+
+// Not used in script
+void Interpreter::O_CHECKINV() {
+ error("O_CHECKINV");
+}
+
+void Interpreter::O_TALKHERO() {
+ int32 hero = readScriptFlagValue();
+ _vm->talkHero(hero);
+ debugInterpreter("O_TALKHERO hero %d", hero);
+}
+
+void Interpreter::O_WAITTEXT() {
+ int32 slot = readScriptFlagValue();
+ Text &text = _vm->_textSlots[slot];
+ if (text._time && text._str) {
+ if (_flags->getFlagValue(Flags::ESCAPED)) {
+ text._time = 1;
+ if (!slot) {
+ _vm->_mainHero->_talkTime = 1;
+ } else if (slot == 1) {
+ _vm->_secondHero->_talkTime = 1;
+ }
+ } else {
+ _opcodeNF = 1;
+ _currentInstruction -= 4;
+ }
+ }
+ //debugInterpreter("O_WAITTEXT slot %d", slot);
+}
+
+void Interpreter::O_SETHEROANIM() {
+ int32 heroId = readScriptFlagValue();
+ int32 offset = readScript32();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ hero->freeHeroAnim();
+ if (hero ->_specAnim == nullptr) {
+ hero->_specAnim = new Animation();
+ if (offset < 100) {
+ const Common::String animName = Common::String::format("AN%02d", offset);
+ Resource::loadResource(hero->_specAnim, animName.c_str(), true);
+ } else {
+ const Common::String animName = Common::String((const char *)_script->getHeroAnimName(offset));
+ Common::String normalizedPath = lastPathComponent(animName, '\\');
+ Resource::loadResource(hero->_specAnim, normalizedPath.c_str(), true);
+ }
+ hero->_phase = 0;
+ hero->_state = Hero::kHeroStateSpec;
+ }
+ }
+ debugInterpreter("O_SETHEROANIM hero %d, offset %d", hero, offset);
+}
+
+void Interpreter::O_WAITHEROANIM() {
+ int32 heroId = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ if (hero->_state == Hero::kHeroStateSpec) {
+ _currentInstruction -= 4;
+ _opcodeNF = 1;
+ }
+ }
+ debugInterpreter("O_WAITHEROANIM heroId %d", heroId);
+}
+
+void Interpreter::O_GETHERODATA() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 heroId = readScriptFlagValue();
+ int32 heroOffset = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ _flags->setFlagValue(flagId, hero->getData((Hero::AttrId)heroOffset));
+ }
+ debugInterpreter("O_GETHERODATA flag %04x - (%s), heroId %d, heroOffset %d", flagId, Flags::getFlagName(flagId), heroId, heroOffset);
+}
+
+// No need of implementation here
+void Interpreter::O_GETMOUSEBUTTON() {
+ debugInterpreter("O_GETMOUSEBUTTON");
+}
+
+void Interpreter::O_CHANGEFRAMES() {
+ int32 anim = readScriptFlagValue();
+ int32 frame = readScriptFlagValue();
+ int32 lastFrame = readScriptFlagValue();
+ int32 loopFrame = readScriptFlagValue();
+ _vm->_normAnimList[anim]._frame = frame;
+ _vm->_normAnimList[anim]._lastFrame = lastFrame;
+ _vm->_normAnimList[anim]._loopFrame = loopFrame;
+ debugInterpreter("O_CHANGFRAMES anim %d, frame %d, lastFrame %d, loopFrame %d", anim, frame, lastFrame, loopFrame);
+}
+
+void Interpreter::O_CHANGEBACKFRAMES() {
+ int32 anim = readScriptFlagValue();
+ int32 frame = readScriptFlagValue();
+ int32 lastFrame = readScriptFlagValue();
+ int32 loopFrame = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[anim]._seq._currRelative;
+ Anim &backAnim = _vm->_backAnimList[anim].backAnims[currAnim];
+ backAnim._frame = frame;
+ backAnim._lastFrame = lastFrame;
+ backAnim._loopFrame = loopFrame;
+ debugInterpreter("O_CHANGEBACKFRAMES anim %d, frame %d, lastFrame %d, loopFrame %d", anim, frame, lastFrame, loopFrame);
+}
+
+void Interpreter::O_GETBACKANIMDATA() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 animNumber = readScriptFlagValue();
+ int32 animDataOffset = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[animNumber]._seq._currRelative;
+ int16 value = _vm->_backAnimList[animNumber].backAnims[currAnim].getAnimData((Anim::AnimOffsets)(animDataOffset));
+ _flags->setFlagValue((Flags::Id)(flagId), value);
+ debugInterpreter("O_GETBACKANIMDATA flag %04X (%s), animNumber %d, animDataOffset %d, value %d", flagId, Flags::getFlagName(flagId), animNumber, animDataOffset, value);
+}
+
+void Interpreter::O_GETANIMDATA() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 anim = readScriptFlagValue();
+ int32 animOffset = readScriptFlagValue();
+ if (_vm->_normAnimList[anim]._animData != nullptr) {
+ _flags->setFlagValue(flagId, _vm->_normAnimList[anim].getAnimData((Anim::AnimOffsets)(animOffset)));
+ }
+ debugInterpreter("O_GETANIMDATA flag %04X (%s), anim %d, animOffset %d", flagId, Flags::getFlagName(flagId), anim, animOffset);
+}
+
+void Interpreter::O_SETBGCODE() {
+ int32 offset = readScript32();
+ _bgOpcodePC = _currentInstruction + offset - 4;
+ debugInterpreter("O_SETBGCODE next %08x, offset %08x", _bgOpcodePC, offset);
+}
+
+void Interpreter::O_SETBACKFRAME() {
+ int32 anim = readScriptFlagValue();
+ int32 frame = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[anim]._seq._currRelative;
+ if (_vm->_backAnimList[anim].backAnims[currAnim]._animData != nullptr) {
+ _vm->_backAnimList[anim].backAnims[currAnim]._frame = frame;
+ }
+ debugInterpreter("O_SETBACKFRAME anim %d, frame %d", anim, frame);
+}
+
+void Interpreter::O_GETRND() {
+ Flags::Id flag = readScriptFlagId();
+ uint16 rndSeed = readScript16();
+ int value = _vm->_randomSource.getRandomNumber(rndSeed - 1);
+ _flags->setFlagValue(flag, value);
+ debugInterpreter("O_GETRND flag %d, rndSeed %d, value %d", flag, rndSeed, value);
+}
+
+void Interpreter::O_TALKBACKANIM() {
+ int32 animNumber = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ _vm->doTalkAnim(animNumber, slot, kBackgroundAnimation);
+ debugInterpreter("O_TALKBACKANIM animNumber %d, slot %d", animNumber, slot);
+}
+
+// Simplifying, because used only once in Location 20
+void Interpreter::O_LOADPATH() {
+ readScript32();
+ _vm->loadPath("path2");
+ debugInterpreter("O_LOADPATH - path2");
+}
+
+void Interpreter::O_GETCHAR() {
+ Flags::Id flagId = readScriptFlagId();
+ _flags->setFlagValue(flagId, *_string);
+ _string++;
+ debugInterpreter("O_GETCHAR %04X (%s) %02x", flagId, Flags::getFlagName(flagId), _flags->getFlagValue(flagId));
+}
+
+void Interpreter::O_SETDFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 address = readScript32();
+ _flags->setFlagValue((Flags::Id)(flagId), _currentInstruction + address - 4);
+ debugInterpreter("O_SETDFLAG 0x%04X (%s) = 0x%04X", flagId, Flags::getFlagName(flagId), _currentInstruction + address - 4);
+}
+
+void Interpreter::O_CALLDFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ _stack[_stacktop] = _currentInstruction;
+ _stacktop++;
+ _currentInstruction = _flags->getFlagValue(flagId);
+ debugInterpreter("O_CALLDFLAG 0x%04X (%s) = 0x%04X", flagId, Flags::getFlagName(flagId), _currentInstruction);
+}
+
+void Interpreter::O_PRINTAT() {
+ int32 slot = readScriptFlagValue();
+ int32 x = readScriptFlagValue();
+ int32 y = readScriptFlagValue();
+ int32 color = _flags->getFlagValue(Flags::KOLOR);
+ _vm->printAt(slot, color, (char *)_string, x, y);
+ increaseString();
+ debugInterpreter("O_PRINTAT slot %d, x %d, y %d", slot, x, y);
+}
+
+void Interpreter::O_ZOOMIN() {
+ int32 slot = readScriptFlagValue();
+ _vm->initZoomIn(slot);
+ debugInterpreter("O_ZOOMIN slot %04d", slot);
+}
+
+void Interpreter::O_ZOOMOUT() {
+ int32 slot = readScriptFlagValue();
+ _vm->initZoomOut(slot);
+ debugInterpreter("O_ZOOMOUT slot %d", slot);
+}
+
+// Not used in script
+void Interpreter::O_SETSTRINGOFFSET() {
+ error("O_SETSTRINGOFFSET");
+}
+
+void Interpreter::O_GETOBJDATA() {
+ Flags::Id flag = readScriptFlagId();
+ int32 slot = readScriptFlagValue();
+ int32 objOffset = readScriptFlagValue();
+ int nr = _vm->_objSlot[slot];
+ if (nr != 0xFF) {
+ int16 value = _vm->_objList[nr]->getData((Object::AttrId)objOffset);
+ _flags->setFlagValue(flag, value);
+ }
+ debugInterpreter("O_GETOBJDATA flag %d, objSlot %d, objOffset %d", flag, slot, objOffset);
+}
+
+void Interpreter::O_SETOBJDATA() {
+ int32 slot = readScriptFlagValue();
+ int32 objOffset = readScriptFlagValue();
+ int32 value = readScriptFlagValue();
+ int nr = _vm->_objSlot[slot];
+ if (nr != 0xFF) {
+ _vm->_objList[nr]->setData((Object::AttrId)objOffset, value);
+ }
+ debugInterpreter("O_SETOBJDATA objSlot %d, objOffset %d, value %d", slot, objOffset, value);
+}
+
+// Not used in script
+void Interpreter::O_SWAPOBJECTS() {
+ error("O_SWAPOBJECTS");
+}
+
+void Interpreter::O_CHANGEHEROSET() {
+ int32 heroId = readScriptFlagValue();
+ int32 heroSet = readScriptFlagValue();
+ if (!heroId) {
+ _vm->_mainHero->loadAnimSet(heroSet);
+ } else if (heroId == 1) {
+ _vm->_secondHero->loadAnimSet(heroSet);
+ }
+ debugInterpreter("O_CHANGEHEROSET hero %d, heroSet %d", heroId, heroSet);
+}
+
+// Not used in script
+void Interpreter::O_ADDSTRING() {
+ error("O_ADDSTRING");
+}
+
+void Interpreter::O_SUBSTRING() {
+ int32 value = readScriptFlagValue();
+ _string -= value;
+ debugInterpreter("O_SUBSTRING value %d", value);
+}
+
+int Interpreter::checkSeq(byte *string) {
+ int freeHSlotIncrease = 0;
+ byte c;
+ while ((c = string[0]) != 0xFF) {
+ string++;
+ if (c < 0xF0) {
+ freeHSlotIncrease++;
+ while ((c = string[0])) {
+ string++;
+ }
+ string++;
+ } else if (c != 0xFE) {
+ string++;
+ }
+ }
+ return freeHSlotIncrease;
+}
+
+void Interpreter::O_INITDIALOG() {
+ if (_string[0] == 255) {
+ byte *stringCurrOff = _string;
+ byte *string = _string;
+ stringCurrOff++;
+ int32 adressOfFirstSequence = (int)READ_LE_UINT16(stringCurrOff);
+ stringCurrOff += 2;
+ _string = string + adressOfFirstSequence;
+
+ for (int i = 0; i < 32; i++) {
+ _vm->_dialogBoxAddr[i] = 0;
+ _vm->_dialogOptAddr[i] = 0;
+ }
+
+ for (int i = 0; i < 4 * 32; i++) {
+ _vm->_dialogOptLines[i] = 0;
+ }
+
+ int16 off;
+ byte *line = nullptr;
+
+ int dialogBox = 0;
+ while ((off = (int)READ_LE_UINT16(stringCurrOff)) != -1) {
+ stringCurrOff += 2;
+ if (off) {
+ line = string + off;
+ }
+ _vm->_dialogBoxAddr[dialogBox] = line;
+ dialogBox++;
+ }
+ stringCurrOff += 2;
+
+ int dialogOpt = 0;
+ while ((off = (int)READ_LE_UINT16(stringCurrOff)) != -1) {
+ stringCurrOff += 2;
+ if (off) {
+ line = string + off;
+ }
+ _vm->_dialogOptAddr[dialogOpt] = line;
+ dialogOpt++;
+ }
+
+ _flags->setFlagValue(Flags::VOICE_A_LINE, 0);
+ _flags->setFlagValue(Flags::VOICE_B_LINE, 0); // bx in original?
+
+ int freeHSlot = 0;
+ for (int i = 31; i >= 0; i--) {
+ if (_vm->_dialogOptAddr[i] != 0) {
+ i++;
+ freeHSlot = i;
+ _flags->setFlagValue(Flags::VOICE_H_LINE, i);
+ break;
+ }
+ }
+
+ freeHSlot += checkSeq(_string);
+
+ for (int i = 0; i < 32; i++) {
+ _vm->_dialogOptLines[i * 4] = freeHSlot;
+ _vm->_dialogOptLines[i * 4 + 1] = freeHSlot;
+ _vm->_dialogOptLines[i * 4 + 2] = freeHSlot;
+ if (_vm->_dialogOptAddr[i]) {
+ freeHSlot += checkSeq(_vm->_dialogOptAddr[i]);
+ }
+ }
+ }
+ debugInterpreter("O_INITDIALOG");
+}
+
+void Interpreter::O_ENABLEDIALOGOPT() {
+ int32 opt = readScriptFlagValue();
+ int dialogDataValue = (int)READ_LE_UINT32(_vm->_dialogData);
+ dialogDataValue &= ~(1u << opt);
+ WRITE_LE_UINT32(_vm->_dialogData, dialogDataValue);
+ debugInterpreter("O_ENABLEDIALOGOPT opt %d", opt);
+}
+
+void Interpreter::O_DISABLEDIALOGOPT() {
+ int32 opt = readScriptFlagValue();
+ int dialogDataValue = (int)READ_LE_UINT32(_vm->_dialogData);
+ dialogDataValue |= (1u << opt);
+ WRITE_LE_UINT32(_vm->_dialogData, dialogDataValue);
+ debugInterpreter("O_DISABLEDIALOGOPT opt %d", opt);
+}
+
+void Interpreter::O_SHOWDIALOGBOX() {
+ int32 box = readScriptFlagValue();
+ uint32 currInstr = _currentInstruction;
+ _vm->createDialogBox(box);
+ _flags->setFlagValue(Flags::DIALINES, _vm->_dialogLines);
+ if (_vm->_dialogLines) {
+ _vm->changeCursor(1);
+ _vm->runDialog();
+ _vm->changeCursor(0);
+ }
+ _currentInstruction = currInstr;
+ debugInterpreter("O_SHOWDIALOGBOX box %d", box);
+}
+
+void Interpreter::O_STOPSAMPLE() {
+ int32 slot = readScriptFlagValue();
+ _vm->stopSample(slot);
+ debugInterpreter("O_STOPSAMPLE slot %d", slot);
+}
+
+void Interpreter::O_BACKANIMRANGE() {
+ int32 slotId = readScriptFlagValue();
+ uint16 animId = readScript16();
+ int32 low = readScriptFlagValue();
+ int32 high = readScriptFlagValue();
+ if (animId != 0xFFFF) {
+ if (animId & InterpreterFlags::kFlagMask) {
+ animId = _flags->getFlagValue((Flags::Id)animId);
+ }
+ }
+ _result = 1;
+ if (!_vm->_backAnimList[slotId].backAnims.empty()) {
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ if (_vm->_backAnimList[slotId].backAnims[currAnim]._animData != nullptr) {
+ if (animId == 0xFFFF || _vm->_backAnimList[slotId]._seq._current == animId) {
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ Anim &backAnim = _vm->_backAnimList[slotId].backAnims[currAnim];
+ if (!backAnim._state) {
+ if (backAnim._frame >= low) {
+ if (backAnim._frame <= high) {
+ _result = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ debugInterpreter("O_BACKANIMRANGE slotId %d, animId %d, low %d, high %d, _result %d", slotId, animId, low, high, _result);
+}
+
+void Interpreter::O_CLEARPATH() {
+ for (int i = 0; i < _vm->kPathBitmapLen; i++) {
+ _vm->_roomPathBitmap[i] = 255;
+ }
+ debugInterpreter("O_CLEARPATH");
+}
+
+void Interpreter::O_SETPATH() {
+ _vm->loadPath("path");
+ debugInterpreter("O_SETPATH");
+}
+
+void Interpreter::O_GETHEROX() {
+ int32 heroId = readScriptFlagValue();
+ Flags::Id flagId = readScriptFlagId();
+ if (!heroId) {
+ _flags->setFlagValue(flagId, _vm->_mainHero->_middleX);
+ } else if (heroId == 1) {
+ _flags->setFlagValue(flagId, _vm->_secondHero->_middleX);
+ }
+ debugInterpreter("O_GETHEROX heroId %d, flagId %d", heroId, flagId);
+}
+
+void Interpreter::O_GETHEROY() {
+ int32 heroId = readScriptFlagValue();
+ Flags::Id flagId = readScriptFlagId();
+ if (!heroId) {
+ _flags->setFlagValue(flagId, _vm->_mainHero->_middleY);
+ } else if (heroId == 1) {
+ _flags->setFlagValue(flagId, _vm->_secondHero->_middleY);
+ }
+ debugInterpreter("O_GETHEROY heroId %d, flagId %d", heroId, flagId);
+}
+
+void Interpreter::O_GETHEROD() {
+ int32 heroId = readScriptFlagValue();
+ Flags::Id flagId = readScriptFlagId();
+ if (!heroId) {
+ _flags->setFlagValue(flagId, _vm->_mainHero->_lastDirection);
+ } else if (heroId == 1) {
+ _flags->setFlagValue(flagId, _vm->_secondHero->_lastDirection);
+ }
+ debugInterpreter("O_GETHEROD heroId %d, flagId %d", heroId, flagId);
+}
+
+void Interpreter::O_PUSHSTRING() {
+ _stringStack.string = _string;
+ _stringStack.dialogData = _vm->_dialogData;
+ _stringStack.currentString = _currentString;
+ debugInterpreter("O_PUSHSTRING");
+}
+
+void Interpreter::O_POPSTRING() {
+ _string = _stringStack.string;
+ _vm->_dialogData = _stringStack.dialogData;
+ _currentString = _stringStack.currentString;
+ debugInterpreter("O_POPSTRING");
+}
+
+void Interpreter::O_SETFGCODE() {
+ int32 offset = readScript32();
+ _fgOpcodePC = _currentInstruction + offset - 4;
+ debugInterpreter("O_SETFGCODE next %08x, offset %08x", _fgOpcodePC, offset);
+}
+
+void Interpreter::O_STOPHERO() {
+ int32 heroId = readScriptFlagValue();
+ if (!heroId) {
+ _vm->_mainHero->freeOldMove();
+ } else if (heroId == 1) {
+ _vm->_secondHero->freeOldMove();
+ }
+ debugInterpreter("O_STOPHERO heroId %d", heroId);
+}
+
+void Interpreter::O_ANIMUPDATEOFF() {
+ int32 slotId = readScriptFlagValue();
+ _vm->_normAnimList[slotId]._state = 1;
+ debugInterpreter("O_ANIMUPDATEOFF slotId %d", slotId);
+}
+
+void Interpreter::O_ANIMUPDATEON() {
+ int32 slotId = readScriptFlagValue();
+ _vm->_normAnimList[slotId]._state = 0;
+ debugInterpreter("O_ANIMUPDATEON slotId %d", slotId);
+}
+
+void Interpreter::O_FREECURSOR() {
+ _vm->changeCursor(0);
+ _vm->_currentPointerNumber = 1;
+ // free memory here?
+ debugInterpreter("O_FREECURSOR");
+}
+
+void Interpreter::O_ADDINVQUIET() {
+ int32 hero = readScriptFlagValue();
+ int32 item = readScriptFlagValue();
+ _vm->addInv(hero, item, true);
+ debugInterpreter("O_ADDINVQUIET hero %d, item %d", hero, item);
+}
+
+void Interpreter::O_RUNHERO() {
+ int32 heroId = readScriptFlagValue();
+ int32 x = readScriptFlagValue();
+ int32 y = readScriptFlagValue();
+ int32 dir = readScriptFlagValue();
+ _vm->moveRunHero(heroId, x, y, dir, true);
+ debugInterpreter("O_RUNHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
+}
+
+void Interpreter::O_SETBACKANIMDATA() {
+ uint16 animNumber = readScript16();
+ uint16 animDataOffset = readScript16();
+ Flags::Id flagId = readScriptFlagId();
+ uint16 value = _flags->getFlagValue((Flags::Id)(flagId));
+ int currAnim = _vm->_backAnimList[animNumber]._seq._currRelative;
+ _vm->_backAnimList[animNumber].backAnims[currAnim].setAnimData((Anim::AnimOffsets)(animDataOffset), value);
+ debugInterpreter("O_SETBACKANIMDATA flag %04X (%s), animNumber %d, animDataOffset %d, value %d", flagId, Flags::getFlagName(flagId), animNumber, animDataOffset, value);
+}
+
+void Interpreter::O_VIEWFLC() {
+ int32 animNr = readScriptFlagValue();
+ _vm->_flcFrameSurface = nullptr;
+ _vm->loadAnim(animNr, false);
+ debugInterpreter("O_VIEWFLC animNr %d", animNr);
+}
+
+void Interpreter::O_CHECKFLCFRAME() {
+ int32 frameNr = readScriptFlagValue();
+ debugInterpreter("O_CHECKFLCFRAME frame number %d", frameNr);
+ if (_vm->_flicPlayer.getCurFrame() != frameNr) {
+ _currentInstruction -= 4;
+ _opcodeNF = 1;
+ }
+}
+
+void Interpreter::O_CHECKFLCEND() {
+ const Video::FlicDecoder &flicPlayer = _vm->_flicPlayer;
+ debugInterpreter("O_CHECKFLCEND frameCount %d, currentFrame %d", flicPlayer.getFrameCount(), flicPlayer.getCurFrame());
+ if (flicPlayer.getFrameCount() - flicPlayer.getCurFrame() > 1) {
+ _currentInstruction -= 2;
+ _opcodeNF = 1;
+ }
+}
+
+void Interpreter::O_FREEFLC() {
+ _vm->_flcFrameSurface = nullptr;
+ debugInterpreter("O_FREEFLC");
+}
+
+void Interpreter::O_TALKHEROSTOP() {
+ int32 heroId = readScriptFlagValue();
+ if (!heroId) {
+ _vm->_mainHero->_state = Hero::kHeroStateStay;
+ } else if (heroId == 1) {
+ _vm->_secondHero->_state = Hero::kHeroStateStay;
+ }
+ debugInterpreter("O_TALKHEROSTOP %d", heroId);
+}
+
+void Interpreter::O_HEROCOLOR() {
+ int32 heroId = readScriptFlagValue();
+ int32 color = readScriptFlagValue();
+ if (!heroId) {
+ _vm->_mainHero->_color = color;
+ } else if (heroId == 1) {
+ _vm->_secondHero->_color = color;
+ }
+ debugInterpreter("O_HEROCOLOR heroId %d, color %d", heroId, color);
+}
+
+void Interpreter::O_GRABMAPA() {
+ _vm->grabMap();
+ debugInterpreter("O_GRABMAPA");
+}
+
+void Interpreter::O_ENABLENAK() {
+ int32 nakId = readScriptFlagValue();
+ _vm->_maskList[nakId]._flags = 0;
+ debugInterpreter("O_ENABLENAK nakId %d", nakId);
+}
+
+void Interpreter::O_DISABLENAK() {
+ int32 nakId = readScriptFlagValue();
+ _vm->_maskList[nakId]._flags = 1;
+ debugInterpreter("O_DISABLENAK nakId %d", nakId);
+}
+
+void Interpreter::O_GETMOBNAME() {
+ int32 modId = readScriptFlagValue();
+ _string = (byte *)_vm->_mobList[modId]._name.c_str();
+ debugInterpreter("O_GETMOBNAME modId %d", modId);
+}
+
+void Interpreter::O_SWAPINVENTORY() {
+ int32 hero = readScriptFlagValue();
+ _vm->swapInv(hero);
+ debugInterpreter("O_SWAPINVENTORY hero %d", hero);
+}
+
+void Interpreter::O_CLEARINVENTORY() {
+ int32 hero = readScriptFlagValue();
+ _vm->clearInv(hero);
+ debugInterpreter("O_CLEARINVENTORY hero %d", hero);
+}
+
+void Interpreter::O_SKIPTEXT() {
+ increaseString();
+ debugInterpreter("O_SKIPTEXT");
+}
+
+void Interpreter::O_SETVOICEH() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_H_SLOT = 28;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_H_SLOT, voiceLineH);
+}
+
+void Interpreter::O_SETVOICEA() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_A_SLOT = 29;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_A_SLOT, voiceLineH);
+}
+
+void Interpreter::O_SETVOICEB() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_B_SLOT = 30;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_B_SLOT, voiceLineH);
+}
+
+void Interpreter::O_SETVOICEC() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_C_SLOT = 31;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_C_SLOT, voiceLineH);
+}
+
+void Interpreter::O_SETVOICED() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_D_SLOT = 32;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_D_SLOT, voiceLineH);
+}
+
+void Interpreter::O_VIEWFLCLOOP() {
+ int32 animId = readScriptFlagValue();
+ _vm->loadAnim(animId, true);
+ debugInterpreter("O_VIEWFLCLOOP animId %d", animId);
+}
+
+// Not used in script
+void Interpreter::O_FLCSPEED() {
+ error("O_FLCSPEED speed %d");
+}
+
+void Interpreter::O_OPENINVENTORY() {
+ _vm->_showInventoryFlag = true;
+ _opcodeNF = 1;
+ debugInterpreter("O_OPENINVENTORY");
+}
+
+void Interpreter::O_KRZYWA() {
+ _vm->makeCurve();
+ debugInterpreter("O_KRZYWA");
+}
+
+void Interpreter::O_GETKRZYWA() {
+ _vm->getCurve();
+ debugInterpreter("O_GETKRZYWA");
+}
+
+void Interpreter::O_GETMOB() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 posX = readScriptFlagValue();
+ int32 posY = readScriptFlagValue();
+ int mobNumber = _vm->getMob(_vm->_mobList, true, posX, posY);
+ _flags->setFlagValue(flagId, mobNumber + 1);
+ debugInterpreter("O_GETMOB flagId %d, posX %d, posY %d", flagId, posX, posY);
+}
+
+// Not used in game
+void Interpreter::O_INPUTLINE() {
+ error("O_INPUTLINE");
+}
+
+// Not used in script
+void Interpreter::O_BREAK_POINT() {
+ error("O_BREAK_POINT");
+}
+
+Interpreter::OpcodeFunc Interpreter::_opcodes[kNumOpcodes] = {
+ &Interpreter::O_WAITFOREVER,
+ &Interpreter::O_BLACKPALETTE,
+ &Interpreter::O_SETUPPALETTE,
+ &Interpreter::O_INITROOM,
+ &Interpreter::O_SETSAMPLE,
+ &Interpreter::O_FREESAMPLE,
+ &Interpreter::O_PLAYSAMPLE,
+ &Interpreter::O_PUTOBJECT,
+ &Interpreter::O_REMOBJECT,
+ &Interpreter::O_SHOWANIM,
+ &Interpreter::O_CHECKANIMEND,
+ &Interpreter::O_FREEANIM,
+ &Interpreter::O_CHECKANIMFRAME,
+ &Interpreter::O_PUTBACKANIM,
+ &Interpreter::O_REMBACKANIM,
+ &Interpreter::O_CHECKBACKANIMFRAME,
+ &Interpreter::O_FREEALLSAMPLES,
+ &Interpreter::O_SETMUSIC,
+ &Interpreter::O_STOPMUSIC,
+ &Interpreter::O__WAIT,
+ &Interpreter::O_UPDATEOFF,
+ &Interpreter::O_UPDATEON,
+ &Interpreter::O_UPDATE ,
+ &Interpreter::O_CLS,
+ &Interpreter::O__CALL,
+ &Interpreter::O_RETURN,
+ &Interpreter::O_GO,
+ &Interpreter::O_BACKANIMUPDATEOFF,
+ &Interpreter::O_BACKANIMUPDATEON,
+ &Interpreter::O_CHANGECURSOR,
+ &Interpreter::O_CHANGEANIMTYPE,
+ &Interpreter::O__SETFLAG,
+ &Interpreter::O_COMPARE,
+ &Interpreter::O_JUMPZ,
+ &Interpreter::O_JUMPNZ,
+ &Interpreter::O_EXIT,
+ &Interpreter::O_ADDFLAG,
+ &Interpreter::O_TALKANIM,
+ &Interpreter::O_SUBFLAG,
+ &Interpreter::O_SETSTRING,
+ &Interpreter::O_ANDFLAG,
+ &Interpreter::O_GETMOBDATA,
+ &Interpreter::O_ORFLAG,
+ &Interpreter::O_SETMOBDATA,
+ &Interpreter::O_XORFLAG,
+ &Interpreter::O_GETMOBTEXT,
+ &Interpreter::O_MOVEHERO,
+ &Interpreter::O_WALKHERO,
+ &Interpreter::O_SETHERO,
+ &Interpreter::O_HEROOFF,
+ &Interpreter::O_HEROON,
+ &Interpreter::O_CLSTEXT,
+ &Interpreter::O_CALLTABLE,
+ &Interpreter::O_CHANGEMOB,
+ &Interpreter::O_ADDINV,
+ &Interpreter::O_REMINV,
+ &Interpreter::O_REPINV,
+ &Interpreter::O_OBSOLETE_GETACTION,
+ &Interpreter::O_ADDWALKAREA,
+ &Interpreter::O_REMWALKAREA,
+ &Interpreter::O_RESTOREWALKAREA,
+ &Interpreter::O_WAITFRAME,
+ &Interpreter::O_SETFRAME,
+ &Interpreter::O_RUNACTION,
+ &Interpreter::O_COMPAREHI,
+ &Interpreter::O_COMPARELO,
+ &Interpreter::O_PRELOADSET,
+ &Interpreter::O_FREEPRELOAD,
+ &Interpreter::O_CHECKINV,
+ &Interpreter::O_TALKHERO,
+ &Interpreter::O_WAITTEXT,
+ &Interpreter::O_SETHEROANIM,
+ &Interpreter::O_WAITHEROANIM,
+ &Interpreter::O_GETHERODATA,
+ &Interpreter::O_GETMOUSEBUTTON,
+ &Interpreter::O_CHANGEFRAMES,
+ &Interpreter::O_CHANGEBACKFRAMES,
+ &Interpreter::O_GETBACKANIMDATA,
+ &Interpreter::O_GETANIMDATA,
+ &Interpreter::O_SETBGCODE,
+ &Interpreter::O_SETBACKFRAME,
+ &Interpreter::O_GETRND,
+ &Interpreter::O_TALKBACKANIM,
+ &Interpreter::O_LOADPATH,
+ &Interpreter::O_GETCHAR,
+ &Interpreter::O_SETDFLAG,
+ &Interpreter::O_CALLDFLAG,
+ &Interpreter::O_PRINTAT,
+ &Interpreter::O_ZOOMIN,
+ &Interpreter::O_ZOOMOUT,
+ &Interpreter::O_SETSTRINGOFFSET,
+ &Interpreter::O_GETOBJDATA,
+ &Interpreter::O_SETOBJDATA,
+ &Interpreter::O_SWAPOBJECTS,
+ &Interpreter::O_CHANGEHEROSET,
+ &Interpreter::O_ADDSTRING,
+ &Interpreter::O_SUBSTRING,
+ &Interpreter::O_INITDIALOG,
+ &Interpreter::O_ENABLEDIALOGOPT,
+ &Interpreter::O_DISABLEDIALOGOPT,
+ &Interpreter::O_SHOWDIALOGBOX,
+ &Interpreter::O_STOPSAMPLE,
+ &Interpreter::O_BACKANIMRANGE,
+ &Interpreter::O_CLEARPATH,
+ &Interpreter::O_SETPATH,
+ &Interpreter::O_GETHEROX,
+ &Interpreter::O_GETHEROY,
+ &Interpreter::O_GETHEROD,
+ &Interpreter::O_PUSHSTRING,
+ &Interpreter::O_POPSTRING,
+ &Interpreter::O_SETFGCODE,
+ &Interpreter::O_STOPHERO,
+ &Interpreter::O_ANIMUPDATEOFF,
+ &Interpreter::O_ANIMUPDATEON,
+ &Interpreter::O_FREECURSOR,
+ &Interpreter::O_ADDINVQUIET,
+ &Interpreter::O_RUNHERO,
+ &Interpreter::O_SETBACKANIMDATA,
+ &Interpreter::O_VIEWFLC,
+ &Interpreter::O_CHECKFLCFRAME,
+ &Interpreter::O_CHECKFLCEND,
+ &Interpreter::O_FREEFLC,
+ &Interpreter::O_TALKHEROSTOP,
+ &Interpreter::O_HEROCOLOR,
+ &Interpreter::O_GRABMAPA,
+ &Interpreter::O_ENABLENAK,
+ &Interpreter::O_DISABLENAK,
+ &Interpreter::O_GETMOBNAME,
+ &Interpreter::O_SWAPINVENTORY,
+ &Interpreter::O_CLEARINVENTORY,
+ &Interpreter::O_SKIPTEXT,
+ &Interpreter::O_SETVOICEH,
+ &Interpreter::O_SETVOICEA,
+ &Interpreter::O_SETVOICEB,
+ &Interpreter::O_SETVOICEC,
+ &Interpreter::O_VIEWFLCLOOP,
+ &Interpreter::O_FLCSPEED,
+ &Interpreter::O_OPENINVENTORY,
+ &Interpreter::O_KRZYWA,
+ &Interpreter::O_GETKRZYWA,
+ &Interpreter::O_GETMOB,
+ &Interpreter::O_INPUTLINE,
+ &Interpreter::O_SETVOICED,
+ &Interpreter::O_BREAK_POINT,
+};
+
+} // End of namespace Prince