aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/kyra/kyra_v2.cpp35
-rw-r--r--engines/kyra/kyra_v2.h75
-rw-r--r--engines/kyra/module.mk2
-rw-r--r--engines/kyra/script.cpp2
-rw-r--r--engines/kyra/script_tim.cpp269
-rw-r--r--engines/kyra/script_tim.h104
-rw-r--r--engines/kyra/script_v2.cpp56
-rw-r--r--engines/kyra/sequences_tim.cpp335
-rw-r--r--engines/kyra/text_v2.cpp66
-rw-r--r--engines/kyra/util.h29
10 files changed, 527 insertions, 446 deletions
diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp
index 78c9573d5a..8f48e2896e 100644
--- a/engines/kyra/kyra_v2.cpp
+++ b/engines/kyra/kyra_v2.cpp
@@ -30,6 +30,7 @@
#include "kyra/wsamovie.h"
#include "kyra/sound.h"
#include "kyra/script.h"
+#include "kyra/script_tim.h"
#include "kyra/text_v2.h"
#include "kyra/timer.h"
#include "kyra/debugger.h"
@@ -87,12 +88,9 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags) : KyraEngi
_chatObject = -1;
_lastIdleScript = -1;
- _timChatText = 0;
- _timChatObject = -1;
-
- _currentTalkSections.STATim = NULL;
- _currentTalkSections.TLKTim = NULL;
- _currentTalkSections.ENDTim = NULL;
+ _currentTalkSections.STATim = 0;
+ _currentTalkSections.TLKTim = 0;
+ _currentTalkSections.ENDTim = 0;
memset(&_invWsa, 0, sizeof(_invWsa));
_itemAnimData = 0;
@@ -159,6 +157,7 @@ KyraEngine_v2::~KyraEngine_v2() {
delete _screen;
delete _text;
delete _gui;
+ delete _tim;
_text = 0;
delete _debugger;
delete _invWsa.wsa;
@@ -196,6 +195,8 @@ int KyraEngine_v2::init() {
assert(_text);
_gui = new GUI_v2(this);
assert(_gui);
+ _tim = new TIMInterpreter(this, _system);
+ assert(_tim);
if (_flags.isDemo && !_flags.isTalkie) {
_screen->loadFont(_screen->FID_8_FNT, "FONT9P.FNT");
@@ -223,8 +224,6 @@ int KyraEngine_v2::init() {
if (_flags.isDemo && !_flags.isTalkie)
return 0;
- tim_setupOpcodes();
-
_mouseSHPBuf = _res->fileData("PWGMOUSE.SHP", 0);
assert(_mouseSHPBuf);
@@ -2252,6 +2251,26 @@ void KyraEngine_v2::dinoRide() {
#pragma mark -
+void KyraEngine_v2::playTim(const char *filename) {
+ TIM *tim = _tim->load(filename, &_timOpcodes);
+ if (!tim)
+ return;
+
+ _tim->resetFinishedFlag();
+ while (!_quitFlag && !_tim->finished()) {
+ _tim->exec(tim, 0);
+ if (_chatText)
+ updateWithText();
+ else
+ update();
+ delay(10);
+ }
+
+ _tim->unload(tim);
+}
+
+#pragma mark -
+
void KyraEngine_v2::registerDefaultSettings() {
KyraEngine::registerDefaultSettings();
diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h
index 371c76af3c..10953a71a3 100644
--- a/engines/kyra/kyra_v2.h
+++ b/engines/kyra/kyra_v2.h
@@ -31,6 +31,7 @@
#include "kyra/screen_v2.h"
#include "kyra/text_v2.h"
#include "kyra/gui_v2.h"
+#include "kyra/util.h"
#include "common/list.h"
@@ -98,8 +99,11 @@ enum kNestedSequencesDemo {
class WSAMovieV2;
class KyraEngine_v2;
class TextDisplayer_v2;
+class TIMInterpreter;
class Debugger_v2;
+struct TIM;
+
typedef int (KyraEngine_v2::*SeqProc)(WSAMovieV2*, int, int, int);
struct FrameControl {
@@ -286,6 +290,7 @@ protected:
Screen_v2 *_screen;
TextDisplayer_v2 *_text;
Debugger_v2 *_debugger;
+ TIMInterpreter *_tim;
uint8 *_mouseSHPBuf;
@@ -809,73 +814,23 @@ protected:
TalkObject *_talkObjectList;
struct TalkSections {
- uint8 *STATim;
- uint8 *TLKTim;
- uint8 *ENDTim;
+ TIM *STATim;
+ TIM *TLKTim;
+ TIM *ENDTim;
};
TalkSections _currentTalkSections;
char _TLKFilename[13];
- bool _objectChatFinished;
-
- // tim sequence
- void tim_setupOpcodes();
- uint8 *tim_loadFile(const char *filename, uint8 *buffer, int32 bufferSize);
- void tim_releaseBuffer(uint8 *buffer);
- void tim_processSequence(uint8 *timBuffer, int loop);
- void tim_playFullSequence(const char *filename);
-
- int tim_o_dummy_r0(uint8 *ptr);
- int tim_o_dummy_r1(uint8 *ptr);
- int tim_o_clearCmds2(uint8 *ptr);
- int tim_o_abort(uint8 *ptr);
- int tim_o_selectcurrentCommandSet(uint8 *ptr);
- int tim_o_deleteBuffer(uint8 *ptr);
- int tim_o_refreshTimers(uint8 *ptr);
- int tim_o_execSubOpcode(uint8 *ptr);
- int tim_o_initActiveSub(uint8 *ptr);
- int tim_o_resetActiveSub(uint8 *ptr);
- int tim_o_printTalkText(uint8 *ptr);
- int tim_o_updateSceneAnim(uint8 *ptr);
- int tim_o_resetChat(uint8 *ptr);
- int tim_o_playSoundEffect(uint8 *ptr);
-
- typedef int (KyraEngine_v2::*TimOpc)(uint8 *ptr);
- const TimOpc * _timOpcodes;
-
- struct TIMHeader {
- uint16 deleteBufferFlag;
- int16 unkFlag;
- int16 unkFlag2;
- int16 cmdsOffset;
- int16 unkOffset2;
- int16 AVTLOffset;
- int16 TEXTOffset;
- };
- struct Cmds {
- uint8 *dataPtr;
- uint32 unk_2;
- uint32 timer1;
- uint32 timer2;
- uint8 *backupPtr;
- uint8 *AVTLSubChunk;
- };
+ // tim
+ void playTim(const char *filename);
- struct TIMBuffers {
- uint8 *AVTLChunk;
- uint8 *TEXTChunk;
- uint8 *offsUnkFlag2;
- uint8 *offsUnkFlag;
- int16 currentEntry;
- int16 unk_12;
- Cmds *currentCommandSet;
- uint8 *unkCmds;
- };
- TIMBuffers _TIMBuffers;
+ int t2_initChat(const TIM *tim, const uint16 *param);
+ int t2_updateSceneAnim(const TIM *tim, const uint16 *param);
+ int t2_resetChat(const TIM *tim, const uint16 *param);
+ int t2_playSoundEffect(const TIM *tim, const uint16 *param);
- const char *_timChatText;
- int _timChatObject;
+ Common::Array<const TIMOpcode*> _timOpcodes;
// sound
int _oldTalkFile;
diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk
index f419137865..fd6bb9deef 100644
--- a/engines/kyra/module.mk
+++ b/engines/kyra/module.mk
@@ -32,8 +32,8 @@ MODULE_OBJS := \
script_v2.o \
script_v3.o \
script.o \
+ script_tim.o \
seqplayer.o \
- sequences_tim.o \
sequences_v1.o \
sequences_v2.o \
sound_adlib.o \
diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp
index 02a44f7791..169c84f763 100644
--- a/engines/kyra/script.cpp
+++ b/engines/kyra/script.cpp
@@ -207,7 +207,7 @@ bool ScriptHelper::runScript(ScriptState *script) {
if (opcode > 18) {
error("Script unknown command: %d", opcode);
} else {
- debugC(5, kDebugLevelScript, "[0x%.08X] %s([%d/%u])", instOffset, _commands[opcode].desc, _parameter, (uint)_parameter);
+ debugC(5, kDebugLevelScript, "[0x%.08X] ScriptHelper::%s([%d/%u])", instOffset, _commands[opcode].desc, _parameter, (uint)_parameter);
(this->*(_commands[opcode].proc))(script);
}
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
+
diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h
new file mode 100644
index 0000000000..da5ba74831
--- /dev/null
+++ b/engines/kyra/script_tim.h
@@ -0,0 +1,104 @@
+/* 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$
+ *
+ */
+
+#ifndef KYRA_SCRIPT_TIM_H
+#define KYRA_SCRIPT_TIM_H
+
+#include "kyra/kyra.h"
+#include "kyra/util.h"
+
+#include "common/array.h"
+
+namespace Kyra {
+
+struct TIM {
+ int16 procFunc;
+ uint16 unkFlag;
+
+ struct Function {
+ const uint16 *ip;
+
+ uint32 lastTime;
+ uint32 nextTime;
+
+ const uint16 *avtl;
+ } func[10];
+
+ uint16 *avtl;
+ uint8 *text;
+
+ const Common::Array<const TIMOpcode*> *opcodes;
+};
+
+class TIMInterpreter {
+public:
+ TIMInterpreter(KyraEngine *vm, OSystem *system);
+
+ TIM *load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes);
+ void unload(TIM *&tim) const;
+
+ void resetFinishedFlag() { _finished = false; }
+ bool finished() const { return _finished; }
+
+ void exec(TIM *tim, bool loop);
+ void stopCurFunc() { if (_currentTim) cmd_stopCurFunc(0); }
+
+ void play(const char *filename);
+private:
+ KyraEngine *_vm;
+ OSystem *_system;
+
+ TIM *_currentTim;
+ int _currentFunc;
+
+ bool _finished;
+
+ 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_restartFunc0(const uint16 *param);
+ int cmd_stopCurFunc(const uint16 *param);
+ int cmd_initFunc(const uint16 *param);
+ int cmd_stopFunc(const uint16 *param);
+ int cmd_resetAllNextTime(const uint16 *param);
+ int cmd_execOpcode(const uint16 *param);
+ int cmd_initFuncNow(const uint16 *param);
+ int cmd_stopFuncNow(const uint16 *param);
+ template<int T>
+ int cmd_return(const uint16 *) { return T; }
+};
+
+} // end of namespace Kyra
+
+#endif
+
diff --git a/engines/kyra/script_v2.cpp b/engines/kyra/script_v2.cpp
index 00a66ec238..13e3f02c3e 100644
--- a/engines/kyra/script_v2.cpp
+++ b/engines/kyra/script_v2.cpp
@@ -28,6 +28,7 @@
#include "kyra/wsamovie.h"
#include "kyra/sound.h"
#include "kyra/timer.h"
+#include "kyra/script_tim.h"
#include "common/endian.h"
@@ -1426,7 +1427,7 @@ int KyraEngine_v2::o2_deinitObject(ScriptState *script) {
int KyraEngine_v2::o2_playTimSequence(ScriptState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_playTimSequence(%p) ('%s')", (const void *)script, stackPosString(0));
- tim_playFullSequence(stackPosString(0));
+ playTim(stackPosString(0));
return 0;
}
@@ -1833,9 +1834,52 @@ int KyraEngine_v2::o2t_setShapeFlag(ScriptState *script) {
#pragma mark -
+int KyraEngine_v2::t2_initChat(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::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_v2::t2_updateSceneAnim(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::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_v2::t2_resetChat(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::t2_resetChat(%p, %p) ()", (const void*)tim, (const void*)param);
+ _text->restoreScreen();
+ _chatText = 0;
+ _chatObject = -1;
+ return 0;
+}
+
+int KyraEngine_v2::t2_playSoundEffect(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::t2_playSoundEffect(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]);
+ snd_playSoundEffect(*param);
+ return 0;
+}
+
+#pragma mark -
+
typedef Functor1Mem<ScriptState*, int, KyraEngine_v2> OpcodeV2;
#define Opcode(x) OpcodeV2(this, &KyraEngine_v2::x)
#define OpcodeUnImpl() OpcodeV2(this, 0)
+
+typedef Functor2Mem<const TIM*, const uint16*, int, KyraEngine_v2> TIMOpcodeV2;
+#define OpcodeTim(x) TIMOpcodeV2(this, &KyraEngine_v2::x)
+#define OpcodeTimUnImpl() TIMOpcodeV2(this, 0)
+
void KyraEngine_v2::setupOpcodeTable() {
static const OpcodeV2 opcodeTable[] = {
// 0x00
@@ -2075,6 +2119,16 @@ void KyraEngine_v2::setupOpcodeTable() {
for (int i = 0; i < ARRAYSIZE(opcodeTemporaryTable); ++i)
_opcodesTemporary.push_back(&opcodeTemporaryTable[i]);
+
+ static const TIMOpcodeV2 timOpcodeTable[] = {
+ OpcodeTim(t2_initChat),
+ OpcodeTim(t2_updateSceneAnim),
+ OpcodeTim(t2_resetChat),
+ OpcodeTim(t2_playSoundEffect)
+ };
+
+ for (int i = 0; i < ARRAYSIZE(timOpcodeTable); ++i)
+ _timOpcodes.push_back(&timOpcodeTable[i]);
}
} // end of namespace Kyra
diff --git a/engines/kyra/sequences_tim.cpp b/engines/kyra/sequences_tim.cpp
deleted file mode 100644
index f403dfcfc3..0000000000
--- a/engines/kyra/sequences_tim.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/* 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/text_v2.h"
-#include "kyra/kyra_v2.h"
-#include "kyra/sound.h"
-#include "kyra/resource.h"
-
-#include "common/endian.h"
-
-namespace Kyra {
-
-uint8 *KyraEngine_v2::tim_loadFile(const char *filename, byte *buffer, int32 bufferSize) {
- ScriptFileParser file(filename, _res);
- if (!file) {
- error("Couldn't open script file '%s'", filename);
- return NULL;
- }
-
- int32 formBlockSize = file.getFORMBlockSize();
- if (formBlockSize == -1) {
- error("No FORM chunk found in file: '%s'", filename);
- return NULL;
- }
-
- if (formBlockSize < 20) {
- return NULL;
- }
-
- formBlockSize += sizeof(TIMHeader) + 10 * (sizeof(Cmds) + 120);
-
- TIMHeader *timHeader;
- if (buffer == NULL || bufferSize < formBlockSize) {
- buffer = new byte[formBlockSize];
- timHeader = (TIMHeader *)buffer;
- timHeader->deleteBufferFlag = 0xBABE;
- } else {
- timHeader = (TIMHeader *)buffer;
- timHeader->deleteBufferFlag = 0x0;
- }
-
- int32 chunkSize = file.getIFFBlockSize(AVTL_CHUNK);
- timHeader->unkFlag = -1;
- timHeader->unkFlag2 = 0;
- timHeader->cmdsOffset = sizeof(TIMHeader);
- timHeader->unkOffset2 = timHeader->cmdsOffset + 10 * sizeof(Cmds);
- timHeader->AVTLOffset = timHeader->unkOffset2 + 120;
- timHeader->TEXTOffset = timHeader->AVTLOffset + chunkSize;
-
- _TIMBuffers.AVTLChunk = buffer + timHeader->AVTLOffset;
- _TIMBuffers.TEXTChunk = buffer + timHeader->TEXTOffset;
-
- if (!file.loadIFFBlock(AVTL_CHUNK, _TIMBuffers.AVTLChunk, chunkSize)) {
- error("Couldn't load AVTL chunk from file: '%s'", filename);
- return NULL;
- }
-
- _TIMBuffers.currentCommandSet = (Cmds *)(buffer + timHeader->cmdsOffset);
-
- for (int i = 0; i < 10; i++) {
- _TIMBuffers.currentCommandSet[i].dataPtr = 0;
- _TIMBuffers.currentCommandSet[i].unk_2 = 0;
- _TIMBuffers.currentCommandSet[i].AVTLSubChunk = &_TIMBuffers.AVTLChunk[READ_LE_UINT16(&_TIMBuffers.AVTLChunk[i << 1]) << 1];
- _TIMBuffers.currentCommandSet[i].timer1 = 0;
- _TIMBuffers.currentCommandSet[i].timer2 = 0;
- }
-
- chunkSize = file.getIFFBlockSize(TEXT_CHUNK);
- if (chunkSize > 0) {
- if (!file.loadIFFBlock(TEXT_CHUNK, _TIMBuffers.TEXTChunk, chunkSize)) {
- error("Couldn't load TEXT chunk from file: '%s'", filename);
- return NULL;
- }
- }
-
- return buffer;
-}
-
-void KyraEngine_v2::tim_releaseBuffer(byte *buffer) {
- TIMHeader *timHeader = (TIMHeader *)buffer;
- if (timHeader->deleteBufferFlag == 0xBABE)
- delete[] buffer;
-}
-
-void KyraEngine_v2::tim_processSequence(uint8 *timBuffer, int loop) {
- if (!timBuffer)
- return;
-
- TIMHeader *hdr = (TIMHeader*) timBuffer;
- _TIMBuffers.offsUnkFlag = (uint8*) &hdr->unkFlag;
- _TIMBuffers.offsUnkFlag2 = (uint8*) &hdr->unkFlag2;
- _TIMBuffers.currentCommandSet = (Cmds*) (timBuffer + hdr->cmdsOffset);
- _TIMBuffers.unkCmds = timBuffer + hdr->unkOffset2;
- _TIMBuffers.AVTLChunk = timBuffer + hdr->AVTLOffset;
- _TIMBuffers.TEXTChunk = timBuffer + hdr->TEXTOffset;
-
- if (!_TIMBuffers.currentCommandSet->dataPtr) {
- _TIMBuffers.currentCommandSet->dataPtr = _TIMBuffers.currentCommandSet->AVTLSubChunk;
- _TIMBuffers.currentCommandSet->timer1 = _system->getMillis();
- _TIMBuffers.currentCommandSet->timer2 = _system->getMillis();
- }
-
- do {
- _TIMBuffers.currentEntry = 0;
-
- while (_TIMBuffers.currentEntry < 10) {
- Cmds *s = &_TIMBuffers.currentCommandSet[_TIMBuffers.currentEntry];
- if ((int16)READ_LE_UINT16(_TIMBuffers.offsUnkFlag) != -1)
- (this->*_timOpcodes[28])(_TIMBuffers.offsUnkFlag2);
-
- bool running = true;
-
- while (s->dataPtr && s->timer2 <= _system->getMillis() && running) {
- uint8 cmd = s->dataPtr[4];
- hdr->unkFlag2 = cmd;
- uint8 *para = &s->dataPtr[6];
-
- switch((this->*_timOpcodes[cmd])(para)) {
- case -3:
- WRITE_LE_UINT16(_TIMBuffers.offsUnkFlag, _TIMBuffers.currentEntry);
- _TIMBuffers.unk_12 = -1;
- break;
-
- case -2:
- running = false;
- break;
-
- case -1:
- loop = 0;
- running = false;
- _TIMBuffers.currentEntry = 11;
- break;
-
- case 22:
- s->backupPtr = 0;
- break;
-
- default:
- break;
- }
-
- if (s) {
- if (s->dataPtr) {
- s->dataPtr += (READ_LE_UINT16(s->dataPtr) * 2);
- s->timer1 = s->timer2;
- s->timer2 += (READ_LE_UINT16(s->dataPtr + 2) * _tickLength);
- }
- }
- }
-
- _TIMBuffers.currentEntry++;
- }
- } while (loop);
-
-}
-
-void KyraEngine_v2::tim_playFullSequence(const char *filename) {
- uint8 *ptr = tim_loadFile(filename, 0, 0);
- if (!ptr)
- return;
-
- _objectChatFinished = 0;
-
- while (ptr && !_objectChatFinished) {
- if (ptr)
- tim_processSequence(ptr, 0);
- if (_timChatText)
- updateWithText();
- else
- update();
- }
-
- if (ptr)
- tim_releaseBuffer(ptr);
-}
-
-int KyraEngine_v2::tim_o_dummy_r0(uint8 *ptr) {
- return 0;
-}
-
-int KyraEngine_v2::tim_o_dummy_r1(uint8 *ptr) {
- return 1;
-}
-
-int KyraEngine_v2::tim_o_clearCmds2(uint8 *ptr) {
- for (int i = 1; i < 10; i++)
- memset(&_TIMBuffers.unkCmds[i], 0, 12);
- _TIMBuffers.currentCommandSet[0].dataPtr = _TIMBuffers.currentCommandSet[0].AVTLSubChunk;
- _TIMBuffers.currentCommandSet[0].timer1 = _system->getMillis();
- return 1;
-}
-
-int KyraEngine_v2::tim_o_abort(uint8 *ptr) {
- _TIMBuffers.currentCommandSet[_TIMBuffers.currentEntry].dataPtr = 0;
- if(!_TIMBuffers.currentEntry)
- _objectChatFinished = true;
- return -2;
-}
-
-
-int KyraEngine_v2::tim_o_selectcurrentCommandSet(uint8 *ptr) {
- _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].dataPtr = _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].AVTLSubChunk ?
- _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].AVTLSubChunk : &_TIMBuffers.AVTLChunk[_TIMBuffers.AVTLChunk[READ_LE_UINT16(ptr) << 1] << 1];
- return 1;
-}
-
-int KyraEngine_v2::tim_o_deleteBuffer(uint8 *ptr) {
- _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].dataPtr = 0;
- return 1;
-}
-
-int KyraEngine_v2::tim_o_refreshTimers(uint8 *ptr) {
- for (int i = 1; i < 10; i++) {
- if (_TIMBuffers.currentCommandSet[i].dataPtr)
- _TIMBuffers.currentCommandSet[i].timer2 = _system->getMillis();
- }
-
- return 1;
-}
-
-int KyraEngine_v2::tim_o_execSubOpcode(uint8 *ptr) {
- return (this->*_timOpcodes[30 + READ_LE_UINT16(ptr)])(ptr + 2);
-}
-
-int KyraEngine_v2::tim_o_initActiveSub(uint8 *ptr) {
- _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].dataPtr = _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].AVTLSubChunk;
- _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].timer1 = _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].timer2 = _system->getMillis();
- return 1;
-}
-
-int KyraEngine_v2::tim_o_resetActiveSub(uint8 *ptr) {
- _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].dataPtr = 0;
- _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].timer2 = 0;
- _TIMBuffers.currentCommandSet[READ_LE_UINT16(ptr)].timer1 = 0;
- return 1;
-}
-
-int KyraEngine_v2::tim_o_printTalkText(uint8 *ptr) {
- _chatText = _timChatText = (const char*) _TIMBuffers.TEXTChunk + READ_LE_UINT16(_TIMBuffers.TEXTChunk + (READ_LE_UINT16(ptr) << 1));
- _chatObject = _timChatObject = READ_LE_UINT16(ptr + 2);
-
- if (_flags.lang == Common::JA_JPN) {
- for (int i = 0; i < _ingameTimJpStrSize; i += 2) {
- if (!scumm_stricmp(_timChatText, _ingameTimJpStr[i]))
- _chatText = _ingameTimJpStr[i + 1];
- }
- }
- objectChatInit(_chatText, _timChatObject);
- return 0;
-}
-
-int KyraEngine_v2::tim_o_updateSceneAnim(uint8 *ptr) {
- updateSceneAnim(READ_LE_UINT16(ptr + 2), READ_LE_UINT16(ptr));
- return 0;
-}
-
-int KyraEngine_v2::tim_o_resetChat(uint8 *ptr) {
- _text->restoreScreen();
- _chatText = 0;
- _chatObject = -1;
- _timChatText = 0;
- _timChatObject = -1;
- return 0;
-}
-
-int KyraEngine_v2::tim_o_playSoundEffect(uint8 *ptr) {
- snd_playSoundEffect(READ_LE_UINT16(ptr));
- return 0;
-}
-
-void KyraEngine_v2::tim_setupOpcodes() {
- static const TimOpc Opcodes[] = {
- &KyraEngine_v2::tim_o_clearCmds2,
- &KyraEngine_v2::tim_o_abort,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_selectcurrentCommandSet,
- &KyraEngine_v2::tim_o_deleteBuffer,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_dummy_r0,
- &KyraEngine_v2::tim_o_refreshTimers,
- &KyraEngine_v2::tim_o_dummy_r1,
- &KyraEngine_v2::tim_o_execSubOpcode,
- &KyraEngine_v2::tim_o_initActiveSub,
- &KyraEngine_v2::tim_o_resetActiveSub,
- &KyraEngine_v2::tim_o_dummy_r1,
- &KyraEngine_v2::tim_o_dummy_r1,
- &KyraEngine_v2::tim_o_printTalkText,
- &KyraEngine_v2::tim_o_updateSceneAnim,
- &KyraEngine_v2::tim_o_resetChat,
- &KyraEngine_v2::tim_o_playSoundEffect,
- };
-
- _timOpcodes = (const TimOpc*) Opcodes;
-}
-
-} // end of namespace Kyra
-
diff --git a/engines/kyra/text_v2.cpp b/engines/kyra/text_v2.cpp
index 0e5470a118..c857a806e3 100644
--- a/engines/kyra/text_v2.cpp
+++ b/engines/kyra/text_v2.cpp
@@ -25,6 +25,7 @@
#include "kyra/text_v2.h"
#include "kyra/kyra_v2.h"
+#include "kyra/script_tim.h"
#include "kyra/resource.h"
#include "common/endian.h"
@@ -574,13 +575,13 @@ void KyraEngine_v2::initTalkObject(int index) {
strcpy(_TLKFilename, object.filename);
strcpy(ENDFilename, object.filename);
- strcpy(STAFilename + 4, "_STA.TIM");
- strcpy(_TLKFilename + 4, "_TLK.TIM");
- strcpy(ENDFilename + 4, "_END.TIM");
+ strcat(STAFilename + 4, "_STA.TIM");
+ strcat(_TLKFilename + 4, "_TLK.TIM");
+ strcat(ENDFilename + 4, "_END.TIM");
- _currentTalkSections.STATim = tim_loadFile(STAFilename, NULL, 0);
- _currentTalkSections.TLKTim = tim_loadFile(_TLKFilename, NULL, 0);
- _currentTalkSections.ENDTim = tim_loadFile(ENDFilename, NULL, 0);
+ _currentTalkSections.STATim = _tim->load(STAFilename, &_timOpcodes);
+ _currentTalkSections.TLKTim = _tim->load(_TLKFilename, &_timOpcodes);
+ _currentTalkSections.ENDTim = _tim->load(ENDFilename, &_timOpcodes);
if (object.scriptId != -1) {
_specialSceneScriptStateBackup[object.scriptId] = _specialSceneScriptState[object.scriptId];
@@ -588,13 +589,14 @@ void KyraEngine_v2::initTalkObject(int index) {
}
if (_currentTalkSections.STATim) {
- _objectChatFinished = false;
- while (!_objectChatFinished) {
- tim_processSequence(_currentTalkSections.STATim, 0);
+ _tim->resetFinishedFlag();
+ while (!_quitFlag && !_tim->finished()) {
+ _tim->exec(_currentTalkSections.STATim, false);
if (_chatText)
updateWithText();
else
update();
+ delay(10);
}
}
}
@@ -603,34 +605,23 @@ void KyraEngine_v2::deinitTalkObject(int index) {
TalkObject &object = _talkObjectList[index];
if (_currentTalkSections.ENDTim) {
- _objectChatFinished = false;
- while (!_objectChatFinished) {
- tim_processSequence(_currentTalkSections.ENDTim, 0);
+ _tim->resetFinishedFlag();
+ while (!_quitFlag && !_tim->finished()) {
+ _tim->exec(_currentTalkSections.ENDTim, false);
if (_chatText)
updateWithText();
else
update();
+ delay(10);
}
}
- if (object.scriptId != -1) {
+ if (object.scriptId != -1)
_specialSceneScriptState[object.scriptId] = _specialSceneScriptStateBackup[object.scriptId];
- }
-
- if (_currentTalkSections.STATim != NULL) {
- tim_releaseBuffer(_currentTalkSections.STATim);
- _currentTalkSections.STATim = NULL;
- }
- if (_currentTalkSections.TLKTim != NULL) {
- tim_releaseBuffer(_currentTalkSections.TLKTim);
- _currentTalkSections.TLKTim = NULL;
- }
-
- if (_currentTalkSections.ENDTim != NULL) {
- tim_releaseBuffer(_currentTalkSections.ENDTim);
- _currentTalkSections.ENDTim = NULL;
- }
+ _tim->unload(_currentTalkSections.STATim);
+ _tim->unload(_currentTalkSections.TLKTim);
+ _tim->unload(_currentTalkSections.ENDTim);
}
void KyraEngine_v2::npcChatSequence(const char *str, int objectId, int vocHigh, int vocLow) {
@@ -639,7 +630,7 @@ void KyraEngine_v2::npcChatSequence(const char *str, int objectId, int vocHigh,
objectChatInit(str, objectId, vocHigh, vocLow);
if (!_currentTalkSections.TLKTim)
- _currentTalkSections.TLKTim = tim_loadFile(_TLKFilename, 0, 0);
+ _currentTalkSections.TLKTim = _tim->load(_TLKFilename, &_timOpcodes);
setNextIdleAnimTimer();
@@ -655,29 +646,26 @@ void KyraEngine_v2::npcChatSequence(const char *str, int objectId, int vocHigh,
while (((textEnabled() && _chatEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) && !(_quitFlag || skipFlag())) {
if (!speechEnabled() && chatAnimEndTime > _system->getMillis() || speechEnabled() && snd_voiceIsPlaying()) {
- _objectChatFinished = false;
-
- while (!_objectChatFinished && !skipFlag()) {
+ _tim->resetFinishedFlag();
+ while (!_tim->finished() && !skipFlag() && !_quitFlag) {
if (_currentTalkSections.TLKTim)
- tim_processSequence(_currentTalkSections.TLKTim, 0);
+ _tim->exec(_currentTalkSections.TLKTim, false);
else
- _objectChatFinished = false;
+ _tim->resetFinishedFlag();
updateWithText();
delay(10);
}
+
if (_currentTalkSections.TLKTim)
- tim_o_abort(0);
+ _tim->stopCurFunc();
}
updateWithText();
}
resetSkipFlag();
- if (_currentTalkSections.TLKTim) {
- tim_releaseBuffer(_currentTalkSections.TLKTim);
- _currentTalkSections.TLKTim = 0;
- }
+ _tim->unload(_currentTalkSections.TLKTim);
_text->restoreScreen();
_chatText = 0;
diff --git a/engines/kyra/util.h b/engines/kyra/util.h
index 1c4b8462cc..78925441f3 100644
--- a/engines/kyra/util.h
+++ b/engines/kyra/util.h
@@ -78,10 +78,37 @@ private:
Res (T::*_func)(Arg);
};
-struct ScriptState;
+template<class Arg1, class Arg2, class Res>
+struct Functor2 : public Common::BinaryFunction<Arg1, Arg2, Res> {
+ virtual ~Functor2() {}
+
+ virtual bool isValid() const = 0;
+ virtual Res operator()(Arg1, Arg2) const = 0;
+};
+
+template<class Arg1, class Arg2, class Res, class T>
+class Functor2Mem : public Functor2<Arg1, Arg2, Res> {
+public:
+ typedef Res (T::*FuncType)(Arg1, Arg2);
+
+ Functor2Mem(T *t, const FuncType &func) : _t(t), _func(func) {}
+
+ bool isValid() const { return _func != 0; }
+ Res operator()(Arg1 v1, Arg2 v2) const {
+ return (_t->*_func)(v1, v2);
+ }
+private:
+ mutable T *_t;
+ Res (T::*_func)(Arg1, Arg2);
+};
+struct ScriptState;
typedef Functor1<ScriptState*, int> Opcode;
+struct TIM;
+typedef Functor2<const TIM*, const uint16*, int> TIMOpcode;
+
} // end of namespace Kyra
#endif
+