Browse Source

Partially done support for external creature dwellings.

Michał W. Urbańczyk 16 years ago
parent
commit
b551f6a72b

+ 2 - 0
CGameInterface.h

@@ -28,6 +28,7 @@ struct TryMoveHero;
 class CGHeroInstance;
 class CGTownInstance;
 class CGObjectInstance;
+class CGDwelling;
 class CCreatureSet;
 class CArmedInstance;
 struct BattleResult;
@@ -81,6 +82,7 @@ public:
 	virtual void init(ICallback * CB){};
 	virtual void receivedResource(int type, int val){};
 	virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID){};
+	virtual void showRecruitmentDialog(const CGDwelling *dwelling, int level){}
 	//virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
 	//virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
 	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.

+ 10 - 6
client/CCastleInterface.cpp

@@ -932,15 +932,19 @@ void CCastleInterface::recreateBuildings()
 
 CRecruitmentWindow * CCastleInterface::showRecruitmentWindow( int building )
 {
-	if(building>36)
+	if(building>36) //upg dwelling
 		building-=7;
+
+	int level = building-30;
+	assert(level >= 0 && level <= 6);
+
 	std::vector<std::pair<int,int > > crs;
-	int amount = (const_cast<CGTownInstance*>(town))->strInfo.creatures[building-30]; //trzeba odconstowac, bo inaczej operator [] by sypal :(
+	int amount = town->creatures[level].first;
 
-	if(town->builtBuildings.find(building+7) != town->builtBuildings.end()) //check if there is an upgraded building
-		crs.push_back(std::make_pair(town->town->upgradedCreatures[building-30],amount));
+	const std::vector<ui32> &cres = town->creatures[level].second;
 
-	crs.push_back(std::make_pair(town->town->basicCreatures[building-30],amount));
+	for(size_t i = 0; i < cres.size(); i++)
+		crs.push_back(std::make_pair((int)cres[i],amount));
 
 	CRecruitmentWindow *rw = new CRecruitmentWindow(crs,boost::bind(&CCallback::recruitCreatures,LOCPLINT->cb,town,_1,_2));
 	LOCPLINT->pushInt(rw);
@@ -1436,7 +1440,7 @@ void CFortScreen::draw( CCastleInterface * owner, bool first)
 		printAtMiddle(CGI->buildh->buildings[owner->town->subID][30+i+upgraded*7]->Name(),positions[i].x+79,positions[i].y+100,GEOR13,zwykly,bg); //dwelling name
 		if(present) //if creature is present print avail able quantity
 		{
-			SDL_itoa(owner->town->strInfo.creatures.find(i)->second,buf,10);
+			SDL_itoa(owner->town->creatures[i].first,buf,10);
 			printAtMiddle(CGI->generaltexth->allTexts[217] + buf,positions[i].x+79,positions[i].y+118,GEOR13,zwykly,bg);
 		}
 		blitAt(icons,positions[i].x+261,positions[i].y+3,bg);

+ 1 - 1
client/CMT.cpp

@@ -122,7 +122,7 @@ void init()
 	tlog0<<"Screen handler: "<<pomtime.getDif()<<std::endl;
 	pomtime.getDif();
 	graphics = new Graphics();
-	graphics->loadHeroAnim();
+	graphics->loadHeroAnims();
 	tlog0<<"\tMain graphics: "<<tmh.getDif()<<std::endl;
 	tlog0<<"Initializing game graphics: "<<tmh.getDif()<<std::endl;
 

+ 13 - 0
client/CPlayerInterface.cpp

@@ -1756,3 +1756,16 @@ const CGHeroInstance * CPlayerInterface::getWHero( int pos )
 		return NULL;
 	return wanderingHeroes[pos];
 }
+
+void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, int level)
+{
+	std::vector<std::pair<int,int> > cres;
+	for(int i = 0; i < dwelling->creatures.size(); i++)
+	{
+		if(i == level || level < 0)
+			for(size_t j = 0; j < dwelling->creatures[i].second.size(); j++)
+				cres.push_back( std::make_pair(dwelling->creatures[i].second[j],dwelling->creatures[i].first));
+	}
+	CRecruitmentWindow *cr = new CRecruitmentWindow(cres, boost::bind(&CCallback::recruitCreatures, cb, dwelling, _1, _2));
+	pushInt(cr);
+}

+ 1 - 2
client/CPlayerInterface.h

@@ -134,8 +134,7 @@ public:
 	void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town);
 	void receivedResource(int type, int val);
 	void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID);
-	//void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
-	//void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
+	void showRecruitmentDialog(const CGDwelling *dwelling, int level);
 	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel); //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
 	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd);
 	void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war

+ 38 - 29
client/Graphics.cpp

@@ -305,49 +305,58 @@ void Graphics::loadHeroPortraits()
 	}
 	of.close();
 }
-void Graphics::loadHeroAnim()
+void Graphics::loadHeroAnims()
 {
-	heroAnims.resize(F_NUMBER * 2);
 	std::vector<std::pair<int,int> > rotations; //first - group number to be rotated1, second - group number after rotation1
 	rotations += std::make_pair(6,10), std::make_pair(7,11), std::make_pair(8,12), std::make_pair(1,13),
 		std::make_pair(2,14), std::make_pair(3,15);
-	for(size_t i=0; i<heroAnims.size(); ++i)
+	for(size_t i=0; i<F_NUMBER * 2; ++i)
 	{
 		std::ostringstream nm;
 		nm << "AH" << std::setw(2) << std::setfill('0') << i << "_.DEF";
+		loadHeroAnim(nm.str(), rotations, &Graphics::heroAnims);
 		std::string name = nm.str();
-		heroAnims[i] = CDefHandler::giveDefEss(name);
-		int pom = 0; //how many groups has been rotated
-		for(int o=7; pom<6; ++o)
+	}	
+
+	loadHeroAnim("AB01_.DEF", rotations, &Graphics::boatAnims);
+	loadHeroAnim("AB02_.DEF", rotations, &Graphics::boatAnims);
+	loadHeroAnim("AB03_.DEF", rotations, &Graphics::boatAnims);
+}
+
+void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst )
+{
+	CDefEssential *anim = CDefHandler::giveDefEss(name);
+	heroAnims.push_back(anim);
+	int pom = 0; //how many groups has been rotated
+	for(int o=7; pom<6; ++o)
+	{
+		for(int p=0;p<6;p++)
 		{
-			for(int p=0;p<6;p++)
+			if(anim->ourImages[o].groupNumber == rotations[p].first)
 			{
-				if(heroAnims[i]->ourImages[o].groupNumber==rotations[p].first)
+				for(int e=0; e<8; ++e)
 				{
-					for(int e=0; e<8; ++e)
-					{
-						Cimage nci;
-						nci.bitmap = CSDL_Ext::rotate01(heroAnims[i]->ourImages[o+e].bitmap);
-						nci.groupNumber = rotations[p].second;
-						nci.imName = std::string();
-						heroAnims[i]->ourImages.push_back(nci);
-						if(pom>2) //we need only one frame for groups 13/14/15
-							break;
-					}
-					if(pom<3) //there are eight frames of animtion of groups 6/7/8 so for speed we'll skip them
-						o+=8;
-					else //there is only one frame of 1/2/3
-						o+=1;
-					++pom;
-					if(p==2 && pom<4) //group1 starts at index 1
-						o = 1;
+					Cimage nci;
+					nci.bitmap = CSDL_Ext::rotate01(anim->ourImages[o+e].bitmap);
+					nci.groupNumber = rotations[p].second;
+					nci.imName = std::string();
+					anim->ourImages.push_back(nci);
+					if(pom>2) //we need only one frame for groups 13/14/15
+						break;
 				}
+				if(pom<3) //there are eight frames of animtion of groups 6/7/8 so for speed we'll skip them
+					o+=8;
+				else //there is only one frame of 1/2/3
+					o+=1;
+				++pom;
+				if(p==2 && pom<4) //group1 starts at index 1
+					o = 1;
 			}
 		}
-		for(size_t ff=0; ff<heroAnims[i]->ourImages.size(); ++ff)
-		{
-			CSDL_Ext::alphaTransform(heroAnims[i]->ourImages[ff].bitmap);
-		}
+	}
+	for(size_t ff=0; ff<anim->ourImages.size(); ++ff)
+	{
+		CSDL_Ext::alphaTransform(anim->ourImages[ff].bitmap);
 	}
 }
 

+ 3 - 1
client/Graphics.h

@@ -48,6 +48,7 @@ public:
 	CDefEssential * smallIcons, *resources32; //resources 32x32
 	CDefEssential * flags;
 	std::vector<CDefEssential *> heroAnims; // [class id: 0 - 17]  //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
+	std::vector<CDefEssential *> boatAnims; // [boat type: 0 - 3]  //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
 	//creatures
 	std::map<int,SDL_Surface*> smallImgs; //creature ID -> small 32x32 img of creature; //ID=-2 is for blank (black) img; -1 for the border
 	std::map<int,SDL_Surface*> bigImgs; //creature ID -> big 58x64 img of creature; //ID=-2 is for blank (black) img; -1 for the border
@@ -69,7 +70,8 @@ public:
 	void loadPaletteAndColors();
 	void loadHeroFlags();
 	void loadHeroFlags(std::pair<std::vector<CDefEssential *> Graphics::*, std::vector<const char *> > &pr, bool mode);
-	void loadHeroAnim();
+	void loadHeroAnims();
+	void loadHeroAnim(const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst);
 	void loadHeroPortraits();
 	SDL_Surface * drawHeroInfoWin(const CGHeroInstance * curh);
 	SDL_Surface * drawPrimarySkill(const CGHeroInstance *curh, SDL_Surface *ret, int from=0, int to=PRIMARY_SKILLS);

+ 19 - 3
client/NetPacksClient.cpp

@@ -459,11 +459,27 @@ void ShowInInfobox::applyCl(CClient *cl)
 	}
 }
 
-void HeroExchange::applyFirstCl(CClient *cl)
+void OpenWindow::applyFirstCl(CClient *cl)
 {
 }
 
-void HeroExchange::applyCl(CClient *cl)
+void OpenWindow::applyCl(CClient *cl)
 {
-	cl->playerint[player]->heroExchangeStarted(hero1, hero2);
+	switch(window)
+	{
+	case EXCHANGE_WINDOW:
+		{
+			const CGHeroInstance *h = cl->getHero(id1);
+			const CGObjectInstance *h2 = cl->getHero(id2);
+			assert(h && h2);
+			INTERFACE_CALL_IF_PRESENT(h->tempOwner,heroExchangeStarted, id1, id2);
+		}
+		break;
+	case RECRUITMENT_FIRST:
+		{
+			const CGDwelling *dw = dynamic_cast<const CGDwelling*>(cl->getObj(id1));
+			INTERFACE_CALL_IF_PRESENT(dw->tempOwner,showRecruitmentDialog, dw, 0);
+		}
+	}
+
 }

+ 80 - 11
hch/CObjectHandler.cpp

@@ -903,6 +903,77 @@ si32 CGHeroInstance::getArtPos(int aid) const
 	return -1;
 }
 
+void CGDwelling::initObj()
+{
+	switch(ID)
+	{
+	case 17:
+		creatures.resize(1);
+		creatures[0].second.push_back(VLC->objh->cregens[subID]);
+		break;
+	case 20:
+		creatures.resize(4);
+		if(subID == 1) // Elemental Conflux 
+		{
+			creatures[0].second.push_back(32);  //Stone Golem
+			creatures[1].second.push_back(33);  //Iron Golem  
+			creatures[2].second.push_back(116); //Gold Golem
+			creatures[3].second.push_back(117); //Diamond Golem
+		}
+		else if(subID == 1) //Golem Factory
+		{
+			creatures[0].second.push_back(112); //Air Elemental
+			creatures[1].second.push_back(113); //Earth Elemental
+			creatures[2].second.push_back(114); //Fire Elemental
+			creatures[3].second.push_back(115); //Water Elemental
+		}
+		else
+		{
+			assert(0);
+		}
+		break;
+	default:
+		assert(0);
+		break;
+	}
+}
+
+void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
+{
+	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);
+}
+
+void CGDwelling::newTurn() const
+{
+	if(cb->getDate(1) != 1) //not first day of week
+		return;
+
+
+	bool change = false;
+
+	SetAvailableCreatures sac;
+	sac.creatures = creatures;
+	sac.tid = id;
+	for (size_t i = 0; i < creatures.size(); i++)
+	{
+		if(creatures[i].second.size())
+		{
+			sac.creatures[i].first += VLC->creh->creatures[creatures[i].second[0]].growth;
+			change = true;
+		}
+	}
+
+	if(change)
+		cb->sendAndApply(&sac);
+}
+
 int CGTownInstance::getSightRadious() const //returns sight distance
 {
 	return 5;
@@ -1042,6 +1113,15 @@ void CGTownInstance::initObj()
 	MetaString ms;
 	ms << name << ", " << town->Name();
 	hoverName = toString(ms);
+
+	creatures.resize(CREATURES_PER_TOWN);
+	for (int i = 0; i < CREATURES_PER_TOWN; i++)
+	{
+		if(creatureDwelling(i,false))
+			creatures[i].second.push_back(town->basicCreatures[i]);
+		if(creatureDwelling(i,true))
+			creatures[i].second.push_back(town->upgradedCreatures[i]);
+	}
 }
 
 int3 CGTownInstance::getSightCenter() const
@@ -2144,17 +2224,6 @@ const std::string & CGWitchHut::getHoverText() const
 	return hoverName;
 }
 
-
-void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
-{
-
-}
-
-void CGDwelling::initObj()
-{
-
-}
-
 void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
 {
 	bool visited = h->getBonus(HeroBonus::OBJECT,ID);

+ 25 - 23
hch/CObjectHandler.h

@@ -284,7 +284,22 @@ public:
 	void onHeroVisit(const CGHeroInstance * h) const;
 };
 
-class DLL_EXPORT CGTownInstance : public CArmedInstance
+class DLL_EXPORT CGDwelling : public CArmedInstance
+{
+public:
+	std::vector<std::pair<ui32, std::vector<ui32> > > creatures; //creatures[level] -> <vector of alternative ids (base creature and upgrades, creatures amount>
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CArmedInstance&>(*this) & creatures;
+	}
+
+	void initObj();
+	void onHeroVisit(const CGHeroInstance * h) const;
+	void newTurn() const;
+};
+
+class DLL_EXPORT CGTownInstance : public CGDwelling
 {
 public:
 	CTown * town;
@@ -298,15 +313,15 @@ public:
 	std::vector<ui32> possibleSpells, obligatorySpells;
 	std::vector<std::vector<ui32> > spells; //spells[level] -> vector of spells, first will be available in guild
 
-	struct StrInfo
-	{
-		std::map<si32,ui32> creatures; //level - available amount
+	//struct StrInfo
+	//{
+	//	std::map<si32,ui32> creatures; //level - available amount
 
-		template <typename Handler> void serialize(Handler &h, const int version)
-		{
-			h & creatures;
-		}
-	} strInfo;
+	//	template <typename Handler> void serialize(Handler &h, const int version)
+	//	{
+	//		h & creatures;
+	//	}
+	//} strInfo;
 	std::set<CCastleEvent> events;
 
 	//////////////////////////////////////////////////////////////////////////
@@ -316,7 +331,7 @@ public:
 	{
 		h & static_cast<CArmedInstance&>(*this);
 		h & name & builded & destroyed & identifier & alignment & forbiddenBuildings & builtBuildings
-			& possibleSpells & obligatorySpells & spells & strInfo & events;
+			& possibleSpells & obligatorySpells & spells & /*strInfo & */events;
 
 		ui8 standardType = (&VLC->townh->towns[subID] == town);
 		h & standardType;
@@ -666,19 +681,6 @@ public:
 	}
 };
 
-class DLL_EXPORT CGDwelling : public CGObjectInstance //teleports and subterranean gates
-{
-public:
-	static std::map<int,std::map<int, std::vector<int> > > objs; //map[ID][subID] => vector of ids
-	void onHeroVisit(const CGHeroInstance * h) const;
-	void initObj();	
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & static_cast<CGObjectInstance&>(*this);
-	}
-};
-
 class DLL_EXPORT CGBonusingObject : public CGObjectInstance //objects giving bonuses to luck/morale/movement
 {
 public:

+ 4 - 3
lib/CGameState.cpp

@@ -1343,11 +1343,12 @@ int CGameState::battleGetBattlefieldType(int3 tile)
 	else if(tile==int3() && !curB)
 		return -1;
 
-	std::vector <CGObjectInstance*> & objs = map->objects;
+	const std::vector <CGObjectInstance*> & objs = map->objects;
 	for(int g=0; g<objs.size(); ++g)
 	{
-		if( objs[g]->pos.x - tile.x < 0 || objs[g]->pos.x - tile.x >= 8 || tile.y - objs[g]->pos.y + 5 < 0 || tile.y - objs[g]->pos.y + 5 >=6 ||
-			!objs[g]->coveringAt(objs[g]->pos.x - tile.x, tile.y - objs[g]->pos.y + 5)
+		if( !objs[g] || objs[g]->pos.x - tile.x < 0  ||  objs[g]->pos.x - tile.x >= 8  
+			||  tile.y - objs[g]->pos.y + 5 < 0  ||  tile.y - objs[g]->pos.y + 5 >=6 
+			|| !objs[g]->coveringAt(objs[g]->pos.x - tile.x, tile.y - objs[g]->pos.y + 5)
 			) //look only for objects covering given tile
 			continue;
 		switch(objs[g]->ID)

+ 7 - 6
lib/NetPacks.h

@@ -409,7 +409,7 @@ struct SetAvailableCreatures : public CPackForClient //506
 	DLL_EXPORT void applyGs(CGameState *gs);
 
 	si32 tid;
-	std::map<si32,ui32> creatures;
+	std::vector<std::pair<ui32, std::vector<ui32> > > creatures;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -480,19 +480,20 @@ struct GiveHero : public CPackForClient //516
 	}
 };  
 
-struct HeroExchange : public CPackForClient //517
+struct OpenWindow : public CPackForClient //517
 {
-	HeroExchange(){type = 517;};
+	OpenWindow(){type = 517;};
 	void applyFirstCl(CClient *cl);
 	void applyCl(CClient *cl);
 	DLL_EXPORT void applyGs(CGameState *gs);
 
-	si32 hero1, hero2; //heroes for exchange
-	ui8 player;
+	enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL};
+	ui8 window;
+	ui32 id1, id2;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & hero1 & hero2 & player;
+		h & window & id1 & id2;
 	}
 };
 

+ 2 - 2
lib/NetPacksLib.cpp

@@ -278,7 +278,7 @@ DLL_EXPORT void NewStructures::applyGs( CGameState *gs )
 
 DLL_EXPORT void SetAvailableCreatures::applyGs( CGameState *gs )
 {
-	gs->getTown(tid)->strInfo.creatures = creatures;
+	gs->getTown(tid)->creatures = creatures;
 }
 
 DLL_EXPORT void SetHeroesInTown::applyGs( CGameState *gs )
@@ -418,7 +418,7 @@ DLL_EXPORT void GiveHero::applyGs( CGameState *gs )
 	h->inTownGarrison = false;
 }
 
-DLL_EXPORT void HeroExchange::applyGs(CGameState *gs)
+DLL_EXPORT void OpenWindow::applyGs(CGameState *gs)
 {
 }
 

+ 1 - 1
lib/RegisterTypes.cpp

@@ -93,7 +93,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<SetStackEffect>();
 	s.template registerType<StacksInjured>();
 	s.template registerType<ShowInInfobox>();
-	s.template registerType<HeroExchange>();
+	s.template registerType<OpenWindow>();
 
 	s.template registerType<SaveGame>();
 	s.template registerType<SetSelection>();

+ 9 - 3
lib/map.cpp

@@ -1672,6 +1672,12 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 				break;
 			}
 		case 17: case 18: case 19: case 20: //dwellings
+			{
+				nobj = new CGDwelling();
+				nobj->setOwner(bufor[i++]);
+				i+=3;
+				break;
+			}
 		case 42: //lighthouse
 		case 87: //shipyard
 		case 220://mine (?)
@@ -1759,7 +1765,7 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 			}
 		case 217:
 			{
-				nobj = new CGObjectInstance();
+				nobj = new CGDwelling();
 				CCreGenObjInfo * spec = new CCreGenObjInfo;
 				spec->player = readNormalNr(bufor,i); i+=4;
 				spec->identifier =  readNormalNr(bufor,i); i+=4;
@@ -1779,7 +1785,7 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 			}
 		case 216:
 			{
-				nobj = new CGObjectInstance();
+				nobj = new CGDwelling();
 				CCreGen2ObjInfo * spec = new CCreGen2ObjInfo;
 				spec->player = readNormalNr(bufor,i); i+=4;
 				spec->identifier =  readNormalNr(bufor,i); i+=4;
@@ -1801,7 +1807,7 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 			}
 		case 218:
 			{
-				nobj = new CGObjectInstance();
+				nobj = new CGDwelling();
 				CCreGen3ObjInfo * spec = new CCreGen3ObjInfo;
 				spec->player = bufor[i]; ++i;
 				i+=3;

+ 37 - 39
mapHandler.cpp

@@ -773,63 +773,61 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
 				SDL_Rect pp = objects[h].second;
 				pp.h = sr.h;
 				pp.w = sr.w;
-				const CGHeroInstance * themp = (dynamic_cast<const CGHeroInstance*>(objects[h].first));
 
-				if(themp && themp->moveDir && !themp->isStanding && themp->ID!=62) //last condition - this is not prison
+				const CGHeroInstance * themp = (objects[h].first->ID != HEROI_TYPE  
+					? NULL  
+					: static_cast<const CGHeroInstance*>(objects[h].first));
+
+				if(themp && themp->moveDir) //it's hero
 				{
 					int imgVal = 8;
 					SDL_Surface * tb;
-
 					if(themp->type==NULL)
 						continue;
 					std::vector<Cimage> & iv = graphics->heroAnims[themp->type->heroType]->ourImages;
 
-                    size_t gg;
-					for(gg=0; gg<iv.size(); ++gg)
+					if(!themp->isStanding) //hero is moving
 					{
-						if(iv[gg].groupNumber==getHeroFrameNum(themp->moveDir, !themp->isStanding))
+						size_t gg;
+						for(gg=0; gg<iv.size(); ++gg)
 						{
-							tb = iv[gg+heroAnim%imgVal].bitmap;
-							break;
+							if(iv[gg].groupNumber==getHeroFrameNum(themp->moveDir, !themp->isStanding))
+							{
+								tb = iv[gg+heroAnim%imgVal].bitmap;
+								break;
+							}
 						}
+						CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
+						pp.y+=imgVal*2-32;
+						sr.y-=16;
+						SDL_BlitSurface(graphics->flags4[themp->getOwner()]->ourImages[gg+heroAnim%imgVal+35].bitmap, &pp, extSurf, &sr);
 					}
-					CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
-					pp.y+=imgVal*2-32;
-					sr.y-=16;
-					SDL_BlitSurface(graphics->flags4[themp->getOwner()]->ourImages[gg+heroAnim%imgVal+35].bitmap, &pp, extSurf, &sr);
-				}
-				else if(themp && themp->moveDir && themp->isStanding && themp->ID!=62) //last condition - this is not prison)
-				{
-					int imgVal = 8;
-					SDL_Surface * tb;
-
-					if(themp->type==NULL)
-						continue;
-					std::vector<Cimage> & iv = graphics->heroAnims[themp->type->heroType]->ourImages;
-
-                    size_t gg;
-					for(gg=0; gg < iv.size(); ++gg)
+					else //hero stands still
 					{
-						if(iv[gg].groupNumber==getHeroFrameNum(themp->moveDir, !themp->isStanding))
+						size_t gg;
+						for(gg=0; gg < iv.size(); ++gg)
 						{
-							tb = iv[gg].bitmap;
-							break;
+							if(iv[gg].groupNumber==getHeroFrameNum(themp->moveDir, !themp->isStanding))
+							{
+								tb = iv[gg].bitmap;
+								break;
+							}
 						}
-					}
-					CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
+						CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
 
-					if(themp->pos.x==top_tile.x+bx && themp->pos.y==top_tile.y+by)
-					{
-						SDL_Rect bufr = sr;
-						bufr.x-=2*32;
-						bufr.y-=1*32;
-						bufr.h = 64;
-						bufr.w = 96;
-						if(bufr.x-extRect->x>-64)
-							SDL_BlitSurface(graphics->flags4[themp->getOwner()]->ourImages[ getHeroFrameNum(themp->moveDir, !themp->isStanding) *8+(heroAnim/4)%imgVal].bitmap, NULL, extSurf, &bufr);
+						if(themp->pos.x==top_tile.x+bx && themp->pos.y==top_tile.y+by)
+						{
+							SDL_Rect bufr = sr;
+							bufr.x-=2*32;
+							bufr.y-=1*32;
+							bufr.h = 64;
+							bufr.w = 96;
+							if(bufr.x-extRect->x>-64)
+								SDL_BlitSurface(graphics->flags4[themp->getOwner()]->ourImages[ getHeroFrameNum(themp->moveDir, !themp->isStanding) *8+(heroAnim/4)%imgVal].bitmap, NULL, extSurf, &bufr);
+						}
 					}
 				}
-				else
+				else //blit object
 				{
 					const CGObjectInstance *obj = objects[h].first;
 					const std::vector<Cimage> &ourImages = obj->defInfo->handler->ourImages;

+ 48 - 28
server/CGameHandler.cpp

@@ -709,14 +709,14 @@ void CGameHandler::newTurn()
 			{
 				SetAvailableCreatures sac;
 				sac.tid = (**j).id;
-				sac.creatures = (**j).strInfo.creatures;
+				sac.creatures = (**j).creatures;
 				for(int k=0;k<CREATURES_PER_TOWN;k++) //creature growths
 				{
 					if((**j).creatureDwelling(k))//there is dwelling (k-level)
 					{
-						sac.creatures[k] += (**j).creatureGrowth(k);
+						sac.creatures[k].first += (**j).creatureGrowth(k);
 						if(!gs->getDate(0)) //first day of game: use only basic growths
-							amin(sac.creatures[k], VLC->creh->creatures[(*j)->town->basicCreatures[k]].growth);
+							amin(sac.creatures[k].first, VLC->creh->creatures[(*j)->town->basicCreatures[k]].growth);
 					}
 				}
 				n.cres.push_back(sac);
@@ -1203,7 +1203,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
 			{
 				if (obj->blockVisit)
 				{
-					obj->onHeroVisit(h);
+					objectVisited(obj, h);
 				}
 			}
 			tlog5 << "Blocking visit at " << hmpos << std::endl;
@@ -1224,7 +1224,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
 			//call objects if they are visited
 			BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects)
 			{
-				obj->onHeroVisit(h);
+				objectVisited(obj, h);
 			}
 		}
 		tlog5 << "Movement end!\n";
@@ -1449,10 +1449,10 @@ void CGameHandler::heroExchange(si32 hero1, si32 hero2)
 
 	if(player1 == player2)
 	{
-		HeroExchange hex;
-		hex.hero1 = hero1;
-		hex.hero2 = hero2;
-		hex.player = player1;
+		OpenWindow hex;
+		hex.window = OpenWindow::EXCHANGE_WINDOW;
+		hex.id1 = hero1;
+		hex.id2 = hero2;
 		sendAndApply(&hex);
 	}
 }
@@ -1679,8 +1679,8 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid )
 	{
 		SetAvailableCreatures ssi;
 		ssi.tid = tid;
-		ssi.creatures = t->strInfo.creatures;
-		ssi.creatures[bid-30] = VLC->creh->creatures[t->town->basicCreatures[bid-30]].growth;
+		ssi.creatures = t->creatures;
+		ssi.creatures[bid-30].first = VLC->creh->creatures[t->town->basicCreatures[bid-30]].growth;
 		sendAndApply(&ssi);
 	}
 
@@ -1715,26 +1715,41 @@ void CGameHandler::sendMessageToAll( const std::string &message )
 
 bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
 {
-	si32 ser = -1;
-	CGTownInstance * t = static_cast<CGTownInstance*>(gs->map->objects[objid]);
+	const CGDwelling *dw = static_cast<CGDwelling*>(gs->map->objects[objid]);
+	const CArmedInstance *dst = NULL;
+
+	if(dw->ID == TOWNI_TYPE)
+		dst = dw;
+	else if(dw->ID == 17  ||  dw->ID == 20) //advmap dwelling
+		dst = getHero(gs->getPlayer(dw->tempOwner)->currentSelection); //TODO: check if current hero is really visiting dwelling
+
+	assert(dw && dst);
 
 	//verify
 	bool found = false;
+	int level = -1;
+
+
 	typedef std::pair<const int,int> Parka;
-	for(std::map<si32,ui32>::iterator av = t->strInfo.creatures.begin();  av!=t->strInfo.creatures.end();  av++)
+	for(level = 0; level < dw->creatures.size(); level++) //iterate through all levels
 	{
-		if(	(   found  = (crid == t->town->basicCreatures[av->first])   ) //creature is available among basic cretures
-			|| (found  = (crid == t->town->upgradedCreatures[av->first]))			)//creature is available among upgraded cretures
+		const std::pair<ui32, std::vector<ui32> > &cur = dw->creatures[level]; //current level info <amount, list of cr. ids>
+		int i = 0;
+		for(; i < cur.second.size(); i++) //look for crid among available creatures list on current level
+			if(cur.second[i] == crid)
+				break;
+
+		if(i < cur.second.size())
 		{
-			cram = std::min(cram,av->second); //reduce recruited amount up to available amount
-			ser = av->first;
+			found = true;
+			cram = std::min(cram, cur.first); //reduce recruited amount up to available amount
 			break;
 		}
 	}
-	int slot = t->army.getSlotFor(crid);
+	int slot = dst->army.getSlotFor(crid);
 
 	if(!found && complain("Cannot recruit: no such creatures!")
-		|| cram > VLC->creh->creatures[crid].maxAmount(gs->getPlayer(t->tempOwner)->resources) && complain("Cannot recruit: lack of resources!")
+		|| cram > VLC->creh->creatures[crid].maxAmount(gs->getPlayer(dst->tempOwner)->resources) && complain("Cannot recruit: lack of resources!")
 		|| cram<=0	&& complain("Cannot recruit: cram <= 0!")
 		|| slot<0  && complain("Cannot recruit: no available slot!")) 
 	{
@@ -1743,24 +1758,24 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
 
 	//recruit
 	SetResources sr;
-	sr.player = t->tempOwner;
+	sr.player = dst->tempOwner;
 	for(int i=0;i<RESOURCE_QUANTITY;i++)
-		sr.res[i]  =  gs->getPlayer(t->tempOwner)->resources[i] - (VLC->creh->creatures[crid].cost[i] * cram);
+		sr.res[i]  =  gs->getPlayer(dst->tempOwner)->resources[i] - (VLC->creh->creatures[crid].cost[i] * cram);
 
 	SetAvailableCreatures sac;
 	sac.tid = objid;
-	sac.creatures = t->strInfo.creatures;
-	sac.creatures[ser] -= cram;
+	sac.creatures = dw->creatures;
+	sac.creatures[level].first -= cram;
 
 	SetGarrisons sg;
-	sg.garrs[objid] = t->army;
-	if(sg.garrs[objid].slots.find(slot) == sg.garrs[objid].slots.end()) //take a free slot
+	sg.garrs[dst->id] = dst->army;
+	if(sg.garrs[dst->id].slots.find(slot) == sg.garrs[dst->id].slots.end()) //take a free slot
 	{
-		sg.garrs[objid].slots[slot] = std::make_pair(crid,cram);
+		sg.garrs[dst->id].slots[slot] = std::make_pair(crid,cram);
 	}
 	else //add creatures to a already existing stack
 	{
-		sg.garrs[objid].slots[slot].second += cram;
+		sg.garrs[dst->id].slots[slot].second += cram;
 	}
 	sendAndApply(&sr); 
 	sendAndApply(&sac);
@@ -2667,3 +2682,8 @@ bool CGameHandler::isAllowedExchange( int id1, int id2 )
 
 	return false;
 }
+
+void CGameHandler::objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h )
+{
+	obj->onHeroVisit(h);
+}

+ 1 - 0
server/CGameHandler.h

@@ -156,6 +156,7 @@ public:
 	void close();
 	void handleTimeEvents();
 	bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
+	void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{