aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/script
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/script')
-rw-r--r--engines/kyra/script/script.cpp445
-rw-r--r--engines/kyra/script/script.h159
-rw-r--r--engines/kyra/script/script_eob.cpp1622
-rw-r--r--engines/kyra/script/script_eob.h131
-rw-r--r--engines/kyra/script/script_hof.cpp1727
-rw-r--r--engines/kyra/script/script_lok.cpp1962
-rw-r--r--engines/kyra/script/script_lol.cpp3051
-rw-r--r--engines/kyra/script/script_mr.cpp1377
-rw-r--r--engines/kyra/script/script_tim.cpp1101
-rw-r--r--engines/kyra/script/script_tim.h306
-rw-r--r--engines/kyra/script/script_v1.cpp125
-rw-r--r--engines/kyra/script/script_v2.cpp342
12 files changed, 12348 insertions, 0 deletions
diff --git a/engines/kyra/script/script.cpp b/engines/kyra/script/script.cpp
new file mode 100644
index 0000000000..27c9643034
--- /dev/null
+++ b/engines/kyra/script/script.cpp
@@ -0,0 +1,445 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/script/script.h"
+#include "kyra/kyra_v1.h"
+#include "kyra/resource/resource.h"
+
+#include "common/endian.h"
+
+namespace Kyra {
+EMCInterpreter::EMCInterpreter(KyraEngine_v1 *vm) : _vm(vm), _scriptData(0), _filename(0) {
+#define OPCODE(x) { &EMCInterpreter::x, #x }
+ static const OpcodeEntry opcodes[] = {
+ // 0x00
+ OPCODE(op_jmp),
+ OPCODE(op_setRetValue),
+ OPCODE(op_pushRetOrPos),
+ OPCODE(op_push),
+ // 0x04
+ OPCODE(op_push),
+ OPCODE(op_pushReg),
+ OPCODE(op_pushBPNeg),
+ OPCODE(op_pushBPAdd),
+ // 0x08
+ OPCODE(op_popRetOrPos),
+ OPCODE(op_popReg),
+ OPCODE(op_popBPNeg),
+ OPCODE(op_popBPAdd),
+ // 0x0C
+ OPCODE(op_addSP),
+ OPCODE(op_subSP),
+ OPCODE(op_sysCall),
+ OPCODE(op_ifNotJmp),
+ // 0x10
+ OPCODE(op_negate),
+ OPCODE(op_eval),
+ OPCODE(op_setRetAndJmp)
+ };
+ _opcodes = opcodes;
+#undef OPCODE
+}
+
+bool EMCInterpreter::callback(Common::IFFChunk &chunk) {
+ switch (chunk._type) {
+ case MKTAG('T','E','X','T'):
+ _scriptData->text = new byte[chunk._size];
+ assert(_scriptData->text);
+ if (chunk._stream->read(_scriptData->text, chunk._size) != chunk._size)
+ error("Couldn't read TEXT chunk from file '%s'", _filename);
+ break;
+
+ case MKTAG('O','R','D','R'):
+ _scriptData->ordr = new uint16[chunk._size >> 1];
+ assert(_scriptData->ordr);
+ if (chunk._stream->read(_scriptData->ordr, chunk._size) != chunk._size)
+ error("Couldn't read ORDR chunk from file '%s'", _filename);
+
+ for (int i = (chunk._size >> 1) - 1; i >= 0; --i)
+ _scriptData->ordr[i] = READ_BE_UINT16(&_scriptData->ordr[i]);
+ break;
+
+ case MKTAG('D','A','T','A'):
+ _scriptData->data = new uint16[chunk._size >> 1];
+ assert(_scriptData->data);
+ if (chunk._stream->read(_scriptData->data, chunk._size) != chunk._size)
+ error("Couldn't read DATA chunk from file '%s'", _filename);
+
+ for (int i = (chunk._size >> 1) - 1; i >= 0; --i)
+ _scriptData->data[i] = READ_BE_UINT16(&_scriptData->data[i]);
+ break;
+
+ default:
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._type), chunk._size, _filename);
+ }
+
+ return false;
+}
+
+bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array<const Opcode *> *opcodes) {
+ Common::SeekableReadStream *stream = _vm->resource()->createReadStream(filename);
+ if (!stream) {
+ error("Couldn't open script file '%s'", filename);
+ return false; // for compilers that don't support NORETURN
+ }
+
+ memset(scriptData, 0, sizeof(EMCData));
+
+ _scriptData = scriptData;
+ _filename = filename;
+
+ IFFParser iff(*stream);
+ Common::Functor1Mem< Common::IFFChunk &, bool, EMCInterpreter > c(this, &EMCInterpreter::callback);
+ iff.parse(c);
+
+ if (!_scriptData->ordr)
+ error("No ORDR chunk found in file: '%s'", filename);
+
+ if (!_scriptData->data)
+ error("No DATA chunk found in file: '%s'", filename);
+
+ if (stream->err())
+ error("Read error while parsing file '%s'", filename);
+
+ delete stream;
+
+ _scriptData->sysFuncs = opcodes;
+
+ Common::strlcpy(_scriptData->filename, filename, 13);
+
+ _scriptData = 0;
+ _filename = 0;
+
+ return true;
+}
+
+void EMCInterpreter::unload(EMCData *data) {
+ if (!data)
+ return;
+
+ delete[] data->text;
+ delete[] data->ordr;
+ delete[] data->data;
+
+ data->text = 0;
+ data->ordr = data->data = 0;
+}
+
+void EMCInterpreter::init(EMCState *scriptStat, const EMCData *data) {
+ scriptStat->dataPtr = data;
+ scriptStat->ip = 0;
+ scriptStat->stack[EMCState::kStackLastEntry] = 0;
+ scriptStat->bp = EMCState::kStackSize+1;
+ scriptStat->sp = EMCState::kStackLastEntry;
+}
+
+bool EMCInterpreter::start(EMCState *script, int function) {
+ if (!script->dataPtr)
+ return false;
+
+ uint16 functionOffset = script->dataPtr->ordr[function];
+ if (functionOffset == 0xFFFF)
+ return false;
+
+ if (_vm->game() == GI_KYRA1) {
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+ script->ip = &script->dataPtr->data[functionOffset+1];
+ else
+ script->ip = &script->dataPtr->data[functionOffset];
+ } else {
+ script->ip = &script->dataPtr->data[functionOffset+1];
+ }
+
+ return true;
+}
+
+bool EMCInterpreter::isValid(EMCState *script) {
+ if (!script->ip || !script->dataPtr || _vm->shouldQuit())
+ return false;
+ return true;
+}
+
+bool EMCInterpreter::run(EMCState *script) {
+ _parameter = 0;
+
+ if (!script->ip)
+ return false;
+
+ // Should be no Problem at all to cast to uint32 here, since that's the biggest ptrdiff the original
+ // would allow, of course that's not realistic to happen to be somewhere near the limit of uint32 anyway.
+ const uint32 instOffset = (uint32)((const byte *)script->ip - (const byte *)script->dataPtr->data);
+ int16 code = *script->ip++;
+ int16 opcode = (code >> 8) & 0x1F;
+
+ if (code & 0x8000) {
+ opcode = 0;
+ _parameter = code & 0x7FFF;
+ } else if (code & 0x4000) {
+ _parameter = (int8)(code);
+ } else if (code & 0x2000) {
+ _parameter = *script->ip++;
+ } else {
+ _parameter = 0;
+ }
+
+ if (opcode > 18) {
+ error("Unknown script opcode: %d in file '%s' at offset 0x%.08X", opcode, script->dataPtr->filename, instOffset);
+ } else {
+ debugC(5, kDebugLevelScript, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset, _opcodes[opcode].desc, _parameter, (uint)_parameter);
+ (this->*(_opcodes[opcode].proc))(script);
+ }
+
+ return (script->ip != 0);
+}
+
+#pragma mark -
+#pragma mark - Command implementations
+#pragma mark -
+
+void EMCInterpreter::op_jmp(EMCState *script) {
+ script->ip = script->dataPtr->data + _parameter;
+}
+
+void EMCInterpreter::op_setRetValue(EMCState *script) {
+ script->retValue = _parameter;
+}
+
+void EMCInterpreter::op_pushRetOrPos(EMCState *script) {
+ switch (_parameter) {
+ case 0:
+ script->stack[--script->sp] = script->retValue;
+ break;
+
+ case 1:
+ script->stack[--script->sp] = script->ip - script->dataPtr->data + 1;
+ script->stack[--script->sp] = script->bp;
+ script->bp = script->sp + 2;
+ break;
+
+ default:
+ script->ip = 0;
+ }
+}
+
+void EMCInterpreter::op_push(EMCState *script) {
+ script->stack[--script->sp] = _parameter;
+}
+
+void EMCInterpreter::op_pushReg(EMCState *script) {
+ script->stack[--script->sp] = script->regs[_parameter];
+}
+
+void EMCInterpreter::op_pushBPNeg(EMCState *script) {
+ script->stack[--script->sp] = script->stack[(-(int32)(_parameter + 2)) + script->bp];
+}
+
+void EMCInterpreter::op_pushBPAdd(EMCState *script) {
+ script->stack[--script->sp] = script->stack[(_parameter - 1) + script->bp];
+}
+
+void EMCInterpreter::op_popRetOrPos(EMCState *script) {
+ switch (_parameter) {
+ case 0:
+ script->retValue = script->stack[script->sp++];
+ break;
+
+ case 1:
+ if (script->sp >= EMCState::kStackLastEntry) {
+ script->ip = 0;
+ } else {
+ script->bp = script->stack[script->sp++];
+ script->ip = script->dataPtr->data + script->stack[script->sp++];
+ }
+ break;
+
+ default:
+ script->ip = 0;
+ }
+}
+
+void EMCInterpreter::op_popReg(EMCState *script) {
+ script->regs[_parameter] = script->stack[script->sp++];
+}
+
+void EMCInterpreter::op_popBPNeg(EMCState *script) {
+ script->stack[(-(int32)(_parameter + 2)) + script->bp] = script->stack[script->sp++];
+}
+
+void EMCInterpreter::op_popBPAdd(EMCState *script) {
+ script->stack[(_parameter - 1) + script->bp] = script->stack[script->sp++];
+}
+
+void EMCInterpreter::op_addSP(EMCState *script) {
+ script->sp += _parameter;
+}
+
+void EMCInterpreter::op_subSP(EMCState *script) {
+ script->sp -= _parameter;
+}
+
+void EMCInterpreter::op_sysCall(EMCState *script) {
+ const uint8 id = _parameter;
+
+ assert(script->dataPtr->sysFuncs);
+ assert(id < script->dataPtr->sysFuncs->size());
+
+ if ((*script->dataPtr->sysFuncs)[id] && ((*script->dataPtr->sysFuncs)[id])->isValid()) {
+ script->retValue = (*(*script->dataPtr->sysFuncs)[id])(script);
+ } else {
+ script->retValue = 0;
+ warning("Unimplemented system call 0x%.02X/%d used in file '%s'", id, id, script->dataPtr->filename);
+ }
+}
+
+void EMCInterpreter::op_ifNotJmp(EMCState *script) {
+ if (!script->stack[script->sp++]) {
+ _parameter &= 0x7FFF;
+ script->ip = script->dataPtr->data + _parameter;
+ }
+}
+
+void EMCInterpreter::op_negate(EMCState *script) {
+ int16 value = script->stack[script->sp];
+ switch (_parameter) {
+ case 0:
+ if (!value)
+ script->stack[script->sp] = 1;
+ else
+ script->stack[script->sp] = 0;
+ break;
+
+ case 1:
+ script->stack[script->sp] = -value;
+ break;
+
+ case 2:
+ script->stack[script->sp] = ~value;
+ break;
+
+ default:
+ warning("Unknown negation func: %d", _parameter);
+ script->ip = 0;
+ }
+}
+
+void EMCInterpreter::op_eval(EMCState *script) {
+ int16 ret = 0;
+ bool error = false;
+
+ int16 val1 = script->stack[script->sp++];
+ int16 val2 = script->stack[script->sp++];
+
+ switch (_parameter) {
+ case 0:
+ ret = (val2 && val1) ? 1 : 0;
+ break;
+
+ case 1:
+ ret = (val2 || val1) ? 1 : 0;
+ break;
+
+ case 2:
+ ret = (val1 == val2) ? 1 : 0;
+ break;
+
+ case 3:
+ ret = (val1 != val2) ? 1 : 0;
+ break;
+
+ case 4:
+ ret = (val1 > val2) ? 1 : 0;
+ break;
+
+ case 5:
+ ret = (val1 >= val2) ? 1 : 0;
+ break;
+
+ case 6:
+ ret = (val1 < val2) ? 1 : 0;
+ break;
+
+ case 7:
+ ret = (val1 <= val2) ? 1 : 0;
+ break;
+
+ case 8:
+ ret = val1 + val2;
+ break;
+
+ case 9:
+ ret = val2 - val1;
+ break;
+
+ case 10:
+ ret = val1 * val2;
+ break;
+
+ case 11:
+ ret = val2 / val1;
+ break;
+
+ case 12:
+ ret = val2 >> val1;
+ break;
+
+ case 13:
+ ret = val2 << val1;
+ break;
+
+ case 14:
+ ret = val1 & val2;
+ break;
+
+ case 15:
+ ret = val1 | val2;
+ break;
+
+ case 16:
+ ret = val2 % val1;
+ break;
+
+ case 17:
+ ret = val1 ^ val2;
+ break;
+
+ default:
+ warning("Unknown evaluate func: %d", _parameter);
+ error = true;
+ }
+
+ if (error)
+ script->ip = 0;
+ else
+ script->stack[--script->sp] = ret;
+}
+
+void EMCInterpreter::op_setRetAndJmp(EMCState *script) {
+ if (script->sp >= EMCState::kStackLastEntry) {
+ script->ip = 0;
+ } else {
+ script->retValue = script->stack[script->sp++];
+ uint16 temp = script->stack[script->sp++];
+ script->stack[EMCState::kStackLastEntry] = 0;
+ script->ip = &script->dataPtr->data[temp];
+ }
+}
+} // End of namespace Kyra
diff --git a/engines/kyra/script/script.h b/engines/kyra/script/script.h
new file mode 100644
index 0000000000..12a44b0a03
--- /dev/null
+++ b/engines/kyra/script/script.h
@@ -0,0 +1,159 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KYRA_SCRIPT_H
+#define KYRA_SCRIPT_H
+
+#include "common/stream.h"
+#include "common/array.h"
+#include "common/func.h"
+#include "common/iff_container.h"
+
+namespace Kyra {
+
+struct EMCState;
+typedef Common::Functor1<EMCState *, int> Opcode;
+
+struct EMCData {
+ char filename[13];
+
+ byte *text;
+ uint16 *data;
+ uint16 *ordr;
+ uint16 dataSize;
+
+ const Common::Array<const Opcode *> *sysFuncs;
+};
+
+struct EMCState {
+ enum {
+ kStackSize = 100,
+ kStackLastEntry = kStackSize - 1
+ };
+
+ const uint16 *ip;
+ const EMCData *dataPtr;
+ int16 retValue;
+ uint16 bp;
+ uint16 sp;
+ int16 regs[30]; // VM registers
+ int16 stack[kStackSize]; // VM stack
+};
+
+#define stackPos(x) (script->stack[script->sp+x])
+#define stackPosString(x) ((const char *)&script->dataPtr->text[READ_BE_UINT16(&script->dataPtr->text[stackPos(x)<<1])])
+
+class Resource;
+class KyraEngine_v1;
+
+class IFFParser : public Common::IFFParser {
+public:
+ IFFParser(Common::ReadStream &input) : Common::IFFParser(&input) {
+ // It seems Westwood missunderstood the 'size' field of the FORM chunk.
+ //
+ // For EMC scripts (type EMC2) it's filesize instead of filesize - 8,
+ // means accidently including the 8 bytes used by the chunk header for the FORM
+ // chunk.
+ //
+ // For TIM scripts (type AVFS) it's filesize - 12 instead of filesize - 8,
+ // means it will not include the size of the 'type' field in the FORM chunk,
+ // instead of only not including the chunk header size.
+ //
+ // Both lead to some problems in our IFF parser, either reading after the end
+ // of file or producing a "Chunk overread" error message. To work around this
+ // we need to adjust the size field properly.
+
+ // Fix for certain Russian fan translations:
+ // Westwood's original code completely ignores the FORM chunk and its size
+ // setting. After opening a TIM or EMC file they just check whether the FORM
+ // chunk exists (as a kind of file type verification) and then immediately seek
+ // behind the FORM chunk.
+ // This means that their parser is immune to weird fan translation scripts
+ // where the file size doesn't match the form chunk size. In our implemetation
+ // this would produce "Chunk overread" errors.
+ // Westwood also always pads all chunk sizes to 2 byte alignment after reading
+ // them from the file (not with FORM though, since they completely ignore it).
+ // This seems to do the trick for our FORM chunk size issue with the Russian
+ // fan translations. Another method which I have tried and which seems to work
+ // well would be simply setting _formChunk.size to the file size (-12 for TIM).
+
+ _formChunk.size = (_formChunk.size + 1) & ~1;
+
+ if (_formType == MKTAG('E','M','C','2'))
+ _formChunk.size -= 8;
+ else if (_formType == MKTAG('A','V','F','S'))
+ _formChunk.size += 4;
+ }
+};
+
+class EMCInterpreter {
+public:
+ EMCInterpreter(KyraEngine_v1 *vm);
+
+ bool load(const char *filename, EMCData *data, const Common::Array<const Opcode *> *opcodes);
+ void unload(EMCData *data);
+
+ void init(EMCState *scriptState, const EMCData *data);
+ bool start(EMCState *script, int function);
+
+ bool isValid(EMCState *script);
+
+ bool run(EMCState *script);
+protected:
+ KyraEngine_v1 *_vm;
+ int16 _parameter;
+
+ const char *_filename;
+ EMCData *_scriptData;
+
+ bool callback(Common::IFFChunk &chunk);
+
+ typedef void (EMCInterpreter::*OpcodeProc)(EMCState *);
+ struct OpcodeEntry {
+ OpcodeProc proc;
+ const char *desc;
+ };
+
+ const OpcodeEntry *_opcodes;
+private:
+ void op_jmp(EMCState *);
+ void op_setRetValue(EMCState *);
+ void op_pushRetOrPos(EMCState *);
+ void op_push(EMCState *);
+ void op_pushReg(EMCState *);
+ void op_pushBPNeg(EMCState *);
+ void op_pushBPAdd(EMCState *);
+ void op_popRetOrPos(EMCState *);
+ void op_popReg(EMCState *);
+ void op_popBPNeg(EMCState *);
+ void op_popBPAdd(EMCState *);
+ void op_addSP(EMCState *);
+ void op_subSP(EMCState *);
+ void op_sysCall(EMCState *);
+ void op_ifNotJmp(EMCState *);
+ void op_negate(EMCState *);
+ void op_eval(EMCState *);
+ void op_setRetAndJmp(EMCState *);
+};
+} // End of namespace Kyra
+
+#endif
diff --git a/engines/kyra/script/script_eob.cpp b/engines/kyra/script/script_eob.cpp
new file mode 100644
index 0000000000..709921deb9
--- /dev/null
+++ b/engines/kyra/script/script_eob.cpp
@@ -0,0 +1,1622 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/engine/eobcommon.h"
+#include "kyra/graphics/screen_eob.h"
+#include "kyra/script/script_eob.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void EoBCoreEngine::runLevelScript(int block, int flags) {
+ _inf->run(block, flags);
+}
+
+void EoBCoreEngine::setScriptFlags(uint32 flags) {
+ _inf->setFlags(flags);
+}
+
+void EoBCoreEngine::clearScriptFlags(uint32 flags) {
+ _inf->clearFlags(flags);
+}
+
+bool EoBCoreEngine::checkScriptFlags(uint32 flags) {
+ return _inf->checkFlags(flags);
+}
+
+const uint8 *EoBCoreEngine::initScriptTimers(const uint8 *pos) {
+ _scriptTimersCount = 0;
+
+ while (((int16)READ_LE_UINT16(pos)) != -1) {
+ _scriptTimers[_scriptTimersCount].func = READ_LE_UINT16(pos);
+ pos += 2;
+ uint16 ticks = READ_LE_UINT16(pos) * 18;
+ _scriptTimers[_scriptTimersCount].ticks = ticks;
+ pos += 2;
+ _scriptTimers[_scriptTimersCount++].next = _system->getMillis() + ticks * _tickLength;
+ }
+
+ return pos;
+}
+
+void EoBCoreEngine::updateScriptTimers() {
+ bool timerUpdate = false;
+ if ((_scriptTimersMode & 2) && _stepsUntilScriptCall && _stepCounter > _stepsUntilScriptCall) {
+ _inf->run(0, 0x20);
+ _stepCounter = 0;
+ timerUpdate = true;
+ }
+
+ if (_scriptTimersMode & 1) {
+ for (int i = 0; i < _scriptTimersCount; i++) {
+ if (_scriptTimers[i].next < _system->getMillis()) {
+ _inf->run(_scriptTimers[i].func, _flags.gameID == GI_EOB1 ? 0x20 : 0x80);
+ _scriptTimers[i].next = _system->getMillis() + _scriptTimers[i].ticks * _tickLength;
+ _sceneUpdateRequired = true;
+ timerUpdate = true;
+ }
+ }
+ }
+
+ if (timerUpdate)
+ updateScriptTimersExtra();
+}
+
+EoBInfProcessor::EoBInfProcessor(EoBCoreEngine *engine, Screen_EoB *screen) : _vm(engine), _screen(screen),
+ _commandMin(engine->game() == GI_EOB1 ? -27 : -31) {
+
+#define Opcode(x) _opcodes.push_back(new InfOpcode(new InfProc(this, &EoBInfProcessor::x), #x))
+#define OpcodeAlt(x) if (_vm->game() == GI_EOB1) { Opcode(x##_v1); } else { Opcode(x##_v2); }
+ Opcode(oeob_setWallType);
+ Opcode(oeob_toggleWallState);
+ Opcode(oeob_openDoor);
+ Opcode(oeob_closeDoor);
+ Opcode(oeob_replaceMonster);
+ Opcode(oeob_movePartyOrObject);
+ Opcode(oeob_moveInventoryItemToBlock);
+ OpcodeAlt(oeob_printMessage);
+ Opcode(oeob_setFlags);
+ Opcode(oeob_playSoundEffect);
+ Opcode(oeob_removeFlags);
+ Opcode(oeob_modifyCharacterHitPoints);
+ Opcode(oeob_calcAndInflictCharacterDamage);
+ Opcode(oeob_jump);
+ Opcode(oeob_end);
+ Opcode(oeob_returnFromSubroutine);
+ Opcode(oeob_callSubroutine);
+ OpcodeAlt(oeob_eval);
+ Opcode(oeob_deleteItem);
+ Opcode(oeob_loadNewLevelOrMonsters);
+ Opcode(oeob_increasePartyExperience);
+ OpcodeAlt(oeob_createItem);
+ Opcode(oeob_launchObject);
+ Opcode(oeob_changeDirection);
+ Opcode(oeob_identifyItems);
+ Opcode(oeob_sequence);
+ Opcode(oeob_delay);
+ Opcode(oeob_drawScene);
+ Opcode(oeob_dialogue);
+ Opcode(oeob_specialEvent);
+#undef Opcode
+#undef OpcodeAlt
+
+ _scriptData = 0;
+ _scriptSize = 0;
+
+ _abortScript = 0;
+ _abortAfterSubroutine = 0;
+ _dlgResult = 0;
+ _preventRest = 0;
+
+ _lastScriptFunc = 0;
+ _lastScriptFlags = 0;
+
+ _subroutineStack = new int8*[10];
+ memset(_subroutineStack, 0, 10 * sizeof(int8 *));
+ _subroutineStackPos = 0;
+
+ _flagTable = new uint32[18];
+ memset(_flagTable, 0, 18 * sizeof(uint32));
+
+ _stack = new int16[30];
+ memset(_stack, 0, 30 * sizeof(int16));
+ _stackIndex = 0;
+
+ _activeCharacter = -1;
+}
+
+EoBInfProcessor::~EoBInfProcessor() {
+ delete[] _subroutineStack;
+ delete[] _flagTable;
+ delete[] _stack;
+ delete[] _scriptData;
+
+ for (Common::Array<const InfOpcode *>::const_iterator a = _opcodes.begin(); a != _opcodes.end(); ++a)
+ delete *a;
+
+ _opcodes.clear();
+}
+
+void EoBInfProcessor::loadData(const uint8 *data, uint32 dataSize) {
+ delete[] _scriptData;
+ _scriptSize = dataSize;
+ _scriptData = new int8[_scriptSize];
+ memcpy(_scriptData, data, _scriptSize);
+}
+
+void EoBInfProcessor::run(int func, int flags) {
+ int o = _vm->_levelBlockProperties[func].assignedObjects;
+ if (!o)
+ return;
+
+ uint16 f = _vm->_levelBlockProperties[func].flags;
+
+ uint16 subFlags = ((f & 0xFFF8) >> 3) | 0xE0;
+ if (!(flags & subFlags))
+ return;
+
+ _abortScript = 0;
+ _abortAfterSubroutine = 0;
+ _dlgResult = 0;
+ _activeCharacter = -1;
+
+ _lastScriptFunc = func;
+ _lastScriptFlags = flags;
+
+ int8 *pos = (int8 *)(_scriptData + o);
+
+ do {
+ int8 cmd = *pos++;
+ if (cmd <= _commandMin || cmd >= 0)
+ continue;
+ debugC(3, kDebugLevelScript, "[0x%.04X] EoBInfProcessor::%s()", (uint32)(pos - _scriptData), _opcodes[-(cmd + 1)]->desc.c_str());
+ pos += (*_opcodes[-(cmd + 1)]->proc)(pos);
+ } while (!_abortScript && !_abortAfterSubroutine);
+}
+
+void EoBInfProcessor::setFlags(uint32 flags) {
+ _flagTable[17] |= flags;
+}
+
+void EoBInfProcessor::clearFlags(uint32 flags) {
+ _flagTable[17] &= ~flags;
+}
+
+bool EoBInfProcessor::checkFlags(uint32 flags) const {
+ return ((_flagTable[17] & flags) == flags) ? true : false;
+}
+
+bool EoBInfProcessor::preventRest() const {
+ return _preventRest ? true : false;
+}
+
+void EoBInfProcessor::loadState(Common::SeekableSubReadStreamEndian &in, bool origFile) {
+ _preventRest = (_vm->game() == GI_EOB1 && origFile) ? 0 : in.readByte();
+ int numFlags = (_vm->game() == GI_EOB1 && origFile) ? 12 : 18;
+ for (int i = 0; i < numFlags; i++)
+ _flagTable[i] = in.readUint32();
+ if (_vm->game() == GI_EOB1 && origFile)
+ setFlags(in.readUint32());
+}
+
+void EoBInfProcessor::saveState(Common::OutSaveFile *out, bool origFile) {
+ if (_vm->game() == GI_EOB2 || !origFile)
+ out->writeByte(_preventRest);
+ int numFlags = (_vm->game() == GI_EOB1 && origFile) ? 12 : 18;
+ for (int i = 0; i < numFlags; i++) {
+ if (origFile)
+ out->writeUint32LE(_flagTable[i]);
+ else
+ out->writeUint32BE(_flagTable[i]);
+ }
+ if (_vm->game() == GI_EOB1 && origFile)
+ out->writeUint32LE(_flagTable[17]);
+}
+
+void EoBInfProcessor::reset() {
+ _preventRest = 0;
+ memset(_flagTable, 0, 18 * sizeof(uint32));
+}
+
+const char *EoBInfProcessor::getString(uint16 index) {
+ if (index == 0xFFFF)
+ return 0;
+
+ int8 *res = _scriptData + READ_LE_UINT16(_scriptData);
+
+ while (index) {
+ if (*res++)
+ continue;
+ index--;
+ }
+
+ return (const char *)res;
+}
+
+int EoBInfProcessor::oeob_setWallType(int8 *data) {
+ int8 *pos = data;
+
+ uint16 block = 0;
+ int8 dir = 0;
+
+ switch (*pos++) {
+ case -23:
+ block = READ_LE_UINT16(pos);
+ pos += 2;
+ dir = *pos++;
+ _vm->_levelBlockProperties[block].walls[dir] = *pos++;
+ _vm->checkSceneUpdateNeed(block);
+ break;
+
+ case -19:
+ _vm->_currentDirection = *pos++;
+ break;
+
+ case -9:
+ block = READ_LE_UINT16(pos);
+ pos += 2;
+ dir = *pos++;
+ memset(_vm->_levelBlockProperties[block].walls, dir, 4 * sizeof(uint8));
+ _vm->checkSceneUpdateNeed(block);
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_toggleWallState(int8 *data) {
+ int8 *pos = data;
+
+ uint16 block = 0;
+ int8 dir = 0;
+ uint8 a = 0;
+ uint8 b = 0;
+
+ switch (*pos++) {
+ case -23:
+ block = READ_LE_UINT16(pos);
+ pos += 2;
+ dir = *pos++;
+ a = (uint8)*pos++;
+ b = (uint8)*pos++;
+ a = (_vm->_levelBlockProperties[block].walls[dir] == a) ? b : a;
+ _vm->_levelBlockProperties[block].walls[dir] = a;
+ _vm->checkSceneUpdateNeed(block);
+ break;
+
+ case -22:
+ _vm->processDoorSwitch(READ_LE_UINT16(pos), 0);
+ pos += 2;
+ break;
+
+ case -9:
+ block = READ_LE_UINT16(pos);
+ pos += 2;
+ a = (uint8)*pos++;
+ b = (uint8)*pos++;
+ a = (_vm->_levelBlockProperties[block].walls[dir] == a) ? b : a;
+ memset(_vm->_levelBlockProperties[block].walls, a, 4 * sizeof(uint8));
+ _vm->checkSceneUpdateNeed(block);
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_openDoor(int8 *data) {
+ int8 *pos = data;
+ _vm->openDoor(READ_LE_UINT16(pos));
+ pos += 2;
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_closeDoor(int8 *data) {
+ int8 *pos = data;
+ _vm->closeDoor(READ_LE_UINT16(pos));
+ pos += 2;
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_replaceMonster(int8 *data) {
+ int8 *pos = data;
+ _vm->replaceMonster(pos[1], READ_LE_UINT16(pos + 2), pos[4], pos[5], pos[6], pos[7], pos[8], pos[9], READ_LE_UINT16(pos + 10), READ_LE_UINT16(pos + 12));
+ pos += 14;
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_movePartyOrObject(int8 *data) {
+ int8 *pos = data;
+
+ int8 a = *pos++;
+ uint16 b = 0xFFFF;
+ uint16 c = 0;
+ uint16 d = 0;
+
+ if (_vm->game() == GI_EOB2 && a == -31) {
+ b = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ if (_vm->game() == GI_EOB1) {
+ if (a != -15) {
+ c = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+ d = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ if (_vm->game() == GI_EOB2 && a != -31 && a != -11) {
+ c = READ_LE_UINT16(pos);
+ pos += 2;
+ d = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ if (a == -13) {
+ // move monster from block c to block d
+ for (int i = 0; i < 30; i++) {
+ if (_vm->_monsters[i].block != c)
+ continue;
+ _vm->placeMonster(&_vm->_monsters[i], d, _vm->_monsters[i].pos);
+ }
+ debugC(5, kDebugLevelScript, " - move monsters on block '0x%.04X' to block '0x%.04X'", c, d);
+
+ } else if (a == -24) {
+ // move party to block d
+ int ba = _dlgResult;
+ int bb = _lastScriptFunc;
+ int bc = _lastScriptFlags;
+ int bd = _abortScript;
+ int be = _activeCharacter;
+ int bf = _subroutineStackPos;
+
+ _vm->moveParty(d);
+ debugC(5, kDebugLevelScript, " - move party to block '0x%.04X'", d);
+
+ _dlgResult = ba;
+ _lastScriptFunc = bb;
+ _lastScriptFlags = bc;
+ _abortScript = bd;
+ _activeCharacter = be;
+ if (!_abortAfterSubroutine)
+ _subroutineStackPos = bf;
+ _vm->_sceneDefaultUpdate = 0;
+
+ } else if ((a == -31 && _vm->game() == GI_EOB2) || a == -11) {
+ // move item
+ int8 e = _vm->_currentLevel;
+ int8 f = _vm->_currentLevel;
+
+ if (_vm->game() == GI_EOB2) {
+ e = (*pos++ == -21) ? _vm->_currentLevel : *pos++;
+ c = READ_LE_UINT16(pos);
+ pos += 2;
+ f = (*pos++ == -21) ? _vm->_currentLevel : *pos++;
+ d = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ if (e == _vm->_currentLevel) {
+ int i = _vm->countQueuedItems(_vm->_levelBlockProperties[c].drawObjects, -1, (int16)b, 0, 1);
+ while (i) {
+ int p = _vm->_items[i].pos;
+ _vm->getQueuedItem((Item *)&_vm->_levelBlockProperties[c].drawObjects, 0, i);
+ if (_vm->_currentLevel == f) {
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[d].drawObjects, d, i, p);
+ } else {
+ _vm->_items[i].level = f;
+ _vm->_items[i].block = d;
+ if (p < 8)
+ _vm->_items[i].pos = p & 3;
+ }
+ i = _vm->countQueuedItems(_vm->_levelBlockProperties[c].drawObjects, -1, (int16)b, 0, 1);
+ }
+
+ for (i = 0; i < 10; i++) {
+ if (_vm->_flyingObjects[i].enable != 1 || _vm->_flyingObjects[i].curBlock != c)
+ continue;
+ if (f == _vm->_currentLevel || _vm->game() == GI_EOB1)
+ _vm->_flyingObjects[i].curBlock = d;
+ else
+ _vm->_flyingObjects[i].enable = 0;
+ }
+
+ } else {
+ for (int i = 0; i < 600; i++) {
+ if (_vm->_items[i].level != e || _vm->_items[i].block != c)
+ continue;
+ _vm->_items[i].level = f;
+ _vm->_items[i].block = d;
+ }
+ }
+ debugC(5, kDebugLevelScript, " - move items from level '%d', block '0x%.04X' to level '%d', block '0x%.04X'", c, e, d, f);
+ }
+
+ _vm->_sceneUpdateRequired = true;
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_moveInventoryItemToBlock(int8 *data) {
+ int8 *pos = data;
+ int8 c = *pos++;
+ uint16 block = READ_LE_UINT16(pos);
+ pos += 2;
+ int8 p = *pos++;
+
+ if (c == -1)
+ c = _vm->rollDice(1, 6, -1);
+
+ while (!(_vm->_characters[c].flags & 1)) {
+ if (++c == 5)
+ c = 0;
+ }
+
+ if (_vm->_currentControlMode && (_vm->_updateCharNum == c))
+ return pos - data;
+
+ int slot = _vm->rollDice(1, 27, 0);
+ int itm = 0;
+ int i = 0;
+
+ for (; i < 27; i++) {
+ if ((!_vm->_currentControlMode && slot > 1) || slot == 16)
+ continue;
+
+ itm = _vm->_characters[c].inventory[slot];
+
+ if (!itm)
+ continue;
+
+ if (_vm->_dscItemShapeMap[_vm->_items[itm].icon] >= 15)
+ break;
+
+ if (++slot == 27)
+ slot = 0;
+ }
+
+ if (i < 27 && itm) {
+ _vm->_characters[c].inventory[slot] = 0;
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[block].drawObjects, block, itm, p);
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_printMessage_v1(int8 *data) {
+ static const char colorConfig[] = "\x6\x21\x2\x21";
+ char col[5];
+ int8 *pos = data;
+
+ strcpy(col, colorConfig);
+ const char *str = (const char *)pos;
+ pos += (strlen(str) + 1);
+
+ col[1] = *pos++;
+ col[3] = *pos++;
+ _vm->txt()->printMessage(col);
+ _vm->txt()->printMessage(str);
+
+ col[1] = _screen->_curDim->unk8;
+ col[3] = _screen->_curDim->unkA;
+ _vm->txt()->printMessage(col);
+ _vm->txt()->printMessage("\r");
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_printMessage_v2(int8 *data) {
+ int8 *pos = data;
+ uint16 str = READ_LE_UINT16(pos);
+ pos += 2;
+ uint8 col = (uint8)*pos;
+ pos += 2;
+
+ int c = 0;
+ if (_activeCharacter == -1) {
+ c = _vm->rollDice(1, 6, -1);
+ while (!_vm->testCharacter(c, 3))
+ c = (c + 1) % 6;
+ } else {
+ c = _activeCharacter;
+ }
+
+ _vm->txt()->printMessage(getString(str), col, _vm->_characters[c].name);
+ _vm->txt()->printMessage("\r");
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_setFlags(int8 *data) {
+ int8 *pos = data;
+ int8 b = 0;
+
+ switch (*pos++) {
+ case -47:
+ _preventRest = 0;
+ debugC(5, kDebugLevelScript, " - set preventRest to 0");
+ break;
+
+ case -28:
+ _dlgResult = 1;
+ debugC(5, kDebugLevelScript, " - set dlgResult to 1");
+ break;
+
+ case -17:
+ _flagTable[_vm->_currentLevel] |= (1 << (*pos++));
+ debugC(5, kDebugLevelScript, " - set level flag '%d' for current level (current level = '%d')", *(pos - 1), _vm->_currentLevel);
+ break;
+
+ case -16:
+ _flagTable[17] |= (1 << (*pos++));
+ debugC(5, kDebugLevelScript, " - set global flag '%d'", *(pos - 1));
+ break;
+
+ case -13:
+ b = *pos++;
+ _vm->_monsters[b].flags |= (1 << (*pos++));
+ _vm->_monsters[b].mode = 0;
+ debugC(5, kDebugLevelScript, " - set monster flag '%d' for monster '%d'", *(pos - 1), b);
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_playSoundEffect(int8 *data) {
+ int8 *pos = data;
+ uint16 block = READ_LE_UINT16(pos + 1);
+
+ if (block) {
+ _vm->snd_processEnvironmentalSoundEffect(pos[0], block);
+ } else {
+ _vm->snd_playSoundEffect(pos[0]);
+ }
+
+ pos += 3;
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_removeFlags(int8 *data) {
+ int8 *pos = data;
+ int8 a = *pos++;
+
+ switch (a) {
+ case -47:
+ _preventRest = 1;
+ debugC(5, kDebugLevelScript, " - set preventRest to 1");
+ break;
+
+ case -28:
+ _dlgResult = 0;
+ debugC(5, kDebugLevelScript, " - set dlgResult to 0");
+ break;
+
+ case -17:
+ _flagTable[_vm->_currentLevel] &= ~(1 << (*pos++));
+ debugC(5, kDebugLevelScript, " - clear level flag '%d' for current level (current level = '%d')", *(pos - 1), _vm->_currentLevel);
+ break;
+
+ case -16:
+ _flagTable[17] &= ~(1 << (*pos++));
+ debugC(5, kDebugLevelScript, " - clear global flag '%d'", *(pos - 1));
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_modifyCharacterHitPoints(int8 *data) {
+ int8 *pos = data;
+ int8 c = *pos++;
+ int8 p = *pos++;
+
+ if (c == -1) {
+ for (c = 0; c < 6; c++)
+ _vm->modifyCharacterHitpoints(c, p);
+ } else {
+ _vm->modifyCharacterHitpoints(c, p);
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_calcAndInflictCharacterDamage(int8 *data) {
+ int8 *pos = data;
+ int charIndex = *pos++;
+ int times = *pos++;
+ int itemOrPips = *pos++;
+ int useStrModifierOrBase = *pos++;
+
+ int flg = (charIndex == -1) ? 4 : 0;
+ int savingThrowType = 5;
+ int savingThrowEffect = 1;
+
+ if (_vm->game() == GI_EOB2) {
+ flg = *pos++;
+ savingThrowType = *pos++;
+ savingThrowEffect = *pos++;
+ } else if (!itemOrPips) {
+ useStrModifierOrBase = times;
+ times = 0;
+ }
+
+ if (charIndex == -1) {
+ for (int i = 0; i < 6; i++)
+ _vm->calcAndInflictCharacterDamage(i, times, itemOrPips, useStrModifierOrBase, flg, savingThrowType, savingThrowEffect);
+ } else {
+ _vm->calcAndInflictCharacterDamage(charIndex, times, itemOrPips, useStrModifierOrBase, flg, savingThrowType, savingThrowEffect);
+ }
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_jump(int8 *data) {
+ int8 *pos = data;
+ pos = _scriptData + READ_LE_UINT16(pos);
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_end(int8 *data) {
+ _abortScript = 1;
+ _subroutineStackPos = 0;
+ return 0;
+}
+
+int EoBInfProcessor::oeob_returnFromSubroutine(int8 *data) {
+ int8 *pos = data;
+
+ if (_subroutineStackPos)
+ pos = _subroutineStack[--_subroutineStackPos];
+ else
+ _abortScript = 1;
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_callSubroutine(int8 *data) {
+ int8 *pos = data;
+ uint16 offs = READ_LE_UINT16(pos);
+ assert(offs < _scriptSize);
+ pos += 2;
+
+ if (_subroutineStackPos < 10) {
+ _subroutineStack[_subroutineStackPos++] = pos;
+ pos = _scriptData + offs;
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_eval_v1(int8 *data) {
+ int8 *pos = data;
+ int8 cmd = *pos++;
+
+ int a = 0;
+ int b = 0;
+ int i = 0;
+ EoBItem *itm = &_vm->_items[_vm->_itemInHand];
+ Common::String tempString1;
+ Common::String tempString2;
+
+ while (cmd != -18) {
+ switch (cmd + 38) {
+ case 0:
+ a = 1;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if (_vm->_characters[i].effectFlags & 0x40)
+ continue;
+ a = 0;
+ break;
+ }
+ _stack[_stackIndex++] = a;
+ debugC(5, kDebugLevelScript, " - check if whole party is invisible - PUSH result: '%d'", a);
+ break;
+
+ case 1:
+ _stack[_stackIndex++] = _vm->rollDice(pos[0], pos[1], pos[2]);
+ debugC(9, kDebugLevelScript, " - throw dice(s): num = '%d', pips = '%d', offset = '%d' - PUSH result: '%d'", pos[0], pos[1], pos[2], _stack[_stackIndex - 1]);
+ pos += 3;
+ break;
+
+ case 2:
+ cmd = *pos++;
+ b = 0;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if (_vm->_classModifierFlags[_vm->_characters[i].cClass] & cmd) {
+ b = 1;
+ break;
+ }
+ }
+ _stack[_stackIndex++] = b;
+ debugC(5, kDebugLevelScript, " - check if character with class flags '0x%.02X' is present - PUSH result: '%d'", cmd, b);
+ break;
+
+ case 3:
+ cmd = *pos++;
+ b = 0;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if ((_vm->_characters[i].raceSex >> 1) == cmd) {
+ b = 1;
+ break;
+ }
+ }
+ _stack[_stackIndex++] = b;
+ debugC(5, kDebugLevelScript, " - check if character with race '%d' is present - PUSH result: '%d'", cmd, b);
+ break;
+
+ case 6:
+ _stack[_stackIndex++] = _lastScriptFlags;
+ debugC(5, kDebugLevelScript, " - get script execution flags - PUSH result: '%d'", _lastScriptFlags);
+ break;
+
+ case 13:
+ itm = &_vm->_items[_vm->_itemInHand];
+ switch (*pos++) {
+ case -31:
+ _stack[_stackIndex++] = itm->type;
+ debugC(5, kDebugLevelScript, " - get hand item type (hand item number = '%d') - PUSH result: '%d'", _vm->_itemInHand, itm->type);
+ break;
+
+ case -11:
+ _stack[_stackIndex++] = _vm->_itemInHand;
+ debugC(5, kDebugLevelScript, " - get hand item number - PUSH result: '%d'", _vm->_itemInHand);
+ break;
+
+ default:
+ _stack[_stackIndex++] = itm->value;
+ debugC(5, kDebugLevelScript, " - get hand item value (hand item number = '%d') - PUSH result: '%d'", _vm->_itemInHand, itm->value);
+ break;
+ }
+ break;
+
+ case 15:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos + 1)].walls[pos[0]];
+ debugC(5, kDebugLevelScript, " - get wall index for block '0x%.04X', direction '%d' - PUSH result: '%d'", READ_LE_UINT16(pos + 1), pos[0], _stack[_stackIndex - 1]);
+ pos += 3;
+ break;
+
+ case 19:
+ _stack[_stackIndex++] = _vm->_currentDirection;
+ debugC(5, kDebugLevelScript, " - get current direction - PUSH result: '%d'", _vm->_currentDirection);
+ break;
+
+ case 21:
+ _stack[_stackIndex++] = (_flagTable[_vm->_currentLevel] & (1 << (*pos++))) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - test level flag '%d' (current level = '%d') - PUSH result: '%d'", *(pos - 1), _vm->_currentLevel, _stack[_stackIndex - 1]);
+ break;
+
+ case 22:
+ _stack[_stackIndex++] = (_flagTable[17] & (1 << (*pos++))) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - test global flag '%d' - PUSH result: '%d'", *(pos - 1), _stack[_stackIndex - 1]);
+ break;
+
+ case 23:
+ _stack[_stackIndex++] = (_vm->_currentBlock == READ_LE_UINT16(pos)) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - compare current block with block '0x%.04X' (current block = '0x%.04X') - PUSH result: '%d'", _vm->_currentBlock, READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
+ pos += 2;
+ break;
+
+ case 24:
+ a = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ b = READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[b].drawObjects, a, -1, 0, 1);
+ debugC(5, kDebugLevelScript, " - find item number '%d' on block '0x%.04X' - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 25:
+ _stack[_stackIndex++] = (_vm->_levelBlockProperties[READ_LE_UINT16(pos)].flags & 1) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - test block flag '1' for block '0x%.04X' - PUSH result: '%d'", READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
+ pos += 2;
+ break;
+
+ case 27:
+ b = *pos++;
+ i = READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[i].drawObjects, -1, b, 1, 1);
+ debugC(5, kDebugLevelScript, " - count items of type '%d' on block '0x%.04X' - PUSH result: '%d'", b, i, _stack[_stackIndex - 1]);
+ break;
+
+ case 29:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].walls[0];
+ debugC(5, kDebugLevelScript, " - get wall index 0 for block '0x%.04X' - PUSH result: '%d'", READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
+ pos += 2;
+ break;
+
+ case 30:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a || b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') || POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 31:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a && b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') && POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 32:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a <= b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') <= POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 33:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a < b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') < POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 34:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a >= b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') >= POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 35:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a > b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') > POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 36:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a != b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') != POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 37:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a == b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') == POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ default:
+ a = cmd;
+ if (a >= 0 && a < 128)
+ _stack[_stackIndex++] = a;
+ debugC(5, kDebugLevelScript, " - PUSH value: '%d'", a);
+ break;
+ }
+ cmd = *pos++;
+ }
+
+ cmd = _stack[--_stackIndex];
+ if (cmd)
+ pos += 2;
+ else
+ pos = _scriptData + READ_LE_UINT16(pos);
+ debugC(5, kDebugLevelScript, " - conditional jump depending on POP('%d')", cmd);
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_eval_v2(int8 *data) {
+ int8 *pos = data;
+ int8 cmd = *pos++;
+
+ int a = 0;
+ int b = 0;
+ int i = 0;
+ EoBItem *itm = (_vm->_itemInHand != -1) ? &_vm->_items[_vm->_itemInHand] : 0;
+ Common::String tempString1;
+ Common::String tempString2;
+
+ while (cmd != -18) {
+ switch (cmd + 50) {
+ case 0:
+ a = 0;
+ b = *pos++;
+
+ for (i = 0; i < 6; i++) {
+ if (!_vm->testCharacter(i, 5))
+ continue;
+
+ if (_vm->_characters[i].portrait != b) {
+ a = 1;
+ _activeCharacter = i;
+ break;
+ }
+ }
+
+ _stack[_stackIndex++] = a;
+ break;
+
+ case 4:
+ _stack[_stackIndex++] = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ break;
+
+ case 9:
+ switch (*pos++) {
+ case -36:
+ _stack[_stackIndex++] = _vm->_itemTypes[_vm->_items[_vm->_lastUsedItem].type].extraProperties & 0x7F;
+ break;
+ case -31:
+ _stack[_stackIndex++] = _vm->_items[_vm->_lastUsedItem].type;
+ break;
+ case -11:
+ _stack[_stackIndex++] = _vm->_lastUsedItem;
+ break;
+ case -10:
+ _stack[_stackIndex++] = _vm->_items[_vm->_lastUsedItem].value;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case 12:
+ a = 1;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if (_vm->_characters[i].effectFlags & 0x40)
+ continue;
+ a = 0;
+ break;
+ }
+ _stack[_stackIndex++] = a;
+ break;
+
+ case 13:
+ _stack[_stackIndex++] = _vm->rollDice(pos[0], pos[1], pos[2]);
+ pos += 3;
+ break;
+
+ case 14:
+ cmd = *pos++;
+ a = _vm->rollDice(1, 6);
+ b = 0;
+ for (i = 0; i < 6 && b == 0; i++) {
+ if (++a > 5)
+ a = 0;
+ if (_vm->testCharacter(a, 5)) {
+ if (_vm->_classModifierFlags[_vm->_characters[a].cClass] & cmd) {
+ _activeCharacter = a;
+ b = 1;
+ }
+ }
+ }
+ _stack[_stackIndex++] = b;
+ break;
+
+ case 15:
+ cmd = *pos++;
+ a = _vm->rollDice(1, 6);
+ b = 0;
+ for (i = 0; i < 6; i++) {
+ if (++a > 5)
+ a = 0;
+ if (_vm->testCharacter(a, 5)) {
+ if ((_vm->_characters[a].raceSex >> 1) == cmd) {
+ _activeCharacter = a;
+ b = 1;
+ }
+ }
+ }
+ _stack[_stackIndex++] = b;
+ break;
+
+ case 17:
+ _stack[_stackIndex++] = _vm->_activeSpell;
+ break;
+
+ case 18:
+ _stack[_stackIndex++] = _lastScriptFlags;
+ break;
+
+ case 22:
+ _stack[_stackIndex++] = _dlgResult;
+ break;
+
+ case 25:
+ itm = &_vm->_items[_vm->_itemInHand];
+
+ switch (*pos++) {
+ case -49:
+ a = *pos++;
+ tempString1 = _vm->_itemNames[itm->nameId];
+ tempString1.toUppercase();
+ tempString2 = (const char *)pos;
+ tempString2.toUppercase();
+ pos += a;
+ _stack[_stackIndex++] = tempString1.contains(tempString2) ? 1 : 0;
+ break;
+
+ case -48:
+ a = *pos++;
+ tempString1 = _vm->_itemNames[itm->nameUnid];
+ tempString1.toUppercase();
+ tempString2 = (const char *)pos;
+ tempString2.toUppercase();
+ pos += a;
+ _stack[_stackIndex++] = tempString1.contains(tempString2) ? 1 : 0;
+ break;
+
+ case -31:
+ _stack[_stackIndex++] = itm->type;
+ break;
+
+ case -11:
+ _stack[_stackIndex++] = _vm->_itemInHand;
+ break;
+
+ case -10:
+ _stack[_stackIndex++] = itm->value;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case 26:
+ a = 0;
+ for (i = 0; i < 6; i++) {
+ if (_vm->testCharacter(i, 0x0F))
+ a++;
+ }
+ _stack[_stackIndex++] = a;
+ break;
+
+ case 27:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos + 1)].walls[pos[0]];
+ pos += 3;
+ break;
+
+ case 31:
+ _stack[_stackIndex++] = _vm->_currentDirection;
+ break;
+
+ case 33:
+ _stack[_stackIndex++] = (_flagTable[_vm->_currentLevel] & (1 << (*pos++))) ? 1 : 0;
+ break;
+
+ case 34:
+ _stack[_stackIndex++] = (_flagTable[17] & (1 << (*pos++))) ? 1 : 0;
+ break;
+
+ case 35:
+ if (*pos++ == -11) {
+ a = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ b = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countCharactersWithSpecificItems(a, b);
+ } else {
+ _stack[_stackIndex++] = (_vm->_currentBlock == READ_LE_UINT16(pos)) ? 1 : 0;
+ pos += 2;
+ }
+ break;
+
+ case 36:
+ a = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ b = READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[b].drawObjects, a, -1, 0, 0);
+ break;
+
+ case 37:
+ if (*pos++ == -1) {
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].flags & 7;
+ pos += 2;
+ } else {
+ do {
+ a += _vm->countSpecificMonsters(*pos++);
+ } while (*pos != -1);
+ pos++;
+ _stack[_stackIndex++] = a;
+ }
+ break;
+
+ case 39:
+ a = *pos++;
+ b = *pos++;
+ i = READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[i].drawObjects, -1, b, 1, a);
+ break;
+
+ case 41:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].walls[0];
+ pos += 2;
+ break;
+
+ case 42:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a || b) ? 1 : 0;
+ break;
+
+ case 43:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a && b) ? 1 : 0;
+ break;
+
+ case 44:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a <= b) ? 1 : 0;
+ break;
+
+ case 45:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a < b) ? 1 : 0;
+ break;
+
+ case 46:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a >= b) ? 1 : 0;
+ break;
+
+ case 47:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a > b) ? 1 : 0;
+ break;
+
+ case 48:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a != b) ? 1 : 0;
+ break;
+
+ case 49:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a == b) ? 1 : 0;
+ break;
+
+ default:
+ break;
+ }
+ cmd = *pos++;
+ }
+
+ cmd = _stack[--_stackIndex];
+ if (cmd)
+ pos += 2;
+ else
+ pos = _scriptData + READ_LE_UINT16(pos);
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_deleteItem(int8 *data) {
+ int8 *pos = data;
+ int8 c = *pos++;
+
+ if (c == -1) {
+ _vm->deleteInventoryItem(0, -1);
+ debugC(5, kDebugLevelScript, " - delete hand item");
+ } else {
+ _vm->deleteBlockItem(READ_LE_UINT16(pos), (c == -2) ? -1 : c);
+ debugC(5, kDebugLevelScript, " - delete item(s) of type '%d' on block '0x%.04X'", (c == -2) ? -1 : c, READ_LE_UINT16(pos));
+ pos += 2;
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_loadNewLevelOrMonsters(int8 *data) {
+ int8 *pos = data;
+ _vm->gui_updateControls();
+
+ int8 cmd = *pos++;
+ int8 index = *pos++;
+ int res = 0;
+
+ if (cmd == -27 || _vm->game() == GI_EOB1) {
+ cmd = _vm->game() == GI_EOB2 ? *pos++ : 0;
+ _vm->_currentBlock = READ_LE_UINT16(pos);
+ pos += 2;
+ uint8 dir = (uint8)*pos++;
+
+ if (dir != 0xFF)
+ _vm->_currentDirection = dir;
+
+ for (int i = 0; i < 30; i++)
+ _vm->_monsters[i].curAttackFrame = 0;
+
+ for (int i = 0; i < 10; i++) {
+ EoBFlyingObject *fo = &_vm->_flyingObjects[i];
+ if (fo->enable == 1) {
+ _vm->_items[fo->item].pos &= 3;
+ run(_vm->_items[fo->item].block, 4);
+ }
+ fo->enable = 0;
+ }
+
+ _vm->completeDoorOperations();
+
+ _vm->generateTempData();
+ _vm->txt()->removePageBreakFlag();
+ _screen->setScreenDim(7);
+
+ _vm->loadLevel(index, cmd);
+ debugC(5, kDebugLevelScript, " - entering level '%d', sub level '%d', start block '0x%.04X', start direction '%d'", index, cmd, _vm->_currentBlock, _vm->_currentDirection);
+
+ if (_vm->_dialogueField)
+ _vm->restoreAfterDialogueSequence();
+
+ _vm->moveParty(_vm->_currentBlock);
+
+ _abortScript = 1;
+ _abortAfterSubroutine = 1;
+ _vm->_sceneUpdateRequired = true;
+
+ _vm->gui_drawAllCharPortraitsWithStats();
+ _subroutineStackPos = 0;
+
+ } else {
+ cmd = *pos++;
+ _vm->releaseMonsterShapes(cmd * 18, 18);
+ _vm->loadMonsterShapes((const char *)pos, cmd * 18, true, index * 18);
+ debugC(5, kDebugLevelScript, " - loading monster shapes '%s', monster number '%d', encode type '%d'", (const char *)pos, cmd, index);
+ pos += 13;
+ _vm->gui_restorePlayField();
+ res = pos - data;
+ }
+
+ return res;
+}
+
+int EoBInfProcessor::oeob_increasePartyExperience(int8 *data) {
+ int8 *pos = data;
+ if (*pos++ == -30) {
+ _vm->increasePartyExperience((int16)READ_LE_UINT16(pos));
+ debugC(5, kDebugLevelScript, " - award '%d' experience points", READ_LE_UINT16(pos));
+ pos += 2;
+ }
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_createItem_v1(int8 *data) {
+ int8 *pos = data;
+ uint16 itm = _vm->duplicateItem(READ_LE_UINT16(pos));
+ pos += 2;
+ uint16 block = READ_LE_UINT16(pos);
+ pos += 2;
+ uint8 itmPos = *pos++;
+
+ if (itm) {
+ if (block == 0xFFFF && !_vm->_itemInHand) {
+ _vm->setHandItem(itm);
+ debugC(5, kDebugLevelScript, " - create hand item '%d'", itm);
+ } else if (block != 0xFFFF) {
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[block & 0x3FF].drawObjects, block, itm, itmPos);
+ debugC(5, kDebugLevelScript, " - create item '%d' on block '0x%.04X', position '%d'", itm, block, itmPos);
+ }
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_createItem_v2(int8 *data) {
+ static const uint8 _itemPos[] = { 0, 1, 2, 3, 1, 3, 0, 2, 3, 2, 1, 0, 2, 0, 3, 1 };
+ int8 *pos = data;
+
+ uint16 itm = _vm->duplicateItem(READ_LE_UINT16(pos));
+ pos += 2;
+ uint16 block = READ_LE_UINT16(pos);
+ pos += 2;
+ uint8 itmPos = *pos++;
+ uint8 flg = *pos++;
+
+ if (flg & 1)
+ _vm->_items[itm].value = *pos++;
+
+ if (flg & 2)
+ _vm->_items[itm].flags = *pos++;
+
+ if (flg & 4)
+ _vm->_items[itm].icon = *pos++;
+
+ if (!itm)
+ return pos - data;
+
+ if (block == 0xFFFF) {
+ if (!_vm->_itemInHand) {
+ _vm->setHandItem(itm);
+ debugC(5, kDebugLevelScript, " - create hand item '%d' (value '%d', flags '0x%X', icon number '%d')", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
+ } else {
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[_vm->_currentBlock & 0x3FF].drawObjects, _vm->_currentBlock, itm, _itemPos[_vm->rollDice(1, 2, -1)]);
+ debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on current block", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
+ }
+ } else if (block == 0xFFFE) {
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[_vm->_currentBlock & 0x3FF].drawObjects, _vm->_currentBlock, itm, _itemPos[(_vm->_currentDirection << 2) + _vm->rollDice(1, 2, -1)]);
+ debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on current block", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
+ } else {
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[block & 0x3FF].drawObjects, block, itm, itmPos);
+ debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on block '0x%.04X', position '%d'", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon, block, itmPos);
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_launchObject(int8 *data) {
+ static const uint8 startPos[] = { 2, 3, 0, 2, 1, 0, 3, 1 };
+
+ int8 *pos = data;
+ bool m = (*pos++ == -33);
+ int i = READ_LE_UINT16(pos);
+ pos += 2;
+ uint16 block = READ_LE_UINT16(pos);
+ pos += 2;
+ int dir = *pos++;
+ int dirOffs = *pos++;
+
+ if (m) {
+ uint8 openBookType = _vm->_openBookType;
+ _vm->_openBookType = 0;
+ _vm->launchMagicObject(-1, i, block, startPos[dir * 2 + dirOffs], dir);
+ _vm->_openBookType = openBookType;
+ } else {
+ Item itm = _vm->duplicateItem(i);
+ if (itm) {
+ if (!_vm->launchObject(-1, itm, block, startPos[dir * 2 + dirOffs], dir, _vm->_items[itm].type))
+ _vm->_items[itm].block = -1;
+ }
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_changeDirection(int8 *data) {
+ int8 *pos = data;
+
+ int8 cmd = *pos++;
+ int8 dir = *pos++;
+
+ if (cmd == -15) {
+ _vm->_currentDirection = (_vm->_currentDirection + dir) & 3;
+ //_vm->_keybControlUnk = -1;
+ _vm->_sceneUpdateRequired = true;
+
+ } else if (cmd == -11) {
+ for (int i = 0; i < 10; i++) {
+ if (_vm->_flyingObjects[i].enable)
+ _vm->_flyingObjects[i].direction = (_vm->_flyingObjects[i].direction + dir) & 3;
+ }
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_identifyItems(int8 *data) {
+ int8 *pos = data;
+ uint16 block = READ_LE_UINT16(pos);
+
+ if (block == _vm->_currentBlock) {
+ for (int i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+
+ for (int ii = 0; ii < 27; ii++) {
+ int inv = _vm->_characters[i].inventory[ii];
+ if (inv)
+ _vm->_items[inv].flags |= 0x40;
+ }
+
+ _vm->identifyQueuedItems(_vm->_characters[i].inventory[16]);
+ }
+ }
+
+ _vm->identifyQueuedItems(_vm->_levelBlockProperties[block].drawObjects);
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_sequence(int8 *data) {
+ int8 *pos = data;
+ _vm->_npcSequenceSub = -1;
+ _vm->txt()->setWaitButtonMode(0);
+ _vm->gui_updateControls();
+ _vm->drawScene(1);
+
+ int cmd = *pos++;
+
+ if (_vm->game() == GI_EOB1) {
+ if (cmd == 10)
+ cmd = -1;
+ else if (cmd == 9)
+ cmd = -3;
+ else if (cmd == 8)
+ cmd = -2;
+ }
+
+ switch (cmd) {
+ case -3:
+ _vm->seq_xdeath();
+ _vm->_runFlag = false;
+ _vm->_playFinale = true;
+ _abortScript = 1;
+ return 0;
+
+ case -2:
+ _vm->seq_portal();
+ break;
+
+ case -1:
+ if (_vm->gameFlags().platform == Common::kPlatformDOS)
+ _vm->_runFlag = _vm->checkPassword();
+ break;
+
+ default:
+ _vm->npcSequence(cmd);
+ break;
+ }
+ _vm->screen()->setScreenDim(7);
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_delay(int8 *data) {
+ int8 *pos = data;
+ _vm->delay(READ_LE_UINT16(pos) * _vm->tickLength());
+ pos += 2;
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_drawScene(int8 *data) {
+ _vm->drawScene(1);
+ return 0;
+}
+
+int EoBInfProcessor::oeob_dialogue(int8 *data) {
+ int8 *pos = data;
+
+ switch (*pos++) {
+ case -45:
+ _vm->drawSequenceBitmap((const char *)pos, pos[13], READ_LE_UINT16(pos + 14), READ_LE_UINT16(pos + 16), READ_LE_UINT16(pos + 18));
+ pos += 20;
+ break;
+
+ case -44:
+ _vm->restoreAfterDialogueSequence();
+ break;
+
+ case -43:
+ _vm->initDialogueSequence();
+ break;
+
+ case -42:
+ _vm->gui_drawDialogueBox();
+ break;
+
+ case -40:
+ _dlgResult = _vm->runDialogue(READ_LE_UINT16(pos), READ_LE_UINT16(pos + 6) == 0xFFFF ? 2 : 3, getString(READ_LE_UINT16(pos + 2)), getString(READ_LE_UINT16(pos + 4)), getString(READ_LE_UINT16(pos + 6)));
+ pos += 8;
+ break;
+
+ case -8:
+ _vm->txt()->printDialogueText(READ_LE_UINT16(pos), getString(READ_LE_UINT16(pos + 2)));
+ pos += 4;
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_specialEvent(int8 *data) {
+ int8 *pos = data;
+ uint16 cmd = READ_LE_UINT16(pos);
+ pos += 2;
+
+ uint32 endTime = 0;
+ int i = 0;
+
+ switch (cmd) {
+ case 0:
+ _vm->drawScene(1);
+ _screen->_curPage = 2;
+ _screen->copyRegion(72, 0, 0, 0, 32, 120, 2, 12, Screen::CR_NO_P_CHECK);
+
+ for (; i < 4; i++) {
+ endTime = _vm->_system->getMillis() + _vm->_tickLength;
+ _vm->drawLightningColumn();
+ _screen->copyRegion(72, 0, 72, 0, 32, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _screen->copyRegion(0, 0, 72, 0, 32, 120, 12, 2, Screen::CR_NO_P_CHECK);
+ _vm->delayUntil(endTime);
+ }
+
+ _screen->_curPage = 0;
+ _vm->_sceneUpdateRequired = true;
+ break;
+
+ case 1:
+ _dlgResult = _vm->charSelectDialogue();
+ break;
+
+ case 2:
+ _vm->characterLevelGain(_dlgResult);
+ break;
+
+ case 3:
+ _dlgResult = _vm->resurrectionSelectDialogue();
+ break;
+
+ case 4:
+ if (_vm->prepareForNewPartyMember(33, 5))
+ _vm->initNpc(4);
+ break;
+
+ case 5:
+ _vm->deletePartyItems(46, 5);
+ _vm->deletePartyItems(46, 6);
+ break;
+
+ case 6:
+ _vm->loadVcnData(0, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/script/script_eob.h b/engines/kyra/script/script_eob.h
new file mode 100644
index 0000000000..b996e314d5
--- /dev/null
+++ b/engines/kyra/script/script_eob.h
@@ -0,0 +1,131 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#ifndef KYRA_SCRIPT_EOB_H
+#define KYRA_SCRIPT_EOB_H
+
+#include "common/func.h"
+#include "common/substream.h"
+#include "common/savefile.h"
+
+namespace Kyra {
+
+class KyraRpgEngine;
+
+class EoBInfProcessor {
+public:
+ EoBInfProcessor(EoBCoreEngine *engine, Screen_EoB *_screen);
+ ~EoBInfProcessor();
+
+ void loadData(const uint8 *data, uint32 dataSize);
+ void run(int func, int flags);
+
+ void setFlags(uint32 flags);
+ void clearFlags(uint32 flags);
+ bool checkFlags(uint32 flags) const;
+ bool preventRest() const;
+
+ void loadState(Common::SeekableSubReadStreamEndian &in, bool origFile = false);
+ void saveState(Common::OutSaveFile *out, bool origFile = false);
+ void reset();
+
+private:
+ const char *getString(uint16 index);
+
+ int oeob_setWallType(int8 *data);
+ int oeob_toggleWallState(int8 *data);
+ int oeob_openDoor(int8 *data);
+ int oeob_closeDoor(int8 *data);
+ int oeob_replaceMonster(int8 *data);
+ int oeob_movePartyOrObject(int8 *data);
+ int oeob_moveInventoryItemToBlock(int8 *data);
+ int oeob_printMessage_v1(int8 *data);
+ int oeob_printMessage_v2(int8 *data);
+ int oeob_setFlags(int8 *data);
+ int oeob_playSoundEffect(int8 *data);
+ int oeob_removeFlags(int8 *data);
+ int oeob_modifyCharacterHitPoints(int8 *data);
+ int oeob_calcAndInflictCharacterDamage(int8 *data);
+ int oeob_jump(int8 *data);
+ int oeob_end(int8 *data);
+ int oeob_returnFromSubroutine(int8 *data);
+ int oeob_callSubroutine(int8 *data);
+ int oeob_eval_v1(int8 *data);
+ int oeob_eval_v2(int8 *data);
+ int oeob_deleteItem(int8 *data);
+ int oeob_loadNewLevelOrMonsters(int8 *data);
+ int oeob_increasePartyExperience(int8 *data);
+ int oeob_createItem_v1(int8 *data);
+ int oeob_createItem_v2(int8 *data);
+ int oeob_launchObject(int8 *data);
+ int oeob_changeDirection(int8 *data);
+ int oeob_identifyItems(int8 *data);
+ int oeob_sequence(int8 *data);
+ int oeob_delay(int8 *data);
+ int oeob_drawScene(int8 *data);
+ int oeob_dialogue(int8 *data);
+ int oeob_specialEvent(int8 *data);
+
+ EoBCoreEngine *_vm;
+ Screen_EoB *_screen;
+
+ typedef Common::Functor1Mem<int8 *, int, EoBInfProcessor> InfProc;
+ struct InfOpcode : private Common::NonCopyable {
+ InfOpcode(InfProc *p, const char *d) : proc(p), desc(d) {}
+ ~InfOpcode() { delete proc; }
+
+ InfProc *proc;
+ Common::String desc;
+ };
+ Common::Array<const InfOpcode *> _opcodes;
+
+ int8 *_scriptData;
+ uint16 _scriptSize;
+
+ uint8 _abortScript;
+ uint16 _abortAfterSubroutine;
+ int _dlgResult;
+ uint8 _preventRest;
+
+ uint16 _lastScriptFunc;
+ uint16 _lastScriptFlags;
+
+ int8 **_subroutineStack;
+ int _subroutineStackPos;
+
+ uint32 *_flagTable;
+
+ int16 *_stack;
+ int _stackIndex;
+
+ int8 _activeCharacter;
+
+ const int _commandMin;
+};
+
+} // End of namespace Kyra
+
+#endif
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/script/script_hof.cpp b/engines/kyra/script/script_hof.cpp
new file mode 100644
index 0000000000..94d3a82cc4
--- /dev/null
+++ b/engines/kyra/script/script_hof.cpp
@@ -0,0 +1,1727 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/kyra_hof.h"
+#include "kyra/engine/timer.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+int KyraEngine_HoF::o2_setCharacterFacingRefresh(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setCharacterFacingRefresh(%p) (-, %d, %d)", (const void *)script, stackPos(1), stackPos(2));
+ int animFrame = stackPos(2);
+ if (animFrame >= 0)
+ _mainCharacter.animFrame = animFrame;
+ _mainCharacter.facing = stackPos(1);
+ updateCharacterAnim(0);
+ refreshAnimObjectsIfNeed();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setCharacterPos(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setCharacterFacingRefresh(%p) (-, %d, %d)", (const void *)script, stackPos(1), stackPos(2));
+ int x = stackPos(1);
+ int y = stackPos(2);
+
+ if (x != -1 && y != -1) {
+ x &= ~3;
+ y &= ~1;
+ }
+
+ restorePage3();
+ _mainCharacter.x2 = _mainCharacter.x1 = x;
+ _mainCharacter.y2 = _mainCharacter.y1 = y;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_defineObject(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_defineObject(%p) (%d, '%s', %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPosString(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ TalkObject *object = &_talkObjectList[stackPos(0)];
+ strcpy(object->filename, stackPosString(1));
+ object->scriptId = stackPos(2);
+ object->x = stackPos(3);
+ object->y = stackPos(4);
+ object->color = stackPos(5);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_refreshCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_refreshCharacter(%p) (-, %d, %d, %d)", (const void *)script, stackPos(1), stackPos(2), stackPos(3));
+ int unk = stackPos(1);
+ int facing = stackPos(2);
+ int refresh = stackPos(3);
+ if (facing >= 0)
+ _mainCharacter.facing = facing;
+ if (unk >= 0 && unk != 32)
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ updateCharacterAnim(0);
+ if (refresh)
+ refreshAnimObjectsIfNeed();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setSceneComment(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setSceneComment(%p) ('%s')", (const void *)script, stackPosString(0));
+ _sceneCommentString = stackPosString(0);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setCharacterAnimFrame(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setCharacterAnimFrame(%p) (-, %d, %d)", (const void *)script, stackPos(1), stackPos(2));
+ int animFrame = stackPos(1);
+ int updateAnim = stackPos(2);
+
+ _mainCharacter.animFrame = animFrame;
+ if (updateAnim)
+ updateCharacterAnim(0);
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_customCharacterChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_customCharacterChat(%p) ('%s', %d, %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ playVoice(_vocHigh, stackPos(4));
+ _text->printCustomCharacterText(stackPosString(0), stackPos(1), stackPos(2), stackPos(3), 0, 2);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_soundFadeOut(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_soundFadeOut(%p) ()", (const void *)script);
+ _sound->beginFadeOut();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_showChapterMessage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_showChapterMessage(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ showChapterMessage(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_restoreTalkTextMessageBkgd(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_restoreTalkTextMessageBkgd(%p) ()", (const void *)script);
+ _text->restoreTalkTextMessageBkgd(2, 0);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_wsaClose(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_wsaClose(%p) (%d)", (const void *)script, stackPos(0));
+ assert(stackPos(0) >= 0 && stackPos(0) < ARRAYSIZE(_wsaSlots));
+ _wsaSlots[stackPos(0)]->close();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_meanWhileScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_meanWhileScene(%p) (%d)", (const void *)script, stackPos(0));
+ static const uint8 jpSubtitle[] = { 0x88, 0xEA, 0x95, 0xFB, 0x81, 0x45, 0x81, 0x45, 0x81, 0x45 };
+ const char *cpsfile = stackPosString(0);
+ const char *palfile = stackPosString(1);
+
+ _screen->loadBitmap(cpsfile, 3, 3, 0);
+ _screen->copyPalette(2, 0);
+ _screen->loadPalette(palfile, _screen->getPalette(2));
+ _screen->fillRect(0, 0, 319, 199, 207);
+ _screen->setScreenPalette(_screen->getPalette(2));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ if (!scumm_stricmp(cpsfile, "_MEANWIL.CPS") && _flags.lang == Common::JA_JPN) {
+ Screen::FontId o = _screen->setFont(Screen::FID_SJIS_FNT);
+ _screen->printText((const char *)jpSubtitle, 140, 176, 255, 132);
+ _screen->setFont(o);
+ }
+ _screen->updateScreen();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_backUpScreen(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_backUpScreen(%p) (%d)", (const void *)script, stackPos(0));
+ _screen->copyRegionToBuffer(stackPos(0), 0, 0, 320, 144, _screenBuffer);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_restoreScreen(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_restoreScreen(%p) (%d)", (const void *)script, stackPos(0));
+ _screen->copyBlockToPage(stackPos(0), 0, 0, 320, 144, _screenBuffer);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_displayWsaFrame(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_displayWsaFrame(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8));
+ int frame = stackPos(0);
+ int x = stackPos(1);
+ int y = stackPos(2);
+ int waitTime = stackPos(3);
+ int slot = stackPos(4);
+ int copyParam = stackPos(5);
+ int doUpdate = stackPos(6);
+ int dstPage = stackPos(7);
+ int backUp = stackPos(8);
+
+ _screen->hideMouse();
+ const uint32 endTime = _system->getMillis() + waitTime * _tickLength;
+ _wsaSlots[slot]->displayFrame(frame, dstPage, x, y, copyParam | 0xC000, 0, 0);
+ _screen->updateScreen();
+
+ if (backUp)
+ memcpy(_gamePlayBuffer, _screen->getCPagePtr(3), 46080);
+
+ delayUntil(endTime, false, doUpdate != 0);
+ _screen->showMouse();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_displayWsaSequentialFramesLooping(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_displayWsaSequentialFramesLooping(%p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ int startFrame = stackPos(0);
+ int endFrame = stackPos(1);
+ int x = stackPos(2);
+ int y = stackPos(3);
+ int waitTime = stackPos(4);
+ int slot = stackPos(5);
+ int maxTimes = stackPos(6);
+ int copyFlags = stackPos(7);
+
+ if (maxTimes > 1)
+ maxTimes = 1;
+
+ _screen->hideMouse();
+ int curTime = 0;
+ while (curTime < maxTimes) {
+ if (startFrame < endFrame) {
+ for (int i = startFrame; i <= endFrame; ++i) {
+ const uint32 endTime = _system->getMillis() + waitTime * _tickLength;
+ _wsaSlots[slot]->displayFrame(i, 0, x, y, 0xC000 | copyFlags, 0, 0);
+
+ if (!skipFlag()) {
+ _screen->updateScreen();
+ delayUntil(endTime, false, true);
+ }
+ }
+ } else {
+ for (int i = startFrame; i >= endFrame; --i) {
+ const uint32 endTime = _system->getMillis() + waitTime * _tickLength;
+ _wsaSlots[slot]->displayFrame(i, 0, x, y, 0xC000 | copyFlags, 0, 0);
+
+ if (!skipFlag()) {
+ _screen->updateScreen();
+ delayUntil(endTime, false, true);
+ }
+ }
+ }
+
+ ++curTime;
+ }
+ resetSkipFlag();
+ _screen->showMouse();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_wsaOpen(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_wsaOpen(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1));
+ assert(stackPos(1) >= 0 && stackPos(1) < ARRAYSIZE(_wsaSlots));
+ _wsaSlots[stackPos(1)]->open(stackPosString(0), 1, 0);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_displayWsaSequentialFrames(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_displayWsaSequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6));
+
+ uint16 frameDelay = stackPos(2) * _tickLength;
+ uint16 currentFrame = stackPos(3);
+ uint16 lastFrame = stackPos(4);
+ uint16 index = stackPos(5);
+ uint16 copyParam = stackPos(6) | 0xC000;
+
+ _screen->hideMouse();
+
+ while (currentFrame <= lastFrame) {
+ const uint32 endTime = _system->getMillis() + frameDelay;
+ _wsaSlots[index]->displayFrame(currentFrame++, 0, stackPos(0), stackPos(1), copyParam, 0, 0);
+ if (!skipFlag()) {
+ _screen->updateScreen();
+ delayUntil(endTime);
+ }
+ }
+
+ resetSkipFlag();
+ _screen->showMouse();
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_displayWsaSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_displayWsaSequence(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+
+ const int frameDelay = stackPos(2) * _tickLength;
+ const int index = stackPos(3);
+ const bool doUpdate = (stackPos(4) != 0);
+ const uint16 copyParam = stackPos(5) | 0xC000;
+
+ _screen->hideMouse();
+
+ int currentFrame = 0;
+ const int lastFrame = _wsaSlots[index]->frames();
+
+ while (currentFrame <= lastFrame) {
+ const uint32 endTime = _system->getMillis() + frameDelay;
+ _wsaSlots[index]->displayFrame(currentFrame++, 0, stackPos(0), stackPos(1), copyParam, 0, 0);
+ if (!skipFlag()) {
+ if (doUpdate)
+ update();
+ _screen->updateScreen();
+ delayUntil(endTime);
+ }
+ }
+
+ resetSkipFlag();
+ _screen->showMouse();
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_addItemToInventory(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_addItemToInventory(%p) (%d, -, %d)", (const void *)script, stackPos(0), stackPos(2));
+ int slot = findFreeVisibleInventorySlot();
+ if (slot != -1) {
+ _mainCharacter.inventory[slot] = stackPos(0);
+ if (stackPos(2))
+ redrawInventory(0);
+ }
+ return slot;
+}
+
+int KyraEngine_HoF::o2_drawShape(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_drawShape(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+
+ uint8 *shp = getShapePtr(stackPos(0) + 64);
+ int x = stackPos(1);
+ int y = stackPos(2);
+ uint8 dsFlag = stackPos(3) & 0xFF;
+ uint8 modeFlag = stackPos(4) & 0xFF;
+
+ if (modeFlag) {
+ _screen->drawShape(2, shp, x, y, 2, dsFlag ? 1 : 0);
+ } else {
+ restorePage3();
+ _screen->drawShape(2, shp, x, y, 2, dsFlag ? 1 : 0);
+ memcpy(_gamePlayBuffer, _screen->getCPagePtr(3), 46080);
+ _screen->drawShape(0, shp, x, y, 2, dsFlag ? 1 : 0);
+
+ flagAnimObjsForRefresh();
+ flagAnimObjsSpecialRefresh();
+ refreshAnimObjectsIfNeed();
+ }
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_addItemToCurScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_addItemToCurScene(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ const int16 id = stackPos(0);
+ int x = stackPos(1);
+ int y = stackPos(2);
+
+ int freeItem = findFreeItem();
+ x = MAX(14, x);
+ x = MIN(304, x);
+ y = MAX(14, y);
+ y = MIN(136, y);
+ if (freeItem >= 0) {
+ _itemList[freeItem].id = id;
+ _itemList[freeItem].x = x;
+ _itemList[freeItem].y = y;
+ _itemList[freeItem].sceneId = _mainCharacter.sceneId;
+ addItemToAnimList(freeItem);
+ refreshAnimObjectsIfNeed();
+ }
+ return 0;
+}
+
+int KyraEngine_HoF::o2_loadSoundFile(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_loadSoundFile(%p) (%d)", (const void *)script, stackPos(0));
+ if (_flags.platform == Common::kPlatformDOS)
+ snd_loadSoundFile(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_removeSlotFromInventory(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_removeSlotFromInventory(%p) (%d)", (const void *)script, stackPos(0));
+ removeSlotFromInventory(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_removeItemFromInventory(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_removeItemFromInventory(%p) (%d)", (const void *)script, stackPos(0));
+ uint16 item = stackPos(0);
+ int slot = -1;
+ while ((slot = getInventoryItemSlot(item)) != -1)
+ removeSlotFromInventory(slot);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_countItemInInventory(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_countItemInInventory(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ uint16 item = stackPos(1);
+ int count = 0;
+
+ for (int i = 0; i < 20; ++i) {
+ if (_mainCharacter.inventory[i] == item)
+ ++count;
+ }
+
+ if ((stackPos(0) == 0) && _itemInHand == int16(item))
+ ++count;
+
+ return count;
+}
+
+int KyraEngine_HoF::o2_countItemsInScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_countItemsInScene(%p) (%d)", (const void *)script, stackPos(0));
+ int count = 0;
+ for (int i = 0; i < 30; ++i) {
+ if (_itemList[i].sceneId == stackPos(0) && _itemList[i].id != kItemNone)
+ ++count;
+ }
+ return count;
+}
+
+int KyraEngine_HoF::o2_wipeDownMouseItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_wipeDownMouseItem(%p) (-, %d, %d)", (const void *)script, stackPos(1), stackPos(2));
+ _screen->hideMouse();
+ const int x = stackPos(1) - 8;
+ const int y = stackPos(2) - 15;
+
+ if (_itemInHand >= 0) {
+ backUpGfxRect32x32(x, y);
+ uint8 *shape = getShapePtr(_itemInHand+64);
+ for (int curY = y, height = 16; height > 0; height -= 2, curY += 2) {
+ restoreGfxRect32x32(x, y);
+ _screen->setNewShapeHeight(shape, height);
+ uint32 waitTime = _system->getMillis() + _tickLength;
+ _screen->drawShape(0, shape, x, curY, 0, 0);
+ _screen->updateScreen();
+ delayUntil(waitTime);
+ }
+ restoreGfxRect32x32(x, y);
+ _screen->resetShapeHeight(shape);
+ }
+
+ _screen->showMouse();
+ removeHandItem();
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getElapsedSecs(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getElapsedSecs(%p) ()", (const void *)script);
+ return _system->getMillis() / 1000;
+}
+
+int KyraEngine_HoF::o2_getTimerDelay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getTimerDelay(%p) (%d)", (const void *)script, stackPos(0));
+ return _timer->getDelay(stackPos(0));
+}
+
+int KyraEngine_HoF::o2_delaySecs(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_delaySecs(%p) (%d)", (const void *)script, stackPos(0));
+ delay(stackPos(0) * 1000, true);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setTimerDelay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setTimerDelay(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _timer->setDelay(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setScaleTableItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setScaleTableItem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ setScaleTableItem(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setDrawLayerTableItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setDrawLayerTableItem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ setDrawLayerTableEntry(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setCharPalEntry(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setCharPalEntry(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ setCharPalEntry(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_loadZShapes(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_loadZShapes(%p) (%d)", (const void *)script, stackPos(0));
+ loadCharacterShapes(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_drawSceneShape(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_drawSceneShape(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1),
+ stackPos(2), stackPos(3));
+
+ int shape = stackPos(0);
+ int x = stackPos(1);
+ int y = stackPos(2);
+ int flag = (stackPos(3) != 0) ? 1 : 0;
+
+ restorePage3();
+
+ _screen->drawShape(2, _sceneShapeTable[shape], x, y, 2, flag);
+
+ memcpy(_gamePlayBuffer, _screen->getCPagePtr(3), 46080);
+
+ _screen->drawShape(0, _sceneShapeTable[shape], x, y, 2, flag);
+
+ flagAnimObjsSpecialRefresh();
+ flagAnimObjsForRefresh();
+ refreshAnimObjectsIfNeed();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_drawSceneShapeOnPage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_drawSceneShapeOnPage(%p) (%d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ int shape = stackPos(0);
+ int x = stackPos(1);
+ int y = stackPos(2);
+ int flag = stackPos(3);
+ int drawPage = stackPos(4);
+
+ _screen->drawShape(drawPage, _sceneShapeTable[shape], x, y, 2, flag ? 1 : 0);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_disableAnimObject(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_disableAnimObject(%p) (%d)", (const void *)script, stackPos(0));
+ _animObjects[stackPos(0)+1].enabled = false;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_enableAnimObject(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_enableAnimObject(%p) (%d)", (const void *)script, stackPos(0));
+ _animObjects[stackPos(0)+1].enabled = true;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_loadPalette384(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_loadPalette384(%p) ('%s')", (const void *)script, stackPosString(0));
+ _screen->copyPalette(1, 0);
+ _res->loadFileToBuf(stackPosString(0), _screen->getPalette(1).getData(), 384);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setPalette384(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setPalette384(%p) ()", (const void *)script);
+ _screen->getPalette(0).copy(_screen->getPalette(1), 0, 128);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_restoreBackBuffer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_restoreBackBuffer(%p) (%d)", (const void *)script, stackPos(0));
+ int disable = stackPos(0);
+ int oldState = 0;
+
+ if (disable) {
+ oldState = _animObjects[0].enabled;
+ _animObjects[0].enabled = 0;
+ }
+
+ restorePage3();
+
+ if (disable)
+ _animObjects[0].enabled = (oldState != 0);
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_backUpInventoryGfx(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_backUpInventoryGfx(%p) ()", (const void *)script);
+ _screen->copyRegionToBuffer(1, 0, 144, 320, 56, _screenBuffer);
+ _inventorySaved = true;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_disableSceneAnim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_disableSceneAnim(%p) (%d)", (const void *)script, stackPos(0));
+ _sceneAnims[stackPos(0)].flags &= ~1;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_enableSceneAnim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_enableSceneAnim(%p) (%d)", (const void *)script, stackPos(0));
+ _sceneAnims[stackPos(0)].flags |= 1;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_restoreInventoryGfx(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_restoreInventoryGfx(%p) ()", (const void *)script);
+ _screen->copyBlockToPage(1, 0, 144, 320, 56, _screenBuffer);
+ _inventorySaved = false;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setSceneAnimPos2(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setSceneAnimPos2(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ _sceneAnims[stackPos(0)].x2 = stackPos(1);
+ _sceneAnims[stackPos(0)].y2 = stackPos(2);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_fadeScenePal(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_fadeScenePal(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ fadeScenePal(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_enterNewScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_enterNewScene(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0),
+ stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+
+ int skipNpcScript = stackPos(3);
+ enterNewScene(stackPos(0), stackPos(1), stackPos(2), skipNpcScript, stackPos(4));
+
+ if (!skipNpcScript)
+ runSceneScript4(0);
+
+ _unk5 = 1;
+
+ if (_mainCharX == -1 || _mainCharY == -1) {
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ updateCharacterAnim(0);
+ }
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_switchScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_switchScene(%p) (%d)", (const void *)script, stackPos(0));
+ setGameFlag(0x1EF);
+ _mainCharX = _mainCharacter.x1;
+ _mainCharY = _mainCharacter.y1;
+ _noScriptEnter = false;
+ enterNewScene(stackPos(0), _mainCharacter.facing, 0, 0, 0);
+ _noScriptEnter = true;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setPathfinderFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setPathfinderFlag(%p) (%d)", (const void *)script, stackPos(0));
+ _pathfinderFlag = stackPos(0);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getSceneExitToFacing(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getSceneExitToFacing(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ const int scene = stackPos(0);
+ const int facing = stackPos(1);
+
+ if (facing == 0)
+ return (int16)_sceneList[scene].exit1;
+ else if (facing == 2)
+ return (int16)_sceneList[scene].exit2;
+ else if (facing == 4)
+ return (int16)_sceneList[scene].exit3;
+ else if (facing == 6)
+ return (int16)_sceneList[scene].exit4;
+ return -1;
+}
+
+int KyraEngine_HoF::o2_setLayerFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setLayerFlag(%p) (%d)", (const void *)script, stackPos(0));
+ int layer = stackPos(0);
+ if (layer >= 1 && layer <= 16)
+ _layerFlagTable[layer] = 1;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setZanthiaPos(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setZanthiaPos(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _mainCharX = stackPos(0);
+ _mainCharY = stackPos(1);
+
+ if (_mainCharX == -1 && _mainCharY == -1)
+ _mainCharacter.animFrame = 32;
+ else
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_loadMusicTrack(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_loadMusicTrack(%p) (%d)", (const void *)script, stackPos(0));
+ snd_loadSoundFile(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setSceneAnimPos(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setSceneAnimPos(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ _sceneAnims[stackPos(0)].x = stackPos(1);
+ _sceneAnims[stackPos(0)].y = stackPos(2);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setCauldronState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setCauldronState(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ setCauldronState(stackPos(0), stackPos(1) != 0);
+ clearCauldronTable();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_showItemString(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_showItemString(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ const int item = stackPos(0);
+
+ int string = 0;
+ if (stackPos(1) == 1) {
+ if (_lang == 1)
+ string = getItemCommandStringPickUp(item);
+ else
+ string = 7;
+ } else {
+ if (_lang == 1)
+ string = getItemCommandStringInv(item);
+ else
+ string = 8;
+ }
+
+ updateCommandLineEx(item+54, string, 0xD6);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_isAnySoundPlaying(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_isAnySoundPlaying(%p) ()", (const void *)script);
+
+ // WORKAROUND
+ //
+ // The input script function in the skull scene does busy wait
+ // for the sound effect, which is played after completing the
+ // song, to finish. To avoid too much CPU use, we add some slight
+ // delay here.
+ //
+ // Also the Nintendo DS backend seems only to update the sound, when
+ // either OSystem::updateScreen or OSystem::delayMillis is called.
+ // So we have to call delay here, since otherwise the game would hang.
+#ifndef __DS__
+ if (_currentScene == 16 && _currentChapter == 1)
+#endif
+ delay(_tickLength);
+
+ return _sound->voiceIsPlaying() ? 1 : 0;
+}
+
+int KyraEngine_HoF::o2_setDrawNoShapeFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setDrawNoShapeFlag(%p) (%d)", (const void *)script, stackPos(0));
+ _drawNoShapeFlag = (stackPos(0) != 0);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setRunFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setRunFlag(%p) (%d)", (const void *)script, stackPos(0));
+ // this is usually just _runFlag, but since this is just used when the game should play the credits
+ // we handle it a bit different :-)
+ _showOutro = true;
+ _runFlag = false;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_showLetter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_showLetter(%p) (%d)", (const void *)script, stackPos(0));
+ const int letter = stackPos(0);
+ char filename[16];
+
+ _screen->hideMouse();
+
+ showMessage(0, 0xCF);
+ displayInvWsaLastFrame();
+ backUpPage0();
+
+ _screen->copyPalette(2, 0);
+
+ _screen->clearPage(3);
+ _screen->loadBitmap("_NOTE.CPS", 3, 3, 0);
+
+ sprintf(filename, "_NTEPAL%.1d.COL", letter+1);
+ _screen->loadPalette(filename, _screen->getPalette(0));
+
+ _screen->fadeToBlack(0x14);
+
+ sprintf(filename, "LETTER%.1d.%s", letter, _languageExtension[_lang]);
+ uint8 *letterBuffer = _res->fileData(filename, 0);
+ if (!letterBuffer) {
+ // some floppy versions use a TXT extension
+ sprintf(filename, "LETTER%.1d.TXT", letter);
+ letterBuffer = _res->fileData(filename, 0);
+ }
+
+ if (letterBuffer) {
+ bookDecodeText(letterBuffer);
+ bookPrintText(2, letterBuffer, 0xC, 0xA, 0x20);
+ }
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->fadePalette(_screen->getPalette(0), 0x14);
+ _screen->setMouseCursor(0, 0, getShapePtr(0));
+ setMousePos(280, 160);
+
+ _screen->showMouse();
+
+ bool running = true;
+ while (running) {
+ int inputFlag = checkInput(0);
+ removeInputTop();
+
+ if (inputFlag == 198 || inputFlag == 199)
+ running = false;
+
+ _screen->updateScreen();
+ _system->delayMillis(10);
+ }
+
+ _screen->hideMouse();
+ _screen->fadeToBlack(0x14);
+ restorePage0();
+ _screen->copyPalette(0, 2);
+ _screen->fadePalette(_screen->getPalette(0), 0x14);
+ setHandItem(_itemInHand);
+ _screen->showMouse();
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_playFireflyScore(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_playFireflyScore(%p) ()", (const void *)script);
+ if (_sound->getSfxType() == Sound::kAdLib || _sound->getSfxType() == Sound::kPCSpkr ||
+ _sound->getSfxType() == Sound::kMidiMT32 || _sound->getSfxType() == Sound::kMidiGM) {
+ snd_playWanderScoreViaMap(86, 1);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int KyraEngine_HoF::o2_encodeShape(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_encodeShape(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1),
+ stackPos(2), stackPos(3), stackPos(4));
+ _sceneShapeTable[stackPos(0)] = _screen->encodeShape(stackPos(1), stackPos(2), stackPos(3), stackPos(4), 2);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_defineSceneAnim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_defineSceneAnim(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, '%s')", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8),
+ stackPos(9), stackPos(10), stackPos(11), stackPosString(12));
+ int animId = stackPos(0);
+ SceneAnim &anim = _sceneAnims[animId];
+ anim.flags = stackPos(1);
+ anim.x = stackPos(2);
+ anim.y = stackPos(3);
+ anim.x2 = stackPos(4);
+ anim.y2 = stackPos(5);
+ anim.width = stackPos(6);
+ anim.height = stackPos(7);
+ anim.specialSize = stackPos(9);
+ anim.shapeIndex = stackPos(11);
+ if (stackPosString(12) != 0)
+ strcpy(anim.filename, stackPosString(12));
+
+ if (anim.flags & 0x40) {
+ if (!_sceneAnimMovie[animId]->open(anim.filename, 1, 0))
+ error("couldn't load '%s'", anim.filename);
+
+ if (_sceneAnimMovie[animId]->xAdd() || _sceneAnimMovie[animId]->yAdd())
+ anim.wsaFlag = 1;
+ else
+ anim.wsaFlag = 0;
+ }
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_updateSceneAnim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_updateSceneAnim(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ updateSceneAnim(stackPos(0), stackPos(1));
+
+ // HACK: Some animations are really too fast because of missing delay times.
+ // Notice that the delay time is purely subjective set here, it could look
+ // slower or maybe faster in the original, but at least this looks OK for
+ // Raziel^.
+ //
+ // We know currently of some different animations where this happens.
+ // - Where Marco is dangling from the flesh-eating plant (see bug
+ // #1923638 "HoF: Marco missing animation frames").
+ // - After giving the ticket to the captain. He would move very fast
+ // (barely noticeable) onto the ship without this delay.
+ // - The scene after giving the sandwitch to the guards in the city.
+ // (see bug #1926838 "HoF: Animation plays too fast")
+ // This scene script calls o2_delay though, but since this updates
+ // the scene animation scripts again there is no delay for the
+ // animation.
+ // - When the sheriff enters the jail, either to lock you up or to throw
+ // away the key. (see bug #1926838 "HoF: Animation plays too fast").
+
+ if ((stackPos(0) == 2 && _mainCharacter.sceneId == 3) ||
+ (stackPos(0) == 3 && _mainCharacter.sceneId == 33) ||
+ ((stackPos(0) == 1 || stackPos(0) == 2) && _mainCharacter.sceneId == 19) ||
+ ((stackPos(0) == 1 || stackPos(0) == 2) && _mainCharacter.sceneId == 27))
+ _sceneSpecialScriptsTimer[_lastProcessedSceneScript] = _system->getMillis() + _tickLength * 6;
+
+ _specialSceneScriptRunFlag = false;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_addToSceneAnimPosAndUpdate(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_addToSceneAnimPosAndUpdate(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ const int anim = stackPos(0);
+ _sceneAnims[anim].x2 += stackPos(1);
+ _sceneAnims[anim].y2 += stackPos(2);
+ if (_sceneAnims[anim].flags & 2) {
+ _sceneAnims[anim].x += stackPos(1);
+ _sceneAnims[anim].y += stackPos(2);
+ }
+ updateSceneAnim(anim, stackPos(3));
+ _specialSceneScriptRunFlag = false;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_useItemOnMainChar(EMCState *script) {
+ EMCState tmpScript;
+ _emc->init(&tmpScript, &_npcScriptData);
+ _emc->start(&tmpScript, 0);
+ tmpScript.regs[4] = _itemInHand;
+ tmpScript.regs[0] = _mainCharacter.sceneId;
+
+ int oldVocH = _vocHigh;
+ _vocHigh = 0x5A;
+
+ while (_emc->isValid(&tmpScript))
+ _emc->run(&tmpScript);
+
+ _vocHigh = oldVocH;
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_startDialogue(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_startDialogue(%p) (%d)", (const void *)script, stackPos(0));
+ startDialogue(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_addCauldronStateTableEntry(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_addCauldronStateTableEntry(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return addToCauldronStateTable(stackPos(0), stackPos(1)) ? 1 : 0;
+}
+
+int KyraEngine_HoF::o2_setCountDown(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setCountDown(%p) (%d)", (const void *)script, stackPos(0));
+ _scriptCountDown = _system->getMillis() + stackPos(0) * _tickLength;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getCountDown(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getCountDown(%p)", (const void *)script);
+ uint32 time = _system->getMillis();
+ return (time > _scriptCountDown) ? 0 : (_scriptCountDown - time) / _tickLength;
+}
+
+int KyraEngine_HoF::o2_pressColorKey(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_pressColorKey(%p) (%d)", (const void *)script, stackPos(0));
+ for (int i = 6; i; i--)
+ _inputColorCode[i] = _inputColorCode[i - 1];
+ _inputColorCode[0] = stackPos(0) & 0xFF;
+ for (int i = 0; i < 7; i++) {
+ if (_presetColorCode[i] != _inputColorCode[6 - i])
+ return _dbgPass;
+ }
+ return 1;
+}
+
+int KyraEngine_HoF::o2_objectChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_objectChat(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1));
+ if (_flags.isTalkie)
+ warning("Unexpected call: o2_objectChat(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1));
+ else
+ objectChat(stackPosString(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_changeChapter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_changeChapter(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ const int chapter = stackPos(0);
+ const int scene = stackPos(1);
+
+ resetItemList();
+
+ _newChapterFile = chapter;
+ runStartScript(chapter, 0);
+
+ _mainCharacter.dlgIndex = 0;
+ memset(_newSceneDlgState, 0, 32);
+
+ static const int zShapeList[] = { 1, 2, 2, 2, 4 };
+ assert(chapter > 1 && chapter <= ARRAYSIZE(zShapeList));
+ loadCharacterShapes(zShapeList[chapter-1]);
+
+ enterNewScene(scene, (chapter == 2) ? 2 : 0, 0, 0, 0);
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getColorCodeFlag1(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getColorCodeFlag1(%p) ()", (const void *)script);
+ return _colorCodeFlag1;
+}
+
+int KyraEngine_HoF::o2_setColorCodeFlag1(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getColorCodeFlag1(%p) (%d)", (const void *)script, stackPos(0));
+ _colorCodeFlag1 = stackPos(0);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getColorCodeFlag2(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getColorCodeFlag2(%p) ()", (const void *)script);
+ return _colorCodeFlag2;
+}
+
+int KyraEngine_HoF::o2_setColorCodeFlag2(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getColorCodeFlag2(%p) (%d)", (const void *)script, stackPos(0));
+ _colorCodeFlag2 = stackPos(0);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getColorCodeValue(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getColorCodeValue(%p) (%d)", (const void *)script, stackPos(0));
+ return _presetColorCode[stackPos(0)];
+}
+
+int KyraEngine_HoF::o2_setColorCodeValue(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setColorCodeValue(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _presetColorCode[stackPos(0)] = stackPos(1) & 0xFF;
+ return stackPos(1) & 0xFF;
+}
+
+int KyraEngine_HoF::o2_countItemInstances(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_countItemInstances(%p) (%d)", (const void *)script, stackPos(0));
+ Item item = stackPos(0);
+
+ int count = 0;
+ for (int i = 0; i < 20; ++i) {
+ if (_mainCharacter.inventory[i] == item)
+ ++count;
+ }
+
+ if (_itemInHand == item)
+ ++count;
+
+ for (int i = 0; i < 30; ++i) {
+ if (_itemList[i].id == item)
+ ++count;
+ }
+
+ if (_hiddenItems[0] == item && _newChapterFile == 1)
+ ++count;
+ if (_hiddenItems[1] == item && _newChapterFile == 1)
+ ++count;
+ if (_hiddenItems[2] == item && _newChapterFile == 2)
+ ++count;
+ if (_hiddenItems[3] == item && _newChapterFile == 2)
+ ++count;
+ if (_hiddenItems[4] == item && _newChapterFile == 1)
+ ++count;
+
+ return count;
+}
+
+int KyraEngine_HoF::o2_removeItemFromScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_removeItemFromScene(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ const int scene = stackPos(0);
+ const uint16 item = stackPos(1);
+ for (int i = 0; i < 30; ++i) {
+ if (_itemList[i].sceneId == scene && _itemList[i].id == item)
+ _itemList[i].id = kItemNone;
+ }
+ return 0;
+}
+
+int KyraEngine_HoF::o2_initObject(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_initObject(%p) (%d)", (const void *)script, stackPos(0));
+ initTalkObject(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_npcChat(EMCState *script) {
+ if (_flags.isTalkie) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_npcChat(%p) ('%s', %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), _vocHigh, stackPos(2));
+ npcChatSequence(stackPosString(0), stackPos(1), _vocHigh, stackPos(2));
+ } else {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_npcChat(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1));
+ npcChatSequence(stackPosString(0), stackPos(1));
+ }
+ return 0;
+}
+
+int KyraEngine_HoF::o2_deinitObject(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_deinitObject(%p) (%d)", (const void *)script, stackPos(0));
+ deinitTalkObject(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_playTimSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_playTimSequence(%p) ('%s')", (const void *)script, stackPosString(0));
+ playTim(stackPosString(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_makeBookOrCauldronAppear(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_makeBookOrCauldronAppear(%p) (%d)", (const void *)script, stackPos(0));
+ seq_makeBookOrCauldronAppear(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_resetInputColorCode(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_resetInputColorCode(%p)", (const void *)script);
+ memset(_inputColorCode, 255, 7);
+ return 0;
+}
+
+int KyraEngine_HoF::o2_mushroomEffect(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_mushroomEffect(%p)", (const void *)script);
+ _screen->copyPalette(2, 0);
+
+ for (int i = 1; i < 768; i += 3)
+ _screen->getPalette(0)[i] = 0;
+ snd_playSoundEffect(106);
+ _screen->fadePalette(_screen->getPalette(0), 90, &_updateFunctor);
+ _screen->copyPalette(0, 2);
+
+ for (int i = 0; i < 768; i += 3) {
+ _screen->getPalette(0)[i] = _screen->getPalette(0)[i + 1] = 0;
+ _screen->getPalette(0)[i + 2] += (((int8)_screen->getPalette(0)[i + 2]) >> 1);
+ if (_screen->getPalette(0)[i + 2] > 63)
+ _screen->getPalette(0)[i + 2] = 63;
+ }
+ snd_playSoundEffect(106);
+ _screen->fadePalette(_screen->getPalette(0), 90, &_updateFunctor);
+
+ _screen->copyPalette(0, 2);
+ _screen->fadePalette(_screen->getPalette(0), 30, &_updateFunctor);
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_customChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_customChat(%p) ('%s', %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2));
+ strcpy((char *)_unkBuf500Bytes, stackPosString(0));
+ _chatText = (char *)_unkBuf500Bytes;
+ _chatObject = stackPos(1);
+
+ _chatVocHigh = _chatVocLow = -1;
+ objectChatInit(_chatText, _chatObject, _vocHigh, stackPos(2));
+ playVoice(_vocHigh, stackPos(2));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_customChatFinish(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_customChatFinish(%p) ()", (const void *)script);
+ _text->restoreScreen();
+ _chatText = 0;
+ _chatObject = -1;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_setupSceneAnimation(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setupSceneAnimation(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, '%s')", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPosString(12));
+ const int index = stackPos(0);
+ const uint16 flags = stackPos(1);
+
+ restorePage3();
+
+ SceneAnim &anim = _sceneAnims[index];
+ anim.flags = flags;
+ anim.x = stackPos(2);
+ anim.y = stackPos(3);
+ anim.x2 = stackPos(4);
+ anim.y2 = stackPos(5);
+ anim.width = stackPos(6);
+ anim.height = stackPos(7);
+ anim.specialSize = stackPos(9);
+ anim.shapeIndex = stackPos(11);
+ if (stackPosString(12))
+ strcpy(anim.filename, stackPosString(12));
+
+ if (flags & 0x40) {
+ _sceneAnimMovie[index]->open(stackPosString(12), 0, 0);
+ if (_sceneAnimMovie[index]->xAdd() || _sceneAnimMovie[index]->yAdd())
+ anim.wsaFlag = 1;
+ else
+ anim.wsaFlag = 0;
+ }
+
+ AnimObj *obj = &_animObjects[1+index];
+ obj->enabled = 1;
+ obj->needRefresh = 1;
+ obj->specialRefresh = 1;
+ obj->animFlags = anim.flags & 8;
+
+ if (anim.flags & 2)
+ obj->flags = 0x800;
+ else
+ obj->flags = 0;
+
+ if (anim.flags & 4)
+ obj->flags |= 1;
+
+ obj->xPos1 = anim.x;
+ obj->yPos1 = anim.y;
+
+ if ((anim.flags & 0x20) && anim.shapeIndex >= 0)
+ obj->shapePtr = _sceneShapeTable[anim.shapeIndex];
+ else
+ obj->shapePtr = 0;
+
+ if (anim.flags & 0x40) {
+ obj->shapeIndex3 = anim.shapeIndex;
+ obj->animNum = index;
+ } else {
+ obj->shapeIndex3 = 0xFFFF;
+ obj->animNum = 0xFFFF;
+ }
+
+ obj->shapeIndex2 = 0xFFFF;
+ obj->xPos2 = obj->xPos3 = anim.x2;
+ obj->yPos2 = obj->yPos3 = anim.y2;
+ obj->width = anim.width;
+ obj->height = anim.height;
+ obj->width2 = obj->height2 = anim.specialSize;
+
+ _animList = addToAnimListSorted(_animList, obj);
+ obj->needRefresh = 1;
+ obj->specialRefresh = 1;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_stopSceneAnimation(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_stopSceneAnimation(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ const int index = stackPos(0);
+ AnimObj &obj = _animObjects[1+index];
+ restorePage3();
+ obj.shapeIndex3 = 0xFFFF;
+ obj.animNum = 0xFFFF;
+ obj.needRefresh = 1;
+ obj.specialRefresh = 1;
+ if (stackPos(1))
+ refreshAnimObjectsIfNeed();
+ obj.enabled = 0;
+ _animList = deleteAnimListEntry(_animList, &_animObjects[1+index]);
+
+ if (_sceneAnimMovie[index]->opened())
+ _sceneAnimMovie[index]->close();
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_processPaletteIndex(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_processPaletteIndex(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ Palette &palette = _screen->getPalette(0);
+
+ const int index = stackPos(0);
+ const bool updatePalette = (stackPos(4) != 0);
+ const int delayTime = stackPos(5);
+
+ palette[index*3+0] = (stackPos(1) * 0x3F) / 100;
+ palette[index*3+1] = (stackPos(2) * 0x3F) / 100;
+ palette[index*3+2] = (stackPos(3) * 0x3F) / 100;
+
+ if (updatePalette) {
+ if (delayTime > 0)
+ _screen->fadePalette(palette, delayTime, &_updateFunctor);
+ else
+ _screen->setScreenPalette(palette);
+ }
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_updateTwoSceneAnims(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_updateTwoSceneAnims(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ updateSceneAnim(stackPos(0), stackPos(1));
+ updateSceneAnim(stackPos(2), stackPos(3));
+ _specialSceneScriptRunFlag = false;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getRainbowRoomData(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getRainbowRoomData(%p) (%d)", (const void *)script, stackPos(0));
+ return _rainbowRoomData[stackPos(0)];
+}
+
+int KyraEngine_HoF::o2_drawSceneShapeEx(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_drawSceneShapeEx(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ const int itemShape = stackPos(0) + 64;
+ const int x = stackPos(1);
+ const int y = stackPos(2);
+ const bool skipFronUpdate = (stackPos(3) != 0);
+
+ _screen->drawShape(2, _sceneShapeTable[6], x, y, 2, 0);
+ _screen->drawShape(2, getShapePtr(itemShape), x+2, y+2, 2, 0);
+
+ if (!skipFronUpdate) {
+ _screen->copyRegion(x, y, x, y, 0x15, 0x14, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ }
+
+ return 0;
+}
+
+int KyraEngine_HoF::o2_midiSoundFadeout(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_midiSoundFadeout(%p) ()", (const void *)script);
+ if (!stackPos(0)) {
+ if ((_sound->getMusicType() == Sound::kMidiMT32 || _sound->getMusicType() == Sound::kMidiGM) &&
+ (_sound->getSfxType() == Sound::kMidiMT32 || _sound->getSfxType() == Sound::kMidiGM)) {
+ _sound->beginFadeOut();
+ delay(2000, true);
+ _lastMusicCommand = -1;
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int KyraEngine_HoF::o2_getSfxDriver(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getSfxDriver(%p) ()", (const void *)script);
+ if (_sound->getSfxType() == Sound::kAdLib)
+ return 1;
+ else if (_sound->getSfxType() == Sound::kPCSpkr)
+ return 4;
+ else if (_sound->getSfxType() == Sound::kMidiMT32)
+ return 6;
+ else if (_sound->getSfxType() == Sound::kMidiGM)
+ return 7;
+ // TODO: find nice default value
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getVocSupport(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getVocSupport(%p) ()", (const void *)script);
+ // we always support VOC file playback
+ return 1;
+}
+
+int KyraEngine_HoF::o2_getMusicDriver(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getMusicDriver(%p) ()", (const void *)script);
+ if (_sound->getMusicType() == Sound::kAdLib)
+ return 1;
+ else if (_sound->getMusicType() == Sound::kPCSpkr)
+ return 4;
+ else if (_sound->getMusicType() == Sound::kMidiMT32)
+ return 6;
+ else if (_sound->getMusicType() == Sound::kMidiGM)
+ return 7;
+ // TODO: find nice default value
+ return 0;
+}
+
+int KyraEngine_HoF::o2_zanthiaChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_zanthiaChat(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1));
+ objectChat(stackPosString(0), 0, _vocHigh, stackPos(1));
+ return 0;
+}
+
+int KyraEngine_HoF::o2_isVoiceEnabled(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_isVoiceEnabled(%p) ()", (const void *)script);
+ return speechEnabled() ? 1 : 0;
+}
+
+int KyraEngine_HoF::o2_isVoicePlaying(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_isVoicePlaying(%p) ()", (const void *)script);
+ return (snd_voiceIsPlaying() && !skipFlag()) ? 1 : 0;
+}
+
+int KyraEngine_HoF::o2_stopVoicePlaying(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_stopVoicePlaying(%p) ()", (const void *)script);
+ snd_stopVoice();
+ return 0;
+}
+
+int KyraEngine_HoF::o2_getGameLanguage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getGameLanguage(%p) ()", (const void *)script);
+ return _lang;
+}
+
+int KyraEngine_HoF::o2_demoFinale(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_demoFinale(%p) ()", (const void *)script);
+ if (!_flags.isDemo)
+ return 0;
+
+ int tmpSize;
+ const char *const *strings = _staticres->loadStrings(k2IngameTlkDemoStrings, tmpSize);
+ assert(strings);
+
+ _screen->clearPage(0);
+ _screen->loadPalette("THANKS.COL", _screen->getPalette(0));
+ _screen->loadBitmap("THANKS.CPS", 3, 3, 0);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+
+ _screen->_curPage = 0;
+ int y = _lang == 1 ? 70 : 65;
+ for (int i = 0; i < 6; i++)
+ _text->printText(strings[i], _text->getCenterStringX(strings[i], 1, 319), y + i * 10, 255, 207, 0);
+
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->updateScreen();
+
+ _eventList.clear();
+ while (!skipFlag() && !shouldQuit())
+ delay(10);
+
+ _sound->beginFadeOut();
+ _screen->fadeToBlack();
+
+ _runFlag = 0;
+ return 0;
+}
+
+int KyraEngine_HoF::o2_dummy(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_dummy(%p) ()", (const void *)script);
+ return 0;
+}
+
+#pragma mark -
+
+int KyraEngine_HoF::o2a_setCharacterFrame(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2a_setCharacterFrame(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _animNewFrame = stackPos(0);
+ _animDelayTime = stackPos(1);
+ _animNeedUpdate = true;
+ return 0;
+}
+
+#pragma mark -
+
+int KyraEngine_HoF::t2_initChat(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::t2_initChat(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ _chatText = (const char *)tim->text + READ_LE_UINT16(tim->text + (param[0] << 1));
+ _chatObject = param[1];
+
+ if (_flags.lang == Common::JA_JPN) {
+ for (int i = 0; i < _ingameTimJpStrSize; i += 2) {
+ if (!scumm_stricmp(_chatText, _ingameTimJpStr[i]))
+ _chatText = _ingameTimJpStr[i + 1];
+ }
+ }
+
+ objectChatInit(_chatText, _chatObject);
+ return 0;
+}
+
+int KyraEngine_HoF::t2_updateSceneAnim(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::t2_updateSceneAnim(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]);
+ updateSceneAnim(param[1], param[0]);
+ return 0;
+}
+
+int KyraEngine_HoF::t2_resetChat(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::t2_resetChat(%p, %p) ()", (const void *)tim, (const void *)param);
+ _text->restoreScreen();
+ _chatText = 0;
+ _chatObject = -1;
+ return 0;
+}
+
+int KyraEngine_HoF::t2_playSoundEffect(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::t2_playSoundEffect(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ snd_playSoundEffect(*param);
+ return 0;
+}
+
+#pragma mark -
+
+typedef Common::Functor1Mem<EMCState *, int, KyraEngine_HoF> OpcodeV2;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV2(this, &KyraEngine_HoF::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV2(this, 0))
+
+typedef Common::Functor2Mem<const TIM *, const uint16 *, int, KyraEngine_HoF> TIMOpcodeV2;
+#define OpcodeTim(x) _timOpcodes.push_back(new TIMOpcodeV2(this, &KyraEngine_HoF::x))
+#define OpcodeTimUnImpl() _timOpcodes.push_back(new TIMOpcodeV2(this, 0))
+
+void KyraEngine_HoF::setupOpcodeTable() {
+ Common::Array<const Opcode *> *table = 0;
+
+ _opcodes.reserve(176);
+ SetOpcodeTable(_opcodes);
+ // 0x00
+ Opcode(o2_setCharacterFacingRefresh);
+ Opcode(o2_setCharacterPos);
+ Opcode(o2_defineObject);
+ Opcode(o2_refreshCharacter);
+ // 0x04
+ Opcode(o2_getCharacterX);
+ Opcode(o2_getCharacterY);
+ Opcode(o2_getCharacterFacing);
+ Opcode(o2_getCharacterScene);
+ // 0x08
+ Opcode(o2_setSceneComment);
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ Opcode(o2_setCharacterAnimFrame);
+ // 0x0C
+ Opcode(o2_setCharacterFacingOverwrite);
+ Opcode(o2_trySceneChange);
+ Opcode(o2_moveCharacter);
+ Opcode(o2_customCharacterChat);
+ // 0x10
+ Opcode(o2_soundFadeOut);
+ Opcode(o2_showChapterMessage);
+ Opcode(o2_restoreTalkTextMessageBkgd);
+ OpcodeUnImpl();
+ // 0x14
+ Opcode(o2_wsaClose);
+ Opcode(o2_backUpScreen);
+ Opcode(o2_restoreScreen);
+ Opcode(o2_displayWsaFrame);
+ // 0x18
+ Opcode(o2_displayWsaSequentialFramesLooping);
+ Opcode(o2_wsaOpen);
+ Opcode(o2_displayWsaSequentialFrames);
+ Opcode(o2_displayWsaSequence);
+ // 0x1C
+ Opcode(o2_addItemToInventory);
+ Opcode(o2_drawShape);
+ Opcode(o2_addItemToCurScene);
+ Opcode(o2_dummy); // the original used this opcode to limit the mouse range temporary,
+ // since that is of no use and not really important we just use a dummy here
+ // 0x20
+ Opcode(o2_checkForItem);
+ Opcode(o2_loadSoundFile);
+ Opcode(o2_removeSlotFromInventory);
+ Opcode(o2_defineItem);
+ // 0x24
+ Opcode(o2_removeItemFromInventory);
+ Opcode(o2_countItemInInventory);
+ Opcode(o2_countItemsInScene);
+ Opcode(o1_queryGameFlag);
+ // 0x28
+ Opcode(o1_resetGameFlag);
+ Opcode(o1_setGameFlag);
+ Opcode(o1_setHandItem);
+ Opcode(o1_removeHandItem);
+ // 0x2C
+ Opcode(o1_getMouseState);
+ Opcode(o1_hideMouse);
+ Opcode(o2_addSpecialExit);
+ Opcode(o1_setMousePos);
+ // 0x30
+ Opcode(o1_showMouse);
+ OpcodeUnImpl();
+ Opcode(o2_wipeDownMouseItem);
+ Opcode(o2_getElapsedSecs);
+ // 0x34
+ Opcode(o2_getTimerDelay);
+ Opcode(o1_playSoundEffect);
+ Opcode(o2_delaySecs);
+ Opcode(o2_delay);
+ // 0x38
+ Opcode(o2_dummy);
+ Opcode(o2_setTimerDelay);
+ Opcode(o2_setScaleTableItem);
+ Opcode(o2_setDrawLayerTableItem);
+ // 0x3C
+ Opcode(o2_setCharPalEntry);
+ Opcode(o2_loadZShapes);
+ Opcode(o2_drawSceneShape);
+ Opcode(o2_drawSceneShapeOnPage);
+ // 0x40
+ Opcode(o2_disableAnimObject);
+ Opcode(o2_enableAnimObject);
+ Opcode(o2_dummy);
+ Opcode(o2_loadPalette384);
+ // 0x44
+ Opcode(o2_setPalette384);
+ Opcode(o2_restoreBackBuffer);
+ Opcode(o2_backUpInventoryGfx);
+ Opcode(o2_disableSceneAnim);
+ // 0x48
+ Opcode(o2_enableSceneAnim);
+ Opcode(o2_restoreInventoryGfx);
+ Opcode(o2_setSceneAnimPos2);
+ Opcode(o2_update);
+ // 0x4C
+ OpcodeUnImpl();
+ Opcode(o2_fadeScenePal);
+ Opcode(o2_dummy);
+ Opcode(o2_dummy);
+ // 0x50
+ Opcode(o2_enterNewScene);
+ Opcode(o2_switchScene);
+ Opcode(o2_getShapeFlag1);
+ Opcode(o2_setPathfinderFlag);
+ // 0x54
+ Opcode(o2_getSceneExitToFacing);
+ Opcode(o2_setLayerFlag);
+ Opcode(o2_setZanthiaPos);
+ Opcode(o2_loadMusicTrack);
+ // 0x58
+ Opcode(o1_playWanderScoreViaMap);
+ Opcode(o1_playSoundEffect);
+ Opcode(o2_setSceneAnimPos);
+ Opcode(o1_blockInWalkableRegion);
+ // 0x5C
+ Opcode(o1_blockOutWalkableRegion);
+ OpcodeUnImpl();
+ Opcode(o2_setCauldronState);
+ Opcode(o2_showItemString);
+ // 0x60
+ Opcode(o1_getRand);
+ Opcode(o2_isAnySoundPlaying);
+ Opcode(o1_setDeathHandler);
+ Opcode(o2_setDrawNoShapeFlag);
+ // 0x64
+ Opcode(o2_setRunFlag);
+ Opcode(o2_showLetter);
+ OpcodeUnImpl();
+ Opcode(o1_fillRect);
+ // 0x68
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ Opcode(o2_playFireflyScore);
+ Opcode(o2_waitForConfirmationClick);
+ // 0x6C
+ Opcode(o2_encodeShape);
+ Opcode(o2_defineRoomEntrance);
+ Opcode(o2_runAnimationScript);
+ Opcode(o2_setSpecialSceneScriptRunTime);
+ // 0x70
+ Opcode(o2_defineSceneAnim);
+ Opcode(o2_updateSceneAnim);
+ Opcode(o2_updateSceneAnim);
+ Opcode(o2_addToSceneAnimPosAndUpdate);
+ // 0x74
+ Opcode(o2_useItemOnMainChar);
+ Opcode(o2_startDialogue);
+ Opcode(o2_randomSceneChat);
+ Opcode(o2_setDlgIndex);
+ // 0x78
+ Opcode(o2_getDlgIndex);
+ Opcode(o2_defineScene);
+ Opcode(o2_addCauldronStateTableEntry);
+ Opcode(o2_setCountDown);
+ // 0x7C
+ Opcode(o2_getCountDown);
+ Opcode(o2_dummy);
+ Opcode(o2_dummy);
+ Opcode(o2_pressColorKey);
+ // 0x80
+ Opcode(o2_objectChat);
+ Opcode(o2_changeChapter);
+ Opcode(o2_getColorCodeFlag1);
+ Opcode(o2_setColorCodeFlag1);
+ // 0x84
+ Opcode(o2_getColorCodeFlag2);
+ Opcode(o2_setColorCodeFlag2);
+ Opcode(o2_getColorCodeValue);
+ Opcode(o2_setColorCodeValue);
+ // 0x88
+ Opcode(o2_countItemInstances);
+ Opcode(o2_removeItemFromScene);
+ Opcode(o2_initObject);
+ Opcode(o2_npcChat);
+ // 0x8C
+ Opcode(o2_deinitObject);
+ Opcode(o2_playTimSequence);
+ Opcode(o2_makeBookOrCauldronAppear);
+ Opcode(o2_setSpecialSceneScriptState);
+ // 0x90
+ Opcode(o2_clearSpecialSceneScriptState);
+ Opcode(o2_querySpecialSceneScriptState);
+ Opcode(o2_resetInputColorCode);
+ Opcode(o2_setHiddenItemsEntry);
+ // 0x94
+ Opcode(o2_getHiddenItemsEntry);
+ Opcode(o2_mushroomEffect);
+ Opcode(o2_wsaClose);
+ Opcode(o2_meanWhileScene);
+ // 0x98
+ Opcode(o2_customChat);
+ Opcode(o2_customChatFinish);
+ Opcode(o2_setupSceneAnimation);
+ Opcode(o2_stopSceneAnimation);
+ // 0x9C
+ Opcode(o2_disableTimer);
+ Opcode(o2_enableTimer);
+ Opcode(o2_setTimerCountdown);
+ Opcode(o2_processPaletteIndex);
+ // 0xA0
+ Opcode(o2_updateTwoSceneAnims);
+ Opcode(o2_getRainbowRoomData);
+ Opcode(o2_drawSceneShapeEx);
+ Opcode(o2_midiSoundFadeout);
+ // 0xA4
+ Opcode(o2_getSfxDriver);
+ Opcode(o2_getVocSupport);
+ Opcode(o2_getMusicDriver);
+ Opcode(o2_setVocHigh);
+ // 0xA8
+ Opcode(o2_getVocHigh);
+ Opcode(o2_zanthiaChat);
+ Opcode(o2_isVoiceEnabled);
+ Opcode(o2_isVoicePlaying);
+ // 0xAC
+ Opcode(o2_stopVoicePlaying);
+ Opcode(o2_getGameLanguage);
+ Opcode(o2_demoFinale);
+ Opcode(o2_dummy);
+
+ _opcodesAnimation.reserve(6);
+ SetOpcodeTable(_opcodesAnimation);
+
+ // 0x00
+ Opcode(o2a_setAnimationShapes);
+ Opcode(o2a_setCharacterFrame);
+ Opcode(o1_playSoundEffect);
+ Opcode(o2_fadeScenePal);
+ // 0x04
+ _flags.isTalkie ? Opcode(o2a_setResetFrame) : Opcode(o2_dummy);
+ Opcode(o2_dummy);
+
+ // ---- TIM opcodes
+
+ _timOpcodes.reserve(4);
+ // 0x00
+ OpcodeTim(t2_initChat);
+ OpcodeTim(t2_updateSceneAnim);
+ OpcodeTim(t2_resetChat);
+ OpcodeTim(t2_playSoundEffect);
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/script/script_lok.cpp b/engines/kyra/script/script_lok.cpp
new file mode 100644
index 0000000000..325ee67c9e
--- /dev/null
+++ b/engines/kyra/script/script_lok.cpp
@@ -0,0 +1,1962 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/kyra_lok.h"
+#include "kyra/engine/sprites.h"
+#include "kyra/graphics/wsamovie.h"
+#include "kyra/graphics/animator_lok.h"
+#include "kyra/text/text.h"
+#include "kyra/engine/timer.h"
+#include "kyra/sound/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+int KyraEngine_LoK::o1_magicInMouseItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_magicInMouseItem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ magicInMouseItem(stackPos(0), stackPos(1), -1);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_characterSays(EMCState *script) {
+ resetSkipFlag();
+ if (_flags.isTalkie) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_characterSays(%p) (%d, '%s', %d, %d)", (const void *)script, stackPos(0), stackPosString(1), stackPos(2), stackPos(3));
+ characterSays(stackPos(0), stackPosString(1), stackPos(2), stackPos(3));
+ } else {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_characterSays(%p) ('%s', %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2));
+ const char *string = stackPosString(0);
+
+ if ((_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) && _flags.lang == Common::JA_JPN) {
+ static const uint8 townsString1[] = {
+ 0x83, 0x75, 0x83, 0x89, 0x83, 0x93, 0x83, 0x83, 0x93, 0x81,
+ 0x41, 0x82, 0xDC, 0x82, 0xBD, 0x97, 0x88, 0x82, 0xBD, 0x82,
+ 0xCC, 0x82, 0xA9, 0x81, 0x48, 0x00, 0x00, 0x00
+ };
+ static const uint8 townsString2[] = {
+ 0x83, 0x75, 0x83, 0x89, 0x83, 0x93, 0x83, 0x5C, 0x83, 0x93,
+ 0x81, 0x41, 0x82, 0xDC, 0x82, 0xBD, 0x97, 0x88, 0x82, 0xBD,
+ 0x82, 0xCC, 0x82, 0xA9, 0x81, 0x48, 0x00, 0x00
+ };
+
+ if (strncmp((const char *)townsString1, string, sizeof(townsString1)) == 0)
+ string = (const char *)townsString2;
+ }
+
+ characterSays(-1, string, stackPos(1), stackPos(2));
+ }
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_delay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_delay(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ if (stackPos(1)) {
+ warning("STUB: special o1_delay");
+ // delete this after correct implementing
+ delayWithTicks(stackPos(0));
+ } else {
+ delayWithTicks(stackPos(0));
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_drawSceneAnimShape(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_drawSceneAnimShape(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ _screen->drawShape(stackPos(4), _sprites->_sceneShapes[stackPos(0)], stackPos(1), stackPos(2), 0, (stackPos(3) != 0) ? 1 : 0);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_runNPCScript(EMCState *script) {
+ warning("STUB: o1_runNPCScript");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setSpecialExitList(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setSpecialExitList(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9));
+
+ for (int i = 0; i < 10; ++i)
+ _exitList[i] = stackPos(i);
+ _exitListPtr = _exitList;
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_walkPlayerToPoint(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_walkPlayerToPoint(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+
+ int normalTimers = stackPos(2);
+ if (!normalTimers) {
+ _timer->disable(19);
+ _timer->disable(14);
+ _timer->disable(18);
+ }
+
+ int reinitScript = handleSceneChange(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+
+ if (!normalTimers) {
+ _timer->enable(19);
+ _timer->enable(14);
+ _timer->enable(18);
+ }
+
+ if (reinitScript)
+ _emc->init(script, script->dataPtr);
+
+ if (_sceneChangeState) {
+ _sceneChangeState = 0;
+ return 1;
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_dropItemInScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_dropItemInScene(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ int item = stackPos(0);
+ int xpos = stackPos(1);
+ int ypos = stackPos(2);
+
+ byte freeItem = findFreeItemInScene(_currentCharacter->sceneId);
+ if (freeItem != 0xFF) {
+ int sceneId = _currentCharacter->sceneId;
+ Room *room = &_roomTable[sceneId];
+ room->itemsXPos[freeItem] = xpos;
+ room->itemsYPos[freeItem] = ypos;
+ room->itemsTable[freeItem] = item;
+
+ _animator->animAddGameItem(freeItem, sceneId);
+ _animator->updateAllObjectShapes();
+ } else {
+ if (item == 43)
+ placeItemInGenericMapScene(item, 0);
+ else
+ placeItemInGenericMapScene(item, 1);
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_drawAnimShapeIntoScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_drawAnimShapeIntoScene(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ _animator->restoreAllObjectBackgrounds();
+ int shape = stackPos(0);
+ int xpos = stackPos(1);
+ int ypos = stackPos(2);
+ int flags = (stackPos(3) != 0) ? 1 : 0;
+ _screen->drawShape(2, _sprites->_sceneShapes[shape], xpos, ypos, 0, flags);
+ _screen->drawShape(0, _sprites->_sceneShapes[shape], xpos, ypos, 0, flags);
+ _animator->flagAllObjectsForBkgdChange();
+ _animator->preserveAnyChangedBackgrounds();
+ _animator->flagAllObjectsForRefresh();
+ _animator->updateAllObjectShapes();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_savePageToDisk(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_savePageToDisk(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1));
+ _screen->savePageToDisk(stackPosString(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_sceneAnimOn(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_sceneAnimOn(%p) (%d)", (const void *)script, stackPos(0));
+ _sprites->_anims[stackPos(0)].play = true;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_sceneAnimOff(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_sceneAnimOff(%p) (%d)", (const void *)script, stackPos(0));
+ _sprites->_anims[stackPos(0)].play = false;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getElapsedSeconds(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getElapsedSeconds(%p) ()", (const void *)script);
+ return _system->getMillis() / 1000;
+}
+
+int KyraEngine_LoK::o1_mouseIsPointer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_mouseIsPointer(%p) ()", (const void *)script);
+ return (_itemInHand == kItemNone);
+}
+
+int KyraEngine_LoK::o1_runSceneAnimUntilDone(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_runSceneAnimUntilDone(%p) (%d)", (const void *)script, stackPos(0));
+ _screen->hideMouse();
+ _animator->restoreAllObjectBackgrounds();
+ _sprites->_anims[stackPos(0)].play = true;
+ _animator->sprites()[stackPos(0)].active = 1;
+ _animator->flagAllObjectsForBkgdChange();
+ _animator->preserveAnyChangedBackgrounds();
+ while (_sprites->_anims[stackPos(0)].play) {
+ _sprites->updateSceneAnims();
+ _animator->updateAllObjectShapes();
+ delay(10);
+ }
+ _animator->restoreAllObjectBackgrounds();
+ _screen->showMouse();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_fadeSpecialPalette(EMCState *script) {
+ if (_flags.platform == Common::kPlatformAmiga) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_fadeSpecialPalette(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ if (_currentCharacter->sceneId != 45) {
+ if (stackPos(0) == 13) {
+ _screen->copyPalette(0, 12);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+ } else {
+ setupZanthiaPalette(stackPos(0));
+ _screen->getPalette(0).copy(_screen->getPalette(4), 12, 1);
+ _screen->fadePalette(_screen->getPalette(0), 2);
+ }
+ } else {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_fadeSpecialPalette(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ _screen->fadeSpecialPalette(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_phaseInSameScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_phaseInSameScene(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ transcendScenes(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setScenePhasingFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setScenePhasingFlag(%p) ()", (const void *)script);
+ _scenePhasingFlag = 1;
+ return 1;
+}
+
+int KyraEngine_LoK::o1_resetScenePhasingFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_resetScenePhasingFlag(%p) ()", (const void *)script);
+ _scenePhasingFlag = 0;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_queryScenePhasingFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_queryScenePhasingFlag(%p) ()", (const void *)script);
+ return _scenePhasingFlag;
+}
+
+int KyraEngine_LoK::o1_sceneToDirection(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_sceneToDirection(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ assert(stackPos(0) < _roomTableSize);
+ Room *curRoom = &_roomTable[stackPos(0)];
+ uint16 returnValue = 0xFFFF;
+ switch (stackPos(1)) {
+ case 0:
+ returnValue = curRoom->northExit;
+ break;
+
+ case 2:
+ returnValue = curRoom->eastExit;
+ break;
+
+ case 4:
+ returnValue = curRoom->southExit;
+ break;
+
+ case 6:
+ returnValue = curRoom->westExit;
+ break;
+
+ default:
+ break;
+ }
+ if (returnValue == 0xFFFF)
+ return -1;
+ return returnValue;
+}
+
+int KyraEngine_LoK::o1_setBirthstoneGem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setBirthstoneGem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ int index = stackPos(0);
+ if (index < 4 && index >= 0) {
+ _birthstoneGemTable[index] = stackPos(1);
+ return 1;
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_placeItemInGenericMapScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_placeItemInGenericMapScene(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ placeItemInGenericMapScene(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setBrandonStatusBit(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setBrandonStatusBit(%p) (%d)", (const void *)script, stackPos(0));
+ _brandonStatusBit |= stackPos(0);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_delaySecs(EMCState *script) {
+ if (_flags.isTalkie && speechEnabled()) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_voiceDelay(%p) (%d)", (const void *)script, stackPos(0));
+ if (stackPos(0) == 0) {
+ snd_voiceWaitForFinish(true);
+ } else if (stackPos(0) < 0) {
+ uint32 time = ABS(stackPos(0)) * _tickLength;
+ delay(time, true);
+ }
+ } else {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_delaySecs(%p) (%d)", (const void *)script, stackPos(0));
+ if (stackPos(0) >= 0 && !skipFlag())
+ delay(stackPos(0) * 1000, true);
+ }
+
+ resetSkipFlag();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getCharacterScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getCharacterScene(%p) (%d)", (const void *)script, stackPos(0));
+ return _characterList[stackPos(0)].sceneId;
+}
+
+int KyraEngine_LoK::o1_runNPCSubscript(EMCState *script) {
+ warning("STUB: o1_runNPCSubscript");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_magicOutMouseItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_magicOutMouseItem(%p) (%d)", (const void *)script, stackPos(0));
+ magicOutMouseItem(stackPos(0), -1);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_internalAnimOn(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_internalAnimOn(%p) (%d)", (const void *)script, stackPos(0));
+ _animator->sprites()[stackPos(0)].active = 1;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_forceBrandonToNormal(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_forceBrandonToNormal(%p) ()", (const void *)script);
+ checkAmuletAnimFlags();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_poisonDeathNow(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_poisonDeathNow(%p) ()", (const void *)script);
+ seq_poisonDeathNow(1);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setScaleMode(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setScaleMode(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ int len = stackPos(0);
+ int setValue1 = stackPos(1);
+ int start2 = stackPos(2);
+ int setValue2 = stackPos(3);
+ for (int i = 0; i < len; ++i)
+ _scaleTable[i] = setValue1;
+ int temp = setValue2 - setValue1;
+ int temp2 = start2 - len;
+ for (int i = len, offset = 0; i < start2; ++i, ++offset)
+ _scaleTable[i] = (offset * temp) / temp2 + setValue1;
+ for (int i = start2; i < 145; ++i)
+ _scaleTable[i] = setValue2;
+ _scaleMode = 1;
+ return _scaleMode;
+}
+
+int KyraEngine_LoK::o1_openWSAFile(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_openWSAFile(%p) ('%s', %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2), stackPos(3));
+
+ const char *filename = stackPosString(0);
+ int wsaIndex = stackPos(1);
+
+ _movieObjects[wsaIndex]->open(filename, (stackPos(3) != 0) ? 1 : 0, 0);
+ assert(_movieObjects[wsaIndex]->opened());
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_closeWSAFile(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_closeWSAFile(%p) (%d)", (const void *)script, stackPos(0));
+
+ int wsaIndex = stackPos(0);
+ if (_movieObjects[wsaIndex])
+ _movieObjects[wsaIndex]->close();
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_runWSAFromBeginningToEnd(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_runWSAFromBeginningToEnd(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+
+ _screen->hideMouse();
+
+ bool running = true;
+
+ int xpos = stackPos(0);
+ int ypos = stackPos(1);
+ int waitTime = stackPos(2);
+ int wsaIndex = stackPos(3);
+ int worldUpdate = stackPos(4);
+ int wsaFrame = 0;
+
+ while (running) {
+ const uint32 continueTime = waitTime * _tickLength + _system->getMillis();
+
+ _movieObjects[wsaIndex]->displayFrame(wsaFrame++, 0, xpos, ypos, 0, 0, 0);
+ if (wsaFrame >= _movieObjects[wsaIndex]->frames())
+ running = false;
+
+ delayUntil(continueTime, false, worldUpdate != 0);
+ }
+
+ _screen->showMouse();
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_displayWSAFrame(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSAFrame(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ int frame = stackPos(0);
+ int xpos = stackPos(1);
+ int ypos = stackPos(2);
+ int waitTime = stackPos(3);
+ int wsaIndex = stackPos(4);
+ _screen->hideMouse();
+ const uint32 continueTime = waitTime * _tickLength + _system->getMillis();
+ _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos, 0, 0, 0);
+ delayUntil(continueTime, false, true);
+ _screen->showMouse();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_enterNewScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_enterNewScene(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ enterNewScene(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setSpecialEnterXAndY(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setSpecialEnterXAndY(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _brandonPosX = stackPos(0);
+ _brandonPosY = stackPos(1);
+ if (_brandonPosX + 1 == 0 && _brandonPosY + 1 == 0)
+ _currentCharacter->currentAnimFrame = 88;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_runWSAFrames(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_runWSAFrames(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ int xpos = stackPos(0);
+ int ypos = stackPos(1);
+ int delayTime = stackPos(2);
+ int startFrame = stackPos(3);
+ int endFrame = stackPos(4);
+ int wsaIndex = stackPos(5);
+ _screen->hideMouse();
+ for (; startFrame <= endFrame; ++startFrame) {
+ const uint32 nextRun = _system->getMillis() + delayTime * _tickLength;
+ _movieObjects[wsaIndex]->displayFrame(startFrame, 0, xpos, ypos, 0, 0, 0);
+ delayUntil(nextRun, false, true);
+ }
+ _screen->showMouse();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_popBrandonIntoScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_popBrandonIntoScene(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ int changeScaleMode = stackPos(3);
+ int xpos = (int16)(stackPos(0) & 0xFFFC);
+ int ypos = (int16)(stackPos(1) & 0xFFFE);
+ int facing = stackPos(2);
+ _currentCharacter->x1 = _currentCharacter->x2 = xpos;
+ _currentCharacter->y1 = _currentCharacter->y2 = ypos;
+ _currentCharacter->facing = facing;
+ _currentCharacter->currentAnimFrame = 7;
+ int xOffset = _defaultShapeTable[0].xOffset;
+ int yOffset = _defaultShapeTable[0].yOffset;
+ int width = _defaultShapeTable[0].w << 3;
+ int height = _defaultShapeTable[0].h;
+ Animator_LoK::AnimObject *curAnim = _animator->actors();
+
+ if (changeScaleMode) {
+ curAnim->x1 = _currentCharacter->x1;
+ curAnim->y1 = _currentCharacter->y1;
+ _animator->_brandonScaleY = _scaleTable[_currentCharacter->y1];
+ _animator->_brandonScaleX = _animator->_brandonScaleY;
+
+ int animWidth = _animator->fetchAnimWidth(curAnim->sceneAnimPtr, _animator->_brandonScaleX) >> 1;
+ int animHeight = _animator->fetchAnimHeight(curAnim->sceneAnimPtr, _animator->_brandonScaleY);
+
+ animWidth = (xOffset * animWidth) / width;
+ animHeight = (yOffset * animHeight) / height;
+
+ curAnim->x2 = curAnim->x1 += animWidth;
+ curAnim->y2 = curAnim->y1 += animHeight;
+ } else {
+ curAnim->x2 = curAnim->x1 = _currentCharacter->x1 + xOffset;
+ curAnim->y2 = curAnim->y1 = _currentCharacter->y1 + yOffset;
+ }
+
+ int scaleModeBackup = _scaleMode;
+ if (changeScaleMode)
+ _scaleMode = 1;
+
+ _animator->animRefreshNPC(0);
+ _animator->preserveAllBackgrounds();
+ _animator->prepDrawAllObjects();
+ _animator->copyChangedObjectsForward(0);
+
+ _scaleMode = scaleModeBackup;
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_restoreAllObjectBackgrounds(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_restoreAllObjectBackgrounds(%p) (%d)", (const void *)script, stackPos(0));
+ int disable = stackPos(0);
+ int activeBackup = 0;
+ if (disable) {
+ activeBackup = _animator->actors()->active;
+ _animator->actors()->active = 0;
+ }
+ _animator->restoreAllObjectBackgrounds();
+ if (disable)
+ _animator->actors()->active = activeBackup;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setCustomPaletteRange(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCustomPaletteRange(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ if (_flags.platform == Common::kPlatformAmiga) {
+ if (_currentCharacter->sceneId == 45) {
+ setupZanthiaPalette(stackPos(0));
+ } else if (stackPos(0) == 29) {
+ _screen->copyPalette(0, 11);
+ } else if (stackPos(0) == 13) {
+ _screen->copyPalette(0, 12);
+ }
+ } else {
+ if (!_specialPalettes[stackPos(0)])
+ warning("KyraEngine_LoK::o1_setCustomPaletteRange(): Trying to use missing special palette %d", stackPos(0));
+ else
+ _screen->getPalette(1).copy(_specialPalettes[stackPos(0)], 0, stackPos(2), stackPos(1));
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_loadPageFromDisk(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_loadPageFromDisk(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1));
+ _screen->loadPageFromDisk(stackPosString(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_customPrintTalkString(EMCState *script) {
+ if (_flags.isTalkie) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_customPrintTalkString(%p) (%d, '%s', %d, %d, %d)", (const void *)script, stackPos(0), stackPosString(1), stackPos(2), stackPos(3), stackPos(4) & 0xFF);
+
+ if (speechEnabled()) {
+ snd_voiceWaitForFinish();
+ snd_playVoiceFile(stackPos(0));
+ }
+
+ resetSkipFlag();
+ if (textEnabled())
+ _text->printTalkTextMessage(stackPosString(1), stackPos(2), stackPos(3), stackPos(4) & 0xFF, 0, 2);
+ } else {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_customPrintTalkString(%p) ('%s', %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2), stackPos(3) & 0xFF);
+ resetSkipFlag();
+ _text->printTalkTextMessage(stackPosString(0), stackPos(1), stackPos(2), stackPos(3) & 0xFF, 0, 2);
+ }
+ _screen->updateScreen();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_restoreCustomPrintBackground(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_restoreCustomPrintBackground(%p) ()", (const void *)script);
+ _text->restoreTalkTextMessageBkgd(2, 0);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getCharacterX(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getCharacterX(%p) (%d)", (const void *)script, stackPos(0));
+ return _characterList[stackPos(0)].x1;
+}
+
+int KyraEngine_LoK::o1_getCharacterY(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getCharacterY(%p) (%d)", (const void *)script, stackPos(0));
+ return _characterList[stackPos(0)].y1;
+}
+
+int KyraEngine_LoK::o1_setCharacterFacing(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCharacterFacing(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ int character = stackPos(0);
+ int facing = stackPos(1);
+ int newAnimFrame = stackPos(2);
+
+ _animator->restoreAllObjectBackgrounds();
+ if (newAnimFrame != -1)
+ _characterList[character].currentAnimFrame = newAnimFrame;
+ _characterList[character].facing = facing;
+ _animator->animRefreshNPC(character);
+ _animator->preserveAllBackgrounds();
+ _animator->prepDrawAllObjects();
+ _animator->copyChangedObjectsForward(0);
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_copyWSARegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_copyWSARegion(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ int xpos = stackPos(0);
+ int ypos = stackPos(1);
+ int width = stackPos(2);
+ int height = stackPos(3);
+ int srcPage = stackPos(4);
+ int dstPage = stackPos(5);
+ _screen->copyRegion(xpos, ypos, xpos, ypos, width, height, srcPage, dstPage);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_printText(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_printText(%p) ('%s', %d, %d, 0x%X, 0x%X)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ if (_flags.lang == Common::JA_JPN && stackPos(3) == 7)
+ _screen->printText(stackPosString(0), stackPos(1), stackPos(2), 0, 0x80);
+ else
+ _screen->printText(stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ _screen->updateScreen();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_loadSoundFile(EMCState *script) {
+ warning("STUB: o1_loadSoundFile");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_displayWSAFrameOnHidPage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSAFrameOnHidPage(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ int frame = stackPos(0);
+ int xpos = stackPos(1);
+ int ypos = stackPos(2);
+ int waitTime = stackPos(3);
+ int wsaIndex = stackPos(4);
+
+ _screen->hideMouse();
+ const uint32 continueTime = waitTime * _tickLength + _system->getMillis();
+ _movieObjects[wsaIndex]->displayFrame(frame, 2, xpos, ypos, 0, 0, 0);
+ delayUntil(continueTime, false, true);
+ _screen->showMouse();
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) {
+ if (_flags.isTalkie)
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSASequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ else
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSASequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6));
+ int startFrame = stackPos(0);
+ int endFrame = stackPos(1);
+ int xpos = stackPos(2);
+ int ypos = stackPos(3);
+ int waitTime = stackPos(4);
+ int wsaIndex = stackPos(5);
+ int maxTime = stackPos(6);
+
+ if (_flags.isTalkie) {
+ int specialTime = stackPos(7);
+ if (specialTime) {
+ uint32 voiceTime = snd_getVoicePlayTime();
+ if (voiceTime) {
+ int displayFrames = ABS(endFrame - startFrame) + 1;
+ displayFrames *= maxTime;
+ assert(displayFrames != 0);
+
+ bool voiceSync = false;
+
+ if (specialTime < 0) {
+ voiceSync = true;
+ specialTime = ABS(specialTime);
+ }
+
+ voiceTime *= specialTime;
+ voiceTime /= 100;
+
+ if (voiceSync) {
+ uint32 voicePlayedTime = _sound->voicePlayedTime(_speechHandle);
+ if (voicePlayedTime >= voiceTime)
+ voiceTime = 0;
+ else
+ voiceTime -= voicePlayedTime;
+ }
+
+ waitTime = voiceTime / displayFrames;
+ waitTime /= _tickLength;
+ }
+ }
+ }
+
+ if (maxTime - 1 <= 0)
+ maxTime = 1;
+
+ // WORKAROUND for bug #1498221 "KYRA1: Glitches when meeting Zanthia".
+ // The original did not do a forced screen update after displaying a WSA
+ // frame while we have to do it, which makes Brandon disappear for a short
+ // moment. That is not supposed to happen. So we're not updating the
+ // screen for this special case.
+ // This is only an issue for the CD version, but since the floppy version
+ // does not use the specified paramaeters like these, it is safe to enable
+ // it for all versions.
+ if (startFrame == 18 && endFrame == 18 && waitTime == 10 && wsaIndex == 0 && _currentRoom == 45) {
+ _movieObjects[wsaIndex]->displayFrame(18, 0, xpos, ypos, 0, 0, 0);
+ // We call delayMillis manually here to avoid the screen getting
+ // updated.
+ _system->delayMillis(waitTime * _tickLength);
+ return 0;
+ }
+
+ int curTime = 0;
+ _screen->hideMouse();
+ while (curTime < maxTime) {
+ if (endFrame >= startFrame) {
+ int frame = startFrame;
+ while (endFrame >= frame) {
+ const uint32 continueTime = waitTime * _tickLength + _system->getMillis();
+ _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos, 0, 0, 0);
+ delayUntil(continueTime, false, true);
+ ++frame;
+ }
+ } else {
+ int frame = startFrame;
+ while (endFrame <= frame) {
+ const uint32 continueTime = waitTime * _tickLength + _system->getMillis();
+ _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos, 0, 0, 0);
+ delayUntil(continueTime, false, true);
+ --frame;
+ }
+ }
+
+ if (skipFlag())
+ break;
+ else
+ ++curTime;
+ }
+ _screen->showMouse();
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_refreshCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_refreshCharacter(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ int character = stackPos(0);
+ int animFrame = stackPos(1);
+ int newFacing = stackPos(2);
+ int updateShapes = stackPos(3);
+ _characterList[character].currentAnimFrame = animFrame;
+ if (newFacing != -1)
+ _characterList[character].facing = newFacing;
+ _animator->animRefreshNPC(character);
+ if (updateShapes)
+ _animator->updateAllObjectShapes();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_internalAnimOff(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_internalAnimOff(%p) (%d)", (const void *)script, stackPos(0));
+ _animator->sprites()[stackPos(0)].active = 0;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_changeCharactersXAndY(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_changeCharactersXAndY(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ Character *ch = &_characterList[stackPos(0)];
+ int16 x = stackPos(1);
+ int16 y = stackPos(2);
+ if (x != -1 && y != -1) {
+ x &= 0xFFFC;
+ y &= 0xFFFE;
+ }
+ _animator->restoreAllObjectBackgrounds();
+ ch->x1 = ch->x2 = x;
+ ch->y1 = ch->y2 = y;
+ _animator->preserveAllBackgrounds();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_clearSceneAnimatorBeacon(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_clearSceneAnimatorBeacon(%p) ()", (const void *)script);
+ _sprites->_sceneAnimatorBeaconFlag = 0;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_querySceneAnimatorBeacon(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_querySceneAnimatorBeacon(%p) ()", (const void *)script);
+ return _sprites->_sceneAnimatorBeaconFlag;
+}
+
+int KyraEngine_LoK::o1_refreshSceneAnimator(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_refreshSceneAnimator(%p) ()", (const void *)script);
+ _sprites->updateSceneAnims();
+ _animator->updateAllObjectShapes();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_placeItemInOffScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_placeItemInOffScene(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ int item = stackPos(0);
+ int xpos = stackPos(1);
+ int ypos = stackPos(2);
+ int sceneId = stackPos(3);
+
+ byte freeItem = findFreeItemInScene(sceneId);
+ if (freeItem != 0xFF) {
+ assert(sceneId < _roomTableSize);
+ Room *room = &_roomTable[sceneId];
+
+ room->itemsTable[freeItem] = item;
+ room->itemsXPos[freeItem] = xpos;
+ room->itemsYPos[freeItem] = ypos;
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_wipeDownMouseItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_wipeDownMouseItem(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ _screen->hideMouse();
+ wipeDownMouseItem(stackPos(1), stackPos(2));
+ removeHandItem();
+ _screen->showMouse();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_placeCharacterInOtherScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_placeCharacterInOtherScene(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ int id = stackPos(0);
+ int sceneId = stackPos(1);
+ int xpos = (int16)(stackPos(2) & 0xFFFC);
+ int ypos = (int16)(stackPos(3) & 0xFFFE);
+ int facing = stackPos(4);
+ int animFrame = stackPos(5);
+
+ _characterList[id].sceneId = sceneId;
+ _characterList[id].x1 = _characterList[id].x2 = xpos;
+ _characterList[id].y1 = _characterList[id].y2 = ypos;
+ _characterList[id].facing = facing;
+ _characterList[id].currentAnimFrame = animFrame;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getKey(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getKey(%p) ()", (const void *)script);
+
+ while (true) {
+ delay(10);
+
+ if (skipFlag())
+ break;
+ }
+
+ resetSkipFlag();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_specificItemInInventory(EMCState *script) {
+ warning("STUB: o1_specificItemInInventory");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_popMobileNPCIntoScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_popMobileNPCIntoScene(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), (int16)(stackPos(4) & 0xFFFC), (int8)(stackPos(5) & 0xFE));
+ int character = stackPos(0);
+ int sceneId = stackPos(1);
+ int animFrame = stackPos(2);
+ int facing = stackPos(3);
+ int16 xpos = (int16)(stackPos(4) & 0xFFFC);
+ int8 ypos = (int16)(stackPos(5) & 0xFFFE);
+ Character *curChar = &_characterList[character];
+
+ curChar->sceneId = sceneId;
+ curChar->currentAnimFrame = animFrame;
+ curChar->facing = facing;
+ curChar->x1 = curChar->x2 = xpos;
+ curChar->y1 = curChar->y2 = ypos;
+
+ _animator->animAddNPC(character);
+ _animator->updateAllObjectShapes();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_mobileCharacterInScene(EMCState *script) {
+ warning("STUB: o1_mobileCharacterInScene");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_hideMobileCharacter(EMCState *script) {
+ warning("STUB: o1_hideMobileCharacter");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_unhideMobileCharacter(EMCState *script) {
+ warning("STUB: o1_unhideMobileCharacter");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setCharacterLocation(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCharacterLocation(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ Character *ch = &_characterList[stackPos(0)];
+ Animator_LoK::AnimObject *animObj = &_animator->actors()[stackPos(0)];
+ int newScene = stackPos(1);
+ if (_currentCharacter->sceneId == ch->sceneId) {
+ if (_currentCharacter->sceneId != newScene)
+ animObj->active = 0;
+ } else if (_currentCharacter->sceneId == newScene) {
+ if (_currentCharacter->sceneId != ch->sceneId)
+ animObj->active = 1;
+ }
+
+ ch->sceneId = stackPos(1);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_walkCharacterToPoint(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_walkCharacterToPoint(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ int character = stackPos(0);
+ int toX = stackPos(1);
+ int toY = stackPos(2);
+ _pathfinderFlag2 = 1;
+ uint32 nextFrame;
+ int findWayReturn = findWay(_characterList[character].x1, _characterList[character].y1, toX, toY, _movFacingTable, 150);
+ _pathfinderFlag2 = 0;
+
+ if (_lastFindWayRet < findWayReturn)
+ _lastFindWayRet = findWayReturn;
+ if (findWayReturn == 0x7D00 || findWayReturn == 0)
+ return 0;
+
+ int *curPos = _movFacingTable;
+ bool running = true;
+ while (running) {
+ bool forceContinue = false;
+ switch (*curPos) {
+ case 0:
+ _characterList[character].facing = 2;
+ break;
+
+ case 1:
+ _characterList[character].facing = 1;
+ break;
+
+ case 2:
+ _characterList[character].facing = 0;
+ break;
+
+ case 3:
+ _characterList[character].facing = 7;
+ break;
+
+ case 4:
+ _characterList[character].facing = 6;
+ break;
+
+ case 5:
+ _characterList[character].facing = 5;
+ break;
+
+ case 6:
+ _characterList[character].facing = 4;
+ break;
+
+ case 7:
+ _characterList[character].facing = 3;
+ break;
+
+ case 8:
+ running = 0;
+ break;
+
+ default:
+ ++curPos;
+ forceContinue = true;
+ }
+
+ if (forceContinue || !running)
+ continue;
+
+ setCharacterPosition(character, 0);
+ ++curPos;
+
+ delayUntil(nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis(), true, true);
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_specialEventDisplayBrynnsNote(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_specialEventDisplayBrynnsNote(%p) ()", (const void *)script);
+ _screen->hideMouse();
+ _screen->savePageToDisk("HIDPAGE.TMP", 2);
+ _screen->savePageToDisk("SEENPAGE.TMP", 0);
+ if (_flags.isTalkie) {
+ if (_flags.lang == Common::EN_ANY || _flags.lang == Common::IT_ITA)
+ _screen->loadBitmap("NOTEENG.CPS", 3, 3, 0);
+ else if (_flags.lang == Common::FR_FRA)
+ _screen->loadBitmap("NOTEFRE.CPS", 3, 3, 0);
+ else if (_flags.lang == Common::DE_DEU)
+ _screen->loadBitmap("NOTEGER.CPS", 3, 3, 0);
+ } else {
+ _screen->loadBitmap("NOTE.CPS", 3, 3, 0);
+ }
+ _screen->copyRegion(63, 8, 63, 8, 194, 128, 2, 0);
+ _screen->updateScreen();
+ _screen->showMouse();
+
+ if (_flags.platform != Common::kPlatformAmiga && !_flags.isTalkie && _flags.lang != Common::JA_JPN)
+ _screen->setFont(Screen::FID_6_FNT);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_specialEventRemoveBrynnsNote(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_specialEventRemoveBrynnsNote(%p) ()", (const void *)script);
+ _screen->hideMouse();
+ _screen->loadPageFromDisk("SEENPAGE.TMP", 0);
+ _screen->loadPageFromDisk("HIDPAGE.TMP", 2);
+ _screen->updateScreen();
+ _screen->showMouse();
+
+ if (_flags.platform != Common::kPlatformAmiga && !_flags.isTalkie && _flags.lang != Common::JA_JPN)
+ _screen->setFont(Screen::FID_8_FNT);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setLogicPage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setLogicPage(%p) (%d)", (const void *)script, stackPos(0));
+ _screen->_curPage = stackPos(0);
+ return stackPos(0);
+}
+
+int KyraEngine_LoK::o1_fatPrint(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_fatPrint(%p) ('%s', %d, %d, %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+
+ // Workaround for bug #1582672 ("KYRA1: Text crippled and drawn wrong")
+ // I'm not sure how the original handles this, since it seems to call
+ // printText also, maybe it fails somewhere inside...
+ // TODO: fix the reason for this workaround
+ if (_currentRoom == 117)
+ return 0;
+ _text->printText(stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_preserveAllObjectBackgrounds(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_preserveAllObjectBackgrounds(%p) ()", (const void *)script);
+ _animator->preserveAllBackgrounds();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_updateSceneAnimations(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_updateSceneAnimations(%p) (%d)", (const void *)script, stackPos(0));
+ int times = stackPos(0);
+ while (times--) {
+ _sprites->updateSceneAnims();
+ _animator->updateAllObjectShapes();
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_sceneAnimationActive(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_sceneAnimationActive(%p) (%d)", (const void *)script, stackPos(0));
+ return _sprites->_anims[stackPos(0)].play;
+}
+
+int KyraEngine_LoK::o1_setCharacterMovementDelay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCharacterMovementDelay(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _timer->setDelay(stackPos(0) + 5, stackPos(1));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getCharacterFacing(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getCharacterFacing(%p) (%d)", (const void *)script, stackPos(0));
+ return _characterList[stackPos(0)].facing;
+}
+
+int KyraEngine_LoK::o1_bkgdScrollSceneAndMasksRight(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_bkgdScrollSceneAndMasksRight(%p) (%d)", (const void *)script, stackPos(0));
+ _screen->copyBackgroundBlock(stackPos(0), 2, 0);
+ _screen->copyBackgroundBlock2(stackPos(0));
+ // update the whole screen
+ _screen->copyRegion(7, 7, 7, 7, 305, 129, 3, 0);
+ // Don't do a screen update here, see bug #1910180 "KYRA1: Screen 'flash'"
+ // it would cause to draw the screen with a wrong palette and thus look
+ // strange for the user. Since this opcode should be just called on scene
+ // initialization anyway, there should be no problem with not updating the
+ // screen right now.
+ return 0;
+}
+
+int KyraEngine_LoK::o1_dispelMagicAnimation(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_dispelMagicAnimation(%p) ()", (const void *)script);
+ seq_dispelMagicAnimation();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_findBrightestFireberry(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_findBrightestFireberry(%p) ()", (const void *)script);
+ if (_currentCharacter->sceneId >= 187 && _currentCharacter->sceneId <= 198)
+ return 29;
+
+ // The following rooms are only a "A fireberry bush" scene in the CD version
+ // of Kyrandia 1. In all other versions they are a usual dark cave, thus we do only
+ // return a glow value of "29" over here, when we are running a CD version.
+ if (_flags.isTalkie) {
+ if (_currentCharacter->sceneId == 133 || _currentCharacter->sceneId == 137 ||
+ _currentCharacter->sceneId == 165 || _currentCharacter->sceneId == 173)
+ return 29;
+ }
+
+ if (_itemInHand == 28)
+ return 28;
+
+ int brightestFireberry = 107;
+ if (_itemInHand >= 29 && _itemInHand <= 33)
+ brightestFireberry = _itemInHand;
+ for (int i = 0; i < 10; ++i) {
+ uint8 item = _currentCharacter->inventoryItems[i];
+ if (item == 0xFF)
+ continue;
+ if (item == 28)
+ return 28;
+ if (item >= 29 && item <= 33) {
+ if (item < brightestFireberry)
+ brightestFireberry = item;
+ }
+ }
+ assert(_currentCharacter->sceneId < _roomTableSize);
+ Room *curRoom = &_roomTable[_currentCharacter->sceneId];
+ for (int i = 0; i < 12; ++i) {
+ uint8 item = curRoom->itemsTable[i];
+ if (item == 0xFF)
+ continue;
+ if (item == 28)
+ return 28;
+ if (item >= 29 && item <= 33) {
+ if (item < brightestFireberry)
+ brightestFireberry = item;
+ }
+ }
+ if (brightestFireberry == 107)
+ return -1;
+ return brightestFireberry;
+}
+
+int KyraEngine_LoK::o1_setFireberryGlowPalette(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setFireberryGlowPalette(%p) (%d)", (const void *)script, stackPos(0));
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ int palIndex = 0;
+
+ switch (stackPos(0)) {
+ case -1:
+ // The original seemed to draw some lines on page 2 here, which looks strange...
+ //if (!(_brandonStatusBit & 2))
+ // warning("Unimplemented case for o1_setFireberryGlowPalette");
+ palIndex = 9;
+ break;
+
+ case 30:
+ palIndex = 7;
+ break;
+
+ case 31:
+ palIndex = 8;
+ break;
+
+ case 32:
+ case 33:
+ palIndex = 9;
+ break;
+
+ case 28: case 29: default:
+ palIndex = 6;
+ }
+
+ if (_brandonStatusBit & 2) {
+ if (_currentCharacter->sceneId < 187 || _currentCharacter->sceneId > 198)
+ palIndex = 10;
+ }
+
+ _screen->copyPalette(0, palIndex);
+ } else {
+ int palIndex = 0;
+
+ switch (stackPos(0)) {
+ case 0x1E:
+ palIndex = 9;
+ break;
+
+ case 0x1F:
+ palIndex = 10;
+ break;
+
+ case 0x20:
+ palIndex = 11;
+ break;
+
+ case 0x21:
+ case -1:
+ palIndex = 12;
+ break;
+
+ default:
+ palIndex = 8;
+ }
+
+ if (_brandonStatusBit & 2) {
+ if (_currentCharacter->sceneId != 133 && _currentCharacter->sceneId != 137 &&
+ _currentCharacter->sceneId != 165 && _currentCharacter->sceneId != 173 &&
+ (_currentCharacter->sceneId < 187 || _currentCharacter->sceneId > 198)) {
+ palIndex = 14;
+ }
+ }
+
+ _screen->getPalette(1).copy(_specialPalettes[palIndex], 0, 15, 228);
+ }
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_drinkPotionAnimation(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_drinkPotionAnimation(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ seq_playDrinkPotionAnim(stackPos(0), stackPos(1), stackPos(2));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_makeAmuletAppear(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_makeAmuletAppear(%p) ()", (const void *)script);
+ Movie *amulet = createWSAMovie();
+ assert(amulet);
+ amulet->open("AMULET.WSA", 1, 0);
+
+ if (amulet->opened()) {
+ assert(_amuleteAnim);
+ _screen->hideMouse();
+ snd_playSoundEffect(0x70);
+ for (int i = 0; _amuleteAnim[i] != 0xFF; ++i) {
+ const uint32 nextTime = _system->getMillis() + 5 * _tickLength;
+
+ uint8 code = _amuleteAnim[i];
+ if (code == 3 || code == 7)
+ snd_playSoundEffect(0x71);
+
+ if (code == 5)
+ snd_playSoundEffect(0x72);
+
+ if (code == 14)
+ snd_playSoundEffect(0x73);
+
+ amulet->displayFrame(code, 0, 224, 152, 0, 0, 0);
+ delayUntil(nextTime, false, true);
+ }
+ _screen->showMouse();
+ }
+
+ delete amulet;
+ setGameFlag(0x2D);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_drawItemShapeIntoScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_drawItemShapeIntoScene(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ int item = stackPos(0);
+ int x = stackPos(1);
+ int y = stackPos(2);
+ int flags = stackPos(3);
+ int onlyHidPage = stackPos(4);
+
+ if (flags)
+ flags = 1;
+
+ if (onlyHidPage) {
+ _screen->drawShape(2, _shapes[216 + item], x, y, 0, flags);
+ } else {
+ _animator->restoreAllObjectBackgrounds();
+ _screen->drawShape(2, _shapes[216 + item], x, y, 0, flags);
+ _screen->drawShape(0, _shapes[216 + item], x, y, 0, flags);
+ _animator->flagAllObjectsForBkgdChange();
+ _animator->preserveAnyChangedBackgrounds();
+ _animator->flagAllObjectsForRefresh();
+ _animator->updateAllObjectShapes();
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setCharacterCurrentFrame(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCharacterCurrentFrame(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _characterList[stackPos(0)].currentAnimFrame = stackPos(1);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_waitForConfirmationMouseClick(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_waitForConfirmationMouseClick(%p) ()", (const void *)script);
+
+ _eventList.clear();
+ while (true) {
+ updateMousePointer();
+ _sprites->updateSceneAnims();
+ _animator->updateAllObjectShapes();
+
+ updateInput();
+
+ int input = checkInput(0, false) & 0xFF;
+ removeInputTop();
+ if (input == 200)
+ break;
+
+ delay(10);
+ }
+
+ script->regs[1] = _mouseX;
+ script->regs[2] = _mouseY;
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_pageFlip(EMCState *script) {
+ warning("STUB: o1_pageFlip");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setSceneFile(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setSceneFile(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ setSceneFile(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getItemInMarbleVase(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getItemInMarbleVase(%p) ()", (const void *)script);
+ return _marbleVaseItem;
+}
+
+int KyraEngine_LoK::o1_setItemInMarbleVase(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setItemInMarbleVase(%p) (%d)", (const void *)script, stackPos(0));
+ _marbleVaseItem = stackPos(0);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_addItemToInventory(EMCState *script) {
+ warning("STUB: o1_addItemToInventory");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_intPrint(EMCState *script) {
+ warning("STUB: o1_intPrint");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_shakeScreen(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_shakeScreen(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ int waitTicks = stackPos(1);
+ int times = stackPos(0);
+
+ for (int i = 0; i < times; ++i) {
+ _screen->shakeScreen(1);
+ delay(waitTicks * _tickLength);
+ }
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_createAmuletJewel(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_createAmuletJewel(%p) (%d)", (const void *)script, stackPos(0));
+ seq_createAmuletJewel(stackPos(0), 0, 0, 0);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setSceneAnimCurrXY(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setSceneAnimCurrXY(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ _sprites->_anims[stackPos(0)].x = stackPos(1);
+ _sprites->_anims[stackPos(0)].y = stackPos(2);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_poisonBrandonAndRemaps(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_poisonBrandonAndRemaps(%p) ()", (const void *)script);
+ setBrandonPoisonFlags(1);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_fillFlaskWithWater(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_fillFlaskWithWater(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ seq_fillFlaskWithWater(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getCharacterMovementDelay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getCharacterMovementDelay(%p) (%d)", (const void *)script, stackPos(0));
+ return _timer->getDelay(stackPos(0) + 5);
+}
+
+int KyraEngine_LoK::o1_getBirthstoneGem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getBirthstoneGem(%p) (%d)", (const void *)script, stackPos(0));
+ if (stackPos(0) < 4)
+ return _birthstoneGemTable[stackPos(0)];
+ return 0;
+}
+
+int KyraEngine_LoK::o1_queryBrandonStatusBit(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_queryBrandonStatusBit(%p) (%d)", (const void *)script, stackPos(0));
+ if (_brandonStatusBit & stackPos(0))
+ return 1;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_playFluteAnimation(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_playFluteAnimation(%p) ()", (const void *)script);
+ seq_playFluteAnimation();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_playWinterScrollSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_playWinterScrollSequence(%p) (%d)", (const void *)script, stackPos(0));
+ if (!stackPos(0))
+ seq_winterScroll2();
+ else
+ seq_winterScroll1();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getIdolGem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getIdolGem(%p) (%d)", (const void *)script, stackPos(0));
+ return _idolGemsTable[stackPos(0)];
+}
+
+int KyraEngine_LoK::o1_setIdolGem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setIdolGem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _idolGemsTable[stackPos(0)] = stackPos(1);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_totalItemsInScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_totalItemsInScene(%p) (%d)", (const void *)script, stackPos(0));
+ return countItemsInScene(stackPos(0));
+}
+
+int KyraEngine_LoK::o1_restoreBrandonsMovementDelay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_restoreBrandonsMovementDelay(%p) ()", (const void *)script);
+ setWalkspeed(_configWalkspeed);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setEntranceMouseCursorTrack(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setEntranceMouseCursorTrack(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ _entranceMouseCursorTracks[0] = stackPos(0);
+ _entranceMouseCursorTracks[1] = stackPos(1);
+ _entranceMouseCursorTracks[2] = stackPos(0) + stackPos(2) - 1;
+ _entranceMouseCursorTracks[3] = stackPos(1) + stackPos(3) - 1;
+ _entranceMouseCursorTracks[4] = stackPos(4);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_itemAppearsOnGround(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_itemAppearsOnGround(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ processItemDrop(_currentCharacter->sceneId, stackPos(0), stackPos(1), stackPos(2), 2, 0);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setNoDrawShapesFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setNoDrawShapesFlag(%p) (%d)", (const void *)script, stackPos(0));
+ _animator->_noDrawShapesFlag = stackPos(0);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_fadeEntirePalette(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_fadeEntirePalette(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ int cmd = stackPos(0);
+
+ int fadePal = 0;
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ if (cmd == 0) {
+ _screen->getPalette(2).clear();
+ fadePal = 2;
+ _screen->copyPalette(4, 0);
+ } else if (cmd == 1) {
+ fadePal = 0;
+ _screen->copyPalette(0, 4);
+ } else if (cmd == 2) {
+ fadePal = 0;
+ _screen->getPalette(2).clear();
+ }
+ } else {
+ if (cmd == 0) {
+ fadePal = 2;
+ _screen->getPalette(2).clear();
+ _screen->copyPalette(3, 0);
+ } else if (cmd == 1) {
+ //fadePal = 3;
+ warning("unimplemented o1_fadeEntirePalette function");
+ return 0;
+ } else if (cmd == 2) {
+ _screen->getPalette(2).clear();
+ _screen->copyPalette(0, 1);
+ fadePal = 0;
+ }
+ }
+
+ _screen->fadePalette(_screen->getPalette(fadePal), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_itemOnGroundHere(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_itemOnGroundHere(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ assert(stackPos(0) < _roomTableSize);
+ Room *curRoom = &_roomTable[stackPos(0)];
+ for (int i = 0; i < 12; ++i) {
+ if (curRoom->itemsTable[i] == stackPos(1))
+ return 1;
+ }
+ return 0;
+}
+
+int KyraEngine_LoK::o1_queryCauldronState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_queryCauldronState(%p) ()", (const void *)script);
+ return _cauldronState;
+}
+
+int KyraEngine_LoK::o1_setCauldronState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCauldronState(%p) (%d)", (const void *)script, stackPos(0));
+ _cauldronState = stackPos(0);
+ return _cauldronState;
+}
+
+int KyraEngine_LoK::o1_queryCrystalState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_queryCrystalState(%p) (%d)", (const void *)script, stackPos(0));
+ if (!stackPos(0))
+ return _crystalState[0];
+ else if (stackPos(0) == 1)
+ return _crystalState[1];
+ return -1;
+}
+
+int KyraEngine_LoK::o1_setCrystalState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCrystalState(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ if (!stackPos(0))
+ _crystalState[0] = stackPos(1);
+ else if (stackPos(0) == 1)
+ _crystalState[1] = stackPos(1);
+ return stackPos(1);
+}
+
+int KyraEngine_LoK::o1_setPaletteRange(EMCState *script) {
+ warning("STUB: o1_setPaletteRange");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_shrinkBrandonDown(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_shrinkBrandonDown(%p) (%d)", (const void *)script, stackPos(0));
+ int delayTime = stackPos(0);
+ checkAmuletAnimFlags();
+ int scaleValue = _scaleTable[_currentCharacter->y1];
+ int scale = 0;
+
+ if (_scaleMode)
+ scale = scaleValue;
+ else
+ scale = 256;
+
+ int scaleModeBackUp = _scaleMode;
+ _scaleMode = 1;
+ int scaleEnd = scale >> 1;
+ for (; scaleEnd <= scale; --scale) {
+ _scaleTable[_currentCharacter->y1] = scale;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(1);
+ }
+ delayWithTicks(delayTime); // XXX
+ _scaleTable[_currentCharacter->y1] = scaleValue;
+ _scaleMode = scaleModeBackUp;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_growBrandonUp(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_growBrandonUp(%p) ()", (const void *)script);
+ int scaleValue = _scaleTable[_currentCharacter->y1];
+ int scale = 0;
+ if (_scaleMode)
+ scale = scaleValue;
+ else
+ scale = 256;
+
+ int scaleModeBackUp = _scaleMode;
+ _scaleMode = 1;
+ for (int curScale = scale >> 1; curScale <= scale; ++curScale) {
+ _scaleTable[_currentCharacter->y1] = curScale;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(1);
+ }
+ _scaleTable[_currentCharacter->y1] = scaleValue;
+ _scaleMode = scaleModeBackUp;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setBrandonScaleXAndY(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setBrandonScaleXAndY(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _animator->_brandonScaleX = stackPos(0);
+ _animator->_brandonScaleY = stackPos(1);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_resetScaleMode(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_resetScaleMode(%p) ()", (const void *)script);
+ _scaleMode = 0;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_getScaleDepthTableValue(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getScaleDepthTableValue(%p) (%d)", (const void *)script, stackPos(0));
+ assert(stackPos(0) < ARRAYSIZE(_scaleTable));
+ return _scaleTable[stackPos(0)];
+}
+
+int KyraEngine_LoK::o1_setScaleDepthTableValue(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setScaleDepthTableValue(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ assert(stackPos(0) < ARRAYSIZE(_scaleTable));
+ _scaleTable[stackPos(0)] = stackPos(1);
+ return stackPos(1);
+}
+
+int KyraEngine_LoK::o1_message(EMCState *script) {
+ if (_flags.isTalkie) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_message(%p) (%d, '%s', %d)", (const void *)script, stackPos(0), stackPosString(1), stackPos(2));
+ drawSentenceCommand(stackPosString(1), stackPos(2));
+ } else {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_message(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1));
+ drawSentenceCommand(stackPosString(0), stackPos(1));
+ }
+
+ return 0;
+}
+
+int KyraEngine_LoK::o1_checkClickOnNPC(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_checkClickOnNPC(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return checkForNPCScriptRun(stackPos(0), stackPos(1));
+}
+
+int KyraEngine_LoK::o1_getFoyerItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getFoyerItem(%p) (%d)", (const void *)script, stackPos(0));
+ assert(stackPos(0) < ARRAYSIZE(_foyerItemTable));
+ return _foyerItemTable[stackPos(0)];
+}
+
+int KyraEngine_LoK::o1_setFoyerItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setFoyerItem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ assert(stackPos(0) < ARRAYSIZE(_foyerItemTable));
+ _foyerItemTable[stackPos(0)] = stackPos(1);
+ return stackPos(1);
+}
+
+int KyraEngine_LoK::o1_setNoItemDropRegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setNoItemDropRegion(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ addToNoDropRects(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ return 0;
+}
+
+int KyraEngine_LoK::o1_walkMalcolmOn(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_walkMalcolmOn(%p) ()", (const void *)script);
+ if (!_malcolmFlag)
+ _malcolmFlag = 1;
+ return 0;
+}
+
+int KyraEngine_LoK::o1_passiveProtection(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_passiveProtection(%p) ()", (const void *)script);
+ return 1;
+}
+
+int KyraEngine_LoK::o1_setPlayingLoop(EMCState *script) {
+ warning("STUB: o1_setPlayingLoop");
+ return 0;
+}
+
+int KyraEngine_LoK::o1_brandonToStoneSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_brandonToStoneSequence(%p) ()", (const void *)script);
+ seq_brandonToStone();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_brandonHealingSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_brandonHealingSequence(%p) ()", (const void *)script);
+ seq_brandonHealing();
+ return 0;
+}
+
+int KyraEngine_LoK::o1_protectCommandLine(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_protectCommandLine(%p) (%d)", (const void *)script, stackPos(0));
+ return stackPos(0);
+}
+
+int KyraEngine_LoK::o1_pauseMusicSeconds(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_pauseMusicSeconds(%p) ()", (const void *)script);
+ // if music disabled
+ // return
+ delay(stackPos(0) * 1000, true);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_resetMaskRegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_resetMaskRegion(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ _screen->fillRect(stackPos(1), stackPos(2), stackPos(1) + stackPos(3), stackPos(2) + stackPos(4), 0, 5);
+ return 0;
+}
+
+int KyraEngine_LoK::o1_setPaletteChangeFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setPaletteChangeFlag(%p) (%d)", (const void *)script, stackPos(0));
+ _paletteChanged = stackPos(0);
+ return _paletteChanged;
+}
+
+int KyraEngine_LoK::o1_vocUnload(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_vocUnload(%p) ()", (const void *)script);
+ // this should unload all voc files (not needed)
+ return 0;
+}
+
+int KyraEngine_LoK::o1_vocLoad(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_vocLoad(%p) (%d)", (const void *)script, stackPos(0));
+ // this should load the specified voc file (not needed)
+ return 0;
+}
+
+int KyraEngine_LoK::o1_dummy(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_dummy(%p) ()", (const void *)script);
+ return 0;
+}
+
+#pragma mark -
+
+typedef Common::Functor1Mem<EMCState *, int, KyraEngine_LoK> OpcodeV1;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV1(this, &KyraEngine_LoK::x))
+void KyraEngine_LoK::setupOpcodeTable() {
+ Common::Array<const Opcode *> *table = 0;
+
+ _opcodes.reserve(157);
+ SetOpcodeTable(_opcodes);
+ // 0x00
+ Opcode(o1_magicInMouseItem);
+ Opcode(o1_characterSays);
+ Opcode(o1_delay);
+ Opcode(o1_drawSceneAnimShape);
+ // 0x04
+ Opcode(o1_queryGameFlag);
+ Opcode(o1_setGameFlag);
+ Opcode(o1_resetGameFlag);
+ Opcode(o1_runNPCScript);
+ // 0x08
+ Opcode(o1_setSpecialExitList);
+ Opcode(o1_blockInWalkableRegion);
+ Opcode(o1_blockOutWalkableRegion);
+ Opcode(o1_walkPlayerToPoint);
+ // 0x0C
+ Opcode(o1_dropItemInScene);
+ Opcode(o1_drawAnimShapeIntoScene);
+ Opcode(o1_setHandItem);
+ Opcode(o1_savePageToDisk);
+ // 0x10
+ Opcode(o1_sceneAnimOn);
+ Opcode(o1_sceneAnimOff);
+ Opcode(o1_getElapsedSeconds);
+ Opcode(o1_mouseIsPointer);
+ // 0x14
+ Opcode(o1_removeHandItem);
+ Opcode(o1_runSceneAnimUntilDone);
+ Opcode(o1_fadeSpecialPalette);
+ Opcode(o1_playSoundEffect);
+ // 0x18
+ Opcode(o1_playWanderScoreViaMap);
+ Opcode(o1_phaseInSameScene);
+ Opcode(o1_setScenePhasingFlag);
+ Opcode(o1_resetScenePhasingFlag);
+ // 0x1C
+ Opcode(o1_queryScenePhasingFlag);
+ Opcode(o1_sceneToDirection);
+ Opcode(o1_setBirthstoneGem);
+ Opcode(o1_placeItemInGenericMapScene);
+ // 0x20
+ Opcode(o1_setBrandonStatusBit);
+ Opcode(o1_delaySecs);
+ Opcode(o1_getCharacterScene);
+ Opcode(o1_runNPCSubscript);
+ // 0x24
+ Opcode(o1_magicOutMouseItem);
+ Opcode(o1_internalAnimOn);
+ Opcode(o1_forceBrandonToNormal);
+ Opcode(o1_poisonDeathNow);
+ // 0x28
+ Opcode(o1_setScaleMode);
+ Opcode(o1_openWSAFile);
+ Opcode(o1_closeWSAFile);
+ Opcode(o1_runWSAFromBeginningToEnd);
+ // 0x2C
+ Opcode(o1_displayWSAFrame);
+ Opcode(o1_enterNewScene);
+ Opcode(o1_setSpecialEnterXAndY);
+ Opcode(o1_runWSAFrames);
+ // 0x30
+ Opcode(o1_popBrandonIntoScene);
+ Opcode(o1_restoreAllObjectBackgrounds);
+ Opcode(o1_setCustomPaletteRange);
+ Opcode(o1_loadPageFromDisk);
+ // 0x34
+ Opcode(o1_customPrintTalkString);
+ Opcode(o1_restoreCustomPrintBackground);
+ Opcode(o1_hideMouse);
+ Opcode(o1_showMouse);
+ // 0x38
+ Opcode(o1_getCharacterX);
+ Opcode(o1_getCharacterY);
+ Opcode(o1_setCharacterFacing);
+ Opcode(o1_copyWSARegion);
+ // 0x3C
+ Opcode(o1_printText);
+ Opcode(o1_getRand);
+ Opcode(o1_loadSoundFile);
+ Opcode(o1_displayWSAFrameOnHidPage);
+ // 0x40
+ Opcode(o1_displayWSASequentialFrames);
+ Opcode(o1_refreshCharacter);
+ Opcode(o1_internalAnimOff);
+ Opcode(o1_changeCharactersXAndY);
+ // 0x44
+ Opcode(o1_clearSceneAnimatorBeacon);
+ Opcode(o1_querySceneAnimatorBeacon);
+ Opcode(o1_refreshSceneAnimator);
+ Opcode(o1_placeItemInOffScene);
+ // 0x48
+ Opcode(o1_wipeDownMouseItem);
+ Opcode(o1_placeCharacterInOtherScene);
+ Opcode(o1_getKey);
+ Opcode(o1_specificItemInInventory);
+ // 0x4C
+ Opcode(o1_popMobileNPCIntoScene);
+ Opcode(o1_mobileCharacterInScene);
+ Opcode(o1_hideMobileCharacter);
+ Opcode(o1_unhideMobileCharacter);
+ // 0x50
+ Opcode(o1_setCharacterLocation);
+ Opcode(o1_walkCharacterToPoint);
+ Opcode(o1_specialEventDisplayBrynnsNote);
+ Opcode(o1_specialEventRemoveBrynnsNote);
+ // 0x54
+ Opcode(o1_setLogicPage);
+ Opcode(o1_fatPrint);
+ Opcode(o1_preserveAllObjectBackgrounds);
+ Opcode(o1_updateSceneAnimations);
+ // 0x58
+ Opcode(o1_sceneAnimationActive);
+ Opcode(o1_setCharacterMovementDelay);
+ Opcode(o1_getCharacterFacing);
+ Opcode(o1_bkgdScrollSceneAndMasksRight);
+ // 0x5C
+ Opcode(o1_dispelMagicAnimation);
+ Opcode(o1_findBrightestFireberry);
+ Opcode(o1_setFireberryGlowPalette);
+ Opcode(o1_setDeathHandler);
+ // 0x60
+ Opcode(o1_drinkPotionAnimation);
+ Opcode(o1_makeAmuletAppear);
+ Opcode(o1_drawItemShapeIntoScene);
+ Opcode(o1_setCharacterCurrentFrame);
+ // 0x64
+ Opcode(o1_waitForConfirmationMouseClick);
+ Opcode(o1_pageFlip);
+ Opcode(o1_setSceneFile);
+ Opcode(o1_getItemInMarbleVase);
+ // 0x68
+ Opcode(o1_setItemInMarbleVase);
+ Opcode(o1_addItemToInventory);
+ Opcode(o1_intPrint);
+ Opcode(o1_shakeScreen);
+ // 0x6C
+ Opcode(o1_createAmuletJewel);
+ Opcode(o1_setSceneAnimCurrXY);
+ Opcode(o1_poisonBrandonAndRemaps);
+ Opcode(o1_fillFlaskWithWater);
+ // 0x70
+ Opcode(o1_getCharacterMovementDelay);
+ Opcode(o1_getBirthstoneGem);
+ Opcode(o1_queryBrandonStatusBit);
+ Opcode(o1_playFluteAnimation);
+ // 0x74
+ Opcode(o1_playWinterScrollSequence);
+ Opcode(o1_getIdolGem);
+ Opcode(o1_setIdolGem);
+ Opcode(o1_totalItemsInScene);
+ // 0x78
+ Opcode(o1_restoreBrandonsMovementDelay);
+ Opcode(o1_setMousePos);
+ Opcode(o1_getMouseState);
+ Opcode(o1_setEntranceMouseCursorTrack);
+ // 0x7C
+ Opcode(o1_itemAppearsOnGround);
+ Opcode(o1_setNoDrawShapesFlag);
+ Opcode(o1_fadeEntirePalette);
+ Opcode(o1_itemOnGroundHere);
+ // 0x80
+ Opcode(o1_queryCauldronState);
+ Opcode(o1_setCauldronState);
+ Opcode(o1_queryCrystalState);
+ Opcode(o1_setCrystalState);
+ // 0x84
+ Opcode(o1_setPaletteRange);
+ Opcode(o1_shrinkBrandonDown);
+ Opcode(o1_growBrandonUp);
+ Opcode(o1_setBrandonScaleXAndY);
+ // 0x88
+ Opcode(o1_resetScaleMode);
+ Opcode(o1_getScaleDepthTableValue);
+ Opcode(o1_setScaleDepthTableValue);
+ Opcode(o1_message);
+ // 0x8C
+ Opcode(o1_checkClickOnNPC);
+ Opcode(o1_getFoyerItem);
+ Opcode(o1_setFoyerItem);
+ Opcode(o1_setNoItemDropRegion);
+ // 0x90
+ Opcode(o1_walkMalcolmOn);
+ Opcode(o1_passiveProtection);
+ Opcode(o1_setPlayingLoop);
+ Opcode(o1_brandonToStoneSequence);
+ // 0x94
+ Opcode(o1_brandonHealingSequence);
+ Opcode(o1_protectCommandLine);
+ Opcode(o1_pauseMusicSeconds);
+ Opcode(o1_resetMaskRegion);
+ // 0x98
+ Opcode(o1_setPaletteChangeFlag);
+ Opcode(o1_fillRect);
+ Opcode(o1_vocUnload);
+ Opcode(o1_vocLoad);
+ // 0x9C
+ Opcode(o1_dummy);
+}
+#undef Opcode
+
+} // End of namespace Kyra
diff --git a/engines/kyra/script/script_lol.cpp b/engines/kyra/script/script_lol.cpp
new file mode 100644
index 0000000000..65d0f6c1e0
--- /dev/null
+++ b/engines/kyra/script/script_lol.cpp
@@ -0,0 +1,3051 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_LOL
+
+#include "kyra/engine/lol.h"
+#include "kyra/graphics/screen_lol.h"
+#include "kyra/engine/timer.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void LoLEngine::runInitScript(const char *filename, int optionalFunc) {
+ _suspendScript = true;
+ EMCData scriptData;
+ EMCState scriptState;
+ memset(&scriptData, 0, sizeof(EMCData));
+ _emc->unload(&_scriptData);
+ _emc->load(filename, &scriptData, &_opcodes);
+
+ _emc->init(&scriptState, &scriptData);
+ _emc->start(&scriptState, 0);
+ while (_emc->isValid(&scriptState))
+ _emc->run(&scriptState);
+
+ if (optionalFunc) {
+ _emc->init(&scriptState, &scriptData);
+ _emc->start(&scriptState, optionalFunc);
+ while (_emc->isValid(&scriptState))
+ _emc->run(&scriptState);
+ }
+
+ _emc->unload(&scriptData);
+ _suspendScript = false;
+}
+
+void LoLEngine::runInfScript(const char *filename) {
+ _emc->unload(&_scriptData);
+ _emc->load(filename, &_scriptData, &_opcodes);
+ runLevelScript(0x400, -1);
+}
+
+void LoLEngine::runLevelScript(int block, int flags) {
+ runLevelScriptCustom(block, flags, -1, 0, 0, 0);
+}
+
+void LoLEngine::runLevelScriptCustom(int block, int flags, int charNum, int item, int reg3, int reg4) {
+ EMCState scriptState;
+ memset(&scriptState, 0, sizeof(EMCState));
+
+ if (!_suspendScript) {
+ _emc->init(&scriptState, &_scriptData);
+ _emc->start(&scriptState, block);
+
+ scriptState.regs[0] = flags;
+ scriptState.regs[1] = charNum;
+ scriptState.regs[2] = item;
+ scriptState.regs[3] = reg3;
+ scriptState.regs[4] = reg4;
+ scriptState.regs[5] = block;
+ scriptState.regs[6] = _scriptDirection;
+
+ if (_emc->isValid(&scriptState)) {
+ if (*(scriptState.ip - 1) & flags) {
+ while (_emc->isValid(&scriptState))
+ _emc->run(&scriptState);
+ }
+ }
+ }
+
+ checkSceneUpdateNeed(block);
+}
+
+int LoLEngine::olol_setWallType(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setWallType(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ if (stackPos(2) != -1) {
+ if (_wllWallFlags[stackPos(2)] & 4)
+ deleteMonstersFromBlock(stackPos(0));
+ }
+ setWallType(stackPos(0), stackPos(1), stackPos(2));
+ return 1;
+}
+
+int LoLEngine::olol_getWallType(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getWallType(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return (int8)_levelBlockProperties[stackPos(0)].walls[stackPos(1) & 3];
+}
+
+int LoLEngine::olol_drawScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_drawScene(%p) (%d)", (const void *)script, stackPos(0));
+ drawScene(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_rollDice(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_rollDice(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return rollDice(stackPos(0), stackPos(1));
+}
+
+int LoLEngine::olol_moveParty(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_moveParty(%p) (%d)", (const void *)script, stackPos(0));
+ int mode = stackPos(0);
+ if (mode > 5 && mode < 10)
+ mode = (mode - 6 - _currentDirection) & 3;
+
+ Button b;
+ b.data0Val2 = b.data1Val2 = b.data2Val2 = 0xFE;
+ b.data0Val3 = b.data1Val3 = b.data2Val3 = 0x01;
+
+ switch (mode) {
+ case 0:
+ clickedUpArrow(&b);
+ break;
+
+ case 1:
+ clickedRightArrow(&b);
+ break;
+
+ case 2:
+ clickedDownArrow(&b);
+ break;
+
+ case 3:
+ clickedLeftArrow(&b);
+ break;
+
+ case 4:
+ clickedTurnLeftArrow(&b);
+ break;
+
+ case 5:
+ clickedTurnRightArrow(&b);
+ break;
+
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ mode = ABS(mode - 10 - _currentDirection);
+ if (mode > 2)
+ mode = (mode ^ 2) * -1;
+
+ while (mode) {
+ if (mode > 0) {
+ clickedTurnRightArrow(&b);
+ mode--;
+ } else {
+ clickedTurnLeftArrow(&b);
+ mode++;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+
+int LoLEngine::olol_delay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_delay(%p) (%d)", (const void *)script, stackPos(0));
+ delay(stackPos(0) * _tickLength, true);
+ return 1;
+}
+
+int LoLEngine::olol_setGameFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setGameFlag(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+
+ if (stackPos(1))
+ setGameFlag(stackPos(0));
+ else
+ resetGameFlag(stackPos(0));
+
+ return 1;
+}
+
+int LoLEngine::olol_testGameFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_testGameFlag(%p) (%d)", (const void *)script, stackPos(0));
+ if (stackPos(0) < 0)
+ return 0;
+
+ return queryGameFlag(stackPos(0));
+}
+
+int LoLEngine::olol_loadLevelGraphics(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadLevelGraphics(%p) (%s, %d, %d, %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ loadLevelGraphics(stackPosString(0), stackPos(1), stackPos(2), stackPos(3) == -1 ? -1 : (uint16)stackPos(3), stackPos(4) == -1 ? -1 : (uint16)stackPos(4), (stackPos(5) == -1) ? 0 : stackPosString(5));
+ return 1;
+}
+
+int LoLEngine::olol_loadBlockProperties(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadBlockProperties(%p) (%s)", (const void *)script, stackPosString(0));
+ loadBlockProperties(stackPosString(0));
+ return 1;
+}
+
+int LoLEngine::olol_loadMonsterShapes(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadMonsterShapes(%p) (%s, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2));
+ loadMonsterShapes(stackPosString(0), stackPos(1), stackPos(2));
+ return 1;
+}
+
+int LoLEngine::olol_deleteHandItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_deleteHandItem(%p) ()", (const void *)script);
+ int r = _itemInHand;
+ deleteItem(_itemInHand);
+ setHandItem(0);
+ return r;
+}
+
+int LoLEngine::olol_allocItemPropertiesBuffer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_allocItemPropertiesBuffer(%p) (%d)", (const void *)script, stackPos(0));
+ delete[] _itemProperties;
+ _itemProperties = new ItemProperty[stackPos(0)];
+ return 1;
+}
+
+int LoLEngine::olol_setItemProperty(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setItemProperty(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9));
+ ItemProperty *tmp = &_itemProperties[stackPos(0)];
+
+ tmp->nameStringId = stackPos(1);
+ tmp->shpIndex = stackPos(2);
+ tmp->type = stackPos(3);
+
+ // WORKAROUND for unpatched early floppy versions.
+ // The Vaelan's cube should not be able to be equipped in a weapon slot.
+ if (stackPos(0) == 264 && tmp->type == 5)
+ tmp->type = 0;
+
+ tmp->itemScriptFunc = stackPos(4);
+ tmp->might = stackPos(5);
+ tmp->skill = stackPos(6);
+ tmp->protection = stackPos(7);
+ tmp->flags = stackPos(8);
+ tmp->unkB = stackPos(9);
+ return 1;
+}
+
+int LoLEngine::olol_makeItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_makeItem(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ return makeItem(stackPos(0), stackPos(1), stackPos(2));
+}
+
+int LoLEngine::olol_placeMoveLevelItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_placeMoveLevelItem(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ placeMoveLevelItem(stackPos(0), stackPos(1), stackPos(2), stackPos(3) & 0xFF, stackPos(4) & 0xFF, stackPos(5));
+ return 1;
+}
+
+int LoLEngine::olol_createLevelItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_createLevelItem(%p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ int item = makeItem(stackPos(0), stackPos(1), stackPos(2));
+ if (item == -1)
+ return item;
+ placeMoveLevelItem(item, stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ return item;
+}
+
+int LoLEngine::olol_getItemPara(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getItemPara(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ if (!stackPos(0))
+ return 0;
+
+ LoLItem *i = &_itemsInPlay[stackPos(0)];
+ ItemProperty *p = &_itemProperties[i->itemPropertyIndex];
+
+ switch (stackPos(1)) {
+ case 0:
+ return i->block;
+ case 1:
+ return i->x;
+ case 2:
+ return i->y;
+ case 3:
+ return i->level;
+ case 4:
+ return i->itemPropertyIndex;
+ case 5:
+ return i->shpCurFrame_flg;
+ case 6:
+ return p->nameStringId;
+ case 7:
+ break;
+ case 8:
+ return p->shpIndex;
+ case 9:
+ return p->type;
+ case 10:
+ return p->itemScriptFunc;
+ case 11:
+ return p->might;
+ case 12:
+ return p->skill;
+ case 13:
+ return p->protection;
+ case 14:
+ return p->unkB;
+ case 15:
+ return i->shpCurFrame_flg & 0x1FFF;
+ case 16:
+ return p->flags;
+ case 17:
+ return (p->skill << 8) | ((uint8)p->might);
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int LoLEngine::olol_getCharacterStat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getCharacterStat(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ LoLCharacter *c = &_characters[stackPos(0)];
+ int d = stackPos(2);
+
+ switch (stackPos(1)) {
+ case 0:
+ return c->flags;
+
+ case 1:
+ return c->raceClassSex;
+
+ case 5:
+ return c->hitPointsCur;
+
+ case 6:
+ return c->hitPointsMax;
+
+ case 7:
+ return c->magicPointsCur;
+
+ case 8:
+ return c->magicPointsMax;
+
+ case 9:
+ return c->itemProtection;
+
+ case 10:
+ return c->items[d];
+
+ case 11:
+ return c->skillLevels[d] + c->skillModifiers[d];
+
+ case 12:
+ return c->protectionAgainstItems[d];
+
+ case 13:
+ return (d & 0x80) ? c->itemsMight[7] : c->itemsMight[d];
+
+ case 14:
+ return c->skillModifiers[d];
+
+ case 15:
+ return c->id;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int LoLEngine::olol_setCharacterStat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setCharacterStat(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ LoLCharacter *c = &_characters[stackPos(0)];
+ int d = stackPos(2);
+ int e = stackPos(3);
+
+ switch (stackPos(1)) {
+ case 0:
+ c->flags = e;
+ break;
+
+ case 1:
+ c->raceClassSex = e & 0x0F;
+ break;
+
+ case 5:
+ setCharacterMagicOrHitPoints(stackPos(0), 0, e, 0);
+ break;
+
+ case 6:
+ c->hitPointsMax = e;
+ break;
+
+ case 7:
+ setCharacterMagicOrHitPoints(stackPos(0), 1, e, 0);
+ break;
+
+ case 8:
+ c->magicPointsMax = e;
+ break;
+
+ case 9:
+ c->itemProtection = e;
+ break;
+
+ case 10:
+ c->items[d] = 0;
+ break;
+
+ case 11:
+ c->skillLevels[d] = e;
+ break;
+
+ case 12:
+ c->protectionAgainstItems[d] = e;
+ break;
+
+ case 13:
+ if (d & 0x80)
+ c->itemsMight[7] = e;
+ else
+ c->itemsMight[d] = e;
+ break;
+
+ case 14:
+ c->skillModifiers[d] = e;
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int LoLEngine::olol_loadLevelShapes(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadLevelShapes(%p) (%s, %s)", (const void *)script, stackPosString(0), stackPosString(1));
+ loadLevelShpDat(stackPosString(0), stackPosString(1), true);
+ return 1;
+}
+
+int LoLEngine::olol_closeLevelShapeFile(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_closeLevelShapeFile(%p) ()", (const void *)script);
+ delete _lvlShpFileHandle;
+ _lvlShpFileHandle = 0;
+ return 1;
+}
+
+int LoLEngine::olol_loadDoorShapes(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadDoorShapes(%p) (%s, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2));
+ _screen->loadBitmap(stackPosString(0), 3, 3, 0);
+ const uint8 *p = _screen->getCPagePtr(2);
+ if (_doorShapes[0])
+ delete[] _doorShapes[0];
+ _doorShapes[0] = _screen->makeShapeCopy(p, stackPos(1));
+ if (_doorShapes[1])
+ delete[] _doorShapes[1];
+ _doorShapes[1] = _screen->makeShapeCopy(p, stackPos(2));
+
+ for (int i = 0; i < 20; i++) {
+ _wllWallFlags[i + 3] |= 7;
+ int t = i % 5;
+ if (t == 4)
+ _wllWallFlags[i + 3] &= 0xF8;
+ if (t == 3)
+ _wllWallFlags[i + 3] &= 0xFD;
+ }
+
+ if (stackPos(3)) {
+ for (int i = 3; i < 13; i++)
+ _wllWallFlags[i] &= 0xFD;
+ }
+
+ if (stackPos(4)) {
+ for (int i = 13; i < 23; i++)
+ _wllWallFlags[i] &= 0xFD;
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_initAnimStruct(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_initAnimStruct(%p) (%s, %d, %d, %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ if (_tim->initAnimStruct(stackPos(1), stackPosString(0), stackPos(2), stackPos(3), stackPos(4), 0, stackPos(5)))
+ return 1;
+ return 0;
+}
+
+int LoLEngine::olol_playAnimationPart(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playAnimationPart(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ _tim->animator()->playPart(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ return 1;
+}
+
+int LoLEngine::olol_freeAnimStruct(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_freeAnimStruct(%p) (%d)", (const void *)script, stackPos(0));
+ if (_tim->freeAnimStruct(stackPos(0)))
+ return 1;
+ return 0;
+}
+
+int LoLEngine::olol_getDirection(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getDirection(%p)", (const void *)script);
+ return _currentDirection;
+}
+
+int LoLEngine::olol_characterSurpriseFeedback(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_characterSurpriseFeedback(%p)", (const void *)script);
+ for (int i = 0; i < 4; i++) {
+ if (!(_characters[i].flags & 1) || _characters[i].id >= 0)
+ continue;
+ int s = -_characters[i].id;
+ int sfx = (s == 1) ? 136 : ((s == 5) ? 50 : ((s == 8) ? 49 : ((s == 9) ? 48 : 0)));
+ if (sfx)
+ snd_playSoundEffect(sfx, -1);
+ return 1;
+ }
+ return 1;
+}
+
+int LoLEngine::olol_setMusicTrack(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setMusicTrack(%p) (%d)", (const void *)script, stackPos(0));
+ _curMusicTheme = stackPos(0);
+ return 1;
+}
+
+int LoLEngine::olol_setSequenceButtons(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setSequenceButtons(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ setSequenceButtons(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ return 1;
+}
+
+int LoLEngine::olol_setDefaultButtonState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setDefaultButtonState(%p)", (const void *)script);
+ setDefaultButtonState();
+ return 1;
+}
+
+int LoLEngine::olol_checkRectForMousePointer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkRectForMousePointer(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ return posWithinRect(_mouseX, _mouseY, stackPos(0), stackPos(1), stackPos(2), stackPos(3)) ? 1 : 0;
+}
+
+int LoLEngine::olol_clearDialogueField(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_clearDialogueField(%p) (%d)", (const void *)script, stackPos(0));
+ if (_currentControlMode && (!textEnabled()))
+ return 1;
+
+ _screen->setScreenDim(5);
+ const ScreenDim *d = _screen->getScreenDim(5);
+ _screen->fillRect(d->sx, d->sy, d->sx + d->w - (_flags.use16ColorMode ? 3 : 2), d->sy + d->h - 2, d->unkA);
+ _txt->clearDim(4);
+ _txt->resetDimTextPositions(4);
+
+ return 1;
+}
+
+int LoLEngine::olol_setupBackgroundAnimationPart(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setupBackgroundAnimationPart(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9));
+ _tim->animator()->setupPart(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9));
+ return 0;
+}
+
+int LoLEngine::olol_startBackgroundAnimation(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_startBackgroundAnimation(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _tim->animator()->start(stackPos(0), stackPos(1));
+ return 1;
+}
+
+int LoLEngine::olol_fadeToBlack(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_fadeToBlack(%p) (%d)", (const void *)script, stackPos(0));
+ _screen->fadeToBlack(10);
+ return 1;
+}
+
+int LoLEngine::olol_fadePalette(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_fadePalette(%p)", (const void *)script);
+ if (_flags.use16ColorMode)
+ setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
+ else
+ _screen->fadePalette(_screen->getPalette(3), 10);
+ _screen->_fadeFlag = 0;
+ return 1;
+}
+
+int LoLEngine::olol_loadBitmap(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadBitmap(%p) (%s, %d)", (const void *)script, stackPosString(0), stackPos(1));
+ _screen->loadBitmap(stackPosString(0), 3, 3, &_screen->getPalette(3));
+ if (stackPos(1) != 2)
+ _screen->copyPage(3, stackPos(1));
+ return 1;
+}
+
+int LoLEngine::olol_stopBackgroundAnimation(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_stopBackgroundAnimation(%p) (%d)", (const void *)script, stackPos(0));
+ _tim->animator()->stop(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_getGlobalScriptVar(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getGlobalScriptVar(%p) (%d)", (const void *)script, stackPos(0));
+ assert(stackPos(0) < 24);
+ return _globalScriptVars[stackPos(0)];
+}
+
+int LoLEngine::olol_setGlobalScriptVar(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setGlobalScriptVar(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ assert(stackPos(0) < 24);
+ _globalScriptVars[stackPos(0)] = stackPos(1);
+ return 1;
+}
+
+int LoLEngine::olol_getGlobalVar(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getGlobalVar(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+
+ switch (stackPos(0)) {
+ case 0:
+ return _currentBlock;
+ case 1:
+ return _currentDirection;
+ case 2:
+ return _currentLevel;
+ case 3:
+ return _itemInHand;
+ case 4:
+ return _brightness;
+ case 5:
+ return _credits;
+ case 6:
+ return _globalScriptVars2[stackPos(1)];
+ case 8:
+ return _updateFlags;
+ case 9:
+ return _lampOilStatus;
+ case 10:
+ return _sceneDefaultUpdate;
+ case 11:
+ return _compassBroken;
+ case 12:
+ return _drainMagic;
+ case 13:
+ return getVolume(kVolumeSpeech) - 2;
+ case 14:
+ return _tim->_abortFlag;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int LoLEngine::olol_setGlobalVar(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setGlobalVar(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ uint16 a = stackPos(1);
+ uint16 b = stackPos(2);
+
+ switch (stackPos(0)) {
+ case 0:
+ _currentBlock = b;
+ calcCoordinates(_partyPosX, _partyPosY, _currentBlock, 0x80, 0x80);
+ updateAutoMap(_currentBlock);
+ break;
+
+ case 1:
+ _currentDirection = b;
+ break;
+
+ case 2:
+ _currentLevel = b & 0xFF;
+ break;
+
+ case 3:
+ setHandItem(b);
+ break;
+
+ case 4:
+ _brightness = b & 0xFF;
+ break;
+
+ case 5:
+ _credits = b;
+ break;
+
+ case 6:
+ _globalScriptVars2[a] = b;
+ break;
+
+ case 7:
+ break;
+
+ case 8:
+ _updateFlags = b;
+ if (b == 1) {
+ if (!textEnabled() || (!(_currentControlMode & 2)))
+ timerUpdatePortraitAnimations(1);
+ disableSysTimer(2);
+ } else {
+ enableSysTimer(2);
+ }
+ break;
+
+ case 9:
+ _lampOilStatus = b & 0xFF;
+ break;
+
+ case 10:
+ _sceneDefaultUpdate = b & 0xFF;
+ gui_toggleButtonDisplayMode(0, 0);
+ break;
+
+ case 11:
+ _compassBroken = a & 0xFF;
+ break;
+
+ case 12:
+ _drainMagic = a & 0xFF;
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_triggerDoorSwitch(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_triggerDoorSwitch(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ processDoorSwitch(stackPos(0)/*, (_wllWallFlags[_levelBlockProperties[stackPos(0)].walls[0]] & 8) ? 0 : 1*/, stackPos(1));
+ return 1;
+}
+
+int LoLEngine::olol_checkEquippedItemScriptFlags(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkEquippedItemScriptFlags(%p)", (const void *)script);
+ for (int i = 0; i < 4; i++) {
+ if (!(_characters[i].flags & 1))
+ continue;
+ for (int ii = 0; ii < 4; ii++) {
+ uint8 f = _itemProperties[_itemsInPlay[_characters[i].items[ii]].itemPropertyIndex].itemScriptFunc;
+ if (f == 0 || f == 2)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int LoLEngine::olol_setDoorState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setDoorState(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ if (stackPos(1))
+ _levelBlockProperties[stackPos(0)].flags = (_levelBlockProperties[stackPos(0)].flags & 0xEF) | 0x20;
+ else
+ _levelBlockProperties[stackPos(0)].flags &= 0xDF;
+ return 1;
+}
+
+int LoLEngine::olol_updateBlockAnimations(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_updateBlockAnimations(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ int block = stackPos(0);
+ int wall = stackPos(1);
+ setWallType(block, wall, _levelBlockProperties[block].walls[(wall == -1) ? 0 : wall] == stackPos(2) ? stackPos(3) : stackPos(2));
+ return 0;
+}
+
+int LoLEngine::olol_assignLevelDecorationShape(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_assignLevelDecorationShape(%p) (%d)", (const void *)script, stackPos(0));
+ return assignLevelDecorationShapes(stackPos(0));
+}
+
+int LoLEngine::olol_resetBlockShapeAssignment(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_resetBlockShapeAssignment(%p) (%d)", (const void *)script, stackPos(0));
+ uint8 v = stackPos(0) & 0xFF;
+ memset(_wllShapeMap + 3, v, 5);
+ memset(_wllShapeMap + 13, v, 5);
+ return 1;
+}
+
+int LoLEngine::olol_copyRegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_copyRegion(%p) (%d, %d, %d, %d, %d, %d, %d, %d)",
+ (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ _screen->copyRegion(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), Screen::CR_NO_P_CHECK);
+ if (!stackPos(7))
+ _screen->updateScreen();
+ return 1;
+}
+
+int LoLEngine::olol_initMonster(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_initMonster(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10));
+ uint16 x = 0;
+ uint16 y = 0;
+ calcCoordinates(x, y, stackPos(0), stackPos(1), stackPos(2));
+ uint16 w = _monsterProperties[stackPos(4)].maxWidth;
+
+ if (checkBlockBeforeObjectPlacement(x, y, w, 7, 7))
+ return -1;
+
+ for (uint8 i = 0; i < 30; i++) {
+ LoLMonster *l = &_monsters[i];
+ if (l->hitPoints || l->mode == 13)
+ continue;
+
+ memset(l, 0, sizeof(LoLMonster));
+ l->id = i;
+ l->x = x;
+ l->y = y;
+ l->facing = stackPos(3);
+ l->type = stackPos(4);
+ l->properties = &_monsterProperties[l->type];
+ l->direction = l->facing << 1;
+ l->hitPoints = (l->properties->hitPoints * _monsterModifiers1[_monsterDifficulty]) >> 8;
+
+ if (_currentLevel != 12 || l->type != 2)
+ l->hitPoints = (l->hitPoints * (rollDice(1, 128) + 192)) >> 8;
+
+ l->numDistAttacks = l->properties->numDistAttacks;
+ l->distAttackTick = rollDice(1, calcMonsterSkillLevel(l->id | 0x8000, 8)) - 1;
+ l->flyingHeight = 2;
+ l->flags = stackPos(5);
+ l->assignedItems = 0;
+
+ setMonsterMode(l, stackPos(6));
+ placeMonster(l, l->x, l->y);
+
+ l->destX = l->x;
+ l->destY = l->y;
+ l->destDirection = l->direction;
+
+ for (int ii = 0; ii < 4; ii++)
+ l->equipmentShapes[ii] = stackPos(7 + ii) & 0xFF;
+
+ checkSceneUpdateNeed(l->block);
+ return i;
+ }
+
+ return -1;
+}
+
+int LoLEngine::olol_fadeClearSceneWindow(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_fadeClearSceneWindow(%p)", (const void *)script);
+ _screen->fadeClearSceneWindow(10);
+ return 1;
+}
+
+int LoLEngine::olol_fadeSequencePalette(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_fadeSequencePalette(%p)", (const void *)script);
+ if (_flags.use16ColorMode) {
+ setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
+ } else {
+ _screen->getPalette(3).copy(_screen->getPalette(0), 128);
+ _screen->loadSpecialColors(_screen->getPalette(3));
+ _screen->fadePalette(_screen->getPalette(3), 10);
+ }
+ _screen->_fadeFlag = 0;
+ return 1;
+}
+
+int LoLEngine::olol_redrawPlayfield(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_redrawPlayfield(%p)", (const void *)script);
+ if (_screen->_fadeFlag != 2)
+ _screen->fadeClearSceneWindow(10);
+ gui_drawPlayField();
+ setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
+ _screen->_fadeFlag = 0;
+ return 1;
+}
+
+int LoLEngine::olol_loadNewLevel(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadNewLevel(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ _screen->fadeClearSceneWindow(10);
+ _screen->fillRect(112, 0, 288, 120, 0);
+ disableSysTimer(2);
+
+ for (int i = 0; i < 8; i++) {
+ if (!_flyingObjects[i].enable || _flyingObjects[i].objectType)
+ continue;
+ endObjectFlight(&_flyingObjects[i], _flyingObjects[i].x, _flyingObjects[i].y, 1);
+ }
+
+ completeDoorOperations();
+
+ generateTempData();
+
+ _currentBlock = stackPos(1);
+ _currentDirection = stackPos(2);
+ calcCoordinates(_partyPosX, _partyPosY, _currentBlock, 0x80, 0x80);
+
+ loadLevel(stackPos(0));
+
+ enableSysTimer(2);
+
+ script->ip = 0;
+ return 1;
+}
+
+int LoLEngine::olol_getNearestMonsterFromCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getNearestMonsterFromCharacter(%p) (%d)", (const void *)script, stackPos(0));
+ return getNearestMonsterFromCharacter(stackPos(0));
+}
+
+int LoLEngine::olol_dummy0(EMCState *script) {
+ return 0;
+}
+
+int LoLEngine::olol_loadMonsterProperties(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadMonsterProperties(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
+ (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5),
+ stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPos(12), stackPos(13),
+ stackPos(14), stackPos(15), stackPos(16), stackPos(17), stackPos(18), stackPos(19), stackPos(20),
+ stackPos(21), stackPos(22), stackPos(23), stackPos(24), stackPos(25), stackPos(26), stackPos(27),
+ stackPos(28), stackPos(29), stackPos(30), stackPos(31), stackPos(32), stackPos(33), stackPos(34),
+ stackPos(35), stackPos(36), stackPos(37), stackPos(38), stackPos(39), stackPos(40), stackPos(41));
+
+ LoLMonsterProperty *l = &_monsterProperties[stackPos(0)];
+ l->shapeIndex = stackPos(1) & 0xFF;
+
+ int shpWidthMax = 0;
+
+ for (int i = 0; i < 16; i++) {
+ uint8 m = _monsterShapes[(l->shapeIndex << 4) + i][3];
+ if (m > shpWidthMax)
+ shpWidthMax = m;
+ }
+
+ l->maxWidth = shpWidthMax;
+
+ l->fightingStats[0] = (stackPos(2) << 8) / 100; // hit chance
+ l->fightingStats[1] = 256; //
+ l->fightingStats[2] = (stackPos(3) << 8) / 100; // protection
+ l->fightingStats[3] = stackPos(4); // evade chance
+ l->fightingStats[4] = (stackPos(5) << 8) / 100; // speed
+ l->fightingStats[5] = (stackPos(6) << 8) / 100; //
+ l->fightingStats[6] = (stackPos(7) << 8) / 100; //
+ l->fightingStats[7] = (stackPos(8) << 8) / 100; //
+ l->fightingStats[8] = 0;
+
+ for (int i = 0; i < 8; i++) {
+ l->itemsMight[i] = stackPos(9 + i);
+ l->protectionAgainstItems[i] = (stackPos(17 + i) << 8) / 100;
+ }
+
+ l->itemProtection = stackPos(25);
+ l->hitPoints = stackPos(26);
+ l->speedTotalWaitTicks = 1;
+ l->flags = stackPos(27);
+ // This is what the original does here (setting the value first to stackPos(28) and then to stackPos(29):
+ //l->unk5 = stackPos(28);
+ l->unk5 = stackPos(29);
+
+ l->numDistAttacks = stackPos(30);
+ l->numDistWeapons = stackPos(31);
+ for (int i = 0; i < 3; i++)
+ l->distWeapons[i] = stackPos(32 + i);
+
+ l->attackSkillChance = stackPos(35);
+ l->attackSkillType = stackPos(36);
+ l->defenseSkillChance = stackPos(37);
+ l->defenseSkillType = stackPos(38);
+
+ for (int i = 0; i < 3; i++)
+ l->sounds[i] = stackPos(39 + i);
+
+ return 1;
+}
+
+int LoLEngine::olol_battleHitSkillTest(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_battleHitSkillTest(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ return battleHitSkillTest(stackPos(0), stackPos(1), stackPos(2));
+}
+
+int LoLEngine::olol_inflictDamage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_inflictDamage(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ if (stackPos(0) == -1) {
+ for (int i = 0; i < 4; i++)
+ inflictDamage(i, stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ } else {
+ inflictDamage(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_moveMonster(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_moveMonster(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ LoLMonster *m = &_monsters[stackPos(0)];
+
+ if (m->mode == 1 || m->mode == 2) {
+ calcCoordinates(m->destX, m->destY, stackPos(1), stackPos(2), stackPos(3));
+ m->destDirection = stackPos(4) << 1;
+ if (m->x != m->destX || m->y != m->destY)
+ setMonsterDirection(m, calcMonsterDirection(m->x, m->y, m->destX, m->destY));
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_setupDialogueButtons(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setupDialogueButtons(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ setupDialogueButtons(stackPos(0), getLangString(stackPos(1)), getLangString(stackPos(2)), getLangString(stackPos(3)));
+ return 1;
+}
+
+int LoLEngine::olol_giveTakeMoney(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_giveTakeMoney(%p) (%d)", (const void *)script, stackPos(0));
+ int c = stackPos(0);
+ if (c >= 0)
+ giveCredits(c, 1);
+ else
+ takeCredits(-c, 1);
+
+ return 1;
+}
+
+int LoLEngine::olol_checkMoney(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkMoney(%p) (%d)", (const void *)script, stackPos(0));
+ return (stackPos(0) > _credits) ? 0 : 1;
+}
+
+int LoLEngine::olol_setScriptTimer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setScriptTimer(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ uint8 id = 0x50 + stackPos(0);
+
+ if (stackPos(1)) {
+ _timer->enable(id);
+ _timer->setCountdown(id, stackPos(1));
+
+ } else {
+ _timer->disable(id);
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_createHandItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_createHandItem(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ if (_itemInHand)
+ return 0;
+
+ setHandItem(makeItem(stackPos(0), stackPos(1), stackPos(2)));
+ return 1;
+}
+
+int LoLEngine::olol_playAttackSound(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playAttackSound(%p) (%d)", (const void *)script, stackPos(0));
+
+ static const uint8 sounds[] = { 12, 62, 63 };
+ int d = stackPos(0);
+
+ if ((d < 70 || d > 74) && (d < 81 || d > 89) && (d < 93 || d > 97) && (d < 102 || d > 106))
+ snd_playSoundEffect(sounds[_itemProperties[d].skill & 3], -1);
+ else
+ snd_playSoundEffect(12, -1);
+
+ return 1;
+}
+
+int LoLEngine::olol_addRemoveCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_addRemoveCharacter(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+
+ int16 id = stackPos(0);
+ if (id < 0) {
+ id = -id;
+ for (int i = 0; i < 4; i++) {
+ if (!(_characters[i].flags & 1) || _characters[i].id != id)
+ continue;
+
+ _characters[i].flags &= 0xFFFE;
+ calcCharPortraitXpos();
+
+ if (_selectedCharacter == i)
+ _selectedCharacter = 0;
+ break;
+ }
+ } else {
+ addCharacter(id);
+ }
+
+ if (!_updateFlags) {
+ gui_enableDefaultPlayfieldButtons();
+ gui_drawPlayField();
+ }
+
+ return 1;
+}
+int LoLEngine::olol_giveItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_giveItem(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ int item = makeItem(stackPos(0), stackPos(1), stackPos(2));
+ if (addItemToInventory(item))
+ return 1;
+
+ deleteItem(item);
+ return 0;
+}
+
+int LoLEngine::olol_loadTimScript(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadTimScript(%p) (%d, %s)", (const void *)script, stackPos(0), stackPosString(1));
+ if (_activeTim[stackPos(0)])
+ return 1;
+ Common::String file = Common::String::format("%s.TIM", stackPosString(1));
+ _activeTim[stackPos(0)] = _tim->load(file.c_str(), &_timIngameOpcodes);
+ return 1;
+}
+
+int LoLEngine::olol_runTimScript(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_runTimScript(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return _tim->exec(_activeTim[stackPos(0)], stackPos(1));
+}
+
+int LoLEngine::olol_releaseTimScript(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_releaseTimScript(%p) (%d)", (const void *)script, stackPos(0));
+ _tim->unload(_activeTim[stackPos(0)]);
+ return 1;
+}
+
+int LoLEngine::olol_initSceneWindowDialogue(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_initSceneWindowDialogue(%p) (%d)", (const void *)script, stackPos(0));
+ initSceneWindowDialogue(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_restoreAfterSceneWindowDialogue(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restoreAfterSceneWindowDialogue(%p) (%d)", (const void *)script, stackPos(0));
+ restoreAfterSceneWindowDialogue(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_getItemInHand(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getItemInHand(%p))", (const void *)script);
+ return _itemInHand;
+}
+
+int LoLEngine::olol_checkMagic(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkMagic(%p )(%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ return checkMagic(stackPos(0), stackPos(1), stackPos(2));
+}
+
+int LoLEngine::olol_giveItemToMonster(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_giveItemToMonster(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ if (stackPos(0) == -1)
+ return 0;
+ giveItemToMonster(&_monsters[stackPos(0)], stackPos(1));
+ return 1;
+}
+
+int LoLEngine::olol_loadLangFile(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadLangFile(%p) (%s)", (const void *)script, stackPosString(0));
+ Common::String filename = Common::String::format("%s.%s", stackPosString(0), _languageExt[_lang]);
+ delete[] _levelLangFile;
+ _levelLangFile = _res->fileData(filename.c_str(), 0);
+ return 1;
+}
+
+int LoLEngine::olol_playSoundEffect(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playSoundEffect(%p) (%d)", (const void *)script, stackPos(0));
+ snd_playSoundEffect(stackPos(0), -1);
+ return 1;
+}
+
+int LoLEngine::olol_processDialogue(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_processDialogue(%p)", (const void *)script);
+ return processDialogue();
+}
+
+int LoLEngine::olol_stopTimScript(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_stopTimScript(%p) (%d)", (const void *)script, stackPos(0));
+ _tim->stopAllFuncs(_activeTim[stackPos(0)]);
+ return 1;
+}
+
+int LoLEngine::olol_getWallFlags(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getWallFlags(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return _wllWallFlags[_levelBlockProperties[stackPos(0)].walls[stackPos(1) & 3]];
+}
+
+int LoLEngine::olol_changeMonsterStat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_changeMonsterStat(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ if (stackPos(0) == -1)
+ return 1;
+
+ LoLMonster *m = &_monsters[stackPos(0) & 0x7FFF];
+
+ int16 d = stackPos(2);
+ uint16 x = 0;
+ uint16 y = 0;
+
+ switch (stackPos(1)) {
+ case 0:
+ setMonsterMode(m, d);
+ break;
+
+ case 1:
+ m->hitPoints = d;
+ break;
+
+ case 2:
+ calcCoordinates(x, y, d, m->x & 0xFF, m->y & 0xFF);
+ if (!walkMonsterCheckDest(x, y, m, 7))
+ placeMonster(m, x, y);
+ break;
+
+ case 3:
+ setMonsterDirection(m, d << 1);
+ break;
+
+ case 6:
+ m->flags |= d;
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_getMonsterStat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getMonsterStat(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ if (stackPos(0) == -1)
+ return 0;
+
+ LoLMonster *m = &_monsters[stackPos(0) & 0x7FFF];
+ int d = stackPos(1);
+
+ switch (d) {
+ case 0:
+ return m->mode;
+ case 1:
+ return m->hitPoints;
+ case 2:
+ return m->block;
+ case 3:
+ return m->facing;
+ case 4:
+ return m->type;
+ case 5:
+ return m->properties->hitPoints;
+ case 6:
+ return m->flags;
+ case 7:
+ return m->properties->flags;
+ case 8:
+ return _monsterAnimType[m->properties->shapeIndex];
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int LoLEngine::olol_releaseMonsterShapes(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_releaseMonsterShapes(%p)", (const void *)script);
+ for (int i = 0; i < 3; i++)
+ releaseMonsterShapes(i);
+ return 0;
+}
+
+int LoLEngine::olol_playCharacterScriptChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playCharacterScriptChat(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ if (_flags.isTalkie) {
+ snd_stopSpeech(1);
+ stopPortraitSpeechAnim();
+ }
+ return playCharacterScriptChat(stackPos(0), stackPos(1), 1, getLangString(stackPos(2)), script, 0, 3);
+}
+
+int LoLEngine::olol_playEnvironmentalSfx(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playEnvironmentalSfx(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ uint16 block = (stackPos(1) == -1) ? _currentBlock : stackPos(1);
+ snd_processEnvironmentalSoundEffect(stackPos(0), block);
+ return 1;
+}
+
+int LoLEngine::olol_update(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_update(%p)", (const void *)script);
+ update();
+ return 1;
+}
+
+int LoLEngine::olol_healCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_healCharacter(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ if (stackPos(3)) {
+ processMagicHeal(stackPos(0), stackPos(1));
+ } else {
+ increaseCharacterHitpoints(stackPos(0), stackPos(1), true);
+ if (stackPos(2))
+ gui_drawCharPortraitWithStats(stackPos(0));
+ }
+ return 1;
+}
+
+int LoLEngine::olol_drawExitButton(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_drawExitButton(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+
+ static const uint8 printPara[] = { 0x90, 0x78, 0x0C, 0x9F, 0x80, 0x1E };
+
+ int cp = _screen->setCurPage(0);
+ Screen::FontId cf = _screen->setFont(Screen::FID_6_FNT);
+ int x = printPara[3 * stackPos(0)] << 1;
+ int y = printPara[3 * stackPos(0) + 1];
+ int offs = printPara[3 * stackPos(0) + 2];
+
+ char *str = getLangString(0x4033);
+ int w = _screen->getTextWidth(str);
+
+ if (_flags.use16ColorMode) {
+ gui_drawBox(x - offs - w, y - 9, w + offs, 9, 0xEE, 0xCC, 0x11);
+ _screen->printText(str, x - (offs >> 1) - w, y - 7, 0xBB, 0);
+ } else {
+ gui_drawBox(x - offs - w, y - 9, w + offs, 9, 136, 251, 252);
+ _screen->printText(str, x - (offs >> 1) - w, y - 7, 144, 0);
+ }
+
+ if (stackPos(1))
+ _screen->drawGridBox(x - offs - w + 1, y - 8, w + offs - 2, 7, 1);
+
+ _screen->setFont(cf);
+ _screen->setCurPage(cp);
+ return 1;
+}
+
+int LoLEngine::olol_loadSoundFile(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadSoundFile(%p) (%d)", (const void *)script, stackPos(0));
+ snd_loadSoundFile(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_playMusicTrack(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playMusicTrack(%p) (%d)", (const void *)script, stackPos(0));
+ return snd_playTrack(stackPos(0));
+}
+
+int LoLEngine::olol_deleteMonstersFromBlock(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_deleteMonstersFromBlock(%p) (%d)", (const void *)script, stackPos(0));
+ deleteMonstersFromBlock(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_countBlockItems(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_countBlockItems(%p) (%d)", (const void *)script, stackPos(0));
+ uint16 o = _levelBlockProperties[stackPos(0)].assignedObjects;
+ int res = 0;
+
+ while (o) {
+ if (!(o & 0x8000))
+ res++;
+ o = findObject(o)->nextAssignedObject;
+ }
+
+ return res;
+}
+
+int LoLEngine::olol_characterSkillTest(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_characterSkillTest(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ int skill = stackPos(0);
+ int n = countActiveCharacters();
+ int m = 0;
+ int c = 0;
+
+ for (int i = 0; i < n; i++) {
+ int v = _characters[i].skillModifiers[skill] + _characters[i].skillLevels[skill] + 25;
+ if (v > m) {
+ m = v;
+ c = i;
+ }
+ }
+
+ return (rollDice(1, 100) > m) ? -1 : c;
+}
+
+int LoLEngine::olol_countAllMonsters(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_countAllMonsters(%p)", (const void *)script);
+ int res = 0;
+
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].hitPoints > 0 && _monsters[i].mode != 13)
+ res++;
+ }
+
+ return res;
+}
+
+int LoLEngine::olol_playEndSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playEndSequence(%p)", (const void *)script);
+
+ int c = 0;
+ if (_characters[0].id == -9)
+ c = 1;
+ else if (_characters[0].id == -5)
+ c = 3;
+ else if (_characters[0].id == -1)
+ c = 2;
+
+ while (snd_updateCharacterSpeech())
+ delay(_tickLength);
+
+ _eventList.clear();
+ _screen->hideMouse();
+ _screen->getPalette(1).clear();
+
+ showOutro(c, (_monsterDifficulty == 2));
+ // Don't call quitGame() on a RTL request (because this would
+ // make the next game launched from the launcher quit instantly.
+ if (!shouldQuit())
+ quitGame();
+
+ return 0;
+}
+
+int LoLEngine::olol_stopPortraitSpeechAnim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_stopPortraitSpeechAnim(%p)", (const void *)script);
+ if (_flags.isTalkie)
+ snd_stopSpeech(1);
+ stopPortraitSpeechAnim();
+ return 1;
+}
+
+int LoLEngine::olol_setPaletteBrightness(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setPaletteBrightness(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ uint16 old = _brightness;
+ _brightness = stackPos(0);
+ if (stackPos(1) == 1)
+ setPaletteBrightness(_screen->getPalette(0), stackPos(0), _lampEffect);
+ return old;
+}
+
+int LoLEngine::olol_calcInflictableDamage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_calcInflictableDamage(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ return calcInflictableDamage(stackPos(0), stackPos(1), stackPos(2));
+}
+
+int LoLEngine::olol_getInflictedDamage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getInflictedDamage(%p) (%d)", (const void *)script, stackPos(0));
+ int mx = stackPos(0);
+ return rollDice(2, mx);
+}
+
+int LoLEngine::olol_checkForCertainPartyMember(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkForCertainPartyMember(%p) (%d)", (const void *)script, stackPos(0));
+ for (int i = 0; i < 4; i++) {
+ if (_characters[i].flags & 9 && _characters[i].id == stackPos(0))
+ return 1;
+ }
+ return 0;
+}
+
+int LoLEngine::olol_printMessage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_printMessage(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9));
+ int snd = stackPos(2);
+ _txt->printMessage(stackPos(0), getLangString(stackPos(1)), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9));
+
+ if (snd >= 0)
+ snd_playSoundEffect(snd, -1);
+
+ return 1;
+}
+
+int LoLEngine::olol_deleteLevelItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_deleteLevelItem(%p) (%d)", (const void *)script, stackPos(0));
+ if (_itemsInPlay[stackPos(0)].block)
+ removeLevelItem(stackPos(0), _itemsInPlay[stackPos(0)].block);
+
+ deleteItem(stackPos(0));
+
+ return 1;
+}
+
+int LoLEngine::olol_calcInflictableDamagePerItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_calcInflictableDamagePerItem(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ return calcInflictableDamagePerItem(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+}
+
+int LoLEngine::olol_distanceAttack(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_distanceAttack(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8));
+
+ uint16 fX = stackPos(3);
+ uint16 fY = stackPos(4);
+
+ if (!(stackPos(8) & 0x8000))
+ fX = fY = 0x80;
+
+ uint16 x = 0;
+ uint16 y = 0;
+ calcCoordinates(x, y, stackPos(2), fX, fY);
+
+ if (launchObject(stackPos(0), stackPos(1), x, y, stackPos(5), stackPos(6) << 1, stackPos(7), stackPos(8), 0x3F))
+ return 1;
+
+ deleteItem(stackPos(1));
+ return 0;
+}
+
+int LoLEngine::olol_removeCharacterEffects(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_removeCharacterEffects(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ removeCharacterEffects(&_characters[stackPos(0)], stackPos(1), stackPos(2));
+ return 1;
+}
+
+int LoLEngine::olol_checkInventoryFull(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkInventoryFull(%p)", (const void *)script);
+ for (int i = 0; i < 48; i++) {
+ if (_inventory[i])
+ return 0;
+ }
+ return 1;
+}
+
+int LoLEngine::olol_moveBlockObjects(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_moveBlockObjects(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ int o = _levelBlockProperties[stackPos(0)].assignedObjects;
+ int res = 0;
+ int level = stackPos(2);
+ int destBlock = stackPos(1);
+ int runScript = stackPos(4);
+ int includeMonsters = stackPos(3);
+ int includeItems = stackPos(5);
+
+ // WORKAROUND for script bug
+ // Items would vanish when thrown towards the stairs
+ // in white tower level 3.
+ if (_currentLevel == 21 && level == 21 && destBlock == 0x3E0) {
+ level = 20;
+ destBlock = 0x0247;
+ }
+
+ while (o) {
+ int l = o;
+ o = findObject(o)->nextAssignedObject;
+ if (l & 0x8000) {
+ if (!includeMonsters)
+ continue;
+
+ l &= 0x7FFF;
+
+ LoLMonster *m = &_monsters[l];
+
+ setMonsterMode(m, 14);
+ checkSceneUpdateNeed(m->block);
+ placeMonster(m, 0, 0);
+
+ res = 1;
+
+ } else {
+ if (!(_itemsInPlay[l].shpCurFrame_flg & 0x4000) || !includeItems)
+ continue;
+
+ placeMoveLevelItem(l, level, destBlock, _itemsInPlay[l].x & 0xFF, _itemsInPlay[l].y & 0xFF, _itemsInPlay[l].flyingHeight);
+ res = 1;
+
+ if (!runScript || level != _currentLevel)
+ continue;
+
+ runLevelScriptCustom(destBlock, 0x80, -1, l, 0, 0);
+ }
+ }
+
+ return res;
+}
+
+int LoLEngine::olol_addSpellToScroll(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_addSpellToScroll(%p) (%d)", (const void *)script, stackPos(0));
+ addSpellToScroll(stackPos(0), stackPos(1));
+ return 1;
+}
+
+int LoLEngine::olol_playDialogueText(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playDialogueText(%p) (%d)", (const void *)script, stackPos(0));
+ _txt->printDialogueText(3, getLangString(stackPos(0)), script, 0, 1);
+ return 1;
+}
+
+int LoLEngine::olol_playDialogueTalkText(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playDialogueTalkText(%p) (%d)", (const void *)script, stackPos(0));
+ int track = stackPos(0);
+
+ if (!snd_playCharacterSpeech(track, 0, 0) || textEnabled()) {
+ char *s = getLangString(track);
+ _txt->printDialogueText(4, s, script, 0, 1);
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_checkMonsterTypeHostility(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkMonsterTypeHostility(%p) (%d)", (const void *)script, stackPos(0));
+ for (int i = 0; i < 30; i++) {
+ if (stackPos(0) != _monsters[i].type && stackPos(0) != -1)
+ continue;
+ return (_monsters[i].mode == 1) ? 0 : 1;
+ }
+ return 1;
+}
+
+int LoLEngine::olol_setNextFunc(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setNextFunc(%p) (%d)", (const void *)script, stackPos(0));
+ _nextScriptFunc = stackPos(0);
+ return 1;
+}
+
+int LoLEngine::olol_dummy1(EMCState *script) {
+ return 1;
+}
+
+int LoLEngine::olol_suspendMonster(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_suspendMonster(%p) (%d)", (const void *)script, stackPos(0));
+ LoLMonster *m = &_monsters[stackPos(0) & 0x7FFF];
+ setMonsterMode(m, 14);
+ checkSceneUpdateNeed(m->block);
+ placeMonster(m, 0, 0);
+ return 1;
+}
+
+int LoLEngine::olol_setScriptTextParameter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setScriptTextParameter(%p) (%d)", (const void *)script, stackPos(0));
+ _txt->_scriptTextParameter = stackPos(0);
+ return 1;
+}
+
+int LoLEngine::olol_triggerEventOnMouseButtonClick(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_triggerEventOnMouseButtonClick(%p) (%d)", (const void *)script, stackPos(0));
+ gui_notifyButtonListChanged();
+ snd_updateCharacterSpeech();
+
+ int f = checkInput(0);
+ removeInputTop();
+ if (f == 0 || (f & 0x800))
+ return 0;
+
+ int evt = stackPos(0);
+ if (evt) {
+ gui_triggerEvent(evt);
+ _seqTrigger = 1;
+ } else {
+ removeInputTop();
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_printWindowText(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_printWindowText(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ int dim = stackPos(0);
+ int flg = stackPos(1);
+ _screen->setScreenDim(dim);
+ if (flg & 1)
+ _txt->clearCurDim();
+ if (flg & 3)
+ _txt->resetDimTextPositions(dim);
+ _txt->printDialogueText(dim, getLangString(stackPos(2)), script, 0, 3);
+ return 1;
+}
+
+int LoLEngine::olol_countSpecificMonsters(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_countSpecificMonsters(%p) (%d, ...)", (const void *)script, stackPos(0));
+ uint16 types = 0;
+ int res = 0;
+ int cnt = 0;
+
+ while (stackPos(cnt) != -1)
+ types |= (1 << stackPos(cnt++));
+
+ for (int i = 0; i < 30; i++) {
+ if (((1 << _monsters[i].type) & types) && _monsters[i].mode < 14)
+ res++;
+ }
+
+ return res;
+}
+
+int LoLEngine::olol_updateBlockAnimations2(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_updateBlockAnimations2(%p) (%d, %d, %d, %d, ...)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ int numFrames = stackPos(3);
+ assert(numFrames <= 97);
+ int curFrame = stackPos(2) % numFrames;
+ setWallType(stackPos(0), stackPos(1), stackPos(4 + curFrame));
+ return 0;
+}
+
+int LoLEngine::olol_checkPartyForItemType(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkPartyForItemType(%p) (%d, %d, %d))", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ int p = stackPos(1);
+
+ if (!stackPos(2)) {
+ for (int i = 0; i < 48; i++) {
+ if (!_inventory[i] || _itemsInPlay[_inventory[i]].itemPropertyIndex != p)
+ continue;
+ return 1;
+ }
+
+ if (_itemsInPlay[_itemInHand].itemPropertyIndex == p)
+ return 1;
+ }
+
+ int last = (stackPos(0) == -1) ? 3 : stackPos(0);
+ int first = (stackPos(0) == -1) ? 0 : stackPos(0);
+
+ for (int i = first; i <= last; i++) {
+ if (itemEquipped(i, p))
+ return 1;
+ }
+
+ return 0;
+}
+
+int LoLEngine::olol_blockDoor(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_blockDoor(%p) (%d)", (const void *)script, stackPos(0));
+ _blockDoor = stackPos(0);
+ return _blockDoor;
+}
+
+int LoLEngine::olol_resetTimDialogueState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_resetTimDialogueState(%p) (%d)", (const void *)script, stackPos(0));
+ _tim->resetDialogueState(_activeTim[stackPos(0)]);
+ return 1;
+}
+
+int LoLEngine::olol_getItemOnPos(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getItemOnPos(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ int pX = stackPos(1);
+ if (pX != -1)
+ pX &= 0xFF;
+
+ int pY = stackPos(2);
+ if (pY != -1)
+ pY &= 0xFF;
+
+ int o = (stackPos(3) || _emcLastItem == -1) ? stackPos(0) : _emcLastItem;
+
+ _emcLastItem = _levelBlockProperties[o].assignedObjects;
+
+ while (_emcLastItem) {
+ if (_emcLastItem & 0x8000) {
+ o = _emcLastItem & 0x7FFF;
+ _emcLastItem = _levelBlockProperties[o].assignedObjects;
+ continue;
+ }
+
+ if (pX != -1 && (_itemsInPlay[_emcLastItem].x & 0xFF) != pX) {
+ o = _emcLastItem & 0x7FFF;
+ _emcLastItem = _levelBlockProperties[o].assignedObjects;
+ continue;
+ }
+
+ if (pY != -1 && (_itemsInPlay[_emcLastItem].y & 0xFF) != pY) {
+ o = _emcLastItem & 0x7FFF;
+ _emcLastItem = _levelBlockProperties[o].assignedObjects;
+ continue;
+ }
+
+ return _emcLastItem;
+ }
+
+ return 0;
+}
+
+int LoLEngine::olol_removeLevelItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_removeLevelItem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ removeLevelItem(stackPos(0), stackPos(1));
+ return 1;
+}
+
+int LoLEngine::olol_savePage5(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_savePage5(%p)", (const void *)script);
+ // Not implemented: The original code uses this to back up and restore page 5 which is used
+ // to load WSA files. Since our WSA player provides its own memory buffers we don't
+ // need to use page 5.
+ return 1;
+}
+
+int LoLEngine::olol_restorePage5(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restorePage5(%p)", (const void *)script);
+ // Not implemented: The original code uses this to back up and restore page 5 which is used
+ // to load WSA files. Since our WSA player provides its own memory buffers we don't
+ // need to use page 5.
+ for (int i = 0; i < 6; i++)
+ _tim->freeAnimStruct(i);
+ return 1;
+}
+
+int LoLEngine::olol_initDialogueSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_initDialogueSequence(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ initDialogueSequence(stackPos(0), stackPos(1));
+ return 1;
+}
+
+int LoLEngine::olol_restoreAfterDialogueSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restoreAfterDialogueSequence(%p) (%d)", (const void *)script, stackPos(0));
+ restoreAfterDialogueSequence(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_setSpecialSceneButtons(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setSpecialSceneButtons(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ setSpecialSceneButtons(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ return 1;
+}
+
+int LoLEngine::olol_restoreButtonsAfterSpecialScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restoreButtonsAfterSpecialScene(%p)", (const void *)script);
+ gui_specialSceneRestoreButtons();
+ return 1;
+}
+
+int LoLEngine::olol_prepareSpecialScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_prepareSpecialScene(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ prepareSpecialScene(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ return 1;
+}
+
+int LoLEngine::olol_restoreAfterSpecialScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restoreAfterSpecialScene(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ return restoreAfterSpecialScene(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+}
+
+int LoLEngine::olol_assignCustomSfx(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_assignCustomSfx(%p) (%s, %d)", (const void *)script, stackPosString(0), stackPos(1));
+ const char *c = stackPosString(0);
+ int i = stackPos(1);
+
+ if (!c || i > 250)
+ return 0;
+
+ uint16 t = READ_LE_UINT16(&_ingameSoundIndex[i << 1]);
+ if (t == 0xFFFF)
+ return 0;
+
+ strcpy(_ingameSoundList[t], c);
+
+ return 0;
+}
+
+int LoLEngine::olol_findAssignedMonster(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_findAssignedMonster(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ uint16 o = stackPos(1) == -1 ? _levelBlockProperties[stackPos(0)].assignedObjects : findObject(stackPos(1))->nextAssignedObject;
+ while (o) {
+ if (o & 0x8000)
+ return o & 0x7FFF;
+ o = findObject(o)->nextAssignedObject;
+ }
+ return -1;
+}
+
+int LoLEngine::olol_checkBlockForMonster(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkBlockForMonster(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ uint16 block = stackPos(0);
+ uint16 id = stackPos(1) | 0x8000;
+
+ uint16 o = _levelBlockProperties[block].assignedObjects;
+ while (o & 0x8000) {
+ if (id == 0xFFFF || id == o)
+ return o & 0x7FFF;
+ o = findObject(o)->nextAssignedObject;
+ }
+ return -1;
+}
+
+int LoLEngine::olol_crossFadeRegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_crossFadeRegion(%p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ _screen->crossFadeRegion(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ return 1;
+}
+
+int LoLEngine::olol_calcCoordinatesAddDirectionOffset(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_calcCoordinatesAddDirectionOffset(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ uint16 x = stackPos(0);
+ uint16 y = stackPos(1);
+ calcCoordinatesAddDirectionOffset(x, y, stackPos(2));
+ return stackPos(3) ? x : y;
+}
+
+int LoLEngine::olol_resetPortraitsAndDisableSysTimer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_resetPortraitsAndDisableSysTimer(%p)", (const void *)script);
+ resetPortraitsAndDisableSysTimer();
+ return 1;
+}
+
+int LoLEngine::olol_enableSysTimer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_enableSysTimer(%p)", (const void *)script);
+ _needSceneRestore = 0;
+ enableSysTimer(2);
+ return 1;
+}
+
+int LoLEngine::olol_checkNeedSceneRestore(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkNeedSceneRestore(%p)", (const void *)script);
+ return _needSceneRestore;
+}
+
+int LoLEngine::olol_getNextActiveCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getNextActiveCharacter(%p) (%d)", (const void *)script, stackPos(0));
+ if (stackPos(0))
+ _scriptCharacterCycle = 0;
+ else
+ _scriptCharacterCycle++;
+
+ while (_scriptCharacterCycle < 4) {
+ if (_characters[_scriptCharacterCycle].flags & 1)
+ return _scriptCharacterCycle;
+ _scriptCharacterCycle++;
+ }
+ return -1;
+}
+
+int LoLEngine::olol_paralyzePoisonCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_paralyzePoisonCharacter(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ return paralyzePoisonCharacter(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+}
+
+int LoLEngine::olol_drawCharPortrait(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_drawCharPortrait(%p) (%d)", (const void *)script, stackPos(0));
+ int charNum = stackPos(0);
+ if (charNum == -1)
+ gui_drawAllCharPortraitsWithStats();
+ else
+ gui_drawCharPortraitWithStats(charNum);
+ return 1;
+}
+
+int LoLEngine::olol_removeInventoryItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_removeInventoryItem(%p) (%d)", (const void *)script, stackPos(0));
+ int itemType = stackPos(0);
+ for (int i = 0; i < 48; i++) {
+ if (!_inventory[i] || _itemsInPlay[_inventory[i]].itemPropertyIndex != itemType)
+ continue;
+ _inventory[i] = 0;
+ gui_drawInventory();
+ return 1;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ if (!(_characters[i].flags & 1))
+ continue;
+
+ for (int ii = 0; ii < 11; ii++) {
+ if (!_characters[i].items[ii] || _itemsInPlay[_characters[i].items[ii]].itemPropertyIndex != itemType)
+ continue;
+ _characters[i].items[ii] = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int LoLEngine::olol_getAnimationLastPart(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getAnimationLastPart(%p) (%d)", (const void *)script, stackPos(0));
+ return _tim->animator()->resetLastPart(stackPos(0));
+}
+
+int LoLEngine::olol_assignSpecialGuiShape(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_assignSpecialGuiShape(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ if (stackPos(0)) {
+ _specialGuiShape = _levelDecorationShapes[_levelDecorationProperties[_wllShapeMap[stackPos(0)]].shapeIndex[stackPos(1)]];
+ _specialGuiShapeX = stackPos(2);
+ _specialGuiShapeY = stackPos(3);
+ _specialGuiShapeMirrorFlag = stackPos(4);
+
+ } else {
+ _specialGuiShape = 0;
+ _specialGuiShapeX = _specialGuiShapeY = _specialGuiShapeMirrorFlag = 0;
+ }
+ return 1;
+}
+
+int LoLEngine::olol_findInventoryItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_findInventoryItem(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ if (stackPos(0) == 0) {
+ for (int i = 0; i < 48; i++) {
+ if (!_inventory[i])
+ continue;
+ if (_itemsInPlay[_inventory[i]].itemPropertyIndex == stackPos(2))
+ return 0;
+ }
+ }
+ int cur = stackPos(1);
+ int last = cur;
+ if (stackPos(1) == -1) {
+ cur = 0;
+ last = 4;
+ }
+ for (; cur < last; cur++) {
+ if (!(_characters[cur].flags & 1))
+ continue;
+ for (int i = 0; i < 11; i++) {
+ if (!_characters[cur].items[i])
+ continue;
+ if (_itemsInPlay[_characters[cur].items[i]].itemPropertyIndex == stackPos(2))
+ return cur;
+ }
+ }
+ return -1;
+}
+
+int LoLEngine::olol_restoreFadePalette(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restoreFadePalette(%p)", (const void *)script);
+ _screen->getPalette(0).copy(_screen->getPalette(1), 0, _flags.use16ColorMode ? 16 : 128);
+ _screen->fadePalette(_screen->getPalette(0), 10);
+ _screen->_fadeFlag = 0;
+ return 1;
+}
+
+int LoLEngine::olol_getSelectedCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getSelectedCharacter(%p)", (const void *)script);
+ return _selectedCharacter;
+}
+
+int LoLEngine::olol_setHandItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setHandItem(%p) (%d)", (const void *)script, stackPos(0));
+ setHandItem(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_drinkBezelCup(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_drinkBezelCup(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ drinkBezelCup(3 - stackPos(0), stackPos(1));
+ return 1;
+}
+
+int LoLEngine::olol_changeItemTypeOrFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_changeItemTypeOrFlag(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ if (stackPos(0) < 1)
+ return 0;
+
+ LoLItem *i = &_itemsInPlay[stackPos(0)];
+ int16 val = stackPos(2);
+
+ if (stackPos(1) == 4)
+ i->itemPropertyIndex = val;
+ else if (stackPos(1) == 15)
+ i->shpCurFrame_flg = (i->shpCurFrame_flg & 0xE000) | (val & 0x1FFF);
+ else
+ val = -1;
+
+ return val;
+}
+
+int LoLEngine::olol_placeInventoryItemInHand(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_placeInventoryItemInHand(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ int itemType = stackPos(0);
+ int i = 0;
+ for (; i < 48; i++) {
+ if (!_inventory[i])
+ continue;
+ if (_itemsInPlay[_inventory[i]].itemPropertyIndex == itemType)
+ break;
+ }
+
+ if (i == 48)
+ return -1;
+
+ _inventoryCurItem = i;
+ int r = _itemInHand;
+ setHandItem(_inventory[i]);
+ _inventory[i] = r;
+
+ if (stackPos(1))
+ gui_drawInventory();
+
+ return r;
+}
+
+int LoLEngine::olol_castSpell(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_castSpell(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ return castSpell(stackPos(0), stackPos(1), stackPos(2));
+}
+
+int LoLEngine::olol_pitDrop(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_pitDrop(%p) (%d)", (const void *)script, stackPos(0));
+ int m = stackPos(0);
+ _screen->updateScreen();
+ if (m) {
+ gui_drawScene(2);
+ pitDropScroll(9);
+ snd_playSoundEffect(-1, -1);
+ shakeScene(30, 4, 0, 1);
+
+ } else {
+ int t = -1;
+ for (int i = 0; i < 4; i++) {
+ if (!(_characters[i].flags & 1) || (_characters[i].id >= 0))
+ continue;
+ if (_characters[i].id == -1)
+ t = 54;
+ else if (_characters[i].id == -5)
+ t = 53;
+ else if (_characters[i].id == -8)
+ t = 52;
+ else if (_characters[i].id == -9)
+ t = 51;
+ }
+
+ _screen->fillRect(112, 0, 288, 120, 0, 2);
+ snd_playSoundEffect(t, -1);
+ pitDropScroll(12);
+ }
+
+ return 1;
+}
+
+int LoLEngine::olol_increaseSkill(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_increaseSkill(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ LoLCharacter *c = &_characters[stackPos(0)];
+ int s = stackPos(1);
+ int l = c->skillLevels[s];
+ increaseExperience(stackPos(0), s, _expRequirements[l] - c->experiencePts[s]);
+ return c->skillLevels[s] - l;
+}
+
+int LoLEngine::olol_paletteFlash(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_paletteFlash(%p) (%d)", (const void *)script, stackPos(0));
+ Palette &p1 = _screen->getPalette(1);
+
+ if (_flags.use16ColorMode) {
+ Palette p2(16);
+ p2.copy(p1);
+ uint8 *d = p2.getData();
+
+ for (int i = 0; i < 16; i++)
+ d[i * 3] = 0x3F;
+
+ _screen->setScreenPalette(p2);
+ _screen->updateScreen();
+
+ delay(4 * _tickLength);
+
+ _screen->setScreenPalette(p1);
+ if (_smoothScrollModeNormal)
+ _screen->copyRegion(112, 0, 112, 0, 176, 120, 2, 0);
+
+ _screen->updateScreen();
+
+ } else {
+ Palette &p2 = _screen->getPalette(3);
+
+ uint8 ovl[256];
+ generateFlashPalette(p1, p2, stackPos(0));
+ _screen->loadSpecialColors(p1);
+ _screen->loadSpecialColors(p2);
+
+ if (_smoothScrollModeNormal) {
+ for (int i = 0; i < 256; i++)
+ ovl[i] = i;
+ ovl[1] = 6;
+
+ _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, 2);
+ _screen->applyOverlay(112, 0, 176, 120, 0, ovl);
+ }
+
+ _screen->setScreenPalette(p2);
+ _screen->updateScreen();
+
+ delay(2 * _tickLength);
+
+ _screen->setScreenPalette(p1);
+ if (_smoothScrollModeNormal)
+ _screen->copyRegion(112, 0, 112, 0, 176, 120, 2, 0);
+
+ _screen->updateScreen();
+ }
+
+ return 0;
+}
+
+int LoLEngine::olol_restoreMagicShroud(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restoreMagicShroud(%p)", (const void *)script);
+
+ WSAMovie_v2 *mov = new WSAMovie_v2(this);
+ mov->open("DARKLITE.WSA", 2, 0);
+ if (!mov->opened()) {
+ delete mov;
+ warning("LoLEngine::olol_restoreMagicShroud: Could not open file: \"DARKLITE.WSA\"");
+ return 1;
+ }
+
+ _screen->hideMouse();
+
+ Palette *fadeTab[28];
+ for (int i = 0; i < 28; i++)
+ fadeTab[i] = new Palette(_flags.use16ColorMode ? 16 : 256);
+
+ Palette **tpal1 = &fadeTab[0];
+ Palette **tpal2 = &fadeTab[1];
+ Palette **tpal3 = &fadeTab[2];
+ Palette **tpal4 = 0;
+
+ int len = _flags.use16ColorMode ? 48 : 768;
+ _res->loadFileToBuf("LITEPAL1.COL", (*tpal1)->getData(), len);
+ tpal2 = _screen->generateFadeTable(tpal3, 0, *tpal1, 21);
+
+ _res->loadFileToBuf("LITEPAL2.COL", (*tpal2)->getData(), len);
+ tpal4 = tpal2++;
+
+ _res->loadFileToBuf("LITEPAL3.COL", (*tpal1)->getData(), len);
+ _screen->generateFadeTable(tpal2, *tpal4, *tpal1, 4);
+
+ for (int i = 0; i < 21; i++) {
+ uint32 etime = _system->getMillis() + 20 * _tickLength;
+ mov->displayFrame(i, 0, 0, 0, 0, 0, 0);
+ _screen->setScreenPalette(**tpal3++);
+ _screen->updateScreen();
+
+ if (i == 2 || i == 5 || i == 8 || i == 11 || i == 13 || i == 15 || i == 17 || i == 19)
+ snd_playSoundEffect(95, -1);
+
+ delayUntil(etime);
+ }
+
+ snd_playSoundEffect(91, -1);
+ _screen->fadePalette(**tpal3++, 300);
+
+ for (int i = 22; i < 38; i++) {
+ uint32 etime = _system->getMillis() + 12 * _tickLength;
+ mov->displayFrame(i, 0, 0, 0, 0, 0, 0);
+ if (i == 22 || i == 24 || i == 28 || i == 32) {
+ snd_playSoundEffect(131, -1);
+ _screen->setScreenPalette(**tpal3++);
+ }
+ _screen->updateScreen();
+ delayUntil(etime);
+ }
+
+ mov->close();
+ delete mov;
+
+ for (int i = 0; i < 28; i++)
+ delete fadeTab[i];
+
+ _screen->showMouse();
+
+ return 1;
+}
+
+int LoLEngine::olol_disableControls(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_disableControls(%p) (%d)", (const void *)script, stackPos(0));
+ return gui_disableControls(stackPos(0));
+}
+
+int LoLEngine::olol_enableControls(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_enableControls(%p)", (const void *)script);
+ return gui_enableControls();
+}
+
+int LoLEngine::olol_shakeScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_shakeScene(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ shakeScene(stackPos(0), stackPos(1), stackPos(2), 1);
+ return 1;
+}
+
+int LoLEngine::olol_gasExplosion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_gasExplosion(%p) (%d)", (const void *)script, stackPos(0));
+ processGasExplosion(stackPos(0));
+ return 1;
+}
+
+int LoLEngine::olol_calcNewBlockPosition(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_calcNewBlockPosition(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return calcNewBlockPosition(stackPos(0), stackPos(1));
+}
+
+int LoLEngine::olol_crossFadeScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_crossFadeScene(%p)", (const void *)script);
+ gui_drawScene(2);
+ _screen->crossFadeRegion(112, 0, 112, 0, 176, 120, 2, 0);
+ updateDrawPage2();
+ return 1;
+}
+
+int LoLEngine::olol_updateDrawPage2(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_updateDrawPage2(%p)", (const void *)script);
+ updateDrawPage2();
+ return 1;
+}
+
+int LoLEngine::olol_setMouseCursor(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setMouseCursor(%p) (%d)", (const void *)script, stackPos(0));
+ if (stackPos(0) == 1)
+ setMouseCursorToIcon(133);
+ else
+ setMouseCursorToItemInHand();
+ return 1;
+}
+
+int LoLEngine::olol_characterSays(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_characterSays(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+
+ if (!_flags.isTalkie)
+ return 0;
+
+ if (stackPos(0) == -1) {
+ snd_stopSpeech(true);
+ return 1;
+ }
+
+ if (stackPos(0) != -2)
+ return characterSays(stackPos(0), stackPos(1), stackPos(2));
+ else
+ return snd_updateCharacterSpeech();
+}
+
+int LoLEngine::olol_queueSpeech(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_queueSpeech(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ if (stackPos(0) && stackPos(1)) {
+ _nextSpeechId = stackPos(0) + 1000;
+ _nextSpeaker = stackPos(1);
+ }
+ return 1;
+}
+
+int LoLEngine::olol_getItemPrice(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getItemPrice(%p) (%d)", (const void *)script, stackPos(0));
+ int c = stackPos(0);
+ if (c < 0) {
+ c = -c;
+ if (c < 50)
+ return 50;
+ c = (c + 99) / 100;
+ return c * 100;
+
+ } else {
+ for (int i = 0; i < 46; i++) {
+ if (_itemCost[i] >= c)
+ return _itemCost[i];
+ }
+ }
+
+ return 0;
+}
+
+int LoLEngine::olol_getLanguage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getLanguage(%p)", (const void *)script);
+ return _lang;
+}
+
+#pragma mark -
+
+int LoLEngine::tlol_setupPaletteFade(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_setupPaletteFade(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff);
+ _tim->_palDelayAcc = 0;
+ return 1;
+}
+
+int LoLEngine::tlol_loadPalette(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_loadPalette(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ const char *palFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0] << 1)));
+ _screen->loadPalette(palFile, _screen->getPalette(0));
+ return 1;
+}
+
+int LoLEngine::tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_setupPaletteFadeEx(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ _screen->copyPalette(0, 1);
+
+ _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff);
+ _tim->_palDelayAcc = 0;
+ return 1;
+}
+
+int LoLEngine::tlol_processWsaFrame(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_processWsaFrame(%p, %p) (%d, %d, %d, %d, %d)",
+ (const void *)tim, (const void *)param, param[0], param[1], param[2], param[3], param[4]);
+
+ const int animIndex = tim->wsa[param[0]].anim - 1;
+ const int frame = param[1];
+ const int x2 = param[2];
+ const int y2 = param[3];
+ const int factor = MAX<int>(0, (int16)param[4]);
+
+ const int x1 = _tim->animator()->getAnimX(animIndex);
+ const int y1 = _tim->animator()->getAnimY(animIndex);
+ const Movie *wsa = _tim->animator()->getWsaCPtr(animIndex);
+
+ int w1 = wsa->width();
+ int h1 = wsa->height();
+ int w2 = (w1 * factor) / 100;
+ int h2 = (h1 * factor) / 100;
+
+ _tim->animator()->displayFrame(animIndex, 2, frame);
+ _screen->wsaFrameAnimationStep(x1, y1, x2, y2, w1, h1, w2, h2, 2, _flags.isDemo && _flags.platform != Common::kPlatformPC98 ? 0 : 8, 0);
+ if (!_flags.isDemo && _flags.platform != Common::kPlatformPC98)
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+
+ return 1;
+}
+
+int LoLEngine::tlol_displayText(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_displayText(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], (int16)param[1]);
+ if (tim->isLoLOutro)
+ _tim->displayText(param[0], param[1], param[2]);
+ else
+ _tim->displayText(param[0], param[1]);
+ return 1;
+}
+
+int LoLEngine::tlol_initSceneWindowDialogue(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_initSceneWindowDialogue(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ initSceneWindowDialogue(param[0]);
+ return 1;
+}
+
+int LoLEngine::tlol_restoreAfterSceneWindowDialogue(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_restoreAfterSceneWindowDialogue(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ restoreAfterSceneWindowDialogue(param[0]);
+ return 1;
+}
+
+int LoLEngine::tlol_giveItem(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_giveItem(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ int item = makeItem(param[0], param[1], param[2]);
+ if (addItemToInventory(item))
+ return 1;
+
+ deleteItem(item);
+ return 0;
+}
+
+int LoLEngine::tlol_setPartyPosition(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_setPartyPosition(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]);
+ if (param[0] == 1) {
+ _currentDirection = param[1];
+ } else if (param[0] == 0) {
+ _currentBlock = param[1];
+ calcCoordinates(_partyPosX, _partyPosY, _currentBlock, 0x80, 0x80);
+ }
+
+ return 1;
+}
+
+int LoLEngine::tlol_fadeClearWindow(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_fadeClearWindow(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+
+ switch (param[0]) {
+ case 0:
+ _screen->fadeClearSceneWindow(10);
+ break;
+
+ case 1:
+ if (_flags.use16ColorMode) {
+ _screen->fadePalette(_screen->getPalette(1), 10);
+ } else {
+ _screen->getPalette(3).copy(_screen->getPalette(0), 128);
+ _screen->loadSpecialColors(_screen->getPalette(3));
+ _screen->fadePalette(_screen->getPalette(3), 10);
+ }
+ _screen->_fadeFlag = 0;
+ break;
+
+ case 2:
+ _screen->fadeToBlack(10);
+ break;
+
+ case 3:
+ _screen->loadSpecialColors(_screen->getPalette(3));
+ _screen->fadePalette(_screen->getPalette(_flags.use16ColorMode ? 1 : 3), 10);
+ _screen->_fadeFlag = 0;
+ break;
+
+ case 4:
+ if (_screen->_fadeFlag != 2)
+ _screen->fadeClearSceneWindow(10);
+ gui_drawPlayField();
+ setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
+ _screen->_fadeFlag = 0;
+ break;
+
+ case 5:
+ _screen->loadSpecialColors(_screen->getPalette(3));
+ _screen->fadePalette(_screen->getPalette(1), 10);
+ _screen->_fadeFlag = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+int LoLEngine::tlol_copyRegion(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_copyRegion(%p, %p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)tim, (const void *)param, param[0], param[1], param[2], param[3], param[4], param[5], param[6], param[7]);
+ _screen->copyRegion(param[0], param[1], param[2], param[3], param[4], param[5], param[6], param[7], Screen::CR_NO_P_CHECK);
+ if (!param[7])
+ _screen->updateScreen();
+ return 1;
+}
+
+int LoLEngine::tlol_characterChat(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_characterChat(%p, %p) (%d, %d, %d)", (const void *)tim, (const void *)param, param[0], param[1], param[2]);
+ playCharacterScriptChat(param[0], param[1], 1, getLangString(param[2]), 0, param, 3);
+ return 1;
+}
+
+int LoLEngine::tlol_drawScene(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_drawScene(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ gui_drawScene(param[0]);
+ //if (_sceneDrawPage2 != 2 && param[0] == 2)
+ // _screen->copyRegion(112 << 3, 0, 112 << 3, 0, 176 << 3, 120, _sceneDrawPage2, 2, Screen::CR_NO_P_CHECK);
+ return 1;
+}
+
+int LoLEngine::tlol_update(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_update(%p, %p)", (const void *)tim, (const void *)param);
+ update();
+ return 1;
+}
+
+int LoLEngine::tlol_clearTextField(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_clearTextField(%p, %p)", (const void *)tim, (const void *)param);
+ if (_currentControlMode && !textEnabled())
+ return 1;
+ _screen->setScreenDim(5);
+ const ScreenDim *d = _screen->_curDim;
+ _screen->fillRect(d->sx, d->sy, d->sx + d->w - (_flags.use16ColorMode ? 3 : 2), d->sy + d->h - 2, d->unkA);
+ _txt->clearDim(4);
+ _txt->resetDimTextPositions(4);
+ return 1;
+}
+
+int LoLEngine::tlol_loadSoundFile(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_loadSoundFile(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ snd_loadSoundFile(param[0]);
+ return 1;
+}
+
+int LoLEngine::tlol_playMusicTrack(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_playMusicTrack(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ snd_playTrack(param[0]);
+ return 1;
+}
+
+int LoLEngine::tlol_playDialogueTalkText(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_playDialogueTalkText(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ if (!snd_playCharacterSpeech(param[0], 0, 0) || textEnabled())
+ _txt->printDialogueText(4, getLangString(param[0]), 0, param, 1);
+ return 1;
+}
+
+int LoLEngine::tlol_playSoundEffect(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_playSoundEffect(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ snd_playSoundEffect(param[0], -1);
+ return 1;
+}
+
+int LoLEngine::tlol_startBackgroundAnimation(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_startBackgroundAnimation(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]);
+ _tim->animator()->start(param[0], param[1]);
+ return 1;
+}
+
+int LoLEngine::tlol_stopBackgroundAnimation(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_stopBackgroundAnimation(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ _tim->animator()->stop(param[0]);
+ return 1;
+}
+
+int LoLEngine::tlol_fadeInScene(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_fadeInScene(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]);
+ const char *sceneFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0] << 1)));
+ const char *overlayFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[1] << 1)));
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 0, 2, Screen::CR_NO_P_CHECK);
+
+ char filename[32];
+ strcpy(filename, sceneFile);
+ strcat(filename, ".CPS");
+
+ _screen->loadBitmap(filename, 7, 5, &_screen->getPalette(0));
+
+ uint8 *overlay = 0;
+ if (!_flags.use16ColorMode) {
+ filename[0] = 0;
+
+ if (_flags.isTalkie) {
+ strcpy(filename, _languageExt[_lang]);
+ strcat(filename, "/");
+ }
+
+ strcat(filename, overlayFile);
+ overlay = _res->fileData(filename, 0);
+
+ for (int i = 0; i < 3; ++i) {
+ uint32 endTime = _system->getMillis() + 10 * _tickLength;
+ _screen->copyBlockAndApplyOverlayOutro(4, 2, overlay);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ delayUntil(endTime);
+ }
+ }
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 4, 0, Screen::CR_NO_P_CHECK);
+
+ if (_flags.use16ColorMode) {
+ _screen->fadePalette(_screen->getPalette(0), 5);
+ } else {
+ _screen->updateScreen();
+ delete[] overlay;
+ }
+
+ return 1;
+}
+
+int LoLEngine::tlol_unusedResourceFunc(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_unusedResourceFunc(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ // The original used 0x6 / 0x7 for some resource caching, we don't need this.
+ return 1;
+}
+
+int LoLEngine::tlol_fadeInPalette(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_fadeInPalette(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]);
+ const char *bitmap = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0] << 1)));
+
+ Palette pal(_screen->getPalette(0).getNumColors());
+ _screen->loadBitmap(bitmap, 3, 3, &pal);
+
+ if (_flags.use16ColorMode) {
+ _screen->getPalette(0).clear();
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->copyPage(2, 0);
+ }
+
+ _screen->fadePalette(pal, param[1]);
+
+ return 1;
+}
+
+int LoLEngine::tlol_fadeOutSound(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_fadeOutSound(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ _sound->beginFadeOut();
+ return 1;
+}
+
+int LoLEngine::tlol_displayAnimFrame(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_displayAnimFrame(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]);
+
+ const int animIndex = tim->wsa[param[0]].anim - 1;
+ const Movie *wsa = _tim->animator()->getWsaCPtr(animIndex);
+
+ if (param[1] == 0xFFFF) {
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 0, 2, Screen::CR_NO_P_CHECK);
+ } else {
+ _tim->animator()->displayFrame(animIndex, 2, param[1], 0);
+ _screen->copyRegion(wsa->xAdd(), wsa->yAdd(), wsa->xAdd(), wsa->yAdd(), wsa->width(), wsa->height(), 2, 0);
+ }
+
+ return 1;
+}
+
+int LoLEngine::tlol_delayForChat(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_delayForChat(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
+ if (!speechEnabled())
+ delay(param[0]);
+ return 1;
+}
+
+#pragma mark -
+
+typedef Common::Functor1Mem<EMCState *, int, LoLEngine> OpcodeV2;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV2(this, &LoLEngine::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV2(this, 0))
+
+typedef Common::Functor2Mem<const TIM *, const uint16 *, int, LoLEngine> TIMOpcodeLoL;
+#define SetTimOpcodeTable(x) timTable = &x;
+#define OpcodeTim(x) timTable->push_back(new TIMOpcodeLoL(this, &LoLEngine::x))
+#define OpcodeTimUnImpl() timTable->push_back(new TIMOpcodeLoL(this, 0))
+
+void LoLEngine::setupOpcodeTable() {
+ Common::Array<const Opcode *> *table = 0;
+
+ _opcodes.reserve(192);
+ SetOpcodeTable(_opcodes);
+ // 0x00
+ Opcode(olol_setWallType);
+ Opcode(olol_getWallType);
+ Opcode(olol_drawScene);
+ Opcode(olol_rollDice);
+
+ // 0x04
+ Opcode(olol_moveParty);
+ OpcodeUnImpl();
+ Opcode(olol_delay);
+ Opcode(olol_setGameFlag);
+
+ // 0x08
+ Opcode(olol_testGameFlag);
+ Opcode(olol_loadLevelGraphics);
+ Opcode(olol_loadBlockProperties);
+ Opcode(olol_loadMonsterShapes);
+
+ // 0x0C
+ Opcode(olol_deleteHandItem);
+ Opcode(olol_allocItemPropertiesBuffer);
+ Opcode(olol_setItemProperty);
+ Opcode(olol_makeItem);
+
+ // 0x10
+ Opcode(olol_placeMoveLevelItem);
+ Opcode(olol_createLevelItem);
+ Opcode(olol_getItemPara);
+ Opcode(olol_getCharacterStat);
+
+ // 0x14
+ Opcode(olol_setCharacterStat);
+ Opcode(olol_loadLevelShapes);
+ Opcode(olol_closeLevelShapeFile);
+ OpcodeUnImpl();
+
+ // 0x18
+ Opcode(olol_loadDoorShapes);
+ Opcode(olol_initAnimStruct);
+ Opcode(olol_playAnimationPart);
+ Opcode(olol_freeAnimStruct);
+
+ // 0x1C
+ Opcode(olol_getDirection);
+ Opcode(olol_characterSurpriseFeedback);
+ Opcode(olol_setMusicTrack);
+ Opcode(olol_setSequenceButtons);
+
+ // 0x20
+ Opcode(olol_setDefaultButtonState);
+ Opcode(olol_checkRectForMousePointer);
+ Opcode(olol_clearDialogueField);
+ Opcode(olol_setupBackgroundAnimationPart);
+
+ // 0x24
+ Opcode(olol_startBackgroundAnimation);
+ Opcode(o1_hideMouse);
+ Opcode(o1_showMouse);
+ Opcode(olol_fadeToBlack);
+
+ // 0x28
+ Opcode(olol_fadePalette);
+ Opcode(olol_loadBitmap);
+ Opcode(olol_stopBackgroundAnimation);
+ OpcodeUnImpl();
+
+ // 0x2C
+ OpcodeUnImpl();
+ Opcode(olol_getGlobalScriptVar);
+ Opcode(olol_setGlobalScriptVar);
+ Opcode(olol_getGlobalVar);
+
+ // 0x30
+ Opcode(olol_setGlobalVar);
+ Opcode(olol_triggerDoorSwitch);
+ Opcode(olol_checkEquippedItemScriptFlags);
+ Opcode(olol_setDoorState);
+
+ // 0x34
+ Opcode(olol_updateBlockAnimations);
+ Opcode(olol_assignLevelDecorationShape);
+ Opcode(olol_resetBlockShapeAssignment);
+ Opcode(olol_copyRegion);
+
+ // 0x38
+ Opcode(olol_initMonster);
+ Opcode(olol_fadeClearSceneWindow);
+ Opcode(olol_fadeSequencePalette);
+ Opcode(olol_redrawPlayfield);
+
+ // 0x3C
+ Opcode(olol_loadNewLevel);
+ Opcode(olol_getNearestMonsterFromCharacter);
+ Opcode(olol_dummy0);
+ Opcode(olol_loadMonsterProperties);
+
+ // 0x40
+ Opcode(olol_battleHitSkillTest);
+ Opcode(olol_inflictDamage);
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+
+ // 0x44
+ Opcode(olol_moveMonster);
+ Opcode(olol_setupDialogueButtons);
+ Opcode(olol_giveTakeMoney);
+ Opcode(olol_checkMoney);
+
+ // 0x48
+ Opcode(olol_setScriptTimer);
+ Opcode(olol_createHandItem);
+ Opcode(olol_playAttackSound);
+ Opcode(olol_addRemoveCharacter);
+
+ // 0x4C
+ Opcode(olol_giveItem);
+ OpcodeUnImpl();
+ Opcode(olol_loadTimScript);
+ Opcode(olol_runTimScript);
+
+ // 0x50
+ Opcode(olol_releaseTimScript);
+ Opcode(olol_initSceneWindowDialogue);
+ Opcode(olol_restoreAfterSceneWindowDialogue);
+ Opcode(olol_getItemInHand);
+
+ // 0x54
+ Opcode(olol_checkMagic);
+ Opcode(olol_giveItemToMonster);
+ Opcode(olol_loadLangFile);
+ Opcode(olol_playSoundEffect);
+
+ // 0x58
+ Opcode(olol_processDialogue);
+ Opcode(olol_stopTimScript);
+ Opcode(olol_getWallFlags);
+ Opcode(olol_changeMonsterStat);
+
+ // 0x5C
+ Opcode(olol_getMonsterStat);
+ Opcode(olol_releaseMonsterShapes);
+ Opcode(olol_playCharacterScriptChat);
+ Opcode(olol_update);
+
+ // 0x60
+ Opcode(olol_playEnvironmentalSfx);
+ Opcode(olol_healCharacter);
+ Opcode(olol_drawExitButton);
+ Opcode(olol_loadSoundFile);
+
+ // 0x64
+ Opcode(olol_playMusicTrack);
+ Opcode(olol_deleteMonstersFromBlock);
+ Opcode(olol_countBlockItems);
+ Opcode(olol_characterSkillTest);
+
+ // 0x68
+ Opcode(olol_countAllMonsters);
+ Opcode(olol_playEndSequence);
+ Opcode(olol_stopPortraitSpeechAnim);
+ Opcode(olol_setPaletteBrightness);
+
+ // 0x6C
+ Opcode(olol_calcInflictableDamage);
+ Opcode(olol_getInflictedDamage);
+ Opcode(olol_checkForCertainPartyMember);
+ Opcode(olol_printMessage);
+
+ // 0x70
+ Opcode(olol_deleteLevelItem);
+ Opcode(olol_calcInflictableDamagePerItem);
+ Opcode(olol_distanceAttack);
+ Opcode(olol_removeCharacterEffects);
+
+ // 0x74
+ Opcode(olol_checkInventoryFull);
+ Opcode(olol_moveBlockObjects);
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+
+ // 0x78
+ Opcode(olol_addSpellToScroll);
+ Opcode(olol_playDialogueText);
+ Opcode(olol_playDialogueTalkText);
+ Opcode(olol_checkMonsterTypeHostility);
+
+ // 0x7C
+ Opcode(olol_setNextFunc);
+ Opcode(olol_dummy1);
+ OpcodeUnImpl();
+ Opcode(olol_suspendMonster);
+
+ // 0x80
+ Opcode(olol_setScriptTextParameter);
+ Opcode(olol_triggerEventOnMouseButtonClick);
+ Opcode(olol_printWindowText);
+ Opcode(olol_countSpecificMonsters);
+
+ // 0x84
+ Opcode(olol_updateBlockAnimations2);
+ Opcode(olol_checkPartyForItemType);
+ Opcode(olol_blockDoor);
+ Opcode(olol_resetTimDialogueState);
+
+ // 0x88
+ Opcode(olol_getItemOnPos);
+ Opcode(olol_removeLevelItem);
+ Opcode(olol_savePage5);
+ Opcode(olol_restorePage5);
+
+ // 0x8C
+ Opcode(olol_initDialogueSequence);
+ Opcode(olol_restoreAfterDialogueSequence);
+ Opcode(olol_setSpecialSceneButtons);
+ Opcode(olol_restoreButtonsAfterSpecialScene);
+
+ // 0x90
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ Opcode(olol_prepareSpecialScene);
+ Opcode(olol_restoreAfterSpecialScene);
+
+ // 0x94
+ Opcode(olol_assignCustomSfx);
+ OpcodeUnImpl();
+ Opcode(olol_findAssignedMonster);
+ Opcode(olol_checkBlockForMonster);
+
+ // 0x98
+ Opcode(olol_crossFadeRegion);
+ Opcode(olol_calcCoordinatesAddDirectionOffset);
+ Opcode(olol_resetPortraitsAndDisableSysTimer);
+ Opcode(olol_enableSysTimer);
+
+ // 0x9C
+ Opcode(olol_checkNeedSceneRestore);
+ Opcode(olol_getNextActiveCharacter);
+ Opcode(olol_paralyzePoisonCharacter);
+ Opcode(olol_drawCharPortrait);
+
+ // 0xA0
+ Opcode(olol_removeInventoryItem);
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ Opcode(olol_getAnimationLastPart);
+
+ // 0xA4
+ Opcode(olol_assignSpecialGuiShape);
+ Opcode(olol_findInventoryItem);
+ Opcode(olol_restoreFadePalette);
+ Opcode(olol_calcNewBlockPosition);
+
+ // 0xA8
+ Opcode(olol_getSelectedCharacter);
+ Opcode(olol_setHandItem);
+ Opcode(olol_drinkBezelCup);
+ Opcode(olol_changeItemTypeOrFlag);
+
+ // 0xAC
+ Opcode(olol_placeInventoryItemInHand);
+ Opcode(olol_castSpell);
+ Opcode(olol_pitDrop);
+ Opcode(olol_increaseSkill);
+
+ // 0xB0
+ Opcode(olol_paletteFlash);
+ Opcode(olol_restoreMagicShroud);
+ Opcode(olol_dummy1); // anim buffer select?
+ Opcode(olol_disableControls);
+
+ // 0xB4
+ Opcode(olol_enableControls);
+ Opcode(olol_shakeScene);
+ Opcode(olol_gasExplosion);
+ Opcode(olol_calcNewBlockPosition);
+
+ // 0xB8
+ Opcode(olol_crossFadeScene);
+ Opcode(olol_updateDrawPage2);
+ Opcode(olol_setMouseCursor);
+ Opcode(olol_characterSays);
+
+ // 0xBC
+ Opcode(olol_queueSpeech);
+ Opcode(olol_getItemPrice);
+ Opcode(olol_getLanguage);
+ Opcode(olol_dummy0);
+
+ Common::Array<const TIMOpcode *> *timTable = 0;
+
+ _timIntroOpcodes.reserve(8);
+ SetTimOpcodeTable(_timIntroOpcodes);
+
+ // 0x00
+ OpcodeTim(tlol_setupPaletteFade);
+ OpcodeTimUnImpl();
+ OpcodeTim(tlol_loadPalette);
+ OpcodeTim(tlol_setupPaletteFadeEx);
+
+ // 0x04
+ OpcodeTim(tlol_processWsaFrame);
+ OpcodeTim(tlol_displayText);
+ OpcodeTimUnImpl();
+ OpcodeTimUnImpl();
+
+ _timOutroOpcodes.reserve(16);
+ SetTimOpcodeTable(_timOutroOpcodes);
+
+ // 0x00
+ OpcodeTim(tlol_setupPaletteFade);
+ OpcodeTimUnImpl();
+ OpcodeTim(tlol_loadPalette);
+ OpcodeTim(tlol_setupPaletteFadeEx);
+
+ // 0x04
+ OpcodeTimUnImpl();
+ OpcodeTim(tlol_fadeInScene);
+ OpcodeTim(tlol_unusedResourceFunc);
+ OpcodeTim(tlol_unusedResourceFunc);
+
+ // 0x08
+ OpcodeTim(tlol_fadeInPalette);
+ OpcodeTimUnImpl();
+ OpcodeTimUnImpl();
+ OpcodeTim(tlol_fadeOutSound);
+
+ // 0x0C
+ OpcodeTim(tlol_displayAnimFrame);
+ OpcodeTim(tlol_delayForChat);
+ OpcodeTim(tlol_displayText);
+ OpcodeTimUnImpl();
+
+ _timIngameOpcodes.reserve(17);
+ SetTimOpcodeTable(_timIngameOpcodes);
+
+ // 0x00
+ OpcodeTim(tlol_initSceneWindowDialogue);
+ OpcodeTim(tlol_restoreAfterSceneWindowDialogue);
+ OpcodeTimUnImpl();
+ OpcodeTim(tlol_giveItem);
+
+ // 0x04
+ OpcodeTim(tlol_setPartyPosition);
+ OpcodeTim(tlol_fadeClearWindow);
+ OpcodeTim(tlol_copyRegion);
+ OpcodeTim(tlol_characterChat);
+
+ // 0x08
+ OpcodeTim(tlol_drawScene);
+ OpcodeTim(tlol_update);
+ OpcodeTim(tlol_clearTextField);
+ OpcodeTim(tlol_loadSoundFile);
+
+ // 0x0C
+ OpcodeTim(tlol_playMusicTrack);
+ OpcodeTim(tlol_playDialogueTalkText);
+ OpcodeTim(tlol_playSoundEffect);
+ OpcodeTim(tlol_startBackgroundAnimation);
+
+ // 0x10
+ OpcodeTim(tlol_stopBackgroundAnimation);
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_LOL
diff --git a/engines/kyra/script/script_mr.cpp b/engines/kyra/script/script_mr.cpp
new file mode 100644
index 0000000000..1051fccbc6
--- /dev/null
+++ b/engines/kyra/script/script_mr.cpp
@@ -0,0 +1,1377 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/kyra_mr.h"
+#include "kyra/text/text_mr.h"
+#include "kyra/resource/resource.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+int KyraEngine_MR::o3_getMalcolmShapes(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getMaloclmShapes(%p) ()", (const void *)script);
+ return _characterShapeFile;
+}
+
+int KyraEngine_MR::o3_setCharacterPos(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setCharacterPos(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ int x = stackPos(0);
+ int y = stackPos(1);
+
+ if (x != -1 && y != -1) {
+ x &= ~3;
+ y &= ~1;
+ }
+
+ _mainCharacter.x1 = _mainCharacter.x2 = x;
+ _mainCharacter.y1 = _mainCharacter.y2 = y;
+
+ return 0;
+}
+
+int KyraEngine_MR::o3_defineObject(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_defineObject(%p) (%d, '%s', %d, %d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPosString(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ TalkObject &obj = _talkObjectList[stackPos(0)];
+ strcpy(obj.filename, stackPosString(1));
+ obj.sceneAnim = stackPos(2);
+ obj.sceneScript = stackPos(3);
+ obj.x = stackPos(4);
+ obj.y = stackPos(5);
+ obj.color = stackPos(6);
+ obj.sceneId = stackPos(7);
+ return 0;
+}
+
+int KyraEngine_MR::o3_refreshCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_refreshCharacter(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ const int frame = stackPos(0);
+ const int facing = stackPos(1);
+ const bool updateNeed = stackPos(2) != 0;
+
+ if (facing >= 0)
+ _mainCharacter.facing = facing;
+
+ if (frame >= 0 && frame != 87)
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ else
+ _mainCharacter.animFrame = 87;
+
+ updateCharacterAnim(0);
+
+ if (updateNeed)
+ refreshAnimObjectsIfNeed();
+ return 0;
+}
+
+int KyraEngine_MR::o3_getMalcolmsMood(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getMalcolmsMood(%p) ()", (const void *)script);
+ return _malcolmsMood;
+}
+
+int KyraEngine_MR::o3_getCharacterFrameFromFacing(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getCharacterFrameFromFacing(%p) ()", (const void *)script);
+ return _characterFrameTable[_mainCharacter.facing];
+}
+
+int KyraEngine_MR::o3_setCharacterFacing(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setCharacterFacing(%p) (%d)", (const void *)script, stackPos(0));
+ _mainCharacter.facing = stackPos(0);
+ return 0;
+}
+
+int KyraEngine_MR::o3_showSceneFileMessage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showSceneFileMessage(%p) (%d)", (const void *)script, stackPos(0));
+ showMessage((const char *)getTableEntry(_scenesFile, stackPos(0)), 0xFF, 0xF0);
+ return 0;
+}
+
+int KyraEngine_MR::o3_setCharacterAnimFrameFromFacing(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setCharacterAnimFrameFromFacing(%p) ()", (const void *)script);
+ updateCharPal(0);
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ updateCharacterAnim(0);
+ refreshAnimObjectsIfNeed();
+ return 0;
+}
+
+int KyraEngine_MR::o3_showBadConscience(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showBadConscience(%p) ()", (const void *)script);
+ showBadConscience();
+ return 0;
+}
+
+int KyraEngine_MR::o3_hideBadConscience(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_hideBadConscience(%p) ()", (const void *)script);
+ hideBadConscience();
+ return 0;
+}
+
+int KyraEngine_MR::o3_showAlbum(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showAlbum(%p) ()", (const void *)script);
+ showAlbum();
+ return 0;
+}
+
+int KyraEngine_MR::o3_setInventorySlot(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setInventorySlot(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ const int slot = MAX<int16>(0, MIN<int16>(10, stackPos(0)));
+ return (_mainCharacter.inventory[slot] = stackPos(1));
+}
+
+int KyraEngine_MR::o3_getInventorySlot(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getInventorySlot(%p) (%d)", (const void *)script, stackPos(0));
+ return _mainCharacter.inventory[stackPos(0)];
+}
+
+int KyraEngine_MR::o3_addItemToInventory(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_addItemToInventory(%p) (%d)", (const void *)script, stackPos(0));
+ int slot = findFreeInventorySlot();
+ if (slot >= 0) {
+ _mainCharacter.inventory[slot] = stackPos(0);
+ if (_inventoryState) {
+ redrawInventory(0);
+ }
+ }
+ return slot;
+}
+
+int KyraEngine_MR::o3_addItemToCurScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_addItemToCurScene(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ const uint16 item = stackPos(0);
+ int x = stackPos(1);
+ int y = stackPos(2);
+ int itemSlot = findFreeItem();
+
+ if (x < 20)
+ x = 20;
+ else if (x > 299)
+ x = 299;
+
+ if (y < 18)
+ y = 18;
+ else if (y > 187)
+ y = 187;
+
+ if (itemSlot >= 0) {
+ _itemList[itemSlot].x = x;
+ _itemList[itemSlot].y = y;
+ _itemList[itemSlot].id = item;
+ _itemList[itemSlot].sceneId = _mainCharacter.sceneId;
+ addItemToAnimList(itemSlot);
+ refreshAnimObjectsIfNeed();
+ }
+
+ return itemSlot;
+}
+
+int KyraEngine_MR::o3_objectChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_objectChat(%p) (%d)", (const void *)script, stackPos(0));
+ int id = stackPos(0);
+ const char *str = (const char *)getTableEntry(_useActorBuffer ? _actorFile : _sceneStrings, id);
+ if (str) {
+ objectChat(str, 0, _vocHigh, id);
+ playStudioSFX(str);
+ }
+ return 0;
+}
+
+int KyraEngine_MR::o3_resetInventory(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_resetInventory(%p) ()", (const void *)script);
+ memset(_mainCharacter.inventory, -1, sizeof(_mainCharacter.inventory));
+ return 0;
+}
+
+int KyraEngine_MR::o3_removeInventoryItemInstances(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeInventoryItemInstances(%p) (%d)", (const void *)script, stackPos(0));
+ const int item = stackPos(0);
+ for (int i = 0; i < 10; ++i) {
+ if (_mainCharacter.inventory[i] == item)
+ _mainCharacter.inventory[i] = kItemNone;
+ }
+ return 0;
+}
+
+int KyraEngine_MR::o3_countInventoryItemInstances(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_countInventoryItemInstances(%p) (%d)", (const void *)script, stackPos(0));
+ const int item = stackPos(0);
+ int count = 0;
+
+ for (int i = 0; i < 10; ++i) {
+ if (_mainCharacter.inventory[i] == item)
+ ++count;
+ }
+
+ if (_itemInHand == item)
+ ++count;
+
+ return count;
+}
+
+int KyraEngine_MR::o3_npcChatSequence(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_npcChatSequence(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ const int id = stackPos(0);
+ const char *str = (const char *)getTableEntry(_sceneStrings, id);
+ if (str)
+ npcChatSequence(str, stackPos(1), _vocHigh, id);
+ return 0;
+}
+
+int KyraEngine_MR::o3_badConscienceChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_badConscienceChat(%p) (%d)", (const void *)script, stackPos(0));
+ int id = stackPos(0);
+ const char *str = (const char *)getTableEntry(_useActorBuffer ? _actorFile : _sceneStrings, id);
+ badConscienceChat(str, _vocHigh, id);
+ return 0;
+}
+
+int KyraEngine_MR::o3_wipeDownMouseItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o3_wipeDownMouseItem(%p) (-, %d, %d)", (const void *)script, stackPos(1), stackPos(2));
+ _screen->hideMouse();
+ const int x = stackPos(1) - 12;
+ const int y = stackPos(2) - 19;
+
+ if (_itemInHand >= 0) {
+ backUpGfxRect32x32(x, y);
+ uint8 *shape = getShapePtr(_itemInHand+248);
+ for (int curY = y, height = 20; height > 0; height -= 2, curY += 2) {
+ restoreGfxRect32x32(x, y);
+ _screen->setNewShapeHeight(shape, height);
+ const uint32 waitTime = _system->getMillis() + _tickLength;
+ _screen->drawShape(0, shape, x, curY, 0, 0);
+ _screen->updateScreen();
+ delayUntil(waitTime);
+ }
+ restoreGfxRect32x32(x, y);
+ _screen->resetShapeHeight(shape);
+ }
+
+ _screen->showMouse();
+ removeHandItem();
+
+ return 0;
+}
+
+int KyraEngine_MR::o3_setMalcolmsMood(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setMalcolmsMood(%p) (%d)", (const void *)script, stackPos(0));
+ return (_malcolmsMood = stackPos(0));
+}
+
+int KyraEngine_MR::o3_updateScore(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_updateScore(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return updateScore(stackPos(0), stackPos(1)) ? 1 : 0;
+}
+
+int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script);
+ saveGameStateIntern(999, "Autosave", 0);
+ return 0;
+}
+
+int KyraEngine_MR::o3_setSceneFilename(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setSceneFilename(%p) (%d, '%s')", (const void *)script, stackPos(0), stackPosString(1));
+ strcpy(_sceneList[stackPos(0)].filename1, stackPosString(1));
+ _sceneList[stackPos(0)].filename1[9] = 0;
+ return 0;
+}
+
+int KyraEngine_MR::o3_removeItemsFromScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeItemsFromScene(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ const uint16 itemId = stackPos(0);
+ const uint16 sceneId = stackPos(1);
+ const bool allItems = (stackPos(2) != 0);
+
+ int retValue = 0;
+
+ for (int i = 0; i < 50; ++i) {
+ if (_itemList[i].sceneId == sceneId && _itemList[i].id == itemId) {
+ resetItem(i);
+ retValue = 1;
+ if (!allItems)
+ return 1;
+ }
+ }
+
+ return retValue;
+}
+
+int KyraEngine_MR::o3_disguiseMalcolm(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o3_disguiseMalcolm(%p) (%d)", (const void *)script, stackPos(0));
+ loadCharacterShapes(stackPos(0));
+ updateDlgIndex();
+ return 0;
+}
+
+int KyraEngine_MR::o3_drawSceneShape(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o3_drawSceneShape(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+
+ int shape = stackPos(0);
+ int flag = (stackPos(1) != 0) ? 1 : 0;
+
+ restorePage3();
+
+ const int x = _sceneShapeDescs[shape].drawX;
+ const int y = _sceneShapeDescs[shape].drawY;
+
+ _screen->drawShape(2, _sceneShapes[shape], x, y, 2, flag);
+
+ _screen->copyRegionToBuffer(3, 0, 0, 320, 200, _gamePlayBuffer);
+
+ _screen->drawShape(0, _sceneShapes[shape], x, y, 2, flag);
+
+ flagAnimObjsForRefresh();
+ refreshAnimObjectsIfNeed();
+ return 0;
+}
+
+int KyraEngine_MR::o3_drawSceneShapeOnPage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_drawSceneShapeOnPage(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ const int shape = stackPos(0);
+
+ int x = _sceneShapeDescs[shape].drawX;
+ int y = _sceneShapeDescs[shape].drawY;
+ _screen->drawShape(stackPos(2), _sceneShapes[shape], x, y, 2, (stackPos(1) != 0) ? 1 : 0);
+ return 0;
+}
+
+int KyraEngine_MR::o3_checkInRect(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_checkInRect(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ const int x1 = stackPos(0);
+ const int y1 = stackPos(1);
+ const int x2 = stackPos(2);
+ const int y2 = stackPos(3);
+ int x = stackPos(4), y = stackPos(5);
+ if (_itemInHand >= 0) {
+ const int8 *desc = &_itemBuffer2[_itemInHand*2];
+ x -= 12;
+ x += desc[0];
+ y -= 19;
+ y += desc[1];
+ }
+
+ if (x >= x1 && x <= x2 && y >= y1 && y <= y2)
+ return 1;
+ else
+ return 0;
+}
+
+int KyraEngine_MR::o3_updateConversations(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_updateConversations(%p) (%d)", (const void *)script, stackPos(0));
+ int dlgIndex = stackPos(0);
+ switch (_currentChapter-2) {
+ case 0:
+ dlgIndex -= 34;
+ break;
+
+ case 1:
+ dlgIndex -= 54;
+ break;
+
+ case 2:
+ dlgIndex -= 55;
+ break;
+
+ case 3:
+ dlgIndex -= 70;
+ break;
+
+ default:
+ break;
+ }
+
+ int convs[4];
+ Common::fill(convs, convs+4, -1);
+
+ if (_currentChapter == 1) {
+ switch (_mainCharacter.dlgIndex) {
+ case 0:
+ convs[0] = 6;
+ convs[1] = 12;
+ break;
+
+ case 2:
+ convs[0] = 8;
+ convs[1] = 14;
+ break;
+
+ case 3:
+ convs[0] = 9;
+ convs[1] = 15;
+ break;
+
+ case 4:
+ convs[0] = 10;
+ convs[1] = 16;
+ break;
+
+ case 5:
+ convs[0] = 11;
+ convs[1] = 17;
+ break;
+
+ case 6:
+ convs[0] = 0;
+ convs[1] = 12;
+ break;
+
+ case 8:
+ convs[0] = 2;
+ convs[1] = 14;
+ break;
+
+ case 9:
+ convs[0] = 3;
+ convs[1] = 15;
+ break;
+
+ case 10:
+ convs[0] = 4;
+ convs[1] = 16;
+ break;
+
+ case 11:
+ convs[0] = 5;
+ convs[1] = 17;
+ break;
+
+ case 12:
+ convs[0] = 0;
+ convs[1] = 6;
+ break;
+
+ case 14:
+ convs[0] = 2;
+ convs[1] = 8;
+ break;
+
+ case 15:
+ convs[0] = 3;
+ convs[1] = 9;
+ break;
+
+ case 16:
+ convs[0] = 4;
+ convs[1] = 10;
+ break;
+
+ case 17:
+ convs[0] = 5;
+ convs[1] = 11;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_currentChapter == 2) {
+ switch (_mainCharacter.dlgIndex) {
+ case 0:
+ convs[0] = 4;
+ convs[1] = 8;
+ convs[2] = 5;
+ convs[3] = 9;
+ break;
+
+ case 1:
+ convs[0] = 4;
+ convs[1] = 8;
+ convs[2] = 0;
+ convs[3] = 5;
+ break;
+
+ case 2:
+ convs[0] = 6;
+ convs[2] = 11;
+ break;
+
+ case 3:
+ convs[0] = 7;
+ convs[2] = 12;
+ break;
+
+ case 4:
+ convs[0] = 0;
+ convs[1] = 8;
+ convs[2] = 1;
+ convs[3] = 9;
+ break;
+
+ case 5:
+ convs[0] = 0;
+ convs[1] = 8;
+ convs[2] = 4;
+ convs[3] = 1;
+ break;
+
+ case 6:
+ convs[0] = 2;
+ convs[1] = 10;
+ break;
+
+ case 7:
+ convs[0] = 3;
+ convs[1] = 11;
+ break;
+
+ case 8:
+ convs[0] = 0;
+ convs[1] = 4;
+ convs[2] = 1;
+ break;
+
+ case 9:
+ convs[0] = 0;
+ convs[1] = 4;
+ convs[2] = 0;
+ convs[3] = 1;
+ break;
+
+ case 10:
+ convs[0] = 2;
+ convs[1] = 6;
+ break;
+
+ case 11:
+ convs[0] = 3;
+ convs[1] = 7;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_currentChapter == 4) {
+ if (_malcolmsMood == 0) {
+ convs[0] = _mainCharacter.dlgIndex - 10;
+ convs[1] = _mainCharacter.dlgIndex - 5;
+ } else if (_malcolmsMood == 1) {
+ convs[0] = _mainCharacter.dlgIndex + 5;
+ convs[1] = _mainCharacter.dlgIndex + 10;
+ } else if (_malcolmsMood == 2) {
+ convs[0] = _mainCharacter.dlgIndex - 5;
+ convs[1] = _mainCharacter.dlgIndex + 5;
+ }
+ }
+
+ for (int i = 0; i < 4; ++i) {
+ if (convs[i] != -1)
+ _conversationState[dlgIndex][convs[i]] = 0;
+ }
+
+ return 1;
+}
+
+int KyraEngine_MR::o3_removeItemSlot(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeItemSlot(%p) (%d)", (const void *)script, stackPos(0));
+ deleteItemAnimEntry(stackPos(0));
+ _itemList[stackPos(0)].id = kItemNone;
+ return 1;
+}
+
+int KyraEngine_MR::o3_setSceneDim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setSceneDim(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _sceneMinX = stackPos(0);
+ _sceneMaxX = stackPos(1);
+ return 0;
+}
+
+int KyraEngine_MR::o3_setSceneAnimPosAndFrame(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setSceneAnimPosAndFrame(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ SceneAnim &anim = _sceneAnims[stackPos(0)];
+ const int newX2 = stackPos(1);
+ const int newY2 = stackPos(2);
+ const int newX = stackPos(3);
+ const int newY = stackPos(4);
+
+ if (newX2 >= 0)
+ anim.x2 = newX2;
+ if (newY2 >= 0)
+ anim.y2 = newY2;
+
+ if (newX >= 0)
+ anim.x = newX;
+ else
+ anim.x = anim.x2 + (anim.width >> 1);
+
+ if (newY >= 0)
+ anim.y = newY;
+ else
+ anim.y = anim.y2 + anim.height - 1;
+
+ updateSceneAnim(stackPos(0), stackPos(5));
+ _specialSceneScriptRunFlag = false;
+ return 0;
+}
+
+int KyraEngine_MR::o3_removeItemInstances(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeItemInstances(%p) (%d)", (const void *)script, stackPos(0));
+ const int16 item = stackPos(0);
+
+ int deleted = 0;
+
+ for (int i = 0; i < 10; ++i) {
+ if (_mainCharacter.inventory[i] == item) {
+ _mainCharacter.inventory[i] = kItemNone;
+ ++deleted;
+ }
+ }
+
+ if (_itemInHand == item) {
+ removeHandItem();
+ ++deleted;
+ }
+
+ for (int i = 0; i < 50; ++i) {
+ if (_itemList[i].id == item) {
+ _itemList[i].id = kItemNone;
+ ++deleted;
+ }
+ }
+
+ return deleted;
+}
+
+int KyraEngine_MR::o3_disableInventory(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_disableInventory(%p) ()", (const void *)script);
+ _enableInventory = false;
+ return 0;
+}
+
+int KyraEngine_MR::o3_enableInventory(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_enableInventory(%p) ()", (const void *)script);
+ _enableInventory = true;
+ return 1;
+}
+
+int KyraEngine_MR::o3_enterNewScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_enterNewScene(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0),
+ stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+
+ _screen->hideMouse();
+ enterNewScene(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+
+ _unk5 = 1;
+
+ if (_mainCharX == -1 || _mainCharY == -1) {
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ updateCharacterAnim(0);
+ }
+ _screen->showMouse();
+
+ return 0;
+}
+
+int KyraEngine_MR::o3_switchScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_switchScene(%p) (%d)", (const void *)script, stackPos(0));
+ setGameFlag(1);
+ _mainCharX = _mainCharacter.x1;
+ _mainCharY = _mainCharacter.y1;
+ _noScriptEnter = false;
+ enterNewScene(stackPos(0), _mainCharacter.facing, 0, 0, 0);
+ _noScriptEnter = true;
+ return 0;
+}
+
+int KyraEngine_MR::o3_setMalcolmPos(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setMalcolmPos(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _mainCharX = stackPos(0);
+ _mainCharY = stackPos(1);
+
+ if (_mainCharX == -1 && _mainCharY == -1)
+ _mainCharacter.animFrame = 87;
+ else
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+
+ return 0;
+}
+
+int KyraEngine_MR::o3_stopMusic(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_stopMusic(%p) ()", (const void *)script);
+ stopMusicTrack();
+ return 0;
+}
+
+int KyraEngine_MR::o3_playSoundEffect(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_playSoundEffect(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ snd_playSoundEffect(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_MR::o3_getScore(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getScore(%p) ()", (const void *)script);
+ return _score;
+}
+
+int KyraEngine_MR::o3_daggerWarning(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_daggerWarning(%p) ()", (const void *)script);
+ int selection = 1;
+
+ _screen->hideMouse();
+ _screen->copyRegionToBuffer(1, 0, 0, 320, 200, _screenBuffer);
+ int curPageBackUp = _screen->_curPage;
+ _screen->_curPage = 2;
+
+ _screen->drawFilledBox(0, 0, 0x13F, 0xC7, 0xB4, 0xB3, 0xB6);
+ _screen->drawFilledBox(0xF, 0xAA, 0x68, 0xBA, 0xB4, 0xB3, 0xB6);
+ _screen->drawFilledBox(0x73, 0xAA, 0xCC, 0xBA, 0xB4, 0xB3, 0xB6);
+ _screen->drawFilledBox(0xD6, 0xAA, 0x12F, 0xBA, 0xB4, 0xB3, 0xB6);
+
+ int y = 15;
+ for (int i = 100; i <= 107; ++i) {
+ const char *str = (const char *)getTableEntry(_cCodeFile, i);
+ int x = _text->getCenterStringX(str, 0, 0x13F);
+ _text->printText(str, x, y, 0xFF, 0xF0, 0x00);
+ y += 10;
+ }
+ y += 15;
+ for (int i = 110; i <= 113; ++i) {
+ const char *str = (const char *)getTableEntry(_cCodeFile, i);
+ int x = _text->getCenterStringX(str, 0, 0x13F);
+ _text->printText(str, x, y, 0xFF, 0xF0, 0x00);
+ y += 10;
+ }
+
+ const char *str = 0;
+ int x = 0;
+
+ str = (const char *)getTableEntry(_cCodeFile, 120);
+ x = _text->getCenterStringX(str, 0xF, 0x68);
+ _text->printText(str, x, 174, 0xFF, 0xF0, 0x00);
+
+ str = (const char *)getTableEntry(_cCodeFile, 121);
+ x = _text->getCenterStringX(str, 0x73, 0xCC);
+ _text->printText(str, x, 174, 0xFF, 0xF0, 0x00);
+
+ str = (const char *)getTableEntry(_cCodeFile, 122);
+ x = _text->getCenterStringX(str, 0xD6, 0x12F);
+ _text->printText(str, x, 174, 0xFF, 0xF0, 0x00);
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->updateScreen();
+
+ _screen->_curPage = curPageBackUp;
+ _screen->showMouse();
+
+ while (!shouldQuit()) {
+ int keys = checkInput(0);
+ removeInputTop();
+
+ if (keys == 198 || keys == 199) {
+ if (_mouseX >= 15 && _mouseX <= 104 && _mouseY >= 170 && _mouseY <= 186) {
+ selection = 1;
+ break;
+ } else if (_mouseX >= 115 && _mouseX <= 204 && _mouseY >= 170 && _mouseY <= 186) {
+ selection = 2;
+ break;
+ } else if (_mouseX >= 214 && _mouseX <= 303 && _mouseY >= 170 && _mouseY <= 186) {
+ selection = 3;
+ break;
+ }
+ }
+
+ delay(10);
+ }
+
+ restorePage3();
+ _screen->copyBlockToPage(1, 0, 0, 320, 200, _screenBuffer);
+ return selection;
+}
+
+int KyraEngine_MR::o3_blockOutWalkableRegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_blockOutWalkableRegion(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ const int x1 = stackPos(0);
+ int y1 = stackPos(1);
+ const int x2 = stackPos(2);
+ int y2 = stackPos(3);
+
+ if (y1 < _maskPageMinY)
+ y1 = _maskPageMinY;
+ if (y2 > _maskPageMaxY)
+ y2 = _maskPageMaxY;
+
+ _screen->blockOutRegion(x1, y1, x2-x1+1, y2-y1+1);
+ return 0;
+}
+
+int KyraEngine_MR::o3_showSceneStringsMessage(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showSceneStringsMessage(%p) (%d)", (const void *)script, stackPos(0));
+ showMessage((const char *)getTableEntry(_sceneStrings, stackPos(0)), 0xFF, 0xF0);
+ return 0;
+}
+
+int KyraEngine_MR::o3_showGoodConscience(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showGoodConscience(%p) ()", (const void *)script);
+ showGoodConscience();
+ return 0;
+}
+
+int KyraEngine_MR::o3_goodConscienceChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_goodConscienceChat(%p) (%d)", (const void *)script, stackPos(0));
+ int id = stackPos(0);
+ const char *str = (const char *)getTableEntry(_useActorBuffer ? _actorFile : _sceneStrings, id);
+ goodConscienceChat(str, _vocHigh, id);
+ return 0;
+}
+
+int KyraEngine_MR::o3_hideGoodConscience(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_hideGoodConscience(%p) ()", (const void *)script);
+ hideGoodConscience();
+ return 0;
+}
+
+int KyraEngine_MR::o3_defineSceneAnim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_defineSceneAnim(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, '%s')",
+ (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7),
+ stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPosString(12));
+ const int animId = stackPos(0);
+ SceneAnim &anim = _sceneAnims[animId];
+
+ uint16 flags = anim.flags = stackPos(1);
+ int x = anim.x = stackPos(2);
+ int y = anim.y = stackPos(3);
+ int x2 = anim.x2 = stackPos(4);
+ int y2 = anim.y2 = stackPos(5);
+ int w = anim.width = stackPos(6);
+ int h = anim.height = stackPos(7);
+ anim.specialSize = stackPos(9);
+ anim.shapeIndex = stackPos(11);
+ const char *filename = stackPosString(12);
+
+ if (filename)
+ strcpy(anim.filename, filename);
+
+ if (flags & 8) {
+ _sceneAnimMovie[animId]->open(filename, 1, 0);
+ if (_sceneAnimMovie[animId]->opened()) {
+ anim.wsaFlag = 1;
+ if (x2 == -1)
+ x2 = _sceneAnimMovie[animId]->xAdd();
+ if (y2 == -1)
+ y2 = _sceneAnimMovie[animId]->yAdd();
+ if (w == -1)
+ w = _sceneAnimMovie[animId]->width();
+ if (h == -1)
+ h = _sceneAnimMovie[animId]->height();
+ if (x == -1)
+ x = (w >> 1) + x2;
+ if (y == -1)
+ y = y2 + h - 1;
+
+ anim.x = x;
+ anim.y = y;
+ anim.x2 = x2;
+ anim.y2 = y2;
+ anim.width = w;
+ anim.height = h;
+ }
+ }
+
+ return 9;
+}
+
+int KyraEngine_MR::o3_updateSceneAnim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_updateSceneAnim(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ updateSceneAnim(stackPos(0), stackPos(1));
+ _specialSceneScriptRunFlag = false;
+ return 0;
+}
+
+int KyraEngine_MR::o3_runActorScript(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_runActorScript(%p) ()", (const void *)script);
+ EMCData data;
+ EMCState state;
+ memset(&data, 0, sizeof(data));
+ memset(&state, 0, sizeof(state));
+
+ _res->exists("_ACTOR.EMC", true);
+ _emc->load("_ACTOR.EMC", &data, &_opcodes);
+ _emc->init(&state, &data);
+ _emc->start(&state, 0);
+
+ state.regs[4] = _itemInHand;
+ state.regs[0] = _mainCharacter.sceneId;
+
+ int vocHigh = _vocHigh;
+ _vocHigh = 200;
+ _useActorBuffer = true;
+
+ while (_emc->isValid(&state))
+ _emc->run(&state);
+
+ _useActorBuffer = false;
+ _vocHigh = vocHigh;
+ _emc->unload(&data);
+
+ if (queryGameFlag(0x218)) {
+ resetGameFlag(0x218);
+ enterNewScene(78, -1, 0, 0, 0);
+ }
+
+ return 0;
+}
+
+int KyraEngine_MR::o3_doDialog(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_doDialog(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ doDialog(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_MR::o3_setConversationState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setConversationState(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ int id = stackPos(0);
+ const int dlgIndex = stackPos(1);
+ const int value = stackPos(2);
+
+ switch (_currentChapter-2) {
+ case 0:
+ id -= 34;
+ break;
+
+ case 1:
+ id -= 54;
+ break;
+
+ case 2:
+ id -= 55;
+ break;
+
+ case 3:
+ id -= 70;
+ break;
+
+ default:
+ break;
+ }
+
+ return (_conversationState[id][dlgIndex] = value);
+}
+
+int KyraEngine_MR::o3_getConversationState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getConversationState(%p) (%d)", (const void *)script, stackPos(0));
+ int id = stackPos(0);
+ const int dlgIndex = _mainCharacter.dlgIndex;
+
+ switch (_currentChapter-2) {
+ case 0:
+ id -= 34;
+ break;
+
+ case 1:
+ id -= 54;
+ break;
+
+ case 2:
+ id -= 55;
+ break;
+
+ case 3:
+ id -= 70;
+ break;
+
+ default:
+ break;
+ }
+
+ return _conversationState[id][dlgIndex];
+}
+
+int KyraEngine_MR::o3_changeChapter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_changeChapter(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ changeChapter(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ return 0;
+}
+
+int KyraEngine_MR::o3_countItemInstances(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_countItemInstances(%p) (%d)", (const void *)script, stackPos(0));
+ int count = 0;
+ const int16 item = stackPos(0);
+
+ for (int i = 0; i < 10; ++i) {
+ if (_mainCharacter.inventory[i] == item)
+ ++count;
+ }
+
+ if (_itemInHand == item)
+ ++count;
+
+ for (int i = 0; i < 50; ++i) {
+ if (_itemList[i].id == item)
+ ++count;
+ }
+
+ return count;
+}
+
+int KyraEngine_MR::o3_dialogStartScript(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_dialogStartScript(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ dialogStartScript(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_MR::o3_dialogEndScript(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_dialogEndScript(%p) (%d)", (const void *)script, stackPos(0));
+ dialogEndScript(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_MR::o3_customChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_customChat(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ const int id = stackPos(0);
+ const int object = stackPos(1);
+ const char *str = (const char *)getTableEntry(_sceneStrings, id);
+
+ if (!str)
+ return 0;
+
+ strcpy(_stringBuffer, str);
+ _chatText = _stringBuffer;
+ _chatObject = object;
+ _chatVocHigh = _chatVocLow = -1;
+ objectChatInit(_stringBuffer, object, _vocHigh, id);
+ playVoice(_vocHigh, id);
+ return 0;
+}
+
+int KyraEngine_MR::o3_customChatFinish(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_customChatFinish(%p) ()", (const void *)script);
+ _text->restoreScreen();
+ _chatText = 0;
+ _chatObject = -1;
+ return 0;
+}
+
+int KyraEngine_MR::o3_setupSceneAnimObject(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setupSceneAnimObject(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9),
+ stackPos(10), stackPos(11), stackPosString(12));
+ setupSceneAnimObject(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8),
+ stackPos(9), stackPos(10), stackPos(11), stackPosString(12));
+ return 0;
+}
+
+int KyraEngine_MR::o3_removeSceneAnimObject(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeSceneAnimObject(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ removeSceneAnimObject(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_MR::o3_dummy(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_dummy(%p) ()", (const void *)script);
+ return 0;
+}
+
+#pragma mark -
+
+int KyraEngine_MR::o3a_setCharacterFrame(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3a_setCharacterFrame(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ static const uint8 frameTable[] = {
+ 0x58, 0xD8, 0xD8, 0x98, 0x78, 0x78, 0xB8, 0xB8
+ };
+
+ _animNewFrame = stackPos(0);
+ if (_useFrameTable)
+ _animNewFrame += frameTable[_mainCharacter.facing];
+
+ _animDelayTime = stackPos(1);
+ _animNeedUpdate = true;
+ return 0;
+}
+
+int KyraEngine_MR::o3a_playSoundEffect(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3a_playSoundEffect(%p) (%d)", (const void *)script, stackPos(0));
+ snd_playSoundEffect(stackPos(0), 200);
+ return 0;
+}
+
+#pragma mark -
+
+int KyraEngine_MR::o3d_updateAnim(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3d_updateAnim(%p) (%d)", (const void *)script, stackPos(0));
+ if (_dialogSceneAnim >= 0)
+ updateSceneAnim(_dialogSceneAnim, stackPos(0));
+ return 0;
+}
+
+int KyraEngine_MR::o3d_delay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3d_delay(%p) (%d)", (const void *)script, stackPos(0));
+ delayUntil(_system->getMillis() + stackPos(0) * _tickLength, false, true);
+ return 0;
+}
+
+#pragma mark -
+
+typedef Common::Functor1Mem<EMCState *, int, KyraEngine_MR> OpcodeV3;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV3(this, &KyraEngine_MR::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV3(this, 0))
+void KyraEngine_MR::setupOpcodeTable() {
+ Common::Array<const Opcode *> *table = 0;
+
+ _opcodes.reserve(176);
+ SetOpcodeTable(_opcodes);
+ // 0x00
+ Opcode(o3_getMalcolmShapes);
+ Opcode(o3_setCharacterPos);
+ Opcode(o3_defineObject);
+ Opcode(o3_refreshCharacter);
+ // 0x04
+ Opcode(o2_getCharacterX);
+ Opcode(o2_getCharacterY);
+ Opcode(o2_getCharacterFacing);
+ Opcode(o2_getCharacterScene);
+ // 0x08
+ Opcode(o3_getMalcolmsMood);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o3_getCharacterFrameFromFacing);
+ // 0x0C
+ Opcode(o2_setCharacterFacingOverwrite);
+ Opcode(o2_trySceneChange);
+ Opcode(o2_moveCharacter);
+ Opcode(o3_setCharacterFacing);
+ // 0x10
+ OpcodeUnImpl();
+ Opcode(o3_showSceneFileMessage);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ // 0x14
+ Opcode(o3_setCharacterAnimFrameFromFacing);
+ Opcode(o3_showBadConscience);
+ Opcode(o3_dummy);
+ Opcode(o3_hideBadConscience);
+ // 0x18
+ OpcodeUnImpl();
+ Opcode(o3_showAlbum);
+ Opcode(o3_setInventorySlot);
+ Opcode(o3_getInventorySlot);
+ // 0x1C
+ Opcode(o3_addItemToInventory);
+ OpcodeUnImpl();
+ Opcode(o3_addItemToCurScene);
+ Opcode(o3_objectChat);
+ // 0x20
+ Opcode(o2_checkForItem);
+ Opcode(o3_dummy);
+ Opcode(o3_resetInventory);
+ Opcode(o2_defineItem);
+ // 0x24
+ Opcode(o3_removeInventoryItemInstances);
+ Opcode(o3_countInventoryItemInstances);
+ Opcode(o3_npcChatSequence);
+ Opcode(o1_queryGameFlag);
+ // 0x28
+ Opcode(o1_resetGameFlag);
+ Opcode(o1_setGameFlag);
+ Opcode(o1_setHandItem);
+ Opcode(o1_removeHandItem);
+ // 0x2C
+ Opcode(o1_getMouseState);
+ Opcode(o1_hideMouse);
+ Opcode(o2_addSpecialExit);
+ Opcode(o1_setMousePos);
+ // 0x30
+ Opcode(o1_showMouse);
+ Opcode(o3_badConscienceChat);
+ Opcode(o3_wipeDownMouseItem);
+ Opcode(o3_dummy);
+ // 0x34
+ Opcode(o3_setMalcolmsMood);
+ Opcode(o3_playSoundEffect);
+ Opcode(o3_dummy);
+ Opcode(o2_delay);
+ // 0x38
+ Opcode(o3_updateScore);
+ Opcode(o3_makeSecondChanceSave);
+ Opcode(o3_setSceneFilename);
+ OpcodeUnImpl();
+ // 0x3C
+ Opcode(o3_removeItemsFromScene);
+ Opcode(o3_disguiseMalcolm);
+ Opcode(o3_drawSceneShape);
+ Opcode(o3_drawSceneShapeOnPage);
+ // 0x40
+ Opcode(o3_checkInRect);
+ Opcode(o3_updateConversations);
+ Opcode(o3_removeItemSlot);
+ Opcode(o3_dummy);
+ // 0x44
+ Opcode(o3_dummy);
+ Opcode(o3_setSceneDim);
+ OpcodeUnImpl();
+ Opcode(o3_dummy);
+ // 0x48
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o3_setSceneAnimPosAndFrame);
+ Opcode(o2_update);
+ // 0x4C
+ Opcode(o3_removeItemInstances);
+ Opcode(o3_dummy);
+ Opcode(o3_disableInventory);
+ Opcode(o3_enableInventory);
+ // 0x50
+ Opcode(o3_enterNewScene);
+ Opcode(o3_switchScene);
+ Opcode(o2_getShapeFlag1);
+ Opcode(o3_dummy);
+ // 0x54
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o3_setMalcolmPos);
+ Opcode(o3_stopMusic);
+ // 0x58
+ Opcode(o1_playWanderScoreViaMap);
+ Opcode(o3_playSoundEffect);
+ Opcode(o3_getScore);
+ Opcode(o3_daggerWarning);
+ // 0x5C
+ Opcode(o3_blockOutWalkableRegion);
+ Opcode(o3_dummy);
+ Opcode(o3_showSceneStringsMessage);
+ OpcodeUnImpl();
+ // 0x60
+ Opcode(o1_getRand);
+ Opcode(o3_dummy);
+ Opcode(o1_setDeathHandler);
+ Opcode(o3_showGoodConscience);
+ // 0x64
+ Opcode(o3_goodConscienceChat);
+ Opcode(o3_hideGoodConscience);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ // 0x68
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o2_waitForConfirmationClick);
+ // 0x6C
+ Opcode(o3_dummy);
+ Opcode(o2_defineRoomEntrance);
+ Opcode(o2_runAnimationScript);
+ Opcode(o2_setSpecialSceneScriptRunTime);
+ // 0x70
+ Opcode(o3_defineSceneAnim);
+ Opcode(o3_dummy);
+ Opcode(o3_updateSceneAnim);
+ Opcode(o3_dummy);
+ // 0x74
+ Opcode(o3_runActorScript);
+ Opcode(o3_doDialog);
+ Opcode(o2_randomSceneChat);
+ Opcode(o2_setDlgIndex);
+ // 0x78
+ Opcode(o2_getDlgIndex);
+ Opcode(o2_defineScene);
+ Opcode(o3_setConversationState);
+ OpcodeUnImpl();
+ // 0x7C
+ OpcodeUnImpl();
+ Opcode(o3_getConversationState);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ // 0x80
+ Opcode(o3_dummy);
+ Opcode(o3_changeChapter);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ // 0x84
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ // 0x88
+ Opcode(o3_countItemInstances);
+ Opcode(o3_dummy);
+ Opcode(o3_dialogStartScript);
+ Opcode(o3_dummy);
+ // 0x8C
+ Opcode(o3_dialogEndScript);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o2_setSpecialSceneScriptState);
+ // 0x90
+ Opcode(o2_clearSpecialSceneScriptState);
+ Opcode(o2_querySpecialSceneScriptState);
+ Opcode(o3_dummy);
+ Opcode(o2_setHiddenItemsEntry);
+ // 0x94
+ Opcode(o2_getHiddenItemsEntry);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ OpcodeUnImpl();
+ // 0x98
+ Opcode(o3_customChat);
+ Opcode(o3_customChatFinish);
+ Opcode(o3_setupSceneAnimObject);
+ Opcode(o3_removeSceneAnimObject);
+ // 0x9C
+ Opcode(o2_disableTimer);
+ Opcode(o2_enableTimer);
+ Opcode(o2_setTimerCountdown);
+ OpcodeUnImpl();
+ // 0xA0
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ Opcode(o3_dummy);
+ // 0xA4
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ Opcode(o2_setVocHigh);
+ // 0xA8
+ Opcode(o2_getVocHigh);
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ // 0xAC
+ OpcodeUnImpl();
+ Opcode(o3_dummy);
+ OpcodeUnImpl();
+ Opcode(o3_dummy);
+
+ _opcodesAnimation.reserve(8);
+ SetOpcodeTable(_opcodesAnimation);
+ // 0x00
+ Opcode(o2a_setAnimationShapes);
+ Opcode(o3a_setCharacterFrame);
+ Opcode(o3a_playSoundEffect);
+ Opcode(o3_dummy);
+ // 0x04
+ Opcode(o2a_setResetFrame);
+ Opcode(o1_getRand);
+ Opcode(o3_getMalcolmShapes);
+ Opcode(o3_dummy);
+
+ _opcodesDialog.reserve(5);
+ SetOpcodeTable(_opcodesDialog);
+ // 0x00
+ Opcode(o3d_updateAnim);
+ Opcode(o3d_delay);
+ Opcode(o1_getRand);
+ Opcode(o1_queryGameFlag);
+ // 0x04
+ Opcode(o3_dummy);
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/script/script_tim.cpp b/engines/kyra/script/script_tim.cpp
new file mode 100644
index 0000000000..7afa35c339
--- /dev/null
+++ b/engines/kyra/script/script_tim.cpp
@@ -0,0 +1,1101 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/script/script_tim.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+
+#ifdef ENABLE_LOL
+#include "kyra/engine/lol.h"
+#include "kyra/graphics/screen_lol.h"
+#endif // ENABLE_LOL
+
+#include "common/iff_container.h"
+#include "common/system.h"
+
+namespace Kyra {
+
+TIMInterpreter::TIMInterpreter(KyraEngine_v1 *engine, Screen_v2 *screen_v2, OSystem *system) : _vm(engine), _screen(screen_v2), _system(system), _currentTim(0) {
+#define COMMAND(x) { &TIMInterpreter::x, #x }
+#define COMMAND_UNIMPL() { 0, 0 }
+#define cmd_return(n) cmd_return_##n
+ static const CommandEntry commandProcs[] = {
+ // 0x00
+ COMMAND(cmd_initFunc0),
+ COMMAND(cmd_stopCurFunc),
+ COMMAND(cmd_initWSA),
+ COMMAND(cmd_uninitWSA),
+ // 0x04
+ COMMAND(cmd_initFunc),
+ COMMAND(cmd_stopFunc),
+ COMMAND(cmd_wsaDisplayFrame),
+ COMMAND(cmd_displayText),
+ // 0x08
+ COMMAND(cmd_loadVocFile),
+ COMMAND(cmd_unloadVocFile),
+ COMMAND(cmd_playVocFile),
+ COMMAND_UNIMPL(),
+ // 0x0C
+ COMMAND(cmd_loadSoundFile),
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_playMusicTrack),
+ COMMAND_UNIMPL(),
+ // 0x10
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_return(1)),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ // 0x14
+ COMMAND(cmd_setLoopIp),
+ COMMAND(cmd_continueLoop),
+ COMMAND(cmd_resetLoopIp),
+ COMMAND(cmd_resetAllRuntimes),
+ // 0x18
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_execOpcode),
+ COMMAND(cmd_initFuncNow),
+ COMMAND(cmd_stopFuncNow),
+ // 0x1C
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_return(n1))
+ };
+#undef cmd_return
+#undef COMMAND_UNIMPL
+#undef COMMAND
+
+ _commands = commandProcs;
+ _commandsSize = ARRAYSIZE(commandProcs);
+
+ _langData = 0;
+ _textDisplayed = false;
+ _textAreaBuffer = new uint8[320*40];
+ assert(_textAreaBuffer);
+ if ((_vm->gameFlags().platform == Common::kPlatformPC98 || _vm->gameFlags().isDemo) && _vm->game() == GI_LOL)
+ _drawPage2 = 0;
+ else
+ _drawPage2 = 8;
+
+ _animator = new TimAnimator(0, screen_v2, 0, false);
+
+ _palDelayInc = _palDiff = _palDelayAcc = 0;
+ _abortFlag = 0;
+ _tim = 0;
+}
+
+TIMInterpreter::~TIMInterpreter() {
+ delete[] _langData;
+ delete[] _textAreaBuffer;
+ delete _animator;
+}
+
+bool TIMInterpreter::callback(Common::IFFChunk &chunk) {
+ switch (chunk._type) {
+ case MKTAG('T','E','X','T'):
+ _tim->text = new byte[chunk._size];
+ assert(_tim->text);
+ if (chunk._stream->read(_tim->text, chunk._size) != chunk._size)
+ error("Couldn't read TEXT chunk from file '%s'", _filename);
+ break;
+
+ case MKTAG('A','V','T','L'):
+ _avtlChunkSize = chunk._size >> 1;
+ _tim->avtl = new uint16[_avtlChunkSize];
+ assert(_tim->avtl);
+ if (chunk._stream->read(_tim->avtl, chunk._size) != chunk._size)
+ error("Couldn't read AVTL chunk from file '%s'", _filename);
+
+ for (int i = _avtlChunkSize - 1; i >= 0; --i)
+ _tim->avtl[i] = READ_LE_UINT16(&_tim->avtl[i]);
+ break;
+
+ default:
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._type), chunk._size, _filename);
+ }
+
+ return false;
+}
+
+TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode *> *opcodes) {
+ if (!_vm->resource()->exists(filename))
+ return 0;
+
+ Common::SeekableReadStream *stream = _vm->resource()->createReadStream(filename);
+ if (!stream)
+ error("Couldn't open TIM file '%s'", filename);
+
+ _avtlChunkSize = 0;
+ _filename = filename;
+
+ _tim = new TIM;
+ assert(_tim);
+ memset(_tim, 0, sizeof(TIM));
+
+ _tim->procFunc = -1;
+ _tim->opcodes = opcodes;
+
+ IFFParser iff(*stream);
+ Common::Functor1Mem<Common::IFFChunk &, bool, TIMInterpreter> c(this, &TIMInterpreter::callback);
+ iff.parse(c);
+
+ if (!_tim->avtl)
+ error("No AVTL chunk found in file: '%s'", filename);
+
+ if (stream->err())
+ error("Read error while parsing file '%s'", filename);
+
+ delete stream;
+
+ const int num = (_avtlChunkSize < TIM::kCountFuncs) ? _avtlChunkSize : (int)TIM::kCountFuncs;
+ for (int i = 0; i < num; ++i)
+ _tim->func[i].avtl = _tim->avtl + _tim->avtl[i];
+
+ Common::strlcpy(_tim->filename, filename, 13);
+
+ _tim->isLoLOutro = (_vm->game() == GI_LOL) && !scumm_stricmp(filename, "LOLFINAL.TIM");
+ _tim->lolCharacter = 0;
+
+ TIM *r = _tim;
+ _tim = 0;
+ return r;
+}
+
+void TIMInterpreter::unload(TIM *&tim) const {
+ if (!tim)
+ return;
+
+ delete[] tim->text;
+ delete[] tim->avtl;
+ delete tim;
+ tim = 0;
+}
+
+void TIMInterpreter::setLangData(const char *filename) {
+ delete[] _langData;
+ _langData = _vm->resource()->fileData(filename, 0);
+}
+
+int TIMInterpreter::exec(TIM *tim, bool loop) {
+ if (!tim)
+ return 0;
+
+ _currentTim = tim;
+ if (!_currentTim->func[0].ip) {
+ _currentTim->func[0].ip = _currentTim->func[0].avtl;
+ _currentTim->func[0].nextTime = _currentTim->func[0].lastTime = _system->getMillis();
+ }
+
+ do {
+ update();
+
+ for (_currentFunc = 0; _currentFunc < TIM::kCountFuncs; ++_currentFunc) {
+ TIM::Function &cur = _currentTim->func[_currentFunc];
+
+ if (_currentTim->procFunc != -1)
+ execCommand(28, &_currentTim->procParam);
+
+ update();
+ checkSpeechProgress();
+
+ bool running = true;
+ int cnt = 0;
+ while (cur.ip && cur.nextTime <= _system->getMillis() && running) {
+ if (cnt++ > 0) {
+ if (_currentTim->procFunc != -1)
+ execCommand(28, &_currentTim->procParam);
+ update();
+ }
+
+ int8 opcode = int8(cur.ip[2] & 0xFF);
+
+ switch (execCommand(opcode, cur.ip + 3)) {
+ case -1:
+ loop = false;
+ running = false;
+ _currentFunc = 11;
+ break;
+
+ case -2:
+ running = false;
+ break;
+
+ case -3:
+ _currentTim->procFunc = _currentFunc;
+ _currentTim->dlgFunc = -1;
+ break;
+
+ case 22:
+ cur.loopIp = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ if (cur.ip) {
+ cur.ip += cur.ip[0];
+ cur.lastTime = cur.nextTime;
+ cur.nextTime += cur.ip[1] * _vm->tickLength();
+ }
+ }
+ }
+ } while (loop && !_vm->shouldQuit());
+
+ return _currentTim->clickedButton;
+}
+
+void TIMInterpreter::refreshTimersAfterPause(uint32 elapsedTime) {
+ if (!_currentTim)
+ return;
+
+ for (int i = 0; i < TIM::kCountFuncs; i++) {
+ if (_currentTim->func[i].lastTime)
+ _currentTim->func[i].lastTime += elapsedTime;
+ if (_currentTim->func[i].nextTime)
+ _currentTim->func[i].nextTime += elapsedTime;
+ }
+}
+
+void TIMInterpreter::displayText(uint16 textId, int16 flags) {
+ char *text = getTableEntry(textId);
+
+ if (_textDisplayed) {
+ _screen->copyBlockToPage(0, 0, 160, 320, 40, _textAreaBuffer);
+ _textDisplayed = false;
+ }
+
+ if (!text)
+ return;
+ if (!text[0])
+ return;
+
+ char filename[16];
+ memset(filename, 0, sizeof(filename));
+
+ if (text[0] == '$') {
+ const char *end = strchr(text+1, '$');
+ if (end)
+ memcpy(filename, text+1, end-1-text);
+ }
+
+ const bool sjisMode = (_vm->gameFlags().lang == Common::JA_JPN && _vm->gameFlags().use16ColorMode);
+ if (filename[0] && (_vm->speechEnabled() || !_vm->gameFlags().isTalkie))
+ _vm->sound()->voicePlay(filename, 0, 255, 255, !_vm->gameFlags().isTalkie);
+
+ if (text[0] == '$')
+ text = strchr(text + 1, '$') + 1;
+
+ if (!_vm->gameFlags().use16ColorMode)
+ setupTextPalette((flags < 0) ? 1 : flags, 0);
+
+ if (flags < 0) {
+ static const uint8 colorMap[] = { 0x00, 0xF0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ _screen->setFont(sjisMode ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+ _screen->setTextColorMap(colorMap);
+ _screen->_charWidth = -2;
+ }
+
+ _screen->_charOffset = -4;
+ _screen->copyRegionToBuffer(0, 0, 160, 320, 40, _textAreaBuffer);
+ _textDisplayed = true;
+
+ char backupChar = 0;
+ char *str = text;
+ int heightAdd = 0;
+
+ while (str[0] && _vm->textEnabled()) {
+ char *nextLine = strchr(str, '\r');
+
+ backupChar = 0;
+ if (nextLine) {
+ backupChar = nextLine[0];
+ nextLine[0] = '\0';
+ }
+
+ int width = _screen->getTextWidth(str);
+
+ if (flags >= 0) {
+ if (_vm->gameFlags().use16ColorMode) {
+ static const uint8 colorMap[] = { 0xE1, 0xE1, 0xC1, 0xA1, 0x81, 0x61 };
+ _screen->printText(str, (320 - width) >> 1, 160 + heightAdd, colorMap[flags], 0x00);
+ } else {
+ _screen->printText(str, (320 - width) >> 1, 160 + heightAdd, 0xF0, 0x00);
+ }
+ } else {
+ _screen->printText(str, (320 - width) >> 1, 188, 0xF0, 0x00);
+ }
+
+ heightAdd += _screen->getFontHeight();
+ str += strlen(str);
+
+ if (backupChar) {
+ nextLine[0] = backupChar;
+ ++str;
+ }
+ }
+
+ _screen->_charOffset = 0;
+
+ if (flags < 0) {
+ static const uint8 colorMap[] = { 0x00, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x00, 0x00, 0x00, 0x00 };
+
+ _screen->setFont(sjisMode ? Screen::FID_SJIS_FNT : Screen::FID_INTRO_FNT);
+ _screen->setTextColorMap(colorMap);
+ _screen->_charWidth = 0;
+ }
+}
+
+void TIMInterpreter::displayText(uint16 textId, int16 flags, uint8 color) {
+ if (!_vm->textEnabled() && !(textId & 0x8000))
+ return;
+
+ char *text = getTableEntry(textId & 0x7FFF);
+
+ if (flags > 0)
+ _screen->copyBlockToPage(0, 0, 0, 320, 40, _textAreaBuffer);
+
+ if (flags == 255)
+ return;
+
+ _screen->setFont((_vm->gameFlags().lang == Common::JA_JPN && _vm->gameFlags().use16ColorMode) ? Screen::FID_SJIS_FNT : Screen::FID_INTRO_FNT);
+
+ static const uint8 colorMap[] = { 0x00, 0xA0, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ _screen->setTextColorMap(colorMap);
+ _screen->_charWidth = 0;
+ if (!_vm->gameFlags().use16ColorMode)
+ _screen->_charOffset = -4;
+
+ if (!flags)
+ _screen->copyRegionToBuffer(0, 0, 0, 320, 40, _textAreaBuffer);
+
+ char backupChar = 0;
+ char *str = text;
+ int y = 0;
+
+ if (_vm->gameFlags().use16ColorMode) {
+ if (color == 0xDA)
+ color = 0xA1;
+ else if (color == 0xF2)
+ color = 0xE1;
+ else if (flags < 0)
+ color = 0xE1;
+ else
+ color = 0xC1;
+ }
+
+ while (str[0]) {
+ char *nextLine = strchr(str, '\r');
+
+ backupChar = 0;
+ if (nextLine) {
+ backupChar = nextLine[0];
+ nextLine[0] = '\0';
+ }
+
+ int width = _screen->getTextWidth(str);
+
+ if (flags >= 0)
+ _screen->printText(str, (320 - width) >> 1, y, color, 0x00);
+ else
+ _screen->printText(str, 0, y, color, 0x00);
+
+ y += (_vm->gameFlags().use16ColorMode ? 16 : (_screen->getFontHeight() - 4));
+ str += strlen(str);
+
+ if (backupChar) {
+ nextLine[0] = backupChar;
+ ++str;
+ }
+ }
+}
+
+void TIMInterpreter::setupTextPalette(uint index, int fadePalette) {
+ static const uint16 palTable[] = {
+ 0x00, 0x00, 0x00,
+ 0x64, 0x64, 0x64,
+ 0x61, 0x51, 0x30,
+ 0x29, 0x48, 0x64,
+ 0x00, 0x4B, 0x3B,
+ 0x64, 0x1E, 0x1E,
+ };
+
+ for (int i = 0; i < 15; ++i) {
+ uint8 *palette = _screen->getPalette(0).getData() + (240 + i) * 3;
+
+ uint8 c1 = (((15 - i) << 2) * palTable[index*3+0]) / 100;
+ uint8 c2 = (((15 - i) << 2) * palTable[index*3+1]) / 100;
+ uint8 c3 = (((15 - i) << 2) * palTable[index*3+2]) / 100;
+
+ palette[0] = c1;
+ palette[1] = c2;
+ palette[2] = c3;
+ }
+
+ if (!fadePalette && !_palDiff) {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ } else {
+ _screen->getFadeParams(_screen->getPalette(0), fadePalette, _palDelayInc, _palDiff);
+ _palDelayAcc = 0;
+ }
+}
+
+int TIMInterpreter::initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags) {
+ Movie *wsa = 0;
+
+ const bool isLoLDemo = _vm->gameFlags().isDemo && _vm->game() == GI_LOL;
+
+ if (isLoLDemo || _vm->gameFlags().platform == Common::kPlatformPC98 || _currentTim->isLoLOutro)
+ _drawPage2 = 0;
+ else
+ _drawPage2 = 8;
+
+ uint16 wsaOpenFlags = 0;
+ if (isLoLDemo) {
+ if (!(wsaFlags & 0x10))
+ wsaOpenFlags |= 1;
+ } else {
+ if (wsaFlags & 0x10)
+ wsaOpenFlags |= 2;
+ wsaOpenFlags |= 1;
+
+ if (offscreenBuffer == 2)
+ wsaOpenFlags = 1;
+ }
+
+ Common::String file = Common::String::format("%s.WSA", filename);
+
+ if (_vm->resource()->exists(file.c_str())) {
+ if (isLoLDemo)
+ wsa = new WSAMovie_v1(_vm);
+ else
+ wsa = new WSAMovie_v2(_vm);
+ assert(wsa);
+
+ wsa->open(file.c_str(), wsaOpenFlags, (index == 1) ? &_screen->getPalette(0) : 0);
+ }
+
+ if (wsa && wsa->opened()) {
+ if (isLoLDemo) {
+ if (x == -1) {
+ int16 t = int8(320 - wsa->width());
+ uint8 v = int8(t & 0x00FF) - int8((t & 0xFF00) >> 8);
+ v >>= 1;
+ x = v;
+ }
+
+ if (y == -1) {
+ int16 t = int8(200 - wsa->height());
+ uint8 v = int8(t & 0x00FF) - int8((t & 0xFF00) >> 8);
+ v >>= 1;
+ y = v;
+ }
+ } else {
+ if (x == -1)
+ x = 0;
+ if (y == -1)
+ y = 0;
+ }
+
+ if (wsaFlags & 2) {
+ _screen->fadePalette(_screen->getPalette(1), 15, 0);
+ _screen->clearPage(_drawPage2);
+ if (_drawPage2)
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ if (wsaFlags & 4) {
+ file = Common::String::format("%s.CPS", filename);
+
+ if (_vm->resource()->exists(file.c_str())) {
+ _screen->loadBitmap(file.c_str(), 3, 3, &_screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, _drawPage2, Screen::CR_NO_P_CHECK);
+ if (_drawPage2)
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ wsa->displayFrame(0, 0, x, y, 0, 0, 0);
+ }
+
+ if (wsaFlags & 2)
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+ } else {
+ if (wsaFlags & 2) {
+ _screen->fadePalette(_screen->getPalette(1), 15, 0);
+ _screen->clearPage(_drawPage2);
+ if (_drawPage2)
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ file = Common::String::format("%s.CPS", filename);
+
+ if (_vm->resource()->exists(file.c_str())) {
+ _screen->loadBitmap(file.c_str(), 3, 3, &_screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, _drawPage2, Screen::CR_NO_P_CHECK);
+ if (_drawPage2)
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ if (wsaFlags & 2)
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+ }
+
+ _animator->init(index, wsa, x, y, wsaFlags, 0);
+
+ return index + 1;
+}
+
+int TIMInterpreter::freeAnimStruct(int index) {
+ _animator->reset(index, true);
+ return 1;
+}
+
+char *TIMInterpreter::getTableEntry(uint idx) {
+ if (!_langData)
+ return 0;
+ else
+ return (char *)(_langData + READ_LE_UINT16(_langData + (idx<<1)));
+}
+
+const char *TIMInterpreter::getCTableEntry(uint idx) const {
+ if (!_langData)
+ return 0;
+ else
+ return (const char *)(_langData + READ_LE_UINT16(_langData + (idx<<1)));
+}
+
+int TIMInterpreter::execCommand(int cmd, const uint16 *param) {
+ if (cmd < 0 || cmd >= _commandsSize) {
+ warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename);
+ return 0;
+ }
+
+ if (_commands[cmd].proc == 0) {
+ warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename);
+ return 0;
+ }
+
+ debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void *)param);
+ return (this->*_commands[cmd].proc)(param);
+}
+
+int TIMInterpreter::cmd_initFunc0(const uint16 *param) {
+ for (int i = 0; i < TIM::kWSASlots; ++i)
+ memset(&_currentTim->wsa[i], 0, sizeof(TIM::WSASlot));
+
+ _currentTim->func[0].ip = _currentTim->func[0].avtl;
+ _currentTim->func[0].lastTime = _system->getMillis();
+ return 1;
+}
+
+int TIMInterpreter::cmd_stopCurFunc(const uint16 *param) {
+ if (_currentFunc < TIM::kCountFuncs)
+ _currentTim->func[_currentFunc].ip = 0;
+ if (!_currentFunc)
+ _finished = true;
+ return -2;
+}
+
+void TIMInterpreter::stopAllFuncs(TIM *tim) {
+ for (int i = 0; i < TIM::kCountFuncs; ++i)
+ tim->func[i].ip = 0;
+}
+
+int TIMInterpreter::cmd_initWSA(const uint16 *param) {
+ const int index = param[0];
+
+ TIM::WSASlot &slot = _currentTim->wsa[index];
+
+ slot.x = int16(param[2]);
+ slot.y = int16(param[3]);
+ slot.offscreen = param[4];
+ slot.wsaFlags = param[5];
+ const char *filename = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (param[1]<<1)));
+
+ slot.anim = initAnimStruct(index, filename, slot.x, slot.y, 10, slot.offscreen, slot.wsaFlags);
+ return 1;
+}
+
+int TIMInterpreter::cmd_uninitWSA(const uint16 *param) {
+ const int index = param[0];
+
+ TIM::WSASlot &slot = _currentTim->wsa[index];
+
+ if (!slot.anim)
+ return 0;
+
+ if (slot.offscreen) {
+ _animator->reset(index, false);
+ slot.anim = 0;
+ } else {
+ //XXX
+ _animator->reset(index, true);
+ memset(&slot, 0, sizeof(TIM::WSASlot));
+ }
+
+ return 1;
+}
+
+int TIMInterpreter::cmd_initFunc(const uint16 *param) {
+ uint16 func = *param;
+ assert(func < TIM::kCountFuncs);
+ if (_currentTim->func[func].avtl)
+ _currentTim->func[func].ip = _currentTim->func[func].avtl;
+ else
+ _currentTim->func[func].avtl = _currentTim->func[func].ip = _currentTim->avtl + _currentTim->avtl[func];
+ return 1;
+}
+
+int TIMInterpreter::cmd_stopFunc(const uint16 *param) {
+ uint16 func = *param;
+ assert(func < TIM::kCountFuncs);
+ _currentTim->func[func].ip = 0;
+ return 1;
+}
+
+int TIMInterpreter::cmd_wsaDisplayFrame(const uint16 *param) {
+ _animator->displayFrame(param[0], _drawPage2, param[1]);
+ return 1;
+}
+
+int TIMInterpreter::cmd_displayText(const uint16 *param) {
+ if (_currentTim->isLoLOutro)
+ displayText(param[0], param[1], 0xF2);
+ else
+ displayText(param[0], param[1]);
+ return 1;
+}
+
+int TIMInterpreter::cmd_loadVocFile(const uint16 *param) {
+ const int stringId = param[0];
+ const int index = param[1];
+
+ _vocFiles[index] = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (stringId << 1)));
+
+ if (index == 2 && _currentTim->isLoLOutro && _vm->gameFlags().isTalkie) {
+ _vocFiles[index] = "CONGRATA.VOC";
+
+ switch (_currentTim->lolCharacter) {
+ case 0:
+ _vocFiles[index].setChar('K', 7);
+ break;
+
+ case 1:
+ _vocFiles[index].setChar('A', 7);
+ break;
+
+ case 2:
+ _vocFiles[index].setChar('M', 7);
+ break;
+
+ case 3:
+ _vocFiles[index].setChar('C', 7);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ for (int i = 0; i < 4; ++i)
+ _vocFiles[index].deleteLastChar();
+ return 1;
+}
+
+int TIMInterpreter::cmd_unloadVocFile(const uint16 *param) {
+ const int index = param[0];
+ _vocFiles[index].clear();
+ return 1;
+}
+
+int TIMInterpreter::cmd_playVocFile(const uint16 *param) {
+ const int index = param[0];
+ const int volume = (param[1] * 255) / 100;
+
+ if (index < ARRAYSIZE(_vocFiles) && !_vocFiles[index].empty())
+ _vm->sound()->voicePlay(_vocFiles[index].c_str(), 0, volume, 255, true);
+ else if (index == 7 && !_vm->gameFlags().isTalkie)
+ _vm->sound()->playTrack(index);
+ else
+ _vm->sound()->playSoundEffect(index);
+
+ return 1;
+}
+
+int TIMInterpreter::cmd_loadSoundFile(const uint16 *param) {
+ const char *file = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (param[0]<<1)));
+
+ _vm->sound()->loadSoundFile(file);
+ if (_vm->game() == GI_LOL)
+ _vm->sound()->loadSfxFile(file);
+
+ return 1;
+}
+
+int TIMInterpreter::cmd_playMusicTrack(const uint16 *param) {
+ _vm->sound()->playTrack(param[0]);
+ return 1;
+}
+
+int TIMInterpreter::cmd_setLoopIp(const uint16 *param) {
+ _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip;
+ return 1;
+}
+
+int TIMInterpreter::cmd_continueLoop(const uint16 *param) {
+ TIM::Function &func = _currentTim->func[_currentFunc];
+
+ if (!func.loopIp)
+ return -2;
+
+ func.ip = func.loopIp;
+
+ uint16 factor = param[0];
+ if (factor) {
+ const uint32 random = _vm->_rnd.getRandomNumberRng(0, 0x8000);
+ uint32 waitTime = (random * factor) / 0x8000;
+ func.nextTime += waitTime * _vm->tickLength();
+ }
+
+ return -2;
+}
+
+int TIMInterpreter::cmd_resetLoopIp(const uint16 *param) {
+ _currentTim->func[_currentFunc].loopIp = 0;
+ return 1;
+}
+
+int TIMInterpreter::cmd_resetAllRuntimes(const uint16 *param) {
+ for (int i = 0; i < TIM::kCountFuncs; ++i) {
+ if (_currentTim->func[i].ip)
+ _currentTim->func[i].nextTime = _system->getMillis();
+ }
+ return 1;
+}
+
+int TIMInterpreter::cmd_execOpcode(const uint16 *param) {
+ const uint16 opcode = *param++;
+
+ if (!_currentTim->opcodes) {
+ warning("Trying to execute TIM opcode %d without opcode list (file '%s')", opcode, _currentTim->filename);
+ return 0;
+ }
+
+ if (opcode > _currentTim->opcodes->size()) {
+ warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename);
+ return 0;
+ }
+
+ if (!(*_currentTim->opcodes)[opcode]->isValid()) {
+ warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename);
+ return 0;
+ }
+
+ return (*(*_currentTim->opcodes)[opcode])(_currentTim, param);
+}
+
+int TIMInterpreter::cmd_initFuncNow(const uint16 *param) {
+ uint16 func = *param;
+ assert(func < TIM::kCountFuncs);
+ _currentTim->func[func].ip = _currentTim->func[func].avtl;
+ _currentTim->func[func].lastTime = _currentTim->func[func].nextTime = _system->getMillis();
+ return 1;
+}
+
+int TIMInterpreter::cmd_stopFuncNow(const uint16 *param) {
+ uint16 func = *param;
+ assert(func < TIM::kCountFuncs);
+ _currentTim->func[func].ip = 0;
+ _currentTim->func[func].lastTime = _currentTim->func[func].nextTime = _system->getMillis();
+ return 1;
+}
+
+// TODO: Consider moving to another file
+
+#ifdef ENABLE_LOL
+// LOL version of the TIM interpreter
+
+TIMInterpreter_LoL::TIMInterpreter_LoL(LoLEngine *engine, Screen_v2 *screen_v2, OSystem *system) :
+ TIMInterpreter(engine, screen_v2, system), _vm(engine) {
+ #define COMMAND(x) { &TIMInterpreter_LoL::x, #x }
+ #define COMMAND_UNIMPL() { 0, 0 }
+ #define cmd_return(n) cmd_return_##n
+ static const CommandEntry commandProcs[] = {
+ // 0x00
+ COMMAND(cmd_initFunc0),
+ COMMAND(cmd_stopAllFuncs),
+ COMMAND(cmd_initWSA),
+ COMMAND(cmd_uninitWSA),
+ // 0x04
+ COMMAND(cmd_initFunc),
+ COMMAND(cmd_stopFunc),
+ COMMAND(cmd_wsaDisplayFrame),
+ COMMAND_UNIMPL(),
+ // 0x08
+ COMMAND(cmd_loadVocFile),
+ COMMAND(cmd_unloadVocFile),
+ COMMAND(cmd_playVocFile),
+ COMMAND_UNIMPL(),
+ // 0x0C
+ COMMAND(cmd_loadSoundFile),
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_playMusicTrack),
+ COMMAND_UNIMPL(),
+ // 0x10
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_return(1)),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ // 0x14
+ COMMAND(cmd_setLoopIp),
+ COMMAND(cmd_continueLoop),
+ COMMAND(cmd_resetLoopIp),
+ COMMAND(cmd_resetAllRuntimes),
+ // 0x18
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_execOpcode),
+ COMMAND(cmd_initFuncNow),
+ COMMAND(cmd_stopFuncNow),
+ // 0x1C
+ COMMAND(cmd_processDialogue),
+ COMMAND(cmd_dialogueBox),
+ COMMAND(cmd_return(n1))
+ };
+ #undef cmd_return
+ #undef COMMAND_UNIMPL
+ #undef COMMAND
+
+ _commands = commandProcs;
+ _commandsSize = ARRAYSIZE(commandProcs);
+
+ _screen = engine->_screen;
+
+ delete _animator;
+ _animator = new TimAnimator(engine, screen_v2, system, true);
+
+ _drawPage2 = 0;
+}
+
+int TIMInterpreter_LoL::initAnimStruct(int index, const char *filename, int x, int y, int frameDelay, int, uint16 wsaFlags) {
+ Movie *wsa = 0;
+ uint16 wsaOpenFlags = 0;
+ if (wsaFlags & 0x10)
+ wsaOpenFlags |= 2;
+ if (wsaFlags & 8)
+ wsaOpenFlags |= 1;
+
+ Common::String file = Common::String::format("%s.WSA", filename);
+
+ if (_vm->resource()->exists(file.c_str())) {
+ wsa = new WSAMovie_v2(_vm);
+ assert(wsa);
+ wsa->open(file.c_str(), wsaOpenFlags, &_screen->getPalette(3));
+ }
+
+ if (!_vm->_flags.use16ColorMode) {
+ if (wsaFlags & 1) {
+ if (_screen->_fadeFlag != 1)
+ _screen->fadeClearSceneWindow(10);
+ _screen->getPalette(3).copy(_screen->getPalette(0), 128, 128);
+ } else if (wsaFlags & 2) {
+ _screen->fadeToBlack(10);
+ }
+ }
+
+ if (wsa && (wsaFlags & 7))
+ wsa->displayFrame(0, 0, x, y, 0, 0, 0);
+
+ if (wsaFlags & 3) {
+ if (_vm->_flags.use16ColorMode) {
+ _vm->setPaletteBrightness(_screen->getPalette(0), _vm->_brightness, _vm->_lampEffect);
+ } else {
+ _screen->loadSpecialColors(_screen->getPalette(3));
+ _screen->fadePalette(_screen->getPalette(3), 10);
+ }
+ _screen->_fadeFlag = 0;
+ }
+
+ _animator->init(index, wsa, x, y, wsaFlags, frameDelay);
+
+ return index + 1;
+}
+
+int TIMInterpreter_LoL::freeAnimStruct(int index) {
+ _animator->reset(index, true);
+ return 1;
+}
+
+void TIMInterpreter_LoL::advanceToOpcode(int opcode) {
+ TIM::Function *f = &_currentTim->func[_currentTim->dlgFunc];
+ uint16 len = f->ip[0];
+
+ while ((f->ip[2] & 0xFF) != opcode) {
+ if ((f->ip[2] & 0xFF) == 1) {
+ f->ip[0] = len;
+ break;
+ }
+ len = f->ip[0];
+ f->ip += len;
+ }
+
+ f->nextTime = _system->getMillis();
+}
+
+void TIMInterpreter_LoL::resetDialogueState(TIM *tim) {
+ if (!tim)
+ return;
+
+ tim->procFunc = 0;
+ tim->procParam = _vm->_dialogueNumButtons ? _vm->_dialogueNumButtons : 1;
+ tim->clickedButton = 0;
+ tim->dlgFunc = -1;
+}
+
+void TIMInterpreter_LoL::update() {
+ _vm->update();
+}
+
+void TIMInterpreter_LoL::checkSpeechProgress() {
+ if (_vm->speechEnabled() && _currentTim->procParam > 1 && _currentTim->func[_currentFunc].loopIp) {
+ if (_vm->snd_updateCharacterSpeech() != 2) {
+ _currentTim->func[_currentFunc].loopIp = 0;
+ _currentTim->dlgFunc = _currentFunc;
+ advanceToOpcode(21);
+ _currentTim->dlgFunc = -1;
+ _animator->reset(5, false);
+ }
+ }
+}
+
+char *TIMInterpreter_LoL::getTableString(int id) {
+ return _vm->getLangString(id);
+}
+
+int TIMInterpreter_LoL::execCommand(int cmd, const uint16 *param) {
+ if (cmd < 0 || cmd >= _commandsSize) {
+ warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename);
+ return 0;
+ }
+
+ if (_commands[cmd].proc == 0) {
+ warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename);
+ return 0;
+ }
+
+ debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void *)param);
+ return (this->*_commands[cmd].proc)(param);
+}
+
+int TIMInterpreter_LoL::cmd_stopAllFuncs(const uint16 *param) {
+ while (_currentTim->dlgFunc == -1 && _currentTim->clickedButton == 0 && !_vm->shouldQuit()) {
+ update();
+ _currentTim->clickedButton = _vm->processDialogue();
+ }
+
+ for (int i = 0; i < TIM::kCountFuncs; ++i)
+ _currentTim->func[i].ip = 0;
+
+ return -1;
+}
+
+int TIMInterpreter_LoL::cmd_setLoopIp(const uint16 *param) {
+ if (_vm->speechEnabled()) {
+ if (_vm->snd_updateCharacterSpeech() == 2)
+ _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip;
+ else
+ advanceToOpcode(21);
+ } else {
+ _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip;
+ }
+ return 1;
+}
+
+int TIMInterpreter_LoL::cmd_continueLoop(const uint16 *param) {
+ TIM::Function &func = _currentTim->func[_currentFunc];
+
+ if (!func.loopIp)
+ return -2;
+
+ func.ip = func.loopIp;
+
+ if (_vm->snd_updateCharacterSpeech() != 2) {
+ uint16 factor = param[0];
+ if (factor) {
+ const uint32 random = _vm->_rnd.getRandomNumberRng(0, 0x8000);
+ uint32 waitTime = (random * factor) / 0x8000;
+ func.nextTime += waitTime * _vm->tickLength();
+ }
+ }
+
+ return -2;
+}
+
+int TIMInterpreter_LoL::cmd_processDialogue(const uint16 *param) {
+ int res = _vm->processDialogue();
+ if (!res || !_currentTim->procParam)
+ return res;
+
+ _vm->snd_stopSpeech(false);
+
+ _currentTim->func[_currentTim->procFunc].loopIp = 0;
+ _currentTim->dlgFunc = _currentTim->procFunc;
+ _currentTim->procFunc = -1;
+ _currentTim->clickedButton = res;
+
+ _animator->reset(5, false);
+
+ if (_currentTim->procParam)
+ advanceToOpcode(21);
+
+ return res;
+}
+
+int TIMInterpreter_LoL::cmd_dialogueBox(const uint16 *param) {
+ uint16 func = *param;
+ assert(func < TIM::kCountFuncs);
+ _currentTim->procParam = func;
+ _currentTim->clickedButton = 0;
+
+ const char *tmpStr[3];
+ int cnt = 0;
+
+ for (int i = 1; i < 4; i++) {
+ if (param[i] != 0xFFFF) {
+ tmpStr[i-1] = getTableString(param[i]);
+ cnt++;
+ } else {
+ tmpStr[i-1] = 0;
+ }
+ }
+
+ _vm->setupDialogueButtons(cnt, tmpStr[0], tmpStr[1], tmpStr[2]);
+ _vm->gui_notifyButtonListChanged();
+
+ return -3;
+}
+#endif // ENABLE_LOL
+
+} // End of namespace Kyra
diff --git a/engines/kyra/script/script_tim.h b/engines/kyra/script/script_tim.h
new file mode 100644
index 0000000000..bd9c2645e5
--- /dev/null
+++ b/engines/kyra/script/script_tim.h
@@ -0,0 +1,306 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KYRA_SCRIPT_TIM_H
+#define KYRA_SCRIPT_TIM_H
+
+#include "kyra/kyra_v1.h"
+
+#include "common/array.h"
+#include "common/func.h"
+#include "common/str.h"
+
+namespace Kyra {
+
+class WSAMovie_v2;
+class Screen_v2;
+class Movie;
+class LoLEngine;
+
+class TimAnimator {
+public:
+ struct AnimPart {
+ uint16 firstFrame;
+ uint16 lastFrame;
+ uint16 cycles;
+ int16 nextPart;
+ int16 partDelay;
+ uint16 field_A;
+ int16 sfxIndex;
+ uint16 sfxFrame;
+ };
+
+ struct Animation {
+ Movie *wsa;
+ int16 x, y;
+ uint32 nextFrame;
+ uint8 enable;
+ uint8 field_D;
+ uint8 frameDelay;
+ int8 curPart;
+ uint8 curFrame;
+ uint8 cyclesCompleted;
+ uint16 wsaCopyParams;
+ int8 lastPart;
+ AnimPart *parts;
+ };
+
+#ifdef ENABLE_LOL
+ TimAnimator(LoLEngine *engine, Screen_v2 *screen_v2, OSystem *system, bool useParts);
+#else
+ TimAnimator(KyraEngine_v1 *engine, Screen_v2 *screen_v2, OSystem *system, bool useParts);
+#endif
+ ~TimAnimator();
+
+ void init(int animIndex, Movie *wsa, int x, int y, int wsaCopyParams, int frameDelay);
+ void reset(int animIndex, bool clearStruct);
+
+ void displayFrame(int animIndex, int page, int frame, int flags = -1);
+
+ const Movie *getWsaCPtr(int animIndex) { return (animIndex >= 0 && animIndex < 6) ? _animations[animIndex].wsa : 0; }
+ int getAnimX(int animIndex) { return (animIndex >= 0 && animIndex < 6) ? _animations[animIndex].x : 0; }
+ int getAnimY(int animIndex) { return (animIndex >= 0 && animIndex < 6) ? _animations[animIndex].y : 0; }
+
+#ifdef ENABLE_LOL
+ void setupPart(int animIndex, int part, int firstFrame, int lastFrame, int cycles, int nextPart, int partDelay, int f, int sfxIndex, int sfxFrame);
+ void start(int animIndex, int part);
+ void stop(int animIndex);
+ void update(int animIndex);
+ void playPart(int animIndex, int firstFrame, int lastFrame, int delay);
+ int resetLastPart(int animIndex);
+#endif
+
+private:
+#ifdef ENABLE_LOL
+ LoLEngine *_vm;
+#else
+ KyraEngine_v1 *_vm;
+#endif
+ Screen_v2 *_screen;
+ OSystem *_system;
+
+ Animation *_animations;
+
+ const bool _useParts;
+};
+
+struct TIM;
+typedef Common::Functor2<const TIM *, const uint16 *, int> TIMOpcode;
+
+struct TIM {
+ char filename[13];
+
+ uint16 clickedButton;
+ int16 dlgFunc;
+
+ int16 procFunc;
+ uint16 procParam;
+
+ enum {
+ kCountFuncs = 10
+ };
+
+ struct Function {
+ uint16 *ip;
+
+ uint32 lastTime;
+ uint32 nextTime;
+
+ uint16 *loopIp;
+
+ uint16 *avtl;
+ } func[kCountFuncs];
+
+ enum {
+ kWSASlots = 6,
+ kAnimParts = 10
+ };
+
+ struct WSASlot {
+ int anim;
+
+ int16 x, y;
+ uint16 wsaFlags;
+ uint16 offscreen;
+ } wsa[kWSASlots];
+
+ uint16 *avtl;
+ uint8 *text;
+
+ const Common::Array<const TIMOpcode *> *opcodes;
+
+ // TODO: Get rid of this ugly HACK to allow the
+ // Lands of Lore outro to be working properly.
+ bool isLoLOutro;
+ uint8 lolCharacter;
+};
+
+class TIMInterpreter {
+public:
+ TIMInterpreter(KyraEngine_v1 *engine, Screen_v2 *screen_v2, OSystem *system);
+ virtual ~TIMInterpreter();
+
+ TIM *load(const char *filename, const Common::Array<const TIMOpcode *> *opcodes);
+ void unload(TIM *&tim) const;
+
+ bool callback(Common::IFFChunk &chunk);
+
+ virtual int initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags);
+ virtual int freeAnimStruct(int index);
+ TimAnimator *animator() { return _animator; }
+
+ void setLangData(const char *filename);
+ void clearLangData() { delete[] _langData; _langData = 0; }
+
+ const char *getCTableEntry(uint idx) const;
+
+ void resetFinishedFlag() { _finished = false; }
+ bool finished() const { return _finished; }
+
+ int exec(TIM *tim, bool loop);
+ void stopCurFunc() { if (_currentTim) cmd_stopCurFunc(0); }
+ void stopAllFuncs(TIM *tim);
+
+ void refreshTimersAfterPause(uint32 elapsedTime);
+
+ void displayText(uint16 textId, int16 flags);
+ void displayText(uint16 textId, int16 flags, uint8 color);
+ void setupTextPalette(uint index, int fadePalette);
+
+ virtual void resetDialogueState(TIM *tim) {}
+
+ int _drawPage2;
+
+ int _palDelayInc, _palDiff, _palDelayAcc;
+ int _abortFlag;
+
+protected:
+ KyraEngine_v1 *_vm;
+ Screen_v2 *_screen;
+ OSystem *_system;
+
+ TIM *_currentTim;
+ int _currentFunc;
+
+ TimAnimator *_animator;
+
+ bool _finished;
+
+ // used when loading
+ int _avtlChunkSize;
+ const char *_filename;
+ TIM *_tim;
+
+ Common::String _vocFiles[120];
+
+ virtual void update() {}
+ virtual void checkSpeechProgress() {}
+
+ char _audioFilename[32];
+
+ uint8 *_langData;
+ char *getTableEntry(uint idx);
+ bool _textDisplayed;
+ uint8 *_textAreaBuffer;
+
+ virtual int execCommand(int cmd, const uint16 *param);
+
+ typedef int (TIMInterpreter::*CommandProc)(const uint16 *);
+ struct CommandEntry {
+ CommandProc proc;
+ const char *desc;
+ };
+
+ const CommandEntry *_commands;
+ int _commandsSize;
+
+ int cmd_initFunc0(const uint16 *param);
+ int cmd_stopCurFunc(const uint16 *param);
+ int cmd_initWSA(const uint16 *param);
+ int cmd_uninitWSA(const uint16 *param);
+ int cmd_initFunc(const uint16 *param);
+ int cmd_stopFunc(const uint16 *param);
+ int cmd_wsaDisplayFrame(const uint16 *param);
+ int cmd_displayText(const uint16 *param);
+ int cmd_loadVocFile(const uint16 *param);
+ int cmd_unloadVocFile(const uint16 *param);
+ int cmd_playVocFile(const uint16 *param);
+ int cmd_loadSoundFile(const uint16 *param);
+ int cmd_playMusicTrack(const uint16 *param);
+ virtual int cmd_setLoopIp(const uint16 *param);
+ virtual int cmd_continueLoop(const uint16 *param);
+ int cmd_resetLoopIp(const uint16 *param);
+ int cmd_resetAllRuntimes(const uint16 *param);
+ int cmd_execOpcode(const uint16 *param);
+ int cmd_initFuncNow(const uint16 *param);
+ int cmd_stopFuncNow(const uint16 *param);
+#define cmd_return(n, v) \
+ int cmd_return_##n(const uint16 *){ return v; }
+ cmd_return( 1, 1)
+ cmd_return(n1, -1)
+#undef cmd_return
+};
+
+#ifdef ENABLE_LOL
+class LoLEngine;
+class Screen_LoL;
+class TIMInterpreter_LoL : public TIMInterpreter {
+public:
+ TIMInterpreter_LoL(LoLEngine *engine, Screen_v2 *screen_v2, OSystem *system);
+
+ int initAnimStruct(int index, const char *filename, int x, int y, int frameDelay, int, uint16 wsaCopyParams);
+ int freeAnimStruct(int index);
+
+ void resetDialogueState(TIM *tim);
+
+private:
+ void update();
+ void checkSpeechProgress();
+
+ char *getTableString(int id);
+ void advanceToOpcode(int opcode);
+
+ LoLEngine *_vm;
+ Screen_LoL *_screen;
+
+ virtual int execCommand(int cmd, const uint16 *param);
+
+ typedef int (TIMInterpreter_LoL::*CommandProc)(const uint16 *);
+ struct CommandEntry {
+ CommandProc proc;
+ const char *desc;
+ };
+
+ const CommandEntry *_commands;
+ int _commandsSize;
+
+ int cmd_stopAllFuncs(const uint16 *param);
+ int cmd_setLoopIp(const uint16 *param);
+ int cmd_continueLoop(const uint16 *param);
+ int cmd_processDialogue(const uint16 *param);
+ int cmd_dialogueBox(const uint16 *param);
+};
+#endif // ENABLE_LOL
+
+} // End of namespace Kyra
+
+#endif
diff --git a/engines/kyra/script/script_v1.cpp b/engines/kyra/script/script_v1.cpp
new file mode 100644
index 0000000000..2fbd2f22f4
--- /dev/null
+++ b/engines/kyra/script/script_v1.cpp
@@ -0,0 +1,125 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/kyra_v1.h"
+#include "kyra/graphics/screen.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+int KyraEngine_v1::o1_queryGameFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_queryGameFlag(%p) (0x%X)", (const void *)script, stackPos(0));
+ return queryGameFlag(stackPos(0));
+}
+
+int KyraEngine_v1::o1_setGameFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_setGameFlag(%p) (0x%X)", (const void *)script, stackPos(0));
+ return setGameFlag(stackPos(0));
+}
+
+int KyraEngine_v1::o1_resetGameFlag(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_resetGameFlag(%p) (0x%X)", (const void *)script, stackPos(0));
+ return resetGameFlag(stackPos(0));
+}
+
+int KyraEngine_v1::o1_getRand(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_getRand(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ int min = stackPos(0);
+ int max = stackPos(1);
+ if (max < min)
+ SWAP(min, max);
+ return _rnd.getRandomNumberRng(min, max);
+}
+
+int KyraEngine_v1::o1_hideMouse(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_hideMouse(%p) ()", (const void *)script);
+ screen()->hideMouse();
+ return 0;
+}
+
+int KyraEngine_v1::o1_showMouse(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_showMouse(%p) ()", (const void *)script);
+ screen()->showMouse();
+ return 0;
+}
+
+int KyraEngine_v1::o1_setMousePos(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_setMousePos(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _system->warpMouse(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_v1::o1_setHandItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_setHandItem(%p) (%d)", (const void *)script, stackPos(0));
+ setHandItem(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_v1::o1_removeHandItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_removeHandItem(%p) ()", (const void *)script);
+ removeHandItem();
+ return 0;
+}
+
+int KyraEngine_v1::o1_getMouseState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_getMouseState(%p) ()", (const void *)script);
+ return _mouseState;
+}
+
+int KyraEngine_v1::o1_setDeathHandler(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_setDeathHandler(%p) (%d)", (const void *)script, stackPos(0));
+ _deathHandler = stackPos(0);
+ return 0;
+}
+
+int KyraEngine_v1::o1_playWanderScoreViaMap(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_playWanderScoreViaMap(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ snd_playWanderScoreViaMap(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_v1::o1_fillRect(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_fillRect(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ screen()->fillRect(stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(0));
+ return 0;
+}
+
+int KyraEngine_v1::o1_blockInWalkableRegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_blockInWalkableRegion(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ screen()->blockInRegion(stackPos(0), stackPos(1), stackPos(2) - stackPos(0) + 1, stackPos(3) - stackPos(1) + 1);
+ return 0;
+}
+
+int KyraEngine_v1::o1_blockOutWalkableRegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_blockOutWalkableRegion(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ screen()->blockOutRegion(stackPos(0), stackPos(1), stackPos(2) - stackPos(0) + 1, stackPos(3) - stackPos(1) + 1);
+ return 0;
+}
+
+int KyraEngine_v1::o1_playSoundEffect(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_playSoundEffect(%p) (%d)", (const void *)script, stackPos(0));
+ snd_playSoundEffect(stackPos(0));
+ return 0;
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/script/script_v2.cpp b/engines/kyra/script/script_v2.cpp
new file mode 100644
index 0000000000..c8168a3353
--- /dev/null
+++ b/engines/kyra/script/script_v2.cpp
@@ -0,0 +1,342 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/kyra_v2.h"
+#include "kyra/graphics/screen_v2.h"
+#include "kyra/engine/timer.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+int KyraEngine_v2::o2_getCharacterX(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_getCharacterX(%p) ()", (const void *)script);
+ return _mainCharacter.x1;
+}
+
+int KyraEngine_v2::o2_getCharacterY(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_getCharacterY(%p) ()", (const void *)script);
+ return _mainCharacter.y1;
+}
+
+int KyraEngine_v2::o2_getCharacterFacing(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_getCharacterFacing(%p) ()", (const void *)script);
+ return _mainCharacter.facing;
+}
+
+int KyraEngine_v2::o2_getCharacterScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_getCharacterScene(%p) ()", (const void *)script);
+ return _mainCharacter.sceneId;
+}
+
+int KyraEngine_v2::o2_setCharacterFacingOverwrite(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_setCharacterFacingOverwrite(%p) (%d)", (const void *)script, stackPos(0));
+ _mainCharacter.facing = stackPos(0);
+ _overwriteSceneFacing = true;
+ return 0;
+}
+
+int KyraEngine_v2::o2_trySceneChange(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_trySceneChange(%p) (%d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+
+ _unkHandleSceneChangeFlag = 1;
+ int success = inputSceneChange(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ _unkHandleSceneChangeFlag = 0;
+
+ if (success) {
+ _emc->init(script, script->dataPtr);
+ _unk4 = 0;
+ _savedMouseState = -1;
+ _unk5 = 1;
+ return 0;
+ } else {
+ return (_unk4 != 0) ? 1 : 0;
+ }
+}
+
+int KyraEngine_v2::o2_moveCharacter(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_moveCharacter(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ moveCharacter(stackPos(0), stackPos(1), stackPos(2));
+ return 0;
+}
+
+int KyraEngine_v2::o2_checkForItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_checkForItem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return findItem(stackPos(0), stackPos(1)) == -1 ? 0 : 1;
+}
+
+int KyraEngine_v2::o2_defineItem(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_defineItem(%p) (%d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ int freeItem = findFreeItem();
+
+ if (freeItem >= 0) {
+ _itemList[freeItem].id = stackPos(0);
+ _itemList[freeItem].x = stackPos(1);
+ _itemList[freeItem].y = stackPos(2);
+ _itemList[freeItem].sceneId = stackPos(3);
+ }
+
+ return freeItem;
+}
+
+int KyraEngine_v2::o2_addSpecialExit(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_addSpecialExit(%p) (%d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ if (_specialExitCount < 5) {
+ _specialExitTable[_specialExitCount + 0] = stackPos(0);
+ _specialExitTable[_specialExitCount + 5] = stackPos(1);
+ _specialExitTable[_specialExitCount + 10] = stackPos(2) + stackPos(0) - 1;
+ _specialExitTable[_specialExitCount + 15] = stackPos(3) + stackPos(1) - 1;
+ _specialExitTable[_specialExitCount + 20] = stackPos(4);
+ ++_specialExitCount;
+ }
+ return 0;
+}
+
+int KyraEngine_v2::o2_delay(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_delay(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ if (stackPos(1)) {
+ uint32 maxWaitTime = _system->getMillis() + stackPos(0) * _tickLength;
+ while (_system->getMillis() < maxWaitTime) {
+ int inputFlag = checkInput(0);
+ removeInputTop();
+
+ if (inputFlag == 198 || inputFlag == 199)
+ return 1;
+
+ if (_chatText)
+ updateWithText();
+ else
+ update();
+ _system->delayMillis(10);
+ }
+ } else {
+ delay(stackPos(0) * _tickLength, true);
+ }
+ return 0;
+}
+
+int KyraEngine_v2::o2_update(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_update(%p) (%d)", (const void *)script, stackPos(0));
+ for (int times = stackPos(0); times != 0; --times) {
+ if (_chatText)
+ updateWithText();
+ else
+ update();
+ }
+ return 0;
+}
+
+int KyraEngine_v2::o2_getShapeFlag1(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_getShapeFlag1(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return screen()->getShapeFlag1(stackPos(0), stackPos(1));
+}
+
+int KyraEngine_v2::o2_waitForConfirmationClick(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_waitForConfirmationClick(%p) (%d)", (const void *)script, stackPos(0));
+ resetSkipFlag();
+ uint32 maxWaitTime = _system->getMillis() + stackPos(0) * _tickLength;
+
+ while (_system->getMillis() < maxWaitTime) {
+ int inputFlag = checkInput(0);
+ removeInputTop();
+
+ if (inputFlag == 198 || inputFlag == 199) {
+ _sceneScriptState.regs[1] = _mouseX;
+ _sceneScriptState.regs[2] = _mouseY;
+ return 0;
+ }
+
+ update();
+ _system->delayMillis(10);
+ }
+
+ _sceneScriptState.regs[1] = _mouseX;
+ _sceneScriptState.regs[2] = _mouseY;
+ return 1;
+}
+
+int KyraEngine_v2::o2_randomSceneChat(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_randomSceneChat(%p)", (const void *)script);
+ randomSceneChat();
+ return 0;
+}
+
+int KyraEngine_v2::o2_setDlgIndex(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_setDlgIndex(%p) (%d)", (const void *)script, stackPos(0));
+ setDlgIndex(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_v2::o2_getDlgIndex(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_getDlgIndex(%p) ()", (const void *)script);
+ return _mainCharacter.dlgIndex;
+}
+
+
+int KyraEngine_v2::o2_defineRoomEntrance(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_defineRoomEntrance(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
+ switch (stackPos(0)) {
+ case 0:
+ _sceneEnterX1 = stackPos(1);
+ _sceneEnterY1 = stackPos(2);
+ break;
+
+ case 1:
+ _sceneEnterX2 = stackPos(1);
+ _sceneEnterY2 = stackPos(2);
+ break;
+
+ case 2:
+ _sceneEnterX3 = stackPos(1);
+ _sceneEnterY3 = stackPos(2);
+ break;
+
+ case 3:
+ _sceneEnterX4 = stackPos(1);
+ _sceneEnterY4 = stackPos(2);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+int KyraEngine_v2::o2_runAnimationScript(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_runAnimationScript(%p) ('%s', %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1),
+ stackPos(2), stackPos(3));
+
+ runAnimationScript(stackPosString(0), stackPos(3), stackPos(2) ? 1 : 0, stackPos(1), stackPos(2));
+ return 0;
+}
+
+int KyraEngine_v2::o2_setSpecialSceneScriptRunTime(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_setSpecialSceneScriptRunTime(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ assert(stackPos(0) >= 0 && stackPos(0) < 10);
+ _sceneSpecialScriptsTimer[stackPos(0)] = _system->getMillis() + stackPos(1) * _tickLength;
+ return 0;
+}
+
+int KyraEngine_v2::o2_defineScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_defineScene(%p) (%d, '%s', %d, %d, %d, %d, %d, %d)",
+ (const void *)script, stackPos(0), stackPosString(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ const int scene = stackPos(0);
+ strcpy(_sceneList[scene].filename1, stackPosString(1));
+ strcpy(_sceneList[scene].filename2, stackPosString(1));
+
+ _sceneList[scene].exit1 = stackPos(2);
+ _sceneList[scene].exit2 = stackPos(3);
+ _sceneList[scene].exit3 = stackPos(4);
+ _sceneList[scene].exit4 = stackPos(5);
+ _sceneList[scene].flags = stackPos(6);
+ _sceneList[scene].sound = stackPos(7);
+
+ if (_mainCharacter.sceneId == scene) {
+ _sceneExit1 = _sceneList[scene].exit1;
+ _sceneExit2 = _sceneList[scene].exit2;
+ _sceneExit3 = _sceneList[scene].exit3;
+ _sceneExit4 = _sceneList[scene].exit4;
+ }
+
+ return 0;
+}
+
+int KyraEngine_v2::o2_setSpecialSceneScriptState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_setSpecialSceneScriptState(%p) (%d)", (const void *)script, stackPos(0));
+ _specialSceneScriptState[stackPos(0)] = 1;
+ return 1;
+}
+
+int KyraEngine_v2::o2_clearSpecialSceneScriptState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_clearSpecialSceneScriptState(%p) (%d)", (const void *)script, stackPos(0));
+ _specialSceneScriptState[stackPos(0)] = 0;
+ return 0;
+}
+
+int KyraEngine_v2::o2_querySpecialSceneScriptState(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_querySpecialSceneScriptState(%p) (%d)", (const void *)script, stackPos(0));
+ return _specialSceneScriptState[stackPos(0)];
+}
+
+int KyraEngine_v2::o2_setHiddenItemsEntry(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_setHiddenItemsEntry(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ return (_hiddenItems[stackPos(0)] = stackPos(1));
+}
+
+int KyraEngine_v2::o2_getHiddenItemsEntry(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_getHiddenItemsEntry(%p) (%d)", (const void *)script, stackPos(0));
+ return (int16)_hiddenItems[stackPos(0)];
+}
+
+int KyraEngine_v2::o2_disableTimer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_disableTimer(%p) (%d)", (const void *)script, stackPos(0));
+ _timer->disable(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_v2::o2_enableTimer(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_enableTimer(%p) (%d)", (const void *)script, stackPos(0));
+ _timer->enable(stackPos(0));
+ return 0;
+}
+
+int KyraEngine_v2::o2_setTimerCountdown(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_setTimerCountdown(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ _timer->setCountdown(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int KyraEngine_v2::o2_setVocHigh(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_setVocHigh(%p) (%d)", (const void *)script, stackPos(0));
+ _vocHigh = stackPos(0);
+ return _vocHigh;
+}
+
+int KyraEngine_v2::o2_getVocHigh(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_getVocHigh(%p) ()", (const void *)script);
+ return _vocHigh;
+}
+
+#pragma mark -
+
+int KyraEngine_v2::o2a_setAnimationShapes(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2a_setAnimationShapes(%p) ('%s', %d, %d, %d, %d, %d)", (const void *)script,
+ stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ strcpy(_animShapeFilename, stackPosString(0));
+ _animShapeLastEntry = stackPos(1);
+ _animShapeWidth = stackPos(2);
+ _animShapeHeight = stackPos(3);
+ _animShapeXAdd = stackPos(4);
+ _animShapeYAdd = stackPos(5);
+ return 0;
+}
+
+int KyraEngine_v2::o2a_setResetFrame(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3t_setResetFrame(%p) (%d)", (const void *)script, stackPos(0));
+ _animResetFrame = stackPos(0);
+ return 0;
+}
+
+} // End of namespace Kyra