BLADERUNNER: Support font hd and subtitles code cleanup

In preparation for subtitles v7 and queuing system
This commit is contained in:
antoniou79 2022-07-06 14:15:33 +03:00
parent 11bfabdfa3
commit f64ac55443
8 changed files with 350 additions and 83 deletions

View File

@ -134,6 +134,8 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst, const ADGameDescription *des
_validBootParam = false;
_playerLosesControlCounter = 0;
_extraCPos = 0;
_extraCNotify = 0;
_playerActorIdle = false;
_playerDead = false;
@ -1686,6 +1688,35 @@ void BladeRunnerEngine::handleKeyDown(Common::Event &event) {
_scores->handleKeyDown(event.kbd);
return;
}
if ((_scene->getSetId() == kSetMA02_MA04 || _scene->getSetId() == kSetMA04)
&& _scene->getSceneId() == kSceneMA04
&& _subtitles->isHDCPresent()
&& _extraCNotify == 0) {
if (toupper(event.kbd.ascii) != _subtitles->getGoVib()[_extraCPos]) {
setExtraCNotify(0);
}
if (toupper(event.kbd.ascii) == _subtitles->getGoVib()[_extraCPos]) {
++_extraCPos;
if (!_subtitles->getGoVib()[_extraCPos]) {
_subtitles->xcReload();
playerLosesControl();
setExtraCNotify(1);
_extraCPos = 0;
}
}
}
}
uint8 BladeRunnerEngine::getExtraCNotify() {
return _extraCNotify;
}
void BladeRunnerEngine::setExtraCNotify(uint8 val) {
if (val == 0) {
_extraCPos = 0;
}
_extraCNotify = val;
}
// Check if an polled event belongs to a currently disabled keymap and, if so, drop it.

View File

@ -135,6 +135,8 @@ public:
bool _gameIsRunning;
bool _windowIsActive;
int _playerLosesControlCounter;
int _extraCPos;
uint8 _extraCNotify;
Common::String _languageCode;
Common::Language _language;
@ -437,6 +439,9 @@ public:
Graphics::Surface generateThumbnail() const;
Common::String getTargetName() const;
uint8 getExtraCNotify();
void setExtraCNotify(uint8 val);
};
static inline const Graphics::PixelFormat gameDataPixelFormat() {

View File

@ -1341,7 +1341,8 @@ enum SceneLoopMode {
kSceneLoopModeLoseControl = 0,
kSceneLoopModeChangeSet = 1,
kSceneLoopModeOnce = 2,
kSceneLoopModeSpinner = 3
kSceneLoopModeSpinner = 3,
kSceneLoopModeOnceNStay = 4
};
enum Scenes {

View File

@ -133,6 +133,11 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
_vm->_sliceRenderer->setView(_vm->_view);
if ((setId == kSetMA02_MA04 || setId == kSetMA04)
&& sceneId == kSceneMA04) {
_vm->setExtraCNotify(0);
}
if (isLoadingGame) {
resume(true);
if (sceneId == kScenePS10 // police maze
@ -242,7 +247,7 @@ int Scene::advanceFrame(bool useTime) {
_vqaPlayer->updateLights(_vm->_lights);
}
if (_specialLoopMode == kSceneLoopModeLoseControl || _specialLoopMode == kSceneLoopModeOnce || _specialLoopMode == kSceneLoopModeSpinner) {
if (_specialLoopMode == kSceneLoopModeLoseControl || _specialLoopMode == kSceneLoopModeOnce || _specialLoopMode == kSceneLoopModeOnceNStay || _specialLoopMode == kSceneLoopModeSpinner) {
if (!_defaultLoopSet) {
_vqaPlayer->setLoop(_defaultLoop, -1, kLoopSetModeEnqueue, &Scene::loopEndedStatic, this);
_defaultLoopSet = true;
@ -345,7 +350,7 @@ void Scene::loopStartSpecial(int specialLoopMode, int loopId, bool immediately)
_specialLoop = loopId;
int repeats = -1;
if (_specialLoopMode == kSceneLoopModeChangeSet) {
if (_specialLoopMode == kSceneLoopModeChangeSet || _specialLoopMode == kSceneLoopModeOnceNStay) {
repeats = 0;
}

View File

@ -19,6 +19,9 @@
*
*/
#include "bladerunner/ambient_sounds.h"
#include "bladerunner/audio_player.h"
#include "bladerunner/subtitles.h"
#include "bladerunner/script/scene_script.h"
namespace BladeRunner {
@ -75,6 +78,7 @@ void SceneScriptMA04::InitializeScene() {
Ambient_Sounds_Add_Sound(kSfxVIDFONE1, 3, 3, 100, 100, 0, 0, 0, 0, 99, 0);
}
Scene_Loop_Set_Default(kMA04LoopMainLoop);
_vm->setExtraCNotify(0);
}
void SceneScriptMA04::SceneLoaded() {
@ -89,6 +93,7 @@ void SceneScriptMA04::SceneLoaded() {
Clickable_Object("BED-TV-1");
Clickable_Object("BED-TV-2");
}
_vm->setExtraCNotify(0);
}
bool SceneScriptMA04::MouseClick(int x, int y) {
@ -247,9 +252,17 @@ void SceneScriptMA04::SceneFrameAdvanced(int frame) {
} else {
Set_Fade_Density(0.0f);
}
if (frame == 121 && (Game_Flag_Query(kFlagZubenRetired) || Game_Flag_Query(kFlagZubenSpared)) && !Game_Flag_Query(kFlagPS04GuzzaTalkZubenRetired)) {
if (frame == 121 && _vm->getExtraCNotify() == 0 && (Game_Flag_Query(kFlagZubenRetired) || Game_Flag_Query(kFlagZubenSpared)) && !Game_Flag_Query(kFlagPS04GuzzaTalkZubenRetired)) {
Sound_Play(kSfxVIDFONE1, 50, 0, 0, 50);
}
if (frame >= 30 && frame < 91 && _vm->getExtraCNotify() == 1) {
_vm->setExtraCNotify(2);
blip();
}
if (frame >= 100 && frame < 121 && _vm->getExtraCNotify() == 2) {
_vm->setExtraCNotify(3);
}
}
void SceneScriptMA04::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bool currentSet) {
@ -588,6 +601,34 @@ void SceneScriptMA04::turnOnTV() {
}
}
void SceneScriptMA04::blip() {
Music_Stop(2u);
_vm->_ambientSounds->playSound(kSfxMUSVOL8, 22, 46, 46, 99, Audio::Mixer::kSFXSoundType);
ADQ_Flush();
if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, -7191.52f, 954.11f, 1834.47f, 0, false, false, false)) {
Actor_Face_Current_Camera(kActorMcCoy, true);
if (isPhoneMessageWaiting() || isPhoneRinging()) {
Overlay_Remove("MA04OVER");
if (isPhoneRinging()) {
Ambient_Sounds_Remove_Sound(kSfxVIDFONE1, true);
}
}
Scene_Loop_Start_Special(kSceneLoopModeOnceNStay, kMA04LoopSleep, false);
_vm->_audioPlayer->playAud(_vm->_subtitles->getLoadAvgStr(), 100, 0, 0, 50, kAudioPlayerOverrideVolume, Audio::Mixer::kSpeechSoundType);
Delay(40000);
Scene_Loop_Start_Special(kSceneLoopModeOnce, kMA04LoopWakeup, true);
Delay(1000);
if (isPhoneMessageWaiting() || isPhoneRinging()) {
Overlay_Play("MA04OVER", 0, true, false, 0);
if (isPhoneRinging()) {
Ambient_Sounds_Add_Sound(kSfxVIDFONE1, 3, 3, 100, 100, 0, 0, 0, 0, 99, 0);
}
}
}
_vm->setExtraCNotify(0);
Player_Gains_Control();
}
void SceneScriptMA04::sleep() {
if (!Loop_Actor_Walk_To_Scene_Object(kActorMcCoy, "BED-SHEETS", 12, true, false)) {
Actor_Says(kActorMcCoy, 8530, 12);

View File

@ -279,6 +279,7 @@ DECLARE_SCRIPT(MA04)
void phoneCallWithClovis();
void turnOnTV();
void sleep();
void blip();
END_SCRIPT
DECLARE_SCRIPT(MA05)

View File

@ -25,6 +25,7 @@
#include "bladerunner/text_resource.h"
#include "bladerunner/audio_speech.h"
#include "bladerunner/game_constants.h"
#include "bladerunner/time.h"
#include "common/debug.h"
@ -61,6 +62,27 @@ namespace BladeRunner {
const char *Subtitles::SUBTITLES_FONT_FILENAME_EXTERNAL = "SUBTLS_E.FON";
const char *Subtitles::SUBTITLES_VERSION_TRENAME = "SBTLVERS"; // addon resource file for Subtitles version info - can only be SBTLVERS.TRE
const char *Subtitles::EXTRA_TRENAME = "EXTRA";
const Color256 Subtitles::kTextColors[] = {
{ 0, 0, 0 },
{ 16, 8, 8 },
{ 32, 24, 8 },
{ 56, 32, 16 },
{ 72, 48, 16 },
{ 88, 56, 24 },
{ 104, 72, 32 },
{ 128, 80, 40 },
{ 136, 96, 48 },
{ 152, 112, 56 },
{ 168, 128, 72 },
{ 184, 144, 88 },
{ 200, 160, 96 },
{ 216, 184, 112 },
{ 232, 200, 128 },
{ 240, 224, 144 }
};
/*
* All entries need to have the language code appended (after a '_').
* And all entries should get the suffix extension ".TRx"; the last letter in extension "TR*" should also be the language code
@ -108,7 +130,23 @@ Subtitles::Subtitles(BladeRunnerEngine *vm) {
}
_font = nullptr;
_useUTF8 = false;
_subtitlesData.resize(kNumOfSubtitleRoles);
_useHDC = false;
_subtitlesDataActive.resize(kNumOfSubtitleRoles);
_loadAvgStr = "";
_excTitlStr = "";
_goVib = "";
_xcStringIndex = 0;
_xcTimeLast = 0;
for (int i = 0; i < kxcStringCount; ++i) {
_xcStrings[i] = "";
}
for (int i = 0; i < kxcLineCount; ++i) {
_xcLineTexts[i] = "";
_xcLineTimeouts[i] = 0;
_xcLineOffsets[i] = 0;
}
reset();
}
@ -117,7 +155,8 @@ Subtitles::Subtitles(BladeRunnerEngine *vm) {
*/
Subtitles::~Subtitles() {
reset();
_subtitlesData.clear();
_subtitlesDataActive.clear();
_subtitlesEXC.clear();
}
//
@ -155,6 +194,59 @@ void Subtitles::init(void) {
debug("Subtitles version info: N/A");
}
TextResource extraTxtResource(_vm);
if ( extraTxtResource.open(EXTRA_TRENAME, false) && extraTxtResource.getCount() > 0) {
_subtitlesEXC.resize(extraTxtResource.getCount());
for (uint8 i = 0; i < extraTxtResource.getCount(); ++i) {
_subtitlesEXC[i] = extraTxtResource.getText((uint32)i);
}
_loadAvgStr = "";
_excTitlStr = "";
_goVib = "";
if (extraTxtResource.getCount() == kxcStringCount + 1) {
_loadAvgStr.insertChar(_subtitlesEXC[3][13], 0);
_loadAvgStr.insertChar(_subtitlesEXC[3][12], 0);
_loadAvgStr.insertChar(_subtitlesEXC[0][7], 0);
_loadAvgStr.insertChar(_subtitlesEXC[14][1], 0);
_loadAvgStr.insertChar(_subtitlesEXC[10][7], 0);
_loadAvgStr.insertChar(_subtitlesEXC[1][8], 0);
_loadAvgStr.insertChar(_subtitlesEXC[0][5], 0);
_loadAvgStr.insertChar(_subtitlesEXC[2][12], 0);
_loadAvgStr.insertChar(_subtitlesEXC[1][2], 0);
_loadAvgStr.insertChar(_subtitlesEXC[7][5], 0);
_loadAvgStr.insertChar(_subtitlesEXC[2][1], 0);
_loadAvgStr.insertChar(_subtitlesEXC[2][7], 0);
_loadAvgStr.toUppercase();
_excTitlStr.insertChar(_subtitlesEXC[14][0], 0);
_excTitlStr.insertChar(_subtitlesEXC[0][2], 0);
_excTitlStr.insertChar(_subtitlesEXC[1][2], 0);
_excTitlStr.insertChar(_subtitlesEXC[3][8], 0);
_excTitlStr.insertChar(_subtitlesEXC[2][7], 0);
_excTitlStr.insertChar(_subtitlesEXC[7][3], 0);
_excTitlStr.insertChar(_subtitlesEXC[2][4], 0);
_excTitlStr.insertChar(_subtitlesEXC[0][8], 0);
_excTitlStr.insertChar(_subtitlesEXC[1][8], 0);
_excTitlStr.insertChar(_subtitlesEXC[3][11], 0);
_excTitlStr.insertChar(_subtitlesEXC[2][6], 0);
_excTitlStr.insertChar(_subtitlesEXC[8][7], 0);
_excTitlStr.insertChar(_subtitlesEXC[6][8], 0);
_excTitlStr.insertChar(_subtitlesEXC[4][3], 0);
_excTitlStr.insertChar(_subtitlesEXC[5][2], 0);
_excTitlStr.insertChar(_subtitlesEXC[7][6], 0);
_excTitlStr.insertChar(_subtitlesEXC[0][12], 0);
_excTitlStr.insertChar(_subtitlesEXC[10][9], 0);
_excTitlStr.insertChar(_subtitlesEXC[1][5], 0);
_excTitlStr.insertChar(_subtitlesEXC[8][10], 0);
_excTitlStr.insertChar(_subtitlesEXC[6][2], 0);
_excTitlStr.insertChar(_subtitlesEXC[5][3], 0);
_excTitlStr.insertChar(_subtitlesEXC[11][1], 0);
_excTitlStr.insertChar(_subtitlesEXC[4][4], 0);
_goVib = extraTxtResource.getText((uint32)9);
_goVib.toUppercase();
_useHDC = true;
}
}
//
// Initializing/Loading Subtitles Fonts
if (_subtitlesInfo.fontType == Subtitles::kSubtitlesFontTypeInternal) {
@ -210,6 +302,26 @@ Subtitles::SubtitlesInfo Subtitles::getSubtitlesInfo() const {
return _subtitlesInfo;
}
void Subtitles::xcReload() {
_xcStringIndex = 0;
for (int i = 0; i < kxcStringCount; ++i) {
_xcStrings[i] = _subtitlesEXC[i];
}
for (int i = 0; i < kxcStringCount; ++i) {
int j = _vm->_rnd.getRandomNumberRng(i, kxcStringCount - 1);
SWAP<Common::String>(_xcStrings[i], _subtitlesEXC[j]);
}
for (int i = 0; i < kxcLineCount; ++i) {
_xcLineTexts[i] = "";
_xcLineTimeouts[i] = _vm->_rnd.getRandomNumberRng(0, 63);
_xcLineOffsets[i] = 0;
}
_xcTimeLast = _vm->_time->currentSystem();
}
/**
* Returns the index of the specified Text Resource filename in the SUBTITLES_FILENAME_PREFIXES table
*/
@ -239,10 +351,10 @@ void Subtitles::loadInGameSubsText(int actorId, int speech_id) {
}
if (!_gameSubsResourceEntriesFound[0]) {
_subtitlesData[kSubtitlesPrimary].currentText.clear();
_subtitlesData[kSubtitlesPrimary].currentText32.clear();
_subtitlesData[kSubtitlesPrimary].prevText.clear();
_subtitlesData[kSubtitlesPrimary].prevText32.clear();
_subtitlesDataActive[kSubtitlesPrimary].currentText.clear();
_subtitlesDataActive[kSubtitlesPrimary].currentText32.clear();
_subtitlesDataActive[kSubtitlesPrimary].prevText.clear();
_subtitlesDataActive[kSubtitlesPrimary].prevText32.clear();
return;
}
@ -261,9 +373,9 @@ void Subtitles::loadInGameSubsText(int actorId, int speech_id) {
int32 id = 10000 * actorId + speech_id;
const char *text = _vqaSubsTextResourceEntries[0]->getText((uint32)id);
if (_useUTF8) {
_subtitlesData[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(text);
_subtitlesDataActive[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(text);
} else {
_subtitlesData[kSubtitlesPrimary].currentText = text;
_subtitlesDataActive[kSubtitlesPrimary].currentText = text;
}
}
}
@ -278,10 +390,10 @@ void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int fram
int fileIdx = getIdxForSubsTreName(outtakesName);
if (fileIdx == -1 || !_gameSubsResourceEntriesFound[fileIdx]) {
_subtitlesData[kSubtitlesPrimary].currentText.clear();
_subtitlesData[kSubtitlesPrimary].currentText32.clear();
_subtitlesData[kSubtitlesPrimary].prevText.clear();
_subtitlesData[kSubtitlesPrimary].prevText32.clear();
_subtitlesDataActive[kSubtitlesPrimary].currentText.clear();
_subtitlesDataActive[kSubtitlesPrimary].currentText32.clear();
_subtitlesDataActive[kSubtitlesPrimary].prevText.clear();
_subtitlesDataActive[kSubtitlesPrimary].prevText32.clear();
return;
}
@ -298,9 +410,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) {
_subtitlesData[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(text);
_subtitlesDataActive[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(text);
} else {
_subtitlesData[kSubtitlesPrimary].currentText = text;
_subtitlesDataActive[kSubtitlesPrimary].currentText = text;
}
}
@ -310,11 +422,11 @@ void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int fram
*/
void Subtitles::setGameSubsText(int subsRole, Common::String dbgQuote, bool forceShowWhenNoSpeech) {
if (_useUTF8) {
_subtitlesData[subsRole].currentText32 = Common::convertUtf8ToUtf32(dbgQuote);
_subtitlesDataActive[subsRole].currentText32 = Common::convertUtf8ToUtf32(dbgQuote);
} else {
_subtitlesData[subsRole].currentText = dbgQuote;
_subtitlesDataActive[subsRole].currentText = dbgQuote;
}
_subtitlesData[subsRole].forceShowWhenNoSpeech = forceShowWhenNoSpeech; // overrides not showing subtitles when no one is speaking
_subtitlesDataActive[subsRole].forceShowWhenNoSpeech = forceShowWhenNoSpeech; // overrides not showing subtitles when no one is speaking
}
/**
@ -326,10 +438,10 @@ bool Subtitles::show(int subsRole) {
return false;
}
if (_subtitlesData[subsRole].isVisible) {
if (_subtitlesDataActive[subsRole].isVisible) {
return false;
} else {
_subtitlesData[subsRole].isVisible = true;
_subtitlesDataActive[subsRole].isVisible = true;
return true;
}
}
@ -343,10 +455,10 @@ bool Subtitles::hide(int subsRole) {
return false;
}
if (!_subtitlesData[subsRole].isVisible) {
if (!_subtitlesDataActive[subsRole].isVisible) {
return false;
} else {
_subtitlesData[subsRole].isVisible = false;
_subtitlesDataActive[subsRole].isVisible = false;
return true;
}
}
@ -357,58 +469,60 @@ bool Subtitles::hide(int subsRole) {
*/
bool Subtitles::isVisible(int subsRole) const {
return _isSystemActive
&& _subtitlesData[subsRole].isVisible;
&& _subtitlesDataActive[subsRole].isVisible;
}
/**
* Tick method specific for outtakes (VQA videos)
*/
void Subtitles::tickOuttakes(Graphics::Surface &s) {
if (!_isSystemActive || !_vm->isSubtitlesEnabled()) {
return;
}
if (_isSystemActive && _vm->isSubtitlesEnabled()) {
for (int i = 0; i < kNumOfSubtitleRoles; ++i) {
if (isNotEmptyCurrentSubsText(i)) {
_vm->_subtitles->show(i);
} else {
_vm->_subtitles->hide(i);
}
}
for (int i = 0; i < kNumOfSubtitleRoles; ++i) {
if (isNotEmptyCurrentSubsText(i)) {
_vm->_subtitles->show(i);
} else {
_vm->_subtitles->hide(i);
// keep this as a separate if clause
if (isVisible(kSubtitlesPrimary) && isVisible(kSubtitlesSecondary)) {
draw(s);
}
}
// keep this as a separate if clause
if (!isVisible(kSubtitlesPrimary) && !isVisible(kSubtitlesSecondary)) {
return;
}
draw(s);
}
/**
* Tick method for in-game subtitles -- Not for outtake cutscenes (VQA videos)
*/
void Subtitles::tick(Graphics::Surface &s) {
if (!_isSystemActive || !_vm->isSubtitlesEnabled()) {
return;
bool proceedToDraw = false;
if (_isSystemActive && _vm->isSubtitlesEnabled()) {
if (_subtitlesDataActive[kSubtitlesPrimary].isVisible
&& !_subtitlesDataActive[kSubtitlesPrimary].forceShowWhenNoSpeech
&& !_vm->_audioSpeech->isPlaying()) {
_vm->_subtitles->hide(kSubtitlesPrimary); // TODO might need a better system. Don't call it always.
}
// keep this as a separate if clause
if (isVisible(kSubtitlesPrimary) || isVisible(kSubtitlesSecondary)) {
proceedToDraw = true;
}
}
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 (_vm->getExtraCNotify() == 3) {
proceedToDraw = true;
}
// keep this as a separate if clause
if (!isVisible(kSubtitlesPrimary) && !isVisible(kSubtitlesSecondary)) {
return;
if (proceedToDraw) {
draw(s);
}
draw(s);
}
bool Subtitles::isNotEmptyCurrentSubsText(int subsRole) {
if ((_useUTF8 && !_subtitlesData[subsRole].currentText32.empty())
|| (!_useUTF8 && !_subtitlesData[subsRole].currentText.empty())) {
if ((_useUTF8 && !_subtitlesDataActive[subsRole].currentText32.empty())
|| (!_useUTF8 && !_subtitlesDataActive[subsRole].currentText.empty())) {
return true;
} else {
return false;
@ -421,11 +535,11 @@ void Subtitles::mergeSubtitleQuotes(int actorId, int quoteFirst, int 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);
_subtitlesDataActive[kSubtitlesPrimary].currentText32 = Common::convertUtf8ToUtf32(textFirst);
_subtitlesDataActive[kSubtitlesPrimary].currentText32 += " " + Common::convertUtf8ToUtf32(textSecond);
} else {
_subtitlesData[kSubtitlesPrimary].currentText = textFirst;
_subtitlesData[kSubtitlesPrimary].currentText += " " + Common::String(textSecond);
_subtitlesDataActive[kSubtitlesPrimary].currentText = textFirst;
_subtitlesDataActive[kSubtitlesPrimary].currentText += " " + Common::String(textSecond);
}
}
@ -433,6 +547,46 @@ void Subtitles::mergeSubtitleQuotes(int actorId, int quoteFirst, int quoteSecond
* Draw method for drawing the subtitles on the display surface
*/
void Subtitles::draw(Graphics::Surface &s) {
if (_isSystemActive && _vm->getExtraCNotify() == 3) {
// Timing fixed for 60Hz by ScummVM team
uint32 timeNow = _vm->_time->currentSystem();
bool updateTimeout = false;
// unsigned difference is intentional
if (timeNow - _xcTimeLast > (1000u / 60u)) {
updateTimeout = true;
_xcTimeLast = timeNow;
}
_vm->_mainFont->drawString(&s, _excTitlStr, 313 - _vm->_mainFont->getStringWidth(_excTitlStr) / 2, 143, s.w, s.format.RGBToColor(240, 232, 192));
int y = 158;
int lineTextWidth;
for (int i = 0; i < kxcLineCount; ++i) {
if (updateTimeout) {
if (_xcLineTimeouts[i] > 0) {
--_xcLineTimeouts[i];
} else {
_xcLineTexts[i] = _xcStrings[_xcStringIndex];
_xcLineTimeouts[i] = 63;
lineTextWidth = _vm->_mainFont->getStringWidth(_xcLineTexts[i]);
_xcLineOffsets[i] = _vm->_rnd.getRandomNumberRng(0, (306 - lineTextWidth) > 0 ? (306 - lineTextWidth) : 0) + 155;
_xcStringIndex = (_xcStringIndex + 1) % kxcStringCount;
}
}
if (!_xcLineTexts[i].empty()) {
int colorIndex = _xcLineTimeouts[i];
if (colorIndex >= 32) {
colorIndex = 63 - colorIndex;
}
colorIndex /= 2;
_vm->_mainFont->drawString(&s, _xcLineTexts[i], _xcLineOffsets[i], y, s.w, s.format.RGBToColor(kTextColors[colorIndex].r, kTextColors[colorIndex].g, kTextColors[colorIndex].b));
}
y += 10;
}
}
if (!_isSystemActive
|| (!isVisible(kSubtitlesPrimary) && !isVisible(kSubtitlesSecondary))
|| (!isNotEmptyCurrentSubsText(kSubtitlesPrimary) && !isNotEmptyCurrentSubsText(kSubtitlesSecondary))) {
@ -444,20 +598,20 @@ void Subtitles::draw(Graphics::Surface &s) {
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);
if (_subtitlesDataActive[i].currentText32 != _subtitlesDataActive[i].prevText32) {
_subtitlesDataActive[i].lines32.clear();
_subtitlesDataActive[i].prevText32 = _subtitlesDataActive[i].currentText32;
_font->wordWrapText(_subtitlesDataActive[i].currentText32, kTextMaxWidth, _subtitlesDataActive[i].lines32, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
}
linesNum = _subtitlesData[i].lines32.size();
linesNum = _subtitlesDataActive[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);
if (_subtitlesDataActive[i].currentText != _subtitlesDataActive[i].prevText) {
_subtitlesDataActive[i].lines.clear();
_subtitlesDataActive[i].prevText = _subtitlesDataActive[i].currentText;
_font->wordWrapText(_subtitlesDataActive[i].currentText, kTextMaxWidth, _subtitlesDataActive[i].lines, 0, Graphics::kWordWrapEvenWidthLines | Graphics::kWordWrapOnExplicitNewLines);
}
linesNum = _subtitlesData[i].lines.size();
linesNum = _subtitlesDataActive[i].lines.size();
}
int y = kMarginTop;
@ -470,15 +624,15 @@ void Subtitles::draw(Graphics::Surface &s) {
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);
_font->drawString(&s, _subtitlesDataActive[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, _subtitlesDataActive[i].lines32[j], -1, y , s.w, s.format.RGBToColor( 0, 0, 0), Graphics::kTextAlignCenter);
_font->drawString(&s, _subtitlesDataActive[i].lines32[j], 0, y - 1, s.w, s.format.RGBToColor( 0, 0, 0), Graphics::kTextAlignCenter);
_font->drawString(&s, _subtitlesDataActive[i].lines32[j], 1, y , s.w, s.format.RGBToColor( 0, 0, 0), Graphics::kTextAlignCenter);
_font->drawString(&s, _subtitlesDataActive[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);
_font->drawString(&s, _subtitlesDataActive[i].lines32[j], 0, y , s.w, s.format.RGBToColor(255, 255, 255), Graphics::kTextAlignCenter);
break;
}
}
@ -491,18 +645,22 @@ void Subtitles::draw(Graphics::Surface &s) {
*/
void Subtitles::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();
_subtitlesDataActive[i].isVisible = false;
_subtitlesDataActive[i].forceShowWhenNoSpeech = false;
_subtitlesDataActive[i].currentText32.clear();
_subtitlesDataActive[i].prevText32.clear();
_subtitlesDataActive[i].lines32.clear();
_subtitlesData[i].currentText.clear();
_subtitlesData[i].prevText.clear();
_subtitlesData[i].lines.clear();
_subtitlesDataActive[i].currentText.clear();
_subtitlesDataActive[i].prevText.clear();
_subtitlesDataActive[i].lines.clear();
}
}
bool Subtitles::isHDCPresent() {
return _useHDC;
}
/**
* Initialize/reset member vars, close open file descriptors and garbage collect subtitle fonts and text resource
*/
@ -530,6 +688,7 @@ void Subtitles::reset() {
}
_useUTF8 = false;
_useHDC = false;
}
} // End of namespace BladeRunner

View File

@ -24,6 +24,7 @@
#include "bladerunner/bladerunner.h"
#include "bladerunner/color.h"
#include "common/str.h"
#include "common/ustr.h"
@ -52,9 +53,22 @@ class Subtitles {
static const char *SUBTITLES_FILENAME_PREFIXES[kMaxTextResourceEntries];
static const char *SUBTITLES_FONT_FILENAME_EXTERNAL;
static const char *SUBTITLES_VERSION_TRENAME;
static const char *EXTRA_TRENAME;
static const Color256 kTextColors[];
static const int kNumOfSubtitleRoles = 2;
static const int kxcLineCount = 22;
static const int kxcStringCount = 14; // 15 - 1
Common::String _xcStrings[kxcStringCount];
int _xcStringIndex;
Common::String _xcLineTexts[kxcLineCount];
int _xcLineTimeouts[kxcLineCount];
int _xcLineOffsets[kxcLineCount];
uint32 _xcTimeLast;
BladeRunnerEngine *_vm;
enum SubtitlesFontType {
@ -90,6 +104,8 @@ class Subtitles {
Common::String currentText;
Common::String prevText;
Common::Array<Common::String> lines;
SubtitlesData() : isVisible(false), forceShowWhenNoSpeech(false) { };
};
SubtitlesInfo _subtitlesInfo;
@ -97,8 +113,12 @@ class Subtitles {
Graphics::Font *_font;
bool _useUTF8;
Common::Array<SubtitlesData> _subtitlesData;
bool _useHDC;
Common::Array<Common::String> _subtitlesEXC;
Common::Array<SubtitlesData> _subtitlesDataActive;
Common::String _loadAvgStr;
Common::String _excTitlStr;
Common::String _goVib;
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)
@ -119,6 +139,10 @@ public:
bool show(int subsRole);
bool hide(int subsRole);
void clear();
bool isHDCPresent();
void xcReload();
Common::String getLoadAvgStr() const { return _loadAvgStr; }
const char *getGoVib() const { return _goVib.c_str(); }
bool isVisible(int subsRole) const;
void tick(Graphics::Surface &s);