Browse Source

Stacks #5: giving creatures, practically finished (many fixes needed).

Michał W. Urbańczyk 15 years ago
parent
commit
02e4ef507e

+ 1 - 1
client/CBattleInterface.cpp

@@ -3589,7 +3589,7 @@ void CBattleHex::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 
 	if(hovered && strictHovered) //print attacked creature to console
 	{
-		if(myInterface->console->alterTxt.size() == 0 && myInterface->curInt->cb->battleGetStackByID(myNumber) != NULL &&
+		if(myInterface->console->alterTxt.size() == 0 && myInterface->curInt->cb->battleGetStackByPos(myNumber) != NULL &&
 			myInterface->curInt->cb->battleGetStackByPos(myNumber)->owner != myInterface->curInt->playerID &&
 			myInterface->curInt->cb->battleGetStackByPos(myNumber)->alive())
 		{

+ 2 - 2
client/Client.h

@@ -110,7 +110,7 @@ public:
 	void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb){};
 	void showThievesGuildWindow(int requestingObjId){};
 	void giveResource(int player, int which, int val){};
-	void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) {};
+	void giveCreatures (const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) {};
 	void takeCreatures (int objid, TSlots creatures){};
 	void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures){};
 	bool changeStackType(const StackLocation &sl, CCreature *c){return false;};
@@ -119,7 +119,7 @@ public:
 	bool eraseStack(const StackLocation &sl, bool forceRemoval = false){return false;};
 	bool swapStacks(const StackLocation &sl1, const StackLocation &sl2){return false;}
 	bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count){return false;}
-	void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished){}
+	void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging){}
 	bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1){return false;}
 	void showCompInfo(ShowInInfobox * comp){};
 	void heroVisitCastle(int obj, int heroID){};

+ 4 - 4
hch/CObjectHandler.cpp

@@ -3106,7 +3106,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
 		if(cost)
 			cb->giveResource(h->tempOwner,6,-cost);
 
-		cb->tryJoiningArmy(this, h, true);
+		cb->tryJoiningArmy(this, h, true, false);
 // 		int slot = h->getSlotFor(subID);
 // 		if(slot >= 0) //there is place
 // 		{
@@ -4461,7 +4461,7 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
 			{
 				CCreatureSet creatures;
 				creatures.setCreature(0, rID, rVal);
-				cb->giveCreatures(id, h, creatures, false);
+				cb->giveCreatures(this, h, creatures, false);
 			}
 			break;
 		default:
@@ -5029,7 +5029,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con
 		iw.text.addReplacement(h->name);
 
 		cb->showInfoDialog(&iw);
-		cb->giveCreatures (id, h, creatures, true);
+		cb->giveCreatures(this, h, creatures, true);
 		//boost::bind(&CGPandoraBox::endBattle, this, h, _1)
 	}
 	if(!afterBattle && message.size())
@@ -5909,7 +5909,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
 			iw.text.addReplacement(loot.buildList());
 			iw.text.addReplacement(h->name);
 			cb->showInfoDialog(&iw);
-			cb->giveCreatures (id, h, ourArmy, false);
+			cb->giveCreatures(this, h, ourArmy, false);
 		}
 		cb->setObjProperty (id, 15, 0); //bc = NULL
 	}

+ 1 - 1
hch/CObjectHandler.h

@@ -675,7 +675,7 @@ public:
 	}
 };
 
-class DLL_EXPORT CGSeerHut : public CGObjectInstance, public CQuest
+class DLL_EXPORT CGSeerHut : public CArmedInstance, public CQuest //army is used when giving reward
 {
 public:
 	ui8 rewardType; //type of reward: 0 - no reward; 1 - experience; 2 - mana points; 3 - morale bonus; 4 - luck bonus; 5 - resources; 6 - main ability bonus (attak, defence etd.); 7 - secondary ability gain; 8 - artifact; 9 - spell; 10 - creature

+ 23 - 8
lib/CCreatureSet.cpp

@@ -345,17 +345,32 @@ void CCreatureSet::setStackType(TSlot slot, const CCreature *type)
 	s->setType(type->idNumber);
 }
 
-bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs) const
+bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs, bool allowMergingStacks) const
 {
-	std::set<const CCreature*> cres;
+	if(!allowMergingStacks)
+	{
+		int freeSlots = stacksCount() - ARMY_SIZE;
+		std::set<const CCreature*> cresToAdd;
+		for(TSlots::const_iterator i = cs.slots.begin(); i != cs.slots.end(); i++)
+		{
+			TSlot dest = getSlotFor(i->second->type);
+			if(dest < 0 || hasStackAtSlot(dest))
+				cresToAdd.insert(i->second->type);
+		}
+		return cresToAdd.size() <= freeSlots;
+	}
+	else
+	{
+		std::set<const CCreature*> cres;
 
-	//get types of creatures that need their own slot
-	for(TSlots::const_iterator i = cs.slots.begin(); i != cs.slots.end(); i++)
-		cres.insert(i->second->type);
-	for(TSlots::const_iterator i = slots.begin(); i != slots.end(); i++)
-		cres.insert(i->second->type);
+		//get types of creatures that need their own slot
+		for(TSlots::const_iterator i = cs.slots.begin(); i != cs.slots.end(); i++)
+			cres.insert(i->second->type);
+		for(TSlots::const_iterator i = slots.begin(); i != slots.end(); i++)
+			cres.insert(i->second->type);
 
-	return cres.size() <= ARMY_SIZE;
+		return cres.size() <= ARMY_SIZE;
+	}
 }
 
 bool CCreatureSet::hasStackAtSlot(TSlot slot) const

+ 1 - 1
lib/CCreatureSet.h

@@ -124,7 +124,7 @@ public:
 	bool hasStackAtSlot(TSlot slot) const;
 	
 	bool contains(const CStackInstance *stack) const;
-	bool canBeMergedWith(const CCreatureSet &cs) const;
+	bool canBeMergedWith(const CCreatureSet &cs, bool allowMergingStacks = true) const;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 2 - 2
lib/IGameCallback.h

@@ -87,7 +87,7 @@ public:
 	virtual void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb) =0; //cb will be called when player closes garrison window
 	virtual void showThievesGuildWindow(int requestingObjId) =0;
 	virtual void giveResource(int player, int which, int val)=0;
-	virtual void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0;
+	virtual void giveCreatures (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0;
 	//virtual void takeCreatures (int objid, TSlots creatures) =0;
 	virtual void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures) =0;
 	virtual bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0;
@@ -96,7 +96,7 @@ public:
 	virtual bool eraseStack(const StackLocation &sl, bool forceRemoval = false) =0;
 	virtual bool swapStacks(const StackLocation &sl1, const StackLocation &sl2) =0;
 	virtual bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count) =0; //makes new stack or increases count of already existing
-	virtual void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished) =0; //merges army from src do dst or opens a garrison window
+	virtual void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) =0; //merges army from src do dst or opens a garrison window
 	virtual bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count) = 0;
 	virtual void showCompInfo(ShowInInfobox * comp)=0;
 	virtual void heroVisitCastle(int obj, int heroID)=0;

+ 1 - 1
lib/map.cpp

@@ -1439,7 +1439,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
 				CStackInstance *hlp = new CStackInstance();
 				hlp->count =  readNormalNr(bufor,i, 2); i+=2;
 				//type will be set during initialization
-				cre->slots[0] = hlp;
+				cre->putStack(0, hlp);
 
 				cre->character = bufor[i]; ++i;
 				bool isMesTre = bufor[i]; ++i; //true if there is message or treasury

+ 59 - 85
server/CGameHandler.cpp

@@ -24,6 +24,7 @@
 #include <boost/assign/list_of.hpp>
 #include <boost/random/linear_congruential.hpp>
 #include <fstream>
+#include <boost/lexical_cast.hpp>
 #include <boost/system/system_error.hpp>
 
 /*
@@ -50,6 +51,7 @@ extern bool end2;
 #undef max
 #endif
 
+#define COMPLAIN_RET_IF(cond, txt) do {if(cond){complain(txt); return;}} while(0)
 #define COMPLAIN_RET(txt) {complain(txt); return false;}
 #define NEW_ROUND 		BattleNextRound bnr;\
 		bnr.round = gs->curB->round + 1;\
@@ -2062,41 +2064,25 @@ void CGameHandler::giveResource(int player, int which, int val)
 	sr.val = gs->players.find(player)->second.resources[which]+val;
 	sendAndApply(&sr);
 }
-void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove)
-{
-	assert(0);
-// 	if (creatures.stacksCount() <= 0)
-// 		return;
-// 	CCreatureSet heroArmy = h->getArmy();
-// 	std::set<int> takenSlots;
-// 	for (TSlots::const_iterator it = creatures.Slots().begin(); it != creatures.Slots().end(); it++)
-// 	{
-// 		int slot = heroArmy.getSlotFor(it->second->type->idNumber);
-// 		if (slot >= 0)
-// 		{
-// 			heroArmy.addToSlot(slot, it->second); 	//move all matching creatures to hero's army
-// 			takenSlots.insert(it->first); //slot id
-// 		}
-// 	}
-// 	for (std::set<int>::iterator it = takenSlots.begin(); it != takenSlots.end(); it++)
-// 		creatures.eraseStack(*it); //delete them from used army
-// 
-// 	SetGarrisons sg;
-// 	sg.garrs[h->id] = heroArmy;
-// 	sg.garrs[objid] = creatures;
-// 	sendAndApply (&sg);
-// 
-// 	if (remove) //show garrison window and let player pick remaining creatures
-// 	{
-// 		if (creatures.stacksCount()) //Pandora needs to exist until we close garrison window
-// 		{
-// 			showGarrisonDialog (objid, h->id, true, boost::bind(&CGameHandler::removeObject, this, objid));
-// 		}
-// 		else
-// 			removeObject(objid);
-// 	}
-// 	else if (creatures.stacksCount())
-// 		showGarrisonDialog (objid, h->id, true, 0);
+
+void CGameHandler::giveCreatures(const CArmedInstance *obj, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove)
+{
+	boost::function<void()> removeOrNot = 0;
+	if(remove)
+		removeOrNot = boost::bind(&CGameHandler::removeObject, this, obj->id);
+
+	COMPLAIN_RET_IF(!creatures.stacksCount(), "Strange, giveCreatures called without args!");
+	COMPLAIN_RET_IF(obj->stacksCount(), "Cannot give creatures from not-cleared object!");
+	COMPLAIN_RET_IF(creatures.stacksCount() > ARMY_SIZE, "Too many stacks to give!");
+
+	//first we move creatures to give to make them army of object-source
+	for(int i = 0; creatures.stacksCount(); i++)
+	{
+		TSlots::const_iterator stack = creatures.Slots().begin();
+		addToSlot(StackLocation(obj, i), stack->second->type, stack->second->count);
+	}
+
+	tryJoiningArmy(obj, h, remove, false);
 }
 
 void CGameHandler::takeCreatures(int objid, std::vector<CStackBasicDescriptor> creatures)
@@ -2994,6 +2980,38 @@ bool CGameHandler::changeStackType(const StackLocation &sl, CCreature *c)
 	return true;
 }
 
+void CGameHandler::moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging) 
+{
+	assert(src->canBeMergedWith(*dst, allowMerging));
+	while(!src->stacksCount())//while there are unmoved creatures
+	{
+		TSlots::const_iterator i = src->Slots().begin(); //iterator to stack to move
+		StackLocation sl(src, i->first); //location of stack to move
+
+		TSlot pos = dst->getSlotFor(i->second->type);
+		if(pos < 0)
+		{
+			//try to merge two other stacks to make place
+			std::pair<TSlot, TSlot> toMerge;
+			if(dst->mergableStacks(toMerge, i->first) && allowMerging)
+			{
+				moveStack(StackLocation(dst, toMerge.first), StackLocation(dst, toMerge.second)); //merge toMerge.first into toMerge.second
+				assert(!dst->hasStackAtSlot(toMerge.first)); //we have now a new free slot
+				moveStack(sl, StackLocation(dst, toMerge.first)); //move stack to freed slot
+			}
+			else
+			{
+				complain("Unexpected failure during an attempt to move army from " + src->nodeName() + " to " + dst->nodeName() + "!");
+				return;
+			}
+		}
+		else
+		{
+			moveStack(sl, StackLocation(dst, pos));
+		}
+	}
+}
+
 bool CGameHandler::garrisonSwap( si32 tid )
 {
 	CGTownInstance *town = gs->getTown(tid);
@@ -3005,36 +3023,8 @@ bool CGameHandler::garrisonSwap( si32 tid )
 			complain("Cannot make garrison swap, not enough free slots!");
 			return false;
 		}
-
-		const CCreatureSet &cso = *town;
-		const CCreatureSet &csn = *town->visitingHero;
-
-		while(!cso.slots.empty())//while there are unmoved creatures
-		{
-			TSlots::const_iterator i = cso.slots.begin(); //iterator to stack to move
-			StackLocation sl(town, i->first); //location of stack to move
-
-			TSlot pos = csn.getSlotFor(i->second->type);
-			if(pos < 0)
-			{
-				//try to merge two other stacks to make place
-				std::pair<TSlot, TSlot> toMerge;
-				if(csn.mergableStacks(toMerge, i->first))
-				{
-					moveStack(StackLocation(town->visitingHero, toMerge.first), StackLocation(town->visitingHero, toMerge.second)); //merge toMerge.first into toMerge.second
-					moveStack(sl, StackLocation(town->visitingHero, toMerge.first)); //move stack to freed slot
-				}
-				else
-				{
-					complain("Unexpected failure during an attempt to merge town and visiting hero armies!");
-					return false;
-				}
-			}
-			else
-			{
-				moveStack(sl, StackLocation(town->visitingHero, pos));
-			}
-		}
+		
+		moveArmy(town, town->visitingHero, true);
 		
 		SetHeroesInTown intown;
 		intown.tid = tid;
@@ -5274,15 +5264,14 @@ bool CGameHandler::addToSlot(const StackLocation &sl, const CCreature *c, TQuant
 		changeStackCount(sl, count);
 	else
 	{
-		tlog1 << "Cannot add " << c->namePl << " to slot " << sl.slot << std::endl;
-		COMPLAIN_RET("Cannot add stack to slot!");
+		COMPLAIN_RET("Cannot add " + c->namePl + " to slot " + boost::lexical_cast<std::string>(sl.slot) + "!");
 	}
 	return true;
 }
 
-void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished)
+void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging)
 {
-	if(!dst->canBeMergedWith(*src))
+	if(!dst->canBeMergedWith(*src, allowMerging))
 	{
 		boost::function<void()> removeOrNot = 0;
 		if(removeObjWhenFinished) 
@@ -5291,22 +5280,7 @@ void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstanc
 	}
 	else //merge
 	{
-		while(src->slots.size()) //there are not moved cres
-		{
-			TSlots::const_iterator i = src->slots.begin();
-
-			TSlot dstSlot = dst->getSlotFor(i->second->type);
-			if(dstSlot >= 0) //there is place
-			{
-				moveStack(StackLocation(src, i->first), StackLocation(dst, dstSlot), i->second->count);
-			}
-			else
-			{
-				tlog1 << "Unexpected Failure on merging armies!\n";
-				return;
-			}
-		}
-
+		moveArmy(src, dst, allowMerging);
 		if(removeObjWhenFinished)
 			removeObject(src->id);
 	}

+ 3 - 2
server/CGameHandler.h

@@ -148,7 +148,7 @@ public:
 	void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb);
 	void showThievesGuildWindow(int requestingObjId); //TODO: make something more general?
 	void giveResource(int player, int which, int val);
-	void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove);
+	void giveCreatures (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove);
 	void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures);
 	bool changeStackType(const StackLocation &sl, CCreature *c);
 	bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false);
@@ -156,7 +156,7 @@ public:
 	bool eraseStack(const StackLocation &sl, bool forceRemoval = false);
 	bool swapStacks(const StackLocation &sl1, const StackLocation &sl2);
 	bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count);
-	void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished);
+	void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging);
 	bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1);
 	void showCompInfo(ShowInInfobox * comp);
 	void heroVisitCastle(int obj, int heroID);
@@ -221,6 +221,7 @@ public:
 	void engageIntoBattle( ui8 player );
 	bool dig(const CGHeroInstance *h);
 	bool castSpell(const CGHeroInstance *h, int spellID, const int3 &pos);
+	void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{