diff options
author | Alejandro Marzini | 2010-07-13 04:31:15 +0000 |
---|---|---|
committer | Alejandro Marzini | 2010-07-13 04:31:15 +0000 |
commit | 609e08d5dbae3179eddf981abe73d69009432de4 (patch) | |
tree | cddbd0a0e69eaa53b85f98f96dc410a307773f08 /engines/saga | |
parent | 8b6a670391f1b5103e3761d78eef8f41d64cf8cd (diff) | |
parent | 03c0faa5d76f547603ee6389cdf958e2a6f0f43d (diff) | |
download | scummvm-rg350-609e08d5dbae3179eddf981abe73d69009432de4.tar.gz scummvm-rg350-609e08d5dbae3179eddf981abe73d69009432de4.tar.bz2 scummvm-rg350-609e08d5dbae3179eddf981abe73d69009432de4.zip |
Merged from trunk, from Rev 49499 to HEAD
svn-id: r50840
Diffstat (limited to 'engines/saga')
-rw-r--r-- | engines/saga/actor.cpp | 4 | ||||
-rw-r--r-- | engines/saga/console.cpp | 3 | ||||
-rw-r--r-- | engines/saga/detection.cpp | 6 | ||||
-rw-r--r-- | engines/saga/events.cpp | 1 | ||||
-rw-r--r-- | engines/saga/font.h | 2 | ||||
-rw-r--r-- | engines/saga/interface.cpp | 9 | ||||
-rw-r--r-- | engines/saga/music.cpp | 274 | ||||
-rw-r--r-- | engines/saga/music.h | 52 | ||||
-rw-r--r-- | engines/saga/puzzle.cpp | 10 | ||||
-rw-r--r-- | engines/saga/render.cpp | 6 | ||||
-rw-r--r-- | engines/saga/saga.cpp | 18 | ||||
-rw-r--r-- | engines/saga/saga.h | 1 | ||||
-rw-r--r-- | engines/saga/scene.cpp | 12 | ||||
-rw-r--r-- | engines/saga/script.h | 3 | ||||
-rw-r--r-- | engines/saga/sfuncs.cpp | 19 | ||||
-rw-r--r-- | engines/saga/sfuncs_ihnm.cpp | 12 | ||||
-rw-r--r-- | engines/saga/sndres.cpp | 2 | ||||
-rw-r--r-- | engines/saga/sound.cpp | 13 | ||||
-rw-r--r-- | engines/saga/sound.h | 3 | ||||
-rw-r--r-- | engines/saga/sthread.cpp | 8 |
20 files changed, 210 insertions, 248 deletions
diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp index c3f5fec83a..8bc8025032 100644 --- a/engines/saga/actor.cpp +++ b/engines/saga/actor.cpp @@ -1173,7 +1173,9 @@ void Actor::drawActors() { return; } - if (_vm->_anim->hasCutaway()) { + // WORKAROUND + // Bug #2928923: 'ITE: Graphic Glitches during racoon death "Cut Scene"' + if (_vm->_anim->hasCutaway() || _vm->_scene->currentSceneNumber() == 287 || _vm->_scene->currentSceneNumber() == 286) { drawSpeech(); return; } diff --git a/engines/saga/console.cpp b/engines/saga/console.cpp index 2c201ac57d..228febfe9c 100644 --- a/engines/saga/console.cpp +++ b/engines/saga/console.cpp @@ -40,9 +40,6 @@ Console::Console(SagaEngine *vm) : GUI::Debugger() { DCmd_Register("continue", WRAP_METHOD(Console, Cmd_Exit)); - // CVAR_Register_I(&_soundEnabled, "sound", NULL, CVAR_CFG, 0, 1); - // CVAR_Register_I(&_musicEnabled, "music", NULL, CVAR_CFG, 0, 1); - // Actor commands DCmd_Register("actor_walk_to", WRAP_METHOD(Console, cmdActorWalkTo)); diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index 1c2c6bacff..7913291527 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -122,7 +122,11 @@ static const ADParams detectionParams = { // Flags 0, // Additional GUI options (for every game} - Common::GUIO_NONE + Common::GUIO_NONE, + // Maximum directory depth + 1, + // List of directory globs + 0 }; class SagaMetaEngine : public AdvancedMetaEngine { diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp index d15f0b2af3..1f4091d07c 100644 --- a/engines/saga/events.cpp +++ b/engines/saga/events.cpp @@ -306,7 +306,6 @@ int Events::handleOneShot(Event *event) { _vm->_sndRes->playVoice(event->param); break; case kMusicEvent: - _vm->_music->stop(); if (event->op == kEventPlay) _vm->_music->play(event->param, (MusicFlags)event->param2); break; diff --git a/engines/saga/font.h b/engines/saga/font.h index f290384e87..d8b1da30b9 100644 --- a/engines/saga/font.h +++ b/engines/saga/font.h @@ -190,7 +190,7 @@ class Font { } } bool valid(FontId fontId) { - return ((fontId >= 0) && (fontId < _loadedFonts)); + return (fontId < _loadedFonts); } int getByteLen(int numBits) const { int byteLength = numBits / 8; diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index c0d3cee465..c4b4688785 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -544,8 +544,10 @@ bool Interface::processAscii(Common::KeyState keystate) { return true; } +#ifdef ENABLE_IHNM if (_vm->_scene->isNonInteractiveIHNMDemoPart()) _vm->_scene->showIHNMDemoSpecialScreen(); +#endif break; case kPanelCutaway: if (keystate.keycode == Common::KEYCODE_ESCAPE) { @@ -555,8 +557,10 @@ bool Interface::processAscii(Common::KeyState keystate) { return true; } +#ifdef ENABLE_INHM if (_vm->_scene->isNonInteractiveIHNMDemoPart()) _vm->_scene->showIHNMDemoSpecialScreen(); +#endif break; case kPanelVideo: if (keystate.keycode == Common::KEYCODE_ESCAPE) { @@ -570,8 +574,10 @@ bool Interface::processAscii(Common::KeyState keystate) { return true; } +#ifdef ENABLE_IHNM if (_vm->_scene->isNonInteractiveIHNMDemoPart()) _vm->_scene->showIHNMDemoSpecialScreen(); +#endif break; case kPanelOption: // TODO: check input dialog keys @@ -1855,6 +1861,7 @@ void Interface::update(const Point& mousePoint, int updateFlag) { if (updateFlag & UPDATE_MOUSECLICK) { if (!_vm->isIHNMDemo()) { _vm->_scene->clearPsychicProfile(); + _vm->_script->wakeUpThreads(kWaitTypeDelay); } else { setMode(kPanelConverse); _vm->_scene->_textList.clear(); @@ -1866,8 +1873,10 @@ void Interface::update(const Point& mousePoint, int updateFlag) { break; case kPanelNull: +#ifdef ENABLE_IHNM if (_vm->_scene->isNonInteractiveIHNMDemoPart() && (updateFlag & UPDATE_MOUSECLICK)) _vm->_scene->showIHNMDemoSpecialScreen(); +#endif break; } diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 75c5cdffd7..8b7654d689 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -42,19 +42,25 @@ namespace Saga { #define BUFFER_SIZE 4096 #define MUSIC_SUNSPOT 26 -MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false), _passThrough(false), _isGM(false) { +MusicDriver::MusicDriver() : _isGM(false) { memset(_channel, 0, sizeof(_channel)); _masterVolume = 0; + _nativeMT32 = ConfMan.getBool("native_mt32"); + + MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM); + _driver = MidiDriver::createMidi(dev); + if (isMT32()) + _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + this->open(); } -MusicPlayer::~MusicPlayer() { - _driver->setTimerCallback(NULL, NULL); - stopMusic(); +MusicDriver::~MusicDriver() { this->close(); + delete _driver; } -void MusicPlayer::setVolume(int volume) { +void MusicDriver::setVolume(int volume) { volume = CLIP(volume, 0, 255); if (_masterVolume == volume) @@ -71,32 +77,7 @@ void MusicPlayer::setVolume(int volume) { } } -int MusicPlayer::open() { - // Don't ever call open without first setting the output driver! - if (!_driver) - return 255; - - int ret = _driver->open(); - if (ret) - return ret; - - _driver->setTimerCallback(this, &onTimer); - return 0; -} - -void MusicPlayer::close() { - stopMusic(); - if (_driver) - _driver->close(); - _driver = 0; -} - -void MusicPlayer::send(uint32 b) { - if (_passThrough) { - _driver->send(b); - return; - } - +void MusicDriver::send(uint32 b) { byte channel = (byte)(b & 0x0F); if ((b & 0xFFF0) == 0x07B0) { // Adjust volume changes by master volume @@ -104,71 +85,86 @@ void MusicPlayer::send(uint32 b) { _channelVolume[channel] = volume; volume = volume * _masterVolume / 255; b = (b & 0xFF00FFFF) | (volume << 16); - } else if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) { + } else if ((b & 0xF0) == 0xC0 && !_isGM && !isMT32()) { + // Remap MT32 instruments to General Midi b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8; - } - else if ((b & 0xFFF0) == 0x007BB0) { - //Only respond to All Notes Off if this channel - //has currently been allocated - if (_channel[b & 0x0F]) + } else if ((b & 0xFFF0) == 0x007BB0) { + // Only respond to All Notes Off if this channel + // has currently been allocated + if (!_channel[channel]) return; } if (!_channel[channel]) _channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); - - if (_channel[channel]) + else _channel[channel]->send(b); } -void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) { - // FIXME: The "elkfanfare" is played much too quickly. There are some - // meta events that we don't handle. Perhaps there is a - // connection...? - - switch (type) { - case 0x2F: // End of Track - if (_looping) - _parser->jumpToTick(0); - else - stopMusic(); - break; - default: - //warning("Unhandled meta event: %02x", type); - break; - } -} - -void MusicPlayer::onTimer(void *refCon) { - MusicPlayer *music = (MusicPlayer *)refCon; - Common::StackLock lock(music->_mutex); - - if (music->_isPlaying) - music->_parser->onTimer(); -} - -void MusicPlayer::playMusic() { - _isPlaying = true; -} +Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { + _currentVolume = 0; + _driver = new MusicDriver(); -void MusicPlayer::stopMusic() { - Common::StackLock lock(_mutex); + _digitalMusicContext = _vm->_resource->getContext(GAME_DIGITALMUSICFILE); + if (!_driver->isAdlib()) + _musicContext = _vm->_resource->getContext(GAME_MUSICFILE_GM); + else + _musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM); - _isPlaying = false; - if (_parser) { - _parser->unloadMusic(); - _parser = NULL; + if (!_musicContext) { + if (_vm->getGameId() == GID_ITE) { + _musicContext = _vm->_resource->getContext(GAME_RESOURCEFILE); + } else { + // I've listened to music from both the FM and the GM + // file, and I've tentatively reached the conclusion + // that they are both General MIDI. My guess is that + // the FM file has been reorchestrated to sound better + // on AdLib and other FM synths. + // + // Sev says the AdLib music does not sound like in the + // original, but I still think assuming General MIDI is + // the right thing to do. Some music, like the End + // Title (song 0) sound absolutely atrocious when piped + // through our MT-32 to GM mapping. + // + // It is, however, quite possible that the original + // used a different GM to FM mapping. If the original + // sounded markedly better, perhaps we should add some + // way of replacing our stock mapping in adlib.cpp? + // + // For the composer's own recording of the End Title, + // see http://www.johnottman.com/ + + // Oddly enough, the intro music (song 1) is very + // different in the two files. I have no idea why. + // Note that the IHNM demo has only got one music file + // (music.rsc). It is assumed that it contains FM music + _musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM); + } } -} -Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver) : _vm(vm), _mixer(mixer), _adlib(false) { - _player = new MusicPlayer(driver); - _currentVolume = 0; - - xmidiParser = MidiParser::createParser_XMIDI(); - smfParser = MidiParser::createParser_SMF(); + // Check if the game is using XMIDI or SMF music + if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { + // Just set an XMIDI parser for Mac IHNM for now + _parser = MidiParser::createParser_XMIDI(); + } else { + byte *resourceData; + size_t resourceSize; + int resourceId = (_vm->getGameId() == GID_ITE ? 9 : 0); + _vm->_resource->loadResource(_musicContext, resourceId, resourceData, resourceSize); + if (!memcmp(resourceData, "FORM", 4)) { + _parser = MidiParser::createParser_XMIDI(); + // ITE had MT32 mapped instruments + _driver->setGM(_vm->getGameId() != GID_ITE); + } else { + _parser = MidiParser::createParser_SMF(); + } + free(resourceData); + } - _digitalMusicContext = _vm->_resource->getContext(GAME_DIGITALMUSICFILE); + _parser->setMidiDriver(_driver); + _parser->setTimerRate(_driver->getBaseTempo()); + _parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); _songTableLen = 0; _songTable = 0; @@ -180,11 +176,11 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver) : _vm(vm), Music::~Music() { _vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback); _mixer->stopHandle(_musicHandle); - delete _player; - xmidiParser->setMidiDriver(NULL); - smfParser->setMidiDriver(NULL); - delete xmidiParser; - delete smfParser; + _driver->setTimerCallback(NULL, NULL); + _driver->close(); + delete _driver; + _parser->setMidiDriver(NULL); + delete _parser; free(_songTable); free(_midiMusicData); @@ -194,6 +190,12 @@ void Music::musicVolumeGaugeCallback(void *refCon) { ((Music *)refCon)->musicVolumeGauge(); } +void Music::onTimer(void *refCon) { + Music *music = (Music *)refCon; + Common::StackLock lock(music->_driver->_mutex); + music->_parser->onTimer(); +} + void Music::musicVolumeGauge() { int volume; @@ -209,7 +211,7 @@ void Music::musicVolumeGauge() { volume = 1; _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); - _player->setVolume(volume); + _driver->setVolume(volume); if (_currentVolumePercent == 100) { _vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback); @@ -226,23 +228,21 @@ void Music::setVolume(int volume, int time) { if (time == 1) { _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); - _player->setVolume(volume); + _driver->setVolume(volume); _vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback); _currentVolume = volume; return; } - _vm->getTimerManager()->installTimerProc(&musicVolumeGaugeCallback, time * 100L, this); + _vm->getTimerManager()->installTimerProc(&musicVolumeGaugeCallback, time * 3000L, this); } bool Music::isPlaying() { - return _mixer->isSoundHandleActive(_musicHandle) || _player->isPlaying(); + return _mixer->isSoundHandleActive(_musicHandle) || _parser->isPlaying(); } void Music::play(uint32 resourceId, MusicFlags flags) { Audio::SeekableAudioStream *audioStream = NULL; - MidiParser *parser; - ResourceContext *context = NULL; byte *resourceData; size_t resourceSize; uint32 loopStart; @@ -254,8 +254,8 @@ void Music::play(uint32 resourceId, MusicFlags flags) { } _trackNumber = resourceId; - _player->stopMusic(); _mixer->stopHandle(_musicHandle); + _parser->unloadMusic(); int realTrackNumber; @@ -356,55 +356,10 @@ void Music::play(uint32 resourceId, MusicFlags flags) { return; } - if (flags == MUSIC_DEFAULT) { + if (flags == MUSIC_DEFAULT) flags = MUSIC_NORMAL; - } // Load MIDI/XMI resource data - - if (_vm->getGameId() == GID_ITE) { - context = _vm->_resource->getContext(GAME_MUSICFILE_GM); - if (context == NULL) { - context = _vm->_resource->getContext(GAME_RESOURCEFILE); - } - } else if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { - // The music of the Mac version of IHNM is loaded from its - // associated external file later on - } else { - // I've listened to music from both the FM and the GM - // file, and I've tentatively reached the conclusion - // that they are both General MIDI. My guess is that - // the FM file has been reorchestrated to sound better - // on AdLib and other FM synths. - // - // Sev says the AdLib music does not sound like in the - // original, but I still think assuming General MIDI is - // the right thing to do. Some music, like the End - // Title (song 0) sound absolutely atrocious when piped - // through our MT-32 to GM mapping. - // - // It is, however, quite possible that the original - // used a different GM to FM mapping. If the original - // sounded markedly better, perhaps we should add some - // way of replacing our stock mapping in adlib.cpp? - // - // For the composer's own recording of the End Title, - // see http://www.johnottman.com/ - - // Oddly enough, the intro music (song 1) is very - // different in the two files. I have no idea why. - // Note that the IHNM demo has only got one music file - // (music.rsc). It is assumed that it contains FM music - - if (hasAdLib() || _vm->isIHNMDemo()) { - context = _vm->_resource->getContext(GAME_MUSICFILE_FM); - } else { - context = _vm->_resource->getContext(GAME_MUSICFILE_GM); - } - } - - _player->setGM(true); - if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { // Load the external music file for Mac IHNM #if 0 @@ -422,56 +377,39 @@ void Music::play(uint32 resourceId, MusicFlags flags) { #endif return; } else { - _vm->_resource->loadResource(context, resourceId, resourceData, resourceSize); + _vm->_resource->loadResource(_musicContext, resourceId, resourceData, resourceSize); } if (resourceSize < 4) { error("Music::play() wrong music resource size"); } - if (xmidiParser->loadMusic(resourceData, resourceSize)) { - if (_vm->getGameId() == GID_ITE) - _player->setGM(false); + if (!_parser->loadMusic(resourceData, resourceSize)) + error("Music::play() wrong music resource"); - parser = xmidiParser; - } else { - if (smfParser->loadMusic(resourceData, resourceSize)) { - parser = smfParser; - } else { - error("Music::play() wrong music resource"); - } - } - - parser->setTrack(0); - parser->setMidiDriver(_player); - parser->setTimerRate(_player->getBaseTempo()); - parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + _parser->setTrack(0); + _driver->setTimerCallback(this, &onTimer); - _player->_parser = parser; setVolume(_vm->_musicVolume); - if (flags & MUSIC_LOOP) - _player->setLoop(true); - else - _player->setLoop(false); + // Handle music looping + _parser->property(MidiParser::mpAutoLoop, (flags & MUSIC_LOOP) ? 1 : 0); - _player->playMusic(); free(_midiMusicData); _midiMusicData = resourceData; } void Music::pause() { - _player->setVolume(-1); - _player->setPlaying(false); + _driver->setTimerCallback(NULL, NULL); } void Music::resume() { - _player->setVolume(_vm->_musicVolume); - _player->setPlaying(true); + _driver->setTimerCallback(this, &onTimer); } void Music::stop() { - _player->stopMusic(); + _driver->setTimerCallback(NULL, NULL); + _parser->unloadMusic(); } } // End of namespace Saga diff --git a/engines/saga/music.h b/engines/saga/music.h index 131078a9c3..f3b0f177b0 100644 --- a/engines/saga/music.h +++ b/engines/saga/music.h @@ -44,41 +44,32 @@ enum MusicFlags { MUSIC_DEFAULT = 0xffff }; -class MusicPlayer : public MidiDriver { +class MusicDriver : public MidiDriver { public: - MusicPlayer(MidiDriver *driver); - ~MusicPlayer(); - - bool isPlaying() { return _isPlaying; } - void setPlaying(bool playing) { _isPlaying = playing; } + MusicDriver(); + ~MusicDriver(); void setVolume(int volume); int getVolume() { return _masterVolume; } - void setNativeMT32(bool b) { _nativeMT32 = b; } - bool hasNativeMT32() { return _nativeMT32; } - void playMusic(); - void stopMusic(); - void setLoop(bool loop) { _looping = loop; } - void setPassThrough(bool b) { _passThrough = b; } - + bool isAdlib() { return _driverType == MT_ADLIB; } + bool isMT32() { return _driverType == MT_MT32 || _nativeMT32; } void setGM(bool isGM) { _isGM = isGM; } //MidiDriver interface implementation - int open(); - void close(); + int open() { return _driver->open(); } + void close() { _driver->close(); } void send(uint32 b); - void metaEvent(byte type, byte *data, uint16 length); + void metaEvent(byte type, byte *data, uint16 length) {} - void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { } - uint32 getBaseTempo() { return _driver ? _driver->getBaseTempo() : 0; } + void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { _driver->setTimerCallback(timerParam, timerProc); } + uint32 getBaseTempo() { return _driver->getBaseTempo(); } //Channel allocation functions MidiChannel *allocateChannel() { return 0; } MidiChannel *getPercussionChannel() { return 0; } - MidiParser *_parser; Common::Mutex _mutex; protected: @@ -87,14 +78,11 @@ protected: MidiChannel *_channel[16]; MidiDriver *_driver; + MusicType _driverType; byte _channelVolume[16]; - bool _nativeMT32; bool _isGM; - bool _passThrough; + bool _nativeMT32; - bool _isPlaying; - bool _looping; - bool _randomLoop; byte _masterVolume; byte *_musicData; @@ -105,13 +93,8 @@ protected: class Music { public: - Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver); + Music(SagaEngine *vm, Audio::Mixer *mixer); ~Music(); - void setNativeMT32(bool b) { _player->setNativeMT32(b); } - bool hasNativeMT32() { return _player->hasNativeMT32(); } - void setAdLib(bool b) { _adlib = b; } - bool hasAdLib() { return _adlib; } - void setPassThrough(bool b) { _player->setPassThrough(b); } bool isPlaying(); bool hasDigitalMusic() { return _digitalMusic; } @@ -130,24 +113,23 @@ private: SagaEngine *_vm; Audio::Mixer *_mixer; - MusicPlayer *_player; + MusicDriver *_driver; Audio::SoundHandle _musicHandle; uint32 _trackNumber; - bool _adlib; - int _targetVolume; int _currentVolume; int _currentVolumePercent; bool _digitalMusic; + ResourceContext *_musicContext; ResourceContext *_digitalMusicContext; - MidiParser *xmidiParser; - MidiParser *smfParser; + MidiParser *_parser; byte *_midiMusicData; static void musicVolumeGaugeCallback(void *refCon); + static void onTimer(void *refCon); void musicVolumeGauge(); }; diff --git a/engines/saga/puzzle.cpp b/engines/saga/puzzle.cpp index 957ab3c8b6..5b13473d77 100644 --- a/engines/saga/puzzle.cpp +++ b/engines/saga/puzzle.cpp @@ -411,12 +411,12 @@ void Puzzle::solicitHint() { switch (_hintRqState) { case kRQSpeaking: if (_vm->_actor->isSpeaking()) { - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50000, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50 * 1000000, this); break; } _hintRqState = _hintNextRqState; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 333333, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 100*1000000/3, this); break; case kRQNoHint: @@ -439,11 +439,11 @@ void Puzzle::solicitHint() { // Roll to see if Sakka scolds if (_vm->_rnd.getRandomNumber(1)) { _hintRqState = kRQSakkaDenies; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 200000, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 200*1000000, this); } else { _hintRqState = kRQSpeaking; _hintNextRqState = kRQHintRequested; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50000, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50*1000000, this); } break; @@ -456,7 +456,7 @@ void Puzzle::solicitHint() { _hintRqState = kRQSpeaking; _hintNextRqState = kRQHintRequestedStage2; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50000, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50*1000000, this); _vm->_interface->converseClear(); _vm->_interface->converseAddText(optionsStr[_lang][kROAccept], 0, 1, 0, 0 ); diff --git a/engines/saga/render.cpp b/engines/saga/render.cpp index ec168d296e..dc9334b037 100644 --- a/engines/saga/render.cpp +++ b/engines/saga/render.cpp @@ -110,6 +110,12 @@ void Render::drawScene() { _vm->_actor->drawActors(); } + // WORKAROUND + // Bug #2886130: "ITE: Graphic Glitches during Cat Tribe Celebration" + if (_vm->_scene->currentSceneNumber() == 274) { + _vm->_interface->drawStatusBar(); + } + #ifdef SAGA_DEBUG if (getFlags() & RF_OBJECTMAP_TEST) { if (_vm->_scene->_objectMap) diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index ed8a9055ba..d1ab3bc9d7 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -83,7 +83,6 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc) _sndRes = NULL; _sound = NULL; _music = NULL; - _driver = NULL; _anim = NULL; _render = NULL; _isoMap = NULL; @@ -198,9 +197,6 @@ SagaEngine::~SagaEngine() { delete _sound; _sound = NULL; - delete _driver; - _driver = NULL; - delete _gfx; _gfx = NULL; @@ -285,17 +281,7 @@ Common::Error SagaEngine::run() { _console = new Console(this); // Graphics should be initialized before music - MidiDriverType midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); - bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); - bool adlib = (midiDriver == MD_ADLIB); - - _driver = MidiDriver::createMidi(midiDriver); - if (native_mt32) - _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); - - _music = new Music(this, _mixer, _driver); - _music->setNativeMT32(native_mt32); - _music->setAdLib(adlib); + _music = new Music(this, _mixer); _render = new Render(this, _system); if (!_render->initialized()) { return Common::kUnknownError; @@ -433,7 +419,7 @@ void SagaEngine::loadStrings(StringsTable &stringsTable, const byte *stringsPoin offset = scriptS.readUint16(); // In some rooms in IHNM, string offsets can be greater than the maximum value than a 16-bit integer can hold // We detect this by checking the previous offset, and if it was bigger than the current one, an overflow - // occured (since the string offsets are sequential), so we're adding the missing part of the number + // occurred (since the string offsets are sequential), so we're adding the missing part of the number // Fixes bug #1895205 - "IHNM: end game text/caption error" if (prevOffset > offset) offset += 65536; diff --git a/engines/saga/saga.h b/engines/saga/saga.h index 2bef489e05..102d1e5c82 100644 --- a/engines/saga/saga.h +++ b/engines/saga/saga.h @@ -525,7 +525,6 @@ public: SndRes *_sndRes; Sound *_sound; Music *_music; - MidiDriver *_driver; Anim *_anim; Render *_render; IsoMap *_isoMap; diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index 40ee1fb720..d7ee037c50 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -1201,6 +1201,12 @@ void Scene::endScene() { _vm->_script->abortAllThreads(); _vm->_script->_skipSpeeches = false; + // WORKAROUND: Bug #2886151: "ITE: Mouse stops responding at Boar Castle" + // This is bug in original engine + if (_sceneNumber == 50) { + _vm->_interface->activate(); + } + // Copy current screen to render buffer so inset rooms will get proper background if (!(_sceneDescription.flags & kSceneFlagISO) && !_vm->_scene->isInIntro()) { BGInfo bgInfo; @@ -1425,6 +1431,8 @@ void Scene::clearPlacard() { q_event = _vm->_events->chain(q_event, &event); } +#ifdef ENABLE_IHNM + void Scene::showPsychicProfile(const char *text) { int textHeight; static PalEntry cur_pal[PAL_ENTRIES]; @@ -1440,6 +1448,8 @@ void Scene::showPsychicProfile(const char *text) { _vm->_interface->setMode(kPanelPlacard); _vm->_gfx->savePalette(); + _vm->_events->clearList(); + event.type = kEvTOneshot; event.code = kCursorEvent; event.op = kEventHide; @@ -1531,4 +1541,6 @@ void Scene::showIHNMDemoSpecialScreen() { _vm->_scene->changeScene(150, 0, kTransitionFade); } +#endif // IHNM + } // End of namespace Saga diff --git a/engines/saga/script.h b/engines/saga/script.h index f31af7b2ea..21afeb5c44 100644 --- a/engines/saga/script.h +++ b/engines/saga/script.h @@ -246,16 +246,19 @@ public: } void waitWalk(void *threadObj) { + debug(3, "waitWalk()"); wait(kWaitTypeWalk); _threadObj = threadObj; } void waitDelay(int sleepTime) { + debug(3, "waitDelay(%d)", sleepTime); wait(kWaitTypeDelay); _sleepTime = sleepTime; } void waitFrames(int frames) { + debug(3, "waitFrames(%d)", frames); wait(kWaitTypeWaitFrames); _frameWait = frames; } diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index f98a80acd8..328d4040af 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -370,12 +370,15 @@ void Script::sfStopBgdAnim(SCRIPTFUNC_PARAMS) { // reenabled. // Param1: boolean void Script::sfLockUser(SCRIPTFUNC_PARAMS) { - if (thread->pop()) { + int16 param = thread->pop(); + + if (param != 0) { _vm->_interface->deactivate(); } else { _vm->_interface->activate(); } + debug(1, "sfLockUser(%d)", param); } // Script function #12 (0x0C) @@ -1153,18 +1156,6 @@ void Script::sfPlacardOff(SCRIPTFUNC_PARAMS) { _vm->_scene->clearPlacard(); } -void Script::sfPsychicProfile(SCRIPTFUNC_PARAMS) { - thread->wait(kWaitTypePlacard); - - _vm->_scene->showPsychicProfile(thread->_strings->getString(thread->pop())); -} - -void Script::sfPsychicProfileOff(SCRIPTFUNC_PARAMS) { - // This is called a while after the psychic profile is - // opened, to close it automatically - _vm->_scene->clearPsychicProfile(); -} - // Script function #50 (0x32) void Script::sfSetProtagState(SCRIPTFUNC_PARAMS) { _vm->_actor->setProtagState(thread->pop()); @@ -1473,6 +1464,8 @@ void Script::sfPlayLoopedSound(SCRIPTFUNC_PARAMS) { } else { _vm->_sound->stopSound(); } + + debug(1, "sfPlayLoopedSound(%d)", param); } // Script function #72 (0x48) diff --git a/engines/saga/sfuncs_ihnm.cpp b/engines/saga/sfuncs_ihnm.cpp index fe586b54ae..b98c1cb852 100644 --- a/engines/saga/sfuncs_ihnm.cpp +++ b/engines/saga/sfuncs_ihnm.cpp @@ -440,6 +440,18 @@ void Script::sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS) { _vm->_interface->disableAbortSpeeches(thread->pop() != 0); } +void Script::sfPsychicProfile(SCRIPTFUNC_PARAMS) { + thread->wait(kWaitTypePlacard); + + _vm->_scene->showPsychicProfile(thread->_strings->getString(thread->pop())); +} + +void Script::sfPsychicProfileOff(SCRIPTFUNC_PARAMS) { + // This is called a while after the psychic profile is + // opened, to close it automatically + _vm->_scene->clearPsychicProfile(); +} + } // End of namespace Saga #endif diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp index 8ea3fc4003..a27608dcf5 100644 --- a/engines/saga/sndres.cpp +++ b/engines/saga/sndres.cpp @@ -159,7 +159,7 @@ void SndRes::playSound(uint32 resourceId, int volume, bool loop) { return; } - _vm->_sound->playSound(buffer, volume, loop); + _vm->_sound->playSound(buffer, volume, loop, resourceId); } void SndRes::playVoice(uint32 resourceId) { diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp index 811ee709f7..db979e8104 100644 --- a/engines/saga/sound.cpp +++ b/engines/saga/sound.cpp @@ -105,10 +105,20 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, const SoundBuffer &buffe _mixer->playStream(soundType, handle, Audio::makeLoopingAudioStream(stream, loop ? 0 : 1), -1, volume); } -void Sound::playSound(SoundBuffer &buffer, int volume, bool loop) { +void Sound::playSound(SoundBuffer &buffer, int volume, bool loop, int resId) { + // WORKAROUND + // Prevent playing same looped sound for several times + // Fixes bug #2886141: "ITE: Cumulative Snoring sounds in Prince's Bedroom" + for (int i = 0; i < SOUND_HANDLES; i++) + if (_handles[i].type == kEffectHandle && _handles[i].resId == resId) { + debug(1, "Skipped playing SFX #%d", resId); + return; + } + SndHandle *handle = getHandle(); handle->type = kEffectHandle; + handle->resId = resId; playSoundBuffer(&handle->handle, buffer, 2 * volume, handle->type, loop); } @@ -129,6 +139,7 @@ void Sound::stopSound() { if (_handles[i].type == kEffectHandle) { _mixer->stopHandle(_handles[i].handle); _handles[i].type = kFreeHandle; + _handles[i].resId = -1; } } diff --git a/engines/saga/sound.h b/engines/saga/sound.h index 9cf8f29767..7ee2765a0f 100644 --- a/engines/saga/sound.h +++ b/engines/saga/sound.h @@ -63,6 +63,7 @@ enum sndHandleType { struct SndHandle { Audio::SoundHandle handle; sndHandleType type; + int resId; }; class Sound { @@ -71,7 +72,7 @@ public: Sound(SagaEngine *vm, Audio::Mixer *mixer); ~Sound(); - void playSound(SoundBuffer &buffer, int volume, bool loop); + void playSound(SoundBuffer &buffer, int volume, bool loop, int resId); void pauseSound(); void resumeSound(); void stopSound(); diff --git a/engines/saga/sthread.cpp b/engines/saga/sthread.cpp index c133f8de88..be674e5acd 100644 --- a/engines/saga/sthread.cpp +++ b/engines/saga/sthread.cpp @@ -58,6 +58,8 @@ ScriptThread &Script::createThread(uint16 scriptModuleNumber, uint16 scriptEntry _threadList.push_front(newThread); + debug(3, "createThread(). Total threads: %d", _threadList.size()); + ScriptThread &tmp = *_threadList.begin(); tmp._stackBuf = (int16 *)malloc(ScriptThread::THREAD_STACK_SIZE * sizeof(int16)); tmp._stackTopIndex = ScriptThread::THREAD_STACK_SIZE - 2; @@ -78,6 +80,8 @@ void Script::wakeUpActorThread(int waitType, void *threadObj) { void Script::wakeUpThreads(int waitType) { ScriptThreadList::iterator threadIterator; + debug(3, "wakeUpThreads(%d)", waitType); + for (threadIterator = _threadList.begin(); threadIterator != _threadList.end(); ++threadIterator) { ScriptThread &thread = *threadIterator; if ((thread._flags & kTFlagWaiting) && (thread._waitType == waitType)) { @@ -89,6 +93,8 @@ void Script::wakeUpThreads(int waitType) { void Script::wakeUpThreadsDelayed(int waitType, int sleepTime) { ScriptThreadList::iterator threadIterator; + debug(3, "wakeUpThreads(%d, %d)", waitType, sleepTime); + for (threadIterator = _threadList.begin(); threadIterator != _threadList.end(); ++threadIterator) { ScriptThread &thread = *threadIterator; if ((thread._flags & kTFlagWaiting) && (thread._waitType == waitType)) { @@ -169,6 +175,8 @@ void Script::executeThreads(uint msec) { void Script::abortAllThreads() { ScriptThreadList::iterator threadIterator; + debug(3, "abortAllThreads()"); + threadIterator = _threadList.begin(); while (threadIterator != _threadList.end()) { |