Przeglądaj źródła

#39 and #106 - fixed cosmetic buildings behaviour
#102 - fixed config + requirements system
#161 - extended clickable rectangle
and some minor fixes

Ivan Savenko 16 lat temu
rodzic
commit
def041a8c9

+ 5 - 0
CCallback.cpp

@@ -813,6 +813,11 @@ const TerrainTile * CCallback::getTileInfo( int3 tile ) const
 int CCallback::canBuildStructure( const CGTownInstance *t, int ID )
 {
 	return gs->canBuildStructure(t,ID);
+}
+
+std::set<int> CCallback::getBuildingRequiments( const CGTownInstance *t, int ID )
+{
+	return gs->getBuildingRequiments(t,ID);
 }
 
 bool CCallback::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret)

+ 2 - 1
CCallback.h

@@ -156,7 +156,7 @@ public:
 	virtual std::vector < const CGTownInstance *> getTownsInfo(bool onlyOur=true) const=0;
 	virtual std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const =0; //heroes that can be recruited
 	virtual int canBuildStructure(const CGTownInstance *t, int ID) =0;//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
-	
+	virtual std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID) =0;
 	virtual void getMarketOffer(int t1, int t2, int &give, int &rec, int mode=0)const =0; //t1 - type of given resource, t2 - type of received resource; give is the amount of resource t1 that can be traded for amount rec of resource t2 (one of them is 1)
 	virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const = 0;
 
@@ -273,6 +273,7 @@ public:
 	std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const; //heroes that can be recruited
 	const TerrainTile * getTileInfo(int3 tile) const;
 	int canBuildStructure(const CGTownInstance *t, int ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
+	std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);
 	bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret);
 	const CGPathNode *getPathInfo(int3 tile);
 	bool getPath2(int3 dest, CGPath &ret);

+ 5 - 5
client/AdventureMapButton.cpp

@@ -157,9 +157,6 @@ void AdventureMapButton::clickRight(tribool down, bool previousState)
 
 void AdventureMapButton::hover (bool on)
 {
-	if(blocked)
-		return;
-
 	if(hoverable)
 	{
 		if(on)
@@ -585,8 +582,11 @@ CSlider::CSlider(int x, int y, int totalw, boost::function<void(int)> Moved, int
 	}
 
 	if(style == 0)
-	{
-		imgs = CDefHandler::giveDefEss("IGPCRDIV.DEF");
+	{
+		if (horizontal)
+			imgs = CDefHandler::giveDefEss("IGPCRDIV.DEF");
+		else
+			imgs = CDefHandler::giveDefEss("OVBUTN2.DEF");
 		left->imgs.resize(1); right->imgs.resize(1); slider->imgs.resize(1);
 		left->imgs[0].push_back(imgs->ourImages[0].bitmap); left->imgs[0].push_back(imgs->ourImages[1].bitmap);
 		right->imgs[0].push_back(imgs->ourImages[2].bitmap); right->imgs[0].push_back(imgs->ourImages[3].bitmap);

+ 22 - 31
client/CBitmapHandler.cpp

@@ -158,48 +158,39 @@ SDL_Surface * BitmapHandler::loadBitmap(std::string fname, bool setKey)
 		return NULL;
 	}
 	if(e->offset<0)
-	{
-		fname.replace(fname.find_last_of('.'),fname.find_last_of('.')+4,".BMP");
+	{
+		fname = e->realName;
 		fname = DATA_DIR "/Data/" + fname;
 		FILE * f = fopen(fname.c_str(),"r");
-		if(f)
+		char sign[3];
+		f = fopen(fname.c_str(),"r");
+		if(!f)
+		{
+			tlog1 << "Cannot open " << fname << " - not present as bmp nor as pcx.\n";
+			return NULL; 
+		}
+		fread(sign,1,3,f);
+		if(sign[0]=='B' && sign[1]=='M') //BMP named as PCX - people (eg. Kulex) sometimes use such files
 		{
 			fclose(f);
 			return SDL_LoadBMP(fname.c_str());
 		}
-		else  //file .bmp not present, check .pcx
+		else //PCX - but we don't know which
 		{
-			char sign[3];
-			fname.replace(fname.find_last_of('.'),fname.find_last_of('.')+4,".PCX");
-			f = fopen(fname.c_str(),"r");
-			if(!f)
-			{
-				tlog1 << "Cannot open " << fname << " - not present as bmp nor as pcx.\n";
-				return NULL; 
-			}
-			fread(sign,1,3,f);
-			if(sign[0]=='B' && sign[1]=='M') //BMP named as PCX - people (eg. Kulex) sometimes use such files
+			if((sign[0]==10) && (sign[1]<6) && (sign[2]==1)) //ZSoft PCX
 			{
 				fclose(f);
-				return SDL_LoadBMP(fname.c_str());
+				return IMG_Load(fname.c_str());
 			}
-			else //PCX - but we don't know which
+			else //H3-style PCX
 			{
-				if((sign[0]==10) && (sign[1]<6) && (sign[2]==1)) //ZSoft PCX
-				{
-					fclose(f);
-					return IMG_Load(fname.c_str());
-				}
-				else //H3-style PCX
-				{
-					CPCXConv cp;
-					pcx = new unsigned char[e->realSize];
-					memcpy(pcx,sign,3);
-					int res = fread((char*)pcx+3, 1, e->realSize-3, f); //TODO use me
-					fclose(f);
-					cp.openPCX((char*)pcx,e->realSize);
-					return cp.getSurface();
-				}
+				CPCXConv cp;
+				pcx = new unsigned char[e->realSize];
+				memcpy(pcx,sign,3);
+				int res = fread((char*)pcx+3, 1, e->realSize-3, f); //TODO use me
+				fclose(f);
+				cp.openPCX((char*)pcx,e->realSize);
+				return cp.getSurface();
 			}
 		}
 	}

+ 34 - 60
client/CCastleInterface.cpp

@@ -442,7 +442,6 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
 	garr->splitButtons.push_back(split);
 	statusbar = new CStatusBar(pos.x+7,pos.y+555,"TSTATBAR.bmp",732);
 	resdatabar = new CResDataBar("ZRESBAR.bmp",pos.x+3,pos.y+575,32,2,85,85);
-	resdatabar->pos.x = pos.x+3; resdatabar->pos.y = pos.y+575;
 
 	townlist->fun = boost::bind(&CCastleInterface::townChange,this);
 	townlist->genList();
@@ -622,11 +621,8 @@ void CCastleInterface::buildingClicked(int building)
 				GH.pushInt(cmw);
 				break;
 			}
-		case 15: //resource silo
-			{
-				LOCPLINT->showInfoDialog(CGI->buildh->buildings[town->subID][15]->Description(),std::vector<SComponent*>(), soundBase::sound_todo);
-				break;
-			}
+		//case 15: //resource silo - default handling should be enought
+
 		case 16: //blacksmith
 			{
 				const CGHeroInstance *hero = town->visitingHero;
@@ -662,7 +658,7 @@ void CCastleInterface::buildingClicked(int building)
 					break;
 
 				default:
-					tlog4<<"This building isn't handled...\n";
+					defaultBuildingClicked(building);
 					break;
 				}
 				break;
@@ -671,10 +667,20 @@ void CCastleInterface::buildingClicked(int building)
 		//TODO: case 24: //basic horde 2
 		//TODO: case 25: //upg horde 2
 		//TODO: case 26: //grail
-		default:
-			tlog4<<"This building isn't handled...\n";
+		default:
+				defaultBuildingClicked(building);
+				break;
 		}
 	}
+}
+void CCastleInterface::defaultBuildingClicked(int building)
+{
+	std::vector<SComponent*> comps(1,
+			new CCustomImgComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
+
+	LOCPLINT->showInfoDialog(
+		CGI->buildh->buildings[town->subID][building]->Description(),
+		comps, soundBase::sound_todo);
 }
 
 void CCastleInterface::enterHall()
@@ -1034,7 +1040,7 @@ void CCastleInterface::CCreaInfo::clickLeft(tribool down, bool previousState)
 	}
 };
 
-int AddToString(std::string from, std::string & to, int numb)
+int CCastleInterface::CCreaInfo::AddToString(std::string from, std::string & to, int numb)
 {
 	if (!numb)
 		return 0;//do not add string if 0
@@ -1077,8 +1083,8 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState)
 				CGI->creh->creatures[crid].hordeGrowth);
 
 		cnt = 0;
-		for (std::vector<CGDwelling*>::const_iterator it = CGI->state->players[0].dwellings.begin();
-			it !=CGI->state->players[0].dwellings.end(); ++it)
+		for (std::vector<CGDwelling*>::const_iterator it = CGI->state->players[ci->town->tempOwner].dwellings.begin();
+			it !=CGI->state->players[ci->town->tempOwner].dwellings.end(); ++it)
 				if (CGI->creh->creatures[crid].idNumber == (*it)->creatures[0].second[0])
 					cnt++;//external dwellings count to summ
 		summ+=AddToString(CGI->generaltexth->allTexts[591],descr,cnt);
@@ -1362,7 +1368,7 @@ CHallInterface::CBuildingBox::CBuildingBox(int id)
 	:BID(id)
 {
 	pos.w = 150;
-	pos.h = 70;
+	pos.h = 88;
 }
 CHallInterface::CBuildingBox::CBuildingBox(int id, int x, int y)
 	:BID(id)
@@ -1370,7 +1376,7 @@ CHallInterface::CBuildingBox::CBuildingBox(int id, int x, int y)
 	pos.x = x;
 	pos.y = y;
 	pos.w = 150;
-	pos.h = 70;
+	pos.h = 88;
 }
 
 
@@ -1381,7 +1387,8 @@ CHallInterface::CHallInterface(CCastleInterface * owner)
 	resdatabar->pos.x += pos.x;
 	resdatabar->pos.y += pos.y;
 	LOCPLINT->castleInt->statusbar->clear();
-	bg = BitmapHandler::loadBitmap(CGI->buildh->hall[owner->town->subID].first);
+	bg = BitmapHandler::loadBitmap(CGI->buildh->hall[owner->town->subID].first);
+	bid = owner->town->hallLevel()+10;
 	graphics->blueToPlayersAdv(bg,LOCPLINT->playerID);
 	exit = new AdventureMapButton
 		(CGI->generaltexth->hcommands[8],"",boost::bind(&CHallInterface::close,this),pos.x+748,pos.y+556,"TPMAGE1.DEF",SDLK_RETURN);
@@ -1454,16 +1461,17 @@ void CHallInterface::close()
 	GH.popIntTotally(this);
 }
 void CHallInterface::show(SDL_Surface * to)
-{
-	blitAt(bg,pos,to);
-	LOCPLINT->castleInt->statusbar->show(to);
+{
+	blitAt(bg,pos,to);
+	LOCPLINT->castleInt->statusbar->show(to);
+	printAtMiddle(CGI->buildh->buildings[LOCPLINT->castleInt->town->subID][bid]->Name(),400+pos.x,13+pos.y,GEORXX,zwykly,to);
 	resdatabar->show(to);
 	exit->show(to);
 	for(int i=0; i<5; i++)
 	{
 		for(size_t j=0;j<boxes[i].size(); ++j)
 			boxes[i][j]->show(to);
-	}
+	}
 }
 void CHallInterface::activate()
 {
@@ -1553,53 +1561,19 @@ std::string CHallInterface::CBuildWindow::getTextForState(int state)
 	case 8:
 		{
 			ret = CGI->generaltexth->allTexts[52];
-			std::set<int> used;
-			used.insert(bid);
-			std::set<int> reqs;
-
-			for(std::set<int>::iterator i=CGI->townh->requirements[tid][bid].begin();
-				i!=CGI->townh->requirements[tid][bid].end();
-				i++
-			  )
-			{
-				if (LOCPLINT->castleInt->town->builtBuildings.find(*i)   ==  LOCPLINT->castleInt->town->builtBuildings.end())
-					reqs.insert(*i);
-			}
-			while(true)
-			{
-				size_t czystych=0;
-				for(std::set<int>::iterator i=reqs.begin();i!=reqs.end();i++)
-				{
-					if(used.find(*i)==used.end()) //we haven't added requirements for this building
-					{
-						used.insert(*i);
-						for(
-							std::set<int>::iterator j=CGI->townh->requirements[tid][*i].begin();
-							j!=CGI->townh->requirements[tid][*i].end();
-							j++
-								)
-						{
-							if(LOCPLINT->castleInt->town->builtBuildings.find(*j)   ==   //this building is not built
-													LOCPLINT->castleInt->town->builtBuildings.end())
-							reqs.insert(*j);
-						}
-					}
-					else
-					{
-						czystych++;
-					}
-				}
-				if(czystych==reqs.size())
-					break;
-			}
+			std::set<int> reqs= LOCPLINT->cb->getBuildingRequiments(LOCPLINT->castleInt->town, bid);
+
 			bool first=true;
 			for(std::set<int>::iterator i=reqs.begin();i!=reqs.end();i++)
-			{
+			{
+				if (vstd::contains(LOCPLINT->castleInt->town->builtBuildings, *i))
+					continue;//skipping constructed buildings
 				ret+=(((first)?(" "):(", ")) + CGI->buildh->buildings[tid][*i]->Name());
-				first = false;
+				first = false;//TODO - currently can return "Mage guild lvl 1, MG lvl 2..." - extra check needed
 			}
 		}
 	}
+
 	return ret;
 }
 

+ 5 - 3
client/CCastleInterface.h

@@ -77,7 +77,8 @@ class CCastleInterface : public CWindowWithGarrison
 	public:
 		int crid,bid;
 		CCreaInfo(int CRID, int BID); //c-tor
-		~CCreaInfo();//d-tor
+		~CCreaInfo();//d-tor
+		int AddToString(std::string from, std::string & to, int numb);
 		void hover(bool on);
 		void clickLeft(tribool down, bool previousState);
 		void clickRight(tribool down, bool previousState);
@@ -127,7 +128,8 @@ public:
 	void keyPressed(const SDL_KeyboardEvent & key);
 	void show(SDL_Surface * to);
 	void showAll(SDL_Surface * to);
-	void buildingClicked(int building);
+	void buildingClicked(int building);
+	void defaultBuildingClicked(int building);//for buildings with simple description + pic left-click messages
 	void enterTavern();
 	void enterMageGuild();
 	void splitClicked(); //for hero meeting (splitting stacks is handled by garrison int)
@@ -189,7 +191,7 @@ public:
 	AdventureMapButton *exit;
 
 	SDL_Surface * bg; //background
-
+	int bid;//building ID
 
 	CHallInterface(CCastleInterface * owner); //c-tor
 	~CHallInterface(); //d-tor

+ 6 - 1
client/GUIClasses.cpp

@@ -15,7 +15,8 @@
 #include "CConfigHandler.h"
 #include "CCreatureAnimation.h"
 #include "Graphics.h"
-#include "../hch/CArtHandler.h"
+#include "../hch/CArtHandler.h"
+#include "../hch/CBuildingHandler.h"
 #include "../hch/CGeneralTextHandler.h"
 #include "../hch/CHeroHandler.h"
 #include "../hch/CLodHandler.h"
@@ -813,6 +814,10 @@ void SComponent::init(Etype Type, int Subtype, int Val)
 			tlog1 << "Wrong subtype=" << Subtype << std::endl;
 		}
 		subtitle = oss.str();
+		break;
+	case building:
+		description = CGI->buildh->buildings[Subtype][Val]->Description();
+		subtitle = CGI->buildh->buildings[Subtype][Val]->Name();
 		break;
 	case secskill44: case secskill:
 		subtitle += CGI->generaltexth->levels[Val-1] + " " + CGI->generaltexth->skillName[Subtype];

+ 1 - 1
client/GUIClasses.h

@@ -130,7 +130,7 @@ class SComponent : public virtual CIntObject //common popup window component
 public:
 	enum Etype
 	{
-		primskill, secskill, resource, creature, artifact, experience, secskill44, spell, morale, luck
+		primskill, secskill, resource, creature, artifact, experience, secskill44, spell, morale, luck, building
 	} type; //component type
 	int subtype; //TODO: comment me
 	int val; //TODO: comment me

+ 2 - 1
client/Graphics.cpp

@@ -291,7 +291,8 @@ Graphics::Graphics()
 	tasks += GET_DEF_ESS(halls,"ITMTLS.DEF");
 	tasks += GET_DEF_ESS(bigTownPic,"ITPT.DEF");
 	tasks += GET_DEF_ESS(pskillsb,"PSKILL.DEF");
-	tasks += GET_DEF_ESS(pskillsm,"PSKIL42.DEF");
+	tasks += GET_DEF_ESS(pskillsm,"PSKIL42.DEF");
+	tasks += GET_DEF_ESS(pskillst,"PSKIL32.DEF");
 	tasks += GET_DEF_ESS(resources,"RESOUR82.DEF");
 	tasks += GET_DEF_ESS(un44,"UN44.DEF");
 	tasks += GET_DEF_ESS(smallIcons,"ITPA.DEF");

+ 2 - 1
client/Graphics.h

@@ -70,7 +70,8 @@ public:
 	std::vector<SDL_Surface *> portraitLarge; //58x64 px portraits of heroes
 	std::vector<CDefEssential *> flags1, flags2, flags3, flags4; //flags blitted on heroes when ,
 	CDefEssential * pskillsb, *resources; //82x93
-	CDefEssential * pskillsm; //42x42
+	CDefEssential * pskillsm; //42x42  primary skills
+	CDefEssential * pskillst; //32x32
 	CDefEssential * un44; //many things
 	CDefEssential * smallIcons, *resources32; //resources 32x32
 	CDefEssential * flags;

+ 2 - 2
config/buildings.txt

@@ -167,7 +167,7 @@
 4 21 TBNCEXT0.def 307 61
 4 22 TBNCEXT1.def 247 275
 4 -1 TBNCEXT2.def 25 279
-4 27 TBNCEXT3.def 307 246
+4 27 TBNCEXT3.def 0 241
 4 28 TBNCEXT4.def 321 255
 4 29 TBNCEXT5.def 475 257
 4 11 TBNCHAL2.def 482 56
@@ -346,4 +346,4 @@
 8 41 TBELUP_4.def 264 168
 8 42 TBELUP_5.def 394 283
 8 43 TBELUP_6.def 43 0
-8 20 TBELBOAT.def 239 215
+8 20 TBELBOAT.def 239 215

+ 5 - 3
config/buildings2.txt

@@ -48,9 +48,11 @@ CASTLE 1
 10
 11
 12
-13
+13
+17
 21
-22
+22
+23
 -1
 27
 28
@@ -258,4 +260,4 @@ EOD
 
 EOD
 
-Buildings not mentioned in the file will be blitted as first. File can contain data for any count of castles.
+Buildings not mentioned in the file will be blitted as first. File can contain data for any count of castles.

+ 34 - 45
config/requirements.txt

@@ -6,24 +6,23 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 17 6
-18 7 16 30 32 33
-19 7 16 30 39 33
+18 32
+19 39
 20 6
-21 7 16 30 33
+21 33
 22 5
 30 7
-31 7 30
-32 7 16 30 33
-33 7 16 30
-34 0 7 16 30 33
-35 7 16 21 30 33
-36 0 7 16 30 33 34
+31 30
+32 33
+33 16 30
+34 0 33
+35 21
+36 34
 37 30
 38 31
 39 32
@@ -39,11 +38,10 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 18 31
 19 38
 21 17
@@ -72,11 +70,10 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 17 14
 18 31
 19 38
@@ -105,11 +102,10 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 18 30
 19 37
 21 7
@@ -139,14 +135,13 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 17 7
-18 30
-19 37
+18 22 30
+19 22 37
 20 6
 21 0
 22 30
@@ -172,17 +167,14 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 17 14
 18 30
 19 37
 21 0
-22 10
-23 10
 30 7
 31 30
 32 30
@@ -205,11 +197,10 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 17 7
 18 30
 19 37
@@ -238,11 +229,10 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 17 11 21
 18 30
 19 37
@@ -270,18 +260,17 @@
 4 3
 8 7
 9 8
-11 5
+11 10 5
 12 11 0 14 16
-13 12 7 8 9
+13 12 9
 15 14
-16 10
 17 14
 18 30
 19 37
 21 0
 30 7
-31 30
-32 30
+31 30 0
+32 30 0
 33 31
 34 32
 35 33 34
@@ -289,8 +278,8 @@
 37 30
 38 31
 39 32
-40 33
+40 33 31
 41 34
-42 35
+42 35 1
 43 36
--1
+-1

+ 6 - 3
hch/CLodHandler.cpp

@@ -226,20 +226,23 @@ void CLodHandler::init(std::string lodFile, std::string dirName)
 		{
 			if(boost::filesystem::is_regular(dir->status()))
 			{
-				std::string name = dir->path().leaf();
+				std::string name = dir->path().leaf();
+				std::string realname = name;
 				std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))toupper);
 				boost::algorithm::replace_all(name,".BMP",".PCX");
 				Entry * e = entries.znajdz(name);
 				if(e) //file present in .lod - overwrite its entry
 				{
-					e->offset = -1;
+					e->offset = -1;
+					e->realName = realname;
 					e->realSize = e->size = boost::filesystem::file_size(dir->path());
 				}
 				else //file not present in lod - add entry for it
 				{
 					Entry e2;
 					e2.offset = -1;
-					e2.nameStr = name;
+					e2.nameStr = name;
+					e2.realName = realname;
 					e2.realSize = e2.size = boost::filesystem::file_size(dir->path());
 					entries.push_back(e2);
 				}

+ 2 - 1
hch/CLodHandler.h

@@ -40,7 +40,8 @@ struct LodEntry {
 struct Entry
 {
 	// Info extracted from LOD file
-	std::string nameStr;
+	std::string nameStr,
+		    realName;
 	int offset, //from beginning
 		realSize, //size without compression
 		size;	//and with

+ 42 - 7
lib/CGameState.cpp

@@ -1796,10 +1796,47 @@ int CGameState::getMovementCost(const CGHeroInstance *h, const int3 &src, const
 	}
 	return ret;
 }
+
+std::set<int> CGameState::getBuildingRequiments(const CGTownInstance *t, int ID)
+{
+	std::set<int> used;
+	used.insert(ID);
+	std::set<int> reqs = VLC->townh->requirements[t->subID][ID];
+
+	while(true)
+	{
+		size_t noloop=0;
+		for(std::set<int>::iterator i=reqs.begin();i!=reqs.end();i++)
+		{
+			if(used.find(*i)==used.end()) //we haven't added requirements for this building
+			{
+				used.insert(*i);
+				for(
+					std::set<int>::iterator j=VLC->townh->requirements[t->subID][*i].begin();
+					j!=VLC->townh->requirements[t->subID][*i].end();
+					j++)
+					{
+						reqs.insert(*j);//creating full list of requirements
+					}
+			}
+			else
+			{
+				noloop++;
+			}
+		}
+		if(noloop==reqs.size())
+			break;
+	}
+	return reqs;
+}
 
 int CGameState::canBuildStructure( const CGTownInstance *t, int ID )
 {
-	int ret = 7; //allowed by default
+	int ret = 7; //allowed by default
+
+	if(t->builded >= MAX_BUILDING_PER_TURN)
+		ret = 5; //building limit
+
 	//checking resources
 	CBuilding * pom = VLC->buildh->buildings[t->subID][ID];
 	
@@ -1812,10 +1849,10 @@ int CGameState::canBuildStructure( const CGTownInstance *t, int ID )
 			ret = 6; //lack of res
 	}
 
-	//checking for requirements
-	for( std::set<int>::iterator ri  =  VLC->townh->requirements[t->subID][ID].begin();
-		ri != VLC->townh->requirements[t->subID][ID].end();
-		ri++ )
+	//checking for requirements
+	std::set<int> reqs = getBuildingRequiments(t, ID);//getting all requiments
+
+	for( std::set<int>::iterator ri  =  reqs.begin(); ri != reqs.end(); ri++ )
 	{
 		if(t->builtBuildings.find(*ri)==t->builtBuildings.end())
 			ret = 8; //lack of requirements - cannot build
@@ -1824,8 +1861,6 @@ int CGameState::canBuildStructure( const CGTownInstance *t, int ID )
 	//can we build it?
 	if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end())
 		ret = 2; //forbidden
-	else if(t->builded >= MAX_BUILDING_PER_TURN)
-		ret = 5; //building limit
 
 	if(ID == 13) //capitol
 	{

+ 2 - 1
lib/CGameState.h

@@ -372,7 +372,8 @@ public:
 	si8 battleMaxSpellLevel(); //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, SPELL_LEVELS is returned
 	bool battleCanShoot(int ID, int dest); //determines if stack with given ID shoot at the selected destination
 	UpgradeInfo getUpgradeInfo(const CArmedInstance *obj, int stackPos);
-	float getMarketEfficiency(int player, int mode=0);
+	float getMarketEfficiency(int player, int mode=0);
+	std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);
 	int canBuildStructure(const CGTownInstance *t, int ID);// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
 	bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
 	bool checkForVisitableDir(const int3 & src, const TerrainTile *pom, const int3 & dst) const; //check if src tile is visitable from dst tile

+ 7 - 1
server/CGameHandler.cpp

@@ -2040,7 +2040,13 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid )
 		ssi.creatures[bid-30].first = VLC->creh->creatures[crid].growth;
 		ssi.creatures[bid-30].second.push_back(crid);
 		sendAndApply(&ssi);
-	}
+	}
+	else if(bid == 11)
+		ns.bid.insert(27);
+	else if(bid == 12)
+		ns.bid.insert(28);
+	else if(bid == 13)
+		ns.bid.insert(29);
 
 	ns.bid.insert(bid);
 	ns.builded = t->builded + 1;