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