Browse Source

- fix for #95 and #602
- implemented animation for new town buildings

Ivan Savenko 14 years ago
parent
commit
c6f1d87ede

+ 59 - 14
client/CAnimation.cpp

@@ -585,7 +585,9 @@ SDLImage::SDLImage(std::string filename, bool compressed):
 		delete [] pic;
 	}
 	else if(bitmaph->haveFile(filename, FILE_GRAPHICS))
+	{
 		surf = BitmapHandler::loadBitmap(filename);
+	}
 	else
 	{
 		tlog0<<"Error: file not found: "<<filename<<"\n";
@@ -648,8 +650,9 @@ CompImage::CompImage(SDL_Surface * surf)
 	assert(0);
 }
 
-void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, unsigned char rotation) const
+void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, ui8 alpha) const
 {
+	int rotation = 0; //TODO
 	//rotation & 2 = horizontal rotation
 	//rotation & 4 = vertical rotation
 	if (!surf)
@@ -706,7 +709,7 @@ void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, unsigned
 		while (currX + size < sourceRect.w)
 		{
 			//blit block, pointers will be modified if needed
-			BlitBlockWithBpp(bpp, type, size, data, blitPos, rotation & 2);
+			BlitBlockWithBpp(bpp, type, size, data, blitPos, alpha, rotation & 2);
 
 			currX += size;
 			type = *(data++);
@@ -714,14 +717,14 @@ void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, unsigned
 		}
 		//Blit last, semi-visible block
 		size = sourceRect.w - currX;
-		BlitBlockWithBpp(bpp, type, size, data, blitPos, rotation & 2);
+		BlitBlockWithBpp(bpp, type, size, data, blitPos, alpha, rotation & 2);
 	}
 }
 
-#define CASEBPP(x,y) case x: BlitBlock<x,y>(type, size, data, dest); break
+#define CASEBPP(x,y) case x: BlitBlock<x,y>(type, size, data, dest, alpha); break
 
 //FIXME: better way to get blitter
-void CompImage::BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest, bool rotated) const
+void CompImage::BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha, bool rotated) const
 {
 	assert(bpp>1 && bpp<5);
 	
@@ -744,22 +747,33 @@ void CompImage::BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&
 
 //Blit one block from RLE-d surface
 template<int bpp, int dir>
-void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
+void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha) const
 {
 	//Raw data
 	if (type == 0xff)
 	{
 		ui8 color = *data;
+		if (alpha != 255)//Per-surface alpha is set
+		{
+			for (size_t i=0; i<size; i++)
+			{
+				SDL_Color col = palette[*(data++)];
+				col.unused = (unsigned int)col.unused*(255-alpha)/255;
+				ColorPutter<bpp, 1>::PutColorAlpha(dest, col);
+			}
+			return;
+		}
+
 		if (palette[color].unused == 255)
 		{
 			//Put row of RGB data
-			for (int i=0; i<size; i++)
+			for (size_t i=0; i<size; i++)
 				ColorPutter<bpp, 1>::PutColor(dest, palette[*(data++)]);
 		}
 		else
 		{
 			//Put row of RGBA data
-			for (int i=0; i<size; i++)
+			for (size_t i=0; i<size; i++)
 				ColorPutter<bpp, 1>::PutColorAlpha(dest, palette[*(data++)]);
 			
 		}
@@ -767,6 +781,15 @@ void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
 	//RLE-d sequence
 	else
 	{
+		if (alpha != 255 && palette[type].unused !=0)//Per-surface alpha is set
+		{
+			SDL_Color col = palette[type];
+			col.unused = (int)col.unused*(255-alpha)/255;
+			for (size_t i=0; i<size; i++)
+				ColorPutter<bpp, 1>::PutColorAlpha(dest, col);
+			return;
+		}
+
 		switch (palette[type].unused)
 		{
 			case 0:
@@ -784,7 +807,7 @@ void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
 			default:
 			{
 				//Put RGBA row
-				for (int i=0; i<size; i++)
+				for (size_t i=0; i<size; i++)
 					ColorPutter<bpp, 1>::PutColorAlpha(dest, palette[type]);
 				break;
 			}
@@ -792,7 +815,6 @@ void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
 	}
 }
 
-
 void CompImage::playerColored(int player)
 {
 	SDL_Color *pal = NULL;
@@ -991,6 +1013,7 @@ CAnimation::CAnimation(std::string Name, bool Compressed):
 	CDefFile * file = getFile();
 	init(file);
 	delete file;
+	loadedAnims.insert(this);
 }
 
 CAnimation::CAnimation():
@@ -998,6 +1021,7 @@ CAnimation::CAnimation():
 	compressed(false)
 {
 	init(NULL);
+	loadedAnims.insert(this);
 }
 
 CAnimation::~CAnimation()
@@ -1009,6 +1033,7 @@ CAnimation::~CAnimation()
 			for (image_map::iterator image = group->second.begin(); image != group->second.end(); ++image )
 				delete image->second;
 	}
+	loadedAnims.erase(this);
 }
 
 void CAnimation::setCustom(std::string filename, size_t frame, size_t group)
@@ -1090,6 +1115,21 @@ size_t CAnimation::size(size_t group) const
 	return 0;
 }
 
+std::set<CAnimation*> CAnimation::loadedAnims;
+
+void CAnimation::getAnimInfo()
+{
+	tlog1<<"Animation stats: Loaded "<<loadedAnims.size()<<" total\n";
+	for (std::set<CAnimation*>::iterator it = loadedAnims.begin(); it != loadedAnims.end(); it++)
+	{
+		CAnimation * anim = *it;
+		tlog1<<"Name: "<<anim->name<<" Groups: "<<anim->images.size();
+		if (!anim->images.empty())
+			tlog1<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
+		tlog1<<"\n";
+	}
+}
+
 CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, unsigned char Flags):
 	frame(Frame),
 	group(Group),
@@ -1172,7 +1212,8 @@ CShowableAnim::CShowableAnim(int x, int y, std::string name, unsigned char Flags
 	value(0),
 	flags(Flags),
 	xOffset(0),
-	yOffset(0)
+	yOffset(0),
+	alpha(255)
 {
 	anim.loadGroup(group);
 	last = anim.size(group);
@@ -1188,6 +1229,11 @@ CShowableAnim::~CShowableAnim()
 	anim.unloadGroup(group);
 }
 
+void CShowableAnim::setAlpha(unsigned int alphaValue)
+{
+	alpha = std::min<unsigned int>(alphaValue, 255);
+}
+
 bool CShowableAnim::set(size_t Group, size_t from, size_t to)
 {
 	size_t max = anim.size(Group);
@@ -1265,7 +1311,7 @@ void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
 	assert(to);
 	Rect src( xOffset, yOffset, pos.w, pos.h);
 	IImage * img = anim.getImage(frame, group);
-	img->draw(to, pos.x-xOffset, pos.y-yOffset, &src);
+	img->draw(to, pos.x-xOffset, pos.y-yOffset, &src, alpha);
 }
 
 void CShowableAnim::rotate(bool on, bool vertical)
@@ -1350,8 +1396,7 @@ void CCreatureAnim::reset()
 		if (set(at))
 			return;
 	}
-	set(type);
-	tlog0<<"Warning: next sequence was not found for animation!\n";
+	set(HOLDING);
 }
 
 void CCreatureAnim::startPreview()

+ 19 - 12
client/CAnimation.h

@@ -68,7 +68,7 @@ class IImage
 public:
 
 	//draws image on surface "where" at position
-	virtual void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL, unsigned char rotation=0) const=0;
+	virtual void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL, ui8 alpha=255) const=0;
 
 	//decrease ref count, returns true if image can be deleted (refCount <= 0)
 	bool decreaseRef();
@@ -104,7 +104,7 @@ public:
 	SDLImage(SDL_Surface * from, bool extraRef);
 	~SDLImage();
 
-	void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL, unsigned char rotation=0) const;
+	void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL,  ui8 alpha=255) const;
 	void playerColored(int player);
 	int width() const;
 	int height() const;
@@ -140,8 +140,8 @@ class CompImage : public IImage
 
 	//Used internally to blit one block of data
 	template<int bpp, int dir>
-	void BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const;
-	void BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest, bool rotated) const;
+	void BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha) const;
+	void BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha, bool rotated) const;
 
 public:
 	//Load image from def file
@@ -150,7 +150,7 @@ public:
 	CompImage(SDL_Surface * surf);
 	~CompImage();
 
-	void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL, unsigned char rotation=0) const;
+	void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL, ui8 alpha=255) const;
 	void playerColored(int player);
 	int width() const;
 	int height() const;
@@ -158,9 +158,8 @@ public:
 	friend class CompImageLoader;
 };
 
-/*
- * Class for handling animation.
- */
+
+/// Class for handling animation
 class CAnimation
 {
 private:
@@ -201,6 +200,10 @@ public:
 	CAnimation();
 	~CAnimation();
 
+	//static method for debugging - print info about loaded animations in tlog1
+	static void getAnimInfo();
+	static std::set<CAnimation*> loadedAnims;
+
 	//add custom surface to the selected position.
 	void setCustom(std::string filename, size_t frame, size_t group=0);
 
@@ -223,9 +226,8 @@ public:
 	size_t size(size_t group=0) const;
 };
 
-/*
- * Class for displaying one image from animation
- */
+
+/// Class for displaying one image from animation
 class CAnimImage: public CIntObject
 {
 private:
@@ -283,10 +285,15 @@ protected:
 	//For clipping in rect, offsets of picture coordinates
 	int xOffset, yOffset;
 
+	ui8 alpha;
+
 public:
 	//called when next animation sequence is required
 	boost::function<void()> callback;
 
+	//Set per-surface alpha, 0 = transparent, 255 = opaque
+	void setAlpha(unsigned int alphaValue);
+
 	CShowableAnim(int x, int y, std::string name, unsigned char flags=0, unsigned int Delay=4, size_t Group=0);
 	~CShowableAnim();
 
@@ -308,7 +315,7 @@ public:
 	void showAll(SDL_Surface *to);
 };
 
-/// Creature-dependend animations like attacking, moving,... outside battles
+/// Creature-dependend animations like attacking, moving,...
 class CCreatureAnim: public CShowableAnim
 {
 public:

File diff suppressed because it is too large
+ 524 - 337
client/CCastleInterface.cpp


+ 60 - 20
client/CCastleInterface.h

@@ -19,6 +19,7 @@ class CTransformerWindow;
 class CPicture;
 class CCreaturePic;
 class CMinorResDataBar;
+class CCastleBuildings;
 
 /*
  * CCastleInterface.h, part of VCMI engine
@@ -34,10 +35,14 @@ class CMinorResDataBar;
 class CBuildingRect : public CShowableAnim
 {
 public:
+	CCastleBuildings * parent;
 	const Structure* str;
 	SDL_Surface* border;
 	SDL_Surface* area;
-	CBuildingRect(const Structure *Str); //c-tor
+	
+	unsigned int stateCounter;//For building construction - current stage in animation
+	
+	CBuildingRect(CCastleBuildings * Par, const Structure *Str); //c-tor
 	~CBuildingRect(); //d-tor
 	bool operator<(const CBuildingRect & p2) const;
 	void hover(bool on);
@@ -67,6 +72,54 @@ public:
 	~CHeroGSlot(); //d-tor
 };
 
+/// Class for town screen management (town background and structures)
+class CCastleBuildings : public CIntObject
+{
+	struct AnimRule
+	{
+		int townID, buildID;
+		int toCheck;
+		size_t firstA, lastA;
+		size_t firstB, lastB;
+	};
+	
+	CPicture *background;
+	//List of buildings for each group
+	std::map< int, std::vector<const Structure*> > groups;
+	//Vector with all blittable buildings
+	std::vector<CBuildingRect*> buildings;
+
+	const CGTownInstance * town;
+
+	const CGHeroInstance* getHero();//Select hero for buildings usage
+	void checkRules();//Check animation rules (special anims for Shipyard and Mana Vortex)
+
+	void enterBlacksmith(int ArtifactID);//support for blacksmith + ballista yard
+	void enterBuilding(int building);//for buildings with simple description + pic left-click messages
+	void enterCastleGate();
+	void enterFountain(int building);//Rampart's fountains
+	void enterMagesGuild();
+	void enterTownHall();
+
+	void openMagesGuild();
+	void openTownHall();
+
+public:
+	CBuildingRect * selectedBuilding;
+
+	CCastleBuildings(const CGTownInstance* town);
+	~CCastleBuildings();
+
+	void enterDwelling(int level);
+
+	void buildingClicked(int building);
+	void addBuilding(int building);
+	void removeBuilding(int building);//FIXME: not tested!!!
+	
+	void show(SDL_Surface *to);
+	void showAll(SDL_Surface *to);
+};
+
 /// Huge class which manages the castle window
 class CCastleInterface : public CWindowWithGarrison
 {
@@ -83,7 +136,7 @@ class CCastleInterface : public CWindowWithGarrison
 		void clickRight(tribool down, bool previousState);
 		void show(SDL_Surface * to);
 	};
-	/// Town info which gets shown by right-clicking on a town at the map
+	/// Icons from town screen with castle\town hall images
 	class CTownInfo : public CIntObject
 	{
 	public:
@@ -96,15 +149,13 @@ class CCastleInterface : public CWindowWithGarrison
 		void clickRight(tribool down, bool previousState);
 		void show(SDL_Surface * to);
 	};
+
 public:
-	bool showing; //indicates if interface is active
-	CBuildingRect * hBuild; //highlighted building
+	CCastleBuildings *builds;
 	SDL_Surface * townInt;
-	SDL_Surface * cityBg;
 	const CGTownInstance * town;
 	CStatusBar * statusbar;
 	CResDataBar *resdatabar;
-	unsigned char animval, count;
 	int winMode;//0=right-click popup, 1 = normal, 2 = town hall only, 3 = fort only;
 
 	CDefEssential *bars, //0 - yellow, 1 - green, 2 - red, 3 - gray
@@ -118,7 +169,6 @@ public:
 	AdventureMapButton *split;
 
 	std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner);
-	std::vector<CBuildingRect*> buildings; //building id, building def, structure struct, border, filling
 
 	CCastleInterface(const CGTownInstance * Town, int listPos = 1); //c-tor
 	~CCastleInterface(); //d-tor
@@ -128,22 +178,12 @@ public:
 	void keyPressed(const SDL_KeyboardEvent & key);
 	void show(SDL_Surface * to);
 	void showAll(SDL_Surface * to);
-	void buildingClicked(int building);
-	void defaultBuildingClicked(int building);//for buildings with simple description + pic left-click messages
-	void enterFountain(int building);
-	void enterBlacksmith(int ArtifactID);//support for blacksmith + ballista yard
-	void enterTavern();
-	void enterMageGuild();
 	void splitClicked(); //for hero meeting (splitting stacks is handled by garrison int)
-	void showRecruitmentWindow( int level );
-	void enterHall();
 	void close();
-	void splitF();
 	void activate();
 	void deactivate();
 	void addBuilding(int bid);
 	void removeBuilding(int bid);
-	void recreateBuildings();
 	void recreateIcons();
 };
 
@@ -153,7 +193,7 @@ class CHallInterface : public CIntObject
 public:
 	CMinorResDataBar * resdatabar;
 
-	/// The building information box which gets shown by right-clicking on a building image
+	/// Building box from town hall (building icon + subtitle)
 	class CBuildingBox : public CIntObject
 	{
 	public:
@@ -169,7 +209,7 @@ public:
 		~CBuildingBox(); //d-tor
 	};
 
-	/// The actual building window where you can decide to buy a building or not
+	///  Window where you can decide to buy a building or not
 	class CBuildWindow: public CIntObject
 	{
 	public:
@@ -263,7 +303,7 @@ public:
 
 };
 
-/// The blacksmith window where you can buy one of the three war machines
+/// The blacksmith window where you can buy available in town war machine
 class CBlacksmithDialog : public CIntObject
 {
 public:

+ 8 - 6
client/CCreatureAnimation.h

@@ -66,8 +66,15 @@ private:
 	int curFrame, internalFrame; //number of currently displayed frame
 	unsigned int frames; //number of frames
 	CCreatureAnim::EAnimType type; //type of animation being displayed (-1 - whole animation, >0 - specified part [default: -1])
-public:
+	
+	template<int bpp>
+	int nextFrameT(SDL_Surface * dest, int x, int y, bool attacker, unsigned char animCount, bool incrementFrame = true, bool yellowBorder = false, bool blueBorder = false, SDL_Rect * destRect = NULL); //0 - success, any other - error //print next 
+	int nextFrameMiddle(SDL_Surface * dest, int x, int y, bool attacker, unsigned char animCount, bool IncrementFrame = true, bool yellowBorder = false, bool blueBorder = false, SDL_Rect * destRect = NULL); //0 - success, any other - error //print next 
+	
 	std::map<int, std::vector<int> > frameGroups; //groups of frames; [groupID] -> vector of frame IDs in group
+	bool once;
+
+public:
 	int fullWidth, fullHeight; //read-only, please!
 	CCreatureAnimation(std::string name); //c-tor
 	~CCreatureAnimation(); //d-tor
@@ -75,17 +82,12 @@ public:
 	void setType(CCreatureAnim::EAnimType type); //sets type of animation and cleares framecount
 	CCreatureAnim::EAnimType getType() const; //returns type of animation
 
-
-	template<int bpp>
-	int nextFrameT(SDL_Surface * dest, int x, int y, bool attacker, unsigned char animCount, bool incrementFrame = true, bool yellowBorder = false, bool blueBorder = false, SDL_Rect * destRect = NULL); //0 - success, any other - error //print next 
 	int nextFrame(SDL_Surface * dest, int x, int y, bool attacker, unsigned char animCount, bool incrementFrame = true, bool yellowBorder = false, bool blueBorder = false, SDL_Rect * destRect = NULL); //0 - success, any other - error //print next 
-	int nextFrameMiddle(SDL_Surface * dest, int x, int y, bool attacker, unsigned char animCount, bool IncrementFrame = true, bool yellowBorder = false, bool blueBorder = false, SDL_Rect * destRect = NULL); //0 - success, any other - error //print next 
 	void incrementFrame();
 	int getFrame() const;
 	bool onFirstFrameInGroup();
 	bool onLastFrameInGroup();
 
-	bool once;
 	void playOnce(CCreatureAnim::EAnimType type); //plays once given stage of animation, then resets to 2
 
 	int framesInGroup(CCreatureAnim::EAnimType group) const; //retirns number of fromes in given group

+ 6 - 2
client/CMT.cpp

@@ -224,8 +224,8 @@ int main(int argc, char** argv)
 	}
 
 	//Set environment vars to make window centered. Sometimes work, sometimes not. :/
-	putenv("SDL_VIDEO_WINDOW_POS");
-	putenv("SDL_VIDEO_CENTERED=1");
+	putenv((char*)"SDL_VIDEO_WINDOW_POS");
+	putenv((char*)"SDL_VIDEO_CENTERED=1");
 
 	timeHandler total, pomtime;
 	std::cout.flags(std::ios::unitbuf);
@@ -482,6 +482,10 @@ void processCommand(const std::string &message)
 					if(const CArtifactInstance *a = h->getArt(id2))
 						tlog4 << a->nodeName();
 		}
+		else if (what == "anim" )
+		{
+			CAnimation::getAnimInfo();
+		}
 	}
 	else if(client && client->serv && client->serv->connected) //send to server
 	{

+ 19 - 5
client/CPlayerInterface.cpp

@@ -264,7 +264,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
 					//TODO: smooth disappear / appear effect
 		}
 
-		if (details.result != TryMoveHero::SUCCESS && details.result != TryMoveHero::FAILED //hero didn't change tile but visit succeeded
+		if ((details.result != TryMoveHero::SUCCESS && details.result != TryMoveHero::FAILED) //hero didn't change tile but visit succeeded
 			|| directlyAttackingCreature) // or creature was attacked from endangering tile.
 		{
 			eraseCurrentPathOf(ho);
@@ -1021,7 +1021,7 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus
 	if(bonus.type == Bonus::NONE)	return;
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	updateInfo(hero);
-	if (bonus.type == Bonus::FLYING_MOVEMENT || bonus.type == Bonus::WATER_WALKING && !gain)
+	if ((bonus.type == Bonus::FLYING_MOVEMENT || bonus.type == Bonus::WATER_WALKING) && !gain)
 	{
 		//recalculate paths because hero has lost bonus influencing pathfinding
 		cb->recalculatePaths();
@@ -1213,10 +1213,12 @@ void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
 		}
 
 		if(obj->ID == TOWNI_TYPE)
+		{
 			if(obj->tempOwner == playerID)
 				towns.push_back(static_cast<const CGTownInstance *>(obj));
 			else
 				towns -= obj;
+		}
 
 		assert(cb->getTownsInfo().size() == towns.size());
 	}
@@ -1279,7 +1281,7 @@ void CPlayerInterface::newObject( const CGObjectInstance * obj )
 		&&  obj->pos-obj->getVisitableOffset() == LOCPLINT->castleInt->town->bestLocation())
 	{
 		CCS->soundh->playSound(soundBase::newBuilding);
-		LOCPLINT->castleInt->recreateBuildings();
+		LOCPLINT->castleInt->addBuilding(20);
 	}
 }
 
@@ -2054,7 +2056,7 @@ void CPlayerInterface::showMarketWindow(const IMarket *market, const CGHeroInsta
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	if(market->o->ID == 2) //Altar
 	{
-		EMarketMode mode = market->availableModes().front();
+		//EMarketMode mode = market->availableModes().front();
 		if(market->allowsTrade(ARTIFACT_EXP) && visitor->getAlignment() != EVIL)
 			GH.pushInt(new CAltarWindow(market, visitor, ARTIFACT_EXP));
 		else if(market->allowsTrade(CREATURE_EXP) && visitor->getAlignment() != GOOD)
@@ -2158,7 +2160,7 @@ void CPlayerInterface::newStackInserted(const StackLocation &location, const CSt
 void CPlayerInterface::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	bool updateInfobox = true;
+	//bool updateInfobox = true;
 	garrisonChanged(src.army, UPDATE_IF(src));
 	if(dst.army != src.army)
 		garrisonChanged(dst.army, UPDATE_IF(dst));
@@ -2179,27 +2181,39 @@ void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const Artifact
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	BOOST_FOREACH(IShowActivable *isa, GH.listInt)
+	{
 		if(isa->type & IShowActivable::WITH_ARTIFACTS)
+		{
 			BOOST_FOREACH(CArtifactsOfHero *aoh, (dynamic_cast<CWindowWithArtifacts*>(isa))->artSets)
 				aoh->artifactMoved(src, dst);
+		}
+	}
 }
 
 void CPlayerInterface::artifactAssembled(const ArtifactLocation &al)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	BOOST_FOREACH(IShowActivable *isa, GH.listInt)
+	{
 		if(isa->type & IShowActivable::WITH_ARTIFACTS)
+		{
 			BOOST_FOREACH(CArtifactsOfHero *aoh, (dynamic_cast<CWindowWithArtifacts*>(isa))->artSets)
 				aoh->artifactAssembled(al);
+		}
+	}
 }
 
 void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	BOOST_FOREACH(IShowActivable *isa, GH.listInt)
+	{
 		if(isa->type & IShowActivable::WITH_ARTIFACTS)
+		{
 			BOOST_FOREACH(CArtifactsOfHero *aoh, (dynamic_cast<CWindowWithArtifacts*>(isa))->artSets)
 				aoh->artifactDisassembled(al);
+		}
+	}
 }
 
 boost::recursive_mutex * CPlayerInterface::pim = new boost::recursive_mutex;

+ 2 - 1
client/GUIBase.cpp

@@ -50,6 +50,7 @@ void CGuiHandler::popInt( IShowActivable *top )
 	if(listInt.size())
 		listInt.front()->activate();
 	totalRedraw();
+	fakeMouseMove();
 }
 
 void CGuiHandler::popIntTotally( IShowActivable *top )
@@ -333,7 +334,7 @@ void CGuiHandler::fakeMouseMove()
 
 	evnt.motion = sme;
 	current = &evnt;
-	handleMoveInterested(sme);
+	handleMouseMotion(&evnt);
 }
 
 void CGuiHandler::run()

+ 4 - 2
client/GUIClasses.cpp

@@ -494,6 +494,8 @@ void CGarrisonInt::setArmy(const CArmedInstance *army, bool bottomGarrison)
 CInfoWindow::CInfoWindow(std::string Text, int player, const TCompsInfo &comps, const TButtonsInfo &Buttons, bool delComps)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
+
+	type |= BLOCK_ADV_HOTKEYS;
 	ID = -1;
 	for(int i=0;i<Buttons.size();i++)
 	{
@@ -4919,9 +4921,9 @@ void LRClickableAreaOpenTown::clickLeft(tribool down, bool previousState)
 		LOCPLINT->openTownWindow(town);
 		LOCPLINT->castleInt->winMode = type;
 		if ( type == 2 )
-			LOCPLINT->castleInt->buildingClicked(10);
+			LOCPLINT->castleInt->builds->buildingClicked(10);
 		else if ( type == 3 && town->fortLevel() )
-			LOCPLINT->castleInt->buildingClicked(7);
+			LOCPLINT->castleInt->builds->buildingClicked(7);
 		}
 }
 

+ 2 - 0
config/buildings4.txt

@@ -90,6 +90,8 @@ GROUP
 19
 CASTLE 6
 GROUP
+21
+GROUP
 30
 37
 18

Some files were not shown because too many files changed in this diff