1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "prince/script.h"
24 #include "prince/prince.h"
25 #include "prince/flags.h"
26 #include "prince/variatxt.h"
27 #include "prince/font.h"
28 #include "prince/hero.h"
29 #include "prince/resource.h"
30 #include "prince/animation.h"
31 
32 #include "common/debug.h"
33 #include "common/debug-channels.h"
34 #include "common/archive.h"
35 #include "common/memstream.h"
36 
37 namespace Prince {
38 
39 static const uint16 kNumOpcodes = 144;
40 
Room()41 Room::Room() {}
42 
loadRoom(byte * roomData)43 bool Room::loadRoom(byte *roomData) {
44 	int roomSize = 64;
45 	Common::MemoryReadStream roomStream(roomData, roomSize);
46 
47 	_mobs = roomStream.readSint32LE();
48 	_backAnim = roomStream.readSint32LE();
49 	_obj = roomStream.readSint32LE();
50 	_nak = roomStream.readSint32LE();
51 	_itemUse = roomStream.readSint32LE();
52 	_itemGive = roomStream.readSint32LE();
53 	_walkTo = roomStream.readSint32LE();
54 	_examine = roomStream.readSint32LE();
55 	_pickup = roomStream.readSint32LE();
56 	_use = roomStream.readSint32LE();
57 	_pushOpen = roomStream.readSint32LE();
58 	_pullClose = roomStream.readSint32LE();
59 	_talk = roomStream.readSint32LE();
60 	_give = roomStream.readSint32LE();
61 
62 	return true;
63 }
64 
getOptionOffset(int option)65 int Room::getOptionOffset(int option) {
66 	switch (option) {
67 	case 0:
68 		return _walkTo;
69 	case 1:
70 		return _examine;
71 	case 2:
72 		return _pickup;
73 	case 3:
74 		return _use;
75 	case 4:
76 		return _pushOpen;
77 	case 5:
78 		return _pullClose;
79 	case 6:
80 		return _talk;
81 	case 7:
82 		return _give;
83 	default:
84 		error("Wrong option - nr %d", option);
85 	}
86 }
87 
Script(PrinceEngine * vm)88 Script::Script(PrinceEngine *vm) : _vm(vm), _data(nullptr), _dataSize(0) {
89 }
90 
~Script()91 Script::~Script() {
92 	if (_data != nullptr) {
93 		free(_data);
94 		_dataSize = 0;
95 		_data = nullptr;
96 	}
97 }
98 
loadStream(Common::SeekableReadStream & stream)99 bool Script::loadStream(Common::SeekableReadStream &stream) {
100 	_dataSize = stream.size();
101 	if (!_dataSize) {
102 		return false;
103 	}
104 
105 	_data = (byte *)malloc(_dataSize);
106 
107 	if (!_data) {
108 		return false;
109 	}
110 
111 	stream.read(_data, _dataSize);
112 
113 	Common::MemoryReadStream scriptDataStream(_data, _dataSize);
114 	_scriptInfo.rooms = scriptDataStream.readSint32LE();
115 	_scriptInfo.startGame = scriptDataStream.readSint32LE();
116 	_scriptInfo.restoreGame = scriptDataStream.readSint32LE();
117 	_scriptInfo.stdExamine = scriptDataStream.readSint32LE();
118 	_scriptInfo.stdPickup = scriptDataStream.readSint32LE();
119 	_scriptInfo.stdUse = scriptDataStream.readSint32LE();
120 	_scriptInfo.stdOpen = scriptDataStream.readSint32LE();
121 	_scriptInfo.stdClose = scriptDataStream.readSint32LE();
122 	_scriptInfo.stdTalk = scriptDataStream.readSint32LE();
123 	_scriptInfo.stdGive = scriptDataStream.readSint32LE();
124 	_scriptInfo.usdCode = scriptDataStream.readSint32LE();
125 	_scriptInfo.invObjExam = scriptDataStream.readSint32LE();
126 	_scriptInfo.invObjUse = scriptDataStream.readSint32LE();
127 	_scriptInfo.invObjUU = scriptDataStream.readSint32LE();
128 	_scriptInfo.stdUseItem = scriptDataStream.readSint32LE();
129 	_scriptInfo.lightSources = scriptDataStream.readSint32LE();
130 	_scriptInfo.specRout = scriptDataStream.readSint32LE();
131 	_scriptInfo.invObjGive = scriptDataStream.readSint32LE();
132 	_scriptInfo.stdGiveItem = scriptDataStream.readSint32LE();
133 	_scriptInfo.goTester = scriptDataStream.readSint32LE();
134 
135 	return true;
136 }
137 
readScript16(uint32 address)138 uint16 Script::readScript16(uint32 address) {
139 	assert((_data + address + sizeof(uint16)) <= (_data + _dataSize));
140 	uint16 data = READ_LE_UINT16(&_data[address]);
141 	return data;
142 }
143 
readScript32(uint32 address)144 uint32 Script::readScript32(uint32 address) {
145 	assert((_data + address + sizeof(uint32)) <= (_data + _dataSize));
146 	uint32 data = READ_LE_UINT32(&_data[address]);
147 	return data;
148 }
149 
getLightX(int locationNr)150 int16 Script::getLightX(int locationNr) {
151 	return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8]);
152 }
153 
getLightY(int locationNr)154 int16 Script::getLightY(int locationNr) {
155 	return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8 + 2]);
156 }
157 
getShadowScale(int locationNr)158 int32 Script::getShadowScale(int locationNr) {
159 	return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8 + 4]);
160 }
161 
getStartGameOffset()162 uint32 Script::getStartGameOffset() {
163 	return _scriptInfo.startGame;
164 }
165 
getLocationInitScript(int initRoomTableOffset,int roomNr)166 uint32 Script::getLocationInitScript(int initRoomTableOffset, int roomNr) {
167 	return (uint32)READ_LE_UINT32(&_data[initRoomTableOffset + roomNr * 4]);
168 }
169 
getMobVisible(int roomMobOffset,uint16 mob)170 byte Script::getMobVisible(int roomMobOffset, uint16 mob) {
171 	return _data[roomMobOffset + mob];
172 }
173 
setMobVisible(int roomMobOffset,uint16 mob,byte value)174 void Script::setMobVisible(int roomMobOffset, uint16 mob, byte value) {
175 	_data[roomMobOffset + mob] = value;
176 }
177 
getRoomOffset(int locationNr)178 uint8 *Script::getRoomOffset(int locationNr) {
179 	return &_data[_scriptInfo.rooms + locationNr * 64];
180 }
181 
getOptionStandardOffset(int option)182 int32 Script::getOptionStandardOffset(int option) {
183 	switch (option) {
184 	case 1:
185 		return _scriptInfo.stdExamine;
186 	case 2:
187 		return _scriptInfo.stdPickup;
188 	case 3:
189 		return _scriptInfo.stdUse;
190 	case 4:
191 		return _scriptInfo.stdOpen;
192 	case 5:
193 		return _scriptInfo.stdClose;
194 	case 6:
195 		return _scriptInfo.stdTalk;
196 	case 7:
197 		return _scriptInfo.stdGive;
198 	default:
199 		error("Wrong standard option - nr %d", option);
200 	}
201 }
202 
getHeroAnimName(int offset)203 uint8 *Script::getHeroAnimName(int offset) {
204 	return &_data[offset];
205 }
206 
getBackAnimId(int roomBackAnimOffset,int slot)207 uint32 Script::getBackAnimId(int roomBackAnimOffset, int slot) {
208 	uint32 animId = READ_LE_UINT32(&_data[roomBackAnimOffset + slot * 4]);
209 	return animId;
210 }
211 
setBackAnimId(int roomBackAnimOffset,int slot,int animId)212 void Script::setBackAnimId(int roomBackAnimOffset, int slot, int animId) {
213 	WRITE_LE_UINT32(&_data[roomBackAnimOffset + slot * 4], animId);
214 }
215 
getObjId(int roomObjOffset,int slot)216 byte Script::getObjId(int roomObjOffset, int slot) {
217 	return _data[roomObjOffset + slot];
218 }
219 
setObjId(int roomObjOffset,int slot,byte objectId)220 void Script::setObjId(int roomObjOffset, int slot, byte objectId) {
221 	_data[roomObjOffset + slot] = objectId;
222 }
223 
scanMobEvents(int mobMask,int dataEventOffset)224 int Script::scanMobEvents(int mobMask, int dataEventOffset) {
225 	debug(3, "scanMobEvents: mobMask: %d", mobMask);
226 	int i = 0;
227 	int16 mob;
228 	int32 code;
229 	do {
230 		mob = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 6]);
231 		if (mob == mobMask) {
232 			code = (int)READ_LE_UINT32(&_data[dataEventOffset + i * 6 + 2]);
233 			debug(3, "scanMobEvents: code: %d", code);
234 			return code;
235 		}
236 		i++;
237 	} while (mob != -1);
238 	return -1;
239 }
240 
scanMobEventsWithItem(int mobMask,int dataEventOffset,int itemMask)241 int Script::scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask) {
242 	debug(3, "scanMobEventsWithItem: mobMask: %d", mobMask);
243 	int i = 0;
244 	int16 mob;
245 	int16 item;
246 	int32 code;
247 	do {
248 		mob = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 8]);
249 		if (mob == mobMask) {
250 			item = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 8 + 2]);
251 			if (item == itemMask) {
252 				code = (int)READ_LE_UINT32(&_data[dataEventOffset + i * 8 + 4]);
253 				debug(3, "scanMobEventsWithItem: itemMask: %d", item);
254 				debug(3, "scanMobEventsWithItem: code: %d", code);
255 				return code;
256 			}
257 		}
258 		i++;
259 	} while (mob != -1);
260 	return -1;
261 }
262 
installSingleBackAnim(Common::Array<BackgroundAnim> & backAnimList,int slot,int roomBackAnimOffset)263 void Script::installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int roomBackAnimOffset) {
264 
265 	_vm->removeSingleBackAnim(slot); // free slot before loading
266 
267 	int offset = roomBackAnimOffset + slot * 4; // BackgroundAnim offset for selected slot number
268 
269 	BackgroundAnim newBackgroundAnim; // BackgroundAnim seq data and its array of Anim
270 
271 	int animOffset = READ_LE_UINT32(&_data[offset]); // pos of BackgroundAnim data in script
272 	int anims = READ_LE_UINT32(&_data[animOffset + 8]); // amount of Anim in BackgroundAnim
273 
274 	if (anims == 0) {
275 		anims = 1; // anims with 0 as amount in game data has just 1 animation
276 	}
277 
278 	if (animOffset != 0) {
279 		Common::MemoryReadStream stream(_data, _dataSize); // stream from script data
280 		for (int i = 0; i < anims; i++) {
281 			Anim newAnim;
282 			stream.seek(animOffset + kStructSizeBAS + kStructSizeBASA * i);
283 			// Anim BASA data
284 			newAnim._basaData._num = stream.readUint16LE();
285 			newAnim._basaData._start = stream.readUint16LE();
286 			newAnim._basaData._end = stream.readUint16LE();
287 
288 			// Anim number in game files
289 			int animNumber = newAnim._basaData._num;
290 			const Common::String animName = Common::String::format("AN%02d", animNumber);
291 			const Common::String shadowName = Common::String::format("AN%02dS", animNumber);
292 			newAnim._animData = new Animation();
293 			newAnim._shadowData = new Animation();
294 			Resource::loadResource(newAnim._animData, animName.c_str(), true);
295 			if (!Resource::loadResource(newAnim._shadowData, shadowName.c_str(), false)) {
296 				delete newAnim._shadowData;
297 				newAnim._shadowData = nullptr;
298 			}
299 
300 			newAnim._usage = 0;
301 			newAnim._state = 0; // enabled
302 			if ((_vm->_animList[animNumber]._flags & 4)) {
303 				newAnim._state = 1;
304 				newAnim._frame = _vm->_animList[animNumber]._endPhase;
305 				newAnim._showFrame = _vm->_animList[animNumber]._endPhase;
306 			} else {
307 				newAnim._frame = _vm->_animList[animNumber]._startPhase;
308 				newAnim._showFrame = _vm->_animList[animNumber]._startPhase;
309 			}
310 			newAnim._flags = _vm->_animList[animNumber]._flags;
311 			newAnim._lastFrame = _vm->_animList[animNumber]._endPhase;
312 			newAnim._loopFrame = _vm->_animList[animNumber]._loopPhase;
313 			newAnim._loopType = _vm->_animList[animNumber]._loopType;
314 			newAnim._nextAnim = _vm->_animList[animNumber]._nextAnim;
315 			newAnim._x = _vm->_animList[animNumber]._x;
316 			newAnim._y = _vm->_animList[animNumber]._y;
317 			newAnim._currFrame = 0;
318 			newAnim._currX = _vm->_animList[animNumber]._x;
319 			newAnim._currY = _vm->_animList[animNumber]._y;
320 			newAnim._currW = 0;
321 			newAnim._currH = 0;
322 			newAnim._packFlag = 0;
323 			newAnim._shadowBack = _vm->_animList[animNumber]._type;
324 			newBackgroundAnim.backAnims.push_back(newAnim);
325 		}
326 
327 		// Anim BAS data
328 		stream.seek(animOffset);
329 		newBackgroundAnim._seq._type = stream.readUint32LE();
330 		newBackgroundAnim._seq._data = stream.readUint32LE();
331 		newBackgroundAnim._seq._anims = stream.readUint32LE();
332 		stream.skip(12);
333 		newBackgroundAnim._seq._current = newBackgroundAnim.backAnims[0]._basaData._num;
334 		newBackgroundAnim._seq._counter = 0;
335 		newBackgroundAnim._seq._currRelative = 0;
336 		newBackgroundAnim._seq._data2 = stream.readUint32LE();
337 
338 		int start = newBackgroundAnim.backAnims[0]._basaData._start; // BASA_Start of first frame
339 		int end = newBackgroundAnim.backAnims[0]._basaData._end; // BASA_End of first frame
340 
341 		if (start != -1) {
342 			newBackgroundAnim.backAnims[0]._frame = start;
343 			newBackgroundAnim.backAnims[0]._showFrame = start;
344 			newBackgroundAnim.backAnims[0]._loopFrame = start;
345 		}
346 
347 		if (end != -1) {
348 			newBackgroundAnim.backAnims[0]._lastFrame = end;
349 		}
350 
351 		backAnimList[slot] = newBackgroundAnim;
352 	}
353 }
354 
installBackAnims(Common::Array<BackgroundAnim> & backAnimList,int roomBackAnimOffset)355 void Script::installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int roomBackAnimOffset) {
356 	for (int i = 0; i < _vm->kMaxBackAnims; i++) {
357 		installSingleBackAnim(backAnimList, i, roomBackAnimOffset);
358 	}
359 }
360 
installObjects(int offset)361 void Script::installObjects(int offset) {
362 	for (int i = 0; i < _vm->kMaxObjects; i++) {
363 		_vm->_objSlot[i] = _data[offset];
364 		offset++;
365 	}
366 }
367 
loadAllMasks(Common::Array<Mask> & maskList,int offset)368 bool Script::loadAllMasks(Common::Array<Mask> &maskList, int offset) {
369 	Mask tempMask;
370 	while (1) {
371 		Common::MemoryReadStream maskStream(_data, _dataSize);
372 		maskStream.seek(offset);
373 		tempMask._state = maskStream.readUint16LE();
374 		if (tempMask._state == 0xffff) {
375 			break;
376 		}
377 		tempMask._flags = maskStream.readUint16LE();
378 		tempMask._x1 = maskStream.readUint16LE();
379 		tempMask._y1 = maskStream.readUint16LE();
380 		tempMask._x2 = maskStream.readUint16LE();
381 		tempMask._y2 = maskStream.readUint16LE();
382 		tempMask._z = maskStream.readUint16LE();
383 		tempMask._number = maskStream.readUint16LE();
384 
385 		const Common::String msStreamName = Common::String::format("MS%02d", tempMask._number);
386 		Common::SeekableReadStream *msStream = SearchMan.createReadStreamForMember(msStreamName);
387 		if (!msStream) {
388 			tempMask._width = 0;
389 			tempMask._height = 0;
390 			tempMask._data = nullptr;
391 			warning("loadAllMasks: Can't load %s", msStreamName.c_str());
392 			delete msStream;
393 		} else {
394 			msStream = Resource::getDecompressedStream(msStream);
395 
396 			int32 dataSize = msStream->size();
397 			if (dataSize != -1) {
398 				tempMask._data = (byte *)malloc(dataSize);
399 				if (msStream->read(tempMask._data, dataSize) != (uint32)dataSize) {
400 					free(tempMask._data);
401 					delete msStream;
402 					return false;
403 				}
404 				delete msStream;
405 
406 				tempMask._width = tempMask.getWidth();
407 				tempMask._height = tempMask.getHeight();
408 			} else {
409 				return false;
410 			}
411 		}
412 
413 		maskList.push_back(tempMask);
414 		offset += 16; // size of Mask (Nak) struct
415 	}
416 	return true;
417 }
418 
InterpreterFlags()419 InterpreterFlags::InterpreterFlags() {
420 	resetAllFlags();
421 }
422 
resetAllFlags()423 void InterpreterFlags::resetAllFlags() {
424 	memset(_flags, 0, sizeof(_flags));
425 }
426 
setFlagValue(Flags::Id flagId,int32 value)427 void InterpreterFlags::setFlagValue(Flags::Id flagId, int32 value) {
428 	_flags[(uint32)flagId - kFlagMask] = value;
429 }
430 
getFlagValue(Flags::Id flagId)431 int32 InterpreterFlags::getFlagValue(Flags::Id flagId) {
432 	return _flags[(uint32)flagId - kFlagMask];
433 }
434 
Interpreter(PrinceEngine * vm,Script * script,InterpreterFlags * flags)435 Interpreter::Interpreter(PrinceEngine *vm, Script *script, InterpreterFlags *flags) :
436 	_vm(vm), _script(script), _flags(flags),
437 	_stacktop(0), _opcodeNF(false), _opcodeEnd(false),
438 	_waitFlag(0), _result(true) {
439 
440 	// Initialize the script
441 	_mode = "fg";
442 	_fgOpcodePC = _script->getStartGameOffset();
443 	_bgOpcodePC = 0;
444 
445 	_currentInstruction = 0;
446 	_lastOpcode = 0;
447 	_lastInstruction = 0;
448 
449 	_string = nullptr;
450 	_currentString = 0;
451 
452 	_stringStack.string = nullptr;
453 	_stringStack.dialogData = nullptr;
454 	_stringStack.currentString = 0;
455 
456 	memset(_stringBuf, 1, 1024);
457 }
458 
debugInterpreter(const char * s,...)459 void Interpreter::debugInterpreter(const char *s, ...) {
460 	char buf[STRINGBUFLEN];
461 	va_list va;
462 	va_start(va, s);
463 	vsnprintf(buf, STRINGBUFLEN, s, va);
464 	va_end(va);
465 
466 	Common::String str = Common::String::format("@0x%08X: ", _lastInstruction);
467 	str += Common::String::format("op %04d: ", _lastOpcode);
468 	if (!strcmp(_mode, "fg")) {
469 		debug(10, "PrinceEngine::Script %s %s", str.c_str(), buf);
470 	}
471 }
472 
stepBg()473 void Interpreter::stepBg() {
474 	if (_bgOpcodePC) {
475 		_mode = "bg";
476 		_bgOpcodePC = step(_bgOpcodePC);
477 	}
478 }
479 
stepFg()480 void Interpreter::stepFg() {
481 	if (_fgOpcodePC) {
482 		_mode = "fg";
483 		_fgOpcodePC = step(_fgOpcodePC);
484 	}
485 }
486 
step(uint32 opcodePC)487 uint32 Interpreter::step(uint32 opcodePC) {
488 	_currentInstruction = opcodePC;
489 
490 	while (!_opcodeNF) {
491 		_lastInstruction = _currentInstruction;
492 
493 		// Get the current opcode
494 		_lastOpcode = readScript16();
495 
496 		if (_lastOpcode >= kNumOpcodes)
497 			error(
498 				"Trying to execute unknown opcode @0x%04X: %02d",
499 				_currentInstruction,
500 				_lastOpcode);
501 
502 		// Execute the current opcode
503 		OpcodeFunc op = _opcodes[_lastOpcode];
504 		(this->*op)();
505 		if (_opcodeNF) {
506 			_opcodeNF = 0;
507 			break;
508 		}
509 	}
510 
511 	if (_opcodeEnd) {
512 		_vm->quitGame();
513 	}
514 
515 	return _currentInstruction;
516 }
517 
storeNewPC(int opcodePC)518 void Interpreter::storeNewPC(int opcodePC) {
519 	if (_flags->getFlagValue(Flags::GETACTION) == 1) {
520 		_flags->setFlagValue(Flags::GETACTIONDATA, opcodePC);
521 		opcodePC = _flags->getFlagValue(Flags::GETACTIONBACK);
522 	}
523 	_fgOpcodePC = opcodePC;
524 }
525 
getLastOPCode()526 int Interpreter::getLastOPCode() {
527 	return _lastOpcode;
528 }
529 
getFgOpcodePC()530 int Interpreter::getFgOpcodePC() {
531 	return _fgOpcodePC;
532 }
533 
getCurrentString()534 uint32 Interpreter::getCurrentString() {
535 	return _currentString;
536 }
537 
setCurrentString(uint32 value)538 void Interpreter::setCurrentString(uint32 value) {
539 	_currentString = value;
540 }
541 
getString()542 byte *Interpreter::getString() {
543 	return _string;
544 }
545 
setString(byte * newString)546 void Interpreter::setString(byte *newString) {
547 	_string = newString;
548 }
549 
increaseString()550 void Interpreter::increaseString() {
551 	while (*_string) {
552 		_string++;
553 	}
554 	_string++;
555 }
556 
setResult(byte value)557 void Interpreter::setResult(byte value) {
558 	_result = value;
559 }
560 
setBgOpcodePC(uint32 value)561 void Interpreter::setBgOpcodePC(uint32 value) {
562 	_bgOpcodePC = value;
563 }
564 
setFgOpcodePC(uint32 value)565 void Interpreter::setFgOpcodePC(uint32 value) {
566 	_fgOpcodePC = value;
567 }
568 
readScript16()569 uint16 Interpreter::readScript16() {
570 	uint16 data = _script->readScript16(_currentInstruction);
571 	_currentInstruction += sizeof(uint16);
572 	return data;
573 }
574 
readScript32()575 uint32 Interpreter::readScript32() {
576 	uint32 data = _script->readScript32(_currentInstruction);
577 	_currentInstruction += sizeof(uint32);
578 	return data;
579 }
580 
readScriptFlagValue()581 int32 Interpreter::readScriptFlagValue() {
582 	uint16 value = readScript16();
583 	if (value & InterpreterFlags::kFlagMask) {
584 		return _flags->getFlagValue((Flags::Id)value);
585 	}
586 	return value;
587 }
588 
readScriptFlagId()589 Flags::Id Interpreter::readScriptFlagId() {
590 	return (Flags::Id)readScript16();
591 }
592 
O_WAITFOREVER()593 void Interpreter::O_WAITFOREVER() {
594 	debugInterpreter("O_WAITFOREVER");
595 	_vm->changeCursor(_vm->_currentPointerNumber);
596 	_opcodeNF = 1;
597 	_currentInstruction -= 2;
598 }
599 
O_BLACKPALETTE()600 void Interpreter::O_BLACKPALETTE() {
601 	debugInterpreter("O_BLACKPALETTE");
602 	_vm->blackPalette();
603 }
604 
O_SETUPPALETTE()605 void Interpreter::O_SETUPPALETTE() {
606 	debugInterpreter("O_SETUPPALETTE");
607 	_vm->setPalette(_vm->_roomBmp->getPalette());
608 }
609 
O_INITROOM()610 void Interpreter::O_INITROOM() {
611 	int32 roomId = readScriptFlagValue();
612 	debugInterpreter("O_INITROOM %d", roomId);
613 	_vm->loadLocation(roomId);
614 	_opcodeNF = 1;
615 }
616 
O_SETSAMPLE()617 void Interpreter::O_SETSAMPLE() {
618 	int32 sampleId = readScriptFlagValue();
619 	int32 sampleNameOffset = readScript32();
620 	const char *sampleName = _script->getString(_currentInstruction + sampleNameOffset - 4);
621 	debugInterpreter("O_SETSAMPLE %d %s", sampleId, sampleName);
622 	_vm->loadSample(sampleId, sampleName);
623 }
624 
O_FREESAMPLE()625 void Interpreter::O_FREESAMPLE() {
626 	int32 sampleId = readScriptFlagValue();
627 	debugInterpreter("O_FREESAMPLE sampleId: %d", sampleId);
628 	_vm->freeSample(sampleId);
629 }
630 
O_PLAYSAMPLE()631 void Interpreter::O_PLAYSAMPLE() {
632 	int32 sampleId = readScriptFlagValue();
633 	uint16 loopType = readScript16();
634 	debugInterpreter("O_PLAYSAMPLE sampleId %d loopType %d", sampleId, loopType);
635 	_vm->playSample(sampleId, loopType);
636 }
637 
O_PUTOBJECT()638 void Interpreter::O_PUTOBJECT() {
639 	int32 roomId = readScriptFlagValue();
640 	int32 slot = readScriptFlagValue();
641 	int32 objectId = readScriptFlagValue();
642 	debugInterpreter("O_PUTOBJECT roomId %d, slot %d, objectId %d", roomId, slot, objectId);
643 	Room *room = new Room();
644 	room->loadRoom(_script->getRoomOffset(roomId));
645 	_vm->_script->setObjId(room->_obj, slot, objectId);
646 	if (_vm->_locationNr == roomId) {
647 		_vm->_objSlot[slot] = objectId;
648 	}
649 	delete room;
650 }
651 
O_REMOBJECT()652 void Interpreter::O_REMOBJECT() {
653 	int32 roomId = readScriptFlagValue();
654 	int32 slot = readScriptFlagValue();
655 	debugInterpreter("O_REMOBJECT roomId %d slot %d", roomId, slot);
656 	Room *room = new Room();
657 	room->loadRoom(_script->getRoomOffset(roomId));
658 	_vm->_script->setObjId(room->_obj, slot, 0xFF);
659 	if (_vm->_locationNr == roomId) {
660 		_vm->_objSlot[slot] = 0xFF;
661 	}
662 	delete room;
663 }
664 
O_SHOWANIM()665 void Interpreter::O_SHOWANIM() {
666 	int32 slot = readScriptFlagValue();
667 	int32 animId = readScriptFlagValue();
668 	debugInterpreter("O_SHOWANIM slot %d, animId %d", slot, animId);
669 	_vm->freeNormAnim(slot);
670 	Anim &anim = _vm->_normAnimList[slot];
671 	AnimListItem &animList = _vm->_animList[animId];
672 	anim._currFrame = 0;
673 	anim._packFlag = 0;
674 	anim._state = 0;
675 	anim._frame = animList._startPhase;
676 	anim._showFrame = animList._startPhase;
677 	anim._lastFrame = animList._endPhase;
678 	anim._loopFrame = animList._loopPhase;
679 	anim._x = animList._x;
680 	anim._y = animList._y;
681 	anim._loopType = animList._loopType;
682 	anim._shadowBack = animList._type;
683 	anim._flags = animList._flags;
684 	anim._nextAnim = animList._nextAnim;
685 	int fileNumber = animList._fileNumber;
686 	const Common::String animName = Common::String::format("AN%02d", fileNumber);
687 	const Common::String shadowName = Common::String::format("AN%02dS", fileNumber);
688 	anim._animData = new Animation();
689 	anim._shadowData = new Animation();
690 	Resource::loadResource(anim._animData, animName.c_str(), true);
691 	if (!Resource::loadResource(anim._shadowData, shadowName.c_str(), false)) {
692 		delete anim._shadowData;
693 		anim._shadowData = nullptr;
694 	}
695 
696 	// WALKAROUND: fix for turning off bard's wife background animation
697 	// in front of bard's house (location 7) after giving her poem (item 33)
698 	// in script: GiveLetter (line 11082)
699 	if (_currentInstruction == kGiveLetterScriptFix) {
700 		_vm->_backAnimList[1].backAnims[0]._state = 1;
701 	}
702 }
703 
O_CHECKANIMEND()704 void Interpreter::O_CHECKANIMEND() {
705 	int32 slot = readScriptFlagValue();
706 	debugInterpreter("O_CHECKANIMEND slot %d", slot);
707 	if (_vm->_normAnimList[slot]._frame != _vm->_normAnimList[slot]._lastFrame - 1) {
708 		_currentInstruction -= 4;
709 		_opcodeNF = 1;
710 	}
711 }
712 
O_FREEANIM()713 void Interpreter::O_FREEANIM() {
714 	int32 slot = readScriptFlagValue();
715 	debugInterpreter("O_FREEANIM slot %d", slot);
716 	_vm->freeNormAnim(slot);
717 }
718 
O_CHECKANIMFRAME()719 void Interpreter::O_CHECKANIMFRAME() {
720 	int32 slot = readScriptFlagValue();
721 	int32 frameNumber = readScriptFlagValue();
722 	debugInterpreter("O_CHECKANIMFRAME slot %d, frameNumber %d", slot, frameNumber);
723 	if (_vm->_normAnimList[slot]._frame != frameNumber - 1) {
724 		_currentInstruction -= 6;
725 		_opcodeNF = 1;
726 	}
727 }
728 
O_PUTBACKANIM()729 void Interpreter::O_PUTBACKANIM() {
730 	int32 roomId = readScriptFlagValue();
731 	int32 slot = readScriptFlagValue();
732 	int32 animId = readScript32();
733 	debugInterpreter("O_PUTBACKANIM roomId %d, slot %d, animId %d", roomId, slot, animId);
734 	Room *room = new Room();
735 	room->loadRoom(_script->getRoomOffset(roomId));
736 	_vm->_script->setBackAnimId(room->_backAnim, slot, animId);
737 	if (_vm->_locationNr == roomId) {
738 		_vm->_script->installSingleBackAnim(_vm->_backAnimList, slot, room->_backAnim);
739 	}
740 	delete room;
741 
742 	// WALKAROUND: fix for turning on 'walking bird' background animation too soon,
743 	// after completing 'throw a rock' mini-game in Silmaniona location.
744 	// Second bird shouldn't appear when normal animation is still in use
745 	// in script lines 13814 and 13848
746 	if (_currentInstruction == kSecondBirdAnimationScriptFix) {
747 		if (_vm->_normAnimList[1]._state == 0) {
748 			_vm->_backAnimList[0].backAnims[0]._state = 1;
749 		}
750 	}
751 }
752 
O_REMBACKANIM()753 void Interpreter::O_REMBACKANIM() {
754 	int32 roomId = readScriptFlagValue();
755 	int32 slot = readScriptFlagValue();
756 	debugInterpreter("O_REMBACKANIM roomId %d, slot %d", roomId, slot);
757 	if (_vm->_locationNr == roomId) {
758 		_vm->removeSingleBackAnim(slot);
759 	}
760 	Room *room = new Room();
761 	room->loadRoom(_script->getRoomOffset(roomId));
762 	_vm->_script->setBackAnimId(room->_backAnim, slot, 0);
763 	delete room;
764 }
765 
O_CHECKBACKANIMFRAME()766 void Interpreter::O_CHECKBACKANIMFRAME() {
767 	int32 slotId = readScriptFlagValue();
768 	int32 frameId = readScriptFlagValue();
769 	debugInterpreter("O_CHECKBACKANIMFRAME slotId %d, frameId %d", slotId, frameId);
770 	int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
771 	if (_vm->_backAnimList[slotId].backAnims[currAnim]._frame != frameId - 1) {
772 		_currentInstruction -= 6;
773 		_opcodeNF = 1;
774 	}
775 }
776 
777 // Not used in script
O_FREEALLSAMPLES()778 void Interpreter::O_FREEALLSAMPLES() {
779 	error("O_FREEALLSAMPLES");
780 }
781 
O_SETMUSIC()782 void Interpreter::O_SETMUSIC() {
783 	uint16 musicId = readScript16();
784 	debugInterpreter("O_SETMUSIC musicId %d", musicId);
785 	_vm->loadMusic(musicId);
786 }
787 
O_STOPMUSIC()788 void Interpreter::O_STOPMUSIC() {
789 	debugInterpreter("O_STOPMUSIC");
790 	_vm->stopMusic();
791 }
792 
O__WAIT()793 void Interpreter::O__WAIT() {
794 	int32 pause = readScriptFlagValue();
795 	debugInterpreter("O__WAIT pause %d", pause);
796 	if (!_waitFlag) {
797 		// set new wait flag value and continue
798 		_waitFlag = pause;
799 		_opcodeNF = 1;
800 		_currentInstruction -= 4;
801 		return;
802 	}
803 	_waitFlag--;
804 	if (_waitFlag > 0) {
805 		_opcodeNF = 1;
806 		_currentInstruction -= 4;
807 		return;
808 	}
809 }
810 
811 // Not used in script
O_UPDATEOFF()812 void Interpreter::O_UPDATEOFF() {
813 	error("O_UPDATEOFF");
814 }
815 
816 // Not used in script
O_UPDATEON()817 void Interpreter::O_UPDATEON() {
818 	error("O_UPDATEON");
819 }
820 
821 // Not used in script
O_UPDATE()822 void Interpreter::O_UPDATE () {
823 	error("O_UPDATE");
824 }
825 
826 // Not used in script
O_CLS()827 void Interpreter::O_CLS() {
828 	error("O_CLS");
829 }
830 
O__CALL()831 void Interpreter::O__CALL() {
832 	int32 address = readScript32();
833 	debugInterpreter("O__CALL 0x%04X", _currentInstruction);
834 	_stack[_stacktop] = _currentInstruction;
835 	_stacktop++;
836 	_currentInstruction += address - 4;
837 }
838 
O_RETURN()839 void Interpreter::O_RETURN() {
840 	debugInterpreter("O_RETURN 0x%04X", _currentInstruction);
841 	if (_stacktop > 0) {
842 		_stacktop--;
843 		_currentInstruction = _stack[_stacktop];
844 	} else {
845 		error("O_RETURN: Stack is empty");
846 	}
847 }
848 
O_GO()849 void Interpreter::O_GO() {
850 	int32 opPC = readScript32();
851 	debugInterpreter("O_GO 0x%04X", opPC);
852 	_currentInstruction += opPC - 4;
853 }
854 
O_BACKANIMUPDATEOFF()855 void Interpreter::O_BACKANIMUPDATEOFF() {
856 	int32 slotId = readScriptFlagValue();
857 	debugInterpreter("O_BACKANIMUPDATEOFF slotId %d", slotId);
858 	int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
859 	if (!_vm->_backAnimList[slotId].backAnims.empty()) {
860 		_vm->_backAnimList[slotId].backAnims[currAnim]._state = 1;
861 	}
862 }
863 
O_BACKANIMUPDATEON()864 void Interpreter::O_BACKANIMUPDATEON() {
865 	int32 slotId = readScriptFlagValue();
866 	debugInterpreter("O_BACKANIMUPDATEON slotId %d", slotId);
867 	int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
868 	if (!_vm->_backAnimList[slotId].backAnims.empty()) {
869 		_vm->_backAnimList[slotId].backAnims[currAnim]._state = 0;
870 	}
871 }
872 
O_CHANGECURSOR()873 void Interpreter::O_CHANGECURSOR() {
874 	int32 cursorId = readScriptFlagValue();
875 	debugInterpreter("O_CHANGECURSOR %x", cursorId);
876 	_vm->changeCursor(cursorId);
877 }
878 
879 // Not used in script
O_CHANGEANIMTYPE()880 void Interpreter::O_CHANGEANIMTYPE() {
881 	error("O_CHANGEANIMTYPE");
882 }
883 
O__SETFLAG()884 void Interpreter::O__SETFLAG() {
885 	Flags::Id flagId = readScriptFlagId();
886 	int32 value = readScriptFlagValue();
887 	debugInterpreter("O__SETFLAG 0x%04X (%s) = %d", flagId, _flagMap.getFlagName(flagId), value);
888 	_flags->setFlagValue((Flags::Id)(flagId), value);
889 }
890 
O_COMPARE()891 void Interpreter::O_COMPARE() {
892 	Flags::Id flagId = readScriptFlagId();
893 	int32 value = readScriptFlagValue();
894 	_result = _flags->getFlagValue(flagId) != value;
895 	debugInterpreter("O_COMPARE flagId 0x%04X (%s), value %d == %d (%d)", flagId, _flagMap.getFlagName(flagId), value, _flags->getFlagValue(flagId), _result);
896 }
897 
O_JUMPZ()898 void Interpreter::O_JUMPZ() {
899 	int32 offset = readScript32();
900 	if (!_result) {
901 		_currentInstruction += offset - 4;
902 	}
903 	debugInterpreter("O_JUMPZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset);
904 }
905 
O_JUMPNZ()906 void Interpreter::O_JUMPNZ() {
907 	int32 offset = readScript32();
908 	if (_result) {
909 		_currentInstruction += offset - 4;
910 	}
911 	debugInterpreter("O_JUMPNZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset);
912 }
913 
O_EXIT()914 void Interpreter::O_EXIT() {
915 	int32 exitCode = readScriptFlagValue();
916 	debugInterpreter("O_EXIT exitCode %d", exitCode);
917 	_opcodeEnd = true;
918 	_opcodeNF = 1;
919 	if (exitCode == 0x2EAD) {
920 		_vm->scrollCredits();
921 	}
922 }
923 
O_ADDFLAG()924 void Interpreter::O_ADDFLAG() {
925 	Flags::Id flagId = readScriptFlagId();
926 	int32 value = readScriptFlagValue();
927 	debugInterpreter("O_ADDFLAG flagId %04x (%s), value %d", flagId, _flagMap.getFlagName(flagId), value);
928 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) + value);
929 	if (_flags->getFlagValue(flagId)) {
930 		_result = 1;
931 	} else {
932 		_result = 0;
933 	}
934 }
935 
O_TALKANIM()936 void Interpreter::O_TALKANIM() {
937 	int32 animNumber = readScriptFlagValue();
938 	int32 slot = readScriptFlagValue();
939 	debugInterpreter("O_TALKANIM animNumber %d, slot %d", animNumber, slot);
940 	_vm->doTalkAnim(animNumber, slot, kNormalAnimation);
941 }
942 
O_SUBFLAG()943 void Interpreter::O_SUBFLAG() {
944 	Flags::Id flagId = readScriptFlagId();
945 	int32 value = readScriptFlagValue();
946 	debugInterpreter("O_SUBFLAG flagId %d, value %d", flagId, value);
947 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) - value);
948 	if (_flags->getFlagValue(flagId)) {
949 		_result = 1;
950 	} else {
951 		_result = 0;
952 	}
953 }
954 
O_SETSTRING()955 void Interpreter::O_SETSTRING() {
956 	int32 offset = readScript32();
957 	debugInterpreter("O_SETSTRING %04d", offset);
958 	_currentString = offset;
959 	if (offset >= 80000) {
960 		_string = _vm->_variaTxt->getString(offset - 80000);
961 		debugInterpreter("GetVaria %s", _string);
962 	} else if (offset < 2000) {
963 		_vm->_dialogData = &_vm->_dialogDat[offset * 4 - 4];
964 		uint32 of = READ_LE_UINT32(_vm->_talkTxt + offset * 4);
965 		const char *txt = (const char *)&_vm->_talkTxt[of];
966 		_string = &_vm->_talkTxt[of];
967 		debugInterpreter("TalkTxt %d %s", of, txt);
968 	}
969 }
970 
O_ANDFLAG()971 void Interpreter::O_ANDFLAG() {
972 	Flags::Id flagId = readScriptFlagId();
973 	int32 value = readScriptFlagValue();
974 	debugInterpreter("O_ANDFLAG flagId %d, value %d", flagId, value);
975 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) & value);
976 	if (_flags->getFlagValue(flagId)) {
977 		_result = 1;
978 	} else {
979 		_result = 0;
980 	}
981 }
982 
O_GETMOBDATA()983 void Interpreter::O_GETMOBDATA() {
984 	Flags::Id flagId = readScriptFlagId();
985 	int32 mobId = readScriptFlagValue();
986 	int32 mobOffset = readScriptFlagValue();
987 	debugInterpreter("O_GETMOBDATA flagId %d, modId %d, mobOffset %d", flagId, mobId, mobOffset);
988 	int16 value = _vm->_mobList[mobId].getData((Mob::AttrId)mobOffset);
989 	_flags->setFlagValue(flagId, value);
990 }
991 
O_ORFLAG()992 void Interpreter::O_ORFLAG() {
993 	Flags::Id flagId = readScriptFlagId();
994 	int32 value = readScriptFlagValue();
995 	debugInterpreter("O_ORFLAG flagId %d, value %d", flagId, value);
996 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) | value);
997 	if (_flags->getFlagValue(flagId)) {
998 		_result = 1;
999 	} else {
1000 		_result = 0;
1001 	}
1002 }
1003 
O_SETMOBDATA()1004 void Interpreter::O_SETMOBDATA() {
1005 	int32 mobId = readScriptFlagValue();
1006 	int32 mobOffset = readScriptFlagValue();
1007 	int32 value = readScriptFlagValue();
1008 	debugInterpreter("O_SETMOBDATA mobId %d, mobOffset %d, value %d", mobId, mobOffset, value);
1009 	_vm->_mobList[mobId].setData((Mob::AttrId)mobOffset, value);
1010 }
1011 
O_XORFLAG()1012 void Interpreter::O_XORFLAG() {
1013 	Flags::Id flagId = readScriptFlagId();
1014 	int32 value = readScriptFlagValue();
1015 	debugInterpreter("O_XORFLAG flagId %d, value %d", flagId, value);
1016 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) ^ value);
1017 	if (_flags->getFlagValue(flagId)) {
1018 		_result = 1;
1019 	} else {
1020 		_result = 0;
1021 	}
1022 }
1023 
O_GETMOBTEXT()1024 void Interpreter::O_GETMOBTEXT() {
1025 	int32 mob = readScriptFlagValue();
1026 	debugInterpreter("O_GETMOBTEXT mob %d", mob);
1027 	_currentString = _vm->_locationNr * 100 + mob + 60001;
1028 	// Use memcpy() instead of strncpy() because the examination text can contain
1029 	// different phrases separated by '\0' characters, followed by an ID.
1030 	// The examination text ends for a mob if the ID is 0xFF.
1031 	// Strings are properly extracted by the interpreter in that format.
1032 	memcpy((char *)_stringBuf, _vm->_mobList[mob]._examText.c_str(), MIN<int>(_vm->_mobList[mob]._examText.size(), 1023));
1033 	_string = _stringBuf;
1034 }
1035 
O_MOVEHERO()1036 void Interpreter::O_MOVEHERO() {
1037 	int32 heroId = readScriptFlagValue();
1038 	int32 x = readScriptFlagValue();
1039 	int32 y = readScriptFlagValue();
1040 	int32 dir = readScriptFlagValue();
1041 	debugInterpreter("O_MOVEHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
1042 	_vm->moveRunHero(heroId, x, y, dir, false);
1043 }
1044 
O_WALKHERO()1045 void Interpreter::O_WALKHERO() {
1046 	int32 heroId = readScriptFlagValue();
1047 	debugInterpreter("O_WALKHERO %d", heroId);
1048 	Hero *hero = nullptr;
1049 	if (!heroId) {
1050 		hero = _vm->_mainHero;
1051 	} else if (heroId == 1) {
1052 		hero = _vm->_secondHero;
1053 	}
1054 	if (hero != nullptr) {
1055 		if (hero->_state != Hero::kHeroStateStay) {
1056 			_currentInstruction -= 4;
1057 			_opcodeNF = 1;
1058 		}
1059 	}
1060 }
1061 
O_SETHERO()1062 void Interpreter::O_SETHERO() {
1063 	int32 heroId = readScriptFlagValue();
1064 	int32 x = readScriptFlagValue();
1065 	int32 y = readScriptFlagValue();
1066 	int32 dir = readScriptFlagValue();
1067 	debugInterpreter("O_SETHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
1068 	Hero *hero = nullptr;
1069 	if (!heroId) {
1070 		hero = _vm->_mainHero;
1071 	} else if (heroId == 1) {
1072 		hero = _vm->_secondHero;
1073 	}
1074 	if (hero != nullptr) {
1075 		hero->setPos(x, y);
1076 		hero->_lastDirection = dir;
1077 		hero->_visible = 1;
1078 		hero->countDrawPosition();
1079 	}
1080 }
1081 
O_HEROOFF()1082 void Interpreter::O_HEROOFF() {
1083 	int32 heroId = readScriptFlagValue();
1084 	debugInterpreter("O_HEROOFF %d", heroId);
1085 	Hero *hero = nullptr;
1086 	if (!heroId) {
1087 		hero = _vm->_mainHero;
1088 	} else if (heroId == 1) {
1089 		hero = _vm->_secondHero;
1090 	}
1091 	if (hero != nullptr) {
1092 		hero->setVisible(false);
1093 	}
1094 }
1095 
O_HEROON()1096 void Interpreter::O_HEROON() {
1097 	int32 heroId = readScriptFlagValue();
1098 	debugInterpreter("O_HEROON %d", heroId);
1099 	Hero *hero = nullptr;
1100 	if (!heroId) {
1101 		hero = _vm->_mainHero;
1102 	} else if (heroId == 1) {
1103 		hero = _vm->_secondHero;
1104 	}
1105 	if (hero != nullptr) {
1106 		hero->setVisible(true);
1107 	}
1108 }
1109 
O_CLSTEXT()1110 void Interpreter::O_CLSTEXT() {
1111 	int32 slot = readScriptFlagValue();
1112 	debugInterpreter("O_CLSTEXT slot %d", slot);
1113 	_vm->_textSlots[slot]._str = nullptr;
1114 	_vm->_textSlots[slot]._time = 0;
1115 }
1116 
O_CALLTABLE()1117 void Interpreter::O_CALLTABLE() {
1118 	Flags::Id flagId = readScriptFlagId();
1119 	int roomNr = _flags->getFlagValue(flagId);
1120 	debugInterpreter("O_CALLTABLE loc %d", roomNr);
1121 	int32 tableOffset = readScript32();
1122 	int initLocationScript = _script->getLocationInitScript(tableOffset, roomNr);
1123 	if (initLocationScript) {
1124 		_stack[_stacktop] = _currentInstruction;
1125 		_stacktop++;
1126 		_currentInstruction = initLocationScript;
1127 	}
1128 }
1129 
O_CHANGEMOB()1130 void Interpreter::O_CHANGEMOB() {
1131 	int32 mob = readScriptFlagValue();
1132 	int32 value = readScriptFlagValue();
1133 	value ^= 1;
1134 	debugInterpreter("O_CHANGEMOB mob %d, value %d", mob, value);
1135 	_vm->_script->setMobVisible(_vm->_room->_mobs, mob, value);
1136 	_vm->_mobList[mob]._visible = value;
1137 }
1138 
O_ADDINV()1139 void Interpreter::O_ADDINV() {
1140 	int32 hero = readScriptFlagValue();
1141 	int32 item = readScriptFlagValue();
1142 	debugInterpreter("O_ADDINV hero %d, item %d", hero, item);
1143 	_vm->addInv(hero, item, false);
1144 }
1145 
O_REMINV()1146 void Interpreter::O_REMINV() {
1147 	int32 hero = readScriptFlagValue();
1148 	int32 item = readScriptFlagValue();
1149 	debugInterpreter("O_REMINV hero %d, item %d", hero, item);
1150 	_vm->remInv(hero, item);
1151 }
1152 
1153 // Not used in script
O_REPINV()1154 void Interpreter::O_REPINV() {
1155 	error("O_REPINV");
1156 }
1157 
1158 // Not used in script
O_OBSOLETE_GETACTION()1159 void Interpreter::O_OBSOLETE_GETACTION() {
1160 	error("O_OBSOLETE_GETACTION");
1161 }
1162 
1163 // Not used in script
O_ADDWALKAREA()1164 void Interpreter::O_ADDWALKAREA() {
1165 	error("O_ADDWALKAREA");
1166 }
1167 
1168 // Not used in script
O_REMWALKAREA()1169 void Interpreter::O_REMWALKAREA() {
1170 	error("O_REMWALKAREA");
1171 }
1172 
1173  // Not used in script
O_RESTOREWALKAREA()1174 void Interpreter::O_RESTOREWALKAREA() {
1175 	error("O_RESTOREWALKAREA");
1176 }
1177 
O_WAITFRAME()1178 void Interpreter::O_WAITFRAME() {
1179 	debugInterpreter("O_WAITFRAME");
1180 	_opcodeNF = true;
1181 }
1182 
O_SETFRAME()1183 void Interpreter::O_SETFRAME() {
1184 	int32 anim = readScriptFlagValue();
1185 	int32 frame = readScriptFlagValue();
1186 	debugInterpreter("O_SETFRAME anim %d, frame %d", anim, frame);
1187 	_vm->_normAnimList[anim]._frame = frame;
1188 }
1189 
1190 // Not used in script
O_RUNACTION()1191 void Interpreter::O_RUNACTION() {
1192 	error("O_RUNACTION");
1193 }
1194 
O_COMPAREHI()1195 void Interpreter::O_COMPAREHI() {
1196 	Flags::Id flag = readScriptFlagId();
1197 	int32 value = readScriptFlagValue();
1198 	int32 flagValue = _flags->getFlagValue(flag);
1199 	if (flagValue > value) {
1200 		_result = 0;
1201 	} else {
1202 		_result = 1;
1203 	}
1204 	debugInterpreter("O_COMPAREHI flag %04x - (%s), value %d, flagValue %d, result %d", flag, _flagMap.getFlagName(flag), value, flagValue, _result);
1205 }
1206 
O_COMPARELO()1207 void Interpreter::O_COMPARELO() {
1208 	Flags::Id flag = readScriptFlagId();
1209 	int32 value = readScriptFlagValue();
1210 	int32 flagValue = _flags->getFlagValue(flag);
1211 	if (flagValue < value) {
1212 		_result = 0;
1213 	} else {
1214 		_result = 1;
1215 	}
1216 	debugInterpreter("O_COMPARELO flag %04x - (%s), value %d, flagValue %d, result %d", flag, _flagMap.getFlagName(flag), value, flagValue, _result);
1217 }
1218 
1219 // Not used in script
O_PRELOADSET()1220 void Interpreter::O_PRELOADSET() {
1221 	error("O_PRELOADSET");
1222 }
1223 
1224 // Not used in script
O_FREEPRELOAD()1225 void Interpreter::O_FREEPRELOAD() {
1226 	error("O_FREEPRELOAD");
1227 }
1228 
1229 // Not used in script
O_CHECKINV()1230 void Interpreter::O_CHECKINV() {
1231 	error("O_CHECKINV");
1232 }
1233 
O_TALKHERO()1234 void Interpreter::O_TALKHERO() {
1235 	int32 hero = readScriptFlagValue();
1236 	debugInterpreter("O_TALKHERO hero %d", hero);
1237 	_vm->talkHero(hero);
1238 }
1239 
O_WAITTEXT()1240 void Interpreter::O_WAITTEXT() {
1241 	int32 slot = readScriptFlagValue();
1242 	debugInterpreter("O_WAITTEXT slot %d", slot);
1243 	Text &text = _vm->_textSlots[slot];
1244 	if (text._time && text._str) {
1245 		if (_flags->getFlagValue(Flags::ESCAPED)) {
1246 			text._time = 1;
1247 			if (!slot) {
1248 				_vm->_mainHero->_talkTime = 1;
1249 			} else if (slot == 1) {
1250 				_vm->_secondHero->_talkTime = 1;
1251 			}
1252 		} else {
1253 			_opcodeNF = 1;
1254 			_currentInstruction -= 4;
1255 		}
1256 	}
1257 }
1258 
O_SETHEROANIM()1259 void Interpreter::O_SETHEROANIM() {
1260 	int32 heroId = readScriptFlagValue();
1261 	int32 offset = readScript32();
1262 	debugInterpreter("O_SETHEROANIM hero %d, offset %d", heroId, offset);
1263 	Hero *hero = nullptr;
1264 	if (!heroId) {
1265 		hero = _vm->_mainHero;
1266 	} else {
1267 		hero = _vm->_secondHero;
1268 	}
1269 	if (hero != nullptr) {
1270 		hero->freeHeroAnim();
1271 		if (hero ->_specAnim == nullptr) {
1272 			hero->_specAnim = new Animation();
1273 			if (offset < 100) {
1274 				const Common::String animName = Common::String::format("AN%02d", offset);
1275 				Resource::loadResource(hero->_specAnim, animName.c_str(), true);
1276 			} else {
1277 				const Common::String animName = Common::String((const char *)_script->getHeroAnimName(offset));
1278 				Common::String normalizedPath = lastPathComponent(animName, '\\');
1279 				Resource::loadResource(hero->_specAnim, normalizedPath.c_str(), true);
1280 			}
1281 			hero->_phase = 0;
1282 			hero->_state = Hero::kHeroStateSpec;
1283 		}
1284 	}
1285 }
1286 
O_WAITHEROANIM()1287 void Interpreter::O_WAITHEROANIM() {
1288 	int32 heroId = readScriptFlagValue();
1289 	debugInterpreter("O_WAITHEROANIM heroId %d", heroId);
1290 	Hero *hero = nullptr;
1291 	if (!heroId) {
1292 		hero = _vm->_mainHero;
1293 	} else {
1294 		hero = _vm->_secondHero;
1295 	}
1296 	if (hero != nullptr) {
1297 		if (hero->_state == Hero::kHeroStateSpec) {
1298 			_currentInstruction -= 4;
1299 			_opcodeNF = 1;
1300 		}
1301 	}
1302 }
1303 
O_GETHERODATA()1304 void Interpreter::O_GETHERODATA() {
1305 	Flags::Id flagId = readScriptFlagId();
1306 	int32 heroId = readScriptFlagValue();
1307 	int32 heroOffset = readScriptFlagValue();
1308 	debugInterpreter("O_GETHERODATA flag %04x - (%s), heroId %d, heroOffset %d", flagId, _flagMap.getFlagName(flagId), heroId, heroOffset);
1309 	Hero *hero = nullptr;
1310 	if (!heroId) {
1311 		hero = _vm->_mainHero;
1312 	} else {
1313 		hero = _vm->_secondHero;
1314 	}
1315 	if (hero != nullptr) {
1316 		_flags->setFlagValue(flagId, hero->getData((Hero::AttrId)heroOffset));
1317 	}
1318 }
1319 
1320 // No need of implementation here
O_GETMOUSEBUTTON()1321 void Interpreter::O_GETMOUSEBUTTON() {
1322 	debugInterpreter("O_GETMOUSEBUTTON");
1323 }
1324 
O_CHANGEFRAMES()1325 void Interpreter::O_CHANGEFRAMES() {
1326 	int32 anim = readScriptFlagValue();
1327 	int32 frame = readScriptFlagValue();
1328 	int32 lastFrame = readScriptFlagValue();
1329 	int32 loopFrame = readScriptFlagValue();
1330 	debugInterpreter("O_CHANGFRAMES anim %d, frame %d, lastFrame %d, loopFrame %d", anim, frame, lastFrame, loopFrame);
1331 	_vm->_normAnimList[anim]._frame = frame;
1332 	_vm->_normAnimList[anim]._lastFrame = lastFrame;
1333 	_vm->_normAnimList[anim]._loopFrame = loopFrame;
1334 }
1335 
O_CHANGEBACKFRAMES()1336 void Interpreter::O_CHANGEBACKFRAMES() {
1337 	int32 anim = readScriptFlagValue();
1338 	int32 frame = readScriptFlagValue();
1339 	int32 lastFrame = readScriptFlagValue();
1340 	int32 loopFrame = readScriptFlagValue();
1341 	debugInterpreter("O_CHANGEBACKFRAMES anim %d, frame %d, lastFrame %d, loopFrame %d", anim, frame, lastFrame, loopFrame);
1342 	int currAnim = _vm->_backAnimList[anim]._seq._currRelative;
1343 	Anim &backAnim = _vm->_backAnimList[anim].backAnims[currAnim];
1344 	backAnim._frame = frame;
1345 	backAnim._lastFrame = lastFrame;
1346 	backAnim._loopFrame = loopFrame;
1347 }
1348 
O_GETBACKANIMDATA()1349 void Interpreter::O_GETBACKANIMDATA() {
1350 	Flags::Id flagId = readScriptFlagId();
1351 	int32 animNumber = readScriptFlagValue();
1352 	int32 animDataOffset = readScriptFlagValue();
1353 	int currAnim = _vm->_backAnimList[animNumber]._seq._currRelative;
1354 	int16 value = _vm->_backAnimList[animNumber].backAnims[currAnim].getAnimData((Anim::AnimOffsets)(animDataOffset));
1355 	debugInterpreter("O_GETBACKANIMDATA flag %04X (%s), animNumber %d, animDataOffset %d, value %d", flagId, _flagMap.getFlagName(flagId), animNumber, animDataOffset, value);
1356 	_flags->setFlagValue((Flags::Id)(flagId), value);
1357 }
1358 
O_GETANIMDATA()1359 void Interpreter::O_GETANIMDATA() {
1360 	Flags::Id flagId = readScriptFlagId();
1361 	int32 anim = readScriptFlagValue();
1362 	int32 animOffset = readScriptFlagValue();
1363 	debugInterpreter("O_GETANIMDATA flag %04X (%s), anim %d, animOffset %d", flagId, _flagMap.getFlagName(flagId), anim, animOffset);
1364 	if (_vm->_normAnimList[anim]._animData != nullptr) {
1365 		_flags->setFlagValue(flagId, _vm->_normAnimList[anim].getAnimData((Anim::AnimOffsets)(animOffset)));
1366 	}
1367 }
1368 
O_SETBGCODE()1369 void Interpreter::O_SETBGCODE() {
1370 	int32 offset = readScript32();
1371 	_bgOpcodePC = _currentInstruction + offset - 4;
1372 	debugInterpreter("O_SETBGCODE next %08x, offset %08x", _bgOpcodePC, offset);
1373 }
1374 
O_SETBACKFRAME()1375 void Interpreter::O_SETBACKFRAME() {
1376 	int32 anim = readScriptFlagValue();
1377 	int32 frame = readScriptFlagValue();
1378 	debugInterpreter("O_SETBACKFRAME anim %d, frame %d", anim, frame);
1379 	int currAnim = _vm->_backAnimList[anim]._seq._currRelative;
1380 	if (_vm->_backAnimList[anim].backAnims[currAnim]._animData != nullptr) {
1381 		_vm->_backAnimList[anim].backAnims[currAnim]._frame = frame;
1382 	}
1383 }
1384 
O_GETRND()1385 void Interpreter::O_GETRND() {
1386 	Flags::Id flag = readScriptFlagId();
1387 	uint16 rndSeed = readScript16();
1388 	int value = _vm->_randomSource.getRandomNumber(rndSeed - 1);
1389 	debugInterpreter("O_GETRND flag %d, rndSeed %d, value %d", flag, rndSeed, value);
1390 	_flags->setFlagValue(flag, value);
1391 }
1392 
O_TALKBACKANIM()1393 void Interpreter::O_TALKBACKANIM() {
1394 	int32 animNumber = readScriptFlagValue();
1395 	int32 slot = readScriptFlagValue();
1396 	debugInterpreter("O_TALKBACKANIM animNumber %d, slot %d", animNumber, slot);
1397 	_vm->doTalkAnim(animNumber, slot, kBackgroundAnimation);
1398 }
1399 
1400 // Simplifying, because used only once in Location 20
O_LOADPATH()1401 void Interpreter::O_LOADPATH() {
1402 	readScript32();
1403 	debugInterpreter("O_LOADPATH - path2");
1404 	_vm->loadPath("path2");
1405 }
1406 
O_GETCHAR()1407 void Interpreter::O_GETCHAR() {
1408 	Flags::Id flagId = readScriptFlagId();
1409 	debugInterpreter("O_GETCHAR %04X (%s) %02x", flagId, _flagMap.getFlagName(flagId), _flags->getFlagValue(flagId));
1410 	_flags->setFlagValue(flagId, *_string);
1411 	_string++;
1412 
1413 	if (_vm->_missingVoice) {	// Sometimes data is missing the END tag, insert it here
1414 		_flags->setFlagValue(flagId, 255);
1415 		_vm->_missingVoice = false;
1416 	}
1417 }
1418 
O_SETDFLAG()1419 void Interpreter::O_SETDFLAG() {
1420 	Flags::Id flagId = readScriptFlagId();
1421 	int32 address = readScript32();
1422 	debugInterpreter("O_SETDFLAG 0x%04X (%s) = 0x%04X", flagId, _flagMap.getFlagName(flagId), _currentInstruction + address - 4);
1423 	_flags->setFlagValue((Flags::Id)(flagId), _currentInstruction + address - 4);
1424 }
1425 
O_CALLDFLAG()1426 void Interpreter::O_CALLDFLAG() {
1427 	Flags::Id flagId = readScriptFlagId();
1428 	_stack[_stacktop] = _currentInstruction;
1429 	_stacktop++;
1430 	_currentInstruction = _flags->getFlagValue(flagId);
1431 	debugInterpreter("O_CALLDFLAG 0x%04X (%s) = 0x%04X", flagId, _flagMap.getFlagName(flagId), _currentInstruction);
1432 }
1433 
O_PRINTAT()1434 void Interpreter::O_PRINTAT() {
1435 	int32 slot = readScriptFlagValue();
1436 	int32 x = readScriptFlagValue();
1437 	int32 y = readScriptFlagValue();
1438 	debugInterpreter("O_PRINTAT slot %d, x %d, y %d", slot, x, y);
1439 	int32 color = _flags->getFlagValue(Flags::KOLOR);
1440 	_vm->printAt(slot, color, (char *)_string, x, y);
1441 	increaseString();
1442 }
1443 
O_ZOOMIN()1444 void Interpreter::O_ZOOMIN() {
1445 	int32 slot = readScriptFlagValue();
1446 	debugInterpreter("O_ZOOMIN slot %04d", slot);
1447 	_vm->initZoomIn(slot);
1448 }
1449 
O_ZOOMOUT()1450 void Interpreter::O_ZOOMOUT() {
1451 	int32 slot = readScriptFlagValue();
1452 	debugInterpreter("O_ZOOMOUT slot %d", slot);
1453 	_vm->initZoomOut(slot);
1454 }
1455 
1456 // Not used in script
O_SETSTRINGOFFSET()1457 void Interpreter::O_SETSTRINGOFFSET() {
1458 	error("O_SETSTRINGOFFSET");
1459 }
1460 
O_GETOBJDATA()1461 void Interpreter::O_GETOBJDATA() {
1462 	Flags::Id flag = readScriptFlagId();
1463 	int32 slot = readScriptFlagValue();
1464 	int32 objOffset = readScriptFlagValue();
1465 	debugInterpreter("O_GETOBJDATA flag %d, objSlot %d, objOffset %d", flag, slot, objOffset);
1466 	int nr = _vm->_objSlot[slot];
1467 	if (nr != 0xFF) {
1468 		int16 value = _vm->_objList[nr]->getData((Object::AttrId)objOffset);
1469 		_flags->setFlagValue(flag, value);
1470 	}
1471 }
1472 
O_SETOBJDATA()1473 void Interpreter::O_SETOBJDATA() {
1474 	int32 slot = readScriptFlagValue();
1475 	int32 objOffset = readScriptFlagValue();
1476 	int32 value = readScriptFlagValue();
1477 	debugInterpreter("O_SETOBJDATA objSlot %d, objOffset %d, value %d", slot, objOffset, value);
1478 	int nr = _vm->_objSlot[slot];
1479 	if (nr != 0xFF) {
1480 		_vm->_objList[nr]->setData((Object::AttrId)objOffset, value);
1481 	}
1482 }
1483 
1484 // Not used in script
O_SWAPOBJECTS()1485 void Interpreter::O_SWAPOBJECTS() {
1486 	error("O_SWAPOBJECTS");
1487 }
1488 
O_CHANGEHEROSET()1489 void Interpreter::O_CHANGEHEROSET() {
1490 	int32 heroId = readScriptFlagValue();
1491 	int32 heroSet = readScriptFlagValue();
1492 	debugInterpreter("O_CHANGEHEROSET hero %d, heroSet %d", heroId, heroSet);
1493 	if (!heroId) {
1494 		_vm->_mainHero->loadAnimSet(heroSet);
1495 	} else if (heroId == 1) {
1496 		_vm->_secondHero->loadAnimSet(heroSet);
1497 	}
1498 }
1499 
1500 // Not used in script
O_ADDSTRING()1501 void Interpreter::O_ADDSTRING() {
1502 	error("O_ADDSTRING");
1503 }
1504 
O_SUBSTRING()1505 void Interpreter::O_SUBSTRING() {
1506 	int32 value = readScriptFlagValue();
1507 	debugInterpreter("O_SUBSTRING value %d", value);
1508 	_string -= value;
1509 }
1510 
checkSeq(byte * string)1511 int Interpreter::checkSeq(byte *string) {
1512 	int freeHSlotIncrease = 0;
1513 	byte c;
1514 	while ((c = string[0]) != 0xFF) {
1515 		string++;
1516 		if (c < 0xF0) {
1517 			freeHSlotIncrease++;
1518 			while ((c = string[0])) {
1519 				string++;
1520 			}
1521 			string++;
1522 		} else if (c != 0xFE) {
1523 			string++;
1524 		}
1525 	}
1526 	return freeHSlotIncrease;
1527 }
1528 
O_INITDIALOG()1529 void Interpreter::O_INITDIALOG() {
1530 	debugInterpreter("O_INITDIALOG");
1531 	if (_string[0] == 255) {
1532 		byte *stringCurrOff = _string;
1533 		byte *string = _string;
1534 		stringCurrOff++;
1535 		int32 adressOfFirstSequence = (int)READ_LE_UINT16(stringCurrOff);
1536 		stringCurrOff += 2;
1537 		_string = string + adressOfFirstSequence;
1538 
1539 		for (int i = 0; i < 32; i++) {
1540 			_vm->_dialogBoxAddr[i] = 0;
1541 			_vm->_dialogOptAddr[i] = 0;
1542 		}
1543 
1544 		for (int i = 0; i < 4 * 32; i++) {
1545 			_vm->_dialogOptLines[i] = 0;
1546 		}
1547 
1548 		int16 off;
1549 		byte *line = nullptr;
1550 
1551 		int dialogBox = 0;
1552 		while ((off = (int)READ_LE_UINT16(stringCurrOff)) != -1) {
1553 			stringCurrOff += 2;
1554 			if (off) {
1555 				line = string + off;
1556 			}
1557 			_vm->_dialogBoxAddr[dialogBox] = line;
1558 			dialogBox++;
1559 		}
1560 		stringCurrOff += 2;
1561 
1562 		int dialogOpt = 0;
1563 		while ((off = (int)READ_LE_UINT16(stringCurrOff)) != -1) {
1564 			stringCurrOff += 2;
1565 			if (off) {
1566 				line = string + off;
1567 			}
1568 			_vm->_dialogOptAddr[dialogOpt] = line;
1569 			dialogOpt++;
1570 		}
1571 
1572 		_flags->setFlagValue(Flags::VOICE_A_LINE, 0);
1573 		_flags->setFlagValue(Flags::VOICE_B_LINE, 0); // bx in original?
1574 
1575 		int freeHSlot = 0;
1576 		for (int i = 31; i >= 0; i--) {
1577 			if (_vm->_dialogOptAddr[i] != 0) {
1578 				i++;
1579 				freeHSlot = i;
1580 				_flags->setFlagValue(Flags::VOICE_H_LINE, i);
1581 				break;
1582 			}
1583 		}
1584 
1585 		freeHSlot += checkSeq(_string);
1586 
1587 		for (int i = 0; i < 32; i++) {
1588 			_vm->_dialogOptLines[i * 4] = freeHSlot;
1589 			_vm->_dialogOptLines[i * 4 + 1] = freeHSlot;
1590 			_vm->_dialogOptLines[i * 4 + 2] = freeHSlot;
1591 			if (_vm->_dialogOptAddr[i]) {
1592 				freeHSlot += checkSeq(_vm->_dialogOptAddr[i]);
1593 			}
1594 		}
1595 	}
1596 }
1597 
O_ENABLEDIALOGOPT()1598 void Interpreter::O_ENABLEDIALOGOPT() {
1599 	int32 opt = readScriptFlagValue();
1600 	debugInterpreter("O_ENABLEDIALOGOPT opt %d", opt);
1601 	int dialogDataValue = (int)READ_LE_UINT32(_vm->_dialogData);
1602 	dialogDataValue &= ~(1u << opt);
1603 	WRITE_LE_UINT32(_vm->_dialogData, dialogDataValue);
1604 }
1605 
O_DISABLEDIALOGOPT()1606 void Interpreter::O_DISABLEDIALOGOPT() {
1607 	int32 opt = readScriptFlagValue();
1608 	debugInterpreter("O_DISABLEDIALOGOPT opt %d", opt);
1609 	int dialogDataValue = (int)READ_LE_UINT32(_vm->_dialogData);
1610 	dialogDataValue |= (1u << opt);
1611 	WRITE_LE_UINT32(_vm->_dialogData, dialogDataValue);
1612 }
1613 
O_SHOWDIALOGBOX()1614 void Interpreter::O_SHOWDIALOGBOX() {
1615 	int32 box = readScriptFlagValue();
1616 	debugInterpreter("O_SHOWDIALOGBOX box %d", box);
1617 	uint32 currInstr = _currentInstruction;
1618 	_vm->createDialogBox(box);
1619 	_flags->setFlagValue(Flags::DIALINES, _vm->_dialogLines);
1620 	if (_vm->_dialogLines) {
1621 		_vm->changeCursor(1);
1622 		_vm->dialogRun();
1623 		_vm->changeCursor(0);
1624 	}
1625 	_currentInstruction = currInstr;
1626 }
1627 
O_STOPSAMPLE()1628 void Interpreter::O_STOPSAMPLE() {
1629 	int32 slot = readScriptFlagValue();
1630 	debugInterpreter("O_STOPSAMPLE slot %d", slot);
1631 	_vm->stopSample(slot);
1632 }
1633 
O_BACKANIMRANGE()1634 void Interpreter::O_BACKANIMRANGE() {
1635 	int32 slotId = readScriptFlagValue();
1636 	uint16 animId = readScript16();
1637 	int32 low = readScriptFlagValue();
1638 	int32 high = readScriptFlagValue();
1639 	if (animId != 0xFFFF) {
1640 		if (animId & InterpreterFlags::kFlagMask) {
1641 			animId = _flags->getFlagValue((Flags::Id)animId);
1642 		}
1643 	}
1644 	_result = 1;
1645 	if (!_vm->_backAnimList[slotId].backAnims.empty()) {
1646 		int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
1647 		if (_vm->_backAnimList[slotId].backAnims[currAnim]._animData != nullptr) {
1648 			if (animId == 0xFFFF || _vm->_backAnimList[slotId]._seq._current == animId) {
1649 				Anim &backAnim = _vm->_backAnimList[slotId].backAnims[currAnim];
1650 				if (!backAnim._state) {
1651 					if (backAnim._frame >= low) {
1652 						if (backAnim._frame <= high) {
1653 							_result = 0;
1654 						}
1655 					}
1656 				}
1657 			}
1658 		}
1659 	}
1660 	debugInterpreter("O_BACKANIMRANGE slotId %d, animId %d, low %d, high %d, _result %d", slotId, animId, low, high, _result);
1661 }
1662 
O_CLEARPATH()1663 void Interpreter::O_CLEARPATH() {
1664 	debugInterpreter("O_CLEARPATH");
1665 	for (uint i = 0; i < _vm->kPathBitmapLen; i++) {
1666 		_vm->_roomPathBitmap[i] = 255;
1667 	}
1668 }
1669 
O_SETPATH()1670 void Interpreter::O_SETPATH() {
1671 	debugInterpreter("O_SETPATH");
1672 	_vm->loadPath("path");
1673 }
1674 
O_GETHEROX()1675 void Interpreter::O_GETHEROX() {
1676 	int32 heroId = readScriptFlagValue();
1677 	Flags::Id flagId = readScriptFlagId();
1678 	debugInterpreter("O_GETHEROX heroId %d, flagId %d", heroId, flagId);
1679 	if (!heroId) {
1680 		_flags->setFlagValue(flagId, _vm->_mainHero->_middleX);
1681 	} else if (heroId == 1) {
1682 		_flags->setFlagValue(flagId, _vm->_secondHero->_middleX);
1683 	}
1684 }
1685 
O_GETHEROY()1686 void Interpreter::O_GETHEROY() {
1687 	int32 heroId = readScriptFlagValue();
1688 	Flags::Id flagId = readScriptFlagId();
1689 	debugInterpreter("O_GETHEROY heroId %d, flagId %d", heroId, flagId);
1690 	if (!heroId) {
1691 		_flags->setFlagValue(flagId, _vm->_mainHero->_middleY);
1692 	} else if (heroId == 1) {
1693 		_flags->setFlagValue(flagId, _vm->_secondHero->_middleY);
1694 	}
1695 }
1696 
O_GETHEROD()1697 void Interpreter::O_GETHEROD() {
1698 	int32 heroId = readScriptFlagValue();
1699 	Flags::Id flagId = readScriptFlagId();
1700 	debugInterpreter("O_GETHEROD heroId %d, flagId %d", heroId, flagId);
1701 	if (!heroId) {
1702 		_flags->setFlagValue(flagId, _vm->_mainHero->_lastDirection);
1703 	} else if (heroId == 1) {
1704 		_flags->setFlagValue(flagId, _vm->_secondHero->_lastDirection);
1705 	}
1706 }
1707 
O_PUSHSTRING()1708 void Interpreter::O_PUSHSTRING() {
1709 	debugInterpreter("O_PUSHSTRING");
1710 	_stringStack.string = _string;
1711 	_stringStack.dialogData = _vm->_dialogData;
1712 	_stringStack.currentString = _currentString;
1713 }
1714 
O_POPSTRING()1715 void Interpreter::O_POPSTRING() {
1716 	debugInterpreter("O_POPSTRING");
1717 	_string = _stringStack.string;
1718 	_vm->_dialogData = _stringStack.dialogData;
1719 	_currentString = _stringStack.currentString;
1720 }
1721 
O_SETFGCODE()1722 void Interpreter::O_SETFGCODE() {
1723 	int32 offset = readScript32();
1724 	_fgOpcodePC = _currentInstruction + offset - 4;
1725 	debugInterpreter("O_SETFGCODE next %08x, offset %08x", _fgOpcodePC, offset);
1726 }
1727 
O_STOPHERO()1728 void Interpreter::O_STOPHERO() {
1729 	int32 heroId = readScriptFlagValue();
1730 	debugInterpreter("O_STOPHERO heroId %d", heroId);
1731 	if (!heroId) {
1732 		_vm->_mainHero->freeOldMove();
1733 	} else if (heroId == 1) {
1734 		_vm->_secondHero->freeOldMove();
1735 	}
1736 }
1737 
O_ANIMUPDATEOFF()1738 void Interpreter::O_ANIMUPDATEOFF() {
1739 	int32 slotId = readScriptFlagValue();
1740 	debugInterpreter("O_ANIMUPDATEOFF slotId %d", slotId);
1741 	_vm->_normAnimList[slotId]._state = 1;
1742 }
1743 
O_ANIMUPDATEON()1744 void Interpreter::O_ANIMUPDATEON() {
1745 	int32 slotId = readScriptFlagValue();
1746 	debugInterpreter("O_ANIMUPDATEON slotId %d", slotId);
1747 	_vm->_normAnimList[slotId]._state = 0;
1748 }
1749 
O_FREECURSOR()1750 void Interpreter::O_FREECURSOR() {
1751 	debugInterpreter("O_FREECURSOR");
1752 	_vm->changeCursor(0);
1753 	_vm->_currentPointerNumber = 1;
1754 	// free memory here?
1755 }
1756 
O_ADDINVQUIET()1757 void Interpreter::O_ADDINVQUIET() {
1758 	int32 hero = readScriptFlagValue();
1759 	int32 item = readScriptFlagValue();
1760 	debugInterpreter("O_ADDINVQUIET hero %d, item %d", hero, item);
1761 	_vm->addInv(hero, item, true);
1762 }
1763 
O_RUNHERO()1764 void Interpreter::O_RUNHERO() {
1765 	int32 heroId = readScriptFlagValue();
1766 	int32 x = readScriptFlagValue();
1767 	int32 y = readScriptFlagValue();
1768 	int32 dir = readScriptFlagValue();
1769 	debugInterpreter("O_RUNHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
1770 	_vm->moveRunHero(heroId, x, y, dir, true);
1771 }
1772 
O_SETBACKANIMDATA()1773 void Interpreter::O_SETBACKANIMDATA() {
1774 	uint16 animNumber = readScript16();
1775 	uint16 animDataOffset = readScript16();
1776 	Flags::Id flagId = readScriptFlagId();
1777 	uint16 value = _flags->getFlagValue((Flags::Id)(flagId));
1778 	debugInterpreter("O_SETBACKANIMDATA flag %04X (%s), animNumber %d, animDataOffset %d, value %d", flagId, _flagMap.getFlagName(flagId), animNumber, animDataOffset, value);
1779 	int currAnim = _vm->_backAnimList[animNumber]._seq._currRelative;
1780 	_vm->_backAnimList[animNumber].backAnims[currAnim].setAnimData((Anim::AnimOffsets)(animDataOffset), value);
1781 }
1782 
O_VIEWFLC()1783 void Interpreter::O_VIEWFLC() {
1784 	int32 animNr = readScriptFlagValue();
1785 	debugInterpreter("O_VIEWFLC animNr %d", animNr);
1786 	_vm->_flcFrameSurface = nullptr;
1787 	_vm->loadAnim(animNr, false);
1788 }
1789 
O_CHECKFLCFRAME()1790 void Interpreter::O_CHECKFLCFRAME() {
1791 	int32 frameNr = readScriptFlagValue();
1792 	debugInterpreter("O_CHECKFLCFRAME frame number %d", frameNr);
1793 	if (_vm->_flicPlayer.getCurFrame() != frameNr) {
1794 		_currentInstruction -= 4;
1795 		_opcodeNF = 1;
1796 	}
1797 }
1798 
O_CHECKFLCEND()1799 void Interpreter::O_CHECKFLCEND() {
1800 	const Video::FlicDecoder &flicPlayer = _vm->_flicPlayer;
1801 	debugInterpreter("O_CHECKFLCEND frameCount %d, currentFrame %d", flicPlayer.getFrameCount(), flicPlayer.getCurFrame());
1802 	if (flicPlayer.getFrameCount() - flicPlayer.getCurFrame() > 1) {
1803 		_currentInstruction -= 2;
1804 		_opcodeNF = 1;
1805 	}
1806 }
1807 
O_FREEFLC()1808 void Interpreter::O_FREEFLC() {
1809 	debugInterpreter("O_FREEFLC");
1810 	_vm->_flcFrameSurface = nullptr;
1811 }
1812 
O_TALKHEROSTOP()1813 void Interpreter::O_TALKHEROSTOP() {
1814 	int32 heroId = readScriptFlagValue();
1815 	debugInterpreter("O_TALKHEROSTOP %d", heroId);
1816 	if (!heroId) {
1817 		_vm->_mainHero->_state = Hero::kHeroStateStay;
1818 	} else if (heroId == 1) {
1819 		_vm->_secondHero->_state = Hero::kHeroStateStay;
1820 	}
1821 }
1822 
O_HEROCOLOR()1823 void Interpreter::O_HEROCOLOR() {
1824 	int32 heroId = readScriptFlagValue();
1825 	int32 color = readScriptFlagValue();
1826 	debugInterpreter("O_HEROCOLOR heroId %d, color %d", heroId, color);
1827 	if (!heroId) {
1828 		_vm->_mainHero->_color = color;
1829 	} else if (heroId == 1) {
1830 		_vm->_secondHero->_color = color;
1831 	}
1832 }
1833 
O_GRABMAPA()1834 void Interpreter::O_GRABMAPA() {
1835 	debugInterpreter("O_GRABMAPA");
1836 	_vm->grabMap();
1837 }
1838 
O_ENABLENAK()1839 void Interpreter::O_ENABLENAK() {
1840 	int32 nakId = readScriptFlagValue();
1841 	debugInterpreter("O_ENABLENAK nakId %d", nakId);
1842 	_vm->_maskList[nakId]._flags = 0;
1843 }
1844 
O_DISABLENAK()1845 void Interpreter::O_DISABLENAK() {
1846 	int32 nakId = readScriptFlagValue();
1847 	debugInterpreter("O_DISABLENAK nakId %d", nakId);
1848 	_vm->_maskList[nakId]._flags = 1;
1849 }
1850 
O_GETMOBNAME()1851 void Interpreter::O_GETMOBNAME() {
1852 	int32 modId = readScriptFlagValue();
1853 	debugInterpreter("O_GETMOBNAME modId %d", modId);
1854 	strncpy((char *)_stringBuf, _vm->_mobList[modId]._name.c_str(), 1023);
1855 	_string = _stringBuf;
1856 }
1857 
O_SWAPINVENTORY()1858 void Interpreter::O_SWAPINVENTORY() {
1859 	int32 hero = readScriptFlagValue();
1860 	debugInterpreter("O_SWAPINVENTORY hero %d", hero);
1861 	_vm->swapInv(hero);
1862 }
1863 
O_CLEARINVENTORY()1864 void Interpreter::O_CLEARINVENTORY() {
1865 	int32 hero = readScriptFlagValue();
1866 	debugInterpreter("O_CLEARINVENTORY hero %d", hero);
1867 	_vm->clearInv(hero);
1868 }
1869 
O_SKIPTEXT()1870 void Interpreter::O_SKIPTEXT() {
1871 	debugInterpreter("O_SKIPTEXT");
1872 	increaseString();
1873 }
1874 
O_SETVOICEH()1875 void Interpreter::O_SETVOICEH() {
1876 	int32 slot = readScriptFlagValue();
1877 	debugInterpreter("O_SETVOICEH slot %d", slot);
1878 	static const uint32 VOICE_H_SLOT = 28;
1879 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1880 	_vm->setVoice(slot, VOICE_H_SLOT, voiceLineH);
1881 }
1882 
O_SETVOICEA()1883 void Interpreter::O_SETVOICEA() {
1884 	int32 slot = readScriptFlagValue();
1885 	debugInterpreter("O_SETVOICEA slot %d", slot);
1886 	static const uint32 VOICE_A_SLOT = 29;
1887 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1888 	_vm->setVoice(slot, VOICE_A_SLOT, voiceLineH);
1889 }
1890 
O_SETVOICEB()1891 void Interpreter::O_SETVOICEB() {
1892 	int32 slot = readScriptFlagValue();
1893 	debugInterpreter("O_SETVOICEB slot %d", slot);
1894 	static const uint32 VOICE_B_SLOT = 30;
1895 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1896 	_vm->setVoice(slot, VOICE_B_SLOT, voiceLineH);
1897 }
1898 
O_SETVOICEC()1899 void Interpreter::O_SETVOICEC() {
1900 	int32 slot = readScriptFlagValue();
1901 	debugInterpreter("O_SETVOICEC slot %d", slot);
1902 	static const uint32 VOICE_C_SLOT = 31;
1903 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1904 	_vm->setVoice(slot, VOICE_C_SLOT, voiceLineH);
1905 }
1906 
O_SETVOICED()1907 void Interpreter::O_SETVOICED() {
1908 	int32 slot = readScriptFlagValue();
1909 	debugInterpreter("O_SETVOICED slot %d", slot);
1910 	static const uint32 VOICE_D_SLOT = 32;
1911 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1912 	_vm->setVoice(slot, VOICE_D_SLOT, voiceLineH);
1913 }
1914 
O_VIEWFLCLOOP()1915 void Interpreter::O_VIEWFLCLOOP() {
1916 	int32 animId = readScriptFlagValue();
1917 	debugInterpreter("O_VIEWFLCLOOP animId %d", animId);
1918 	_vm->loadAnim(animId, true);
1919 }
1920 
1921 // Not used in script
O_FLCSPEED()1922 void Interpreter::O_FLCSPEED() {
1923 	int32 speed = readScriptFlagValue();
1924 	error("O_FLCSPEED speed %d", speed);
1925 }
1926 
O_OPENINVENTORY()1927 void Interpreter::O_OPENINVENTORY() {
1928 	debugInterpreter("O_OPENINVENTORY");
1929 	_vm->_showInventoryFlag = true;
1930 	_opcodeNF = 1;
1931 }
1932 
O_KRZYWA()1933 void Interpreter::O_KRZYWA() {
1934 	debugInterpreter("O_KRZYWA");
1935 	_vm->makeCurve();
1936 }
1937 
O_GETKRZYWA()1938 void Interpreter::O_GETKRZYWA() {
1939 	debugInterpreter("O_GETKRZYWA");
1940 	_vm->getCurve();
1941 }
1942 
O_GETMOB()1943 void Interpreter::O_GETMOB() {
1944 	Flags::Id flagId = readScriptFlagId();
1945 	int32 posX = readScriptFlagValue();
1946 	int32 posY = readScriptFlagValue();
1947 	debugInterpreter("O_GETMOB flagId %d, posX %d, posY %d", flagId, posX, posY);
1948 	int mobNumber = _vm->getMob(_vm->_mobList, true, posX, posY);
1949 	_flags->setFlagValue(flagId, mobNumber + 1);
1950 }
1951 
1952 // Not used in game
O_INPUTLINE()1953 void Interpreter::O_INPUTLINE() {
1954 	error("O_INPUTLINE");
1955 }
1956 
1957 // Not used in script
O_BREAK_POINT()1958 void Interpreter::O_BREAK_POINT() {
1959 	error("O_BREAK_POINT");
1960 }
1961 
1962 Interpreter::OpcodeFunc Interpreter::_opcodes[kNumOpcodes] = {
1963 	&Interpreter::O_WAITFOREVER,
1964 	&Interpreter::O_BLACKPALETTE,
1965 	&Interpreter::O_SETUPPALETTE,
1966 	&Interpreter::O_INITROOM,
1967 	&Interpreter::O_SETSAMPLE,
1968 	&Interpreter::O_FREESAMPLE,
1969 	&Interpreter::O_PLAYSAMPLE,
1970 	&Interpreter::O_PUTOBJECT,
1971 	&Interpreter::O_REMOBJECT,
1972 	&Interpreter::O_SHOWANIM,
1973 	&Interpreter::O_CHECKANIMEND,
1974 	&Interpreter::O_FREEANIM,
1975 	&Interpreter::O_CHECKANIMFRAME,
1976 	&Interpreter::O_PUTBACKANIM,
1977 	&Interpreter::O_REMBACKANIM,
1978 	&Interpreter::O_CHECKBACKANIMFRAME,
1979 	&Interpreter::O_FREEALLSAMPLES,
1980 	&Interpreter::O_SETMUSIC,
1981 	&Interpreter::O_STOPMUSIC,
1982 	&Interpreter::O__WAIT,
1983 	&Interpreter::O_UPDATEOFF,
1984 	&Interpreter::O_UPDATEON,
1985 	&Interpreter::O_UPDATE ,
1986 	&Interpreter::O_CLS,
1987 	&Interpreter::O__CALL,
1988 	&Interpreter::O_RETURN,
1989 	&Interpreter::O_GO,
1990 	&Interpreter::O_BACKANIMUPDATEOFF,
1991 	&Interpreter::O_BACKANIMUPDATEON,
1992 	&Interpreter::O_CHANGECURSOR,
1993 	&Interpreter::O_CHANGEANIMTYPE,
1994 	&Interpreter::O__SETFLAG,
1995 	&Interpreter::O_COMPARE,
1996 	&Interpreter::O_JUMPZ,
1997 	&Interpreter::O_JUMPNZ,
1998 	&Interpreter::O_EXIT,
1999 	&Interpreter::O_ADDFLAG,
2000 	&Interpreter::O_TALKANIM,
2001 	&Interpreter::O_SUBFLAG,
2002 	&Interpreter::O_SETSTRING,
2003 	&Interpreter::O_ANDFLAG,
2004 	&Interpreter::O_GETMOBDATA,
2005 	&Interpreter::O_ORFLAG,
2006 	&Interpreter::O_SETMOBDATA,
2007 	&Interpreter::O_XORFLAG,
2008 	&Interpreter::O_GETMOBTEXT,
2009 	&Interpreter::O_MOVEHERO,
2010 	&Interpreter::O_WALKHERO,
2011 	&Interpreter::O_SETHERO,
2012 	&Interpreter::O_HEROOFF,
2013 	&Interpreter::O_HEROON,
2014 	&Interpreter::O_CLSTEXT,
2015 	&Interpreter::O_CALLTABLE,
2016 	&Interpreter::O_CHANGEMOB,
2017 	&Interpreter::O_ADDINV,
2018 	&Interpreter::O_REMINV,
2019 	&Interpreter::O_REPINV,
2020 	&Interpreter::O_OBSOLETE_GETACTION,
2021 	&Interpreter::O_ADDWALKAREA,
2022 	&Interpreter::O_REMWALKAREA,
2023 	&Interpreter::O_RESTOREWALKAREA,
2024 	&Interpreter::O_WAITFRAME,
2025 	&Interpreter::O_SETFRAME,
2026 	&Interpreter::O_RUNACTION,
2027 	&Interpreter::O_COMPAREHI,
2028 	&Interpreter::O_COMPARELO,
2029 	&Interpreter::O_PRELOADSET,
2030 	&Interpreter::O_FREEPRELOAD,
2031 	&Interpreter::O_CHECKINV,
2032 	&Interpreter::O_TALKHERO,
2033 	&Interpreter::O_WAITTEXT,
2034 	&Interpreter::O_SETHEROANIM,
2035 	&Interpreter::O_WAITHEROANIM,
2036 	&Interpreter::O_GETHERODATA,
2037 	&Interpreter::O_GETMOUSEBUTTON,
2038 	&Interpreter::O_CHANGEFRAMES,
2039 	&Interpreter::O_CHANGEBACKFRAMES,
2040 	&Interpreter::O_GETBACKANIMDATA,
2041 	&Interpreter::O_GETANIMDATA,
2042 	&Interpreter::O_SETBGCODE,
2043 	&Interpreter::O_SETBACKFRAME,
2044 	&Interpreter::O_GETRND,
2045 	&Interpreter::O_TALKBACKANIM,
2046 	&Interpreter::O_LOADPATH,
2047 	&Interpreter::O_GETCHAR,
2048 	&Interpreter::O_SETDFLAG,
2049 	&Interpreter::O_CALLDFLAG,
2050 	&Interpreter::O_PRINTAT,
2051 	&Interpreter::O_ZOOMIN,
2052 	&Interpreter::O_ZOOMOUT,
2053 	&Interpreter::O_SETSTRINGOFFSET,
2054 	&Interpreter::O_GETOBJDATA,
2055 	&Interpreter::O_SETOBJDATA,
2056 	&Interpreter::O_SWAPOBJECTS,
2057 	&Interpreter::O_CHANGEHEROSET,
2058 	&Interpreter::O_ADDSTRING,
2059 	&Interpreter::O_SUBSTRING,
2060 	&Interpreter::O_INITDIALOG,
2061 	&Interpreter::O_ENABLEDIALOGOPT,
2062 	&Interpreter::O_DISABLEDIALOGOPT,
2063 	&Interpreter::O_SHOWDIALOGBOX,
2064 	&Interpreter::O_STOPSAMPLE,
2065 	&Interpreter::O_BACKANIMRANGE,
2066 	&Interpreter::O_CLEARPATH,
2067 	&Interpreter::O_SETPATH,
2068 	&Interpreter::O_GETHEROX,
2069 	&Interpreter::O_GETHEROY,
2070 	&Interpreter::O_GETHEROD,
2071 	&Interpreter::O_PUSHSTRING,
2072 	&Interpreter::O_POPSTRING,
2073 	&Interpreter::O_SETFGCODE,
2074 	&Interpreter::O_STOPHERO,
2075 	&Interpreter::O_ANIMUPDATEOFF,
2076 	&Interpreter::O_ANIMUPDATEON,
2077 	&Interpreter::O_FREECURSOR,
2078 	&Interpreter::O_ADDINVQUIET,
2079 	&Interpreter::O_RUNHERO,
2080 	&Interpreter::O_SETBACKANIMDATA,
2081 	&Interpreter::O_VIEWFLC,
2082 	&Interpreter::O_CHECKFLCFRAME,
2083 	&Interpreter::O_CHECKFLCEND,
2084 	&Interpreter::O_FREEFLC,
2085 	&Interpreter::O_TALKHEROSTOP,
2086 	&Interpreter::O_HEROCOLOR,
2087 	&Interpreter::O_GRABMAPA,
2088 	&Interpreter::O_ENABLENAK,
2089 	&Interpreter::O_DISABLENAK,
2090 	&Interpreter::O_GETMOBNAME,
2091 	&Interpreter::O_SWAPINVENTORY,
2092 	&Interpreter::O_CLEARINVENTORY,
2093 	&Interpreter::O_SKIPTEXT,
2094 	&Interpreter::O_SETVOICEH,
2095 	&Interpreter::O_SETVOICEA,
2096 	&Interpreter::O_SETVOICEB,
2097 	&Interpreter::O_SETVOICEC,
2098 	&Interpreter::O_VIEWFLCLOOP,
2099 	&Interpreter::O_FLCSPEED,
2100 	&Interpreter::O_OPENINVENTORY,
2101 	&Interpreter::O_KRZYWA,
2102 	&Interpreter::O_GETKRZYWA,
2103 	&Interpreter::O_GETMOB,
2104 	&Interpreter::O_INPUTLINE,
2105 	&Interpreter::O_SETVOICED,
2106 	&Interpreter::O_BREAK_POINT,
2107 };
2108 
2109 } // End of namespace Prince
2110