aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/script_tim.cpp
diff options
context:
space:
mode:
authorJohannes Schickel2008-04-19 13:52:09 +0000
committerJohannes Schickel2008-04-19 13:52:09 +0000
commitbf46b5f17868cee22aea71b274a3515593206fbd (patch)
tree2b991a7c516d8a5c04266ba011caa8ab8c650b67 /engines/kyra/script_tim.cpp
parent76b1f4bcea6a89e37087f61d672cd55b47e6f719 (diff)
downloadscummvm-rg350-bf46b5f17868cee22aea71b274a3515593206fbd.tar.gz
scummvm-rg350-bf46b5f17868cee22aea71b274a3515593206fbd.tar.bz2
scummvm-rg350-bf46b5f17868cee22aea71b274a3515593206fbd.zip
- reworked tim handling
- moved tim interpreter to new class TIMInterpreter svn-id: r31569
Diffstat (limited to 'engines/kyra/script_tim.cpp')
-rw-r--r--engines/kyra/script_tim.cpp269
1 files changed, 269 insertions, 0 deletions
diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp
new file mode 100644
index 0000000000..4454dec539
--- /dev/null
+++ b/engines/kyra/script_tim.cpp
@@ -0,0 +1,269 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "kyra/script_tim.h"
+#include "kyra/script.h"
+
+#include "common/endian.h"
+
+namespace Kyra {
+
+TIMInterpreter::TIMInterpreter(KyraEngine *vm, OSystem *system) : _vm(vm), _system(system), _currentTim(0) {
+#define COMMAND(x) { &TIMInterpreter::x, #x }
+#define COMMAND_UNIMPL() { 0, 0 }
+ static CommandEntry commandProcs[] = {
+ // 0x00
+ COMMAND(cmd_restartFunc0),
+ COMMAND(cmd_stopCurFunc),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ // 0x04
+ COMMAND(cmd_initFunc),
+ COMMAND(cmd_stopFunc),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ // 0x08
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ // 0x0C
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ // 0x10
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ // 0x14
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ COMMAND_UNIMPL(),
+ COMMAND(cmd_resetAllNextTime),
+ // 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<-1>)
+ };
+
+ _commands = commandProcs;
+ _commandsSize = ARRAYSIZE(commandProcs);
+}
+
+TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes) {
+ ScriptFileParser file(filename, _vm->resource());
+ if (!file)
+ error("Couldn't open TIM file '%s'", filename);
+
+ uint32 formBlockSize = file.getFORMBlockSize();
+ if (formBlockSize == 0xFFFFFFFF) {
+ warning("No FORM chunk found in TIM file '%s'", filename);
+ return 0;
+ }
+
+ if (formBlockSize < 20) {
+ warning("TIM file '%s' FORM chunk size smaller than 20", filename);
+ return 0;
+ }
+
+ TIM *tim = new TIM;
+ assert(tim);
+ memset(tim, 0, sizeof(TIM));
+
+ tim->procFunc = -1;
+ tim->opcodes = opcodes;
+
+ uint32 avtlChunkSize = file.getIFFBlockSize(AVTL_CHUNK);
+ uint32 textChunkSize = file.getIFFBlockSize(TEXT_CHUNK);
+
+ tim->avtl = new uint16[avtlChunkSize/2];
+ if (textChunkSize != 0xFFFFFFFF)
+ tim->text = new byte[textChunkSize];
+
+ if (!file.loadIFFBlock(AVTL_CHUNK, tim->avtl, avtlChunkSize))
+ error("Couldn't read AVTL chunk in TIM file '%s'", filename);
+ if (textChunkSize != 0xFFFFFFFF && !file.loadIFFBlock(TEXT_CHUNK, tim->text, textChunkSize))
+ error("Couldn't read TEXT chunk in TIM file '%s'", filename);
+
+ avtlChunkSize >>= 1;
+ for (uint i = 0; i < avtlChunkSize; ++i)
+ tim->avtl[i] = READ_LE_UINT16(tim->avtl + i);
+
+ for (int i = 0; i < 10; ++i)
+ tim->func[i].avtl = tim->avtl + tim->avtl[i];
+
+ return tim;
+}
+
+void TIMInterpreter::unload(TIM *&tim) const {
+ if (!tim)
+ return;
+
+ delete [] tim->text;
+ delete [] tim->avtl;
+ delete tim;
+ tim = 0;
+}
+
+void TIMInterpreter::exec(TIM *tim, bool loop) {
+ if (!tim)
+ return;
+
+ _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 {
+ for (_currentFunc = 0; _currentFunc < 10; ++_currentFunc) {
+ TIM::Function &cur = _currentTim->func[_currentFunc];
+
+ if (_currentTim->procFunc != -1)
+ execCommand(28, &_currentTim->unkFlag);
+
+ bool running = true;
+ while (cur.ip && cur.nextTime <= _system->getMillis() && running) {
+ 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;
+ break;
+
+ default:
+ break;
+ }
+
+ if (cur.ip) {
+ cur.ip += cur.ip[0];
+ cur.lastTime = cur.nextTime;
+ cur.nextTime += cur.ip[1] * _vm->tickLength();
+ }
+ }
+ }
+ } while (loop);
+}
+
+int TIMInterpreter::execCommand(int cmd, const uint16 *param) {
+ if (cmd < 0 || cmd >= _commandsSize) {
+ warning("Calling unimplemented TIM command %d", cmd);
+ return 0;
+ }
+
+ if (_commands[cmd].proc == 0) {
+ warning("Calling unimplemented TIM command %d", cmd);
+ return 0;
+ }
+
+ debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void*)param);
+ return (this->*_commands[cmd].proc)(param);
+}
+
+int TIMInterpreter::cmd_restartFunc0(const uint16 *param) {
+ _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 < 10)
+ _currentTim->func[_currentFunc].ip = 0;
+ if (!_currentFunc)
+ _finished = true;
+ return -2;
+}
+
+int TIMInterpreter::cmd_initFunc(const uint16 *param) {
+ uint16 func = *param;
+ 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;
+ _currentTim->func[func].ip = 0;
+ return 1;
+}
+
+int TIMInterpreter::cmd_resetAllNextTime(const uint16 *param) {
+ for (int i = 0; i < 10; ++i) {
+ if (_currentTim->func[i].ip)
+ _currentTim->func[i].nextTime = _system->getMillis();
+ }
+ return 1;
+}
+
+int TIMInterpreter::cmd_execOpcode(const uint16 *param) {
+ if (!_currentTim->opcodes) {
+ warning("Trying to execute TIM opcode without opcode list");
+ return 0;
+ }
+
+ uint16 opcode = *param++;
+ if (opcode > _currentTim->opcodes->size()) {
+ warning("calling unimplemented opcode(0x%.02X/%d)", opcode, opcode);
+ return 0;
+ }
+
+ return (*(*_currentTim->opcodes)[opcode])(_currentTim, param);
+}
+
+int TIMInterpreter::cmd_initFuncNow(const uint16 *param) {
+ uint16 func = *param;
+ _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;
+ _currentTim->func[func].ip = 0;
+ _currentTim->func[func].lastTime = _currentTim->func[func].nextTime = _system->getMillis();
+ return 1;
+}
+
+} // end of namespace Kyra
+