[Scummvm-git-logs] scummvm master -> d8f456b57d721c2dd03f9a99006862cd0dae53a1
sev-
noreply at scummvm.org
Mon Jul 21 10:34:37 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:
d8f456b57d CINE: Add text-to-speech (TTS)
Commit: d8f456b57d721c2dd03f9a99006862cd0dae53a1
https://github.com/scummvm/scummvm/commit/d8f456b57d721c2dd03f9a99006862cd0dae53a1
Author: ellm135 (ellm13531 at gmail.com)
Date: 2025-07-21T12:34:34+02:00
Commit Message:
CINE: Add text-to-speech (TTS)
Changed paths:
engines/cine/cine.cpp
engines/cine/cine.h
engines/cine/detection.cpp
engines/cine/detection.h
engines/cine/gfx.cpp
engines/cine/main_loop.cpp
engines/cine/metaengine.cpp
engines/cine/object.cpp
engines/cine/various.cpp
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp
index 9b315d48ae4..b10e3fc1bb1 100644
--- a/engines/cine/cine.cpp
+++ b/engines/cine/cine.cpp
@@ -42,6 +42,138 @@
namespace Cine {
+#ifdef USE_TTS
+
+// The color names for the copy protection screens are images, so they are transcribed here for TTS
+static const char *copyProtectionColorsFWEnglish[] = {
+ "White",
+ "Yellow",
+ "Red",
+ "Orange",
+ "Black",
+ "Blue",
+ "Brown",
+ "Green"
+};
+
+static const char *copyProtectionColorsFWFrench[] = {
+ "Blanc",
+ "Jaune",
+ "Rouge",
+ "Orange",
+ "Noir",
+ "Bleu",
+ "Marron",
+ "Vert"
+};
+
+static const char *copyProtectionColorsFWGerman[] = {
+ "Wei\236",
+ "Gelb",
+ "Rot",
+ "Orange",
+ "Schwarz",
+ "Blau",
+ "Braun",
+ "Grun"
+};
+
+static const char *copyProtectionColorsFWSpanish[] = {
+ "Blanco",
+ "Amarillo",
+ "Rojo",
+ "Naranja",
+ "Negro",
+ "Azul",
+ "Marr\242n",
+ "Verde"
+};
+
+static const char *copyProtectionColorsOSEnglish[] = {
+ "Black",
+ "White",
+ "Yellow",
+ "Orange",
+ "Red",
+ "Brown",
+ "Grey",
+ "Pink",
+ "Purple",
+ "Light Blue",
+ "Dark Blue",
+ "Light Green",
+ "Dark Green"
+};
+
+static const char *copyProtectionColorsOSFrench[] = {
+ "Noir",
+ "Blanc",
+ "Jaune",
+ "Orange",
+ "Rouge",
+ "Marron",
+ "Gris",
+ "Rose",
+ "Violet",
+ "Bleu Clair",
+ "Bleu Fonc\202",
+ "Vert Clair",
+ "Vert Fonc\202"
+};
+
+static const char *copyProtectionColorsOSGerman[] = {
+ "Schwarz",
+ "Wei\236",
+ "Gelb",
+ "Orange",
+ "Rot",
+ "Braun",
+ "Grau",
+ "Pink",
+ "Violett",
+ "Hellblau",
+ "Dunkelblau",
+ "Hellgr\201n",
+ "Dunkelgr\201n"
+};
+
+static const char *copyProtectionColorsOSSpanish[] = {
+ "Negro",
+ "Blanco",
+ "Amarillo",
+ "Naranja",
+ "Rojo",
+ "Marr\242n",
+ "Gris",
+ "Rosa",
+ "Morado",
+ "Azul Claro",
+ "Azul Oscuro",
+ "Verde Claro",
+ "Verde Oscuro"
+};
+
+static const char *copyProtectionColorsOSItalian[] = {
+ "Nero",
+ "Bianco",
+ "Giallo",
+ "Arancione",
+ "Rosso",
+ "Marrone",
+ "Grigio",
+ "Rosa",
+ "Viola",
+ "Blu Chiaro",
+ "Blu Scuro",
+ "Verde Chiaro",
+ "Verde Scuro"
+};
+
+static const int kNumOfFWColors = 8;
+static const int kNumOfOSColors = 13;
+
+#endif
+
Sound *g_sound = nullptr;
CineEngine *g_cine = nullptr;
@@ -117,6 +249,39 @@ Common::Error CineEngine::run() {
_restartRequested = false;
+ Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
+ if (ttsMan != nullptr) {
+ ttsMan->setLanguage(ConfMan.get("language"));
+ ttsMan->enable(ConfMan.getBool("tts_enabled"));
+ }
+
+ switch (getLanguage()) {
+ case Common::EN_ANY:
+ case Common::EN_USA:
+ case Common::EN_GRB:
+ _ttsLanguage = kEnglish;
+ break;
+ case Common::FR_FRA:
+ _ttsLanguage = kFrench;
+ break;
+ case Common::DE_DEU:
+ _ttsLanguage = kGerman;
+ break;
+ case Common::ES_ESP:
+ _ttsLanguage = kSpanish;
+ break;
+ case Common::IT_ITA:
+ _ttsLanguage = kItalian;
+ break;
+ default:
+ _ttsLanguage = kEnglish;
+ break;
+ }
+
+ _copyProtectionColorScreen = false;
+ _copyProtectionTextScreen = false;
+ _saveInputMenuOpen = false;
+
do {
initialize();
@@ -330,4 +495,129 @@ void CineEngine::showSplashScreen() {
decoder.destroy();
}
+void CineEngine::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 button. 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 != nullptr && ConfMan.getBool("tts_enabled") && text != _previousSaid) {
+ if (getLanguage() == Common::DE_DEU) {
+ // German translation encodes à as 0x9e, but it's 0xe1 in codepage 850
+ Common::String ttsMessage = text;
+ ttsMessage.replace('\x9e', '\xe1');
+ ttsMan->say(ttsMessage, action, Common::CodePage::kDos850);
+ } else if (getLanguage() == Common::FR_FRA && getGameType() == GType_FW) {
+ // French translation for Future Wars encodes ê as 0x97, but it's 0x88 in codepage 850
+ Common::String ttsMessage = text;
+ ttsMessage.replace('\x97', '\x88');
+ ttsMan->say(ttsMessage, action, Common::CodePage::kDos850);
+ } else {
+ ttsMan->say(text, action, Common::CodePage::kDos850);
+ }
+
+ _previousSaid = text;
+ }
+}
+
+void CineEngine::stopTextToSpeech() {
+ Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
+ if (ttsMan != nullptr && ConfMan.getBool("tts_enabled") && ttsMan->isSpeaking()) {
+ ttsMan->stop();
+ _previousSaid.clear();
+ }
+}
+
+#ifdef USE_TTS
+
+void CineEngine::mouseOverButton() {
+ if (!_copyProtectionTextScreen && !_copyProtectionColorScreen) {
+ return;
+ }
+
+ uint16 mouseX, mouseY, mouseButton;
+ getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY);
+
+ int16 objIdx = getObjectUnderCursor(mouseX, mouseY);
+
+ if (objIdx != -1) {
+ if (_copyProtectionTextScreen) {
+ // Operation Stealth has other objects than just the "Ok" button in this screen
+ if (getGameType() == GType_OS && _objectTable[objIdx].frame != 151) {
+ return;
+ }
+
+ sayText("Ok", Common::TextToSpeechManager::INTERRUPT);
+ } else if (_copyProtectionColorScreen) {
+ const char **colors;
+
+ if (getGameType() == GType_FW) {
+ // The Amiga and Atari versions use a different copy protection screen from the DOS version
+ // and don't have these color buttons
+ // The only exception is the US Amiga version, which uses the color screen
+ if (getPlatform() != Common::kPlatformDOS && getLanguage() != Common::EN_USA) {
+ return;
+ }
+
+ int16 index = objIdx - 150;
+
+ if (index < 0 || index >= kNumOfFWColors) {
+ return;
+ }
+
+ switch (_ttsLanguage) {
+ case kEnglish:
+ colors = copyProtectionColorsFWEnglish;
+ break;
+ case kFrench:
+ colors = copyProtectionColorsFWFrench;
+ break;
+ case kGerman:
+ colors = copyProtectionColorsFWGerman;
+ break;
+ case kSpanish:
+ colors = copyProtectionColorsFWSpanish;
+ break;
+ default:
+ colors = copyProtectionColorsFWEnglish;
+ break;
+ }
+ sayText(colors[index], Common::TextToSpeechManager::INTERRUPT);
+ } else {
+ int16 index = objIdx - 240;
+
+ if (index < 0 || index >= kNumOfOSColors) {
+ return;
+ }
+
+ switch (_ttsLanguage) {
+ case kEnglish:
+ colors = copyProtectionColorsOSEnglish;
+ break;
+ case kFrench:
+ colors = copyProtectionColorsOSFrench;
+ break;
+ case kItalian:
+ colors = copyProtectionColorsOSItalian;
+ break;
+ case kGerman:
+ colors = copyProtectionColorsOSGerman;
+ break;
+ case kSpanish:
+ colors = copyProtectionColorsOSSpanish;
+ break;
+ default:
+ colors = copyProtectionColorsOSEnglish;
+ break;
+ }
+ sayText(colors[index], Common::TextToSpeechManager::INTERRUPT);
+ }
+ }
+ } else {
+ _previousSaid.clear();
+ }
+}
+
+#endif
+
} // End of namespace Cine
diff --git a/engines/cine/cine.h b/engines/cine/cine.h
index 7f1ec1f43f1..b8c4729d565 100644
--- a/engines/cine/cine.h
+++ b/engines/cine/cine.h
@@ -31,6 +31,7 @@
#include "common/hash-str.h"
#include "common/random.h"
#include "common/events.h"
+#include "common/text-to-speech.h"
#include "engines/engine.h"
@@ -122,6 +123,14 @@ enum CINEAction {
kActionMenuOptionDown
};
+enum TTSLanguage {
+ kEnglish = 0,
+ kFrench = 1,
+ kGerman = 2,
+ kSpanish = 3,
+ kItalian = 4
+};
+
class CineConsole;
class CineEngine : public Engine {
@@ -159,6 +168,12 @@ public:
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
+ void sayText(const Common::String &text, Common::TextToSpeechManager::Action action);
+ void stopTextToSpeech();
+#ifdef USE_TTS
+ void mouseOverButton();
+#endif
+
const CINEGameDescription *_gameDescription;
Common::File _partFileHandle;
@@ -170,6 +185,12 @@ public:
bool _restartRequested;
+ Common::String _previousSaid;
+ TTSLanguage _ttsLanguage;
+ bool _copyProtectionTextScreen;
+ bool _copyProtectionColorScreen;
+ bool _saveInputMenuOpen;
+
private:
void initialize();
void showSplashScreen();
diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp
index 0e2776ebdf6..ef037e81fac 100644
--- a/engines/cine/detection.cpp
+++ b/engines/cine/detection.cpp
@@ -45,7 +45,7 @@ static const DebugChannelDef debugFlagList[] = {
class CineMetaEngineDetection : public AdvancedMetaEngineDetection<Cine::CINEGameDescription> {
public:
CineMetaEngineDetection() : AdvancedMetaEngineDetection(Cine::gameDescriptions, cineGames) {
- _guiOptions = GUIO3(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TRANSPARENT_DIALOG_BOXES);
+ _guiOptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TRANSPARENT_DIALOG_BOXES, GAMEOPTION_TTS);
}
const char *getName() const override {
diff --git a/engines/cine/detection.h b/engines/cine/detection.h
index 02e869ed460..f608e64e2cc 100644
--- a/engines/cine/detection.h
+++ b/engines/cine/detection.h
@@ -49,6 +49,7 @@ struct CINEGameDescription {
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
#define GAMEOPTION_TRANSPARENT_DIALOG_BOXES GUIO_GAMEOPTIONS2
+#define GAMEOPTION_TTS GUIO_GAMEOPTIONS3
} // End of namespace Cine
diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp
index 51d0b8dde6d..81dc4106b52 100644
--- a/engines/cine/gfx.cpp
+++ b/engines/cine/gfx.cpp
@@ -93,6 +93,381 @@ static const byte mouseCursorCross[] = {
0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00
};
+#ifdef USE_TTS
+
+// Most text on the copy protection screens are images, so they are transcribed here for TTS
+static const char *copyProtectionTextsFWDOS[] = {
+ // English
+ "Copy Protection\n"
+ "On the back cover of your \"Future Wars\" manual is a full color representation of the copy protection screen.\n"
+ "When the paint spots flash on-screen, indicate which color they are on the illustration. "
+ "You will be asked to do this twice.\n"
+ "Failure to do this correctly will result in a midnight visit to your house by the Copy-Protection Police!\n"
+ "Click on OK when ready.",
+ // French
+ "Protection\n"
+ "En vous basant sur l'illustration couleur figurant au dos de votre manuel \"Les Voyageurs du Temps\", "
+ "retroveuz la couleur de la t\203che clignotante \205 l'\202cran.\n"
+ "Il vous faudra r\202pondre correctement deux fois au test pour acc\202der au jeu.",
+ // German
+ "Kopierschutz\n"
+ "Auf der R\201ckseite des Einbandes der \"Future Wars\" Anleitung findest Du einen farbigen "
+ "Abdruck der Kopierschutzabfrage des Programmes.\n"
+ "Du mu\236t nur die richtige Farbe des blinkenden Ausschnitts auf dem Bildschirm gem\204\236 der "
+ "R\201ckseite der Anleitung angeben.\n"
+ "Du hast zwei Versuche.",
+ // Spanish
+ "Protecci\242n\n"
+ "Usando la ilustraci\242n a color de la contreportade del manuel de Future Wars, encuentra el "
+ "color que parpadea en la pantella.\n"
+ "Deberas responder correctamente dos veces para poder acceder el juego."
+};
+
+static const char *copyProtectionTextsFWAmigaAtari[] = {
+ // English
+ "Copy Protection\n"
+ "Place the grid you have been given on the page whose number will be indicated.\n"
+ "Then state which of the illustrations displayed on the screen is at the intersection of the column and "
+ "line requested.",
+ // French
+ "Protection\n"
+ "Placez la grille qui vous est fournie sur la page dont le numero vous sera indiqu\202.\n"
+ "D\202signez laquelle des vignettes affich\202es \205 l'\202cran se trouve \205 l'intersection de la colonne et "
+ "la ligne demand\202e.",
+ // German
+ "Sicherheitsabfrage\n"
+ "Bitte die Gitterfolie auf die Seite legen, die angezeigt wird!\n"
+ "Dann klicken Sie auf das entsprechende Feld.",
+ // Spanish
+ "Protecci\242n contra copia\n"
+ "Situa la rejilla de plastico que hay en el paquete sobre la p\240gina cuyo numero se indica.\n"
+ "Entonces identifica que ilustraci\242n es la que te solicita el programa "
+ "(columna y fila) ya pincha sobre ella.",
+ // Italian
+ "Protezione da copie illegali\n"
+ "Metti la griglia che hai trovato nella confezione sulla pagina del manuale il cui numero \212 indicato.\n"
+ "Poi indica quale delle illustrazioni visualizzate si trova all'intersezione della colonna e della linea richieste."
+};
+
+static const char *copyProtectionTextsOSEnglish[] = {
+ "Operation Stealth",
+ "The following information is classified: "
+ "Top Secret",
+ "To gain access to this file match the proper color codes from your color code card. Refer to your system "
+ "documentation for complete information on security procedures.",
+ "To gain access to this file match the flashing area displayed on your monitor with the proper color code "
+ "from the back of your system documentation." // Alternative used by US Amiga and DOS (not 256 colors) versions
+};
+
+// Used by the GB Amiga/Atari versions
+static const char *copyProtectionTextsOSEnglishAlt[] = {
+ "Operation Stealth",
+ "The information enclosed in this file is classified: "
+ "Secret Defense",
+ "Please check with the color codes card to confirm your habilitation."
+};
+
+static const char *copyProtectionTextsOSFrench[] = {
+ "Operation Stealth",
+ "Les informations contenues dans ce dossier sont classees: "
+ "Secret Defense",
+ "Veuillez vous referer a la carte des codes de couleurs pour confirmer votre habilitation."
+};
+
+static const char *copyProtectionTextsOSGerman[] = {
+ "Operation Stealth",
+ "Die Informationen dieses Dossiers sind: "
+ "Streng Geheim",
+ "Bitte entnehmen Sie der Codekarte die zugeh\224rige Farbe, um Ihre Zugriffsberechtigung zu best\204tigen."
+};
+
+static const char *copyProtectionTextsOSSpanish[] = {
+ "Operation Stealth",
+ "Las informaciones contenidas en este dossier son claves: "
+ "Secretas",
+ "Consulta la carta de colores para confirmar tu autorizacion."
+};
+
+static const char *copyProtectionTextsOSItalian[] = {
+ "Operation Stealth",
+ "Le informazioni contenute in questo incartamento sono classificate: "
+ "Segreto Difesa",
+ "Vogliate fare riferimento alla scheda dei codici colori per confermare la vostra abilitazione."
+};
+
+static const char *copyProtectionFailTextsOS[] = {
+ "Sorry, the colors you just chose don't match.", // English
+ "Les couleurs que vous avez choisies ne correspondent pas.", // French
+ "Die Farben, die Sie gew\204hlt haben, sind falsch.", // German
+ "Los colores elegidos no son correctos.", // Spanish
+ "I colori che avete scelto non corrispondono." // Italian
+};
+
+// Other text is also in the form of images, and transcribed here
+static const char *theEndTexts[] = {
+ "The End", // English
+ "La Fin", // French
+ "Das Ende", // German
+ "El Fin", // Spanish
+ "La Fine" // Italian
+};
+
+static const char *openingCreditsFWEnglish[] = {
+ "Designed and programmed by Paul Cuisset",
+ "Visual design by Eric Chahi",
+ "Music composed by Jean Baudlot",
+ "Future Wars: Adventures in Time\nCopyright 1990 Delphine Software", // DOS only (except for US version)
+ "Future Wars: Time Travellers", // Amiga/Atari only
+ "IBM PC version by Daniel Morais" // DOS only
+};
+
+static const char *openingCreditsFWFrench[] = {
+ "Conception et programme Paul Cuisset",
+ "Graphisme et animations Eric Chahi",
+ "Musique et bruitages Jean Baudlot",
+ "Les Voyageurs du Temps: La Menace\nCopyright 1990 Delphine Software", // DOS only
+ "Les Voyageurs du Temps: La Menace", // Amiga/Atari only
+ "Version IBM PC Daniel Morais" // DOS only
+};
+
+// German, Spanish, and Italian credits are in English in-game, but are translated here
+// for TTS
+static const char *openingCreditsFWGerman[] = {
+ "Entwurf und Programm Paul Cuisset",
+ "Visuelle Gestaltung Eric Chahi",
+ "Musik Jean Baudlot",
+ "Future Wars: Adventures in Time\nCopyright 1990 Delphine Software", // DOS only
+ "Future Wars: Time Travellers", // Amiga/Atari only
+ "IBM PC Version Daniel Morais" // DOS only
+};
+
+static const char *openingCreditsFWSpanish[] = {
+ "Dise\244o y programa Paul Cuisset",
+ "Visual dise\244o Eric Chahi",
+ "M\243sica Jean Baudlot",
+ "Future Wars: Adventures in Time\nCopyright 1990 Delphine Software", // DOS only
+ "Future Wars: Time Travellers", // Amiga/Atari only
+ "Versi\242n de IBM PC Daniel Morais" // DOS only
+};
+
+static const char *openingCreditsFWItalian[] = {
+ "Design e programmazione di Paul Cuisset",
+ "Direzione grafica di Eric Chahi",
+ "Musica composta da Jean Baudlot",
+ "", // DOS only (no DOS version exists)
+ "Future Wars: Time Travellers", // Amiga/Atari only
+ "" // DOS only (no DOS version exists)
+};
+
+static const char *endCreditsFW[] = {
+ // English, first line
+ "Design: Paul Cuisset",
+ // English, second line DOS
+ "IBM PC Version: Daniel Morais",
+ // English, second line Amiga/Atari
+ "Program: Paul Cuisset",
+ // English, remainder of credits
+ "Graphics: Eric Chahi\n"
+ "Music: Jean Baudlot\n"
+ "Sound effects: Antoine O'Heix\n"
+ "Delphine Studio Midi: Marc Minier\n"
+ "Technical help: Philippe Chastel, Jesus Martinez\n"
+ "Digitized sounds sampling: Philippe Chastel, Paul Cuisset, Antoine O'Heix, Jesus Martinez\n"
+ "Cinematique interpreter: Paul Cuisset\n"
+ "Many thanks to: Philippe Delamarre, Emmanuel Lecoz, Michael Sportouch, Peter Stone, Matthew Tims, "
+ "Patricia Vermander",
+
+ // French, first line
+ "Scenario: Paul Cuisset",
+ // French, second line DOS
+ "Version IBM PC: Daniel Morais",
+ // French, second line Amiga/Atari
+ "Programmation: Paul Cuisset",
+ // French, remainder of credits
+ "Graphismes: Eric Chahi\n"
+ "Musiques: Jean Baudlot\n"
+ "Bruitages: Antoine O'Heix\n"
+ "Delphine Studio Midi: Marc Minier\n"
+ "Aide technique: Philippe Chastel, Jesus Martinez\n"
+ "Echantillonage sons numeriques: Philippe Chastel, Paul Cuisset, Antoine O'Heix, Jesus Martinez\n"
+ "Systeme Cinematique: Paul Cuisset\n"
+ "Nous tenons \205 remercier: Philippe Delamarre, Emmanuel Lecoz, Michael Sportouch, Peter Stone, Matthew Tims, "
+ "Patricia Vermander",
+
+ // German, first line
+ "Entwurf: Paul Cuisset",
+ // German, second line DOS
+ "IBM PC Version: Daniel Morais",
+ // German, second line Amiga/Atari
+ "Programmierung: Paul Cuisset",
+ // German, remainder of credits
+ "Grafiken: Eric Chahi\n"
+ "Musiken: Jean Baudlot\n"
+ "Soundeffekte: Antoine O'Heix\n"
+ "Delphine Studio Midi: Marc Minier\n"
+ "Technische Hilfe: Philippe Chastel, Jesus Martinez\n"
+ "Sampling digitalisierter Kl\204nge: Philippe Chastel, Paul Cuisset, Antoine O'Heix, Jesus Martinez\n"
+ "Cinematique System: Paul Cuisset\n"
+ "Wir danken: Philippe Delamarre, Emmanuel Lecoz, Michael Sportouch, Peter Stone, Matthew Tims, "
+ "Patricia Vermander",
+
+ // Spanish, first line
+ "Dise\244o: Paul Cuisset",
+ // Spanish, second line DOS
+ "Versi\242n de IBM PC: Daniel Morais",
+ // Spanish, second line Amiga/Atari
+ "Programaci\242n: Paul Cuisset",
+ // Spanish, remainder of credits
+ "Gr\240ficos: Eric Chahi\n"
+ "M\243sicas: Jean Baudlot\n"
+ "Efectos de sonido: Antoine O'Heix\n"
+ "Delphine Studio Midi: Marc Minier\n"
+ "Ayuda Tecnica: Philippe Chastel, Jesus Martinez\n"
+ "Muestreo de sonidos digitalizados: Philippe Chastel, Paul Cuisset, Antoine O'Heix, Jesus Martinez\n"
+ "Sistema Cinematique: Paul Cuisset\n"
+ "Muchas gracias a: Philippe Delamarre, Emmanuel Lecoz, Michael Sportouch, Peter Stone, Matthew Tims, "
+ "Patricia Vermander",
+
+ // Italian, first line
+ "Design: Paul Cuisset",
+ // Italian, second line DOS (no Italian DOS version exists)
+ "",
+ // Italian, second line Amiga/Atari
+ "Programmazione: Paul Cuisset",
+ // Italian, remainder of credits
+ "Grafica: Eric Chahi\n"
+ "Musiche: Jean Baudlot\n"
+ "Effetti sonori: Antoine O'Heix\n"
+ "Delphine Studio Midi: Marc Minier\n"
+ "Aiuto tecnico: Philippe Chastel, Jesus Martinez\n"
+ "Campionamento di suoni digitalizzati: Philippe Chastel, Paul Cuisset, Antoine O'Heix, Jesus Martinez\n"
+ "Sistema Cinematique: Paul Cuisset\n"
+ "Sentiti ringraziamenti a: Philippe Delamarre, Emmanuel Lecoz, Michael Sportouch, Peter Stone, Matthew Tims, "
+ "Patricia Vermander"
+};
+
+static const char *openingCreditsOSEnglish[] = {
+ "Script\nP. Cuisset\nP. Chastel",
+ "Illustrations\nImagex\nM. Bacque\nE. Lecoz",
+ "Programming\nP. Cuisset\nP. Chastel\nJ. Martinez",
+ "Music\nJ. Baudlot \nEffects\nM. Minier"
+};
+
+static const char *openingCreditsOSFrench[] = {
+ "Scenario\nP. Cuisset\nP. Chastel",
+ "Illustrations\nImagex\nM. Bacque\nE. Lecoz",
+ "Programme\nP. Cuisset\nP. Chastel\nJ. Martinez",
+ "Musique\nJ. Baudlot \nBruitages\nM. Minier"
+};
+
+static const char *openingCreditsOSGerman[] = {
+ "Skript\nP. Cuisset\nP. Chastel",
+ "Illustrationen\nImagex\nM. Bacque\nE. Lecoz",
+ "Programm\nP. Cuisset\nP. Chastel\nJ. Martinez",
+ "Musik\nJ. Baudlot \nSoundeffekte\nM. Minier"
+};
+
+static const char *openingCreditsOSSpanish[] = {
+ "Guion\nP. Cuisset\nP. Chastel",
+ "Ilustraciones\nImagex\nM. Bacque\nE. Lecoz",
+ "Programa\nP. Cuisset\nP. Chastel\nJ. Martinez",
+ "M\243sica\nJ. Baudlot \nEfectos\nM. Minier"
+};
+
+static const char *openingCreditsOSItalian[] = {
+ "Copione\nP. Cuisset\nP. Chastel",
+ "Illustrazioni\nImagex\nM. Bacque\nE. Lecoz",
+ "Programmazione\nP. Cuisset\nP. Chastel\nJ. Martinez",
+ "Musica\nJ. Baudlot \nEffetti\nM. Minier"
+};
+
+static const char *endCreditsOS[] = {
+ // English
+ "Script\n Paul Cuisset, Philippe Chastel\n"
+ "Programming\n Paul Cuisset, Philippe Chastel, J\202sus Martinez, Daniel Morais IBM PC\n"
+ "Illustrations\n Mich\212le Bacqu\202, Imagex, Emmanuel Lecoz\n"
+ "Music\n Jean Baudlot\n"
+ "Sound effects\n Marc Minier\n"
+ "User's manual\n Michael Sportouch\n"
+ "Illustration manual\n Jean-Pierre Fert\202\n"
+ "Packaging\n Philippe Delamarre\n"
+ "Our special thanks to\n Patricia Vermander, Claire Le Hello, Muriel Fraboni\n",
+ // English, final credits screen
+ "Delphine team hopes you had a great time with %s and we thank you for your support.\n"
+ "See you soon in our next adventure.",
+
+ // French
+ "Sc\202nario\n Paul Cuisset, Philippe Chastel\n"
+ "Programmation\n Paul Cuisset, Philippe Chastel, J\202sus Martinez, Daniel Morais IBM PC\n"
+ "Graphismes\n Mich\212le Bacqu\202, Imagex, Emmanuel Lecoz\n"
+ "Musique\n Jean Baudlot\n"
+ "Bruitages\n Marc Minier\n"
+ "Documentation notice\n Michael Sportouch\n"
+ "Illustration notice\n Jean-Pierre Fert\202\n"
+ "Packaging\n Philippe Delamarre\n"
+ "Remerciements\n Patricia Vermander, Claire Le Hello, Muriel Fraboni\n",
+ // French, final credits screen
+ "Toute l'\202quipe de Delphine esp\212re que John Glames vous a fait passer de bons moments, "
+ "et vous remercie de votre confiance.\n"
+ "A bient\223t pour une prochaine aventure.",
+
+ // German
+ "Skript\n Paul Cuisset, Philippe Chastel\n"
+ "Programmierung\n Paul Cuisset, Philippe Chastel, J\202sus Martinez, Daniel Morais IBM PC\n"
+ "Illustrationen\n Mich\212le Bacqu\202, Imagex, Emmanuel Lecoz\n"
+ "Musik\n Jean Baudlot\n"
+ "Soundeffekte\n Marc Minier\n"
+ "Bedienungsanleitung\n Michael Sportouch\n"
+ "Illustrationshandbuch\n Jean-Pierre Fert\202\n"
+ "Verpackung\n Philippe Delamarre\n"
+ "Unser Dank gilt\n Patricia Vermander, Claire Le Hello, Muriel Fraboni\n",
+ // German, final credits screen
+ "Delphine Team hofft, Sie hatten eine tolle Zeit mit John Glames und dankt Ihnen f\201r Ihre Unterst\201tzung.\n"
+ "Bis bald bei unserem n\204chsten Abenteuer.",
+
+ // Spanish
+ "Guion\n Paul Cuisset, Philippe Chastel\n"
+ "Programaci\242n\n Paul Cuisset, Philippe Chastel, J\202sus Martinez, Daniel Morais IBM PC\n"
+ "Ilustraciones\n Mich\212le Bacqu\202, Imagex, Emmanuel Lecoz\n"
+ "M\243sica\n Jean Baudlot\n"
+ "Efectos de sonido\n Marc Minier\n"
+ "Manual de usuario\n Michael Sportouch\n"
+ "Manual de ilustraciones\n Jean-Pierre Fert\202\n"
+ "Embalaje\n Philippe Delamarre\n"
+ "Gracias a\n Patricia Vermander, Claire Le Hello, Muriel Fraboni\n",
+ // Spanish, final credits screen
+ "Todo el equipo de Delphine espera que John Glames te haga pasar muy buenos ratos y agradecemos tu confianza.\n"
+ "Hasta la pr\242xima aventura.",
+
+ // Italian
+ "Copione\n Paul Cuisset, Philippe Chastel\n"
+ "Programmazione\n Paul Cuisset, Philippe Chastel, J\202sus Martinez, Daniel Morais IBM PC\n"
+ "Grafica\n Mich\212le Bacqu\202, Imagex, Emmanuel Lecoz\n"
+ "Musica\n Jean Baudlot\n"
+ "Effetti sonori\n Marc Minier\n"
+ "Manuale dell'utente\n Michael Sportouch\n"
+ "Illustrazioni del manuale\n Jean-Pierre Fert\202\n"
+ "Confezione\n Philippe Delamarre\n"
+ "Grazie a\n Patricia Vermander, Claire Le Hello, Muriel Fraboni\n",
+ // Italian, final credits screen
+ "Tutto il gruppo della Delphine spera che John Glames vi abbia fatto trascorrere dei momenti piacevoli "
+ "e vi ringrazia della fiducia accordata.\n"
+ "Appuntamento a presto per una nuova avventura."
+};
+
+static const int kDOSTitle = 3;
+static const int kAmigaAtariTitle = 4;
+static const int kIBMCredit = 5;
+
+enum OpeningCreditsOSIndex {
+ kScript = 0,
+ kIllustrations = 1,
+ kProgramming = 2,
+ kMusic = 3
+};
+
+#endif
+
static const struct MouseCursor {
int hotspotX;
int hotspotY;
@@ -260,6 +635,32 @@ void FWRenderer::incrustSprite(const BGIncrust &incrust) {
width = g_cine->_animDataTable[obj.frame]._realWidth;
height = g_cine->_animDataTable[obj.frame]._height;
+ if (g_cine->_copyProtectionColorScreen && scumm_stricmp(currentPrcName, "TOTO.PRC") == 0) {
+ Common::String checkingText;
+
+ switch (g_cine->_ttsLanguage) {
+ case kEnglish:
+ checkingText = "Checking";
+ break;
+ case kFrench:
+ case kSpanish:
+ checkingText = "Test";
+ break;
+ case kGerman:
+ checkingText = "Pr\201fung";
+ break;
+ default:
+ checkingText = "Checking";
+ break;
+ }
+
+ if (obj.frame == 34) {
+ g_cine->sayText(checkingText + " #1", Common::TextToSpeechManager::QUEUE);
+ } else {
+ g_cine->sayText(checkingText + " #2", Common::TextToSpeechManager::QUEUE);
+ }
+ }
+
// There was an assert(mask) here before but it made savegame loading
// in Future Wars sometimes fail the assertion (e.g. see bug #3868).
// Not drawing sprites that have no mask seems to work, but not sure
@@ -284,6 +685,10 @@ void FWRenderer::drawCommand() {
x += 2;
y += 2;
+ if (!inMenu) {
+ g_cine->sayText(_cmd, Common::TextToSpeechManager::INTERRUPT);
+ }
+
for (unsigned int i = 0; i < _cmd.size(); i++) {
x = drawChar(_cmd[i], x, y);
}
@@ -340,6 +745,10 @@ void FWRenderer::drawString(const char *string, byte param) {
int FWRenderer::drawMessage(const char *str, int x, int y, int width, int color, bool draw) {
// Keep a vertically overflowing message box inside the main screen (Fixes bug #11708).
if (draw) {
+ Common::String ttsMessage = str;
+ ttsMessage.replace('|', '\n');
+ g_cine->sayText(ttsMessage, Common::TextToSpeechManager::QUEUE);
+
int maxY = this->drawMessage(str, x, y, width, color, false);
if (maxY > 199) {
y -= (maxY - 199);
@@ -682,6 +1091,86 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
memset(mask, 0, len);
}
remaskSprite(mask, it);
+
+#ifdef USE_TTS
+ if (g_cine->getGameType() == GType_FW) {
+ // "The End" that appears at the end of the game
+ if (it->objIdx == 209 && scumm_stricmp(_bgName, "THE_END2.PI1") == 0) {
+ g_cine->sayText(theEndTexts[g_cine->_ttsLanguage], Common::TextToSpeechManager::INTERRUPT);
+ } else if (it->objIdx == 100 && scumm_stricmp(currentPrcName, "INTRO.PRC") == 0) { // Opening credits
+ int16 frame = g_cine->_objectTable[it->objIdx].frame;
+
+ const char **creditsTexts;
+
+ switch (g_cine->_ttsLanguage) {
+ case kEnglish:
+ creditsTexts = openingCreditsFWEnglish;
+ break;
+ case kFrench:
+ creditsTexts = openingCreditsFWFrench;
+ break;
+ case kGerman:
+ creditsTexts = openingCreditsFWGerman;
+ break;
+ case kSpanish:
+ creditsTexts = openingCreditsFWSpanish;
+ break;
+ case kItalian:
+ creditsTexts = openingCreditsFWItalian;
+ break;
+ default:
+ creditsTexts = openingCreditsFWEnglish;
+ break;
+ }
+
+ if (frame == 117) { // Only the DOS version has this extra IBM credit
+ g_cine->sayText(creditsTexts[kIBMCredit], Common::TextToSpeechManager::QUEUE);
+ } else {
+ frame -= 89;
+ if (frame == 3) { // Title screen, which differs between DOS and Amiga/Atari versions
+ if (g_cine->getPlatform() == Common::kPlatformDOS || g_cine->getLanguage() == Common::EN_USA) {
+ g_cine->sayText(creditsTexts[kDOSTitle], Common::TextToSpeechManager::QUEUE);
+ } else {
+ g_cine->sayText(creditsTexts[kAmigaAtariTitle], Common::TextToSpeechManager::QUEUE);
+ }
+ } else {
+ g_cine->sayText(creditsTexts[frame], Common::TextToSpeechManager::QUEUE);
+ }
+ }
+ } else if (it->objIdx == 199 && scumm_strnicmp(_bgName, "GRID__", 6) == 0) { // Amiga/Atari copy protection grid screen
+ Common::String ttsMessage;
+ switch (g_cine->_ttsLanguage) {
+ case kEnglish:
+ case kFrench:
+ ttsMessage = "page ";
+ break;
+ case kGerman:
+ ttsMessage = "Seite ";
+ break;
+ case kSpanish:
+ ttsMessage = "p\240gina ";
+ break;
+ case kItalian:
+ ttsMessage = "pagina ";
+ break;
+ default:
+ ttsMessage = "page ";
+ break;
+ }
+ // Index 11 is left number of page; can be 0 (frame 26) or 1 (27)
+ ttsMessage += (char)(g_cine->_objectTable[11].frame + 0x16);
+ // Index 2 is right number of page; page number can be 0 (frame 26), 4 (30), 6 (32), or 7 (33)
+ ttsMessage += (char)(g_cine->_objectTable[2].frame + 0x16);
+ ttsMessage += '\n';
+ // Index 1 is left number of grid; ranges from A (frame 0) to D (3)
+ ttsMessage += (char)(g_cine->_objectTable[1].frame + 0x41);
+ // Index 12 is right number of grid; ranges from 1 (frame 27) to 5 (31)
+ ttsMessage += (char)(g_cine->_objectTable[12].frame + 0x16);
+ g_cine->sayText(ttsMessage, Common::TextToSpeechManager::INTERRUPT);
+ }
+ }
+#endif
+
drawMaskedSprite(g_cine->_objectTable[it->objIdx], mask);
delete[] mask;
break;
@@ -892,6 +1381,44 @@ int16 FWRenderer::addBackground(const char *bgName, uint16 bgIdx) {
void FWRenderer::loadBg16(const byte *bg, const char *name, unsigned int idx) {
assert(idx == 0);
+#ifdef USE_TTS
+ if (scumm_stricmp(currentDatName, "SUITE23.DAT") == 0 && scumm_stricmp(currentPartName, "PART04B") == 0) { // End credits
+ int languageIndex = g_cine->_ttsLanguage * 4;
+
+ // Voice the first line
+ g_cine->sayText(endCreditsFW[languageIndex], Common::TextToSpeechManager::QUEUE);
+
+ // Voice the second line, depending on the platform
+ if (g_cine->getPlatform() == Common::kPlatformDOS) {
+ g_cine->sayText(endCreditsFW[languageIndex + 1], Common::TextToSpeechManager::QUEUE);
+ } else {
+ g_cine->sayText(endCreditsFW[languageIndex + 2], Common::TextToSpeechManager::QUEUE);
+ }
+
+ // Voice the rest of the credits
+ g_cine->sayText(endCreditsFW[languageIndex + 3], Common::TextToSpeechManager::QUEUE);
+ } else if (scumm_stricmp(name, "PROTEC.PI1") == 0) { // Copy protection screen
+ const char *text;
+
+ if (g_cine->getPlatform() == Common::kPlatformDOS || g_cine->getLanguage() == Common::EN_USA) {
+ text = copyProtectionTextsFWDOS[g_cine->_ttsLanguage];
+ } else {
+ text = copyProtectionTextsFWAmigaAtari[g_cine->_ttsLanguage];
+ }
+
+ g_cine->sayText(text, Common::TextToSpeechManager::QUEUE);
+ g_cine->_copyProtectionTextScreen = true;
+ g_cine->_copyProtectionColorScreen = false;
+ } else if ((g_cine->getPlatform() == Common::kPlatformDOS || g_cine->getLanguage() == Common::EN_USA) &&
+ scumm_stricmp(name, "FW.PI1") == 0) { // Second copy protection screen
+ g_cine->_copyProtectionTextScreen = false;
+ g_cine->_copyProtectionColorScreen = true;
+ } else {
+ g_cine->_copyProtectionTextScreen = false;
+ g_cine->_copyProtectionColorScreen = false;
+ }
+#endif
+
if (!_background) {
_background = new byte[_screenSize];
}
@@ -1192,6 +1719,21 @@ void FWRenderer::fadeFromBlack() {
g_system->delayMillis(fadeDelayMs());
}
+#ifdef USE_TTS
+ if (g_cine->_copyProtectionColorScreen && scumm_stricmp(currentPrcName, "AUTO00.PRC") == 0 && g_cine->getGameType() == GType_OS) {
+ Common::List<overlay>::iterator it;
+ for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) {
+ if (g_cine->_objectTable[it->objIdx].frame == 109) { // Second copy protection test
+ g_cine->sayText("Test #2", Common::TextToSpeechManager::QUEUE);
+ break;
+ } else if (g_cine->_objectTable[it->objIdx].frame == 150) { // Failed copy protection
+ g_cine->sayText(copyProtectionFailTextsOS[g_cine->_ttsLanguage], Common::TextToSpeechManager::QUEUE);
+ break;
+ }
+ }
+ }
+#endif
+
forbidBgPalReload = gfxFadeOutCompleted = 0;
}
@@ -1261,6 +1803,17 @@ void SelectionMenu::drawMenu(FWRenderer &r, bool top) {
if (!top) {
color += (r.useTransparentDialogBoxes() ? r.transparentDialogBoxStartColor() : 0);
+ } else {
+ // In the USE menu (playerCommand 3), queue up the first inventory item after opening the menu
+ // This allows the USE command to be spoken if the player opens the use menu using F3
+ // Also queue up the first item when the save input menu is open, so that the player input will be voiced
+ if ((g_cine->_previousSaid == defaultActionCommand[3] && playerCommand == 3)
+ || (g_cine->_saveInputMenuOpen && _elements[i] == confirmMenu[0])) {
+ g_cine->sayText(_elements[i], Common::TextToSpeechManager::QUEUE);
+ g_cine->_saveInputMenuOpen = false;
+ } else {
+ g_cine->sayText(_elements[i], Common::TextToSpeechManager::INTERRUPT);
+ }
}
r.drawPlainBox(x + 2, lineY - 1, _width - 3, 9, color);
@@ -1472,6 +2025,100 @@ void OSRenderer::incrustSprite(const BGIncrust &incrust) {
height = g_cine->_animDataTable[incrust.frame]._height;
if (_bgTable[incrust.bgIdx].bg) {
+#ifdef USE_TTS
+ // Opening credits
+ if ((incrust.objIdx == 100 || incrust.frame == 10) && scumm_stricmp(currentPrcName, "INTRO3.PRC") == 0
+ && scumm_stricmp(_bgTable[incrust.bgIdx].name, "") != 0) {
+ const char **openingCredits;
+ switch (g_cine->_ttsLanguage) {
+ case kEnglish:
+ openingCredits = openingCreditsOSEnglish;
+ break;
+ case kFrench:
+ openingCredits = openingCreditsOSFrench;
+ break;
+ case kGerman:
+ openingCredits = openingCreditsOSGerman;
+ break;
+ case kSpanish:
+ openingCredits = openingCreditsOSSpanish;
+ break;
+ case kItalian:
+ openingCredits = openingCreditsOSItalian;
+ break;
+ default:
+ openingCredits = openingCreditsOSEnglish;
+ break;
+ }
+
+ int index = -1;
+
+ if (scumm_stricmp(_bgTable[incrust.bgIdx].name, "I00.PI1") == 0) {
+ index = kScript;
+ } else if (scumm_stricmp(_bgTable[incrust.bgIdx].name, "SALLE02.PI1") == 0) {
+ index = kIllustrations;
+ } else if (scumm_stricmp(_bgTable[incrust.bgIdx].name, "BASE02.PI1") == 0) {
+ index = kProgramming;
+ } else if (scumm_stricmp(_bgTable[incrust.bgIdx].name, "PISTEA.PI1") == 0 || scumm_stricmp(_bgTable[incrust.bgIdx].name, "PISTEB.PI1") == 0) {
+ index = kMusic;
+ }
+
+ if (index != -1) {
+ g_cine->sayText(openingCredits[index], Common::TextToSpeechManager::QUEUE);
+ }
+ } else if (g_cine->_copyProtectionTextScreen && incrust.objIdx == 231) { // Copy protection screen
+ const char **copyProtectionTexts;
+ switch (g_cine->_ttsLanguage) {
+ case kEnglish:
+ if (g_cine->getLanguage() == Common::EN_GRB && g_cine->getPlatform() != Common::kPlatformDOS) {
+ copyProtectionTexts = copyProtectionTextsOSEnglishAlt;
+ } else {
+ copyProtectionTexts = copyProtectionTextsOSEnglish;
+ }
+ break;
+ case kFrench:
+ copyProtectionTexts = copyProtectionTextsOSFrench;
+ break;
+ case kGerman:
+ copyProtectionTexts = copyProtectionTextsOSGerman;
+ break;
+ case kSpanish:
+ copyProtectionTexts = copyProtectionTextsOSSpanish;
+ break;
+ case kItalian:
+ copyProtectionTexts = copyProtectionTextsOSItalian;
+ break;
+ default:
+ copyProtectionTexts = copyProtectionTextsOSEnglish;
+ break;
+ }
+
+ int index = -1;
+
+ if (incrust.frame == 200) {
+ index = 0;
+ } else if (incrust.frame == 201) {
+ index = 1;
+ } else if (incrust.frame == 204) {
+ if (g_cine->getLanguage() == Common::EN_USA && (g_cine->getPlatform() == Common::kPlatformAmiga ||
+ (g_cine->getPlatform() == Common::kPlatformDOS &&
+ scumm_stricmp(g_cine->_gameDescription->desc.extra, "256 colors")))) {
+ index = 3;
+ } else {
+ index = 2;
+ }
+ }
+
+ if (index != -1) {
+ g_cine->sayText(copyProtectionTexts[index], Common::TextToSpeechManager::QUEUE);
+ }
+ } else if (incrust.objIdx == 20 && scumm_stricmp(currentPrcName, "FIN2.PRC") == 0) { // "The End"
+ g_cine->sayText(theEndTexts[g_cine->_ttsLanguage], Common::TextToSpeechManager::QUEUE);
+ } else if (incrust.objIdx == 3 && scumm_stricmp(currentPrcName, "STARTA.PRC") == 0) {
+ g_cine->sayText("Santa Paragua", Common::TextToSpeechManager::QUEUE);
+ }
+#endif
+
// HACK: Fix transparency colors of shadings near walls
// in labyrinth scene in Operation Stealth after loading a savegame
// saved in the labyrinth.
@@ -1732,6 +2379,40 @@ int16 OSRenderer::addBackground(const char *bgName, uint16 bgIdx) {
void OSRenderer::loadBg16(const byte *bg, const char *name, unsigned int idx) {
assert(idx < 9);
+#ifdef USE_TTS
+ if (scumm_stricmp(name, "GEN1.PI1") == 0) { // Closing credits
+ int languageIndex = g_cine->_ttsLanguage * 2;
+ g_cine->sayText(endCreditsOS[languageIndex], Common::TextToSpeechManager::QUEUE);
+ } else if (scumm_stricmp(name, "GEN4.PI1") == 0) { // Closing credits, last screen
+ int languageIndex = (g_cine->_ttsLanguage * 2) + 1;
+
+ if (g_cine->_ttsLanguage != kEnglish) {
+ g_cine->sayText(endCreditsOS[languageIndex], Common::TextToSpeechManager::QUEUE);
+ } else {
+ Common::String formattedText;
+
+ // James Bond in the USA version; John Glames in the British version
+ if (g_cine->getLanguage() == Common::EN_ANY || g_cine->getLanguage() == Common::EN_GRB) {
+ formattedText = Common::String::format(endCreditsOS[languageIndex], "John Glames");
+ } else {
+ formattedText = Common::String::format(endCreditsOS[languageIndex], "James Bond");
+ }
+
+ g_cine->sayText(formattedText, Common::TextToSpeechManager::QUEUE);
+ }
+ } else if (scumm_stricmp(name, "MASKD.PI1") == 0) { // First copy protection screen
+ g_cine->_copyProtectionTextScreen = true;
+ g_cine->_copyProtectionColorScreen = false;
+ } else if (scumm_stricmp(name, "MASKB.PI1") == 0) { // Second copy protection screen
+ g_cine->sayText("Test #1", Common::TextToSpeechManager::QUEUE);
+ g_cine->_copyProtectionTextScreen = false;
+ g_cine->_copyProtectionColorScreen = true;
+ } else {
+ g_cine->_copyProtectionTextScreen = false;
+ g_cine->_copyProtectionColorScreen = false;
+ }
+#endif
+
if (!_bgTable[idx].bg) {
_bgTable[idx].bg = new byte[_screenSize];
}
diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp
index 9a9561e6338..7d80821a4fe 100644
--- a/engines/cine/main_loop.cpp
+++ b/engines/cine/main_loop.cpp
@@ -68,6 +68,9 @@ static void processEvent(Common::Event &event) {
mouseLeft = mouseRight = 0;
break;
case Common::EVENT_MOUSEMOVE:
+#ifdef USE_TTS
+ g_cine->mouseOverButton();
+#endif
break;
case Common::EVENT_WHEELUP:
g_cine->_actionList.push_back(Common::CustomEventType(kActionMenuOptionUp));
@@ -103,12 +106,14 @@ static void processEvent(Common::Event &event) {
case kActionInventory:
if (allowPlayerInput && !inMenu) {
playerCommand = 2; // INVENTORY
+ g_cine->sayText(defaultActionCommand[playerCommand], Common::TextToSpeechManager::INTERRUPT);
makeCommandLine();
}
break;
case kActionUse:
if (allowPlayerInput && !inMenu) {
playerCommand = 3; // USE
+ g_cine->sayText(defaultActionCommand[playerCommand], Common::TextToSpeechManager::INTERRUPT);
makeCommandLine();
}
break;
@@ -533,6 +538,7 @@ void CineEngine::mainLoop(int bootScriptIdx) {
_messageLen = 800;
manageEvents(MAIN_LOOP_WAIT_FOR_PLAYER_CLICK, UNTIL_MOUSE_BUTTON_UP_DOWN_UP);
+ stopTextToSpeech();
waitForPlayerClick = 0;
}
diff --git a/engines/cine/metaengine.cpp b/engines/cine/metaengine.cpp
index 46db8d824cf..96737ee1d15 100644
--- a/engines/cine/metaengine.cpp
+++ b/engines/cine/metaengine.cpp
@@ -62,6 +62,19 @@ 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/cine/object.cpp b/engines/cine/object.cpp
index ab972e9e5d2..99025928307 100644
--- a/engines/cine/object.cpp
+++ b/engines/cine/object.cpp
@@ -143,6 +143,10 @@ void addOverlay(uint16 objIdx, uint16 type) {
if (g_cine->getGameType() == Cine::GType_OS && it != g_cine->_overlayList.end() && it->objIdx == objIdx && it->type == type) {
return;
}
+
+ if (g_cine->getGameType() == Cine::GType_OS && g_cine->_objectTable[it->objIdx].frame == 22 && scumm_stricmp(currentPrcName, "STARTA.PRC") == 0) {
+ g_cine->sayText("Washington D.C.\nCIA Headquarters", Common::TextToSpeechManager::QUEUE);
+ }
tmp.objIdx = objIdx;
tmp.type = type;
diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp
index 3d072700c91..977c17b3d05 100644
--- a/engines/cine/various.cpp
+++ b/engines/cine/various.cpp
@@ -395,6 +395,8 @@ void CineEngine::makeSystemMenu() {
int16 mouseX, mouseY, mouseButton;
int16 selectedSave;
+ g_cine->_previousSaid.clear();
+
if (disableSystemMenu != 1) {
inMenu = true;
@@ -508,9 +510,12 @@ void CineEngine::makeSystemMenu() {
if (selectedSave >= 0) {
CommandeType saveName;
saveName[0] = 0;
+ _saveInputMenuOpen = true;
- if (!makeTextEntryMenu(otherMessages[6], saveName, sizeof(CommandeType), 120))
+ if (!makeTextEntryMenu(otherMessages[6], saveName, sizeof(CommandeType), 120)) {
+ _saveInputMenuOpen = false;
break;
+ }
Common::strlcpy(currentSaveName[selectedSave], saveName, sizeof(CommandeType));
@@ -583,8 +588,12 @@ void processInventory(int16 x, int16 y) {
return;
Common::StringArray list;
- for (int i = 0; i < listSize; ++i)
+ for (int i = 0; i < listSize; ++i) {
list.push_back(objectListCommand[i]);
+ // Some items are duplicated in the inventory, so clear _previousSaid to make sure they are repeated
+ g_cine->_previousSaid.clear();
+ g_cine->sayText(objectListCommand[i], Common::TextToSpeechManager::QUEUE);
+ }
SelectionMenu *menu = new SelectionMenu(Common::Point(x, y), menuWidth, list);
inMenu = true;
@@ -598,6 +607,7 @@ void processInventory(int16 x, int16 y) {
manageEvents(PROCESS_INVENTORY, UNTIL_MOUSE_BUTTON_DOWN_UP);
inMenu = false;
+ g_cine->stopTextToSpeech();
}
int16 buildObjectListCommand(int16 param) {
@@ -804,6 +814,7 @@ void makeFWCommandLine() {
if (!disableSystemMenu) {
isDrawCommandEnabled = 1;
+ g_cine->_previousSaid.clear();
renderer->setCommand(g_cine->_commandBuffer);
}
}
@@ -1002,6 +1013,8 @@ void makeActionMenu() {
uint16 mouseX;
uint16 mouseY;
+ g_cine->_previousSaid.clear();
+
inMenu = true;
getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY);
@@ -1899,6 +1912,8 @@ bool makeTextEntryMenu(const char *messagePtr, char *inputString, int stringMaxL
TextInputMenu *inputBox = new TextInputMenu(Common::Point(x - 16, y), width + 32, messagePtr);
renderer->pushMenu(inputBox);
+ g_cine->sayText(messagePtr, Common::TextToSpeechManager::INTERRUPT);
+
while (!quit) {
if (redraw) {
inputBox->setInput(inputString, inputPos);
@@ -1996,6 +2011,8 @@ bool makeTextEntryMenu(const char *messagePtr, char *inputString, int stringMaxL
renderer->popMenu();
delete inputBox;
+ g_cine->sayText(inputString, Common::TextToSpeechManager::QUEUE);
+
if (quit == kRightMouseButton)
return false;
More information about the Scummvm-git-logs
mailing list