aboutsummaryrefslogtreecommitdiff
path: root/engines/saga
diff options
context:
space:
mode:
Diffstat (limited to 'engines/saga')
-rw-r--r--engines/saga/animation.cpp5
-rw-r--r--engines/saga/detection.cpp51
-rw-r--r--engines/saga/displayinfo.h14
-rw-r--r--engines/saga/input.cpp3
-rw-r--r--engines/saga/interface.cpp85
-rw-r--r--engines/saga/interface.h5
-rw-r--r--engines/saga/introproc_ihnm.cpp10
-rw-r--r--engines/saga/itedata.cpp14
-rw-r--r--engines/saga/itedata.h2
-rw-r--r--engines/saga/music.cpp22
-rw-r--r--engines/saga/music.h3
-rw-r--r--engines/saga/rscfile.cpp157
-rw-r--r--engines/saga/saga.cpp62
-rw-r--r--engines/saga/saga.h9
-rw-r--r--engines/saga/scene.cpp2
-rw-r--r--engines/saga/sfuncs.cpp43
-rw-r--r--engines/saga/sndres.cpp61
-rw-r--r--engines/saga/sndres.h1
-rw-r--r--engines/saga/sound.cpp47
-rw-r--r--engines/saga/sound.h7
-rw-r--r--engines/saga/sprite.cpp12
21 files changed, 354 insertions, 261 deletions
diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp
index 9fffb0f8bf..493c05022c 100644
--- a/engines/saga/animation.cpp
+++ b/engines/saga/animation.cpp
@@ -579,6 +579,9 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
_vm->_events->queue(&event);
}
return;
+ } else {
+ anim->currentFrame = 0;
+ anim->completed = 0;
}
}
@@ -866,7 +869,7 @@ int Anim::fillFrameOffsets(AnimationData *anim, bool reallyFill) {
readS._bigEndian = !_vm->isBigEndian(); // RLE has inversion BE<>LE
- while (!readS.eos()) {
+ while (readS.pos() != readS.size()) {
if (reallyFill) {
anim->frameOffsets[currentFrame] = readS.pos();
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index 9c897d8ebc..a31e9b755a 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -147,9 +147,20 @@ public:
return "Inherit the Earth (C) Wyrmkeep Entertainment";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
};
+bool SagaMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave);
+}
+
bool SagaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Saga::SAGAGameDescription *gd = (const Saga::SAGAGameDescription *)desc;
if (gd) {
@@ -158,6 +169,46 @@ bool SagaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common
return gd != 0;
}
+SaveStateList SagaMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ char saveDesc[SAVE_TITLE_SIZE];
+ Common::String pattern = target;
+ pattern += ".s??";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 2 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 2);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ for (int i = 0; i < 3; i++)
+ in->readUint32BE();
+ in->read(saveDesc, SAVE_TITLE_SIZE);
+ saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+void SagaMetaEngine::removeSaveState(const char *target, int slot) const {
+ char extension[6];
+ snprintf(extension, sizeof(extension), ".s%02d", slot);
+
+ Common::String filename = target;
+ filename += extension;
+
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
#if PLUGIN_ENABLED_DYNAMIC(SAGA)
REGISTER_PLUGIN_DYNAMIC(SAGA, PLUGIN_TYPE_ENGINE, SagaMetaEngine);
#else
diff --git a/engines/saga/displayinfo.h b/engines/saga/displayinfo.h
index 7fee5fbee1..c85b5b830f 100644
--- a/engines/saga/displayinfo.h
+++ b/engines/saga/displayinfo.h
@@ -64,7 +64,7 @@ struct GameDisplayInfo {
int saveReminderWidth;
int saveReminderHeight;
int saveReminderFirstSpriteNumber;
- int saveReminderSecondSpriteNumber;
+ int saveReminderNumSprites;
int leftPortraitXOffset;
int leftPortraitYOffset;
@@ -230,7 +230,8 @@ static const GameDisplayInfo ITE_DisplayInfo = {
15, // status BG color
308,137, // save reminder pos
12,12, // save reminder w & h
- 6,7, // save reminder sprite numbers
+ 6, // save reminder first sprite number
+ 2, // number of save reminder sprites
5, 4, // left portrait x, y offset
274, 4, // right portrait x, y offset
@@ -348,9 +349,9 @@ static PanelButton IHNM_QuitPanelButtons[] = {
};
static PanelButton IHNM_LoadPanelButtons[] = {
- // TODO
- {kPanelButtonLoad, 101,19, 60,16, kTextOK,'o',0, 0,0,0},
- {kPanelButtonLoadText, -1,5, 0,0, kTextLoadSuccessful,'-',0, 0,0,0},
+ {kPanelButtonLoad, 26,80, 80,25, kTextOK,'o',0, 0,0,0},
+ {kPanelButtonLoad, 156,80, 80,25, kTextCancel,'c',0, 0,0,0},
+ {kPanelButtonLoadText, -1,30, 0,0, kTextLoadSavedGame,'-',0, 0,0,0},
};
static PanelButton IHNM_SavePanelButtons[] = {
@@ -376,7 +377,8 @@ static const GameDisplayInfo IHNM_DisplayInfo = {
250, // status BG color
616, 304, // save reminder pos
24, 24, // save reminder w&h
- 0,1, // save reminder sprite numbers
+ 0, // save reminder first sprite number
+ 16, // number of save reminder sprites
11, 12, // left portrait x, y offset
-1, -1, // right portrait x, y offset
diff --git a/engines/saga/input.cpp b/engines/saga/input.cpp
index ac80d87dd0..61b729b701 100644
--- a/engines/saga/input.cpp
+++ b/engines/saga/input.cpp
@@ -141,9 +141,6 @@ int SagaEngine::processInput() {
break;
case Common::EVENT_MOUSEMOVE:
break;
- case Common::EVENT_QUIT:
- shutDown();
- break;
default:
break;
}
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index 1d048baaad..38d126c5d4 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -94,7 +94,7 @@ static int IHNMTextStringIdsLUT[56] = {
8, // Give
10, // Options
11, // Test
- 12, //
+ 12, // Demo
13, // Help
14, // Quit Game
16, // Fast
@@ -358,15 +358,12 @@ void Interface::saveReminderCallback(void *refCon) {
}
void Interface::updateSaveReminder() {
- // TODO: finish this
- /*
if (_active && _panelMode == kPanelMain) {
- _vm->_timer->removeTimerProc(&saveReminderCallback);
- _saveReminderState = (_saveReminderState == 0) ? 1 : 0;
+ _saveReminderState = _saveReminderState % _vm->getDisplayInfo().saveReminderNumSprites + 1;
drawStatusBar();
- _vm->_timer->installTimerProc(&saveReminderCallback, TIMETOSAVE, this);
+ _vm->_timer->removeTimerProc(&saveReminderCallback);
+ _vm->_timer->installTimerProc(&saveReminderCallback, ((_vm->getGameType() == GType_ITE) ? TIMETOBLINK_ITE : TIMETOBLINK_IHNM), this);
}
- */
}
int Interface::activate() {
@@ -423,7 +420,7 @@ void Interface::setMode(int mode) {
if (mode == kPanelMain) {
_inMainMode = true;
- _saveReminderState = 1; //TODO: blinking timeout
+ _saveReminderState = 1;
} else if (mode == kPanelChapterSelection) {
_saveReminderState = 1;
} else if (mode == kPanelNull) {
@@ -688,7 +685,7 @@ bool Interface::processAscii(Common::KeyState keystate) {
setMode(kPanelMain);
_vm->_script->setNoPendingVerb();
} else if (ascii == 'q' || ascii == 'Q') {
- _vm->shutDown();
+ _vm->quitGame();
}
break;
case kPanelBoss:
@@ -905,10 +902,13 @@ void Interface::drawPanelText(Surface *ds, InterfacePanel *panel, PanelButton *p
textFont = kKnownFontMedium;
textShadowKnownColor = kKnownColorVerbTextShadow;
} else {
- if (panelButton->id < 39 || panelButton->id > 50) {
+ if ((panelButton->id < 39 || panelButton->id > 50) && panelButton->id != kTextLoadSavedGame) {
// Read non-hardcoded strings from the LUT string table, loaded from the game
// data files
text = _vm->_script->_mainStrings.getString(IHNMTextStringIdsLUT[panelButton->id]);
+ } else if (panelButton->id == kTextLoadSavedGame) {
+ // a bit of a kludge, but it will do
+ text = _vm->getTextString(52);
} else {
// Hardcoded strings in IHNM are read from the ITE hardcoded strings
text = _vm->getTextString(panelButton->id);
@@ -1081,7 +1081,7 @@ void Interface::setQuit(PanelButton *panelButton) {
if (_vm->getGameId() == GID_IHNM_DEMO)
_vm->_scene->creditsScene(); // display sales info for IHNM demo
else
- _vm->shutDown();
+ _vm->quitGame();
break;
}
}
@@ -1142,7 +1142,22 @@ void Interface::setLoad(PanelButton *panelButton) {
_loadPanel.currentButton = NULL;
switch (panelButton->id) {
case kTextOK:
- setMode(kPanelMain);
+ if (_vm->getGameType() == GType_ITE) {
+ setMode(kPanelMain);
+ } else {
+ if (_vm->getSaveFilesCount() > 0) {
+ if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
+ debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
+ setMode(kPanelMain);
+ _vm->load(_vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber));
+ _vm->syncSoundSettings();
+ }
+ }
+ }
+ break;
+ case kTextCancel:
+ // IHNM only
+ setMode(kPanelOption);
break;
}
}
@@ -1402,6 +1417,10 @@ void Interface::setSave(PanelButton *panelButton) {
fileName = _vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
_vm->save(fileName, _textInputString);
}
+ _vm->_timer->removeTimerProc(&saveReminderCallback);
+ _vm->_timer->installTimerProc(&saveReminderCallback, TIMETOSAVE, this);
+ setSaveReminderState(1);
+
_textInput = false;
setMode(kPanelOption);
break;
@@ -1573,7 +1592,6 @@ void Interface::handleChapterSelectionClick(const Point& mousePoint) {
}
void Interface::setOption(PanelButton *panelButton) {
- char * fileName;
_optionPanel.currentButton = NULL;
switch (panelButton->id) {
case kTextContinuePlaying:
@@ -1594,13 +1612,17 @@ void Interface::setOption(PanelButton *panelButton) {
setMode(kPanelQuit);
break;
case kTextLoad:
- if (_vm->getSaveFilesCount() > 0) {
- if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
- debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
- fileName = _vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
- setMode(kPanelMain);
- _vm->load(fileName);
+ if (_vm->getGameType() == GType_ITE) {
+ if (_vm->getSaveFilesCount() > 0) {
+ if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
+ debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
+ setMode(kPanelMain);
+ _vm->load(_vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber));
+ _vm->syncSoundSettings();
+ }
}
+ } else {
+ setMode(kPanelLoad);
}
break;
case kTextSave:
@@ -1625,14 +1647,16 @@ void Interface::setOption(PanelButton *panelButton) {
}
break;
case kTextMusic:
- _vm->_musicVolume = (_vm->_musicVolume + 1) % 11;
- _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
- ConfMan.setInt("music_volume", _vm->_musicVolume * 25);
+ _vm->_musicVolume = _vm->_musicVolume + 25;
+ if (_vm->_musicVolume > 255) _vm->_musicVolume = 0;
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
+ ConfMan.setInt("music_volume", _vm->_musicVolume);
break;
case kTextSound:
- _vm->_soundVolume = (_vm->_soundVolume + 1) % 11;
- _vm->_sound->setVolume(_vm->_soundVolume == 10 ? 255 : _vm->_soundVolume * 25);
- ConfMan.setInt("sfx_volume", _vm->_soundVolume * 25);
+ _vm->_soundVolume = _vm->_soundVolume + 25;
+ if (_vm->_soundVolume > 255) _vm->_soundVolume = 0;
+ ConfMan.setInt("sound_volume", _vm->_soundVolume);
+ _vm->_sound->setVolume();
break;
case kTextVoices:
if (_vm->_voiceFilesExist) {
@@ -1650,6 +1674,11 @@ void Interface::setOption(PanelButton *panelButton) {
_vm->_subtitlesEnabled = true; // Set it to "Text"
_vm->_voicesEnabled = false;
}
+
+ _vm->_speechVolume = _vm->_speechVolume + 25;
+ if (_vm->_speechVolume > 255) _vm->_speechVolume = 0;
+ ConfMan.setInt("speech_volume", _vm->_speechVolume);
+ _vm->_sound->setVolume();
ConfMan.setBool("subtitles", _vm->_subtitlesEnabled);
ConfMan.setBool("voices", _vm->_voicesEnabled);
@@ -1897,7 +1926,7 @@ void Interface::drawStatusBar() {
rect.right = rect.left + _vm->getDisplayInfo().saveReminderWidth;
rect.bottom = rect.top + _vm->getDisplayInfo().saveReminderHeight;
_vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _vm->_sprite->_saveReminderSprites,
- _saveReminderState == 1 ? _vm->getDisplayInfo().saveReminderFirstSpriteNumber : _vm->getDisplayInfo().saveReminderSecondSpriteNumber,
+ _vm->getDisplayInfo().saveReminderFirstSpriteNumber + _saveReminderState - 1,
rect, 256);
}
@@ -2250,13 +2279,13 @@ void Interface::drawPanelButtonText(Surface *ds, InterfacePanel *panel, PanelBut
break;
case kTextMusic:
if (_vm->_musicVolume)
- textId = kText10Percent + _vm->_musicVolume - 1;
+ textId = kText10Percent + _vm->_musicVolume / 25 - 1;
else
textId = kTextOff;
break;
case kTextSound:
if (_vm->_soundVolume)
- textId = kText10Percent + _vm->_soundVolume - 1;
+ textId = kText10Percent + _vm->_soundVolume / 25 - 1;
else
textId = kTextOff;
break;
diff --git a/engines/saga/interface.h b/engines/saga/interface.h
index 2091c9f071..46df12ed51 100644
--- a/engines/saga/interface.h
+++ b/engines/saga/interface.h
@@ -59,8 +59,9 @@ enum InterfaceUpdateFlags {
#define RID_IHNM_BOSS_SCREEN 19 // not in demo
#define RID_ITE_TYCHO_MAP 1686
#define RID_ITE_SPR_CROSSHAIR (73 + 9)
-#define TIMETOSAVE (kScriptTimeTicksPerSecond * 1000 * 60 * 30)
-#define TIMETOBLINK (kScriptTimeTicksPerSecond * 1000 * 1)
+#define TIMETOSAVE (1000000 * 60 * 30) // 30 minutes
+#define TIMETOBLINK_ITE (1000000 * 1)
+#define TIMETOBLINK_IHNM (1000000 / 10)
// Converse-specific stuff
diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp
index 6614f4098f..aaa428ca53 100644
--- a/engines/saga/introproc_ihnm.cpp
+++ b/engines/saga/introproc_ihnm.cpp
@@ -59,8 +59,12 @@ int Scene::IHNMStartProc() {
// Play Cyberdreams logo for 168 frames
if (!playTitle(0, logoLength, true)) {
+ if (_vm->quit())
+ return !SUCCESS;
// Play Dreamers Guild logo for 10 seconds
if (!playLoopingTitle(1, 10)) {
+ if (_vm->quit())
+ return !SUCCESS;
// Play the title music
_vm->_music->play(1, MUSIC_NORMAL);
// Play title screen
@@ -70,6 +74,8 @@ int Scene::IHNMStartProc() {
} else {
_vm->_music->play(1, MUSIC_NORMAL);
playTitle(0, 10);
+ if (_vm->quit())
+ return !SUCCESS;
playTitle(2, 12);
}
@@ -142,9 +148,9 @@ bool Scene::checkKey() {
while (_vm->_eventMan->pollEvent(event)) {
switch (event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
res = true;
- _vm->shutDown();
break;
case Common::EVENT_KEYDOWN:
// Don't react to modifier keys alone. The original did
@@ -187,7 +193,7 @@ bool Scene::playTitle(int title, int time, int mode) {
_vm->_gfx->getCurrentPal(pal_cut);
- while (!done) {
+ while (!done && !_vm->quit()) {
curTime = _vm->_system->getMillis();
switch (phase) {
diff --git a/engines/saga/itedata.cpp b/engines/saga/itedata.cpp
index 43c3d21012..bbd5cbb615 100644
--- a/engines/saga/itedata.cpp
+++ b/engines/saga/itedata.cpp
@@ -339,7 +339,7 @@ FxTable ITE_SfxTable[ITE_SFXCOUNT] = {
{ 73, 64 }
};
-const char *ITEinterfaceTextStrings[][52] = {
+const char *ITEinterfaceTextStrings[][53] = {
{
// Note that the "Load Successful!" string is never used in ScummVM
"Walk to", "Look At", "Pick Up", "Talk to", "Open",
@@ -358,7 +358,8 @@ const char *ITEinterfaceTextStrings[][52] = {
"There's no opening to close.",
"I don't know how to do that.",
"Show Dialog",
- "What is Rif's reply?"
+ "What is Rif's reply?",
+ "Loading a saved game"
},
// German
{
@@ -378,7 +379,8 @@ const char *ITEinterfaceTextStrings[][52] = {
"Hier ist keine \231ffnung zum Schlie$en.",
"Ich wei$ nicht, wie ich das machen soll.",
"Text zeigen",
- "Wie lautet die Antwort?"
+ "Wie lautet die Antwort?",
+ "Spielstand wird geladen"
},
// Italian fan translation
{
@@ -398,7 +400,8 @@ const char *ITEinterfaceTextStrings[][52] = {
"Nessuna apertura da chiudere.",
"Non saprei come farlo.",
"Dialoghi",
- "Come risponderebbe Rif?"
+ "Come risponderebbe Rif?",
+ "Vuoi davvero caricare il gioco?"
},
// Spanish IHNM
{
@@ -420,7 +423,8 @@ const char *ITEinterfaceTextStrings[][52] = {
NULL,
NULL,
NULL,
- NULL
+ NULL,
+ "Cardango una partida guardada"
}
};
diff --git a/engines/saga/itedata.h b/engines/saga/itedata.h
index 00efd070c1..6d0f5a9d70 100644
--- a/engines/saga/itedata.h
+++ b/engines/saga/itedata.h
@@ -88,7 +88,7 @@ struct FxTable {
extern ObjectTableData ITE_ObjectTable[ITE_OBJECTCOUNT];
extern FxTable ITE_SfxTable[ITE_SFXCOUNT];
-extern const char *ITEinterfaceTextStrings[][52];
+extern const char *ITEinterfaceTextStrings[][53];
#define PUZZLE_PIECES 15
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index 732bd0b50c..5bf0c0ec03 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -249,6 +249,8 @@ void MusicPlayer::setVolume(int volume) {
_masterVolume = volume;
+ Common::StackLock lock(_mutex);
+
for (int i = 0; i < 16; ++i) {
if (_channel[i]) {
_channel[i]->volume(_channelVolume[i] * _masterVolume / 255);
@@ -346,7 +348,7 @@ void MusicPlayer::stopMusic() {
}
}
-Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enabled) : _vm(vm), _mixer(mixer), _enabled(enabled), _adlib(false) {
+Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver) : _vm(vm), _mixer(mixer), _adlib(false) {
_player = new MusicPlayer(driver);
_currentVolume = 0;
@@ -402,7 +404,7 @@ void Music::musicVolumeGauge() {
}
void Music::setVolume(int volume, int time) {
- _targetVolume = volume * 2; // ScummVM has different volume scale
+ _targetVolume = volume;
_currentVolumePercent = 0;
if (volume == -1) // Set Full volume
@@ -432,11 +434,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
uint32 loopStart;
debug(2, "Music::play %d, %d", resourceId, flags);
-
- if (!_enabled) {
- return;
- }
-
+
if (isPlaying() && _trackNumber == resourceId) {
return;
}
@@ -444,11 +442,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
_trackNumber = resourceId;
_player->stopMusic();
_mixer->stopHandle(_musicHandle);
-
- if (!_vm->_musicVolume) {
- return;
- }
-
+
int realTrackNumber;
if (_vm->getGameType() == GType_ITE) {
@@ -591,7 +585,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
_player->_parser = parser;
- setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
+ setVolume(_vm->_musicVolume);
if (flags & MUSIC_LOOP)
_player->setLoop(true);
@@ -609,7 +603,7 @@ void Music::pause(void) {
}
void Music::resume(void) {
- _player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
+ _player->setVolume(_vm->_musicVolume);
_player->setPlaying(true);
}
diff --git a/engines/saga/music.h b/engines/saga/music.h
index 1953dc6f91..57ff9e0671 100644
--- a/engines/saga/music.h
+++ b/engines/saga/music.h
@@ -105,7 +105,7 @@ protected:
class Music {
public:
- Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enabled);
+ Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver);
~Music(void);
void setNativeMT32(bool b) { _player->setNativeMT32(b); }
bool hasNativeMT32() { return _player->hasNativeMT32(); }
@@ -133,7 +133,6 @@ private:
Audio::SoundHandle _musicHandle;
uint32 _trackNumber;
- int _enabled;
bool _adlib;
int _targetVolume;
diff --git a/engines/saga/rscfile.cpp b/engines/saga/rscfile.cpp
index e150caeca5..05b1162973 100644
--- a/engines/saga/rscfile.cpp
+++ b/engines/saga/rscfile.cpp
@@ -121,7 +121,7 @@ bool Resource::loadSagaContext(ResourceContext *context, uint32 contextOffset, u
resourceData->offset = contextOffset + readS1.readUint32();
resourceData->size = readS1.readUint32();
//sanity check
- if ((resourceData->offset > context->file->size()) || (resourceData->size > contextSize)) {
+ if ((resourceData->offset > (uint)context->file->size()) || (resourceData->size > contextSize)) {
result = false;
break;
}
@@ -181,8 +181,8 @@ bool Resource::loadMacContext(ResourceContext *context) {
macDataLength = context->file->readUint32BE();
macMapLength = context->file->readUint32BE();
- if (macDataOffset >= context->file->size() || macMapOffset >= context->file->size() ||
- macDataLength + macMapLength > context->file->size()) {
+ if (macDataOffset >= (uint)context->file->size() || macMapOffset >= (uint)context->file->size() ||
+ macDataLength + macMapLength > (uint)context->file->size()) {
return false;
}
@@ -384,24 +384,24 @@ bool Resource::createContexts() {
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")) {
+ if (Common::File::exists("sounds.rsc")) {
_contextsCount++;
soundFileIndex = _contextsCount - 1;
- if (Common::File::exists("sounds.rsc")) {
- sprintf(soundFileName, "sounds.rsc");
- } else {
- sprintf(soundFileName, "sounds.cmp");
- _vm->_gf_compressed_sounds = true;
- }
- } else if (Common::File::exists("soundsd.rsc") || Common::File::exists("soundsd.cmp")) {
+ sprintf(soundFileName, "sounds.rsc");
+ } else if (Common::File::exists("sounds.cmp")) {
_contextsCount++;
soundFileIndex = _contextsCount - 1;
- if (Common::File::exists("soundsd.rsc")) {
- sprintf(soundFileName, "soundsd.rsc");
- } else {
- sprintf(soundFileName, "soundsd.cmp");
- _vm->_gf_compressed_sounds = true;
- }
+ sprintf(soundFileName, "sounds.cmp");
+ _vm->_gf_compressed_sounds = true;
+ } else if (Common::File::exists("soundsd.rsc")) {
+ _contextsCount++;
+ soundFileIndex = _contextsCount - 1;
+ sprintf(soundFileName, "soundsd.rsc");
+ } else if (Common::File::exists("soundsd.cmp")) {
+ _contextsCount++;
+ soundFileIndex = _contextsCount - 1;
+ sprintf(soundFileName, "soundsd.cmp");
+ _vm->_gf_compressed_sounds = true;
} else {
// No sound file found, don't add any file to the array
soundFileInArray = true;
@@ -410,15 +410,15 @@ bool Resource::createContexts() {
}
} 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")) {
+ if (Common::File::exists("sfx.res")) {
_contextsCount++;
soundFileIndex = _contextsCount - 1;
- if (Common::File::exists("sfx.res")) {
- sprintf(soundFileName, "sfx.res");
- } else {
- sprintf(soundFileName, "sfx.cmp");
- _vm->_gf_compressed_sounds = true;
- }
+ sprintf(soundFileName, "sfx.res");
+ } else if (Common::File::exists("sfx.cmp")) {
+ _contextsCount++;
+ soundFileIndex = _contextsCount - 1;
+ sprintf(soundFileName, "sfx.cmp");
+ _vm->_gf_compressed_sounds = true;
} else {
// No sound file found, don't add any file to the array
soundFileInArray = true;
@@ -429,24 +429,24 @@ bool Resource::createContexts() {
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")) {
+ if (Common::File::exists("voices.rsc")) {
_contextsCount++;
voicesFileIndex = _contextsCount - 1;
- if (Common::File::exists("voices.rsc")) {
- sprintf(_voicesFileName[0], "voices.rsc");
- } else {
- sprintf(_voicesFileName[0], "voices.cmp");
- _vm->_gf_compressed_sounds = true;
- }
- } else if (Common::File::exists("voicesd.rsc") || Common::File::exists("voicesd.cmp")) {
+ sprintf(_voicesFileName[0], "voices.rsc");
+ } else if (Common::File::exists("voices.cmp")) {
_contextsCount++;
voicesFileIndex = _contextsCount - 1;
- if (Common::File::exists("voicesd.rsc")) {
- sprintf(_voicesFileName[0], "voicesd.rsc");
- } else {
- sprintf(_voicesFileName[0], "voicesd.cmp");
- _vm->_gf_compressed_sounds = true;
- }
+ sprintf(_voicesFileName[0], "voices.cmp");
+ _vm->_gf_compressed_sounds = true;
+ } else if (Common::File::exists("voicesd.rsc")) {
+ _contextsCount++;
+ voicesFileIndex = _contextsCount - 1;
+ sprintf(_voicesFileName[0], "voicesd.rsc");
+ } else if (Common::File::exists("voicesd.cmp")) {
+ _contextsCount++;
+ voicesFileIndex = _contextsCount - 1;
+ sprintf(_voicesFileName[0], "voicesd.cmp");
+ _vm->_gf_compressed_sounds = true;
} else if (Common::File::exists("inherit the earth voices") ||
Common::File::exists("inherit the earth voices.cmp")) {
_contextsCount++;
@@ -493,15 +493,15 @@ bool Resource::createContexts() {
sprintf(_voicesFileName[0], "voicess.cmp");
_vm->_gf_compressed_sounds = true;
}
- } else if (Common::File::exists("voicesd.res") || Common::File::exists("voicesd.cmp")) {
+ } else if (Common::File::exists("voicesd.res")) {
_contextsCount++;
voicesFileIndex = _contextsCount - 1;
- if (Common::File::exists("voicesd.res")) {
- sprintf(_voicesFileName[0], "voicesd.res");
- } else {
- sprintf(_voicesFileName[0], "voicesd.cmp");
- _vm->_gf_compressed_sounds = true;
- }
+ sprintf(_voicesFileName[0], "voicesd.res");
+ } else if (Common::File::exists("voicesd.cmp")) {
+ _contextsCount++;
+ voicesFileIndex = _contextsCount - 1;
+ sprintf(_voicesFileName[0], "voicesd.cmp");
+ _vm->_gf_compressed_sounds = true;
} else {
// No voice file found, don't add any file to the array
voicesFileInArray = true;
@@ -521,20 +521,22 @@ bool Resource::createContexts() {
if (_vm->getGameType() == GType_ITE) {
// Check for digital music in ITE
- if (Common::File::exists("music.rsc") || Common::File::exists("music.cmp")) {
+ if (Common::File::exists("music.rsc")) {
_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")) {
+ sprintf(musicFileName, "music.rsc");
+ } else if (Common::File::exists("music.cmp")) {
_contextsCount++;
digitalMusic = true;
- if (Common::File::exists("musicd.cmp"))
- sprintf(musicFileName, "musicd.cmp");
- else
- sprintf(musicFileName, "musicd.rsc");
+ sprintf(musicFileName, "music.cmp");
+ } else if (Common::File::exists("musicd.rsc")) {
+ _contextsCount++;
+ digitalMusic = true;
+ sprintf(musicFileName, "musicd.rsc");
+ } else if (Common::File::exists("musicd.cmp")) {
+ _contextsCount++;
+ digitalMusic = true;
+ sprintf(musicFileName, "musicd.cmp");
} else {
digitalMusic = false;
}
@@ -661,9 +663,7 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) {
if (chapter < 0)
chapter = (_vm->getGameId() != GID_IHNM_DEMO) ? 8 : 7;
- // TODO
- //if (module.voiceLUT)
- // free module.voiceLUT;
+ _vm->_script->_globalVoiceLUT.freeMem();
// TODO: close chapter context, or rather reassign it in our case
@@ -769,7 +769,6 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) {
_vm->_sprite->_mainSprites.freeMem();
_vm->_sprite->loadList(_metaResource.mainSpritesID, _vm->_sprite->_mainSprites);
-
_vm->_actor->loadObjList(_metaResource.objectCount, _metaResource.objectsResourceID);
_vm->_resource->loadResource(resourceContext, _metaResource.cutawayListResourceID, resourcePointer, resourceLength);
@@ -805,49 +804,21 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) {
free(resourcePointer);
} else {
// The IHNM demo has a fixed music track and doesn't load a song table
- _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(3, MUSIC_LOOP);
free(resourcePointer);
}
int voiceLUTResourceID = 0;
- _vm->_script->_globalVoiceLUT.freeMem();
-
- switch (chapter) {
- case 1:
- _vm->_sndRes->setVoiceBank(1);
- voiceLUTResourceID = 23;
- break;
- case 2:
- _vm->_sndRes->setVoiceBank(2);
- voiceLUTResourceID = 24;
- break;
- case 3:
- _vm->_sndRes->setVoiceBank(3);
- voiceLUTResourceID = 25;
- break;
- case 4:
- _vm->_sndRes->setVoiceBank(4);
- voiceLUTResourceID = 26;
- break;
- case 5:
- _vm->_sndRes->setVoiceBank(5);
- voiceLUTResourceID = 27;
- break;
- case 6:
- _vm->_sndRes->setVoiceBank(6);
- voiceLUTResourceID = 28;
- break;
- case 7:
+ if (chapter != 7) {
+ int voiceBank = (chapter == 8) ? 0 : chapter;
+ _vm->_sndRes->setVoiceBank(voiceBank);
+ voiceLUTResourceID = 22 + voiceBank;
+ } else {
// IHNM demo
_vm->_sndRes->setVoiceBank(0);
voiceLUTResourceID = 17;
- break;
- case 8:
- _vm->_sndRes->setVoiceBank(0);
- voiceLUTResourceID = 22;
- break;
}
if (voiceLUTResourceID) {
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index fafbd02cec..5ce5d6ab93 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -64,7 +64,6 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc)
_leftMouseButtonPressed = _rightMouseButtonPressed = false;
_console = NULL;
- _quit = false;
_resource = NULL;
_sndRes = NULL;
@@ -93,20 +92,20 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc)
// The Linux version of Inherit the Earth puts all data files in an
// 'itedata' sub-directory, except for voices.rsc
- Common::File::addDefaultDirectory(_gameDataPath + "itedata/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("itedata"));
// The Windows version of Inherit the Earth puts various data files in
// other subdirectories.
- Common::File::addDefaultDirectory(_gameDataPath + "graphics/");
- Common::File::addDefaultDirectory(_gameDataPath + "music/");
- Common::File::addDefaultDirectory(_gameDataPath + "sound/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("graphics"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("music"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("sound"));
// 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
- Common::File::addDefaultDirectory(_gameDataPath + "game/itedata/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("game").getChild("itedata"));
// Mac CD Wyrmkeep
- Common::File::addDefaultDirectory(_gameDataPath + "patch/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("patch"));
_displayClip.left = _displayClip.top = 0;
syst->getEventManager()->registerRandomSource(_rnd, "saga");
@@ -142,8 +141,7 @@ SagaEngine::~SagaEngine() {
}
int SagaEngine::init() {
- _soundVolume = ConfMan.getInt("sfx_volume") / 25;
- _musicVolume = ConfMan.getInt("music_volume") / 25;
+ _musicVolume = ConfMan.getInt("music_volume");
_subtitlesEnabled = ConfMan.getBool("subtitles");
_readingSpeed = getTalkspeed();
_copyProtection = ConfMan.getBool("copy_protection");
@@ -194,29 +192,21 @@ int SagaEngine::init() {
if (native_mt32)
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- _music = new Music(this, _mixer, _driver, _musicVolume);
+ _music = new Music(this, _mixer, _driver);
_music->setNativeMT32(native_mt32);
_music->setAdlib(adlib);
-
- if (!_musicVolume) {
- debug(1, "Music disabled.");
- }
-
_render = new Render(this, _system);
if (!_render->initialized()) {
return FAILURE;
}
// Initialize system specific sound
- _sound = new Sound(this, _mixer, _soundVolume);
- if (!_soundVolume) {
- debug(1, "Sound disabled.");
- }
-
+ _sound = new Sound(this, _mixer);
+
_interface->converseInit();
_script->setVerb(_script->getVerbType(kVerbWalkTo));
- _music->setVolume(-1, 1);
+ _music->setVolume(_musicVolume, 1);
_gfx->initPalette();
@@ -233,6 +223,8 @@ int SagaEngine::init() {
}
}
+ syncSoundSettings();
+
// FIXME: This is the ugly way of reducing redraw overhead. It works
// well for 320x200 but it's unclear how well it will work for
// 640x480.
@@ -255,14 +247,22 @@ int SagaEngine::go() {
_interface->addToInventory(_actor->objIndexToId(0)); // Magic hat
_scene->changeScene(ConfMan.getInt("boot_param"), 0, kTransitionNoFade);
} else if (ConfMan.hasKey("save_slot")) {
+ // Init the current chapter to 8 (character selection) for IHNM
+ if (getGameType() == GType_IHNM)
+ _scene->changeScene(-2, 0, kTransitionFade, 8);
+
// First scene sets up palette
_scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade);
_events->handleEvents(0); // Process immediate events
- _interface->setMode(kPanelMain);
- char *fileName;
- fileName = calcSaveFileName(ConfMan.getInt("save_slot"));
+ if (getGameType() != GType_IHNM)
+ _interface->setMode(kPanelMain);
+ else
+ _interface->setMode(kPanelChapterSelection);
+
+ char *fileName = calcSaveFileName(ConfMan.getInt("save_slot"));
load(fileName);
+ syncSoundSettings();
} else {
_framesEsc = 0;
_scene->startScene();
@@ -270,7 +270,7 @@ int SagaEngine::go() {
uint32 currentTicks;
- while (!_quit) {
+ while (!quit()) {
if (_console->isAttached())
_console->onFrame();
@@ -520,4 +520,16 @@ int SagaEngine::getTalkspeed() {
return (ConfMan.getInt("talkspeed") * 3 + 255 / 2) / 255;
}
+void SagaEngine::syncSoundSettings() {
+ _subtitlesEnabled = ConfMan.getBool("subtitles");
+ _readingSpeed = getTalkspeed();
+
+ if (_readingSpeed > 3)
+ _readingSpeed = 0;
+
+ _musicVolume = ConfMan.getInt("music_volume");
+ _music->setVolume(_musicVolume, 1);
+ _sound->setVolume();
+}
+
} // End of namespace Saga
diff --git a/engines/saga/saga.h b/engines/saga/saga.h
index 6b6eb6b3fb..0b6b3b1478 100644
--- a/engines/saga/saga.h
+++ b/engines/saga/saga.h
@@ -295,7 +295,8 @@ enum TextStringIds {
kTextVoices,
kTextText,
kTextAudio,
- kTextBoth
+ kTextBoth,
+ kTextLoadSavedGame
};
struct GameResourceDescription {
@@ -491,7 +492,6 @@ protected:
public:
SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc);
virtual ~SagaEngine();
- void shutDown() { _quit = true; }
void save(const char *fileName, const char *saveName);
void load(const char *fileName);
@@ -512,6 +512,8 @@ public:
return isSaveListFull() ? _saveFilesCount : _saveFilesCount + 1;
}
+ virtual void syncSoundSettings();
+
int16 _framesEsc;
uint32 _globalFlags;
@@ -520,6 +522,7 @@ public:
int _soundVolume;
int _musicVolume;
+ int _speechVolume;
bool _subtitlesEnabled;
bool _voicesEnabled;
bool _voiceFilesExist;
@@ -610,8 +613,6 @@ public:
bool _rightMouseButtonPressed;
int _mouseClickCount;
- bool _quit;
-
//current game description
int _gameNumber;
const SAGAGameDescription *_gameDescription;
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index c3c1587822..074b4c933a 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -315,7 +315,7 @@ void Scene::creditsScene() {
break;
}
- _vm->shutDown();
+ _vm->quitGame();
return;
}
diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp
index ea61f5ce04..e19fd5ae02 100644
--- a/engines/saga/sfuncs.cpp
+++ b/engines/saga/sfuncs.cpp
@@ -276,31 +276,14 @@ void Script::sfTakeObject(SCRIPTFUNC_PARAMS) {
if (obj->_sceneNumber != ITE_SCENE_INV) {
obj->_sceneNumber = ITE_SCENE_INV;
- // WORKAROUND for a problematic object in IHNM
- // There are 3 different scenes in front of the zeppelin, in Gorrister's chapter. A scene where the
- // zeppelin is in the air (scene 17), a scene where it approaches Gorrister's (scene 16) and another one
- // where it has landed (scene 18).
- // In two of these scenes (the "on air" and "approaching" ones), when the player uses the knife with the
- // rope, the associated script picks up object id 16392. In the "zeppelin landed" scene (scene 18), the
- // associated script picks up object id 16390. This seems to be a script bug, as it should be id 16392,
- // like in the other two scenes, as it is the same object (the rope). Picking up object 16390 leads to an
- // assertion anyway, therefore we change the problematic object (16390) to the correct one (16392) here.
- // Fixes bug #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring"
- if (_vm->getGameType() == GType_IHNM) {
- if (_vm->_scene->currentChapterNumber() == 1 && _vm->_scene->currentSceneNumber() == 18) {
- if (objectId == 16390)
- objectId = 16392;
- }
- }
-
- // 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 (objectId == 16408)
- obj->_spriteListResourceId = 24;
- if (objectId == 16409)
- obj->_spriteListResourceId = 25;
- }
+ // Normally, when objects are picked up, they should always have the same
+ // _spriteListResourceId as their _index value. Some don't in IHNM, so
+ // we fix their sprite here
+ // Fixes bugs #2057200 - "IHNM: Invisible inventory objects",
+ // #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring"
+ // and some incorrect objects in the IHNM demo
+ if (_vm->getGameType() == GType_IHNM)
+ obj->_spriteListResourceId = obj->_index;
_vm->_interface->addToInventory(objectId);
}
@@ -356,7 +339,7 @@ void Script::sfMainMode(SCRIPTFUNC_PARAMS) {
// exit the game. Known non-interactive demos are GID_ITE_MACDEMO1 and
// GID_ITE_WINDEMO1
if (_vm->getFeatures() & GF_NON_INTERACTIVE)
- _vm->shutDown();
+ _vm->quitGame();
}
// Script function #6 (0x06) blocking
@@ -572,7 +555,7 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) {
}
if (_vm->getGameType() == GType_ITE && sceneNumber < 0) {
- _vm->shutDown();
+ _vm->quitGame();
return;
}
@@ -1482,7 +1465,7 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) {
int16 param = thread->pop() + 9;
if (param >= 9 && param <= 34) {
- _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(param);
} else {
_vm->_music->stop();
@@ -1499,7 +1482,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(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(_vm->_music->_songTable[param1], param2 ? MUSIC_LOOP : MUSIC_NORMAL);
if (!_vm->_scene->haveChapterPointsChanged()) {
_vm->_scene->setCurrentMusicTrack(param1);
@@ -1945,7 +1928,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(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ _vm->_music->setVolume(_vm->_musicVolume, 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 8d269fb3e8..b990b8ddf7 100644
--- a/engines/saga/sndres.cpp
+++ b/engines/saga/sndres.cpp
@@ -169,7 +169,6 @@ void SndRes::playVoice(uint32 resourceId) {
}
bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buffer, bool onlyHeader) {
- byte *soundResource;
Audio::AudioStream *voxStream;
size_t soundResourceLength;
bool result = false;
@@ -180,13 +179,13 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
byte flags;
size_t voxSize;
const GameSoundInfo *soundInfo;
+ Common::File* file;
if (resourceId == (uint32)-1) {
return false;
}
if (_vm->getGameType() == GType_IHNM && _vm->isMacResources()) {
- Common::File soundFile;
char soundFileName[40];
int dirIndex = resourceId / 64;
@@ -199,15 +198,23 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
} else {
sprintf(soundFileName, "SFX/SFX%d/SFX%03x", dirIndex, resourceId);
}
- soundFile.open(soundFileName);
- soundResourceLength = soundFile.size();
- soundResource = new byte[soundResourceLength];
- soundFile.read(soundResource, soundResourceLength);
- soundFile.close();
+
+ file = new Common::File();
+
+ file->open(soundFileName);
+ soundResourceLength = file->size();
} else {
- _vm->_resource->loadResource(context, resourceId, soundResource, soundResourceLength);
+
+ ResourceData* resourceData = _vm->_resource->getResourceData(context, resourceId);
+ file = context->getFile(resourceData);
+
+ file->seek(resourceData->offset);
+ soundResourceLength = resourceData->size;
+
}
+ Common::SeekableReadStream& readS = *file;
+
if ((context->fileType & GAME_VOICEFILE) != 0) {
soundInfo = _vm->getVoiceInfo();
} else {
@@ -220,16 +227,20 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
context->table[resourceId].fillSoundPatch(soundInfo);
}
- MemoryReadStream readS(soundResource, soundResourceLength);
resourceType = soundInfo->resourceType;
if (soundResourceLength >= 8) {
- if (!memcmp(soundResource, "Creative", 8)) {
+ byte header[8];
+
+ readS.read(&header, 8);
+ readS.seek(readS.pos() - 8);
+
+ if (!memcmp(header, "Creative", 8)) {
resourceType = kSoundVOC;
- } else if (!memcmp(soundResource, "RIFF", 4) != 0) {
+ } else if (!memcmp(header, "RIFF", 4) != 0) {
resourceType = kSoundWAV;
- } else if (!memcmp(soundResource, "FORM", 4) != 0) {
+ } else if (!memcmp(header, "FORM", 4) != 0) {
resourceType = kSoundAIFF;
}
@@ -244,11 +255,11 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
uncompressedSound = true;
if ((_vm->getFeatures() & GF_COMPRESSED_SOUNDS) && !uncompressedSound) {
- if (soundResource[0] == char(0)) {
+ if (header[0] == char(0)) {
resourceType = kSoundMP3;
- } else if (soundResource[0] == char(1)) {
+ } else if (header[0] == char(1)) {
resourceType = kSoundOGG;
- } else if (soundResource[0] == char(2)) {
+ } else if (header[0] == char(2)) {
resourceType = kSoundFLAC;
}
}
@@ -268,9 +279,9 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.stereo = false;
if (onlyHeader) {
buffer.buffer = NULL;
- free(soundResource);
} else {
- buffer.buffer = soundResource;
+ buffer.buffer = (byte *) malloc(soundResourceLength);
+ readS.read(buffer.buffer, soundResourceLength);
}
result = true;
break;
@@ -284,9 +295,10 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.buffer = NULL;
} else {
buffer.buffer = (byte *)malloc(buffer.size);
- memcpy(buffer.buffer, soundResource + 36, buffer.size);
+
+ readS.seek(readS.pos() + 36);
+ readS.read(buffer.buffer, buffer.size);
}
- free(soundResource);
result = true;
break;
case kSoundVOX:
@@ -297,7 +309,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.size = soundResourceLength * 4;
if (onlyHeader) {
buffer.buffer = NULL;
- free(soundResource);
} else {
voxStream = Audio::makeADPCMStream(&readS, false, soundResourceLength, Audio::kADPCMOki);
buffer.buffer = (byte *)malloc(buffer.size);
@@ -325,7 +336,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
result = true;
}
- free(soundResource);
break;
case kSoundWAV:
if (Audio::loadWAVFromStream(readS, size, rate, flags)) {
@@ -342,7 +352,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
result = true;
}
- free(soundResource);
break;
case kSoundAIFF:
if (Audio::loadAIFFFromStream(readS, size, rate, flags)) {
@@ -359,7 +368,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
result = true;
}
- free(soundResource);
break;
case kSoundMP3:
case kSoundOGG:
@@ -382,12 +390,17 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.buffer = NULL;
result = true;
- free(soundResource);
break;
default:
error("SndRes::load Unknown sound type");
}
+
+ if (_vm->getGameType() == GType_IHNM && _vm->isMacResources()) {
+ delete file;
+ }
+
+
// In ITE CD De some voices are absent and contain just 5 bytes header
// Round it to even number so soundmanager will not crash.
// See bug #1256701
diff --git a/engines/saga/sndres.h b/engines/saga/sndres.h
index e77c833076..d5507ebc55 100644
--- a/engines/saga/sndres.h
+++ b/engines/saga/sndres.h
@@ -39,7 +39,6 @@ public:
SndRes(SagaEngine *vm);
~SndRes();
- int loadSound(uint32 resourceId);
void playSound(uint32 resourceId, int volume, bool loop);
void playVoice(uint32 resourceId);
int getVoiceLength(uint32 resourceId);
diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp
index 1d3263d302..1d41d39cf2 100644
--- a/engines/saga/sound.cpp
+++ b/engines/saga/sound.cpp
@@ -22,8 +22,10 @@
* $Id$
*
*/
-#include "saga/saga.h"
+#include "common/config-manager.h"
+
+#include "saga/saga.h"
#include "saga/sound.h"
#include "sound/audiostream.h"
@@ -32,13 +34,13 @@
namespace Saga {
-Sound::Sound(SagaEngine *vm, Audio::Mixer *mixer, int volume) :
+Sound::Sound(SagaEngine *vm, Audio::Mixer *mixer) :
_vm(vm), _mixer(mixer), _voxStream(0) {
for (int i = 0; i < SOUND_HANDLES; i++)
_handles[i].type = kFreeHandle;
- setVolume(volume == 10 ? 255 : volume * 25);
+ setVolume();
}
Sound::~Sound() {
@@ -61,7 +63,8 @@ SndHandle *Sound::getHandle() {
return NULL;
}
-void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume, bool loop) {
+void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume,
+ sndHandleType handleType, bool loop) {
byte flags;
flags = Audio::Mixer::FLAG_AUTOFREE;
@@ -81,7 +84,12 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int
flags |= Audio::Mixer::FLAG_UNSIGNED;
if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) {
- _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume);
+ if (handleType == kVoiceHandle)
+ _mixer->playRaw(Audio::Mixer::kSpeechSoundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, flags, -1, volume);
+ else
+ _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, flags, -1, volume);
} else {
Audio::AudioStream *stream = NULL;
MemoryReadStream *tmp = NULL;
@@ -116,12 +124,23 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int
#endif
default:
// No compression, play it as raw sound
- _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume);
+ if (handleType == kVoiceHandle)
+ _mixer->playRaw(Audio::Mixer::kSpeechSoundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, flags, -1, volume);
+ else
+ _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, flags, -1, volume);
break;
}
- if (stream != NULL)
- _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, stream, -1, volume, 0, true, false);
+ if (stream != NULL) {
+ if (handleType == kVoiceHandle)
+ _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, handle, stream, -1,
+ volume, 0, true, false);
+ else
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, stream, -1,
+ volume, 0, true, false);
+ }
}
}
@@ -129,7 +148,7 @@ void Sound::playSound(SoundBuffer &buffer, int volume, bool loop) {
SndHandle *handle = getHandle();
handle->type = kEffectHandle;
- playSoundBuffer(&handle->handle, buffer, 2 * volume, loop);
+ playSoundBuffer(&handle->handle, buffer, 2 * volume, handle->type, loop);
}
void Sound::pauseSound() {
@@ -156,7 +175,7 @@ void Sound::playVoice(SoundBuffer &buffer) {
SndHandle *handle = getHandle();
handle->type = kVoiceHandle;
- playSoundBuffer(&handle->handle, buffer, 255, false);
+ playSoundBuffer(&handle->handle, buffer, 255, handle->type, false);
}
void Sound::pauseVoice() {
@@ -184,9 +203,11 @@ void Sound::stopAll() {
stopSound();
}
-void Sound::setVolume(int volume) {
- _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
- _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
+void Sound::setVolume() {
+ _vm->_soundVolume = ConfMan.getInt("sound_volume");
+ _vm->_speechVolume = ConfMan.getInt("speech_volume");
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, _vm->_soundVolume);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, _vm->_speechVolume);
}
} // End of namespace Saga
diff --git a/engines/saga/sound.h b/engines/saga/sound.h
index ce479c64d1..6d9e42a49d 100644
--- a/engines/saga/sound.h
+++ b/engines/saga/sound.h
@@ -71,7 +71,7 @@ struct SndHandle {
class Sound {
public:
- Sound(SagaEngine *vm, Audio::Mixer *mixer, int volume);
+ Sound(SagaEngine *vm, Audio::Mixer *mixer);
~Sound();
void playSound(SoundBuffer &buffer, int volume, bool loop);
@@ -86,11 +86,12 @@ public:
void stopAll();
- void setVolume(int volume);
+ void setVolume();
private:
- void playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume, bool loop);
+ void playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume,
+ sndHandleType handleType, bool loop);
SndHandle *getHandle();
diff --git a/engines/saga/sprite.cpp b/engines/saga/sprite.cpp
index be4f2a423d..a1f78e1b9f 100644
--- a/engines/saga/sprite.cpp
+++ b/engines/saga/sprite.cpp
@@ -74,9 +74,11 @@ Sprite::Sprite(SagaEngine *vm) : _vm(vm) {
Sprite::~Sprite(void) {
debug(8, "Shutting down sprite subsystem...");
_mainSprites.freeMem();
- _inventorySprites.freeMem();
- _arrowSprites.freeMem();
- _saveReminderSprites.freeMem();
+ if (_vm->getGameType() == GType_IHNM) {
+ _inventorySprites.freeMem();
+ _arrowSprites.freeMem();
+ _saveReminderSprites.freeMem();
+ }
free(_decodeBuf);
}
@@ -410,6 +412,8 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou
while (!readS.eos() && (outPointer < outPointerEnd)) {
bg_runcount = readS.readByte();
+ if (readS.eos())
+ break;
fg_runcount = readS.readByte();
for (c = 0; c < bg_runcount && !readS.eos(); c++) {
@@ -422,6 +426,8 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou
for (c = 0; c < fg_runcount && !readS.eos(); c++) {
*outPointer = readS.readByte();
+ if (readS.eos())
+ break;
if (outPointer < outPointerEnd)
outPointer++;
else