aboutsummaryrefslogtreecommitdiff
path: root/engines/saga
diff options
context:
space:
mode:
Diffstat (limited to 'engines/saga')
-rw-r--r--engines/saga/detection_tables.h33
-rw-r--r--engines/saga/introproc_ihnm.cpp4
-rw-r--r--engines/saga/introproc_ite.cpp70
-rw-r--r--engines/saga/music.cpp48
-rw-r--r--engines/saga/music.h3
-rw-r--r--engines/saga/saga.cpp6
-rw-r--r--engines/saga/saga.h4
-rw-r--r--engines/saga/scene.cpp26
-rw-r--r--engines/saga/scene.h2
-rw-r--r--engines/saga/script.cpp6
-rw-r--r--engines/saga/sndres.cpp15
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: {