diff options
-rw-r--r-- | engines/kyra/kyra_v2.cpp | 35 | ||||
-rw-r--r-- | engines/kyra/kyra_v2.h | 75 | ||||
-rw-r--r-- | engines/kyra/module.mk | 2 | ||||
-rw-r--r-- | engines/kyra/script.cpp | 2 | ||||
-rw-r--r-- | engines/kyra/script_tim.cpp | 269 | ||||
-rw-r--r-- | engines/kyra/script_tim.h | 104 | ||||
-rw-r--r-- | engines/kyra/script_v2.cpp | 56 | ||||
-rw-r--r-- | engines/kyra/sequences_tim.cpp | 335 | ||||
-rw-r--r-- | engines/kyra/text_v2.cpp | 66 | ||||
-rw-r--r-- | engines/kyra/util.h | 29 |
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 + |