diff options
author | Johannes Schickel | 2008-04-19 13:52:09 +0000 |
---|---|---|
committer | Johannes Schickel | 2008-04-19 13:52:09 +0000 |
commit | bf46b5f17868cee22aea71b274a3515593206fbd (patch) | |
tree | 2b991a7c516d8a5c04266ba011caa8ab8c650b67 /engines/kyra/script_tim.cpp | |
parent | 76b1f4bcea6a89e37087f61d672cd55b47e6f719 (diff) | |
download | scummvm-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.cpp | 269 |
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 + |