diff options
Diffstat (limited to 'engines/saga')
36 files changed, 1297 insertions, 1156 deletions
diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp index d7882a78fd..c2ecff4a1a 100644 --- a/engines/saga/actor.cpp +++ b/engines/saga/actor.cpp @@ -897,7 +897,9 @@ void Actor::updateActorsScene(int actorsEntrance) { } } - assert(_protagonist); + // _protagonist can be null while loading a game from the command line + if (_protagonist == NULL) + return; if ((actorsEntrance >= 0) && (_vm->_scene->_entryList.entryListCount > 0)) { if (_vm->_scene->_entryList.entryListCount <= actorsEntrance) { @@ -1605,7 +1607,9 @@ void Actor::handleActions(int msec, bool setup) { if (actor->_lastZone) stepZoneAction(actor, actor->_lastZone, true, false); actor->_lastZone = hitZone; - if (hitZone) + // WORKAROUND for graphics glitch in the rat caves. Don't do this step zone action in the rat caves + // (room 51) to avoid the glitch + if (hitZone && !(_vm->getGameType() == GType_ITE && _vm->_scene->currentSceneNumber() == 51)) stepZoneAction(actor, hitZone, false, false); } } @@ -2127,7 +2131,10 @@ bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) { if ((((actor->_currentAction >= kActionWalkToPoint) && (actor->_currentAction <= kActionWalkDir)) || (actor == _protagonist)) && !_vm->_scene->canWalk(pointFrom)) { - for (i = 1; i < 8; i++) { + + int max = _vm->getGameType() == GType_ITE ? 8 : 4; + + for (i = 1; i < max; i++) { pointAdd = pointFrom; pointAdd.y += i; if (_vm->_scene->canWalk(pointAdd)) { @@ -2140,17 +2147,19 @@ bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) { pointFrom = pointAdd; break; } - pointAdd = pointFrom; - pointAdd.x += i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - pointAdd = pointFrom; - pointAdd.x -= i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; + if (_vm->getGameType() == GType_ITE) { + pointAdd = pointFrom; + pointAdd.x += i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + pointAdd = pointFrom; + pointAdd.x -= i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } } } } diff --git a/engines/saga/actor.h b/engines/saga/actor.h index b9ec62337c..ef62661c6c 100644 --- a/engines/saga/actor.h +++ b/engines/saga/actor.h @@ -41,7 +41,7 @@ namespace Saga { class HitZone; -// #define ACTOR_DEBUG 1 //only for actor pathfinding debug! +//#define ACTOR_DEBUG 1 //only for actor pathfinding debug! #define ACTOR_BARRIERS_MAX 16 @@ -614,11 +614,6 @@ public: void showActors(bool flag) { _showActors = flag; } - /* - uint16 _currentFrameIndex; - void frameTest() { - _currentFrameIndex++; - }*/ protected: friend class Script; bool loadActorResources(ActorData *actor); diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp index d29fc6ebe6..7b3bdcd665 100644 --- a/engines/saga/animation.cpp +++ b/engines/saga/animation.cpp @@ -24,6 +24,7 @@ */ // Background animation management module + #include "saga/saga.h" #include "saga/gfx.h" @@ -94,7 +95,10 @@ void Anim::playCutaway(int cut, bool fade) { startImmediately = true; } - _vm->_gfx->savePalette(); + // WORKAROUND: The IHNM demo deals with chained cutaways in a different manner. Don't save + // the palette of cutaway 11 (the woman looking at the marble) + if (!(_vm->getGameId() == GID_IHNM_DEMO && cut == 11)) + _vm->_gfx->savePalette(); if (fade) { _vm->_gfx->getCurrentPal(saved_pal); @@ -152,6 +156,12 @@ void Anim::playCutaway(int cut, bool fade) { _vm->_gfx->setPalette(palette); + // WORKAROUND for a bug found in the original IHNM demo. The palette of cutaway 12 is incorrect (the incorrect + // palette can be seen in the original demo too, for a split second). Therefore, use the saved palette for this + // cutaway + if (_vm->getGameId() == GID_IHNM_DEMO && cut == 12) + _vm->_gfx->restorePalette(); + free(buf); free(resourceData); @@ -307,7 +317,17 @@ void Anim::clearCutaway(void) { } _vm->_interface->restoreMode(); - _vm->_gfx->showCursor(true); + + if (_vm->getGameId() != GID_IHNM_DEMO) { + if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) { + // Don't show the mouse cursor in the non-interactive part of the IHNM demo + } else { + _vm->_gfx->showCursor(true); + } + } else { + // Enable the save reminder state after each cutaway for the IHNM demo + _vm->_interface->setSaveReminderState(true); + } } } @@ -367,16 +387,6 @@ void Anim::load(uint16 animId, const byte *animResourceData, size_t animResource fillFrameOffsets(anim); - /* char s[200]; - sprintf(s, "d:\\anim%i",animId); - long flen=anim->resourceLength; - char *buf=(char*)anim->resourceData; - FILE*f; - f=fopen(s,"wb"); - for (long i = 0; i < flen; i++) - fputc(buf[i],f); - fclose(f);*/ - // Set animation data anim->currentFrame = 0; anim->completed = 0; @@ -642,7 +652,7 @@ void Anim::decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_ yStart = readS.readUint16BE(); else yStart = readS.readByte(); - readS.readByte(); /* Skip pad byte */ + readS.readByte(); // Skip pad byte /*xPos = */readS.readUint16BE(); /*yPos = */readS.readUint16BE(); /*width = */readS.readUint16BE(); diff --git a/engines/saga/animation.h b/engines/saga/animation.h index 89a1e77807..f8cf90425f 100644 --- a/engines/saga/animation.h +++ b/engines/saga/animation.h @@ -154,6 +154,7 @@ public: } return (_animations[animId] != NULL); } + int cutawayResourceID(int cutaway) { return _cutawayList[cutaway].animResourceId; } private: void decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_t bufLength); void fillFrameOffsets(AnimationData *anim); @@ -208,4 +209,4 @@ private: } // End of namespace Saga -#endif /* ANIMATION_H_ */ +#endif // ANIMATION_H_ diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index 9b9a0ca872..c8918998f1 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -69,7 +69,19 @@ int SagaEngine::getFontsCount() const { return _gameDescription->fontsCount; } int SagaEngine::getGameId() const { return _gameDescription->gameId; } int SagaEngine::getGameType() const { return _gameDescription->gameType; } -uint32 SagaEngine::getFeatures() const { return _gameDescription->features; } + +uint32 SagaEngine::getFeatures() const { + uint32 result = _gameDescription->features; + + if (_gf_wyrmkeep) + result |= GF_WYRMKEEP; + + if (_gf_compressed_sounds) + result |= GF_COMPRESSED_SOUNDS; + + return result; +} + Common::Language SagaEngine::getLanguage() const { return _gameDescription->desc.language; } Common::Platform SagaEngine::getPlatform() const { return _gameDescription->desc.platform; } int SagaEngine::getGameNumber() const { return _gameNumber; } @@ -133,6 +145,26 @@ bool SagaEngine::initGame() { _displayClip.right = getDisplayInfo().logicalWidth; _displayClip.bottom = getDisplayInfo().logicalHeight; + if (Common::File::exists("graphics/credit3n.dlt")) { + _gf_wyrmkeep = true; + } + + // If a compressed sound file is found in the game's directory, set the compressed flag to true + if (_gameDescription->gameType == GType_ITE) { + if (Common::File::exists("sounds.cmp") || Common::File::exists("soundsd.cmp") || + Common::File::exists("voices.cmp") || Common::File::exists("voicesd.cmp") || + Common::File::exists("inherit the earth voices.cmp")) { + _gf_compressed_sounds = true; + } + } else { + if (Common::File::exists("voicess.cmp") || Common::File::exists("voices1.cmp") || + Common::File::exists("voices2.cmp") || Common::File::exists("voices3.cmp") || + Common::File::exists("voices4.cmp") || Common::File::exists("voices5.cmp") || + Common::File::exists("voices6.cmp") || Common::File::exists("voicesd.cmp")) { + _gf_compressed_sounds = true; + } + } + return _resource->createContexts(); } diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h index da06255a82..0d57adb87d 100644 --- a/engines/saga/detection_tables.h +++ b/engines/saga/detection_tables.h @@ -23,6 +23,8 @@ * */ +// Game detection information and MD5s + namespace Saga { static const GameResourceDescription ITE_Resources = { @@ -36,6 +38,7 @@ static const GameResourceDescription ITE_Resources = { RID_ITE_MAIN_PANEL_SPRITES, 0, // Option panel sprites (IHNM only) RID_ITE_DEFAULT_PORTRAITS, + 0, // Psychic profile background (IHNM only) RID_ITE_MAIN_STRINGS, RID_ITE_ACTOR_NAMES }; @@ -51,6 +54,7 @@ static const GameResourceDescription ITEDemo_Resources = { RID_ITEDEMO_MAIN_PANEL_SPRITES, 0, // Option panel sprites (IHNM only) RID_ITEDEMO_DEFAULT_PORTRAITS, + 0, // Psychic profile background (IHNM only) RID_ITEDEMO_MAIN_STRINGS, RID_ITEDEMO_ACTOR_NAMES }; @@ -61,15 +65,6 @@ static const GameFontDescription ITEDEMO_GameFonts[] = { {1} }; -static const GameSoundInfo ITEDEMO_GameSound = { - kSoundVOC, - -1, - -1, - false, - false, - true -}; - // Inherit the Earth - Wyrmkeep Win32 Demo version static const GameFontDescription ITEWINDEMO_GameFonts[] = { @@ -132,16 +127,6 @@ static const GameSoundInfo ITEMACDEMO_GameMusic = { true }; -// Inherit the Earth - Wyrmkeep Linux Demo version -static const GameSoundInfo ITELINDEMO_GameMusic = { - kSoundPCM, - 11025, - 16, - true, - false, - true -}; - static const GameSoundInfo ITEMACCD_G_GameSound = { kSoundMacPCM, 22050, @@ -201,7 +186,8 @@ static const GameSoundInfo ITECD_GameSound = { true }; -static const GamePatchDescription ITEWinPatch1_Files[] = { +// Patch files. Files not found will be ignored +static const GamePatchDescription ITEPatch_Files[] = { { "cave.mid", GAME_RESOURCEFILE, 9, NULL}, { "intro.mid", GAME_RESOURCEFILE, 10, NULL}, { "fvillage.mid", GAME_RESOURCEFILE, 11, NULL}, @@ -235,31 +221,11 @@ static const GamePatchDescription ITEWinPatch1_Files[] = { { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL}, { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL}, { "credit3n.dlt", GAME_RESOURCEFILE, 1796, NULL}, + { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL}, // Macintosh { "credit4n.dlt", GAME_RESOURCEFILE, 1797, NULL}, - { "p2_a.voc", GAME_VOICEFILE, 4, NULL} -}; - -static const GamePatchDescription ITEWinPatch2_Files[] = { - { "cave.mid", GAME_RESOURCEFILE, 9, NULL}, - { "intro.mid", GAME_RESOURCEFILE, 10, NULL}, - { "fvillage.mid", GAME_RESOURCEFILE, 11, NULL}, - { "elkfanfare.mid", GAME_RESOURCEFILE, 19, NULL}, - { "bcexpl.mid", GAME_RESOURCEFILE, 20, NULL}, - { "boargtnt.mid", GAME_RESOURCEFILE, 21, NULL}, - { "explorea.mid", GAME_RESOURCEFILE, 23, NULL}, - { "sweet.mid", GAME_RESOURCEFILE, 32, NULL}, - - { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL}, - { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL}, - { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL}, - { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL}, + { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL}, // Macintosh + { "p2_a.voc", GAME_VOICEFILE, 4, NULL}, { "p2_a.iaf", GAME_VOICEFILE, 4, &ITECD_GameSound} -/* boarhall.bbm - elkenter.bbm - ferrets.bbm - ratdoor.bbm - sanctuar.bbm - tycho.bbm*/ }; static const GamePatchDescription ITEMacPatch_Files[] = { @@ -273,16 +239,6 @@ static const GamePatchDescription ITEMacPatch_Files[] = { { "p2_a.iaf", GAME_VOICEFILE, 4, &ITEMACCD_GameSound} }; -static const GamePatchDescription ITELinPatch_Files[] = { - { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL}, - { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL}, - { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL}, - { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL}, - { "credit3n.dlt", GAME_RESOURCEFILE, 1796, NULL}, - { "credit4n.dlt", GAME_RESOURCEFILE, 1797, NULL}, - { "P2_A.iaf", GAME_VOICEFILE, 4, &ITECD_GameSound} -}; - // IHNM section static const GameResourceDescription IHNM_Resources = { @@ -296,10 +252,27 @@ static const GameResourceDescription IHNM_Resources = { RID_IHNM_MAIN_PANEL_SPRITES, RID_IHNM_OPTION_PANEL_SPRITES, 0, // Default portraits (ITE only) + RID_IHNM_PROFILE_BG, RID_IHNM_MAIN_STRINGS, 0 // Actors strings (ITE only) }; +static const GameResourceDescription IHNMDEMO_Resources = { + RID_IHNMDEMO_SCENE_LUT, // Scene lookup table RN + RID_IHNMDEMO_SCRIPT_LUT, // Script lookup table RN + RID_IHNMDEMO_MAIN_PANEL, + RID_IHNMDEMO_CONVERSE_PANEL, + RID_IHNMDEMO_OPTION_PANEL, + RID_IHNMDEMO_WARNING_PANEL, + RID_IHNMDEMO_MAIN_SPRITES, + RID_IHNMDEMO_MAIN_PANEL_SPRITES, + RID_IHNMDEMO_OPTION_PANEL_SPRITES, + 0, // Default portraits (ITE only) + RID_IHNMDEMO_PROFILE_BG, + RID_IHNMDEMO_MAIN_STRINGS, + 0 // Actors strings (ITE only) +}; + static const GameFontDescription IHNMDEMO_GameFonts[] = { {2}, {3}, @@ -326,6 +299,14 @@ static const GameSoundInfo IHNM_GameSound = { }; static const SAGAGameDescription gameDescriptions[] = { + // ITE Section //////////////////////////////////////////////////////////////////////////////////////////// + + + // ITE Demos ////////////////////////////////////////////////////////////////////////////////////////////// + + // Note: This version is NOT supported yet + // Based on a very early version of the engine + // Inherit the earth - DOS Demo version // sound unchecked { @@ -336,7 +317,7 @@ static const SAGAGameDescription gameDescriptions[] = { {"ite.rsc", GAME_RESOURCEFILE, "986c79c4d2939dbe555576529fd37932", -1}, //{"ite.dmo", GAME_DEMOFILE}, "0b9a70eb4e120b6f00579b46c8cae29e" {"scripts.rsc", GAME_SCRIPTFILE, "d5697dd3240a3ceaddaa986c47e1a2d7", -1}, - {"voices.rsc", GAME_SOUNDFILE | GAME_VOICEFILE, "c58e67c506af4ffa03fd0aac2079deb0", -1}, + //{"voices.rsc", GAME_SOUNDFILE | GAME_VOICEFILE, "c58e67c506af4ffa03fd0aac2079deb0", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -350,24 +331,25 @@ static const SAGAGameDescription gameDescriptions[] = { &ITEDemo_Resources, ARRAYSIZE(ITEDEMO_GameFonts), ITEDEMO_GameFonts, - &ITEDEMO_GameSound, - &ITEDEMO_GameSound, - NULL, + &ITEDISK_GameSound, + &ITEDISK_GameSound, + &ITEMACCD_GameMusic, // note: this version did not originally have digital music 0, NULL, }, - // Inherit the earth - MAC Demo version 2 + + // Inherit the earth - MAC Demo version { { "ite", "Demo 2", { - {"ited.rsc", GAME_RESOURCEFILE, "addfc9d82bc2fa1f4cab23743c652c08", -1}, - {"scriptsd.rsc", GAME_SCRIPTFILE, "fded5c59b8b7c5976229f960d21e6b0b", -1}, - {"soundsd.rsc", GAME_SOUNDFILE, "b3a831fbed337d1f1300fee1dd474f6c", -1}, - {"voicesd.rsc", GAME_VOICEFILE, "e139d86bab2ee8ba3157337f894a92d4", -1}, - {"musicd.rsc", GAME_MUSICFILE, "495bdde51fd9f4bea2b9c911091b1ab2", -1}, + {"ited.rsc", GAME_RESOURCEFILE, "addfc9d82bc2fa1f4cab23743c652c08", 1865461}, + {"scriptsd.rsc", GAME_SCRIPTFILE, "fded5c59b8b7c5976229f960d21e6b0b", 70083}, + //{"soundsd.rsc", GAME_SOUNDFILE, "b3a831fbed337d1f1300fee1dd474f6c", -1}, + //{"voicesd.rsc", GAME_VOICEFILE, "e139d86bab2ee8ba3157337f894a92d4", -1}, + //{"musicd.rsc", GAME_MUSICFILE, "495bdde51fd9f4bea2b9c911091b1ab2", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -388,17 +370,21 @@ static const SAGAGameDescription gameDescriptions[] = { ITEMacPatch_Files, }, + + // Note: This version is NOT supported yet + // Exiting the faire leads to a crash + // Inherit the earth - MAC Demo version 1 { { "ite", "Demo 1", { - {"ited.rsc", GAME_RESOURCEFILE, "addfc9d82bc2fa1f4cab23743c652c08", -1}, - {"scriptsd.rsc", GAME_SCRIPTFILE, "fded5c59b8b7c5976229f960d21e6b0b", -1}, - {"soundsd.rsc", GAME_SOUNDFILE, "b3a831fbed337d1f1300fee1dd474f6c", -1}, - {"voicesd.rsc", GAME_VOICEFILE, "e139d86bab2ee8ba3157337f894a92d4", -1}, - {"musicd.rsc", GAME_MUSICFILE, "1a91cd60169f367ecb6c6e058d899b2f", -1}, + {"ited.rsc", GAME_RESOURCEFILE, "addfc9d82bc2fa1f4cab23743c652c08", 1131098}, + {"scriptsd.rsc", GAME_SCRIPTFILE, "fded5c59b8b7c5976229f960d21e6b0b", 38613}, + //{"soundsd.rsc", GAME_SOUNDFILE, "b3a831fbed337d1f1300fee1dd474f6c", -1}, + //{"voicesd.rsc", GAME_VOICEFILE, "e139d86bab2ee8ba3157337f894a92d4", -1}, + //{"musicd.rsc", GAME_MUSICFILE, "1a91cd60169f367ecb6c6e058d899b2f", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -419,142 +405,19 @@ static const SAGAGameDescription gameDescriptions[] = { ITEMacPatch_Files, }, - // Inherit the earth - MAC CD Guild version - { - { - "ite", - "CD", - { - {"ite resources.bin", GAME_RESOURCEFILE | GAME_MACBINARY, "0bd506aa887bfc7965f695c6bd28237d", -1}, - {"ite scripts.bin", GAME_SCRIPTFILE | GAME_MACBINARY, "af0d7a2588e09ad3ecbc5b474ea238bf", -1}, - {"ite sounds.bin", GAME_SOUNDFILE | GAME_MACBINARY, "441426c6bb2a517f65c7e49b57f7a345", -1}, - {"ite music.bin", GAME_MUSICFILE_GM | GAME_MACBINARY, "c1d20324b7cdf1650e67061b8a93251c", -1}, - {"ite voices.bin", GAME_VOICEFILE | GAME_MACBINARY, "dba92ae7d57e942250fe135609708369", -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformMacintosh, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_MACCD_G, - GF_BIG_ENDIAN_DATA | GF_CD_FX, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEWINDEMO_GameFonts), - ITEWINDEMO_GameFonts, - &ITEMACCD_G_GameSound, - &ITEMACCD_G_GameSound, - NULL, - 0, - NULL, - }, - // Inherit the earth - MAC CD Wyrmkeep version + // Inherit the earth - Win32 Demo version 2/3, Linux Demo version + // Win32 Version 3 and Linux Demo version have digital music, Win32 version 2 has MIDI music { { "ite", - "Wyrmkeep CD", - { - {"ite.rsc", GAME_RESOURCEFILE, "4f7fa11c5175980ed593392838523060", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "adf1f46c1d0589083996a7060c798ad0", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "95863b89a0916941f6c5e1789843ba14", -1}, - {"inherit the earth voices", GAME_VOICEFILE, "c14c4c995e7a0d3828e3812a494301b7", -1}, - {"music.rsc", GAME_MUSICFILE, "1a91cd60169f367ecb6c6e058d899b2f", -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformMacintosh, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_MACCD, - GF_BIG_ENDIAN_DATA | GF_WYRMKEEP | GF_CD_FX, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEWINDEMO_GameFonts), - ITEWINDEMO_GameFonts, - &ITEMACCD_GameSound, - &ITEMACCD_GameSound, - &ITEMACCD_GameMusic, - ARRAYSIZE(ITEMacPatch_Files), - ITEMacPatch_Files, - }, - - // Inherit the earth - MAC CD Wyrmkeep version (compressed sound) - { - { - "ite", - "Wyrmkeep CD", - { - {"ite.rsc", GAME_RESOURCEFILE, "4f7fa11c5175980ed593392838523060", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "adf1f46c1d0589083996a7060c798ad0", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"inherit the earth voices.cmp",GAME_VOICEFILE, NULL, -1}, - {"music.cmp", GAME_MUSICFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformMacintosh, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_MACCD, - GF_BIG_ENDIAN_DATA | GF_WYRMKEEP | GF_CD_FX | GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEWINDEMO_GameFonts), - ITEWINDEMO_GameFonts, - &ITEMACCD_GameSound, - &ITEMACCD_GameSound, - &ITEMACCD_GameMusic, - ARRAYSIZE(ITEMacPatch_Files), - ITEMacPatch_Files, - }, - - // Inherit the earth - Linux Demo version - // Note: it should be before GID_ITE_WINDEMO2 version - { - { - "ite", - "Demo", - { - {"ited.rsc", GAME_RESOURCEFILE, "3a450852cbf3c80773984d565647e6ac", -1}, - {"scriptsd.rsc", GAME_SCRIPTFILE, "3f12b67fa93e56e1a6be39d2921d80bb", -1}, - {"soundsd.rsc", GAME_SOUNDFILE, "95a6c148e22e99a8c243f2978223583c", 2026769}, - {"voicesd.rsc", GAME_VOICEFILE, "e139d86bab2ee8ba3157337f894a92d4", -1}, - {"musicd.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformLinux, - Common::ADGF_DEMO - }, - GType_ITE, - GID_ITE_LINDEMO, - GF_WYRMKEEP | GF_CD_FX | GF_SCENE_SUBSTITUTES, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEWINDEMO_GameFonts), - ITEWINDEMO_GameFonts, - &ITEWINDEMO2_GameVoice, - &ITEWINDEMO2_GameSound, - &ITELINDEMO_GameMusic, - ARRAYSIZE(ITELinPatch_Files), - ITELinPatch_Files, - }, - - // Inherit the earth - Win32 Demo version 3 - { - { - "ite", - "Demo 3", + "Win Demo 2/3, Linux Demo", { - {"ited.rsc", GAME_RESOURCEFILE, "3a450852cbf3c80773984d565647e6ac", -1}, - {"scriptsd.rsc", GAME_SCRIPTFILE, "3f12b67fa93e56e1a6be39d2921d80bb", -1}, - {"soundsd.rsc", GAME_SOUNDFILE, "95a6c148e22e99a8c243f2978223583c", 2005074}, - {"voicesd.rsc", GAME_VOICEFILE, "e139d86bab2ee8ba3157337f894a92d4", -1}, - {"musicd.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, + {"ited.rsc", GAME_RESOURCEFILE, "3a450852cbf3c80773984d565647e6ac", 1951395}, + {"scriptsd.rsc", GAME_SCRIPTFILE, "3f12b67fa93e56e1a6be39d2921d80bb", 70051}, + //{"soundsd.rsc", GAME_SOUNDFILE, "95a6c148e22e99a8c243f2978223583c", -1}, + //{"voicesd.rsc", GAME_VOICEFILE, "e139d86bab2ee8ba3157337f894a92d4", -1}, + //{"musicd.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -570,21 +433,25 @@ static const SAGAGameDescription gameDescriptions[] = { ITEWINDEMO_GameFonts, &ITEWINDEMO2_GameVoice, &ITEWINDEMO2_GameSound, - &ITELINDEMO_GameMusic, - ARRAYSIZE(ITEWinPatch2_Files), - ITEWinPatch2_Files, + &ITEMACCD_GameMusic, + ARRAYSIZE(ITEPatch_Files), + ITEPatch_Files, }, - // Inherit the earth - Win32 Demo version 2 + + // Note: This version is NOT supported yet + // Exiting the faire leads to a crash + + // Inherit the earth - Win32 Demo version 1 { { "ite", - "Demo 2", + "Demo 1", { - {"ited.rsc", GAME_RESOURCEFILE, "3a450852cbf3c80773984d565647e6ac", -1}, - {"scriptsd.rsc", GAME_SCRIPTFILE, "3f12b67fa93e56e1a6be39d2921d80bb", -1}, - {"soundsd.rsc", GAME_SOUNDFILE, "95a6c148e22e99a8c243f2978223583c", 2005074}, - {"voicesd.rsc", GAME_VOICEFILE, "e139d86bab2ee8ba3157337f894a92d4", -1}, + {"ited.rsc", GAME_RESOURCEFILE, "3a450852cbf3c80773984d565647e6ac", 1327323}, + {"scriptsd.rsc", GAME_SCRIPTFILE, "3f12b67fa93e56e1a6be39d2921d80bb", 38613}, + //{"soundsd.rsc", GAME_SOUNDFILE, "a741139dd7365a13f463cd896ff9969a", -1}, + //{"voicesd.rsc", GAME_VOICEFILE, "0759eaf5b64ae19fd429920a70151ad3", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -592,86 +459,91 @@ static const SAGAGameDescription gameDescriptions[] = { Common::ADGF_DEMO }, GType_ITE, - GID_ITE_WINDEMO2, - GF_WYRMKEEP | GF_CD_FX | GF_SCENE_SUBSTITUTES, + GID_ITE_WINDEMO1, + GF_WYRMKEEP | GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), ITEWINDEMO_GameFonts, - &ITEWINDEMO2_GameVoice, - &ITEWINDEMO2_GameSound, - NULL, - ARRAYSIZE(ITEWinPatch2_Files), - ITEWinPatch2_Files, + &ITEWINDEMO1_GameSound, + &ITEWINDEMO1_GameSound, + &ITEMACCD_GameMusic, // note: this version did not originally have digital music + ARRAYSIZE(ITEPatch_Files), + ITEPatch_Files, }, - // Inherit the earth - Win32 Demo version 1 + + // TODO: Add Amiga demos here (not supported yet) + + + // ITE Mac versions /////////////////////////////////////////////////////////////////////////////////////// + + // Inherit the earth - MAC CD Guild version { { "ite", - "Demo 1", + "CD", { - {"ited.rsc", GAME_RESOURCEFILE, "3a450852cbf3c80773984d565647e6ac", -1}, - {"scriptsd.rsc", GAME_SCRIPTFILE, "3f12b67fa93e56e1a6be39d2921d80bb", -1}, - {"soundsd.rsc", GAME_SOUNDFILE, "a741139dd7365a13f463cd896ff9969a", -1}, - {"voicesd.rsc", GAME_VOICEFILE, "0759eaf5b64ae19fd429920a70151ad3", -1}, + {"ite resources.bin", GAME_RESOURCEFILE | GAME_MACBINARY, "0bd506aa887bfc7965f695c6bd28237d", -1}, + {"ite scripts.bin", GAME_SCRIPTFILE | GAME_MACBINARY, "af0d7a2588e09ad3ecbc5b474ea238bf", -1}, + {"ite sounds.bin", GAME_SOUNDFILE | GAME_MACBINARY, "441426c6bb2a517f65c7e49b57f7a345", -1}, + {"ite music.bin", GAME_MUSICFILE_GM | GAME_MACBINARY, "c1d20324b7cdf1650e67061b8a93251c", -1}, + {"ite voices.bin", GAME_VOICEFILE | GAME_MACBINARY, "dba92ae7d57e942250fe135609708369", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, - Common::kPlatformWindows, - Common::ADGF_DEMO + Common::kPlatformMacintosh, + Common::ADGF_NO_FLAGS }, GType_ITE, - GID_ITE_WINDEMO1, - GF_WYRMKEEP | GF_CD_FX, + GID_ITE_MACCD_G, + GF_BIG_ENDIAN_DATA | GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), ITEWINDEMO_GameFonts, - &ITEWINDEMO1_GameSound, - &ITEWINDEMO1_GameSound, + &ITEMACCD_G_GameSound, + &ITEMACCD_G_GameSound, + &ITEMACCD_GameMusic, // note: this version did not originally have digital music + 0, NULL, - ARRAYSIZE(ITEWinPatch1_Files), - ITEWinPatch1_Files, }, - // Inherit the earth - Wyrmkeep combined Windows/Mac/Linux CD - - // version is different from the other Wyrmkeep re-releases in that it does - // not have any substitute files. Presumably the ite.rsc file has been - // modified to include the Wyrmkeep changes. The resource files are little- - // endian, except for the voice file which is big-endian. + // Inherit the earth - MAC CD Wyrmkeep version { { "ite", - "Multi-OS CD Version", + "Wyrmkeep CD", { - {"ite.rsc", GAME_RESOURCEFILE, "a6433e34b97b15e64fe8214651012db9", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, - {"inherit the earth voices", GAME_VOICEFILE | GAME_SWAPENDIAN, "c14c4c995e7a0d3828e3812a494301b7", -1}, - {"music.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, + {"ite.rsc", GAME_RESOURCEFILE, "4f7fa11c5175980ed593392838523060", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "adf1f46c1d0589083996a7060c798ad0", -1}, + //{"sounds.rsc", GAME_SOUNDFILE, "95863b89a0916941f6c5e1789843ba14", -1}, + //{"inherit the earth voices", GAME_VOICEFILE, "c14c4c995e7a0d3828e3812a494301b7", -1}, + //{"music.rsc", GAME_MUSICFILE, "1a91cd60169f367ecb6c6e058d899b2f", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, - Common::kPlatformUnknown, + Common::kPlatformMacintosh, Common::ADGF_NO_FLAGS }, GType_ITE, - GID_ITE_MULTICD, - GF_WYRMKEEP | GF_CD_FX, + GID_ITE_MACCD, + GF_BIG_ENDIAN_DATA | GF_WYRMKEEP | GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, + ARRAYSIZE(ITEWINDEMO_GameFonts), + ITEWINDEMO_GameFonts, + &ITEMACCD_GameSound, &ITEMACCD_GameSound, - &ITECD_GameSound, &ITEMACCD_GameMusic, - 0, - NULL, + ARRAYSIZE(ITEMacPatch_Files), + ITEMacPatch_Files, }, - // Inherit the earth - Wyrmkeep combined Windows/Mac/Linux CD (compressed sound) + + // ITE PC CD versions ////////////////////////////////////////////////////////////////////////////////////// + + // Inherit the earth - Wyrmkeep combined Windows/Mac/Linux CD // version is different from the other Wyrmkeep re-releases in that it does // not have any substitute files. Presumably the ite.rsc file has been @@ -684,9 +556,9 @@ static const SAGAGameDescription gameDescriptions[] = { { {"ite.rsc", GAME_RESOURCEFILE, "a6433e34b97b15e64fe8214651012db9", -1}, {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"inherit the earth voices.cmp",GAME_VOICEFILE | GAME_SWAPENDIAN, NULL, -1}, - {"music.cmp", GAME_MUSICFILE, NULL, -1}, + //{"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, + //{"inherit the earth voices", GAME_VOICEFILE | GAME_SWAPENDIAN, "c14c4c995e7a0d3828e3812a494301b7", -1}, + //{"music.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -695,7 +567,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, GType_ITE, GID_ITE_MULTICD, - GF_WYRMKEEP | GF_CD_FX | GF_COMPRESSED_SOUNDS, + GF_WYRMKEEP | GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITECD_GameFonts), @@ -707,138 +579,17 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, - // Inherit the earth - Wyrmkeep Linux CD version - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, - {"voices.rsc", GAME_VOICEFILE, "41bb6b95d792dde5196bdb78740895a6", -1}, - {"music.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformLinux, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_LINCD, - GF_WYRMKEEP | GF_CD_FX, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, - ARRAYSIZE(ITELinPatch_Files), - ITELinPatch_Files, - }, - - // Inherit the earth - Wyrmkeep Linux CD version (compressed sound) - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"voices.cmp", GAME_VOICEFILE, NULL, -1}, - {"music.cmp", GAME_MUSICFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformLinux, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_LINCD, - GF_WYRMKEEP | GF_CD_FX | GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, - ARRAYSIZE(ITELinPatch_Files), - ITELinPatch_Files, - }, - - // Inherit the earth - Wyrmkeep Windows CD version - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, - {"voices.rsc", GAME_VOICEFILE, "41bb6b95d792dde5196bdb78740895a6", -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformWindows, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_WINCD, - GF_WYRMKEEP | GF_CD_FX, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - NULL, - ARRAYSIZE(ITEWinPatch1_Files), - ITEWinPatch1_Files, - }, - - // Inherit the earth - Wyrmkeep Windows CD version (compressed sound) + // Inherit the earth - Windows/Linux/DOS CD version { { "ite", - "CD Version", + "Windows/Linux/DOS CD Version", { {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"voices.cmp", GAME_VOICEFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformWindows, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_WINCD, - GF_WYRMKEEP | GF_CD_FX | GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - NULL, - ARRAYSIZE(ITEWinPatch1_Files), - ITEWinPatch1_Files, - }, - - // Inherit the earth - DOS CD version - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "50a0d2d7003c926a3832d503c8534e90", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, - {"voices.rsc", GAME_VOICEFILE, "41bb6b95d792dde5196bdb78740895a6", -1}, + //{"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, + //{"voices.rsc", GAME_VOICEFILE, "41bb6b95d792dde5196bdb78740895a6", -1}, + //{"music.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -846,7 +597,7 @@ static const SAGAGameDescription gameDescriptions[] = { Common::ADGF_NO_FLAGS }, GType_ITE, - GID_ITE_CD_G, + GID_ITE_CD, GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, @@ -854,12 +605,12 @@ static const SAGAGameDescription gameDescriptions[] = { ITECD_GameFonts, &ITECD_GameSound, &ITECD_GameSound, - NULL, - 0, - NULL, + &ITEMACCD_GameMusic, + ARRAYSIZE(ITEPatch_Files), + ITEPatch_Files, }, - // Inherit the earth - DOS CD version (compressed sound) + // Inherit the earth - DOS CD version { { "ite", @@ -867,8 +618,8 @@ static const SAGAGameDescription gameDescriptions[] = { { {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, {"scripts.rsc", GAME_SCRIPTFILE, "50a0d2d7003c926a3832d503c8534e90", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"voices.cmp", GAME_VOICEFILE, NULL, -1}, + //{"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, + //{"voices.rsc", GAME_VOICEFILE, "41bb6b95d792dde5196bdb78740895a6", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -877,37 +628,6 @@ static const SAGAGameDescription gameDescriptions[] = { }, GType_ITE, GID_ITE_CD_G, - GF_CD_FX | GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - NULL, - 0, - NULL, - }, - - // Inherit the earth - DOS CD version with digital music - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "50a0d2d7003c926a3832d503c8534e90", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, - {"voices.rsc", GAME_VOICEFILE, "41bb6b95d792dde5196bdb78740895a6", -1}, - {"music.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_CD_G2, GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, @@ -915,40 +635,9 @@ static const SAGAGameDescription gameDescriptions[] = { ITECD_GameFonts, &ITECD_GameSound, &ITECD_GameSound, - &ITEMACCD_GameMusic, - 0, - NULL, - }, - - // Inherit the earth - DOS CD version with digital music (compressed sound) - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "50a0d2d7003c926a3832d503c8534e90", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"voices.cmp", GAME_VOICEFILE, NULL, -1}, - {"music.cmp", GAME_MUSICFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_CD_G2, - GF_CD_FX | GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, - 0, - NULL, + &ITEMACCD_GameMusic, // note: this version did not originally have digital music + ARRAYSIZE(ITEPatch_Files), + ITEPatch_Files, }, // Inherit the earth - DOS CD German version @@ -960,8 +649,8 @@ static const SAGAGameDescription gameDescriptions[] = { { {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, - {"voices.rsc", GAME_VOICEFILE, "2fbad5d10b9b60a3415dc4aebbb11718", -1}, + //{"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, + //{"voices.rsc", GAME_VOICEFILE, "2fbad5d10b9b60a3415dc4aebbb11718", -1}, { NULL, 0, NULL, 0} }, Common::DE_DEU, @@ -977,163 +666,13 @@ static const SAGAGameDescription gameDescriptions[] = { ITECD_GameFonts, &ITECD_GameSound, &ITECD_GameSound, - NULL, + &ITEMACCD_GameMusic, // note: this version did not originally have digital music 0, NULL, }, - // Inherit the earth - DOS CD German version (compressed sound) - // reported by mld. Bestsellergamers cover disk - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"voices.cmp", GAME_VOICEFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::DE_DEU, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_CD_DE, - GF_CD_FX | GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - NULL, - 0, - NULL, - }, - // Inherit the earth - DOS CD German version with digital music - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, - {"voices.rsc", GAME_VOICEFILE, "2fbad5d10b9b60a3415dc4aebbb11718", -1}, - {"music.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, - { NULL, 0, NULL, 0} - }, - Common::DE_DEU, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_CD_DE2, - GF_CD_FX, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, - 0, - NULL, - }, - - // Inherit the earth - DOS CD German version with digital music (compressed sound) - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"voices.cmp", GAME_VOICEFILE, NULL, -1}, - {"music.cmp", GAME_MUSICFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::DE_DEU, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_CD_DE2, - GF_CD_FX | GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, - 0, - NULL, - }, - - // Inherit the earth - CD version - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.rsc", GAME_SOUNDFILE, "e2ccb61c325d6d1ead3be0e731fe29fe", -1}, - {"voices.rsc", GAME_VOICEFILE, "41bb6b95d792dde5196bdb78740895a6", -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_CD, - GF_CD_FX, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - NULL, - 0, - NULL, - }, - - // Inherit the earth - CD version (compressed sound) - { - { - "ite", - "CD Version", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, - {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, - {"voices.cmp", GAME_VOICEFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_CD, - GF_CD_FX | GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - NULL, - 0, - NULL, - }, + // ITE floppy versions //////////////////////////////////////////////////////////////////////////////////// // Inherit the earth - German Floppy version { @@ -1143,36 +682,7 @@ static const SAGAGameDescription gameDescriptions[] = { { {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, - {"voices.rsc", GAME_SOUNDFILE | GAME_VOICEFILE, "0c9113e630f97ef0996b8c3114badb08", -1}, - { NULL, 0, NULL, 0} - }, - Common::DE_DEU, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_DISK_DE, - 0, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, - &ITEDISK_GameSound, - &ITEDISK_GameSound, - NULL, - 0, - NULL, - }, - - // Inherit the earth - German Floppy version (compressed sound) - { - { - "ite", - "Floppy", - { - {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, - {"voices.cmp", GAME_SOUNDFILE | GAME_VOICEFILE, NULL, -1}, + //{"voices.rsc", GAME_SOUNDFILE | GAME_VOICEFILE, "0c9113e630f97ef0996b8c3114badb08", -1}, { NULL, 0, NULL, 0} }, Common::DE_DEU, @@ -1181,74 +691,14 @@ static const SAGAGameDescription gameDescriptions[] = { }, GType_ITE, GID_ITE_DISK_DE, - GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, - &ITEDISK_GameSound, - &ITEDISK_GameSound, - NULL, - 0, - NULL, - }, - - // Inherit the earth - German Floppy version with digital music - { - { - "ite", - "Floppy", - { - {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, - {"voices.rsc", GAME_SOUNDFILE | GAME_VOICEFILE, "0c9113e630f97ef0996b8c3114badb08", -1}, - {"music.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, - { NULL, 0, NULL, 0} - }, - Common::DE_DEU, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_DISK_DE2, - 0, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, - &ITEDISK_GameSound, - &ITEDISK_GameSound, - &ITEMACCD_GameMusic, 0, - NULL, - }, - - // Inherit the earth - German Floppy version with digital music (compressed sound) - { - { - "ite", - "Floppy", - { - {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, - {"voices.cmp", GAME_SOUNDFILE | GAME_VOICEFILE, NULL, -1}, - {"music.cmp", GAME_MUSICFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::DE_DEU, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_DISK_DE2, - GF_COMPRESSED_SOUNDS, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEDISK_GameFonts), ITEDISK_GameFonts, &ITEDISK_GameSound, &ITEDISK_GameSound, - &ITEMACCD_GameMusic, + &ITEMACCD_GameMusic, // note: this version did not originally have digital music 0, NULL, }, @@ -1261,7 +711,7 @@ static const SAGAGameDescription gameDescriptions[] = { { {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, - {"voices.rsc", GAME_SOUNDFILE | GAME_VOICEFILE, "c46e4392fcd2e89bc91e5567db33b62d", -1}, + //{"voices.rsc", GAME_SOUNDFILE | GAME_VOICEFILE, "c46e4392fcd2e89bc91e5567db33b62d", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -1277,99 +727,18 @@ static const SAGAGameDescription gameDescriptions[] = { ITEDISK_GameFonts, &ITEDISK_GameSound, &ITEDISK_GameSound, - NULL, - 0, - NULL, + &ITEMACCD_GameMusic, // note: this version did not originally have digital music + ARRAYSIZE(ITEPatch_Files), + ITEPatch_Files, }, - // Inherit the earth - Disk version (compressed sound) - { - { - "ite", - "Floppy", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, - {"voices.cmp", GAME_SOUNDFILE | GAME_VOICEFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_DISK_G, - GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, - &ITEDISK_GameSound, - &ITEDISK_GameSound, - NULL, - 0, - NULL, - }, - // Inherit the earth - Disk version with digital music - { - { - "ite", - "Floppy", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, - {"voices.rsc", GAME_SOUNDFILE | GAME_VOICEFILE, "c46e4392fcd2e89bc91e5567db33b62d", -1}, - {"music.rsc", GAME_MUSICFILE, "d6454756517f042f01210458abe8edd4", -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_DISK_G2, - 0, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, - &ITEDISK_GameSound, - &ITEDISK_GameSound, - &ITEMACCD_GameMusic, - 0, - NULL, - }, + // ITE Amiga versions ///////////////////////////////////////////////////////////////////////////////////// - // Inherit the earth - Disk version with digital music (compressed sound) - { - { - "ite", - "Floppy", - { - {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, - {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, - {"voices.cmp", GAME_SOUNDFILE | GAME_VOICEFILE, NULL, -1}, - {"music.cmp", GAME_MUSICFILE, NULL, -1}, - { NULL, 0, NULL, 0} - }, - Common::EN_ANY, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - GType_ITE, - GID_ITE_DISK_G2, - GF_COMPRESSED_SOUNDS, - ITE_DEFAULT_SCENE, - &ITE_Resources, - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, - &ITEDISK_GameSound, - &ITEDISK_GameSound, - &ITEMACCD_GameMusic, - 0, - NULL, - }, + // TODO: Add the Amiga versions here (not supported yet) + + + // IHNM Section /////////////////////////////////////////////////////////////////////////////////////////// // I Have No Mouth And I Must Scream - Demo version { @@ -1377,10 +746,11 @@ static const SAGAGameDescription gameDescriptions[] = { "ihnm", "Demo", { + {"music.res", GAME_MUSICFILE_FM, "0439083e3dfdc51b486071d45872ae52", -1}, {"scream.res", GAME_RESOURCEFILE, "46bbdc65d164ba7e89836a0935eec8e6", -1}, {"scripts.res", GAME_SCRIPTFILE, "9626bda8978094ff9b29198bc1ed5f9a", -1}, {"sfx.res", GAME_SOUNDFILE, "1c610d543f32ec8b525e3f652536f269", -1}, - {"voicesd.res", GAME_VOICEFILE, "3bbc16a8f741dbb511da506c660a0b54", -1}, + //{"voicesd.res", GAME_VOICEFILE, "3bbc16a8f741dbb511da506c660a0b54", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -1390,8 +760,8 @@ static const SAGAGameDescription gameDescriptions[] = { GType_IHNM, GID_IHNM_DEMO, 0, - 0, - &IHNM_Resources, + IHNMDEMO_DEFAULT_SCENE, + &IHNMDEMO_Resources, ARRAYSIZE(IHNMDEMO_GameFonts), IHNMDEMO_GameFonts, &IHNM_GameSound, @@ -1413,13 +783,13 @@ static const SAGAGameDescription gameDescriptions[] = { {"patch.re_", GAME_PATCHFILE | GAME_RESOURCEFILE, "58b79e61594779513c7f2d35509fa89e", -1}, {"scripts.res", GAME_SCRIPTFILE, "be38bbc5a26be809dbf39f13befebd01", -1}, {"sfx.res", GAME_SOUNDFILE, "1c610d543f32ec8b525e3f652536f269", -1}, - {"voicess.res", GAME_VOICEFILE, "54b1f2013a075338ceb0e258d97808bd", -1}, //order of voice bank file is important - {"voices1.res", GAME_VOICEFILE, "fc6440b38025f4b2cc3ff55c3da5c3eb", -1}, - {"voices2.res", GAME_VOICEFILE, "b37f10fd1696ade7d58704ccaaebceeb", -1}, - {"voices3.res", GAME_VOICEFILE, "3bbc16a8f741dbb511da506c660a0b54", -1}, - {"voices4.res", GAME_VOICEFILE, "ebfa160122d2247a676ca39920e5d481", -1}, - {"voices5.res", GAME_VOICEFILE, "1f501ce4b72392bdd1d9ec38f6eec6da", -1}, - {"voices6.res", GAME_VOICEFILE, "f580ed7568c7d6ef34e934ba20adf834", -1}, + //{"voicess.res", GAME_VOICEFILE, "54b1f2013a075338ceb0e258d97808bd", -1}, //order of voice bank file is important + //{"voices1.res", GAME_VOICEFILE, "fc6440b38025f4b2cc3ff55c3da5c3eb", -1}, + //{"voices2.res", GAME_VOICEFILE, "b37f10fd1696ade7d58704ccaaebceeb", -1}, + //{"voices3.res", GAME_VOICEFILE, "3bbc16a8f741dbb511da506c660a0b54", -1}, + //{"voices4.res", GAME_VOICEFILE, "ebfa160122d2247a676ca39920e5d481", -1}, + //{"voices5.res", GAME_VOICEFILE, "1f501ce4b72392bdd1d9ec38f6eec6da", -1}, + //{"voices6.res", GAME_VOICEFILE, "f580ed7568c7d6ef34e934ba20adf834", -1}, { NULL, 0, NULL, 0} }, Common::EN_ANY, @@ -1454,12 +824,12 @@ static const SAGAGameDescription gameDescriptions[] = { {"scripts.res", GAME_SCRIPTFILE, "32aa01a89937520fe0ea513950117292", -1}, {"patch.re_", GAME_PATCHFILE | GAME_RESOURCEFILE, "58b79e61594779513c7f2d35509fa89e", -1}, {"sfx.res", GAME_SOUNDFILE, "1c610d543f32ec8b525e3f652536f269", -1}, - {"voicess.res", GAME_VOICEFILE, "8b09a196a52627cacb4eab13bfe0b2c3", -1}, //order of voice bank file is important - {"voices1.res", GAME_VOICEFILE, "424971e1e2373187c3f5734fe36071a2", -1}, - {"voices2.res", GAME_VOICEFILE, "c270e0980782af43641a86e4a14e2a32", -1}, - {"voices3.res", GAME_VOICEFILE, "49e42befea883fd101ec3d0f5d0647b9", -1}, - {"voices5.res", GAME_VOICEFILE, "c477443c52a0aa56e686ebd8d051e4ab", -1}, - {"voices6.res", GAME_VOICEFILE, "2b9aea838f74b4eecfb29a8f205a2bd4", -1}, + //{"voicess.res", GAME_VOICEFILE, "8b09a196a52627cacb4eab13bfe0b2c3", -1}, //order of voice bank file is important + //{"voices1.res", GAME_VOICEFILE, "424971e1e2373187c3f5734fe36071a2", -1}, + //{"voices2.res", GAME_VOICEFILE, "c270e0980782af43641a86e4a14e2a32", -1}, + //{"voices3.res", GAME_VOICEFILE, "49e42befea883fd101ec3d0f5d0647b9", -1}, + //{"voices5.res", GAME_VOICEFILE, "c477443c52a0aa56e686ebd8d051e4ab", -1}, + //{"voices6.res", GAME_VOICEFILE, "2b9aea838f74b4eecfb29a8f205a2bd4", -1}, { NULL, 0, NULL, 0} }, Common::DE_DEU, @@ -1492,13 +862,13 @@ static const SAGAGameDescription gameDescriptions[] = { {"patch.re_", GAME_PATCHFILE | GAME_RESOURCEFILE, "58b79e61594779513c7f2d35509fa89e", -1}, {"scripts.res", GAME_SCRIPTFILE, "be38bbc5a26be809dbf39f13befebd01", -1}, {"sfx.res", GAME_SOUNDFILE, "1c610d543f32ec8b525e3f652536f269", -1}, - {"voicess.res", GAME_VOICEFILE, "d869de9883c8faea7f687217a9ec7057", -1}, //order of voice bank file is important - {"voices1.res", GAME_VOICEFILE, "dc6a34e3d1668730ea46815a92c7847f", -1}, - {"voices2.res", GAME_VOICEFILE, "dc6a5fa7a4cdc2ca5a6fd924e969986c", -1}, - {"voices3.res", GAME_VOICEFILE, "dc6a5fa7a4cdc2ca5a6fd924e969986c", -1}, - {"voices4.res", GAME_VOICEFILE, "0f87400b804232a58dd22e404420cc45", -1}, - {"voices5.res", GAME_VOICEFILE, "172668cfc5d8c305cb5b1a9b4d995fc0", -1}, - {"voices6.res", GAME_VOICEFILE, "96c9bda9a5f41d6bc232ed7bf6d371d9", -1}, + //{"voicess.res", GAME_VOICEFILE, "d869de9883c8faea7f687217a9ec7057", -1}, //order of voice bank file is important + //{"voices1.res", GAME_VOICEFILE, "dc6a34e3d1668730ea46815a92c7847f", -1}, + //{"voices2.res", GAME_VOICEFILE, "dc6a5fa7a4cdc2ca5a6fd924e969986c", -1}, + //{"voices3.res", GAME_VOICEFILE, "dc6a5fa7a4cdc2ca5a6fd924e969986c", -1}, + //{"voices4.res", GAME_VOICEFILE, "0f87400b804232a58dd22e404420cc45", -1}, + //{"voices5.res", GAME_VOICEFILE, "172668cfc5d8c305cb5b1a9b4d995fc0", -1}, + //{"voices6.res", GAME_VOICEFILE, "96c9bda9a5f41d6bc232ed7bf6d371d9", -1}, { NULL, 0, NULL, 0} }, Common::ES_ESP, @@ -1531,13 +901,13 @@ static const SAGAGameDescription gameDescriptions[] = { {"patch.re_", GAME_PATCHFILE | GAME_RESOURCEFILE, "58b79e61594779513c7f2d35509fa89e", -1}, {"scripts.res", GAME_SCRIPTFILE, "be38bbc5a26be809dbf39f13befebd01", -1}, {"sfx.res", GAME_SOUNDFILE, "1c610d543f32ec8b525e3f652536f269", -1}, - {"voicess.res", GAME_VOICEFILE, "9df7cd3b18ddaa16b5291b3432567036", -1}, //order of voice bank file is important - {"voices1.res", GAME_VOICEFILE, "d6100d2dc3b2b9f2e1ad247f613dce9b", -1}, - {"voices2.res", GAME_VOICEFILE, "84f6f48ecc2832841ea6417a9a379430", -1}, - {"voices3.res", GAME_VOICEFILE, "ebb9501283047f27a0f54e27b3c8ba1e", -1}, - {"voices4.res", GAME_VOICEFILE, "4c145da5fa6d1306162a7ca8ce5a4f2e", -1}, - {"voices5.res", GAME_VOICEFILE, "871a559644281917677eca4af1b05620", -1}, - {"voices6.res", GAME_VOICEFILE, "211be5c24f066d69a2f6cfa953acfba6", -1}, + //{"voicess.res", GAME_VOICEFILE, "9df7cd3b18ddaa16b5291b3432567036", -1}, //order of voice bank file is important + //{"voices1.res", GAME_VOICEFILE, "d6100d2dc3b2b9f2e1ad247f613dce9b", -1}, + //{"voices2.res", GAME_VOICEFILE, "84f6f48ecc2832841ea6417a9a379430", -1}, + //{"voices3.res", GAME_VOICEFILE, "ebb9501283047f27a0f54e27b3c8ba1e", -1}, + //{"voices4.res", GAME_VOICEFILE, "4c145da5fa6d1306162a7ca8ce5a4f2e", -1}, + //{"voices5.res", GAME_VOICEFILE, "871a559644281917677eca4af1b05620", -1}, + //{"voices6.res", GAME_VOICEFILE, "211be5c24f066d69a2f6cfa953acfba6", -1}, { NULL, 0, NULL, 0} }, Common::RU_RUS, @@ -1570,12 +940,12 @@ static const SAGAGameDescription gameDescriptions[] = { {"scripts.res", GAME_SCRIPTFILE, "32aa01a89937520fe0ea513950117292", -1}, {"patch.re_", GAME_PATCHFILE | GAME_RESOURCEFILE, "58b79e61594779513c7f2d35509fa89e", -1}, {"sfx.res", GAME_SOUNDFILE, "1c610d543f32ec8b525e3f652536f269", -1}, - {"voicess.res", GAME_VOICEFILE, "b8642e943bbebf89cef2f48b31cb4305", -1}, //order of voice bank file is important - {"voices1.res", GAME_VOICEFILE, "424971e1e2373187c3f5734fe36071a2", -1}, - {"voices2.res", GAME_VOICEFILE, "c2d93a35d2c2def9c3d6d242576c794b", -1}, - {"voices3.res", GAME_VOICEFILE, "49e42befea883fd101ec3d0f5d0647b9", -1}, - {"voices5.res", GAME_VOICEFILE, "f4c415de7c03de86b73f9a12b8bd632f", -1}, - {"voices6.res", GAME_VOICEFILE, "3fc5358a5d8eee43bdfab2740276572e", -1}, + //{"voicess.res", GAME_VOICEFILE, "b8642e943bbebf89cef2f48b31cb4305", -1}, //order of voice bank file is important + //{"voices1.res", GAME_VOICEFILE, "424971e1e2373187c3f5734fe36071a2", -1}, + //{"voices2.res", GAME_VOICEFILE, "c2d93a35d2c2def9c3d6d242576c794b", -1}, + //{"voices3.res", GAME_VOICEFILE, "49e42befea883fd101ec3d0f5d0647b9", -1}, + //{"voices5.res", GAME_VOICEFILE, "f4c415de7c03de86b73f9a12b8bd632f", -1}, + //{"voices6.res", GAME_VOICEFILE, "3fc5358a5d8eee43bdfab2740276572e", -1}, { NULL, 0, NULL, 0} }, Common::FR_FRA, diff --git a/engines/saga/displayinfo.h b/engines/saga/displayinfo.h index 83bc536959..74bbcc4343 100644 --- a/engines/saga/displayinfo.h +++ b/engines/saga/displayinfo.h @@ -23,6 +23,8 @@ * */ +// Interface widget display information + #ifndef SAGA_DISPLAYINFO_H #define SAGA_DISPLAYINFO_H diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp index b93c6017c7..80e6b58595 100644 --- a/engines/saga/events.cpp +++ b/engines/saga/events.cpp @@ -35,6 +35,7 @@ #include "saga/palanim.h" #include "saga/render.h" #include "saga/sndres.h" +#include "saga/rscfile.h" #include "saga/music.h" #include "saga/actor.h" @@ -344,6 +345,39 @@ int Events::handleOneShot(Event *event) { _vm->_actor->showActors(true); } break; + case kPsychicProfileBgEvent: + { + ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE); + + byte *resourceData; + size_t resourceDataLength; + + _vm->_resource->loadResource(context, _vm->getResourceDescription()->psychicProfileResourceId, resourceData, resourceDataLength); + + byte *buf; + size_t buflen; + int width; + int height; + + _vm->decodeBGImage(resourceData, resourceDataLength, &buf, &buflen, &width, &height); + + const PalEntry *palette = (const PalEntry *)_vm->getImagePal(resourceData, resourceDataLength); + + Surface *bgSurface = _vm->_render->getBackGroundSurface(); + const Rect profileRect(width, height); + + bgSurface->blit(profileRect, buf); + _vm->_frameCount++; + + _vm->_gfx->setPalette(palette); + + free(buf); + free(resourceData); + + // Draw the scene. It won't be drawn by Render::drawScene(), as the RF_PLACARD is set + _vm->_scene->draw(); + } + break; case kAnimEvent: switch (event->op) { case kEventPlay: @@ -460,12 +494,13 @@ int Events::handleOneShot(Event *event) { _vm->_gfx->showCursor(false); break; case kEventSetNormalCursor: - // in ITE there is just one cursor - if (_vm->getGameType() == GType_IHNM) + // in ITE and IHNM demo there is just one cursor + if (_vm->getGameType() == GType_IHNM && _vm->getGameId() != GID_IHNM_DEMO) _vm->_gfx->setCursor(kCursorNormal); break; case kEventSetBusyCursor: - if (_vm->getGameType() == GType_IHNM) + // in ITE and IHNM demo there is just one cursor + if (_vm->getGameType() == GType_IHNM && _vm->getGameId() != GID_IHNM_DEMO) _vm->_gfx->setCursor(kCursorBusy); break; default: diff --git a/engines/saga/events.h b/engines/saga/events.h index d0af1fe916..2486525751 100644 --- a/engines/saga/events.h +++ b/engines/saga/events.h @@ -60,7 +60,8 @@ enum EventCodes { kScriptEvent, kCursorEvent, kGraphicsEvent, - kCutawayEvent + kCutawayEvent, + kPsychicProfileBgEvent }; enum EventOps { diff --git a/engines/saga/font.cpp b/engines/saga/font.cpp index ece48512df..71cd6b0eef 100644 --- a/engines/saga/font.cpp +++ b/engines/saga/font.cpp @@ -24,6 +24,7 @@ */ // Font management and font drawing module + #include "saga/saga.h" #include "saga/gfx.h" #include "saga/rscfile.h" @@ -331,7 +332,7 @@ void Font::outFont(const FontStyle &drawFont, Surface *ds, const char *text, siz // Check if character is defined if ((drawFont.fontCharEntry[c_code].index == 0) && (c_code != FONT_FIRSTCHAR)) { #if FONT_SHOWUNDEFINED - if (c_code == FONT_CH_SPACE) { + if (c_code == FONT_CH_SPACE || c_code == 9) { textPoint.x += drawFont.fontCharEntry[c_code].tracking; continue; } @@ -629,7 +630,8 @@ void Font::textDrawRect(FontId fontId, Surface *ds, const char *text, const Comm Font::FontId Font::knownFont2FontIdx(KnownFont font) { FontId fontId = kSmallFont; - if (_vm->getGameType() == GType_ITE) { + // The demo version of IHNM has 3 font types (like ITE), not 6 (like the full version of IHNM) + if (_vm->getGameType() == GType_ITE || _vm->getGameId() == GID_IHNM_DEMO) { switch (font) { case (kKnownFontSmall): @@ -652,7 +654,7 @@ Font::FontId Font::knownFont2FontIdx(KnownFont font) { fontId = _vm->_font->valid(kBigFont) ? kBigFont : kMediumFont; break; } - } else if (_vm->getGameType() == GType_IHNM) { + } else if (_vm->getGameType() == GType_IHNM && _vm->getGameId() != GID_IHNM_DEMO) { switch (font) { case (kKnownFontSmall): diff --git a/engines/saga/gfx.cpp b/engines/saga/gfx.cpp index a9c6801714..56ffe04c96 100644 --- a/engines/saga/gfx.cpp +++ b/engines/saga/gfx.cpp @@ -130,10 +130,7 @@ void Surface::drawPolyLine(const Point *points, int count, int color) { } } -/** -* Dissolve one image with another. -* If flags if set to 1, do zero masking. -*/ +// Dissolve one image with another. If flags is set to 1, do zero masking. void Surface::transitionDissolve(const byte *sourceBuffer, const Common::Rect &sourceRect, int flags, double percent) { #define XOR_MASK 0xB400; int pixelcount = w * h; @@ -431,7 +428,10 @@ void Gfx::setCursor(CursorType cursorType) { switch (cursorType) { case kCursorBusy: - resourceId = RID_IHNM_HOURGLASS_CURSOR; + if (_vm->getGameId() != GID_IHNM_DEMO) + resourceId = RID_IHNM_HOURGLASS_CURSOR; + else + resourceId = (uint32)-1; break; default: resourceId = (uint32)-1; diff --git a/engines/saga/ihnm_introproc.cpp b/engines/saga/ihnm_introproc.cpp index e122082322..631da37e82 100644 --- a/engines/saga/ihnm_introproc.cpp +++ b/engines/saga/ihnm_introproc.cpp @@ -31,6 +31,7 @@ #include "saga/animation.h" #include "saga/events.h" #include "saga/interface.h" +#include "saga/rscfile.h" #include "saga/sndres.h" #include "saga/music.h" @@ -39,7 +40,7 @@ namespace Saga { SceneResourceData IHNM_IntroMovie1RL[] = { - {30, 2, 0, 0, false} , + {30, 2, 0, 0, false}, {31, 14, 0, 0, false} }; @@ -50,7 +51,7 @@ SceneDescription IHNM_IntroMovie1Desc = { }; SceneResourceData IHNM_IntroMovie2RL[] = { - {32, 2, 0, 0, false} , + {32, 2, 0, 0, false}, {33, 14, 0, 0, false} }; @@ -82,28 +83,100 @@ SceneDescription IHNM_IntroMovie4Desc = { ARRAYSIZE(IHNM_IntroMovie4RL) }; +// Demo +SceneResourceData IHNMDEMO_IntroMovie1RL[] = { + {19, 2, 0, 0, false} // this scene doesn't have an animation +}; + +SceneDescription IHNMDEMO_IntroMovie1Desc = { + 0, 0, 0, 0, 0, 0, 0, 0, + IHNMDEMO_IntroMovie1RL, + ARRAYSIZE(IHNMDEMO_IntroMovie1RL) +}; + +SceneResourceData IHNMDEMO_IntroMovie2RL[] = { + {22, 2, 0, 0, false}, + {23, 14, 0, 0, false} +}; + +SceneDescription IHNMDEMO_IntroMovie2Desc = { + 0, 0, 0, 0, 0, 0, 0, 0, + IHNMDEMO_IntroMovie2RL, + ARRAYSIZE(IHNMDEMO_IntroMovie2RL) +}; + LoadSceneParams IHNM_IntroList[] = { {0, kLoadByDescription, &IHNM_IntroMovie1Desc, Scene::SC_IHNMIntroMovieProc1, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, {0, kLoadByDescription, &IHNM_IntroMovie2Desc, Scene::SC_IHNMIntroMovieProc2, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, {0, kLoadByDescription, &IHNM_IntroMovie3Desc, Scene::SC_IHNMIntroMovieProc3, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, }; +LoadSceneParams IHNMDEMO_IntroList[] = { + {0, kLoadByDescription, &IHNMDEMO_IntroMovie1Desc, Scene::SC_IHNMIntroMovieProc1, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, + {0, kLoadByDescription, &IHNMDEMO_IntroMovie2Desc, Scene::SC_IHNMIntroMovieProc3, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, +}; + +// IHNM cutaway intro resource IDs +#define RID_IHNM_INTRO_CUTAWAYS 39 +#define RID_IHNMDEMO_INTRO_CUTAWAYS 25 + int Scene::IHNMStartProc() { size_t n_introscenes; size_t i; LoadSceneParams firstScene; + /* + // Test code - uses loadCutawayList to load the intro cutaways, like the original + + ResourceContext *resourceContext; + //ResourceContext *soundContext; + byte *resourcePointer; + size_t resourceLength; + + resourceContext = _vm->_resource->getContext(GAME_RESOURCEFILE); + if (resourceContext == NULL) { + error("Scene::IHNMStartProc() resource context not found"); + } + + if (_vm->getGameId() != GID_IHNM_DEMO) + _vm->_resource->loadResource(resourceContext, RID_IHNM_INTRO_CUTAWAYS, resourcePointer, resourceLength); + else + _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_INTRO_CUTAWAYS, resourcePointer, resourceLength); + + if (resourceLength == 0) { + error("Scene::IHNMStartProc() Can't load cutaway list"); + } + + // Load the cutaways for the title screens + _vm->_anim->loadCutawayList(resourcePointer, resourceLength); + + // Note that the resource ID needed is the returned ID minus one + printf("%i\n", _vm->_anim->cutawayResourceID(0)); + printf("%i\n", _vm->_anim->cutawayResourceID(1)); + printf("%i\n", _vm->_anim->cutawayResourceID(2)); + */ + // The original used the "play video" mechanism for the first part of // the intro. We just use that panel mode. _vm->_anim->setCutAwayMode(kPanelVideo); _vm->_interface->setMode(kPanelVideo); - n_introscenes = ARRAYSIZE(IHNM_IntroList); - - for (i = 0; i < n_introscenes; i++) { - _vm->_scene->queueScene(&IHNM_IntroList[i]); + if (_vm->getGameId() != GID_IHNM_DEMO) + n_introscenes = ARRAYSIZE(IHNM_IntroList); + else + n_introscenes = ARRAYSIZE(IHNMDEMO_IntroList); + + // Queue the company and title videos + if (_vm->getGameId() != GID_IHNM_DEMO) { + for (i = 0; i < n_introscenes; i++) { + _vm->_scene->queueScene(&IHNM_IntroList[i]); + } + } else { + for (i = 0; i < n_introscenes; i++) { + _vm->_scene->queueScene(&IHNMDEMO_IntroList[i]); + } } firstScene.loadFlag = kLoadBySceneNumber; @@ -140,16 +213,40 @@ int Scene::IHNMIntroMovieProc1(int param) { q_event = _vm->_events->queue(&event); - _vm->_anim->setFrameTime(0, IHNM_INTRO_FRAMETIME); - _vm->_anim->setFlag(0, ANIM_FLAG_ENDSCENE); + if (_vm->getGameId() != GID_IHNM_DEMO) { + _vm->_anim->setFrameTime(0, IHNM_INTRO_FRAMETIME); + _vm->_anim->setFlag(0, ANIM_FLAG_ENDSCENE); - event.type = kEvTOneshot; - event.code = kAnimEvent; - event.op = kEventPlay; - event.param = 0; - event.time = 0; + event.type = kEvTOneshot; + event.code = kAnimEvent; + event.op = kEventPlay; + event.param = 0; + event.time = 0; + + q_event = _vm->_events->chain(q_event, &event); + } else { + // Start playing the intro music for the demo version + event.type = kEvTOneshot; + event.code = kMusicEvent; + event.param = 1; + event.param2 = MUSIC_NORMAL; + event.op = kEventPlay; + event.time = 0; + + q_event = _vm->_events->chain(q_event, &event); + + // The IHNM demo doesn't have an animation at the + // Cyberdreans logo screen + + // Queue end of scene after a while + event.type = kEvTOneshot; + event.code = kSceneEvent; + event.op = kEventEnd; + event.time = 8000; + + q_event = _vm->_events->chain(q_event, &event); + } - q_event = _vm->_events->chain(q_event, &event); break; default: break; @@ -273,14 +370,16 @@ int Scene::IHNMIntroMovieProc3(int param) { // In the GM file, this music also appears as tracks 7, 13, 19, // 25 and 31, but only track 1 sounds right with the FM music. - event.type = kEvTOneshot; - event.code = kMusicEvent; - event.param = 1; - event.param2 = MUSIC_NORMAL; - event.op = kEventPlay; - event.time = 0; + if (_vm->getGameId() != GID_IHNM_DEMO) { + event.type = kEvTOneshot; + event.code = kMusicEvent; + event.param = 1; + event.param2 = MUSIC_NORMAL; + event.op = kEventPlay; + event.time = 0; - q_event = _vm->_events->chain(q_event, &event); + q_event = _vm->_events->chain(q_event, &event); + } // Background for intro scene is the first frame of the intro // animation; display it but don't set palette @@ -317,7 +416,10 @@ int Scene::IHNMIntroMovieProc3(int param) { event.type = kEvTOneshot; event.code = kSceneEvent; event.op = kEventEnd; - event.time = _vm->_music->hasAdlib() ? IHNM_TITLE_TIME_FM : IHNM_TITLE_TIME_GM; + if (_vm->getGameId() != GID_IHNM_DEMO) + event.time = _vm->_music->hasAdlib() ? IHNM_TITLE_TIME_FM : IHNM_TITLE_TIME_GM; + else + event.time = 12000; q_event = _vm->_events->chain(q_event, &event); break; diff --git a/engines/saga/image.cpp b/engines/saga/image.cpp index f76258c565..9f72036634 100644 --- a/engines/saga/image.cpp +++ b/engines/saga/image.cpp @@ -24,6 +24,7 @@ */ // SAGA Image resource management routines + #include "saga/saga.h" #include "saga/stream.h" diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 55b2b0a996..8cfd993391 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -337,13 +337,23 @@ int Interface::activate() { _vm->_script->_skipSpeeches = false; _vm->_actor->_protagonist->_targetObject = ID_NOTHING; unlockMode(); - if (_panelMode == kPanelMain || _panelMode == kPanelChapterSelection){ + if (_panelMode == kPanelMain || _panelMode == kPanelChapterSelection) { + _saveReminderState = 1; + } else if (_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO) { _saveReminderState = 1; } draw(); } - _vm->_gfx->showCursor(true); + if (_vm->getGameId() != GID_IHNM_DEMO) { + _vm->_gfx->showCursor(true); + } else { + if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) { + // Don't show the mouse cursor in the non-interactive part of the IHNM demo + } else { + _vm->_gfx->showCursor(true); + } + } return SUCCESS; } @@ -359,18 +369,18 @@ int Interface::deactivate() { } void Interface::rememberMode() { - assert (_savedMode == -1); + debug(1, "rememberMode(%d)", _savedMode); _savedMode = _panelMode; - - debug(1, "rememberMode(%d)", _savedMode); } void Interface::restoreMode(bool draw_) { - assert (_savedMode != -1); - debug(1, "restoreMode(%d)", _savedMode); + // If _savedMode is -1 by a race condition, set it to kPanelMain + if (_savedMode == -1) + _savedMode = kPanelMain; + _panelMode = _savedMode; _savedMode = -1; @@ -386,10 +396,23 @@ void Interface::setMode(int mode) { _saveReminderState = 1; //TODO: blinking timeout } else if (mode == kPanelChapterSelection) { _saveReminderState = 1; + } else if (mode == kPanelNull) { + if (_vm->getGameId() == GID_IHNM_DEMO) { + _inMainMode = true; + _saveReminderState = 1; + if ((_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) || + _vm->_scene->currentSceneNumber() == 0 || _vm->_scene->currentSceneNumber() == -1) + _vm->_gfx->showCursor(false); + } + } else if (mode == kPanelOption) { + // Show the cursor in the IHNM demo + if (_vm->getGameId() == GID_IHNM_DEMO) + _vm->_gfx->showCursor(true); } else { if (mode == kPanelConverse) { _inMainMode = false; } + _saveReminderState = 0; } @@ -440,12 +463,18 @@ void Interface::setMode(int mode) { _vm->_render->setFlag(RF_DEMO_SUBST); break; case kPanelProtect: - _protectPanel.currentButton = NULL; - _textInputMaxWidth = _protectEdit->width - 10; - _textInput = true; - _textInputString[0] = 0; - _textInputStringLength = 0; - _textInputPos = _textInputStringLength + 1; + if (_vm->getGameType() == GType_ITE) { + // This is used as the copy protection panel in ITE + _protectPanel.currentButton = NULL; + _textInputMaxWidth = _protectEdit->width - 10; + _textInput = true; + _textInputString[0] = 0; + _textInputStringLength = 0; + _textInputPos = _textInputStringLength + 1; + } else { + // In the IHNM demo, this panel mode is set by the scripts + // to flip through the pages of the help system + } break; } @@ -476,6 +505,11 @@ bool Interface::processAscii(uint16 ascii) { } return true; } + + if (_vm->getGameId() == GID_IHNM_DEMO) { + if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) + _vm->_scene->showIHNMDemoSpecialScreen(); + } break; case kPanelCutaway: if (ascii == 27) { // Esc @@ -484,6 +518,11 @@ bool Interface::processAscii(uint16 ascii) { _vm->_scene->cutawaySkip(); return true; } + + if (_vm->getGameId() == GID_IHNM_DEMO) { + if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) + _vm->_scene->showIHNMDemoSpecialScreen(); + } break; case kPanelVideo: if (ascii == 27) { // Esc @@ -494,6 +533,12 @@ bool Interface::processAscii(uint16 ascii) { _vm->_actor->abortAllSpeeches(); } _vm->_scene->cutawaySkip(); + return true; + } + + if (_vm->getGameId() == GID_IHNM_DEMO) { + if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) + _vm->_scene->showIHNMDemoSpecialScreen(); } break; case kPanelOption: @@ -632,18 +677,35 @@ bool Interface::processAscii(uint16 ascii) { keyBossExit(); break; case kPanelProtect: - if (_textInput && processTextInput(ascii)) { - return true; - } + if (_vm->getGameType() == GType_ITE) { + if (_textInput && processTextInput(ascii)) { + return true; + } - if (ascii == 27 || ascii == 13) { // Esc or Enter - _vm->_script->wakeUpThreads(kWaitTypeRequest); - _vm->_interface->setMode(kPanelMain); - - _protectHash = 0; + if (ascii == 27 || ascii == 13) { // Esc or Enter + _vm->_script->wakeUpThreads(kWaitTypeRequest); + _vm->_interface->setMode(kPanelMain); + + _protectHash = 0; - for (char *p = _textInputString; *p; p++) - _protectHash = (_protectHash << 1) + toupper(*p); + for (char *p = _textInputString; *p; p++) + _protectHash = (_protectHash << 1) + toupper(*p); + } + } else { + // In the IHNM demo, this panel mode is set by the scripts + // to flip through the pages of the help system + } + break; + case kPanelPlacard: + if (_vm->getGameType() == GType_IHNM) { + // Any keypress here returns the user back to the game + if (_vm->getGameId() != GID_IHNM_DEMO) { + _vm->_scene->clearPsychicProfile(); + } else { + setMode(kPanelConverse); + _vm->_scene->_textList.clear(); + _vm->_script->wakeUpThreads(kWaitTypeDelay); + } } break; } @@ -656,6 +718,10 @@ void Interface::setStatusText(const char *text, int statusColor) { if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 8) return; + // Disable the status text in the introduction of the IHNM demo + if (_vm->getGameId() == GID_IHNM_DEMO && _vm->_scene->currentSceneNumber() == 0) + return; + assert(text != NULL); assert(strlen(text) < STATUS_TEXT_LEN); @@ -719,7 +785,8 @@ void Interface::draw() { drawStatusBar(); - if (_panelMode == kPanelMain || _panelMode == kPanelMap) { + if (_panelMode == kPanelMain || _panelMode == kPanelMap || + (_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO)) { _mainPanel.getRect(rect); backBuffer->blit(rect, _mainPanel.image); @@ -745,7 +812,8 @@ void Interface::draw() { } if (_panelMode == kPanelMain || _panelMode == kPanelConverse || - _lockedMode == kPanelMain || _lockedMode == kPanelConverse) { + _lockedMode == kPanelMain || _lockedMode == kPanelConverse || + (_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO)) { leftPortraitPoint.x = _mainPanel.x + _vm->getDisplayInfo().leftPortraitXOffset; leftPortraitPoint.y = _mainPanel.y + _vm->getDisplayInfo().leftPortraitYOffset; _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _defPortraits, _leftPortrait, leftPortraitPoint, 256); @@ -1467,10 +1535,20 @@ void Interface::setOption(PanelButton *panelButton) { switch (panelButton->id) { case kTextContinuePlaying: ConfMan.flushToDisk(); - if (!(_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 8)) + if (_vm->getGameType() == GType_ITE) { setMode(kPanelMain); - else - setMode(kPanelChapterSelection); + } else { + if (_vm->_scene->currentChapterNumber() == 8) { + setMode(kPanelChapterSelection); + } else if (_vm->getGameId() == GID_IHNM_DEMO) { + if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) + setMode(kPanelNull); + else + setMode(kPanelMain); + } else { + setMode(kPanelMain); + } + } break; case kTextQuitGame: setMode(kPanelQuit); @@ -1486,6 +1564,12 @@ void Interface::setOption(PanelButton *panelButton) { } break; case kTextSave: + // Disallow saving in the non-interactive part of the IHNM demo + if (_vm->getGameId() == GID_IHNM_DEMO) { + if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) + return; + } + if (!_vm->isSaveListFull() && (_optionSaveFileTitleNumber == 0)) { _textInputString[0] = 0; } else { @@ -1536,7 +1620,12 @@ void Interface::update(const Point& mousePoint, int updateFlag) { _vm->_actor->abortSpeech(); if (_vm->_scene->isInIntro() || _fadeMode == kFadeOut || !_active) { - return; + // When opening the psychic profile, or the options screen in the non-interactive part of the IHNM demo, + // the interface is locked (_active is false) + // Don't return in those cases, so that mouse actions can be processed + if (!(_vm->getGameType() == GType_IHNM && _panelMode == kPanelPlacard && (updateFlag & UPDATE_MOUSECLICK)) && + !(_vm->getGameId() == GID_IHNM_DEMO && (_panelMode == kPanelOption || _panelMode == kPanelQuit))) + return; } if (_statusTextInput) { @@ -1682,6 +1771,27 @@ void Interface::update(const Point& mousePoint, int updateFlag) { // No mouse interaction break; + case kPanelPlacard: + if (_vm->getGameType() == GType_IHNM) { + // Any mouse click here returns the user back to the game + if (updateFlag & UPDATE_MOUSECLICK) { + if (_vm->getGameId() != GID_IHNM_DEMO) { + _vm->_scene->clearPsychicProfile(); + } else { + setMode(kPanelConverse); + _vm->_scene->_textList.clear(); + _vm->_script->wakeUpThreads(kWaitTypeDelay); + } + } + } + break; + + case kPanelNull: + if (_vm->getGameId() == GID_IHNM_DEMO && (updateFlag & UPDATE_MOUSECLICK)) { + if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) + _vm->_scene->showIHNMDemoSpecialScreen(); + } + break; } _lastMousePoint = mousePoint; @@ -2016,10 +2126,10 @@ void Interface::drawButtonBox(Surface *ds, const Rect& rect, ButtonKind kind, bo ((byte *)ds->getBasePtr(x, ye))[0] = cornerColor; ((byte *)ds->getBasePtr(xe, y))[0] = cornerColor; ((byte *)ds->getBasePtr(xe, ye))[0] = cornerColor; - ds->hLine(x + 1, y, x + 1 + w - 2, frameColor); - ds->hLine(x + 1, ye, x + 1 + w - 2, frameColor); - ds->vLine(x, y + 1, y + 1 + h - 2, frameColor); - ds->vLine(xe, y + 1, y + 1 + h - 2, frameColor); + ds->hLine(x + 1, y, x + w - 2, frameColor); + ds->hLine(x + 1, ye, x + w - 2, frameColor); + ds->vLine(x, y + 1, y + h - 2, frameColor); + ds->vLine(xe, y + 1, y + h - 2, frameColor); x++; y++; @@ -2029,7 +2139,7 @@ void Interface::drawButtonBox(Surface *ds, const Rect& rect, ButtonKind kind, bo h -= 2; ds->vLine(x, y, y + h - 1, odl); ds->hLine(x, ye, x + w - 1, odl); - ds->vLine(xe, y, y + h - 1, our); + ds->vLine(xe, y, y + h - 2, our); ds->hLine(x + 1, y, x + 1 + w - 2, our); x++; @@ -2042,7 +2152,7 @@ void Interface::drawButtonBox(Surface *ds, const Rect& rect, ButtonKind kind, bo ((byte *)ds->getBasePtr(xe, ye))[0] = fillColor; ds->vLine(x, y + 1, y + 1 + h - 2, idl); ds->hLine(x + 1, ye, x + 1 + w - 2, idl); - ds->vLine(xe, y, y + h - 1, iur); + ds->vLine(xe, y, y + h - 2, iur); ds->hLine(x + 1, y, x + 1 + w - 2, iur); x++; y++; diff --git a/engines/saga/isomap.cpp b/engines/saga/isomap.cpp index 124242204b..4f635c6e3b 100644 --- a/engines/saga/isomap.cpp +++ b/engines/saga/isomap.cpp @@ -24,6 +24,7 @@ */ // Isometric level module + #include "saga/saga.h" #include "saga/gfx.h" @@ -1609,6 +1610,7 @@ void IsoMap::findTilePath(ActorData* actor, const Location &start, const Locatio /* if (i > 64) { i = 64; }*/ + actor->_walkStepsCount = i; if (i) { actor->setTileDirectionsSize(i, false); diff --git a/engines/saga/ite_introproc.cpp b/engines/saga/ite_introproc.cpp index ec4d07c069..1664969644 100644 --- a/engines/saga/ite_introproc.cpp +++ b/engines/saga/ite_introproc.cpp @@ -23,7 +23,6 @@ * */ - // Intro sequence scene procedures #include "saga/saga.h" diff --git a/engines/saga/list.h b/engines/saga/list.h index 28159475c3..1363155f43 100644 --- a/engines/saga/list.h +++ b/engines/saga/list.h @@ -23,6 +23,8 @@ * */ +// List functions + #ifndef SAGA_LIST_H #define SAGA_LIST_H diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 71b6964530..04e79c174d 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -22,6 +22,9 @@ * $Id$ * */ + +// MIDI and digital music class + #include "saga/saga.h" #include "saga/rscfile.h" @@ -38,14 +41,12 @@ namespace Saga { #define BUFFER_SIZE 4096 -// I haven't decided yet if it's a good idea to make looping part of the audio -// stream class, or if I should use a "wrapper" class, like I did for Broken -// Sword 2, to make it easier to add support for compressed music... but I'll -// worry about that later. - -class RAWInputStream : public Audio::AudioStream { +class DigitalMusicInputStream : public Audio::AudioStream { private: + Audio::AudioStream *_compressedStream; ResourceContext *_context; + ResourceData * resourceData; + GameSoundTypes soundType; Common::File *_file; uint32 _filePos; uint32 _startPos; @@ -56,6 +57,7 @@ private: const int16 *_bufferEnd; const int16 *_pos; const GameSoundInfo *_musicInfo; + Common::MemoryReadStream *_memoryStream; void refill(); bool eosIntern() const { @@ -63,7 +65,10 @@ private: } public: - RAWInputStream(SagaEngine *vm, ResourceContext *context, uint32 resourceId, bool looping, uint32 loopStart); + DigitalMusicInputStream(SagaEngine *vm, ResourceContext *context, uint32 resourceId, bool looping, uint32 loopStart); + ~DigitalMusicInputStream(); + + void createCompressedStream(); int readBuffer(int16 *buffer, const int numSamples); @@ -72,17 +77,36 @@ public: int getRate() const { return _musicInfo->frequency; } }; -RAWInputStream::RAWInputStream(SagaEngine *vm, ResourceContext *context, uint32 resourceId, bool looping, uint32 loopStart) +DigitalMusicInputStream::DigitalMusicInputStream(SagaEngine *vm, ResourceContext *context, uint32 resourceId, bool looping, uint32 loopStart) : _context(context), _finished(false), _looping(looping), _bufferEnd(_buf + BUFFER_SIZE) { - ResourceData * resourceData; + byte compressedHeader[10]; resourceData = vm->_resource->getResourceData(context, resourceId); _file = context->getFile(resourceData); _musicInfo = vm->getMusicInfo(); if (_musicInfo == NULL) { - error("RAWInputStream() wrong musicInfo"); + error("DigitalMusicInputStream() wrong musicInfo"); + } + + _compressedStream = NULL; + + if (Common::File::exists("music.cmp")) { + // Read compressed header to determine compression type + _file->seek((long)resourceData->offset, SEEK_SET); + _file->read(compressedHeader, 9); + + if (compressedHeader[0] == char(0)) { + soundType = kSoundMP3; + } else if (compressedHeader[0] == char(1)) { + soundType = kSoundOGG; + } else if (compressedHeader[0] == char(2)) { + soundType = kSoundFLAC; + } + + createCompressedStream(); + resourceData->offset += 9; // Skip compressed header } // Determine the end position @@ -96,22 +120,59 @@ RAWInputStream::RAWInputStream(SagaEngine *vm, ResourceContext *context, uint32 refill(); } -int RAWInputStream::readBuffer(int16 *buffer, const int numSamples) { +DigitalMusicInputStream::~DigitalMusicInputStream() { + delete _compressedStream; +} + +void DigitalMusicInputStream::createCompressedStream() { + uint numLoops = _looping ? 0 : 1; + _memoryStream = _file->readStream(resourceData->size); + + switch (soundType) { +#ifdef USE_MAD + case kSoundMP3: + debug(1, "Playing MP3 compressed digital music"); + _compressedStream = Audio::makeMP3Stream(_memoryStream, true, 0, 0, numLoops); + break; +#endif +#ifdef USE_VORBIS + case kSoundOGG: + debug(1, "Playing OGG compressed digital music"); + _compressedStream = Audio::makeVorbisStream(_memoryStream, true, 0, 0, numLoops); + break; +#endif +#ifdef USE_FLAC + case kSoundFLAC: + debug(1, "Playing FLAC compressed digital music"); + _compressedStream = Audio::makeFlacStream(_memoryStream, true, 0, 0, numLoops); + break; +#endif + default: + // Unknown compression + error("Trying to play a compressed digital music, but the compression is not known"); + break; + } +} + +int DigitalMusicInputStream::readBuffer(int16 *buffer, const int numSamples) { + if (_compressedStream != NULL) + return _compressedStream->readBuffer(buffer, numSamples); + int samples = 0; while (samples < numSamples && !eosIntern()) { - const int len = MIN(numSamples - samples, (int) (_bufferEnd - _pos)); + int len = 0; + len = MIN(numSamples - samples, (int) (_bufferEnd - _pos)); memcpy(buffer, _pos, len * 2); buffer += len; _pos += len; samples += len; - if (_pos >= _bufferEnd) { + if (_pos >= _bufferEnd) refill(); - } } return samples; } -void RAWInputStream::refill() { +void DigitalMusicInputStream::refill() { if (_finished) return; @@ -282,7 +343,7 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enable xmidiParser = MidiParser::createParser_XMIDI(); smfParser = MidiParser::createParser_SMF(); - _musicContext = _vm->_resource->getContext(GAME_MUSICFILE); + _digitalMusicContext = _vm->_resource->getContext(GAME_MUSICFILE); _songTableLen = 0; _songTable = 0; @@ -373,6 +434,10 @@ void Music::play(uint32 resourceId, MusicFlags flags) { _player->stopMusic(); _mixer->stopHandle(_musicHandle); + if (!_vm->_musicVolume) { + return; + } + int realTrackNumber; if (_vm->getGameType() == GType_ITE) { @@ -405,7 +470,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) { if (_vm->getGameType() == GType_ITE) { if (resourceId >= 9 && resourceId <= 34) { - if (_musicContext != NULL) { + if (_digitalMusicContext != NULL) { //TODO: check resource size loopStart = 0; // fix ITE sunstatm score @@ -413,61 +478,8 @@ void Music::play(uint32 resourceId, MusicFlags flags) { loopStart = 4 * 18727; } - if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) { - // uncompressed digital music - audioStream = new RAWInputStream(_vm, _musicContext, resourceId - 9, flags == MUSIC_LOOP, loopStart); - } else { - // compressed digital music - ResourceData * musicResourceData; - Common::File *_file; - byte compressedHeader[10]; - GameSoundTypes soundType; - - musicResourceData = _vm->_resource->getResourceData(_musicContext, resourceId - 9); - _file = _musicContext->getFile(musicResourceData); - - if (_vm->getMusicInfo() == NULL) { - error("RAWInputStream() wrong musicInfo"); - } - - _file->seek((long)musicResourceData->offset, SEEK_SET); - - _file->read(compressedHeader, 9); - - if (compressedHeader[0] == char(0)) { - soundType = kSoundMP3; - } else if (compressedHeader[0] == char(1)) { - soundType = kSoundOGG; - } else if (compressedHeader[0] == char(2)) { - soundType = kSoundFLAC; - } - - switch (soundType) { -#ifdef USE_MAD - case kSoundMP3: - debug(1, "Playing MP3 compressed digital music"); - audioStream = Audio::makeMP3Stream(_file, musicResourceData->size); - break; -#endif -#ifdef USE_VORBIS - case kSoundOGG: - debug(1, "Playing OGG compressed digital music"); - audioStream = Audio::makeVorbisStream(_file, musicResourceData->size); - break; -#endif -#ifdef USE_FLAC - case kSoundFLAC: - debug(1, "Playing FLAC compressed digital music"); - audioStream = Audio::makeFlacStream(_file, musicResourceData->size); - break; -#endif - default: - // Unknown compression - error("Trying to play a compressed digital music, but the compression is not known"); - break; - } - - } + // digital music + audioStream = new DigitalMusicInputStream(_vm, _digitalMusicContext, resourceId - 9, flags == MUSIC_LOOP, loopStart); } } } @@ -512,8 +524,10 @@ void Music::play(uint32 resourceId, MusicFlags flags) { // Oddly enough, the intro music (song 1) is very // different in the two files. I have no idea why. + // Note that the IHNM demo has only got one music file + // (music.rsc). It is assumed that it contains FM music - if (hasAdlib()) { + if (hasAdlib() || _vm->getGameId() == GID_IHNM_DEMO) { context = _vm->_resource->getContext(GAME_MUSICFILE_FM); } else { context = _vm->_resource->getContext(GAME_MUSICFILE_GM); diff --git a/engines/saga/music.h b/engines/saga/music.h index 96d8608bcd..b038a25a11 100644 --- a/engines/saga/music.h +++ b/engines/saga/music.h @@ -137,7 +137,7 @@ private: int _currentVolume; int _currentVolumePercent; - ResourceContext *_musicContext; + ResourceContext *_digitalMusicContext; MidiParser *xmidiParser; MidiParser *smfParser; diff --git a/engines/saga/objectmap.cpp b/engines/saga/objectmap.cpp index 52f2e89be7..9e633a6709 100644 --- a/engines/saga/objectmap.cpp +++ b/engines/saga/objectmap.cpp @@ -28,6 +28,7 @@ // Polygon Hit Test code ( HitTestPoly() ) adapted from code (C) Eric Haines // appearing in Graphics Gems IV, "Point in Polygon Strategies." // p. 24-46, code: p. 34-45 + #include "saga/saga.h" #include "saga/gfx.h" diff --git a/engines/saga/puzzle.h b/engines/saga/puzzle.h index 92bf73e2a0..3713cbaab7 100644 --- a/engines/saga/puzzle.h +++ b/engines/saga/puzzle.h @@ -23,6 +23,8 @@ * */ +// ITE puzzle scene + #ifndef SAGA_PUZZLE_H #define SAGA_PUZZLE_H diff --git a/engines/saga/render.cpp b/engines/saga/render.cpp index 16536f762e..930476b4e2 100644 --- a/engines/saga/render.cpp +++ b/engines/saga/render.cpp @@ -24,6 +24,7 @@ */ // Main rendering loop + #include "saga/saga.h" #include "saga/actor.h" diff --git a/engines/saga/rscfile.cpp b/engines/saga/rscfile.cpp index 33e8a7d603..4d3ff1e47c 100644 --- a/engines/saga/rscfile.cpp +++ b/engines/saga/rscfile.cpp @@ -24,6 +24,7 @@ */ // RSC Resource file management module + #include "saga/saga.h" #include "saga/actor.h" @@ -329,6 +330,7 @@ bool Resource::loadContext(ResourceContext *context) { if (resourceData->patchData->_patchFile->open(patchDescription->fileName)) { resourceData->offset = 0; resourceData->size = resourceData->patchData->_patchFile->size(); + resourceData->patchData->_patchFile->close(); } else { delete resourceData->patchData; resourceData->patchData = NULL; @@ -343,18 +345,188 @@ bool Resource::loadContext(ResourceContext *context) { bool Resource::createContexts() { int i; ResourceContext *context; + char musicFileName[256]; + char soundFileName[256]; + char voicesFileName[256]; + int soundFileIndex = 0; + int voicesFileIndex = 0; + bool digitalMusic = false; + bool soundFileInArray = false; + bool voicesFileInArray = false; + bool multipleVoices = false; + bool censoredVersion = false; + uint16 voiceFileType = GAME_VOICEFILE; _contextsCount = 0; - for (i = 0; _vm->getFilesDescriptions()[i].fileName; i++) + for (i = 0; _vm->getFilesDescriptions()[i].fileName; i++) { _contextsCount++; + if (_vm->getFilesDescriptions()[i].fileType == GAME_SOUNDFILE) + soundFileInArray = true; + if (_vm->getFilesDescriptions()[i].fileType == GAME_VOICEFILE) + voicesFileInArray = true; + } + + if (!soundFileInArray) { + if (_vm->getGameType() == GType_ITE) { + // If the sound file is not specified in the detector table, add it here + if (Common::File::exists("sounds.rsc") || Common::File::exists("sounds.cmp")) { + _contextsCount++; + soundFileIndex = _contextsCount - 1; + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(soundFileName, "sounds.cmp"); + else + sprintf(soundFileName, "sounds.rsc"); + } else if (Common::File::exists("soundsd.rsc") || Common::File::exists("soundsd.cmp")) { + _contextsCount++; + soundFileIndex = _contextsCount - 1; + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(soundFileName, "soundsd.cmp"); + else + sprintf(soundFileName, "soundsd.rsc"); + } else { + // No sound file found, don't add any file to the array + soundFileInArray = true; + // ITE floppy versions have both voices and sounds in voices.rsc + voiceFileType = GAME_SOUNDFILE | GAME_VOICEFILE; + } + } else { + // If the sound file is not specified in the detector table, add it here + if (Common::File::exists("sfx.res") || Common::File::exists("sfx.cmp")) { + _contextsCount++; + soundFileIndex = _contextsCount - 1; + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(soundFileName, "sfx.cmp"); + else + sprintf(soundFileName, "sfx.res"); + } else { + // No sound file found, don't add any file to the array + soundFileInArray = true; + } + } + } + + if (!voicesFileInArray) { + if (_vm->getGameType() == GType_ITE) { + // If the voices file is not specified in the detector table, add it here + if (Common::File::exists("voices.rsc") || Common::File::exists("voices.cmp")) { + _contextsCount++; + voicesFileIndex = _contextsCount - 1; + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(voicesFileName, "voices.cmp"); + else + sprintf(voicesFileName, "voices.rsc"); + } else if (Common::File::exists("voicesd.rsc") || Common::File::exists("voicesd.cmp")) { + _contextsCount++; + voicesFileIndex = _contextsCount - 1; + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(voicesFileName, "voicesd.cmp"); + else + sprintf(voicesFileName, "voicesd.rsc"); + } else if (Common::File::exists("inherit the earth voices") || + Common::File::exists("inherit the earth voices.cmp")) { + _contextsCount++; + voicesFileIndex = _contextsCount - 1; + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(voicesFileName, "inherit the earth voices.cmp"); + else + sprintf(voicesFileName, "inherit the earth voices"); + // The resources in the Wyrmkeep combined Windows/Mac/Linux CD version are little endian, but + // the voice file is big endian. If we got such a version with mixed files, mark this voice file + // as big endian + if (!_vm->isBigEndian()) + voiceFileType = GAME_VOICEFILE | GAME_SWAPENDIAN; // This file is big endian + } else { + // No voice file found, don't add any file to the array + voicesFileInArray = true; + } + } else { + // If the voices file is not specified in the detector table, add it here + if (Common::File::exists("voicess.res") || Common::File::exists("voicess.cmp")) { + _contextsCount++; + voicesFileIndex = _contextsCount - 1; + // IHNM has multiple voice files + multipleVoices = true; + // Note: it is assumed that the voices are always last in the list + if (Common::File::exists("voices4.res") || Common::File::exists("voices4.cmp")) { + _contextsCount += 6; // voices1-voices6 + } else { + // The German and French versions of IHNM don't have Nimdok's chapter, therefore the voices file + // for that chapter is missing + _contextsCount += 5; // voices1-voices3, voices4-voices5 + censoredVersion = true; + } + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(voicesFileName, "voicess.cmp"); + else + sprintf(voicesFileName, "voicess.res"); + } else if (Common::File::exists("voicesd.res") || Common::File::exists("voicesd.cmp")) { + _contextsCount++; + voicesFileIndex = _contextsCount - 1; + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(voicesFileName, "voicesd.cmp"); + else + sprintf(voicesFileName, "voicesd.res"); + } else { + // No voice file found, don't add any file to the array + voicesFileInArray = true; + } + } + } + + if (_vm->getGameType() == GType_ITE) { + // Check for digital music in ITE + if (Common::File::exists("music.rsc") || Common::File::exists("music.cmp")) { + _contextsCount++; + digitalMusic = true; + if (Common::File::exists("music.cmp")) + sprintf(musicFileName, "music.cmp"); + else + sprintf(musicFileName, "music.rsc"); + } else if (Common::File::exists("musicd.rsc") || Common::File::exists("musicd.cmp")) { + _contextsCount++; + digitalMusic = true; + if (Common::File::exists("musicd.cmp")) + sprintf(musicFileName, "musicd.cmp"); + else + sprintf(musicFileName, "musicd.rsc"); + } else { + digitalMusic = false; + } + } _contexts = (ResourceContext*)calloc(_contextsCount, sizeof(*_contexts)); for (i = 0; i < _contextsCount; i++) { context = &_contexts[i]; context->file = new Common::File(); - context->fileName = _vm->getFilesDescriptions()[i].fileName; - context->fileType = _vm->getFilesDescriptions()[i].fileType; + + // For ITE, add the digital music file and sfx file information here + if (_vm->getGameType() == GType_ITE && digitalMusic && i == _contextsCount - 1) { + context->fileName = musicFileName; + context->fileType = GAME_MUSICFILE; + } else if (!soundFileInArray && i == soundFileIndex) { + context->fileName = soundFileName; + context->fileType = GAME_SOUNDFILE; + } else if (!voicesFileInArray && i == voicesFileIndex) { + context->fileName = voicesFileName; + // can be GAME_VOICEFILE or GAME_SOUNDFILE | GAME_VOICEFILE or GAME_VOICEFILE | GAME_SWAPENDIAN + context->fileType = voiceFileType; + } else { + if (!(!voicesFileInArray && multipleVoices && (i > voicesFileIndex))) { + context->fileName = _vm->getFilesDescriptions()[i].fileName; + context->fileType = _vm->getFilesDescriptions()[i].fileType; + } else { + int token = (censoredVersion && (i - voicesFileIndex >= 4)) ? 1 : 0; // censored versions don't have voice4 + + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) + sprintf(voicesFileName, "voices%i.cmp", i - voicesFileIndex + token); + else + sprintf(voicesFileName, "voices%i.res", i - voicesFileIndex + token); + + context->fileName = voicesFileName; + context->fileType = GAME_VOICEFILE; + } + } context->serial = 0; // IHNM has serveral different voice files, so we need to allow @@ -434,13 +606,20 @@ void Resource::loadResource(ResourceContext *context, uint32 resourceId, byte*&r if (file->read(resourceBuffer, resourceSize) != resourceSize) { error("Resource::loadResource() failed to read"); } + if (resourceData->patchData != NULL) + file->close(); } static int metaResourceTable[] = { 0, 326, 517, 677, 805, 968, 1165, 0, 1271 }; +static int metaResourceTableDemo[] = { 0, 0, 0, 0, 0, 0, 0, 285, 0 }; void Resource::loadGlobalResources(int chapter, int actorsEntrance) { - if (chapter < 0) - chapter = 8; + if (chapter < 0) { + if (_vm->getGameId() != GID_IHNM_DEMO) + chapter = 8; + else + chapter = 7; + } // TODO //if (module.voiceLUT) @@ -465,8 +644,13 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { byte *resourcePointer; size_t resourceLength; - _vm->_resource->loadResource(resourceContext, metaResourceTable[chapter], - resourcePointer, resourceLength); + if (_vm->getGameId() != GID_IHNM_DEMO) { + _vm->_resource->loadResource(resourceContext, metaResourceTable[chapter], + resourcePointer, resourceLength); + } else { + _vm->_resource->loadResource(resourceContext, metaResourceTableDemo[chapter], + resourcePointer, resourceLength); + } if (resourceLength == 0) { error("Resource::loadGlobalResources wrong metaResource"); @@ -555,22 +739,27 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { _vm->_anim->loadCutawayList(resourcePointer, resourceLength); - _vm->_resource->loadResource(resourceContext, _metaResource.songTableID, resourcePointer, resourceLength); + if (_metaResource.songTableID > 0) { + _vm->_resource->loadResource(resourceContext, _metaResource.songTableID, resourcePointer, resourceLength); - if (resourceLength == 0) { - error("Resource::loadGlobalResources Can't load songs list for current track"); - } + if (resourceLength == 0) { + error("Resource::loadGlobalResources Can't load songs list for current track"); + } - free(_vm->_music->_songTable); - - _vm->_music->_songTableLen = resourceLength / 4; - _vm->_music->_songTable = (int32 *)malloc(sizeof(int32) * _vm->_music->_songTableLen); + free(_vm->_music->_songTable); + + _vm->_music->_songTableLen = resourceLength / 4; + _vm->_music->_songTable = (int32 *)malloc(sizeof(int32) * _vm->_music->_songTableLen); - MemoryReadStream songS(resourcePointer, resourceLength); + MemoryReadStream songS(resourcePointer, resourceLength); - for (i = 0; i < _vm->_music->_songTableLen; i++) - _vm->_music->_songTable[i] = songS.readSint32LE(); - free(resourcePointer); + for (i = 0; i < _vm->_music->_songTableLen; i++) + _vm->_music->_songTable[i] = songS.readSint32LE(); + free(resourcePointer); + } else { + // The IHNM demo has a fixed music track and doesn't load a song table + _vm->_music->play(3, MUSIC_LOOP); + } int voiceLUTResourceID = 0; @@ -602,6 +791,9 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { voiceLUTResourceID = 28; break; case 7: + // IHNM demo + _vm->_sndRes->setVoiceBank(0); + voiceLUTResourceID = 17; break; case 8: _vm->_sndRes->setVoiceBank(0); diff --git a/engines/saga/rscfile.h b/engines/saga/rscfile.h index f8b6ddc3be..2df3b2eb7c 100644 --- a/engines/saga/rscfile.h +++ b/engines/saga/rscfile.h @@ -83,6 +83,8 @@ struct ResourceContext { Common::File *getFile(ResourceData *resourceData) const { if (resourceData->patchData != NULL) { + if (!resourceData->patchData->_patchFile->isOpen()) + resourceData->patchData->_patchFile->open(resourceData->patchData->_patchDescription->fileName); return resourceData->patchData->_patchFile; } else { return file; diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 99462c5583..76731c201a 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -107,7 +107,6 @@ SagaEngine::SagaEngine(OSystem *syst) // Mac CD Wyrmkeep Common::File::addDefaultDirectory(_gameDataPath + "patch/"); - // Setup mixer if (!_mixer->isReady()) { warning("Sound initialization failed."); @@ -150,6 +149,8 @@ int SagaEngine::init() { _subtitlesEnabled = ConfMan.getBool("subtitles"); _readingSpeed = getTalkspeed(); _copyProtection = ConfMan.getBool("copy_protection"); + _gf_wyrmkeep = false; + _gf_compressed_sounds = false; if (_readingSpeed > 3) _readingSpeed = 0; @@ -454,6 +455,9 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) { colorId = kITEColorTransBlack; break; + case (kKnownColorBrightWhite): + colorId = kITEColorBrightWhite; + break; case (kKnownColorBlack): colorId = kIHNMColorBlack; break; diff --git a/engines/saga/saga.h b/engines/saga/saga.h index 844a738418..43952fe564 100644 --- a/engines/saga/saga.h +++ b/engines/saga/saga.h @@ -301,6 +301,7 @@ struct GameResourceDescription { uint32 mainPanelSpritesResourceId; uint32 optionPanelSpritesResourceId; uint32 defaultPortraitsResourceId; + uint32 psychicProfileResourceId; uint32 mainStringsResourceId; uint32 actorsStringsResourceId; }; @@ -527,6 +528,8 @@ public: int _readingSpeed; bool _copyProtection; + bool _gf_wyrmkeep; + bool _gf_compressed_sounds; SndRes *_sndRes; Sound *_sound; @@ -548,7 +551,7 @@ public: Resource *_resource; - /** Random number generator */ + // Random number generator Common::RandomSource _rnd; private: diff --git a/engines/saga/sagaresnames.h b/engines/saga/sagaresnames.h index 94f97635c1..761ac1ab68 100644 --- a/engines/saga/sagaresnames.h +++ b/engines/saga/sagaresnames.h @@ -45,8 +45,9 @@ namespace Saga { #define RID_IHNMDEMO_SCENE_LUT 286 #define RID_IHNMDEMO_SCRIPT_LUT 18 +#define RID_IHNMDEMO_SFX_LUT 222 -//obj names +// Object names #define ITE_OBJ_MAP 14 #define ITE_OBJ_MAGIC_HAT 0 @@ -54,10 +55,10 @@ namespace Saga { #define RID_IHNM_DEFAULT_PALETTE 1 -//actor names +// Actor names #define ITE_ACTOR_PUZZLE 176 -// SCENES +// Scenes #define ITE_SCENE_INV -1 #define ITE_SCENE_PUZZLE 26 #define ITE_SCENE_LODGE 21 @@ -67,13 +68,14 @@ namespace Saga { #define IHNM_DEFAULT_SCENE 151 #define ITEDEMO_DEFAULT_SCENE 68 +#define IHNMDEMO_DEFAULT_SCENE 144 -// FONTS +// Fonts #define RID_MEDIUM_FONT 0 #define RID_BIG_FONT 1 #define RID_SMALL_FONT 2 -// INTERFACE IMAGES +// Interface images #define RID_ITE_MAIN_PANEL 3 #define RID_ITE_CONVERSE_PANEL 4 #define RID_ITE_OPTION_PANEL 5 @@ -99,7 +101,7 @@ namespace Saga { #define RID_IHNM_MAIN_PANEL 9 #define RID_IHNM_CONVERSE_PANEL 10 #define RID_IHNM_HOURGLASS_CURSOR 11 -#define RID_IHNM_MAIN_SPRITES 12 // TODO: verify this +#define RID_IHNM_MAIN_SPRITES 12 #define RID_IHNM_MAIN_PANEL_SPRITES 12 #define RID_IHNM_ARROW_SPRITES 13 #define RID_IHNM_SAVEREMINDER_SPRITES 14 @@ -110,6 +112,20 @@ namespace Saga { #define RID_IHNM_PROFILE_BG 20 #define RID_IHNM_MAIN_STRINGS 21 +#define RID_IHNMDEMO_MAIN_PANEL 5 +#define RID_IHNMDEMO_CONVERSE_PANEL 6 +#define RID_IHNMDEMO_HOURGLASS_CURSOR 6 // Does not exist in the demo +#define RID_IHNMDEMO_MAIN_SPRITES 7 +#define RID_IHNMDEMO_MAIN_PANEL_SPRITES 7 +#define RID_IHNMDEMO_ARROW_SPRITES 8 +#define RID_IHNMDEMO_SAVEREMINDER_SPRITES 9 +#define RID_IHNMDEMO_OPTION_PANEL 10 +#define RID_IHNMDEMO_OPTION_PANEL_SPRITES 11 +#define RID_IHNMDEMO_WARNING_PANEL 12 +#define RID_IHNMDEMO_BOSS_SCREEN 13 // Does not exist in the demo +#define RID_IHNMDEMO_PROFILE_BG 15 +#define RID_IHNMDEMO_MAIN_STRINGS 16 + // Puzzle portraits #define RID_ITE_SAKKA_APPRAISING 6 #define RID_ITE_SAKKA_DENIAL 7 @@ -151,7 +167,7 @@ namespace Saga { #define RID_ITE_INTRO_IMG_3 1561 #define RID_ITE_INTRO_IMG_4 1565 -// ITE_VOICES +// ITE voices #define RID_CAVE_VOICE_0 0 #define RID_CAVE_VOICE_1 1 #define RID_CAVE_VOICE_2 2 @@ -177,7 +193,7 @@ namespace Saga { #define RID_BOAR_VOICE_006 245 #define RID_BOAR_VOICE_007 246 -// MUSIC +// Music #define MUSIC_1 9 #define MUSIC_2 10 #define MUSIC_SUNSPOT 26 @@ -185,7 +201,7 @@ namespace Saga { // TODO: If the sound effects are numbered sequentially, we don't really need // these constants. But for now they might be useful for debugging. -// SOUND EFFECTS +// Sound effects #define FX_DOOR_OPEN 14 #define FX_DOOR_CLOSE 15 diff --git a/engines/saga/saveload.cpp b/engines/saga/saveload.cpp index bb3164a79c..77d7816963 100644 --- a/engines/saga/saveload.cpp +++ b/engines/saga/saveload.cpp @@ -172,14 +172,6 @@ void SagaEngine::fillSaveList() { } i++; } -/* 4debug - for (i = 0; i < 14; i++) { - sprintf(_saveFiles[i].name,"test%i", i); - _saveFiles[i].slotNumber = i; - } - _saveFilesCount = 14; - _saveFilesMaxCount = 14; - */ } @@ -294,7 +286,10 @@ void SagaEngine::load(const char *fileName) { _scene->setCurrentMusicTrack(in->readSint32LE()); _scene->setCurrentMusicRepeat(in->readSint32LE()); _music->stop(); - _music->play(_music->_songTable[_scene->getCurrentMusicTrack()], _scene->getCurrentMusicRepeat() ? MUSIC_LOOP : MUSIC_NORMAL); + if (getGameId() != GID_IHNM_DEMO) + _music->play(_music->_songTable[_scene->getCurrentMusicTrack()], _scene->getCurrentMusicRepeat() ? MUSIC_LOOP : MUSIC_NORMAL); + else + _music->play(3, MUSIC_LOOP); } // Inset scene diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index 362b212b14..c49fe546ee 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -570,8 +570,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { _chapterPointsChanged = false; - _vm->_actor->showActors(false); - if ((_vm->getGameType() == GType_IHNM) && (loadSceneParams->chapter != NO_CHAPTER_CHANGE)) { if (loadSceneParams->loadFlag != kLoadBySceneNumber) { error("loadScene wrong usage"); @@ -581,7 +579,16 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { _vm->_interface->setLeftPortrait(0); _vm->_anim->freeCutawayList(); - _vm->_script->freeModules(); + // FIXME: Freed script modules are not reloaded correctly when changing chapters. + // This is apparent when returning back to the character selection screen, + // where the scene script module is loaded incorrectly + // Don't free them for now, but free them on game exit, like ITE. + // This has no impact on the game itself (other than increased memory usage), + // as each chapter uses a different module slot + // TODO: Find out why the script modules are not loaded correctly when + // changing chapters and uncomment this again + //_vm->_script->freeModules(); + // deleteAllScenes(); // installSomeAlarm() @@ -591,10 +598,14 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { _vm->_interface->addToInventory(IHNM_OBJ_PROFILE); _vm->_interface->activate(); - if (loadSceneParams->chapter == 8 || loadSceneParams->chapter == -1) - _vm->_interface->setMode(kPanelChapterSelection); - else + if (loadSceneParams->chapter == 8 || loadSceneParams->chapter == -1) { + if (_vm->getGameId() != GID_IHNM_DEMO) + _vm->_interface->setMode(kPanelChapterSelection); + else + _vm->_interface->setMode(kPanelNull); + } else { _vm->_interface->setMode(kPanelMain); + } _inGame = true; @@ -640,6 +651,15 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { debug(3, "Loading scene number %d:", _sceneNumber); + if (_vm->getGameId() == GID_IHNM_DEMO && _sceneNumber == 144) { + // WORKAROUND for the non-interactive part of the IHNM demo: When restarting the + // non-interactive demo, opcode sfMainMode is incorrectly called. Therefore, if the + // starting scene of the non-interactive demo is loaded (scene 144), set panel to null + // and lock the user interface + _vm->_interface->deactivate(); + _vm->_interface->setMode(kPanelNull); + } + // Load scene descriptor and resource list resources if (_loadDescription) { debug(3, "Loading scene resource %i", _sceneResourceId); @@ -1282,4 +1302,174 @@ void Scene::loadSceneEntryList(const byte* resourcePointer, size_t resourceLengt } } +void Scene::clearPlacard() { + static PalEntry cur_pal[PAL_ENTRIES]; + PalEntry *pal; + Event event; + Event *q_event; + + _vm->_interface->restoreMode(); + + _vm->_gfx->getCurrentPal(cur_pal); + + event.type = kEvTImmediate; + event.code = kPalEvent; + event.op = kEventPalToBlack; + event.time = 0; + event.duration = kNormalFadeDuration; + event.data = cur_pal; + + q_event = _vm->_events->queue(&event); + + event.type = kEvTOneshot; + event.code = kGraphicsEvent; + event.op = kEventClearFlag; + event.param = RF_PLACARD; + + q_event = _vm->_events->chain(q_event, &event); + + event.type = kEvTOneshot; + event.code = kTextEvent; + event.op = kEventRemove; + event.data = _vm->_script->getPlacardTextEntry(); + + q_event = _vm->_events->chain(q_event, &event); + + _vm->_scene->getBGPal(pal); + + event.type = kEvTImmediate; + event.code = kPalEvent; + event.op = kEventBlackToPal; + event.time = 0; + event.duration = kNormalFadeDuration; + event.data = pal; + + q_event = _vm->_events->chain(q_event, &event); + + event.type = kEvTOneshot; + event.code = kCursorEvent; + event.op = kEventShow; + + q_event = _vm->_events->chain(q_event, &event); + + event.type = kEvTOneshot; + event.code = kScriptEvent; + event.op = kEventThreadWake; + event.param = kWaitTypePlacard; + + q_event = _vm->_events->chain(q_event, &event); +} + +void Scene::showPsychicProfile(const char *text) { + int textHeight; + static PalEntry cur_pal[PAL_ENTRIES]; + PalEntry *pal; + TextListEntry textEntry; + Event event; + Event *q_event; + + if (_vm->_interface->getMode() == kPanelPlacard) + return; + + _vm->_interface->rememberMode(); + _vm->_interface->setMode(kPanelPlacard); + _vm->_gfx->savePalette(); + + event.type = kEvTOneshot; + event.code = kCursorEvent; + event.op = kEventHide; + + q_event = _vm->_events->queue(&event); + + _vm->_gfx->getCurrentPal(cur_pal); + + event.type = kEvTImmediate; + event.code = kPalEvent; + event.op = kEventPalToBlack; + event.time = 0; + event.duration = kNormalFadeDuration; + event.data = cur_pal; + + q_event = _vm->_events->chain(q_event, &event); + + event.type = kEvTOneshot; + event.code = kInterfaceEvent; + event.op = kEventClearStatus; + + q_event = _vm->_events->chain(q_event, &event); + + event.type = kEvTOneshot; + event.code = kGraphicsEvent; + event.op = kEventSetFlag; + event.param = RF_PLACARD; + + q_event = _vm->_events->chain(q_event, &event); + + // Set the background and palette for the psychic profile + event.type = kEvTOneshot; + event.code = kPsychicProfileBgEvent; + + q_event = _vm->_events->chain(q_event, &event); + + _vm->_scene->_textList.clear(); + + if (text != NULL) { + textHeight = _vm->_font->getHeight(kKnownFontVerb, text, 226, kFontCentered); + + textEntry.knownColor = kKnownColorBlack; + textEntry.useRect = true; + textEntry.rect.left = 245; + textEntry.rect.setHeight(210 + 76); + textEntry.rect.setWidth(226); + textEntry.rect.top = 210 - textHeight; + textEntry.font = kKnownFontVerb; + textEntry.flags = (FontEffectFlags)(kFontCentered); + textEntry.text = text; + + TextListEntry *_psychicProfileTextEntry = _vm->_scene->_textList.addEntry(textEntry); + + event.type = kEvTOneshot; + event.code = kTextEvent; + event.op = kEventDisplay; + event.data = _psychicProfileTextEntry; + + q_event = _vm->_events->chain(q_event, &event); + } + + _vm->_scene->getBGPal(pal); + + event.type = kEvTImmediate; + event.code = kPalEvent; + event.op = kEventBlackToPal; + event.time = 0; + event.duration = kNormalFadeDuration; + event.data = pal; + + q_event = _vm->_events->chain(q_event, &event); + + event.type = kEvTOneshot; + event.code = kScriptEvent; + event.op = kEventThreadWake; + event.param = kWaitTypePlacard; + + q_event = _vm->_events->chain(q_event, &event); +} + +void Scene::clearPsychicProfile() { + if (_vm->_interface->getMode() == kPanelPlacard || _vm->getGameId() == GID_IHNM_DEMO) { + _vm->_scene->clearPlacard(); + _vm->_scene->_textList.clear(); + _vm->_actor->showActors(false); + _vm->_gfx->restorePalette(); + _vm->_scene->restoreScene(); + _vm->_interface->activate(); + } +} + +void Scene::showIHNMDemoSpecialScreen() { + _vm->_gfx->showCursor(true); + _vm->_interface->clearInventory(); + _vm->_scene->changeScene(150, 0, kTransitionFade); +} + } // End of namespace Saga diff --git a/engines/saga/scene.h b/engines/saga/scene.h index 5fa4569949..da97bddff5 100644 --- a/engines/saga/scene.h +++ b/engines/saga/scene.h @@ -340,6 +340,11 @@ class Scene { return _vm->getDisplayInfo().sceneHeight; } + void clearPlacard(); + void showPsychicProfile(const char *text); + void clearPsychicProfile(); + void showIHNMDemoSpecialScreen(); + private: void loadScene(LoadSceneParams *loadSceneParams); void loadSceneDescriptor(uint32 resourceId); @@ -392,13 +397,11 @@ class Scene { static int SC_IHNMIntroMovieProc1(int param, void *refCon); static int SC_IHNMIntroMovieProc2(int param, void *refCon); static int SC_IHNMIntroMovieProc3(int param, void *refCon); - static int SC_IHNMHateProc(int param, void *refCon); private: int IHNMIntroMovieProc1(int param); int IHNMIntroMovieProc2(int param); int IHNMIntroMovieProc3(int param); - int IHNMHateProc(int param); public: static int SC_ITEIntroAnimProc(int param, void *refCon); diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp index 262d63c51f..82fcb352c0 100644 --- a/engines/saga/script.cpp +++ b/engines/saga/script.cpp @@ -750,6 +750,10 @@ void Script::whichObject(const Point& mousePoint) { _leftButtonVerb = _currentVerb; newRightButtonVerb = getVerbType(kVerbNone); + // _protagonist can be null while loading a game from the command line + if (_vm->_actor->_protagonist == NULL) + return; + if (_vm->_actor->_protagonist->_currentAction != kActionWalkDir) { if (_vm->_scene->getHeight() >= mousePoint.y) { newObjectId = _vm->_actor->hitTest(mousePoint, true); diff --git a/engines/saga/script.h b/engines/saga/script.h index 5adfb6181a..5e5e702132 100644 --- a/engines/saga/script.h +++ b/engines/saga/script.h @@ -380,6 +380,7 @@ public: setPointerVerb(); } int getVerbType(VerbTypes verbType); + TextListEntry *getPlacardTextEntry() { return _placardTextEntry; } private: // When reading or writing data to the common buffer, we have to use a @@ -443,6 +444,7 @@ private: int _stickyVerb; int _leftButtonVerb; int _rightButtonVerb; + int _ihnmDemoCurrentY; public: uint16 _pendingObject[2]; @@ -590,11 +592,12 @@ private: void sfScriptStartVideo(SCRIPTFUNC_PARAMS); void sfScriptReturnFromVideo(SCRIPTFUNC_PARAMS); void sfScriptEndVideo(SCRIPTFUNC_PARAMS); - void sf87(SCRIPTFUNC_PARAMS); - void sf88(SCRIPTFUNC_PARAMS); - void sf89(SCRIPTFUNC_PARAMS); + void sfShowIHNMDemoHelpBg(SCRIPTFUNC_PARAMS); + void sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS); + void sfShowIHNMDemoHelpPage(SCRIPTFUNC_PARAMS); void sfGetPoints(SCRIPTFUNC_PARAMS); void sfSetGlobalFlag(SCRIPTFUNC_PARAMS); + void sf92(SCRIPTFUNC_PARAMS); void sfClearGlobalFlag(SCRIPTFUNC_PARAMS); void sfTestGlobalFlag(SCRIPTFUNC_PARAMS); void sfSetPoints(SCRIPTFUNC_PARAMS); diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index 4954188a6e..c0e44584df 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -40,6 +40,7 @@ #include "saga/render.h" #include "saga/sound.h" #include "saga/sndres.h" +#include "saga/rscfile.h" #include "saga/script.h" #include "saga/objectmap.h" @@ -224,12 +225,12 @@ static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCT OPCODE(sfScriptReturnFromVideo), OPCODE(sfScriptEndVideo), OPCODE(sfSetActorZ), - OPCODE(sf87), - OPCODE(sf88), - OPCODE(sf89), + OPCODE(sfShowIHNMDemoHelpBg), + OPCODE(sfAddIHNMDemoHelpTextLine), + OPCODE(sfShowIHNMDemoHelpPage), OPCODE(sfVstopFX), OPCODE(sfVstopLoopedFX), - OPCODE(sfNull), + OPCODE(sf92), // only used in the demo version of IHNM OPCODE(sfDemoIsInteractive), OPCODE(sfVsetTrack), OPCODE(sfGetPoints), @@ -277,7 +278,16 @@ void Script::sfTakeObject(SCRIPTFUNC_PARAMS) { obj = _vm->_actor->getObj(objectId); if (obj->_sceneNumber != ITE_SCENE_INV) { obj->_sceneNumber = ITE_SCENE_INV; - //4debug for (int j=0;j<17;j++) + + // WORKAROUND for two incorrect object sprites in the IHNM demo + // (the mirror and the icon in Ted's part). Set them correctly here + if (_vm->getGameId() == GID_IHNM_DEMO) { + if (obj->_spriteListResourceId == 4 && objectId == 16408) + obj->_spriteListResourceId = 24; + if (obj->_spriteListResourceId == 3 && objectId == 16409) + obj->_spriteListResourceId = 25; + } + _vm->_interface->addToInventory(objectId); } } @@ -562,16 +572,19 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) { } if (_vm->getGameType() == GType_IHNM) { + // WORKAROUND for the briefly appearing actors at the beginning of each chapter + // This will stop the actors being drawn in those specific scenes until the scene background has been drawn + if ((_vm->_scene->currentChapterNumber() == 1 && _vm->_scene->currentSceneNumber() == 6) || + (_vm->_scene->currentChapterNumber() == 2 && _vm->_scene->currentSceneNumber() == 31) || + (_vm->_scene->currentChapterNumber() == 3 && _vm->_scene->currentSceneNumber() == 58) || + (_vm->_scene->currentChapterNumber() == 4 && _vm->_scene->currentSceneNumber() == 68) || + (_vm->_scene->currentChapterNumber() == 5 && _vm->_scene->currentSceneNumber() == 91) || + (_vm->_scene->currentChapterNumber() == 7 && _vm->_scene->currentSceneNumber() == 145)) + _vm->_actor->showActors(false); // Stop showing actors before the background is drawn + // Since it doesn't look like the IHNM scripts remove the - // cutaway after the intro, this is probably the best place to - // to it. - Event event; - event.type = kEvTImmediate; - event.code = kCutawayEvent; - event.op = kEventClear; - event.time = 0; - event.duration = 0; - _vm->_events->queue(&event); + // cutaway after the intro, this is probably the best place to do it + _vm->_anim->clearCutaway(); } // It is possible to leave scene when converse panel is on, @@ -868,10 +881,16 @@ void Script::sfDropObject(SCRIPTFUNC_PARAMS) { _vm->_scene->currentSceneNumber() == 59 && obj->_id == 16385) obj->_sceneNumber = -1; - if (_vm->getGameType() == GType_IHNM) - obj->_spriteListResourceId = spriteId; - else + if (_vm->getGameType() == GType_IHNM) { + if (_vm->getGameId() != GID_IHNM_DEMO) { + obj->_spriteListResourceId = spriteId; + } else { + // Don't update the object's _spriteListResourceId in the IHNM demo, as this function is + // called incorrectly there (with spriteId == 0, which resets the object sprites) + } + } else { obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId; + } obj->_location.x = x; obj->_location.y = y; @@ -1296,11 +1315,6 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) { Event event; Event *q_event; - if (_vm->getGameType() == GType_IHNM) { - warning("Psychic profile is not implemented"); - return; - } - thread->wait(kWaitTypePlacard); _vm->_interface->rememberMode(); @@ -1397,72 +1411,24 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) { // Script function #49 (0x31) void Script::sfPlacardOff(SCRIPTFUNC_PARAMS) { - static PalEntry cur_pal[PAL_ENTRIES]; - PalEntry *pal; - Event event; - Event *q_event; - thread->wait(kWaitTypePlacard); - _vm->_interface->restoreMode(); - - _vm->_gfx->getCurrentPal(cur_pal); - - event.type = kEvTImmediate; - event.code = kPalEvent; - event.op = kEventPalToBlack; - event.time = 0; - event.duration = kNormalFadeDuration; - event.data = cur_pal; - - q_event = _vm->_events->queue(&event); - - event.type = kEvTOneshot; - event.code = kGraphicsEvent; - event.op = kEventClearFlag; - event.param = RF_PLACARD; - - q_event = _vm->_events->chain(q_event, &event); - - event.type = kEvTOneshot; - event.code = kTextEvent; - event.op = kEventRemove; - event.data = _placardTextEntry; - - q_event = _vm->_events->chain(q_event, &event); - - _vm->_scene->getBGPal(pal); - - event.type = kEvTImmediate; - event.code = kPalEvent; - event.op = kEventBlackToPal; - event.time = 0; - event.duration = kNormalFadeDuration; - event.data = pal; - - q_event = _vm->_events->chain(q_event, &event); - - event.type = kEvTOneshot; - event.code = kCursorEvent; - event.op = kEventShow; - - q_event = _vm->_events->chain(q_event, &event); - - event.type = kEvTOneshot; - event.code = kScriptEvent; - event.op = kEventThreadWake; - event.param = kWaitTypePlacard; - - q_event = _vm->_events->chain(q_event, &event); - + _vm->_scene->clearPlacard(); } void Script::sfPsychicProfile(SCRIPTFUNC_PARAMS) { - SF_stub("sfPsychicProfile", thread, nArgs); + thread->wait(kWaitTypePlacard); + + int stringId = thread->pop(); + _vm->_scene->showPsychicProfile(thread->_strings->getString(stringId)); } void Script::sfPsychicProfileOff(SCRIPTFUNC_PARAMS) { - SF_stub("sfPsychicProfileOff", thread, nArgs); + thread->wait(kWaitTypePlacard); + + // This is called a while after the psychic profile is + // opened, to close it automatically + _vm->_scene->clearPsychicProfile(); } // Script function #50 (0x32) @@ -1695,7 +1661,7 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) { int16 param = thread->pop() + 9; if (param >= 9 && param <= 34) { - _vm->_music->setVolume(-1, 1); + _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); _vm->_music->play(param); } else { _vm->_music->stop(); @@ -1712,7 +1678,7 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) { if (param1 >= _vm->_music->_songTableLen) { warning("sfPlayMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1); } else { - _vm->_music->setVolume(-1, 1); + _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); _vm->_music->play(_vm->_music->_songTable[param1], param2 ? MUSIC_LOOP : MUSIC_NORMAL); if (!_vm->_scene->haveChapterPointsChanged()) { _vm->_scene->setCurrentMusicTrack(param1); @@ -2032,16 +1998,49 @@ void Script::sfScriptEndVideo(SCRIPTFUNC_PARAMS) { _vm->_anim->endVideo(); } -void Script::sf87(SCRIPTFUNC_PARAMS) { - SF_stub("sf87", thread, nArgs); +void Script::sfShowIHNMDemoHelpBg(SCRIPTFUNC_PARAMS) { + _ihnmDemoCurrentY = 0; + _vm->_scene->_textList.clear(); + _vm->_interface->setMode(kPanelConverse); + _vm->_scene->showPsychicProfile(NULL); } -void Script::sf88(SCRIPTFUNC_PARAMS) { - SF_stub("sf88", thread, nArgs); +void Script::sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS) { + int stringId, textHeight; + TextListEntry textEntry; + Event event; + + stringId = thread->pop(); + + textHeight = _vm->_font->getHeight(kKnownFontVerb, thread->_strings->getString(stringId), 226, kFontCentered); + + textEntry.knownColor = kKnownColorBlack; + textEntry.useRect = true; + textEntry.rect.left = 245; + textEntry.rect.setHeight(210 + 76); + textEntry.rect.setWidth(226); + textEntry.rect.top = 76 + _ihnmDemoCurrentY; + textEntry.font = kKnownFontVerb; + textEntry.flags = (FontEffectFlags)(kFontCentered); + textEntry.text = thread->_strings->getString(stringId); + + TextListEntry *_psychicProfileTextEntry = _vm->_scene->_textList.addEntry(textEntry); + + event.type = kEvTOneshot; + event.code = kTextEvent; + event.op = kEventDisplay; + event.data = _psychicProfileTextEntry; + + _vm->_events->queue(&event); + + _ihnmDemoCurrentY += 10; } -void Script::sf89(SCRIPTFUNC_PARAMS) { - SF_stub("sf89", thread, nArgs); +void Script::sfShowIHNMDemoHelpPage(SCRIPTFUNC_PARAMS) { + // Note: The IHNM demo changes panel mode to 8 (kPanelProtect in ITE) + // when changing pages + _vm->_interface->setMode(kPanelPlacard); + _ihnmDemoCurrentY = 0; } void Script::sfVstopFX(SCRIPTFUNC_PARAMS) { @@ -2052,6 +2051,11 @@ void Script::sfVstopLoopedFX(SCRIPTFUNC_PARAMS) { _vm->_sound->stopSound(); } +void Script::sf92(SCRIPTFUNC_PARAMS) { + SF_stub("sf92", thread, nArgs); + // This opcode is empty in the full version of IHNM, but it's not empty in the demo +} + void Script::sfDemoIsInteractive(SCRIPTFUNC_PARAMS) { thread->_returnValue = 0; } @@ -2144,7 +2148,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) { if (param1 >= _vm->_music->_songTableLen) { warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1); } else { - _vm->_music->setVolume(-1, 1); + _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); event.type = kEvTOneshot; event.code = kMusicEvent; event.param = _vm->_music->_songTable[param1]; diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp index ceb1ebf630..edbdebabab 100644 --- a/engines/saga/sndres.cpp +++ b/engines/saga/sndres.cpp @@ -44,7 +44,7 @@ namespace Saga { SndRes::SndRes(SagaEngine *vm) : _vm(vm) { - /* Load sound module resource file contexts */ + // Load sound module resource file contexts _sfxContext = _vm->_resource->getContext(GAME_SOUNDFILE); if (_sfxContext == NULL) { error("SndRes::SndRes resource context not found"); @@ -68,8 +68,13 @@ SndRes::SndRes(SagaEngine *vm) : _vm(vm) { byte *resourcePointer; size_t resourceLength; - _vm->_resource->loadResource(resourceContext, RID_IHNM_SFX_LUT, - resourcePointer, resourceLength); + if (_vm->getGameId() == GID_IHNM_DEMO) { + _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_SFX_LUT, + resourcePointer, resourceLength); + } else { + _vm->_resource->loadResource(resourceContext, RID_IHNM_SFX_LUT, + resourcePointer, resourceLength); + } if (resourceLength == 0) { error("Sndres::SndRes can't read SfxIDs table"); @@ -169,7 +174,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff MemoryReadStream readS(soundResource, soundResourceLength); resourceType = soundInfo->resourceType; - buffer.isBigEndian = soundInfo->isBigEndian; if (soundResourceLength >= 8) { if (!memcmp(soundResource, "Creative", 8)) { @@ -178,7 +182,17 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff resourceType = kSoundWAV; } - if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) { + bool uncompressedSound = false; + // If a patch file exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed + if (_vm->getGameType() == GType_ITE && resourceId == 4 && + (Common::File::exists("sound/p2_a.iaf") || Common::File::exists("sound/p2_a.voc"))) + uncompressedSound = true; + + // FIXME: Currently, the SFX.RES file in IHNM cannot be compressed + if (_vm->getGameType() == GType_IHNM && (context->fileType & GAME_SOUNDFILE)) + uncompressedSound = true; + + if ((_vm->getFeatures() & GF_COMPRESSED_SOUNDS) && !uncompressedSound) { if (soundResource[0] == char(0)) { resourceType = kSoundMP3; } else if (soundResource[0] == char(1)) { @@ -190,6 +204,9 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff } + buffer.isBigEndian = soundInfo->isBigEndian; + buffer.soundType = resourceType; + buffer.originalSize = 0; switch (resourceType) { case kSoundPCM: @@ -319,7 +336,7 @@ int SndRes::getVoiceLength(uint32 resourceId) { return -1; } - if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) + if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS) || buffer.originalSize == 0) msDouble = (double)buffer.size; else msDouble = (double)buffer.originalSize; diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp index 6c2516c8a3..621b3ed310 100644 --- a/engines/saga/sound.cpp +++ b/engines/saga/sound.cpp @@ -83,31 +83,40 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) { _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume); } else { - buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET); Audio::AudioStream *stream = NULL; + Common::MemoryReadStream *tmp = NULL; switch (buffer.soundType) { #ifdef USE_MAD case kSoundMP3: debug(1, "Playing MP3 compressed sound"); - stream = Audio::makeMP3Stream(buffer.soundFile, buffer.size); + buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET); + tmp = buffer.soundFile->readStream(buffer.size); + assert(tmp); + stream = Audio::makeMP3Stream(tmp, true); break; #endif #ifdef USE_VORBIS case kSoundOGG: debug(1, "Playing OGG compressed sound"); - stream = Audio::makeVorbisStream(buffer.soundFile, buffer.size); + buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET); + tmp = buffer.soundFile->readStream(buffer.size); + assert(tmp); + stream = Audio::makeVorbisStream(tmp, true); break; #endif #ifdef USE_FLAC case kSoundFLAC: debug(1, "Playing FLAC compressed sound"); - stream = Audio::makeFlacStream(buffer.soundFile, buffer.size); + buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET); + tmp = buffer.soundFile->readStream(buffer.size); + assert(tmp); + stream = Audio::makeFlacStream(tmp, true); break; #endif default: - // Unknown compression - error("Trying to play a compressed sound, but the compression is not known"); + // No compression, play it as raw sound + _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume); break; } diff --git a/engines/saga/sprite.cpp b/engines/saga/sprite.cpp index 607e7d0a0b..ac911e5a9c 100644 --- a/engines/saga/sprite.cpp +++ b/engines/saga/sprite.cpp @@ -24,6 +24,7 @@ */ // Sprite management module + #include "saga/saga.h" #include "saga/gfx.h" @@ -57,8 +58,13 @@ Sprite::Sprite(SagaEngine *vm) : _vm(vm) { loadList(_vm->getResourceDescription()->mainSpritesResourceId, _mainSprites); _arrowSprites = _saveReminderSprites = _inventorySprites = _mainSprites; } else { - loadList(RID_IHNM_ARROW_SPRITES, _arrowSprites); - loadList(RID_IHNM_SAVEREMINDER_SPRITES, _saveReminderSprites); + if (_vm->getGameId() == GID_IHNM_DEMO) { + loadList(RID_IHNMDEMO_ARROW_SPRITES, _arrowSprites); + loadList(RID_IHNMDEMO_SAVEREMINDER_SPRITES, _saveReminderSprites); + } else { + loadList(RID_IHNM_ARROW_SPRITES, _arrowSprites); + loadList(RID_IHNM_SAVEREMINDER_SPRITES, _saveReminderSprites); + } } } @@ -113,7 +119,9 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) { offset = readS.readUint16(); if (offset >= spriteListLength) { - error("Sprite::loadList offset exceed"); + // ITE Mac demos throw this warning + warning("Sprite::loadList offset exceeded"); + return; } spritePointer = spriteListData; |