[Scummvm-git-logs] scummvm master -> 26f1b8daa6c2ee4d7e67736b8e3f3447e11dcf15

criezy noreply at scummvm.org
Wed May 14 22:18:13 UTC 2025


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

Summary:
26f1b8daa6 DRASCULA: Add text-to-speech (TTS)


Commit: 26f1b8daa6c2ee4d7e67736b8e3f3447e11dcf15
    https://github.com/scummvm/scummvm/commit/26f1b8daa6c2ee4d7e67736b8e3f3447e11dcf15
Author: ellm135 (ellm13531 at gmail.com)
Date: 2025-05-14T23:18:10+01:00

Commit Message:
DRASCULA: Add text-to-speech (TTS)

Changed paths:
    engines/drascula/animation.cpp
    engines/drascula/converse.cpp
    engines/drascula/detection.cpp
    engines/drascula/detection.h
    engines/drascula/drascula.cpp
    engines/drascula/drascula.h
    engines/drascula/graphics.cpp
    engines/drascula/interface.cpp
    engines/drascula/metaengine.cpp
    engines/drascula/saveload.cpp
    engines/drascula/sound.cpp


diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index facb897f2dc..4f2b225ac86 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -21,6 +21,8 @@
 
 #include "drascula/drascula.h"
 
+#include "common/text-to-speech.h"
+
 namespace Drascula {
 
 void DrasculaEngine::updateAnim(int y, int destX, int destY, int width, int height, int count, byte* src, int delayVal, bool copyRectangle) {
@@ -75,6 +77,9 @@ void DrasculaEngine::animation_1_1() {
 			break;
 		color_abc(kColorRed);
 		centerText(_textmisc[1], 160, 100);
+
+		sayText(_textmisc[1], Common::TextToSpeechManager::INTERRUPT);
+
 		updateScreen();
 		if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit())
 			break;
@@ -766,6 +771,9 @@ void DrasculaEngine::animation_16_2() {
 			Common::strcpy_s(curPic, "his4_2.alg");
 
 		loadPic(curPic, screenSurface, HALF_PAL);
+
+		sayText(_texthis[i], Common::TextToSpeechManager::QUEUE);
+
 		centerText(_texthis[i], 180, 180);
 		updateScreen();
 
diff --git a/engines/drascula/converse.cpp b/engines/drascula/converse.cpp
index 9712864da1f..589cca51261 100644
--- a/engines/drascula/converse.cpp
+++ b/engines/drascula/converse.cpp
@@ -23,6 +23,8 @@
 
 #include "drascula/drascula.h"
 
+#include "common/text-to-speech.h"
+
 namespace Drascula {
 
 void DrasculaEngine::playTalkSequence(int sequence) {
@@ -195,6 +197,23 @@ void DrasculaEngine::converse(int index) {
 	// from 1(top) to 31
 	color_abc(kColorLightGreen);
 
+	Common::String ttsPhrase1 = phrase1;
+	Common::String ttsPhrase2 = phrase2;
+	Common::String ttsPhrase3 = phrase3;
+	Common::String ttsPhrase4 = phrase4;
+
+	if (_lang == kRussian) {
+		ttsPhrase1.replace('%', ' ');
+		ttsPhrase2.replace('%', ' ');
+		ttsPhrase3.replace('%', ' ');
+		ttsPhrase4.replace('%', ' ');
+	}
+
+	sayText(ttsPhrase1, Common::TextToSpeechManager::QUEUE);
+	sayText(ttsPhrase2, Common::TextToSpeechManager::QUEUE);
+	sayText(ttsPhrase3, Common::TextToSpeechManager::QUEUE);
+	sayText(ttsPhrase4, Common::TextToSpeechManager::QUEUE);
+
 	while (breakOut == 0 && !shouldQuit()) {
 		updateRoom();
 
@@ -223,6 +242,8 @@ void DrasculaEngine::converse(int index) {
 
 			print_abc_opc(phrase1, 2, kDialogOptionSelected);
 
+			sayText(ttsPhrase1, Common::TextToSpeechManager::INTERRUPT);
+
 			if (_leftMouseButton == 1) {
 				delay(100);
 				game1 = kDialogOptionClicked;
@@ -237,6 +258,8 @@ void DrasculaEngine::converse(int index) {
 
 			print_abc_opc(phrase2, phrase1_bottom + 2, kDialogOptionSelected);
 
+			sayText(ttsPhrase2, Common::TextToSpeechManager::INTERRUPT);
+
 			if (_leftMouseButton == 1) {
 				delay(100);
 				game2 = kDialogOptionClicked;
@@ -251,6 +274,8 @@ void DrasculaEngine::converse(int index) {
 
 			print_abc_opc(phrase3, phrase2_bottom + 2, kDialogOptionSelected);
 
+			sayText(ttsPhrase3, Common::TextToSpeechManager::INTERRUPT);
+
 			if (_leftMouseButton == 1) {
 				delay(100);
 				game3 = kDialogOptionClicked;
@@ -260,6 +285,8 @@ void DrasculaEngine::converse(int index) {
 		} else if (_mouseY > phrase3_bottom && _mouseY < phrase4_bottom) {
 			print_abc_opc(phrase4, phrase3_bottom + 2, kDialogOptionSelected);
 
+			sayText(ttsPhrase4, Common::TextToSpeechManager::INTERRUPT);
+
 			if (_leftMouseButton == 1) {
 				delay(100);
 				talk(phrase4, sound4);
@@ -267,6 +294,8 @@ void DrasculaEngine::converse(int index) {
 			}
 		} else if (_color != kColorLightGreen)
 			color_abc(kColorLightGreen);
+		else
+			_previousSaid.clear();
 
 		_system->delayMillis(10);
 		updateScreen();
diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp
index 2bbac38a2cb..088fb323f94 100644
--- a/engines/drascula/detection.cpp
+++ b/engines/drascula/detection.cpp
@@ -53,7 +53,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::EN_ANY,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -70,7 +70,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::FR_FRA,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -87,7 +87,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::FR_FRA,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -104,7 +104,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::DE_DEU,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -117,7 +117,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::IT_ITA,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -134,7 +134,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::IT_ITA,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -147,7 +147,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::ES_ESP,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -164,7 +164,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::ES_ESP,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -181,7 +181,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::RU_RUS,
 			Common::kPlatformDOS,
 			GF_PACKED,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -196,7 +196,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::EN_ANY,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -209,7 +209,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::FR_FRA,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -222,7 +222,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::FR_FRA,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -235,7 +235,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::DE_DEU,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -248,7 +248,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::IT_ITA,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -261,7 +261,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::IT_ITA,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
@@ -274,7 +274,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::ES_ESP,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 	{
@@ -286,7 +286,7 @@ static const DrasculaGameDescription gameDescriptions[] = {
 			Common::RU_RUS,
 			Common::kPlatformDOS,
 			ADGF_NO_FLAGS,
-			GUIO1(GUIO_LINKSPEECHTOSFX)
+			GUIO2(GAMEOPTION_TTS, GUIO_LINKSPEECHTOSFX)
 		},
 	},
 
diff --git a/engines/drascula/detection.h b/engines/drascula/detection.h
index 7a71682a8f5..eea9275fcf9 100644
--- a/engines/drascula/detection.h
+++ b/engines/drascula/detection.h
@@ -37,6 +37,7 @@ struct DrasculaGameDescription {
 };
 
 #define GAMEOPTION_ORIGINAL_SAVELOAD      GUIO_GAMEOPTIONS1
+#define GAMEOPTION_TTS                    GUIO_GAMEOPTIONS2
 
 } // End of namespace Drascula
 
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index ffc46414f7c..4a8a6f2fae2 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -23,6 +23,7 @@
 #include "common/keyboard.h"
 #include "common/file.h"
 #include "common/config-manager.h"
+#include "common/text-to-speech.h"
 #include "common/textconsole.h"
 #include "common/translation.h"
 
@@ -249,6 +250,18 @@ Common::Error DrasculaEngine::run() {
 		_lang = kEnglish;
 	}
 
+	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
+	if (ttsMan != nullptr) {
+		ttsMan->setLanguage(ConfMan.get("language"));
+		ttsMan->enable(ConfMan.getBool("tts_enabled"));
+
+		if (_lang == kRussian) {
+			_ttsTextEncoding = Common::CodePage::kWindows1251;
+		} else {
+			_ttsTextEncoding = Common::CodePage::kDos850;
+		}
+	}
+
 	setDebugger(new Console(this));
 
 	if (!loadDrasculaDat())
@@ -688,6 +701,9 @@ bool DrasculaEngine::runCurrentChapter() {
 			ConfMan.setBool("subtitles", !_subtitlesDisabled);
 
 			print_abc(_textsys[2], 96, 86);
+
+			sayText(_textsys[2], Common::TextToSpeechManager::INTERRUPT);
+
 			updateScreen();
 			delay(1410);
 		} else if (key == Common::KEYCODE_t) {
@@ -695,6 +711,9 @@ bool DrasculaEngine::runCurrentChapter() {
 			ConfMan.setBool("subtitles", !_subtitlesDisabled);
 
 			print_abc(_textsys[3], 94, 86);
+
+			sayText(_textsys[3], Common::TextToSpeechManager::INTERRUPT);
+
 			updateScreen();
 			delay(1460);
 		} else if (key == Common::KEYCODE_ESCAPE) {
@@ -1171,4 +1190,17 @@ void DrasculaEngine::freeTexts(char **ptr) {
 	free(ptr);
 }
 
+void DrasculaEngine::sayText(const Common::String &text, Common::TextToSpeechManager::Action action) {
+	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
+
+	// _previousSaid is used to prevent the TTS from looping when sayText is called inside a loop,
+	// for example when the cursor stays on a verb icon. Without it when the text ends it would speak
+	// the same text again.
+	// _previousSaid is cleared when appropriate to allow for repeat requests
+	if (ttsMan && ConfMan.getBool("tts_enabled") && _previousSaid != text) {
+		_previousSaid = text;
+		ttsMan->say(text, action, _ttsTextEncoding);
+	}
+}
+
 } // End of namespace Drascula
diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h
index ebc7d15a3e1..1a9b3d72259 100644
--- a/engines/drascula/drascula.h
+++ b/engines/drascula/drascula.h
@@ -34,6 +34,7 @@
 #include "common/savefile.h"
 #include "common/system.h"
 #include "common/util.h"
+#include "common/text-to-speech.h"
 
 #include "engines/savestate.h"
 
@@ -729,6 +730,8 @@ public:
 	void update_62();
 	void update_62_pre();
 	void update_102();
+	
+	void sayText(const Common::String &text, Common::TextToSpeechManager::Action action);
 
 private:
 	int _lang;
@@ -776,6 +779,8 @@ private:
 	RoomTalkAction *_roomActions;
 	TalkSequenceCommand *_talkSequences;
 	Common::String _saveNames[10];
+	Common::String _previousSaid;
+	Common::CodePage _ttsTextEncoding;
 
 	char **loadTexts(Common::File &in);
 	void freeTexts(char **ptr);
diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp
index a3d5e872fa9..9fd4090902f 100644
--- a/engines/drascula/graphics.cpp
+++ b/engines/drascula/graphics.cpp
@@ -24,6 +24,7 @@
 
 #include "common/stream.h"
 #include "common/textconsole.h"
+#include "common/text-to-speech.h"
 
 namespace Drascula {
 
@@ -80,8 +81,13 @@ void DrasculaEngine::moveCursor() {
 			color_abc(kColorRed);
 	} else if (!_menuScreen && _color != kColorLightGreen)
 		color_abc(kColorLightGreen);
-	if (_hasName && !_menuScreen)
+	if (_hasName && !_menuScreen) {
+		sayText(textName, Common::TextToSpeechManager::INTERRUPT);
+
 		centerText(textName, _mouseX, _mouseY);
+	} else if (!_menuBar && !_menuScreen)
+		_previousSaid.clear();
+	
 	if (_menuScreen)
 		showMenu();
 	else if (_menuBar)
diff --git a/engines/drascula/interface.cpp b/engines/drascula/interface.cpp
index 73b8a4d6233..68c4971011a 100644
--- a/engines/drascula/interface.cpp
+++ b/engines/drascula/interface.cpp
@@ -22,6 +22,74 @@
 #include "drascula/drascula.h"
 #include "graphics/cursorman.h"
 
+#include "common/text-to-speech.h"
+
+// The verbs are represented in-game as a picture, thus we are
+// adding transcriptions here
+// While only English, Spanish, Italian, and Russian are translated in-game,
+// they are translated for the TTS system here
+static const char *verbNamesEnglish[] = {
+	"Walk",
+	"Look",
+	"Take",
+	"Open",
+	"Close",
+	"Talk",
+	"Push"
+};
+
+static const char *verbNamesSpanish[] = {
+	"Ir a",
+	"Mirar",
+	"Coger",
+	"Abrir",
+	"Cerrar",
+	"Hablar",
+	"Mover"
+};
+
+static const char *verbNamesItalian[] = {
+	"Vai",
+	"Guarda",
+	"Prendi",
+	"Apri",
+	"Chiudi",
+	"Parla",
+	"Premi"
+};
+
+static const char *verbNamesFrench[] = {
+	"Marcher",
+	"Regarder",
+	"Ramasser",
+	"Ouvrir",
+	"Fermer",
+	"Parler",
+	"Pousser"
+};
+
+static const char *verbNamesGerman[] = {
+	"Gehe",
+	"Schau",
+	"Nimm",
+	"\231ffne",
+	"Schlie\341e",
+	"Rede",
+	"Dr\201cke"
+};
+
+static const char *verbNamesRussian[] = {
+	"\xc8\xe4\xf2\xe8",					// "Идти"
+	"\xd1\xec\xee\xf2\xf0\xe5\xf2\xfc",	// "Смотреть"
+	"\xc2\xe7\xff\xf2\xfc",				// "Взять"
+	"\xce\xf2\xea\xf0\xfb\xf2\xfc",		// "Открыть"
+	"\xc7\xe0\xea\xf0\xfb\xf2\xfc",		// "Закрыть"
+	"\xc3\xee\xe2\xee\xf0\xe8\xf2\xfc",	// "Говорить"
+	"\xd2\xee\xeb\xea\xe0\xf2\xfc"		// "Толкать"
+};
+
+static const int kConfirmExit = 1;
+
 namespace Drascula {
 
 void DrasculaEngine::setCursor(int cursor) {
@@ -80,6 +148,33 @@ void DrasculaEngine::selectVerb(int verb) {
 	if (verb > 0) {
 		takeObject = 1;
 		pickedObject = verb;
+
+		const char **verbNames;
+
+		switch (_lang) {
+		case kEnglish:
+			verbNames = verbNamesEnglish;
+			break;
+		case kSpanish:
+			verbNames = verbNamesSpanish;
+			break;
+		case kGerman:
+			verbNames = verbNamesGerman;
+			break;
+		case kFrench:
+			verbNames = verbNamesFrench;
+			break;
+		case kItalian:
+			verbNames = verbNamesItalian;
+			break;
+		case kRussian:
+			verbNames = verbNamesRussian;
+			break;
+		default:
+			verbNames = verbNamesEnglish;
+		}
+
+		sayText(verbNames[verb], Common::TextToSpeechManager::INTERRUPT);
 	} else {
 		takeObject = 0;
 		_hasName = false;
@@ -94,6 +189,8 @@ bool DrasculaEngine::confirmExit() {
 	centerText(_textsys[1], 160, 87);
 	updateScreen();
 
+	sayText(_textsys[kConfirmExit], Common::TextToSpeechManager::INTERRUPT);
+
 	delay(100);
 	while (!shouldQuit()) {
 		key = getScan();
@@ -134,16 +231,48 @@ void DrasculaEngine::showMenu() {
 				OBJWIDTH, OBJHEIGHT, cursorSurface, screenSurface);
 	}
 
-	if (x < 7)
+	if (x < 7) {
+		sayText(iconName[x], Common::TextToSpeechManager::INTERRUPT);
+
 		print_abc(iconName[x], _itemLocations[x].x - 2, _itemLocations[x].y - 7);
+	}
 }
 
 void DrasculaEngine::clearMenu() {
 	int n, verbActivated = 1;
 
 	for (n = 0; n < 7; n++) {
-		if (_mouseX > _verbBarX[n] && _mouseX < _verbBarX[n + 1])
+		if (_mouseX > _verbBarX[n] && _mouseX < _verbBarX[n + 1]) {
 			verbActivated = 0;
+
+			const char **verbNames;
+
+			switch (_lang) {
+			case kEnglish:
+				verbNames = verbNamesEnglish;
+				break;
+			case kSpanish:
+				verbNames = verbNamesSpanish;
+				break;
+			case kGerman:
+				verbNames = verbNamesGerman;
+				break;
+			case kFrench:
+				verbNames = verbNamesFrench;
+				break;
+			case kItalian:
+				verbNames = verbNamesItalian;
+				break;
+			case kRussian:
+				verbNames = verbNamesRussian;
+				break;
+			default:
+				verbNames = verbNamesEnglish;
+			}
+
+			sayText(verbNames[n], Common::TextToSpeechManager::INTERRUPT);
+		}
+		
 		copyRect(OBJWIDTH * n, OBJHEIGHT * verbActivated, _verbBarX[n], 2,
 						OBJWIDTH, OBJHEIGHT, cursorSurface, screenSurface);
 		verbActivated = 1;
diff --git a/engines/drascula/metaengine.cpp b/engines/drascula/metaengine.cpp
index f47b76e7d4f..dfb9af34fe9 100644
--- a/engines/drascula/metaengine.cpp
+++ b/engines/drascula/metaengine.cpp
@@ -43,6 +43,21 @@ static const ADExtraGuiOptionsMap optionsList[] = {
 			0
 		}
 	},
+
+#ifdef USE_TTS
+	{
+		GAMEOPTION_TTS,
+		{
+			_s("Enable Text to Speech"),
+			_s("Use TTS to read text in the game (if TTS is available)"),
+			"tts_enabled",
+			false,
+			0,
+			0
+		}
+	},
+#endif
+
 	AD_EXTRA_GUI_OPTIONS_TERMINATOR
 };
 
diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp
index ab44e3ce1a7..d73df33dc00 100644
--- a/engines/drascula/saveload.cpp
+++ b/engines/drascula/saveload.cpp
@@ -21,6 +21,7 @@
 
 #include "common/textconsole.h"
 #include "common/translation.h"
+#include "common/text-to-speech.h"
 
 #include "engines/savestate.h"
 #include "graphics/thumbnail.h"
@@ -427,6 +428,10 @@ bool DrasculaEngine::saveLoadScreen() {
 		}
 		print_abc(selectedName.c_str(), 117, 15);
 
+		if (selectedName.size() > 0) {
+			sayText(selectedName.c_str(), Common::TextToSpeechManager::INTERRUPT);
+		}
+
 		updateScreen();
 		updateEvents();
 
@@ -456,6 +461,8 @@ bool DrasculaEngine::saveLoadScreen() {
 			if (_mouseX > 208 && _mouseY > 123 && _mouseX < 282 && _mouseY < 149) {
 				// "Save" button
 				if (selectedName.empty()) {
+					sayText("Please select a slot", Common::TextToSpeechManager::INTERRUPT);
+
 					print_abc("Please select a slot", 117, 15);
 					updateScreen();
 					delay(200);
@@ -472,6 +479,8 @@ bool DrasculaEngine::saveLoadScreen() {
 			} else if (_mouseX > 125 && _mouseY > 123 && _mouseX < 199 && _mouseY < 149) {
 				// "Load" button
 				if (selectedName.empty()) {
+					sayText("Please select a slot", Common::TextToSpeechManager::INTERRUPT);
+
 					print_abc("Please select a slot", 117, 15);
 					updateScreen();
 					delay(200);
diff --git a/engines/drascula/sound.cpp b/engines/drascula/sound.cpp
index 5234181a7ba..01e90bf3156 100644
--- a/engines/drascula/sound.cpp
+++ b/engines/drascula/sound.cpp
@@ -26,11 +26,57 @@
 #include "common/config-manager.h"
 #include "common/textconsole.h"
 #include "common/substream.h"
+#include "common/text-to-speech.h"
 
 #include "backends/audiocd/audiocd.h"
 
 #include "drascula/drascula.h"
 
+// For consistency with the verb names, the English words in the volume controls menu (which are pictures) 
+// are translated into the game's language for text-to-speech
+static const char *volumeControlsEnglish[] = {
+	"Master",
+	"Voice/FX",
+	"Music"
+};
+
+static const char *volumeControlsSpanish[] = {
+	"Maestro",
+	"Voces/efectos de sonido",
+	"M\243sica"
+};
+
+static const char *volumeControlsItalian[] = {
+	"Principale",
+	"Voci/effetti sonori",
+	"Musica"
+};
+
+static const char *volumeControlsFrench[] = {
+	"Principal",
+	"Voix/effets sonores",
+	"Musique"
+};
+
+static const char *volumeControlsGerman[] = {
+	"Gesamtlautst\204rke",
+	"Stimmen/Soundeffekte",
+	"Musik"
+};
+
+// The Russian volume controls are translated in-game
+static const char *volumeControlsRussian[] = {
+	"\xce\xe1\xf9\xe8\xe9",		// "Общий"
+	"\xc3\xee\xeb\xee\xf1",		// "Голос"
+	"\xcc\xf3\xe7\xfb\xea\xe0"	// "Музыка"
+};
+
+enum VolumeControlType {
+	kMaster = 0,
+	kSpeechAndSFX = 1,
+	kMusic = 2
+};
+
 namespace Drascula {
 
 void DrasculaEngine::syncSoundSettings() {
@@ -154,6 +200,44 @@ void DrasculaEngine::volumeControls() {
 			ConfMan.setInt("music_volume", musicVolume);
 		}
 
+		const char **controlNames;
+
+		switch (_lang) {
+		case kEnglish:
+			controlNames = volumeControlsEnglish;
+			break;
+		case kSpanish:
+			controlNames = volumeControlsSpanish;
+			break;
+		case kGerman:
+			controlNames = volumeControlsGerman;
+			break;
+		case kFrench:
+			controlNames = volumeControlsFrench;
+			break;
+		case kItalian:
+			controlNames = volumeControlsItalian;
+			break;
+		case kRussian:
+			controlNames = volumeControlsRussian;
+			break;
+		default:
+			controlNames = volumeControlsEnglish;
+		}
+
+		Common::String ttsMessage;
+		if (_mouseX > 80 && _mouseX < 121)
+			ttsMessage = controlNames[kMaster];
+		else if (_mouseX > 136 && _mouseX < 178)
+			ttsMessage = controlNames[kSpeechAndSFX];
+		else if (_mouseX > 192 && _mouseX < 233)
+			ttsMessage = controlNames[kMusic];
+		else
+			_previousSaid.clear();
+
+		if (ttsMessage.size() > 0) {
+			sayText(ttsMessage, Common::TextToSpeechManager::INTERRUPT);
+		}
 	}
 
 	if (_lang == kSpanish && currentChapter != 6)




More information about the Scummvm-git-logs mailing list