TWINE: Little big adventure can't mix language between voice and text #14261

this is now possible with a new in-game option
This commit is contained in:
Martin Gerhardy 2023-03-27 06:22:26 +02:00
parent 95e10fbef9
commit 697c6e4a72
10 changed files with 111 additions and 33 deletions

View File

@ -67,7 +67,8 @@ enum MenuButtonTypesEnum {
kShadowSettings = 7,
kSceneryZoom = 8,
kHighResolution = 9,
kWallCollision = 10
kWallCollision = 10,
kVoice = 11
};
}
@ -123,11 +124,19 @@ static MenuSettings createGiveUpSaveMenu() {
return settings;
}
static MenuSettings createLanguageMenu(bool lba1) {
MenuSettings settings;
settings.addButton(TextId::kReturnMenu);
settings.addButton(TextId::kCustomVoicesEnglish, MenuButtonTypes::kVoice);
return settings;
}
static MenuSettings createOptionsMenu(bool lba1) {
MenuSettings settings;
settings.addButton(TextId::kReturnMenu);
settings.addButton(TextId::kVolumeSettings);
settings.addButton(TextId::kSaveManage);
settings.addButton(TextId::kCustomLanguageOption);
settings.addButton(TextId::kAdvanced);
return settings;
}
@ -183,6 +192,7 @@ Menu::Menu(TwinEEngine *engine) {
_engine = engine;
_optionsMenuState = _priv::createOptionsMenu(engine->isLBA1());
_languageMenuState = _priv::createLanguageMenu(engine->isLBA1());
_giveUpMenuWithSaveState = _priv::createGiveUpSaveMenu();
_volumeMenuState = _priv::createVolumeMenu();
_saveManageMenuState = _priv::createSaveManageMenu();
@ -396,6 +406,17 @@ int16 Menu::drawButtons(MenuSettings *menuSettings, bool hover) {
default:
break;
}
} else if (menuSettings == &_languageMenuState) {
int16 id = menuSettings->getButtonState(i);
switch (id) {
case MenuButtonTypes::kVoice: {
const int voiceLanguage = ConfMan.getInt("audio_language");
menuSettings->setButtonTextId(i, (TextId)((int)TextId::kCustomVoicesNone - voiceLanguage));
break;
}
default:
break;
}
}
const int32 menuItemId = menuSettings->getButtonState(i);
const char *text = menuSettings->getButtonText(_engine->_text, i);
@ -522,6 +543,28 @@ int32 Menu::processMenu(MenuSettings *menuSettings) {
default:
break;
}
} else if (menuSettings == &_languageMenuState) {
switch (id) {
case MenuButtonTypes::kVoice:
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
int voiceLanguage = ConfMan.getInt("audio_language");
--voiceLanguage;
if (voiceLanguage < 0) {
voiceLanguage = 3;
}
ConfMan.setInt("audio_language", voiceLanguage);
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight) || _engine->_input->toggleActionIfActive(TwinEActionType::UIEnter)) {
int voiceLanguage = ConfMan.getInt("audio_language");
++voiceLanguage;
if (voiceLanguage > 3) {
voiceLanguage = 0;
}
ConfMan.setInt("audio_language", voiceLanguage);
}
break;
default:
break;
}
} else if (menuSettings == &_volumeMenuState) {
Audio::Mixer *mixer = _engine->_system->getMixer();
switch (id) {
@ -714,6 +757,26 @@ int32 Menu::volumeMenu() {
return 0;
}
int32 Menu::languageMenu() {
_engine->restoreFrontBuffer();
ScopedCursor scoped(_engine);
for (;;) {
switch (processMenu(&_languageMenuState)) {
case (int32)TextId::kReturnMenu:
return 0;
case kQuitEngine:
return kQuitEngine;
case (int32)MenuButtonTypes::kVoice:
default:
warning("Unknown menu button handled");
break;
}
}
return 0;
}
void Menu::inGameOptionsMenu() {
_engine->_text->initDial(TextBankId::Options_and_menus);
_optionsMenuState.setButtonTextId(0, TextId::kReturnGame);
@ -739,6 +802,9 @@ int32 Menu::optionsMenu() {
case (int32)TextId::kVolumeSettings: {
checkMenuQuit(volumeMenu()) break;
}
case (int32)TextId::kCustomLanguageOption: {
checkMenuQuit(languageMenu()) break;
}
case (int32)TextId::kSaveManage: {
checkMenuQuit(savemanageMenu()) break;
}

View File

@ -156,6 +156,7 @@ private:
MenuSettings _newGameMenuState;
MenuSettings _advOptionsMenuState;
MenuSettings _optionsMenuState;
MenuSettings _languageMenuState;
// objectRotation
int16 _itemAngle[NUM_INVENTORY_ITEMS];
@ -180,6 +181,7 @@ private:
int32 advoptionsMenu();
/** Used to run the volume menu */
int32 volumeMenu();
int32 languageMenu();
/** Used to run the save game management menu */
int32 savemanageMenu();
void drawInfoMenu(int16 left, int16 top, int16 width);

View File

@ -94,23 +94,12 @@ static const ADExtraGuiOptionsMap twineOptionsList[] = {
0
}
},
{
GAMEOPTION_VOICES,
{
_s("Enable voices"),
_s("Enable the voices for the game"),
"voice",
true,
0,
0
}
},
{
GAMEOPTION_TEXT,
{
_s("Enable text"),
_s("Enable the text for the game"),
"displaytext",
"subtitles",
true,
0,
0

View File

@ -480,7 +480,7 @@ bool Movies::playSmkMovie(const char *name, int index) {
decoder.start();
decoder.setAudioTrack(0); // music
if (_engine->_cfgfile.Voice) {
if (ConfMan.getInt("audio_language") > 0) {
int additionalAudioTrack = -1;
if (!scumm_strnicmp(name, "INTRO", 5)) {
switch (_engine->getGameLang()) {

View File

@ -35,6 +35,11 @@ void TextData::initCustomTexts(TextBankId textBankId) {
add(textBankId, TextEntry{_c("High resolution off", "Options menu").encode(Common::CodePage::kDos850), -1, TextId::kCustomHighResOptionOff});
add(textBankId, TextEntry{_c("Wall collision on", "Options menu").encode(Common::CodePage::kDos850), -1, TextId::kCustomWallCollisionOn});
add(textBankId, TextEntry{_c("Wall collision off", "Options menu").encode(Common::CodePage::kDos850), -1, TextId::kCustomWallCollisionOff});
add(textBankId, TextEntry{_c("Language selection", "Options menu").encode(Common::CodePage::kDos850), -1, TextId::kCustomLanguageOption});
add(textBankId, TextEntry{_c("Voices: None", "Options menu").encode(Common::CodePage::kDos850), -1, TextId::kCustomVoicesNone});
add(textBankId, TextEntry{_c("Voices: English", "Options menu").encode(Common::CodePage::kDos850), -1, TextId::kCustomVoicesEnglish});
add(textBankId, TextEntry{_c("Voices: French", "Options menu").encode(Common::CodePage::kDos850), -1, TextId::kCustomVoicesFrench});
add(textBankId, TextEntry{_c("Voices: German", "Options menu").encode(Common::CodePage::kDos850), -1, TextId::kCustomVoicesGerman});
}
}

View File

@ -195,7 +195,7 @@ void Resources::initResources() {
const int32 textEntryCount = _engine->isLBA1() ? 28 : 30;
for (int32 i = 0; i < textEntryCount / 2; ++i) {
if (!_textData.loadFromHQR(Resources::HQR_TEXT_FILE, (TextBankId)i, _engine->_cfgfile.LanguageId, _engine->isLBA1(), textEntryCount)) {
if (!_textData.loadFromHQR(Resources::HQR_TEXT_FILE, (TextBankId)i, _engine->_cfgfile._languageId, _engine->isLBA1(), textEntryCount)) {
error("HQR ERROR: Parsing textbank %i failed", i);
}
}

View File

@ -586,6 +586,11 @@ enum class TextId : int16 {
kCustomHighResOptionOff = -3,
kCustomWallCollisionOn = -4,
kCustomWallCollisionOff = -5,
kCustomLanguageOption = -6,
kCustomVoicesNone = -7,
kCustomVoicesEnglish = -8,
kCustomVoicesFrench = -9,
kCustomVoicesGerman = -10,
// ------ lba2

View File

@ -77,11 +77,20 @@ void Text::initVoxBank(TextBankId bankIdx) {
if ((int)bankIdx < 0 || (int)bankIdx >= ARRAYSIZE(LanguageSuffixTypes)) {
error("bankIdx is out of bounds: %i", (int)bankIdx);
}
// get the correct vox hqr file
_currentVoxBankFile = Common::String::format("%s%s" VOX_EXT, LanguageTypes[_engine->_cfgfile.LanguageId].id, LanguageSuffixTypes[(int)bankIdx]);
_currentOggBaseFile = Common::String::format("%s%s_", LanguageTypes[_engine->_cfgfile.LanguageId].id, LanguageSuffixTypes[(int)bankIdx]);
// TODO: loop through other languages and take the scummvm settings regarding voices into account...
// get the correct vox hqr file - english is the default
_currentVoxBankFile = Common::String::format("%s%s" VOX_EXT, LanguageTypes[0].id, LanguageSuffixTypes[(int)bankIdx]);
_currentOggBaseFile = Common::String::format("%s%s_", LanguageTypes[0].id, LanguageSuffixTypes[(int)bankIdx]);
const int voice = ConfMan.getInt("audio_language");
const int32 length = ARRAYSIZE(LanguageTypes);
for (int32 i = 0; i < length; i++) {
if (LanguageTypes[i].voice == voice) {
_currentVoxBankFile = Common::String::format("%s%s" VOX_EXT, LanguageTypes[i].id, LanguageSuffixTypes[(int)bankIdx]);
_currentOggBaseFile = Common::String::format("%s%s_", LanguageTypes[i].id, LanguageSuffixTypes[(int)bankIdx]);
return;
}
}
warning("Could not find voice mapping for %i", voice);
// TODO check the rest to reverse
}
@ -99,7 +108,8 @@ bool Text::initVoxToPlay(const TextEntry *text) {
return false;
}
if (!_engine->_cfgfile.Voice) {
const int voice = ConfMan.getInt("audio_language");
if (voice <= 0) {
debug(3, "Voices are disabled");
return false;
}
@ -108,7 +118,7 @@ bool Text::initVoxToPlay(const TextEntry *text) {
}
bool Text::playVox(const TextEntry *text) {
if (!_engine->_cfgfile.Voice) {
if (ConfMan.getInt("audio_language") <= 0) {
return false;
}
if (text == nullptr) {

View File

@ -271,7 +271,6 @@ Common::Error TwinEEngine::run() {
debug("(c) 1994 by Adeline Software International, All Rights Reserved.");
ConfMan.registerDefault("usehighres", false);
ConfMan.registerDefault("wallcollision", false);
const Common::String &gameTarget = ConfMan.getActiveDomainName();
AchMan.setActiveDomain(getMetaEngine()->getAchievementsInfo(gameTarget));
@ -463,11 +462,13 @@ static int getLanguageTypeIndex(const char *languageName) {
void TwinEEngine::initConfigurations() {
// TODO: use existing entries for some of the settings - like volume and so on.
ConfMan.registerDefault("wallcollision", false);
const char *lng = Common::getLanguageDescription(_gameLang);
_cfgfile.LanguageId = getLanguageTypeIndex(lng);
_cfgfile.Voice = ConfGetBoolOrDefault("voice", true);
_cfgfile.FlagDisplayText = ConfGetBoolOrDefault("displaytext", true);
_cfgfile._languageId = getLanguageTypeIndex(lng);
ConfMan.registerDefault("audio_language", LanguageTypes[_cfgfile._languageId].voice);
_cfgfile.FlagDisplayText = ConfGetBoolOrDefault("displaytext", true); // TODO: use subtitles
const Common::String midiType = ConfGetOrDefault("miditype", "auto");
if (midiType == "None") {
_cfgfile.MidiType = MIDIFILE_NONE;

View File

@ -60,13 +60,14 @@ namespace TwinE {
static const struct TwinELanguage {
const char *name;
const char *id;
const int voice;
} LanguageTypes[] = {
{"English", "EN_"},
{"French", "FR_"},
{"German", "DE_"},
{"Spanish", "SP_"},
{"Italian", "IT_"},
{"Portuguese", ""}};
{"English", "EN_", 1},
{"French", "FR_", 2},
{"German", "DE_", 3},
{"Spanish", "SP_", 1},
{"Italian", "IT_", 1},
{"Portuguese", "", 1}};
enum MidiFileType {
MIDIFILE_NONE,
@ -88,8 +89,7 @@ enum MovieType {
All the settings with (*) means they are new and only exist in this engine. */
struct ConfigFile {
/** Index into the LanguageTypes array. */
int32 LanguageId = 0;
bool Voice = true;
int32 _languageId = 0;
/** Enable/Disable game dialogues */
bool FlagDisplayText = false;
/** Flag to display game debug */