2
0
Эх сурвалжийг харах

Further part of external dwellings handling. Still not done.
Redone MetaString.

Michał W. Urbańczyk 16 жил өмнө
parent
commit
1d816b2eb9

+ 6 - 3
client/NetPacksClient.cpp

@@ -262,7 +262,8 @@ void InfoWindow::applyCl( CClient *cl )
 	{
 		comps.push_back(&components[i]);
 	}
-	std::string str = toString(text);
+	std::string str;
+	text.toString(str);
 
 	if(vstd::contains(cl->playerint,player))
 		cl->playerint[player]->showInfoDialog(str,comps,(soundBase::soundID)soundID);
@@ -282,7 +283,9 @@ void HeroLevelUp::applyCl( CClient *cl )
 
 void BlockingDialog::applyCl( CClient *cl )
 {
-	std::string str = toString(text);
+	std::string str;
+	text.toString(str);
+
 	if(vstd::contains(cl->playerint,player))
 		cl->playerint[player]->showBlockingDialog(str,components,id,(soundBase::soundID)soundID,selection(),cancel());
 	else
@@ -452,7 +455,7 @@ void PlayerMessage::applyCl(CClient *cl)
 void ShowInInfobox::applyCl(CClient *cl)
 {
 	SComponent sc(c);
-	sc.description = toString(text);
+	text.toString(sc.description);
 	if(cl->playerint[player]->human)
 	{
 		static_cast<CPlayerInterface*>(cl->playerint[player])->showComp(sc);

+ 9 - 0
hch/CCreatureHandler.h

@@ -66,6 +66,15 @@ public:
 	si32 maxAmount(const std::vector<si32> &res) const; //how many creatures can be bought
 	static int getQuantityID(const int & quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion
 
+	template<typename RanGen>
+	int getRandomAmount(RanGen &ranGen)
+	{
+		if(ammMax == ammMin)
+			return ammMax;
+		else
+			return ammMin + (ranGen() % (ammMax - ammMin));
+	}
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & namePl & nameSing & nameRef

+ 1 - 1
hch/CDefObjInfoHandler.cpp

@@ -55,7 +55,7 @@ void CDefObjInfoHandler::load()
 		{
 			nobj->blockMap[o] = 0xff;
 			nobj->visitMap[o] = 0x00;
-			nobj->coverageMap[0] = 0x00;
+			nobj->coverageMap[o] = 0x00;
 		}
 		inp>>mapStr;
 		std::reverse(mapStr.begin(), mapStr.end());

+ 9 - 0
hch/CGeneralTextHandler.cpp

@@ -305,6 +305,15 @@ void CGeneralTextHandler::load()
 		creGens.push_back(temp);
 	}
 
+	tlog5 << "\t\tReading CRGN4 \n";
+	buf = bitmaph->getTextFile("CRGEN4.TXT");
+	it=0;
+	while (it<buf.length()-1)
+	{
+		loadToIt(temp,buf,it,3);
+		creGens4.push_back(temp);
+	}
+
 	buf = bitmaph->getTextFile("GENRLTXT.TXT");
 	std::string tmp;
 	andame = buf.size();

+ 1 - 0
hch/CGeneralTextHandler.h

@@ -53,6 +53,7 @@ public:
 	//objects
 	std::vector<std::string> names; //vector of objects; i-th object in vector has subnumber i
 	std::vector<std::string> creGens; //names of creatures' generators
+	std::vector<std::string> creGens4; //names of multiple creatures' generators
 	std::vector<std::string> advobtxt;
 	std::vector<std::string> xtrainfo;
 	std::vector<std::string> restypes;

+ 136 - 30
hch/CObjectHandler.cpp

@@ -908,12 +908,24 @@ void CGDwelling::initObj()
 	switch(ID)
 	{
 	case 17:
-		creatures.resize(1);
-		creatures[0].second.push_back(VLC->objh->cregens[subID]);
+		{
+			int crid = VLC->objh->cregens[subID];
+			CCreature *crs = &VLC->creh->creatures[crid];
+
+			creatures.resize(1);
+			creatures[0].second.push_back(crid);
+			hoverName = VLC->generaltexth->creGens[subID];
+			if(crs->level > 4)
+			{
+				army.slots[0].first = crs->idNumber;
+				army.slots[0].second = crs->getRandomAmount(ran);
+			}
+		}
 		break;
+
 	case 20:
 		creatures.resize(4);
-		if(subID == 1) // Elemental Conflux 
+		if(subID == 0) // Elemental Conflux 
 		{
 			creatures[0].second.push_back(32);  //Stone Golem
 			creatures[1].second.push_back(33);  //Iron Golem  
@@ -931,7 +943,9 @@ void CGDwelling::initObj()
 		{
 			assert(0);
 		}
+		hoverName = VLC->generaltexth->creGens4[subID];
 		break;
+
 	default:
 		assert(0);
 		break;
@@ -940,14 +954,29 @@ void CGDwelling::initObj()
 
 void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
 {
+	if(h->tempOwner != tempOwner  &&  army) //object is guarded
+	{
+		BlockingDialog bd;
+		bd.player = h->tempOwner;
+		bd.flags = BlockingDialog::ALLOW_CANCEL;
+		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(MetaString::CREGENS, subID);
+		bd.text.addReplacement(MetaString::ARRAY_TXT, 176 + CCreature::getQuantityID(army.slots.begin()->second.second)*3);
+		bd.text.addReplacement(MetaString::CRE_PL_NAMES, creatures[0].second[0]);
+		cb->showBlockingDialog(&bd, boost::bind(&CGDwelling::wantsFight, this, h, _1));
+		return;
+	}
+
 	if(h->tempOwner != tempOwner)
 		cb->setOwner(id, h->tempOwner);
 
-	OpenWindow ow;
-	ow.id1 = id;
-	ow.id2 = id;
-	ow.window = OpenWindow::RECRUITMENT_FIRST;
-	cb->sendAndApply(&ow);
+	BlockingDialog bd;
+	bd.player = h->tempOwner;
+	bd.flags = BlockingDialog::ALLOW_CANCEL;
+	bd.text.addTxt(MetaString::ADVOB_TXT, 35); //{%s}	Would you like to recruit %s?
+	bd.text.addReplacement(MetaString::CREGENS, subID);
+	bd.text.addReplacement(MetaString::CRE_PL_NAMES, creatures[0].second[0]);
+	cb->showBlockingDialog(&bd, boost::bind(&CGDwelling::heroAcceptsCreatures, this, h, _1));
 }
 
 void CGDwelling::newTurn() const
@@ -974,10 +1003,88 @@ void CGDwelling::newTurn() const
 		cb->sendAndApply(&sac);
 }
 
+void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h, ui32 answer ) const
+{
+	if(!answer)
+		return;
+
+	int crid = creatures[0].second[0];
+	CCreature *crs = &VLC->creh->creatures[crid];
+
+	if(crs->level == 1) //first level - creatures are for free
+	{
+		if(creatures[0].first) //there are available creatures
+		{
+			int slot = h->army.getSlotFor(crid);
+			if(slot < 0) //no available slot
+			{
+				InfoWindow iw;
+				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);
+				cb->showInfoDialog(&iw);
+			}
+			else //give creatures
+			{
+				SetAvailableCreatures sac;
+				sac.tid = id;
+				sac.creatures = creatures;
+				sac.creatures[0].first = 0;
+
+				SetGarrisons sg;
+				sg.garrs[h->id] = h->army;
+				sg.garrs[h->id].slots[slot].first = crid;
+				sg.garrs[h->id].slots[slot].second += creatures[0].first;
+
+				InfoWindow iw;
+				iw.player = h->tempOwner;
+				iw.text.addTxt(MetaString::GENERAL_TXT, 423); //%d %s join your army.
+				iw.text.addReplacement(creatures[0].first);
+				iw.text.addReplacement(MetaString::CRE_PL_NAMES, crid);
+
+				cb->showInfoDialog(&iw);
+				cb->sendAndApply(&sac);
+				cb->sendAndApply(&sg);
+			}
+		}
+		else //there no creatures
+		{
+			InfoWindow iw;
+			iw.text.addTxt(MetaString::GENERAL_TXT, 422); //There are no %s here to recruit.
+			iw.text.addReplacement(MetaString::CRE_PL_NAMES, crid);
+			iw.player = h->tempOwner;
+			cb->sendAndApply(&iw);
+		}
+	}
+	else if(ID == 17)
+	{
+		OpenWindow ow;
+		ow.id1 = id;
+		ow.id2 = id;
+		ow.window = OpenWindow::RECRUITMENT_FIRST;
+		cb->sendAndApply(&ow);
+	}
+}
+
+void CGDwelling::wantsFight( const CGHeroInstance *h, ui32 answer ) const
+{
+	if(answer)
+		cb->startBattleI(h->id,army,pos,boost::bind(&CGDwelling::fightOver, this, h, _1));
+}
+
+void CGDwelling::fightOver(const CGHeroInstance *h, BattleResult *result) const
+{
+	if (result->winner == 0)
+	{
+		onHeroVisit(h);
+	}
+}
+
 int CGTownInstance::getSightRadious() const //returns sight distance
 {
 	return 5;
 }
+
 int CGTownInstance::fortLevel() const //0 - none, 1 - fort, 2 - citadel, 3 - castle
 {
 	if((builtBuildings.find(9))!=builtBuildings.end())
@@ -988,6 +1095,7 @@ int CGTownInstance::fortLevel() const //0 - none, 1 - fort, 2 - citadel, 3 - cas
 		return 1;
 	return 0;
 }
+
 int CGTownInstance::hallLevel() const // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
 {
 	if ((builtBuildings.find(13))!=builtBuildings.end())
@@ -1109,10 +1217,8 @@ void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
 }
 
 void CGTownInstance::initObj()
-{
-	MetaString ms;
-	ms << name << ", " << town->Name();
-	hoverName = toString(ms);
+{ 
+	hoverName = name + ", " + town->Name();
 
 	creatures.resize(CREATURES_PER_TOWN);
 	for (int i = 0; i < CREATURES_PER_TOWN; i++)
@@ -1485,8 +1591,8 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
 		{
 			BlockingDialog ynd(true,false);
 			ynd.player = h->tempOwner;
-			ynd.text << std::pair<ui8,ui32>(11,86); 
-			ynd.text.replacements.push_back(VLC->creh->creatures[subID].namePl);
+			ynd.text << std::pair<ui8,ui32>(MetaString::ADVOB_TXT, 86); 
+			ynd.text.addReplacement(MetaString::CRE_PL_NAMES, subID);
 			cb->showBlockingDialog(&ynd,boost::bind(&CGCreature::joinDecision,this,h,0,_1));
 			break;
 		}
@@ -1566,7 +1672,7 @@ void CGCreature::initObj()
 	int pom = CCreature::getQuantityID(army.slots.find(0)->second.second);
 	pom = 174 + 3*pom + 1;
 	ms << std::pair<ui8,ui32>(6,pom) << " " << std::pair<ui8,ui32>(7,subID);
-	hoverName = toString(ms);
+	ms.toString(hoverName);
 }
 
 int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
@@ -1719,7 +1825,7 @@ void CGCreature::flee( const CGHeroInstance * h ) const
 	BlockingDialog ynd(true,false);
 	ynd.player = h->tempOwner;
 	ynd.text << std::pair<ui8,ui32>(11,91); 
-	ynd.text.replacements.push_back(VLC->creh->creatures[subID].namePl);
+	ynd.text.addReplacement(MetaString::CRE_PL_NAMES, subID);
 	cb->showBlockingDialog(&ynd,boost::bind(&CGCreature::fleeDecision,this,h,_1));
 }
 
@@ -1778,7 +1884,7 @@ void CGMine::initObj()
 		tempOwner = NEUTRAL_PLAYER;	
 	else
 		ms << " (" << std::pair<ui8,ui32>(6,23+tempOwner) << ")";
-	hoverName = toString(ms);
+	ms.toString(hoverName);
 }
 
 void CGResource::initObj()
@@ -1839,7 +1945,7 @@ void CGResource::collectRes( int player ) const
 	sii.player = player;
 	sii.c = Component(2,subID,amount,0);
 	sii.text << std::pair<ui8,ui32>(11,113);
-	sii.text.replacements.push_back(VLC->generaltexth->restypes[subID]);
+	sii.text.addReplacement(MetaString::RES_NAMES, subID);
 	cb->showCompInfo(&sii);
 	cb->removeObject(id);
 }
@@ -2140,7 +2246,7 @@ void CGPickable::onHeroVisit( const CGHeroInstance * h ) const
 				iw.player = h->tempOwner;
 				iw.components.push_back(Component(4,val1,1,0));
 				iw.text << std::pair<ui8,ui32>(11,145);
-				iw.text.replacements.push_back(VLC->arth->artifacts[val1].Name());
+				iw.text.addReplacement(MetaString::ART_NAMES, val1);
 				cb->showInfoDialog(&iw);
 				break;
 			}
@@ -2193,18 +2299,18 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
 	if(h->getSecSkillLevel(ability)) //you alredy know this skill
 	{
 		iw.text << std::pair<ui8,ui32>(11,172);
-		iw.text.replacements.push_back(VLC->generaltexth->skillName[ability]);
+		iw.text.addReplacement(MetaString::SEC_SKILL_NAME, ability);
 	}
 	else if(h->secSkills.size() >= SKILL_PER_HERO) //already all skills slots used
 	{
 		iw.text << std::pair<ui8,ui32>(11,173);
-		iw.text.replacements.push_back(VLC->generaltexth->skillName[ability]);
+		iw.text.addReplacement(MetaString::SEC_SKILL_NAME, ability);
 	}
 	else //give sec skill
 	{
 		iw.components.push_back(Component(1, ability, 1, 0));
 		iw.text << std::pair<ui8,ui32>(11,171);
-		iw.text.replacements.push_back(VLC->generaltexth->skillName[ability]);
+		iw.text.addReplacement(MetaString::SEC_SKILL_NAME, ability);
 		cb->changeSecSkill(h->id,ability,1,true);
 	}
 
@@ -2260,7 +2366,7 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
 		gbonus.bonus.type = HeroBonus::LUCK;
 		gbonus.bonus.val = rand()%5 - 1;
 		gbonus.bdescr <<  std::pair<ui8,ui32>(6,69);
-		gbonus.bdescr.replacements.push_back((gbonus.bonus.val<0 ? "-" : "+") + boost::lexical_cast<std::string>(gbonus.bonus.val));
+		gbonus.bdescr.addReplacement((gbonus.bonus.val<0 ? "-" : "+") + boost::lexical_cast<std::string>(gbonus.bonus.val));
 		break;
 	case 38: //idol of fortune
 		messageID = 62;
@@ -2596,14 +2702,14 @@ void CGEvent::giveContents( const CGHeroInstance *h, bool afterBattle ) const
 			if(iw.components.front().val == 1)
 			{
 				iw.text.addTxt(MetaString::ADVOB_TXT,185);//A %s joins %s's army.
-				iw.text.replacements.push_back(VLC->creh->creatures[iw.components.front().subtype].nameSing);
+				iw.text.addReplacement(MetaString::CRE_SING_NAMES, iw.components.front().subtype);
 			}
 			else
 			{
 				iw.text.addTxt(MetaString::ADVOB_TXT,186);//%s join %s's army.
-				iw.text.replacements.push_back(VLC->creh->creatures[iw.components.front().subtype].namePl);
+				iw.text.addReplacement(MetaString::CRE_PL_NAMES, iw.components.front().subtype);
 			}
-			iw.text.replacements.push_back(h->name);
+			iw.text.addReplacement(h->name);
 		}
 		else
 		{
@@ -2661,7 +2767,7 @@ void CGEvent::getText( InfoWindow &iw, bool &afterBattle, int text, const CGHero
 	if(afterBattle)
 	{
 		iw.text.addTxt(MetaString::ADVOB_TXT,text);//%s has lost treasure.
-		iw.text.replacements.push_back(h->name);
+		iw.text.addReplacement(h->name);
 	}
 	else
 	{
@@ -2677,7 +2783,7 @@ void CGEvent::getText( InfoWindow &iw, bool &afterBattle, int val, int positive,
 	if(afterBattle)
 	{
 		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.replacements.push_back(h->name);
+		iw.text.addReplacement(h->name);
 	}
 	else
 	{
@@ -2927,7 +3033,7 @@ void CGOnceVisitable::onHeroVisit( const CGHeroInstance * h ) const
 		if(ID == 105  &&  artOrRes == 1) 
 		{
 			txtid++;
-			iw.text.replacements.push_back(VLC->arth->artifacts[bonusType].Name());
+			iw.text.addReplacement(MetaString::ART_NAMES, bonusType);
 		}
 
 
@@ -3057,7 +3163,7 @@ void CGOnceVisitable::searchTomb(const CGHeroInstance *h, ui32 accept) const
 		{
 			iw.text.addTxt(MetaString::ADVOB_TXT,162);
 			iw.components.push_back(Component(Component::ARTIFACT,bonusType,0,0));
-			iw.text.replacements.push_back(VLC->arth->artifacts[bonusType].Name());
+			iw.text.addReplacement(MetaString::ART_NAMES, bonusType);
 
 			cb->giveHeroArtifact(bonusType,h->id,-2);
 		}

+ 3 - 0
hch/CObjectHandler.h

@@ -297,6 +297,9 @@ public:
 	void initObj();
 	void onHeroVisit(const CGHeroInstance * h) const;
 	void newTurn() const;
+	void heroAcceptsCreatures(const CGHeroInstance *h, ui32 answer) const;
+	void fightOver(const CGHeroInstance *h, BattleResult *result) const;
+	void wantsFight(const CGHeroInstance *h, ui32 answer) const;
 };
 
 class DLL_EXPORT CGTownInstance : public CGDwelling

+ 96 - 67
lib/CGameState.cpp

@@ -19,10 +19,11 @@
 #include "../StartInfo.h"
 #include "NetPacks.h"
 #include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
 #include <boost/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
-
 #include "RegisterTypes.cpp"
+
 boost::rand48 ran;
 
 #ifdef min
@@ -89,83 +90,111 @@ public:
 
 } *applierGs = NULL;
 
-std::string DLL_EXPORT toString(MetaString &ms)
+void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst) const
 {
-	std::string ret;
-	for(size_t i=0;i<ms.message.size();++i)
+	int type = txt.first, ser = txt.second;
+
+	if(type == ART_NAMES)
+	{
+		dst = VLC->arth->artifacts[ser].Name();
+	}
+	else if(type == CRE_PL_NAMES)
+	{
+		dst = VLC->creh->creatures[ser].namePl;
+	}
+	else if(type == MINE_NAMES)
+	{
+		dst = VLC->generaltexth->mines[ser].first;
+	}
+	else if(type == MINE_EVNTS)
 	{
-		if(ms.message[i]>0)
+		dst = VLC->generaltexth->mines[ser].second;
+	}
+	else if(type == SPELL_NAME)
+	{
+		dst = VLC->spellh->spells[ser].name;
+	}
+	else if(type == CRE_SING_NAMES)
+	{
+		dst = VLC->creh->creatures[ser].nameSing;
+	}
+	else
+	{
+		std::vector<std::string> *vec;
+		switch(type)
 		{
-			ret += ms.strings[ms.message[i]-1];
+		case GENERAL_TXT:
+			vec = &VLC->generaltexth->allTexts;
+			break;
+		case XTRAINFO_TXT:
+			vec = &VLC->generaltexth->xtrainfo;
+			break;
+		case OBJ_NAMES:
+			vec = &VLC->generaltexth->names;
+			break;
+		case RES_NAMES:
+			vec = &VLC->generaltexth->restypes;
+			break;
+		case ARRAY_TXT:
+			vec = &VLC->generaltexth->arraytxt;
+			break;
+		case CREGENS:
+			vec = &VLC->generaltexth->creGens;
+			break;
+		case ADVOB_TXT:
+			vec = &VLC->generaltexth->advobtxt;
+			break;
+		case ART_EVNTS:
+			vec = &VLC->generaltexth->artifEvents;
+			break;
+		case SEC_SKILL_NAME:
+			vec = &VLC->generaltexth->skillName;
+			break;
 		}
-		else
+		dst = (*vec)[ser];
+	}
+}
+
+DLL_EXPORT void MetaString::toString(std::string &dst) const
+{
+	size_t exSt = 0, loSt = 0, nums = 0;
+	dst.clear();
+
+	for(size_t i=0;i<message.size();++i)
+	{//TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER
+		switch(message[i])
 		{
-			std::vector<std::string> *vec;
-			int type = ms.texts[-ms.message[i]-1].first,
-				ser = ms.texts[-ms.message[i]-1].second;
-			if(type == 5)
-			{
-				ret += VLC->arth->artifacts[ser].Name();
-				continue;
-			}
-			else if(type == 7)
-			{
-				ret += VLC->creh->creatures[ser].namePl;
-				continue;
-			}
-			else if(type == 9)
-			{
-				ret += VLC->generaltexth->mines[ser].first;
-				continue;
-			}
-			else if(type == 10)
-			{
-				ret += VLC->generaltexth->mines[ser].second;
-				continue;
-			}
-			else if(type == MetaString::SPELL_NAME)
+		case TEXACT_STRING:
+			dst += exactStrings[exSt++];
+			break;
+		case TLOCAL_STRING:
 			{
-				ret += VLC->spellh->spells[ser].name;
-				continue;
+				std::string hlp;
+				getLocalString(localStrings[loSt++], hlp);
+				dst += hlp;
 			}
-			else
+			break;
+		case TNUMBER:
+			dst += boost::lexical_cast<std::string>(numbers[nums++]);
+			break;
+		case TREPLACE_ESTRING:
+			dst.replace(dst.find("%s"), 2, exactStrings[exSt++]);
+			break;
+		case TREPLACE_LSTRING:
 			{
-				switch(type)
-				{
-				case 1:
-					vec = &VLC->generaltexth->allTexts;
-					break;
-				case 2:
-					vec = &VLC->generaltexth->xtrainfo;
-					break;
-				case 3:
-					vec = &VLC->generaltexth->names;
-					break;
-				case 4:
-					vec = &VLC->generaltexth->restypes;
-					break;
-				case 6:
-					vec = &VLC->generaltexth->arraytxt;
-					break;
-				case 8:
-					vec = &VLC->generaltexth->creGens;
-					break;
-				case 11:
-					vec = &VLC->generaltexth->advobtxt;
-					break;
-				case 12:
-					vec = &VLC->generaltexth->artifEvents;
-					break;
-				}
-				ret += (*vec)[ser];
+				std::string hlp;
+				getLocalString(localStrings[loSt++], hlp);
+				dst.replace(dst.find("%s"), 2, hlp);
 			}
+			break;
+		case TREPLACE_NUMBER:
+			dst.replace(dst.find("%d"), 2, boost::lexical_cast<std::string>(numbers[nums++]));
+			break;
+		default:
+			tlog1 << "MetaString processing error!\n";
+			break;
 		}
 	}
-	for(size_t i=0; i < ms.replacements.size(); ++i)
-	{
-		ret.replace(ret.find("%s"),2,ms.replacements[i]);
-	}
-	return ret;
 }
 
 static CGObjectInstance * createObject(int id, int subid, int3 pos, int owner)

+ 0 - 3
lib/CGameState.h

@@ -50,9 +50,6 @@ struct CPack;
 class CSpell;
 
 
-std::string DLL_EXPORT toString(MetaString &ms);
-
-
 namespace boost
 {
 	class shared_mutex;

+ 48 - 15
lib/NetPacks.h

@@ -66,44 +66,77 @@ struct Query : public CPackForClient
 	ui32 id;
 };
 
+
 struct MetaString : public CPack //2001 helper for object scrips
 {
+private:
+	enum EMessage {TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER};
+public:
 	enum {GENERAL_TXT=1, XTRAINFO_TXT, OBJ_NAMES, RES_NAMES, ART_NAMES, ARRAY_TXT, CRE_PL_NAMES, CREGENS, MINE_NAMES, 
-		MINE_EVNTS, ADVOB_TXT, ART_EVNTS, SPELL_NAME};
-	std::vector<std::string> strings;
-	std::vector<std::pair<ui8,ui32> > texts; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID].first; 10 - objh->mines[ID].second; 11 - objh->advobtxt
-	std::vector<si32> message;
-	std::vector<std::string> replacements;
+		MINE_EVNTS, ADVOB_TXT, ART_EVNTS, SPELL_NAME, SEC_SKILL_NAME, CRE_SING_NAMES};
+
+	std::vector<ui8> message; //vector of EMessage
+
+	std::vector<std::pair<ui8,ui32> > localStrings; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID].first; 10 - objh->mines[ID].second; 11 - objh->advobtxt
+	std::vector<std::string> exactStrings;
+	std::vector<si32> numbers;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & strings & texts & message & replacements;
+		h & exactStrings & localStrings & message & numbers;
 	}
 	void addTxt(ui8 type, ui32 serial)
 	{
-		*this << std::make_pair(type,serial);
+		message.push_back(TLOCAL_STRING);
+		localStrings.push_back(std::pair<ui8,ui32>(type, serial));
 	}
 	MetaString& operator<<(const std::pair<ui8,ui32> &txt)
 	{
-		message.push_back(-((si32)texts.size())-1);
-		texts.push_back(txt);
+		message.push_back(TLOCAL_STRING);
+		localStrings.push_back(txt);
 		return *this;
 	}
 	MetaString& operator<<(const std::string &txt)
 	{
-		message.push_back(strings.size()+1);
-		strings.push_back(txt);
+		message.push_back(TEXACT_STRING);
+		exactStrings.push_back(txt);
 		return *this;
 	}
+	MetaString& operator<<(int txt)
+	{
+		message.push_back(TNUMBER);
+		numbers.push_back(txt);
+		return *this;
+	}
+	void addReplacement(ui8 type, ui32 serial)
+	{
+		message.push_back(TREPLACE_LSTRING);
+		localStrings.push_back(std::pair<ui8,ui32>(type, serial));
+	}
+	void addReplacement(const std::string &txt)
+	{
+		message.push_back(TREPLACE_ESTRING);
+		exactStrings.push_back(txt);
+	}
+	void addReplacement(int txt)
+	{
+		message.push_back(TREPLACE_NUMBER);
+		numbers.push_back(txt);
+	}
 	void clear()
 	{
-		strings.clear();
-		texts.clear();
+		exactStrings.clear();
+		localStrings.clear();
 		message.clear();
-		replacements.clear();
+		numbers.clear();
 	}
+	DLL_EXPORT void toString(std::string &dst) const;
+	void getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst) const;
 
-	MetaString(){type = 2001;};
+	MetaString()
+	{
+		type = 2001;
+	}
 }; 
 
 /***********************************************************************************************************/

+ 3 - 3
lib/NetPacksLib.cpp

@@ -179,7 +179,7 @@ DLL_EXPORT void GiveBonus::applyGs( CGameState *gs )
 
 	std::string &descr = h->bonuses.back().description;
 
-	if(!bdescr.texts.size() 
+	if(!bdescr.message.size() 
 		&& bonus.source == HeroBonus::OBJECT 
 		&& (bonus.type == HeroBonus::LUCK || bonus.type == HeroBonus::MORALE || bonus.type == HeroBonus::MORALE_AND_LUCK)
 		&& gs->map->objects[bonus.id]->ID == 26) //it's morale/luck bonus from an event without description
@@ -189,7 +189,7 @@ DLL_EXPORT void GiveBonus::applyGs( CGameState *gs )
 	}
 	else
 	{
-		descr = toString(bdescr);
+		bdescr.toString(descr);
 	}
 }
 
@@ -461,7 +461,7 @@ DLL_EXPORT void SetObjectProperty::applyGs( CGameState *gs )
 
 DLL_EXPORT void SetHoverName::applyGs( CGameState *gs )
 {
-	gs->map->objects[id]->hoverName = toString(name);
+	name.toString(gs->map->objects[id]->hoverName);
 }
 
 DLL_EXPORT void HeroLevelUp::applyGs( CGameState *gs )