diff options
Diffstat (limited to 'engines')
24 files changed, 204 insertions, 197 deletions
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index c7f8d1c3d9..ea3e2ce7ec 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -510,7 +510,10 @@ void MohawkEngine_Riven::delay(uint32 ms) { void MohawkEngine_Riven::runLoadDialog() { GUI::SaveLoadChooser slc(_("Load game:"), _("Load"), false); + pauseEngine(true); int slot = slc.runModalWithCurrentTarget(); + pauseEngine(false); + if (slot >= 0) { loadGameStateAndDisplayError(slot); } diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp index d8b115f9bd..8c45a2890e 100644 --- a/engines/saga/actor.cpp +++ b/engines/saga/actor.cpp @@ -1174,21 +1174,6 @@ void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount, _activeSpeech.speechBox.right = _vm->getDisplayInfo().width - 10; } - // HACK for the compact disk in Ellen's chapter - // Once Ellen starts saying that "Something is different", bring the compact disk in the - // scene. After speaking with AM, the compact disk is visible. She always says this line - // when entering room 59, after speaking with AM, if the compact disk is not picked up yet - // Check Script::sfDropObject for the other part of this hack - if (_vm->getGameId() == GID_IHNM && _vm->_scene->currentChapterNumber() == 3 && - _vm->_scene->currentSceneNumber() == 59 && _activeSpeech.sampleResourceId == 286) { - for (ObjectDataArray::iterator obj = _objs.begin(); obj != _objs.end(); ++obj) { - if (obj->_id == 16385) { // the compact disk - obj->_sceneNumber = 59; - break; - } - } - } - } void Actor::nonActorSpeech(const Common::Rect &box, const char **strings, int stringsCount, int sampleResourceId, int speechFlags) { diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 9dcc8d9137..e6b196c4cd 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -2533,10 +2533,12 @@ void Interface::converseDisplayTextLines() { char bullet[2] = { (char)0xb7, 0 }; - Rect rect(8, _vm->getDisplayInfo().converseTextLines * _vm->getDisplayInfo().converseTextHeight); - Point textPoint; assert(_conversePanel.buttonsCount >= 6); + Rect rect(8, _vm->getDisplayInfo().converseTextLines * _vm->getDisplayInfo().converseTextHeight); + rect.moveTo(_conversePanel.x + _conversePanel.buttons[0].xOffset, _conversePanel.y + _conversePanel.buttons[0].yOffset); + + Point textPoint; if (_vm->getGameId() == GID_ITE) { bulletForegnd = kITEColorGreen; @@ -2547,13 +2549,11 @@ void Interface::converseDisplayTextLines() { bullet[0] = '>'; // different bullet in IHNM } - rect.moveTo(_conversePanel.x + _conversePanel.buttons[0].xOffset, - _conversePanel.y + _conversePanel.buttons[0].yOffset); - if (_vm->getGameId() == GID_ITE) - _vm->_gfx->drawRect(rect, kITEColorDarkGrey); //fill bullet place - else - _vm->_gfx->drawRect(rect, _vm->KnownColor2ColorId(kKnownColorBlack)); //fill bullet place + _vm->_gfx->drawRect(rect, kITEColorDarkGrey); // fill bullet place + else if (_vm->getGameId() == GID_IHNM) + // TODO: Add these to IHNM_DisplayInfo? + _vm->_gfx->drawRect(Common::Rect(118, 345, 603, 463), _vm->KnownColor2ColorId(kKnownColorBlack)); // fill converse rect for (int i = 0; i < _vm->getDisplayInfo().converseTextLines; i++) { relPos = _converseStartPos + i; diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp index 3cc6586432..7a84944b17 100644 --- a/engines/saga/script.cpp +++ b/engines/saga/script.cpp @@ -1709,15 +1709,16 @@ void Script::whichObject(const Point& mousePoint) { if (_vm->getGameId() == GID_IHNM && objectId == 8199) newRightButtonVerb = getVerbType(kVerbLookAt); - if ((_currentVerb == getVerbType(kVerbPickUp)) || - (_currentVerb == getVerbType(kVerbOpen)) || - (_currentVerb == getVerbType(kVerbClose)) || - ((_currentVerb == getVerbType(kVerbGive)) && !_firstObjectSet) || - ((_currentVerb == getVerbType(kVerbUse)) && !(actor->_flags & kFollower))) { - if (_vm->getGameId() == GID_ITE) { - objectId = ID_NOTHING; - newObjectId = ID_NOTHING; - } + bool actorIsFollower = (actor->_flags & kFollower); + bool actorCanBeUsed = (actor->_flags & kUsable); + + if ( _currentVerb == getVerbType(kVerbPickUp) || + _currentVerb == getVerbType(kVerbOpen) || + _currentVerb == getVerbType(kVerbClose) || + (_currentVerb == getVerbType(kVerbGive) && !_firstObjectSet) || + (_currentVerb == getVerbType(kVerbUse) && !_firstObjectSet && !(actorIsFollower || actorCanBeUsed))) { + objectId = ID_NOTHING; + newObjectId = ID_NOTHING; } } } diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index 2175d8f40a..6456daeb02 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -704,14 +704,6 @@ void Script::sfDropObject(SCRIPTFUNC_PARAMS) { obj->_sceneNumber = _vm->_scene->currentSceneNumber(); - // HACK for the compact disk in Ellen's chapter - // Change the scene number of the compact disk so that it's not shown. It will be shown - // once Ellen says that there's something different (i.e. after speaking with AM) - // See Actor::actorSpeech for the other part of this hack - if (_vm->getGameId() == GID_IHNM && _vm->_scene->currentChapterNumber() == 3 && - _vm->_scene->currentSceneNumber() == 59 && obj->_id == 16385) - obj->_sceneNumber = -1; - if (_vm->getGameId() == GID_IHNM) { // Don't update _spriteListResourceId if spriteId is 0 and the object is not the // psychic profile. If spriteId == 0, the object's sprite is incorrectly reset. diff --git a/engines/sludge/sound.cpp b/engines/sludge/sound.cpp index 79b9ab79d8..6820ae14be 100644 --- a/engines/sludge/sound.cpp +++ b/engines/sludge/sound.cpp @@ -52,10 +52,9 @@ SoundManager::SoundManager() { _soundCache = nullptr; _soundCache = new SoundThing[MAX_SAMPLES]; - #if 0 + _modCache = nullptr; _modCache = new SoundThing[MAX_MODS]; - #endif _defVol = 128; _defSoundVol = 255; @@ -70,10 +69,8 @@ SoundManager::~SoundManager() { delete []_soundCache; _soundCache = nullptr; - #if 0 delete []_modCache; _modCache = nullptr; - #endif } bool SoundManager::initSoundStuff() { @@ -82,12 +79,13 @@ bool SoundManager::initSoundStuff() { _soundCache[a].looping = false; _soundCache[a].inSoundList = false; } -#if 0 + for (int a = 0; a < MAX_MODS; a ++) { - _modCache[a].stream = NULL; - _modCache[a].playing = false; + _soundCache[a].fileLoaded = -1; + _soundCache[a].looping = false; + _soundCache[a].inSoundList = false; } -#endif + return _soundOK = true; } @@ -95,48 +93,24 @@ void SoundManager::killSoundStuff() { if (!_soundOK) return; - _silenceIKillYou = true; - for (int i = 0; i < MAX_SAMPLES; i ++) { - if (g_sludge->_mixer->isSoundHandleActive(_soundCache[i].handle)) { - g_sludge->_mixer->stopHandle(_soundCache[i].handle); - } - } -#if 0 - for (int i = 0; i < MAX_MODS; i ++) { - if (_modCache[i].playing) { - - if (! alureStopSource(modCache[i].playingOnSource, AL_TRUE)) { - debugOut("Failed to stop source: %s\n", - alureGetErrorString()); - } - - } - - if (_modCache[i].stream != NULL) { - - if (! alureDestroyStream(modCache[i].stream, 0, NULL)) { - debugOut("Failed to destroy stream: %s\n", - alureGetErrorString()); - } + for (int i = 0; i < MAX_SAMPLES; ++i) + freeSound(i); - } - } -#endif - _silenceIKillYou = false; + for (int i = 0; i < MAX_MODS; ++i) + stopMOD(i); } /* * Some setters: */ - void SoundManager::setMusicVolume(int a, int v) { if (!_soundOK) return; -#if 0 - if (_modCache[a].playing) { - alSourcef(modCache[a].playingOnSource, AL_GAIN, (float) _modLoudness * v / 256); + + if (g_sludge->_mixer->isSoundHandleActive(_modCache[a].handle)) { + _modCache[a].vol = v; + g_sludge->_mixer->setChannelVolume(_modCache[a].handle, _modLoudness * v / 256); } -#endif } void SoundManager::setDefaultMusicVolume(int v) { @@ -176,14 +150,11 @@ int SoundManager::findInSoundCache(int a) { void SoundManager::stopMOD(int i) { if (!_soundOK) return; -#if 0 - alGetError(); - if (modCache[i].playing) { - if (! alureStopSource(modCache[i].playingOnSource, AL_TRUE)) { - debugOut("Failed to stop source: %s\n", alureGetErrorString()); - } + + if (g_sludge->_mixer->isSoundHandleActive(_modCache[i].handle)) { + g_sludge->_mixer->stopHandle(_modCache[i].handle); } -#endif + _modCache[i].fileLoaded = -1; } void SoundManager::huntKillSound(int filenum) { @@ -191,15 +162,10 @@ void SoundManager::huntKillSound(int filenum) { return; int gotSlot = findInSoundCache(filenum); - if (gotSlot == -1) return; - - _silenceIKillYou = true; - - if (g_sludge->_mixer->isSoundHandleActive(_soundCache[gotSlot].handle)) { - g_sludge->_mixer->stopHandle(_soundCache[gotSlot].handle); - } + if (gotSlot == -1) + return; - _silenceIKillYou = false; + freeSound(gotSlot); } void SoundManager::freeSound(int a) { @@ -214,6 +180,8 @@ void SoundManager::freeSound(int a) { handleSoundLists(); } + _soundCache[a].inSoundList = false; + _soundCache[a].looping = false; _soundCache[a].fileLoaded = -1; _silenceIKillYou = false; @@ -233,69 +201,33 @@ void SoundManager::huntKillFreeSound(int filenum) { */ bool SoundManager::playMOD(int f, int a, int fromTrack) { #if 0 + if (!_soundOK) + return true; + stopMOD(a); + // load sound setResourceForFatal(f); - uint32 length = openFileFromNum(f); + uint length = g_sludge->_resMan->openFileFromNum(f); if (length == 0) { - finishAccess(); + g_sludge->_resMan->finishAccess(); setResourceForFatal(-1); return false; } - Common::SeekableReadStream *memImage = bigDataFile->readStream(length); - if (memImage->size() != length || bigDataFile->err()) + // make audio stream + Common::SeekableReadStream *readStream = g_sludge->_resMan->getData(); + Common::SeekableReadStream *memImage = readStream->readStream(length); + if (memImage->size() != (int)length || readStream->err()) debug("Sound reading failed"); Audio::AudioStream *stream = Audio::makeProtrackerStream(memImage); - //TODO: replace by xm file decoders + if (!stream) return false; // play sound - Audio::SoundHandle soundHandle; - g_sludge->_mixer->playStream(Audio::Mixer::kSFXSoundType, &soundHandle, + g_sludge->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_modCache[a].handle, stream, -1, Audio::Mixer::kMaxChannelVolume); - if (!_soundOK) - return true; - stopMOD(a); - - setResourceForFatal(f); - uint32 length = openFileFromNum(f); - if (length == 0) { - finishAccess(); - setResourceForFatal(-1); - return false; - } - - byte *memImage; - memImage = (byte *) loadEntireFileToMemory(bigDataFile, length); - if (! memImage) return fatal(ERROR_MUSIC_MEMORY_LOW); - - _modCache[a].stream = alureCreateStreamFromMemory(memImage, length, 19200, 0, NULL); - - delete memImage; - - if (_modCache[a].stream != NULL) { - setMusicVolume(a, defVol); - - if (! alureSetStreamOrder(modCache[a].stream, fromTrack)) { - debugOut("Failed to set stream order: %s\n", - alureGetErrorString()); - } - - playStream(a, true, true); - - } else { - - debugOut("Failed to create stream from MOD: %s\n", - alureGetErrorString()); - - warning(ERROR_MUSIC_ODDNESS); - _soundCache[a].stream = NULL; - _soundCache[a].playing = false; - _soundCache[a].playingOnSource = 0; - } - setResourceForFatal(-1); #endif return true; } @@ -363,20 +295,12 @@ int SoundManager::makeSoundAudioStream(int f, Audio::AudioStream *&audiostream, return -1; int a = findInSoundCache(f); - if (a != -1) { // if this sound has been loaded before - // still playing - if (g_sludge->_mixer->isSoundHandleActive(_soundCache[a].handle)) { - g_sludge->_mixer->stopHandle(_soundCache[a].handle); // stop it - if (_soundCache[a].inSoundList) { - handleSoundLists(); - } - } - } else { + if (a == -1) { if (f == -2) return -1; a = findEmptySoundSlot(); - freeSound(a); } + freeSound(a); setResourceForFatal(f); uint32 length = g_sludge->_resMan->openFileFromNum(f); @@ -398,6 +322,7 @@ int SoundManager::makeSoundAudioStream(int f, Audio::AudioStream *&audiostream, if (stream) { audiostream = Audio::makeLoopingAudioStream(stream, loopy ? 0 : 1); _soundCache[a].fileLoaded = f; + _soundCache[a].looping = loopy; setResourceForFatal(-1); } else { audiostream = nullptr; diff --git a/engines/sludge/sound.h b/engines/sludge/sound.h index cdd76b33cc..1e1a2a47e4 100644 --- a/engines/sludge/sound.h +++ b/engines/sludge/sound.h @@ -83,9 +83,9 @@ private: struct SoundThing { Audio::SoundHandle handle; - int fileLoaded, vol; //Used for sounds only. (sound saving/loading) - bool looping; //Used for sounds only. (sound saving/loading) - bool inSoundList; + int fileLoaded, vol; //Used for wav/ogg sounds only. (sound saving/loading) + bool looping; //Used for wav/ogg sounds only. (sound saving/loading) + bool inSoundList; //Used for wav/ogg sounds only }; typedef Common::List<SoundList *> SoundListHandles; @@ -97,9 +97,7 @@ private: bool _isHandlingSoundList; SoundThing *_soundCache; - #if 0 SoundThing *_modCache; - #endif int _defVol; int _defSoundVol; diff --git a/engines/sludge/sprites.cpp b/engines/sludge/sprites.cpp index 98d88a8337..c37c4a1905 100644 --- a/engines/sludge/sprites.cpp +++ b/engines/sludge/sprites.cpp @@ -271,6 +271,13 @@ bool GraphicsManager::loadSpriteBank(int fileNum, SpriteBank &loadhere, bool isF // pasteSpriteToBackDrop uses the colour specified by the setPasteColour (or setPasteColor) void GraphicsManager::pasteSpriteToBackDrop(int x1, int y1, Sprite &single, const SpritePalette &fontPal) { + // kill zBuffer + if (_zBuffer->originalNum >= 0 && _zBuffer->sprites) { + int num = _zBuffer->originalNum; + killZBuffer(); + _zBuffer->originalNum = num; + } + //TODO: shader: useLightTexture x1 -= single.xhot; y1 -= single.yhot; @@ -282,6 +289,13 @@ void GraphicsManager::pasteSpriteToBackDrop(int x1, int y1, Sprite &single, cons // burnSpriteToBackDrop adds text in the colour specified by setBurnColour // using the differing brightness levels of the font to achieve an anti-aliasing effect. void GraphicsManager::burnSpriteToBackDrop(int x1, int y1, Sprite &single, const SpritePalette &fontPal) { + // kill zBuffer + if (_zBuffer->originalNum >= 0 && _zBuffer->sprites) { + int num = _zBuffer->originalNum; + killZBuffer(); + _zBuffer->originalNum = num; + } + //TODO: shader: useLightTexture x1 -= single.xhot; y1 -= single.yhot - 1; diff --git a/engines/titanic/carry/mouth.cpp b/engines/titanic/carry/mouth.cpp index d750fc969e..1b2830b99e 100644 --- a/engines/titanic/carry/mouth.cpp +++ b/engines/titanic/carry/mouth.cpp @@ -74,6 +74,11 @@ bool CMouth::PETGainedObjectMsg(CPETGainedObjectMsg *msg) { _field13C = true; } + // WORKAROUND: If Mouth is removed from Titania after inserting, + // message the Titania control so it can be flagged as removed + CTakeHeadPieceMsg headpieceMsg(getName()); + headpieceMsg.execute("TitaniaControl"); + return true; } diff --git a/engines/titanic/game/bridge_view.cpp b/engines/titanic/game/bridge_view.cpp index e8d70c8c43..14361b4e8c 100644 --- a/engines/titanic/game/bridge_view.cpp +++ b/engines/titanic/game/bridge_view.cpp @@ -55,6 +55,7 @@ bool CBridgeView::ActMsg(CActMsg *msg) { } else if (msg->_action == "Go") { _action = BA_GO; setVisible(true); + hideMouse(); volumeMsg._volume = 100; volumeMsg.execute("EngineSounds"); onMsg.execute("EngineSounds"); @@ -67,10 +68,13 @@ bool CBridgeView::ActMsg(CActMsg *msg) { if (msg->_action == "Cruise") { _action = BA_CRUISE; setVisible(true); + hideMouse(); playMovie(MOVIE_NOTIFY_OBJECT); } else if (msg->_action == "GoEnd") { _action = BA_ENDING1; setVisible(true); + hideMouse(); + CChangeMusicMsg musicMsg; musicMsg._flags = 1; musicMsg.execute("BridgeAutoMusicPlayer"); @@ -90,6 +94,7 @@ bool CBridgeView::MovieEndMsg(CMovieEndMsg *msg) { case BA_GO: case BA_CRUISE: setVisible(false); + showMouse(); decTransitions(); break; diff --git a/engines/titanic/game/chicken_dispensor.cpp b/engines/titanic/game/chicken_dispensor.cpp index 89873dcc4d..d44bc7157b 100644 --- a/engines/titanic/game/chicken_dispensor.cpp +++ b/engines/titanic/game/chicken_dispensor.cpp @@ -104,7 +104,7 @@ bool CChickenDispensor::StatusChangeMsg(CStatusChangeMsg *msg) { } bool CChickenDispensor::MovieEndMsg(CMovieEndMsg *msg) { - int movieFrame = getMovieFrame(); + int movieFrame = msg->_endFrame; if (movieFrame == 16) { // Dispensed a chicken @@ -113,12 +113,7 @@ bool CChickenDispensor::MovieEndMsg(CMovieEndMsg *msg) { CActMsg actMsg("Dispense Chicken"); actMsg.execute("Chicken"); - if (_dispenseMode == DISPENSE_HOT) { - // A properly hot chicken is dispensed, no further ones will be - // until the current one is used up, and the fuse in Titania's - // fusebox is removed and replaced - _dispenseMode = DISPENSE_NONE; - } else { + if (_dispenseMode != DISPENSE_HOT) { // WORKAROUND: If the fuse for the dispensor is removed in Titania's fusebox, // make the dispensed chicken already cold CChicken::_temperature = 0; diff --git a/engines/titanic/game/fan_control.cpp b/engines/titanic/game/fan_control.cpp index 7ed22fd560..fc99bd8b36 100644 --- a/engines/titanic/game/fan_control.cpp +++ b/engines/titanic/game/fan_control.cpp @@ -107,7 +107,7 @@ bool CFanControl::StatusChangeMsg(CStatusChangeMsg *msg) { case 2: // Fan Speed button if (_fanOn) { - _state = (_state + 1) % 4; + _state = (_state + 1) % 3; switch (_state) { case 0: playMovie(18, 24, 0); diff --git a/engines/titanic/game_manager.cpp b/engines/titanic/game_manager.cpp index 13fe1d2872..65a2a278c8 100644 --- a/engines/titanic/game_manager.cpp +++ b/engines/titanic/game_manager.cpp @@ -81,8 +81,8 @@ void CGameManager::preLoad() { _timers.destroyContents(); _soundMaker = nullptr; - _trueTalkManager.preLoad(); _sound.preLoad(); + _trueTalkManager.preLoad(); } void CGameManager::postLoad(CProjectItem *project) { diff --git a/engines/titanic/main_game_window.cpp b/engines/titanic/main_game_window.cpp index 053712d412..cfea98cdf1 100644 --- a/engines/titanic/main_game_window.cpp +++ b/engines/titanic/main_game_window.cpp @@ -341,6 +341,12 @@ void CMainGameWindow::keyDown(Common::KeyState keyState) { _gameManager->_gameState.changeView(newView, nullptr); } + } else if (keyState.keycode == Common::KEYCODE_F5) { + // Show the GMM save dialog + g_vm->showScummVMSaveDialog(); + } else if (keyState.keycode == Common::KEYCODE_F7) { + // Show the GMM load dialog + g_vm->showScummVMRestoreDialog(); } else if (_inputAllowed) { _gameManager->_inputTranslator.keyDown(keyState); } diff --git a/engines/titanic/npcs/titania.cpp b/engines/titanic/npcs/titania.cpp index 70ca4bace6..d3e3395fc8 100644 --- a/engines/titanic/npcs/titania.cpp +++ b/engines/titanic/npcs/titania.cpp @@ -149,9 +149,10 @@ bool CTitania::ActMsg(CActMsg *msg) { playSound("z#47.wav", 100); changeView("Titania.Node 7.S", ""); + // Re-enable control, and reset bomb's volume back to normal 60% petShow(); enableMouse(); - CSetFrameMsg frameMsg; + CSetFrameMsg frameMsg(60); frameMsg.execute("Bomb"); } else if (msg->_action == "CheckHead") { @@ -173,8 +174,9 @@ bool CTitania::ActMsg(CActMsg *msg) { workingMsg3._value = _speechCentre ? "Working" : "Random"; } - if (_centralCore && _eye1 && _eye2 && _ear1 && _ear2 && _nose && _mouth - && _speechCentre && _olfactoryCentre && _auditoryCentre) { + if (_centralCore && _eye1 && _eye2 && _ear1 && _ear2 && _nose + && _mouth && _visionCentre && _speechCentre + && _olfactoryCentre && _auditoryCentre) { CProximity prox(Audio::Mixer::kSpeechSoundType); playSound("z#47.wav", prox); @@ -203,11 +205,14 @@ bool CTitania::EnterViewMsg(CEnterViewMsg *msg) { disableMouse(); petHide(); + // The Bomb uses the CSetFrameMsg as a hack for setting the volume. + // In case it's currently active, set it to a quieter 25% so that + // it won't obscure Titania's speech. CSetFrameMsg frameMsg; frameMsg._frameNumber = 25; frameMsg.execute("Bomb"); - playCutscene(0, 52); + playCutscene(0, 52); setVisible(false); CActMsg actMsg("TitaniaSpeech"); actMsg.execute("TitaniaSpeech"); diff --git a/engines/titanic/sound/qmixer.cpp b/engines/titanic/sound/qmixer.cpp index 5c511c3cae..beb1502ab4 100644 --- a/engines/titanic/sound/qmixer.cpp +++ b/engines/titanic/sound/qmixer.cpp @@ -208,18 +208,13 @@ void QMixer::qsWaveMixPump() { if (!channel._sounds.empty()) { SoundEntry &sound = channel._sounds.front(); if (sound._started && !_mixer->isSoundHandleActive(sound._soundHandle)) { - if (sound._loops == -1 || sound._loops-- > 0) { - // Need to loop (replay) the sound again - sound._soundHandle = sound._waveFile->play(channel.getRawVolume()); - } else { - // Sound is finished - if (sound._callback) - // Call the callback to signal end - sound._callback(iChannel, sound._waveFile, sound._userData); - - // Remove sound record from channel - channel._sounds.erase(channel._sounds.begin()); - } + // Sound is finished + if (sound._callback) + // Call the callback to signal end + sound._callback(iChannel, sound._waveFile, sound._userData); + + // Remove sound record from channel + channel._sounds.erase(channel._sounds.begin()); } } @@ -232,7 +227,8 @@ void QMixer::qsWaveMixPump() { channel._distance = 0.0; // Play the wave - sound._soundHandle = sound._waveFile->play(channel.getRawVolume()); + sound._soundHandle = sound._waveFile->play( + sound._loops, channel.getRawVolume()); sound._started = true; } } diff --git a/engines/titanic/sound/sound_manager.cpp b/engines/titanic/sound/sound_manager.cpp index 514618783b..4b5887b1e7 100644 --- a/engines/titanic/sound/sound_manager.cpp +++ b/engines/titanic/sound/sound_manager.cpp @@ -288,7 +288,7 @@ void QSoundManager::setVolume(int handle, uint volume, uint seconds) { _channelsVolume[slot._channel] = volume; updateVolume(slot._channel, seconds * 1000); - if (volume) { + if (!volume) { uint ticks = g_vm->_events->getTicksCount() + seconds * 1000; if (!slot._ticks || ticks >= slot._ticks) slot._ticks = ticks; diff --git a/engines/titanic/sound/wave_file.cpp b/engines/titanic/sound/wave_file.cpp index 8a4755ac97..c1aab42a7f 100644 --- a/engines/titanic/sound/wave_file.cpp +++ b/engines/titanic/sound/wave_file.cpp @@ -204,10 +204,15 @@ void CWaveFile::unlock(const int16 *ptr) { // No implementation needed in ScummVM } -Audio::SoundHandle CWaveFile::play(byte volume) { - Audio::SeekableAudioStream *stream = createAudioStream(); +Audio::SoundHandle CWaveFile::play(int numLoops, byte volume) { + Audio::SeekableAudioStream *audioStream = createAudioStream(); Audio::SoundHandle handle; + Audio::AudioStream *stream = audioStream; + if (numLoops != 0) + stream = new Audio::LoopingAudioStream(audioStream, + (numLoops == -1) ? 0 : numLoops); + _mixer->playStream(_soundType, &handle, stream, -1, volume, 0, DisposeAfterUse::NO); return handle; diff --git a/engines/titanic/sound/wave_file.h b/engines/titanic/sound/wave_file.h index 17c7b62f4b..c14891e2e4 100644 --- a/engines/titanic/sound/wave_file.h +++ b/engines/titanic/sound/wave_file.h @@ -126,8 +126,12 @@ public: /** * Plays the wave file + * @param numLoops Number of times to loop. 0 for none, + * -1 for infinite, and >0 for specified number of times + * @param volume Volume to play at + * @returns Audio handle for started sound */ - Audio::SoundHandle play(byte volume); + Audio::SoundHandle play(int numLoops, byte volume); }; } // End of namespace Titanic diff --git a/engines/titanic/support/credit_text.cpp b/engines/titanic/support/credit_text.cpp index 98c3d9bf1d..6ee17a2b95 100644 --- a/engines/titanic/support/credit_text.cpp +++ b/engines/titanic/support/credit_text.cpp @@ -96,7 +96,7 @@ void CCreditText::setup() { _screenManagerP->setFontNumber(oldFontNumber); _groupIt = _groups.begin(); _lineIt = (*_groupIt)->_lines.begin(); - _yOffset = _objectP->getBounds().height() + _fontHeight * 2; + _yOffset = _objectP->_bounds.height() + _fontHeight * 2; } CString CCreditText::readLine(Common::SeekableReadStream *stream) { diff --git a/engines/titanic/titanic.cpp b/engines/titanic/titanic.cpp index 8a1b00c0fc..b6ee868877 100644 --- a/engines/titanic/titanic.cpp +++ b/engines/titanic/titanic.cpp @@ -25,9 +25,11 @@ #include "common/config-manager.h" #include "common/debug-channels.h" #include "common/events.h" +#include "common/translation.h" #include "engines/util.h" #include "graphics/scaler.h" #include "graphics/thumbnail.h" +#include "gui/saveload.h" #include "titanic/titanic.h" #include "titanic/debugger.h" #include "titanic/carry/hose.h" @@ -179,23 +181,30 @@ bool TitanicEngine::canLoadGameStateCurrently() { CGameManager *gameManager = _window->_gameManager; CScreenManager *screenMan = CScreenManager::_screenManagerPtr; - if (!_window->_inputAllowed || !gameManager->_gameState._petActive) + if (!_window->_inputAllowed) return false; if (screenMan && screenMan->_inputHandler->isLocked()) return false; CProjectItem *project = gameManager->_project; if (project) { - CPetControl *pet = project->getPetControl(); - if (pet && !pet->isAreaUnlocked()) - return false; + if (gameManager->_gameState._petActive) { + CPetControl *pet = project->getPetControl(); + if (pet && !pet->isAreaUnlocked()) + return false; + } + } else { + return false; } return true; } bool TitanicEngine::canSaveGameStateCurrently() { - return canLoadGameStateCurrently(); + CGameManager *gameManager = _window->_gameManager; + + return gameManager->_gameState._petActive && + canLoadGameStateCurrently(); } Common::Error TitanicEngine::loadGameState(int slot) { @@ -251,4 +260,47 @@ void TitanicEngine::GUIError(const char *msg, ...) { GUIErrorMessage(buffer); } + +void TitanicEngine::showScummVMSaveDialog() { + if (!canSaveGameStateCurrently()) + return; + + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); + + pauseEngine(true); + int slot = dialog->runModalWithCurrentTarget(); + pauseEngine(false); + + if (slot >= 0) { + Common::String desc = dialog->getResultString(); + + if (desc.empty()) { + // create our own description for the saved game, the user didn't enter it + desc = dialog->createDefaultSaveDescription(slot); + } + + // Save the game + saveGameState(slot, desc); + } + + delete dialog; +} + +void TitanicEngine::showScummVMRestoreDialog() { + if (!canLoadGameStateCurrently()) + return; + + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); + + pauseEngine(true); + int slot = dialog->runModalWithCurrentTarget(); + pauseEngine(false); + + if (slot >= 0) { + loadGameState(slot); + } + + delete dialog; +} + } // End of namespace Titanic diff --git a/engines/titanic/titanic.h b/engines/titanic/titanic.h index dc7fd156b8..0c15cf3e72 100644 --- a/engines/titanic/titanic.h +++ b/engines/titanic/titanic.h @@ -191,6 +191,16 @@ public: * Displays an error message in a GUI dialog */ void GUIError(const char *msg, ...) GCC_PRINTF(2, 3); + + /** + * Shows the ScummVM GMM save dialog + */ + void showScummVMSaveDialog(); + + /** + * Shows the ScummVM GMM load dialog + */ + void showScummVMRestoreDialog(); }; extern TitanicEngine *g_vm; diff --git a/engines/wage/detection_tables.h b/engines/wage/detection_tables.h index b207946882..bde10785df 100644 --- a/engines/wage/detection_tables.h +++ b/engines/wage/detection_tables.h @@ -158,7 +158,6 @@ static const ADGameDescription gameDescriptions[] = { FANGAME("Star Trek", "3067332e6f0bb0314579f9bf102e1b56", 53320), FANGAME("Strange Disappearance", "9d6e41b61c0fc90400e5da2fcb653a4a", 772282), FANGAME("The Sultan's Palace", "fde31cbcc77b66969b4cfcd43075341e", 456855), - // Code 0x03 in text FANGAME("Swamp Witch", "bd8c8394be31f7845d55785b7ccfbbde", 739781), // Original file name "Swamp Witch†" FANGAME("Swamp Witch", "07463c8b3b908b0c493a41b949ac1ff5", 740131), // alt version, normal file name FANGAME("Sweetspace Now!", "574dc7dd25543f7a516d6524f0c5ab33", 123813), // Comes with Jumble diff --git a/engines/wage/script.cpp b/engines/wage/script.cpp index c4cf23fcb1..3405c8bf47 100644 --- a/engines/wage/script.cpp +++ b/engines/wage/script.cpp @@ -1161,12 +1161,19 @@ void Script::convertToText() { break; if (c < 0x80) { - if (c < 0x20) - error("convertToText: Unknown code 0x%02x at %d", c, _data->pos()); + if (c < 0x20) { + warning("convertToText: Unknown code 0x%02x at %d", c, _data->pos()); + c = ' '; + } do { scr->line += c; c = _data->readByte(); + + if (c < 0x20) { + warning("convertToText: Unknown code 0x%02x at %d", c, _data->pos()); + c = ' '; + } } while (c < 0x80); _data->seek(-1, SEEK_CUR); |