TWINE: added highres option to advanced menu

also use enum class for TextId and TextBankId
This commit is contained in:
Martin Gerhardy 2021-04-09 10:43:03 +02:00
parent 8420729fd7
commit 8289072496
24 changed files with 280 additions and 254 deletions

View file

@ -1 +1,2 @@
engines/twine/metaengine.cpp engines/twine/metaengine.cpp
engines/twine/parser/text.cpp

View file

@ -304,7 +304,7 @@ bool TwinEConsole::doListMenuText(int argc, const char **argv) {
_engine->_text->initTextBank(TextBankId::Inventory_Intro_and_Holomap); _engine->_text->initTextBank(TextBankId::Inventory_Intro_and_Holomap);
for (int32 i = 0; i < 1000; ++i) { for (int32 i = 0; i < 1000; ++i) {
char buf[256]; char buf[256];
if (_engine->_text->getMenuText(i, buf, sizeof(buf))) { if (_engine->_text->getMenuText((TextId)i, buf, sizeof(buf))) {
debugPrintf("%4i: %s\n", i, buf); debugPrintf("%4i: %s\n", i, buf);
} }
} }

View file

@ -67,7 +67,7 @@ bool Holomap::loadLocations() {
_locations[i].angle.x = ClampAngle(stream.readSint16LE()); _locations[i].angle.x = ClampAngle(stream.readSint16LE());
_locations[i].angle.y = ClampAngle(stream.readSint16LE()); _locations[i].angle.y = ClampAngle(stream.readSint16LE());
_locations[i].angle.z = ClampAngle(stream.readSint16LE()); _locations[i].angle.z = ClampAngle(stream.readSint16LE());
_locations[i].textIndex = stream.readUint16LE(); _locations[i].textIndex = (TextId)stream.readUint16LE();
if (_engine->_text->getMenuText(_locations[i].textIndex, _locations[i].name, sizeof(_locations[i].name))) { if (_engine->_text->getMenuText(_locations[i].textIndex, _locations[i].name, sizeof(_locations[i].name))) {
debug(2, "Scene %i: %s", i, _locations[i].name); debug(2, "Scene %i: %s", i, _locations[i].name);

View file

@ -46,7 +46,7 @@ private:
struct Location { struct Location {
IVec3 angle; IVec3 angle;
uint16 textIndex = 0; TextId textIndex = TextId::kNone;
char name[30] = ""; char name[30] = "";
}; };

View file

@ -65,7 +65,8 @@ enum _MenuButtonTypes {
kAggressiveMode = 6, kAggressiveMode = 6,
kPolygonDetails = 7, kPolygonDetails = 7,
kShadowSettings = 8, kShadowSettings = 8,
kSceneryZoom = 9 kSceneryZoom = 9,
kHighResolution = 10
}; };
} }
@ -120,6 +121,7 @@ static MenuSettings createAdvancedOptionsMenu() {
settings.addButton(TextId::kDetailsPolygonsHigh, MenuButtonTypes::kPolygonDetails); settings.addButton(TextId::kDetailsPolygonsHigh, MenuButtonTypes::kPolygonDetails);
settings.addButton(TextId::kDetailsShadowHigh, MenuButtonTypes::kShadowSettings); settings.addButton(TextId::kDetailsShadowHigh, MenuButtonTypes::kShadowSettings);
settings.addButton(TextId::kSceneryZoomOn, MenuButtonTypes::kSceneryZoom); settings.addButton(TextId::kSceneryZoomOn, MenuButtonTypes::kSceneryZoom);
settings.addButton(TextId::kCustomHighResOptionOn, MenuButtonTypes::kHighResolution);
return settings; return settings;
} }
@ -147,7 +149,7 @@ static MenuSettings createVolumeMenu() {
const char *MenuSettings::getButtonText(Text *text, int buttonIndex) { const char *MenuSettings::getButtonText(Text *text, int buttonIndex) {
if (_buttonTexts[buttonIndex].empty()) { if (_buttonTexts[buttonIndex].empty()) {
const int32 textId = getButtonTextId(buttonIndex); const TextId textId = getButtonTextId(buttonIndex);
char dialText[256] = ""; char dialText[256] = "";
text->getMenuText(textId, dialText, sizeof(dialText)); text->getMenuText(textId, dialText, sizeof(dialText));
_buttonTexts[buttonIndex] = dialText; _buttonTexts[buttonIndex] = dialText;
@ -359,6 +361,15 @@ int16 Menu::drawButtons(MenuSettings *menuSettings, bool hover) {
menuSettings->setButtonTextId(i, TextId::kNoSceneryZoom); menuSettings->setButtonTextId(i, TextId::kNoSceneryZoom);
} }
break; break;
case MenuButtonTypes::kHighResolution: {
const bool highRes = ConfMan.getBool("usehighres");
if (highRes) {
menuSettings->setButtonTextId(i, TextId::kCustomHighResOptionOn);
} else {
menuSettings->setButtonTextId(i, TextId::kCustomHighResOptionOff);
}
break;
}
default: default:
break; break;
} }
@ -467,6 +478,12 @@ int32 Menu::processMenu(MenuSettings *menuSettings, bool showCredits) {
_engine->cfgfile.SceZoom = !_engine->cfgfile.SceZoom; _engine->cfgfile.SceZoom = !_engine->cfgfile.SceZoom;
} }
break; break;
case MenuButtonTypes::kHighResolution:
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft) || _engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
const bool highRes = ConfMan.getBool("usehighres");
ConfMan.setBool("usehighres", !highRes);
}
break;
default: default:
break; break;
} }
@ -552,9 +569,9 @@ int32 Menu::processMenu(MenuSettings *menuSettings, bool showCredits) {
} }
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIAbort)) { if (_engine->_input->toggleActionIfActive(TwinEActionType::UIAbort)) {
for (int i = 0; i < menuSettings->getButtonCount(); ++i) { for (int i = 0; i < menuSettings->getButtonCount(); ++i) {
const int16 textId = menuSettings->getButtonTextId(i); const TextId textId = menuSettings->getButtonTextId(i);
if (textId == TextId::kReturnMenu || textId == TextId::kReturnGame || textId == TextId::kContinue) { if (textId == TextId::kReturnMenu || textId == TextId::kReturnGame || textId == TextId::kContinue) {
return textId; return (int32)textId;
} }
} }
startMillis = loopMillis; startMillis = loopMillis;
@ -575,7 +592,7 @@ int32 Menu::processMenu(MenuSettings *menuSettings, bool showCredits) {
} }
} while (!_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter)); } while (!_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter));
return menuSettings->getActiveButtonTextId(); return (int32)menuSettings->getActiveButtonTextId();
} }
int32 Menu::advoptionsMenu() { int32 Menu::advoptionsMenu() {
@ -585,15 +602,15 @@ int32 Menu::advoptionsMenu() {
ScopedCursor scoped(_engine); ScopedCursor scoped(_engine);
for (;;) { for (;;) {
switch (processMenu(&advOptionsMenuState)) { switch (processMenu(&advOptionsMenuState)) {
case TextId::kReturnMenu: { case (int32)TextId::kReturnMenu: {
return 0; return 0;
} }
case kQuitEngine: case kQuitEngine:
return kQuitEngine; return kQuitEngine;
case TextId::kBehaviourAggressiveManual: case (int32)TextId::kBehaviourAggressiveManual:
case TextId::kDetailsPolygonsHigh: case (int32)TextId::kDetailsPolygonsHigh:
case TextId::kDetailsShadowHigh: case (int32)TextId::kDetailsShadowHigh:
case TextId::kSceneryZoomOn: case (int32)TextId::kSceneryZoomOn:
default: default:
warning("Unknown menu button handled"); warning("Unknown menu button handled");
break; break;
@ -610,12 +627,12 @@ int32 Menu::savemanageMenu() {
ScopedCursor scoped(_engine); ScopedCursor scoped(_engine);
for (;;) { for (;;) {
switch (processMenu(&saveManageMenuState)) { switch (processMenu(&saveManageMenuState)) {
case TextId::kReturnMenu: case (int32)TextId::kReturnMenu:
return 0; return 0;
case TextId::kCreateSaveGame: case (int32)TextId::kCreateSaveGame:
_engine->_menuOptions->saveGameMenu(); _engine->_menuOptions->saveGameMenu();
break; break;
case TextId::kDeleteSaveGame: case (int32)TextId::kDeleteSaveGame:
_engine->_menuOptions->deleteSaveMenu(); _engine->_menuOptions->deleteSaveMenu();
break; break;
case kQuitEngine: case kQuitEngine:
@ -636,18 +653,18 @@ int32 Menu::volumeMenu() {
ScopedCursor scoped(_engine); ScopedCursor scoped(_engine);
for (;;) { for (;;) {
switch (processMenu(&volumeMenuState)) { switch (processMenu(&volumeMenuState)) {
case TextId::kReturnMenu: case (int32)TextId::kReturnMenu:
return 0; return 0;
case TextId::kSaveSettings: case (int32)TextId::kSaveSettings:
ConfMan.flushToDisk(); ConfMan.flushToDisk();
break; break;
case kQuitEngine: case kQuitEngine:
return kQuitEngine; return kQuitEngine;
case TextId::kMusicVolume: case (int32)TextId::kMusicVolume:
case TextId::kSoundVolume: case (int32)TextId::kSoundVolume:
case TextId::kCDVolume: case (int32)TextId::kCDVolume:
case TextId::kLineInVolume: case (int32)TextId::kLineInVolume:
case TextId::kMasterVolume: case (int32)TextId::kMasterVolume:
default: default:
warning("Unknown menu button handled"); warning("Unknown menu button handled");
break; break;
@ -676,17 +693,17 @@ int32 Menu::optionsMenu() {
ScopedCursor scoped(_engine); ScopedCursor scoped(_engine);
for (;;) { for (;;) {
switch (processMenu(&optionsMenuState)) { switch (processMenu(&optionsMenuState)) {
case TextId::kReturnGame: case (int32)TextId::kReturnGame:
case TextId::kReturnMenu: { case (int32)TextId::kReturnMenu: {
return 0; return 0;
} }
case TextId::kVolumeSettings: { case (int32)TextId::kVolumeSettings: {
checkMenuQuit(volumeMenu()) break; checkMenuQuit(volumeMenu()) break;
} }
case TextId::kSaveManage: { case (int32)TextId::kSaveManage: {
checkMenuQuit(savemanageMenu()) break; checkMenuQuit(savemanageMenu()) break;
} }
case TextId::kAdvanced: { case (int32)TextId::kAdvanced: {
checkMenuQuit(advoptionsMenu()) break; checkMenuQuit(advoptionsMenu()) break;
} }
case kQuitEngine: case kQuitEngine:
@ -741,19 +758,19 @@ EngineState Menu::run() {
ScopedCursor scoped(_engine); ScopedCursor scoped(_engine);
switch (processMenu(&mainMenuState)) { switch (processMenu(&mainMenuState)) {
case TextId::kNewGame: { case (int32)TextId::kNewGame: {
if (_engine->_menuOptions->newGameMenu()) { if (_engine->_menuOptions->newGameMenu()) {
return EngineState::GameLoop; return EngineState::GameLoop;
} }
break; break;
} }
case TextId::kContinueGame: { case (int32)TextId::kContinueGame: {
if (_engine->_menuOptions->continueGameMenu()) { if (_engine->_menuOptions->continueGameMenu()) {
return EngineState::LoadedGame; return EngineState::LoadedGame;
} }
break; break;
} }
case TextId::kOptions: { case (int32)TextId::kOptions: {
optionsMenu(); optionsMenu();
break; break;
} }
@ -761,7 +778,7 @@ EngineState Menu::run() {
_engine->_screens->loadMenuImage(); _engine->_screens->loadMenuImage();
break; break;
} }
case TextId::kQuit: case (int32)TextId::kQuit:
case kQuitEngine: case kQuitEngine:
debug("quit the game"); debug("quit the game");
return EngineState::QuitGame; return EngineState::QuitGame;
@ -789,13 +806,13 @@ int32 Menu::giveupMenu() {
_engine->_text->initTextBank(TextBankId::Options_and_menus); _engine->_text->initTextBank(TextBankId::Options_and_menus);
menuId = processMenu(localMenu); menuId = processMenu(localMenu);
switch (menuId) { switch (menuId) {
case TextId::kContinue: case (int32)TextId::kContinue:
_engine->_sound->resumeSamples(); _engine->_sound->resumeSamples();
break; break;
case TextId::kGiveUp: case (int32)TextId::kGiveUp:
_engine->_gameState->giveUp(); _engine->_gameState->giveUp();
return 1; return 1;
case TextId::kCreateSaveGame: case (int32)TextId::kCreateSaveGame:
_engine->_menuOptions->saveGameMenu(); _engine->_menuOptions->saveGameMenu();
break; break;
case kQuitEngine: case kQuitEngine:
@ -804,7 +821,7 @@ int32 Menu::giveupMenu() {
warning("Unknown menu button handled: %i", menuId); warning("Unknown menu button handled: %i", menuId);
} }
_engine->_text->initSceneTextBank(); _engine->_text->initSceneTextBank();
} while (menuId != TextId::kGiveUp && menuId != TextId::kContinue && menuId != TextId::kCreateSaveGame); } while (menuId != (int32)TextId::kGiveUp && menuId != (int32)TextId::kContinue && menuId != (int32)TextId::kCreateSaveGame);
return 0; return 0;
} }
@ -1022,7 +1039,7 @@ void Menu::processBehaviourMenu() {
_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer); _engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
int32 tmpTextBank = _engine->_scene->sceneTextBank; TextBankId tmpTextBank = _engine->_scene->sceneTextBank;
_engine->_scene->sceneTextBank = TextBankId::None; _engine->_scene->sceneTextBank = TextBankId::None;
_engine->_text->initTextBank(TextBankId::Options_and_menus); _engine->_text->initTextBank(TextBankId::Options_and_menus);
@ -1228,9 +1245,9 @@ void Menu::processInventoryMenu() {
if (updateItemText) { if (updateItemText) {
_engine->_text->initInventoryDialogueBox(); _engine->_text->initInventoryDialogueBox();
if (inventorySelectedItem < NUM_INVENTORY_ITEMS && _engine->_gameState->hasItem((InventoryItems)inventorySelectedItem) && !_engine->_gameState->inventoryDisabled()) { if (inventorySelectedItem < NUM_INVENTORY_ITEMS && _engine->_gameState->hasItem((InventoryItems)inventorySelectedItem) && !_engine->_gameState->inventoryDisabled()) {
_engine->_text->initInventoryText(inventorySelectedItem); _engine->_text->initInventoryText((InventoryItems)inventorySelectedItem);
} else { } else {
_engine->_text->initInventoryText(NUM_INVENTORY_ITEMS); _engine->_text->initInventoryText(InventoryItems::MaxInventoryItems);
} }
textState = ProgressiveTextState::ContinueRunning; textState = ProgressiveTextState::ContinueRunning;
updateItemText = false; updateItemText = false;

View file

@ -54,8 +54,8 @@ private:
int8 _activeButtonIdx = 0; int8 _activeButtonIdx = 0;
public: public:
int16 getButtonTextId(int buttonIndex) const { TextId getButtonTextId(int buttonIndex) const {
return _settings[MenuSettings_FirstButton + buttonIndex * 2]; return (TextId)_settings[MenuSettings_FirstButton + buttonIndex * 2];
} }
void reset() { void reset() {
@ -77,16 +77,16 @@ public:
_settings[MenuSettings_CurrentLoadedButton] = buttonIdx; _settings[MenuSettings_CurrentLoadedButton] = buttonIdx;
} }
void setActiveButtonTextId(int16 textIndex) { void setActiveButtonTextId(TextId textIndex) {
setButtonTextId(getActiveButton(), textIndex); setButtonTextId(getActiveButton(), textIndex);
} }
void setButtonTextId(int16 buttonIdx, int16 textIndex) { void setButtonTextId(int16 buttonIdx, TextId textIndex) {
_settings[MenuSettings_FirstButton + buttonIdx * 2] = textIndex; _settings[MenuSettings_FirstButton + buttonIdx * 2] = (int16)textIndex;
_buttonTexts[buttonIdx].clear(); _buttonTexts[buttonIdx].clear();
} }
int16 getActiveButtonTextId() const { TextId getActiveButtonTextId() const {
return getButtonTextId(getActiveButton()); return getButtonTextId(getActiveButton());
} }
@ -112,14 +112,14 @@ public:
return _settings[MenuSettings_NumberOfButtons]; return _settings[MenuSettings_NumberOfButtons];
} }
void setTextBankId(int16 textBankIndex) { void setTextBankId(TextBankId textBankIndex) {
_settings[MenuSettings_HeaderEnd] = textBankIndex; _settings[MenuSettings_HeaderEnd] = (int16)textBankIndex;
} }
void addButton(int16 textId, int16 state = 0) { void addButton(TextId textId, int16 state = 0) {
const int16 i = _settings[MenuSettings_NumberOfButtons]; const int16 i = _settings[MenuSettings_NumberOfButtons];
_settings[i * 2 + MenuSettings_FirstButtonState] = state; _settings[i * 2 + MenuSettings_FirstButtonState] = state;
_settings[i * 2 + MenuSettings_FirstButton] = textId; _settings[i * 2 + MenuSettings_FirstButton] = (int16)textId;
++_settings[MenuSettings_NumberOfButtons]; ++_settings[MenuSettings_NumberOfButtons];
} }

View file

@ -249,7 +249,7 @@ public:
} }
}; };
bool MenuOptions::enterText(int32 textIdx, char *textTargetBuf, size_t bufSize) { bool MenuOptions::enterText(TextId textIdx, char *textTargetBuf, size_t bufSize) {
textTargetBuf[0] = '\0'; textTargetBuf[0] = '\0';
_engine->_text->initTextBank(TextBankId::Options_and_menus); _engine->_text->initTextBank(TextBankId::Options_and_menus);
char buffer[256]; char buffer[256];
@ -364,7 +364,7 @@ bool MenuOptions::newGameMenu() {
return true; return true;
} }
int MenuOptions::chooseSave(int textIdx, bool showEmptySlots) { int MenuOptions::chooseSave(TextId textIdx, bool showEmptySlots) {
const SaveStateList &savegames = _engine->getSaveSlots(); const SaveStateList &savegames = _engine->getSaveSlots();
if (savegames.empty() && !showEmptySlots) { if (savegames.empty() && !showEmptySlots) {
return -1; return -1;
@ -394,7 +394,7 @@ int MenuOptions::chooseSave(int textIdx, bool showEmptySlots) {
const int32 id = _engine->_menu->processMenu(&saveFiles); const int32 id = _engine->_menu->processMenu(&saveFiles);
switch (id) { switch (id) {
case kQuitEngine: case kQuitEngine:
case TextId::kReturnMenu: case (int32)TextId::kReturnMenu:
return -1; return -1;
default: default:
const int16 slot = saveFiles.getButtonState(id); const int16 slot = saveFiles.getButtonState(id);

View file

@ -44,11 +44,11 @@ private:
void setOnScreenKeyboard(int x, int y); void setOnScreenKeyboard(int x, int y);
bool enterText(int32 textIdx, char *textTargetBuf, size_t bufSize); bool enterText(TextId textIdx, char *textTargetBuf, size_t bufSize);
void drawSelectableCharacters(); void drawSelectableCharacters();
void drawInputText(int32 centerx, int32 top, int32 type, const char *text); void drawInputText(int32 centerx, int32 top, int32 type, const char *text);
void drawSelectableCharacter(int32 x, int32 y, Common::Rect &dirtyRect); void drawSelectableCharacter(int32 x, int32 y, Common::Rect &dirtyRect);
int chooseSave(int textIdx, bool showEmptySlots = false); int chooseSave(TextId textIdx, bool showEmptySlots = false);
public: public:
MenuOptions(TwinEEngine *engine) : _engine(engine) {} MenuOptions(TwinEEngine *engine) : _engine(engine) {}

View file

@ -23,12 +23,13 @@
#include "twine/parser/text.h" #include "twine/parser/text.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/util.h" #include "common/util.h"
#include "common/translation.h"
#include "twine/resources/hqr.h" #include "twine/resources/hqr.h"
namespace TwinE { namespace TwinE {
bool TextData::loadFromHQR(const char *name, int textBankId, int language, int entryCount) { bool TextData::loadFromHQR(const char *name, TextBankId textBankId, int language, int entryCount) {
const int langIdx = textBankId * 2 + (entryCount * language); const int langIdx = (int)textBankId * 2 + (entryCount * language);
Common::SeekableReadStream *indexStream = HQR::makeReadStream(name, langIdx + 0); Common::SeekableReadStream *indexStream = HQR::makeReadStream(name, langIdx + 0);
Common::SeekableReadStream *offsetStream = HQR::makeReadStream(name, langIdx + 1); Common::SeekableReadStream *offsetStream = HQR::makeReadStream(name, langIdx + 1);
if (indexStream == nullptr || offsetStream == nullptr) { if (indexStream == nullptr || offsetStream == nullptr) {
@ -38,13 +39,13 @@ bool TextData::loadFromHQR(const char *name, int textBankId, int language, int e
return false; return false;
} }
_texts[textBankId].clear(); _texts[(int)textBankId].clear();
const int numIdxEntries = indexStream->size() / 2; const int numIdxEntries = indexStream->size() / 2;
_texts[textBankId].reserve(numIdxEntries); _texts[(int)textBankId].reserve(numIdxEntries);
for (int entry = 0; entry < numIdxEntries; ++entry) { for (int entry = 0; entry < numIdxEntries; ++entry) {
const uint16 textIdx = indexStream->readUint16LE(); const TextId textIdx = (TextId)indexStream->readUint16LE();
const uint16 start = offsetStream->readUint16LE(); const uint16 start = offsetStream->readUint16LE();
const int32 offsetPos = offsetStream->pos(); const int32 offsetPos = offsetStream->pos();
const uint16 end = offsetStream->readUint16LE(); const uint16 end = offsetStream->readUint16LE();
@ -54,8 +55,8 @@ bool TextData::loadFromHQR(const char *name, int textBankId, int language, int e
const char c = (char)offsetStream->readByte(); const char c = (char)offsetStream->readByte();
result += c; result += c;
} }
_texts[textBankId].push_back(TextEntry{result, entry, textIdx}); _texts[(int)textBankId].push_back(TextEntry{result, entry, textIdx});
debug(5, "index: %i (bank %i), text: %s", textIdx, textBankId, result.c_str()); debug(5, "index: %i (bank %i), text: %s", (int)textIdx, (int)textBankId, result.c_str());
offsetStream->seek(offsetPos); offsetStream->seek(offsetPos);
if (end >= offsetStream->size()) { if (end >= offsetStream->size()) {
break; break;
@ -63,18 +64,23 @@ bool TextData::loadFromHQR(const char *name, int textBankId, int language, int e
} }
delete indexStream; delete indexStream;
delete offsetStream; delete offsetStream;
// custom texts that are not included in the original game
_texts[(int)TextBankId::Options_and_menus].push_back(TextEntry{_sc("High resolution on", "Options menu"), -1, TextId::kCustomHighResOptionOn});
_texts[(int)TextBankId::Options_and_menus].push_back(TextEntry{_sc("High resolution off", "Options menu"), -1, TextId::kCustomHighResOptionOff});
return true; return true;
} }
const TextEntry *TextData::getText(int textBankId, int textIndex) const { const TextEntry *TextData::getText(TextBankId textBankId, TextId textIndex) const {
const Common::Array<TextEntry> &entries = _texts[textBankId]; const Common::Array<TextEntry> &entries = _texts[(int)textBankId];
const int32 size = entries.size(); const int32 size = entries.size();
for (int32 i = 0; i < size; ++i) { for (int32 i = 0; i < size; ++i) {
if (entries[i].textIndex == textIndex) { if (entries[i].textIndex == textIndex) {
return &entries[i]; return &entries[i];
} }
} }
debug(1, "Failed to find text entry for bank id %i with text index %i", textBankId, textIndex); debug(1, "Failed to find text entry for bank id %i with text index %i", (int)textBankId, (int)textIndex);
return nullptr; return nullptr;
} }

View file

@ -35,7 +35,7 @@ class TextEntry {
public: public:
Common::String string; /**< The real string behind the text id */ Common::String string; /**< The real string behind the text id */
int index; /**< The index in the text index hqr file. This is also the index in the corresponding vox hqr file */ int index; /**< The index in the text index hqr file. This is also the index in the corresponding vox hqr file */
int textIndex; /**< The text identifier */ TextId textIndex; /**< The text identifier */
}; };
class TextData { class TextData {
@ -43,9 +43,9 @@ private:
// 30 is the max for lba2, lba1 uses 28 // 30 is the max for lba2, lba1 uses 28
Common::Array<TextEntry> _texts[30]; Common::Array<TextEntry> _texts[30];
public: public:
bool loadFromHQR(const char *name, int textBankId, int language, int entryCount); bool loadFromHQR(const char *name, TextBankId textBankId, int language, int entryCount);
const TextEntry *getText(int textBankId, int textIndex) const; const TextEntry *getText(TextBankId textBankId, TextId textIndex) const;
}; };
} // End of namespace TwinE } // End of namespace TwinE

View file

@ -633,7 +633,7 @@ void Redraw::renderOverlays() {
} }
case OverlayType::koText: { case OverlayType::koText: {
char text[256]; char text[256];
_engine->_text->getMenuText(overlay->info0, text, sizeof(text)); _engine->_text->getMenuText((TextId)overlay->info0, text, sizeof(text));
const int32 textLength = _engine->_text->getTextSize(text); const int32 textLength = _engine->_text->getTextSize(text);
const int32 textHeight = 48; const int32 textHeight = 48;

View file

@ -206,14 +206,14 @@ void Resources::initResources() {
const int32 textEntryCount = _engine->isLBA1() ? 28 : 30; const int32 textEntryCount = _engine->isLBA1() ? 28 : 30;
for (int32 i = 0; i < textEntryCount / 2; ++i) { for (int32 i = 0; i < textEntryCount / 2; ++i) {
if (!_textData.loadFromHQR(Resources::HQR_TEXT_FILE, i, _engine->cfgfile.LanguageId, textEntryCount)) { if (!_textData.loadFromHQR(Resources::HQR_TEXT_FILE, (TextBankId)i, _engine->cfgfile.LanguageId, textEntryCount)) {
error("HQR ERROR: Parsing textbank %i failed", i); error("HQR ERROR: Parsing textbank %i failed", i);
} }
} }
debug("Loaded %i text banks", textEntryCount / 2); debug("Loaded %i text banks", textEntryCount / 2);
} }
const TextEntry *Resources::getText(int textBankId, int index) const { const TextEntry *Resources::getText(TextBankId textBankId, TextId index) const {
return _textData.getText(textBankId, index); return _textData.getText(textBankId, index);
} }

View file

@ -204,7 +204,7 @@ public:
const Trajectory *getTrajectory(int index) const; const Trajectory *getTrajectory(int index) const;
const TextEntry *getText(int textBankId, int index) const; const TextEntry *getText(TextBankId textBankId, TextId index) const;
// main palette // main palette
static constexpr const char *HQR_RESS_FILE = "ress.hqr"; static constexpr const char *HQR_RESS_FILE = "ress.hqr";

View file

@ -140,12 +140,12 @@ void Actor::initSpriteActor(int32 actorIdx) {
} }
} }
int32 Actor::getTextIdForBehaviour() const { TextId Actor::getTextIdForBehaviour() const {
if (heroBehaviour == HeroBehaviourType::kAggressive && autoAggressive) { if (heroBehaviour == HeroBehaviourType::kAggressive && autoAggressive) {
return TextId::kBehaviourAggressiveAuto; return TextId::kBehaviourAggressiveAuto;
} }
// the other values are matching the text ids // the other values are matching the text ids
return (int32)heroBehaviour; return (TextId)(int32)heroBehaviour;
} }
int32 Actor::initBody(BodyType bodyIdx, int32 actorIdx, ActorBoundingBox &actorBoundingBox) { int32 Actor::initBody(BodyType bodyIdx, int32 actorIdx, ActorBoundingBox &actorBoundingBox) {

View file

@ -318,7 +318,7 @@ public:
/** Load hero 3D body and animations */ /** Load hero 3D body and animations */
void loadHeroEntities(); void loadHeroEntities();
int32 getTextIdForBehaviour() const; TextId getTextIdForBehaviour() const;
/** /**
* Set hero behaviour * Set hero behaviour

View file

@ -53,7 +53,7 @@ GameState::GameState(TwinEEngine *engine) : _engine(engine) {
clearGameFlags(); clearGameFlags();
Common::fill(&inventoryFlags[0], &inventoryFlags[NUM_INVENTORY_ITEMS], 0); Common::fill(&inventoryFlags[0], &inventoryFlags[NUM_INVENTORY_ITEMS], 0);
Common::fill(&holomapFlags[0], &holomapFlags[NUM_LOCATIONS], 0); Common::fill(&holomapFlags[0], &holomapFlags[NUM_LOCATIONS], 0);
Common::fill(&gameChoices[0], &gameChoices[10], 0); Common::fill(&gameChoices[0], &gameChoices[10], TextId::kNone);
} }
void GameState::initEngineProjections() { void GameState::initEngineProjections() {
@ -302,7 +302,7 @@ void GameState::setGameFlag(uint8 index, uint8 value) {
} }
} }
void GameState::processFoundItem(int32 item) { void GameState::processFoundItem(InventoryItems item) {
ScopedEngineFreeze freeze(_engine); ScopedEngineFreeze freeze(_engine);
_engine->_grid->centerOnActor(_engine->_scene->sceneHero); _engine->_grid->centerOnActor(_engine->_scene->sceneHero);
@ -355,7 +355,7 @@ void GameState::processFoundItem(int32 item) {
ProgressiveTextState textState = ProgressiveTextState::ContinueRunning; ProgressiveTextState textState = ProgressiveTextState::ContinueRunning;
_engine->_text->initVoxToPlayTextId(item); _engine->_text->initVoxToPlayTextId((TextId)item);
const int32 bodyAnimIdx = _engine->_animations->getBodyAnimIndex(AnimationTypes::kFoundItem); const int32 bodyAnimIdx = _engine->_animations->getBodyAnimIndex(AnimationTypes::kFoundItem);
const AnimData &currentAnimData = _engine->_resources->animData[bodyAnimIdx]; const AnimData &currentAnimData = _engine->_resources->animData[bodyAnimIdx];
@ -446,11 +446,11 @@ void GameState::processFoundItem(int32 item) {
_engine->_scene->sceneHero->animTimerData = tmpAnimTimer; _engine->_scene->sceneHero->animTimerData = tmpAnimTimer;
} }
void GameState::processGameChoices(int32 choiceIdx) { void GameState::processGameChoices(TextId choiceIdx) {
_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer); _engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
_gameChoicesSettings.reset(); _gameChoicesSettings.reset();
_gameChoicesSettings.setTextBankId(_engine->_scene->sceneTextBank + TextBankId::Citadel_Island); _gameChoicesSettings.setTextBankId((TextBankId)((int)_engine->_scene->sceneTextBank + (int)TextBankId::Citadel_Island));
// filled via script // filled via script
for (int32 i = 0; i < numChoices; i++) { for (int32 i = 0; i < numChoices; i++) {

View file

@ -32,38 +32,6 @@
namespace TwinE { namespace TwinE {
enum InventoryItems {
kiHolomap = 0,
kiMagicBall = 1,
kiUseSabre = 2,
kiGawleysHorn = 3,
kiTunic = 4,
kiBookOfBu = 5,
kSendellsMedallion = 6,
kFlaskOfClearWater = 7,
kRedCard = 8,
kBlueCard = 9,
kIDCard = 10,
kMrMiesPass = 11,
kiProtoPack = 12,
kSnowboard = 13,
kiPinguin = 14,
kGasItem = 15,
kPirateFlag = 16,
kMagicFlute = 17,
kSpaceGuitar = 18,
kHairDryer = 19,
kAncesteralKey = 20,
kBottleOfSyrup = 21,
kEmptyBottle = 22,
kFerryTicket = 23,
kKeypad = 24,
kCoffeeCan = 25,
kiBonusList = 26,
kiCloverLeaf = 27,
MaxInventoryItems = 28
};
/** Magicball strength*/ /** Magicball strength*/
enum MagicballStrengthType { enum MagicballStrengthType {
kNoBallStrength = 2, kNoBallStrength = 2,
@ -213,9 +181,9 @@ public:
char sceneName[30] {}; char sceneName[30] {};
int32 gameChoices[10]; // inGameMenuData TextId gameChoices[10]; // inGameMenuData
int32 numChoices = 0; // numOfOptionsInChoice int32 numChoices = 0; // numOfOptionsInChoice
int32 choiceAnswer = 0; // inGameMenuAnswer TextId choiceAnswer = TextId::kNone; // inGameMenuAnswer
/** Initialize all engine variables */ /** Initialize all engine variables */
void initEngineVars(); void initEngineVars();
@ -223,13 +191,13 @@ public:
/** Initialize engine 3D projections */ /** Initialize engine 3D projections */
void initEngineProjections(); void initEngineProjections();
void processFoundItem(int32 item); void processFoundItem(InventoryItems item);
void giveUp(); void giveUp();
bool loadGame(Common::SeekableReadStream *file); bool loadGame(Common::SeekableReadStream *file);
bool saveGame(Common::WriteStream *file); bool saveGame(Common::WriteStream *file);
void processGameChoices(int32 choiceIdx); void processGameChoices(TextId choiceIdx);
void processGameoverAnimation(); void processGameoverAnimation();
}; };

View file

@ -149,7 +149,7 @@ void Scene::setBonusParameterFlags(ActorStruct *act, uint16 bonusFlags) {
bool Scene::loadSceneLBA2() { bool Scene::loadSceneLBA2() {
Common::MemoryReadStream stream(currentScene, _currentSceneSize); Common::MemoryReadStream stream(currentScene, _currentSceneSize);
sceneTextBank = stream.readByte(); sceneTextBank = (TextBankId)stream.readByte();
_currentGameOverScene = stream.readByte(); _currentGameOverScene = stream.readByte();
stream.skip(4); stream.skip(4);
@ -281,7 +281,7 @@ bool Scene::loadSceneLBA1() {
Common::MemoryReadStream stream(currentScene, _currentSceneSize); Common::MemoryReadStream stream(currentScene, _currentSceneSize);
// load scene ambience properties // load scene ambience properties
sceneTextBank = stream.readByte(); sceneTextBank = (TextBankId)stream.readByte();
_currentGameOverScene = stream.readByte(); _currentGameOverScene = stream.readByte();
stream.skip(4); stream.skip(4);

View file

@ -26,7 +26,7 @@
#include "common/scummsys.h" #include "common/scummsys.h"
#include "common/util.h" #include "common/util.h"
#include "twine/scene/actor.h" #include "twine/scene/actor.h"
#include "twine/text.h" #include "twine/shared.h"
namespace TwinE { namespace TwinE {
@ -75,7 +75,7 @@ struct ZoneStruct {
/** show a text (e.g. when reading a sign) */ /** show a text (e.g. when reading a sign) */
struct { struct {
int32 textIdx; /*!< text index in the current active text bank */ TextId textIdx; /*!< text index in the current active text bank */
int32 textColor; /*!< text color (see @c ActorStruct::talkColor) */ int32 textColor; /*!< text color (see @c ActorStruct::talkColor) */
} DisplayText; } DisplayText;
struct { struct {
@ -178,7 +178,7 @@ public:
int32 holomapTrajectory = -1; int32 holomapTrajectory = -1;
int32 sceneTextBank = TextBankId::None; TextBankId sceneTextBank = TextBankId::None;
int32 alphaLight = ANGLE_0; int32 alphaLight = ANGLE_0;
int32 betaLight = ANGLE_0; int32 betaLight = ANGLE_0;

View file

@ -41,6 +41,7 @@
#include "twine/renderer/screens.h" #include "twine/renderer/screens.h"
#include "twine/resources/resources.h" #include "twine/resources/resources.h"
#include "twine/scene/scene.h" #include "twine/scene/scene.h"
#include "twine/shared.h"
#include "twine/text.h" #include "twine/text.h"
#include "twine/twine.h" #include "twine/twine.h"
@ -347,7 +348,7 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
} }
case kcCHOICE: case kcCHOICE:
conditionValueSize = 2; conditionValueSize = 2;
engine->_scene->currentScriptValue = engine->_gameState->choiceAnswer; engine->_scene->currentScriptValue = (int16)engine->_gameState->choiceAnswer;
break; break;
case kcFUEL: case kcFUEL:
engine->_scene->currentScriptValue = engine->_gameState->inventoryNumGas; engine->_scene->currentScriptValue = engine->_gameState->inventoryNumGas;
@ -646,7 +647,7 @@ static int32 lSET_TRACK_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x19 * @note Opcode @c 0x19
*/ */
static int32 lMESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lMESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 textIdx = ctx.stream.readSint16LE(); const TextId textIdx = (TextId)ctx.stream.readSint16LE();
engine->freezeTime(); engine->freezeTime();
if (engine->_text->showDialogueBubble) { if (engine->_text->showDialogueBubble) {
@ -902,7 +903,7 @@ static int32 lRESTORE_L_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
*/ */
static int32 lMESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lMESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 otherActorIdx = ctx.stream.readByte(); const int32 otherActorIdx = ctx.stream.readByte();
const int32 textIdx = ctx.stream.readSint16LE(); const TextId textIdx = (TextId)ctx.stream.readSint16LE();
engine->freezeTime(); engine->freezeTime();
if (engine->_text->showDialogueBubble) { if (engine->_text->showDialogueBubble) {
@ -931,7 +932,7 @@ static int32 lINC_CHAPTER(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x2E * @note Opcode @c 0x2E
*/ */
static int32 lFOUND_OBJECT(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lFOUND_OBJECT(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 item = ctx.stream.readByte(); const InventoryItems item = (InventoryItems)ctx.stream.readByte();
engine->_gameState->processFoundItem(item); engine->_gameState->processFoundItem(item);
engine->_redraw->redrawEngineActions(true); engine->_redraw->redrawEngineActions(true);
@ -1249,7 +1250,7 @@ static int32 lSET_USED_INVENTORY(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x44 * @note Opcode @c 0x44
*/ */
static int32 lADD_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lADD_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) {
int32 choiceIdx = ctx.stream.readSint16LE(); TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
engine->_gameState->gameChoices[engine->_gameState->numChoices++] = choiceIdx; engine->_gameState->gameChoices[engine->_gameState->numChoices++] = choiceIdx;
return 0; return 0;
} }
@ -1259,7 +1260,7 @@ static int32 lADD_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x45 * @note Opcode @c 0x45
*/ */
static int32 lASK_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lASK_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) {
int32 choiceIdx = ctx.stream.readSint16LE(); TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
engine->freezeTime(); engine->freezeTime();
if (engine->_text->showDialogueBubble) { if (engine->_text->showDialogueBubble) {
@ -1279,7 +1280,7 @@ static int32 lASK_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x46 * @note Opcode @c 0x46
*/ */
static int32 lBIG_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lBIG_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
int32 textIdx = ctx.stream.readSint16LE(); TextId textIdx = (TextId)ctx.stream.readSint16LE();
engine->freezeTime(); engine->freezeTime();
engine->_text->textClipFull(); engine->_text->textClipFull();
@ -1363,9 +1364,9 @@ static int32 lSET_GRM(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x4D * @note Opcode @c 0x4D
*/ */
static int32 lSAY_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lSAY_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
int16 textEntry = ctx.stream.readSint16LE(); TextId textEntry = (TextId)ctx.stream.readSint16LE();
engine->_redraw->addOverlay(OverlayType::koText, textEntry, 0, 0, ctx.actorIdx, OverlayPosType::koFollowActor, 2); engine->_redraw->addOverlay(OverlayType::koText, (int16)textEntry, 0, 0, ctx.actorIdx, OverlayPosType::koFollowActor, 2);
ScopedEngineFreeze scoped(engine); ScopedEngineFreeze scoped(engine);
engine->_text->initVoxToPlayTextId(textEntry); engine->_text->initVoxToPlayTextId(textEntry);
@ -1379,9 +1380,9 @@ static int32 lSAY_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
*/ */
static int32 lSAY_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lSAY_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
int32 otherActorIdx = ctx.stream.readByte(); int32 otherActorIdx = ctx.stream.readByte();
int16 textEntry = ctx.stream.readSint16LE(); TextId textEntry = (TextId)ctx.stream.readSint16LE();
engine->_redraw->addOverlay(OverlayType::koText, textEntry, 0, 0, otherActorIdx, OverlayPosType::koFollowActor, 2); engine->_redraw->addOverlay(OverlayType::koText, (int16)textEntry, 0, 0, otherActorIdx, OverlayPosType::koFollowActor, 2);
ScopedEngineFreeze scoped(engine); ScopedEngineFreeze scoped(engine);
engine->_text->initVoxToPlayTextId(textEntry); engine->_text->initVoxToPlayTextId(textEntry);
@ -1536,7 +1537,7 @@ static int32 lBUBBLE_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
*/ */
static int32 lASK_CHOICE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lASK_CHOICE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 otherActorIdx = ctx.stream.readByte(); const int32 otherActorIdx = ctx.stream.readByte();
const int32 choiceIdx = ctx.stream.readSint16LE(); const TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
engine->freezeTime(); engine->freezeTime();
if (engine->_text->showDialogueBubble) { if (engine->_text->showDialogueBubble) {
@ -1708,12 +1709,12 @@ static int32 lPROJ_3D(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x67 * @note Opcode @c 0x67
*/ */
static int32 lTEXT(TwinEEngine *engine, LifeScriptContext &ctx) { static int32 lTEXT(TwinEEngine *engine, LifeScriptContext &ctx) {
int32 textIdx = ctx.stream.readSint16LE(); TextId textIdx = (TextId)ctx.stream.readSint16LE();
const int32 textHeight = 40; const int32 textHeight = 40;
if (lTextYPos < engine->height() - textHeight) { if (lTextYPos < engine->height() - textHeight) {
if (engine->cfgfile.Version == USA_VERSION) { if (engine->cfgfile.Version == USA_VERSION) {
if (!textIdx) { if (textIdx == TextId::kBehaviourNormal) {
textIdx = TextId::kSaveSettings; textIdx = TextId::kSaveSettings;
} }
} }

View file

@ -405,6 +405,115 @@ enum LBA1SceneId {
SceneIdMax = 120 SceneIdMax = 120
}; };
// lba
enum class TextBankId : int16 {
None = -1,
Options_and_menus = 0,
Credits = 1,
Inventory_Intro_and_Holomap = 2,
Citadel_Island = 3,
Principal_Island = 4,
White_Leaf_Desert = 5,
Proxima_Island = 6,
Rebellion_Island = 7,
Hamalayi_mountains_southern_range = 8,
Hamalayi_mountains_northern_range = 9,
Tippet_Island = 10,
Brundle_Island = 11,
Fortress_Island = 12,
Polar_Island = 13
};
/** menu text ids */
enum class TextId : int16 {
kNone = -1,
kBehaviourNormal = 0,
kBehaviourSporty = 1,
kBehaviourAggressiveManual = 2,
kBehaviourHiding = 3,
kBehaviourAggressiveAuto = 4,
kUseProtopack = 5,
kSendell = 6,
kMusicVolume = 10,
kSoundVolume = 11,
kCDVolume = 12,
kLineInVolume = 13,
kMasterVolume = 14,
kReturnGame = 15,
kSaveSettings = 16,
kNewGame = 20,
kContinueGame = 21,
kQuit = 22,
kOptions = 23,
kDelete = 24,
kReturnMenu = 26,
kGiveUp = 27,
kContinue = 28,
kVolumeSettings = 30,
kDetailsPolygonsHigh = 31,
kDetailsShadowHigh = 32,
//kSceneryZoomOn = 33, // duplicate with 133 - TODO check if this is the same in all languages
kCreateNewPlayer = 40,
kCreateSaveGame = 41,
kEnterYourName = 42,
kPlayerAlreadyExists = 43,
kEnterYourNewName = 44,
kDeleteSaveGame = 45,
kSaveManage = 46,
kAdvanced = 47,
kDelete2 = 48, // difference between 24 and 48?
kTransferVoices = 49,
kPleaseWaitWhileVoicesAreSaved = 50,
kRemoveProtoPack = 105,
kDetailsPolygonsMiddle = 131,
kShadowsFigures = 132,
kSceneryZoomOn = 133,
kIntroText1 = 150,
kIntroText2 = 151,
kIntroText3 = 152,
kBookOfBu = 161,
kBonusList = 162,
kDetailsPolygonsLow = 231,
kShadowsDisabled = 232,
kNoSceneryZoom = 233,
// custom strings (not originally included in the game)
kCustomHighResOptionOn = -2,
kCustomHighResOptionOff = -3
};
enum InventoryItems {
kiHolomap = 0,
kiMagicBall = 1,
kiUseSabre = 2,
kiGawleysHorn = 3,
kiTunic = 4,
kiBookOfBu = 5,
kSendellsMedallion = 6,
kFlaskOfClearWater = 7,
kRedCard = 8,
kBlueCard = 9,
kIDCard = 10,
kMrMiesPass = 11,
kiProtoPack = 12,
kSnowboard = 13,
kiPinguin = 14,
kGasItem = 15,
kPirateFlag = 16,
kMagicFlute = 17,
kSpaceGuitar = 18,
kHairDryer = 19,
kAncesteralKey = 20,
kBottleOfSyrup = 21,
kEmptyBottle = 22,
kFerryTicket = 23,
kKeypad = 24,
kCoffeeCan = 25,
kiBonusList = 26,
kiCloverLeaf = 27,
MaxInventoryItems = 28
};
// lba2 does from 0 to 0x1000 // lba2 does from 0 to 0x1000
// lba1 angles // lba1 angles
// TODO: wrap in a class to be able to handle lba1 and lba2 // TODO: wrap in a class to be able to handle lba1 and lba2

View file

@ -38,6 +38,7 @@
#include "twine/renderer/screens.h" #include "twine/renderer/screens.h"
#include "twine/resources/hqr.h" #include "twine/resources/hqr.h"
#include "twine/resources/resources.h" #include "twine/resources/resources.h"
#include "twine/scene/gamestate.h"
#include "twine/scene/scene.h" #include "twine/scene/scene.h"
#include "twine/twine.h" #include "twine/twine.h"
@ -55,7 +56,7 @@ Text::Text(TwinEEngine *engine) : _engine(engine) {
Text::~Text() { Text::~Text() {
} }
void Text::initVoxBank(int32 bankIdx) { void Text::initVoxBank(TextBankId bankIdx) {
static const char *LanguageSuffixTypes[] = { static const char *LanguageSuffixTypes[] = {
"sys", "sys",
"cre", "cre",
@ -73,17 +74,17 @@ void Text::initVoxBank(int32 bankIdx) {
"010", // Polar Island voices "010", // Polar Island voices
"011" // "011" //
}; };
if (bankIdx < 0 || bankIdx >= ARRAYSIZE(LanguageSuffixTypes)) { if ((int)bankIdx < 0 || (int)bankIdx >= ARRAYSIZE(LanguageSuffixTypes)) {
error("bankIdx is out of bounds: %i", bankIdx); error("bankIdx is out of bounds: %i", (int)bankIdx);
} }
// get the correct vox hqr file // get the correct vox hqr file
currentVoxBankFile = Common::String::format("%s%s" VOX_EXT, LanguageTypes[_engine->cfgfile.LanguageId].id, LanguageSuffixTypes[bankIdx]); currentVoxBankFile = Common::String::format("%s%s" VOX_EXT, LanguageTypes[_engine->cfgfile.LanguageId].id, LanguageSuffixTypes[(int)bankIdx]);
// TODO: loop through other languages and take the scummvm settings regarding voices into account... // TODO: loop through other languages and take the scummvm settings regarding voices into account...
// TODO check the rest to reverse // TODO check the rest to reverse
} }
bool Text::initVoxToPlayTextId(int textId) { bool Text::initVoxToPlayTextId(TextId textId) {
const TextEntry *text = _engine->_resources->getText(_currentBankIdx, textId); const TextEntry *text = _engine->_resources->getText(_currentBankIdx, textId);
return initVoxToPlay(text); return initVoxToPlay(text);
} }
@ -148,7 +149,7 @@ bool Text::stopVox(const TextEntry *text) {
return true; return true;
} }
void Text::initTextBank(int32 bankIdx) { void Text::initTextBank(TextBankId bankIdx) {
// don't load if we already have the dialogue text bank loaded // don't load if we already have the dialogue text bank loaded
if (bankIdx == _currentBankIdx) { if (bankIdx == _currentBankIdx) {
return; return;
@ -159,7 +160,7 @@ void Text::initTextBank(int32 bankIdx) {
} }
void Text::initSceneTextBank() { void Text::initSceneTextBank() {
initTextBank(_engine->_scene->sceneTextBank + TextBankId::Citadel_Island); initTextBank((TextBankId)((int)_engine->_scene->sceneTextBank + (int)TextBankId::Citadel_Island));
} }
void Text::drawCharacter(int32 x, int32 y, uint8 character) { void Text::drawCharacter(int32 x, int32 y, uint8 character) {
@ -293,16 +294,16 @@ void Text::initInventoryDialogueBox() {
_fadeInCharactersPos = 0; _fadeInCharactersPos = 0;
} }
void Text::initInventoryText(int index) { void Text::initInventoryText(InventoryItems index) {
// 100 if the offset for the inventory item descriptions // 100 if the offset for the inventory item descriptions
initText(100 + index); initText((TextId)(100 + (int)index));
} }
void Text::initItemFoundText(int index) { void Text::initItemFoundText(InventoryItems index) {
initText(100 + index); initText((TextId)(100 + (int)index));
} }
void Text::initText(int32 index) { void Text::initText(TextId index) {
if (!getText(index)) { if (!getText(index)) {
_hasValidTextHandle = false; _hasValidTextHandle = false;
return; return;
@ -579,9 +580,9 @@ ProgressiveTextState Text::updateProgressiveText() {
return ProgressiveTextState::ContinueRunning; return ProgressiveTextState::ContinueRunning;
} }
bool Text::displayText(int32 index, bool showText, bool playVox, bool loop) { bool Text::displayText(TextId index, bool showText, bool playVox, bool loop) {
debug(3, "displayText(index = %i, showText = %s, playVox = %s)", debug(3, "displayText(index = %i, showText = %s, playVox = %s)",
index, showText ? "true" : "false", playVox ? "true" : "false"); (int)index, showText ? "true" : "false", playVox ? "true" : "false");
if (playVox) { if (playVox) {
const TextEntry *textEntry = _engine->_resources->getText(_currentBankIdx, index); const TextEntry *textEntry = _engine->_resources->getText(_currentBankIdx, index);
// get right VOX entry index // get right VOX entry index
@ -655,7 +656,7 @@ bool Text::displayText(int32 index, bool showText, bool playVox, bool loop) {
return aborted; return aborted;
} }
bool Text::drawTextProgressive(int32 index, bool playVox, bool loop) { bool Text::drawTextProgressive(TextId index, bool playVox, bool loop) {
_engine->exitSceneryView(); _engine->exitSceneryView();
_engine->_interface->saveClip(); _engine->_interface->saveClip();
_engine->_interface->resetClip(); _engine->_interface->resetClip();
@ -688,7 +689,7 @@ void Text::setTextCrossColor(int32 stopColor, int32 startColor, int32 stepSize)
_dialTextBufferSize = ((startColor - stopColor) + 1) / stepSize; _dialTextBufferSize = ((startColor - stopColor) + 1) / stepSize;
} }
bool Text::getText(int32 index) { bool Text::getText(TextId index) {
const TextEntry *textEntry = _engine->_resources->getText(_currentBankIdx, index); const TextEntry *textEntry = _engine->_resources->getText(_currentBankIdx, index);
if (textEntry == nullptr) { if (textEntry == nullptr) {
return false; return false;
@ -699,11 +700,11 @@ bool Text::getText(int32 index) {
// RECHECK: this was added for vox playback // RECHECK: this was added for vox playback
currDialTextEntry = textEntry; currDialTextEntry = textEntry;
debug(3, "text for bank %i with index %i (currIndex: %i): %s", _currentBankIdx, textEntry->index, textEntry->textIndex, _currDialTextPtr); debug(3, "text for bank %i with index %i (currIndex: %i): %s", (int)_currentBankIdx, textEntry->index, (int)textEntry->textIndex, _currDialTextPtr);
return true; return true;
} }
bool Text::getMenuText(int32 index, char *text, uint32 textSize) { bool Text::getMenuText(TextId index, char *text, uint32 textSize) {
if (index == _currMenuTextIndex) { if (index == _currMenuTextIndex) {
if (_currMenuTextBank == _engine->_scene->sceneTextBank) { if (_currMenuTextBank == _engine->_scene->sceneTextBank) {
Common::strlcpy(text, _currMenuTextBuffer, textSize); Common::strlcpy(text, _currMenuTextBuffer, textSize);
@ -753,11 +754,11 @@ void Text::textClipSmall() {
_dialTextBoxMaxX = _engine->width() - 2 * margin - 2 * PADDING; _dialTextBoxMaxX = _engine->width() - 2 * margin - 2 * PADDING;
} }
void Text::drawAskQuestion(int32 index) { void Text::drawAskQuestion(TextId index) {
displayText(index, true, true, true); displayText(index, true, true, true);
} }
void Text::drawHolomapLocation(int32 index) { void Text::drawHolomapLocation(TextId index) {
textClipSmall(); textClipSmall();
setFontCrossColor(COLOR_WHITE); setFontCrossColor(COLOR_WHITE);
_engine->_interface->drawFilledRect(_dialTextBox, COLOR_BLACK); _engine->_interface->drawFilledRect(_dialTextBox, COLOR_BLACK);

View file

@ -26,87 +26,12 @@
#include "common/scummsys.h" #include "common/scummsys.h"
#include "common/str.h" #include "common/str.h"
#include "common/rect.h" #include "common/rect.h"
#include "twine/shared.h"
namespace TwinE { namespace TwinE {
class TextEntry; class TextEntry;
// lba
namespace TextBankId {
enum _TextBankId {
None = -1,
Options_and_menus = 0,
Credits = 1,
Inventory_Intro_and_Holomap = 2,
Citadel_Island = 3,
Principal_Island = 4,
White_Leaf_Desert = 5,
Proxima_Island = 6,
Rebellion_Island = 7,
Hamalayi_mountains_southern_range = 8,
Hamalayi_mountains_northern_range = 9,
Tippet_Island = 10,
Brundle_Island = 11,
Fortress_Island = 12,
Polar_Island = 13
};
}
/** menu text ids */
namespace TextId {
enum _TextId {
kBehaviourNormal = 0,
kBehaviourSporty = 1,
kBehaviourAggressiveManual = 2,
kBehaviourHiding = 3,
kBehaviourAggressiveAuto = 4,
kUseProtopack = 5,
kSendell = 6,
kMusicVolume = 10,
kSoundVolume = 11,
kCDVolume = 12,
kLineInVolume = 13,
kMasterVolume = 14,
kReturnGame = 15,
kSaveSettings = 16,
kNewGame = 20,
kContinueGame = 21,
kQuit = 22,
kOptions = 23,
kDelete = 24,
kReturnMenu = 26,
kGiveUp = 27,
kContinue = 28,
kVolumeSettings = 30,
kDetailsPolygonsHigh = 31,
kDetailsShadowHigh = 32,
//kSceneryZoomOn = 33, // duplicate with 133 - TODO check if this is the same in all languages
kCreateNewPlayer = 40,
kCreateSaveGame = 41,
kEnterYourName = 42,
kPlayerAlreadyExists = 43,
kEnterYourNewName = 44,
kDeleteSaveGame = 45,
kSaveManage = 46,
kAdvanced = 47,
kDelete2 = 48, // difference between 24 and 48?
kTransferVoices = 49,
kPleaseWaitWhileVoicesAreSaved = 50,
kRemoveProtoPack = 105,
kDetailsPolygonsMiddle = 131,
kShadowsFigures = 132,
kSceneryZoomOn = 133,
kIntroText1 = 150,
kIntroText2 = 151,
kIntroText3 = 152,
kBookOfBu = 161,
kBonusList = 162,
kDetailsPolygonsLow = 231,
kShadowsDisabled = 232,
kNoSceneryZoom = 233
};
}
#define TEXT_MAX_FADE_IN_CHR 32 #define TEXT_MAX_FADE_IN_CHR 32
#define COLOR_BLACK 0 #define COLOR_BLACK 0
@ -134,7 +59,7 @@ class TwinEEngine;
class Text { class Text {
private: private:
TwinEEngine *_engine; TwinEEngine *_engine;
void initVoxBank(int32 bankIdx); void initVoxBank(TextBankId bankIdx);
/** /**
* Draw a certain character in the screen * Draw a certain character in the screen
* @param x X coordinate in screen * @param x X coordinate in screen
@ -171,10 +96,8 @@ private:
*/ */
void fadeInCharacters(int32 counter, int32 fontColor); void fadeInCharacters(int32 counter, int32 fontColor);
// RECHECK THIS LATER TextBankId _currentBankIdx = TextBankId::None;
int32 _currentBankIdx = TextBankId::None; // textVar1
// TODO: refactor all this variables and related functions
char _progressiveTextBuffer[256] {'\0'}; char _progressiveTextBuffer[256] {'\0'};
const char *_currentTextPosition = nullptr; const char *_currentTextPosition = nullptr;
@ -199,8 +122,8 @@ private:
int32 _currDialTextSize = 0; int32 _currDialTextSize = 0;
char _currMenuTextBuffer[256]; char _currMenuTextBuffer[256];
int32 _currMenuTextBank = TextBankId::None; TextBankId _currMenuTextBank = TextBankId::None;
int32 _currMenuTextIndex = -1; TextId _currMenuTextIndex = TextId::kNone;
/** Pixel size between dialogue text */ /** Pixel size between dialogue text */
int32 _dialSpaceBetween = 0; int32 _dialSpaceBetween = 0;
@ -227,7 +150,7 @@ private:
int32 _dialTextBoxLines = 0; // dialogueBoxParam1 int32 _dialTextBoxLines = 0; // dialogueBoxParam1
int32 _dialTextBoxMaxX = 0; // dialogueBoxParam2 int32 _dialTextBoxMaxX = 0; // dialogueBoxParam2
bool displayText(int32 index, bool showText, bool playVox, bool loop); bool displayText(TextId index, bool showText, bool playVox, bool loop);
public: public:
Text(TwinEEngine *engine); Text(TwinEEngine *engine);
~Text(); ~Text();
@ -252,9 +175,9 @@ public:
* Initialize dialogue * Initialize dialogue
* @param bankIdx Text bank index * @param bankIdx Text bank index
*/ */
void initTextBank(int32 bankIdx); void initTextBank(TextBankId bankIdx);
void initSceneTextBank(); void initSceneTextBank();
inline int textBank() const { inline TextBankId textBank() const {
return _currentBankIdx; return _currentBankIdx;
} }
@ -266,7 +189,7 @@ public:
*/ */
void drawText(int32 x, int32 y, const char *dialogue); void drawText(int32 x, int32 y, const char *dialogue);
bool drawTextProgressive(int32 index, bool playVox = true, bool loop = true); bool drawTextProgressive(TextId index, bool playVox = true, bool loop = true);
/** /**
* Gets dialogue text width size * Gets dialogue text width size
@ -279,9 +202,9 @@ public:
void initDialogueBox(); void initDialogueBox();
void initInventoryDialogueBox(); void initInventoryDialogueBox();
void initText(int32 index); void initText(TextId index);
void initInventoryText(int index); void initInventoryText(InventoryItems index);
void initItemFoundText(int index); void initItemFoundText(InventoryItems index);
void fadeInRemainingChars(); void fadeInRemainingChars();
ProgressiveTextState updateProgressiveText(); ProgressiveTextState updateProgressiveText();
@ -317,7 +240,7 @@ public:
* @sa initTextBank() * @sa initTextBank()
* @param index dialogue index * @param index dialogue index
*/ */
bool getText(int32 index); bool getText(TextId index);
/** /**
* Gets menu dialogue text * Gets menu dialogue text
@ -325,19 +248,19 @@ public:
* @param text dialogue text buffer to display * @param text dialogue text buffer to display
* @param textSize The size of the text buffer * @param textSize The size of the text buffer
*/ */
bool getMenuText(int32 index, char *text, uint32 textSize); bool getMenuText(TextId index, char *text, uint32 textSize);
void textClipFull(); void textClipFull();
void textClipSmall(); void textClipSmall();
void drawAskQuestion(int32 index); void drawAskQuestion(TextId index);
void drawHolomapLocation(int32 index); void drawHolomapLocation(TextId index);
bool playVox(const TextEntry *text); bool playVox(const TextEntry *text);
bool playVoxSimple(const TextEntry *text); bool playVoxSimple(const TextEntry *text);
bool stopVox(const TextEntry *text); bool stopVox(const TextEntry *text);
bool initVoxToPlay(const TextEntry *text); bool initVoxToPlay(const TextEntry *text);
bool initVoxToPlayTextId(int textId); bool initVoxToPlayTextId(TextId index);
}; };
} // namespace TwinE } // namespace TwinE

View file

@ -225,15 +225,15 @@ Common::Error TwinEEngine::run() {
debug("The original Little Big Adventure game is:"); debug("The original Little Big Adventure game is:");
debug("(c) 1994 by Adeline Software International, All Rights Reserved."); debug("(c) 1994 by Adeline Software International, All Rights Reserved.");
ConfMan.registerDefault("usehighres", false);
syncSoundSettings(); syncSoundSettings();
int32 w = ORIGINAL_WIDTH; int32 w = ORIGINAL_WIDTH;
int32 h = ORIGINAL_HEIGHT; int32 h = ORIGINAL_HEIGHT;
if (ConfMan.hasKey("usehighres")) { const bool highRes = ConfMan.getBool("usehighres");
const bool highRes = ConfMan.getBool("usehighres"); if (highRes) {
if (highRes) { w = 1024;
w = 1024; h = 768;
h = 768;
}
} }
initGraphics(w, h); initGraphics(w, h);