Răsfoiți Sursa

Merge pull request #1682 from IvanSavenko/h3m_text_export

H3M/H3C text export
Ivan Savenko 2 ani în urmă
părinte
comite
962f7ac4de

+ 2 - 0
Mods/vcmi/config/vcmi/ukrainian.json

@@ -38,6 +38,8 @@
 	"vcmi.systemOptions.otherGroup" : "Інші налаштування",
 	"vcmi.systemOptions.townsGroup" : "Екран міста",
 
+    "vcmi.adventureOptions.infoBarPick.help" : "{Повідомлення у панелі статусу}\n\nЗа можливості, повідомлення про відвідування об'єктів карти пригод будуть відображені у панелі статусу замість окремого вікна",
+    "vcmi.adventureOptions.infoBarPick.hover" : "Повідомлення у панелі статусу",
 	"vcmi.systemOptions.fullscreenButton.hover" : "Повноекранний режим",
 	"vcmi.systemOptions.fullscreenButton.help"  : "{Повноекранний режим}\n\n Якщо обрано, VCMI буде запускатися в режимі на весь екран, інакше — віконний режим",
 	"vcmi.systemOptions.resolutionButton.hover" : "Роздільна здатність: %wx%h",

+ 38 - 0
client/ClientCommandManager.cpp

@@ -23,6 +23,9 @@
 #include "../lib/CGameState.h"
 #include "../lib/CPlayerState.h"
 #include "../lib/StringConstants.h"
+#include "../lib/mapping/CMapService.h"
+#include "../lib/mapping/CMap.h"
+#include "../lib/mapping/CCampaignHandler.h"
 #include "windows/CCastleInterface.h"
 #include "render/CAnimation.h"
 #include "../CCallback.h"
@@ -153,6 +156,41 @@ void ClientCommandManager::processCommand(const std::string &message, bool calle
 //	}
 	else if(message=="convert txt")
 	{
+		logGlobal->info("Searching for available maps");
+		std::unordered_set<ResourceID> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
+		{
+			return ident.getType() == EResType::MAP;
+		});
+
+		std::unordered_set<ResourceID> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
+		{
+			return ident.getType() == EResType::CAMPAIGN;
+		});
+
+		CMapService mapService;
+
+		logGlobal->info("Loading maps for export");
+		for (auto const & mapName : mapList)
+		{
+			try
+			{
+				// load and drop loaded map - we only need loader to run over all maps
+				mapService.loadMap(mapName);
+			}
+			catch(std::exception & e)
+			{
+				logGlobal->error("Map %s is invalid. Message: %s", mapName.getName(), e.what());
+			}
+		}
+
+		logGlobal->info("Loading campaigns for export");
+		for (auto const & campaignName : campaignList)
+		{
+			CCampaignState state(CCampaignHandler::getCampaign(campaignName.getName()));
+			for (auto const & part : state.camp->mapPieces)
+				delete state.getMap(part.first);
+		}
+
 		VLC->generaltexth->dumpAllTexts();
 	}
 	else if(message=="get config")

+ 5 - 2
lib/CGeneralTextHandler.cpp

@@ -311,10 +311,13 @@ bool CGeneralTextHandler::validateTranslation(const std::string & language, cons
 	for (auto const & string : stringsLocalizations)
 	{
 		if (string.second.modContext != modContext)
-			continue;
+			continue; // Not our mod
+
+		if (string.second.overrideLanguage == language)
+			continue; // Already translated
 
 		if (string.second.baseLanguage == language && !string.second.baseValue.empty())
-			continue;
+			continue; // Base string already uses our language
 
 		if (config.Struct().count(string.first) > 0)
 			continue;

+ 1 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -970,7 +970,7 @@ void CGHeroInstance::initExp(CRandomGenerator & rand)
 
 std::string CGHeroInstance::nodeName() const
 {
-	return "Hero " + getNameTranslated();
+	return "Hero " + getNameTextID();
 }
 
 std::string CGHeroInstance::getNameTranslated() const

+ 6 - 3
lib/mapObjects/CObjectClassesHandler.cpp

@@ -339,11 +339,14 @@ std::set<si32> CObjectClassesHandler::knownObjects() const
 
 std::set<si32> CObjectClassesHandler::knownSubObjects(si32 primaryID) const
 {
-	assert(primaryID < objects.size());
-	assert(objects[primaryID]);
-
 	std::set<si32> ret;
 
+	if (!objects.at(primaryID))
+	{
+		logGlobal->error("Failed to find object %d", primaryID);
+		return ret;
+	}
+
 	for(const auto & entry : objects.at(primaryID)->objects)
 		if (entry)
 			ret.insert(entry->subtype);

+ 38 - 17
lib/mapping/CCampaignHandler.cpp

@@ -53,7 +53,7 @@ CCampaignHeader CCampaignHandler::getHeader( const std::string & name)
 
 	CMemoryStream stream(cmpgn.data(), cmpgn.size());
 	CBinaryReader reader(&stream);
-	CCampaignHeader ret = readHeaderFromMemory(reader, name, modName, encoding);
+	CCampaignHeader ret = readHeaderFromMemory(reader, resourceID.getName(), modName, encoding);
 
 	return ret;
 }
@@ -72,12 +72,12 @@ std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & na
 
 	CMemoryStream stream(file[0].data(), file[0].size());
 	CBinaryReader reader(&stream);
-	ret->header = readHeaderFromMemory(reader, name, modName, encoding);
+	ret->header = readHeaderFromMemory(reader, resourceID.getName(), modName, encoding);
 
 	int howManyScenarios = static_cast<int>(VLC->generaltexth->getCampaignLength(ret->header.mapVersion));
 	for(int g=0; g<howManyScenarios; ++g)
 	{
-		CCampaignScenario sc = readScenarioFromMemory(reader, encoding, ret->header.version, ret->header.mapVersion);
+		CCampaignScenario sc = readScenarioFromMemory(reader, resourceID.getName(), modName, encoding, ret->header.version, ret->header.mapVersion);
 		ret->scenarios.push_back(sc);
 	}
 
@@ -91,7 +91,7 @@ std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & na
 			scenarioID++;
 		}
 
-		std::string scenarioName = name.substr(0, name.find('.'));
+		std::string scenarioName = resourceID.getName();
 		boost::to_lower(scenarioName);
 		scenarioName += ':' + std::to_string(g - 1);
 
@@ -109,11 +109,11 @@ std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & na
 	}
 
 	// handle campaign specific discrepancies
-	if(name == "DATA/AB.H3C")
+	if(resourceID.getName() == "DATA/AB")
 	{
 		ret->scenarios[6].keepHeroes.emplace_back(155); // keep hero Xeron for map 7 To Kill A Hero
 	}
-	else if(name == "DATA/FINAL.H3C")
+	else if(resourceID.getName() == "DATA/FINAL")
 	{
 		// keep following heroes for map 8 Final H
 		ret->scenarios[7].keepHeroes.emplace_back(148); // Gelu
@@ -125,9 +125,30 @@ std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & na
 	return ret;
 }
 
-std::string CCampaignHandler::readLocalizedString(CBinaryReader & reader, std::string encoding)
+static std::string convertMapName(std::string input)
 {
-	return TextOperations::toUnicode(reader.readBaseString(), encoding);
+	boost::algorithm::to_lower(input);
+	boost::algorithm::trim(input);
+
+	size_t slashPos = input.find_last_of("/");
+
+	if (slashPos != std::string::npos)
+		return input.substr(slashPos + 1);
+
+	return input;
+}
+
+std::string CCampaignHandler::readLocalizedString(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier)
+{
+	TextIdentifier stringID( "campaign", convertMapName(filename), identifier);
+
+	std::string input = TextOperations::toUnicode(reader.readBaseString(), encoding);
+
+	if (input.empty())
+		return "";
+
+	VLC->generaltexth->registerString(modName, stringID, input);
+	return VLC->generaltexth->translate(stringID.get());
 }
 
 CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader, std::string filename, std::string modName, std::string encoding )
@@ -136,8 +157,8 @@ CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader,
 
 	ret.version = reader.readUInt32();
 	ret.mapVersion = reader.readUInt8() - 1;//change range of it from [1, 20] to [0, 19]
-	ret.name = readLocalizedString(reader, encoding);
-	ret.description = readLocalizedString(reader, encoding);
+	ret.name = readLocalizedString(reader, filename, modName, encoding, "name");
+	ret.description = readLocalizedString(reader, filename, modName, encoding, "description");
 	if (ret.version > CampaignVersion::RoE)
 		ret.difficultyChoosenByPlayer = reader.readInt8();
 	else
@@ -149,9 +170,9 @@ CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader,
 	return ret;
 }
 
-CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & reader, std::string encoding, int version, int mapVersion )
+CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, int version, int mapVersion )
 {
-	auto prologEpilogReader = [&]() -> CCampaignScenario::SScenarioPrologEpilog
+	auto prologEpilogReader = [&](const std::string & identifier) -> CCampaignScenario::SScenarioPrologEpilog
 	{
 		CCampaignScenario::SScenarioPrologEpilog ret;
 		ret.hasPrologEpilog = reader.readUInt8();
@@ -159,14 +180,14 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read
 		{
 			ret.prologVideo = reader.readUInt8();
 			ret.prologMusic = reader.readUInt8();
-			ret.prologText = readLocalizedString(reader, encoding);
+			ret.prologText = readLocalizedString(reader, filename, modName, encoding, identifier);
 		}
 		return ret;
 	};
 
 	CCampaignScenario ret;
 	ret.conquered = false;
-	ret.mapName = readLocalizedString(reader, encoding);
+	ret.mapName = reader.readBaseString();
 	ret.packedMapSize = reader.readUInt32();
 	if(mapVersion == 18)//unholy alliance
 	{
@@ -178,9 +199,9 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read
 	}
 	ret.regionColor = reader.readUInt8();
 	ret.difficulty = reader.readUInt8();
-	ret.regionText = readLocalizedString(reader, encoding);
-	ret.prolog = prologEpilogReader();
-	ret.epilog = prologEpilogReader();
+	ret.regionText = readLocalizedString(reader, filename, modName, encoding, ret.mapName + ".region");
+	ret.prolog = prologEpilogReader(ret.mapName + ".prolog");
+	ret.epilog = prologEpilogReader(ret.mapName + ".epilog");
 
 	ret.travelOptions = readScenarioTravelFromMemory(reader, version);
 

+ 2 - 2
lib/mapping/CCampaignHandler.h

@@ -220,10 +220,10 @@ class DLL_LINKAGE CCampaignHandler
 {
 	std::vector<size_t> scenariosCountPerCampaign;
 
-	static std::string readLocalizedString(CBinaryReader & reader, std::string encoding);
+	static std::string readLocalizedString(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier);
 
 	static CCampaignHeader readHeaderFromMemory(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding);
-	static CCampaignScenario readScenarioFromMemory(CBinaryReader & reader, std::string encoding, int version, int mapVersion );
+	static CCampaignScenario readScenarioFromMemory(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, int version, int mapVersion );
 	static CScenarioTravel readScenarioTravelFromMemory(CBinaryReader & reader, int version);
 	/// returns h3c split in parts. 0 = h3c header, 1-end - maps (binary h3m)
 	/// headerOnly - only header will be decompressed, returned vector wont have any maps

+ 18 - 5
lib/mapping/MapFormatH3M.cpp

@@ -35,11 +35,24 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 const bool CMapLoaderH3M::IS_PROFILING_ENABLED = false;
 
+static std::string convertMapName(std::string input)
+{
+	boost::algorithm::to_lower(input);
+	boost::algorithm::trim(input);
+
+	size_t slashPos = input.find_last_of("/");
+
+	if (slashPos != std::string::npos)
+		return input.substr(slashPos + 1);
+
+	return input;
+}
+
 CMapLoaderH3M::CMapLoaderH3M(const std::string & mapName, const std::string & modName, const std::string & encodingName, CInputStream * stream)
 	: map(nullptr)
 	, reader(new CBinaryReader(stream))
 	, inputStream(stream)
-	, mapName(boost::algorithm::to_lower_copy(mapName))
+	, mapName(convertMapName(mapName))
 	, modName(modName)
 	, fileEncoding(encodingName)
 {
@@ -1436,11 +1449,11 @@ void CMapLoaderH3M::readObjects()
 				if(htid == 0xff)
 				{
 					hp->power = reader->readUInt8();
-					logGlobal->info("Hero placeholder: by power at %s", objPos.toString());
+					logGlobal->debug("Hero placeholder: by power at %s", objPos.toString());
 				}
 				else
 				{
-					logGlobal->info("Hero placeholder: %s at %s", VLC->heroh->objects[htid]->getNameTranslated(), objPos.toString());
+					logGlobal->debug("Hero placeholder: %s at %s", VLC->heroh->objects[htid]->getNameTranslated(), objPos.toString());
 					hp->power = 0;
 				}
 
@@ -1692,7 +1705,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven,
 		if(!nhi->spells.empty())
 		{
 			nhi->clear();
-			logGlobal->warn("Hero %s subID=%d has spells set twice (in map properties and on adventure map instance). Using the latter set...", nhi->getNameTranslated(), nhi->subID);
+			logGlobal->warn("Hero %s subID=%d has spells set twice (in map properties and on adventure map instance). Using the latter set...", nhi->getNameTextID(), nhi->subID);
 		}
 
 		if(hasCustomSpells)
@@ -2252,7 +2265,7 @@ std::string CMapLoaderH3M::readBasicString()
 std::string CMapLoaderH3M::readLocalizedString(const TextIdentifier & stringIdentifier)
 {
 	std::string mapString = TextOperations::toUnicode(reader->readBaseString(), fileEncoding);
-	TextIdentifier fullIdentifier(mapName, stringIdentifier.get());
+	TextIdentifier fullIdentifier("map", mapName, stringIdentifier.get());
 
 	if (mapString.empty())
 		return "";