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 
debugInterpreter(const char * s,...)446 void Interpreter::debugInterpreter(const char *s, ...) {
447 	char buf[STRINGBUFLEN];
448 	va_list va;
449 	va_start(va, s);
450 	vsnprintf(buf, STRINGBUFLEN, s, va);
451 	va_end(va);
452 
453 	Common::String str = Common::String::format("@0x%08X: ", _lastInstruction);
454 	str += Common::String::format("op %04d: ", _lastOpcode);
455 	if (!strcmp(_mode, "fg")) {
456 		debug(10, "PrinceEngine::Script %s %s", str.c_str(), buf);
457 	}
458 }
459 
stepBg()460 void Interpreter::stepBg() {
461 	if (_bgOpcodePC) {
462 		_mode = "bg";
463 		_bgOpcodePC = step(_bgOpcodePC);
464 	}
465 }
466 
stepFg()467 void Interpreter::stepFg() {
468 	if (_fgOpcodePC) {
469 		_mode = "fg";
470 		_fgOpcodePC = step(_fgOpcodePC);
471 	}
472 }
473 
step(uint32 opcodePC)474 uint32 Interpreter::step(uint32 opcodePC) {
475 	_currentInstruction = opcodePC;
476 
477 	while (!_opcodeNF) {
478 		_lastInstruction = _currentInstruction;
479 
480 		// Get the current opcode
481 		_lastOpcode = readScript16();
482 
483 		if (_lastOpcode >= kNumOpcodes)
484 			error(
485 				"Trying to execute unknown opcode @0x%04X: %02d",
486 				_currentInstruction,
487 				_lastOpcode);
488 
489 		// Execute the current opcode
490 		OpcodeFunc op = _opcodes[_lastOpcode];
491 		(this->*op)();
492 		if (_opcodeNF) {
493 			_opcodeNF = 0;
494 			break;
495 		}
496 	}
497 
498 	if (_opcodeEnd) {
499 		_vm->quitGame();
500 	}
501 
502 	return _currentInstruction;
503 }
504 
storeNewPC(int opcodePC)505 void Interpreter::storeNewPC(int opcodePC) {
506 	if (_flags->getFlagValue(Flags::GETACTION) == 1) {
507 		_flags->setFlagValue(Flags::GETACTIONDATA, opcodePC);
508 		opcodePC = _flags->getFlagValue(Flags::GETACTIONBACK);
509 	}
510 	_fgOpcodePC = opcodePC;
511 }
512 
getLastOPCode()513 int Interpreter::getLastOPCode() {
514 	return _lastOpcode;
515 }
516 
getFgOpcodePC()517 int Interpreter::getFgOpcodePC() {
518 	return _fgOpcodePC;
519 }
520 
getCurrentString()521 uint32 Interpreter::getCurrentString() {
522 	return _currentString;
523 }
524 
setCurrentString(uint32 value)525 void Interpreter::setCurrentString(uint32 value) {
526 	_currentString = value;
527 }
528 
getString()529 byte *Interpreter::getString() {
530 	return _string;
531 }
532 
setString(byte * newString)533 void Interpreter::setString(byte *newString) {
534 	_string = newString;
535 }
536 
increaseString()537 void Interpreter::increaseString() {
538 	while (*_string) {
539 		_string++;
540 	}
541 	_string++;
542 }
543 
setResult(byte value)544 void Interpreter::setResult(byte value) {
545 	_result = value;
546 }
547 
setBgOpcodePC(uint32 value)548 void Interpreter::setBgOpcodePC(uint32 value) {
549 	_bgOpcodePC = value;
550 }
551 
setFgOpcodePC(uint32 value)552 void Interpreter::setFgOpcodePC(uint32 value) {
553 	_fgOpcodePC = value;
554 }
555 
readScript16()556 uint16 Interpreter::readScript16() {
557 	uint16 data = _script->readScript16(_currentInstruction);
558 	_currentInstruction += sizeof(uint16);
559 	return data;
560 }
561 
readScript32()562 uint32 Interpreter::readScript32() {
563 	uint32 data = _script->readScript32(_currentInstruction);
564 	_currentInstruction += sizeof(uint32);
565 	return data;
566 }
567 
readScriptFlagValue()568 int32 Interpreter::readScriptFlagValue() {
569 	uint16 value = readScript16();
570 	if (value & InterpreterFlags::kFlagMask) {
571 		return _flags->getFlagValue((Flags::Id)value);
572 	}
573 	return value;
574 }
575 
readScriptFlagId()576 Flags::Id Interpreter::readScriptFlagId() {
577 	return (Flags::Id)readScript16();
578 }
579 
O_WAITFOREVER()580 void Interpreter::O_WAITFOREVER() {
581 	_vm->changeCursor(_vm->_currentPointerNumber);
582 	_opcodeNF = 1;
583 	_currentInstruction -= 2;
584 	//debugInterpreter("O_WAITFOREVER");
585 }
586 
O_BLACKPALETTE()587 void Interpreter::O_BLACKPALETTE() {
588 	_vm->blackPalette();
589 	debugInterpreter("O_BLACKPALETTE");
590 }
591 
O_SETUPPALETTE()592 void Interpreter::O_SETUPPALETTE() {
593 	_vm->setPalette(_vm->_roomBmp->getPalette());
594 	debugInterpreter("O_SETUPPALETTE");
595 }
596 
O_INITROOM()597 void Interpreter::O_INITROOM() {
598 	int32 roomId = readScriptFlagValue();
599 	_vm->loadLocation(roomId);
600 	_opcodeNF = 1;
601 	debugInterpreter("O_INITROOM %d", roomId);
602 }
603 
O_SETSAMPLE()604 void Interpreter::O_SETSAMPLE() {
605 	int32 sampleId = readScriptFlagValue();
606 	int32 sampleNameOffset = readScript32();
607 	const char *sampleName = _script->getString(_currentInstruction + sampleNameOffset - 4);
608 	_vm->loadSample(sampleId, sampleName);
609 	debugInterpreter("O_SETSAMPLE %d %s", sampleId, sampleName);
610 }
611 
O_FREESAMPLE()612 void Interpreter::O_FREESAMPLE() {
613 	int32 sampleId = readScriptFlagValue();
614 	_vm->freeSample(sampleId);
615 	debugInterpreter("O_FREESAMPLE sampleId: %d", sampleId);
616 }
617 
O_PLAYSAMPLE()618 void Interpreter::O_PLAYSAMPLE() {
619 	int32 sampleId = readScriptFlagValue();
620 	uint16 loopType = readScript16();
621 	_vm->playSample(sampleId, loopType);
622 	debugInterpreter("O_PLAYSAMPLE sampleId %d loopType %d", sampleId, loopType);
623 }
624 
O_PUTOBJECT()625 void Interpreter::O_PUTOBJECT() {
626 	int32 roomId = readScriptFlagValue();
627 	int32 slot = readScriptFlagValue();
628 	int32 objectId = readScriptFlagValue();
629 	Room *room = new Room();
630 	room->loadRoom(_script->getRoomOffset(roomId));
631 	_vm->_script->setObjId(room->_obj, slot, objectId);
632 	if (_vm->_locationNr == roomId) {
633 		_vm->_objSlot[slot] = objectId;
634 	}
635 	delete room;
636 	debugInterpreter("O_PUTOBJECT roomId %d, slot %d, objectId %d", roomId, slot, objectId);
637 }
638 
O_REMOBJECT()639 void Interpreter::O_REMOBJECT() {
640 	int32 roomId = readScriptFlagValue();
641 	int32 slot = readScriptFlagValue();
642 	Room *room = new Room();
643 	room->loadRoom(_script->getRoomOffset(roomId));
644 	_vm->_script->setObjId(room->_obj, slot, 0xFF);
645 	if (_vm->_locationNr == roomId) {
646 		_vm->_objSlot[slot] = 0xFF;
647 	}
648 	delete room;
649 	debugInterpreter("O_REMOBJECT roomId %d slot %d", roomId, slot);
650 }
651 
O_SHOWANIM()652 void Interpreter::O_SHOWANIM() {
653 	int32 slot = readScriptFlagValue();
654 	int32 animId = readScriptFlagValue();
655 	_vm->freeNormAnim(slot);
656 	Anim &anim = _vm->_normAnimList[slot];
657 	AnimListItem &animList = _vm->_animList[animId];
658 	anim._currFrame = 0;
659 	anim._packFlag = 0;
660 	anim._state = 0;
661 	anim._frame = animList._startPhase;
662 	anim._showFrame = animList._startPhase;
663 	anim._lastFrame = animList._endPhase;
664 	anim._loopFrame = animList._loopPhase;
665 	anim._x = animList._x;
666 	anim._y = animList._y;
667 	anim._loopType = animList._loopType;
668 	anim._shadowBack = animList._type;
669 	anim._flags = animList._flags;
670 	anim._nextAnim = animList._nextAnim;
671 	int fileNumber = animList._fileNumber;
672 	const Common::String animName = Common::String::format("AN%02d", fileNumber);
673 	const Common::String shadowName = Common::String::format("AN%02dS", fileNumber);
674 	anim._animData = new Animation();
675 	anim._shadowData = new Animation();
676 	Resource::loadResource(anim._animData, animName.c_str(), true);
677 	if (!Resource::loadResource(anim._shadowData, shadowName.c_str(), false)) {
678 		delete anim._shadowData;
679 		anim._shadowData = nullptr;
680 	}
681 
682 	// WALKAROUND: fix for turning off bard's wife background animation
683 	// in front of bard's house (location 7) after giving her poem (item 33)
684 	// in script: GiveLetter (line 11082)
685 	if (_currentInstruction == kGiveLetterScriptFix) {
686 		_vm->_backAnimList[1].backAnims[0]._state = 1;
687 	}
688 
689 	debugInterpreter("O_SHOWANIM slot %d, animId %d", slot, animId);
690 }
691 
O_CHECKANIMEND()692 void Interpreter::O_CHECKANIMEND() {
693 	int32 slot = readScriptFlagValue();
694 	if (_vm->_normAnimList[slot]._frame != _vm->_normAnimList[slot]._lastFrame - 1) {
695 		_currentInstruction -= 4;
696 		_opcodeNF = 1;
697 	}
698 	debugInterpreter("O_CHECKANIMEND slot %d", slot);
699 }
700 
O_FREEANIM()701 void Interpreter::O_FREEANIM() {
702 	int32 slot = readScriptFlagValue();
703 	_vm->freeNormAnim(slot);
704 	debugInterpreter("O_FREEANIM slot %d", slot);
705 }
706 
O_CHECKANIMFRAME()707 void Interpreter::O_CHECKANIMFRAME() {
708 	int32 slot = readScriptFlagValue();
709 	int32 frameNumber = readScriptFlagValue();
710 	if (_vm->_normAnimList[slot]._frame != frameNumber - 1) {
711 		_currentInstruction -= 6;
712 		_opcodeNF = 1;
713 	}
714 	debugInterpreter("O_CHECKANIMFRAME slot %d, frameNumber %d", slot, frameNumber);
715 }
716 
O_PUTBACKANIM()717 void Interpreter::O_PUTBACKANIM() {
718 	int32 roomId = readScriptFlagValue();
719 	int32 slot = readScriptFlagValue();
720 	int32 animId = readScript32();
721 	Room *room = new Room();
722 	room->loadRoom(_script->getRoomOffset(roomId));
723 	_vm->_script->setBackAnimId(room->_backAnim, slot, animId);
724 	if (_vm->_locationNr == roomId) {
725 		_vm->_script->installSingleBackAnim(_vm->_backAnimList, slot, room->_backAnim);
726 	}
727 	delete room;
728 
729 	// WALKAROUND: fix for turning on 'walking bird' background animation too soon,
730 	// after completing 'throw a rock' mini-game in Silmaniona location.
731 	// Second bird shouldn't appear when normal animation is still in use
732 	// in script lines 13814 and 13848
733 	if (_currentInstruction == kSecondBirdAnimationScriptFix) {
734 		if (_vm->_normAnimList[1]._state == 0) {
735 			_vm->_backAnimList[0].backAnims[0]._state = 1;
736 		}
737 	}
738 
739 	debugInterpreter("O_PUTBACKANIM roomId %d, slot %d, animId %d", roomId, slot, animId);
740 }
741 
O_REMBACKANIM()742 void Interpreter::O_REMBACKANIM() {
743 	int32 roomId = readScriptFlagValue();
744 	int32 slot = readScriptFlagValue();
745 	if (_vm->_locationNr == roomId) {
746 		_vm->removeSingleBackAnim(slot);
747 	}
748 	Room *room = new Room();
749 	room->loadRoom(_script->getRoomOffset(roomId));
750 	_vm->_script->setBackAnimId(room->_backAnim, slot, 0);
751 	delete room;
752 	debugInterpreter("O_REMBACKANIM roomId %d, slot %d", roomId, slot);
753 }
754 
O_CHECKBACKANIMFRAME()755 void Interpreter::O_CHECKBACKANIMFRAME() {
756 	int32 slotId = readScriptFlagValue();
757 	int32 frameId = readScriptFlagValue();
758 	int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
759 	if (_vm->_backAnimList[slotId].backAnims[currAnim]._frame != frameId - 1) {
760 		_currentInstruction -= 6;
761 		_opcodeNF = 1;
762 	}
763 	debugInterpreter("O_CHECKBACKANIMFRAME slotId %d, frameId %d", slotId, frameId);
764 }
765 
766 // Not used in script
O_FREEALLSAMPLES()767 void Interpreter::O_FREEALLSAMPLES() {
768 	error("O_FREEALLSAMPLES");
769 }
770 
O_SETMUSIC()771 void Interpreter::O_SETMUSIC() {
772 	uint16 musicId = readScript16();
773 	_vm->loadMusic(musicId);
774 	debugInterpreter("O_SETMUSIC musicId %d", musicId);
775 }
776 
O_STOPMUSIC()777 void Interpreter::O_STOPMUSIC() {
778 	_vm->stopMusic();
779 	debugInterpreter("O_STOPMUSIC");
780 }
781 
O__WAIT()782 void Interpreter::O__WAIT() {
783 	int32 pause = readScriptFlagValue();
784 	debugInterpreter("O__WAIT pause %d", pause);
785 	if (!_waitFlag) {
786 		// set new wait flag value and continue
787 		_waitFlag = pause;
788 		_opcodeNF = 1;
789 		_currentInstruction -= 4;
790 		return;
791 	}
792 	_waitFlag--;
793 	if (_waitFlag > 0) {
794 		_opcodeNF = 1;
795 		_currentInstruction -= 4;
796 		return;
797 	}
798 }
799 
800 // Not used in script
O_UPDATEOFF()801 void Interpreter::O_UPDATEOFF() {
802 	error("O_UPDATEOFF");
803 }
804 
805 // Not used in script
O_UPDATEON()806 void Interpreter::O_UPDATEON() {
807 	error("O_UPDATEON");
808 }
809 
810 // Not used in script
O_UPDATE()811 void Interpreter::O_UPDATE () {
812 	error("O_UPDATE");
813 }
814 
815 // Not used in script
O_CLS()816 void Interpreter::O_CLS() {
817 	error("O_CLS");
818 }
819 
O__CALL()820 void Interpreter::O__CALL() {
821 	int32 address = readScript32();
822 	_stack[_stacktop] = _currentInstruction;
823 	_stacktop++;
824 	_currentInstruction += address - 4;
825 	debugInterpreter("O__CALL 0x%04X", _currentInstruction);
826 }
827 
O_RETURN()828 void Interpreter::O_RETURN() {
829 	if (_stacktop > 0) {
830 		_stacktop--;
831 		_currentInstruction = _stack[_stacktop];
832 		debugInterpreter("O_RETURN 0x%04X", _currentInstruction);
833 	} else {
834 		error("O_RETURN: Stack is empty");
835 	}
836 }
837 
O_GO()838 void Interpreter::O_GO() {
839 	int32 opPC = readScript32();
840 	_currentInstruction += opPC - 4;
841 	debugInterpreter("O_GO 0x%04X", opPC);
842 }
843 
O_BACKANIMUPDATEOFF()844 void Interpreter::O_BACKANIMUPDATEOFF() {
845 	int32 slotId = readScriptFlagValue();
846 	int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
847 	if (!_vm->_backAnimList[slotId].backAnims.empty()) {
848 		_vm->_backAnimList[slotId].backAnims[currAnim]._state = 1;
849 	}
850 	debugInterpreter("O_BACKANIMUPDATEOFF slotId %d", slotId);
851 }
852 
O_BACKANIMUPDATEON()853 void Interpreter::O_BACKANIMUPDATEON() {
854 	int32 slotId = readScriptFlagValue();
855 	int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
856 	if (!_vm->_backAnimList[slotId].backAnims.empty()) {
857 		_vm->_backAnimList[slotId].backAnims[currAnim]._state = 0;
858 	}
859 	debugInterpreter("O_BACKANIMUPDATEON slotId %d", slotId);
860 }
861 
O_CHANGECURSOR()862 void Interpreter::O_CHANGECURSOR() {
863 	int32 cursorId = readScriptFlagValue();
864 	_vm->changeCursor(cursorId);
865 	debugInterpreter("O_CHANGECURSOR %x", cursorId);
866 }
867 
868 // Not used in script
O_CHANGEANIMTYPE()869 void Interpreter::O_CHANGEANIMTYPE() {
870 	error("O_CHANGEANIMTYPE");
871 }
872 
O__SETFLAG()873 void Interpreter::O__SETFLAG() {
874 	Flags::Id flagId = readScriptFlagId();
875 	int32 value = readScriptFlagValue();
876 	_flags->setFlagValue((Flags::Id)(flagId), value);
877 	debugInterpreter("O__SETFLAG 0x%04X (%s) = %d", flagId, Flags::getFlagName(flagId), value);
878 }
879 
O_COMPARE()880 void Interpreter::O_COMPARE() {
881 	Flags::Id flagId = readScriptFlagId();
882 	int32 value = readScriptFlagValue();
883 	_result = _flags->getFlagValue(flagId) != value;
884 	debugInterpreter("O_COMPARE flagId 0x%04X (%s), value %d == %d (%d)", flagId, Flags::getFlagName(flagId), value, _flags->getFlagValue(flagId), _result);
885 }
886 
O_JUMPZ()887 void Interpreter::O_JUMPZ() {
888 	int32 offset = readScript32();
889 	if (!_result) {
890 		_currentInstruction += offset - 4;
891 	}
892 	debugInterpreter("O_JUMPZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset);
893 }
894 
O_JUMPNZ()895 void Interpreter::O_JUMPNZ() {
896 	int32 offset = readScript32();
897 	if (_result) {
898 		_currentInstruction += offset - 4;
899 	}
900 	debugInterpreter("O_JUMPNZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset);
901 }
902 
O_EXIT()903 void Interpreter::O_EXIT() {
904 	int32 exitCode = readScriptFlagValue();
905 	_opcodeEnd = true;
906 	_opcodeNF = 1;
907 	if (exitCode == 0x2EAD) {
908 		_vm->scrollCredits();
909 	}
910 	debugInterpreter("O_EXIT exitCode %d", exitCode);
911 }
912 
O_ADDFLAG()913 void Interpreter::O_ADDFLAG() {
914 	Flags::Id flagId = readScriptFlagId();
915 	int32 value = readScriptFlagValue();
916 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) + value);
917 	if (_flags->getFlagValue(flagId)) {
918 		_result = 1;
919 	} else {
920 		_result = 0;
921 	}
922 	debugInterpreter("O_ADDFLAG flagId %04x (%s), value %d", flagId, Flags::getFlagName(flagId), value);
923 }
924 
O_TALKANIM()925 void Interpreter::O_TALKANIM() {
926 	int32 animNumber = readScriptFlagValue();
927 	int32 slot = readScriptFlagValue();
928 	_vm->doTalkAnim(animNumber, slot, kNormalAnimation);
929 	debugInterpreter("O_TALKANIM animNumber %d, slot %d", animNumber, slot);
930 }
931 
O_SUBFLAG()932 void Interpreter::O_SUBFLAG() {
933 	Flags::Id flagId = readScriptFlagId();
934 	int32 value = readScriptFlagValue();
935 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) - value);
936 	if (_flags->getFlagValue(flagId)) {
937 		_result = 1;
938 	} else {
939 		_result = 0;
940 	}
941 	debugInterpreter("O_SUBFLAG flagId %d, value %d", flagId, value);
942 }
943 
O_SETSTRING()944 void Interpreter::O_SETSTRING() {
945 	int32 offset = readScript32();
946 	_currentString = offset;
947 	if (offset >= 80000) {
948 		_string = _vm->_variaTxt->getString(offset - 80000);
949 		debugInterpreter("GetVaria %s", _string);
950 	} else if (offset < 2000) {
951 		_vm->_dialogData = &_vm->_dialogDat[offset * 4 - 4];
952 		uint32 of = READ_LE_UINT32(_vm->_talkTxt + offset * 4);
953 		const char *txt = (const char *)&_vm->_talkTxt[of];
954 		_string = &_vm->_talkTxt[of];
955 		debugInterpreter("TalkTxt %d %s", of, txt);
956 	}
957 	debugInterpreter("O_SETSTRING %04d", offset);
958 }
959 
O_ANDFLAG()960 void Interpreter::O_ANDFLAG() {
961 	Flags::Id flagId = readScriptFlagId();
962 	int32 value = readScriptFlagValue();
963 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) & value);
964 	if (_flags->getFlagValue(flagId)) {
965 		_result = 1;
966 	} else {
967 		_result = 0;
968 	}
969 	debugInterpreter("O_ANDFLAG flagId %d, value %d", flagId, value);
970 }
971 
O_GETMOBDATA()972 void Interpreter::O_GETMOBDATA() {
973 	Flags::Id flagId = readScriptFlagId();
974 	int32 mobId = readScriptFlagValue();
975 	int32 mobOffset = readScriptFlagValue();
976 	int16 value = _vm->_mobList[mobId].getData((Mob::AttrId)mobOffset);
977 	_flags->setFlagValue(flagId, value);
978 	debugInterpreter("O_GETMOBDATA flagId %d, modId %d, mobOffset %d", flagId, mobId, mobOffset);
979 }
980 
O_ORFLAG()981 void Interpreter::O_ORFLAG() {
982 	Flags::Id flagId = readScriptFlagId();
983 	int32 value = readScriptFlagValue();
984 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) | value);
985 	if (_flags->getFlagValue(flagId)) {
986 		_result = 1;
987 	} else {
988 		_result = 0;
989 	}
990 	debugInterpreter("O_ORFLAG flagId %d, value %d", flagId, value);
991 }
992 
O_SETMOBDATA()993 void Interpreter::O_SETMOBDATA() {
994 	int32 mobId = readScriptFlagValue();
995 	int32 mobOffset = readScriptFlagValue();
996 	int32 value = readScriptFlagValue();
997 	_vm->_mobList[mobId].setData((Mob::AttrId)mobOffset, value);
998 	debugInterpreter("O_SETMOBDATA mobId %d, mobOffset %d, value %d", mobId, mobOffset, value);
999 }
1000 
O_XORFLAG()1001 void Interpreter::O_XORFLAG() {
1002 	Flags::Id flagId = readScriptFlagId();
1003 	int32 value = readScriptFlagValue();
1004 	_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) ^ value);
1005 	if (_flags->getFlagValue(flagId)) {
1006 		_result = 1;
1007 	} else {
1008 		_result = 0;
1009 	}
1010 	debugInterpreter("O_XORFLAG flagId %d, value %d", flagId, value);
1011 }
1012 
O_GETMOBTEXT()1013 void Interpreter::O_GETMOBTEXT() {
1014 	int32 mob = readScriptFlagValue();
1015 	_currentString = _vm->_locationNr * 100 + mob + 60001;
1016 	// FIXME: UB?
1017 	// This casts away the constness of the pointer returned by c_str() which is
1018 	// stored and potentially modified later (for example in printAt()).
1019 	// Also, the pointer is only valid as long as _vm->_mobList[mob]
1020 	// is around and _vm->_mobList[mob]._examText hasn't been modified by any of its
1021 	// non-const member functions which also might or might not be a problem.
1022 	_string = (byte *)_vm->_mobList[mob]._examText.c_str();
1023 	debugInterpreter("O_GETMOBTEXT mob %d", mob);
1024 }
1025 
O_MOVEHERO()1026 void Interpreter::O_MOVEHERO() {
1027 	int32 heroId = readScriptFlagValue();
1028 	int32 x = readScriptFlagValue();
1029 	int32 y = readScriptFlagValue();
1030 	int32 dir = readScriptFlagValue();
1031 	_vm->moveRunHero(heroId, x, y, dir, false);
1032 	debugInterpreter("O_MOVEHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
1033 }
1034 
O_WALKHERO()1035 void Interpreter::O_WALKHERO() {
1036 	int32 heroId = readScriptFlagValue();
1037 	Hero *hero = nullptr;
1038 	if (!heroId) {
1039 		hero = _vm->_mainHero;
1040 	} else if (heroId == 1) {
1041 		hero = _vm->_secondHero;
1042 	}
1043 	if (hero != nullptr) {
1044 		if (hero->_state != Hero::kHeroStateStay) {
1045 			_currentInstruction -= 4;
1046 			_opcodeNF = 1;
1047 		}
1048 	}
1049 	debugInterpreter("O_WALKHERO %d", heroId);
1050 }
1051 
O_SETHERO()1052 void Interpreter::O_SETHERO() {
1053 	int32 heroId = readScriptFlagValue();
1054 	int32 x = readScriptFlagValue();
1055 	int32 y = readScriptFlagValue();
1056 	int32 dir = readScriptFlagValue();
1057 	Hero *hero = nullptr;
1058 	if (!heroId) {
1059 		hero = _vm->_mainHero;
1060 	} else if (heroId == 1) {
1061 		hero = _vm->_secondHero;
1062 	}
1063 	if (hero != nullptr) {
1064 		hero->setPos(x, y);
1065 		hero->_lastDirection = dir;
1066 		hero->_visible = 1;
1067 		hero->countDrawPosition();
1068 	}
1069 	debugInterpreter("O_SETHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
1070 }
1071 
O_HEROOFF()1072 void Interpreter::O_HEROOFF() {
1073 	int32 heroId = readScriptFlagValue();
1074 	Hero *hero = nullptr;
1075 	if (!heroId) {
1076 		hero = _vm->_mainHero;
1077 	} else if (heroId == 1) {
1078 		hero = _vm->_secondHero;
1079 	}
1080 	if (hero != nullptr) {
1081 		hero->setVisible(false);
1082 	}
1083 	debugInterpreter("O_HEROOFF %d", heroId);
1084 }
1085 
O_HEROON()1086 void Interpreter::O_HEROON() {
1087 	int32 heroId = readScriptFlagValue();
1088 	Hero *hero = nullptr;
1089 	if (!heroId) {
1090 		hero = _vm->_mainHero;
1091 	} else if (heroId == 1) {
1092 		hero = _vm->_secondHero;
1093 	}
1094 	if (hero != nullptr) {
1095 		hero->setVisible(true);
1096 	}
1097 	debugInterpreter("O_HEROON %d", heroId);
1098 }
1099 
O_CLSTEXT()1100 void Interpreter::O_CLSTEXT() {
1101 	int32 slot = readScriptFlagValue();
1102 	_vm->_textSlots[slot]._str = nullptr;
1103 	_vm->_textSlots[slot]._time = 0;
1104 	debugInterpreter("O_CLSTEXT slot %d", slot);
1105 }
1106 
O_CALLTABLE()1107 void Interpreter::O_CALLTABLE() {
1108 	Flags::Id flagId = readScriptFlagId();
1109 	int roomNr = _flags->getFlagValue(flagId);
1110 	int32 tableOffset = readScript32();
1111 	int initLocationScript = _script->getLocationInitScript(tableOffset, roomNr);
1112 	if (initLocationScript) {
1113 		_stack[_stacktop] = _currentInstruction;
1114 		_stacktop++;
1115 		_currentInstruction = initLocationScript;
1116 	}
1117 	debugInterpreter("O_CALLTABLE loc %d", roomNr);
1118 }
1119 
O_CHANGEMOB()1120 void Interpreter::O_CHANGEMOB() {
1121 	int32 mob = readScriptFlagValue();
1122 	int32 value = readScriptFlagValue();
1123 	value ^= 1;
1124 	_vm->_script->setMobVisible(_vm->_room->_mobs, mob, value);
1125 	_vm->_mobList[mob]._visible = value;
1126 	debugInterpreter("O_CHANGEMOB mob %d, value %d", mob, value);
1127 }
1128 
O_ADDINV()1129 void Interpreter::O_ADDINV() {
1130 	int32 hero = readScriptFlagValue();
1131 	int32 item = readScriptFlagValue();
1132 	_vm->addInv(hero, item, false);
1133 	debugInterpreter("O_ADDINV hero %d, item %d", hero, item);
1134 }
1135 
O_REMINV()1136 void Interpreter::O_REMINV() {
1137 	int32 hero = readScriptFlagValue();
1138 	int32 item = readScriptFlagValue();
1139 	_vm->remInv(hero, item);
1140 	debugInterpreter("O_REMINV hero %d, item %d", hero, item);
1141 }
1142 
1143 // Not used in script
O_REPINV()1144 void Interpreter::O_REPINV() {
1145 	error("O_REPINV");
1146 }
1147 
1148 // Not used in script
O_OBSOLETE_GETACTION()1149 void Interpreter::O_OBSOLETE_GETACTION() {
1150 	error("O_OBSOLETE_GETACTION");
1151 }
1152 
1153 // Not used in script
O_ADDWALKAREA()1154 void Interpreter::O_ADDWALKAREA() {
1155 	error("O_ADDWALKAREA");
1156 }
1157 
1158 // Not used in script
O_REMWALKAREA()1159 void Interpreter::O_REMWALKAREA() {
1160 	error("O_REMWALKAREA");
1161 }
1162 
1163  // Not used in script
O_RESTOREWALKAREA()1164 void Interpreter::O_RESTOREWALKAREA() {
1165 	error("O_RESTOREWALKAREA");
1166 }
1167 
O_WAITFRAME()1168 void Interpreter::O_WAITFRAME() {
1169 	_opcodeNF = true;
1170 	debugInterpreter("O_WAITFRAME");
1171 }
1172 
O_SETFRAME()1173 void Interpreter::O_SETFRAME() {
1174 	int32 anim = readScriptFlagValue();
1175 	int32 frame = readScriptFlagValue();
1176 	_vm->_normAnimList[anim]._frame = frame;
1177 	debugInterpreter("O_SETFRAME anim %d, frame %d", anim, frame);
1178 }
1179 
1180 // Not used in script
O_RUNACTION()1181 void Interpreter::O_RUNACTION() {
1182 	error("O_RUNACTION");
1183 }
1184 
O_COMPAREHI()1185 void Interpreter::O_COMPAREHI() {
1186 	Flags::Id flag = readScriptFlagId();
1187 	int32 value = readScriptFlagValue();
1188 	int32 flagValue = _flags->getFlagValue(flag);
1189 	if (flagValue > value) {
1190 		_result = 0;
1191 	} else {
1192 		_result = 1;
1193 	}
1194 	debugInterpreter("O_COMPAREHI flag %04x - (%s), value %d, flagValue %d, result %d", flag, Flags::getFlagName(flag), value, flagValue, _result);
1195 }
1196 
O_COMPARELO()1197 void Interpreter::O_COMPARELO() {
1198 	Flags::Id flag = readScriptFlagId();
1199 	int32 value = readScriptFlagValue();
1200 	int32 flagValue = _flags->getFlagValue(flag);
1201 	if (flagValue < value) {
1202 		_result = 0;
1203 	} else {
1204 		_result = 1;
1205 	}
1206 	debugInterpreter("O_COMPARELO flag %04x - (%s), value %d, flagValue %d, result %d", flag, Flags::getFlagName(flag), value, flagValue, _result);
1207 }
1208 
1209 // Not used in script
O_PRELOADSET()1210 void Interpreter::O_PRELOADSET() {
1211 	error("O_PRELOADSET");
1212 }
1213 
1214 // Not used in script
O_FREEPRELOAD()1215 void Interpreter::O_FREEPRELOAD() {
1216 	error("O_FREEPRELOAD");
1217 }
1218 
1219 // Not used in script
O_CHECKINV()1220 void Interpreter::O_CHECKINV() {
1221 	error("O_CHECKINV");
1222 }
1223 
O_TALKHERO()1224 void Interpreter::O_TALKHERO() {
1225 	int32 hero = readScriptFlagValue();
1226 	_vm->talkHero(hero);
1227 	debugInterpreter("O_TALKHERO hero %d", hero);
1228 }
1229 
O_WAITTEXT()1230 void Interpreter::O_WAITTEXT() {
1231 	int32 slot = readScriptFlagValue();
1232 	Text &text = _vm->_textSlots[slot];
1233 	if (text._time && text._str) {
1234 		if (_flags->getFlagValue(Flags::ESCAPED)) {
1235 			text._time = 1;
1236 			if (!slot) {
1237 				_vm->_mainHero->_talkTime = 1;
1238 			} else if (slot == 1) {
1239 				_vm->_secondHero->_talkTime = 1;
1240 			}
1241 		} else {
1242 			_opcodeNF = 1;
1243 			_currentInstruction -= 4;
1244 		}
1245 	}
1246 	//debugInterpreter("O_WAITTEXT slot %d", slot);
1247 }
1248 
O_SETHEROANIM()1249 void Interpreter::O_SETHEROANIM() {
1250 	int32 heroId = readScriptFlagValue();
1251 	int32 offset = readScript32();
1252 	Hero *hero = nullptr;
1253 	if (!heroId) {
1254 		hero = _vm->_mainHero;
1255 	} else {
1256 		hero = _vm->_secondHero;
1257 	}
1258 	if (hero != nullptr) {
1259 		hero->freeHeroAnim();
1260 		if (hero ->_specAnim == nullptr) {
1261 			hero->_specAnim = new Animation();
1262 			if (offset < 100) {
1263 				const Common::String animName = Common::String::format("AN%02d", offset);
1264 				Resource::loadResource(hero->_specAnim, animName.c_str(), true);
1265 			} else {
1266 				const Common::String animName = Common::String((const char *)_script->getHeroAnimName(offset));
1267 				Common::String normalizedPath = lastPathComponent(animName, '\\');
1268 				Resource::loadResource(hero->_specAnim, normalizedPath.c_str(), true);
1269 			}
1270 			hero->_phase = 0;
1271 			hero->_state = Hero::kHeroStateSpec;
1272 		}
1273 	}
1274 	debugInterpreter("O_SETHEROANIM hero %d, offset %d", hero, offset);
1275 }
1276 
O_WAITHEROANIM()1277 void Interpreter::O_WAITHEROANIM() {
1278 	int32 heroId = readScriptFlagValue();
1279 	Hero *hero = nullptr;
1280 	if (!heroId) {
1281 		hero = _vm->_mainHero;
1282 	} else {
1283 		hero = _vm->_secondHero;
1284 	}
1285 	if (hero != nullptr) {
1286 		if (hero->_state == Hero::kHeroStateSpec) {
1287 			_currentInstruction -= 4;
1288 			_opcodeNF = 1;
1289 		}
1290 	}
1291 	debugInterpreter("O_WAITHEROANIM heroId %d", heroId);
1292 }
1293 
O_GETHERODATA()1294 void Interpreter::O_GETHERODATA() {
1295 	Flags::Id flagId = readScriptFlagId();
1296 	int32 heroId = readScriptFlagValue();
1297 	int32 heroOffset = readScriptFlagValue();
1298 	Hero *hero = nullptr;
1299 	if (!heroId) {
1300 		hero = _vm->_mainHero;
1301 	} else {
1302 		hero = _vm->_secondHero;
1303 	}
1304 	if (hero != nullptr) {
1305 		_flags->setFlagValue(flagId, hero->getData((Hero::AttrId)heroOffset));
1306 	}
1307 	debugInterpreter("O_GETHERODATA flag %04x - (%s), heroId %d, heroOffset %d", flagId, Flags::getFlagName(flagId), heroId, heroOffset);
1308 }
1309 
1310 // No need of implementation here
O_GETMOUSEBUTTON()1311 void Interpreter::O_GETMOUSEBUTTON() {
1312 	debugInterpreter("O_GETMOUSEBUTTON");
1313 }
1314 
O_CHANGEFRAMES()1315 void Interpreter::O_CHANGEFRAMES() {
1316 	int32 anim = readScriptFlagValue();
1317 	int32 frame = readScriptFlagValue();
1318 	int32 lastFrame = readScriptFlagValue();
1319 	int32 loopFrame = readScriptFlagValue();
1320 	_vm->_normAnimList[anim]._frame = frame;
1321 	_vm->_normAnimList[anim]._lastFrame = lastFrame;
1322 	_vm->_normAnimList[anim]._loopFrame = loopFrame;
1323 	debugInterpreter("O_CHANGFRAMES anim %d, frame %d, lastFrame %d, loopFrame %d", anim, frame, lastFrame, loopFrame);
1324 }
1325 
O_CHANGEBACKFRAMES()1326 void Interpreter::O_CHANGEBACKFRAMES() {
1327 	int32 anim = readScriptFlagValue();
1328 	int32 frame = readScriptFlagValue();
1329 	int32 lastFrame = readScriptFlagValue();
1330 	int32 loopFrame = readScriptFlagValue();
1331 	int currAnim = _vm->_backAnimList[anim]._seq._currRelative;
1332 	Anim &backAnim = _vm->_backAnimList[anim].backAnims[currAnim];
1333 	backAnim._frame = frame;
1334 	backAnim._lastFrame = lastFrame;
1335 	backAnim._loopFrame = loopFrame;
1336 	debugInterpreter("O_CHANGEBACKFRAMES anim %d, frame %d, lastFrame %d, loopFrame %d", anim, frame, lastFrame, loopFrame);
1337 }
1338 
O_GETBACKANIMDATA()1339 void Interpreter::O_GETBACKANIMDATA() {
1340 	Flags::Id flagId = readScriptFlagId();
1341 	int32 animNumber = readScriptFlagValue();
1342 	int32 animDataOffset = readScriptFlagValue();
1343 	int currAnim = _vm->_backAnimList[animNumber]._seq._currRelative;
1344 	int16 value = _vm->_backAnimList[animNumber].backAnims[currAnim].getAnimData((Anim::AnimOffsets)(animDataOffset));
1345 	_flags->setFlagValue((Flags::Id)(flagId), value);
1346 	debugInterpreter("O_GETBACKANIMDATA flag %04X (%s), animNumber %d, animDataOffset %d, value %d", flagId, Flags::getFlagName(flagId), animNumber, animDataOffset, value);
1347 }
1348 
O_GETANIMDATA()1349 void Interpreter::O_GETANIMDATA() {
1350 	Flags::Id flagId = readScriptFlagId();
1351 	int32 anim = readScriptFlagValue();
1352 	int32 animOffset = readScriptFlagValue();
1353 	if (_vm->_normAnimList[anim]._animData != nullptr) {
1354 		_flags->setFlagValue(flagId, _vm->_normAnimList[anim].getAnimData((Anim::AnimOffsets)(animOffset)));
1355 	}
1356 	debugInterpreter("O_GETANIMDATA flag %04X (%s), anim %d, animOffset %d", flagId, Flags::getFlagName(flagId), anim, animOffset);
1357 }
1358 
O_SETBGCODE()1359 void Interpreter::O_SETBGCODE() {
1360 	int32 offset = readScript32();
1361 	_bgOpcodePC = _currentInstruction + offset - 4;
1362 	debugInterpreter("O_SETBGCODE next %08x, offset %08x", _bgOpcodePC, offset);
1363 }
1364 
O_SETBACKFRAME()1365 void Interpreter::O_SETBACKFRAME() {
1366 	int32 anim = readScriptFlagValue();
1367 	int32 frame = readScriptFlagValue();
1368 	int currAnim = _vm->_backAnimList[anim]._seq._currRelative;
1369 	if (_vm->_backAnimList[anim].backAnims[currAnim]._animData != nullptr) {
1370 		_vm->_backAnimList[anim].backAnims[currAnim]._frame = frame;
1371 	}
1372 	debugInterpreter("O_SETBACKFRAME anim %d, frame %d", anim, frame);
1373 }
1374 
O_GETRND()1375 void Interpreter::O_GETRND() {
1376 	Flags::Id flag = readScriptFlagId();
1377 	uint16 rndSeed = readScript16();
1378 	int value = _vm->_randomSource.getRandomNumber(rndSeed - 1);
1379 	_flags->setFlagValue(flag, value);
1380 	debugInterpreter("O_GETRND flag %d, rndSeed %d, value %d", flag, rndSeed, value);
1381 }
1382 
O_TALKBACKANIM()1383 void Interpreter::O_TALKBACKANIM() {
1384 	int32 animNumber = readScriptFlagValue();
1385 	int32 slot = readScriptFlagValue();
1386 	_vm->doTalkAnim(animNumber, slot, kBackgroundAnimation);
1387 	debugInterpreter("O_TALKBACKANIM animNumber %d, slot %d", animNumber, slot);
1388 }
1389 
1390 // Simplifying, because used only once in Location 20
O_LOADPATH()1391 void Interpreter::O_LOADPATH() {
1392 	readScript32();
1393 	_vm->loadPath("path2");
1394 	debugInterpreter("O_LOADPATH - path2");
1395 }
1396 
O_GETCHAR()1397 void Interpreter::O_GETCHAR() {
1398 	Flags::Id flagId = readScriptFlagId();
1399 	_flags->setFlagValue(flagId, *_string);
1400 	_string++;
1401 	debugInterpreter("O_GETCHAR %04X (%s) %02x", flagId, Flags::getFlagName(flagId), _flags->getFlagValue(flagId));
1402 }
1403 
O_SETDFLAG()1404 void Interpreter::O_SETDFLAG() {
1405 	Flags::Id flagId = readScriptFlagId();
1406 	int32 address = readScript32();
1407 	_flags->setFlagValue((Flags::Id)(flagId), _currentInstruction + address - 4);
1408 	debugInterpreter("O_SETDFLAG 0x%04X (%s) = 0x%04X", flagId, Flags::getFlagName(flagId), _currentInstruction + address - 4);
1409 }
1410 
O_CALLDFLAG()1411 void Interpreter::O_CALLDFLAG() {
1412 	Flags::Id flagId = readScriptFlagId();
1413 	_stack[_stacktop] = _currentInstruction;
1414 	_stacktop++;
1415 	_currentInstruction = _flags->getFlagValue(flagId);
1416 	debugInterpreter("O_CALLDFLAG 0x%04X (%s) = 0x%04X", flagId, Flags::getFlagName(flagId), _currentInstruction);
1417 }
1418 
O_PRINTAT()1419 void Interpreter::O_PRINTAT() {
1420 	int32 slot = readScriptFlagValue();
1421 	int32 x = readScriptFlagValue();
1422 	int32 y = readScriptFlagValue();
1423 	int32 color = _flags->getFlagValue(Flags::KOLOR);
1424 	_vm->printAt(slot, color, (char *)_string, x, y);
1425 	increaseString();
1426 	debugInterpreter("O_PRINTAT slot %d, x %d, y %d", slot, x, y);
1427 }
1428 
O_ZOOMIN()1429 void Interpreter::O_ZOOMIN() {
1430 	int32 slot = readScriptFlagValue();
1431 	_vm->initZoomIn(slot);
1432 	debugInterpreter("O_ZOOMIN slot %04d", slot);
1433 }
1434 
O_ZOOMOUT()1435 void Interpreter::O_ZOOMOUT() {
1436 	int32 slot = readScriptFlagValue();
1437 	_vm->initZoomOut(slot);
1438 	debugInterpreter("O_ZOOMOUT slot %d", slot);
1439 }
1440 
1441 // Not used in script
O_SETSTRINGOFFSET()1442 void Interpreter::O_SETSTRINGOFFSET() {
1443 	error("O_SETSTRINGOFFSET");
1444 }
1445 
O_GETOBJDATA()1446 void Interpreter::O_GETOBJDATA() {
1447 	Flags::Id flag = readScriptFlagId();
1448 	int32 slot = readScriptFlagValue();
1449 	int32 objOffset = readScriptFlagValue();
1450 	int nr = _vm->_objSlot[slot];
1451 	if (nr != 0xFF) {
1452 		int16 value = _vm->_objList[nr]->getData((Object::AttrId)objOffset);
1453 		_flags->setFlagValue(flag, value);
1454 	}
1455 	debugInterpreter("O_GETOBJDATA flag %d, objSlot %d, objOffset %d", flag, slot, objOffset);
1456 }
1457 
O_SETOBJDATA()1458 void Interpreter::O_SETOBJDATA() {
1459 	int32 slot = readScriptFlagValue();
1460 	int32 objOffset = readScriptFlagValue();
1461 	int32 value = readScriptFlagValue();
1462 	int nr = _vm->_objSlot[slot];
1463 	if (nr != 0xFF) {
1464 		_vm->_objList[nr]->setData((Object::AttrId)objOffset, value);
1465 	}
1466 	debugInterpreter("O_SETOBJDATA objSlot %d, objOffset %d, value %d", slot, objOffset, value);
1467 }
1468 
1469 // Not used in script
O_SWAPOBJECTS()1470 void Interpreter::O_SWAPOBJECTS() {
1471 	error("O_SWAPOBJECTS");
1472 }
1473 
O_CHANGEHEROSET()1474 void Interpreter::O_CHANGEHEROSET() {
1475 	int32 heroId = readScriptFlagValue();
1476 	int32 heroSet = readScriptFlagValue();
1477 	if (!heroId) {
1478 		_vm->_mainHero->loadAnimSet(heroSet);
1479 	} else if (heroId == 1) {
1480 		_vm->_secondHero->loadAnimSet(heroSet);
1481 	}
1482 	debugInterpreter("O_CHANGEHEROSET hero %d, heroSet %d", heroId, heroSet);
1483 }
1484 
1485 // Not used in script
O_ADDSTRING()1486 void Interpreter::O_ADDSTRING() {
1487 	error("O_ADDSTRING");
1488 }
1489 
O_SUBSTRING()1490 void Interpreter::O_SUBSTRING() {
1491 	int32 value = readScriptFlagValue();
1492 	_string -= value;
1493 	debugInterpreter("O_SUBSTRING value %d", value);
1494 }
1495 
checkSeq(byte * string)1496 int Interpreter::checkSeq(byte *string) {
1497 	int freeHSlotIncrease = 0;
1498 	byte c;
1499 	while ((c = string[0]) != 0xFF) {
1500 		string++;
1501 		if (c < 0xF0) {
1502 			freeHSlotIncrease++;
1503 			while ((c = string[0])) {
1504 				string++;
1505 			}
1506 			string++;
1507 		} else if (c != 0xFE) {
1508 			string++;
1509 		}
1510 	}
1511 	return freeHSlotIncrease;
1512 }
1513 
O_INITDIALOG()1514 void Interpreter::O_INITDIALOG() {
1515 	if (_string[0] == 255) {
1516 		byte *stringCurrOff = _string;
1517 		byte *string = _string;
1518 		stringCurrOff++;
1519 		int32 adressOfFirstSequence = (int)READ_LE_UINT16(stringCurrOff);
1520 		stringCurrOff += 2;
1521 		_string = string + adressOfFirstSequence;
1522 
1523 		for (int i = 0; i < 32; i++) {
1524 			_vm->_dialogBoxAddr[i] = 0;
1525 			_vm->_dialogOptAddr[i] = 0;
1526 		}
1527 
1528 		for (int i = 0; i < 4 * 32; i++) {
1529 			_vm->_dialogOptLines[i] = 0;
1530 		}
1531 
1532 		int16 off;
1533 		byte *line = nullptr;
1534 
1535 		int dialogBox = 0;
1536 		while ((off = (int)READ_LE_UINT16(stringCurrOff)) != -1) {
1537 			stringCurrOff += 2;
1538 			if (off) {
1539 				line = string + off;
1540 			}
1541 			_vm->_dialogBoxAddr[dialogBox] = line;
1542 			dialogBox++;
1543 		}
1544 		stringCurrOff += 2;
1545 
1546 		int dialogOpt = 0;
1547 		while ((off = (int)READ_LE_UINT16(stringCurrOff)) != -1) {
1548 			stringCurrOff += 2;
1549 			if (off) {
1550 				line = string + off;
1551 			}
1552 			_vm->_dialogOptAddr[dialogOpt] = line;
1553 			dialogOpt++;
1554 		}
1555 
1556 		_flags->setFlagValue(Flags::VOICE_A_LINE, 0);
1557 		_flags->setFlagValue(Flags::VOICE_B_LINE, 0); // bx in original?
1558 
1559 		int freeHSlot = 0;
1560 		for (int i = 31; i >= 0; i--) {
1561 			if (_vm->_dialogOptAddr[i] != 0) {
1562 				i++;
1563 				freeHSlot = i;
1564 				_flags->setFlagValue(Flags::VOICE_H_LINE, i);
1565 				break;
1566 			}
1567 		}
1568 
1569 		freeHSlot += checkSeq(_string);
1570 
1571 		for (int i = 0; i < 32; i++) {
1572 			_vm->_dialogOptLines[i * 4] = freeHSlot;
1573 			_vm->_dialogOptLines[i * 4 + 1] = freeHSlot;
1574 			_vm->_dialogOptLines[i * 4 + 2] = freeHSlot;
1575 			if (_vm->_dialogOptAddr[i]) {
1576 				freeHSlot += checkSeq(_vm->_dialogOptAddr[i]);
1577 			}
1578 		}
1579 	}
1580 	debugInterpreter("O_INITDIALOG");
1581 }
1582 
O_ENABLEDIALOGOPT()1583 void Interpreter::O_ENABLEDIALOGOPT() {
1584 	int32 opt = readScriptFlagValue();
1585 	int dialogDataValue = (int)READ_LE_UINT32(_vm->_dialogData);
1586 	dialogDataValue &= ~(1u << opt);
1587 	WRITE_LE_UINT32(_vm->_dialogData, dialogDataValue);
1588 	debugInterpreter("O_ENABLEDIALOGOPT opt %d", opt);
1589 }
1590 
O_DISABLEDIALOGOPT()1591 void Interpreter::O_DISABLEDIALOGOPT() {
1592 	int32 opt = readScriptFlagValue();
1593 	int dialogDataValue = (int)READ_LE_UINT32(_vm->_dialogData);
1594 	dialogDataValue |= (1u << opt);
1595 	WRITE_LE_UINT32(_vm->_dialogData, dialogDataValue);
1596 	debugInterpreter("O_DISABLEDIALOGOPT opt %d", opt);
1597 }
1598 
O_SHOWDIALOGBOX()1599 void Interpreter::O_SHOWDIALOGBOX() {
1600 	int32 box = readScriptFlagValue();
1601 	uint32 currInstr = _currentInstruction;
1602 	_vm->createDialogBox(box);
1603 	_flags->setFlagValue(Flags::DIALINES, _vm->_dialogLines);
1604 	if (_vm->_dialogLines) {
1605 		_vm->changeCursor(1);
1606 		_vm->dialogRun();
1607 		_vm->changeCursor(0);
1608 	}
1609 	_currentInstruction = currInstr;
1610 	debugInterpreter("O_SHOWDIALOGBOX box %d", box);
1611 }
1612 
O_STOPSAMPLE()1613 void Interpreter::O_STOPSAMPLE() {
1614 	int32 slot = readScriptFlagValue();
1615 	_vm->stopSample(slot);
1616 	debugInterpreter("O_STOPSAMPLE slot %d", slot);
1617 }
1618 
O_BACKANIMRANGE()1619 void Interpreter::O_BACKANIMRANGE() {
1620 	int32 slotId = readScriptFlagValue();
1621 	uint16 animId = readScript16();
1622 	int32 low = readScriptFlagValue();
1623 	int32 high = readScriptFlagValue();
1624 	if (animId != 0xFFFF) {
1625 		if (animId & InterpreterFlags::kFlagMask) {
1626 			animId = _flags->getFlagValue((Flags::Id)animId);
1627 		}
1628 	}
1629 	_result = 1;
1630 	if (!_vm->_backAnimList[slotId].backAnims.empty()) {
1631 		int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
1632 		if (_vm->_backAnimList[slotId].backAnims[currAnim]._animData != nullptr) {
1633 			if (animId == 0xFFFF || _vm->_backAnimList[slotId]._seq._current == animId) {
1634 				Anim &backAnim = _vm->_backAnimList[slotId].backAnims[currAnim];
1635 				if (!backAnim._state) {
1636 					if (backAnim._frame >= low) {
1637 						if (backAnim._frame <= high) {
1638 							_result = 0;
1639 						}
1640 					}
1641 				}
1642 			}
1643 		}
1644 	}
1645 	debugInterpreter("O_BACKANIMRANGE slotId %d, animId %d, low %d, high %d, _result %d", slotId, animId, low, high, _result);
1646 }
1647 
O_CLEARPATH()1648 void Interpreter::O_CLEARPATH() {
1649 	for (uint i = 0; i < _vm->kPathBitmapLen; i++) {
1650 		_vm->_roomPathBitmap[i] = 255;
1651 	}
1652 	debugInterpreter("O_CLEARPATH");
1653 }
1654 
O_SETPATH()1655 void Interpreter::O_SETPATH() {
1656 	_vm->loadPath("path");
1657 	debugInterpreter("O_SETPATH");
1658 }
1659 
O_GETHEROX()1660 void Interpreter::O_GETHEROX() {
1661 	int32 heroId = readScriptFlagValue();
1662 	Flags::Id flagId = readScriptFlagId();
1663 	if (!heroId) {
1664 		_flags->setFlagValue(flagId, _vm->_mainHero->_middleX);
1665 	} else if (heroId == 1) {
1666 		_flags->setFlagValue(flagId, _vm->_secondHero->_middleX);
1667 	}
1668 	debugInterpreter("O_GETHEROX heroId %d, flagId %d", heroId, flagId);
1669 }
1670 
O_GETHEROY()1671 void Interpreter::O_GETHEROY() {
1672 	int32 heroId = readScriptFlagValue();
1673 	Flags::Id flagId = readScriptFlagId();
1674 	if (!heroId) {
1675 		_flags->setFlagValue(flagId, _vm->_mainHero->_middleY);
1676 	} else if (heroId == 1) {
1677 		_flags->setFlagValue(flagId, _vm->_secondHero->_middleY);
1678 	}
1679 	debugInterpreter("O_GETHEROY heroId %d, flagId %d", heroId, flagId);
1680 }
1681 
O_GETHEROD()1682 void Interpreter::O_GETHEROD() {
1683 	int32 heroId = readScriptFlagValue();
1684 	Flags::Id flagId = readScriptFlagId();
1685 	if (!heroId) {
1686 		_flags->setFlagValue(flagId, _vm->_mainHero->_lastDirection);
1687 	} else if (heroId == 1) {
1688 		_flags->setFlagValue(flagId, _vm->_secondHero->_lastDirection);
1689 	}
1690 	debugInterpreter("O_GETHEROD heroId %d, flagId %d", heroId, flagId);
1691 }
1692 
O_PUSHSTRING()1693 void Interpreter::O_PUSHSTRING() {
1694 	_stringStack.string = _string;
1695 	_stringStack.dialogData = _vm->_dialogData;
1696 	_stringStack.currentString = _currentString;
1697 	debugInterpreter("O_PUSHSTRING");
1698 }
1699 
O_POPSTRING()1700 void Interpreter::O_POPSTRING() {
1701 	_string = _stringStack.string;
1702 	_vm->_dialogData = _stringStack.dialogData;
1703 	_currentString = _stringStack.currentString;
1704 	debugInterpreter("O_POPSTRING");
1705 }
1706 
O_SETFGCODE()1707 void Interpreter::O_SETFGCODE() {
1708 	int32 offset = readScript32();
1709 	_fgOpcodePC = _currentInstruction + offset - 4;
1710 	debugInterpreter("O_SETFGCODE next %08x, offset %08x", _fgOpcodePC, offset);
1711 }
1712 
O_STOPHERO()1713 void Interpreter::O_STOPHERO() {
1714 	int32 heroId = readScriptFlagValue();
1715 	if (!heroId) {
1716 		_vm->_mainHero->freeOldMove();
1717 	} else if (heroId == 1) {
1718 		_vm->_secondHero->freeOldMove();
1719 	}
1720 	debugInterpreter("O_STOPHERO heroId %d", heroId);
1721 }
1722 
O_ANIMUPDATEOFF()1723 void Interpreter::O_ANIMUPDATEOFF() {
1724 	int32 slotId = readScriptFlagValue();
1725 	_vm->_normAnimList[slotId]._state = 1;
1726 	debugInterpreter("O_ANIMUPDATEOFF slotId %d", slotId);
1727 }
1728 
O_ANIMUPDATEON()1729 void Interpreter::O_ANIMUPDATEON() {
1730 	int32 slotId = readScriptFlagValue();
1731 	_vm->_normAnimList[slotId]._state = 0;
1732 	debugInterpreter("O_ANIMUPDATEON slotId %d", slotId);
1733 }
1734 
O_FREECURSOR()1735 void Interpreter::O_FREECURSOR() {
1736 	_vm->changeCursor(0);
1737 	_vm->_currentPointerNumber = 1;
1738 	// free memory here?
1739 	debugInterpreter("O_FREECURSOR");
1740 }
1741 
O_ADDINVQUIET()1742 void Interpreter::O_ADDINVQUIET() {
1743 	int32 hero = readScriptFlagValue();
1744 	int32 item = readScriptFlagValue();
1745 	_vm->addInv(hero, item, true);
1746 	debugInterpreter("O_ADDINVQUIET hero %d, item %d", hero, item);
1747 }
1748 
O_RUNHERO()1749 void Interpreter::O_RUNHERO() {
1750 	int32 heroId = readScriptFlagValue();
1751 	int32 x = readScriptFlagValue();
1752 	int32 y = readScriptFlagValue();
1753 	int32 dir = readScriptFlagValue();
1754 	_vm->moveRunHero(heroId, x, y, dir, true);
1755 	debugInterpreter("O_RUNHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
1756 }
1757 
O_SETBACKANIMDATA()1758 void Interpreter::O_SETBACKANIMDATA() {
1759 	uint16 animNumber = readScript16();
1760 	uint16 animDataOffset = readScript16();
1761 	Flags::Id flagId = readScriptFlagId();
1762 	uint16 value = _flags->getFlagValue((Flags::Id)(flagId));
1763 	int currAnim = _vm->_backAnimList[animNumber]._seq._currRelative;
1764 	_vm->_backAnimList[animNumber].backAnims[currAnim].setAnimData((Anim::AnimOffsets)(animDataOffset), value);
1765 	debugInterpreter("O_SETBACKANIMDATA flag %04X (%s), animNumber %d, animDataOffset %d, value %d", flagId, Flags::getFlagName(flagId), animNumber, animDataOffset, value);
1766 }
1767 
O_VIEWFLC()1768 void Interpreter::O_VIEWFLC() {
1769 	int32 animNr = readScriptFlagValue();
1770 	_vm->_flcFrameSurface = nullptr;
1771 	_vm->loadAnim(animNr, false);
1772 	debugInterpreter("O_VIEWFLC animNr %d", animNr);
1773 }
1774 
O_CHECKFLCFRAME()1775 void Interpreter::O_CHECKFLCFRAME() {
1776 	int32 frameNr = readScriptFlagValue();
1777 	debugInterpreter("O_CHECKFLCFRAME frame number %d", frameNr);
1778 	if (_vm->_flicPlayer.getCurFrame() != frameNr) {
1779 		_currentInstruction -= 4;
1780 		_opcodeNF = 1;
1781 	}
1782 }
1783 
O_CHECKFLCEND()1784 void Interpreter::O_CHECKFLCEND() {
1785 	const Video::FlicDecoder &flicPlayer = _vm->_flicPlayer;
1786 	debugInterpreter("O_CHECKFLCEND frameCount %d, currentFrame %d", flicPlayer.getFrameCount(), flicPlayer.getCurFrame());
1787 	if (flicPlayer.getFrameCount() - flicPlayer.getCurFrame() > 1) {
1788 		_currentInstruction -= 2;
1789 		_opcodeNF = 1;
1790 	}
1791 }
1792 
O_FREEFLC()1793 void Interpreter::O_FREEFLC() {
1794 	_vm->_flcFrameSurface = nullptr;
1795 	debugInterpreter("O_FREEFLC");
1796 }
1797 
O_TALKHEROSTOP()1798 void Interpreter::O_TALKHEROSTOP() {
1799 	int32 heroId = readScriptFlagValue();
1800 	if (!heroId) {
1801 		_vm->_mainHero->_state = Hero::kHeroStateStay;
1802 	} else if (heroId == 1) {
1803 		_vm->_secondHero->_state = Hero::kHeroStateStay;
1804 	}
1805 	debugInterpreter("O_TALKHEROSTOP %d", heroId);
1806 }
1807 
O_HEROCOLOR()1808 void Interpreter::O_HEROCOLOR() {
1809 	int32 heroId = readScriptFlagValue();
1810 	int32 color = readScriptFlagValue();
1811 	if (!heroId) {
1812 		_vm->_mainHero->_color = color;
1813 	} else if (heroId == 1) {
1814 		_vm->_secondHero->_color = color;
1815 	}
1816 	debugInterpreter("O_HEROCOLOR heroId %d, color %d", heroId, color);
1817 }
1818 
O_GRABMAPA()1819 void Interpreter::O_GRABMAPA() {
1820 	_vm->grabMap();
1821 	debugInterpreter("O_GRABMAPA");
1822 }
1823 
O_ENABLENAK()1824 void Interpreter::O_ENABLENAK() {
1825 	int32 nakId = readScriptFlagValue();
1826 	_vm->_maskList[nakId]._flags = 0;
1827 	debugInterpreter("O_ENABLENAK nakId %d", nakId);
1828 }
1829 
O_DISABLENAK()1830 void Interpreter::O_DISABLENAK() {
1831 	int32 nakId = readScriptFlagValue();
1832 	_vm->_maskList[nakId]._flags = 1;
1833 	debugInterpreter("O_DISABLENAK nakId %d", nakId);
1834 }
1835 
O_GETMOBNAME()1836 void Interpreter::O_GETMOBNAME() {
1837 	int32 modId = readScriptFlagValue();
1838 	// FIXME: UB?
1839 	// This casts away the constness of the pointer returned by c_str() which is
1840 	// stored and potentially modified later (for example in printAt()).
1841 	// Also, the pointer is only valid as long as _vm->_mobList[mobId]
1842 	// is around and _vm->_mobList[mobId]._name hasn't been modified by any of its
1843 	// non-const member functions which also might or might not be a problem.
1844 	_string = (byte *)_vm->_mobList[modId]._name.c_str();
1845 	debugInterpreter("O_GETMOBNAME modId %d", modId);
1846 }
1847 
O_SWAPINVENTORY()1848 void Interpreter::O_SWAPINVENTORY() {
1849 	int32 hero = readScriptFlagValue();
1850 	_vm->swapInv(hero);
1851 	debugInterpreter("O_SWAPINVENTORY hero %d", hero);
1852 }
1853 
O_CLEARINVENTORY()1854 void Interpreter::O_CLEARINVENTORY() {
1855 	int32 hero = readScriptFlagValue();
1856 	_vm->clearInv(hero);
1857 	debugInterpreter("O_CLEARINVENTORY hero %d", hero);
1858 }
1859 
O_SKIPTEXT()1860 void Interpreter::O_SKIPTEXT() {
1861 	increaseString();
1862 	debugInterpreter("O_SKIPTEXT");
1863 }
1864 
O_SETVOICEH()1865 void Interpreter::O_SETVOICEH() {
1866 	int32 slot = readScriptFlagValue();
1867 	static const uint32 VOICE_H_SLOT = 28;
1868 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1869 	_vm->setVoice(slot, VOICE_H_SLOT, voiceLineH);
1870 }
1871 
O_SETVOICEA()1872 void Interpreter::O_SETVOICEA() {
1873 	int32 slot = readScriptFlagValue();
1874 	static const uint32 VOICE_A_SLOT = 29;
1875 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1876 	_vm->setVoice(slot, VOICE_A_SLOT, voiceLineH);
1877 }
1878 
O_SETVOICEB()1879 void Interpreter::O_SETVOICEB() {
1880 	int32 slot = readScriptFlagValue();
1881 	static const uint32 VOICE_B_SLOT = 30;
1882 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1883 	_vm->setVoice(slot, VOICE_B_SLOT, voiceLineH);
1884 }
1885 
O_SETVOICEC()1886 void Interpreter::O_SETVOICEC() {
1887 	int32 slot = readScriptFlagValue();
1888 	static const uint32 VOICE_C_SLOT = 31;
1889 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1890 	_vm->setVoice(slot, VOICE_C_SLOT, voiceLineH);
1891 }
1892 
O_SETVOICED()1893 void Interpreter::O_SETVOICED() {
1894 	int32 slot = readScriptFlagValue();
1895 	static const uint32 VOICE_D_SLOT = 32;
1896 	uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
1897 	_vm->setVoice(slot, VOICE_D_SLOT, voiceLineH);
1898 }
1899 
O_VIEWFLCLOOP()1900 void Interpreter::O_VIEWFLCLOOP() {
1901 	int32 animId = readScriptFlagValue();
1902 	_vm->loadAnim(animId, true);
1903 	debugInterpreter("O_VIEWFLCLOOP animId %d", animId);
1904 }
1905 
1906 // Not used in script
O_FLCSPEED()1907 void Interpreter::O_FLCSPEED() {
1908 	int32 speed = readScriptFlagValue();
1909 	error("O_FLCSPEED speed %d", speed);
1910 }
1911 
O_OPENINVENTORY()1912 void Interpreter::O_OPENINVENTORY() {
1913 	_vm->_showInventoryFlag = true;
1914 	_opcodeNF = 1;
1915 	debugInterpreter("O_OPENINVENTORY");
1916 }
1917 
O_KRZYWA()1918 void Interpreter::O_KRZYWA() {
1919 	_vm->makeCurve();
1920 	debugInterpreter("O_KRZYWA");
1921 }
1922 
O_GETKRZYWA()1923 void Interpreter::O_GETKRZYWA() {
1924 	_vm->getCurve();
1925 	debugInterpreter("O_GETKRZYWA");
1926 }
1927 
O_GETMOB()1928 void Interpreter::O_GETMOB() {
1929 	Flags::Id flagId = readScriptFlagId();
1930 	int32 posX = readScriptFlagValue();
1931 	int32 posY = readScriptFlagValue();
1932 	int mobNumber = _vm->getMob(_vm->_mobList, true, posX, posY);
1933 	_flags->setFlagValue(flagId, mobNumber + 1);
1934 	debugInterpreter("O_GETMOB flagId %d, posX %d, posY %d", flagId, posX, posY);
1935 }
1936 
1937 // Not used in game
O_INPUTLINE()1938 void Interpreter::O_INPUTLINE() {
1939 	error("O_INPUTLINE");
1940 }
1941 
1942 // Not used in script
O_BREAK_POINT()1943 void Interpreter::O_BREAK_POINT() {
1944 	error("O_BREAK_POINT");
1945 }
1946 
1947 Interpreter::OpcodeFunc Interpreter::_opcodes[kNumOpcodes] = {
1948 	&Interpreter::O_WAITFOREVER,
1949 	&Interpreter::O_BLACKPALETTE,
1950 	&Interpreter::O_SETUPPALETTE,
1951 	&Interpreter::O_INITROOM,
1952 	&Interpreter::O_SETSAMPLE,
1953 	&Interpreter::O_FREESAMPLE,
1954 	&Interpreter::O_PLAYSAMPLE,
1955 	&Interpreter::O_PUTOBJECT,
1956 	&Interpreter::O_REMOBJECT,
1957 	&Interpreter::O_SHOWANIM,
1958 	&Interpreter::O_CHECKANIMEND,
1959 	&Interpreter::O_FREEANIM,
1960 	&Interpreter::O_CHECKANIMFRAME,
1961 	&Interpreter::O_PUTBACKANIM,
1962 	&Interpreter::O_REMBACKANIM,
1963 	&Interpreter::O_CHECKBACKANIMFRAME,
1964 	&Interpreter::O_FREEALLSAMPLES,
1965 	&Interpreter::O_SETMUSIC,
1966 	&Interpreter::O_STOPMUSIC,
1967 	&Interpreter::O__WAIT,
1968 	&Interpreter::O_UPDATEOFF,
1969 	&Interpreter::O_UPDATEON,
1970 	&Interpreter::O_UPDATE ,
1971 	&Interpreter::O_CLS,
1972 	&Interpreter::O__CALL,
1973 	&Interpreter::O_RETURN,
1974 	&Interpreter::O_GO,
1975 	&Interpreter::O_BACKANIMUPDATEOFF,
1976 	&Interpreter::O_BACKANIMUPDATEON,
1977 	&Interpreter::O_CHANGECURSOR,
1978 	&Interpreter::O_CHANGEANIMTYPE,
1979 	&Interpreter::O__SETFLAG,
1980 	&Interpreter::O_COMPARE,
1981 	&Interpreter::O_JUMPZ,
1982 	&Interpreter::O_JUMPNZ,
1983 	&Interpreter::O_EXIT,
1984 	&Interpreter::O_ADDFLAG,
1985 	&Interpreter::O_TALKANIM,
1986 	&Interpreter::O_SUBFLAG,
1987 	&Interpreter::O_SETSTRING,
1988 	&Interpreter::O_ANDFLAG,
1989 	&Interpreter::O_GETMOBDATA,
1990 	&Interpreter::O_ORFLAG,
1991 	&Interpreter::O_SETMOBDATA,
1992 	&Interpreter::O_XORFLAG,
1993 	&Interpreter::O_GETMOBTEXT,
1994 	&Interpreter::O_MOVEHERO,
1995 	&Interpreter::O_WALKHERO,
1996 	&Interpreter::O_SETHERO,
1997 	&Interpreter::O_HEROOFF,
1998 	&Interpreter::O_HEROON,
1999 	&Interpreter::O_CLSTEXT,
2000 	&Interpreter::O_CALLTABLE,
2001 	&Interpreter::O_CHANGEMOB,
2002 	&Interpreter::O_ADDINV,
2003 	&Interpreter::O_REMINV,
2004 	&Interpreter::O_REPINV,
2005 	&Interpreter::O_OBSOLETE_GETACTION,
2006 	&Interpreter::O_ADDWALKAREA,
2007 	&Interpreter::O_REMWALKAREA,
2008 	&Interpreter::O_RESTOREWALKAREA,
2009 	&Interpreter::O_WAITFRAME,
2010 	&Interpreter::O_SETFRAME,
2011 	&Interpreter::O_RUNACTION,
2012 	&Interpreter::O_COMPAREHI,
2013 	&Interpreter::O_COMPARELO,
2014 	&Interpreter::O_PRELOADSET,
2015 	&Interpreter::O_FREEPRELOAD,
2016 	&Interpreter::O_CHECKINV,
2017 	&Interpreter::O_TALKHERO,
2018 	&Interpreter::O_WAITTEXT,
2019 	&Interpreter::O_SETHEROANIM,
2020 	&Interpreter::O_WAITHEROANIM,
2021 	&Interpreter::O_GETHERODATA,
2022 	&Interpreter::O_GETMOUSEBUTTON,
2023 	&Interpreter::O_CHANGEFRAMES,
2024 	&Interpreter::O_CHANGEBACKFRAMES,
2025 	&Interpreter::O_GETBACKANIMDATA,
2026 	&Interpreter::O_GETANIMDATA,
2027 	&Interpreter::O_SETBGCODE,
2028 	&Interpreter::O_SETBACKFRAME,
2029 	&Interpreter::O_GETRND,
2030 	&Interpreter::O_TALKBACKANIM,
2031 	&Interpreter::O_LOADPATH,
2032 	&Interpreter::O_GETCHAR,
2033 	&Interpreter::O_SETDFLAG,
2034 	&Interpreter::O_CALLDFLAG,
2035 	&Interpreter::O_PRINTAT,
2036 	&Interpreter::O_ZOOMIN,
2037 	&Interpreter::O_ZOOMOUT,
2038 	&Interpreter::O_SETSTRINGOFFSET,
2039 	&Interpreter::O_GETOBJDATA,
2040 	&Interpreter::O_SETOBJDATA,
2041 	&Interpreter::O_SWAPOBJECTS,
2042 	&Interpreter::O_CHANGEHEROSET,
2043 	&Interpreter::O_ADDSTRING,
2044 	&Interpreter::O_SUBSTRING,
2045 	&Interpreter::O_INITDIALOG,
2046 	&Interpreter::O_ENABLEDIALOGOPT,
2047 	&Interpreter::O_DISABLEDIALOGOPT,
2048 	&Interpreter::O_SHOWDIALOGBOX,
2049 	&Interpreter::O_STOPSAMPLE,
2050 	&Interpreter::O_BACKANIMRANGE,
2051 	&Interpreter::O_CLEARPATH,
2052 	&Interpreter::O_SETPATH,
2053 	&Interpreter::O_GETHEROX,
2054 	&Interpreter::O_GETHEROY,
2055 	&Interpreter::O_GETHEROD,
2056 	&Interpreter::O_PUSHSTRING,
2057 	&Interpreter::O_POPSTRING,
2058 	&Interpreter::O_SETFGCODE,
2059 	&Interpreter::O_STOPHERO,
2060 	&Interpreter::O_ANIMUPDATEOFF,
2061 	&Interpreter::O_ANIMUPDATEON,
2062 	&Interpreter::O_FREECURSOR,
2063 	&Interpreter::O_ADDINVQUIET,
2064 	&Interpreter::O_RUNHERO,
2065 	&Interpreter::O_SETBACKANIMDATA,
2066 	&Interpreter::O_VIEWFLC,
2067 	&Interpreter::O_CHECKFLCFRAME,
2068 	&Interpreter::O_CHECKFLCEND,
2069 	&Interpreter::O_FREEFLC,
2070 	&Interpreter::O_TALKHEROSTOP,
2071 	&Interpreter::O_HEROCOLOR,
2072 	&Interpreter::O_GRABMAPA,
2073 	&Interpreter::O_ENABLENAK,
2074 	&Interpreter::O_DISABLENAK,
2075 	&Interpreter::O_GETMOBNAME,
2076 	&Interpreter::O_SWAPINVENTORY,
2077 	&Interpreter::O_CLEARINVENTORY,
2078 	&Interpreter::O_SKIPTEXT,
2079 	&Interpreter::O_SETVOICEH,
2080 	&Interpreter::O_SETVOICEA,
2081 	&Interpreter::O_SETVOICEB,
2082 	&Interpreter::O_SETVOICEC,
2083 	&Interpreter::O_VIEWFLCLOOP,
2084 	&Interpreter::O_FLCSPEED,
2085 	&Interpreter::O_OPENINVENTORY,
2086 	&Interpreter::O_KRZYWA,
2087 	&Interpreter::O_GETKRZYWA,
2088 	&Interpreter::O_GETMOB,
2089 	&Interpreter::O_INPUTLINE,
2090 	&Interpreter::O_SETVOICED,
2091 	&Interpreter::O_BREAK_POINT,
2092 };
2093 
2094 } // End of namespace Prince
2095