[Scummvm-git-logs] scummvm master -> 6a8209ef10a8b6ec8bcfd6940ecb1add1652302f

NMIError noreply at scummvm.org
Mon Sep 29 17:56:17 UTC 2025


This automated email contains information about 12 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
9ce9a17bc3 DARKSEED: Fix bad filename in floppy ending
d187e7d3c2 DARKSEED: Restart room music after package cutscene
ac914e64f9 AUDIO/MIDI: Add parser function to get current track
ca552331ce DARKSEED: Prevent clock SFX from overlapping when repeatedly advancing time
a88ffc416e DARKSEED: Quick implementation of cutscene skipping with spacebar
9826df86fa DARKSEED: Stop sound effects when opening menu
d23f08e5c5 DARKSEED: Add missing SFX for drinking water
c3236e8f3d DARKSEED: Fix menu button sound being cut off
f3d8cde32a DARKSEED: Add support for floppy SFX
3c014c513d DARKSEED: Add sound debug commands
7afb254302 DARKSEED: Add some floppy-only SFX
6a8209ef10 DARKSEED: Add SFX mode GUI option


Commit: 9ce9a17bc34bff220cc2e5232f544c70e18d3174
    https://github.com/scummvm/scummvm/commit/9ce9a17bc34bff220cc2e5232f544c70e18d3174
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Fix bad filename in floppy ending

Changed paths:
    engines/darkseed/animation.cpp


diff --git a/engines/darkseed/animation.cpp b/engines/darkseed/animation.cpp
index 1841c6004b3..16d10ec56b5 100644
--- a/engines/darkseed/animation.cpp
+++ b/engines/darkseed/animation.cpp
@@ -1328,7 +1328,7 @@ void Animation::libAnim(bool pickingUpReservedBook) {
 void Animation::wonGame() {
 	_player->loadAnimations("libparts.nsp");
 	g_engine->_room->loadLocationSprites("libmorph.nsp");
-	g_engine->showFullscreenPic("lib_babe.pic");
+	g_engine->showFullscreenPic(g_engine->isCdVersion() ? "lib_babe.pic" : "lib-babe.pic");
 
 	g_engine->_cursor.showCursor(false);
 	g_engine->_console->printTosText(925);


Commit: d187e7d3c2967d171d3c24f7f1ce1f72ab3b09db
    https://github.com/scummvm/scummvm/commit/d187e7d3c2967d171d3c24f7f1ce1f72ab3b09db
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Restart room music after package cutscene

Changed paths:
    engines/darkseed/cutscene.cpp


diff --git a/engines/darkseed/cutscene.cpp b/engines/darkseed/cutscene.cpp
index b7cc0fdfc50..4831f1b7c27 100644
--- a/engines/darkseed/cutscene.cpp
+++ b/engines/darkseed/cutscene.cpp
@@ -120,6 +120,7 @@ void Cutscene::update() {
 			g_engine->_room->restorePalette();
 			g_engine->_frame.draw();
 			g_engine->_cursor.showCursor(true);
+			g_engine->_room->loadRoomMusic();
 		}
 	}
 }


Commit: ac914e64f9910ee71c8324e89a8c08946197fa6d
    https://github.com/scummvm/scummvm/commit/ac914e64f9910ee71c8324e89a8c08946197fa6d
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
AUDIO/MIDI: Add parser function to get current track

Changed paths:
    audio/midiparser.h


diff --git a/audio/midiparser.h b/audio/midiparser.h
index 0bb12c7271f..d045f7fc46d 100644
--- a/audio/midiparser.h
+++ b/audio/midiparser.h
@@ -567,6 +567,7 @@ public:
 	void resumePlaying();
 
 	bool setTrack(int track);
+	byte getActiveTrack() { return _activeTrack; }
 	bool jumpToTick(uint32 tick, bool fireEvents = false, bool stopNotes = true, bool dontSendNoteOn = false);
 	/**
 	 * Returns true if the active track has a jump point defined for the


Commit: ca552331ce1bb6837c13675c5dd2a28318e72957
    https://github.com/scummvm/scummvm/commit/ca552331ce1bb6837c13675c5dd2a28318e72957
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Prevent clock SFX from overlapping when repeatedly advancing time

Changed paths:
    engines/darkseed/darkseed.cpp


diff --git a/engines/darkseed/darkseed.cpp b/engines/darkseed/darkseed.cpp
index e0ed9316c86..1a914d15d77 100644
--- a/engines/darkseed/darkseed.cpp
+++ b/engines/darkseed/darkseed.cpp
@@ -277,8 +277,10 @@ void DarkseedEngine::gameLoop() {
 			}
 			if ((_room->_roomNumber < 10 || _room->_roomNumber == 61 || _room->_roomNumber == 62) && _currentTimeInSeconds % 3600 == 0) {
 				if (_room->_roomNumber == 7) {
+					if (!_sound->isPlayingSfx(45))
 					playSound(45, 5, -1);
 				} else {
+					if (!_sound->isPlayingSfx(46))
 					playSound(46, 5, -1);
 				}
 			}


Commit: a88ffc416ee3b5b164ed4ec04f064bf16d14113a
    https://github.com/scummvm/scummvm/commit/a88ffc416ee3b5b164ed4ec04f064bf16d14113a
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Quick implementation of cutscene skipping with spacebar

Changed paths:
    engines/darkseed/darkseed.cpp
    engines/darkseed/darkseed.h
    engines/darkseed/metaengine.cpp


diff --git a/engines/darkseed/darkseed.cpp b/engines/darkseed/darkseed.cpp
index 1a914d15d77..5f5facfa9bc 100644
--- a/engines/darkseed/darkseed.cpp
+++ b/engines/darkseed/darkseed.cpp
@@ -394,6 +394,9 @@ void DarkseedEngine::updateEvents() {
 				}
 			} else if (event.customType == kDarkseedActionQuit) {
 				quitGame();
+			} else if (event.customType == kDarkseedActionSkipCutscene) {
+				// TODO Implement properly
+				_isRightMouseClicked = true;
 			}
 			break;
 		default:
diff --git a/engines/darkseed/darkseed.h b/engines/darkseed/darkseed.h
index 8b11c20e677..a15d50afc25 100644
--- a/engines/darkseed/darkseed.h
+++ b/engines/darkseed/darkseed.h
@@ -58,7 +58,8 @@ enum DarkseedAction {
 	kDarkseedActionSelect,
 	kDarkseedActionChangeCommand,
 	kDarkseedActionTimeAdvance,
-	kDarkseedActionQuit
+	kDarkseedActionQuit,
+	kDarkseedActionSkipCutscene
 };
 
 enum ActionMode : uint8 {
diff --git a/engines/darkseed/metaengine.cpp b/engines/darkseed/metaengine.cpp
index 2b0f9958aaa..edc8d2ec5a7 100644
--- a/engines/darkseed/metaengine.cpp
+++ b/engines/darkseed/metaengine.cpp
@@ -95,6 +95,11 @@ Common::KeymapArray DarkseedMetaEngine::initKeymaps(const char *target) const {
 	act->addDefaultInputMapping("C+q");
 	engineKeyMap->addAction(act);
 
+	act = new Action("SKIPCUTSCENE", _("Skip Cutscene"));
+	act->setCustomEngineActionEvent(Darkseed::kDarkseedActionSkipCutscene);
+	act->addDefaultInputMapping("SPACE");
+	engineKeyMap->addAction(act);
+
 	return Keymap::arrayOf(engineKeyMap);
 }
 


Commit: 9826df86faeb83165fbfb86110f2b743fdd9440c
    https://github.com/scummvm/scummvm/commit/9826df86faeb83165fbfb86110f2b743fdd9440c
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Stop sound effects when opening menu

Changed paths:
    engines/darkseed/menu.cpp


diff --git a/engines/darkseed/menu.cpp b/engines/darkseed/menu.cpp
index 6bcb688eae5..9b11d9c5800 100644
--- a/engines/darkseed/menu.cpp
+++ b/engines/darkseed/menu.cpp
@@ -124,6 +124,8 @@ Menu::~Menu() {
 }
 
 void Menu::loadMenu() {
+	g_engine->_sound->stopSfx();
+	g_engine->_sound->stopSpeech();
 	if (g_engine->_sound->isPlayingMusic()) {
 		g_engine->_sound->startFadeOut();
 		while (g_engine->_sound->isFading()) {


Commit: d23f08e5c582bc62bcb16d7589c815bec71891f4
    https://github.com/scummvm/scummvm/commit/d23f08e5c582bc62bcb16d7589c815bec71891f4
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Add missing SFX for drinking water

Changed paths:
    engines/darkseed/animation.cpp


diff --git a/engines/darkseed/animation.cpp b/engines/darkseed/animation.cpp
index 16d10ec56b5..367edd5ca9b 100644
--- a/engines/darkseed/animation.cpp
+++ b/engines/darkseed/animation.cpp
@@ -530,9 +530,13 @@ void Animation::updateAnimation() {
 		}
 		break;
 	case 30:
-	case 31: {
+	case 31: { // Have a drink of water
 		int animIdx = _otherNspAnimationType_maybe - 30;
 		advanceAnimationFrame(animIdx);
+		if (_frameAdvanced && _otherNspAnimationType_maybe == 30 && _animIndexTbl[animIdx] == 6) {
+			// This sound effect is missing in the CD version
+			g_engine->playSound(35, 5, -1); // water
+		}
 		if (_isPlayingAnimation_maybe) {
 			_player->_frameIdx = _player->_animations.getAnimAt(animIdx)._frameNo[_animIndexTbl[animIdx]];
 		}


Commit: c3236e8f3dd5cec26810fa5dbf71f01ecc93b16f
    https://github.com/scummvm/scummvm/commit/c3236e8f3dd5cec26810fa5dbf71f01ecc93b16f
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Fix menu button sound being cut off

Changed paths:
    engines/darkseed/menu.cpp


diff --git a/engines/darkseed/menu.cpp b/engines/darkseed/menu.cpp
index 9b11d9c5800..c1b64082b4e 100644
--- a/engines/darkseed/menu.cpp
+++ b/engines/darkseed/menu.cpp
@@ -124,7 +124,6 @@ Menu::~Menu() {
 }
 
 void Menu::loadMenu() {
-	g_engine->_sound->stopSfx();
 	g_engine->_sound->stopSpeech();
 	if (g_engine->_sound->isPlayingMusic()) {
 		g_engine->_sound->startFadeOut();
@@ -133,6 +132,7 @@ void Menu::loadMenu() {
 		}
 		g_engine->_sound->stopMusic();
 	}
+	g_engine->_sound->stopSfx();
 
 	_open = true;
 	Graphics::Surface screenCopy;


Commit: f3d8cde32a2ffbb08173911734e0db06f4e05e1d
    https://github.com/scummvm/scummvm/commit/f3d8cde32a2ffbb08173911734e0db06f4e05e1d
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Add support for floppy SFX

Changed paths:
    engines/darkseed/midiparser_sbr.cpp
    engines/darkseed/midiparser_sbr.h
    engines/darkseed/music.cpp
    engines/darkseed/music.h
    engines/darkseed/sound.cpp
    engines/darkseed/sound.h


diff --git a/engines/darkseed/midiparser_sbr.cpp b/engines/darkseed/midiparser_sbr.cpp
index 3eded8f622e..4a5459cef4d 100644
--- a/engines/darkseed/midiparser_sbr.cpp
+++ b/engines/darkseed/midiparser_sbr.cpp
@@ -294,4 +294,10 @@ bool MidiParser_SBR::loadMusic(const byte *data, uint32 size) {
 	return true;
 }
 
+bool MidiParser_SBR::isSampleSfx(uint8 sfxId) {
+	if (!_sfx || sfxId >= _numTracks)
+		return false;
+	return _tracks[sfxId][0] != nullptr && _tracks[sfxId][0][0] == 0x03;
+}
+
 } // End of namespace Darkseed
diff --git a/engines/darkseed/midiparser_sbr.h b/engines/darkseed/midiparser_sbr.h
index 9a920975676..bf6ad6da553 100644
--- a/engines/darkseed/midiparser_sbr.h
+++ b/engines/darkseed/midiparser_sbr.h
@@ -34,6 +34,7 @@ public:
 	MidiParser_SBR(int8 source = -1, bool sfx = false);
 
 	bool loadMusic(const byte *data, uint32 size) override;
+	bool isSampleSfx(uint8 sfxId);
 
 protected:
 	void parseNextEvent(EventInfo &info) override;
diff --git a/engines/darkseed/music.cpp b/engines/darkseed/music.cpp
index f3e11d3ae88..5c4f7e19533 100644
--- a/engines/darkseed/music.cpp
+++ b/engines/darkseed/music.cpp
@@ -21,25 +21,31 @@
 
 #include "darkseed/music.h"
 #include "darkseed/darkseed.h"
-#include "darkseed/midiparser_sbr.h"
 
 namespace Darkseed {
 
-MusicPlayer::MusicPlayer(DarkseedEngine* vm, bool useFloppyMusic) :
-	_vm(vm),
-	_driver(nullptr),
-	_floppyAdLibDriver(nullptr),
-	_paused(false),
-	_deviceType(MT_NULL),
-	_parser(nullptr),
-	_musicData(nullptr),
-	_tosInstrumentBankData(nullptr),
-	_tosInstrumentBankLoaded(false),
-	_useFloppyMusic(useFloppyMusic) {
+MusicPlayer::MusicPlayer(DarkseedEngine* vm, bool useFloppyMusic, bool useFloppySfx) :
+		_vm(vm),
+		_driver(nullptr),
+		_floppyAdLibDriver(nullptr),
+		_paused(false),
+		_deviceType(MT_NULL),
+		_musicParser(nullptr),
+		_musicData(nullptr),
+		_sfxParserSbr(nullptr),
+		_sfxData(nullptr),
+		_tosInstrumentBankData(nullptr),
+		_tosInstrumentBankLoaded(false),
+		_useFloppyMusic(useFloppyMusic),
+		_useFloppySfx(useFloppySfx) {
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		_sfxParsers[i] = nullptr;
+	}
 }
 
 MusicPlayer::~MusicPlayer() {
-	stop();
+	stopMusic();
+	stopAllSfx();
 	if (_driver != nullptr) {
 		_driver->setTimerCallback(nullptr, nullptr);
 		_driver->close();
@@ -47,10 +53,16 @@ MusicPlayer::~MusicPlayer() {
 
 	Common::StackLock lock(_mutex);
 
-	if (_parser != nullptr)
-		delete _parser;
+	if (_musicParser != nullptr)
+		delete _musicParser;
 	if (_musicData != nullptr)
 		delete[] _musicData;
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (_sfxParsers[i] != nullptr)
+			delete _sfxParsers[i];
+	}
+	if (_sfxData != nullptr)
+		delete _sfxData;
 	if (_tosInstrumentBankData != nullptr)
 		delete[] _tosInstrumentBankData;
 	if (_driver != nullptr) {
@@ -79,7 +91,18 @@ int MusicPlayer::open() {
 				break;
 		}
 
-		_parser = new MidiParser_SBR(0);
+		_musicParser = new MidiParser_SBR(0);
+		if (_useFloppySfx) {
+			for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+				if (_sfxParserSbr == nullptr) {
+					_sfxParserSbr = new MidiParser_SBR(i + 1, true);
+					_sfxParsers[i] = _sfxParserSbr;
+				}
+				else {
+					_sfxParsers[i] = new MidiParser_SBR(i + 1, true);
+				}
+			}
+		}
 	} else {
 		switch (_deviceType) {
 			case MT_ADLIB:
@@ -97,12 +120,17 @@ int MusicPlayer::open() {
 		}
 
 		// CD version uses SMF data
-		_parser = MidiParser::createParser_SMF(0);
+		_musicParser = MidiParser::createParser_SMF(0);
 	}
 
 	_driver->property(MidiDriver::PROP_USER_VOLUME_SCALING, true);
-	if (_parser)
-		_parser->property(MidiParser::mpDisableAutoStartPlayback, true);
+	if (_musicParser != nullptr)
+		_musicParser->property(MidiParser::mpDisableAutoStartPlayback, true);
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (_sfxParsers[i] != nullptr) {
+			_sfxParsers[i]->property(MidiParser::mpDisableAutoStartPlayback, true);
+		}
+	}
 
 	int returnCode = _driver->open();
 	if (returnCode != 0) {
@@ -112,11 +140,17 @@ int MusicPlayer::open() {
 
 	syncSoundSettings();
 
-	if (_parser) {
-		_parser->setMidiDriver(_driver);
-		_parser->setTimerRate(_driver->getBaseTempo());
-		_driver->setTimerCallback(_parser, &_parser->timerCallback);
+	if (_musicParser != nullptr) {
+		_musicParser->setMidiDriver(_driver);
+		_musicParser->setTimerRate(_driver->getBaseTempo());
 	}
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (_sfxParsers[i] != nullptr) {
+			_sfxParsers[i]->setMidiDriver(_driver);
+			_sfxParsers[i]->setTimerRate(_driver->getBaseTempo());
+		}
+	}
+	_driver->setTimerCallback(this, &onTimer);
 
 	return 0;
 }
@@ -126,65 +160,174 @@ void MusicPlayer::onTimer(void *data) {
 
 	Common::StackLock lock(p->_mutex);
 
-	if (p->_parser) {
-		p->_parser->onTimer();
+	if (p->_musicParser != nullptr)
+		p->_musicParser->onTimer();
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (p->_sfxParsers[i] != nullptr) {
+			p->_sfxParsers[i]->onTimer();
+		}
 	}
 }
 
-bool MusicPlayer::isPlaying() {
+bool MusicPlayer::isPlayingMusic() {
 	Common::StackLock lock(_mutex);
 
-	return _parser && _parser->isPlaying();
+	return _musicParser != nullptr && _musicParser->isPlaying();
 }
 
-void MusicPlayer::stop() {
+void MusicPlayer::stopMusic() {
 	Common::StackLock lock(_mutex);
 
-	if (_parser) {
-		_parser->stopPlaying();
-		if (_driver) {
+	if (_musicParser != nullptr) {
+		_musicParser->stopPlaying();
+		if (_driver != nullptr) {
 			_driver->deinitSource(0);
 		}
 	}
 }
 
-void MusicPlayer::pause(bool pause) {
+void MusicPlayer::pauseMusic(bool pause) {
 	Common::StackLock lock(_mutex);
 
-	if (_paused == pause || !_parser)
+	if (_paused == pause || _musicParser == nullptr)
 		return;
 
 	_paused = pause;
 
 	if (_paused) {
-		_parser->pausePlaying();
+		_musicParser->pausePlaying();
 	} else {
-		_parser->resumePlaying();
+		_musicParser->resumePlaying();
+	}
+}
+
+bool MusicPlayer::isPlayingSfx() {
+	Common::StackLock lock(_mutex);
+
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (_sfxParsers[i] != nullptr && _sfxParsers[i]->isPlaying()) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool MusicPlayer::isPlayingSfx(uint8 sfxId) {
+	Common::StackLock lock(_mutex);
+
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (_sfxParsers[i] != nullptr && _sfxParsers[i]->isPlaying() && _sfxParsers[i]->getActiveTrack() == sfxId) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void MusicPlayer::playSfx(uint8 sfxId, uint8 priority) {
+	Common::StackLock lock(_mutex);
+
+	if (_sfxParsers[0] == nullptr)
+		return;
+
+	if (!_tosInstrumentBankLoaded) {
+		warning("Attempt to play floppy sound effect %i while TOS instrument bank is not loaded", sfxId);
+		return;
+	}
+
+	uint8 sfxParserIdx = assignSfxParser();
+	if (sfxParserIdx == 0xFF) {
+		warning("All SFX parsers in use when trying to play SFX %i", sfxId);
+		return;
+	}
+
+	if (_driver != nullptr) {
+		_driver->resetSourceVolume(sfxParserIdx + 1);
+	}
+	if (_floppyAdLibDriver != nullptr)
+		_floppyAdLibDriver->setSourcePriority(sfxParserIdx + 1, priority);
+
+	_sfxParsers[sfxParserIdx]->setTrack(sfxId);
+	_sfxParsers[sfxParserIdx]->startPlaying();
+}
+
+uint8 MusicPlayer::assignSfxParser() {
+	Common::StackLock lock(_mutex);
+
+	int parserIdx = 0xFF;
+
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (_sfxParsers[i] != nullptr && !_sfxParsers[i]->isPlaying()) {
+			// Make sure all inactive SFX parsers have released their resources
+			if (_driver != nullptr)
+				_driver->deinitSource(i + 1);
+
+			if (parserIdx == 0xFF)
+				parserIdx = i;
+		}
+	}
+	// If all SFX parsers are already playing, parserIdx is still 0xFF
+
+	return parserIdx;
+}
+
+void MusicPlayer::stopAllSfx() {
+	Common::StackLock lock(_mutex);
+
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (_sfxParsers[i] != nullptr) {
+			_sfxParsers[i]->stopPlaying();
+			if (_driver != nullptr) {
+				_driver->deinitSource(i + 1);
+			}
+		}
 	}
 }
 
+bool MusicPlayer::stopSfx(uint8 sfxId) {
+	Common::StackLock lock(_mutex);
+
+	bool stoppedSfx = false;
+
+	for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+		if (_sfxParsers[i] != nullptr && _sfxParsers[i]->getActiveTrack() == sfxId) {
+			_sfxParsers[i]->stopPlaying();
+			if (_driver != nullptr) {
+				_driver->deinitSource(i + 1);
+			}
+			stoppedSfx = true;
+		}
+	}
+
+	return stoppedSfx;
+}
+
 void MusicPlayer::syncSoundSettings() {
 	if (_driver)
 		_driver->syncSoundSettings();
 }
 
-void MusicPlayer::setLoop(bool loop) {
+void MusicPlayer::setLoopMusic(bool loop) {
 	Common::StackLock lock(_mutex);
 
-	if (_parser)
-		_parser->property(MidiParser::mpAutoLoop, loop);
+	if (_musicParser)
+		_musicParser->property(MidiParser::mpAutoLoop, loop);
 }
 
 void MusicPlayer::load(Common::SeekableReadStream *in, int32 size, bool sfx) {
 	Common::StackLock lock(_mutex);
 
-	if (!_parser)
+	MidiParser *parser = sfx ? _sfxParsers[0] : _musicParser;
+	byte **dataPtr = sfx ? &_sfxData : &_musicData;
+
+	if (parser == nullptr)
 		return;
 
 	if (size < 0) {
 		// Use the parser to determine the size of the MIDI data.
 		int64 startPos = in->pos();
-		size = _parser->determineDataSize(in);
+		size = parser->determineDataSize(in);
 		if (size < 0) {
 			warning("MusicPlayer::load - Could not determine size of music data");
 			return;
@@ -194,17 +337,31 @@ void MusicPlayer::load(Common::SeekableReadStream *in, int32 size, bool sfx) {
 		in->seek(startPos);
 	}
 
-	if (isPlaying())
-		stop();
-	_parser->unloadMusic();
-	if (_musicData) {
-		delete[] _musicData;
+	if (!sfx && isPlayingMusic()) {
+		stopMusic();
+		_musicParser->unloadMusic();
+	}
+	if (sfx && isPlayingSfx()) {
+		stopAllSfx();
+		for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+			_sfxParsers[i]->unloadMusic();
+		}
+	}
+	if (*dataPtr != nullptr) {
+		delete[] *dataPtr;
 	}
 
-	_musicData = new byte[size];
-	in->read(_musicData, size);
+	*dataPtr = new byte[size];
+	in->read(*dataPtr, size);
 
-	_parser->loadMusic(_musicData, size);
+	if (!sfx) {
+		_musicParser->loadMusic(*dataPtr, size);
+	}
+	else {
+		for (int i = 0; i < NUM_SFX_PARSERS; i++) {
+			_sfxParsers[i]->loadMusic(*dataPtr, size);
+		}
+	}
 }
 
 void MusicPlayer::loadTosInstrumentBankData(Common::SeekableReadStream* in, int32 size) {
@@ -231,8 +388,8 @@ void MusicPlayer::loadTosInstrumentBank() {
 	}
 
 	if (!_tosInstrumentBankLoaded) {
-		if (isPlaying())
-			stop();
+		if (isPlayingMusic())
+			stopMusic();
 		_floppyAdLibDriver->loadInstrumentBank(_tosInstrumentBankData);
 		_tosInstrumentBankLoaded = true;
 	}
@@ -251,20 +408,26 @@ void MusicPlayer::loadInstrumentBank(Common::SeekableReadStream *in, int32 size)
 	byte *instrumentBankData = new byte[size];
 	in->read(instrumentBankData, size);
 
-	if (isPlaying())
-		stop();
+	if (isPlayingMusic())
+		stopMusic();
 	_floppyAdLibDriver->loadInstrumentBank(instrumentBankData);
 	_tosInstrumentBankLoaded = false;
 }
 
-void MusicPlayer::play(uint8 priority, bool loop) {
+bool MusicPlayer::isSampleSfx(uint8 sfxId) {
+	if (_sfxParserSbr == nullptr)
+		return false;
+	return _sfxParserSbr->isSampleSfx(sfxId);
+}
+
+void MusicPlayer::playMusic(uint8 priority, bool loop) {
 	Common::StackLock lock(_mutex);
 
-	if (!_parser)
+	if (_musicParser == nullptr || _driver == nullptr)
 		return;
 
 	if (!_useFloppyMusic)
-		_parser->property(MidiParser::mpAutoLoop, loop);
+		_musicParser->property(MidiParser::mpAutoLoop, loop);
 	if (_floppyAdLibDriver != nullptr)
 		_floppyAdLibDriver->setSourcePriority(0, priority);
 
@@ -272,14 +435,14 @@ void MusicPlayer::play(uint8 priority, bool loop) {
 		_driver->abortFade();
 	_driver->resetSourceVolume(0);
 
-	_parser->startPlaying();
+	_musicParser->startPlaying();
 }
 
-void MusicPlayer::startFadeOut() {
+void MusicPlayer::startFadeOutMusic() {
 	_driver->startFade(0, 1100, 0);
 }
 
-bool MusicPlayer::isFading() {
+bool MusicPlayer::isFadingMusic() {
 	return _driver->isFading();
 }
 
diff --git a/engines/darkseed/music.h b/engines/darkseed/music.h
index 8df15026388..bf113ca4222 100644
--- a/engines/darkseed/music.h
+++ b/engines/darkseed/music.h
@@ -24,6 +24,7 @@
 
 #include "darkseed/adlib_dsf.h"
 #include "darkseed/adlib_worx.h"
+#include "darkseed/midiparser_sbr.h"
 
 #include "audio/mididrv_ms.h"
 #include "audio/midiparser.h"
@@ -35,24 +36,32 @@ class DarkseedEngine;
 
 class MusicPlayer {
 protected:
+	static const uint8 NUM_SFX_PARSERS = 5;
+
 	DarkseedEngine *_vm;
 
 	Common::Mutex _mutex;
 	MidiDriver_Multisource *_driver;
 	MidiDriver_DarkSeedFloppy_AdLib *_floppyAdLibDriver;
 
-	MidiParser *_parser;
+	MidiParser *_musicParser;
+	MidiParser *_sfxParsers[NUM_SFX_PARSERS];
+	MidiParser_SBR *_sfxParserSbr;
+	// The type of the music device selected for playback.
+	MusicType _deviceType;
 	byte *_musicData;
+	byte *_sfxData;
 	byte *_tosInstrumentBankData;
 	bool _tosInstrumentBankLoaded;
 	bool _useFloppyMusic;
+	bool _useFloppySfx;
 
 	bool _paused;
 
 	static void onTimer(void *data);
 
 public:
-	MusicPlayer(DarkseedEngine *vm, bool useFloppyMusic);
+	MusicPlayer(DarkseedEngine *vm, bool useFloppyMusic, bool useFloppySfx);
 	~MusicPlayer();
 
 	int open();
@@ -61,21 +70,26 @@ public:
 	void loadTosInstrumentBankData(Common::SeekableReadStream *in, int32 size = -1);
 	void loadTosInstrumentBank();
 	void loadInstrumentBank(Common::SeekableReadStream *in, int32 size = -1);
-
-	void play(uint8 priority = 0xFF, bool loop = false);
-	void setLoop(bool loop);
-	bool isPlaying();
-	void stop();
-	void pause(bool pause);
-
-	void startFadeOut();
-	bool isFading();
+	bool isSampleSfx(uint8 sfxId);
+
+	void playMusic(uint8 priority = 0xFF, bool loop = false);
+	void setLoopMusic(bool loop);
+	bool isPlayingMusic();
+	void stopMusic();
+	void pauseMusic(bool pause);
+	void playSfx(uint8 sfxId, uint8 priority = 0xFF);
+	bool isPlayingSfx();
+	bool isPlayingSfx(uint8 sfxId);
+	void stopAllSfx();
+	bool stopSfx(uint8 sfxId);
+
+	void startFadeOutMusic();
+	bool isFadingMusic();
 
 	void syncSoundSettings();
 
-private:
-	// The type of the music device selected for playback.
-	MusicType _deviceType;
+protected:
+	uint8 assignSfxParser();
 };
 
 } // namespace Darkseed
diff --git a/engines/darkseed/sound.cpp b/engines/darkseed/sound.cpp
index 7feab1a0419..6773ae08206 100644
--- a/engines/darkseed/sound.cpp
+++ b/engines/darkseed/sound.cpp
@@ -23,6 +23,7 @@
 #include "audio/decoders/raw.h"
 #include "audio/decoders/voc.h"
 #include "common/config-manager.h"
+#include "common/util.h"
 #include "darkseed/sound.h"
 #include "darkseed/darkseed.h"
 
@@ -132,10 +133,130 @@ static constexpr char sfxCDFilenameTbl[][14] = {
 	"beaming.sfx"
 };
 
-Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer) {
+// Maps CD SFX IDs to floppy SFX IDs
+static constexpr int sfxCdFloppyMapping[60] = {
+	//  0
+	 -1,	// Unused
+	 10,	// House front door
+	 11,	// Shower
+	 -1,	// Delbert's dog (not present in floppy version)
+	 13,	// Stairs
+	 14,	// Press button
+	 15,	// Pick up item
+	 16,	// Unused (energizing hammer head?)
+	 17,	// Lever
+	 18,	// Spaceship
+	// 10
+	 19,	// Leech
+	 20,	// Car engine start
+	 21,	// Mausoleum sigils (only used by floppy version)
+	 22,	// Mausoleum door (only used by CD version)
+	 23,	// Shovel
+	 24,	// Car door
+	 25,	// Car engine start failure
+	 26,	// Assembling hammer
+	 27,	// Lock picking
+	 28,	// Guardian
+	// 20
+	 29,	// Alien dog
+	 30,	// Alien cop gun
+	 12,	// Cup
+	 32,	// Cocoon
+	 90,	// Phone (loud)
+	 91,	// Phone (quiet)
+	118,	// Fixing mirror
+	 93,	// Doorbell (loud)
+	 94,	// Destroying mirror
+	 95,	// Doorbell (quiet)
+	// 30
+	 96,	// Electricity
+	 97,	// Car trunk / trunk (attic)
+	 98,	// Drinking / pouring
+	 99,	// Unused (tuning radio?)
+	100,	// Bathroom cabinet
+	101,	// Bathroom faucet
+	 -1,	// Unused
+	 -1,	// Unused (running water?)
+	 -1,	// Unused (press button alternate?)
+	111,	// Car horn
+	// 40
+	 -1,	// Unused
+	116,	// Secret door
+	115,	// Kitchen doors
+	107,	// Clock tick (only used by floppy version)
+	108,	// Clock tock (only used by floppy version)
+	104,	// Clock chime (loud)
+	106,	// Clock chime (quiet)
+	113,	// Urn
+	114,	// Teleporter
+	 -1,	// Unused
+	// 50	Floppy-only sound effects
+	 35,	// Recruitment center
+	 51,	// Car engine running (original code uses 50 here, which sounds wrong)
+	 92,	// Footstep
+	105,	// Mosquito (upstairs hallway)
+	109,	// Book stamp
+	110,	// Kitchen faucet / fountain
+	112,	// Phone dial tone
+	 -1,
+	 -1,
+	 -1
+};
+
+// Maps DOS CD speech IDs to DOS floppy SFX IDs
+static Common::Pair<int, int> speechCdFloppyMapping[] = {
+				  // 59: ralph1 (unused & invalid)
+	{ 904,  60 }, // m1-1   Librarian (phone): "Hello?" "Hello Mike. This is Sue at the library. ..."
+	{ 927,  61 }, // cl1    Store clerk: "Serve yourself, Mr. Dawson."
+	{ 905,  62 }, // cl2    Store clerk: "That's the last bottle of Scotch. ..."
+	{ 907,  63 }, // d4a-1  Delbert: "Hi you must be Mike. ..."
+	{ 908,  64 }, // d6c-2  Delbert: "You're a writer, huh? ..."
+	{ 909,  65 }, // d5a-1  Delbert: "Good to see you, Dawson. ..."
+	{ 910,  66 }, // d6a-2  Delbert: "Boy, that's smooth. ..."
+	{ 906,  67 }, // cl3    Store clerk: "I'm sorry, Mr. Dawson, ..."
+				  // CD ID 925 includes both this line and the next. These are 2 separate IDs in the floppy version. CD ID 926 is unused.
+	{ 925,  68 }, // gl0a   Librarian: "I'm not really sure why I'm here, ..."
+	{ 926,  69 }, // gl1b   Librarian: "I know it sounds strange, ..."
+	{ 924,  70 }, // gl2a   Librarian: "This card really should be kept with the book. ..."
+				  // 71: s7a-1 (invalid)
+	{ 912,  72 }, // s8a-2  Cop: "You're under arrest, Dawson. ..."
+	{ 913,  73 }, // k9a-3  Keeper: "Greetings Michael. ..."
+	{ 914,  74 }, // k9c-3  Keeper: "If born, this creature will destroy you..."
+	{ 915,  75 }, // k9e-3  Keeper: "Also, the Police in your world..."
+	{ 928,  76 }, // gl3a   Librarian: "Hi Mike. Here's the book that was put on hold for you."
+				  // 77: k9e-3 (duplicate of 75)
+				  // 78: k9f-3 (invalid)
+	{ 916,  79 }, // g10a-1 Sargo: "Greetings, human. ..."
+	{ 917,  80 }, // g10b-1 Sargo: "I am prepared to give you the gift..."
+	{ 918,  81 }, // m11a-1 Mike: "I'm just beginning to understand."
+	{ 919,  82 }, // o12a-1 Keeper (radio): "Steal from those who protect you..."
+	{ 920,  83 }, // o13a-1 Keeper (radio): "What you do in the light..."
+				  // 84: o13b-1 (invalid)
+	{ 921,  85 }, // o14a-1 Keeper (radio): "Turn yourself in and leave behind the key..."
+	{ 922,  86 }, // k15a-1 Keeper (phone): "Remember, anything seen in the mirror..."
+	{ 923,  87 }, // s16a-1 Alien cop: "So that's where my gun went! ..."
+				  // 88: l17a-1 (invalid)
+				  // 89: l18a-1 (invalid)
+	{  -1,  -1 }
+};
+
+Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer), _lastPlayedDigitalSfx(0) {
+	memset(_sfxFloppyDigFilenameTbl, 0, 120 * 14);
+
 	bool floppyMusicSetting = ConfMan.hasKey("use_floppy_music") ? ConfMan.getBool("use_floppy_music") : false;
-	_useFloppyMusic = !g_engine->isCdVersion() || floppyMusicSetting;
-	_musicPlayer = new MusicPlayer(g_engine, _useFloppyMusic);
+	_useFloppyMusic = g_engine->isDosFloppy() || floppyMusicSetting;
+
+	// SFX mode 0: CD SFX only
+	// SFX mode 1: CD SFX + additional floppy SFX
+	// SFX mode 2: floppy SFX only
+	// CD SFX are only available when using the CD version
+	// Floppy SFX are only available when using floppy music
+	int sfxMode = ConfMan.hasKey("sfx_mode") ? ConfMan.getInt("sfx_mode") : -1;
+	_useCdSfx = g_engine->isCdVersion() && (!_useFloppyMusic || sfxMode != 2);
+	_useFloppySfx = _useFloppyMusic && (g_engine->isDosFloppy() || sfxMode == 1 || sfxMode == 2);
+
+	_musicPlayer = new MusicPlayer(g_engine, _useFloppyMusic, _useFloppySfx);
+
 	_didSpeech.resize(978);
 	resetSpeech();
 }
@@ -145,23 +266,89 @@ Sound::~Sound() {
 }
 
 int Sound::init() {
-	if (_useFloppyMusic) {
+	int returnCode = _musicPlayer->open();
+	if (returnCode != 0)
+		return returnCode;
+
+	if (_useFloppyMusic || _useFloppySfx) {
 		Common::File file;
 		Common::Path path = g_engine->isCdVersion() ? Common::Path("sound").join("tos1.sit") : Common::Path("tos1.sit");
 		if (file.open(path)) {
 			_musicPlayer->loadTosInstrumentBankData(&file, (int32)file.size());
 		} else {
-			debug("Failed to load TOS instrument bank data %s", path.toString().c_str());
+			warning("Failed to load TOS floppy instrument bank data %s", path.toString().c_str());
+		}
+		file.close();
+	}
+
+	if (_useFloppySfx) {
+		Common::File file;
+		Common::Path path = g_engine->isCdVersion() ? Common::Path("sound").join("tos1.sbr") : Common::Path("tos1.sbr");
+		if (file.open(path)) {
+			_musicPlayer->load(&file, (int32)file.size(), true);
+		} else {
+			warning("Failed to load TOS floppy sound effects data %s", path.toString().c_str());
+		}
+		file.close();
+	}
+
+	if (g_engine->isDosFloppy()) {
+		Common::File file;
+		Common::Path path = Common::Path("tos1.dig");
+		if (file.open(path)) {
+			loadTosDigData(&file, (int32)file.size());
+		} else {
+			warning("Failed to load TOS floppy speech data %s", path.toString().c_str());
 		}
 		file.close();
 	}
 
-	return _musicPlayer->open();
+	return 0;
+}
+
+void Sound::loadTosDigData(Common::SeekableReadStream* in, int32 size) {
+	int32 bytesRead = 0;
+	int entriesRead = 0;
+	while (bytesRead < size && entriesRead < 120) {
+		byte type = in->readByte();
+		if (type == 3) {
+			// VOC filename entry
+			uint32 entryBytesRead = in->read(_sfxFloppyDigFilenameTbl[entriesRead], 14);
+			if (entryBytesRead != 14) {
+				warning("Failed to read all bytes from DIG filename entry %i", entriesRead);
+				return;
+			}
+			bytesRead += 15;
+		}
+		else if (type == 0) {
+			// Unknown what this entry type contains. It is ignored by the original code.
+			uint16 entrySize = in->readUint16LE();
+			if (!in->skip(entrySize - 3)) {
+				warning("Failed to read all bytes from DIG type 0 entry %i", entriesRead);
+				return;
+			}
+			bytesRead += entrySize;
+		}
+		else {
+			// Unknown entry type.
+			warning("Unknown DIG entry type %X in entry %i", type, entriesRead);
+			return;
+		}
+		entriesRead++;
+	}
+	if (entriesRead < 100) {
+		// DIG files typically contain at least 100 entries
+		warning("DIG file only contained %i entries", entriesRead);
+	}
 }
 
 void Sound::playTosSpeech(int tosIdx) {
 	if (g_engine->isDosFloppy()) {
-		playFloppySpeech(tosIdx);
+		int floppySfxId = convertCdSpeechToFloppySfxId(tosIdx);
+		if (floppySfxId == -1)
+			return;
+
+		playDosFloppySfx(floppySfxId, 5);
 		return;
 	}
 
@@ -190,11 +377,23 @@ bool Sound::isPlayingSpeech() const {
 }
 
 bool Sound::isPlayingSfx() const {
-	return _mixer->isSoundHandleActive(_sfxHandle);
+	return _mixer->isSoundHandleActive(_sfxHandle) || _musicPlayer->isPlayingSfx();
+}
+
+bool Sound::isPlayingSfx(uint8 sfxId) const {
+	if (_useFloppySfx) {
+		int floppySfxId = sfxCdFloppyMapping[sfxId];
+		if (floppySfxId == -1)
+			return false;
+
+		return _musicPlayer->isPlayingSfx(floppySfxId);
+	}
+
+	return _lastPlayedDigitalSfx == sfxId && _mixer->isSoundHandleActive(_sfxHandle);
 }
 
 bool Sound::isPlayingMusic() {
-	return _musicPlayer->isPlaying();
+	return _musicPlayer->isPlayingMusic();
 }
 
 void Sound::resetSpeech() {
@@ -255,15 +454,15 @@ void Sound::playMusic(Common::String const &musicFilename, Common::String const
 	_musicPlayer->load(&file, (int32)file.size());
 	file.close();
 
-	_musicPlayer->play(priority, loop);
+	_musicPlayer->playMusic(priority, loop);
 }
 
 void Sound::stopMusic() {
-	_musicPlayer->stop();
+	_musicPlayer->stopMusic();
 }
 
 void Sound::pauseMusic(bool pause) {
-	_musicPlayer->pause(pause);
+	_musicPlayer->pauseMusic(pause);
 }
 
 void Sound::killAllSound() {
@@ -289,24 +488,29 @@ bool Sound::isMuted() const {
 	return soundIsMuted;
 }
 
-void Sound::playSfx(uint8 sfxId, int unk1, int unk2) {
-	if (g_engine->isCdVersion()) {
+void Sound::playSfx(uint8 sfxId, uint8 priority, int unk2) {
+	// Do not play floppy-only SFX using the CD SFX playing code
+	if (_useCdSfx && sfxId <= 48 && sfxId != 43 && sfxId != 44) {
 		playDosCDSfx(sfxId);
 	}
+	else if (_useFloppySfx && sfxId < 60) {
+		int floppySfxId = sfxCdFloppyMapping[sfxId];
+		if (floppySfxId == -1)
+			return;
+
+		playDosFloppySfx(floppySfxId, priority);
+	}
 }
 
 void Sound::stopSfx() {
 	_mixer->stopHandle(_sfxHandle);
+	_musicPlayer->stopAllSfx();
 }
 
 void Sound::playDosCDSfx(int sfxId) {
-	if (sfxId == 0) {
-		// TODO midi SFX
+	if (sfxId == 0 || sfxId > 48) {
 		return;
 	}
-	if (sfxId > 48) {
-		error("playDosCDSfx: Invalid sfxId %d", sfxId);
-	}
 	if (isPlayingSfx()) {
 		return;
 	}
@@ -319,43 +523,27 @@ void Sound::playDosCDSfx(int sfxId) {
 	Common::SeekableReadStream *srcStream = f.readStream((uint32)f.size());
 	Audio::SeekableAudioStream *stream = Audio::makeVOCStream(srcStream,
 															  Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
-	_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_sfxHandle, stream);
+	_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, stream);
+	_lastPlayedDigitalSfx = sfxId;
 }
 
-void Sound::playFloppySpeech(int tosIdx) {
-	Common::String filename;
-
-	switch (tosIdx) {
-	case 927 : filename = "CL1.VOC"; break;
-	case 905 : filename = "CL2.VOC"; break;
-	case 906 : filename = "CL3.VOC"; break;
-	case 907 : filename = "D4A-1.VOC"; break;
-	case 909 : filename = "D5A-1.VOC"; break;
-	case 910 : filename = "D6A-2.VOC"; break;
-	case 908 : filename = "D6C-2.VOC"; break;
-	case 916 : filename = "G10A-1.VOC"; break;
-	case 917 : filename = "G10B-1.VOC"; break;
-	case 925 : filename = "GL0A.VOC"; break;
-	case 926 : filename = "GL1B.VOC"; break;
-	case 924 : filename = "GL2A.VOC"; break;
-	case 928 : filename = "GL3A.VOC"; break; // TODO is this correct?
-	case 922 : filename = "K15A-1.VOC"; break;
-	case 913 : filename = "K9A-3.VOC"; break;
-	case 914 : filename = "K9C-3.VOC"; break;
-	case 915 : filename = "K9E-3.VOC"; break;
-	case 904 : filename = "M1-1.VOC"; break;
-	case 918 : filename = "M11A-1.VOC"; break;
-	case 919 : filename = "O12A-1.VOC"; break;
-	case 920 : filename = "O13A-1.VOC"; break;
-	case 921 : filename = "O14A-1.VOC"; break;
-	case 923 : filename = "S16A-1.VOC"; break;
-	case 912 : filename = "S8A-2.VOC"; break;
-	default : return;
+void Sound::playDosFloppySfx(byte floppySfxId, uint8 priority) {
+	if (_musicPlayer->isSampleSfx(floppySfxId)) {
+		playFloppySpeech(floppySfxId);
+	} else if (floppySfxId >= 10 && floppySfxId < 120) {
+		_musicPlayer->playSfx(floppySfxId, priority);
 	}
+}
+
+void Sound::playFloppySpeech(int floppySfxId) {
+	Common::String filename = _sfxFloppyDigFilenameTbl[floppySfxId];
+	if (filename.size() == 0)
+		return;
 
-	Common::Path path = Common::Path(filename);
+	Common::Path path = Common::Path(filename + ".voc");
 	Common::File f;
 	if (!f.open(path)) {
+		warning("Failed to load speech file %s", path.toString().c_str());
 		return;
 	}
 
@@ -366,11 +554,31 @@ void Sound::playFloppySpeech(int tosIdx) {
 }
 
 void Sound::startFadeOut() {
-	_musicPlayer->startFadeOut();
+	_musicPlayer->startFadeOutMusic();
 }
 
 bool Sound::isFading() {
-	return _musicPlayer->isFading();
+	return _musicPlayer->isFadingMusic();
+}
+
+int Sound::convertCdSpeechToFloppySfxId(int cdSfxId) {
+	int i = 0;
+	while (true) {
+		int entryCdSfxId = speechCdFloppyMapping[i].first;
+		if (entryCdSfxId == -1)
+			return -1;
+		if (entryCdSfxId == cdSfxId)
+			return speechCdFloppyMapping[i].second;
+		i++;
+	}
+}
+
+bool Sound::isUsingCdSfx() const {
+	return _useCdSfx;
+}
+
+bool Sound::isUsingFloppySfx() const {
+	return _useFloppySfx;
 }
 
 } // End of namespace Darkseed
diff --git a/engines/darkseed/sound.h b/engines/darkseed/sound.h
index ca6ff3d6dcb..aa340358608 100644
--- a/engines/darkseed/sound.h
+++ b/engines/darkseed/sound.h
@@ -58,12 +58,18 @@ enum class StartMusicId : uint8 {
 };
 
 class Sound {
+	// Floppy speech filenames from TOS1.DIG
+	char _sfxFloppyDigFilenameTbl[120][14];
+
 	Audio::Mixer *_mixer;
 	Audio::SoundHandle _speechHandle;
 	Audio::SoundHandle _sfxHandle;
 	MusicPlayer *_musicPlayer;
 	Common::Array<uint8> _didSpeech;
 	bool _useFloppyMusic;
+	bool _useCdSfx;
+	bool _useFloppySfx;
+	uint8 _lastPlayedDigitalSfx;
 
 public:
 	explicit Sound(Audio::Mixer *mixer);
@@ -78,6 +84,7 @@ public:
 	void stopSpeech();
 	bool isPlayingSpeech() const;
 	bool isPlayingSfx() const;
+	bool isPlayingSfx(uint8 sfxId) const;
 	bool isPlayingMusic();
 	void resetSpeech();
 	void playMusic(MusicId musicId, bool loop = true);
@@ -85,16 +92,21 @@ public:
 	void playMusic(Common::String const &filename, Common::String const *instrBankFilename = nullptr, uint8 priority = 0xFF, bool loop = false);
 	void stopMusic();
 	void pauseMusic(bool pause);
-	void playSfx(uint8 sfxId, int unk1, int unk2);
+	void playSfx(uint8 sfxId, uint8 priority, int unk2);
+	void playDosFloppySfx(byte sfxId, uint8 priority);
 	void stopSfx();
+	bool isUsingCdSfx() const;
+	bool isUsingFloppySfx() const;
 	void syncSoundSettings();
 	void killAllSound();
 	void startFadeOut();
 	bool isFading();
 
 private:
+	void loadTosDigData(Common::SeekableReadStream *in, int32 size);
 	void playDosCDSfx(int sfxId);
 	void playFloppySpeech(int tosIdx);
+	int convertCdSpeechToFloppySfxId(int cdSfxId);
 };
 
 } // namespace Darkseed


Commit: 3c014c513da3b4d997a41b92bc42e2f5d1b0edf5
    https://github.com/scummvm/scummvm/commit/3c014c513da3b4d997a41b92bc42e2f5d1b0edf5
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Add sound debug commands

Changed paths:
    engines/darkseed/debugconsole.cpp
    engines/darkseed/debugconsole.h


diff --git a/engines/darkseed/debugconsole.cpp b/engines/darkseed/debugconsole.cpp
index b46612a2438..67ca29bf4ae 100644
--- a/engines/darkseed/debugconsole.cpp
+++ b/engines/darkseed/debugconsole.cpp
@@ -36,6 +36,11 @@ DebugConsole::DebugConsole(TosText *tosText) : _tosText(tosText) {
 	registerCmd("invRemove",   WRAP_METHOD(DebugConsole, Cmd_invRemove));
 	registerCmd("changeDay",   WRAP_METHOD(DebugConsole, Cmd_changeDay));
 	registerCmd("searchTos",   WRAP_METHOD(DebugConsole, Cmd_searchTos));
+	registerCmd("playMusic",   WRAP_METHOD(DebugConsole, Cmd_playMusic));
+	registerCmd("stopMusic",   WRAP_METHOD(DebugConsole, Cmd_stopMusic));
+	registerCmd("playSfx",   WRAP_METHOD(DebugConsole, Cmd_playSfx));
+	registerCmd("playFloppySfx",   WRAP_METHOD(DebugConsole, Cmd_playFloppySfx));
+	registerCmd("playSpeech", WRAP_METHOD(DebugConsole, Cmd_playSpeech));
 }
 
 DebugConsole::~DebugConsole() {
@@ -200,6 +205,80 @@ bool DebugConsole::Cmd_searchTos(int argc, const char **argv) {
 	return true;
 }
 
+bool DebugConsole::Cmd_playMusic(int argc, const char **argv) {
+	if (argc != 2) {
+		debugPrintf("Usage: playMusic <trackNumber>\n");
+		return true;
+	}
+
+	uint8 trackNumber = (uint8)atoi(argv[1]);
+	if (trackNumber > 19) {
+		debugPrintf("Error: track number must be in range of 0 .. 19\n");
+		return true;
+	}
+
+	if (trackNumber < 8) {
+		g_engine->_sound->playMusic(static_cast<StartMusicId>(trackNumber));
+	}
+	else {
+		g_engine->_sound->playMusic(static_cast<MusicId>(trackNumber - 7), false);
+	}
+	return true;
+}
+
+bool DebugConsole::Cmd_stopMusic(int argc, const char** argv) {
+	g_engine->_sound->stopMusic();
+	return true;
+}
+
+bool DebugConsole::Cmd_playSfx(int argc, const char** argv) {
+	if (argc != 2) {
+		debugPrintf("Usage: playSfx <sfxNumber>\n");
+		return true;
+	}
+
+	uint8 sfxId = (uint8)atoi(argv[1]);
+	if (sfxId > 59) {
+		debugPrintf("Error: SFX number must be in range of 0 .. 59\n");
+		return true;
+	}
+
+	g_engine->_sound->playSfx(sfxId, 1, -1);
+	return true;
+}
+
+bool DebugConsole::Cmd_playFloppySfx(int argc, const char **argv) {
+	if (argc != 2) {
+		debugPrintf("Usage: playFloppySfx <sfxNumber>\n");
+		return true;
+	}
+
+	uint8 sfxId = (uint8)atoi(argv[1]);
+	if (sfxId < 10 || sfxId > 119) {
+		debugPrintf("Error: SFX number must be in range of 10 .. 119\n");
+		return true;
+	}
+
+	g_engine->_sound->playDosFloppySfx(sfxId, 1);
+	return true;
+}
+
+bool DebugConsole::Cmd_playSpeech(int argc, const char **argv) {
+	if (argc != 2) {
+		debugPrintf("Usage: playSpeech <speechNumber>\n");
+		return true;
+	}
+
+	int speechId = atoi(argv[1]);
+	if (speechId < 0 || speechId > 998) {
+		debugPrintf("Error: speech number must be in range of 0 .. 998\n");
+		return true;
+	}
+
+	g_engine->_sound->playTosSpeech(speechId);
+	return true;
+}
+
 void DebugConsole::printDayAndTime() {
 	int hour = g_engine->_currentTimeInSeconds / 60 / 60 + 1;
 	debugPrintf("Day %d at %d:%02d%s (%d seconds)\n",
diff --git a/engines/darkseed/debugconsole.h b/engines/darkseed/debugconsole.h
index 1d3fcc2be94..41f97ab2485 100644
--- a/engines/darkseed/debugconsole.h
+++ b/engines/darkseed/debugconsole.h
@@ -41,6 +41,11 @@ class DebugConsole : public GUI::Debugger {
 	bool Cmd_invRemove(int argc, const char **argv);
 	bool Cmd_changeDay(int argc, const char **argv);
 	bool Cmd_searchTos(int argc, const char **argv);
+	bool Cmd_playMusic(int argc, const char **argv);
+	bool Cmd_stopMusic(int argc, const char **argv);
+	bool Cmd_playSfx(int argc, const char **argv);
+	bool Cmd_playFloppySfx(int argc, const char **argv);
+	bool Cmd_playSpeech(int argc, const char **argv);
 	bool validateObjVarIndex(int16 varIdx);
 	void printDayAndTime();
 


Commit: 7afb254302a213a4d1527684f28c6556875f0433
    https://github.com/scummvm/scummvm/commit/7afb254302a213a4d1527684f28c6556875f0433
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Add some floppy-only SFX

Changed paths:
    engines/darkseed/animation.cpp
    engines/darkseed/darkseed.cpp
    engines/darkseed/darkseed.h
    engines/darkseed/usecode.cpp


diff --git a/engines/darkseed/animation.cpp b/engines/darkseed/animation.cpp
index 367edd5ca9b..7ba9fec36e3 100644
--- a/engines/darkseed/animation.cpp
+++ b/engines/darkseed/animation.cpp
@@ -305,6 +305,9 @@ void Animation::updateAnimation() {
 			if (_otherNspAnimationType_maybe == 8) {
 				_player->_frameIdx = _player->_animations.getAnimAt(0)._frameNo[_animIndexTbl[0]];
 			} else {
+				if (_player->_frameIdx == 3)
+					// Phone dial tone
+					g_engine->playSound(56, 5, -1);
 				_player->_frameIdx = _player->_animations.getAnimAt(2)._frameNo[_animIndexTbl[2]];
 			}
 		} else {
diff --git a/engines/darkseed/darkseed.cpp b/engines/darkseed/darkseed.cpp
index 5f5facfa9bc..bca23dca96a 100644
--- a/engines/darkseed/darkseed.cpp
+++ b/engines/darkseed/darkseed.cpp
@@ -278,10 +278,10 @@ void DarkseedEngine::gameLoop() {
 			if ((_room->_roomNumber < 10 || _room->_roomNumber == 61 || _room->_roomNumber == 62) && _currentTimeInSeconds % 3600 == 0) {
 				if (_room->_roomNumber == 7) {
 					if (!_sound->isPlayingSfx(45))
-					playSound(45, 5, -1);
+						playSound(45, 5, -1);
 				} else {
 					if (!_sound->isPlayingSfx(46))
-					playSound(46, 5, -1);
+						playSound(46, 5, -1);
 				}
 			}
 			_room->darkenSky();
@@ -550,11 +550,11 @@ void DarkseedEngine::handleInput() {
 			_counter_2c85_888b = 0;
 			_player->_playerWalkFrameIdx = (_player->_playerWalkFrameIdx + 1) % 8;
 			if ((_player->_playerWalkFrameIdx == 0 || _player->_playerWalkFrameIdx == 4)
-				&& currentRoomNumber != 0x22 && currentRoomNumber != 0x13
-				&& currentRoomNumber != 0x14 && currentRoomNumber != 0x15
-				&& currentRoomNumber != 16) {
-				//TODO
-			//							FUN_1208_0dac_sound_related(0x5c,CONCAT11((char)(uVar7 >> 8),5));
+					&& currentRoomNumber != 0x22 && currentRoomNumber != 0x13
+					&& currentRoomNumber != 0x14 && currentRoomNumber != 0x15
+					&& currentRoomNumber != 16) {
+				// Footstep
+				playSound(52, 5, -1);
 			}
 		}
 		_player->updateSprite();
@@ -785,7 +785,6 @@ void DarkseedEngine::handleInput() {
 						) {
 						_player->loadAnimations("opendoor.nsp");
 						_animation->setupOtherNspAnimation(0, 14);
-						// FUN_1208_0dac_sound_related(10,CONCAT11(extraout_AH,5));
 						playSound(1, 5, -1);
 						return;
 					}
@@ -799,7 +798,6 @@ void DarkseedEngine::handleInput() {
 					if (currentRoomNumber == 33 && roomExit.roomNumber == 34 && bVar) {
 						_player->loadAnimations("opendoor.nsp");
 						_animation->setupOtherNspAnimation(0, 25);
-						// FUN_1208_0dac_sound_related(24,CONCAT11(extraout_AH,5));
 						playSound(15, 5, -1); //open car door
 						return;
 					}
@@ -2006,9 +2004,9 @@ void DarkseedEngine::getPackageObj(int packageType) {
 	}
 }
 
-void DarkseedEngine::playSound(uint8 sfxId, uint8 unk1, int16 unk2) {
+void DarkseedEngine::playSound(uint8 sfxId, uint8 priority, int16 unk2) {
 	debug("Play SFX: %d", sfxId);
-	_sound->playSfx(sfxId, unk1, unk2);
+	_sound->playSfx(sfxId, priority, unk2);
 }
 
 void DarkseedEngine::nextFrame(int nspAminIdx) {
@@ -2118,6 +2116,9 @@ void DarkseedEngine::throwmikeinjail() {
 }
 
 void DarkseedEngine::runObjects() {
+	// FIXME This was missing; not sure where it is supposed to go
+	_soundTimer++;
+
 	if (((g_engine->_objectVar[44] != 0) && (g_engine->_objectVar[71] == 2))) {
 		g_engine->_objectVar[44] -= 2;
 		if (g_engine->_objectVar[44] == 0) {
@@ -2130,20 +2131,34 @@ void DarkseedEngine::runObjects() {
 	}
 	if (((_room->_roomNumber == 46) || (_room->_roomNumber == 60)) &&
 		(((_soundTimer & 15) == 0 && (g_engine->_objectVar[57] == 1)))) {
+		// Spaceship engine
 		playSound(9, 5, -1);
 	}
-	if ((_room->_roomNumber == 12) && (_soundTimer > 5)) {
+	// FIXME Changed the timer value from 5 to 4 because it more closely matches
+	// how the floppy version sounds. Maybe soundTimer is increased too slowly?
+	if ((_room->_roomNumber == 12) && (_soundTimer > 4)) {
+		// Library fountain
+		playSound(55, 5, -1);
 		_soundTimer = 0;
 	}
-	if (((_room->_roomNumber == 8) && (_soundTimer > 5)) && (g_engine->_objectVar[110] != 0)) {
+	if (((_room->_roomNumber == 8) && (_soundTimer > 4)) && (g_engine->_objectVar[110] != 0)) {
+		// Kitchen faucet
+		playSound(55, 5, -1);
 		_soundTimer = 0;
 	}
 	if ((_room->_roomNumber == 38) && ((_soundTimer & 31) == 0)) {
+		// Cocoon
 		playSound(23, 5, -1);
 	}
 	if ((_room->_roomNumber == 45) && ((_soundTimer & 63) == 0)) {
+		// Leech
 		playSound(10, 5, -1);
 	}
+	if ((_room->_roomNumber == 33 || _room->_roomNumber == 34) && _objectVar[71] == 2 && _soundTimer > 11) {
+		// Car engine running
+		playSound(51, 5, -1);
+		_soundTimer = 0;
+	}
 
 	int16 delbertSpriteIdx = 0;
 	if (_objectVar[141] == 8 && _room->_roomNumber == 31) {
@@ -2503,11 +2518,11 @@ void DarkseedEngine::runObjects() {
 		case 721:
 			if (((_room->_roomNumber < 10) || (_room->_roomNumber == 61)) || (_room->_roomNumber == 62)) {
 				if (_room->_roomNumber == 6) {
-//					FUN_1208_0dac_sound_related(93,5); TODO floppy sound
+					// Doorbell (loud)
 					playSound(27, 5, -1);
 				} else {
+					// Doorbell (quiet)
 					playSound(29, 5, -1);
-//					FUN_1208_0dac_sound_related(95,5); TODO floppy sound
 				}
 				_console->addI18NText(kI18N_TheDoorbellIsRingingText);
 			}
diff --git a/engines/darkseed/darkseed.h b/engines/darkseed/darkseed.h
index a15d50afc25..6a6ac26c35a 100644
--- a/engines/darkseed/darkseed.h
+++ b/engines/darkseed/darkseed.h
@@ -259,7 +259,7 @@ public:
 	void drawFullscreenPic();
 	void lookCode(int objNum);
 	void handleObjCollision(int targetObjNum);
-	void playSound(uint8 sfxId, uint8 unk1, int16 unk2);
+	void playSound(uint8 sfxId, uint8 priority, int16 unk2);
 	void nextFrame(int nspAminIdx);
 
 	void throwmikeinjail();
diff --git a/engines/darkseed/usecode.cpp b/engines/darkseed/usecode.cpp
index 5b093051d29..d8c74836678 100644
--- a/engines/darkseed/usecode.cpp
+++ b/engines/darkseed/usecode.cpp
@@ -639,7 +639,9 @@ void Darkseed::UseCode::useCode(int objNum) {
 		} else if ((objNum == 68) && (_objectVar[68] == 0)) {
 			if (_objectVar[12] == 2) {
 				if ((_objectVar[66] == 1) && (_objectVar[67] == 1)) {
-					g_engine->playSound(13, 5, -1);
+					// When opening the mausoleum door, the floppy version plays the sigils sound effect.
+					// The CD version plays the door sound effect. (Both sound effects are present in both versions.)
+					g_engine->playSound(g_engine->_sound->isUsingCdSfx() ? 13 : 12, 5, -1);
 					_objectVar[68] = 1;
 					g_engine->_animation->setupOtherNspAnimation(0, 23);
 				} else {
@@ -1146,9 +1148,11 @@ void UseCode::useCodeKeys(int16 actionObjNum, int16 targetObjNum) {
 	} else if (targetObjNum == 71) {
 		if (actionObjNum == 26) {
 			if (_objectVar[44] == 0) {
+				// Car engine start failure
 				g_engine->playSound(16, 5, -1);
 				_console->printTosText(708);
 			} else if (_objectVar[71] == 0) {
+				// Car engine start
 				g_engine->playSound(11, 5, -1);
 				_objectVar[71] = 2;
 				_console->printTosText(709);


Commit: 6a8209ef10a8b6ec8bcfd6940ecb1add1652302f
    https://github.com/scummvm/scummvm/commit/6a8209ef10a8b6ec8bcfd6940ecb1add1652302f
Author: Coen Rampen (crampen at gmail.com)
Date: 2025-09-29T19:55:55+02:00

Commit Message:
DARKSEED: Add SFX mode GUI option

Changed paths:
  A engines/darkseed/dialogs.cpp
  A engines/darkseed/dialogs.h
    engines/darkseed/POTFILES
    engines/darkseed/detection.h
    engines/darkseed/detection_tables.h
    engines/darkseed/metaengine.cpp
    engines/darkseed/metaengine.h
    engines/darkseed/module.mk


diff --git a/engines/darkseed/POTFILES b/engines/darkseed/POTFILES
index 11435c00a8b..7250caa9380 100644
--- a/engines/darkseed/POTFILES
+++ b/engines/darkseed/POTFILES
@@ -1,2 +1,3 @@
 engines/darkseed/darkseed.cpp
+engines/darkseed/dialogs.h
 engines/darkseed/metaengine.cpp
diff --git a/engines/darkseed/detection.h b/engines/darkseed/detection.h
index 778213a9936..9f8654cf40f 100644
--- a/engines/darkseed/detection.h
+++ b/engines/darkseed/detection.h
@@ -40,6 +40,7 @@ extern const ADGameDescription gameDescriptions[];
 
 #define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
 #define GAMEOPTION_FLOPPY_MUSIC GUIO_GAMEOPTIONS2
+#define GAMEOPTION_SFX_MODE GUIO_GAMEOPTIONS3
 
 } // End of namespace Darkseed
 
@@ -67,4 +68,10 @@ public:
 	}
 };
 
+enum DarkseedSfxMode {
+	SFX_MODE_CD_ONLY,
+	SFX_MODE_CD_PLUS_FLOPPY,
+	SFX_MODE_FLOPPY_ONLY
+};
+
 #endif // DARKSEED_DETECTION_H
diff --git a/engines/darkseed/detection_tables.h b/engines/darkseed/detection_tables.h
index 3e7fa435566..0961e940a07 100644
--- a/engines/darkseed/detection_tables.h
+++ b/engines/darkseed/detection_tables.h
@@ -88,7 +88,7 @@ const ADGameDescription gameDescriptions[] = {
 		Common::EN_ANY,
 		Common::kPlatformDOS,
 		ADGF_TESTING | ADGF_CD,
-		GUIO1(GAMEOPTION_FLOPPY_MUSIC)
+		GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
 	},
 	{	// 1.51 according to DS.BAT, 1.5P according to intro
 		"darkseed",
@@ -97,7 +97,7 @@ const ADGameDescription gameDescriptions[] = {
 		Common::EN_ANY,
 		Common::kPlatformDOS,
 		ADGF_TESTING | ADGF_CD,
-		GUIO1(GAMEOPTION_FLOPPY_MUSIC)
+		GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
 	},
 	{
 		"darkseed",
@@ -106,7 +106,7 @@ const ADGameDescription gameDescriptions[] = {
 		Common::DE_DEU,
 		Common::kPlatformDOS,
 		ADGF_TESTING | ADGF_CD,
-		GUIO1(GAMEOPTION_FLOPPY_MUSIC)
+		GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
 	},
 	{
 		"darkseed",
@@ -115,7 +115,7 @@ const ADGameDescription gameDescriptions[] = {
 		Common::FR_FRA,
 		Common::kPlatformDOS,
 		ADGF_TESTING | ADGF_CD,
-		GUIO1(GAMEOPTION_FLOPPY_MUSIC)
+		GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
 	},
 	{
 		"darkseed",
@@ -124,7 +124,7 @@ const ADGameDescription gameDescriptions[] = {
 		Common::ES_ESP,
 		Common::kPlatformDOS,
 		ADGF_TESTING | ADGF_CD,
-		GUIO1(GAMEOPTION_FLOPPY_MUSIC)
+		GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
 	},
 	{
 		"darkseed",
diff --git a/engines/darkseed/dialogs.cpp b/engines/darkseed/dialogs.cpp
new file mode 100644
index 00000000000..48be95854c6
--- /dev/null
+++ b/engines/darkseed/dialogs.cpp
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "base/plugins.h"
+#include "common/file.h"
+#include "common/hashmap.h"
+#include "common/ptr.h"
+#include "common/translation.h"
+#include "engines/advancedDetector.h"
+
+#include "darkseed/detection.h"
+#include "darkseed/dialogs.h"
+
+namespace Darkseed {
+
+OptionsWidget::OptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain) : OptionsContainerWidget(boss, name, "DarkseedGameOptionsDialog", domain) {
+	_guiOptions = ConfMan.get("guioptions", domain);
+
+	for (const ADExtraGuiOptionsMap *entry = optionsList; entry->guioFlag; ++entry)
+		if (checkGameGUIOption(entry->guioFlag, _guiOptions))
+			_checkboxes[entry->option.configOption] = new GUI::CheckboxWidget(widgetsBoss(), _dialogLayout + "." + entry->option.configOption, _(entry->option.label), _(entry->option.tooltip));
+
+	for (const PopUpOptionsMap *entry = popUpOptionsList; entry->guioFlag; ++entry)
+		if (checkGameGUIOption(entry->guioFlag, _guiOptions)) {
+			GUI::StaticTextWidget *textWidget = new GUI::StaticTextWidget(widgetsBoss(), _dialogLayout + "." + entry->configOption + "_desc", _(entry->label), _(entry->tooltip));
+			textWidget->setAlign(Graphics::kTextAlignRight);
+
+			_popUps[entry->configOption] = new GUI::PopUpWidget(widgetsBoss(), _dialogLayout + "." + entry->configOption);
+
+			for (uint i = 0; entry->items[i].label; ++i)
+				_popUps[entry->configOption]->appendEntry(_(entry->items[i].label), entry->items[i].configValue);
+		}
+}
+
+void OptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const {
+	layouts.addDialog(layoutName, overlayedLayout);
+	layouts.addLayout(GUI::ThemeLayout::kLayoutVertical).addPadding(0, 0, 0, 0);
+
+	for (const ADExtraGuiOptionsMap *entry = optionsList; entry->guioFlag; ++entry)
+		layouts.addWidget(entry->option.configOption, "Checkbox");
+
+	for (const PopUpOptionsMap *entry = popUpOptionsList; entry->guioFlag; ++entry) {
+		layouts.addLayout(GUI::ThemeLayout::kLayoutHorizontal).addPadding(0, 0, 0, 0);
+		layouts.addWidget(Common::String(entry->configOption) + "_desc", "OptionsLabel");
+		layouts.addWidget(entry->configOption, "PopUp").closeLayout();
+	}
+
+	layouts.closeLayout().closeDialog();
+}
+
+void OptionsWidget::load() {
+	for (const ADExtraGuiOptionsMap *entry = optionsList; entry->guioFlag; ++entry)
+		if (checkGameGUIOption(entry->guioFlag, _guiOptions))
+			_checkboxes[entry->option.configOption]->setState(ConfMan.getBool(entry->option.configOption, _domain));
+
+	for (const PopUpOptionsMap *entry = popUpOptionsList; entry->guioFlag; ++entry)
+		if (checkGameGUIOption(entry->guioFlag, _guiOptions))
+			_popUps[entry->configOption]->setSelectedTag(ConfMan.getInt(entry->configOption, _domain));
+}
+
+bool OptionsWidget::save() {
+	for (const ADExtraGuiOptionsMap *entry = optionsList; entry->guioFlag; ++entry)
+		if (checkGameGUIOption(entry->guioFlag, _guiOptions))
+			ConfMan.setBool(entry->option.configOption, _checkboxes[entry->option.configOption]->getState(), _domain);
+
+	for (const PopUpOptionsMap *entry = popUpOptionsList; entry->guioFlag; ++entry)
+		if (checkGameGUIOption(entry->guioFlag, _guiOptions))
+			ConfMan.setInt(entry->configOption, _popUps[entry->configOption]->getSelectedTag(), _domain);
+
+	return true;
+}
+
+} // End of namespace Darkseed
diff --git a/engines/darkseed/dialogs.h b/engines/darkseed/dialogs.h
new file mode 100644
index 00000000000..49b343b9355
--- /dev/null
+++ b/engines/darkseed/dialogs.h
@@ -0,0 +1,124 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DARKSEED_DIALOGS_H
+#define DARKSEED_DIALOGS_H
+
+#include "gui/ThemeEval.h"
+#include "gui/widget.h"
+#include "gui/widgets/popup.h"
+
+namespace Darkseed {
+
+struct PopUpOptionsItem {
+	const char *label;
+	int configValue;
+};
+
+#define POPUP_OPTIONS_ITEMS_TERMINATOR {nullptr, 0}
+
+struct PopUpOptionsMap {
+	const char *guioFlag;
+	const char *label;
+	const char *tooltip;
+	const char *configOption;
+	int defaultState;
+	PopUpOptionsItem items[10];
+};
+
+#define POPUP_OPTIONS_TERMINATOR                                                  \
+	{                                                                             \
+		nullptr, nullptr, nullptr, nullptr, 0, { POPUP_OPTIONS_ITEMS_TERMINATOR } \
+	}
+
+class OptionsWidget : public GUI::OptionsContainerWidget {
+public:
+	explicit OptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain);
+
+	// OptionsContainerWidget API
+	void load() override;
+	bool save() override;
+
+private:
+	// OptionsContainerWidget API
+	void defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const override;
+
+	Common::String _guiOptions;
+	Common::HashMap<Common::String, GUI::CheckboxWidget *> _checkboxes;
+	Common::HashMap<Common::String, GUI::PopUpWidget *> _popUps;
+};
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+	{
+		GAMEOPTION_ORIGINAL_SAVELOAD,
+		{
+			_s("Use original save/load screens"),
+			_s("Use the original save/load screens instead of the ScummVM ones"),
+			"original_menus",
+			false,
+			0,
+			0
+		}
+	},
+	{
+		GAMEOPTION_FLOPPY_MUSIC,
+		{
+			_s("Use floppy version music"),
+			_s("Use the music from the floppy version. The floppy version's music files must be copied to the SOUND directory."),
+			"use_floppy_music",
+			false,
+			0,
+			0
+		}
+	},
+	AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+
+static const PopUpOptionsMap popUpOptionsList[] = {
+	{
+		GAMEOPTION_SFX_MODE,
+		_s("SFX mode:"),
+		_s("Determines if the game should use CD version SFX only, CD SFX with additional floppy SFX, or floppy SFX only. Floppy SFX are only available if floppy music is used."),
+		"sfx_mode",
+		SFX_MODE_CD_ONLY,
+		{
+			{
+				_s("CD version SFX only"),
+				SFX_MODE_CD_ONLY
+			},
+			{
+				_s("CD + extra floppy SFX"),
+				SFX_MODE_CD_PLUS_FLOPPY
+			},
+			{
+				_s("Floppy version SFX only"),
+				SFX_MODE_FLOPPY_ONLY
+			},
+			POPUP_OPTIONS_ITEMS_TERMINATOR
+		}
+	},
+	POPUP_OPTIONS_TERMINATOR
+};
+
+} // End of namespace Darkseed
+
+#endif // DARKSEED_DIALOGS_H
diff --git a/engines/darkseed/metaengine.cpp b/engines/darkseed/metaengine.cpp
index edc8d2ec5a7..4a0aeb5c63a 100644
--- a/engines/darkseed/metaengine.cpp
+++ b/engines/darkseed/metaengine.cpp
@@ -26,45 +26,12 @@
 #include "darkseed/metaengine.h"
 #include "darkseed/detection.h"
 #include "darkseed/darkseed.h"
-
-namespace Darkseed {
-
-static const ADExtraGuiOptionsMap optionsList[] = {
-	{
-		GAMEOPTION_ORIGINAL_SAVELOAD,
-		{
-			_s("Use original save/load screens"),
-			_s("Use the original save/load screens instead of the ScummVM ones"),
-			"original_menus",
-			false,
-			0,
-			0
-		}
-	},
-	{
-		GAMEOPTION_FLOPPY_MUSIC,
-		{
-			_s("Use floppy version music"),
-			_s("Use the music from the floppy version. The floppy version's music files must be copied to the SOUND directory."),
-			"use_floppy_music",
-			false,
-			0,
-			0
-		}
-	},
-	AD_EXTRA_GUI_OPTIONS_TERMINATOR
-};
-
-} // End of namespace Darkseed
+#include "darkseed/dialogs.h"
 
 const char *DarkseedMetaEngine::getName() const {
 	return "darkseed";
 }
 
-const ADExtraGuiOptionsMap *DarkseedMetaEngine::getAdvancedExtraGuiOptions() const {
-	return Darkseed::optionsList;
-}
-
 Common::KeymapArray DarkseedMetaEngine::initKeymaps(const char *target) const {
 	using namespace Common;
 
@@ -113,6 +80,10 @@ bool DarkseedMetaEngine::hasFeature(MetaEngineFeature f) const {
 		(f == kSupportsLoadingDuringStartup);
 }
 
+GUI::OptionsContainerWidget *DarkseedMetaEngine::buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const {
+	return new Darkseed::OptionsWidget(boss, name, target);
+}
+
 #if PLUGIN_ENABLED_DYNAMIC(DARKSEED)
 	REGISTER_PLUGIN_DYNAMIC(DARKSEED, PLUGIN_TYPE_ENGINE, DarkseedMetaEngine);
 #else
diff --git a/engines/darkseed/metaengine.h b/engines/darkseed/metaengine.h
index ac26094a168..895177c4962 100644
--- a/engines/darkseed/metaengine.h
+++ b/engines/darkseed/metaengine.h
@@ -38,8 +38,8 @@ public:
 	 */
 	bool hasFeature(MetaEngineFeature f) const override;
 
-	const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override;
 	Common::KeymapArray initKeymaps(const char *target) const override;
+	GUI::OptionsContainerWidget *buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const override;
 };
 
 #endif // DARKSEED_METAENGINE_H
diff --git a/engines/darkseed/module.mk b/engines/darkseed/module.mk
index e5e21cc3e61..e94c1d6c6d9 100644
--- a/engines/darkseed/module.mk
+++ b/engines/darkseed/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS = \
 	cutscene.o \
 	darkseed.o \
 	debugconsole.o \
+	dialogs.o \
 	gamefont.o \
 	img.o \
 	inventory.o \




More information about the Scummvm-git-logs mailing list