Browse Source

Stacks #4 -> giving creatures still needs to be fixed.

Michał W. Urbańczyk 15 years ago
parent
commit
848a00bc6f

+ 6 - 6
AI/GeniusAI/BattleLogic.cpp

@@ -4,6 +4,7 @@
 #include <boost/lambda/lambda.hpp>
 #include <boost/lambda/bind.hpp>
 #include <boost/lambda/if.hpp>
+#include <boost/foreach.hpp>
 
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
@@ -72,8 +73,8 @@ void CBattleLogic::SetCurrentTurn(int turn)
 
 void CBattleLogic::MakeStatistics(int currentCreatureId)
 {
-	typedef std::map<int, CStack> map_stacks;
-	map_stacks allStacks = m_cb->battleGetStacks();
+	typedef std::vector<const CStack*> vector_stacks;
+	vector_stacks allStacks = m_cb->battleGetStacks();
 	const CStack *currentStack = m_cb->battleGetStackByID(currentCreatureId);
 	if(currentStack->position < 0) //turret
 	{
@@ -118,14 +119,13 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
 	int totalDamage = 0;
 	int totalHitPoints = 0;
 
-	for (map_stacks::const_iterator it = allStacks.begin(); it != allStacks.end(); ++it)
+	BOOST_FOREACH(const CStack *st, allStacks)
 	{
-		const CStack *st = &it->second;
 		const int stackHP = st->valOfBonuses(Bonus::STACK_HEALTH);
 
-		if ((it->second.attackerOwned != 0) != m_bIsAttacker)
+		if ((st->attackerOwned != 0) != m_bIsAttacker)
 		{
-			int id = it->first;
+			int id = st->ID;
 			if (st->count < 1)
 			{
 				continue;

+ 9 - 16
CCallback.cpp

@@ -542,19 +542,19 @@ int CCallback::battleGetPos(int stack)
 	return -1;
 }
 
-std::map<int, CStack> CCallback::battleGetStacks()
+std::vector<const CStack*> CCallback::battleGetStacks()
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
-	std::map<int, CStack> ret;
+	std::vector<const CStack*> ret;
 	if(!gs->curB) //there is no battle
 	{
+		tlog2<<"battleGetStacks called when there is no battle!"<<std::endl;
 		return ret;
 	}
 
-	for(size_t g=0; g<gs->curB->stacks.size(); ++g)
-	{
-		ret[gs->curB->stacks[g]->ID] = *(gs->curB->stacks[g]);
-	}
+	BOOST_FOREACH(const CStack *s, gs->curB->stacks)
+		ret.push_back(s);
+
 	return ret;
 }
 
@@ -1037,7 +1037,7 @@ InfoAboutTown::~InfoAboutTown()
 void InfoAboutTown::initFromTown( const CGTownInstance *t, bool detailed )
 {
 	obj = t;
-	army = t->getArmy();
+	army = ArmyDescriptor(t, detailed);
 	built = t->builded;
 	fortLevel = t->fortLevel();
 	name = t->name;
@@ -1053,21 +1053,14 @@ void InfoAboutTown::initFromTown( const CGTownInstance *t, bool detailed )
 		details->hallLevel = t->hallLevel();
 		details->garrisonedHero = t->garrisonHero;
 	}
-	/*else
-	{
-		//hide info about hero stacks counts
-		for(std::map<si32,std::pair<ui32,si32> >::iterator i = slots.begin(); i != slots.end(); ++i)
-		{
-			i->second.second = 0;
-		}
-	}*/
+	//TODO: adjust undetailed info about army to our count of thieves guilds
 }
 
 void InfoAboutTown::initFromGarrison(const CGGarrison *garr, bool detailed)
 {
 	obj = garr;
 	fortLevel = 0;
-	army = garr->getArmy();
+	army = ArmyDescriptor(garr, detailed);
 	name = CGI->generaltexth->names[33]; // "Garrison"
 	owner = garr->tempOwner;
 	built = false;

+ 3 - 3
CCallback.h

@@ -61,7 +61,7 @@ struct InfoAboutTown
 	CTown *tType;
 	bool built;
 
-	CCreatureSet army; //numbers of creatures are valid only if details
+	ArmyDescriptor army; //numbers of creatures are valid only if details
 
 	InfoAboutTown();
 	~InfoAboutTown();
@@ -166,7 +166,7 @@ public:
 	virtual const CStack * battleGetStackByPos(int pos, bool onlyAlive = true)=0; //returns stack info by given pos
 	virtual int battleGetPos(int stack)=0; //returns position (tile ID) of stack
 	virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
-	virtual std::map<int, CStack> battleGetStacks()=0; //returns stacks on battlefield
+	virtual std::vector<const CStack*> battleGetStacks()=0; //returns stacks on battlefield
 	virtual void getStackQueue( std::vector<const CStack *> &out, int howMany )=0; //returns vector of stack in order of their move sequence
 	virtual CCreature battleGetCreature(int number)=0; //returns type of creature by given number of stack
 	//virtual bool battleMoveCreature(int ID, int dest)=0; //moves creature with id ID to dest if possible
@@ -297,7 +297,7 @@ public:
 	const CStack * battleGetStackByPos(int pos, bool onlyAlive = true); //returns stack info by given pos
 	int battleGetPos(int stack); //returns position (tile ID) of stack
 	int battleMakeAction(BattleAction* action);//for casting spells by hero - DO NOT use it for moving active stack
-	std::map<int, CStack> battleGetStacks(); //returns stacks on battlefield
+	std::vector<const CStack*> battleGetStacks(); //returns stacks on battlefield
 	void getStackQueue( std::vector<const CStack *> &out, int howMany ); //returns vector of stack in order of their move sequence
 	CCreature battleGetCreature(int number); //returns type of creature by given number of stack
 	std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable); //reutrns numbers of hexes reachable by creature with id ID

+ 70 - 67
client/CBattleInterface.cpp

@@ -26,6 +26,7 @@
 #include "../hch/CVideoHandler.h"
 #include "../hch/CTownHandler.h"
 #include <boost/assign/list_of.hpp>
+#include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #ifndef __GNUC__
@@ -1138,12 +1139,12 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	curInt->battleInt = this;
 
 	//initializing armies
-	this->army1 = *army1;
-	this->army2 = *army2;
-	std::map<int, CStack> stacks = curInt->cb->battleGetStacks();
-	for(std::map<int, CStack>::iterator b=stacks.begin(); b!=stacks.end(); ++b)
+	this->army1 = army1;
+	this->army2 = army2;
+	std::vector<const CStack*> stacks = curInt->cb->battleGetStacks();
+	BOOST_FOREACH(const CStack *s, stacks)
 	{
-		newStack(b->second.ID);
+		newStack(s->ID);
 	}
 
 	//preparing menu background and terrain
@@ -1264,34 +1265,33 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 		bfield[h].myInterface = this;
 	}
 	//locking occupied positions on batlefield
-	for(std::map<int, CStack>::iterator it = stacks.begin(); it!=stacks.end(); ++it) //stacks gained at top of this function
-	{
-		if(it->second.position >= 0) //turrets have position < 0
-			bfield[it->second.position].accessible = false;
-	}
+	BOOST_FOREACH(const CStack *s, stacks)  //stacks gained at top of this function
+		if(s->position >= 0) //turrets have position < 0
+			bfield[s->position].accessible = false;
 
 	//loading projectiles for units
-	for(std::map<int, CStack>::iterator g = stacks.begin(); g != stacks.end(); ++g)
+	BOOST_FOREACH(const CStack *s, stacks)
 	{
-		int creID = (g->second.getCreature()->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : g->second.getCreature()->idNumber; //id of creature whose shots should be loaded
-		if(g->second.getCreature()->isShooting() && CGI->creh->idToProjectile.find(creID) != CGI->creh->idToProjectile.end())
-		{	
-			idToProjectile[g->second.getCreature()->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile.find(creID)->second);
+		int creID = (s->getCreature()->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : s->getCreature()->idNumber; //id of creature whose shots should be loaded
+		if(s->getCreature()->isShooting() && vstd::contains(CGI->creh->idToProjectile, creID))
+		{
+			CDefHandler *&projectile = idToProjectile[s->getCreature()->idNumber];
+			projectile = CDefHandler::giveDef(CGI->creh->idToProjectile[creID]);
 
-			if(idToProjectile[g->second.getCreature()->idNumber]->ourImages.size() > 2) //add symmetric images
+			if(projectile->ourImages.size() > 2) //add symmetric images
 			{
-				for(int k = idToProjectile[g->second.getCreature()->idNumber]->ourImages.size()-2; k > 1; --k)
+				for(int k = projectile->ourImages.size()-2; k > 1; --k)
 				{
 					Cimage ci;
-					ci.bitmap = CSDL_Ext::rotate01(idToProjectile[g->second.getCreature()->idNumber]->ourImages[k].bitmap);
+					ci.bitmap = CSDL_Ext::rotate01(projectile->ourImages[k].bitmap);
 					ci.groupNumber = 0;
 					ci.imName = std::string();
-					idToProjectile[g->second.getCreature()->idNumber]->ourImages.push_back(ci);
+					projectile->ourImages.push_back(ci);
 				}
 			}
-			for(int s=0; s<idToProjectile[g->second.getCreature()->idNumber]->ourImages.size(); ++s) //alpha transforming
+			for(int s=0; s<projectile->ourImages.size(); ++s) //alpha transforming
 			{
-				CSDL_Ext::alphaTransform(idToProjectile[g->second.getCreature()->idNumber]->ourImages[s].bitmap);
+				CSDL_Ext::alphaTransform(projectile->ourImages[s].bitmap);
 			}
 		}
 	}
@@ -1467,7 +1467,7 @@ void CBattleInterface::deactivate()
 
 void CBattleInterface::show(SDL_Surface * to)
 {
-	std::map<int, CStack> stacks = curInt->cb->battleGetStacks(); //used in a few places
+	std::vector<const CStack*> stacks = curInt->cb->battleGetStacks(); //used in a few places
 	++animCount;
 	if(!to) //"evaluating" to
 		to = screen;
@@ -1558,20 +1558,20 @@ void CBattleInterface::show(SDL_Surface * to)
 	////showing units //a lot of work...
 	std::vector<int> stackAliveByHex[BFIELD_SIZE];
 	//double loop because dead stacks should be printed first
-	for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j)
+	BOOST_FOREACH(const CStack *s, stacks)
 	{
-		if(creAnims.find(j->second.ID) == creAnims.end()) //eg. for summoned but not yet handled stacks
+		if(creAnims.find(s->ID) == creAnims.end()) //eg. for summoned but not yet handled stacks
 			continue;
-		if(creAnims[j->second.ID]->getType() != 5 && j->second.position >= 0) //don't show turrets here
-			stackAliveByHex[j->second.position].push_back(j->second.ID);
+		if(creAnims[s->ID]->getType() != 5 && s->position >= 0) //don't show turrets here
+			stackAliveByHex[s->position].push_back(s->ID);
 	}
 	std::vector<int> stackDeadByHex[BFIELD_SIZE];
-	for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j)
+	BOOST_FOREACH(const CStack *s, stacks)
 	{
-		if(creAnims.find(j->second.ID) == creAnims.end()) //eg. for summoned but not yet handled stacks
+		if(creAnims.find(s->ID) == creAnims.end()) //eg. for summoned but not yet handled stacks
 			continue;
-		if(creAnims[j->second.ID]->getType() == 5)
-			stackDeadByHex[j->second.position].push_back(j->second.ID);
+		if(creAnims[s->ID]->getType() == 5)
+			stackDeadByHex[s->position].push_back(s->ID);
 	}
 
 	//handle animations
@@ -1607,11 +1607,11 @@ void CBattleInterface::show(SDL_Surface * to)
 			activate();
 
 		//restoring good directions of stacks
-		for(std::map<int, CStack>::const_iterator it = stacks.begin(); it != stacks.end(); ++it)
+		BOOST_FOREACH(const CStack *s, stacks)
 		{
-			if(creDir[it->second.ID] != bool(it->second.attackerOwned) && it->second.alive())
+			if(creDir[s->ID] != bool(s->attackerOwned) && s->alive())
 			{
-				addNewAnim(new CReverseAnim(this, it->second.ID, it->second.position, false));
+				addNewAnim(new CReverseAnim(this, s->ID, s->position, false));
 			}
 		}
 
@@ -1631,17 +1631,18 @@ void CBattleInterface::show(SDL_Surface * to)
 			creAnims[stackDeadByHex[b][v]]->nextFrame(to, creAnims[stackDeadByHex[b][v]]->pos.x, creAnims[stackDeadByHex[b][v]]->pos.y, creDir[stackDeadByHex[b][v]], animCount, false); //increment always when moving, never if stack died
 		}
 	}
-	std::vector<int> flyingStacks; //flying stacks should be displayed later, over other stacks and obstacles
+	std::vector<const CStack *> flyingStacks; //flying stacks should be displayed later, over other stacks and obstacles
 	for(int b=0; b<BFIELD_SIZE; ++b) //showing alive stacks
 	{
 		for(size_t v=0; v<stackAliveByHex[b].size(); ++v)
 		{
 			int curStackID = stackAliveByHex[b][v];
+			const CStack *s = LOCPLINT->cb->battleGetStackByID(curStackID, false); //TODO: dlaczego brak false psuje?
 			
-			if(!stacks[curStackID].hasBonusOfType(Bonus::FLYING) || creAnims[curStackID]->getType() != 0)
-				showAliveStack(curStackID, stacks, to);
+			if(!s->hasBonusOfType(Bonus::FLYING) || creAnims[curStackID]->getType() != 0)
+				showAliveStack(s, to);
 			else
-				flyingStacks.push_back(curStackID);
+				flyingStacks.push_back(s);
 		}
 
 		//showing obstacles
@@ -1663,7 +1664,7 @@ void CBattleInterface::show(SDL_Surface * to)
 	}
 	
 	for(int b=0; b<flyingStacks.size(); ++b) //showing flyign stacks
-		showAliveStack(flyingStacks[b], stacks, to);
+		showAliveStack(flyingStacks[b], to);
 
 	//units shown
 
@@ -2279,23 +2280,23 @@ void CBattleInterface::stackAttacking(int ID, int dest, int attackedID)
 void CBattleInterface::newRoundFirst( int round )
 {
 	//handle regeneration
-	std::map<int, CStack> stacks = curInt->cb->battleGetStacks();
-	for(std::map<int, CStack>::const_iterator it = stacks.begin(); it != stacks.end(); ++it)
+	std::vector<const CStack*> stacks = curInt->cb->battleGetStacks();
+	BOOST_FOREACH(const CStack *s, stacks)
 	{
 		//don't show animation when no HP is regenerated
-		if (it->second.firstHPleft == it->second.MaxHealth())
+		if (s->firstHPleft == s->MaxHealth())
 		{
 			continue;
 		}
 
-		if( it->second.hasBonusOfType(Bonus::HP_REGENERATION) && it->second.alive() )
-			displayEffect(74, it->second.position);
+		if( s->hasBonusOfType(Bonus::HP_REGENERATION) && s->alive() )
+			displayEffect(74, s->position);
 
-		if( it->second.hasBonusOfType(Bonus::FULL_HP_REGENERATION, 0) && it->second.alive() )
-			displayEffect(4, it->second.position);
+		if( s->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 0) && s->alive() )
+			displayEffect(4, s->position);
 
-		if( it->second.hasBonusOfType(Bonus::FULL_HP_REGENERATION, 1) && it->second.alive() )
-			displayEffect(74, it->second.position);
+		if( s->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 1) && s->alive() )
+			displayEffect(74, s->position);
 	}
 }
 
@@ -2967,12 +2968,12 @@ void CBattleInterface::endCastingSpell()
 	CGI->curh->changeGraphic(1, 6);
 }
 
-void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stacks, SDL_Surface * to)
+void CBattleInterface::showAliveStack(const CStack *stack, SDL_Surface * to)
 {
+	int ID = stack->ID;
 	if(creAnims.find(ID) == creAnims.end()) //eg. for summoned but not yet handled stacks
 		return;
 
-	const CStack &curStack = stacks.find(ID)->second;
 	int animType = creAnims[ID]->getType();
 
 	int affectingSpeed = curInt->sysOpts.animSpeed;
@@ -3006,21 +3007,21 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
 	creAnims[ID]->nextFrame(to, creAnims[ID]->pos.x, creAnims[ID]->pos.y, creDir[ID], animCount, incrementFrame, ID==activeStack, ID==mouseHoveredStack); //increment always when moving, never if stack died
 
 	//printing amount
-	if(curStack.count > 0 //don't print if stack is not alive
+	if(stack->count > 0 //don't print if stack is not alive
 		&& (!curInt->curAction
 			|| (curInt->curAction->stackNumber != ID //don't print if stack is currently taking an action
-				&& (curInt->curAction->actionType != 6  ||  curStack.position != curInt->curAction->additionalInfo) //nor if it's an object of attack
-				&& (curInt->curAction->destinationTile != curStack.position) //nor if it's on destination tile for current action
+				&& (curInt->curAction->actionType != 6  ||  stack->position != curInt->curAction->additionalInfo) //nor if it's an object of attack
+				&& (curInt->curAction->destinationTile != stack->position) //nor if it's on destination tile for current action
 				)
 			)
-			&& !curStack.hasBonusOfType(Bonus::SIEGE_WEAPON) //and not a war machine...
+			&& !stack->hasBonusOfType(Bonus::SIEGE_WEAPON) //and not a war machine...
 	)
 	{
-		int xAdd = curStack.attackerOwned ? 220 : 202;
+		int xAdd = stack->attackerOwned ? 220 : 202;
 
 		//blitting amoutn background box
 		SDL_Surface *amountBG = NULL;
-		BonusList spellEffects = curStack.getSpellBonuses();
+		BonusList spellEffects = stack->getSpellBonuses();
 		if(!spellEffects.size())
 		{
 			amountBG = amountNormal;
@@ -3028,7 +3029,7 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
 		else
 		{
 			int pos=0; //determining total positiveness of effects
-			std::vector<si32> spellIds = curStack.activeSpells();
+			std::vector<si32> spellIds = stack->activeSpells();
 			for(std::vector<si32>::const_iterator it = spellIds.begin(); it != spellIds.end(); it++)
 			{
 				pos += CGI->spellh->spells[ *it ].positiveness;
@@ -3049,7 +3050,7 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
 		SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[ID]->pos.x + xAdd, creAnims[ID]->pos.y + 260));
 		//blitting amount
 		CSDL_Ext::printAtMiddle(
-			makeNumberShort(curStack.count),
+			makeNumberShort(stack->count),
 			creAnims[ID]->pos.x + xAdd + 15,
 			creAnims[ID]->pos.y + 260 + 5,
 			FONT_TINY,
@@ -3059,7 +3060,7 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
 	}
 }
 
-void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::map<int, CStack> & stacks)
+void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::vector<const CStack*> & stacks)
 {
 	if(!siegeH)
 		return;
@@ -3094,18 +3095,20 @@ void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::map
 
 		if(posToSeek != -1)
 		{
-			int ID = -1;
-			for(std::map<int, CStack>::const_iterator it = stacks.begin(); it != stacks.end(); ++it)
+			const CStack *turret = NULL;
+
+			BOOST_FOREACH(const CStack *s, stacks)
 			{
-				if(it->second.position == posToSeek)
+				if(s->position == posToSeek)
 				{
-					ID = it->second.ID;
+					turret = s;
 					break;
 				}
 			}
-			if(ID != -1)
+
+			if(turret)
 			{
-				showAliveStack(ID, stacks, to);
+				showAliveStack(turret, to);
 				//blitting creature cover
 				switch(posToSeek)
 				{
@@ -3621,7 +3624,7 @@ void CBattleHex::clickRight(tribool down, bool previousState)
 		if(!myst.alive()) return;
 		if(down)
 		{
-			GH.pushInt(new CCreInfoWindow(*myst.base));
+			GH.pushInt(new CCreInfoWindow(myst));
 		}
 	}
 }
@@ -3746,7 +3749,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 	{
 		int bestMonsterID = -1;
 		int bestPower = 0;
-		for(TSlots::const_iterator it = owner->army1.Slots().begin(); it!=owner->army1.Slots().end(); ++it)
+		for(TSlots::const_iterator it = owner->army1->Slots().begin(); it!=owner->army1->Slots().end(); ++it)
 		{
 			if( it->second->type->AIValue > bestPower)
 			{
@@ -3768,7 +3771,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 	{
 		int bestMonsterID = -1;
 		int bestPower = 0;
-		for(TSlots::const_iterator it = owner->army2.Slots().begin(); it!=owner->army2.Slots().end(); ++it)
+		for(TSlots::const_iterator it = owner->army2->Slots().begin(); it!=owner->army2->Slots().end(); ++it)
 		{
 			if( it->second->type->AIValue > bestPower)
 			{

+ 3 - 3
client/CBattleInterface.h

@@ -384,7 +384,7 @@ private:
 	CBattleConsole * console;
 	CBattleHero * attackingHero, * defendingHero; //fighting heroes
 	CStackQueue *queue;
-	CCreatureSet army1, army2; //copy of initial armies (for result window)
+	const CCreatureSet *army1, *army2; //copy of initial armies (for result window)
 	const CGHeroInstance * attackingHeroInstance, * defendingHeroInstance;
 	std::map< int, CCreatureAnimation * > creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
 	std::map< int, CDefHandler * > idToProjectile; //projectiles of creatures (creatureID, defhandler)
@@ -407,8 +407,8 @@ private:
 	BattleAction * spellToCast; //spell for which player is choosing destination
 	void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)
 
-	void showAliveStack(int ID, const std::map<int, CStack> & stacks, SDL_Surface * to); //helper function for function show
-	void showPieceOfWall(SDL_Surface * to, int hex, const std::map<int, CStack> & stacks); //helper function for show
+	void showAliveStack(const CStack *stack, SDL_Surface * to); //helper function for function show
+	void showPieceOfWall(SDL_Surface * to, int hex, const std::vector<const CStack*> & stacks); //helper function for show
 	void redrawBackgroundWithHexes(int activeStack);
 	void printConsoleAttacked(int ID, int dmg, int killed, int IDby);
 

+ 54 - 49
client/GUIClasses.cpp

@@ -2087,7 +2087,7 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::functi
 	: type(Type), dsm(Dsm), dismiss(0), upgrade(0), ok(0)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	init(st.type, &st, st.count);
+	init(st.type, &st, dynamic_cast<const CGHeroInstance*>(st.armyObj), st.count);
 
 	//print abilities text - if r-click popup
 	if(type)
@@ -2132,31 +2132,25 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::functi
 		}
 		ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,boost::bind(&CCreInfoWindow::close,this),216,237,"IOKAY.DEF",SDLK_RETURN);
 	}
-	else
-	{
-		printAtWB(c->abilityText,17,231,FONT_SMALL,35,zwykly,*bitmap);
-	}
-
-	//if we are displying window fo r stack in battle, there are several more things that we need to display
-	if(const CStack *battleStack = dynamic_cast<const CStack*>(&st))
-	{
-		//spell effects
-		int printed=0; //how many effect pics have been printed
-		std::vector<si32> spells = battleStack->activeSpells();
-		BOOST_FOREACH(si32 effect, spells)
-		{
-			blitAt(graphics->spellEffectsPics->ourImages[effect + 1].bitmap, 127 + 52 * printed, 186, *bitmap); 
-			++printed;
-			if(printed >= 3) //we can fit only 3 effects
-				break;
-		}
-		//print current health
-		printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
-	}
 }
 
 
 
+CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount)
+	: type(Type), dismiss(0), upgrade(0), ok(0)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	const CCreature *cre = CGI->creh->creatures[Cid];
+	init(cre, NULL, NULL, creatureCount);
+}
+
+CCreInfoWindow::CCreInfoWindow(const CStack &st, int Type /*= 0*/)
+	: type(Type), dismiss(0), upgrade(0), ok(0)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	init(st.getCreature(), &st, st.getMyHero(), st.count);
+}
+
 void CCreInfoWindow::printLine(int nr, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
 {
 	printAt(text, 155, 48 + nr*19, FONT_SMALL, zwykly, *bitmap);
@@ -2172,15 +2166,11 @@ void CCreInfoWindow::printLine(int nr, const std::string &text, int baseVal, int
 	printTo(hlp, 276, 61 + nr*19, FONT_SMALL, zwykly, *bitmap);
 }
 
-void CCreInfoWindow::init(const CCreature *cre, const CStackInstance *stack, int creatureCount)
+//void CCreInfoWindow::init(const CCreature *cre, const CStackInstance *stack, int creatureCount)
+void CCreInfoWindow::init(const CCreature *cre, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int creatureCount)
 {
-	const CBonusSystemNode *finalNode = NULL;
-	if(stack)
-		finalNode = stack;
-	else
-		finalNode = cre;
-
 	c = cre;
+	if(!stackNode) stackNode = c;
 
 	bitmap = new CPicture("CRSTKPU.bmp");
 	bitmap->colorizeAndConvert(LOCPLINT->playerID);
@@ -2190,53 +2180,68 @@ void CCreInfoWindow::init(const CCreature *cre, const CStackInstance *stack, int
 
 	count = boost::lexical_cast<std::string>(creatureCount);
 
-
 	printAtMiddle(c->namePl,149,30,FONT_SMALL,tytulowy,*bitmap); //creature name
 	
-	printLine(0, CGI->generaltexth->primarySkillNames[0], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), finalNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
-	printLine(1, CGI->generaltexth->primarySkillNames[1], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), finalNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
+	printLine(0, CGI->generaltexth->primarySkillNames[0], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
+	printLine(1, CGI->generaltexth->primarySkillNames[1], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
 	if(c->shots)
 		printLine(2, CGI->generaltexth->allTexts[198], c->shots);
 
 	//TODO
 	int dmgMultiply = 1;
-	if(stack && stack->hasBonusOfType(Bonus::SIEGE_WEAPON))
-		dmgMultiply += stack->armyObj->Attack(); 
+	if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
+		dmgMultiply += heroOwner->Attack(); 
 
-	printLine(3, CGI->generaltexth->allTexts[199], finalNode->getMinDamage() * dmgMultiply, finalNode->getMaxDamage() * dmgMultiply, true);
-	printLine(4, CGI->generaltexth->allTexts[388], cre->valOfBonuses(Bonus::STACK_HEALTH), finalNode->valOfBonuses(Bonus::STACK_HEALTH));
-	printLine(6, CGI->generaltexth->zelp[441].first, cre->valOfBonuses(Bonus::STACKS_SPEED), finalNode->valOfBonuses(Bonus::STACKS_SPEED));
+	printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
+	printLine(4, CGI->generaltexth->allTexts[388], cre->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
+	printLine(6, CGI->generaltexth->zelp[441].first, cre->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED));
 
 	//setting morale
 	morale = new MoraleLuckBox(true);
 	morale->pos = genRect(42, 42, pos.x + 24, pos.y + 189);
-	morale->set(stack);
+	morale->set(stackNode);
 	//setting luck
 	luck = new MoraleLuckBox(false);
 	luck->pos =  genRect(42, 42, pos.x + 77, pos.y + 189);
-	luck->set(stack);
+	luck->set(stackNode);
 
 	//luck and morale
 	int luck = 3, morale = 3;
-	if(stack)
+	if(stackNode)
 	{
 		//add modifiers
-		luck += stack->LuckVal();
-		morale += stack->MoraleVal();
+		luck += stackNode->LuckVal();
+		morale += stackNode->MoraleVal();
 	}
 
 	blitAt(graphics->morale42->ourImages[morale].bitmap, 24, 189, *bitmap);
 	blitAt(graphics->luck42->ourImages[luck].bitmap, 77, 189, *bitmap);
-}
 
-CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount)
-	: type(Type), dismiss(0), upgrade(0), ok(0)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	const CCreature *cre = CGI->creh->creatures[Cid];
-	init(cre, NULL, creatureCount);
+
+	if(!type)
+	{
+		printAtWB(c->abilityText,17,231,FONT_SMALL,35,zwykly,*bitmap);
+	}
+
+	//if we are displying window fo r stack in battle, there are several more things that we need to display
+	if(const CStack *battleStack = dynamic_cast<const CStack*>(stackNode))
+	{
+		//spell effects
+		int printed=0; //how many effect pics have been printed
+		std::vector<si32> spells = battleStack->activeSpells();
+		BOOST_FOREACH(si32 effect, spells)
+		{
+			blitAt(graphics->spellEffectsPics->ourImages[effect + 1].bitmap, 127 + 52 * printed, 186, *bitmap); 
+			++printed;
+			if(printed >= 3) //we can fit only 3 effects
+				break;
+		}
+		//print current health
+		printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
+	}
 }
 
+
 CCreInfoWindow::~CCreInfoWindow()
 {
  	for(int i=0; i<upgResCost.size();i++)

+ 16 - 2
client/GUIClasses.h

@@ -25,6 +25,7 @@
  *
  */
 
+class CStackBasicDescriptor;
 class CBonusSystemNode;
 class CArtifact;
 class CDefEssential;
@@ -879,8 +880,9 @@ public:
 
 	AdventureMapButton *dismiss, *upgrade, *ok;
 	CCreInfoWindow(const CStackInstance &st, int Type = 0, boost::function<void()> Upg = 0, boost::function<void()> Dsm = 0, UpgradeInfo *ui = NULL); //c-tor
+	CCreInfoWindow(const CStack &st, int Type = 0); //c-tor
 	CCreInfoWindow(int Cid, int Type, int creatureCount); //c-tor
-	void init(const CCreature *cre, const CStackInstance *stack, int creatureCount);
+	void init(const CCreature *cre, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int creatureCount);
 	void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false);
 	~CCreInfoWindow(); //d-tor
 	void activate();
@@ -892,10 +894,21 @@ public:
 	void show(SDL_Surface * to);
 };
 
+namespace Arts
+{
+	enum EPos
+	{
+		PRE_FIRST = -1, 
+		HEAD, SHOULDERS, NECK, RIGHT_HAND, LEFT_HAND, TORSO, RIGHT_RING, LEFT_RING, FEET, MISC1, MISC2, MISC3, MISC4,
+		MACH1, MACH2, MACH3, MACH4, SPELLBOOK, MISC5, 
+		AFTER_LAST
+	};
+}
+
 class CArtPlace: public LRClickableAreaWTextComp
 {
 public:
-	ui16 slotID; //0   	head	1 	shoulders		2 	neck		3 	right hand		4 	left hand		5 	torso		6 	right ring		7 	left ring		8 	feet		9 	misc. slot 1		10 	misc. slot 2		11 	misc. slot 3		12 	misc. slot 4		13 	ballista (war machine 1)		14 	ammo cart (war machine 2)		15 	first aid tent (war machine 3)		16 	catapult		17 	spell book		18 	misc. slot 5		19+ 	backpack slots
+	int slotID; //0   	head	1 	shoulders		2 	neck		3 	right hand		4 	left hand		5 	torso		6 	right ring		7 	left ring		8 	feet		9 	misc. slot 1		10 	misc. slot 2		11 	misc. slot 3		12 	misc. slot 4		13 	ballista (war machine 1)		14 	ammo cart (war machine 2)		15 	first aid tent (war machine 3)		16 	catapult		17 	spell book		18 	misc. slot 5		19+ 	backpack slots
 
 	bool marked;
 	bool selectedNo;
@@ -915,6 +928,7 @@ public:
 	~CArtPlace(); //d-tor
 };
 
+
 class CArtifactsOfHero : public CIntObject
 {
 	CGHeroInstance * curHero; //local copy of hero on which we operate

+ 7 - 7
client/Graphics.cpp

@@ -53,17 +53,17 @@ SDL_Surface * Graphics::drawHeroInfoWin(const InfoAboutHero &curh)
 	blitAt(graphics->portraitLarge[curh.portrait],11,12,ret); //portrait
 
 	//army
-	for (TSlots::const_iterator i = curh.army.Slots().begin(); i!=curh.army.Slots().end();i++)
+	for (ArmyDescriptor::const_iterator i = curh.army.begin(); i!=curh.army.end();i++)
 	{
-		blitAt(graphics->smallImgs[(*i).second->type->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret);
+		blitAt(graphics->smallImgs[i->second.type->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret);
 		if(curh.details)
 		{
-			SDL_itoa((*i).second->count,buf,10);
+			SDL_itoa((*i).second.count,buf,10);
 			printAtMiddle(buf,slotsPos[(*i).first].first+17,slotsPos[(*i).first].second+41,FONT_TINY,zwykly,ret);
 		}
 		else
 		{
-			printAtMiddle(VLC->generaltexth->arraytxt[174 + 3*(i->second->count-1)],slotsPos[(*i).first].first+17,slotsPos[(*i).first].second+41,FONT_TINY,zwykly,ret);
+			printAtMiddle(VLC->generaltexth->arraytxt[174 + 3*(i->second.count-1)],slotsPos[(*i).first].first+17,slotsPos[(*i).first].second+41,FONT_TINY,zwykly,ret);
 		}
 	}
 
@@ -110,15 +110,15 @@ SDL_Surface * Graphics::drawTownInfoWin( const InfoAboutTown & curh )
 	int pom = curh.fortLevel - 1; if(pom<0) pom = 3; //fort pic id
 	blitAt(forts->ourImages[pom].bitmap,115,42,ret); //fort
 
-	for (TSlots::const_iterator i=curh.army.Slots().begin(); i!=curh.army.Slots().end();i++)
+	for (ArmyDescriptor::const_iterator i=curh.army.begin(); i!=curh.army.end();i++)
 	{
 		//if(!i->second.second)
 		//	continue;
-		blitAt(graphics->smallImgs[(*i).second->type->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret);
+		blitAt(graphics->smallImgs[(*i).second.type->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret);
 		if(curh.details)
 		{
 			// Show exact creature amount.
-			SDL_itoa((*i).second->count,buf,10);
+			SDL_itoa((*i).second.count,buf,10);
 			printAtMiddle(buf,slotsPos[(*i).first].first+17,slotsPos[(*i).first].second+41,FONT_TINY,zwykly,ret);
 		}
 		else

+ 6 - 6
client/NetPacksClient.cpp

@@ -308,12 +308,12 @@ void TryMoveHero::applyCl( CClient *cl )
 	}
 }
 
-void SetGarrisons::applyCl( CClient *cl )
-{
-	for(std::map<ui32,CCreatureSet>::iterator i = garrs.begin(); i!=garrs.end(); i++)
-		if(vstd::contains(cl->playerint,cl->getOwner(i->first)))
-			cl->playerint[cl->getOwner(i->first)]->garrisonChanged(cl->getObj(i->first));
-}
+// void SetGarrisons::applyCl( CClient *cl )
+// {
+// 	for(std::map<ui32,CCreatureSet>::iterator i = garrs.begin(); i!=garrs.end(); i++)
+// 		if(vstd::contains(cl->playerint,cl->getOwner(i->first)))
+// 			cl->playerint[cl->getOwner(i->first)]->garrisonChanged(cl->getObj(i->first));
+// }
 
 void NewStructures::applyCl( CClient *cl )
 {

+ 4 - 5
hch/CCampaignHandler.cpp

@@ -531,13 +531,12 @@ void CCampaignScenario::prepareCrossoverHeroes( std::vector<CGHeroInstance *> he
 	//trimming creatures
 	BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
 	{
-		CCreatureSet army = cgh->getArmy();
-		for (TSlots::iterator j = army.slots.begin(); j != army.slots.end(); j++)
+		for (TSlots::const_iterator j = cgh->Slots().begin(); j != cgh->Slots().end(); j++)
 		{
-			if (! (travelOptions.monstersKeptByHero[j->first / 8] & (1 << (j->first%8)) ))
+			if (!(travelOptions.monstersKeptByHero[j->first / 8] & (1 << (j->first%8)) ))
 			{
-				army.slots.erase(j);
-				j = army.slots.begin();
+				cgh->eraseStack(j->first);
+				j = cgh->Slots().begin();
 			}
 		}
 	}

+ 19 - 19
hch/CObjectHandler.cpp

@@ -777,6 +777,7 @@ const CArtifact * CGHeroInstance::getArt(int pos) const
 CGHeroInstance::CGHeroInstance()
  : IBoatGenerator(this)
 {
+	nodeType = HERO;
 	ID = HEROI_TYPE;
 	tacticFormationEnabled = inTownGarrison = false;
 	mana = movement = portrait = level = -1;
@@ -3449,28 +3450,27 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
 			{
 				if (!h->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION))
 				{
-					CCreatureSet army = h->getArmy();
-					if (army.Slots().size() > 1 || army.Slots().begin()->second->count > 1)
+					if (h->Slots().size() > 1 || h->Slots().begin()->second->count > 1)
 					{ //we can't remove last unit
-						int targetstack = army.Slots().begin()->first; //slot numbers may vary
-						for(TSlots::const_reverse_iterator i = army.Slots().rbegin(); i != army.Slots().rend(); i++)
+						TSlot targetstack = h->Slots().begin()->first; //slot numbers may vary
+						for(TSlots::const_reverse_iterator i = h->Slots().rbegin(); i != h->Slots().rend(); i++)
 						{
-							if (army.getPower(targetstack) > army.getPower(i->first))
+							if (h->getPower(targetstack) > h->getPower(i->first))
 							{
 								targetstack = (i->first);
 							}
 						}
-						std::vector<CStackBasicDescriptor> cresToTake;
-						cresToTake.push_back(CStackBasicDescriptor(army.getStack(targetstack)));
-						cresToTake[0].count * 0.5;
-						amax (cresToTake[0].count, 1);
+
+						TQuantity countToTake = h->getStackCount(targetstack) * 0.5;
+						amax(countToTake, 1);
+
 
 						InfoWindow iw;
 						iw.player = h->tempOwner;
 						iw.text.addTxt (MetaString::ADVOB_TXT, 168);
-						iw.components.push_back (Component(cresToTake[0]));
+						iw.components.push_back (Component(CStackBasicDescriptor(h->getCreature(targetstack), countToTake)));
 						cb->showInfoDialog(&iw);
-					    cb->takeCreatures (h->id, cresToTake);
+						cb->changeStackCount(StackLocation(h, targetstack), -countToTake);
 					}
 				}
 			}
@@ -4380,7 +4380,7 @@ int CGSeerHut::checkDirection() const
 			return 4;
 	}
 }
-void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const
+void CGSeerHut::finishQuest(const CGHeroInstance * h, ui32 accept) const
 {
 	if (accept)
 	{
@@ -4393,7 +4393,7 @@ void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const
 				}
 				break;
 			case CQuest::MISSION_ARMY:
-					cb->takeCreatures (h->id, m6creatures);
+					cb->takeCreatures(h->id, m6creatures);
 				break;
 			case CQuest::MISSION_RESOURCES:
 				for (int i = 0; i < 7; ++i)
@@ -4404,7 +4404,7 @@ void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const
 			default:
 				break;
 		}
-		cb->setObjProperty (id,11,0); //no more mission avaliable	
+		cb->setObjProperty(id,11,0); //no more mission avaliable	
 		completeQuest(h); //make sure to remove QuestQuard at the very end	
 	}
 }
@@ -4453,11 +4453,11 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
 		}
 			break;
 		case 10:// creature
-		{
-			CCreatureSet creatures;
-			creatures.setCreature (0, rID, rVal);
-			cb->giveCreatures (id, h, creatures,false);
-		}
+			{
+				CCreatureSet creatures;
+				creatures.setCreature(0, rID, rVal);
+				cb->giveCreatures (id, h, creatures,false);
+			}
 			break;
 		default:
 			break;

+ 27 - 3
lib/CCreatureSet.cpp

@@ -295,6 +295,11 @@ CCreatureSet::CCreatureSet()
 	formation = false;
 }
 
+CCreatureSet::CCreatureSet(const CCreatureSet&)
+{
+	assert(0);
+}
+
 CCreatureSet::~CCreatureSet()
 {
 	clear();
@@ -322,7 +327,11 @@ CStackInstance * CCreatureSet::detachStack(TSlot slot)
 	CStackInstance *ret = slots[slot];
 
 	if(CArmedInstance *armedObj = castToArmyObj())
-		ret->detachFrom(armedObj);
+	{
+		ret->setArmyObj(NULL); //detaches from current armyobj
+	}
+
+	assert(!ret->armyObj); //we failed detaching?
 
 	slots.erase(slot);
 	return ret;
@@ -353,6 +362,12 @@ bool CCreatureSet::hasStackAtSlot(TSlot slot) const
 	return vstd::contains(slots, slot);
 }
 
+CCreatureSet & CCreatureSet::operator=(const CCreatureSet&cs)
+{
+	assert(0);
+	return cs;
+}
+
 CStackInstance::CStackInstance()
 	: armyObj(_armyObj)
 {
@@ -410,10 +425,9 @@ void CStackInstance::setArmyObj(const CArmedInstance *ArmyObj)
 	if(_armyObj)
 		detachFrom(const_cast<CArmedInstance*>(_armyObj));
 
+	_armyObj = ArmyObj;
 	if(ArmyObj)
 	{
-		_armyObj = ArmyObj;
-
 		attachTo(const_cast<CArmedInstance*>(_armyObj));
 	}
 }
@@ -446,6 +460,11 @@ bool CStackInstance::valid(bool allowUnrandomized) const
 		return allowUnrandomized;
 }
 
+CStackInstance::~CStackInstance()
+{
+
+}
+
 CStackBasicDescriptor::CStackBasicDescriptor()
 {
 	type = NULL;
@@ -457,6 +476,11 @@ CStackBasicDescriptor::CStackBasicDescriptor(TCreature id, TQuantity Count)
 {
 }
 
+CStackBasicDescriptor::CStackBasicDescriptor(const CCreature *c, TQuantity Count)
+	: type(c), count(Count)
+{
+}
+
 DLL_EXPORT std::ostream & operator<<(std::ostream & str, const CStackInstance & sth)
 {
 	if(!sth.valid(true))

+ 5 - 0
lib/CCreatureSet.h

@@ -24,6 +24,7 @@ public:
 
 	CStackBasicDescriptor();
 	CStackBasicDescriptor(TCreature id, TQuantity Count);
+	CStackBasicDescriptor(const CCreature *c, TQuantity Count);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -57,6 +58,8 @@ public:
 	CStackInstance();
 	CStackInstance(TCreature id, TQuantity count);
 	CStackInstance(const CCreature *cre, TQuantity count);
+	~CStackInstance();
+
 	void setType(int creID);
 	void setType(const CCreature *c);
 	void setArmyObj(const CArmedInstance *ArmyObj);
@@ -71,6 +74,8 @@ typedef std::map<TSlot, CStackInstance*> TSlots;
 
 class DLL_EXPORT CCreatureSet //seven combined creatures
 {
+	CCreatureSet(const CCreatureSet&);;
+	CCreatureSet &operator=(const CCreatureSet&);
 public:
 	TSlots slots; //slots[slot_id]->> pair(creature_id,creature_quantity)
 	ui8 formation; //false - wide, true - tight

+ 37 - 12
lib/CGameState.cpp

@@ -708,7 +708,7 @@ CStack::CStack()
 }
 
 CStack::CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S)
-	: ID(I), owner(O), slot(S), attackerOwned(AO), position(-1), counterAttacks(1)
+	: base(NULL), ID(I), owner(O), slot(S), attackerOwned(AO), position(-1), counterAttacks(1)
 {
 	type = stack->type;
 	count = baseAmount = stack->count;
@@ -1021,10 +1021,23 @@ std::vector<si32> CStack::activeSpells() const
 
 CStack::~CStack()
 {
+	detachFromAll();
 	if(vstd::contains(state, SUMMONED))
 		delNull(base);
 }
 
+const CGHeroInstance * CStack::getMyHero() const
+{
+	if(base)
+		return dynamic_cast<const CGHeroInstance *>(base->armyObj);
+	else //we are attached directly?
+		BOOST_FOREACH(const CBonusSystemNode *n, parents)
+			if(n->nodeType == HERO)
+				dynamic_cast<const CGHeroInstance *>(n);
+
+	return NULL;
+}
+
 CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, std::map<ui32,CGHeroInstance *> &available, const CHeroClass *bannedClass /*= NULL*/) const
 {
 	CGHeroInstance *ret = NULL;
@@ -3482,14 +3495,18 @@ int BattleInfo::calculateSpellDuration( const CSpell * spell, const CGHeroInstan
 
 CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int position) const
 {
-	CStack * ret = new CStack(&base, attackerOwned ? side1 : side2, stackID, attackerOwned, slot);
+	int owner = attackerOwned ? side1 : side2;
+	assert(owner >= PLAYER_LIMIT  ||  base.armyObj && base.armyObj->tempOwner == owner);
+
+	CStack * ret = new CStack(&base, owner, stackID, attackerOwned, slot);
  	ret->position = position;
 	return ret;
 }
 
 CStack * BattleInfo::generateNewStack(const CStackBasicDescriptor &base, int stackID, bool attackerOwned, int slot, int position) const
 {
-	CStack * ret = new CStack(&base, attackerOwned ? side1 : side2, stackID, attackerOwned, slot);
+	int owner = attackerOwned ? side1 : side2;
+	CStack * ret = new CStack(&base, owner, stackID, attackerOwned, slot);
 	ret->position = position;
 	return ret;
 }
@@ -4578,7 +4595,7 @@ void InfoAboutHero::initFromHero( const CGHeroInstance *h, bool detailed )
 	hclass = h->type->heroClass;
 	name = h->name;
 	portrait = h->portrait;
-	army = h->getArmy(); 
+	army = ArmyDescriptor(h, detailed);
 
 	if(detailed) 
 	{
@@ -4594,14 +4611,6 @@ void InfoAboutHero::initFromHero( const CGHeroInstance *h, bool detailed )
 			details->primskills[i] = h->getPrimSkillLevel(i);
 		}
 	}
-	else
-	{
-		//hide info about hero stacks counts using descriptives names ids
-		for(TSlots::const_iterator i = army.Slots().begin(); i != army.Slots().end(); ++i)
-		{
-			army.setStackCount(i->first, i->second->getQuantityID()+1);
-		}
-	}
 }
 
 void InfoAboutHero::assign( const InfoAboutHero & iah )
@@ -4621,3 +4630,19 @@ InfoAboutHero & InfoAboutHero::operator=( const InfoAboutHero & iah )
 }
 
 
+
+ArmyDescriptor::ArmyDescriptor(const CArmedInstance *army, bool detailed)
+{
+	for(TSlots::const_iterator i = army->Slots().begin(); i != army->Slots().end(); i++)
+	{
+		if(detailed)
+			(*this)[i->first] = *i->second;
+		else
+			(*this)[i->first] = CStackBasicDescriptor(i->second->type, i->second->getQuantityID());
+	}
+}
+
+ArmyDescriptor::ArmyDescriptor()
+{
+
+}

+ 25 - 6
lib/CGameState.h

@@ -68,6 +68,13 @@ namespace boost
 	class shared_mutex;
 }
 
+//numbers of creatures are exact numbers if detailed else they are quantity ids (0 - a few, 1 - several and so on; additionaly -1 - unknown)
+struct DLL_EXPORT ArmyDescriptor : public std::map<TSlot, CStackBasicDescriptor>
+{
+	ArmyDescriptor(const CArmedInstance *army, bool detailed); //not detailed -> quantity ids as count
+	ArmyDescriptor();
+};
+
 struct DLL_EXPORT InfoAboutHero
 {
 private:
@@ -83,7 +90,8 @@ public:
 	const CHeroClass *hclass;
 	std::string name;
 	int portrait;
-	CCreatureSet army; //numbers of creatures are exact numbers if detailed else they are quantity ids (0 - a few, 1 - several and so on)
+
+	ArmyDescriptor army; 
 
 	InfoAboutHero();
 	InfoAboutHero(const InfoAboutHero & iah);
@@ -285,6 +293,7 @@ public:
 	BonusList getSpellBonuses() const;
 	void stackEffectToFeature(BonusList & sf, const Bonus & sse);
 	std::vector<si32> activeSpells() const; //returns vector of active spell IDs sorted by time of cast
+	const CGHeroInstance *getMyHero() const; //if stack belongs to hero (directly or was by him summoned) returns hero, NULL otherwise
 
 	static inline Bonus *featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
 	{
@@ -307,6 +316,12 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
+		assert(isIndependentNode());
+		h & static_cast<CBonusSystemNode&>(*this);
+		h & static_cast<CStackBasicDescriptor&>(*this);
+		h & ID & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks
+			& shots & count;
+
 		TSlot slot = (base ? base->armyObj->findStack(base) : -1);
 		const CArmedInstance *army = (base ? base->armyObj : NULL);
 		if(h.saving)
@@ -316,13 +331,17 @@ public:
 		else
 		{
 			h & army & slot;
-			base = &army->getStack(slot);
+			if(!army || slot == -1 || !army->hasStackAtSlot(slot))
+			{
+				base = NULL;
+				tlog3 << type->nameSing << " don't have a base stack!\n";
+			}
+			else
+			{
+				base = &army->getStack(slot);
+			}
 		}
 
-		h & static_cast<CBonusSystemNode&>(*this);
-		h & static_cast<CStackBasicDescriptor&>(*this);
-		h & ID & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks
-			& shots & count;
 	}
 	bool alive() const //determines if stack is alive
 	{

+ 22 - 10
lib/HeroBonus.cpp

@@ -116,6 +116,7 @@ int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selec
 {
 	return valOfBonuses(Selector::type(type) && selector);
 }
+
 int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) const
 {
 	CSelector s = Selector::type(type);
@@ -124,6 +125,7 @@ int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/)
 
 	return valOfBonuses(s);
 }
+
 int CBonusSystemNode::valOfBonuses(const CSelector &selector) const
 {
 	BonusList hlp;
@@ -300,8 +302,7 @@ CBonusSystemNode::CBonusSystemNode()
 
 CBonusSystemNode::~CBonusSystemNode()
 {
-	while(parents.size())
-		detachFrom(parents.front());
+	detachFromAll();
 
 	if(children.size())
 	{
@@ -313,13 +314,13 @@ void CBonusSystemNode::attachTo(CBonusSystemNode *parent)
 {
 	assert(!vstd::contains(parents, parent));
 	parents.push_back(parent);
-	BOOST_FOREACH(Bonus *b, exportedBonuses)
-		propagateBonus(b);
-
-	if(parent->weActAsBonusSourceOnly())
-	{
-
-	}
+// 	BOOST_FOREACH(Bonus *b, exportedBonuses)
+// 		propagateBonus(b);
+// 
+// 	if(parent->weActAsBonusSourceOnly())
+// 	{
+// 
+// 	}
 
 	parent->newChildAttached(this);
 }
@@ -413,6 +414,17 @@ void CBonusSystemNode::childDetached(CBonusSystemNode *child)
 	children -= child;
 }
 
+void CBonusSystemNode::detachFromAll()
+{
+	while(parents.size())
+		detachFrom(parents.front());
+}
+
+bool CBonusSystemNode::isIndependentNode() const
+{
+	return parents.empty() && children.empty();
+}
+
 int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
 {
 	if(obj)
@@ -466,7 +478,7 @@ std::string Bonus::Description() const
 		str << VLC->creh->creatures[id]->namePl;
 		break;
 	}
-	
+
 	return str.str();
 }
 

+ 3 - 1
lib/HeroBonus.h

@@ -410,6 +410,7 @@ public:
 
 	void attachTo(CBonusSystemNode *parent);
 	void detachFrom(CBonusSystemNode *parent);
+	void detachFromAll();
 	void addNewBonus(Bonus *b); //b will be deleted with destruction of node
 
 	void newChildAttached(CBonusSystemNode *child);
@@ -419,6 +420,7 @@ public:
 	void removeBonus(Bonus *b);
 
 	TNodesVector &nodesOnWhichWePropagate();
+	bool isIndependentNode() const; //node is independent when it has no parents nor children
 	bool weActAsBonusSourceOnly() const;
 	bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node
 	CBonusSystemNode *whereToPropagate(Bonus *b);
@@ -432,7 +434,7 @@ public:
 
 	enum ENodeTypes
 	{
-		UNKNOWN, STACK, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE
+		UNKNOWN, STACK, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO
 	};
 };
 

+ 1 - 1
lib/IGameCallback.h

@@ -88,7 +88,7 @@ public:
 	virtual void showThievesGuildWindow(int requestingObjId) =0;
 	virtual void giveResource(int player, int which, int val)=0;
 	virtual void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures, bool remove) =0;
-	virtual void takeCreatures (int objid, TSlots creatures) =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;
 	virtual bool changeStackType(const StackLocation &sl, CCreature *c) =0;

+ 16 - 15
lib/NetPacks.h

@@ -529,19 +529,20 @@ struct TryMoveHero : public CPackForClient //501
 	}
 };
 
-struct SetGarrisons : public CPackForClient //502
-{
-	SetGarrisons(){type = 502;};
-	void applyCl(CClient *cl);
-	DLL_EXPORT void applyGs(CGameState *gs);
+// struct SetGarrisons : public CPackForClient //502
+// {
+// 	SetGarrisons(){type = 502;};
+// 	void applyCl(CClient *cl);
+// 	DLL_EXPORT void applyGs(CGameState *gs);
+// 
+// 	std::map<ui32,CCreatureSet> garrs;
+// 
+// 	template <typename Handler> void serialize(Handler &h, const int version)
+// 	{
+// 		h & garrs;
+// 	}
+// }; 
 
-	std::map<ui32,CCreatureSet> garrs;
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & garrs;
-	}
-}; 
 struct NewStructures : public CPackForClient //504
 {
 	NewStructures(){type = 504;};
@@ -598,7 +599,7 @@ struct SetHeroesInTown : public CPackForClient //508
 	{
 		h & tid & visiting & garrison;
 	}
-};  
+};
 struct SetHeroArtifacts : public CPackForClient //509
 {
 	SetHeroArtifacts(){type = 509;};
@@ -798,7 +799,7 @@ struct SwapStacks : CGarrisonOperationPack  //524
 struct InsertNewStack : CGarrisonOperationPack //525
 {
 	StackLocation sl;
-	CStackInstance *stack;
+	CStackBasicDescriptor stack;
 
 	void applyCl(CClient *cl);
 	DLL_EXPORT void applyGs(CGameState *gs);
@@ -810,7 +811,7 @@ struct InsertNewStack : CGarrisonOperationPack //525
 };
 
 //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
-struct RebalanceStacks : CGarrisonOperationPack  //525
+struct RebalanceStacks : CGarrisonOperationPack  //526
 {
 	StackLocation src, dst;
 	TQuantity count;

+ 64 - 19
lib/NetPacksLib.cpp

@@ -375,23 +375,23 @@ void TryMoveHero::applyGs( CGameState *gs )
 		gs->getPlayerTeam(h->getOwner())->fogOfWarMap[t.x][t.y][t.z] = 1;
 }
 
-DLL_EXPORT void SetGarrisons::applyGs( CGameState *gs )
-{
-	for(std::map<ui32,CCreatureSet>::iterator i = garrs.begin(); i!=garrs.end(); i++)
-	{
-		CArmedInstance *ai = static_cast<CArmedInstance*>(gs->map->objects[i->first]);
-		ai->setToArmy(i->second);
-		if(ai->ID==TOWNI_TYPE && (static_cast<CGTownInstance*>(ai))->garrisonHero) //if there is a hero in garrison then we must update also his army
-			const_cast<CGHeroInstance*>((static_cast<CGTownInstance*>(ai))->garrisonHero)->setToArmy(i->second);
-		else if(ai->ID==HEROI_TYPE)
-		{
-			CGHeroInstance *h =  static_cast<CGHeroInstance*>(ai);
-			CGTownInstance *t = const_cast<CGTownInstance *>(h->visitedTown);
-			if(t && h->inTownGarrison)
-			t->setToArmy(i->second);
-		}
-	}
-}
+// DLL_EXPORT void SetGarrisons::applyGs( CGameState *gs )
+// {
+// 	for(std::map<ui32,CCreatureSet>::iterator i = garrs.begin(); i!=garrs.end(); i++)
+// 	{
+// 		CArmedInstance *ai = static_cast<CArmedInstance*>(gs->map->objects[i->first]);
+// 		ai->setToArmy(i->second);
+// 		if(ai->ID==TOWNI_TYPE && (static_cast<CGTownInstance*>(ai))->garrisonHero) //if there is a hero in garrison then we must update also his army
+// 			const_cast<CGHeroInstance*>((static_cast<CGTownInstance*>(ai))->garrisonHero)->setToArmy(i->second);
+// 		else if(ai->ID==HEROI_TYPE)
+// 		{
+// 			CGHeroInstance *h =  static_cast<CGHeroInstance*>(ai);
+// 			CGTownInstance *t = const_cast<CGTownInstance *>(h->visitedTown);
+// 			if(t && h->inTownGarrison)
+// 			t->setToArmy(i->second);
+// 		}
+// 	}
+// }
 
 DLL_EXPORT void NewStructures::applyGs( CGameState *gs )
 {
@@ -634,11 +634,43 @@ DLL_EXPORT void SwapStacks::applyGs( CGameState *gs )
 
 DLL_EXPORT void InsertNewStack::applyGs( CGameState *gs )
 {
-	sl.army->putStack(sl.slot, stack);
+	CStackInstance *s = new CStackInstance(stack.type, stack.count);
+	sl.army->putStack(sl.slot, s);
 }
 
 DLL_EXPORT void RebalanceStacks::applyGs( CGameState *gs )
 {
+	const CCreature *srcType = src.army->getCreature(src.slot);
+	TQuantity srcCount = src.army->getStackCount(src.slot);
+
+	if(srcCount == count) //moving whole stack
+	{
+		if(const CCreature *c = dst.army->getCreature(dst.slot)) //stack at dest -> merge
+		{
+			assert(c == srcType);
+			src.army->eraseStack(src.slot);
+			dst.army->changeStackCount(dst.slot, count);
+		}
+		else //move stack to an empty slot
+		{
+			CStackInstance *stackDetached = src.army->detachStack(src.slot);
+			dst.army->putStack(dst.slot, stackDetached);
+		}
+	}
+	else
+	{
+		if(const CCreature *c = dst.army->getCreature(dst.slot)) //stack at dest -> rebalance
+		{
+			assert(c == srcType);
+			src.army->changeStackCount(src.slot, -count);
+			dst.army->changeStackCount(dst.slot, count);
+		}
+		else //split stack to an empty slot
+		{
+			src.army->changeStackCount(src.slot, -count);
+			dst.army->addToSlot(dst.slot, srcType->idNumber, count, false);
+		}
+	}
 }
 
 DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs )
@@ -786,7 +818,20 @@ DLL_EXPORT void BattleStart::applyGs( CGameState *gs )
 	info->belligerents[0]->battle = info->belligerents[1]->battle = info;
 
 	BOOST_FOREACH(CStack *s, info->stacks)
-		s->attachTo(const_cast<CStackInstance*>(s->base));
+	{
+		if(s->base) //stack originating from "real" stack in garrison -> attach to it
+		{
+			s->attachTo(const_cast<CStackInstance*>(s->base));
+		}
+		else //attach directly to obj to which stack belongs and creature type
+		{
+			CArmedInstance *army = info->belligerents[!s->attackerOwned];
+			s->attachTo(army);
+			assert(s->type);
+			s->attachTo(const_cast<CCreature*>(s->type));
+		}
+		s->postInit();
+	}
 }
 
 DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )

+ 1 - 1
lib/RegisterTypes.cpp

@@ -105,7 +105,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<UpdateCampaignState>();
 	s.template registerType<RemoveObject>();
 	s.template registerType<TryMoveHero>();
-	s.template registerType<SetGarrisons>();
+	//s.template registerType<SetGarrisons>();
 	s.template registerType<NewStructures>();
 	s.template registerType<RazeStructures>();
 	s.template registerType<SetAvailableCreatures>();

+ 89 - 78
server/CGameHandler.cpp

@@ -310,27 +310,26 @@ void CGameHandler::changeSecSkill( int ID, int which, int val, bool abs/*=false*
 	}
 }
 
-static CCreatureSet takeCasualties(int color, const CCreatureSet &set, BattleInfo *bat)
+void  CGameHandler::takeCasualties(const CArmedInstance *army, BattleInfo *bat)
 {
+	int color = army->tempOwner;
 	if(color == 254)
-		color = 255;
+		color = NEUTRAL_PLAYER;
 
-	CCreatureSet ret(set);
-	for(int i=0; i<bat->stacks.size();i++)
+	BOOST_FOREACH(CStack *st, bat->stacks)
 	{
-		CStack *st = bat->stacks[i];
 		if(vstd::contains(st->state, SUMMONED)) //don't take into account sumoned stacks
 			continue;
 
-		if(st->owner==color && !set.slotEmpty(st->slot) && st->count < set.getStackCount(st->slot))
+		if(st->owner==color && !army->slotEmpty(st->slot) && st->count < army->getStackCount(st->slot))
 		{
+			StackLocation sl(army, st->slot);
 			if(st->alive())
-				ret.setStackCount(st->slot, st->count);
+				changeStackCount(sl, st->count, true);
 			else
-				ret.eraseStack(st->slot);
+				eraseStack(sl);
 		}
 	}
-	return ret;
 }
 
 void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town)
@@ -582,18 +581,6 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
 	if(bEndArmy2 && bEndArmy2->tempOwner<PLAYER_LIMIT)
 		states.setFlag(bEndArmy2->tempOwner, &PlayerStatus::engagedIntoBattle, false);	
 
-	//casualties among heroes armies
-	SetGarrisons sg;
-	sg.garrs[bEndArmy1->id] = takeCasualties(bEndArmy1->tempOwner, *bEndArmy1, gs->curB);
-	sg.garrs[bEndArmy2->id] = takeCasualties(bEndArmy2->tempOwner, *bEndArmy2, gs->curB);
-	sendAndApply(&sg);
-
-	ui8 sides[2];
-	sides[0] = gs->curB->side1;
-	sides[1] = gs->curB->side2;
-
-	ui8 loser = sides[!battleResult.data->winner];
-
 	//end battle, remove all info, free memory
 	giveExp(*battleResult.data);
 	if (hero1)
@@ -602,6 +589,16 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
 		battleResult.data->exp[1] *= (100+hero2->getSecSkillLevel(21)*5)/100.0f;
 	sendAndApply(battleResult.data);
 
+	//casualties among heroes armies
+	takeCasualties(bEndArmy1, gs->curB);
+	takeCasualties(bEndArmy2, gs->curB);
+
+	ui8 sides[2];
+	sides[0] = gs->curB->side1;
+	sides[1] = gs->curB->side2;
+
+	ui8 loser = sides[!battleResult.data->winner];
+	
 	//if one hero has lost we will erase him
 	if(battleResult.data->winner!=0 && hero1)
 	{
@@ -645,7 +642,6 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
 			if (slot != -1) 
 			{
 				winnerHero->showNecromancyDialog(raisedStack);
-				sendAndApply(&sg);
 				addToSlot(StackLocation(winnerHero, slot), raisedStack.type, raisedStack.count);
 			}
 		}
@@ -2096,64 +2092,71 @@ void CGameHandler::giveResource(int player, int which, int val)
 }
 void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures, bool remove)
 {
-	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);
-		
+	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::takeCreatures (int objid, TSlots creatures) //probably we could use ArmedInstance as well
+
+void CGameHandler::takeCreatures(int objid, std::vector<CStackBasicDescriptor> creatures)
 {
 	if (creatures.size() <= 0)
 		return;
 	const CArmedInstance* obj = static_cast<const CArmedInstance*>(getObj(objid));
-	CCreatureSet newArmy = obj->getArmy();
-	while (creatures.size())
-	{
-		int slot = newArmy.getSlotFor(creatures.begin()->second->type->idNumber);
-		if (slot < 0)
-			break;
-		newArmy.slots[slot]->count -= creatures.begin()->second->count;
-		if (newArmy.getStack(slot).count < 1)
-			newArmy.eraseStack(slot);
-		creatures.erase(creatures.begin());
-	}
-	SetGarrisons sg;
-	sg.garrs[objid] = newArmy;
-	sendAndApply(&sg);
-}
 
-void CGameHandler::takeCreatures(int objid, std::vector<CStackBasicDescriptor> creatures)
-{
+	BOOST_FOREACH(CStackBasicDescriptor &sbd, creatures)
+	{
+		TQuantity collected = 0;
+		while(collected < sbd.count)
+		{
+			TSlots::const_iterator i = obj->Slots().begin();
+			for(; i != obj->Slots().end(); i++)
+			{
+				if(i->second->type == sbd.type)
+				{
+					TQuantity take = std::min(sbd.count - collected, i->second->count); //collect as much creatures as we can
+					changeStackCount(StackLocation(obj, i->first), take, false);
+					collected += take;
+					break;
+				}
+			}
 
+			if(i ==  obj->Slots().end()) //we went through the whole loop and haven't found appropriate creatures
+			{
+				complain("Unexpected failure during taking creatures!");
+				return;
+			}
+		}
+	}
 }
 
 void CGameHandler::showCompInfo(ShowInInfobox * comp)
@@ -2549,18 +2552,25 @@ void CGameHandler::sendToAllClients( CPackForClient * info )
 
 void CGameHandler::sendAndApply( CPackForClient * info )
 {
-	gs->apply(info);
 	sendToAllClients(info);
+	gs->apply(info);
 }
 
-void CGameHandler::sendAndApply( SetGarrisons * info )
+void CGameHandler::sendAndApply(CGarrisonOperationPack * info)
 {
 	sendAndApply((CPackForClient*)info);
 	if(gs->map->victoryCondition.condition == gatherTroop)
-		for(std::map<ui32,CCreatureSet>::const_iterator i = info->garrs.begin(); i != info->garrs.end(); i++)
-			checkLossVictory(getObj(i->first)->tempOwner);
+		winLoseHandle(); 
 }
 
+// void CGameHandler::sendAndApply( SetGarrisons * info )
+// {
+// 	sendAndApply((CPackForClient*)info);
+// 	if(gs->map->victoryCondition.condition == gatherTroop)
+// 		for(std::map<ui32,CCreatureSet>::const_iterator i = info->garrs.begin(); i != info->garrs.end(); i++)
+// 			checkLossVictory(getObj(i->first)->tempOwner);
+// }
+
 void CGameHandler::sendAndApply( SetResource * info )
 {
 	sendAndApply((CPackForClient*)info);
@@ -2581,6 +2591,7 @@ void CGameHandler::sendAndApply( NewStructures * info )
 	if(gs->map->victoryCondition.condition == buildCity)
 		checkLossVictory(getTown(info->tid)->tempOwner);
 }
+
 void CGameHandler::save( const std::string &fname )
 {
 	{
@@ -5221,7 +5232,7 @@ bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, T
 
 	InsertNewStack ins;
 	ins.sl = sl;
-	ins.stack = new CStackInstance(c, count);
+	ins.stack = CStackBasicDescriptor(c, count);
 	sendAndApply(&ins);
 	return true;
 }

+ 3 - 3
server/CGameHandler.h

@@ -92,6 +92,7 @@ public:
 	bool isAllowedExchange(int id1, int id2);
 	void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
 	int moveStack(int stack, int dest); //returned value - travelled distance
+	void takeCasualties(const CArmedInstance *army, BattleInfo *bat);
 	void startBattle(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town = NULL); //use hero=NULL for no hero
 	void checkLossVictory(ui8 player);
 	void winLoseHandle(ui8 players=255); //players: bit field - colours of players to be checked; default: all
@@ -136,7 +137,6 @@ public:
 	void showThievesGuildWindow(int requestingObjId); //TODO: make something more general?
 	void giveResource(int player, int which, int val);
 	void giveCreatures (int objid, const CGHeroInstance * h, 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);
 	bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false);
@@ -152,7 +152,6 @@ public:
 	void stopHeroVisitCastle(int obj, int heroID);
 	void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack; pos==-2 - default if available or backpack
 	void giveNewArtifact(int hid, int position);
-	void moveArtifact(int hid, int oldPosition, int destPos);
 	bool removeArtifact(CArtifact* art, int hid);
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL); //use hero=NULL for no hero
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used
@@ -223,7 +222,8 @@ public:
 	void ask(Query * sel, ui8 player, const CFunctionList<void(ui32)> &callback);
 	void sendToAllClients(CPackForClient * info);
 	void sendAndApply(CPackForClient * info);
-	void sendAndApply(SetGarrisons * info);
+	void sendAndApply(CGarrisonOperationPack * info);
+	//void sendAndApply(SetGarrisons * info);
 	void sendAndApply(SetResource * info);
 	void sendAndApply(SetResources * info);
 	void sendAndApply(NewStructures * info);