diff options
Diffstat (limited to 'engines/saga')
-rw-r--r-- | engines/saga/animation.cpp | 5 | ||||
-rw-r--r-- | engines/saga/detection.cpp | 51 | ||||
-rw-r--r-- | engines/saga/displayinfo.h | 14 | ||||
-rw-r--r-- | engines/saga/input.cpp | 3 | ||||
-rw-r--r-- | engines/saga/interface.cpp | 85 | ||||
-rw-r--r-- | engines/saga/interface.h | 5 | ||||
-rw-r--r-- | engines/saga/introproc_ihnm.cpp | 10 | ||||
-rw-r--r-- | engines/saga/itedata.cpp | 14 | ||||
-rw-r--r-- | engines/saga/itedata.h | 2 | ||||
-rw-r--r-- | engines/saga/music.cpp | 22 | ||||
-rw-r--r-- | engines/saga/music.h | 3 | ||||
-rw-r--r-- | engines/saga/rscfile.cpp | 157 | ||||
-rw-r--r-- | engines/saga/saga.cpp | 62 | ||||
-rw-r--r-- | engines/saga/saga.h | 9 | ||||
-rw-r--r-- | engines/saga/scene.cpp | 2 | ||||
-rw-r--r-- | engines/saga/sfuncs.cpp | 43 | ||||
-rw-r--r-- | engines/saga/sndres.cpp | 61 | ||||
-rw-r--r-- | engines/saga/sndres.h | 1 | ||||
-rw-r--r-- | engines/saga/sound.cpp | 47 | ||||
-rw-r--r-- | engines/saga/sound.h | 7 | ||||
-rw-r--r-- | engines/saga/sprite.cpp | 12 |
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 |