diff options
Diffstat (limited to 'engines/kyra')
35 files changed, 1296 insertions, 255 deletions
diff --git a/engines/kyra/animator_hof.cpp b/engines/kyra/animator_hof.cpp index 1192145530..c5d44d10af 100644 --- a/engines/kyra/animator_hof.cpp +++ b/engines/kyra/animator_hof.cpp @@ -127,12 +127,8 @@ void KyraEngine_HoF::updateItemAnimations() { return; const ItemAnimData_v2 *s = &_itemAnimData[_nextAnimItem]; - ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem]; - - if (++_nextAnimItem == 14) { - _nextAnimItem = 0; - return; - } + ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem]; + _nextAnimItem = ++_nextAnimItem % _itemAnimDataSize; uint32 ctime = _system->getMillis(); if (ctime < a->nextFrame) diff --git a/engines/kyra/animator_mr.cpp b/engines/kyra/animator_mr.cpp index f04ca0345d..9702499fe7 100644 --- a/engines/kyra/animator_mr.cpp +++ b/engines/kyra/animator_mr.cpp @@ -205,11 +205,7 @@ void KyraEngine_MR::updateItemAnimations() { const ItemAnimData_v2 *s = &_itemAnimData[_nextAnimItem]; ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem]; - - if (++_nextAnimItem == 11) { - _nextAnimItem = 0; - return; - } + _nextAnimItem = ++_nextAnimItem % 10; uint32 ctime = _system->getMillis(); if (ctime < a->nextFrame) diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp index 0d170dbf05..7ae5414d82 100644 --- a/engines/kyra/debugger.cpp +++ b/engines/kyra/debugger.cpp @@ -192,6 +192,7 @@ bool Debugger::cmd_setTimerCountdown(int argc, const char **argv) { Debugger_LoK::Debugger_LoK(KyraEngine_LoK *vm) : Debugger(vm), _vm(vm) { + DCmd_Register("enter", WRAP_METHOD(Debugger_LoK, cmd_enterRoom)); DCmd_Register("rooms", WRAP_METHOD(Debugger_LoK, cmd_listRooms)); DCmd_Register("give", WRAP_METHOD(Debugger_LoK, cmd_giveItem)); DCmd_Register("birthstones", WRAP_METHOD(Debugger_LoK, cmd_listBirthstones)); diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 3c4c87e12b..a3ca2f829e 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -41,22 +41,25 @@ struct KYRAGameDescription { namespace { -#define FLAGS(x, y, z, a, b, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, id } - -#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, Kyra::GI_KYRA1) -#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, Kyra::GI_KYRA1) -#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, Kyra::GI_KYRA1) - -#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, Kyra::GI_KYRA2) -#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, Kyra::GI_KYRA2) -#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, Kyra::GI_KYRA2) - -#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, Kyra::GI_KYRA3) +#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id } + +#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, false, Kyra::GI_KYRA1) +#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA1) + +#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA2) +#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_KYRA2) + +#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) +#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) const KYRAGameDescription adGameDescs[] = { { @@ -296,6 +299,66 @@ const KYRAGameDescription adGameDescs[] = { KYRA1_DEMO_FLAGS }, + { // Floppy version + { + "kyra2", + 0, + AD_ENTRY1("WESTWOOD.001", "3f52dda68c4f7696c8309038be9f4151"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_FLOPPY_CMP_FLAGS + }, + + { // Floppy version + { + "kyra2", + 0, + AD_ENTRY1("WESTWOOD.001", "d787b9559afddfe058b84c0b3a787224"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_FLOPPY_CMP_FLAGS + }, + + { // // Floppy version extracted + { + "kyra2", + "Extracted", + AD_ENTRY1("FATE.PAK", "1ba18be685ad8e5a0ab5d46a0ce4d345"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_FLOPPY_FLAGS + }, + + { // Floppy version extracted + { + "kyra2", + "Extracted", + AD_ENTRY1("FATE.PAK", "262fb69dd8e52e596c7aefc6456f7c1b"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_FLOPPY_FLAGS + }, + + { // Floppy version extracted + { + "kyra2", + "Extracted", + AD_ENTRY1("FATE.PAK", "f7de11506b4c8fdf64bc763206c3e4e7"), + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_FLOPPY_FLAGS + }, + { // CD version { "kyra2", @@ -417,7 +480,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, { { @@ -432,7 +495,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, { { @@ -447,7 +510,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, // installed version @@ -497,7 +560,7 @@ const KYRAGameDescription adGameDescs[] = { KYRA3_CD_FLAGS }, - { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0) } + { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) } }; const PlainGameDescriptor gameList[] = { diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index 10f7f657a3..555934cb7f 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -455,12 +455,12 @@ void KyraEngine_HoF::showBookPage() { char filename[16]; sprintf(filename, "PAGE%.01X.", _bookCurPage); - strcat(filename, _languageExtension[_lang]); + strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); uint8 *leftPage = _res->fileData(filename, 0); int leftPageY = _bookPageYOffset[_bookCurPage]; sprintf(filename, "PAGE%.01X.", _bookCurPage+1); - strcat(filename, _languageExtension[_lang]); + strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); uint8 *rightPage = (_bookCurPage != _bookMaxPage) ? _res->fileData(filename, 0) : 0; int rightPageY = _bookPageYOffset[_bookCurPage+1]; diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 2b823b1ae7..6fa30c9e9a 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -337,6 +337,8 @@ void GUI_LoK::setGUILabels() { } else if (_vm->gameFlags().lang == Common::ES_ESP) { offsetOn = offsetMainMenu = offsetOptions = offset = -4; menuLabelGarbageOffset = 72; + } else if (_vm->gameFlags().lang == Common::IT_ITA) { + offsetOn = offsetMainMenu = offsetOptions = offset = 32; } else if (_vm->gameFlags().lang == Common::DE_DEU) { offset = offsetMainMenu = offsetOn = offsetOptions = 24; } else if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) { diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp index e86be25707..8eb62c20c2 100644 --- a/engines/kyra/items_lok.cpp +++ b/engines/kyra/items_lok.cpp @@ -176,7 +176,7 @@ void KyraEngine_LoK::placeItemInGenericMapScene(int item, int index) { } void KyraEngine_LoK::setHandItem(uint16 item) { - debugC(9, kDebugLevelMain, "KyraEngine_LoK::setHandItem(%d)", item); + debugC(9, kDebugLevelMain, "KyraEngine_LoK::setHandItem(%u)", item); _screen->hideMouse(); setMouseItem(item); _itemInHand = item; @@ -191,9 +191,9 @@ void KyraEngine_LoK::removeHandItem() { _screen->showMouse(); } -void KyraEngine_LoK::setMouseItem(int item) { - debugC(9, kDebugLevelMain, "KyraEngine_LoK::setMouseItem(%d)", item); - if (item == -1) +void KyraEngine_LoK::setMouseItem(uint16 item) { + debugC(9, kDebugLevelMain, "KyraEngine_LoK::setMouseItem(%u)", item); + if (item == 0xFFFF) _screen->setMouseCursor(1, 1, _shapes[6]); else _screen->setMouseCursor(8, 15, _shapes[216+item]); diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 0bc5162e94..9c5548c1f7 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -177,6 +177,39 @@ KyraEngine_HoF::~KyraEngine_HoF() { _timOpcodes.clear(); } +void KyraEngine_HoF::pauseEngineIntern(bool pause) { + KyraEngine_v2::pauseEngineIntern(pause); + + if (!pause) { + uint32 pausedTime = _system->getMillis() - _pauseStart; + _pauseStart = 0; + + // sequence player + // + // Timers in KyraEngine_HoF::seq_cmpFadeFrame() and KyraEngine_HoF::seq_animatedSubFrame() + // have been left out for now. I think we don't need them here. + + _seqStartTime += pausedTime; + _seqSubFrameStartTime += pausedTime; + _seqEndTime += pausedTime; + _seqSubFrameEndTimeInternal += pausedTime; + _seqWsaChatTimeout += pausedTime; + _seqWsaChatFrameTimeout += pausedTime; + + for (int x = 0; x < 10; x++) { + if (_activeText[x].duration != -1) + _activeText[x].startTime += pausedTime; + } + + for (int x = 0; x < 8; x++) { + if (_activeWSA[x].flags != -1) + _activeWSA[x].nextFrame += pausedTime; + } + + // TODO: item animation, idle animation, tim player, etc + } +} + int KyraEngine_HoF::init() { _screen = new Screen_HoF(this, _system); assert(_screen); @@ -254,6 +287,8 @@ int KyraEngine_HoF::go() { if (_menuChoice != 4) { // load just the pak files needed for ingame _res->loadPakFile(StaticResource::staticDataFilename()); + if (_flags.useInstallerPackage) + _res->loadPakFile("WESTWOOD.001"); if (_flags.platform == Common::kPlatformPC && _flags.isTalkie) _res->loadFileList("FILEDATA.FDT"); else diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h index fe4b6390b7..866dd55d16 100644 --- a/engines/kyra/kyra_hof.h +++ b/engines/kyra/kyra_hof.h @@ -182,6 +182,8 @@ public: KyraEngine_HoF(OSystem *system, const GameFlags &flags); ~KyraEngine_HoF(); + void pauseEngineIntern(bool pause); + Screen *screen() { return _screen; } Screen_v2 *screen_v2() const { return _screen; } GUI_v2 *gui_v2() const { return _gui; } @@ -856,7 +858,12 @@ protected: uint32 _seqFrameDelay; uint32 _seqStartTime; + uint32 _seqSubFrameStartTime; uint32 _seqEndTime; + uint32 _seqSubFrameEndTimeInternal; + uint32 _seqWsaChatTimeout; + uint32 _seqWsaChatFrameTimeout; + int _seqFrameCounter; int _seqScrollTextCounter; int _seqWsaCurrentFrame; diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index 0668cc7202..c852f6e3ee 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -91,6 +91,7 @@ KyraEngine_LoK::KyraEngine_LoK(OSystem *system, const GameFlags &flags) memset(_panPagesTable, 0, sizeof(_panPagesTable)); memset(_sceneAnimTable, 0, sizeof(_sceneAnimTable)); _currHeadShape = 0; + _speechPlayTime = 0; memset(&_itemBkgBackUp, 0, sizeof(_itemBkgBackUp)); } diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h index 5e244e4925..cb3062847e 100644 --- a/engines/kyra/kyra_lok.h +++ b/engines/kyra/kyra_lok.h @@ -113,6 +113,10 @@ public: KyraEngine_LoK(OSystem *system, const GameFlags &flags); ~KyraEngine_LoK(); + //TODO: proper extended implementation of KyraEngine_v1::pauseEngineIntern. + // _sprites and _seqplayer should be paused here too, to avoid some animation glitches, + // also parts of the hardcoded Malcolm fight might need some special handling. + Screen *screen() { return _screen; } Animator_LoK *animator() { return _animator; } virtual Movie *createWSAMovie(); @@ -205,8 +209,11 @@ public: void snd_playWanderScoreViaMap(int command, int restart); virtual void snd_playVoiceFile(int id); void snd_voiceWaitForFinish(bool ingame = true); + uint32 snd_getVoicePlayTime(); protected: + int32 _speechPlayTime; + void saveGame(const char *fileName, const char *saveName); void loadGame(const char *fileName); @@ -284,7 +291,7 @@ protected: // -> mouse item void setHandItem(uint16 item); void removeHandItem(); - void setMouseItem(int item); + void setMouseItem(uint16 item); // -> graphics effects void wipeDownMouseItem(int xpos, int ypos); @@ -628,9 +635,6 @@ protected: int _cdaTrackTableSize; const AudioDataStruct * _soundData; - static const int8 _charXPosTable[]; - static const int8 _charYPosTable[]; - // positions of the inventory static const uint16 _itemPosX[]; static const uint8 _itemPosY[]; @@ -791,9 +795,9 @@ protected: int o1_pauseMusicSeconds(EMCState *script); int o1_resetMaskRegion(EMCState *script); int o1_setPaletteChangeFlag(EMCState *script); - int o1_dummy(EMCState *script); int o1_vocUnload(EMCState *script); int o1_vocLoad(EMCState *script); + int o1_dummy(EMCState *script); }; } // end of namespace Kyra diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index c0c04cb370..c842e318ec 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -370,7 +370,10 @@ void KyraEngine_MR::playVQA(const char *name) { snprintf(filename, sizeof(filename), "%s%d.VQA", name, size); if (vqa.open(filename)) { - _soundDigital->stopAllSounds(); + for (int i = 0; i < 4; ++i) { + if (i != _musicSoundChannel) + _soundDigital->stopSound(i); + } _screen->hideMouse(); memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); @@ -402,14 +405,12 @@ void KyraEngine_MR::playMenuAudioFile() { if (_soundDigital->isPlaying(_musicSoundChannel)) return; - _musicSoundChannel = _soundDigital->playSound(_menuAudioFile, 0xFF, Audio::Mixer::kMusicSoundType); + _musicSoundChannel = _soundDigital->playSound(_menuAudioFile, 0xFF, Audio::Mixer::kMusicSoundType, 255, true); } void KyraEngine_MR::snd_playWanderScoreViaMap(int track, int force) { debugC(9, kDebugLevelMain, "KyraEngine_MR::snd_playWanderScoreViaMap(%d, %d)", track, force); - // XXX byte_3C87C compare - if (_musicSoundChannel != -1 && !_soundDigital->isPlaying(_musicSoundChannel)) force = 1; else if (_musicSoundChannel == -1) diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 4ec02c7849..5af138373c 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -50,6 +50,11 @@ public: KyraEngine_MR(OSystem *system, const GameFlags &flags); ~KyraEngine_MR(); + //TODO: proper extended implementation of KyraEngine_v2::pauseEngineIntern. + // Idle animation time, item animations and album animations should be taken + // care of, but since those would just produce minor glitches it's not that + // important. + Screen *screen() { return _screen; } Screen_v2 *screen_v2() const { return _screen; } GUI_v2 *gui_v2() const { return _gui; } diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index a3d18f7713..1cc1d728bf 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -87,6 +87,11 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags) return _debugger; } +void KyraEngine_v1::pauseEngineIntern(bool pause) { + Engine::pauseEngineIntern(pause); + _timer->pause(pause); +} + int KyraEngine_v1::init() { registerDefaultSettings(); diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 81a6254c7f..4f38ceca98 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -46,11 +46,12 @@ struct GameFlags { Common::Language lang; Common::Platform platform; - bool isDemo : 1; - bool useAltShapeHeader : 1; // alternative shape header (uses 2 bytes more, those are unused though) - bool isTalkie : 1; - bool useHiResOverlay : 1; - bool useDigSound : 1; + bool isDemo : 1; + bool useAltShapeHeader : 1; // alternative shape header (uses 2 bytes more, those are unused though) + bool isTalkie : 1; + bool useHiResOverlay : 1; + bool useDigSound : 1; + bool useInstallerPackage : 1; byte gameID; }; @@ -109,6 +110,8 @@ public: ::GUI::Debugger *getDebugger(); + virtual void pauseEngineIntern(bool pause); + bool quit() const { return _quitFlag; } uint8 game() const { return _flags.gameID; } @@ -263,6 +266,11 @@ protected: static const int8 _addXPosTable[]; static const int8 _addYPosTable[]; + // Character + + static const int8 _charAddXPosTable[]; + static const int8 _charAddYPosTable[]; + // save/load int _gameToLoad; diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 7b720259cc..12da338843 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -68,6 +68,8 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi memset(&_mainCharacter, 0, sizeof(_mainCharacter)); memset(&_mainCharacter.inventory, -1, sizeof(_mainCharacter.inventory)); + + _pauseStart = 0; } KyraEngine_v2::~KyraEngine_v2() { @@ -93,6 +95,22 @@ KyraEngine_v2::~KyraEngine_v2() { delete[] _screenBuffer; } +void KyraEngine_v2::pauseEngineIntern(bool pause) { + KyraEngine_v1::pauseEngineIntern(pause); + + if (!pause) { + uint32 pausedTime = _system->getMillis() - _pauseStart; + + for (int i = 0; i < ARRAYSIZE(_sceneSpecialScriptsTimer); ++i) { + if (_sceneSpecialScriptsTimer[i]) + _sceneSpecialScriptsTimer[i] += pausedTime; + } + + } else { + _pauseStart = _system->getMillis(); + } +} + void KyraEngine_v2::delay(uint32 amount, bool updateGame, bool isMainLoop) { debugC(9, kDebugLevelMain, "KyraEngine_v2::delay(%u, %d, %d)", amount, updateGame, isMainLoop); @@ -326,8 +344,8 @@ int KyraEngine_v2::updateCharPos(int *table, int force) { debugC(9, kDebugLevelMain, "KyraEngine_v2::updateCharPos(%p, %d)", (const void*)table, force); if (_updateCharPosNextUpdate > _system->getMillis() && !force) return 0; - _mainCharacter.x1 += _updateCharPosXTable[_mainCharacter.facing]; - _mainCharacter.y1 += _updateCharPosYTable[_mainCharacter.facing]; + _mainCharacter.x1 += _charAddXPosTable[_mainCharacter.facing]; + _mainCharacter.y1 += _charAddYPosTable[_mainCharacter.facing]; updateCharAnimFrame(0, table); _updateCharPosNextUpdate = _system->getMillis() + getCharacterWalkspeed() * _tickLength; return 1; diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index 2f6d8a6185..24f7aad614 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -75,6 +75,8 @@ public: KyraEngine_v2(OSystem *system, const GameFlags &flags, const EngineDesc &desc); ~KyraEngine_v2(); + virtual void pauseEngineIntern(bool pause); + virtual Screen_v2 *screen_v2() const = 0; virtual GUI *gui_v2() const = 0; @@ -85,6 +87,7 @@ protected: EngineDesc _desc; // run + uint32 _pauseStart; bool _runFlag; bool _showOutro; @@ -355,8 +358,6 @@ protected: void updateCharPosWithUpdate(); uint32 _updateCharPosNextUpdate; - static const int8 _updateCharPosXTable[]; - static const int8 _updateCharPosYTable[]; virtual int getCharacterWalkspeed() const = 0; virtual void updateCharAnimFrame(int num, int *table) = 0; diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index 9d34c669a1..6b38a0f907 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -30,10 +30,10 @@ #include "common/fs.h" #include "common/func.h" -#include "gui/message.h" - #include "kyra/resource.h" +#define INS_CACHE_THRESHOLD 300000 // all files with file size greater than this will be cached + namespace Kyra { Resource::Resource(KyraEngine_v1 *vm) : _loaders(), _map(), _vm(vm) { @@ -55,8 +55,7 @@ bool Resource::reset() { if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat()) { Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website"; - ::GUI::MessageDialog errorMsg(errorMessage); - errorMsg.runModal(); + _vm->GUIErrorMessage(errorMessage); error(errorMessage.c_str()); } @@ -69,17 +68,31 @@ bool Resource::reset() { if (_vm->gameFlags().isTalkie) loadPakFile("CHAPTER1.VRM"); } else if (_vm->game() == GI_KYRA2) { + if (_vm->gameFlags().useInstallerPackage) + loadPakFile("WESTWOOD.001"); + // mouse pointer, fonts, etc. required for initializing if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) { loadPakFile("GENERAL.PAK"); } else { + if (_vm->gameFlags().isTalkie) { + // Add default file directories + Common::File::addDefaultDirectory(ConfMan.get("path") + "hof_cd"); + Common::File::addDefaultDirectory(ConfMan.get("path") + "HOF_CD"); + } + loadPakFile("INTROGEN.PAK"); loadPakFile("OTHER.PAK"); } return true; } else if (_vm->game() == GI_KYRA3) { - loadPakFile("WESTWOOD.001"); + if (_vm->gameFlags().useInstallerPackage) + loadPakFile("WESTWOOD.001"); + // Add default file directories + Common::File::addDefaultDirectory(ConfMan.get("path") + "malcolm"); + Common::File::addDefaultDirectory(ConfMan.get("path") + "MALCOLM"); + loadFileList("FILEDATA.FDT"); return true; @@ -210,7 +223,7 @@ bool Resource::loadFileList(const Common::String &filedata) { buffer[12] = 0; f.seek(offset + 16, SEEK_SET); - Common::String filename = (char*)buffer; + Common::String filename = Common::String((char*)buffer); filename.toUppercase(); if (filename.hasSuffix(".PAK")) { @@ -569,7 +582,7 @@ Common::SeekableReadStream *ResLoaderPak::loadFileFromArchive(const Common::Stri return stream; } -class ResLoaderIns : public ResArchiveLoader { +class ResLoaderInsKyra : public ResArchiveLoader { public: bool checkFilename(Common::String filename) const; bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; @@ -577,16 +590,790 @@ public: Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const; ResFileEntry::kType getType() const { - return ResFileEntry::kIns; + return ResFileEntry::kInsKyra; + } +}; + +bool ResLoaderInsKyra::checkFilename(Common::String filename) const { + return false; +} + +bool ResLoaderInsKyra::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { + return true; +} + +bool ResLoaderInsKyra::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const { + return true; +} + +Common::SeekableReadStream *ResLoaderInsKyra::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const { + return 0; +} + +class FileExpanderSource { +public: + FileExpanderSource(const uint8 *data) : _dataPtr(data), _bitsLeft(8), _key(0), _index(0) {} + ~FileExpanderSource() {} + + void advSrcRefresh(); + void advSrcBitsBy1(); + void advSrcBitsByIndex(uint8 newIndex); + + uint8 getKeyLower() { return _key & 0xff; } + void setIndex(uint8 index) { _index = index; } + uint16 getKeyMasked(uint8 newIndex); + uint16 keyMaskedAlign(uint16 val); + + void copyBytes(uint8 *& dst); + +private: + const uint8 *_dataPtr; + uint16 _key; + int8 _bitsLeft; + uint8 _index; +}; + +void FileExpanderSource::advSrcBitsBy1() { + _key >>= 1; + if (!--_bitsLeft) { + _key = ((*_dataPtr++) << 8 ) | (_key & 0xff); + _bitsLeft = 8; + } +} + +void FileExpanderSource::advSrcBitsByIndex(uint8 newIndex) { + _index = newIndex; + _bitsLeft -= _index; + if (_bitsLeft <= 0) { + _key >>= (_index + _bitsLeft); + _index = -_bitsLeft; + _bitsLeft = 8 - _index; + _key = (*_dataPtr++ << 8) | (_key & 0xff); + } + _key >>= _index; +} + +uint16 FileExpanderSource::getKeyMasked(uint8 newIndex) { + static const uint8 mskTable[] = { 0x0F, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF }; + _index = newIndex; + uint16 res = 0; + + if (_index > 8) { + newIndex = _index - 8; + res = (_key & 0xff) & mskTable[8]; + advSrcBitsByIndex(8); + _index = newIndex; + res |= (((_key & 0xff) & mskTable[_index]) << 8); + advSrcBitsByIndex(_index); + } else { + res = (_key & 0xff) & mskTable[_index]; + advSrcBitsByIndex(_index); } + + return res; +} + +void FileExpanderSource::copyBytes(uint8 *& dst) { + advSrcBitsByIndex(_bitsLeft); + uint16 r = (READ_LE_UINT16(_dataPtr) ^ _key) + 1; + _dataPtr += 2; + + if (r) + error("decompression failure"); + + memcpy(dst, _dataPtr, _key); + _dataPtr += _key; + dst += _key; +} + +uint16 FileExpanderSource::keyMaskedAlign(uint16 val) { + val -= 0x101; + _index = (val & 0xff) >> 2; + int16 b = ((_bitsLeft << 8) | _index) - 1; + _bitsLeft = b >> 8; + _index = b & 0xff; + return (((val & 3) + 4) << _index) + 0x101 + getKeyMasked(_index); +} + +void FileExpanderSource::advSrcRefresh() { + _key = READ_LE_UINT16(_dataPtr); + _dataPtr += 2; + _bitsLeft = 8; +} + +class FileExpander { +public: + FileExpander(); + ~FileExpander(); + + bool process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 insize); + +private: + void generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt); + uint8 calcCmdAndIndex(const uint8 *tbl, int16 ¶); + + FileExpanderSource *_src; + uint8 *_tables[9]; + uint16 *_tables16[3]; }; -bool ResLoaderIns::checkFilename(Common::String filename) const { +FileExpander::FileExpander() : _src(0) { + _tables[0] = new uint8[3914]; + assert(_tables[0]); + + _tables[1] = _tables[0] + 320; + _tables[2] = _tables[0] + 352; + _tables[3] = _tables[0] + 864; + _tables[4] = _tables[0] + 2016; + _tables[5] = _tables[0] + 2528; + _tables[6] = _tables[0] + 2656; + _tables[7] = _tables[0] + 2736; + _tables[8] = _tables[0] + 2756; + + _tables16[0] = (uint16 *)(_tables[0] + 3268); + _tables16[1] = (uint16 *)(_tables[0] + 3302); + _tables16[2] = (uint16 *)(_tables[0] + 3338); +} + +FileExpander::~FileExpander() { + delete _src; + delete[] _tables[0]; +} + +bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 compressedSize) { + static const uint8 indexTable[] = { + 0x10, 0x11, 0x12, 0x00, 0x08, 0x07, 0x09, 0x06, 0x0A, + 0x05, 0x0B, 0x04, 0x0C, 0x03, 0x0D, 0x02, 0x0E, 0x01, 0x0F + }; + + memset(_tables[0], 0, 3914); + + uint8 *d = dst; + uint16 tableSize0 = 0; + uint16 tableSize1 = 0; + bool needrefresh = true; + bool postprocess = false; + + _src = new FileExpanderSource(src); + + while (d < dst + outsize) { + + if (needrefresh) { + needrefresh = false; + _src->advSrcRefresh(); + } + + _src->advSrcBitsBy1(); + + int mode = _src->getKeyMasked(2) - 1; + if (mode == 1) { + tableSize0 = _src->getKeyMasked(5) + 257; + tableSize1 = _src->getKeyMasked(5) + 1; + memset(_tables[7], 0, 19); + + const uint8 *itbl = indexTable; + int numbytes = _src->getKeyMasked(4) + 4; + + while (numbytes--) + _tables[7][*itbl++] = _src->getKeyMasked(3); + + generateTables(7, 8, 255, 19); + + int cnt = tableSize0 + tableSize1; + uint8 *tmp = _tables[0]; + + while (cnt) { + uint16 cmd = _src->getKeyLower(); + cmd = READ_LE_UINT16(&_tables[8][cmd << 1]); + _src->advSrcBitsByIndex(_tables[7][cmd]); + + if (cmd < 16) { + *tmp++ = cmd; + cnt--; + } else { + uint8 tmpI = 0; + if (cmd == 16) { + cmd = _src->getKeyMasked(2) + 3; + tmpI = *(tmp - 1); + } else if (cmd == 17) { + cmd = _src->getKeyMasked(3) + 3; + } else { + cmd = _src->getKeyMasked(7) + 11; + } + _src->setIndex(tmpI); + memset(tmp, tmpI, cmd); + tmp += cmd; + + cnt -= cmd; + if (cnt < 0) + error("decompression failure"); + } + } + + memcpy(_tables[1], _tables[0] + tableSize0, tableSize1); + generateTables(0, 2, 3, tableSize0); + generateTables(1, 4, 5, tableSize1); + postprocess = true; + } else if (mode < 0) { + _src->copyBytes(d); + postprocess = false; + needrefresh = true; + } else if (mode == 0){ + uint8 *d2 = _tables[0]; + memset(d2, 8, 144); + memset(d2 + 144, 9, 112); + memset(d2 + 256, 7, 24); + memset(d2 + 280, 8, 8); + d2 = _tables[1]; + memset(d2, 5, 32); + tableSize0 = 288; + tableSize1 = 32; + + generateTables(0, 2, 3, tableSize0); + generateTables(1, 4, 5, tableSize1); + postprocess = true; + } else { + error("decompression failure"); + } + + if (!postprocess) + continue; + + int16 cmd = 0; + + do { + cmd = ((int16*) _tables[2])[_src->getKeyLower()]; + _src->advSrcBitsByIndex(cmd < 0 ? calcCmdAndIndex(_tables[3], cmd) : _tables[0][cmd]); + + if (cmd == 0x11d) { + cmd = 0x200; + } else if (cmd > 0x108) { + cmd = _src->keyMaskedAlign(cmd); + } + + if (!(cmd >> 8)) { + *d++ = cmd & 0xff; + } else if (cmd != 0x100) { + cmd -= 0xfe; + int16 offset = ((int16*) _tables[4])[_src->getKeyLower()]; + _src->advSrcBitsByIndex(offset < 0 ? calcCmdAndIndex(_tables[5], offset) : _tables[1][offset]); + if ((offset & 0xff) >= 4) { + uint8 newIndex = ((offset & 0xff) >> 1) - 1; + offset = (((offset & 1) + 2) << newIndex) + _src->getKeyMasked(newIndex); + } + + uint8 *s2 = d - 1 - offset; + if (s2 >= dst) { + while (cmd--) + *d++ = *s2++; + } else { + uint32 pos = dst - s2; + s2 += (d - dst); + + if (pos < (uint32) cmd) { + cmd -= pos; + while (pos--) + *d++ = *s2++; + s2 = dst; + } + while (cmd--) + *d++ = *s2++; + } + } + } while (cmd != 0x100); + } + + delete _src; + _src = 0; + + return true; +} + +void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt) { + const uint8 *tbl1 = _tables[srcIndex]; + const uint8 *tbl2 = _tables[dstIndex]; + const uint8 *tbl3 = dstIndex2 == 0xff ? 0 : _tables[dstIndex2]; + + if (!cnt) + return; + + const uint8 *s = tbl1; + memset(_tables16[0], 0, 32); + + for (int i = 0; i < cnt; i++) + _tables16[0][(*s++)]++; + + _tables16[1][1] = 0; + + for (uint16 i = 1, r = 0; i < 16; i++) { + r = (r + _tables16[0][i]) << 1; + _tables16[1][i + 1] = r; + } + + if (_tables16[1][16]) { + uint16 r = 0; + for (uint16 i = 1; i < 16; i++) + r += _tables16[0][i]; + if (r > 1) + error("decompression failure"); + } + + s = tbl1; + uint16 *d = _tables16[2]; + for (int i = 0; i < cnt; i++) { + uint16 t = *s++; + if (t) { + _tables16[1][t]++; + t = _tables16[1][t] - 1; + } + *d++ = t; + } + + s = tbl1; + d = _tables16[2]; + for (int i = 0; i < cnt; i++) { + int8 t = ((int8)(*s++)) - 1; + if (t > 0) { + uint16 v1 = *d; + uint16 v2 = 0; + + do { + v2 = (v2 << 1) | (v1 & 1); + v1 >>= 1; + } while (--t && v1); + + t++; + uint8 c1 = (v1 & 1); + while (t--) { + uint8 c2 = v2 >> 15; + v2 = (v2 << 1) | c1; + c1 = c2; + }; + + *d++ = v2; + } else { + d++; + } + } + + memset((void*) tbl2, 0, 512); + + cnt--; + s = tbl1 + cnt; + d = &_tables16[2][cnt]; + uint16 * bt = (uint16*) tbl3; + uint16 inc = 0; + uint16 cnt2 = 0; + + do { + uint8 t = *s--; + uint16 *s2 = (uint16*) tbl2; + + if (t && t < 9) { + inc = 1 << t; + uint16 o = *d; + + do { + s2[o] = cnt; + o += inc; + } while (!(o & 0xf00)); + + } else if (t > 8) { + if (!bt) + error("decompression failure"); + + t -= 8; + uint8 shiftCnt = 1; + uint8 v = (*d) >> 8; + s2 = &((uint16*) tbl2)[*d & 0xff]; + + do { + if (!*s2) { + *s2 = (uint16)(~cnt2); + *(uint32*)&bt[cnt2] = 0; + cnt2 += 2; + } + + s2 = &bt[(uint16)(~*s2)]; + if (v & shiftCnt) + s2++; + + shiftCnt <<= 1; + } while (--t); + *s2 = cnt; + } + d--; + } while (--cnt >= 0); +} + +uint8 FileExpander::calcCmdAndIndex(const uint8 *tbl, int16 ¶) { + const uint16 *t = (const uint16*)tbl; + _src->advSrcBitsByIndex(8); + uint8 newIndex = 0; + uint16 v = _src->getKeyLower(); + + do { + newIndex++; + para = t[((~para) & 0xfffe) | (v & 1)]; + v >>= 1; + } while (para < 0); + + return newIndex; +} + +class FileCache { +public: + FileCache() : _size(0) {} + ~FileCache() {} + + void add(ResFileEntry entry, const uint8 *data); + bool getData(ResFileEntry entry, uint8 *dst); + void flush(); + +private: + struct FileCacheEntry { + ResFileEntry entry; + const uint8 *data; + }; + + Common::List<FileCacheEntry> _cachedFileList; + uint32 _size; +}; + +void FileCache::add(ResFileEntry entry, const uint8 *data) { + FileCacheEntry fileCacheEntry; + fileCacheEntry.entry.compressedSize = entry.compressedSize; + fileCacheEntry.entry.mounted = entry.mounted; + fileCacheEntry.entry.offset = entry.offset; + fileCacheEntry.entry.parent = entry.parent; + fileCacheEntry.entry.preload = entry.preload; + fileCacheEntry.entry.prot = entry.prot; + fileCacheEntry.entry.size = entry.size; + fileCacheEntry.entry.type = entry.type; + fileCacheEntry.entry.fileIndex = entry.fileIndex; + uint8 *dst = new uint8[entry.size]; + assert(dst); + memcpy(dst, data, entry.size); + fileCacheEntry.data = dst; + _cachedFileList.push_back(fileCacheEntry); + _size += entry.size; +} + +bool FileCache::getData(ResFileEntry entry, uint8 *dst) { + for (Common::List<FileCacheEntry>::const_iterator c = _cachedFileList.begin(); c != _cachedFileList.end(); ++c) { + if (c->entry.offset == entry.offset && c->entry.compressedSize == entry.compressedSize && + c->entry.fileIndex == entry.fileIndex && c->entry.size == entry.size) { + memcpy(dst, c->data, c->entry.size); + return true; + } + } + return false; +} + +void FileCache::flush() { + debug(1, "total amount of cache memory used: %d", _size); + for (Common::List<FileCacheEntry>::const_iterator c = _cachedFileList.begin(); c != _cachedFileList.end(); ++c) + delete[] c->data; + _cachedFileList.clear(); + _size = 0; +} + +class ResLoaderInsHof : public ResArchiveLoader { +public: + ResLoaderInsHof() {} + ~ResLoaderInsHof() { _fileCache.flush(); } + + bool checkFilename(Common::String filename) const; + bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; + bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const; + Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const; + + ResFileEntry::kType getType() const { + return ResFileEntry::kInsHof; + } +private: + mutable FileCache _fileCache; +}; + +bool ResLoaderInsHof::checkFilename(Common::String filename) const { + filename.toUppercase(); + if (!filename.hasSuffix(".001")) + return false; + filename.insertChar('2', filename.size() - 1); + filename.deleteLastChar(); + if (!Common::File::exists(filename)) + return false; + return true; +} + +bool ResLoaderInsHof::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { + uint8 fileId = stream.readByte(); + uint32 size = stream.readUint32LE(); + + if (size < stream.size() + 1) + return false; + + return (fileId == 1); +} + +bool ResLoaderInsHof::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const { + Common::File tmpFile; + + uint32 pos = 0; + uint32 bytesleft = 0; + bool startFile = true; + + Common::String filenameBase(filename.c_str(), 10); + Common::String filenameTemp; + char filenameExt[4]; + + while (filenameBase.lastChar() != '.') + filenameBase.deleteLastChar(); + + InsHofArchive newArchive; + + Common::List<InsHofArchive> archives; + + for (int8 currentFile = 1; currentFile; currentFile++) { + sprintf(filenameExt, "%03d", currentFile); + filenameTemp = filenameBase + Common::String(filenameExt); + + if (!tmpFile.open(filenameTemp)) { + debug(3, "couldn't open file '%s'\n", filenameTemp.c_str()); + break; + } + + tmpFile.seek(pos); + uint8 fileId = tmpFile.readByte(); + pos++; + + uint32 size = tmpFile.size() - 1; + if (startFile) { + size -= 4; + if (fileId == currentFile) { + size -= 6; + pos += 6; + tmpFile.seek(6, SEEK_CUR); + } else { + size = size + 1 - pos; + } + newArchive.filename = filenameBase; + bytesleft = newArchive.totalSize = tmpFile.readUint32LE(); + pos += 4; + newArchive.firstFile = currentFile; + newArchive.startOffset = pos; + startFile = false; + } + + uint32 cs = MIN(size, bytesleft); + bytesleft -= cs; + + tmpFile.close(); + + pos += cs; + if (cs == size) { + if (!bytesleft) { + newArchive.lastFile = currentFile; + newArchive.endOffset = --pos; + archives.push_back(newArchive); + currentFile = -1; + } else { + pos = 0; + } + } else { + startFile = true; + bytesleft = size - cs; + newArchive.lastFile = currentFile--; + newArchive.endOffset = --pos; + archives.push_back(newArchive); + } + } + + ResFileEntry newEntry; + pos = 0; + + const uint32 kExecSize = 0x0bba; + const uint32 kHeaderSize = 30; + const uint32 kHeaderSize2 = 46; + + for (Common::List<InsHofArchive>::iterator a = archives.begin(); a != archives.end(); ++a) { + startFile = true; + for (uint32 i = a->firstFile; i != (a->lastFile + 1); i++) { + sprintf(filenameExt, "%03d", i); + filenameTemp = a->filename + Common::String(filenameExt); + + if (!tmpFile.open(filenameTemp)) { + debug(3, "couldn't open file '%s'\n", filenameTemp.c_str()); + break; + } + + uint32 size = (i == a->lastFile) ? a->endOffset : tmpFile.size(); + + if (startFile) { + startFile = false; + pos = a->startOffset + kExecSize; + if (pos > size) { + pos -= size; + tmpFile.close(); + continue; + } + } else { + pos ++; + } + + while (pos < size) { + uint8 hdr[43]; + uint32 m = 0; + tmpFile.seek(pos); + + if (pos + 42 > size) { + m = size - pos; + uint32 b = 42 - m; + + if (m >= 4) { + uint32 id = tmpFile.readUint32LE(); + if (id == 0x06054B50) { + startFile = true; + break; + } else { + tmpFile.seek(pos); + } + } + + sprintf(filenameExt, "%03d", i + 1); + filenameTemp = a->filename + Common::String(filenameExt); + + Common::File tmpFile2; + tmpFile2.open(filenameTemp); + tmpFile.read(hdr, m); + tmpFile2.read(hdr + m, b); + tmpFile2.close(); + + } else { + tmpFile.read(hdr, 42); + } + + uint32 id = READ_LE_UINT32(hdr); + + if (id == 0x04034B50) { + if (hdr[8] != 8) + error("compression type not implemented"); + newEntry.compressedSize = READ_LE_UINT32(hdr + 18); + newEntry.size = READ_LE_UINT32(hdr + 22); + + uint16 filestrlen = READ_LE_UINT16(hdr + 26); + *(hdr + 30 + filestrlen) = 0; + pos += (kHeaderSize + filestrlen - m); + + newEntry.parent = filename; + newEntry.offset = pos; + newEntry.type = ResFileEntry::kAutoDetect; + newEntry.mounted = false; + newEntry.preload = false; + newEntry.prot = false; + newEntry.fileIndex = i; + files.push_back(File(Common::String((const char *)(hdr + 30)), newEntry)); + + pos += newEntry.compressedSize; + if (pos > size) { + pos -= size; + break; + } + } else { + uint32 filestrlen = READ_LE_UINT32(hdr + 28); + pos += (kHeaderSize2 + filestrlen - m); + } + } + tmpFile.close(); + } + } + + archives.clear(); + + return true; +} + +Common::SeekableReadStream *ResLoaderInsHof::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const { + if (archive) { + delete archive; + archive = 0; + } + + uint8 *outbuffer = (uint8 *)malloc(entry.size); + assert(outbuffer); + + if (!_fileCache.getData(entry, outbuffer)) { + Common::File tmpFile; + char filename[13]; + sprintf(filename, "WESTWOOD.%03d", entry.fileIndex); + + if (!tmpFile.open(filename)) { + free(outbuffer); + return 0; + } + + tmpFile.seek(entry.offset); + + uint8 *inbuffer = new uint8[entry.compressedSize]; + assert(inbuffer); + + if ((entry.offset + entry.compressedSize) > tmpFile.size()) { + // this is for files that are split between two archive files + uint32 a = tmpFile.size() - entry.offset; + uint32 b = entry.compressedSize - a; + + tmpFile.read(inbuffer, a); + tmpFile.close(); + + filename[strlen(filename) - 1]++; + + if (!tmpFile.open(filename)) + return 0; + tmpFile.seek(1); + tmpFile.read(inbuffer + a, b); + } else { + tmpFile.read(inbuffer, entry.compressedSize); + } + + tmpFile.close(); + + FileExpander().process(outbuffer, inbuffer, entry.size, entry.compressedSize); + delete[] inbuffer; + + if (entry.size > INS_CACHE_THRESHOLD) + _fileCache.add(entry, outbuffer); + } + + Common::MemoryReadStream *stream = new Common::MemoryReadStream(outbuffer, entry.size, true); + assert(stream); + + return stream; +} + +class ResLoaderInsMalcolm : public ResArchiveLoader { +public: + bool checkFilename(Common::String filename) const; + bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; + bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const; + Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const; + + ResFileEntry::kType getType() const { + return ResFileEntry::kInsMal; + } +}; + +bool ResLoaderInsMalcolm::checkFilename(Common::String filename) const { filename.toUppercase(); - return (filename.hasSuffix(".001")); + if (!filename.hasSuffix(".001")) + return false; + filename.insertChar('2', filename.size() - 1); + filename.deleteLastChar(); + if (Common::File::exists(filename)) + return false; + return true; } -bool ResLoaderIns::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { +bool ResLoaderInsMalcolm::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { stream.seek(3); uint32 size = stream.readUint32LE(); @@ -600,7 +1387,7 @@ bool ResLoaderIns::isLoadable(const Common::String &filename, Common::SeekableRe return (buffer[0] == 0x0D && buffer[1] == 0x0A); } -bool ResLoaderIns::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const { +bool ResLoaderInsMalcolm::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const { Common::List<Common::String> filenames; // thanks to eriktorbjorn for this code (a bit modified though) @@ -645,7 +1432,7 @@ bool ResLoaderIns::loadFile(const Common::String &filename, Common::SeekableRead return true; } -Common::SeekableReadStream *ResLoaderIns::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const { +Common::SeekableReadStream *ResLoaderInsMalcolm::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const { assert(archive); archive->seek(entry.offset, SEEK_SET); @@ -738,7 +1525,9 @@ Common::SeekableReadStream *ResLoaderTlk::loadFileFromArchive(const Common::Stri void Resource::initializeLoaders() { _loaders.push_back(LoaderList::value_type(new ResLoaderPak())); - _loaders.push_back(LoaderList::value_type(new ResLoaderIns())); + _loaders.push_back(LoaderList::value_type(new ResLoaderInsKyra())); + _loaders.push_back(LoaderList::value_type(new ResLoaderInsHof())); + _loaders.push_back(LoaderList::value_type(new ResLoaderInsMalcolm())); _loaders.push_back(LoaderList::value_type(new ResLoaderTlk())); } diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index a8de21b5ca..90405690a4 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -41,6 +41,15 @@ namespace Kyra { +struct InsHofArchive { + Common::String filename; + uint32 firstFile; + uint32 startOffset; + uint32 lastFile; + uint32 endOffset; + uint32 totalSize; +}; + struct ResFileEntry { Common::String parent; uint32 size; @@ -52,12 +61,17 @@ struct ResFileEntry { enum kType { kRaw = 0, kPak = 1, - kIns = 2, - kTlk = 3, + kInsKyra = 2, + kInsHof = 3, + kInsMal = 4, + kTlk = 5, kAutoDetect }; kType type; uint32 offset; + + int fileIndex; + uint32 compressedSize; }; typedef Common::HashMap<Common::String, ResFileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ResFileMap; @@ -271,7 +285,7 @@ public: bool prefetchId(int id); void unloadId(int id); private: - void outputError(); + void outputError(const Common::String &error); KyraEngine_v1 *_vm; diff --git a/engines/kyra/scene_lok.cpp b/engines/kyra/scene_lok.cpp index 085332b525..e4ae67f751 100644 --- a/engines/kyra/scene_lok.cpp +++ b/engines/kyra/scene_lok.cpp @@ -295,13 +295,13 @@ int KyraEngine_LoK::setCharacterPosition(int character, int *facingTable) { debugC(9, kDebugLevelMain, "KyraEngine_LoK::setCharacterPosition(%d, %p)", character, (const void *)facingTable); if (character == 0) { - _currentCharacter->x1 += _charXPosTable[_currentCharacter->facing]; - _currentCharacter->y1 += _charYPosTable[_currentCharacter->facing]; + _currentCharacter->x1 += _charAddXPosTable[_currentCharacter->facing]; + _currentCharacter->y1 += _charAddYPosTable[_currentCharacter->facing]; setCharacterPositionHelper(0, facingTable); return 1; } else { - _characterList[character].x1 += _charXPosTable[_characterList[character].facing]; - _characterList[character].y1 += _charYPosTable[_characterList[character].facing]; + _characterList[character].x1 += _charAddXPosTable[_characterList[character].facing]; + _characterList[character].y1 += _charAddYPosTable[_characterList[character].facing]; if (_characterList[character].sceneId == _currentCharacter->sceneId) setCharacterPositionHelper(character, 0); } @@ -1009,8 +1009,8 @@ int KyraEngine_LoK::changeScene(int facing) { return 0; } - int xpos = _charXPosTable[facing] + _currentCharacter->x1; - int ypos = _charYPosTable[facing] + _currentCharacter->y1; + int xpos = _charAddXPosTable[facing] + _currentCharacter->x1; + int ypos = _charAddYPosTable[facing] + _currentCharacter->y1; if (xpos >= 12 && xpos <= 308) { if (!lineIsPassable(xpos, ypos)) diff --git a/engines/kyra/scene_v2.cpp b/engines/kyra/scene_v2.cpp index 7072cfc9a5..3bf81bfb39 100644 --- a/engines/kyra/scene_v2.cpp +++ b/engines/kyra/scene_v2.cpp @@ -98,7 +98,7 @@ int KyraEngine_v2::findWay(int x, int y, int toX, int toY, int *moveTable, int m temp = pathfinderInitPositionIndexTable(temp, x, y); pathfinderFinializePath(moveTable, temp, x, y, moveTableSize); usePostProcess = false; - } + } return usePostProcess ? size : getMoveTableSize(moveTable); } @@ -106,13 +106,14 @@ bool KyraEngine_v2::directLinePassable(int x, int y, int toX, int toY) { debugC(9, kDebugLevelMain, "KyraEngine_v2::directLinePassable(%d, %d, %d, %d)", x, y, toX, toY); Screen *scr = screen(); - while (x != toX && y != toY) { + while (x != toX || y != toY) { int facing = getFacingFromPointToPoint(x, y, toX, toY); x += _addXPosTable[facing]; y += _addYPosTable[facing]; if (!scr->getShapeFlag1(x, y)) return false; } + return true; } diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index d2b6b08183..91fbfb3e49 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -760,7 +760,7 @@ int KyraEngine_HoF::o2_showItemString(EMCState *script) { int KyraEngine_HoF::o2_isAnySoundPlaying(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_isAnySoundPlaying(%p) ()", (const void *)script); - return _sound->voiceIsPlaying(); + return _sound->voiceIsPlaying() ? 1 : 0; } int KyraEngine_HoF::o2_setDrawNoShapeFlag(EMCState *script) { @@ -800,7 +800,7 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) { _screen->fadeToBlack(0x14); sprintf(filename, "LETTER%.1d.", letter); - strcat(filename, _languageExtension[_lang]); + strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); uint8 *letterBuffer = _res->fileData(filename, 0); if (letterBuffer) { diff --git a/engines/kyra/script_lok.cpp b/engines/kyra/script_lok.cpp index 670c7282e3..efa0f8e48f 100644 --- a/engines/kyra/script_lok.cpp +++ b/engines/kyra/script_lok.cpp @@ -35,6 +35,7 @@ #include "kyra/animator_lok.h" #include "kyra/text.h" #include "kyra/timer.h" +#include "kyra/sound.h" namespace Kyra { int KyraEngine_LoK::o1_magicInMouseItem(EMCState *script) { @@ -320,9 +321,20 @@ int KyraEngine_LoK::o1_setBrandonStatusBit(EMCState *script) { } int KyraEngine_LoK::o1_delaySecs(EMCState *script) { - debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_delaySecs(%p) (%d)", (const void *)script, stackPos(0)); - if (stackPos(0) > 0 && !_skipFlag) - delay(stackPos(0)*1000, true); + if (_flags.isTalkie && speechEnabled()) { + debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_voiceDelay(%p) (%d)", (const void *)script, stackPos(0)); + if (stackPos(0) == 0) { + snd_voiceWaitForFinish(true); + } else if (stackPos(0) < 0) { + uint32 time = ABS(stackPos(0)) * _tickLength; + delay(time, true); + } + } else { + debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_delaySecs(%p) (%d)", (const void *)script, stackPos(0)); + if (stackPos(0) >= 0 && !_skipFlag) + delay(stackPos(0)*1000, true); + } + _skipFlag = false; return 0; } @@ -700,7 +712,10 @@ int KyraEngine_LoK::o1_displayWSAFrameOnHidPage(EMCState *script) { } int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) { - debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSASequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6)); + if (_flags.isTalkie) + debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSASequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7)); + else + debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSASequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6)); int startFrame = stackPos(0); int endFrame = stackPos(1); int xpos = stackPos(2); @@ -708,6 +723,40 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) { int waitTime = stackPos(4); int wsaIndex = stackPos(5); int maxTime = stackPos(6); + + if (_flags.isTalkie) { + int specialTime = stackPos(7); + if (specialTime) { + uint32 voiceTime = snd_getVoicePlayTime(); + if (voiceTime) { + int displayFrames = ABS(endFrame-startFrame)+1; + displayFrames *= maxTime; + assert(displayFrames != 0); + + bool voiceSync = false; + + if (specialTime < 0) { + voiceSync = true; + specialTime = ABS(specialTime); + } + + voiceTime *= specialTime; + voiceTime /= 100; + + if (voiceSync) { + uint32 voicePlayedTime = _sound->voicePlayedTime(_speechFile.c_str()); + if (voicePlayedTime >= voiceTime) + voiceTime = 0; + else + voiceTime -= voicePlayedTime; + } + + waitTime = voiceTime / displayFrames; + waitTime /= _tickLength; + } + } + } + if (maxTime - 1 <= 0) maxTime = 1; @@ -734,7 +783,8 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) { while (endFrame >= frame) { uint32 continueTime = waitTime * _tickLength + _system->getMillis(); _movieObjects[wsaIndex]->displayFrame(frame); - _animator->_updateScreen = true; + if (waitTime) + _animator->_updateScreen = true; while (_system->getMillis() < continueTime) { _sprites->updateSceneAnims(); _animator->updateAllObjectShapes(); @@ -751,7 +801,8 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) { while (endFrame <= frame) { uint32 continueTime = waitTime * _tickLength + _system->getMillis(); _movieObjects[wsaIndex]->displayFrame(frame); - _animator->_updateScreen = true; + if (waitTime) + _animator->_updateScreen = true; while (_system->getMillis() < continueTime) { _sprites->updateSceneAnims(); _animator->updateAllObjectShapes(); @@ -1691,7 +1742,7 @@ int KyraEngine_LoK::o1_pauseMusicSeconds(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_pauseMusicSeconds(%p) ()", (const void *)script); // if music disabled // return - o1_delaySecs(script); + delay(stackPos(0)*1000, true); return 0; } diff --git a/engines/kyra/script_v1.cpp b/engines/kyra/script_v1.cpp index 7881605b9e..f74c7e3560 100644 --- a/engines/kyra/script_v1.cpp +++ b/engines/kyra/script_v1.cpp @@ -96,9 +96,9 @@ int KyraEngine_v1::o1_playWanderScoreViaMap(EMCState *script) { return 0; } -int KyraEngine_v1::o1_fillRect(EMCState *script) { +int KyraEngine_v1::o1_fillRect(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_fillRect(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5)); - screen()->fillRect(stackPos(1), stackPos(2), stackPos(1)+stackPos(3), stackPos(2)+stackPos(4), stackPos(5), stackPos(0)); + screen()->fillRect(stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(0)); return 0; } diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp index 3e9f6030ac..0751fc15db 100644 --- a/engines/kyra/sequences_hof.cpp +++ b/engines/kyra/sequences_hof.cpp @@ -231,7 +231,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { _seqFrameDelay = cseq.frameDelay; _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength; while (!((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { - uint32 starttime = _system->getMillis(); + _seqSubFrameStartTime = _system->getMillis(); seq_processWSAs(); if (cb) (this->*cb)(0, 0, 0, 0); @@ -246,8 +246,8 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { if (now >= _seqEndTime && !_seqSubframePlaying) break; - uint32 tdiff = _seqEndTime - starttime; - int32 dly = _tickLength - (now - starttime); + uint32 tdiff = _seqEndTime - _seqSubFrameStartTime; + int32 dly = _tickLength - (now - _seqSubFrameStartTime); if (dly > 0) delay(MIN<uint32>(dly, tdiff)); } @@ -263,7 +263,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { _seqEndTime = _system->getMillis() + dl; while (!((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { - uint32 starttime = _system->getMillis(); + _seqSubFrameStartTime = _system->getMillis(); seq_processWSAs(); _screen->copyPage(2, 0); @@ -275,8 +275,8 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { break; } - uint32 tdiff = _seqEndTime - starttime; - int32 dly = _tickLength - (now - starttime); + uint32 tdiff = _seqEndTime - _seqSubFrameStartTime; + int32 dly = _tickLength - (now - _seqSubFrameStartTime); if (dly > 0) delay(MIN<uint32>(dly, tdiff)); } @@ -289,13 +289,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { _sound->voiceStop(); } - if (_flags.isDemo && !_flags.isTalkie) { - if (seqNum == kSequenceDemoFisher) { - _abortIntroFlag = false; - resetSkipFlag(); - seqNum = kSequenceDemoVirgin; - } - } else { + if (!_flags.isDemo || _flags.isTalkie) { if ((seqNum != kSequenceTitle && seqNum < kSequenceZanfaun && (_abortIntroFlag || skipFlag())) || seqNum == kSequenceZanfaun) { _abortIntroFlag = false; @@ -319,8 +313,13 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { } } + if (_flags.isDemo && !_flags.isTalkie) { + _eventList.clear(); + _screen->fadeToBlack(); + } + if (!_menuChoice) - delay(1000); + delay(1200); _screen->setCurPage(oldPage); _screen->showMouse(); @@ -375,13 +374,14 @@ int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm uint8 *tmpPal = &(_screen->getPalette(3)[0x101]); memset(tmpPal, 0, 256); - uint32 endtime = 0, now = 0; + _seqSubFrameEndTimeInternal = 0; + uint32 now = 0; switch (_seqFrameCounter) { case 0: _seqSubframePlaying = true; _sound->playTrack(4); - endtime = _system->getMillis() + 60 * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + 60 * _tickLength; _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); @@ -390,8 +390,8 @@ int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm _screen->setTextColorMap(_seqTextColorMap); now = _system->getMillis(); - if (endtime > now) - delay(endtime - now); + if (_seqSubFrameEndTimeInternal > now) + delay(_seqSubFrameEndTimeInternal - now); break; case 1: @@ -830,7 +830,7 @@ int KyraEngine_HoF::seq_introHand3(WSAMovie_v2 *wsaObj, int x, int y, int frm) { } int KyraEngine_HoF::seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint32 endtime = 0; + _seqSubFrameEndTimeInternal = 0; int chatX = 0; int chatY = 0; int chatW = 0; @@ -851,12 +851,12 @@ int KyraEngine_HoF::seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm _seqTextColor[0] = _seqTextColorMap[1] = 0xff; _screen->setTextColorMap(_seqTextColorMap); - endtime = _system->getMillis() + 480 * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength; seq_printCreditsString(81, 240, 70, _seqTextColorMap, 252); seq_printCreditsString(82, 240, 90, _seqTextColorMap, _seqTextColor[0]); _screen->copyPage(2, 12); - delay(endtime - _system->getMillis()); seq_playTalkText(_flags.isTalkie ? 28 : 24); + delay(_seqSubFrameEndTimeInternal - _system->getMillis()); _seqTextColor[0] = 1; if (_flags.isTalkie) { @@ -914,7 +914,7 @@ int KyraEngine_HoF::seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm } int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint32 endtime = 0; + _seqSubFrameEndTimeInternal = 0; int chatX = 0; int chatY = 0; int chatW = 0; @@ -925,7 +925,7 @@ int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) { switch (frm) { case -2: seq_sequenceCommand(9); - endtime = _system->getMillis() + 480 * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength; seq_printCreditsString(34, 240, _flags.isTalkie ? 60 : 40, _seqTextColorMap, 252); seq_printCreditsString(35, 240, _flags.isTalkie ? 70 : 50, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(36, 240, _flags.isTalkie ? 90 : 70, _seqTextColorMap, 252); @@ -934,7 +934,7 @@ int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) { seq_printCreditsString(39, 240, _flags.isTalkie ? 130 : 120, _seqTextColorMap, _seqTextColor[0]); if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) seq_printCreditsString(103, 240, 130, _seqTextColorMap, _seqTextColor[0]); - delay(endtime - _system->getMillis()); + delay(_seqSubFrameEndTimeInternal - _system->getMillis()); _seqEndTime = 0; break; @@ -998,7 +998,7 @@ int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) { } int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint32 endtime = 0; + _seqSubFrameEndTimeInternal = 0; int chatX = 0; int chatY = 0; int chatW = 0; @@ -1007,7 +1007,7 @@ int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) { switch (frm) { case -2: seq_sequenceCommand(9); - endtime = _system->getMillis() + 480 * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength; seq_printCreditsString(40, 240, _flags.isTalkie ? 55 : 40, _seqTextColorMap, 252); seq_printCreditsString(41, 240, _flags.isTalkie ? 65 : 50, _seqTextColorMap, _seqTextColor[0]); @@ -1016,7 +1016,7 @@ int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) { seq_printCreditsString(44, 240, _flags.isTalkie ? 105 : 90, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(93, 240, _flags.isTalkie ? 125 : 110, _seqTextColorMap, 252); seq_printCreditsString(94, 240, _flags.isTalkie ? 135 : 120, _seqTextColorMap, _seqTextColor[0]); - delay(endtime - _system->getMillis()); + delay(_seqSubFrameEndTimeInternal - _system->getMillis()); _seqEndTime = 0; break; @@ -1075,7 +1075,7 @@ int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) { } int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint32 endtime = 0; + _seqSubFrameEndTimeInternal = 0; int chatX = 0; int chatY = 0; int chatW = 0; @@ -1089,7 +1089,7 @@ int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) _screen->copyPage(2, 0); _screen->updateScreen(); seq_sequenceCommand(9); - endtime = _system->getMillis() + 480 * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength; seq_printCreditsString(49, 240, 20, _seqTextColorMap, 252); seq_printCreditsString(50, 240, 30, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(51, 240, 40, _seqTextColorMap, _seqTextColor[0]); @@ -1106,7 +1106,7 @@ int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) seq_printCreditsString(63, 240, 150, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(64, 240, 160, _seqTextColorMap, _seqTextColor[0]); - delay(endtime - _system->getMillis()); + delay(_seqSubFrameEndTimeInternal - _system->getMillis()); _seqEndTime = 0; break; @@ -1157,7 +1157,7 @@ int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) } int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint32 endtime = 0; + _seqSubFrameEndTimeInternal = 0; int chatX = 0; int chatY = 0; int chatW = 0; @@ -1169,7 +1169,7 @@ int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) _screen->copyPage(2, 0); _screen->updateScreen(); seq_sequenceCommand(9); - endtime = _system->getMillis() + 480 * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength; seq_printCreditsString(45, 240, 40, _seqTextColorMap, 252); seq_printCreditsString(46, 240, 50, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(47, 240, 60, _seqTextColorMap, _seqTextColor[0]); @@ -1182,7 +1182,7 @@ int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) seq_printCreditsString(69, 240, 150, _seqTextColorMap, _seqTextColor[0]); if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) seq_printCreditsString(104, 240, 160, _seqTextColorMap, _seqTextColor[0]); - delay(endtime - _system->getMillis()); + delay(_seqSubFrameEndTimeInternal - _system->getMillis()); _seqEndTime = 0; break; @@ -1227,7 +1227,7 @@ int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) } int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint32 endtime = 0; + _seqSubFrameEndTimeInternal = 0; int chatX = 0; int chatY = 0; int chatW = 0; @@ -1240,7 +1240,7 @@ int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) switch (frm) { case -2: seq_sequenceCommand(9); - endtime = _system->getMillis() + 480 * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength; seq_printCreditsString(70, 240, 20, _seqTextColorMap, 252); seq_printCreditsString(71, 240, 30, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(72, 240, 40, _seqTextColorMap, _seqTextColor[0]); @@ -1255,7 +1255,7 @@ int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) seq_printCreditsString(90, 240, 130, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(91, 240, 140, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(92, 240, 150, _seqTextColorMap, _seqTextColor[0]); - delay(endtime - _system->getMillis()); + delay(_seqSubFrameEndTimeInternal - _system->getMillis()); _seqEndTime = 0; break; @@ -1327,7 +1327,7 @@ int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) } int KyraEngine_HoF::seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint32 endtime = 0; + _seqSubFrameEndTimeInternal = 0; int chatX = 0; int chatY = 0; int chatW = 0; @@ -1339,7 +1339,7 @@ int KyraEngine_HoF::seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm _screen->copyPage(2, 0); _screen->updateScreen(); seq_sequenceCommand(9); - endtime = _system->getMillis() + 480 * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength; seq_printCreditsString(76, 240, 40, _seqTextColorMap, 252); seq_printCreditsString(77, 240, 50, _seqTextColorMap, 252); seq_printCreditsString(78, 240, 60, _seqTextColorMap, _seqTextColor[0]); @@ -1349,7 +1349,7 @@ int KyraEngine_HoF::seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm seq_printCreditsString(85, 240, 110, _seqTextColorMap, _seqTextColor[0]); seq_printCreditsString(99, 240, 130, _seqTextColorMap, 252); seq_printCreditsString(100, 240, 140, _seqTextColorMap, _seqTextColor[0]); - delay(endtime - _system->getMillis()); + delay(_seqSubFrameEndTimeInternal - _system->getMillis()); _seqEndTime = 0; break; @@ -1811,7 +1811,7 @@ uint32 KyraEngine_HoF::seq_activeTextsTimeLeft() { } void KyraEngine_HoF::seq_processWSAs() { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { if (_activeWSA[i].flags != -1) { if (seq_processNextSubFrame(i)) seq_resetActiveWSA(i); @@ -2334,13 +2334,16 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i int dur = int(strlen(_sequenceStrings[strIndex])) * (_flags.isTalkie ? 7 : 15); int entry = textEnabled() ? seq_setTextEntry(strIndex, x, y, dur, width) : strIndex; _activeText[entry].textcolor = textColor; - uint32 chatTimeout = _system->getMillis() + dur * _tickLength; + _seqWsaChatTimeout = _system->getMillis() + dur * _tickLength; int curframe = firstframe; - if (vocIndex && speechEnabled()) + if (vocIndex && speechEnabled()) { + while (_sound->voiceIsPlaying() && !skipFlag()) + delay(4); seq_playTalkText(vocIndex); + } - while (_system->getMillis() < chatTimeout && !(_abortIntroFlag || skipFlag())) { + while (_system->getMillis() < _seqWsaChatTimeout && !(_abortIntroFlag || skipFlag())) { if (lastframe < 0) { int t = ABS(lastframe); if (t < curframe) @@ -2350,7 +2353,7 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i if (ABS(lastframe) < curframe) curframe = firstframe; - uint32 frameTimeout = _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength; + _seqWsaChatFrameTimeout = _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength; if (wsa) { wsa->setDrawPage(2); wsa->setX(wsaXpos); @@ -2363,8 +2366,8 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i seq_processText(); uint32 tm = _system->getMillis(); - if (frameTimeout > tm && chatTimeout > tm) - delay(MIN(frameTimeout - tm, chatTimeout - tm)); + if (_seqWsaChatFrameTimeout > tm && _seqWsaChatTimeout > tm) + delay(MIN(_seqWsaChatFrameTimeout - tm, _seqWsaChatTimeout - tm)); if (speechEnabled() && !textEnabled() && !snd_voiceIsPlaying()) break; @@ -2377,11 +2380,8 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i if (_abortIntroFlag || skipFlag()) _sound->voiceStop(); - if (lastframe < 0) { - int t = ABS(lastframe); - if (t < curframe) - curframe = t; - } + if (ABS(lastframe) < curframe) + curframe = ABS(lastframe); if (curframe == firstframe) curframe++; @@ -2395,27 +2395,46 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int if (!data) return; - static const char mark[] = { 5, 13, 0}; + static const char mark[] = { 5, 13, 0 }; _screen->clearPage(tempPage1); _screen->clearPage(tempPage2); _screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, 0, tempPage1); - uint8 *tmp = new uint8[397]; - memset(tmp, 0, 397); - uint8 **tmpStringTable = new uint8*[35]; + struct ScrollTextData { + int16 x; + int16 y; + uint8 *text; + byte unk1; + byte height; + byte adjust; + + ScrollTextData() { + x = 0; // 0 11 + y = 0; // 2 13 + text = 0; // 4 15 + unk1 = 0; // 8 19 + height = 0; // 9 20 + adjust = 0; // 10 21 + } + }; + + ScrollTextData *textData = new ScrollTextData[36]; uint8 *ptr = data; - int strTblIndex = 0; bool loop = true; int cnt = 0; while (loop) { - uint32 endTime = _system->getMillis() + speed * _tickLength; + _seqSubFrameEndTimeInternal = _system->getMillis() + speed * _tickLength; while (cnt < 35 && *ptr) { - int m = cnt * 11; - uint16 cH = cnt ? READ_LE_UINT16(&tmp[m + 2]) + tmp[m + 9] + (tmp[m + 9] >> 3) : d->h; + uint16 cH; + + if (cnt) + cH = textData[cnt].y + textData[cnt].height + (textData[cnt].height >> 3); + else + cH = d->h; char *str = (char*)ptr; @@ -2423,12 +2442,15 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int if (!ptr) ptr = (uint8*)strchr(str, 0); - tmp[m + 19] = *ptr; + textData[cnt + 1].unk1 = *ptr; *ptr = 0; - if (tmp[m + 19]) + if (textData[cnt + 1].unk1) ptr++; - tmp[m + 21] = (*str == 3 || *str == 4) ? tmp[m + 21] = *str++ : 0; + if (*str == 3 || *str == 4) + textData[cnt + 1].adjust = *str++; + else + textData[cnt + 1].adjust = 0; _screen->setFont(fid1); @@ -2439,18 +2461,25 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int str++; } - tmp[m + 20] = _screen->getFontHeight(); + textData[cnt + 1].height = _screen->getFontHeight(); - WRITE_LE_UINT16(&tmp[m + 11], (tmp[m + 21] == 3) ? 157 - _screen->getTextWidth(str) : - ((tmp[m + 21] == 4) ? 161 : (((d->w << 3) - _screen->getTextWidth(str)) >> 1) + 1)); + switch (textData[cnt + 1].adjust) { + case 3: + textData[cnt + 1].x = 157 - _screen->getTextWidth(str); + break; + case 4: + textData[cnt + 1].x = 161; + break; + default: + textData[cnt + 1].x = (((d->w << 3) - _screen->getTextWidth(str)) >> 1) + 1; + break; + } - if (tmp[m + 8] == 5) - cH -= (tmp[m + 9] + (tmp[m + 9] >> 3)); + if (textData[cnt].unk1 == 5) + cH -= (textData[cnt].height + (textData[cnt].height >> 3)); - WRITE_LE_UINT16(&tmp[m + 13], cH); - WRITE_LE_UINT32(&tmp[m + 15], strTblIndex); - tmpStringTable[strTblIndex] = (uint8*) str; - strTblIndex = (strTblIndex + 1) % 35; + textData[cnt + 1].y = cH; + textData[cnt + 1].text = (uint8*) str; cnt++; } @@ -2460,11 +2489,10 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int bool palCycle = 0; while (cnt2 < cnt) { - int m = cnt2 * 11; - const char *str = (const char*)tmpStringTable[READ_LE_UINT32(&tmp[m + 15])]; + const char *str = (const char*)textData[cnt2 + 1].text; const char *str2 = str; - uint16 cW = READ_LE_UINT16(&tmp[m + 11]) - 10; - uint16 cH = READ_LE_UINT16(&tmp[m + 13]); + int16 cW = textData[cnt2 + 1].x - 10; + int16 cH = textData[cnt2 + 1].y; int x = (d->sx << 3) + cW; int y = d->sy + cH; int col1 = 255; @@ -2472,7 +2500,7 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int if (cH < d->h) { _screen->setCurPage(tempPage2); _screen->setFont(fid1); - if (tmp[m + 20] != _screen->getFontHeight()) + if (textData[cnt2 + 1].height != _screen->getFontHeight()) _screen->setFont(fid2); if (specialData) { @@ -2503,18 +2531,18 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int _screen->setCurPage(0); } - WRITE_LE_UINT16(&tmp[m + 13], READ_LE_UINT16(&tmp[m + 13]) - step); + textData[cnt2 + 1].y -= step; cnt2++; } _screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage2, 0); _screen->updateScreen(); - if ((int16)READ_LE_UINT16(&tmp[13]) < -10) { - tmpStringTable[tmp[15]] += strlen((char*)tmpStringTable[tmp[15]]); - tmpStringTable[tmp[15]][0] = tmp[19]; + if (textData[1].y < -10) { + textData[1].text += strlen((char*)textData[1].text); + textData[1].text[0] = textData[1].unk1; cnt--; - memcpy(&tmp[11], &tmp[22], cnt * 11); + memcpy(&textData[1], &textData[2], cnt * sizeof(ScrollTextData)); } if (palCycle) { @@ -2524,9 +2552,9 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int _screen->setScreenPalette(_screen->_currentPalette); } - delayUntil(endTime); + delayUntil(_seqSubFrameEndTimeInternal); - if ((cnt < 36) && ((d->sy + d->h) > (READ_LE_UINT16(&tmp[cnt * 11 + 2]) + tmp[cnt * 11 + 9])) && !skipFlag()) { + if ((cnt < 36) && ((d->sy + d->h) > (textData[cnt].y + textData[cnt].height)) && !skipFlag()) { resetSkipFlag(); delay(_tickLength * 500); cnt = 0; @@ -2542,8 +2570,7 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int _abortIntroFlag= false; resetSkipFlag(); - delete[] tmp; - delete[] tmpStringTable; + delete[] textData; } void KyraEngine_HoF::seq_scrollPage() { @@ -2594,20 +2621,20 @@ void KyraEngine_HoF::seq_showStarcraftLogo() { _screen->copyPage(2, 0); _screen->fadeFromBlack(); for (int i = 1; i < endframe; i++) { - uint32 endTime = _system->getMillis() + 50; + _seqEndTime = _system->getMillis() + 50; if (skipFlag()) break; ci->displayFrame(i, 0); _screen->copyPage(2, 0); _screen->updateScreen(); - delay(endTime - _system->getMillis()); + delay(_seqEndTime - _system->getMillis()); } if(!skipFlag()) { - uint32 endTime = _system->getMillis() + 50; + _seqEndTime = _system->getMillis() + 50; ci->displayFrame(0, 0); _screen->copyPage(2, 0); _screen->updateScreen(); - delay(endTime - _system->getMillis()); + delay(_seqEndTime - _system->getMillis()); } _screen->fadeToBlack(); _screen->showMouse(); @@ -2624,6 +2651,8 @@ void KyraEngine_HoF::seq_init() { _res->unloadAllPakFiles(); _res->loadPakFile(StaticResource::staticDataFilename()); + if (_flags.useInstallerPackage) + _res->loadPakFile("WESTWOOD.001"); _res->loadFileList(_sequencePakList, _sequencePakListSize); int numShp = -1; @@ -2783,3 +2812,4 @@ void KyraEngine_HoF::seq_makeBookAppear() { } // end of namespace Kyra + diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index a8566a7309..8f9077705e 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -66,17 +66,14 @@ bool Sound::voiceFileIsPresent(const char *file) { return false; } -bool Sound::voicePlay(const char *file, bool isSfx) { - uint32 fileSize = 0; - byte *fileData = 0; - bool found = false; +int32 Sound::voicePlay(const char *file, bool isSfx) { char filenamebuffer[25]; int h = 0; while (_mixer->isSoundHandleActive(_soundChannels[h].channelHandle) && h < kNumChannelHandles) h++; if (h >= kNumChannelHandles) - return false; + return 0; Audio::AudioStream *audioStream = 0; @@ -88,29 +85,29 @@ bool Sound::voicePlay(const char *file, bool isSfx) { if (!stream) continue; audioStream = _supportedCodes[i].streamFunc(stream, true, 0, 0, 1); - found = true; break; } - if (!found) { + if (!audioStream) { strcpy(filenamebuffer, file); strcat(filenamebuffer, ".VOC"); - fileData = _vm->resource()->fileData(filenamebuffer, &fileSize); + uint32 fileSize = 0; + byte *fileData = _vm->resource()->fileData(filenamebuffer, &fileSize); if (!fileData) - return false; + return 0; Common::MemoryReadStream vocStream(fileData, fileSize); audioStream = Audio::makeVOCStream(vocStream); + + delete[] fileData; + fileSize = 0; } _soundChannels[h].file = file; _mixer->playInputStream(isSfx ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType, &_soundChannels[h].channelHandle, audioStream); - delete[] fileData; - fileSize = 0; - - return true; + return audioStream->getTotalPlayTime(); } void Sound::voiceStop(const char *file) { @@ -143,6 +140,18 @@ bool Sound::voiceIsPlaying(const char *file) { return res; } +uint32 Sound::voicePlayedTime(const char *file) { + if (!file) + return 0; + + for (int i = 0; i < kNumChannelHandles; ++i) { + if (_soundChannels[i].file == file) + return _mixer->getSoundElapsedTime(_soundChannels[i].channelHandle); + } + + return 0; +} + #pragma mark - SoundMidiPC::SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *driver) : Sound(vm, mixer) { @@ -529,12 +538,15 @@ void KyraEngine_v1::snd_playWanderScoreViaMap(int command, int restart) { void KyraEngine_v1::snd_stopVoice() { debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine_v1::snd_stopVoice()"); - _sound->voiceStop(_speechFile.empty() ? 0 : _speechFile.c_str()); + if (!_speechFile.empty()) { + _sound->voiceStop(_speechFile.c_str()); + _speechFile.clear(); + } } bool KyraEngine_v1::snd_voiceIsPlaying() { debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine_v1::snd_voiceIsPlaying()"); - return _sound->voiceIsPlaying(_speechFile.empty() ? 0 : _speechFile.c_str()); + return _speechFile.empty() ? false : _sound->voiceIsPlaying(_speechFile.c_str()); } // static res diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 595619c7e9..2427a6cdde 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -174,9 +174,9 @@ public: * * @param file file to be played * @param isSfx marks file as sfx instead of voice - * @return channel the voice file is played on + * @return playtime of the voice file (-1 marks unknown playtime) */ - virtual bool voicePlay(const char *file, bool isSfx = false); + virtual int32 voicePlay(const char *file, bool isSfx = false); /** * Checks if a voice is being played. @@ -186,6 +186,13 @@ public: bool voiceIsPlaying(const char *file = 0); /** + * Checks how long a voice has been playing + * + * @return time in milliseconds + */ + uint32 voicePlayedTime(const char *file); + + /** * Stops playback of the current voice. */ void voiceStop(const char *file = 0); @@ -449,7 +456,7 @@ public: void haltTrack(); void beginFadeOut(); - bool voicePlay(const char *file, bool isSfx = false); + int32 voicePlay(const char *file, bool isSfx = false); void playSoundEffect(uint8) {} private: diff --git a/engines/kyra/sound_lok.cpp b/engines/kyra/sound_lok.cpp index 728013cdaa..8a1d16a6b1 100644 --- a/engines/kyra/sound_lok.cpp +++ b/engines/kyra/sound_lok.cpp @@ -67,7 +67,7 @@ void KyraEngine_LoK::snd_playVoiceFile(int id) { assert(id >= 0 && id < 9999); sprintf(vocFile, "%03d", id); _speechFile = vocFile; - _sound->voicePlay(vocFile); + _speechPlayTime = _sound->voicePlay(vocFile); } void KyraEngine_LoK::snd_voiceWaitForFinish(bool ingame) { @@ -80,4 +80,11 @@ void KyraEngine_LoK::snd_voiceWaitForFinish(bool ingame) { } } +uint32 KyraEngine_LoK::snd_getVoicePlayTime() { + debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine_LoK::snd_getVoicePlayTime()"); + if (!snd_voiceIsPlaying()) + return 0; + return (_speechPlayTime != -1 ? _speechPlayTime : 0); +} + } // end of namespace Kyra diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 513f523194..4265533507 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1301,6 +1301,7 @@ bool SoundTowns::loadInstruments() { void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0); + Common::StackLock lock(_mutex); if (!_parser) { _parser = new MidiParser_EuD(_driver->queue()); @@ -1431,7 +1432,7 @@ void SoundTowns_v2::haltTrack() { //_driver->reset(); } -bool SoundTowns_v2::voicePlay(const char *file, bool) { +int32 SoundTowns_v2::voicePlay(const char *file, bool) { static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 }; int h = 0; @@ -1439,7 +1440,7 @@ bool SoundTowns_v2::voicePlay(const char *file, bool) { while (_mixer->isSoundHandleActive(_soundChannels[h].channelHandle) && h < kNumChannelHandles) h++; if (h >= kNumChannelHandles) - return false; + return 0; } char filename [13]; @@ -1496,7 +1497,7 @@ bool SoundTowns_v2::voicePlay(const char *file, bool) { _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_soundChannels[h].channelHandle, _currentSFX); delete[] data; - return true; + return 1; } void SoundTowns_v2::beginFadeOut() { diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 7ba19e9966..302b92ab07 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -40,11 +40,9 @@ #include "kyra/gui_hof.h" #include "kyra/gui_mr.h" -#include "gui/message.h" - namespace Kyra { -#define RESFILE_VERSION 27 +#define RESFILE_VERSION 28 bool StaticResource::checkKyraDat() { Common::File kyraDat; @@ -293,18 +291,20 @@ bool StaticResource::init() { error("unknown game ID"); } + char errorBuffer[100]; int tempSize = 0; uint8 *temp = getFile("INDEX", tempSize); if (!temp) { - warning("No matching INDEX file found ('%s')", getFilename("INDEX")); - outputError(); + snprintf(errorBuffer, sizeof(errorBuffer), "is missing an '%s' entry", getFilename("INDEX")); + outputError(errorBuffer); return false; } if (tempSize != 3*4) { delete[] temp; - warning("'%s' has illegal filesize %d", getFilename("INDEX"), tempSize); - outputError(); + + snprintf(errorBuffer, sizeof(errorBuffer), "has incorrect header size for entry '%s'", getFilename("INDEX")); + outputError(errorBuffer); return false; } @@ -316,28 +316,25 @@ bool StaticResource::init() { temp = 0; if (version != RESFILE_VERSION) { - warning("Invalid KYRA.DAT file version (%u, required %d)", version, RESFILE_VERSION); - outputError(); + snprintf(errorBuffer, sizeof(errorBuffer), "has invalid version %d required, you got %d", RESFILE_VERSION, version); + outputError(errorBuffer); return false; } if (gameID != _vm->game()) { - warning("Invalid game id (%u)", gameID); - outputError(); + outputError("does not include support for your game"); return false; } uint32 gameFeatures = createFeatures(_vm->gameFlags()); if ((featuresValue & GAME_FLAGS) != gameFeatures) { - warning("Your data file has a different game flags (0x%.08X has the data and your version has 0x%.08X)", (featuresValue & GAME_FLAGS), gameFeatures); - outputError(); + outputError("does not include support for your game version"); return false; } // load all tables for now if (!prefetchId(-1)) { - warning("Couldn't load all needed resources from 'KYRA.DAT'"); - outputError(); + outputError("is lacking entries for your game version"); return false; } return true; @@ -347,11 +344,10 @@ void StaticResource::deinit() { unloadId(-1); } -void StaticResource::outputError() { - Common::String errorMessage = "Your '" + StaticResource::staticDataFilename() + "' file is outdated, reget it from the ScummVM website"; - ::GUI::MessageDialog errorMsg(errorMessage); - errorMsg.runModal(); - error(errorMessage.c_str()); +void StaticResource::outputError(const Common::String &error) { + Common::String errorMessage = "Your '" + StaticResource::staticDataFilename() + "' file " + error + ", reget a correct version from the ScummVM website"; + _vm->GUIErrorMessage(errorMessage); + ::error(errorMessage.c_str()); } const char * const*StaticResource::loadStrings(int id, int &strings) { @@ -1281,7 +1277,7 @@ void KyraEngine_HoF::initStaticResource() { &KyraEngine_HoF::seq_introLibrary2, &KyraEngine_HoF::seq_introLibrary2, &KyraEngine_HoF::seq_introMarco, &KyraEngine_HoF::seq_introHand1a, &KyraEngine_HoF::seq_introHand1b, &KyraEngine_HoF::seq_introHand1c, - &KyraEngine_HoF::seq_introHand2, &KyraEngine_HoF::seq_introHand3, 0 + &KyraEngine_HoF::seq_introHand2, &KyraEngine_HoF::seq_introHand3, 0 }; static const SeqProc hofDemoSequenceCallbacks[] = { @@ -1363,11 +1359,11 @@ const int8 KyraEngine_v1::_addYPosTable[] = { 0, -2, -2, -2, 0, 2, 2, 2 }; -const int8 KyraEngine_LoK::_charXPosTable[] = { +const int8 KyraEngine_v1::_charAddXPosTable[] = { 0, 4, 4, 4, 0, -4, -4, -4 }; -const int8 KyraEngine_LoK::_charYPosTable[] = { +const int8 KyraEngine_v1::_charAddYPosTable[] = { -2, -2, 0, 2, 2, 2, 0, -2 }; @@ -1534,14 +1530,6 @@ const int KyraEngine_LoK::_dosTrackMapSize = ARRAYSIZE(KyraEngine_LoK::_dosTrack // kyra engine v2 static data -const int8 KyraEngine_v2::_updateCharPosXTable[] = { - 0, 4, 4, 4, 0, -4, -4, -4 -}; - -const int8 KyraEngine_v2::_updateCharPosYTable[] = { - -2, -2, 0, 2, 2, 2, 0, -2 -}; - const int GUI_v2::_sliderBarsPosition[] = { 0x92, 0x1F, 0x92, 0x30, 0x92, 0x41, 0x92, 0x52 }; @@ -1554,16 +1542,16 @@ const char *KyraEngine_HoF::_languageExtension[] = { "ENG", "FRE", "GER",/*, - "ITA", Italian and Spanish was never included + "ITA", Italian and Spanish were never included "SPA"*/ - "JPN" + "JPN", }; const char *KyraEngine_HoF::_scriptLangExt[] = { "EMC", "FMC", "GMC",/*, - "IMC", Italian and Spanish was never included + "IMC", Italian and Spanish were never included "SMC"*/ "JMC" }; @@ -1956,7 +1944,7 @@ const char *KyraEngine_MR::_languageExtension[] = { "TRE", "TRF", "TRG"/*, - "TRI", Italian and Spanish was never included + "TRI", Italian and Spanish were never included "TRS"*/ }; diff --git a/engines/kyra/text.cpp b/engines/kyra/text.cpp index 931c5fe1c9..f8eb10a85e 100644 --- a/engines/kyra/text.cpp +++ b/engines/kyra/text.cpp @@ -210,7 +210,7 @@ void TextDisplayer::printTalkTextMessage(const char *text, int x, int y, uint8 c calcWidestLineBounds(x1, x2, w, x); _talkCoords.x = x1; _talkCoords.w = w + 2; - _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkCoords.y, _talkCoords.w, _talkMessageH, srcPage, dstPage); + _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkCoords.y, _talkCoords.w, _talkMessageH, srcPage, dstPage, Screen::CR_NO_P_CHECK); int curPage = _screen->_curPage; _screen->_curPage = srcPage; for (int i = 0; i < lineCount; ++i) { diff --git a/engines/kyra/text_hof.cpp b/engines/kyra/text_hof.cpp index 0d40827390..dd587c5112 100644 --- a/engines/kyra/text_hof.cpp +++ b/engines/kyra/text_hof.cpp @@ -107,8 +107,7 @@ char *TextDisplayer_HoF::preprocessString(const char *str) { int textWidth = _screen->getTextWidth(p); _screen->_charWidth = 0; - // longer text strings for German versions - int maxTextWidth = (_vm->language() == 2 ? 240 : 176); + int maxTextWidth = (_vm->language() == 0) ? 176 : 240; if (textWidth > maxTextWidth) { if (textWidth > (maxTextWidth*2)) { diff --git a/engines/kyra/text_lok.cpp b/engines/kyra/text_lok.cpp index ccca079e32..f6b0407a75 100644 --- a/engines/kyra/text_lok.cpp +++ b/engines/kyra/text_lok.cpp @@ -62,10 +62,8 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const if (chatDuration != -1) chatDuration *= _tickLength; - if (vocFile != -1) { - snd_voiceWaitForFinish(); + if (vocFile != -1) snd_playVoiceFile(vocFile); - } _timer->disable(14); _timer->disable(18); @@ -269,6 +267,8 @@ void KyraEngine_LoK::characterSays(int vocFile, const char *chatStr, int8 charNu if (_currentCharacter->sceneId == 210) return; + snd_voiceWaitForFinish(true); + convoInitialized = initCharacterChat(charNum); chatPartnerNum = getChatPartnerNum(); diff --git a/engines/kyra/text_mr.cpp b/engines/kyra/text_mr.cpp index 13b37fa77a..16c56da099 100644 --- a/engines/kyra/text_mr.cpp +++ b/engines/kyra/text_mr.cpp @@ -55,25 +55,26 @@ char *TextDisplayer_MR::preprocessString(const char *str) { int count = 0, offs = 0; if (textWidth > (3*maxTextWidth)) { count = getCharLength(p, textWidth/4); - offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count); + offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth)); p += count + offs; - } - + // No update of textWidth here + } + if (textWidth > (2*maxTextWidth)) { count = getCharLength(p, textWidth/3); - offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count); + offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth)); p += count + offs; textWidth = _screen->getTextWidth(p); } count = getCharLength(p, textWidth/2); - offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count); + offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth)); p += count + offs; textWidth = _screen->getTextWidth(p); if (textWidth > maxTextWidth) { count = getCharLength(p, textWidth/2); - offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count); + offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth)); } } @@ -232,7 +233,7 @@ void KyraEngine_MR::objectChat(const char *str, int object, int vocHigh, int voc "MTFR00S.EMC", "MTFR00Q.EMC", "MTFR00E.EMC", "MTFR00T.EMC", "MTL00S.EMC", "MTL00Q.EMC", "MTL00E.EMC", "MTL00T.EMC", "MTR00S.EMC", "MTR00Q.EMC", "MTR00E.EMC", "MTR00T.EMC", - "MTA00S.EMC", "MTA00Q.EMC", "MTA00Q.EMC", "MTA00T.EMC" + "MTA00S.EMC", "MTA00Q.EMC", "MTA00E.EMC", "MTA00T.EMC" }; int chat = talkScriptTable[chatType + _mainCharacter.facing * 4]; diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp index cea52e911e..3d18f27c7e 100644 --- a/engines/kyra/vqa.cpp +++ b/engines/kyra/vqa.cpp @@ -362,9 +362,8 @@ void VQAMovie::close() { delete[] _partialCodeBook; delete[] _vectorPointers; - if (_vm->_mixer->isSoundHandleActive(_sound)) { + if (_vm->_mixer->isSoundHandleActive(_sound)) _vm->_mixer->stopHandle(_sound); - } _frameInfo = NULL; _frame = NULL; @@ -655,11 +654,10 @@ void VQAMovie::play() { while (1) { uint32 elapsedTime; - if (_vm->_mixer->isSoundHandleActive(_sound)) { + if (_vm->_mixer->isSoundHandleActive(_sound)) elapsedTime = _vm->_mixer->getSoundElapsedTime(_sound); - } else { + else elapsedTime = _system->getMillis() - startTick; - } if (elapsedTime >= (i * 1000) / _header.frameRate) break; |