From 753536fa61119a20a5e0d0e9b00790593cd5190e Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 17 Feb 2008 02:06:04 +0000 Subject: committing patch 1891492 : dialogue (dlg/tim) support for HoF - talking to NPCs is now possible. - Zanthia's talks when entering a new scene for the first time now work - using items on Zanthia is now possible. svn-id: r30886 --- engines/kyra/kyra_v2.cpp | 41 ++++-- engines/kyra/kyra_v2.h | 163 ++++++++++++++------- engines/kyra/module.mk | 1 + engines/kyra/resource.h | 3 + engines/kyra/scene_v2.cpp | 21 ++- engines/kyra/script_v2.cpp | 69 +++++++++ engines/kyra/sequences_tim.cpp | 315 ++++++++++++++++++++++++++++++++++++++++ engines/kyra/sound.cpp | 30 ++-- engines/kyra/sound.h | 12 +- engines/kyra/sound_towns.cpp | 10 +- engines/kyra/staticres.cpp | 13 +- engines/kyra/text_v2.cpp | 318 +++++++++++++++++++++++++++++++---------- 12 files changed, 840 insertions(+), 156 deletions(-) create mode 100644 engines/kyra/sequences_tim.cpp (limited to 'engines') diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 19fa30e3de..546fd6d954 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -86,13 +86,27 @@ 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; _invWsa.wsa = 0; + _colorCodeFlag1 = 0; + _colorCodeFlag2 = -1; + memset(&_sceneScriptData, 0, sizeof(_sceneScriptData)); + + _dlgBuffer = 0; + _conversationState = new int8*[19]; + for (int i = 0; i < 19; i++) + _conversationState[i] = new int8[14]; + _npcTalkChpIndex = _npcTalkDlgIndex = -1; + _mainCharacter.dlgIndex = 0; + setNewDlgIndex(-1); } KyraEngine_v2::~KyraEngine_v2() { @@ -109,6 +123,12 @@ KyraEngine_v2::~KyraEngine_v2() { _text = 0; delete _debugger; delete _invWsa.wsa; + + if (_dlgBuffer) + delete [] _dlgBuffer; + for (int i = 0; i < 19; i++) + delete [] _conversationState[i]; + delete [] _conversationState; } Movie *KyraEngine_v2::createWSAMovie() { @@ -155,6 +175,8 @@ int KyraEngine_v2::init() { if (_flags.isDemo) return 0; + tim_setupOpcodes(); + _mouseSHPBuf = _res->fileData("PWGMOUSE.SHP", 0); assert(_mouseSHPBuf); @@ -1877,12 +1899,12 @@ void KyraEngine_v2::setupOpcodeTable() { Opcode(o2_updateSceneAnim), OpcodeUnImpl(), // 0x74 + Opcode(o2_useItemOnMainChar), + Opcode(o2_startDialogue), OpcodeUnImpl(), - OpcodeUnImpl(), - OpcodeUnImpl(), - OpcodeUnImpl(), + Opcode(o2_setupDialogue), // 0x78 - OpcodeUnImpl(), + Opcode(o2_getDlgIndex), Opcode(o2_defineRoom), OpcodeUnImpl(), OpcodeUnImpl(), @@ -1894,18 +1916,18 @@ void KyraEngine_v2::setupOpcodeTable() { // 0x80 Opcode(o2_objectChat), OpcodeUnImpl(), - OpcodeUnImpl(), - OpcodeUnImpl(), + Opcode(o2_getColorCodeFlag1), + Opcode(o2_setColorCodeFlag1), // 0x84 - OpcodeUnImpl(), - OpcodeUnImpl(), + Opcode(o2_getColorCodeFlag2), + Opcode(o2_setColorCodeFlag2), OpcodeUnImpl(), OpcodeUnImpl(), // 0x88 Opcode(o2_countItemInstances), OpcodeUnImpl(), Opcode(o2_initObject), - OpcodeUnImpl(), + Opcode(o2_npcChat), // 0x8c Opcode(o2_deinitObject), OpcodeUnImpl(), @@ -1972,3 +1994,4 @@ void KyraEngine_v2::setupOpcodeTable() { } // end of namespace Kyra + diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index 54570b97cd..f35efa1d8d 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -495,6 +495,8 @@ protected: void runSceneScript6(); void runSceneScript7(); + void sceneStartupChat(); + void initSceneAnims(int unk1); void initSceneScreen(int unk1); @@ -589,7 +591,7 @@ protected: // character struct Character { uint16 sceneId; - uint16 unk2; + uint16 dlgIndex; uint8 height; uint8 facing; uint16 animFrame; @@ -652,8 +654,100 @@ protected: void objectChatPrintText(const char *text, int object); void objectChatProcess(const char *script); void objectChatWaitToFinish(); - void initTalkObject(int initObject); - void deinitTalkObject(int initObject); + + void startDialogue(int dlgIndex); + void updateDlgBuffer(); + void loadDlgHeader(int &csEntry, int &vocH, int &scIndex1, int &scIndex2); + void processDialogue(int dlgOffset, int vocH = 0, int csEntry = 0); + void npcChatSequence(const char *str, int objectId, int vocHigh = -1, int vocLow = -1); + void setNewDlgIndex(int dlgIndex); + + int _npcTalkChpIndex; + int _npcTalkDlgIndex; + uint8 _newSceneDlgState[32]; + int8 **_conversationState; + uint8 _npcTalkUNK; + uint8 *_dlgBuffer; + + // 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); + + 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; + }; + + struct TIMBuffers { + uint8 *AVTLChunk; + uint8 *TEXTChunk; + uint8 *offsUnkFlag2; + uint8 *offsUnkFlag; + int16 currentEntry; + int16 unk_12; + Cmds *currentCommandSet; + uint8 *unkCmds; + }; + TIMBuffers _TIMBuffers; + + const char *_timChatText; + int _timChatObject; + + // Talk object handling + void initTalkObject(int index); + void deinitTalkObject(int index); + + struct TalkObject { + char filename[13]; + int8 scriptId; + int16 x, y; + int8 color; + }; + TalkObject *_talkObjectList; + + struct TalkSections { + uint8 *STATim; + uint8 *TLKTim; + uint8 *ENDTim; + }; + TalkSections _currentTalkSections; + + char _TLKFilename[13]; + bool _objectChatFinished; // sound int _oldTalkFile; @@ -688,51 +782,6 @@ protected: // delay void delay(uint32 millis, bool updateGame = false, bool isMainLoop = false); - // Talk object handling - struct TalkObject { - char filename[13]; - int8 scriptId; - int16 x, y; - int8 color; - }; - TalkObject *_talkObjectList; - - struct TIMHeader { - uint16 deleteBufferFlag; - int16 unkFlag; - int16 unkFlag2; - int16 unkOffset; - int16 unkOffset2; - int16 AVTLOffset; - int16 TEXTOffset; - }; - - struct TIMStructUnk1 { - uint16 unk_0; - uint16 unk_2; - uint16 unk_4; - uint16 unk_8; - uint16 *unk_20; - }; - - struct TIMBuffers { - uint16 *AVTLChunk; - byte *TEXTChunk; - TIMStructUnk1 *UnkChunk; - }; - TIMBuffers _TIMBuffers; - - struct TalkSections { - byte *STATim; - byte *TLKTim; - byte *ENDTim; - }; - TalkSections _currentTalkSections; - - bool _objectChatFinished; - byte *loadTIMFile(const char *filename, byte *buffer, int32 bufferSize); - void freeTIM(byte *buffer); - // ingame static sequence handling void seq_makeBookOrCauldronAppear(int type); void seq_makeBookAppear(); @@ -809,10 +858,19 @@ protected: int o2_setSpecialSceneScriptRunTime(ScriptState *script); int o2_defineSceneAnim(ScriptState *script); int o2_updateSceneAnim(ScriptState *script); + int o2_useItemOnMainChar(ScriptState *script); + int o2_startDialogue(ScriptState *script); + int o2_setupDialogue(ScriptState *script); + int o2_getDlgIndex(ScriptState *script); int o2_defineRoom(ScriptState *script); int o2_objectChat(ScriptState *script); + int o2_getColorCodeFlag1(ScriptState *script); + int o2_setColorCodeFlag1(ScriptState *script); + int o2_getColorCodeFlag2(ScriptState *script); + int o2_setColorCodeFlag2(ScriptState *script); int o2_countItemInstances(ScriptState *script); int o2_initObject(ScriptState *script); + int o2_npcChat(ScriptState *script); int o2_deinitObject(ScriptState *script); int o2_makeBookOrCauldronAppear(ScriptState *script); int o2_setSpecialSceneScriptState(ScriptState *script); @@ -896,6 +954,10 @@ protected: int _ingameSoundIndexSize; const char *const *_sequenceStrings; int _sequenceStringsSize; + const uint16 *_ingameTalkObjIndex; + int _ingameTalkObjIndexSize; + const char *const *_ingameTimJpStr; + int _ingameTimJpStrSize; uint8 *_demoShapeDefs; int _sequenceStringsDuration[33]; @@ -919,6 +981,10 @@ protected: Sequence *_sequences; NestedSequence *_nSequences; + + // these are used whenever the color code has to be entered + int _colorCodeFlag1; + int _colorCodeFlag2; }; } // end of namespace Kyra @@ -926,3 +992,4 @@ protected: #endif + diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index e631ddf5dd..bce7364cc8 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -25,6 +25,7 @@ MODULE_OBJS := \ script_v2.o \ script.o \ seqplayer.o \ + sequences_tim.o \ sequences_v1.o \ sequences_v2.o \ sound_adlib.o \ diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index 72b4414ccc..cde5df4bf2 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -218,6 +218,8 @@ enum kKyraResources { k2IngameSfxIndex, k2IngameTracks, k2IngameCDA, + k2IngameTalkObjIndex, + k2IngameTimJpStrings, kMaxResIDs }; @@ -328,3 +330,4 @@ private: #endif + diff --git a/engines/kyra/scene_v2.cpp b/engines/kyra/scene_v2.cpp index 63664c91d8..1eee6fe670 100644 --- a/engines/kyra/scene_v2.cpp +++ b/engines/kyra/scene_v2.cpp @@ -243,7 +243,7 @@ void KyraEngine_v2::enterNewSceneUnk2(int unk1) { if (!unk1) { runSceneScript4(0); - //XXX sub_27158 + sceneStartupChat(); } _unk4 = 0; @@ -499,6 +499,22 @@ void KyraEngine_v2::runSceneScript7() { _screen->_curPage = oldPage; } +void KyraEngine_v2::sceneStartupChat() { + int tableIndex = _mainCharacter.sceneId - READ_LE_UINT16(&_ingameTalkObjIndex[5 + _newChapterFile]); + if (queryGameFlag(0x159) || _newSceneDlgState[tableIndex]) + return; + + int csEntry, vocH, scIndex1, scIndex2; + updateDlgBuffer(); + loadDlgHeader(csEntry, vocH, scIndex1, scIndex2); + + uint8 bufferIndex = 8 + scIndex1 * 6 + scIndex2 * 4 + tableIndex * 2; + int offs = READ_LE_UINT16(_dlgBuffer + bufferIndex); + processDialogue(offs, vocH, csEntry); + + _newSceneDlgState[tableIndex] = 1; +} + void KyraEngine_v2::initSceneAnims(int unk1) { for (int i = 0; i < ARRAYSIZE(_animObjects); ++i) _animObjects[i].enabled = 0; @@ -908,5 +924,4 @@ void KyraEngine_v2::fadeScenePal(int srcIndex, int delayTime) { _screen->fadePalette(_screen->getPalette(0), delayTime, &_updateFunctor); } -} // end of namespace Kyra - +} // end of namespace Kyra \ No newline at end of file diff --git a/engines/kyra/script_v2.cpp b/engines/kyra/script_v2.cpp index f115665f09..587115551d 100644 --- a/engines/kyra/script_v2.cpp +++ b/engines/kyra/script_v2.cpp @@ -622,6 +622,41 @@ int KyraEngine_v2::o2_updateSceneAnim(ScriptState *script) { return 0; } +int KyraEngine_v2::o2_useItemOnMainChar(ScriptState *script) { + ScriptState tmpScript; + _scriptInterpreter->initScript(&tmpScript, &_npcScriptData); + _scriptInterpreter->startScript(&tmpScript, 0); + tmpScript.regs[4] = _itemInHand; + tmpScript.regs[0] = _mainCharacter.sceneId; + + int oldVocH = _vocHigh; + _vocHigh = 0x5a; + + while(_scriptInterpreter->validScript(&tmpScript)) + _scriptInterpreter->runScript(&tmpScript); + + _vocHigh = oldVocH; + + return 0; +} + +int KyraEngine_v2::o2_startDialogue(ScriptState *script) { + debugC(3, kDebugLevelScriptFuncs, "o2_startDialogue(%p) (%d)", (const void *)script, stackPos(0)); + startDialogue(stackPos(0)); + return 0; +} + +int KyraEngine_v2::o2_setupDialogue(ScriptState *script) { + debugC(3, kDebugLevelScriptFuncs, "o2_setupDialogue(%p) (%d)", (const void *)script, stackPos(0)); + setNewDlgIndex(stackPos(0)); + return 0; +} + +int KyraEngine_v2::o2_getDlgIndex(ScriptState *script) { + debugC(3, kDebugLevelScriptFuncs, "o2_setNewDlgIndex(%p) (%d)", (const void *)script, stackPos(0)); + return _mainCharacter.dlgIndex; +} + int KyraEngine_v2::o2_defineRoom(ScriptState *script) { debugC(3, kDebugLevelScriptFuncs, "o2_defineRoom(%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)); @@ -653,6 +688,28 @@ int KyraEngine_v2::o2_objectChat(ScriptState *script) { return 0; } +int KyraEngine_v2::o2_getColorCodeFlag1(ScriptState *script) { + debugC(3, kDebugLevelScriptFuncs, "o2_getColorCodeFlag1(%p)", (const void *)script); + return _colorCodeFlag1; +} + +int KyraEngine_v2::o2_setColorCodeFlag1(ScriptState *script) { + debugC(3, kDebugLevelScriptFuncs, "o2_getColorCodeFlag1(%p) (%d)", (const void *)script, stackPos(0)); + _colorCodeFlag1 = stackPos(0); + return 0; +} + +int KyraEngine_v2::o2_getColorCodeFlag2(ScriptState *script) { + debugC(3, kDebugLevelScriptFuncs, "o2_getColorCodeFlag2(%p)", (const void *)script); + return _colorCodeFlag2; +} + +int KyraEngine_v2::o2_setColorCodeFlag2(ScriptState *script) { + debugC(3, kDebugLevelScriptFuncs, "o2_getColorCodeFlag2(%p) (%d)", (const void *)script, stackPos(0)); + _colorCodeFlag2 = stackPos(0); + return 0; +} + int KyraEngine_v2::o2_countItemInstances(ScriptState *script) { debugC(3, kDebugLevelScriptFuncs, "o2_countItemInstances(%p) (%d)", (const void *)script, stackPos(0)); uint16 item = stackPos(0); @@ -691,6 +748,17 @@ int KyraEngine_v2::o2_initObject(ScriptState *script) { return 0; } +int KyraEngine_v2::o2_npcChat(ScriptState *script) { + if (_flags.isTalkie) { + debugC(3, kDebugLevelScriptFuncs, "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, "o2_npcChat(%p) ('%s', %d)", (const void *)script, stackPosString(0), stackPos(1)); + npcChatSequence(stackPosString(0), stackPos(1)); + } + return 0; +} + int KyraEngine_v2::o2_deinitObject(ScriptState *script) { debugC(3, kDebugLevelScriptFuncs, "o2_deinitObject(%p) (%d)", (const void *)script, stackPos(0)); deinitTalkObject(stackPos(0)); @@ -840,3 +908,4 @@ int KyraEngine_v2::o2t_setShapeFlag(ScriptState *script) { } // end of namespace Kyra + diff --git a/engines/kyra/sequences_tim.cpp b/engines/kyra/sequences_tim.cpp new file mode 100644 index 0000000000..a072f2f64d --- /dev/null +++ b/engines/kyra/sequences_tim.cpp @@ -0,0 +1,315 @@ +/* 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); + +} + +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(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/sound.cpp b/engines/kyra/sound.cpp index a93a9ed66a..692db54af5 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -39,7 +39,7 @@ namespace Kyra { Sound::Sound(KyraEngine *vm, Audio::Mixer *mixer) - : _vm(vm), _mixer(mixer), _currentVocFile(0), _vocHandle(), + : _vm(vm), _mixer(mixer), _currentVocFile(0), _vocHandles(), _musicEnabled(1), _sfxEnabled(true), _soundDataList(0) { } @@ -52,6 +52,14 @@ void Sound::voicePlay(const char *file) { bool found = false; char filenamebuffer[25]; + int h = 0; + if (_currentVocFile) { + while (_mixer->isSoundHandleActive(_vocHandles[h])) + h++; + if (h >= kNumVocHandles) + return; + } + for (int i = 0; _supportedCodes[i].fileext; ++i) { strcpy(filenamebuffer, file); strcat(filenamebuffer, _supportedCodes[i].fileext); @@ -76,21 +84,26 @@ void Sound::voicePlay(const char *file) { _currentVocFile = Audio::makeVOCStream(vocStream); } - if (_currentVocFile) { - //_mixer->stopHandle(_vocHandle); - _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_vocHandle, _currentVocFile); - } + _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_vocHandles[h], _currentVocFile); + delete [] fileData; fileSize = 0; } void Sound::voiceStop() { - if (_mixer->isSoundHandleActive(_vocHandle)) - _mixer->stopHandle(_vocHandle); + for (int h = 0; h < kNumVocHandles; h++) { + if (_mixer->isSoundHandleActive(_vocHandles[h])) + _mixer->stopHandle(_vocHandles[h]); + } } bool Sound::voiceIsPlaying() { - return _mixer->isSoundHandleActive(_vocHandle); + bool res = false; + for (int h = 0; h < kNumVocHandles; h++) { + if (_mixer->isSoundHandleActive(_vocHandles[h])) + res = true; + } + return res; } #pragma mark - @@ -522,3 +535,4 @@ const Sound::SpeechCodecs Sound::_supportedCodes[] = { } // end of namespace Kyra + diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 426d7b6896..919cc3ceab 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -180,6 +180,10 @@ protected: const void *cdaData() const { return _soundDataList != 0 ? _soundDataList->_cdaTracks : 0; } const int cdaTrackNum() const { return _soundDataList != 0 ? _soundDataList->_cdaNumTracks : 0; } + enum { + kNumVocHandles = 4 + }; + int _musicEnabled; bool _sfxEnabled; @@ -191,7 +195,7 @@ protected: private: const AudioDataStruct *_soundDataList; Audio::AudioStream *_currentVocFile; - Audio::SoundHandle _vocHandle; + Audio::SoundHandle _vocHandles[kNumVocHandles]; struct SpeechCodecs { const char *fileext; @@ -425,10 +429,10 @@ private: int _lastTrack; Audio::AudioStream *_currentSFX; - Audio::SoundHandle _sfxHandle; + Audio::SoundHandle _sfxHandles[kNumVocHandles]; - //SoundTowns_v2_TwnDriver * _driver; - uint8 * _twnTrackData; + //SoundTowns_v2_TwnDriver *_driver; + uint8 *_twnTrackData; }; class MixedSoundDriver : public Sound { diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index ae9f3a7915..e3102d747b 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1435,6 +1435,14 @@ void SoundTowns_v2::haltTrack() { void SoundTowns_v2::voicePlay(const char *file) { static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 }; + int h = 0; + if (_currentSFX) { + while (_mixer->isSoundHandleActive(_sfxHandles[h])) + h++; + if (h >= kNumVocHandles) + return; + } + uint8 * data = _vm->resource()->fileData(file, 0); uint8 * src = data; @@ -1482,7 +1490,7 @@ void SoundTowns_v2::voicePlay(const char *file) { _currentSFX = Audio::makeLinearInputStream(sfx, outsize, outputRate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0); - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _currentSFX); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[h], _currentSFX); delete [] data; } diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index a77632617d..f36a67146b 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -35,7 +35,7 @@ namespace Kyra { -#define RESFILE_VERSION 20 +#define RESFILE_VERSION 21 bool StaticResource::checkKyraDat() { Common::File kyraDat; @@ -241,10 +241,12 @@ bool StaticResource::init() { // Ingame { k2IngamePakFiles, kStringList, "I_PAKFILES.TXT" }, - { k2IngameSfxFiles, kStringList, "I_SFXFILES.TXT" }, - { k2IngameSfxIndex, kRawData, "I_SFXINDEX.TRA" }, + { k2IngameSfxFiles, kStringList, "I_SFXFILES.TRA" }, + { k2IngameSfxIndex, kRawData, "I_SFXINDEX.MAP" }, { k2IngameTracks, kStringList, "I_TRACKS.TRA" }, { k2IngameCDA, kRawData, "I_TRACKS.CDA" }, + { k2IngameTalkObjIndex, kRawData, "I_TALKOBJECTS.MAP" }, + { k2IngameTimJpStrings, kStringList, "I_TIMJPSTR.TXT" }, { 0, 0, 0 } }; @@ -926,6 +928,8 @@ void KyraEngine_v2::initStaticResource() { _cdaTrackTableIntro = _staticres->loadRawData(k2SeqplayIntroCDA, _cdaTrackTableIntroSize); _cdaTrackTableIngame = _staticres->loadRawData(k2IngameCDA, _cdaTrackTableIngameSize); _cdaTrackTableFinale = _staticres->loadRawData(k2SeqplayFinaleCDA, _cdaTrackTableFinaleSize); + _ingameTalkObjIndex = (const uint16*) _staticres->loadRawData(k2IngameTalkObjIndex, _ingameTalkObjIndexSize); + _ingameTimJpStr = _staticres->loadStrings(k2IngameTimJpStrings, _ingameTimJpStrSize); // replace sequence talkie files with localized versions and cut off .voc // suffix from voc files so as to allow compression specific file extensions @@ -934,7 +938,7 @@ void KyraEngine_v2::initStaticResource() { // of _sequenceSoundList instead of casting away const. const char* const* tlkfiles = _staticres->loadStrings(k2SeqplayTlkFiles, tmp); for (int i = 0; i < _sequenceSoundListSize; i++) { - uint32 len = strlen(_sequenceSoundList[i]); + int len = strlen(_sequenceSoundList[i]); if (_flags.platform == Common::kPlatformPC) len -= 4; @@ -1494,3 +1498,4 @@ const int KyraEngine_v3::_languageExtensionSize = ARRAYSIZE(KyraEngine_v3::_lang } // End of namespace Kyra + diff --git a/engines/kyra/text_v2.cpp b/engines/kyra/text_v2.cpp index 2f517c2d42..5857fdae66 100644 --- a/engines/kyra/text_v2.cpp +++ b/engines/kyra/text_v2.cpp @@ -27,6 +27,8 @@ #include "kyra/kyra_v2.h" #include "kyra/resource.h" +#include "common/endian.h" + namespace Kyra { TextDisplayer_v2::TextDisplayer_v2(KyraEngine_v2 *vm, Screen_v2 *screen) @@ -325,7 +327,7 @@ void KyraEngine_v2::objectChatWaitToFinish() { } const uint32 curTime = _system->getMillis(); - if ((textEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || _skipFlag) { + if ((textEnabled() && curTime > endTime) || (speechEnabled() && !textEnabled() && !snd_voiceIsPlaying()) || _skipFlag) { _skipFlag = false; nextFrame = curTime; running = false; @@ -340,150 +342,308 @@ void KyraEngine_v2::objectChatWaitToFinish() { resetCharacterAnimDim(); } -void KyraEngine_v2::initTalkObject(int initObject) { - TalkObject &object = _talkObjectList[initObject]; +void KyraEngine_v2::startDialogue(int dlgIndex) { + updateDlgBuffer(); + int csEntry, vocH, unused1, unused2; + loadDlgHeader(csEntry, vocH, unused1, unused2); + int s = _conversationState[dlgIndex][csEntry]; + uint8 bufferIndex = 8; + + if (s == -1) { + bufferIndex += (dlgIndex * 6); + _conversationState[dlgIndex][csEntry] = 0; + } else if (!s || s == 2) { + bufferIndex += (dlgIndex * 6 + 2); + _conversationState[dlgIndex][csEntry] = 1; + } else { + bufferIndex += (dlgIndex * 6 + 4); + _conversationState[dlgIndex][csEntry] = 2; + } + + int offs = READ_LE_UINT16(_dlgBuffer + bufferIndex); + processDialogue(offs, vocH, csEntry); +} + +void KyraEngine_v2::updateDlgBuffer() { + static const char DlgFileTemplate[] = "CH**-S**.DLG"; + char filename[13]; + filename[12] = 0; + memcpy(filename, DlgFileTemplate, 12); + + static const char suffixTalkie[] = "EFG"; + static const char suffixTowns[] = "G J"; + const char * suffix = _flags.isTalkie ? suffixTalkie : suffixTowns; + + filename[2] = (char)((_currentChapter / 10 + 48) & 0xFF); + filename[3] = (char)((_currentChapter % 10 + 48) & 0xFF); + + if (!(_flags.platform == Common::kPlatformPC && !_flags.isTalkie)) + filename[11] = suffix[_lang]; + + if (_currentChapter == _npcTalkChpIndex && _mainCharacter.dlgIndex == _npcTalkDlgIndex) + return; + + _npcTalkChpIndex = _currentChapter; + _npcTalkDlgIndex = _mainCharacter.dlgIndex; + + filename[6] = (char)((_npcTalkDlgIndex / 10 + 48) & 0xFF); + filename[7] = (char)((_npcTalkDlgIndex % 10 + 48) & 0xFF); + + if (_dlgBuffer) + delete [] _dlgBuffer; + + _dlgBuffer = _res->fileData(filename, 0); +} + +void KyraEngine_v2::loadDlgHeader(int &csEntry, int &vocH, int &scIndex1, int &scIndex2) { + csEntry = READ_LE_UINT16(_dlgBuffer); + vocH = READ_LE_UINT16(_dlgBuffer + 2); + scIndex1 = READ_LE_UINT16(_dlgBuffer + 4); + scIndex2 = READ_LE_UINT16(_dlgBuffer + 6); +} + +void KyraEngine_v2::processDialogue(int dlgOffset, int vocH, int csEntry) { + int activeTimSequence = -1; + int nextTimSequence = -1; + int cmd = 0; + int vocHi = -1; + int vocLo = -1; + bool loop = true; + int offs = dlgOffset; + + _screen->hideMouse(); + + while (loop) { + cmd = READ_LE_UINT16(_dlgBuffer + offs); + offs += 2; + + nextTimSequence = READ_LE_UINT16(&_ingameTalkObjIndex[cmd]); + + if (nextTimSequence == 10) { + if (queryGameFlag(0x3e)) + nextTimSequence = 14; + if (queryGameFlag(0x3f)) + nextTimSequence = 15; + if (queryGameFlag(0x40)) + nextTimSequence = 16; + } + + if (nextTimSequence == 27 && _mainCharacter.sceneId == 34) + nextTimSequence = 41; + + if (queryGameFlag(0x72)) { + if (nextTimSequence == 18) + nextTimSequence = 43; + else if (nextTimSequence == 19) + nextTimSequence = 44; + } + + if (_mainCharacter.x1 > 160) { + if (nextTimSequence == 4) + nextTimSequence = 46; + else if (nextTimSequence == 5) + nextTimSequence = 47; + } + + if (cmd == 10) { + loop = false; + + } else if (cmd == 4) { + csEntry = READ_LE_UINT16(_dlgBuffer + offs); + setNewDlgIndex(csEntry); + offs += 2; + + } else { + if (!_flags.isTalkie || cmd == 11) { + int len = READ_LE_UINT16(_dlgBuffer + offs); + offs += 2; + if (_flags.isTalkie) { + vocLo = READ_LE_UINT16(_dlgBuffer + offs); + offs += 2; + } + memcpy(_unkBuf500Bytes, _dlgBuffer + offs, len); + _unkBuf500Bytes[len] = 0; + offs += len; + if (_flags.isTalkie) + continue; + + } else if (_flags.isTalkie) { + int len = READ_LE_UINT16(_dlgBuffer + offs); + offs += 2; + static const int irnv[] = { 91, 105, 110, 114, 118 }; + vocHi = irnv[vocH - 1] + csEntry; + vocLo = READ_LE_UINT16(_dlgBuffer + offs); + offs += 2; + memcpy(_unkBuf500Bytes, _dlgBuffer + offs, len); + _unkBuf500Bytes[len] = 0; + offs += len; + } + + if (_unkBuf500Bytes[0]) { + if ((!_flags.isTalkie && cmd == 11) || (_flags.isTalkie && cmd == 12)) { + if (activeTimSequence > -1) { + deinitTalkObject(activeTimSequence); + activeTimSequence = -1; + } + objectChat((const char*) _unkBuf500Bytes, 0, vocHi, vocLo); + } else { + if (activeTimSequence != nextTimSequence ) { + if (activeTimSequence > -1) { + deinitTalkObject(activeTimSequence); + activeTimSequence = -1; + } + initTalkObject(nextTimSequence); + activeTimSequence = nextTimSequence; + } + npcChatSequence((const char *)_unkBuf500Bytes, nextTimSequence, vocHi, vocLo); + } + } + } + } + + if (activeTimSequence > -1) + deinitTalkObject(activeTimSequence); + + _screen->showMouse(); +} + +void KyraEngine_v2::initTalkObject(int index) { + TalkObject &object = _talkObjectList[index]; char STAFilename[13]; - char TLKFilename[13]; char ENDFilename[13]; strcpy(STAFilename, object.filename); - strcpy(TLKFilename, object.filename); + strcpy(_TLKFilename, object.filename); strcpy(ENDFilename, object.filename); strcpy(STAFilename + 4, "_STA.TIM"); - strcpy(TLKFilename + 4, "_TLK.TIM"); + strcpy(_TLKFilename + 4, "_TLK.TIM"); strcpy(ENDFilename + 4, "_END.TIM"); - _currentTalkSections.STATim = loadTIMFile(STAFilename, NULL, 0); - _currentTalkSections.TLKTim = loadTIMFile(TLKFilename, NULL, 0); - _currentTalkSections.ENDTim = loadTIMFile(ENDFilename, NULL, 0); + _currentTalkSections.STATim = tim_loadFile(STAFilename, NULL, 0); + _currentTalkSections.TLKTim = tim_loadFile(_TLKFilename, NULL, 0); + _currentTalkSections.ENDTim = tim_loadFile(ENDFilename, NULL, 0); if (object.scriptId != -1) { _specialSceneScriptStateBackup[object.scriptId] = _specialSceneScriptState[object.scriptId]; _specialSceneScriptState[object.scriptId] = 1; } - /*if (_currentTalkObject.STATim) { + if (_currentTalkSections.STATim) { _objectChatFinished = false; while (!_objectChatFinished) { - processTalkObject(_currentTalkObject.STATim, 0); + tim_processSequence(_currentTalkSections.STATim, 0); if (_chatText) updateWithText(); else update(); } - }*/ + } } -void KyraEngine_v2::deinitTalkObject(int initObject) { - TalkObject &object = _talkObjectList[initObject]; +void KyraEngine_v2::deinitTalkObject(int index) { + TalkObject &object = _talkObjectList[index]; - /*if (_currentTalkObject.ENDTim) { + if (_currentTalkSections.ENDTim) { _objectChatFinished = false; while (!_objectChatFinished) { - processTalkObject(_currentTalkObject.ENDTim, 0); + tim_processSequence(_currentTalkSections.ENDTim, 0); if (_chatText) updateWithText(); else update(); } - }*/ + } if (object.scriptId != -1) { _specialSceneScriptState[object.scriptId] = _specialSceneScriptStateBackup[object.scriptId]; } if (_currentTalkSections.STATim != NULL) { - freeTIM(_currentTalkSections.STATim); + tim_releaseBuffer(_currentTalkSections.STATim); _currentTalkSections.STATim = NULL; } if (_currentTalkSections.TLKTim != NULL) { - freeTIM(_currentTalkSections.TLKTim); + tim_releaseBuffer(_currentTalkSections.TLKTim); _currentTalkSections.TLKTim = NULL; } if (_currentTalkSections.ENDTim != NULL) { - freeTIM(_currentTalkSections.ENDTim); + tim_releaseBuffer(_currentTalkSections.ENDTim); _currentTalkSections.ENDTim = NULL; } } -byte *KyraEngine_v2::loadTIMFile(const char *filename, byte *buffer, int32 bufferSize) { - ScriptFileParser file(filename, _res); - if (!file) { - error("Couldn't open script file '%s'", filename); - return NULL; - } +void KyraEngine_v2::npcChatSequence(const char *str, int objectId, int vocHigh, int vocLow) { + _chatText = str; + _chatObject = objectId; + objectChatInit(str, objectId, vocHigh, vocLow); - int32 formBlockSize = file.getFORMBlockSize(); - if (formBlockSize == -1) { - error("No FORM chunk found in file: '%s'", filename); - return NULL; - } + if (!_currentTalkSections.TLKTim) + _currentTalkSections.TLKTim = tim_loadFile(_TLKFilename, 0, 0); - if (formBlockSize < 20) { - return NULL; - } + setNextIdleAnimTimer(); - formBlockSize += sizeof(TIMHeader) + 120 + sizeof(TIMStructUnk1) * 10; + uint32 ct = chatCalcDuration(str); + uint32 time = _system->getMillis(); + _chatEndTime = time + (3 + ct) * _tickLength; + uint32 chatAnimEndTime = time + (3 + (ct >> 1)) * _tickLength; - TIMHeader *timHeader; - if (buffer == NULL || bufferSize < formBlockSize) { - buffer = new byte[formBlockSize]; - timHeader = (TIMHeader *)buffer; - timHeader->deleteBufferFlag = 0xBABE; - } else { - timHeader = (TIMHeader *)buffer; - timHeader->deleteBufferFlag = 0x0; + if (_chatVocHigh >= 0) { + playVoice(_chatVocHigh, _chatVocLow); + _chatVocHigh = _chatVocLow = -1; } - int32 chunkSize = file.getIFFBlockSize(AVTL_CHUNK); - timHeader->unkFlag = -1; - timHeader->unkFlag2 = 0; - timHeader->unkOffset = sizeof(TIMHeader); - timHeader->unkOffset2 = timHeader->unkOffset + sizeof(TIMStructUnk1) * 10; - timHeader->AVTLOffset = timHeader->unkOffset2 + 120; - timHeader->TEXTOffset = timHeader->AVTLOffset + chunkSize; - - _TIMBuffers.AVTLChunk = (uint16 *)(buffer + timHeader->AVTLOffset); - _TIMBuffers.TEXTChunk = buffer + timHeader->TEXTOffset; + while (((textEnabled() && _chatEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) && !(_quitFlag || _skipFlag)) { + if (!speechEnabled() && chatAnimEndTime > _system->getMillis() || speechEnabled() && snd_voiceIsPlaying()) { + _objectChatFinished = false; - if (!file.loadIFFBlock(AVTL_CHUNK, _TIMBuffers.AVTLChunk, chunkSize)) { - error("Couldn't load AVTL chunk from file: '%s'", filename); - return NULL; - } + while (!_objectChatFinished && !_skipFlag) { + if (_currentTalkSections.TLKTim) + tim_processSequence(_currentTalkSections.TLKTim, 0); + else + _objectChatFinished = false; - _TIMBuffers.UnkChunk = (TIMStructUnk1 *)(buffer + timHeader->unkOffset); + updateWithText(); - for (int i = 0; i < 10; i++) { - _TIMBuffers.UnkChunk[i].unk_0 = 0; - _TIMBuffers.UnkChunk[i].unk_2 = 0; - _TIMBuffers.UnkChunk[i].unk_20 = &_TIMBuffers.AVTLChunk[ _TIMBuffers.AVTLChunk[i] ]; - _TIMBuffers.UnkChunk[i].unk_4 = 0; - _TIMBuffers.UnkChunk[i].unk_8 = 0; + int inputFlag = checkInput(0); + removeInputTop(); + if (inputFlag == 198 || inputFlag == 199) { + //XXX + _skipFlag = true; + snd_stopVoice(); + } + delay(10); + } + if (_currentTalkSections.TLKTim) + tim_o_abort(0); + } + updateWithText(); } - 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; - } + _skipFlag = false; + + if (_currentTalkSections.TLKTim) { + tim_releaseBuffer(_currentTalkSections.TLKTim); + _currentTalkSections.TLKTim = 0; } - return buffer; + _text->restoreScreen(); + _chatText = 0; + _chatObject = -1; + setNextIdleAnimTimer(); } -void KyraEngine_v2::freeTIM(byte *buffer) { - TIMHeader *timHeader = (TIMHeader *)buffer; - - if (timHeader->deleteBufferFlag == 0xBABE) { - delete[] buffer; - } +void KyraEngine_v2::setNewDlgIndex(int dlgIndex) { + if (dlgIndex == _mainCharacter.dlgIndex) + return; + memset(_newSceneDlgState, 0, 32); + for (int i = 0; i < 19; i++) + memset(_conversationState[i], -1, 14); + _npcTalkUNK = 0; + _mainCharacter.dlgIndex = dlgIndex; } } // end of namespace Kyra - - -- cgit v1.2.3