diff options
Diffstat (limited to 'engines/saga')
-rw-r--r-- | engines/saga/detection_tables.h | 33 | ||||
-rw-r--r-- | engines/saga/introproc_ihnm.cpp | 4 | ||||
-rw-r--r-- | engines/saga/introproc_ite.cpp | 70 | ||||
-rw-r--r-- | engines/saga/music.cpp | 48 | ||||
-rw-r--r-- | engines/saga/music.h | 3 | ||||
-rw-r--r-- | engines/saga/saga.cpp | 6 | ||||
-rw-r--r-- | engines/saga/saga.h | 4 | ||||
-rw-r--r-- | engines/saga/scene.cpp | 26 | ||||
-rw-r--r-- | engines/saga/scene.h | 2 | ||||
-rw-r--r-- | engines/saga/script.cpp | 6 | ||||
-rw-r--r-- | engines/saga/sndres.cpp | 15 |
11 files changed, 173 insertions, 44 deletions
diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h index 2f72e7a13c..98009326ae 100644 --- a/engines/saga/detection_tables.h +++ b/engines/saga/detection_tables.h @@ -192,9 +192,9 @@ static const SAGAGameDescription gameDescriptions[] = { ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, - GID_ITE, // Game id - GF_OLD_ITE_DOS, // features - ITE_DEFAULT_SCENE, // Starting scene number + GID_ITE, + GF_ITE_DOS_DEMO, + ITE_DEFAULT_SCENE, &ITEDemo_Resources, ARRAYSIZE(ITEDEMO_GameFonts), ITEDEMO_GameFonts, @@ -393,6 +393,33 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - German Wyrmkeep combined Windows/Mac/Linux CD + + // Supplied by user nicode in bug #6428. + // Contains voices.rsc instead of "Inherit the Earth Voices". + { + { + "ite", + "Multi-OS CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "420e09cfdbb4db12baefd4bc81d8e154", 8925349}, + {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, + { NULL, 0, NULL, 0} + }, + Common::DE_DEU, + Common::kPlatformUnknown, + ADGF_CD, + GUIO0() + }, + GID_ITE, + 0, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITE_GameFonts), + ITE_GameFonts, + NULL, + }, + // Inherit the earth - Italian Wyrmkeep combined Windows/Mac/Linux CD (fan translation) // version is different from the other Wyrmkeep re-releases in that it does diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp index fc28d2372f..dc3f55e8c1 100644 --- a/engines/saga/introproc_ihnm.cpp +++ b/engines/saga/introproc_ihnm.cpp @@ -68,7 +68,7 @@ int Scene::IHNMStartProc() { // Play the title music _vm->_music->play(1, MUSIC_NORMAL); // Play title screen - playTitle(2, 17); + playTitle(2, _vm->_music->isAdlib() ? 20 : 27); } } } else { @@ -150,7 +150,7 @@ bool Scene::checkKey() { break; case Common::EVENT_KEYDOWN: // Don't react to modifier keys alone. The original did - // non, and the user may want to change scaler without + // not, and the user may want to change scaler without // terminating the intro. if (event.kbd.ascii) res = true; diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp index 0b129dbcc0..3c10cbe1dd 100644 --- a/engines/saga/introproc_ite.cpp +++ b/engines/saga/introproc_ite.cpp @@ -59,6 +59,11 @@ namespace Saga { #define RID_ITE_FAIREPATH_SCENE 1564 #define RID_ITE_FAIRETENT_SCENE 1567 +// Intro scenes - DOS demo +#define RID_ITE_INTRO_ANIM_SCENE_DOS_DEMO 298 +#define RID_ITE_CAVE_SCENE_DOS_DEMO 302 +#define RID_ITE_VALLEY_SCENE_DOS_DEMO 310 + // ITE intro music #define MUSIC_INTRO 9 #define MUSIC_TITLE_THEME 10 @@ -75,22 +80,24 @@ LoadSceneParams ITE_IntroList[] = { {RID_ITE_FAIRETENT_SCENE, kLoadByResourceId, Scene::SC_ITEIntroFaireTentProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE} }; -int Scene::ITEStartProc() { - size_t scenesCount; - size_t i; +LoadSceneParams ITE_DOS_Demo_IntroList[] = { + {RID_ITE_INTRO_ANIM_SCENE_DOS_DEMO, kLoadByResourceId, Scene::SC_ITEIntroAnimProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, + {RID_ITE_CAVE_SCENE_DOS_DEMO, kLoadByResourceId, Scene::SC_ITEIntroCaveDemoProc, false, kTransitionFade, 0, NO_CHAPTER_CHANGE}, + {RID_ITE_VALLEY_SCENE_DOS_DEMO, kLoadByResourceId, Scene::SC_ITEIntroValleyProc, false, kTransitionFade, 0, NO_CHAPTER_CHANGE}, +}; +int Scene::ITEStartProc() { LoadSceneParams firstScene; LoadSceneParams tempScene; + bool dosDemo = (_vm->getFeatures() & GF_ITE_DOS_DEMO); + int scenesCount = (!dosDemo) ? ARRAYSIZE(ITE_IntroList) : ARRAYSIZE(ITE_DOS_Demo_IntroList); - scenesCount = ARRAYSIZE(ITE_IntroList); - - for (i = 0; i < scenesCount; i++) { - tempScene = ITE_IntroList[i]; + for (int i = 0; i < scenesCount; i++) { + tempScene = (!dosDemo) ? ITE_IntroList[i] : ITE_DOS_Demo_IntroList[i]; tempScene.sceneDescriptor = _vm->_resource->convertResourceId(tempScene.sceneDescriptor); _vm->_scene->queueScene(tempScene); } - firstScene.loadFlag = kLoadBySceneNumber; firstScene.sceneDescriptor = _vm->getStartSceneNumber(); firstScene.sceneSkipTarget = true; @@ -437,6 +444,53 @@ int Scene::ITEIntroCaveCommonProc(int param, int caveScene) { return 0; } +int Scene::ITEIntroCaveDemoProc(int param) { + Event event; + EventColumns *eventColumns = NULL; + + switch (param) { + case SCENE_BEGIN: + // Begin palette cycling animation for candles + event.type = kEvTOneshot; + event.code = kPalAnimEvent; + event.op = kEventCycleStart; + event.time = 0; + eventColumns = _vm->_events->chain(eventColumns, event); + + // Queue narrator dialogue list + for (int i = 0; i < 11; i++) { + // Play voice + event.type = kEvTOneshot; + event.code = kVoiceEvent; + event.op = kEventPlay; + event.param = i; + event.time = _vm->_sndRes->getVoiceLength(i); + _vm->_events->chain(eventColumns, event); + } + + // End scene after last dialogue over + event.type = kEvTOneshot; + event.code = kSceneEvent; + event.op = kEventEnd; + event.time = INTRO_VOICE_PAD; + _vm->_events->chain(eventColumns, event); + + break; + case SCENE_END: + break; + + default: + warning("Illegal scene procedure parameter"); + break; + } + + return 0; +} + +int Scene::SC_ITEIntroCaveDemoProc(int param, void *refCon) { + return ((Scene *)refCon)->ITEIntroCaveDemoProc(param); +} + // Handles first introductory cave painting scene int Scene::SC_ITEIntroCave1Proc(int param, void *refCon) { return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 1); diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index d20882ca26..663f5991d0 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -31,6 +31,7 @@ #include "audio/mididrv.h" #include "audio/midiparser.h" #include "audio/midiparser_qt.h" +#include "audio/miles.h" #include "audio/decoders/raw.h" #include "common/config-manager.h" #include "common/file.h" @@ -42,24 +43,51 @@ namespace Saga { #define MUSIC_SUNSPOT 26 MusicDriver::MusicDriver() : _isGM(false) { - - MidiPlayer::createDriver(); - MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM); _driverType = MidiDriver::getMusicType(dev); + switch (_driverType) { + case MT_ADLIB: + if (Common::File::exists("INSTR.AD") && Common::File::exists("INSTR.OPL")) { + _milesAudioMode = true; + _driver = Audio::MidiDriver_Miles_AdLib_create("INSTR.AD", "INSTR.OPL"); + } else if (Common::File::exists("SAMPLE.AD") && Common::File::exists("SAMPLE.OPL")) { + _milesAudioMode = true; + _driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL"); + } else { + _milesAudioMode = false; + MidiPlayer::createDriver(); + } + break; + case MT_MT32: + _milesAudioMode = true; + _driver = Audio::MidiDriver_Miles_MT32_create(""); + break; + default: + _milesAudioMode = false; + MidiPlayer::createDriver(); + break; + } + int retValue = _driver->open(); if (retValue == 0) { - if (_nativeMT32) - _driver->sendMT32Reset(); - else - _driver->sendGMReset(); + if (_driverType != MT_ADLIB) { + if (_driverType == MT_MT32 || _nativeMT32) + _driver->sendMT32Reset(); + else + _driver->sendGMReset(); + } _driver->setTimerCallback(this, &timerCallback); } } void MusicDriver::send(uint32 b) { + if (_milesAudioMode) { + _driver->send(b); + return; + } + if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) { // Remap MT32 instruments to General Midi b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8; @@ -249,7 +277,11 @@ void Music::play(uint32 resourceId, MusicFlags flags) { debug(2, "Music::play %d, %d", resourceId, flags); - if (isPlaying() && _trackNumber == resourceId) { + if (isPlaying() && _trackNumber == resourceId) + return; + + if (_vm->getFeatures() & GF_ITE_DOS_DEMO) { + warning("TODO: Music::play %d, %d for ITE DOS demo", resourceId, flags); return; } diff --git a/engines/saga/music.h b/engines/saga/music.h index 2106fb6fa6..2e7cc4c5ec 100644 --- a/engines/saga/music.h +++ b/engines/saga/music.h @@ -61,6 +61,7 @@ public: protected: MusicType _driverType; bool _isGM; + bool _milesAudioMode; }; class Music { @@ -79,6 +80,8 @@ public: void setVolume(int volume, int time = 1); int getVolume() { return _currentVolume; } + bool isAdlib() const { return _player->isAdlib(); } + Common::Array<int32> _songTable; private: diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 3d38b3ea52..b94bb66bb4 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -117,6 +117,9 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc) SearchMan.addSubDirectoryMatching(gameDataDir, "music"); SearchMan.addSubDirectoryMatching(gameDataDir, "sound"); + // Location of Miles audio files (sample.ad and sample.opl) in IHNM + SearchMan.addSubDirectoryMatching(gameDataDir, "drivers"); + // The Multi-OS version puts the voices file in the root directory of // the CD. The rest of the data files are in game/itedata SearchMan.addSubDirectoryMatching(gameDataDir, "game/itedata"); @@ -634,6 +637,9 @@ void SagaEngine::syncSoundSettings() { } void SagaEngine::pauseEngineIntern(bool pause) { + if (!_render || !_music) + return; + bool engineIsPaused = (_render->getFlags() & RF_RENDERPAUSE); if (engineIsPaused == pause) return; diff --git a/engines/saga/saga.h b/engines/saga/saga.h index 6077e55094..9c7b2f5295 100644 --- a/engines/saga/saga.h +++ b/engines/saga/saga.h @@ -137,9 +137,7 @@ enum GameFileTypes { enum GameFeatures { GF_ITE_FLOPPY = 1 << 0, -#if 0 - GF_OLD_ITE_DOS = 1 << 1, // Currently unused -#endif + GF_ITE_DOS_DEMO = 1 << 1, GF_EXTRA_ITE_CREDITS = 1 << 2, GF_8BIT_UNSIGNED_PCM = 1 << 3 }; diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index f19645dd99..efd4c371b1 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -835,13 +835,14 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) { loadSceneParams.sceneProc(SCENE_BEGIN, this); } - // We probably don't want "followers" to go into scene -1 , 0. At the very - // least we don't want garbage to be drawn that early in the ITE intro. - if (_sceneNumber > 0 && _sceneNumber != ITE_SCENE_PUZZLE) - _vm->_actor->updateActorsScene(loadSceneParams.actorsEntrance); - - if (_sceneNumber == ITE_SCENE_PUZZLE) + if (_vm->getGameId() == GID_ITE && _sceneNumber == ITE_SCENE_PUZZLE) { _vm->_puzzle->execute(); + } else { + // We probably don't want "followers" to go into scene -1 , 0. At the very + // least we don't want garbage to be drawn that early in the ITE intro. + if (_sceneNumber > 0) + _vm->_actor->updateActorsScene(loadSceneParams.actorsEntrance); + } if (getFlags() & kSceneFlagShowCursor) { // Activate user interface @@ -865,15 +866,13 @@ void Scene::loadSceneDescriptor(uint32 resourceId) { _sceneDescription.reset(); - if (resourceId == 0) { + if (resourceId == 0) return; - } _vm->_resource->loadResource(_sceneContext, resourceId, sceneDescriptorData); + ByteArrayReadStreamEndian readS(sceneDescriptorData, _sceneContext->isBigEndian()); - if (sceneDescriptorData.size() == 16) { - ByteArrayReadStreamEndian readS(sceneDescriptorData, _sceneContext->isBigEndian()); - + if (sceneDescriptorData.size() == 14 || sceneDescriptorData.size() == 16) { _sceneDescription.flags = readS.readSint16(); _sceneDescription.resourceListResourceId = readS.readSint16(); _sceneDescription.endSlope = readS.readSint16(); @@ -881,7 +880,10 @@ void Scene::loadSceneDescriptor(uint32 resourceId) { _sceneDescription.scriptModuleNumber = readS.readUint16(); _sceneDescription.sceneScriptEntrypointNumber = readS.readUint16(); _sceneDescription.startScriptEntrypointNumber = readS.readUint16(); - _sceneDescription.musicResourceId = readS.readSint16(); + if (sceneDescriptorData.size() == 16) + _sceneDescription.musicResourceId = readS.readSint16(); + } else { + warning("Scene::loadSceneDescriptor: Unknown scene descriptor data size (%d)", sceneDescriptorData.size()); } } diff --git a/engines/saga/scene.h b/engines/saga/scene.h index 410713c5d5..1a710cfe9c 100644 --- a/engines/saga/scene.h +++ b/engines/saga/scene.h @@ -400,12 +400,14 @@ class Scene { static int SC_ITEIntroTreeHouseProc(int param, void *refCon); static int SC_ITEIntroFairePathProc(int param, void *refCon); static int SC_ITEIntroFaireTentProc(int param, void *refCon); + static int SC_ITEIntroCaveDemoProc(int param, void *refCon); private: EventColumns *queueIntroDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]); EventColumns *queueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]); int ITEIntroAnimProc(int param); int ITEIntroCaveCommonProc(int param, int caveScene); + int ITEIntroCaveDemoProc(int param); int ITEIntroValleyProc(int param); int ITEIntroTreeHouseProc(int param); int ITEIntroFairePathProc(int param); diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp index 94b26c8da3..3cc6586432 100644 --- a/engines/saga/script.cpp +++ b/engines/saga/script.cpp @@ -977,19 +977,15 @@ void Script::opSpeak(SCRIPTOP_PARAMS) { // now data contains last string index -#if 0 - if (_vm->getFeatures() & GF_OLD_ITE_DOS) { // special ITE dos + if (_vm->getFeatures() & GF_ITE_DOS_DEMO) { if ((_vm->_scene->currentSceneNumber() == ITE_DEFAULT_SCENE) && (iparam1 >= 288) && (iparam1 <= (RID_SCENE1_VOICE_END - RID_SCENE1_VOICE_START + 288))) { sampleResourceId = RID_SCENE1_VOICE_START + iparam1 - 288; } } else { -#endif if (thread->_voiceLUT->size() > uint16(first)) sampleResourceId = (*thread->_voiceLUT)[uint16(first)]; -#if 0 } -#endif if (sampleResourceId < 0 || sampleResourceId > 4000) sampleResourceId = -1; diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp index 39578e96f0..b8d03c9c08 100644 --- a/engines/saga/sndres.cpp +++ b/engines/saga/sndres.cpp @@ -327,9 +327,18 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff result = true; } break; case kSoundAIFF: { - Audio::SeekableAudioStream *audStream = Audio::makeAIFFStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES); - buffer.stream = audStream; - buffer.streamLength = audStream->getLength(); + Audio::RewindableAudioStream *audStream = Audio::makeAIFFStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES); + Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(audStream); + + if (!seekStream) { + warning("AIFF file is not seekable"); + delete audStream; + result = false; + break; + } + + buffer.stream = seekStream; + buffer.streamLength = seekStream->getLength(); result = true; } break; case kSoundVOC: { |