nordsoft 2 år sedan
förälder
incheckning
03c099d4fd

+ 2 - 2
client/CPlayerInterface.cpp

@@ -239,7 +239,7 @@ void CPlayerInterface::performAutosave()
 			prefix = settings["general"]["savePrefix"].String();
 			if(prefix.empty())
 			{
-				std::string name = cb->getMapHeader()->name;
+				std::string name = cb->getMapHeader()->name.toString();
 				int txtlen = TextOperations::getUnicodeCharactersCount(name);
 
 				TextOperations::trimRightUnicode(name, std::max(0, txtlen - 15));
@@ -1718,7 +1718,7 @@ void CPlayerInterface::requestReturningToMainMenu(bool won)
 			if(!ps->checkVanquished())
 				param.allDefeated = false;
 	}
-	param.scenarioName = cb->getMapHeader()->name;
+	param.scenarioName = cb->getMapHeader()->name.toString();
 	param.playerName = cb->getStartInfo()->playerInfos.find(*cb->getPlayerID())->second.name;
 	HighScoreCalculation highScoreCalc;
 	highScoreCalc.parameters.push_back(param);

+ 1 - 1
client/CServerHandler.cpp

@@ -701,7 +701,7 @@ void CServerHandler::startCampaignScenario(HighScoreParameter param, std::shared
 		highScoreCalc->isCampaign = true;
 		highScoreCalc->parameters.clear();
 	}
-	param.campaignName = cs->getName();
+	param.campaignName = cs->getNameTranslated();
 	highScoreCalc->parameters.push_back(param);
 
 	GH.dispatchMainThread([ourCampaign, this]()

+ 32 - 37
client/lobby/CBonusSelection.cpp

@@ -79,9 +79,9 @@ CBonusSelection::CBonusSelection()
 	iconsMapSizes = std::make_shared<CAnimImage>(AnimationPath::builtin("SCNRMPSZ"), 4, 0, 735, 26);
 
 	labelCampaignDescription = std::make_shared<CLabel>(481, 63, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[38]);
-	campaignDescription = std::make_shared<CTextBox>(getCampaign()->getDescription(), Rect(480, 86, 286, 117), 1);
+	campaignDescription = std::make_shared<CTextBox>(getCampaign()->getDescriptionTranslated(), Rect(480, 86, 286, 117), 1);
 
-	mapName = std::make_shared<CLabel>(481, 219, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW, CSH->mi->getName());
+	mapName = std::make_shared<CLabel>(481, 219, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW, CSH->mi->getNameTranslated());
 	labelMapDescription = std::make_shared<CLabel>(481, 253, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[496]);
 	mapDescription = std::make_shared<CTextBox>("", Rect(480, 278, 292, 108), 1);
 
@@ -146,18 +146,18 @@ void CBonusSelection::createBonusesIcons()
 		std::string picName = bonusPics[bonusType];
 		size_t picNumber = bonDescs[i].info2;
 
-		std::string desc;
+		MetaString desc;
 		switch(bonDescs[i].type)
 		{
 		case CampaignBonusType::SPELL:
-			desc = CGI->generaltexth->allTexts[715];
-			boost::algorithm::replace_first(desc, "%s", CGI->spells()->getByIndex(bonDescs[i].info2)->getNameTranslated());
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 715);
+			desc.replaceLocalString(EMetaText::SPELL_NAME, bonDescs[i].info2);
 			break;
 		case CampaignBonusType::MONSTER:
 			picNumber = bonDescs[i].info2 + 2;
-			desc = CGI->generaltexth->allTexts[717];
-			boost::algorithm::replace_first(desc, "%d", std::to_string(bonDescs[i].info3));
-			boost::algorithm::replace_first(desc, "%s", CGI->creatures()->getByIndex(bonDescs[i].info2)->getNamePluralTranslated());
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 717);
+			desc.replaceNumber(bonDescs[i].info3);
+			desc.replaceLocalString(EMetaText::CRE_PL_NAMES, bonDescs[i].info2);
 			break;
 		case CampaignBonusType::BUILDING:
 		{
@@ -182,17 +182,16 @@ void CBonusSelection::createBonusesIcons()
 			picNumber = -1;
 
 			if(vstd::contains((*CGI->townh)[faction]->town->buildings, buildID))
-				desc = (*CGI->townh)[faction]->town->buildings.find(buildID)->second->getNameTranslated();
-
+				desc.appendTextID((*CGI->townh)[faction]->town->buildings.find(buildID)->second->getNameTextID());
 			break;
 		}
 		case CampaignBonusType::ARTIFACT:
-			desc = CGI->generaltexth->allTexts[715];
-			boost::algorithm::replace_first(desc, "%s", CGI->artifacts()->getByIndex(bonDescs[i].info2)->getNameTranslated());
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 715);
+			desc.replaceLocalString(EMetaText::ART_NAMES, bonDescs[i].info2);
 			break;
 		case CampaignBonusType::SPELL_SCROLL:
-			desc = CGI->generaltexth->allTexts[716];
-			boost::algorithm::replace_first(desc, "%s", CGI->spells()->getByIndex(bonDescs[i].info2)->getNameTranslated());
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 716);
+			desc.replaceLocalString(EMetaText::ART_NAMES, bonDescs[i].info2);
 			break;
 		case CampaignBonusType::PRIMARY_SKILL:
 		{
@@ -211,7 +210,7 @@ void CBonusSelection::createBonusesIcons()
 				}
 			}
 			picNumber = leadingSkill;
-			desc = CGI->generaltexth->allTexts[715];
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 715);
 
 			std::string substitute; //text to be printed instead of %s
 			for(int v = 0; v < toPrint.size(); ++v)
@@ -224,14 +223,13 @@ void CBonusSelection::createBonusesIcons()
 				}
 			}
 
-			boost::algorithm::replace_first(desc, "%s", substitute);
+			desc.replaceRawString(substitute);
 			break;
 		}
 		case CampaignBonusType::SECONDARY_SKILL:
-			desc = CGI->generaltexth->allTexts[718];
-
-			boost::algorithm::replace_first(desc, "%s", CGI->generaltexth->levels[bonDescs[i].info3 - 1]); //skill level
-			boost::algorithm::replace_first(desc, "%s", CGI->skillh->getByIndex(bonDescs[i].info2)->getNameTranslated()); //skill name
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 718);
+			desc.replaceTextID(TextIdentifier("core", "genrltxt", "levels", bonDescs[i].info3 - 1).get());
+			desc.replaceLocalString(EMetaText::SEC_SKILL_NAME, bonDescs[i].info2);
 			picNumber = bonDescs[i].info2 * 3 + bonDescs[i].info3 - 1;
 
 			break;
@@ -258,18 +256,17 @@ void CBonusSelection::createBonusesIcons()
 			}
 			picNumber = serialResID;
 
-			desc = CGI->generaltexth->allTexts[717];
-			boost::algorithm::replace_first(desc, "%d", std::to_string(bonDescs[i].info2));
-			std::string replacement;
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 717);
+			desc.replaceNumber(bonDescs[i].info2);
+			
 			if(serialResID <= 6)
 			{
-				replacement = CGI->generaltexth->restypes[serialResID];
+				desc.replaceLocalString(EMetaText::RES_NAMES, serialResID);
 			}
 			else
 			{
-				replacement = CGI->generaltexth->allTexts[714 + serialResID];
+				desc.replaceLocalString(EMetaText::GENERAL_TXT, 714 + serialResID);
 			}
-			boost::algorithm::replace_first(desc, "%s", replacement);
 			break;
 		}
 		case CampaignBonusType::HEROES_FROM_PREVIOUS_SCENARIO:
@@ -278,31 +275,29 @@ void CBonusSelection::createBonusesIcons()
 			if(!superhero)
 				logGlobal->warn("No superhero! How could it be transferred?");
 			picNumber = superhero ? superhero->portrait : 0;
-			desc = CGI->generaltexth->allTexts[719];
-
-			boost::algorithm::replace_first(desc, "%s", getCampaign()->scenario(static_cast<CampaignScenarioID>(bonDescs[i].info2)).scenarioName);
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 719);
+			desc.replaceRawString(getCampaign()->scenario(static_cast<CampaignScenarioID>(bonDescs[i].info2)).scenarioName.toString());
 			break;
 		}
 
 		case CampaignBonusType::HERO:
 
-			desc = CGI->generaltexth->allTexts[718];
-			boost::algorithm::replace_first(desc, "%s", CGI->generaltexth->capColors[bonDescs[i].info1]); //hero's color
-
+			desc.appendLocalString(EMetaText::GENERAL_TXT, 718);
+			desc.replaceTextID(TextIdentifier("core", "genrltxt", "capColors", bonDescs[i].info1).get());
 			if(bonDescs[i].info2 == 0xFFFF)
 			{
-				boost::algorithm::replace_first(desc, "%s", CGI->generaltexth->allTexts[101]); //hero's name
+				desc.replaceLocalString(EMetaText::GENERAL_TXT, 101);
 				picNumber = -1;
 				picName = "CBONN1A3.BMP";
 			}
 			else
 			{
-				boost::algorithm::replace_first(desc, "%s", CGI->heroh->objects[bonDescs[i].info2]->getNameTranslated());
+				desc.replaceTextID(CGI->heroh->objects[bonDescs[i].info2]->getNameTextID());
 			}
 			break;
 		}
 
-		std::shared_ptr<CToggleButton> bonusButton = std::make_shared<CToggleButton>(Point(475 + i * 68, 455), AnimationPath(), CButton::tooltip(desc, desc));
+		std::shared_ptr<CToggleButton> bonusButton = std::make_shared<CToggleButton>(Point(475 + i * 68, 455), AnimationPath(), CButton::tooltip(desc.toString(), desc.toString()));
 
 		if(picNumber != -1)
 			picName += ":" + std::to_string(picNumber);
@@ -355,8 +350,8 @@ void CBonusSelection::updateAfterStateChange()
 	if(!CSH->mi)
 		return;
 	iconsMapSizes->setFrame(CSH->mi->getMapSizeIconId());
-	mapName->setText(CSH->mi->getName());
-	mapDescription->setText(CSH->mi->getDescription());
+	mapName->setText(CSH->mi->getNameTranslated());
+	mapDescription->setText(CSH->mi->getDescriptionTranslated());
 	for(size_t i = 0; i < difficultyIcons.size(); i++)
 	{
 		if(i == CSH->si->difficulty)

+ 2 - 2
client/lobby/CSelectionBase.cpp

@@ -200,8 +200,8 @@ void InfoCard::changeSelection()
 		return;
 
 	labelSaveDate->setText(mapInfo->date);
-	mapName->setText(mapInfo->getName());
-	mapDescription->setText(mapInfo->getDescription());
+	mapName->setText(mapInfo->getNameTranslated());
+	mapDescription->setText(mapInfo->getDescriptionTranslated());
 
 	mapDescription->label->scrollTextTo(0, false);
 	if(mapDescription->slider)

+ 2 - 2
client/lobby/RandomMapTab.cpp

@@ -163,8 +163,8 @@ void RandomMapTab::updateMapInfoByHost()
 	mapInfo->isRandomMap = true;
 	mapInfo->mapHeader = std::make_unique<CMapHeader>();
 	mapInfo->mapHeader->version = EMapFormat::VCMI;
-	mapInfo->mapHeader->name = CGI->generaltexth->allTexts[740];
-	mapInfo->mapHeader->description = CGI->generaltexth->allTexts[741];
+	mapInfo->mapHeader->name.appendLocalString(EMetaText::GENERAL_TXT, 740);
+	mapInfo->mapHeader->description.appendLocalString(EMetaText::GENERAL_TXT, 741);
 	mapInfo->mapHeader->difficulty = 1; // Normal
 	mapInfo->mapHeader->height = mapGenOptions->getHeight();
 	mapInfo->mapHeader->width = mapGenOptions->getWidth();

+ 5 - 5
client/lobby/SelectionTab.cpp

@@ -111,11 +111,11 @@ bool mapSorter::operator()(const std::shared_ptr<ElementInfo> aaa, const std::sh
 			return (a->victoryIconIndex < b->victoryIconIndex);
 			break;
 		case _name: //by name
-			return boost::ilexicographical_compare(a->name, b->name);
+			return boost::ilexicographical_compare(a->name.toString(), b->name.toString());
 		case _fileName: //by filename
 			return boost::ilexicographical_compare(aaa->fileURI, bbb->fileURI);
 		default:
-			return boost::ilexicographical_compare(a->name, b->name);
+			return boost::ilexicographical_compare(a->name.toString(), b->name.toString());
 		}
 	}
 	else //if we are sorting campaigns
@@ -125,9 +125,9 @@ bool mapSorter::operator()(const std::shared_ptr<ElementInfo> aaa, const std::sh
 		case _numOfMaps: //by number of maps in campaign
 			return aaa->campaign->scenariosCount() < bbb->campaign->scenariosCount();
 		case _name: //by name
-			return boost::ilexicographical_compare(aaa->campaign->getName(), bbb->campaign->getName());
+			return boost::ilexicographical_compare(aaa->campaign->getNameTranslated(), bbb->campaign->getNameTranslated());
 		default:
-			return boost::ilexicographical_compare(aaa->campaign->getName(), bbb->campaign->getName());
+			return boost::ilexicographical_compare(aaa->campaign->getNameTranslated(), bbb->campaign->getNameTranslated());
 		}
 	}
 }
@@ -367,7 +367,7 @@ void SelectionTab::showPopupWindow(const Point & cursorPosition)
 
 	if(!curItems[py]->isFolder)
 	{
-		std::string text = boost::str(boost::format("{%1%}\r\n\r\n%2%:\r\n%3%") % curItems[py]->getName() % CGI->generaltexth->translate("vcmi.lobby.filename") % curItems[py]->fullFileURI);
+		std::string text = boost::str(boost::format("{%1%}\r\n\r\n%2%:\r\n%3%") % curItems[py]->getNameTranslated() % CGI->generaltexth->translate("vcmi.lobby.filename") % curItems[py]->fullFileURI);
 		if(curItems[py]->date != "")
 			text += boost::str(boost::format("\r\n\r\n%1%:\r\n%2%") % CGI->generaltexth->translate("vcmi.lobby.creationDate") % curItems[py]->date);
 

+ 1 - 1
client/mainmenu/CCampaignScreen.cpp

@@ -105,7 +105,7 @@ CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config, const
 	status = CCampaignScreen::ENABLED;
 
 	auto header = CampaignHandler::getHeader(campFile);
-	hoverText = header->getName();
+	hoverText = header->getNameTranslated();
 
 	if(persistentStorage["completedCampaigns"][header->getFilename()].Bool())
 		status = CCampaignScreen::COMPLETED;

+ 2 - 2
lib/StartInfo.cpp

@@ -62,8 +62,8 @@ PlayerSettings * StartInfo::getPlayersSettings(const ui8 connectedPlayerId)
 
 std::string StartInfo::getCampaignName() const
 {
-	if(!campState->getName().empty())
-		return campState->getName();
+	if(!campState->getNameTranslated().empty())
+		return campState->getNameTranslated();
 	else
 		return VLC->generaltexth->allTexts[508];
 }

+ 5 - 5
lib/campaign/CampaignHandler.cpp

@@ -134,7 +134,7 @@ std::string CampaignHandler::readLocalizedString(CBinaryReader & reader, std::st
 		return "";
 
 	VLC->generaltexth->registerString(modName, stringID, input);
-	return VLC->generaltexth->translate(stringID.get());
+	return stringID.get();
 }
 
 void CampaignHandler::readHeaderFromJson(CampaignHeader & ret, JsonNode & reader, std::string filename, std::string modName, std::string encoding)
@@ -149,8 +149,8 @@ void CampaignHandler::readHeaderFromJson(CampaignHeader & ret, JsonNode & reader
 	ret.version = CampaignVersion::VCMI;
 	ret.campaignRegions = CampaignRegions::fromJson(reader["regions"]);
 	ret.numberOfScenarios = reader["scenarios"].Vector().size();
-	ret.name = reader["name"].String();
-	ret.description = reader["description"].String();
+	ret.name.appendTextID(reader["name"].String());
+	ret.description.appendTextID(reader["description"].String());
 	ret.difficultyChoosenByPlayer = reader["allowDifficultySelection"].Bool();
 	ret.music = AudioPath::fromJson(reader["music"]);
 	ret.filename = filename;
@@ -383,8 +383,8 @@ void CampaignHandler::readHeaderFromMemory( CampaignHeader & ret, CBinaryReader
 	ret.version = static_cast<CampaignVersion>(reader.readUInt32());
 	ui8 campId = reader.readUInt8() - 1;//change range of it from [1, 20] to [0, 19]
 	ret.loadLegacyData(campId);
-	ret.name = readLocalizedString(reader, filename, modName, encoding, "name");
-	ret.description = readLocalizedString(reader, filename, modName, encoding, "description");
+	ret.name.appendTextID(readLocalizedString(reader, filename, modName, encoding, "name"));
+	ret.description.appendTextID(readLocalizedString(reader, filename, modName, encoding, "description"));
 	if (ret.version > CampaignVersion::RoE)
 		ret.difficultyChoosenByPlayer = reader.readInt8();
 	else

+ 5 - 5
lib/campaign/CampaignState.cpp

@@ -134,14 +134,14 @@ bool CampaignHeader::formatVCMI() const
 	return version == CampaignVersion::VCMI;
 }
 
-std::string CampaignHeader::getDescription() const
+std::string CampaignHeader::getDescriptionTranslated() const
 {
-	return description;
+	return description.toString();
 }
 
-std::string CampaignHeader::getName() const
+std::string CampaignHeader::getNameTranslated() const
 {
-	return name;
+	return name.toString();
 }
 
 std::string CampaignHeader::getFilename() const
@@ -267,7 +267,7 @@ void CampaignState::setCurrentMapAsConquered(std::vector<CGHeroInstance *> heroe
 		return a->getHeroStrength() > b->getHeroStrength();
 	});
 
-	logGlobal->info("Scenario %d of campaign %s (%s) has been completed", static_cast<int>(*currentMap), getFilename(), getName());
+	logGlobal->info("Scenario %d of campaign %s (%s) has been completed", static_cast<int>(*currentMap), getFilename(), getNameTranslated());
 
 	mapsConquered.push_back(*currentMap);
 	auto reservedHeroes = getReservedHeroes();

+ 6 - 5
lib/campaign/CampaignState.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include "../lib/GameConstants.h"
+#include "../lib/MetaString.h"
 #include "../lib/filesystem/ResourcePath.h"
 #include "CampaignConstants.h"
 #include "CampaignScenarioPrologEpilog.h"
@@ -74,8 +75,8 @@ class DLL_LINKAGE CampaignHeader : public boost::noncopyable
 
 	CampaignVersion version = CampaignVersion::NONE;
 	CampaignRegions campaignRegions;
-	std::string name;
-	std::string description;
+	MetaString name;
+	MetaString description;
 	AudioPath music;
 	std::string filename;
 	std::string modName;
@@ -90,8 +91,8 @@ public:
 	bool playerSelectedDifficulty() const;
 	bool formatVCMI() const;
 
-	std::string getDescription() const;
-	std::string getName() const;
+	std::string getDescriptionTranslated() const;
+	std::string getNameTranslated() const;
 	std::string getFilename() const;
 	std::string getModName() const;
 	std::string getEncoding() const;
@@ -176,7 +177,7 @@ struct DLL_LINKAGE CampaignTravel
 struct DLL_LINKAGE CampaignScenario
 {
 	std::string mapName; //*.h3m
-	std::string scenarioName; //from header. human-readble
+	MetaString scenarioName; //from header
 	std::set<CampaignScenarioID> preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c)
 	ui8 regionColor = 0;
 	ui8 difficulty = 0;

+ 0 - 5
lib/mapObjects/CGHeroInstance.cpp

@@ -1030,8 +1030,6 @@ si32 CGHeroInstance::manaLimit() const
 
 std::string CGHeroInstance::getNameTranslated() const
 {
-	if (!nameCustom.empty())
-		return nameCustom;
 	return VLC->generaltexth->translate(getNameTextID());
 }
 
@@ -1049,9 +1047,6 @@ std::string CGHeroInstance::getNameTextID() const
 
 std::string CGHeroInstance::getBiographyTranslated() const
 {
-	if (!biographyCustom.empty())
-		return biographyCustom;
-
 	return VLC->generaltexth->translate(getBiographyTextID());
 }
 

+ 2 - 2
lib/mapping/CMapHeader.h

@@ -223,8 +223,8 @@ public:
 	si32 height; /// The default value is 72.
 	si32 width; /// The default value is 72.
 	bool twoLevel; /// The default value is true.
-	std::string name;
-	std::string description;
+	MetaString name;
+	MetaString description;
 	ui8 difficulty; /// The default value is 1 representing a normal map difficulty.
 	/// Specifies the maximum level to reach for a hero. A value of 0 states that there is no
 	///	maximum level for heroes. This is the default value.

+ 9 - 9
lib/mapping/CMapInfo.cpp

@@ -100,12 +100,12 @@ void CMapInfo::countPlayers()
 				amountOfHumanPlayersInSave++;
 }
 
-std::string CMapInfo::getName() const
+std::string CMapInfo::getNameTranslated() const
 {
-	if(campaign && !campaign->getName().empty())
-		return campaign->getName();
-	else if(mapHeader && mapHeader->name.length())
-		return mapHeader->name;
+	if(campaign && !campaign->getNameTranslated().empty())
+		return campaign->getNameTranslated();
+	else if(mapHeader && !mapHeader->name.empty())
+		return mapHeader->name.toString();
 	else
 		return VLC->generaltexth->allTexts[508];
 }
@@ -121,16 +121,16 @@ std::string CMapInfo::getNameForList() const
 	}
 	else
 	{
-		return getName();
+		return getNameTranslated();
 	}
 }
 
-std::string CMapInfo::getDescription() const
+std::string CMapInfo::getDescriptionTranslated() const
 {
 	if(campaign)
-		return campaign->getDescription();
+		return campaign->getDescriptionTranslated();
 	else
-		return mapHeader->description;
+		return mapHeader->description.toString();
 }
 
 int CMapInfo::getMapSizeIconId() const

+ 2 - 2
lib/mapping/CMapInfo.h

@@ -50,9 +50,9 @@ public:
 	void campaignInit();
 	void countPlayers();
 	// TODO: Those must be on client-side
-	std::string getName() const;
+	std::string getNameTranslated() const;
 	std::string getNameForList() const;
-	std::string getDescription() const;
+	std::string getDescriptionTranslated() const;
 	int getMapSizeIconId() const;
 	int getMapSizeFormatIconId() const;
 	std::string getMapSizeName() const;

+ 3 - 3
lib/mapping/MapFormatH3M.cpp

@@ -180,8 +180,8 @@ void CMapLoaderH3M::readHeader()
 	mapHeader->areAnyPlayers = reader->readBool();
 	mapHeader->height = mapHeader->width = reader->readInt32();
 	mapHeader->twoLevel = reader->readBool();
-	mapHeader->name = readLocalizedString("header.name");
-	mapHeader->description = readLocalizedString("header.description");
+	mapHeader->name.appendTextID(readLocalizedString("header.name"));
+	mapHeader->description.appendTextID(readLocalizedString("header.description"));
 	mapHeader->difficulty = reader->readInt8();
 
 	if(features.levelAB)
@@ -2275,7 +2275,7 @@ std::string CMapLoaderH3M::readLocalizedString(const TextIdentifier & stringIden
 		return "";
 
 	VLC->generaltexth->registerString(modName, fullIdentifier, mapString);
-	return VLC->generaltexth->translate(fullIdentifier.get());
+	return fullIdentifier.get();
 }
 
 void CMapLoaderH3M::afterRead()

+ 2 - 2
lib/mapping/MapFormatJson.cpp

@@ -413,8 +413,8 @@ void CMapFormatJson::serializeAllowedFactions(JsonSerializeFormat & handler, std
 
 void CMapFormatJson::serializeHeader(JsonSerializeFormat & handler)
 {
-	handler.serializeString("name", mapHeader->name);
-	handler.serializeString("description", mapHeader->description);
+	handler.serializeStruct("name", mapHeader->name);
+	handler.serializeStruct("description", mapHeader->description);
 	handler.serializeInt("heroLevelLimit", mapHeader->levelLimit, 0);
 
 	//todo: support arbitrary percentage

+ 2 - 2
lib/rmg/CMapGenerator.cpp

@@ -407,8 +407,8 @@ void CMapGenerator::addHeaderInfo()
 	m.width = mapGenOptions.getWidth();
 	m.height = mapGenOptions.getHeight();
 	m.twoLevel = mapGenOptions.getHasTwoLevels();
-	m.name = VLC->generaltexth->allTexts[740];
-	m.description = getMapDescription();
+	m.name.appendLocalString(EMetaText::GENERAL_TXT, 740);
+	m.description.appendRawString(getMapDescription());
 	m.difficulty = 1;
 	addPlayerInfo();
 	m.waterMap = (mapGenOptions.getWaterContent() != EWaterContent::EWaterContent::NONE);