mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Renamed MetaString methods to more logical names
This commit is contained in:
		| @@ -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(); | ||||
|   | ||||
| @@ -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..."); | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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) | ||||
| 	switch(type) | ||||
| 	{ | ||||
| 		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) | ||||
| 	{ | ||||
| 		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 | ||||
|   | ||||
							
								
								
									
										125
									
								
								lib/MetaString.h
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								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 | ||||
|   | ||||
| @@ -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))); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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(); | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
| 	{ | ||||
|   | ||||
| @@ -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); | ||||
| 		} | ||||
|   | ||||
| @@ -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); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
| 		} | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
| 	} | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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); | ||||
| 		} | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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()); | ||||
|   | ||||
| @@ -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); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
| 	} | ||||
|   | ||||
| @@ -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(); | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
| 			} | ||||
|   | ||||
| @@ -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)); | ||||
| 			} | ||||
|   | ||||
| @@ -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)); | ||||
| 			} | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
| 				} | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user