[Scummvm-git-logs] scummvm branch-2-6 -> edbd1761861c17f59553ae440e9aef557d200c02

antoniou79 noreply at scummvm.org
Thu Jun 30 12:15:25 UTC 2022


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

Summary:
689fba8388 BLADERUNNER: Fix subtitles encoding for internal font
1015f9ced4 BLADERUNNER: Add checkbox for no subtitles in intro crawl
4ff6478545 BLADERUNNER: Support secondary subtitles
edbd176186 BLADERUNNER: Fix special case for German audio and subtitles


Commit: 689fba8388a5b2b416d74e172629180227d698aa
    https://github.com/scummvm/scummvm/commit/689fba8388a5b2b416d74e172629180227d698aa
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2022-06-30T15:13:40+03:00

Commit Message:
BLADERUNNER: Fix subtitles encoding for internal font

Changed paths:
    engines/bladerunner/debugger.cpp
    engines/bladerunner/subtitles.cpp
    engines/bladerunner/subtitles.h


diff --git a/engines/bladerunner/debugger.cpp b/engines/bladerunner/debugger.cpp
index 512e6ffdca4..96d6cd74553 100644
--- a/engines/bladerunner/debugger.cpp
+++ b/engines/bladerunner/debugger.cpp
@@ -1415,6 +1415,19 @@ bool Debugger::cmdSubtitle(int argc, const char **argv) {
 
 		} else if (subtitleText == "reset") {
 			_vm->_subtitles->setGameSubsText("", false);
+		} else if (subtitleText == "printExtAscii") {
+			// Test displaying all glyphs in subtitles font
+			Common::String allGlyphQuote;
+			int strpos = 0;
+			for (int j = 1; j < 8; ++j) {
+				for (int i = j * 32; i < (j + 1) * 32 && i < 255 ; ++i) {
+					allGlyphQuote.insertChar((char)i, strpos++);
+					allGlyphQuote.insertChar(' ', strpos++);
+				}
+				if (j < 7) allGlyphQuote.insertChar('\n', strpos++);
+			}
+			_vm->_subtitles->setGameSubsText(allGlyphQuote, true);
+			_vm->_subtitles->show();
 		} else {
 			debugPrintf("Showing text: %s\n", subtitleText.c_str());
 			_vm->_subtitles->setGameSubsText(subtitleText, true);
@@ -1425,7 +1438,7 @@ bool Debugger::cmdSubtitle(int argc, const char **argv) {
 	if (invalidSyntax) {
 		debugPrintf("Show subtitles info, or display and clear (reset) a specified text as subtitle or clear the current subtitle.\n");
 		debugPrintf("Use double quotes to encapsulate the text.\n");
-		debugPrintf("Usage: %s (\"<text_to_display>\" | info | reset)\n", argv[0]);
+		debugPrintf("Usage: %s (info | \"<text_to_display>\" | printExtAscii | reset)\n", argv[0]);
 	}
 	return true;
 
diff --git a/engines/bladerunner/subtitles.cpp b/engines/bladerunner/subtitles.cpp
index 8019b58d933..717fc2474b2 100644
--- a/engines/bladerunner/subtitles.cpp
+++ b/engines/bladerunner/subtitles.cpp
@@ -235,19 +235,22 @@ void Subtitles::loadInGameSubsText(int actorId, int speech_id)  {
 		return;
 	}
 
-	int32 id = 10000 * actorId + speech_id;
 	if (!_gameSubsResourceEntriesFound[0]) {
 		_currentText.clear();
+		_currentText32.clear();
+		_prevText.clear();
+		_prevText32.clear();
 		return;
 	}
 
 	// Search in the first TextResource of the _vqaSubsTextResourceEntries table, which is the TextResource for in-game dialogue (i.e. not VQA dialogue)
+	int32 id = 10000 * actorId + speech_id;
 	const char *text = _vqaSubsTextResourceEntries[0]->getText((uint32)id);
-	// Use of Common::kWindows1252 codepage to fix bug whereby accented characters
-	// would not show for subtitles.
-	// TODO maybe the codepage here should be determined based on some subtitles property per language
-	//      especially for non-latin languages that still use a FON font rather than a TTF font (eg. Greek would need Common::kWindows1253)
-	_currentText = _useUTF8 ? Common::convertUtf8ToUtf32(text) : Common::U32String(text, Common::kWindows1252);
+	if (_useUTF8) {
+		_currentText32 = Common::convertUtf8ToUtf32(text);
+	} else {
+		_currentText = text;
+	}
 }
 
 /**
@@ -261,17 +264,20 @@ void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int fram
 	int fileIdx = getIdxForSubsTreName(outtakesName);
 	if (fileIdx == -1 || !_gameSubsResourceEntriesFound[fileIdx]) {
 		_currentText.clear();
+		_currentText32.clear();
+		_prevText.clear();
+		_prevText32.clear();
 		return;
 	}
 
 	// Search in the requested TextResource at the fileIdx index of the _vqaSubsTextResourceEntries table for a quote that corresponds to the specified video frame
 	// debug("Number of resource quotes to search: %d, requested frame: %u", _vqaSubsTextResourceEntries[fileIdx]->getCount(), (uint32)frame );
 	const char *text = _vqaSubsTextResourceEntries[fileIdx]->getOuttakeTextByFrame((uint32)frame);
-	// Use of Common::kWindows1252 codepage to fix bug whereby accented characters
-	// would not show for subtitles.
-	// TODO maybe the codepage here should be determined based on some subtitles property per language
-	//      especially for non-latin languages that still use a FON font rather than a TTF font (eg. Greek would need Common::kWindows1253)
-	_currentText = _useUTF8 ? Common::convertUtf8ToUtf32(text) : Common::U32String(text, Common::kWindows1252);
+	if (_useUTF8) {
+		_currentText32 = Common::convertUtf8ToUtf32(text);
+	} else {
+		_currentText = text;
+	}
 }
 
 /**
@@ -279,8 +285,11 @@ void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int fram
  * Used for debug purposes mainly.
  */
 void Subtitles::setGameSubsText(Common::String dbgQuote, bool forceShowWhenNoSpeech) {
-	// TODO is Common::kWindows1252 correct here?
-	_currentText = _useUTF8 ? Common::convertUtf8ToUtf32(dbgQuote) : Common::U32String(dbgQuote, Common::kWindows1252);
+	if (_useUTF8) {
+		_currentText32 = Common::convertUtf8ToUtf32(dbgQuote);
+	} else {
+		_currentText = dbgQuote;
+	}
 	_forceShowWhenNoSpeech = forceShowWhenNoSpeech; // overrides not showing subtitles when no one is speaking
 }
 
@@ -334,10 +343,10 @@ void Subtitles::tickOuttakes(Graphics::Surface &s) {
 		return;
 	}
 
-	if (_currentText.empty()) {
-		_vm->_subtitles->hide();
-	} else {
+	if (isNotEmptyCurrentSubsText()) {
 		_vm->_subtitles->show();
+	} else {
+		_vm->_subtitles->hide();
 	}
 
 	if (!_isVisible) { // keep it as a separate if
@@ -366,36 +375,58 @@ void Subtitles::tick(Graphics::Surface &s) {
 	draw(s);
 }
 
+bool Subtitles::isNotEmptyCurrentSubsText() {
+	if ((_useUTF8 && !_currentText32.empty())
+		|| (!_useUTF8 && !_currentText.empty())) {
+		return true;
+	} else {
+		return false;
+	}
+}
+
+
 /**
  * Draw method for drawing the subtitles on the display surface
  */
 void Subtitles::draw(Graphics::Surface &s) {
-	if (!_isSystemActive || !_isVisible || _currentText.empty()) {
+	if (!_isSystemActive || !_isVisible || !isNotEmptyCurrentSubsText()) {
 		return;
 	}
 
-	// This check is done so that lines won't be re-calculated multiple times for the same text
-	if (_currentText != _prevText) {
-		lines.clear();
-		_prevText = _currentText;
-		_font->wordWrapText(_currentText, kTextMaxWidth, lines, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
+	uint linesNum = 0;
+	if (_useUTF8) {
+		// This check is done so that lines won't be re-calculated multiple times for the same text
+		if (_currentText32 != _prevText32) {
+			_lines32.clear();
+			_prevText32 = _currentText32;
+			_font->wordWrapText(_currentText32, kTextMaxWidth, _lines32, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
+		}
+		linesNum = _lines32.size();
+	} else {
+		// This check is done so that lines won't be re-calculated multiple times for the same text
+		if (_currentText != _prevText) {
+			_lines.clear();
+			_prevText = _currentText;
+			_font->wordWrapText(_currentText, kTextMaxWidth, _lines, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
+		}
+		linesNum = _lines.size();
 	}
 
-	int y = s.h - (kMarginBottom + MAX(kPreferedLine, lines.size()) * _font->getFontHeight());
+	int y = s.h - (kMarginBottom + MAX(kPreferedLine, linesNum) * _font->getFontHeight());
 
-	for (uint i = 0; i < lines.size(); ++i, y += _font->getFontHeight()) {
+	for (uint i = 0; i < linesNum; ++i, y += _font->getFontHeight()) {
 		switch (_subtitlesInfo.fontType) {
 			case Subtitles::kSubtitlesFontTypeInternal:
 				// shadow/outline is part of the font color data
-				_font->drawString(&s, lines[i], 0, y, s.w, 0, Graphics::kTextAlignCenter);
+				_font->drawString(&s, _lines[i], 0, y, s.w, 0, Graphics::kTextAlignCenter);
 				break;
 			case Subtitles::kSubtitlesFontTypeTTF:
-				_font->drawString(&s, lines[i], -1, y    , s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
-				_font->drawString(&s, lines[i],  0, y - 1, s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
-				_font->drawString(&s, lines[i],  1, y    , s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
-				_font->drawString(&s, lines[i],  0, y + 1, s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
+				_font->drawString(&s, _lines32[i], -1, y    , s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
+				_font->drawString(&s, _lines32[i],  0, y - 1, s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
+				_font->drawString(&s, _lines32[i],  1, y    , s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
+				_font->drawString(&s, _lines32[i],  0, y + 1, s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
 
-				_font->drawString(&s, lines[i],  0, y    , s.w, s.format.RGBToColor(255, 255, 255), Graphics::kTextAlignCenter);
+				_font->drawString(&s, _lines32[i],  0, y    , s.w, s.format.RGBToColor(255, 255, 255), Graphics::kTextAlignCenter);
 				break;
 		}
 	}
@@ -408,6 +439,11 @@ void Subtitles::clear() {
 	_isVisible = false;
 	_forceShowWhenNoSpeech = false;
 	_currentText.clear();
+	_currentText32.clear();
+	_prevText.clear();
+	_prevText32.clear();
+	_lines.clear();
+	_lines32.clear();
 }
 
 /**
diff --git a/engines/bladerunner/subtitles.h b/engines/bladerunner/subtitles.h
index 1cf7bb3f139..46d1419d3f7 100644
--- a/engines/bladerunner/subtitles.h
+++ b/engines/bladerunner/subtitles.h
@@ -76,10 +76,13 @@ class Subtitles {
 
 	bool              _isVisible;
 	bool              _forceShowWhenNoSpeech;
-	Common::U32String _currentText;
-	Common::U32String _prevText;
+	Common::U32String _currentText32;
+	Common::U32String _prevText32;
+	Common::String    _currentText;
+	Common::String    _prevText;
 
-	Common::Array<Common::U32String> lines;
+	Common::Array<Common::U32String> _lines32;
+	Common::Array<Common::String> _lines;
 
 	bool _gameSubsResourceEntriesFound[kMaxTextResourceEntries]; // false if a TRE file did not open successfully
 	bool _isSystemActive;                                        // true if the whole subtitles subsystem should be disabled (due to missing required resources)
@@ -110,6 +113,7 @@ private:
 	void clear();
 	void reset();
 
+	bool isNotEmptyCurrentSubsText();
 };
 
 } // End of namespace BladeRunner


Commit: 1015f9ced4a8b640211d77cdceec7bd996ba8e49
    https://github.com/scummvm/scummvm/commit/1015f9ced4a8b640211d77cdceec7bd996ba8e49
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2022-06-30T15:13:40+03:00

Commit Message:
BLADERUNNER: Add checkbox for no subtitles in intro crawl

This also covers the Blade Runner Logo and the Westwood Studios logo

Changed paths:
    engines/bladerunner/bladerunner.cpp
    engines/bladerunner/bladerunner.h
    engines/bladerunner/detection.cpp
    engines/bladerunner/detection_tables.h
    engines/bladerunner/subtitles.cpp


diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index bc5abea48c0..a610b867f9c 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -119,6 +119,7 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst, const ADGameDescription *des
 	_actorSpeakStopIsRequested = false;
 
 	_subtitlesEnabled             = false;
+	_showSubtitlesForTextCrawl    = false;
 
 	_surfaceFrontCreated          = false;
 	_surfaceBackCreated           = false;
@@ -635,6 +636,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
 
 	if (!_isNonInteractiveDemo) {
 		ConfMan.registerDefault("subtitles", "true");
+		ConfMan.registerDefault("use_crawl_subs", "true");
 		ConfMan.registerDefault("sitcom", "false");
 		ConfMan.registerDefault("shorty", "false");
 		ConfMan.registerDefault("disable_stamina_drain", "false");
@@ -2417,6 +2419,7 @@ void BladeRunnerEngine::syncSoundSettings() {
 	Engine::syncSoundSettings();
 
 	_subtitlesEnabled = ConfMan.getBool("subtitles");
+	_showSubtitlesForTextCrawl = ConfMan.getBool("use_crawl_subs");
 
 	_mixer->setVolumeForSoundType(_mixer->kMusicSoundType, ConfMan.getInt("music_volume"));
 	_mixer->setVolumeForSoundType(_mixer->kSFXSoundType, ConfMan.getInt("sfx_volume"));
diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h
index b30847f7b6a..e56e6c477e0 100644
--- a/engines/bladerunner/bladerunner.h
+++ b/engines/bladerunner/bladerunner.h
@@ -229,6 +229,7 @@ public:
 	bool _vqaIsPlaying;
 	bool _vqaStopIsRequested;
 	bool _subtitlesEnabled;  // tracks the state of whether subtitles are enabled or disabled from ScummVM GUI option or KIA checkbox (the states are synched)
+	bool _showSubtitlesForTextCrawl;
 	bool _sitcomMode;
 	bool _shortyMode;
 	bool _noDelayMillisFramelimiter;
diff --git a/engines/bladerunner/detection.cpp b/engines/bladerunner/detection.cpp
index 50da3d1c140..6f8b42e1acf 100644
--- a/engines/bladerunner/detection.cpp
+++ b/engines/bladerunner/detection.cpp
@@ -102,6 +102,17 @@ static const ADExtraGuiOptionsMap optionsList[] = {
 			0
 		}
 	},
+	{
+		GAMEOPTION_SHOW_SUBS_IN_CRAWL,
+		{
+			_s("Show subtitles during text crawl"),
+			_s("During the intro cutscene, show subtitles during the text crawl"),
+			"use_crawl_subs",
+			true,
+			0,
+			0
+		}
+	},
 	AD_EXTRA_GUI_OPTIONS_TERMINATOR
 };
 
diff --git a/engines/bladerunner/detection_tables.h b/engines/bladerunner/detection_tables.h
index dc6b9b27134..0c58949d88d 100644
--- a/engines/bladerunner/detection_tables.h
+++ b/engines/bladerunner/detection_tables.h
@@ -30,6 +30,7 @@
 #define GAMEOPTION_FRAMELIMITER_NODELAYMILLIS GUIO_GAMEOPTIONS3
 #define GAMEOPTION_FRAMELIMITER_FPS           GUIO_GAMEOPTIONS4
 #define GAMEOPTION_DISABLE_STAMINA_DRAIN      GUIO_GAMEOPTIONS5
+#define GAMEOPTION_SHOW_SUBS_IN_CRAWL         GUIO_GAMEOPTIONS6
 
 namespace BladeRunner {
 
@@ -42,7 +43,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::EN_ANY,
 		Common::kPlatformWindows,
 		ADGF_NO_FLAGS,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (German) - DEU
@@ -53,7 +54,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::DE_DEU,
 		Common::kPlatformWindows,
 		ADGF_NO_FLAGS,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (French) - FRA - Bug #9722
@@ -64,7 +65,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::FR_FRA,
 		Common::kPlatformWindows,
 		ADGF_NO_FLAGS,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Italian) - ITA
@@ -75,7 +76,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::IT_ITA,
 		Common::kPlatformWindows,
 		ADGF_NO_FLAGS,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Russian - Fargus Multimedia + Home Systems, Inc.) - RUS
@@ -86,7 +87,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::RU_RUS,
 		Common::kPlatformWindows,
 		ADGF_NO_FLAGS,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Russian - Fargus Multimedia + Home Systems, Inc. + Siberian Studio, R3) - RUS
@@ -97,7 +98,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::RU_RUS,
 		Common::kPlatformWindows,
 		ADGF_UNSUPPORTED,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Russian - Fargus Multimedia + Home Systems, Inc. + Siberian Studio, R4) - RUS
@@ -108,7 +109,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::RU_RUS,
 		Common::kPlatformWindows,
 		ADGF_UNSUPPORTED,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Spanish) - ESP
@@ -119,7 +120,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::ES_ESP,
 		Common::kPlatformWindows,
 		ADGF_NO_FLAGS,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Chinese)
@@ -131,7 +132,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::ZH_CHN,
 		Common::kPlatformWindows,
 		ADGF_UNSUPPORTED,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner - Enhanced edition
@@ -155,7 +156,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::EN_ANY,
 		Common::kPlatformWindows,
 		ADGF_UNSTABLE,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (German) - DEU
@@ -166,7 +167,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::DE_DEU,
 		Common::kPlatformWindows,
 		ADGF_UNSTABLE,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (French) - FRA
@@ -177,7 +178,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::FR_FRA,
 		Common::kPlatformWindows,
 		ADGF_UNSTABLE,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Italian) - ITA
@@ -188,7 +189,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::IT_ITA,
 		Common::kPlatformWindows,
 		ADGF_UNSTABLE,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Russian - Fargus Multimedia + Home Systems, Inc.) - RUS
@@ -199,7 +200,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::RU_RUS,
 		Common::kPlatformWindows,
 		ADGF_UNSTABLE,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Russian - Fargus Multimedia + Home Systems, Inc. + Siberian Studio, R3) - RUS
@@ -210,7 +211,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::RU_RUS,
 		Common::kPlatformWindows,
 		ADGF_UNSTABLE,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Russian - Fargus Multimedia + Home Systems, Inc. + Siberian Studio, R4) - RUS
@@ -221,7 +222,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::RU_RUS,
 		Common::kPlatformWindows,
 		ADGF_UNSTABLE,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// BladeRunner (Spanish) - ESP
@@ -232,7 +233,7 @@ static const ADGameDescription gameDescriptions[] = {
 		Common::ES_ESP,
 		Common::kPlatformWindows,
 		ADGF_UNSTABLE,
-		GUIO6(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GUIO_NOMIDI)
+		GUIO7(GAMEOPTION_SITCOM, GAMEOPTION_SHORTY, GAMEOPTION_FRAMELIMITER_NODELAYMILLIS, GAMEOPTION_FRAMELIMITER_FPS, GAMEOPTION_DISABLE_STAMINA_DRAIN, GAMEOPTION_SHOW_SUBS_IN_CRAWL, GUIO_NOMIDI)
 	},
 
 	// Demo Version(s)
diff --git a/engines/bladerunner/subtitles.cpp b/engines/bladerunner/subtitles.cpp
index 717fc2474b2..9a03e415246 100644
--- a/engines/bladerunner/subtitles.cpp
+++ b/engines/bladerunner/subtitles.cpp
@@ -270,6 +270,15 @@ void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int fram
 		return;
 	}
 
+	if (!_vm->_showSubtitlesForTextCrawl
+		&& (fileIdx == 1
+			|| fileIdx == 2
+			|| (fileIdx == 3 && (uint32)frame < 1200))) {
+		// "WSTLGO" or "BRLOGO" or "INTRO" affected
+		// NOTE fileIdx indexes the SUBTITLES_FILENAME_PREFIXES array
+		return;
+	}
+
 	// Search in the requested TextResource at the fileIdx index of the _vqaSubsTextResourceEntries table for a quote that corresponds to the specified video frame
 	// debug("Number of resource quotes to search: %d, requested frame: %u", _vqaSubsTextResourceEntries[fileIdx]->getCount(), (uint32)frame );
 	const char *text = _vqaSubsTextResourceEntries[fileIdx]->getOuttakeTextByFrame((uint32)frame);


Commit: 4ff6478545a4c5f5fd0170a9b916502d377870c0
    https://github.com/scummvm/scummvm/commit/4ff6478545a4c5f5fd0170a9b916502d377870c0
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2022-06-30T15:13:40+03:00

Commit Message:
BLADERUNNER: Support secondary subtitles

Main for debugging and fun stats in shooting range and VK test for now

Changed paths:
    engines/bladerunner/actor.cpp
    engines/bladerunner/bladerunner.cpp
    engines/bladerunner/debugger.cpp
    engines/bladerunner/script/police_maze.cpp
    engines/bladerunner/script/scene/ps13.cpp
    engines/bladerunner/script/script.cpp
    engines/bladerunner/script/script.h
    engines/bladerunner/subtitles.cpp
    engines/bladerunner/subtitles.h
    engines/bladerunner/ui/vk.cpp


diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp
index 77d1463843e..c80e959222b 100644
--- a/engines/bladerunner/actor.cpp
+++ b/engines/bladerunner/actor.cpp
@@ -1474,13 +1474,13 @@ void Actor::speechPlay(int sentenceId, bool voiceOver) {
 	}
 
 	_vm->_subtitles->loadInGameSubsText(_id, sentenceId);
-	_vm->_subtitles->show();
+	_vm->_subtitles->show(BladeRunner::Subtitles::kSubtitlesPrimary);
 
 	_vm->_audioSpeech->playSpeech(name, pan);
 }
 
 void Actor::speechStop() {
-	_vm->_subtitles->hide();
+	_vm->_subtitles->hide(BladeRunner::Subtitles::kSubtitlesPrimary);
 	_vm->_audioSpeech->stopSpeech();
 }
 
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index a610b867f9c..94e75955e10 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -439,6 +439,8 @@ Common::Error BladeRunnerEngine::run() {
 		_gameJustLaunched = true;
 		// reset ammo amounts
 		_settings->reset();
+		// clear subtitles
+		_subtitles->clear();
 		// need to clear kFlagKIAPrivacyAddon to remove Bob's Privacy Addon for KIA
 		// so it won't appear here after end credits
 		_gameFlags->reset(kFlagKIAPrivacyAddon);
@@ -2545,6 +2547,9 @@ void BladeRunnerEngine::playerDied() {
 	_ambientSounds->removeAllLoopingSounds(4u);
 	_music->stop(4u);
 	_audioSpeech->stopSpeech();
+	// clear subtitles
+	_subtitles->clear();
+
 #endif // BLADERUNNER_ORIGINAL_BUGS
 
 	uint32 timeWaitStart = _time->current();
@@ -2654,6 +2659,9 @@ bool BladeRunnerEngine::loadGame(Common::SeekableReadStream &stream, int version
 #endif // BLADERUNNER_ORIGINAL_BUGS
 	_audioSpeech->stopSpeech();
 	_actorDialogueQueue->flush(true, false);
+	// clear subtitles
+	_subtitles->clear();
+
 #if BLADERUNNER_ORIGINAL_BUGS
 #else
 	_screenEffects->toggleEntry(-1, false); // clear the skip list
@@ -2749,6 +2757,9 @@ void BladeRunnerEngine::newGame(int difficulty) {
 	_settings->reset();
 	_combat->reset();
 
+	// clear subtitles
+	_subtitles->clear();
+
 	for (uint i = 0; i < _gameInfo->getActorCount(); ++i) {
 		_actors[i]->setup(i);
 	}
diff --git a/engines/bladerunner/debugger.cpp b/engines/bladerunner/debugger.cpp
index 96d6cd74553..e5f0ce8574e 100644
--- a/engines/bladerunner/debugger.cpp
+++ b/engines/bladerunner/debugger.cpp
@@ -1396,7 +1396,7 @@ bool Debugger::cmdOverlay(int argc, const char **argv) {
 bool Debugger::cmdSubtitle(int argc, const char **argv) {
 	bool invalidSyntax = false;
 
-	if (argc != 2) {
+	if (argc != 2 && argc != 3) {
 		invalidSyntax = true;
 	} else {
 		if (!_vm->_subtitles->isSystemActive()) {
@@ -1404,6 +1404,15 @@ bool Debugger::cmdSubtitle(int argc, const char **argv) {
 		}
 
 		Common::String subtitleText = argv[1];
+		int subtitleRole = BladeRunner::Subtitles::kSubtitlesPrimary;
+		if (argc == 3) {
+			subtitleRole = atoi(argv[2]);
+			// Just interpret any number other than 0 as secondary subtitles
+			if (subtitleRole != BladeRunner::Subtitles::kSubtitlesPrimary) {
+				subtitleRole = BladeRunner::Subtitles::kSubtitlesSecondary;
+			}
+		}
+
 		if (subtitleText == "info") {
 			debugPrintf("Subtitles version info: v%s (%s) %s\nCredits:\n%s\n",
 			            _vm->_subtitles->getSubtitlesInfo().versionStr.c_str(),
@@ -1414,7 +1423,12 @@ bool Debugger::cmdSubtitle(int argc, const char **argv) {
 			            _vm->_subtitles->getSubtitlesInfo().fontName.c_str());
 
 		} else if (subtitleText == "reset") {
-			_vm->_subtitles->setGameSubsText("", false);
+			if (argc == 2) {
+				_vm->_subtitles->setGameSubsText(BladeRunner::Subtitles::kSubtitlesPrimary, "", false);
+				_vm->_subtitles->setGameSubsText(BladeRunner::Subtitles::kSubtitlesSecondary, "", false);
+			} else {
+				_vm->_subtitles->setGameSubsText(subtitleRole, "", false);
+			}
 		} else if (subtitleText == "printExtAscii") {
 			// Test displaying all glyphs in subtitles font
 			Common::String allGlyphQuote;
@@ -1426,22 +1440,22 @@ bool Debugger::cmdSubtitle(int argc, const char **argv) {
 				}
 				if (j < 7) allGlyphQuote.insertChar('\n', strpos++);
 			}
-			_vm->_subtitles->setGameSubsText(allGlyphQuote, true);
-			_vm->_subtitles->show();
+			_vm->_subtitles->setGameSubsText(subtitleRole, allGlyphQuote, true);
+			_vm->_subtitles->show(subtitleRole);
 		} else {
 			debugPrintf("Showing text: %s\n", subtitleText.c_str());
-			_vm->_subtitles->setGameSubsText(subtitleText, true);
-			_vm->_subtitles->show();
+			_vm->_subtitles->setGameSubsText(subtitleRole, subtitleText, true);
+			_vm->_subtitles->show(subtitleRole);
 		}
 	}
 
 	if (invalidSyntax) {
 		debugPrintf("Show subtitles info, or display and clear (reset) a specified text as subtitle or clear the current subtitle.\n");
 		debugPrintf("Use double quotes to encapsulate the text.\n");
-		debugPrintf("Usage: %s (info | \"<text_to_display>\" | printExtAscii | reset)\n", argv[0]);
+		debugPrintf("SubtitleRole can be 0 (primary) or 1 (secondary).\n");
+		debugPrintf("Usage: %s (info | \"<text_to_display>\" [subtitleRole] | printExtAscii [subtitleRole]  | reset [subtitleRole])\n", argv[0]);
 	}
 	return true;
-
 }
 
 /**
diff --git a/engines/bladerunner/script/police_maze.cpp b/engines/bladerunner/script/police_maze.cpp
index 9c70a02cc41..e1c69da3c43 100644
--- a/engines/bladerunner/script/police_maze.cpp
+++ b/engines/bladerunner/script/police_maze.cpp
@@ -153,8 +153,8 @@ void PoliceMaze::tick() {
 	}
 
 	if (_vm->_debugger->_showMazeScore && _isActive && !_isEnding) {
-		_vm->_subtitles->setGameSubsText(Common::String::format("Score: %02d", Global_Variable_Query(kVariablePoliceMazeScore)), true);
-		_vm->_subtitles->show();
+		_vm->_subtitles->setGameSubsText(BladeRunner::Subtitles::kSubtitlesSecondary, Common::String::format("Score: %02d", Global_Variable_Query(kVariablePoliceMazeScore)), true);
+		_vm->_subtitles->show(BladeRunner::Subtitles::kSubtitlesSecondary);
 	}
 
 	if (notFound && _isActive && !_isEnding) {
diff --git a/engines/bladerunner/script/scene/ps13.cpp b/engines/bladerunner/script/scene/ps13.cpp
index 60371eb6c1e..1419e0fb0c5 100644
--- a/engines/bladerunner/script/scene/ps13.cpp
+++ b/engines/bladerunner/script/scene/ps13.cpp
@@ -772,7 +772,7 @@ bool SceneScriptPS13::ClickedOnExit(int exitId) {
 			Police_Maze_Decrement_Score(kPoliceMazePS13TargetCount - Global_Variable_Query(kVariablePoliceMazePS13TargetCounter));
 			Set_Score(kActorMcCoy, Police_Maze_Query_Score());
 //			Common::String scoreString = Common::String::format("Final: %03d", Global_Variable_Query(kVariablePoliceMazeScore)); // Display final score as subtitles
-//			Set_Subtitle_Text_On_Screen(scoreString); // Display final score as subtitles
+//			Set_Subtitle_Text_On_Screen(BladeRunner::Subtitles::kSubtitlesSecondary, scoreString); // Display final score as subtitles
 			Global_Variable_Reset(kVariablePoliceMazePS10TargetCounter);
 			Global_Variable_Reset(kVariablePoliceMazePS11TargetCounter);
 			Global_Variable_Reset(kVariablePoliceMazePS12TargetCounter);
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index 5eb40fdf6a9..c8a9a5afa7e 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -896,10 +896,10 @@ bool ScriptBase::Item_Query_Visible(int itemId) {
 
 // Show text as subtitles mainly for debugging purposes
 // eg. display debug data on screen as subtitles
-void ScriptBase::Set_Subtitle_Text_On_Screen(Common::String displayText) {
-	debugC(kDebugScript, "Set_Subtitle_Text_On_Screen(%s)", displayText.c_str());
-	_vm->_subtitles->setGameSubsText(displayText, true);
-	_vm->_subtitles->show();
+void ScriptBase::Set_Subtitle_Text_On_Screen(int subtitlesRole, Common::String displayText) {
+	debugC(kDebugScript, "Set_Subtitle_Text_On_Screen(%d, %s)", subtitlesRole, displayText.c_str());
+	_vm->_subtitles->setGameSubsText(subtitlesRole, displayText, true);
+	_vm->_subtitles->show(subtitlesRole);
 }
 
 #if BLADERUNNER_ORIGINAL_BUGS
diff --git a/engines/bladerunner/script/script.h b/engines/bladerunner/script/script.h
index ce812fbebe0..d8626284293 100644
--- a/engines/bladerunner/script/script.h
+++ b/engines/bladerunner/script/script.h
@@ -131,7 +131,7 @@ protected:
 	void Item_Pickup_Spin_Effect(int animationId, int x, int y);
 	void Item_Pickup_Spin_Effect_From_Actor(int animationId, int actorId, int xOffset = 0, int yOffset = 0); // new for restored content mostly
 	bool Item_Query_Visible(int itemId);
-	void Set_Subtitle_Text_On_Screen(Common::String displayText);
+	void Set_Subtitle_Text_On_Screen(int subtitlesRole, Common::String displayText);
 #if BLADERUNNER_ORIGINAL_BUGS
 #else
 	void Screen_Effect_Skip(int effectInc, bool forceExtraSceneFrameSkip);
diff --git a/engines/bladerunner/subtitles.cpp b/engines/bladerunner/subtitles.cpp
index 9a03e415246..58a7428debf 100644
--- a/engines/bladerunner/subtitles.cpp
+++ b/engines/bladerunner/subtitles.cpp
@@ -24,6 +24,7 @@
 #include "bladerunner/font.h"
 #include "bladerunner/text_resource.h"
 #include "bladerunner/audio_speech.h"
+#include "bladerunner/game_constants.h"
 
 #include "common/debug.h"
 
@@ -107,6 +108,7 @@ Subtitles::Subtitles(BladeRunnerEngine *vm) {
 	}
 	_font = nullptr;
 	_useUTF8 = false;
+	_subtitlesData.resize(kNumOfSubtitleRoles);
 	reset();
 }
 
@@ -115,6 +117,7 @@ Subtitles::Subtitles(BladeRunnerEngine *vm) {
  */
 Subtitles::~Subtitles() {
 	reset();
+	_subtitlesData.clear();
 }
 
 //
@@ -236,20 +239,21 @@ void Subtitles::loadInGameSubsText(int actorId, int speech_id)  {
 	}
 
 	if (!_gameSubsResourceEntriesFound[0]) {
-		_currentText.clear();
-		_currentText32.clear();
-		_prevText.clear();
-		_prevText32.clear();
+		_subtitlesData[kSubtitlesPrimary].currentText.clear();
+		_subtitlesData[kSubtitlesPrimary].currentText32.clear();
+		_subtitlesData[kSubtitlesPrimary].prevText.clear();
+		_subtitlesData[kSubtitlesPrimary].prevText32.clear();
 		return;
 	}
 
-	// Search in the first TextResource of the _vqaSubsTextResourceEntries table, which is the TextResource for in-game dialogue (i.e. not VQA dialogue)
+	// Search in the first TextResource of the _vqaSubsTextResourceEntries table,
+	// which is the TextResource for in-game dialogue (i.e. not VQA dialogue)
 	int32 id = 10000 * actorId + speech_id;
 	const char *text = _vqaSubsTextResourceEntries[0]->getText((uint32)id);
 	if (_useUTF8) {
-		_currentText32 = Common::convertUtf8ToUtf32(text);
+		_subtitlesData[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(text);
 	} else {
-		_currentText = text;
+		_subtitlesData[kSubtitlesPrimary].currentText = text;
 	}
 }
 
@@ -263,17 +267,17 @@ void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int fram
 
 	int fileIdx = getIdxForSubsTreName(outtakesName);
 	if (fileIdx == -1 || !_gameSubsResourceEntriesFound[fileIdx]) {
-		_currentText.clear();
-		_currentText32.clear();
-		_prevText.clear();
-		_prevText32.clear();
+		_subtitlesData[kSubtitlesPrimary].currentText.clear();
+		_subtitlesData[kSubtitlesPrimary].currentText32.clear();
+		_subtitlesData[kSubtitlesPrimary].prevText.clear();
+		_subtitlesData[kSubtitlesPrimary].prevText32.clear();
 		return;
 	}
 
 	if (!_vm->_showSubtitlesForTextCrawl
-		&& (fileIdx == 1
-			|| fileIdx == 2
-			|| (fileIdx == 3 && (uint32)frame < 1200))) {
+	   && (fileIdx == 1
+	      || fileIdx == 2
+	      || (fileIdx == 3 && (uint32)frame < 1200))) {
 		// "WSTLGO" or "BRLOGO" or "INTRO" affected
 		// NOTE fileIdx indexes the SUBTITLES_FILENAME_PREFIXES array
 		return;
@@ -283,9 +287,9 @@ void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int fram
 	// debug("Number of resource quotes to search: %d, requested frame: %u", _vqaSubsTextResourceEntries[fileIdx]->getCount(), (uint32)frame );
 	const char *text = _vqaSubsTextResourceEntries[fileIdx]->getOuttakeTextByFrame((uint32)frame);
 	if (_useUTF8) {
-		_currentText32 = Common::convertUtf8ToUtf32(text);
+		_subtitlesData[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(text);
 	} else {
-		_currentText = text;
+		_subtitlesData[kSubtitlesPrimary].currentText = text;
 	}
 }
 
@@ -293,55 +297,56 @@ void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int fram
  * Explicitly set the active subtitle text to be displayed
  * Used for debug purposes mainly.
  */
-void Subtitles::setGameSubsText(Common::String dbgQuote, bool forceShowWhenNoSpeech) {
+void Subtitles::setGameSubsText(int subsRole, Common::String dbgQuote, bool forceShowWhenNoSpeech) {
 	if (_useUTF8) {
-		_currentText32 = Common::convertUtf8ToUtf32(dbgQuote);
+		_subtitlesData[subsRole].currentText32 = Common::convertUtf8ToUtf32(dbgQuote);
 	} else {
-		_currentText = dbgQuote;
+		_subtitlesData[subsRole].currentText = dbgQuote;
 	}
-	_forceShowWhenNoSpeech = forceShowWhenNoSpeech; // overrides not showing subtitles when no one is speaking
+	_subtitlesData[subsRole].forceShowWhenNoSpeech = forceShowWhenNoSpeech; // overrides not showing subtitles when no one is speaking
 }
 
 /**
  * Sets the _isVisible member var to true if it's not already set
  * @return true if the member was set now, false if the member was already set
  */
-bool Subtitles::show() {
+bool Subtitles::show(int subsRole) {
 	if (!_isSystemActive) {
 		return false;
 	}
 
-	if (_isVisible) {
+	if (_subtitlesData[subsRole].isVisible) {
 		return false;
+	} else {
+		_subtitlesData[subsRole].isVisible = true;
+		return true;
 	}
-
-	_isVisible = true;
-	return true;
 }
 
 /**
  * Clears the _isVisible member var if not already clear.
  * @return true if the member was cleared, false if it was already clear.
  */
-bool Subtitles::hide() {
+bool Subtitles::hide(int subsRole) {
 	if (!_isSystemActive) {
 		return false;
 	}
 
-	if (!_isVisible) {
+	if (!_subtitlesData[subsRole].isVisible) {
 		return false;
+	} else {
+		_subtitlesData[subsRole].isVisible = false;
+		return true;
 	}
-
-	_isVisible = false;
-	return true;
 }
 
 /**
  * Checks whether the subtitles should be visible or not
  * @return the value of the _isVisible member boolean var
  */
-bool Subtitles::isVisible() const {
-	return !_isSystemActive || _isVisible;
+bool Subtitles::isVisible(int subsRole) const {
+	return _isSystemActive
+	       && _subtitlesData[subsRole].isVisible;
 }
 
 /**
@@ -352,13 +357,16 @@ void Subtitles::tickOuttakes(Graphics::Surface &s) {
 		return;
 	}
 
-	if (isNotEmptyCurrentSubsText()) {
-		_vm->_subtitles->show();
-	} else {
-		_vm->_subtitles->hide();
+	for (int i = 0; i < kNumOfSubtitleRoles; ++i) {
+		if (isNotEmptyCurrentSubsText(i)) {
+			_vm->_subtitles->show(i);
+		} else {
+			_vm->_subtitles->hide(i);
+		}
 	}
 
-	if (!_isVisible) { // keep it as a separate if
+	// keep this as a separate if clause
+	if (!isVisible(kSubtitlesPrimary) && !isVisible(kSubtitlesSecondary)) {
 		return;
 	}
 
@@ -373,86 +381,101 @@ void Subtitles::tick(Graphics::Surface &s) {
 		return;
 	}
 
-	if (_isVisible && !_forceShowWhenNoSpeech && !_vm->_audioSpeech->isPlaying()) {
-		_vm->_subtitles->hide(); // TODO might need a better system. Don't call it always.
+	if (_subtitlesData[kSubtitlesPrimary].isVisible
+	    && !_subtitlesData[kSubtitlesPrimary].forceShowWhenNoSpeech
+	    && !_vm->_audioSpeech->isPlaying()) {
+		_vm->_subtitles->hide(kSubtitlesPrimary); // TODO might need a better system. Don't call it always.
 	}
 
-	if (!_isVisible) { // keep it as a separate if
+	// keep this as a separate if clause
+	if (!isVisible(kSubtitlesPrimary) && !isVisible(kSubtitlesSecondary)) {
 		return;
 	}
 
 	draw(s);
 }
 
-bool Subtitles::isNotEmptyCurrentSubsText() {
-	if ((_useUTF8 && !_currentText32.empty())
-		|| (!_useUTF8 && !_currentText.empty())) {
+bool Subtitles::isNotEmptyCurrentSubsText(int subsRole) {
+	if ((_useUTF8 && !_subtitlesData[subsRole].currentText32.empty())
+	    || (!_useUTF8 && !_subtitlesData[subsRole].currentText.empty())) {
 		return true;
 	} else {
 		return false;
 	}
 }
 
-
 /**
  * Draw method for drawing the subtitles on the display surface
  */
 void Subtitles::draw(Graphics::Surface &s) {
-	if (!_isSystemActive || !_isVisible || !isNotEmptyCurrentSubsText()) {
+	if (!_isSystemActive
+	    || (!isVisible(kSubtitlesPrimary) && !isVisible(kSubtitlesSecondary))
+	    || (!isNotEmptyCurrentSubsText(kSubtitlesPrimary) && !isNotEmptyCurrentSubsText(kSubtitlesSecondary))) {
 		return;
 	}
 
-	uint linesNum = 0;
-	if (_useUTF8) {
-		// This check is done so that lines won't be re-calculated multiple times for the same text
-		if (_currentText32 != _prevText32) {
-			_lines32.clear();
-			_prevText32 = _currentText32;
-			_font->wordWrapText(_currentText32, kTextMaxWidth, _lines32, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
-		}
-		linesNum = _lines32.size();
-	} else {
-		// This check is done so that lines won't be re-calculated multiple times for the same text
-		if (_currentText != _prevText) {
-			_lines.clear();
-			_prevText = _currentText;
-			_font->wordWrapText(_currentText, kTextMaxWidth, _lines, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
-		}
-		linesNum = _lines.size();
-	}
-
-	int y = s.h - (kMarginBottom + MAX(kPreferedLine, linesNum) * _font->getFontHeight());
-
-	for (uint i = 0; i < linesNum; ++i, y += _font->getFontHeight()) {
-		switch (_subtitlesInfo.fontType) {
-			case Subtitles::kSubtitlesFontTypeInternal:
-				// shadow/outline is part of the font color data
-				_font->drawString(&s, _lines[i], 0, y, s.w, 0, Graphics::kTextAlignCenter);
-				break;
-			case Subtitles::kSubtitlesFontTypeTTF:
-				_font->drawString(&s, _lines32[i], -1, y    , s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
-				_font->drawString(&s, _lines32[i],  0, y - 1, s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
-				_font->drawString(&s, _lines32[i],  1, y    , s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
-				_font->drawString(&s, _lines32[i],  0, y + 1, s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
-
-				_font->drawString(&s, _lines32[i],  0, y    , s.w, s.format.RGBToColor(255, 255, 255), Graphics::kTextAlignCenter);
-				break;
+	for (int i = 0; i < kNumOfSubtitleRoles; ++i) {
+		if (isVisible(i) && isNotEmptyCurrentSubsText(i)) {
+			uint linesNum = 0;
+			if (_useUTF8) {
+				// This check is done so that lines won't be re-calculated multiple times for the same text
+				if (_subtitlesData[i].currentText32 != _subtitlesData[i].prevText32) {
+					_subtitlesData[i].lines32.clear();
+					_subtitlesData[i].prevText32 = _subtitlesData[i].currentText32;
+					_font->wordWrapText(_subtitlesData[i].currentText32, kTextMaxWidth, _subtitlesData[i].lines32, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
+				}
+				linesNum = _subtitlesData[i].lines32.size();
+			} else {
+				// This check is done so that lines won't be re-calculated multiple times for the same text
+				if (_subtitlesData[i].currentText != _subtitlesData[i].prevText) {
+					_subtitlesData[i].lines.clear();
+					_subtitlesData[i].prevText = _subtitlesData[i].currentText;
+					_font->wordWrapText(_subtitlesData[i].currentText, kTextMaxWidth, _subtitlesData[i].lines, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
+				}
+				linesNum = _subtitlesData[i].lines.size();
+			}
+
+			int y = kMarginTop;
+			if (i == kSubtitlesPrimary) {
+				// bottom of the screen
+				y = s.h - (kMarginBottom + MAX(kPreferedLine, linesNum) * _font->getFontHeight());
+			}
+
+			for (uint j = 0; j < linesNum; ++j, y += _font->getFontHeight()) {
+				switch (_subtitlesInfo.fontType) {
+				case Subtitles::kSubtitlesFontTypeInternal:
+					// shadow/outline is part of the font color data
+					_font->drawString(&s, _subtitlesData[i].lines[j], 0, y, s.w, 0, Graphics::kTextAlignCenter);
+					break;
+				case Subtitles::kSubtitlesFontTypeTTF:
+					_font->drawString(&s, _subtitlesData[i].lines32[j], -1, y    , s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
+					_font->drawString(&s, _subtitlesData[i].lines32[j],  0, y - 1, s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
+					_font->drawString(&s, _subtitlesData[i].lines32[j],  1, y    , s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
+					_font->drawString(&s, _subtitlesData[i].lines32[j],  0, y + 1, s.w, s.format.RGBToColor(  0,   0,   0), Graphics::kTextAlignCenter);
+
+					_font->drawString(&s, _subtitlesData[i].lines32[j],  0, y    , s.w, s.format.RGBToColor(255, 255, 255), Graphics::kTextAlignCenter);
+					break;
+				}
+			}
 		}
 	}
 }
 
 /**
- * Initialize a few basic member vars
+ * Clear subtitles text and reset isVisible and forceShowWhenNoSpeech flags
  */
 void Subtitles::clear() {
-	_isVisible = false;
-	_forceShowWhenNoSpeech = false;
-	_currentText.clear();
-	_currentText32.clear();
-	_prevText.clear();
-	_prevText32.clear();
-	_lines.clear();
-	_lines32.clear();
+	for (uint8 i = 0; i < kNumOfSubtitleRoles; ++i) {
+		_subtitlesData[i].isVisible = false;
+		_subtitlesData[i].forceShowWhenNoSpeech = false;
+		_subtitlesData[i].currentText32.clear();
+		_subtitlesData[i].prevText32.clear();
+		_subtitlesData[i].lines32.clear();
+
+		_subtitlesData[i].currentText.clear();
+		_subtitlesData[i].prevText.clear();
+		_subtitlesData[i].lines.clear();
+	}
 }
 
 /**
diff --git a/engines/bladerunner/subtitles.h b/engines/bladerunner/subtitles.h
index 46d1419d3f7..70b0f16f99b 100644
--- a/engines/bladerunner/subtitles.h
+++ b/engines/bladerunner/subtitles.h
@@ -44,6 +44,7 @@ class Subtitles {
 	// with corresponding _vm->_languageCode values: "E", "G", "F", "I", "E", "S" (Russian version is built on top of English one)
 	static const uint kPreferedLine            = 2;      // Prefer drawing from this line (the bottom-most of available subtitle lines index is 0) by default
 	static const int  kMarginBottom            = 12;     // In pixels. This is the bottom margin beneath the subtitles space
+	static const int  kMarginTop               = 12;     // In pixels. This is the top margin before secondary subtitles
 	static const int  kTextMaxWidth            = 610;    // In pixels
 	static const int  kMaxTextResourceEntries  = 27;     // Support in-game subs (1) and all possible VQAs (26) with spoken dialogue or translatable text
 	static const int  kMaxLanguageSelectionNum = 1024;   // Max allowed number of languages to select from (should be available in the MIX file)
@@ -52,6 +53,8 @@ class Subtitles {
 	static const char *SUBTITLES_FONT_FILENAME_EXTERNAL;
 	static const char *SUBTITLES_VERSION_TRENAME;
 
+	static const int  kNumOfSubtitleRoles       = 2;
+
 	BladeRunnerEngine *_vm;
 
 	enum SubtitlesFontType {
@@ -66,6 +69,27 @@ class Subtitles {
 		Common::String    credits;
 		SubtitlesFontType fontType;
 		Common::String    fontName;
+
+		SubtitlesInfo() : versionStr(""), dateOfCompile(""), languageMode(""), credits(""), fontName("")  { fontType = kSubtitlesFontTypeInternal; };
+	};
+
+	struct SubtitlesData {
+		bool isVisible;
+		bool forceShowWhenNoSpeech;
+		// U32String for when we use an external font that supports UTF-32 encoding
+		Common::U32String currentText32;
+		Common::U32String prevText32;
+		Common::Array<Common::U32String> lines32;
+
+		// For now, we're using the original game's FON format for native font
+		// and the original MIX for file for text resources.
+		// This means that when not explicitly using an external font,
+		// the text resources are in extended ASCII format that index the native font FON.
+		// FUTURE On a next revision we should support UTF-8 text in the MIX files which
+		// would work with external font.
+		Common::String currentText;
+		Common::String prevText;
+		Common::Array<Common::String> lines;
 	};
 
 	SubtitlesInfo  _subtitlesInfo;
@@ -74,15 +98,7 @@ class Subtitles {
 	Graphics::Font *_font;
 	bool            _useUTF8;
 
-	bool              _isVisible;
-	bool              _forceShowWhenNoSpeech;
-	Common::U32String _currentText32;
-	Common::U32String _prevText32;
-	Common::String    _currentText;
-	Common::String    _prevText;
-
-	Common::Array<Common::U32String> _lines32;
-	Common::Array<Common::String> _lines;
+	Common::Array<SubtitlesData> _subtitlesData;
 
 	bool _gameSubsResourceEntriesFound[kMaxTextResourceEntries]; // false if a TRE file did not open successfully
 	bool _isSystemActive;                                        // true if the whole subtitles subsystem should be disabled (due to missing required resources)
@@ -98,22 +114,29 @@ public:
 	void loadInGameSubsText(int actorId, int speech_id);                     // get the text for actorId, quoteId (in-game subs)
 	void loadOuttakeSubsText(const Common::String &outtakesName, int frame); // get the text for this frame if any
 
-	void setGameSubsText(Common::String dbgQuote, bool force); // for debugging - explicit set subs text
-	bool show();
-	bool hide();
-	bool isVisible() const;
+	void setGameSubsText(int subsRole, Common::String dbgQuote, bool force); // for debugging - explicit set subs text
+
+	bool show(int subsRole);
+	bool hide(int subsRole);
+	void clear();
+
+	bool isVisible(int subsRole) const;
 	void tick(Graphics::Surface &s);
 	void tickOuttakes(Graphics::Surface &s);
 
+	enum SubtitlesRole {
+		kSubtitlesPrimary,
+		kSubtitlesSecondary
+	};
+
 private:
 	void draw(Graphics::Surface &s);
 
 	int getIdxForSubsTreName(const Common::String &treName) const;
 
-	void clear();
 	void reset();
 
-	bool isNotEmptyCurrentSubsText();
+	bool isNotEmptyCurrentSubsText(int subsRole);
 };
 
 } // End of namespace BladeRunner
diff --git a/engines/bladerunner/ui/vk.cpp b/engines/bladerunner/ui/vk.cpp
index d85b5ffb491..3a6122fab46 100644
--- a/engines/bladerunner/ui/vk.cpp
+++ b/engines/bladerunner/ui/vk.cpp
@@ -192,13 +192,9 @@ void VK::tick() {
 	draw();
 
 	if ( _vm->_debugger->_showStatsVk
-		&& !_vm->_actors[_actorId]->isSpeeching()
-		&& !_vm->_actors[kActorMcCoy]->isSpeeching()
-		&& !_vm->_actors[kActorAnsweringMachine]->isSpeeching()
-		&& !_isClosing
-	) {
-		_vm->_subtitles->setGameSubsText(Common::String::format("Adjustment: %03d Calibration: %02d Ratio: %02d\nAnxiety: %02d%% Replicant: %02d%% Human: %02d%%", _adjustment, _calibration, _calibrationRatio, _anxiety, _replicantProbability, _humanProbability), true);
-		_vm->_subtitles->show();
+	    && !_isClosing) {
+		_vm->_subtitles->setGameSubsText(BladeRunner::Subtitles::kSubtitlesSecondary, Common::String::format("Adjustment: %03d Calibration: %02d Ratio: %02d\nAnxiety: %02d%% Replicant: %02d%% Human: %02d%%", _adjustment, _calibration, _calibrationRatio, _anxiety, _replicantProbability, _humanProbability), true);
+		_vm->_subtitles->show(BladeRunner::Subtitles::kSubtitlesSecondary);
 	}
 
 	_vm->_subtitles->tick(_vm->_surfaceFront);
@@ -207,6 +203,10 @@ void VK::tick() {
 
 	// unsigned difference is intentional
 	if (_isClosing && (_vm->_time->current() - _timeCloseStart >= 3000u) && !_script->isInsideScript()) {
+		if ( _vm->_debugger->_showStatsVk) {
+			_vm->_subtitles->setGameSubsText(BladeRunner::Subtitles::kSubtitlesSecondary, "", false);
+			_vm->_subtitles->hide(BladeRunner::Subtitles::kSubtitlesSecondary);
+		}
 		close();
 		_vm->_mouse->enable();
 		reset();


Commit: edbd1761861c17f59553ae440e9aef557d200c02
    https://github.com/scummvm/scummvm/commit/edbd1761861c17f59553ae440e9aef557d200c02
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2022-06-30T15:13:41+03:00

Commit Message:
BLADERUNNER: Fix special case for German audio and subtitles

Two quotes need to be merged in McCoy's beginning speech

Changed paths:
    engines/bladerunner/subtitles.cpp
    engines/bladerunner/subtitles.h


diff --git a/engines/bladerunner/subtitles.cpp b/engines/bladerunner/subtitles.cpp
index 58a7428debf..b3459bb2f44 100644
--- a/engines/bladerunner/subtitles.cpp
+++ b/engines/bladerunner/subtitles.cpp
@@ -246,14 +246,25 @@ void Subtitles::loadInGameSubsText(int actorId, int speech_id)  {
 		return;
 	}
 
-	// Search in the first TextResource of the _vqaSubsTextResourceEntries table,
-	// which is the TextResource for in-game dialogue (i.e. not VQA dialogue)
-	int32 id = 10000 * actorId + speech_id;
-	const char *text = _vqaSubsTextResourceEntries[0]->getText((uint32)id);
-	if (_useUTF8) {
-		_subtitlesData[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(text);
-	} else {
-		_subtitlesData[kSubtitlesPrimary].currentText = text;
+	bool specialSubtitleCase = false;
+	if (_vm->_language == Common::DE_DEU) {
+		// Special cases for some localizations
+		if (actorId == kActorVoiceOver && speech_id == 1850) {
+			mergeSubtitleQuotes(actorId, 1850, 1860);
+			specialSubtitleCase = true;
+		}
+	}
+
+	if (!specialSubtitleCase) {
+		// Search in the first TextResource of the _vqaSubsTextResourceEntries table,
+		// which is the TextResource for in-game dialogue (i.e. not VQA dialogue)
+		int32 id = 10000 * actorId + speech_id;
+		const char *text = _vqaSubsTextResourceEntries[0]->getText((uint32)id);
+		if (_useUTF8) {
+			_subtitlesData[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(text);
+		} else {
+			_subtitlesData[kSubtitlesPrimary].currentText = text;
+		}
 	}
 }
 
@@ -404,6 +415,20 @@ bool Subtitles::isNotEmptyCurrentSubsText(int subsRole) {
 	}
 }
 
+void Subtitles::mergeSubtitleQuotes(int actorId, int quoteFirst, int quoteSecond) {
+	int32 idFirst = 10000 * actorId + quoteFirst;
+	int32 idSecond = 10000 * actorId + quoteSecond;
+	const char *textFirst = _vqaSubsTextResourceEntries[0]->getText((uint32)idFirst);
+	const char *textSecond = _vqaSubsTextResourceEntries[0]->getText((uint32)idSecond);
+	if (_useUTF8) {
+		_subtitlesData[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(textFirst);
+		_subtitlesData[kSubtitlesPrimary].currentText32 += " " + Common::convertUtf8ToUtf32(textSecond);
+	} else {
+		_subtitlesData[kSubtitlesPrimary].currentText = textFirst;
+		_subtitlesData[kSubtitlesPrimary].currentText += " " + Common::String(textSecond);
+	}
+}
+
 /**
  * Draw method for drawing the subtitles on the display surface
  */
diff --git a/engines/bladerunner/subtitles.h b/engines/bladerunner/subtitles.h
index 70b0f16f99b..9fe3ca4799f 100644
--- a/engines/bladerunner/subtitles.h
+++ b/engines/bladerunner/subtitles.h
@@ -137,6 +137,7 @@ private:
 	void reset();
 
 	bool isNotEmptyCurrentSubsText(int subsRole);
+	void mergeSubtitleQuotes(int actorId, int quoteFirst, int quoteSecond);
 };
 
 } // End of namespace BladeRunner




More information about the Scummvm-git-logs mailing list