Pārlūkot izejas kodu

Renamed MetaString methods to more logical names

Ivan Savenko 2 gadi atpakaļ
vecāks
revīzija
56d69e790b

+ 6 - 7
client/CPlayerInterface.cpp

@@ -270,14 +270,14 @@ void CPlayerInterface::acceptTurn()
 			auto daysWithoutCastle = optDaysWithoutCastle.value();
 			if (daysWithoutCastle < 6)
 			{
-				text.addTxt(MetaString::ARRAY_TXT,128); //%s, you only have %d days left to capture a town or you will be banished from this land.
-				text.addReplacement(MetaString::COLOR, playerColor.getNum());
-				text.addReplacement(7 - daysWithoutCastle);
+				text.appendLocalString(EMetaText::ARRAY_TXT,128); //%s, you only have %d days left to capture a town or you will be banished from this land.
+				text.replaceLocalString(EMetaText::COLOR, playerColor.getNum());
+				text.replaceNumber(7 - daysWithoutCastle);
 			}
 			else if (daysWithoutCastle == 6)
 			{
-				text.addTxt(MetaString::ARRAY_TXT,129); //%s, this is your last day to capture a town or you will be banished from this land.
-				text.addReplacement(MetaString::COLOR, playerColor.getNum());
+				text.appendLocalString(EMetaText::ARRAY_TXT,129); //%s, this is your last day to capture a town or you will be banished from this land.
+				text.replaceLocalString(EMetaText::COLOR, playerColor.getNum());
 			}
 
 			showInfoDialogAndWait(components, text);
@@ -1048,8 +1048,7 @@ void CPlayerInterface::showInfoDialogAndWait(std::vector<Component> & components
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 
-	std::string str;
-	text.toString(str);
+	std::string str = text.toString();
 
 	showInfoDialog(EInfoWindowMode::MODAL, str, components, 0);
 	waitWhileDialog();

+ 2 - 4
client/NetPacksClient.cpp

@@ -600,8 +600,7 @@ void ApplyFirstClientNetPackVisitor::visitGiveHero(GiveHero & pack)
 
 void ApplyClientNetPackVisitor::visitInfoWindow(InfoWindow & pack)
 {
-	std::string str;
-	pack.text.toString(str);
+	std::string str = pack.text.toString();
 
 	if(!callInterfaceIfPresent(cl, pack.player, &CGameInterface::showInfoDialog, pack.type, str, pack.components,(soundBase::soundID)pack.soundID))
 		logNetwork->warn("We received InfoWindow for not our player...");
@@ -643,8 +642,7 @@ void ApplyClientNetPackVisitor::visitCommanderLevelUp(CommanderLevelUp & pack)
 
 void ApplyClientNetPackVisitor::visitBlockingDialog(BlockingDialog & pack)
 {
-	std::string str;
-	pack.text.toString(str);
+	std::string str = pack.text.toString();
 
 	if(!callOnlyThatInterface(cl, pack.player, &CGameInterface::showBlockingDialog, str, pack.components, pack.queryID, (soundBase::soundID)pack.soundID, pack.selection(), pack.cancel()))
 		logNetwork->warn("We received YesNoDialog for not our player...");

+ 4 - 4
client/windows/CQuestLog.cpp

@@ -167,12 +167,12 @@ void CQuestLog::recreateLabelList()
 			if (auto seersHut = dynamic_cast<const CGSeerHut *>(quests[i].obj))
 			{
 				MetaString toSeer;
-				toSeer.addRawString(VLC->generaltexth->allTexts[347]);
-				toSeer.addReplacement(seersHut->seerName);
-				text.addReplacement(toSeer.toString());
+				toSeer.appendRawString(VLC->generaltexth->allTexts[347]);
+				toSeer.replaceRawString(seersHut->seerName);
+				text.replaceRawString(toSeer.toString());
 			}
 			else
-				text.addReplacement(quests[i].obj->getObjectName()); //get name of the object
+				text.replaceRawString(quests[i].obj->getObjectName()); //get name of the object
 		}
 		auto label = std::make_shared<CQuestLabel>(Rect(13, 195, 149,31), FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, text.toString());
 		label->disable();

+ 161 - 139
lib/MetaString.cpp

@@ -1,5 +1,5 @@
 /*
- * CGameState.cpp, part of VCMI engine
+ * MetaString.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -22,176 +22,202 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-void MetaString::getLocalString(const std::pair<ui8, ui32> & txt, std::string & dst) const
+void MetaString::appendLocalString(EMetaText type, ui32 serial)
 {
-	int type = txt.first;
+	message.push_back(EMessage::APPEND_LOCAL_STRING);
+	localStrings.emplace_back(type, serial);
+}
+
+void MetaString::appendRawString(std::string value)
+{
+	message.push_back(EMessage::APPEND_RAW_STRING);
+	exactStrings.push_back(value);
+}
+
+void MetaString::appendNumber(int64_t value)
+{
+	message.push_back(EMessage::APPEND_NUMBER);
+	numbers.push_back(value);
+}
+
+void MetaString::replaceLocalString(EMetaText type, ui32 serial)
+{
+	message.push_back(EMessage::REPLACE_LOCAL_STRING);
+	localStrings.emplace_back(type, serial);
+}
+
+void MetaString::replaceRawString(const std::string &txt)
+{
+	message.push_back(EMessage::REPLACE_RAW_STRING);
+	exactStrings.push_back(txt);
+}
+
+void MetaString::replaceNumber(int64_t txt)
+{
+	message.push_back(EMessage::REPLACE_NUMBER);
+	numbers.push_back(txt);
+}
+
+void MetaString::replacePositiveNumber(int64_t txt)
+{
+	message.push_back(EMessage::REPLACE_POSITIVE_NUMBER);
+	numbers.push_back(txt);
+}
+
+void MetaString::clear()
+{
+	exactStrings.clear();
+	localStrings.clear();
+	message.clear();
+	numbers.clear();
+}
+
+bool MetaString::empty() const
+{
+	return message.empty();
+}
+
+std::string MetaString::getLocalString(const std::pair<EMetaText, ui32> & txt) const
+{
+	EMetaText type = txt.first;
 	int ser = txt.second;
 
-	if(type == ART_NAMES)
-	{
-		const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
-		if(art)
-			dst = art->getNameTranslated();
-		else
-			dst = "#!#";
-	}
-	else if(type == ART_DESCR)
-	{
-		const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
-		if(art)
-			dst = art->getDescriptionTranslated();
-		else
-			dst = "#!#";
-	}
-	else if (type == ART_EVNTS)
-	{
-		const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
-		if(art)
-			dst = art->getEventTranslated();
-		else
-			dst = "#!#";
-	}
-	else if(type == CRE_PL_NAMES)
-	{
-		const auto * cre = CreatureID(ser).toCreature(VLC->creatures());
-		if(cre)
-			dst = cre->getNamePluralTranslated();
-		else
-			dst = "#!#";
-	}
-	else if(type == CRE_SING_NAMES)
-	{
-		const auto * cre = CreatureID(ser).toCreature(VLC->creatures());
-		if(cre)
-			dst = cre->getNameSingularTranslated();
-		else
-			dst = "#!#";
-	}
-	else if(type == MINE_NAMES)
-	{
-		dst = VLC->generaltexth->translate("core.minename", ser);
-	}
-	else if(type == MINE_EVNTS)
-	{
-		dst = VLC->generaltexth->translate("core.mineevnt", ser);
-	}
-	else if(type == SPELL_NAME)
-	{
-		const auto * spell = SpellID(ser).toSpell(VLC->spells());
-		if(spell)
-			dst = spell->getNameTranslated();
-		else
-			dst = "#!#";
-	}
-	else if(type == OBJ_NAMES)
-	{
-		dst = VLC->objtypeh->getObjectName(ser, 0);
-	}
-	else if(type == SEC_SKILL_NAME)
+	switch(type)
 	{
-		dst = VLC->skillh->getByIndex(ser)->getNameTranslated();
-	}
-	else
-	{
-		switch(type)
+		case EMetaText::ART_NAMES:
 		{
-		case GENERAL_TXT:
-			dst = VLC->generaltexth->translate("core.genrltxt", ser);
-			break;
-		case RES_NAMES:
-			dst = VLC->generaltexth->translate("core.restypes", ser);
-			break;
-		case ARRAY_TXT:
-			dst = VLC->generaltexth->translate("core.arraytxt", ser);
-			break;
-		case CREGENS:
-			dst = VLC->objtypeh->getObjectName(Obj::CREATURE_GENERATOR1, ser);
-			break;
-		case CREGENS4:
-			dst = VLC->objtypeh->getObjectName(Obj::CREATURE_GENERATOR4, ser);
-			break;
-		case ADVOB_TXT:
-			dst = VLC->generaltexth->translate("core.advevent", ser);
-			break;
-		case COLOR:
-			dst = VLC->generaltexth->translate("vcmi.capitalColors", ser);
-			break;
-		case JK_TXT:
-			dst = VLC->generaltexth->translate("core.jktext", ser);
-			break;
-		default:
-			logGlobal->error("Failed string substitution because type is %d", type);
-			dst = "#@#";
-			return;
+			const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
+			if(art)
+				return art->getNameTranslated();
+			return "#!#";
+		}
+		case EMetaText::ART_DESCR:
+		{
+			const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
+			if(art)
+				return art->getDescriptionTranslated();
+			return "#!#";
+		}
+		case EMetaText::ART_EVNTS:
+		{
+			const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
+			if(art)
+				return art->getEventTranslated();
+			return "#!#";
+		}
+		case EMetaText::CRE_PL_NAMES:
+		{
+			const auto * cre = CreatureID(ser).toCreature(VLC->creatures());
+			if(cre)
+				return cre->getNamePluralTranslated();
+			return "#!#";
+		}
+		case EMetaText::CRE_SING_NAMES:
+		{
+			const auto * cre = CreatureID(ser).toCreature(VLC->creatures());
+			if(cre)
+				return cre->getNameSingularTranslated();
+			return "#!#";
+		}
+		case EMetaText::MINE_NAMES:
+		{
+			return VLC->generaltexth->translate("core.minename", ser);
+		}
+		case EMetaText::MINE_EVNTS:
+		{
+			return VLC->generaltexth->translate("core.mineevnt", ser);
+		}
+		case EMetaText::SPELL_NAME:
+		{
+			const auto * spell = SpellID(ser).toSpell(VLC->spells());
+			if(spell)
+				return spell->getNameTranslated();
+			return "#!#";
 		}
+		case EMetaText::OBJ_NAMES:
+			return VLC->objtypeh->getObjectName(ser, 0);
+		case EMetaText::SEC_SKILL_NAME:
+			return VLC->skillh->getByIndex(ser)->getNameTranslated();
+		case EMetaText::GENERAL_TXT:
+			return VLC->generaltexth->translate("core.genrltxt", ser);
+		case EMetaText::RES_NAMES:
+			return VLC->generaltexth->translate("core.restypes", ser);
+		case EMetaText::ARRAY_TXT:
+			return VLC->generaltexth->translate("core.arraytxt", ser);
+		case EMetaText::CREGENS:
+			return VLC->objtypeh->getObjectName(Obj::CREATURE_GENERATOR1, ser);
+		case EMetaText::CREGENS4:
+			return VLC->objtypeh->getObjectName(Obj::CREATURE_GENERATOR4, ser);
+		case EMetaText::ADVOB_TXT:
+			return VLC->generaltexth->translate("core.advevent", ser);
+		case EMetaText::COLOR:
+			return VLC->generaltexth->translate("vcmi.capitalColors", ser);
+		case EMetaText::JK_TXT:
+			return VLC->generaltexth->translate("core.jktext", ser);
+		default:
+			logGlobal->error("Failed string substitution because type is %d", static_cast<int>(type));
+			return "#@#";
 	}
 }
 
-DLL_LINKAGE void MetaString::toString(std::string &dst) const
+DLL_LINKAGE std::string MetaString::toString() const
 {
+	std::string dst;
+
 	size_t exSt = 0;
 	size_t loSt = 0;
 	size_t nums = 0;
 	dst.clear();
 
 	for(const auto & elem : message)
-	{//TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER
+	{
 		switch(elem)
 		{
-		case TEXACT_STRING:
+		case EMessage::APPEND_RAW_STRING:
 			dst += exactStrings[exSt++];
 			break;
-		case TLOCAL_STRING:
+		case EMessage::APPEND_LOCAL_STRING:
 			{
-				std::string hlp;
-				getLocalString(localStrings[loSt++], hlp);
+				std::string hlp = getLocalString(localStrings[loSt++]);
 				dst += hlp;
 			}
 			break;
-		case TNUMBER:
+		case EMessage::APPEND_NUMBER:
 			dst += std::to_string(numbers[nums++]);
 			break;
-		case TREPLACE_ESTRING:
+		case EMessage::REPLACE_RAW_STRING:
 			boost::replace_first(dst, "%s", exactStrings[exSt++]);
 			break;
-		case TREPLACE_LSTRING:
+		case EMessage::REPLACE_LOCAL_STRING:
 			{
-				std::string hlp;
-				getLocalString(localStrings[loSt++], hlp);
+				std::string hlp = getLocalString(localStrings[loSt++]);
 				boost::replace_first(dst, "%s", hlp);
 			}
 			break;
-		case TREPLACE_NUMBER:
+		case EMessage::REPLACE_NUMBER:
 			boost::replace_first(dst, "%d", std::to_string(numbers[nums++]));
 			break;
-		case TREPLACE_PLUSNUMBER:
+		case EMessage::REPLACE_POSITIVE_NUMBER:
 			boost::replace_first(dst, "%+d", '+' + std::to_string(numbers[nums++]));
 			break;
 		default:
-			logGlobal->error("MetaString processing error! Received message of type %d", int(elem));
+			logGlobal->error("MetaString processing error! Received message of type %d", static_cast<int>(elem));
+			assert(0);
 			break;
 		}
 	}
-}
-
-DLL_LINKAGE std::string MetaString::toString() const
-{
-	std::string ret;
-	toString(ret);
-	return ret;
+	return dst;
 }
 
 DLL_LINKAGE std::string MetaString::buildList () const
-///used to handle loot from creature bank
 {
-
 	size_t exSt = 0;
 	size_t loSt = 0;
 	size_t nums = 0;
 	std::string lista;
 	for (int i = 0; i < message.size(); ++i)
 	{
-		if (i > 0 && (message[i] == TEXACT_STRING || message[i] == TLOCAL_STRING))
+		if (i > 0 && (message[i] == EMessage::APPEND_RAW_STRING || message[i] == EMessage::APPEND_LOCAL_STRING))
 		{
 			if (exSt == exactStrings.size() - 1)
 				lista += VLC->generaltexth->allTexts[141]; //" and "
@@ -200,30 +226,28 @@ DLL_LINKAGE std::string MetaString::buildList () const
 		}
 		switch (message[i])
 		{
-			case TEXACT_STRING:
+			case EMessage::APPEND_RAW_STRING:
 				lista += exactStrings[exSt++];
 				break;
-			case TLOCAL_STRING:
+			case EMessage::APPEND_LOCAL_STRING:
 			{
-				std::string hlp;
-				getLocalString (localStrings[loSt++], hlp);
+				std::string hlp = getLocalString (localStrings[loSt++]);
 				lista += hlp;
 			}
 				break;
-			case TNUMBER:
+			case EMessage::APPEND_NUMBER:
 				lista += std::to_string(numbers[nums++]);
 				break;
-			case TREPLACE_ESTRING:
+			case EMessage::REPLACE_RAW_STRING:
 				lista.replace (lista.find("%s"), 2, exactStrings[exSt++]);
 				break;
-			case TREPLACE_LSTRING:
+			case EMessage::REPLACE_LOCAL_STRING:
 			{
-				std::string hlp;
-				getLocalString (localStrings[loSt++], hlp);
+				std::string hlp = getLocalString (localStrings[loSt++]);
 				lista.replace (lista.find("%s"), 2, hlp);
 			}
 				break;
-			case TREPLACE_NUMBER:
+			case EMessage::REPLACE_NUMBER:
 				lista.replace (lista.find("%d"), 2, std::to_string(numbers[nums++]));
 				break;
 			default:
@@ -234,20 +258,18 @@ DLL_LINKAGE std::string MetaString::buildList () const
 	return lista;
 }
 
-void MetaString::addCreReplacement(const CreatureID & id, TQuantity count) //adds sing or plural name;
+void MetaString::replaceCreatureName(const CreatureID & id, TQuantity count) //adds sing or plural name;
 {
-	if (!count)
-		addReplacement (CRE_PL_NAMES, id); //no creatures - just empty name (eg. defeat Angels)
-	else if (count == 1)
-		addReplacement (CRE_SING_NAMES, id);
+	if (count == 1)
+		replaceLocalString (EMetaText::CRE_SING_NAMES, id);
 	else
-		addReplacement (CRE_PL_NAMES, id);
+		replaceLocalString (EMetaText::CRE_PL_NAMES, id);
 }
 
-void MetaString::addReplacement(const CStackBasicDescriptor & stack)
+void MetaString::replaceCreatureName(const CStackBasicDescriptor & stack)
 {
 	assert(stack.type); //valid type
-	addCreReplacement(stack.type->getId(), stack.count);
+	replaceCreatureName(stack.type->getId(), stack.count);
 }
 
 VCMI_LIB_NAMESPACE_END

+ 70 - 55
lib/MetaString.h

@@ -15,20 +15,84 @@ class CreatureID;
 class CStackBasicDescriptor;
 using TQuantity = si32;
 
+enum class EMetaText : uint8_t
+{
+	GENERAL_TXT = 1,
+	OBJ_NAMES,
+	RES_NAMES,
+	ART_NAMES,
+	ARRAY_TXT,
+	CRE_PL_NAMES,
+	CREGENS,
+	MINE_NAMES,
+	MINE_EVNTS,
+	ADVOB_TXT,
+	ART_EVNTS,
+	SPELL_NAME,
+	SEC_SKILL_NAME,
+	CRE_SING_NAMES,
+	CREGENS4,
+	COLOR,
+	ART_DESCR,
+	JK_TXT
+};
+
 class DLL_LINKAGE MetaString
 {
 private:
-	enum EMessage {TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER, TREPLACE_PLUSNUMBER};
-public:
-	enum {GENERAL_TXT=1, OBJ_NAMES, RES_NAMES, ART_NAMES, ARRAY_TXT, CRE_PL_NAMES, CREGENS, MINE_NAMES,
-		MINE_EVNTS, ADVOB_TXT, ART_EVNTS, SPELL_NAME, SEC_SKILL_NAME, CRE_SING_NAMES, CREGENS4, COLOR, ART_DESCR, JK_TXT};
+	enum class EMessage : uint8_t
+	{
+		APPEND_RAW_STRING,
+		APPEND_LOCAL_STRING,
+		APPEND_NUMBER,
+		REPLACE_RAW_STRING,
+		REPLACE_LOCAL_STRING,
+		REPLACE_NUMBER,
+		REPLACE_POSITIVE_NUMBER
+	};
 
-	std::vector<ui8> message; //vector of EMessage
+	std::vector<EMessage> message;
 
-	std::vector<std::pair<ui8,ui32> > localStrings;
+	std::vector<std::pair<EMetaText,ui32> > localStrings;
 	std::vector<std::string> exactStrings;
 	std::vector<int64_t> numbers;
 
+	std::string getLocalString(const std::pair<EMetaText, ui32> & txt) const;
+
+public:
+	/// Appends local string to resulting string
+	void appendLocalString(EMetaText type, ui32 serial);
+	/// Appends raw string, without translation to resulting string
+	void appendRawString(std::string value);
+	/// Appends specified number to resulting string
+	void appendNumber(int64_t value);
+
+	/// Replaces first '%s' placeholder in string with specified local string
+	void replaceLocalString(EMetaText type, ui32 serial);
+	/// Replaces first '%s' placeholder in string with specified fixed, untranslated string
+	void replaceRawString(const std::string &txt);
+	/// Replaces first '%d' placeholder in string with specified number
+	void replaceNumber(int64_t txt);
+	/// Replaces first '%+d' placeholder in string with specified number using '+' sign as prefix
+	void replacePositiveNumber(int64_t txt);
+
+	/// Replaces first '%s' placeholder with singular or plural name depending on creatures count
+	void replaceCreatureName(const CreatureID & id, TQuantity count);
+	/// Replaces first '%s' placeholder with singular or plural name depending on creatures count
+	void replaceCreatureName(const CStackBasicDescriptor &stack);
+
+	/// erases any existing content in the string
+	void clear();
+
+	///used to handle loot from creature bank
+	std::string buildList () const;
+
+	/// Convert all stored values into a single, user-readable string
+	std::string toString() const;
+
+	/// Returns true if current string is empty
+	bool empty() const;
+
 	template <typename Handler> void serialize(Handler & h, const int version)
 	{
 		h & exactStrings;
@@ -36,55 +100,6 @@ public:
 		h & message;
 		h & numbers;
 	}
-	void addTxt(ui8 type, ui32 serial)
-	{
-		message.push_back(TLOCAL_STRING);
-		localStrings.emplace_back(type, serial);
-	}
-	void addRawString(std::string value)
-	{
-		message.push_back(TEXACT_STRING);
-		exactStrings.push_back(value);
-	}
-	void appendNumber(int64_t value)
-	{
-		message.push_back(TNUMBER);
-		numbers.push_back(value);
-	}
-	void addReplacement(ui8 type, ui32 serial)
-	{
-		message.push_back(TREPLACE_LSTRING);
-		localStrings.emplace_back(type, serial);
-	}
-	void addReplacement(const std::string &txt)
-	{
-		message.push_back(TREPLACE_ESTRING);
-		exactStrings.push_back(txt);
-	}
-	void addReplacement(int64_t txt)
-	{
-		message.push_back(TREPLACE_NUMBER);
-		numbers.push_back(txt);
-	}
-	void addReplacement2(int64_t txt)
-	{
-		message.push_back(TREPLACE_PLUSNUMBER);
-		numbers.push_back(txt);
-	}
-	void addCreReplacement(const CreatureID & id, TQuantity count); //adds sing or plural name;
-	void addReplacement(const CStackBasicDescriptor &stack); //adds sing or plural name;
-	std::string buildList () const;
-	void clear()
-	{
-		exactStrings.clear();
-		localStrings.clear();
-		message.clear();
-		numbers.clear();
-	}
-	void toString(std::string &dst) const;
-	std::string toString() const;
-	void getLocalString(const std::pair<ui8, ui32> & txt, std::string & dst) const;
-
 };
 
 VCMI_LIB_NAMESPACE_END

+ 3 - 3
lib/NetPacksLib.cpp

@@ -985,7 +985,7 @@ void GiveBonus::applyGs(CGameState *gs)
 
 	std::string &descr = b->description;
 
-	if(bdescr.message.empty() && (bonus.type == BonusType::LUCK || bonus.type == BonusType::MORALE))
+	if(bdescr.empty() && (bonus.type == BonusType::LUCK || bonus.type == BonusType::MORALE))
 	{
 		if (bonus.source == BonusSource::OBJECT)
 		{
@@ -998,12 +998,12 @@ void GiveBonus::applyGs(CGameState *gs)
 		}
 		else
 		{
-			bdescr.toString(descr);
+			descr = bdescr.toString();
 		}
 	}
 	else
 	{
-		bdescr.toString(descr);
+		descr = bdescr.toString();
 	}
 	// Some of(?) versions of H3 use %s here instead of %d. Try to replace both of them
 	boost::replace_first(descr, "%d", std::to_string(std::abs(bonus.val)));

+ 2 - 2
lib/battle/CUnitState.cpp

@@ -482,10 +482,10 @@ void CUnitState::getCasterName(MetaString & text) const
 
 void CUnitState::getCastDescription(const spells::Spell * spell, const std::vector<const Unit *> & attacked, MetaString & text) const
 {
-	text.addTxt(MetaString::GENERAL_TXT, 565);//The %s casts %s
+	text.appendLocalString(EMetaText::GENERAL_TXT, 565);//The %s casts %s
 	//todo: use text 566 for single creature
 	getCasterName(text);
-	text.addReplacement(MetaString::SPELL_NAME, spell->getIndex());
+	text.replaceLocalString(EMetaText::SPELL_NAME, spell->getIndex());
 }
 
 int32_t CUnitState::manaLimit() const

+ 7 - 7
lib/battle/Unit.cpp

@@ -173,7 +173,7 @@ BattleHex Unit::occupiedHex(BattleHex assumedPos, bool twoHex, ui8 side)
 	}
 }
 
-void Unit::addText(MetaString & text, ui8 type, int32_t serial, const boost::logic::tribool & plural) const
+void Unit::addText(MetaString & text, EMetaText type, int32_t serial, const boost::logic::tribool & plural) const
 {
 	if(boost::logic::indeterminate(plural))
 		serial = VLC->generaltexth->pluralText(serial, getCount());
@@ -182,17 +182,17 @@ void Unit::addText(MetaString & text, ui8 type, int32_t serial, const boost::log
 	else
 		serial = VLC->generaltexth->pluralText(serial, 1);
 
-	text.addTxt(type, serial);
+	text.appendLocalString(type, serial);
 }
 
 void Unit::addNameReplacement(MetaString & text, const boost::logic::tribool & plural) const
 {
 	if(boost::logic::indeterminate(plural))
-		text.addCreReplacement(creatureId(), getCount());
+		text.replaceCreatureName(creatureId(), getCount());
 	else if(plural)
-		text.addReplacement(MetaString::CRE_PL_NAMES, creatureIndex());
+		text.replaceLocalString(EMetaText::CRE_PL_NAMES, creatureIndex());
 	else
-		text.addReplacement(MetaString::CRE_SING_NAMES, creatureIndex());
+		text.replaceLocalString(EMetaText::CRE_SING_NAMES, creatureIndex());
 }
 
 std::string Unit::formatGeneralMessage(const int32_t baseTextId) const
@@ -200,8 +200,8 @@ std::string Unit::formatGeneralMessage(const int32_t baseTextId) const
 	const int32_t textId = VLC->generaltexth->pluralText(baseTextId, getCount());
 
 	MetaString text;
-	text.addTxt(MetaString::GENERAL_TXT, textId);
-	text.addCreReplacement(creatureId(), getCount());
+	text.appendLocalString(EMetaText::GENERAL_TXT, textId);
+	text.replaceCreatureName(creatureId(), getCount());
 
 	return text.toString();
 }

+ 2 - 1
lib/battle/Unit.h

@@ -21,6 +21,7 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
+enum class EMetaText : uint8_t;
 class MetaString;
 class JsonNode;
 class JsonSerializeFormat;
@@ -122,7 +123,7 @@ public:
 	static BattleHex occupiedHex(BattleHex assumedPos, bool twoHex, ui8 side);
 
 	///MetaStrings
-	void addText(MetaString & text, ui8 type, int32_t serial, const boost::logic::tribool & plural = boost::logic::indeterminate) const;
+	void addText(MetaString & text, EMetaText type, int32_t serial, const boost::logic::tribool & plural = boost::logic::indeterminate) const;
 	void addNameReplacement(MetaString & text, const boost::logic::tribool & plural = boost::logic::indeterminate) const;
 	std::string formatGeneralMessage(const int32_t baseTextId) const;
 

+ 2 - 2
lib/mapObjectConstructors/ShrineInstanceConstructor.cpp

@@ -26,9 +26,9 @@ void ShrineInstanceConstructor::randomizeObject(CGShrine * shrine, CRandomGenera
 	auto visitTextParameter = parameters["visitText"];
 
 	if (visitTextParameter.isNumber())
-		shrine->visitText.addTxt(MetaString::ADVOB_TXT, static_cast<ui32>(visitTextParameter.Float()));
+		shrine->visitText.appendLocalString(EMetaText::ADVOB_TXT, static_cast<ui32>(visitTextParameter.Float()));
 	else
-		shrine->visitText.addRawString(visitTextParameter.String());
+		shrine->visitText.appendRawString(visitTextParameter.String());
 
 	if(shrine->spell == SpellID::NONE) // shrine has no predefined spell
 	{

+ 26 - 26
lib/mapObjects/CBank.cpp

@@ -123,9 +123,9 @@ void CBank::onHeroVisit(const CGHeroInstance * h) const
 	BlockingDialog bd(true, false);
 	bd.player = h->getOwner();
 	bd.soundID = soundBase::invalid; // Sound is handled in json files, else two sounds are played
-	bd.text.addTxt(MetaString::ADVOB_TXT, banktext);
+	bd.text.appendLocalString(EMetaText::ADVOB_TXT, banktext);
 	if (banktext == 32)
-		bd.text.addReplacement(getObjectName());
+		bd.text.replaceRawString(getObjectName());
 	cb->showBlockingDialog(&bd);
 }
 
@@ -179,15 +179,15 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 			{
 			case Obj::SHIPWRECK:
 				textID = 123;
-				gbonus.bdescr.addRawString(VLC->generaltexth->arraytxt[99]);
+				gbonus.bdescr.appendRawString(VLC->generaltexth->arraytxt[99]);
 				break;
 			case Obj::DERELICT_SHIP:
 				textID = 42;
-				gbonus.bdescr.addRawString(VLC->generaltexth->arraytxt[101]);
+				gbonus.bdescr.appendRawString(VLC->generaltexth->arraytxt[101]);
 				break;
 			case Obj::CRYPT:
 				textID = 120;
-				gbonus.bdescr.addRawString(VLC->generaltexth->arraytxt[98]);
+				gbonus.bdescr.appendRawString(VLC->generaltexth->arraytxt[98]);
 				break;
 			}
 			cb->giveHeroBonus(&gbonus);
@@ -208,12 +208,12 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 		case Obj::CREATURE_BANK:
 		case Obj::DRAGON_UTOPIA:
 		default:
-			iw.text.addRawString(VLC->generaltexth->advobtxt[33]);// This was X, now is completely empty
-			iw.text.addReplacement(getObjectName());
+			iw.text.appendRawString(VLC->generaltexth->advobtxt[33]);// This was X, now is completely empty
+			iw.text.replaceRawString(getObjectName());
 		}
 		if(textID != -1)
 		{
-			iw.text.addTxt(MetaString::ADVOB_TXT, textID);
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT, textID);
 		}
 		cb->showInfoDialog(&iw);
 	}
@@ -227,9 +227,9 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 			if (bc->resources[it] != 0)
 			{
 				iw.components.emplace_back(Component::EComponentType::RESOURCE, it, bc->resources[it], 0);
-				loot.addRawString("%d %s");
-				loot.addReplacement(iw.components.back().val);
-				loot.addReplacement(MetaString::RES_NAMES, iw.components.back().subtype);
+				loot.appendRawString("%d %s");
+				loot.replaceNumber(iw.components.back().val);
+				loot.replaceLocalString(EMetaText::RES_NAMES, iw.components.back().subtype);
 				cb->giveResource(hero->getOwner(), static_cast<EGameResID>(it), bc->resources[it]);
 			}
 		}
@@ -237,14 +237,14 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 		for (auto & elem : bc->artifacts)
 		{
 			iw.components.emplace_back(Component::EComponentType::ARTIFACT, elem, 0, 0);
-			loot.addRawString("%s");
-			loot.addReplacement(MetaString::ART_NAMES, elem);
+			loot.appendRawString("%s");
+			loot.replaceLocalString(EMetaText::ART_NAMES, elem);
 			cb->giveHeroNewArtifact(hero, VLC->arth->objects[elem], ArtifactPosition::FIRST_AVAILABLE);
 		}
 		//display loot
 		if (!iw.components.empty())
 		{
-			iw.text.addTxt(MetaString::ADVOB_TXT, textID);
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT, textID);
 			if (textID == 34)
 			{
 				const auto * strongest = boost::range::max_element(bc->guards, [](const CStackBasicDescriptor & a, const CStackBasicDescriptor & b)
@@ -252,8 +252,8 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 					return a.type->getFightValue() < b.type->getFightValue();
 				})->type;
 
-				iw.text.addReplacement(MetaString::CRE_PL_NAMES, strongest->getId());
-				iw.text.addReplacement(loot.buildList());
+				iw.text.replaceLocalString(EMetaText::CRE_PL_NAMES, strongest->getId());
+				iw.text.replaceRawString(loot.buildList());
 			}
 			cb->showInfoDialog(&iw);
 		}
@@ -269,12 +269,12 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 			bool noWisdom = false;
 			if(textID == 106)
 			{
-				iw.text.addTxt(MetaString::ADVOB_TXT, textID); //pyramid
+				iw.text.appendLocalString(EMetaText::ADVOB_TXT, textID); //pyramid
 			}
 			for(const SpellID & spellId : bc->spells)
 			{
 				const auto * spell = spellId.toSpell(VLC->spells());
-				iw.text.addTxt(MetaString::SPELL_NAME, spellId);
+				iw.text.appendLocalString(EMetaText::SPELL_NAME, spellId);
 				if(spell->getLevel() <= hero->maxSpellLevel())
 				{
 					if(hero->canLearnSpell(spell))
@@ -288,9 +288,9 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 			}
 
 			if (!hero->getArt(ArtifactPosition::SPELLBOOK))
-				iw.text.addTxt(MetaString::ADVOB_TXT, 109); //no spellbook
+				iw.text.appendLocalString(EMetaText::ADVOB_TXT, 109); //no spellbook
 			else if(noWisdom)
-				iw.text.addTxt(MetaString::ADVOB_TXT, 108); //no expert Wisdom
+				iw.text.appendLocalString(EMetaText::ADVOB_TXT, 108); //no expert Wisdom
 
 			if(!iw.components.empty() || !iw.text.toString().empty())
 				cb->showInfoDialog(&iw);
@@ -312,19 +312,19 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 		for(const auto & elem : ourArmy.Slots())
 		{
 			iw.components.emplace_back(*elem.second);
-			loot.addRawString("%s");
-			loot.addReplacement(*elem.second);
+			loot.appendRawString("%s");
+			loot.replaceCreatureName(*elem.second);
 		}
 
 		if(ourArmy.stacksCount())
 		{
 			if(ourArmy.stacksCount() == 1 && ourArmy.Slots().begin()->second->count == 1)
-				iw.text.addTxt(MetaString::ADVOB_TXT, 185);
+				iw.text.appendLocalString(EMetaText::ADVOB_TXT, 185);
 			else
-				iw.text.addTxt(MetaString::ADVOB_TXT, 186);
+				iw.text.appendLocalString(EMetaText::ADVOB_TXT, 186);
 
-			iw.text.addReplacement(loot.buildList());
-			iw.text.addReplacement(hero->getNameTranslated());
+			iw.text.replaceRawString(loot.buildList());
+			iw.text.replaceRawString(hero->getNameTranslated());
 			cb->showInfoDialog(&iw);
 			cb->giveCreatures(this, hero, ourArmy, false);
 		}

+ 21 - 21
lib/mapObjects/CGCreature.cpp

@@ -34,12 +34,12 @@ std::string CGCreature::getHoverText(PlayerColor player) const
 	CCreature::CreatureQuantityId monsterQuantityId = stacks.begin()->second->getQuantityID();
 	int quantityTextIndex = 172 + 3 * (int)monsterQuantityId;
 	if(settings["gameTweaks"]["numericCreaturesQuantities"].Bool())
-		ms.addRawString(CCreature::getQuantityRangeStringForId(monsterQuantityId));
+		ms.appendRawString(CCreature::getQuantityRangeStringForId(monsterQuantityId));
 	else
-		ms.addTxt(MetaString::ARRAY_TXT, quantityTextIndex);
-	ms.addRawString(" ");
-	ms.addTxt(MetaString::CRE_PL_NAMES,subID);
-	ms.toString(hoverName);
+		ms.appendLocalString(EMetaText::ARRAY_TXT, quantityTextIndex);
+	ms.appendRawString(" ");
+	ms.appendLocalString(EMetaText::CRE_PL_NAMES,subID);
+	hoverName = ms.toString();
 	return hoverName;
 }
 
@@ -50,30 +50,30 @@ std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
 	{
 		MetaString ms;
 		ms.appendNumber(stacks.begin()->second->count);
-		ms.addRawString(" ");
-		ms.addTxt(MetaString::CRE_PL_NAMES,subID);
+		ms.appendRawString(" ");
+		ms.appendLocalString(EMetaText::CRE_PL_NAMES,subID);
 
-		ms.addRawString("\n");
+		ms.appendRawString("\n");
 
 		int decision = takenAction(hero, true);
 
 		switch (decision)
 		{
 		case FIGHT:
-			ms.addTxt(MetaString::GENERAL_TXT,246);
+			ms.appendLocalString(EMetaText::GENERAL_TXT,246);
 			break;
 		case FLEE:
-			ms.addTxt(MetaString::GENERAL_TXT,245);
+			ms.appendLocalString(EMetaText::GENERAL_TXT,245);
 			break;
 		case JOIN_FOR_FREE:
-			ms.addTxt(MetaString::GENERAL_TXT,243);
+			ms.appendLocalString(EMetaText::GENERAL_TXT,243);
 			break;
 		default: //decision = cost in gold
-			ms.addRawString(boost::to_string(boost::format(VLC->generaltexth->allTexts[244]) % decision));
+			ms.appendRawString(boost::to_string(boost::format(VLC->generaltexth->allTexts[244]) % decision));
 			break;
 		}
 
-		ms.toString(hoverName);
+		hoverName = ms.toString();
 	}
 	else
 	{
@@ -118,8 +118,8 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
 		{
 			BlockingDialog ynd(true,false);
 			ynd.player = h->tempOwner;
-			ynd.text.addTxt(MetaString::ADVOB_TXT, 86);
-			ynd.text.addReplacement(MetaString::CRE_PL_NAMES, subID);
+			ynd.text.appendLocalString(EMetaText::ADVOB_TXT, 86);
+			ynd.text.replaceLocalString(EMetaText::CRE_PL_NAMES, subID);
 			cb->showBlockingDialog(&ynd);
 			break;
 		}
@@ -134,7 +134,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
 			boost::algorithm::replace_first(tmp, "%d", std::to_string(getStackCount(SlotID(0))));
 			boost::algorithm::replace_first(tmp, "%d", std::to_string(action));
 			boost::algorithm::replace_first(tmp,"%s",VLC->creh->objects[subID]->getNamePluralTranslated());
-			ynd.text.addRawString(tmp);
+			ynd.text.appendRawString(tmp);
 			cb->showBlockingDialog(&ynd);
 			break;
 		}
@@ -324,7 +324,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
 		{
 			InfoWindow iw;
 			iw.player = h->tempOwner;
-			iw.text.addTxt(1,29);  //You don't have enough gold
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT,29);  //You don't have enough gold
 			cb->showInfoDialog(&iw);
 
 			//act as if player refused
@@ -390,8 +390,8 @@ void CGCreature::flee( const CGHeroInstance * h ) const
 {
 	BlockingDialog ynd(true,false);
 	ynd.player = h->tempOwner;
-	ynd.text.addTxt(MetaString::ADVOB_TXT,91);
-	ynd.text.addReplacement(MetaString::CRE_PL_NAMES, subID);
+	ynd.text.appendLocalString(EMetaText::ADVOB_TXT,91);
+	ynd.text.replaceLocalString(EMetaText::CRE_PL_NAMES, subID);
 	cb->showBlockingDialog(&ynd);
 }
 
@@ -529,8 +529,8 @@ void CGCreature::giveReward(const CGHeroInstance * h) const
 	if(!iw.components.empty())
 	{
 		iw.type = EInfoWindowMode::AUTO;
-		iw.text.addTxt(MetaString::ADVOB_TXT, 183); // % has found treasure
-		iw.text.addReplacement(h->getNameTranslated());
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT, 183); // % has found treasure
+		iw.text.replaceRawString(h->getNameTranslated());
 		cb->showInfoDialog(&iw);
 	}
 }

+ 21 - 21
lib/mapObjects/CGDwelling.cpp

@@ -167,8 +167,8 @@ void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
 		InfoWindow iw;
 		iw.type = EInfoWindowMode::AUTO;
 		iw.player = h->tempOwner;
-		iw.text.addTxt(MetaString::ADVOB_TXT, 44); //{%s} \n\n The camp is deserted.  Perhaps you should try next week.
-		iw.text.addReplacement(MetaString::OBJ_NAMES, ID);
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT, 44); //{%s} \n\n The camp is deserted.  Perhaps you should try next week.
+		iw.text.replaceLocalString(EMetaText::OBJ_NAMES, ID);
 		cb->sendAndApply(&iw);
 		return;
 	}
@@ -182,13 +182,13 @@ void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
 	{
 		BlockingDialog bd(true,false);
 		bd.player = h->tempOwner;
-		bd.text.addTxt(MetaString::GENERAL_TXT, 421); //Much to your dismay, the %s is guarded by %s %s. Do you wish to fight the guards?
-		bd.text.addReplacement(ID == Obj::CREATURE_GENERATOR1 ? MetaString::CREGENS : MetaString::CREGENS4, subID);
+		bd.text.appendLocalString(EMetaText::GENERAL_TXT, 421); //Much to your dismay, the %s is guarded by %s %s. Do you wish to fight the guards?
+		bd.text.replaceLocalString(ID == Obj::CREATURE_GENERATOR1 ? EMetaText::CREGENS : EMetaText::CREGENS4, subID);
 		if(settings["gameTweaks"]["numericCreaturesQuantities"].Bool())
-			bd.text.addReplacement(CCreature::getQuantityRangeStringForId(Slots().begin()->second->getQuantityID()));
+			bd.text.replaceRawString(CCreature::getQuantityRangeStringForId(Slots().begin()->second->getQuantityID()));
 		else
-			bd.text.addReplacement(MetaString::ARRAY_TXT, 173 + (int)Slots().begin()->second->getQuantityID()*3);
-		bd.text.addReplacement(*Slots().begin()->second);
+			bd.text.replaceLocalString(EMetaText::ARRAY_TXT, 173 + (int)Slots().begin()->second->getQuantityID()*3);
+		bd.text.replaceCreatureName(*Slots().begin()->second);
 		cb->showBlockingDialog(&bd);
 		return;
 	}
@@ -203,20 +203,20 @@ void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
 	bd.player = h->tempOwner;
 	if(ID == Obj::CREATURE_GENERATOR1 || ID == Obj::CREATURE_GENERATOR4)
 	{
-		bd.text.addTxt(MetaString::ADVOB_TXT, ID == Obj::CREATURE_GENERATOR1 ? 35 : 36); //{%s} Would you like to recruit %s? / {%s} Would you like to recruit %s, %s, %s, or %s?
-		bd.text.addReplacement(ID == Obj::CREATURE_GENERATOR1 ? MetaString::CREGENS : MetaString::CREGENS4, subID);
+		bd.text.appendLocalString(EMetaText::ADVOB_TXT, ID == Obj::CREATURE_GENERATOR1 ? 35 : 36); //{%s} Would you like to recruit %s? / {%s} Would you like to recruit %s, %s, %s, or %s?
+		bd.text.replaceLocalString(ID == Obj::CREATURE_GENERATOR1 ? EMetaText::CREGENS : EMetaText::CREGENS4, subID);
 		for(const auto & elem : creatures)
-			bd.text.addReplacement(MetaString::CRE_PL_NAMES, elem.second[0]);
+			bd.text.replaceLocalString(EMetaText::CRE_PL_NAMES, elem.second[0]);
 	}
 	else if(ID == Obj::REFUGEE_CAMP)
 	{
-		bd.text.addTxt(MetaString::ADVOB_TXT, 35); //{%s} Would you like to recruit %s?
-		bd.text.addReplacement(MetaString::OBJ_NAMES, ID);
+		bd.text.appendLocalString(EMetaText::ADVOB_TXT, 35); //{%s} Would you like to recruit %s?
+		bd.text.replaceLocalString(EMetaText::OBJ_NAMES, ID);
 		for(const auto & elem : creatures)
-			bd.text.addReplacement(MetaString::CRE_PL_NAMES, elem.second[0]);
+			bd.text.replaceLocalString(EMetaText::CRE_PL_NAMES, elem.second[0]);
 	}
 	else if(ID == Obj::WAR_MACHINE_FACTORY)
-		bd.text.addTxt(MetaString::ADVOB_TXT, 157); //{War Machine Factory} Would you like to purchase War Machines?
+		bd.text.appendLocalString(EMetaText::ADVOB_TXT, 157); //{War Machine Factory} Would you like to purchase War Machines?
 	else
 		throw std::runtime_error("Illegal dwelling!");
 
@@ -330,8 +330,8 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
 				InfoWindow iw;
 				iw.type = EInfoWindowMode::AUTO;
 				iw.player = h->tempOwner;
-				iw.text.addTxt(MetaString::GENERAL_TXT, 425);//The %s would join your hero, but there aren't enough provisions to support them.
-				iw.text.addReplacement(MetaString::CRE_PL_NAMES, crid);
+				iw.text.appendLocalString(EMetaText::GENERAL_TXT, 425);//The %s would join your hero, but there aren't enough provisions to support them.
+				iw.text.replaceLocalString(EMetaText::CRE_PL_NAMES, crid);
 				cb->showInfoDialog(&iw);
 			}
 			else //give creatures
@@ -345,9 +345,9 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
 				InfoWindow iw;
 				iw.type = EInfoWindowMode::AUTO;
 				iw.player = h->tempOwner;
-				iw.text.addTxt(MetaString::GENERAL_TXT, 423); //%d %s join your army.
-				iw.text.addReplacement(count);
-				iw.text.addReplacement(MetaString::CRE_PL_NAMES, crid);
+				iw.text.appendLocalString(EMetaText::GENERAL_TXT, 423); //%d %s join your army.
+				iw.text.replaceNumber(count);
+				iw.text.replaceLocalString(EMetaText::CRE_PL_NAMES, crid);
 
 				cb->showInfoDialog(&iw);
 				cb->sendAndApply(&sac);
@@ -358,8 +358,8 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
 		{
 			InfoWindow iw;
 			iw.type = EInfoWindowMode::AUTO;
-			iw.text.addTxt(MetaString::GENERAL_TXT, 422); //There are no %s here to recruit.
-			iw.text.addReplacement(MetaString::CRE_PL_NAMES, crid);
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT, 422); //There are no %s here to recruit.
+			iw.text.replaceLocalString(EMetaText::CRE_PL_NAMES, crid);
 			iw.player = h->tempOwner;
 			cb->sendAndApply(&iw);
 		}

+ 7 - 7
lib/mapObjects/CGHeroInstance.cpp

@@ -680,7 +680,7 @@ PlayerColor CGHeroInstance::getCasterOwner() const
 void CGHeroInstance::getCasterName(MetaString & text) const
 {
 	//FIXME: use local name, MetaString need access to gamestate as hero name is part of map object
-	text.addReplacement(getNameTranslated());
+	text.replaceRawString(getNameTranslated());
 }
 
 void CGHeroInstance::getCastDescription(const spells::Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const
@@ -688,9 +688,9 @@ void CGHeroInstance::getCastDescription(const spells::Spell * spell, const std::
 	const bool singleTarget = attacked.size() == 1;
 	const int textIndex = singleTarget ? 195 : 196;
 
-	text.addTxt(MetaString::GENERAL_TXT, textIndex);
+	text.appendLocalString(EMetaText::GENERAL_TXT, textIndex);
 	getCasterName(text);
-	text.addReplacement(MetaString::SPELL_NAME, spell->getIndex());
+	text.replaceLocalString(EMetaText::SPELL_NAME, spell->getIndex());
 	if(singleTarget)
 		attacked.at(0)->addNameReplacement(text, true);
 }
@@ -896,14 +896,14 @@ void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedSta
 
 	if (raisedStack.count > 1) // Practicing the dark arts of necromancy, ... (plural)
 	{
-		iw.text.addTxt(MetaString::GENERAL_TXT, 145);
-		iw.text.addReplacement(raisedStack.count);
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 145);
+		iw.text.replaceNumber(raisedStack.count);
 	}
 	else // Practicing the dark arts of necromancy, ... (singular)
 	{
-		iw.text.addTxt(MetaString::GENERAL_TXT, 146);
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 146);
 	}
-	iw.text.addReplacement(raisedStack);
+	iw.text.replaceCreatureName(raisedStack);
 
 	cb->showInfoDialog(&iw);
 }

+ 25 - 25
lib/mapObjects/CGPandoraBox.cpp

@@ -35,7 +35,7 @@ void CGPandoraBox::onHeroVisit(const CGHeroInstance * h) const
 {
 		BlockingDialog bd (true, false);
 		bd.player = h->getOwner();
-		bd.text.addTxt (MetaString::ADVOB_TXT, 14);
+		bd.text.appendLocalString (EMetaText::ADVOB_TXT, 14);
 		cb->showBlockingDialog (&bd);
 }
 
@@ -79,8 +79,8 @@ void CGPandoraBox::giveContentsUpToExp(const CGHeroInstance *h) const
 	{
 		TExpType expVal = h->calculateXp(gainedExp);
 		//getText(iw,afterBattle,175,h); //wtf?
-		iw.text.addTxt(MetaString::ADVOB_TXT, 175); //%s learns something
-		iw.text.addReplacement(h->getNameTranslated());
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT, 175); //%s learns something
+		iw.text.replaceRawString(h->getNameTranslated());
 
 		if(expVal)
 			iw.components.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast<si32>(expVal), 0);
@@ -156,13 +156,13 @@ void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
 			{
 				if (spellsToGive.size() > 1)
 				{
-					iw.text.addTxt(MetaString::ADVOB_TXT, 188); //%s learns spells
+					iw.text.appendLocalString(EMetaText::ADVOB_TXT, 188); //%s learns spells
 				}
 				else
 				{
-					iw.text.addTxt(MetaString::ADVOB_TXT, 184); //%s learns a spell
+					iw.text.appendLocalString(EMetaText::ADVOB_TXT, 184); //%s learns a spell
 				}
-				iw.text.addReplacement(h->getNameTranslated());
+				iw.text.replaceRawString(h->getNameTranslated());
 				cb->changeSpells(h, true, spellsToGive);
 				cb->showInfoDialog(&iw);
 			}
@@ -227,8 +227,8 @@ void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
 
 	iw.components.clear();
 	// 	getText(iw,afterBattle,183,h);
-	iw.text.addTxt(MetaString::ADVOB_TXT, 183); //% has found treasure
-	iw.text.addReplacement(h->getNameTranslated());
+	iw.text.appendLocalString(EMetaText::ADVOB_TXT, 183); //% has found treasure
+	iw.text.replaceRawString(h->getNameTranslated());
 	for(const auto & elem : artifacts)
 	{
 		iw.components.emplace_back(Component::EComponentType::ARTIFACT, elem, 0, 0);
@@ -236,8 +236,8 @@ void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
 		{
 			cb->showInfoDialog(&iw);
 			iw.components.clear();
-			iw.text.addTxt(MetaString::ADVOB_TXT, 183); //% has found treasure - once more?
-			iw.text.addReplacement(h->getNameTranslated());
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT, 183); //% has found treasure - once more?
+			iw.text.replaceRawString(h->getNameTranslated());
 		}
 	}
 	if(!iw.components.empty())
@@ -259,24 +259,24 @@ void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
 		for(const auto & elem : creatures.Slots())
 		{ //build list of joined creatures
 			iw.components.emplace_back(*elem.second);
-			loot.addRawString("%s");
-			loot.addReplacement(*elem.second);
+			loot.appendRawString("%s");
+			loot.replaceCreatureName(*elem.second);
 		}
 
 		if(creatures.stacksCount() == 1 && creatures.Slots().begin()->second->count == 1)
-			iw.text.addTxt(MetaString::ADVOB_TXT, 185);
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT, 185);
 		else
-			iw.text.addTxt(MetaString::ADVOB_TXT, 186);
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT, 186);
 
-		iw.text.addReplacement(loot.buildList());
-		iw.text.addReplacement(h->getNameTranslated());
+		iw.text.replaceRawString(loot.buildList());
+		iw.text.replaceRawString(h->getNameTranslated());
 
 		cb->showInfoDialog(&iw);
 		cb->giveCreatures(this, h, creatures, false);
 	}
 	if(!hasGuardians && !msg.empty())
 	{
-		iw.text.addRawString(msg);
+		iw.text.appendRawString(msg);
 		cb->showInfoDialog(&iw);
 	}
 }
@@ -285,12 +285,12 @@ void CGPandoraBox::getText( InfoWindow &iw, bool &afterBattle, int text, const C
 {
 	if(afterBattle || message.empty())
 	{
-		iw.text.addTxt(MetaString::ADVOB_TXT,text);//%s has lost treasure.
-		iw.text.addReplacement(h->getNameTranslated());
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT,text);//%s has lost treasure.
+		iw.text.replaceRawString(h->getNameTranslated());
 	}
 	else
 	{
-		iw.text.addRawString(message);
+		iw.text.appendRawString(message);
 		afterBattle = true;
 	}
 }
@@ -301,12 +301,12 @@ void CGPandoraBox::getText( InfoWindow &iw, bool &afterBattle, int val, int nega
 	iw.text.clear();
 	if(afterBattle || message.empty())
 	{
-		iw.text.addTxt(MetaString::ADVOB_TXT,val < 0 ? negative : positive); //%s's luck takes a turn for the worse / %s's luck increases
-		iw.text.addReplacement(h->getNameTranslated());
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT,val < 0 ? negative : positive); //%s's luck takes a turn for the worse / %s's luck increases
+		iw.text.replaceRawString(h->getNameTranslated());
 	}
 	else
 	{
-		iw.text.addRawString(message);
+		iw.text.appendRawString(message);
 		afterBattle = true;
 	}
 }
@@ -461,9 +461,9 @@ void CGEvent::activated( const CGHeroInstance * h ) const
 		InfoWindow iw;
 		iw.player = h->tempOwner;
 		if(!message.empty())
-			iw.text.addRawString(message);
+			iw.text.appendRawString(message);
 		else
-			iw.text.addTxt(MetaString::ADVOB_TXT, 16);
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT, 16);
 		cb->showInfoDialog(&iw);
 		cb->startBattleI(h, this);
 	}

+ 4 - 4
lib/mapObjects/CGTownBuilding.cpp

@@ -156,7 +156,7 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const
 				mp.hid = heroID;
 				cb->setMovePoints(&mp);
 
-				iw.text.addRawString(VLC->generaltexth->allTexts[580]);
+				iw.text.appendRawString(VLC->generaltexth->allTexts[580]);
 				cb->showInfoDialog(&iw);
 			}
 			break;
@@ -168,7 +168,7 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const
 					cb->setManaPoints (heroID, 2 * h->manaLimit());
 				//TODO: investigate line below
 				//cb->setObjProperty (town->id, ObjProperty::VISITED, true);
-				iw.text.addRawString(getVisitingBonusGreeting());
+				iw.text.appendRawString(getVisitingBonusGreeting());
 				cb->showInfoDialog(&iw);
 				//extra visit penalty if hero alredy had double mana points (or even more?!)
 				town->addHeroToStructureVisitors(h, indexOnTV);
@@ -246,7 +246,7 @@ void CTownBonus::onHeroVisit (const CGHeroInstance * h) const
 		if(what != PrimarySkill::NONE)
 		{
 			iw.player = cb->getOwner(heroID);
-				iw.text.addRawString(getVisitingBonusGreeting());
+				iw.text.appendRawString(getVisitingBonusGreeting());
 			cb->showInfoDialog(&iw);
 			cb->changePrimSkill (cb->getHero(heroID), what, val);
 				town->addHeroToStructureVisitors(h, indexOnTV);
@@ -278,7 +278,7 @@ void CTownBonus::applyBonuses(CGHeroInstance * h, const BonusList & bonuses) con
 			addToVisitors = true;
 
 		iw.player = cb->getOwner(h->id);
-		iw.text.addRawString(getCustomBonusGreeting(gb.bonus));
+		iw.text.appendRawString(getCustomBonusGreeting(gb.bonus));
 		cb->showInfoDialog(&iw);
 	}
 	if(addToVisitors)

+ 1 - 1
lib/mapObjects/CGTownInstance.cpp

@@ -320,7 +320,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
 		{
 			InfoWindow iw;
 			iw.player = h->tempOwner;
-			iw.text.addRawString(h->commander->getName());
+			iw.text.appendRawString(h->commander->getName());
 			iw.components.emplace_back(*h->commander);
 			cb->showInfoDialog(&iw);
 		}

+ 69 - 69
lib/mapObjects/CQuest.cpp

@@ -188,20 +188,20 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
 	{
 		isCustom = isCustomFirst;
 		text = firstVisitText;
-		iwText.addRawString(text);
+		iwText.appendRawString(text);
 	}
 	else if(failRequirements)
 	{
 		isCustom = isCustomNext;
 		text = nextVisitText;
-		iwText.addRawString(text);
+		iwText.appendRawString(text);
 	}
 	switch (missionType)
 	{
 		case MISSION_LEVEL:
 			components.emplace_back(Component::EComponentType::EXPERIENCE, 0, m13489val, 0);
 			if(!isCustom)
-				iwText.addReplacement(m13489val);
+				iwText.replaceNumber(m13489val);
 			break;
 		case MISSION_PRIMARY_STAT:
 		{
@@ -211,13 +211,13 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
 				if(m2stats[i])
 				{
 					components.emplace_back(Component::EComponentType::PRIM_SKILL, i, m2stats[i], 0);
-					loot.addRawString("%d %s");
-					loot.addReplacement(m2stats[i]);
-					loot.addReplacement(VLC->generaltexth->primarySkillNames[i]);
+					loot.appendRawString("%d %s");
+					loot.replaceNumber(m2stats[i]);
+					loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
 				}
 			}
 			if (!isCustom)
-				iwText.addReplacement(loot.buildList());
+				iwText.replaceRawString(loot.buildList());
 		}
 			break;
 		case MISSION_KILL_HERO:
@@ -229,7 +229,7 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
 			//FIXME: portrait may not match hero, if custom portrait was set in map editor
 			components.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroh->objects[m13489val]->imageIndex, 0, 0);
 			if(!isCustom)
-				iwText.addReplacement(VLC->heroh->objects[m13489val]->getNameTranslated());
+				iwText.replaceRawString(VLC->heroh->objects[m13489val]->getNameTranslated());
 			break;
 		case MISSION_KILL_CREATURE:
 			{
@@ -246,11 +246,11 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
 			for(const auto & elem : m5arts)
 			{
 				components.emplace_back(Component::EComponentType::ARTIFACT, elem, 0, 0);
-				loot.addRawString("%s");
-				loot.addReplacement(MetaString::ART_NAMES, elem);
+				loot.appendRawString("%s");
+				loot.replaceLocalString(EMetaText::ART_NAMES, elem);
 			}
 			if(!isCustom)
-				iwText.addReplacement(loot.buildList());
+				iwText.replaceRawString(loot.buildList());
 		}
 			break;
 		case MISSION_ARMY:
@@ -259,11 +259,11 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
 			for(const auto & elem : m6creatures)
 			{
 				components.emplace_back(elem);
-				loot.addRawString("%s");
-				loot.addReplacement(elem);
+				loot.appendRawString("%s");
+				loot.replaceCreatureName(elem);
 			}
 			if(!isCustom)
-				iwText.addReplacement(loot.buildList());
+				iwText.replaceRawString(loot.buildList());
 		}
 			break;
 		case MISSION_RESOURCES:
@@ -274,19 +274,19 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
 				if(m7resources[i])
 				{
 					components.emplace_back(Component::EComponentType::RESOURCE, i, m7resources[i], 0);
-					loot.addRawString("%d %s");
-					loot.addReplacement(m7resources[i]);
-					loot.addReplacement(MetaString::RES_NAMES, i);
+					loot.appendRawString("%d %s");
+					loot.replaceNumber(m7resources[i]);
+					loot.replaceLocalString(EMetaText::RES_NAMES, i);
 				}
 			}
 			if(!isCustom)
-				iwText.addReplacement(loot.buildList());
+				iwText.replaceRawString(loot.buildList());
 		}
 			break;
 		case MISSION_PLAYER:
 			components.emplace_back(Component::EComponentType::FLAG, m13489val, 0, 0);
 			if(!isCustom)
-				iwText.addReplacement(VLC->generaltexth->colors[m13489val]);
+				iwText.replaceRawString(VLC->generaltexth->colors[m13489val]);
 			break;
 	}
 }
@@ -297,17 +297,17 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
 	assert(missionType != MISSION_NONE);
 
 	if(onHover)
-		ms.addRawString("\n\n");
+		ms.appendRawString("\n\n");
 
 	std::string questName = missionName(missionType);
 	std::string questState = missionState(onHover ? 3 : 4);
 
-	ms.addRawString(VLC->generaltexth->translate("core.seerhut.quest", questName, questState,textOption));
+	ms.appendRawString(VLC->generaltexth->translate("core.seerhut.quest", questName, questState,textOption));
 
 	switch(missionType)
 	{
 		case MISSION_LEVEL:
-			ms.addReplacement(m13489val);
+			ms.replaceNumber(m13489val);
 			break;
 		case MISSION_PRIMARY_STAT:
 			{
@@ -316,29 +316,29 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
 				{
 					if (m2stats[i])
 					{
-						loot.addRawString("%d %s");
-						loot.addReplacement(m2stats[i]);
-						loot.addReplacement(VLC->generaltexth->primarySkillNames[i]);
+						loot.appendRawString("%d %s");
+						loot.replaceNumber(m2stats[i]);
+						loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
 					}
 				}
-				ms.addReplacement(loot.buildList());
+				ms.replaceRawString(loot.buildList());
 			}
 			break;
 		case MISSION_KILL_HERO:
-			ms.addReplacement(heroName);
+			ms.replaceRawString(heroName);
 			break;
 		case MISSION_KILL_CREATURE:
-			ms.addReplacement(stackToKill);
+			ms.replaceCreatureName(stackToKill);
 			break;
 		case MISSION_ART:
 			{
 				MetaString loot;
 				for(const auto & elem : m5arts)
 				{
-					loot.addRawString("%s");
-					loot.addReplacement(MetaString::ART_NAMES, elem);
+					loot.appendRawString("%s");
+					loot.replaceLocalString(EMetaText::ART_NAMES, elem);
 				}
-				ms.addReplacement(loot.buildList());
+				ms.replaceRawString(loot.buildList());
 			}
 			break;
 		case MISSION_ARMY:
@@ -346,10 +346,10 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
 				MetaString loot;
 				for(const auto & elem : m6creatures)
 				{
-					loot.addRawString("%s");
-					loot.addReplacement(elem);
+					loot.appendRawString("%s");
+					loot.replaceCreatureName(elem);
 				}
-				ms.addReplacement(loot.buildList());
+				ms.replaceRawString(loot.buildList());
 			}
 			break;
 		case MISSION_RESOURCES:
@@ -359,19 +359,19 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
 				{
 					if (m7resources[i])
 					{
-						loot.addRawString("%d %s");
-						loot.addReplacement(m7resources[i]);
-						loot.addReplacement(MetaString::RES_NAMES, i);
+						loot.appendRawString("%d %s");
+						loot.replaceNumber(m7resources[i]);
+						loot.replaceLocalString(EMetaText::RES_NAMES, i);
 					}
 				}
-				ms.addReplacement(loot.buildList());
+				ms.replaceRawString(loot.buildList());
 			}
 			break;
 		case MISSION_HERO:
-			ms.addReplacement(VLC->heroh->objects[m13489val]->getNameTranslated());
+			ms.replaceRawString(VLC->heroh->objects[m13489val]->getNameTranslated());
 			break;
 		case MISSION_PLAYER:
-			ms.addReplacement(VLC->generaltexth->colors[m13489val]);
+			ms.replaceRawString(VLC->generaltexth->colors[m13489val]);
 			break;
 		default:
 			break;
@@ -380,12 +380,12 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
 
 void CQuest::getCompletionText(MetaString &iwText, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h) const
 {
-	iwText.addRawString(completedText);
+	iwText.appendRawString(completedText);
 	switch(missionType)
 	{
 		case CQuest::MISSION_LEVEL:
 			if (!isCustomComplete)
-				iwText.addReplacement(m13489val);
+				iwText.replaceNumber(m13489val);
 			break;
 		case CQuest::MISSION_PRIMARY_STAT:
 			if (vstd::contains (completedText,'%')) //there's one case when there's nothing to replace
@@ -395,13 +395,13 @@ void CQuest::getCompletionText(MetaString &iwText, std::vector<Component> &compo
 				{
 					if (m2stats[i])
 					{
-						loot.addRawString("%d %s");
-						loot.addReplacement(m2stats[i]);
-						loot.addReplacement(VLC->generaltexth->primarySkillNames[i]);
+						loot.appendRawString("%d %s");
+						loot.replaceNumber(m2stats[i]);
+						loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
 					}
 				}
 				if (!isCustomComplete)
-					iwText.addReplacement(loot.buildList());
+					iwText.replaceRawString(loot.buildList());
 			}
 			break;
 		case CQuest::MISSION_ART:
@@ -409,11 +409,11 @@ void CQuest::getCompletionText(MetaString &iwText, std::vector<Component> &compo
 			MetaString loot;
 			for(const auto & elem : m5arts)
 			{
-				loot.addRawString("%s");
-				loot.addReplacement(MetaString::ART_NAMES, elem);
+				loot.appendRawString("%s");
+				loot.replaceLocalString(EMetaText::ART_NAMES, elem);
 			}
 			if (!isCustomComplete)
-				iwText.addReplacement(loot.buildList());
+				iwText.replaceRawString(loot.buildList());
 		}
 			break;
 		case CQuest::MISSION_ARMY:
@@ -421,11 +421,11 @@ void CQuest::getCompletionText(MetaString &iwText, std::vector<Component> &compo
 			MetaString loot;
 			for(const auto & elem : m6creatures)
 			{
-				loot.addRawString("%s");
-				loot.addReplacement(elem);
+				loot.appendRawString("%s");
+				loot.replaceCreatureName(elem);
 			}
 			if (!isCustomComplete)
-				iwText.addReplacement(loot.buildList());
+				iwText.replaceRawString(loot.buildList());
 		}
 			break;
 		case CQuest::MISSION_RESOURCES:
@@ -435,13 +435,13 @@ void CQuest::getCompletionText(MetaString &iwText, std::vector<Component> &compo
 			{
 				if (m7resources[i])
 				{
-					loot.addRawString("%d %s");
-					loot.addReplacement(m7resources[i]);
-					loot.addReplacement(MetaString::RES_NAMES, i);
+					loot.appendRawString("%d %s");
+					loot.replaceNumber(m7resources[i]);
+					loot.replaceLocalString(EMetaText::RES_NAMES, i);
 				}
 			}
 			if (!isCustomComplete)
-				iwText.addReplacement(loot.buildList());
+				iwText.replaceRawString(loot.buildList());
 		}
 			break;
 		case MISSION_KILL_HERO:
@@ -451,11 +451,11 @@ void CQuest::getCompletionText(MetaString &iwText, std::vector<Component> &compo
 			break;
 		case MISSION_HERO:
 			if (!isCustomComplete)
-				iwText.addReplacement(VLC->heroh->objects[m13489val]->getNameTranslated());
+				iwText.replaceRawString(VLC->heroh->objects[m13489val]->getNameTranslated());
 			break;
 		case MISSION_PLAYER:
 			if (!isCustomComplete)
-				iwText.addReplacement(VLC->generaltexth->colors[m13489val]);
+				iwText.replaceRawString(VLC->generaltexth->colors[m13489val]);
 			break;
 	}
 }
@@ -596,7 +596,7 @@ void CGSeerHut::getRolloverText(MetaString &text, bool onHover) const
 {
 	quest->getRolloverText (text, onHover);//TODO: simplify?
 	if(!onHover)
-		text.addReplacement(seerName);
+		text.replaceRawString(seerName);
 }
 
 std::string CGSeerHut::getHoverText(PlayerColor player) const
@@ -622,14 +622,14 @@ void CQuest::addReplacements(MetaString &out, const std::string &base) const
 	switch(missionType)
 	{
 	case MISSION_KILL_CREATURE:
-		out.addReplacement(stackToKill);
+		out.replaceCreatureName(stackToKill);
 		if (std::count(base.begin(), base.end(), '%') == 2) //say where is placed monster
 		{
-			out.addReplacement(VLC->generaltexth->arraytxt[147+stackDirection]);
+			out.replaceRawString(VLC->generaltexth->arraytxt[147+stackDirection]);
 		}
 		break;
 	case MISSION_KILL_HERO:
-		out.addReplacement(heroName);
+		out.replaceRawString(heroName);
 		break;
 	}
 }
@@ -749,9 +749,9 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const
 	}
 	else
 	{
-		iw.text.addRawString(VLC->generaltexth->seerEmpty[quest->completedOption]);
+		iw.text.appendRawString(VLC->generaltexth->seerEmpty[quest->completedOption]);
 		if (ID == Obj::SEER_HUT)
-			iw.text.addReplacement(seerName);
+			iw.text.replaceRawString(seerName);
 		cb->showInfoDialog(&iw);
 	}
 }
@@ -1157,16 +1157,16 @@ void CGBorderGuard::initObj(CRandomGenerator & rand)
 
 void CGBorderGuard::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const
 {
-	text.addTxt(11,18);
+	text.appendLocalString(EMetaText::ADVOB_TXT,18);
 }
 
 void CGBorderGuard::getRolloverText (MetaString &text, bool onHover) const
 {
 	if (!onHover)
 	{
-		text.addRawString(VLC->generaltexth->tentColors[subID]);
-		text.addRawString(" ");
-		text.addRawString(VLC->objtypeh->getObjectName(Obj::KEYMASTER, subID));
+		text.appendRawString(VLC->generaltexth->tentColors[subID]);
+		text.appendRawString(" ");
+		text.appendRawString(VLC->objtypeh->getObjectName(Obj::KEYMASTER, subID));
 	}
 }
 
@@ -1181,7 +1181,7 @@ void CGBorderGuard::onHeroVisit(const CGHeroInstance * h) const
 	{
 		BlockingDialog bd (true, false);
 		bd.player = h->getOwner();
-		bd.text.addTxt (MetaString::ADVOB_TXT, 17);
+		bd.text.appendLocalString (EMetaText::ADVOB_TXT, 17);
 		cb->showBlockingDialog (&bd);
 	}
 	else

+ 5 - 5
lib/mapObjects/IObjectInterface.cpp

@@ -38,7 +38,7 @@ void IObjectInterface::showInfoDialog(const ui32 txtID, const ui16 soundID, EInf
 	iw.soundID = soundID;
 	iw.player = getOwner();
 	iw.type = mode;
-	iw.text.addTxt(MetaString::ADVOB_TXT,txtID);
+	iw.text.appendLocalString(EMetaText::ADVOB_TXT,txtID);
 	IObjectInterface::cb->sendAndApply(&iw);
 }
 
@@ -122,16 +122,16 @@ void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visit
 	switch(shipyardStatus())
 	{
 	case BOAT_ALREADY_BUILT:
-		out.addTxt(MetaString::GENERAL_TXT, 51);
+		out.appendLocalString(EMetaText::GENERAL_TXT, 51);
 		break;
 	case TILE_BLOCKED:
 		if(visitor)
 		{
-			out.addTxt(MetaString::GENERAL_TXT, 134);
-			out.addReplacement(visitor->getNameTranslated());
+			out.appendLocalString(EMetaText::GENERAL_TXT, 134);
+			out.replaceRawString(visitor->getNameTranslated());
 		}
 		else
-			out.addTxt(MetaString::ADVOB_TXT, 189);
+			out.appendLocalString(EMetaText::ADVOB_TXT, 189);
 		break;
 	case NO_WATER:
 		logGlobal->error("Shipyard without water at tile %s! ", getObject()->getPosition().toString());

+ 37 - 37
lib/mapObjects/MiscObjects.cpp

@@ -82,7 +82,7 @@ void CGMine::onHeroVisit( const CGHeroInstance * h ) const
 	{
 		BlockingDialog ynd(true,false);
 		ynd.player = h->tempOwner;
-		ynd.text.addTxt(MetaString::ADVOB_TXT, subID == 7 ? 84 : 187);
+		ynd.text.appendLocalString(EMetaText::ADVOB_TXT, subID == 7 ? 84 : 187);
 		cb->showBlockingDialog(&ynd);
 		return;
 	}
@@ -156,7 +156,7 @@ void CGMine::flagMine(const PlayerColor & player) const
 	InfoWindow iw;
 	iw.type = EInfoWindowMode::AUTO;
 	iw.soundID = soundBase::FLAGMINE;
-	iw.text.addTxt(MetaString::MINE_EVNTS, producedResource); //not use subID, abandoned mines uses default mine texts
+	iw.text.appendLocalString(EMetaText::MINE_EVNTS, producedResource); //not use subID, abandoned mines uses default mine texts
 	iw.player = player;
 	iw.components.emplace_back(Component::EComponentType::RESOURCE, producedResource, producedQuantity, -1);
 	cb->showInfoDialog(&iw);
@@ -268,7 +268,7 @@ void CGResource::onHeroVisit( const CGHeroInstance * h ) const
 		{
 			BlockingDialog ynd(true,false);
 			ynd.player = h->getOwner();
-			ynd.text.addRawString(message);
+			ynd.text.appendRawString(message);
 			cb->showBlockingDialog(&ynd);
 		}
 		else
@@ -288,13 +288,13 @@ void CGResource::collectRes(const PlayerColor & player) const
 	if(!message.empty())
 	{
 		sii.type = EInfoWindowMode::AUTO;
-		sii.text.addRawString(message);
+		sii.text.appendRawString(message);
 	}
 	else
 	{
 		sii.type = EInfoWindowMode::INFO;
-		sii.text.addTxt(MetaString::ADVOB_TXT,113);
-		sii.text.addReplacement(MetaString::RES_NAMES, subID);
+		sii.text.appendLocalString(EMetaText::ADVOB_TXT,113);
+		sii.text.replaceLocalString(EMetaText::RES_NAMES, subID);
 	}
 	sii.components.emplace_back(Component::EComponentType::RESOURCE,subID,amount,0);
 	sii.soundID = soundBase::pickup01 + CRandomGenerator::getDefault().nextInt(6);
@@ -635,7 +635,7 @@ void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const
 		InfoWindow iw;
 		iw.type = EInfoWindowMode::AUTO;
 		iw.player = h->tempOwner;
-		iw.text.addTxt(MetaString::ADVOB_TXT, 168);
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT, 168);
 		iw.components.emplace_back(CStackBasicDescriptor(h->getCreature(targetstack), -countToTake));
 		cb->showInfoDialog(&iw);
 		cb->changeStackCount(StackLocation(h, targetstack), -countToTake);
@@ -727,9 +727,9 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
 			{
 				iw.components.emplace_back(Component::EComponentType::ARTIFACT, subID, 0, 0);
 				if(message.length())
-					iw.text.addRawString(message);
+					iw.text.appendRawString(message);
 				else
-					iw.text.addTxt(MetaString::ART_EVNTS, subID);
+					iw.text.appendLocalString(EMetaText::ART_EVNTS, subID);
 			}
 			break;
 			case Obj::SPELL_SCROLL:
@@ -737,11 +737,11 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
 				int spellID = storedArtifact->getScrollSpellID();
 				iw.components.emplace_back(Component::EComponentType::SPELL, spellID, 0, 0);
 				if(message.length())
-					iw.text.addRawString(message);
+					iw.text.appendRawString(message);
 				else
 				{
-					iw.text.addTxt(MetaString::ADVOB_TXT,135);
-					iw.text.addReplacement(MetaString::SPELL_NAME, spellID);
+					iw.text.appendLocalString(EMetaText::ADVOB_TXT,135);
+					iw.text.replaceLocalString(EMetaText::SPELL_NAME, spellID);
 				}
 			}
 			break;
@@ -749,7 +749,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
 		}
 		else
 		{
-			iw.text.addTxt(MetaString::ADVOB_TXT, 2);
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT, 2);
 		}
 		cb->showInfoDialog(&iw);
 		pick(h);
@@ -763,14 +763,14 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
 				BlockingDialog ynd(true,false);
 				ynd.player = h->getOwner();
 				if(message.length())
-					ynd.text.addRawString(message);
+					ynd.text.appendRawString(message);
 				else
 				{
 					// TODO: Guard text is more complex in H3, see mantis issue 2325 for details
-					ynd.text.addTxt(MetaString::GENERAL_TXT, 420);
-					ynd.text.addReplacement("");
-					ynd.text.addReplacement(getArmyDescription());
-					ynd.text.addReplacement(MetaString::GENERAL_TXT, 43); // creatures
+					ynd.text.appendLocalString(EMetaText::GENERAL_TXT, 420);
+					ynd.text.replaceRawString("");
+					ynd.text.replaceRawString(getArmyDescription());
+					ynd.text.replaceLocalString(EMetaText::GENERAL_TXT, 43); // creatures
 				}
 				cb->showBlockingDialog(&ynd);
 			}
@@ -781,7 +781,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
 				{
 					BlockingDialog ynd(true,false);
 					ynd.player = h->getOwner();
-					ynd.text.addRawString(message);
+					ynd.text.appendRawString(message);
 					cb->showBlockingDialog(&ynd);
 				}
 				else
@@ -878,8 +878,8 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
 		cb->changeSecSkill(h, SecondarySkill(ability), 1, true);
 	}
 
-	iw.text.addTxt(MetaString::ADVOB_TXT,txt_id);
-	iw.text.addReplacement(MetaString::SEC_SKILL_NAME, ability);
+	iw.text.appendLocalString(EMetaText::ADVOB_TXT,txt_id);
+	iw.text.replaceLocalString(EMetaText::SEC_SKILL_NAME, ability);
 	cb->showInfoDialog(&iw);
 }
 
@@ -940,7 +940,7 @@ void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
 	case Obj::REDWOOD_OBSERVATORY:
 	case Obj::PILLAR_OF_FIRE:
 	{
-		iw.text.addTxt(MetaString::ADVOB_TXT,98 + (ID==Obj::PILLAR_OF_FIRE));
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT,98 + (ID==Obj::PILLAR_OF_FIRE));
 
 		FoWChange fw;
 		fw.player = h->tempOwner;
@@ -951,7 +951,7 @@ void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
 	}
 	case Obj::COVER_OF_DARKNESS:
 	{
-		iw.text.addTxt (MetaString::ADVOB_TXT, 31);
+		iw.text.appendLocalString (EMetaText::ADVOB_TXT, 31);
 		for (auto & player : cb->gameState()->players)
 		{
 			if (cb->getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
@@ -979,20 +979,20 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
 	iw.type = EInfoWindowMode::AUTO;
 	iw.player = h->getOwner();
 	iw.text = visitText;
-	iw.text.addTxt(MetaString::SPELL_NAME,spell);
-	iw.text.addRawString(".");
+	iw.text.appendLocalString(EMetaText::SPELL_NAME,spell);
+	iw.text.appendRawString(".");
 
 	if(!h->getArt(ArtifactPosition::SPELLBOOK))
 	{
-		iw.text.addTxt(MetaString::ADVOB_TXT,131);
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT,131);
 	}
 	else if(h->spellbookContainsSpell(spell))//hero already knows the spell
 	{
-		iw.text.addTxt(MetaString::ADVOB_TXT,174);
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT,174);
 	}
 	else if(spell.toSpell()->getLevel() > h->maxSpellLevel()) //it's third level spell and hero doesn't have wisdom
 	{
-		iw.text.addTxt(MetaString::ADVOB_TXT,130);
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT,130);
 	}
 	else //give spell
 	{
@@ -1055,7 +1055,7 @@ void CGSignBottle::onHeroVisit( const CGHeroInstance * h ) const
 {
 	InfoWindow iw;
 	iw.player = h->getOwner();
-	iw.text.addRawString(message);
+	iw.text.appendRawString(message);
 	cb->showInfoDialog(&iw);
 
 	if(ID == Obj::OCEAN_BOTTLE)
@@ -1083,7 +1083,7 @@ void CGScholar::onHeroVisit( const CGHeroInstance * h ) const
 	InfoWindow iw;
 	iw.type = EInfoWindowMode::AUTO;
 	iw.player = h->getOwner();
-	iw.text.addTxt(MetaString::ADVOB_TXT,115);
+	iw.text.appendLocalString(EMetaText::ADVOB_TXT,115);
 
 	switch (type)
 	{
@@ -1332,7 +1332,7 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
 	if(h->hasBonusFrom(BonusSource::OBJECT,ID)) //has already visited Sirens
 	{
 		iw.type = EInfoWindowMode::AUTO;
-		iw.text.addTxt(MetaString::ADVOB_TXT,133);
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT,133);
 	}
 	else
 	{
@@ -1358,13 +1358,13 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
 		if(xp)
 		{
 			xp = h->calculateXp(static_cast<int>(xp));
-			iw.text.addTxt(MetaString::ADVOB_TXT,132);
-			iw.text.addReplacement(static_cast<int>(xp));
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT,132);
+			iw.text.replaceNumber(static_cast<int>(xp));
 			cb->changePrimSkill(h, PrimarySkill::EXPERIENCE, xp, false);
 		}
 		else
 		{
-			iw.text.addTxt(MetaString::ADVOB_TXT,134);
+			iw.text.appendLocalString(EMetaText::ADVOB_TXT,134);
 		}
 	}
 	cb->showInfoDialog(&iw);
@@ -1444,7 +1444,7 @@ void CCartographer::onHeroVisit( const CGHeroInstance * h ) const
 			assert(text);
 			BlockingDialog bd (true, false);
 			bd.player = h->getOwner();
-			bd.text.addTxt (MetaString::ADVOB_TXT, text);
+			bd.text.appendLocalString (EMetaText::ADVOB_TXT, text);
 			cb->showBlockingDialog (&bd);
 		}
 		else //if he cannot afford
@@ -1507,7 +1507,7 @@ void CGObelisk::onHeroVisit( const CGHeroInstance * h ) const
 
 	if(!wasVisited(team))
 	{
-		iw.text.addTxt(MetaString::ADVOB_TXT, 96);
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT, 96);
 		cb->sendAndApply(&iw);
 
 		// increment general visited obelisks counter
@@ -1523,7 +1523,7 @@ void CGObelisk::onHeroVisit( const CGHeroInstance * h ) const
 	}
 	else
 	{
-		iw.text.addTxt(MetaString::ADVOB_TXT, 97);
+		iw.text.appendLocalString(EMetaText::ADVOB_TXT, 97);
 		cb->sendAndApply(&iw);
 	}
 

+ 4 - 4
lib/rewardable/Info.cpp

@@ -34,9 +34,9 @@ namespace {
 	{
 		MetaString ret;
 		if (value.isNumber())
-			ret.addTxt(MetaString::ADVOB_TXT, static_cast<ui32>(value.Float()));
+			ret.appendLocalString(EMetaText::ADVOB_TXT, static_cast<ui32>(value.Float()));
 		else
-			ret.addRawString(value.String());
+			ret.appendRawString(value.String());
 		return ret;
 	}
 
@@ -191,10 +191,10 @@ void Rewardable::Info::configureRewards(
 		info.message = loadMessage(reward["message"]);
 
 		for (const auto & artifact : info.reward.artifacts )
-			info.message.addReplacement(MetaString::ART_NAMES, artifact.getNum());
+			info.message.replaceLocalString(EMetaText::ART_NAMES, artifact.getNum());
 
 		for (const auto & artifact : info.reward.spells )
-			info.message.addReplacement(MetaString::SPELL_NAME, artifact.getNum());
+			info.message.replaceLocalString(EMetaText::SPELL_NAME, artifact.getNum());
 
 		object.info.push_back(info);
 	}

+ 13 - 13
lib/spells/AdventureSpellMechanics.cpp

@@ -147,7 +147,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 333);//%s is already in boat
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 333);//%s is already in boat
 		parameters.caster->getCasterName(iw.text);
 		env->apply(&iw);
 		return ESpellCastResult::CANCEL;
@@ -159,7 +159,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 334);//There is no place to put the boat.
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 334);//There is no place to put the boat.
 		env->apply(&iw);
 		return ESpellCastResult::CANCEL;
 	}
@@ -171,7 +171,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 336); //%s tried to summon a boat, but failed.
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 336); //%s tried to summon a boat, but failed.
 		parameters.caster->getCasterName(iw.text);
 		env->apply(&iw);
 		return ESpellCastResult::OK;
@@ -208,7 +208,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 335); //There are no boats to summon.
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 335); //There are no boats to summon.
 		env->apply(&iw);
 	}
 	else //create boat
@@ -236,7 +236,7 @@ ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(SpellCastEnvironmen
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 337); //%s tried to scuttle the boat, but failed
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 337); //%s tried to scuttle the boat, but failed
 		parameters.caster->getCasterName(iw.text);
 		env->apply(&iw);
 		return ESpellCastResult::OK;
@@ -313,7 +313,7 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironm
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 338); //%s is not skilled enough to cast this spell again today.
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 338); //%s is not skilled enough to cast this spell again today.
 		parameters.caster->getCasterName(iw.text);
 		env->apply(&iw);
 		return ESpellCastResult::CANCEL;
@@ -328,7 +328,7 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironm
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 70); //Dimension Door failed!
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 70); //Dimension Door failed!
 		env->apply(&iw);
 	}
 	else if(env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(parameters.pos), true))
@@ -376,7 +376,7 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment
 		{
 			InfoWindow iw;
 			iw.player = parameters.caster->getCasterOwner();
-			iw.text.addTxt(MetaString::GENERAL_TXT, 123);
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT, 123);
 			env->apply(&iw);
 			return ESpellCastResult::CANCEL;
 		}
@@ -461,7 +461,7 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 124);
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 124);
 		env->apply(&iw);
 		return ESpellCastResult::CANCEL;
 	}
@@ -472,7 +472,7 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons
 	{
 		InfoWindow iw;
 		iw.player = parameters.caster->getCasterOwner();
-		iw.text.addTxt(MetaString::GENERAL_TXT, 125);
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 125);
 		env->apply(&iw);
 		return ESpellCastResult::CANCEL;
 	}
@@ -517,14 +517,14 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons
 		{
 			InfoWindow iw;
 			iw.player = parameters.caster->getCasterOwner();
-			iw.text.addTxt(MetaString::GENERAL_TXT, 124);
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT, 124);
 			env->apply(&iw);
 			return ESpellCastResult::CANCEL;
 		}
 
 		request.player = parameters.caster->getCasterOwner();
-		request.title.addTxt(MetaString::JK_TXT, 40);
-		request.description.addTxt(MetaString::JK_TXT, 41);
+		request.title.appendLocalString(EMetaText::JK_TXT, 40);
+		request.description.appendLocalString(EMetaText::JK_TXT, 41);
 		request.icon.id = Component::EComponentType::SPELL;
 		request.icon.subtype = owner->id.toEnum();
 

+ 1 - 1
lib/spells/BattleSpellMechanics.cpp

@@ -309,7 +309,7 @@ void BattleSpellMechanics::cast(ServerCallback * server, const Target & target)
 		{
 			MetaString line;
 			caster->getCastDescription(owner, affectedUnits, line);
-			if(!line.message.empty())
+			if(!line.empty())
 				castDescription.lines.push_back(line);
 		}
 		break;

+ 3 - 3
lib/spells/BonusCaster.cpp

@@ -33,7 +33,7 @@ BonusCaster::~BonusCaster() = default;
 void BonusCaster::getCasterName(MetaString & text) const
 {
 	if(!bonus->description.empty())
-		text.addReplacement(bonus->description);
+		text.replaceRawString(bonus->description);
 	else
 		actualCaster->getCasterName(text);
 }
@@ -43,9 +43,9 @@ void BonusCaster::getCastDescription(const Spell * spell, const std::vector<cons
 	const bool singleTarget = attacked.size() == 1;
 	const int textIndex = singleTarget ? 195 : 196;
 
-	text.addTxt(MetaString::GENERAL_TXT, textIndex);
+	text.appendLocalString(EMetaText::GENERAL_TXT, textIndex);
 	getCasterName(text);
-	text.addReplacement(MetaString::SPELL_NAME, spell->getIndex());
+	text.replaceLocalString(EMetaText::SPELL_NAME, spell->getIndex());
 	if(singleTarget)
 		attacked.at(0)->addNameReplacement(text, true);
 }

+ 6 - 6
lib/spells/ISpellMechanics.cpp

@@ -460,7 +460,7 @@ bool BaseMechanics::adaptGenericProblem(Problem & target) const
 {
 	MetaString text;
 	// %s recites the incantations but they seem to have no effect.
-	text.addTxt(MetaString::GENERAL_TXT, 541);
+	text.appendLocalString(EMetaText::GENERAL_TXT, 541);
 	assert(caster);
 	caster->getCasterName(text);
 
@@ -489,14 +489,14 @@ bool BaseMechanics::adaptProblem(ESpellCastProblem::ESpellCastProblem source, Pr
 			if(b && b->val == 2 && b->source == BonusSource::ARTIFACT)
 			{
 				//The %s prevents %s from casting 3rd level or higher spells.
-				text.addTxt(MetaString::GENERAL_TXT, 536);
-				text.addReplacement(MetaString::ART_NAMES, b->sid);
+				text.appendLocalString(EMetaText::GENERAL_TXT, 536);
+				text.replaceLocalString(EMetaText::ART_NAMES, b->sid);
 				caster->getCasterName(text);
 				target.add(std::move(text), spells::Problem::NORMAL);
 			}
 			else if(b && b->source == BonusSource::TERRAIN_OVERLAY && VLC->battlefields()->getByIndex(b->sid)->identifier == "cursed_ground")
 			{
-				text.addTxt(MetaString::GENERAL_TXT, 537);
+				text.appendLocalString(EMetaText::GENERAL_TXT, 537);
 				target.add(std::move(text), spells::Problem::NORMAL);
 			}
 			else
@@ -510,14 +510,14 @@ bool BaseMechanics::adaptProblem(ESpellCastProblem::ESpellCastProblem source, Pr
 	case ESpellCastProblem::NO_APPROPRIATE_TARGET:
 		{
 			MetaString text;
-			text.addTxt(MetaString::GENERAL_TXT, 185);
+			text.appendLocalString(EMetaText::GENERAL_TXT, 185);
 			target.add(std::move(text), spells::Problem::NORMAL);
 		}
 		break;
 	case ESpellCastProblem::INVALID:
 		{
 			MetaString text;
-			text.addReplacement("Internal error during check of spell cast.");
+			text.appendRawString("Internal error during check of spell cast.");
 			target.add(std::move(text), spells::Problem::CRITICAL);
 		}
 		break;

+ 14 - 14
lib/spells/effects/Damage.cpp

@@ -135,13 +135,13 @@ void Damage::describeEffect(std::vector<MetaString> & log, const Mechanics * m,
 		MetaString line;
 		if(kills > 1)
 		{
-			line.addTxt(MetaString::GENERAL_TXT, 119); //%d %s die under the terrible gaze of the %s.
-			line.addReplacement(kills);
+			line.appendLocalString(EMetaText::GENERAL_TXT, 119); //%d %s die under the terrible gaze of the %s.
+			line.replaceNumber(kills);
 			firstTarget->addNameReplacement(line, true);
 		}
 		else
 		{
-			line.addTxt(MetaString::GENERAL_TXT, 118); //One %s dies under the terrible gaze of the %s.
+			line.appendLocalString(EMetaText::GENERAL_TXT, 118); //One %s dies under the terrible gaze of the %s.
 			firstTarget->addNameReplacement(line, false);
 		}
 		m->caster->getCasterName(line);
@@ -151,7 +151,7 @@ void Damage::describeEffect(std::vector<MetaString> & log, const Mechanics * m,
 	{
 		{
 			MetaString line;
-			firstTarget->addText(line, MetaString::GENERAL_TXT, -367, true);
+			firstTarget->addText(line, EMetaText::GENERAL_TXT, -367, true);
 			firstTarget->addNameReplacement(line, true);
 			log.push_back(line);
 		}
@@ -161,8 +161,8 @@ void Damage::describeEffect(std::vector<MetaString> & log, const Mechanics * m,
 			//todo: handle newlines in metastring
 			std::string text = VLC->generaltexth->allTexts[343]; //Does %d points of damage.
 			boost::algorithm::trim(text);
-			line.addRawString(text);
-			line.addReplacement(static_cast<int>(damage)); //no more text afterwards
+			line.appendRawString(text);
+			line.replaceNumber(static_cast<int>(damage)); //no more text afterwards
 			log.push_back(line);
 		}
 	}
@@ -170,9 +170,9 @@ void Damage::describeEffect(std::vector<MetaString> & log, const Mechanics * m,
 	{
 		{
 			MetaString line;
-			line.addTxt(MetaString::GENERAL_TXT, 376); // Spell %s does %d damage
-			line.addReplacement(MetaString::SPELL_NAME, m->getSpellIndex());
-			line.addReplacement(static_cast<int>(damage));
+			line.appendLocalString(EMetaText::GENERAL_TXT, 376); // Spell %s does %d damage
+			line.replaceLocalString(EMetaText::SPELL_NAME, m->getSpellIndex());
+			line.replaceNumber(static_cast<int>(damage));
 
 			log.push_back(line);
 		}
@@ -183,19 +183,19 @@ void Damage::describeEffect(std::vector<MetaString> & log, const Mechanics * m,
 
 			if(kills > 1)
 			{
-				line.addTxt(MetaString::GENERAL_TXT, 379); // %d %s perishes
-				line.addReplacement(kills);
+				line.appendLocalString(EMetaText::GENERAL_TXT, 379); // %d %s perishes
+				line.replaceNumber(kills);
 
 				if(multiple)
-					line.addReplacement(MetaString::GENERAL_TXT, 43); // creatures
+					line.replaceLocalString(EMetaText::GENERAL_TXT, 43); // creatures
 				else
 					firstTarget->addNameReplacement(line, true);
 			}
 			else // single creature killed
 			{
-				line.addTxt(MetaString::GENERAL_TXT, 378); // one %s perishes
+				line.appendLocalString(EMetaText::GENERAL_TXT, 378); // one %s perishes
 				if(multiple)
-					line.addReplacement(MetaString::GENERAL_TXT, 42); // creature
+					line.replaceLocalString(EMetaText::GENERAL_TXT, 42); // creature
 				else
 					firstTarget->addNameReplacement(line, false);
 			}

+ 1 - 1
lib/spells/effects/Dispel.cpp

@@ -43,7 +43,7 @@ void Dispel::apply(ServerCallback * server, const Mechanics * m, const EffectTar
 			if(describe && positive && !negative && !neutral)
 			{
 				MetaString line;
-				unit->addText(line, MetaString::GENERAL_TXT, -555, true);
+				unit->addText(line, EMetaText::GENERAL_TXT, -555, true);
 				unit->addNameReplacement(line, true);
 				blm.lines.push_back(std::move(line));
 			}

+ 4 - 4
lib/spells/effects/Heal.cpp

@@ -119,19 +119,19 @@ void Heal::prepareHealEffect(int64_t value, BattleUnitsChanged & pack, BattleLog
 				// %d %s rise from the dead!
 				// in the table first comes plural string, then the singular one
 				MetaString resurrectText;
-				state->addText(resurrectText, MetaString::GENERAL_TXT, 116, resurrectedCount == 1);
+				state->addText(resurrectText, EMetaText::GENERAL_TXT, 116, resurrectedCount == 1);
 				state->addNameReplacement(resurrectText);
-				resurrectText.addReplacement(resurrectedCount);
+				resurrectText.replaceNumber(resurrectedCount);
 				logMessage.lines.push_back(std::move(resurrectText));
 			}
 			else if (unitHPgained > 0 && m->caster->getHeroCaster() == nullptr) //Show text about healed HP if healed by unit
 			{
 				MetaString healText;
 				auto casterUnit = dynamic_cast<const battle::Unit*>(m->caster);
-				healText.addTxt(MetaString::GENERAL_TXT, 414);
+				healText.appendLocalString(EMetaText::GENERAL_TXT, 414);
 				casterUnit->addNameReplacement(healText, false);
 				state->addNameReplacement(healText, false);
-				healText.addReplacement((int)unitHPgained);
+				healText.replaceNumber((int)unitHPgained);
 				logMessage.lines.push_back(std::move(healText));
 			}
 

+ 2 - 2
lib/spells/effects/Obstacle.cpp

@@ -259,8 +259,8 @@ bool Obstacle::isHexAvailable(const CBattleInfoCallback * cb, const BattleHex &
 bool Obstacle::noRoomToPlace(Problem & problem, const Mechanics * m)
 {
 	MetaString text;
-	text.addTxt(MetaString::GENERAL_TXT, 181);//No room to place %s here
-	text.addReplacement(m->getSpellName());
+	text.appendLocalString(EMetaText::GENERAL_TXT, 181);//No room to place %s here
+	text.replaceRawString(m->getSpellName());
 	problem.add(std::move(text));
 	return false;
 }

+ 5 - 5
lib/spells/effects/Summon.cpp

@@ -58,19 +58,19 @@ bool Summon::applicable(Problem & problem, const Mechanics * m) const
 			const auto *elemental = otherSummoned.front();
 
 			MetaString text;
-			text.addTxt(MetaString::GENERAL_TXT, 538);
+			text.appendLocalString(EMetaText::GENERAL_TXT, 538);
 
 			const auto *caster = dynamic_cast<const CGHeroInstance *>(m->caster);
 			if(caster)
 			{
-				text.addReplacement(caster->getNameTranslated());
+				text.replaceRawString(caster->getNameTranslated());
 
-				text.addReplacement(MetaString::CRE_PL_NAMES, elemental->creatureIndex());
+				text.replaceLocalString(EMetaText::CRE_PL_NAMES, elemental->creatureIndex());
 
 				if(caster->type->gender == EHeroGender::FEMALE)
-					text.addReplacement(MetaString::GENERAL_TXT, 540);
+					text.replaceLocalString(EMetaText::GENERAL_TXT, 540);
 				else
-					text.addReplacement(MetaString::GENERAL_TXT, 539);
+					text.replaceLocalString(EMetaText::GENERAL_TXT, 539);
 
 			}
 			problem.add(std::move(text), Problem::NORMAL);

+ 3 - 3
lib/spells/effects/Timed.cpp

@@ -30,7 +30,7 @@ static void describeEffect(std::vector<MetaString> & log, const Mechanics * m, c
 	auto addLogLine = [&](const int32_t baseTextID, const boost::logic::tribool & plural)
 	{
 		MetaString line;
-		target->addText(line, MetaString::GENERAL_TXT, baseTextID, plural);
+		target->addText(line, EMetaText::GENERAL_TXT, baseTextID, plural);
 		target->addNameReplacement(line, plural);
 		log.push_back(std::move(line));
 	};
@@ -78,10 +78,10 @@ static void describeEffect(std::vector<MetaString> & log, const Mechanics * m, c
 
 					//"The %s shrivel with age, and lose %d hit points."
 					MetaString line;
-					target->addText(line, MetaString::GENERAL_TXT, 551);
+					target->addText(line, EMetaText::GENERAL_TXT, 551);
 					target->addNameReplacement(line);
 
-					line.addReplacement(oldHealth - newHealth);
+					line.replaceNumber(oldHealth - newHealth);
 					log.push_back(std::move(line));
 					return;
 				}

+ 61 - 61
server/CGameHandler.cpp

@@ -516,8 +516,8 @@ void CGameHandler::changePrimSkill(const CGHeroInstance * hero, PrimarySkill::Pr
 
 				InfoWindow iw;
 				iw.player = hero->tempOwner;
-				iw.text.addTxt(MetaString::GENERAL_TXT, 1); //can gain no more XP
-				iw.text.addReplacement(hero->getNameTranslated());
+				iw.text.appendLocalString(EMetaText::GENERAL_TXT, 1); //can gain no more XP
+				iw.text.replaceRawString(hero->getNameTranslated());
 				sendAndApply(&iw);
 			}
 		}
@@ -725,7 +725,7 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
 		InfoWindow iw;
 		iw.player = finishingBattle->winnerHero->tempOwner;
 
-		iw.text.addTxt (MetaString::GENERAL_TXT, 30); //You have captured enemy artifact
+		iw.text.appendLocalString (EMetaText::GENERAL_TXT, 30); //You have captured enemy artifact
 
 		for (auto art : arts) //TODO; separate function to display loot for various ojects?
 		{
@@ -751,8 +751,8 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
 
 		InfoWindow iw;
 		iw.player = finishingBattle->winnerHero->tempOwner;
-		iw.text.addTxt(MetaString::GENERAL_TXT, 221); //Through eagle-eyed observation, %s is able to learn %s
-		iw.text.addReplacement(finishingBattle->winnerHero->getNameTranslated());
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 221); //Through eagle-eyed observation, %s is able to learn %s
+		iw.text.replaceRawString(finishingBattle->winnerHero->getNameTranslated());
 
 		std::ostringstream names;
 		for (int i = 0; i < cs.spells.size(); i++)
@@ -765,14 +765,14 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
 		}
 		names << ".";
 
-		iw.text.addReplacement(names.str());
+		iw.text.replaceRawString(names.str());
 
 		auto it = cs.spells.begin();
 		for (int i = 0; i < cs.spells.size(); i++, it++)
 		{
-			iw.text.addReplacement(MetaString::SPELL_NAME, it->toEnum());
+			iw.text.replaceLocalString(EMetaText::SPELL_NAME, it->toEnum());
 			if (i == cs.spells.size() - 2) //we just added pre-last name
-				iw.text.addReplacement(MetaString::GENERAL_TXT, 141); // " and "
+				iw.text.replaceLocalString(EMetaText::GENERAL_TXT, 141); // " and "
 			iw.components.emplace_back(Component::EComponentType::SPELL, *it, 0, 0);
 		}
 		sendAndApply(&iw);
@@ -1042,9 +1042,9 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
 
 		{
 			MetaString text;
-			attacker->addText(text, MetaString::GENERAL_TXT, 376);
+			attacker->addText(text, EMetaText::GENERAL_TXT, 376);
 			attacker->addNameReplacement(text);
-			text.addReplacement(totalDamage);
+			text.replaceNumber(totalDamage);
 			blm.lines.push_back(text);
 		}
 
@@ -1055,9 +1055,9 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
 	if(drainedLife > 0)
 	{
 		MetaString text;
-		attackerState->addText(text, MetaString::GENERAL_TXT, 361);
+		attackerState->addText(text, EMetaText::GENERAL_TXT, 361);
 		attackerState->addNameReplacement(text, false);
-		text.addReplacement(drainedLife);
+		text.replaceNumber(drainedLife);
 		defender->addNameReplacement(text, true);
 		blm.lines.push_back(std::move(text));
 	}
@@ -1105,9 +1105,9 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
 			// TODO: this is already implemented in Damage::describeEffect()
 			{
 				MetaString text;
-				text.addTxt(MetaString::GENERAL_TXT, 376);
-				text.addReplacement(MetaString::SPELL_NAME, SpellID::FIRE_SHIELD);
-				text.addReplacement(totalDamage);
+				text.appendLocalString(EMetaText::GENERAL_TXT, 376);
+				text.replaceLocalString(EMetaText::SPELL_NAME, SpellID::FIRE_SHIELD);
+				text.replaceNumber(totalDamage);
 				blm.lines.push_back(std::move(text));
 			}
 			addGenericKilledLog(blm, attacker, bsa.killedAmount, false);
@@ -1216,7 +1216,7 @@ void CGameHandler::addGenericKilledLog(BattleLogMessage & blm, const CStack * de
 			txt % (multiple ? VLC->generaltexth->allTexts[42] : defender->unitType()->getNameSingularTranslated()); // creature perishes
 		}
 		MetaString line;
-		line.addRawString(txt.str());
+		line.appendRawString(txt.str());
 		blm.lines.push_back(std::move(line));
 	}
 }
@@ -1988,36 +1988,36 @@ void CGameHandler::newTurn()
 			switch (n.specialWeek)
 			{
 				case NewTurn::DOUBLE_GROWTH:
-					iw.text.addTxt(MetaString::ARRAY_TXT, 131);
-					iw.text.addReplacement(MetaString::CRE_SING_NAMES, n.creatureid);
-					iw.text.addReplacement(MetaString::CRE_SING_NAMES, n.creatureid);
+					iw.text.appendLocalString(EMetaText::ARRAY_TXT, 131);
+					iw.text.replaceLocalString(EMetaText::CRE_SING_NAMES, n.creatureid);
+					iw.text.replaceLocalString(EMetaText::CRE_SING_NAMES, n.creatureid);
 					break;
 				case NewTurn::PLAGUE:
-					iw.text.addTxt(MetaString::ARRAY_TXT, 132);
+					iw.text.appendLocalString(EMetaText::ARRAY_TXT, 132);
 					break;
 				case NewTurn::BONUS_GROWTH:
-					iw.text.addTxt(MetaString::ARRAY_TXT, 134);
-					iw.text.addReplacement(MetaString::CRE_SING_NAMES, n.creatureid);
-					iw.text.addReplacement(MetaString::CRE_SING_NAMES, n.creatureid);
+					iw.text.appendLocalString(EMetaText::ARRAY_TXT, 134);
+					iw.text.replaceLocalString(EMetaText::CRE_SING_NAMES, n.creatureid);
+					iw.text.replaceLocalString(EMetaText::CRE_SING_NAMES, n.creatureid);
 					break;
 				case NewTurn::DEITYOFFIRE:
-					iw.text.addTxt(MetaString::ARRAY_TXT, 135);
-					iw.text.addReplacement(MetaString::CRE_SING_NAMES, 42); //%s imp
-					iw.text.addReplacement(MetaString::CRE_SING_NAMES, 42); //%s imp
-					iw.text.addReplacement2(15);							//%+d 15
-					iw.text.addReplacement(MetaString::CRE_SING_NAMES, 43); //%s familiar
-					iw.text.addReplacement2(15);							//%+d 15
+					iw.text.appendLocalString(EMetaText::ARRAY_TXT, 135);
+					iw.text.replaceLocalString(EMetaText::CRE_SING_NAMES, 42); //%s imp
+					iw.text.replaceLocalString(EMetaText::CRE_SING_NAMES, 42); //%s imp
+					iw.text.replacePositiveNumber(15);							//%+d 15
+					iw.text.replaceLocalString(EMetaText::CRE_SING_NAMES, 43); //%s familiar
+					iw.text.replacePositiveNumber(15);							//%+d 15
 					break;
 				default:
 					if (newMonth)
 					{
-						iw.text.addTxt(MetaString::ARRAY_TXT, (130));
-						iw.text.addReplacement(MetaString::ARRAY_TXT, getRandomGenerator().nextInt(32, 41));
+						iw.text.appendLocalString(EMetaText::ARRAY_TXT, (130));
+						iw.text.replaceLocalString(EMetaText::ARRAY_TXT, getRandomGenerator().nextInt(32, 41));
 					}
 					else
 					{
-						iw.text.addTxt(MetaString::ARRAY_TXT, (133));
-						iw.text.addReplacement(MetaString::ARRAY_TXT, getRandomGenerator().nextInt(43, 57));
+						iw.text.appendLocalString(EMetaText::ARRAY_TXT, (133));
+						iw.text.replaceLocalString(EMetaText::ARRAY_TXT, getRandomGenerator().nextInt(43, 57));
 					}
 			}
 			for (auto & elem : gs->players)
@@ -2496,8 +2496,8 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, const PlayerColor owne
 			{
 				InfoWindow iw;
 				iw.player = oldOwner;
-				iw.text.addTxt(MetaString::GENERAL_TXT, 6); //%s, you have lost your last town. If you do not conquer another town in the next week, you will be eliminated.
-				iw.text.addReplacement(MetaString::COLOR, oldOwner.getNum());
+				iw.text.appendLocalString(EMetaText::GENERAL_TXT, 6); //%s, you have lost your last town. If you do not conquer another town in the next week, you will be eliminated.
+				iw.text.replaceLocalString(EMetaText::COLOR, oldOwner.getNum());
 				sendAndApply(&iw);
 			}
 		}
@@ -2797,57 +2797,57 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t
 		iw.player = h1->tempOwner;
 		iw.components.emplace_back(Component::EComponentType::SEC_SKILL, 18, ScholarSkillLevel, 0);
 
-		iw.text.addTxt(MetaString::GENERAL_TXT, 139);//"%s, who has studied magic extensively,
-		iw.text.addReplacement(h1->getNameTranslated());
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 139);//"%s, who has studied magic extensively,
+		iw.text.replaceRawString(h1->getNameTranslated());
 
 		if (!cs2.spells.empty())//if found new spell - apply
 		{
-			iw.text.addTxt(MetaString::GENERAL_TXT, 140);//learns
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT, 140);//learns
 			int size = static_cast<int>(cs2.spells.size());
 			for (auto it : cs2.spells)
 			{
 				iw.components.emplace_back(Component::EComponentType::SPELL, it, 1, 0);
-				iw.text.addTxt(MetaString::SPELL_NAME, it.toEnum());
+				iw.text.appendLocalString(EMetaText::SPELL_NAME, it.toEnum());
 				switch (size--)
 				{
 					case 2:
-						iw.text.addTxt(MetaString::GENERAL_TXT, 141);
+						iw.text.appendLocalString(EMetaText::GENERAL_TXT, 141);
 					case 1:
 						break;
 					default:
-						iw.text.addRawString(", ");
+						iw.text.appendRawString(", ");
 				}
 			}
-			iw.text.addTxt(MetaString::GENERAL_TXT, 142);//from %s
-			iw.text.addReplacement(h2->getNameTranslated());
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT, 142);//from %s
+			iw.text.replaceRawString(h2->getNameTranslated());
 			sendAndApply(&cs2);
 		}
 
 		if (!cs1.spells.empty() && !cs2.spells.empty())
 		{
-			iw.text.addTxt(MetaString::GENERAL_TXT, 141);//and
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT, 141);//and
 		}
 
 		if (!cs1.spells.empty())
 		{
-			iw.text.addTxt(MetaString::GENERAL_TXT, 147);//teaches
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT, 147);//teaches
 			int size = static_cast<int>(cs1.spells.size());
 			for (auto it : cs1.spells)
 			{
 				iw.components.emplace_back(Component::EComponentType::SPELL, it, 1, 0);
-				iw.text.addTxt(MetaString::SPELL_NAME, it.toEnum());
+				iw.text.appendLocalString(EMetaText::SPELL_NAME, it.toEnum());
 				switch (size--)
 				{
 					case 2:
-						iw.text.addTxt(MetaString::GENERAL_TXT, 141);
+						iw.text.appendLocalString(EMetaText::GENERAL_TXT, 141);
 					case 1:
 						break;
 					default:
-						iw.text.addRawString(", ");
+						iw.text.appendRawString(", ");
 				}
 			}
-			iw.text.addTxt(MetaString::GENERAL_TXT, 148);//from %s
-			iw.text.addReplacement(h2->getNameTranslated());
+			iw.text.appendLocalString(EMetaText::GENERAL_TXT, 148);//from %s
+			iw.text.replaceRawString(h2->getNameTranslated());
 			sendAndApply(&cs1);
 		}
 		sendAndApply(&iw);
@@ -4673,9 +4673,9 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
 			BattleLogMessage message;
 
 			MetaString text;
-			stack->addText(text, MetaString::GENERAL_TXT, 120);
+			stack->addText(text, EMetaText::GENERAL_TXT, 120);
 			stack->addNameReplacement(text);
-			text.addReplacement(difference);
+			text.replaceNumber(difference);
 
 			message.lines.push_back(text);
 
@@ -5354,7 +5354,7 @@ void CGameHandler::handleTimeEvents()
 				//prepare dialog
 				InfoWindow iw;
 				iw.player = color;
-				iw.text.addRawString(ev.message);
+				iw.text.appendRawString(ev.message);
 
 				for (int i=0; i<ev.resources.size(); i++)
 				{
@@ -5405,7 +5405,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
 			// dialog
 			InfoWindow iw;
 			iw.player = player;
-			iw.text.addRawString(ev.message);
+			iw.text.appendRawString(ev.message);
 
 			if (ev.resources.nonZero())
 			{
@@ -5791,10 +5791,10 @@ void CGameHandler::getVictoryLossMessage(PlayerColor player, const EVictoryLossC
 {
 	out.player = player;
 	out.text.clear();
-	out.text.addRawString(VLC->generaltexth->translate(victoryLossCheckResult.messageToOthers));
+	out.text.appendRawString(VLC->generaltexth->translate(victoryLossCheckResult.messageToOthers));
 	// hackish, insert one player-specific string, if applicable
 	if (victoryLossCheckResult.messageToOthers.find("%s") != std::string::npos)
-		out.text.addReplacement(MetaString::COLOR, player.getNum());
+		out.text.replaceLocalString(EMetaText::COLOR, player.getNum());
 
 	out.components.emplace_back(Component::EComponentType::FLAG, player.getNum(), 0, 0);
 }
@@ -5822,8 +5822,8 @@ bool CGameHandler::dig(const CGHeroInstance *h)
 	iw.player = h->tempOwner;
 	if (gs->map->grailPos == h->visitablePos())
 	{
-		iw.text.addTxt(MetaString::GENERAL_TXT, 58); //"Congratulations! After spending many hours digging here, your hero has uncovered the "
-		iw.text.addTxt(MetaString::ART_NAMES, ArtifactID::GRAIL);
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 58); //"Congratulations! After spending many hours digging here, your hero has uncovered the "
+		iw.text.appendLocalString(EMetaText::ART_NAMES, ArtifactID::GRAIL);
 		iw.soundID = soundBase::ULTIMATEARTIFACT;
 		giveHeroNewArtifact(h, VLC->arth->objects[ArtifactID::GRAIL], ArtifactPosition::FIRST_AVAILABLE); //give grail
 		sendAndApply(&iw);
@@ -5831,12 +5831,12 @@ bool CGameHandler::dig(const CGHeroInstance *h)
 		iw.soundID = soundBase::invalid;
 		iw.components.emplace_back(Component::EComponentType::ARTIFACT, ArtifactID::GRAIL, 0, 0);
 		iw.text.clear();
-		iw.text.addTxt(MetaString::ART_DESCR, ArtifactID::GRAIL);
+		iw.text.appendLocalString(EMetaText::ART_DESCR, ArtifactID::GRAIL);
 		sendAndApply(&iw);
 	}
 	else
 	{
-		iw.text.addTxt(MetaString::GENERAL_TXT, 59); //"Nothing here. \n Where could it be?"
+		iw.text.appendLocalString(EMetaText::GENERAL_TXT, 59); //"Nothing here. \n Where could it be?"
 		iw.soundID = soundBase::Dig;
 		sendAndApply(&iw);
 	}
@@ -7221,7 +7221,7 @@ void CGameHandler::showInfoDialog(const std::string & msg, PlayerColor player)
 {
 	InfoWindow iw;
 	iw.player = player;
-	iw.text.addRawString(msg);
+	iw.text.appendRawString(msg);
 	showInfoDialog(&iw);
 }