From cb4f5edae93b7e02e9f0fd13a63c72119c07687b Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 28 Dec 2022 00:17:16 +0200 Subject: [PATCH] All Heroes 3 texts are now passed through translator --- client/lobby/CBonusSelection.cpp | 2 - client/lobby/SelectionTab.cpp | 6 +-- client/windows/CCreatureWindow.cpp | 16 +++----- config/translate.json | 16 +++++++- lib/CGeneralTextHandler.cpp | 65 ++++++++++++------------------ lib/CGeneralTextHandler.h | 17 ++++---- lib/mapping/CCampaignHandler.cpp | 2 +- lib/mapping/CCampaignHandler.h | 2 + 8 files changed, 62 insertions(+), 64 deletions(-) diff --git a/client/lobby/CBonusSelection.cpp b/client/lobby/CBonusSelection.cpp index 8fd5b0cc0..b5d2c2fff 100644 --- a/client/lobby/CBonusSelection.cpp +++ b/client/lobby/CBonusSelection.cpp @@ -141,8 +141,6 @@ void CBonusSelection::loadPositionsOfGraphics() idx++; } - - assert(idx == CGI->generaltexth->campaignMapNames.size()); } void CBonusSelection::createBonusesIcons() diff --git a/client/lobby/SelectionTab.cpp b/client/lobby/SelectionTab.cpp index 870627580..d8d89d8d0 100644 --- a/client/lobby/SelectionTab.cpp +++ b/client/lobby/SelectionTab.cpp @@ -99,8 +99,8 @@ bool mapSorter::operator()(const std::shared_ptr aaa, const std::share switch(sortBy) { case _numOfMaps: //by number of maps in campaign - return CGI->generaltexth->campaignRegionNames[aaa->campaignHeader->mapVersion].size() < - CGI->generaltexth->campaignRegionNames[bbb->campaignHeader->mapVersion].size(); + return CGI->generaltexth->getCampaignLength(aaa->campaignHeader->mapVersion) < + CGI->generaltexth->getCampaignLength(bbb->campaignHeader->mapVersion); break; case _name: //by name return boost::ilexicographical_compare(aaa->campaignHeader->name, bbb->campaignHeader->name); @@ -660,7 +660,7 @@ void SelectionTab::ListItem::updateItem(std::shared_ptr info, bool sel iconLossCondition->disable(); labelNumberOfCampaignMaps->enable(); std::ostringstream ostr(std::ostringstream::out); - ostr << CGI->generaltexth->campaignRegionNames[info->campaignHeader->mapVersion].size(); + ostr << CGI->generaltexth->getCampaignLength(info->campaignHeader->mapVersion); labelNumberOfCampaignMaps->setText(ostr.str()); labelNumberOfCampaignMaps->setColor(color); } diff --git a/client/windows/CCreatureWindow.cpp b/client/windows/CCreatureWindow.cpp index f4c001911..0c769b54d 100644 --- a/client/windows/CCreatureWindow.cpp +++ b/client/windows/CCreatureWindow.cpp @@ -377,10 +377,7 @@ CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, i auto getSkillDescription = [this](int skillIndex) -> std::string { - if(CGI->generaltexth->znpc00.size() == 0) - return ""; - - return CGI->generaltexth->znpc00[151 + (12 * skillIndex) + (parent->info->commander->secondarySkills[skillIndex] * 2)]; + return CGI->generaltexth->znpc00[152 + (12 * skillIndex) + (parent->info->commander->secondarySkills[skillIndex] * 2)]; }; for(int index = ECommander::ATTACK; index <= ECommander::SPELL_POWER; ++index) @@ -868,9 +865,9 @@ std::string CStackWindow::generateStackExpDescription() if (!vstd::iswithin(tier, 1, 7)) tier = 0; int number; - std::string expText = CGI->generaltexth->zcrexp[325]; + std::string expText = CGI->generaltexth->translate("vcmi.stackExperience.description"); boost::replace_first(expText, "%s", creature->namePl); - boost::replace_first(expText, "%s", CGI->generaltexth->zcrexp[rank]); + boost::replace_first(expText, "%s", CGI->generaltexth->translate("vcmi.stackExperience.rank", rank)); boost::replace_first(expText, "%i", boost::lexical_cast(rank)); boost::replace_first(expText, "%i", boost::lexical_cast(stack->experience)); number = static_cast(CGI->creh->expRanks[tier][rank] - stack->experience); @@ -905,13 +902,10 @@ void CStackWindow::setSelection(si32 newSkill, std::shared_ptr std::string { - if(CGI->generaltexth->znpc00.size() == 0) - return ""; - if(selected) - return CGI->generaltexth->znpc00[151 + (12 * skillIndex) + ((info->commander->secondarySkills[skillIndex] + 1) * 2)]; //upgrade description + return CGI->generaltexth->znpc00[152 + (12 * skillIndex) + ((info->commander->secondarySkills[skillIndex] + 1) * 2)]; //upgrade description else - return CGI->generaltexth->znpc00[151 + (12 * skillIndex) + (info->commander->secondarySkills[skillIndex] * 2)]; + return CGI->generaltexth->znpc00[152 + (12 * skillIndex) + (info->commander->secondarySkills[skillIndex] * 2)]; }; auto getSkillImage = [this](int skillIndex) -> std::string diff --git a/config/translate.json b/config/translate.json index 803c87046..ffe77719a 100644 --- a/config/translate.json +++ b/config/translate.json @@ -66,5 +66,19 @@ "vcmi.randomMapTab.widgets.defaultTemplate" : "default", "vcmi.randomMapTab.widgets.templateLabel" : "Template", "vcmi.randomMapTab.widgets.teamAlignmentsButton" : "Setup...", - "vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Team alignments" + "vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Team alignments", + + // few strings from WoG used by vcmi + "vcmi.stackExperience.description" : "» S t a c k E x p e r i e n c e D e t a i l s «\n\nCreature Type ................... : %s\nExperience Rank ................. : %s (%i)\nExperience Points ............... : %i\nExperience Points to Next Rank .. : %i\nMaximum Experience per Battle ... : %i%% (%i)\nNumber of Creatures in stack .... : %i\nMaximum New Recruits\n without losing current Rank .... : %i\nExperience Multiplier ........... : %.2f\nUpgrade Multiplier .............. : %.2f\nExperience after Rank 10 ........ : %i\nMaximum New Recruits to remain at\n Rank 10 if at Maximum Experience : %i", + "vcmi.stackExperience.rank.1" : "Basic", + "vcmi.stackExperience.rank.2" : "Novice", + "vcmi.stackExperience.rank.3" : "Trained", + "vcmi.stackExperience.rank.4" : "Skilled", + "vcmi.stackExperience.rank.5" : "Proven", + "vcmi.stackExperience.rank.6" : "Veteran", + "vcmi.stackExperience.rank.7" : "Adept", + "vcmi.stackExperience.rank.8" : "Expert", + "vcmi.stackExperience.rank.9" : "Elite", + "vcmi.stackExperience.rank.10" : "Master", + "vcmi.stackExperience.rank.11" : "Ace" } diff --git a/lib/CGeneralTextHandler.cpp b/lib/CGeneralTextHandler.cpp index 1e05a3821..fd1d22e6a 100644 --- a/lib/CGeneralTextHandler.cpp +++ b/lib/CGeneralTextHandler.cpp @@ -380,6 +380,7 @@ CGeneralTextHandler::CGeneralTextHandler(): seerEmpty (*this, "core.seerhut.empty" ), seerNames (*this, "core.seerhut.names" ), capColors (*this, "vcmi.capitalColors" ), + znpc00 (*this, "vcmi.znpc00" ), // technically - wog qeModCommands (*this, "vcmi.quickExchange" ) { readToVector("core.vcdesc", "DATA/VCDESC.TXT" ); @@ -506,70 +507,46 @@ CGeneralTextHandler::CGeneralTextHandler(): parser.endLine(); std::string text; + size_t campaignsCount = 0; do { text = parser.readString(); if (!text.empty()) - campaignMapNames.push_back(text); + { + registerH3String("core.camptext.names", campaignsCount, text); + campaignsCount += 1; + } } while (parser.endLine() && !text.empty()); - for (size_t i=0; i()); do { text = parser.readString(); if (!text.empty()) - campaignRegionNames.back().push_back(text); + { + registerH3String("core.camptext.regions." + std::to_string(campaignsCount), region, text); + region += 1; + } } while (parser.endLine() && !text.empty()); - } - } - if (VLC->modh->modules.STACK_EXP) - { - CLegacyConfigParser parser("DATA/ZCREXP.TXT"); - parser.endLine();//header - for (size_t iter=0; iter<325; iter++) - { - parser.readString(); //ignore 1st column with description - zcrexp.push_back(parser.readString()); - parser.endLine(); - } - // line 325 - some weird formatting here - zcrexp.push_back(parser.readString()); - parser.readString(); - parser.endLine(); - do // rest of file can be read normally - { - parser.readString(); //ignore 1st column with description - zcrexp.push_back(parser.readString()); + scenariosCountPerCampaign.push_back(region); } - while (parser.endLine()); } if (VLC->modh->modules.COMMANDERS) { - try - { - CLegacyConfigParser parser("DATA/ZNPC00.TXT"); - parser.endLine();//header - - do - { - znpc00.push_back(parser.readString()); - } while (parser.endLine()); - } - catch (const std::runtime_error &) - { - logGlobal->warn("WoG file ZNPC00.TXT containing commander texts was not found"); - } + if (CResourceHandler::get()->existsResource(ResourceID("DATA/ZNPC00.TXT", EResType::TEXT))) + readToVector("vcmi.znpc00", "DATA/ZNPC00.TXT" ); } dumpAllTexts(); @@ -597,12 +574,22 @@ void CGeneralTextHandler::dumpAllTexts() boost::replace_all(cleanString, "\n", "\\n"); boost::replace_all(cleanString, "\r", "\\r"); boost::replace_all(cleanString, "\t", "\\t"); + boost::replace_all(cleanString, "\"", "\\\""); logGlobal->info("\"%s\" : \"%s\",", entry.first, cleanString); } logGlobal->info("END TEXT EXPORT"); } +size_t CGeneralTextHandler::getCampaignLength(size_t campaignID) const +{ + assert(campaignID < scenariosCountPerCampaign.size()); + + if ( campaignID < scenariosCountPerCampaign.size()) + return scenariosCountPerCampaign[campaignID]; + return 0; +} + std::vector CGeneralTextHandler::findStringsWithPrefix(std::string const & prefix) { std::vector result; diff --git a/lib/CGeneralTextHandler.h b/lib/CGeneralTextHandler.h index fd641f656..5f23f589a 100644 --- a/lib/CGeneralTextHandler.h +++ b/lib/CGeneralTextHandler.h @@ -130,7 +130,13 @@ class DLL_LINKAGE CGeneralTextHandler void readToVector(std::string sourceID, std::string sourceName); + /// number of scenarios in specific campaign. TODO: move to a better location + std::vector scenariosCountPerCampaign; public: + // returns true if identifier with such name was registered, even if not translated to current language + // not required right now, can be added if necessary + // bool identifierExists( const std::string identifier) const; + /// returns translated version of a string that can be displayed to user const std::string & translate(const std::string & identifier) const; @@ -143,7 +149,7 @@ public: /// converts identifier into user-readable string, may be identical to 'translate' but reserved for serialization calls const std::string & deserialize(const std::string & identifier) const; - /// Debug methods, dumps all currently known texts into console using Json-like format + /// Debug method, dumps all currently known texts into console using Json-like format void dumpAllTexts(); LegacyTextContainer allTexts; @@ -182,18 +188,15 @@ public: //sec skills LegacyTextContainer levels; - std::vector zcrexp; //more or less useful content of that file //commanders - std::vector znpc00; //more or less useful content of that file - - //campaigns - std::vector campaignMapNames; - std::vector> campaignRegionNames; + LegacyTextContainer znpc00; //more or less useful content of that file std::vector findStringsWithPrefix(std::string const & prefix); int32_t pluralText(const int32_t textIndex, const int32_t count) const; + size_t getCampaignLength(size_t campaignID) const; + CGeneralTextHandler(); CGeneralTextHandler(const CGeneralTextHandler&) = delete; CGeneralTextHandler operator=(const CGeneralTextHandler&) = delete; diff --git a/lib/mapping/CCampaignHandler.cpp b/lib/mapping/CCampaignHandler.cpp index 02d9f9c6e..eacdc82ad 100644 --- a/lib/mapping/CCampaignHandler.cpp +++ b/lib/mapping/CCampaignHandler.cpp @@ -79,7 +79,7 @@ std::unique_ptr CCampaignHandler::getCampaign( const std::string & na ret->header = readHeaderFromMemory(reader); ret->header.filename = name; - int howManyScenarios = static_cast(VLC->generaltexth->campaignRegionNames[ret->header.mapVersion].size()); + int howManyScenarios = static_cast(VLC->generaltexth->getCampaignLength(ret->header.mapVersion)); for(int g=0; gheader.version, ret->header.mapVersion); diff --git a/lib/mapping/CCampaignHandler.h b/lib/mapping/CCampaignHandler.h index ebd11d459..ac6d18ca6 100644 --- a/lib/mapping/CCampaignHandler.h +++ b/lib/mapping/CCampaignHandler.h @@ -229,6 +229,8 @@ public: class DLL_LINKAGE CCampaignHandler { + std::vector scenariosCountPerCampaign; + static CCampaignHeader readHeaderFromMemory(CBinaryReader & reader); static CCampaignScenario readScenarioFromMemory(CBinaryReader & reader, int version, int mapVersion ); static CScenarioTravel readScenarioTravelFromMemory(CBinaryReader & reader, int version);