浏览代码

- Buttons optimization - less memory and CPU usage
- gcc compilation fixes

Ivan Savenko 14 年之前
父节点
当前提交
450ae1772c

+ 160 - 183
client/AdventureMapButton.cpp

@@ -1,18 +1,18 @@
 #include "AdventureMapButton.h"
 #include "CAnimation.h"
-#include "CAdvmapInterface.h"
+//#include "CAdvmapInterface.h"
 #include "SDL_Extensions.h"
 #include "CGameInfo.h"
-#include "../lib/CLodHandler.h"
-#include "../lib/CGeneralTextHandler.h"
-#include "../lib/CTownHandler.h"
+//#include "../lib/CGeneralTextHandler.h"
+//#include "../lib/CTownHandler.h"
 #include "../CCallback.h"
 #include "CConfigHandler.h"
-#include "Graphics.h"
+//#include "Graphics.h"
 #include "CBattleInterface.h"
 #include "CPlayerInterface.h"
 #include "CMessage.h"
 #include "CMusicHandler.h"
+#include "GUIClasses.h"
 
 /*
  * AdventureMapButton.cpp, part of VCMI engine
@@ -26,90 +26,88 @@
 
 CButtonBase::CButtonBase()
 {
+	swappedImages = false;
 	bitmapOffset = 0;
-	curimg=0;
-	type=-1;
-	abs=false;
-	//active=false;
-	notFreeButton = false;
-	ourObj=NULL;
-	state=0;
+	state=NORMAL;
+	image = NULL;
 	text = NULL;
 }
 
 CButtonBase::~CButtonBase()
 {
-	delete text;
-	if(notFreeButton)
-		return;
-	for (size_t i = 0; i<imgs.size(); i++)
-		delete imgs[i];
-	imgs.clear();
+	
 }
 
-void CButtonBase::show(SDL_Surface * to)
+void CButtonBase::update()
 {
-	int img = std::min(state+bitmapOffset,int(imgs[curimg]->size()-1));
-	img = std::max(0, img);
-
-	IImage *toBlit = imgs[curimg]->getImage(img);
-
-	if (abs)
+	if (text)
 	{
-		if(toBlit)
-		{
-			toBlit->draw(to, pos.x, pos.y);
-		}
+		if (state == PRESSED)
+			text->moveTo(Point(pos.x+pos.w/2+1, pos.y+pos.h/2+1));
 		else
-		{
-			SDL_Rect r = pos;
-			SDL_FillRect(to, &r, 0x505000);
-		}
-		if(text)
-		{//using "state" instead of "state == 1" screwed up hoverable buttons with text
-			CSDL_Ext::printAt(text->text, text->x + pos.x + (state == 1), text->y + pos.y + (state == 1), text->font, text->color, to);
-		}
+			text->moveTo(Point(pos.x+pos.w/2, pos.y+pos.h/2));
 	}
-	else
+	size_t newPos = (int)state + bitmapOffset;
+	if (swappedImages)
 	{
-		toBlit->draw(to, pos.x+ourObj->pos.x,pos.y+ourObj->pos.y);
+		     if (newPos == 0) newPos = 1;
+		else if (newPos == 1) newPos = 0;
 	}
+	image->setFrame(newPos);
+	showAll(screen);
+	showAll(screen2);//Any way to remove one of showAll()?
 }
 
-void CButtonBase::showAll( SDL_Surface * to )
+void CButtonBase::addTextOverlay( const std::string &Text, EFonts font, SDL_Color color)
 {
-	show(to);
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	delChild(text);
+	text = new CLabel(pos.w/2, pos.h/2, font, CENTER, color, Text);
+	update();
 }
 
-void CButtonBase::addTextOverlay( const std::string Text, EFonts font, SDL_Color color)
+void CButtonBase::setOffset(int newOffset)
 {
-	delete text;
-	text = new TextOverlay;
-	text->text = Text;
+	if (bitmapOffset == newOffset)
+		return;
+	bitmapOffset = newOffset;
+	update();
+}
 
-	const Font *f = graphics->fonts[font];
-	text->x = pos.w/2 - f->getWidth(Text.c_str())/2;
-	text->y = pos.h/2 - f->height/2;
-	text->font = font;
-	text->color = color;
+void CButtonBase::setState(ButtonState newState)
+{
+	if (state == newState)
+		return;
+	state = newState;
+	update();
 }
 
+CButtonBase::ButtonState CButtonBase::getState()
+{
+	return state;
+}
+
+bool CButtonBase::isBlocked()
+{
+	return state == BLOCKED;
+}
+
+bool CButtonBase::isHighlighted()
+{
+	return state == HIGHLIGHTED;
+}
+
+void CButtonBase::block(bool on)
+{
+	setState(on?BLOCKED:NORMAL);
+}
 
 AdventureMapButton::AdventureMapButton ()
 {
-	type=2;
-	abs=true;
-	hoverable = false;
-	//active=false;
-	ourObj=NULL;
-	state=0;
-	blocked = actOnDown = false;
+	hoverable = actOnDown = false;
 	used = LCLICK | RCLICK | HOVER | KEYBOARD;
 }
-//AdventureMapButton::AdventureMapButton( std::string Name, std::string HelpBox, boost::function<void()> Callback, int x, int y, std::string defName, bool activ,  std::vector<std::string> * add, bool playerColoredButton)
-//{
-//	init(Callback, Name, HelpBox, playerColoredButton, defName, add, x, y, activ);
-//}
+
 AdventureMapButton::AdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y,  const std::string &defName,int key, std::vector<std::string> * add, bool playerColoredButton )
 {
 	std::map<int,std::string> pom;
@@ -117,11 +115,6 @@ AdventureMapButton::AdventureMapButton( const std::string &Name, const std::stri
 	init(Callback, pom, HelpBox, playerColoredButton, defName, add, x, y, key);
 }
 
-AdventureMapButton::AdventureMapButton( const std::map<int,std::string> &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key, std::vector<std::string> * add /*= NULL*/, bool playerColoredButton /*= false */ )
-{
-	init(Callback, Name, HelpBox, playerColoredButton, defName, add, x, y, key);
-}
-
 AdventureMapButton::AdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key/*=0*/ )
 {
 	std::map<int,std::string> pom;
@@ -129,7 +122,7 @@ AdventureMapButton::AdventureMapButton( const std::string &Name, const std::stri
 	init(Callback, pom, HelpBox, info->playerColoured, info->defName, &info->additionalDefs, info->x, info->y, key);
 }
 
-AdventureMapButton::AdventureMapButton( const std::pair<std::string, std::string> help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key/*=0*/, std::vector<std::string> * add /*= NULL*/, bool playerColoredButton /*= false */ )
+AdventureMapButton::AdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key/*=0*/, std::vector<std::string> * add /*= NULL*/, bool playerColoredButton /*= false */ )
 {
 	std::map<int,std::string> pom;
 	pom[0] = help.first;
@@ -137,20 +130,19 @@ AdventureMapButton::AdventureMapButton( const std::pair<std::string, std::string
 }
 void AdventureMapButton::clickLeft(tribool down, bool previousState)
 {
-	if(blocked)
+	if(isBlocked())
 		return;
 
 	if (down) 
 	{
 		CCS->soundh->playSound(soundBase::button);
-		state = 1;
+		setState(PRESSED);
 	} 
 	else if(hoverable && hovered)
-		state = 3;
+		setState(HIGHLIGHTED);
 	else
-		state = 0;
+		setState(NORMAL);
 
-	show(screenBuf);
 	if (actOnDown && down)
 	{
 		callback();
@@ -172,24 +164,18 @@ void AdventureMapButton::hover (bool on)
 	if(hoverable)
 	{
 		if(on)
-			state = 3;
+			setState(HIGHLIGHTED);
 		else
-			state = 0;
+			setState(NORMAL);
 	}
 
-	if(pressedL)
-	{
-		if(on)
-			state = 1;
-		else
-			state = hoverable ? 3 : 0;
-	}
+	if(pressedL && on)
+		setState(PRESSED);
 
-	////Hoverable::hover(on);
-	std::string *name = (vstd::contains(hoverTexts,state)) 
-							? (&hoverTexts[state]) 
+	std::string *name = (vstd::contains(hoverTexts,getState())) 
+							? (&hoverTexts[getState()]) 
 							: (vstd::contains(hoverTexts,0) ? (&hoverTexts[0]) : NULL);
-	if(name && name->size() && blocked!=1) //if there is no name, there is nohing to display also
+	if(name && name->size() && !isBlocked()) //if there is no name, there is nohing to display also
 	{
 		if (LOCPLINT && LOCPLINT->battleInt) //for battle buttons
 		{
@@ -216,69 +202,62 @@ void AdventureMapButton::hover (bool on)
 
 void AdventureMapButton::init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key)
 {
+	currentImage = -1;
 	used = LCLICK | RCLICK | HOVER | KEYBOARD;
 	callback = Callback;
-	blocked = actOnDown = false;
-	type=2;
-	abs=true;
-	hoverable = false;
-	//active=false;
-	ourObj=NULL;
+	actOnDown = hoverable = false;
 	assignedKeys.insert(key);
-	state=0;
 	hoverTexts = Name;
 	helpBox=HelpBox;
 
-	setDef(defName, playerColoredButton);
-
-	if (add && add->size())
-		for (size_t i=0; i<add->size();i++)
-			setDef((*add)[i], playerColoredButton);
-	if (playerColoredButton)
-		setPlayerColor(LOCPLINT->playerID);
-
 	pos.x += x;
 	pos.y += y;
-	pos.w = imgs[curimg]->getImage(0)->width();
-	pos.h = imgs[curimg]->getImage(0)->height() -1;
+
+	if (!defName.empty())
+		imageNames.push_back(defName);
+	if (add)
+		for (size_t i=0; i<add->size();i++ )
+			imageNames.push_back(add->at(i));
+	setIndex(0, playerColoredButton);
 }
 
-void AdventureMapButton::block( ui8 on )
+void AdventureMapButton::setIndex(size_t index, bool playerColoredButton)
 {
-	blocked = on;
-	state = 0;
-	bitmapOffset = on ? 2 : 0;
-	show(screenBuf);
+	if (index == currentImage || index>=imageNames.size())
+		return;
+	currentImage = index;
+	setImage(new CAnimation(imageNames[index]), playerColoredButton);
 }
 
-void AdventureMapButton::setDef(const std::string & defName, bool playerColoredButton, bool reset/*=false*/)
+void AdventureMapButton::setImage(CAnimation* anim, bool playerColoredButton)
 {
-	if (reset)
-	{
-		for (size_t i=0; i<imgs.size(); i++)
-			delete imgs[i];
-		imgs.clear();
-	}
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	
+	if (image && active)
+		image->deactivate();
+	delChild(image);
+	image = new CAnimImage(anim, getState());
+	if (active)
+		image->activate();
+	if (playerColoredButton)
+		image->playerColored(LOCPLINT->playerID);
+
+	pos.w = image->pos.w;
+	pos.h = image->pos.h;
 	
-	imgs.push_back(new CAnimation(defName));
-	imgs.back()->load();
 }
 
 void AdventureMapButton::setPlayerColor(int player)
 {
-	for(size_t i =0; i<imgs.size();i++)
-		for(size_t j=0;j<imgs[i]->size();j++)
-		{
-			imgs[i]->getImage(j)->playerColored(player);
-		}
+	if (image)
+	image->playerColored(player);
 }
 
 void CHighlightableButton::select(bool on)
 {
-	selected = on;
-	state = selected ? 3 : 0;
+	setState(on?HIGHLIGHTED:NORMAL);
 
-	if(selected)
+	if(on)
 		callback();
 	else 
 		callback2();
@@ -291,32 +270,30 @@ void CHighlightableButton::select(bool on)
 
 void CHighlightableButton::clickLeft(tribool down, bool previousState)
 {
-	if(blocked)
+	if(isBlocked())
 		return;
-	if (down) 
+
+	if (down && !(onlyOn && isHighlighted()))
 	{
 		CCS->soundh->playSound(soundBase::button);
-		state = 1;
-	} 
-	else
-		state = selected ? 3 : 0;
+		setState(PRESSED);
+	}
 
-	show(screenBuf);
-	if(previousState  &&  down == false)
+	if(previousState  &&  down == false && getState() == PRESSED)
 	{
-		if(!onlyOn || !selected)
-			select(!selected);
+		//if(!onlyOn || !isHighlighted())
+			select(!isHighlighted());
 	}
 }
 
 CHighlightableButton::CHighlightableButton( const CFunctionList<void()> &onSelect, const CFunctionList<void()> &onDeselect, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key)
-: onlyOn(false), selected(false), callback2(onDeselect)
+: onlyOn(false), callback2(onDeselect)
 {
 	init(onSelect,Name,HelpBox,playerColoredButton,defName,add,x,y,key);
 }
 
-CHighlightableButton::CHighlightableButton( const std::pair<std::string, std::string> help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key/*=0*/, std::vector<std::string> * add /*= NULL*/, bool playerColoredButton /*= false */ )
-: onlyOn(false), selected(false) // TODO: callback2(???)
+CHighlightableButton::CHighlightableButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key/*=0*/, std::vector<std::string> * add /*= NULL*/, bool playerColoredButton /*= false */ )
+: onlyOn(false) // TODO: callback2(???)
 {
 	ID = myid;
 	std::map<int,std::string> pom;
@@ -325,7 +302,7 @@ CHighlightableButton::CHighlightableButton( const std::pair<std::string, std::st
 }
 
 CHighlightableButton::CHighlightableButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key/*=0*/, std::vector<std::string> * add /*= NULL*/, bool playerColoredButton /*= false */ )
-: onlyOn(false), selected(false) // TODO: callback2(???)
+: onlyOn(false) // TODO: callback2(???)
 {
 	ID = myid;
 	std::map<int,std::string> pom;
@@ -335,6 +312,11 @@ CHighlightableButton::CHighlightableButton( const std::string &Name, const std::
 
 void CHighlightableButtonsGroup::addButton(CHighlightableButton* bt)
 {
+	if (bt->parent)
+		bt->parent->removeChild(bt);
+	addChild(bt);
+	bt->recActions = defActions;//FIXME: not needed?
+
 	bt->callback += boost::bind(&CHighlightableButtonsGroup::selectionChanged,this,bt->ID);
 	bt->onlyOn = true;
 	buttons.push_back(bt);
@@ -342,10 +324,11 @@ void CHighlightableButtonsGroup::addButton(CHighlightableButton* bt)
 
 void CHighlightableButtonsGroup::addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect, int key)
 {
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	CHighlightableButton *bt = new CHighlightableButton(OnSelect, 0, tooltip, HelpBox, false, defName, 0, x, y, key);
 	if(musicLike)
 	{
-		bt->bitmapOffset = buttons.size() - 3;
+		bt->setOffset(buttons.size() - 3);
 	}
 	bt->ID = uid;
 	bt->callback += boost::bind(&CHighlightableButtonsGroup::selectionChanged,this,bt->ID);
@@ -359,26 +342,7 @@ CHighlightableButtonsGroup::CHighlightableButtonsGroup(const CFunctionList2<void
 
 CHighlightableButtonsGroup::~CHighlightableButtonsGroup()
 {
-	for(size_t i=0;i<buttons.size();i++)
-	{
-		delete buttons[i];
-	}
-}
-
-void CHighlightableButtonsGroup::activate()
-{
-	for(size_t i=0;i<buttons.size();i++)
-	{
-		buttons[i]->activate();
-	}
-}
-
-void CHighlightableButtonsGroup::deactivate()
-{
-	for(size_t i=0;i<buttons.size();i++)
-	{
-		buttons[i]->deactivate();
-	}
+	
 }
 
 void CHighlightableButtonsGroup::select(int id, bool mode)
@@ -401,23 +365,33 @@ void CHighlightableButtonsGroup::select(int id, bool mode)
 void CHighlightableButtonsGroup::selectionChanged(int to)
 {
 	for(size_t i=0;i<buttons.size(); ++i)
-		if(buttons[i]->ID!=to && buttons[i]->selected)
+		if(buttons[i]->ID!=to && buttons[i]->isHighlighted())
 			buttons[i]->select(false);
 	onChange(to);
 }
 
 void CHighlightableButtonsGroup::show(SDL_Surface * to )
 {
-	for(size_t i=0;i<buttons.size(); ++i) 
+	if (musicLike)
 	{
-		if(!musicLike || (musicLike && buttons[i]->selected)) //if musicLike, print only selected button
-			buttons[i]->show(to);
+		for(size_t i=0;i<buttons.size(); ++i)
+			if(buttons[i]->isHighlighted())
+				buttons[i]->show(to);
 	}
+	else
+		CIntObject::show(to);
 }
 
 void CHighlightableButtonsGroup::showAll( SDL_Surface * to )
 {
-	show(to);
+	if (musicLike)
+	{
+		for(size_t i=0;i<buttons.size(); ++i)
+			if(buttons[i]->isHighlighted())
+				buttons[i]->showAll(to);
+	}
+	else
+		CIntObject::showAll(to);
 }
 
 void CHighlightableButtonsGroup::block( ui8 on )
@@ -495,10 +469,11 @@ void CSlider::moveTo(int to)
 		{
 			float part = (float)to/positions;
 			part*=(pos.w-48);
-			slider->pos.x = part + pos.x + 16;
+			int newPos = part + pos.x + 16 - slider->pos.x;
+			slider->moveBy(Point(newPos, 0));
 		}
 		else
-			slider->pos.x = pos.x+16;
+			slider->moveTo(Point(pos.x+16, pos.y));
 	}
 	else
 	{
@@ -506,10 +481,11 @@ void CSlider::moveTo(int to)
 		{
 			float part = (float)to/positions;
 			part*=(pos.h-48);
-			slider->pos.y = part + pos.y + 16;
+			int newPos = part + pos.y + 16 - slider->pos.y;
+			slider->moveBy(Point(0, newPos));
 		}
 		else
-			slider->pos.y = pos.y+16;
+			slider->moveTo(Point(pos.x, pos.y+16));
 	}
 
 	if(moved)
@@ -518,7 +494,7 @@ void CSlider::moveTo(int to)
 
 void CSlider::clickLeft(tribool down, bool previousState)
 {
-	if(down && !slider->blocked)
+	if(down && !slider->isBlocked())
 	{
 		float pw = 0;
 		float rw = 0;
@@ -600,24 +576,25 @@ CSlider::CSlider(int x, int y, int totalw, boost::function<void(int)> Moved, int
 	if(style == 0)
 	{
 		std::string name = horizontal?"IGPCRDIV.DEF":"OVBUTN2.DEF";
+		CAnimation *animLeft = new CAnimation();
+		animLeft->setCustom(name + ":0", 0);
+		animLeft->setCustom(name + ":1", 1);
+		left->setImage(animLeft);
+
+		CAnimation *animRight = new CAnimation();
+		animRight->setCustom(name + ":2", 0);
+		animRight->setCustom(name + ":3", 1);
+		right->setImage(animRight);
 		
-		left->imgs.push_back(new CAnimation(name));
-		left->imgs.back()->load();
-		left->bitmapOffset = 0;
-
-		right->imgs.push_back(new CAnimation(name));
-		right->imgs.back()->load();
-		right->bitmapOffset = 2;
-
-		slider->imgs.push_back(new CAnimation(name));
-		slider->imgs.back()->load();
-		slider->bitmapOffset = 4;
+		CAnimation *animSlider = new CAnimation();
+		animSlider->setCustom(name + ":4", 0);
+		slider->setImage(animSlider);
 	}
 	else
 	{
-		left->setDef(horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF", false);
-		right->setDef(horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF", false);
-		slider->setDef("SCNRBSL.DEF", false);
+		left->setImage(new CAnimation(horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF"));
+		right->setImage(new CAnimation(horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF"));
+		slider->setImage(new CAnimation("SCNRBSL.DEF"));
 	}
 	slider->actOnDown = true;
 

+ 41 - 37
client/AdventureMapButton.h

@@ -18,6 +18,8 @@
 extern SDL_Color tytulowy, tlo, zwykly ;
 
 class CAnimation;
+class CAnimImage;
+class CLabel;
 
 namespace config{struct ButtonInfo;}
 
@@ -25,59 +27,63 @@ namespace config{struct ButtonInfo;}
 class CButtonBase : public KeyShortcut//basic button class
 {
 public:
-	struct TextOverlay
+	enum ButtonState
 	{
-		EFonts font;
-		std::string text;
-		SDL_Color color;
-		int x, y;
-	} *text;
-	void addTextOverlay(const std::string Text, EFonts font, SDL_Color color = zwykly);
-
-	int bitmapOffset; //TODO: comment me
-	int type; //advmapbutton=2 //TODO: comment me
-	bool abs;//TODO: comment me
-	//bool active; //if true, this button is active and can be pressed
-	bool notFreeButton; //TODO: comment me
-	CIntObject * ourObj; // "owner"
-	int state; //TODO: comment me
-	std::vector< CAnimation * > imgs; //images for this button
-	int curimg; //curently displayed image from imgs
-	virtual void show(SDL_Surface * to);
-	virtual void showAll(SDL_Surface * to);
-	//virtual void activate()=0;
-	//virtual void deactivate()=0;
+		NORMAL=0,
+		PRESSED=1,
+		BLOCKED=2,
+		HIGHLIGHTED=3
+	};
+private:
+	int bitmapOffset; // base offset of visible bitmap from animation
+	ButtonState state;//current state of button from enum
+
+public:
+	bool swappedImages;//fix for some buttons: normal and pressed image are swapped
+
+	void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = zwykly);
+	void update();//to refresh button after image or text change
+
+	void setOffset(int newOffset);
+	void setState(ButtonState newState);
+	ButtonState getState();
+
+	//just to make code clearer
+	void block(bool on);
+	bool isBlocked();
+	bool isHighlighted();
+
+	CAnimImage * image; //image for this button
+	CLabel * text;//text overlay
+
 	CButtonBase(); //c-tor
 	virtual ~CButtonBase(); //d-tor
 };
 
-
 class AdventureMapButton : public CButtonBase
 {
+	std::vector<std::string> imageNames;//store list of images that can be used by this button
+	size_t currentImage;
 public:
-	std::map<int,std::string> hoverTexts; //state -> text for statusbar
+	std::map<int, std::string> hoverTexts; //text for statusbar
 	std::string helpBox; //for right-click help
 	CFunctionList<void()> callback;
-	bool actOnDown, //runs when mouse is pressed down over it, not when up
-		hoverable; //if true, button will be highlighted when hovered
-	ui8 blocked;
+	bool actOnDown,//runs when mouse is pressed down over it, not when up
+	     hoverable;//if true, button will be highlighted when hovered
 
 	void clickRight(tribool down, bool previousState);
 	virtual void clickLeft(tribool down, bool previousState);
 	void hover (bool on);
-	void block(ui8 on); //if button is blocked then it'll change it's graphic to inactive (offset==2) and won't react on l-clicks
-	//void activate(); // makes button active
-	//void deactivate(); // makes button inactive (but doesn't delete)
 
 	AdventureMapButton(); //c-tor
-	AdventureMapButton( const std::map<int,std::string> &, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
 	AdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
-	AdventureMapButton( const std::pair<std::string, std::string> help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
+	AdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
 	AdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key=0);//c-tor
-	//AdventureMapButton( std::string Name, std::string HelpBox, boost::function<void()> Callback, int x, int y, std::string defName, bool activ=false,  std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
 
 	void init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key );
-	void setDef(const std::string & defName, bool playerColoredButton, bool reset=false);
+
+	void setIndex(size_t index, bool playerColoredButton=false);
+	void setImage(CAnimation* anim, bool playerColoredButton=false);
 	void setPlayerColor(int player);
 };
 
@@ -86,9 +92,9 @@ class CHighlightableButton
 {
 public:
 	CHighlightableButton(const CFunctionList<void()> &onSelect, const CFunctionList<void()> &onDeselect, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key=0);
-	CHighlightableButton(const std::pair<std::string, std::string> help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
+	CHighlightableButton(const std::pair<std::string, std::string> &help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
 	CHighlightableButton(const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
-	bool onlyOn, selected;
+	bool onlyOn;//button can not be de-selected
 	int ID; //for identification
 	CFunctionList<void()> callback2; //when de-selecting
 	void select(bool on);
@@ -107,8 +113,6 @@ public:
 	void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect=0, int key=0); //creates new button
 	CHighlightableButtonsGroup(const CFunctionList2<void(int)> &OnChange, bool musicLikeButtons = false);
 	~CHighlightableButtonsGroup();
-	void activate();
-	void deactivate();
 	void select(int id, bool mode); //mode==0: id is serial; mode==1: id is unique button id
 	void selectionChanged(int to);
 	void show(SDL_Surface * to);

+ 40 - 38
client/CAdvmapInterface.cpp

@@ -797,50 +797,52 @@ void CTerrainRect::showPath(const SDL_Rect * extRect, SDL_Surface * to)
 			{
 				if (hvx<0 && hvy<0)
 				{
-					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, NULL, to, &genRect(32, 32, x + moveX, y + moveY));
+					Rect dstRect = genRect(32, 32, x + moveX, y + moveY);
+					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, NULL, to, &dstRect);
 				}
 				else if(hvx<0)
 				{
-					CSDL_Ext::blit8bppAlphaTo24bpp
-						(arrows->ourImages[pn].bitmap,&genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w, 0, 0),
-						to, &genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w, x + moveX, y + moveY));
+					Rect srcRect = genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w, 0, 0);
+					Rect dstRect = genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w, x + moveX, y + moveY);
+					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, &srcRect, to, &dstRect);
 				}
 				else if (hvy<0)
 				{
-					CSDL_Ext::blit8bppAlphaTo24bpp
-						(arrows->ourImages[pn].bitmap,&genRect(arrows->ourImages[pn].bitmap->h, arrows->ourImages[pn].bitmap->w-hvx, 0, 0),
-						to, &genRect(arrows->ourImages[pn].bitmap->h, arrows->ourImages[pn].bitmap->w-hvx, x + moveX, y + moveY));
+					Rect srcRect = genRect(arrows->ourImages[pn].bitmap->h, arrows->ourImages[pn].bitmap->w-hvx, 0, 0);
+					Rect dstRect = genRect(arrows->ourImages[pn].bitmap->h, arrows->ourImages[pn].bitmap->w-hvx, x + moveX, y + moveY);
+					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, &srcRect, to, &dstRect);
 				}
 				else
 				{
-					CSDL_Ext::blit8bppAlphaTo24bpp
-						(arrows->ourImages[pn].bitmap, &genRect(arrows->ourImages[pn].bitmap->h-hvy,arrows->ourImages[pn].bitmap->w-hvx, 0, 0),
-						to, &genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w-hvx, x + moveX, y + moveY));
+					Rect srcRect = genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w-hvx, 0, 0);
+					Rect dstRect = genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w-hvx, x + moveX, y + moveY);
+					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, &srcRect, to, &dstRect);
 				}
 			}
 			else //standard version
 			{
 				if (hvx<0 && hvy<0)
 				{
-					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, NULL, to, &genRect(32, 32, x, y));
+					Rect dstRect = genRect(32, 32, x, y);
+					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, NULL, to, &dstRect);
 				}
 				else if(hvx<0)
 				{
-					CSDL_Ext::blit8bppAlphaTo24bpp
-						(arrows->ourImages[pn].bitmap,&genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w, 0, 0),
-						to, &genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w, x, y));
+					Rect srcRect = genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w, 0, 0);
+					Rect dstRect = genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w, x, y);
+					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, &srcRect, to, &dstRect);
 				}
 				else if (hvy<0)
 				{
-					CSDL_Ext::blit8bppAlphaTo24bpp
-						(arrows->ourImages[pn].bitmap,&genRect(arrows->ourImages[pn].bitmap->h, arrows->ourImages[pn].bitmap->w-hvx, 0, 0),
-						to, &genRect(arrows->ourImages[pn].bitmap->h, arrows->ourImages[pn].bitmap->w-hvx, x, y));
+					Rect srcRect = genRect(arrows->ourImages[pn].bitmap->h, arrows->ourImages[pn].bitmap->w-hvx, 0, 0);
+					Rect dstRect = genRect(arrows->ourImages[pn].bitmap->h, arrows->ourImages[pn].bitmap->w-hvx, x, y);
+					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, &srcRect, to, &dstRect);
 				}
 				else
 				{
-					CSDL_Ext::blit8bppAlphaTo24bpp
-						(arrows->ourImages[pn].bitmap, &genRect(arrows->ourImages[pn].bitmap->h-hvy,arrows->ourImages[pn].bitmap->w-hvx, 0, 0),
-						to, &genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w-hvx, x, y));
+					Rect srcRect = genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w-hvx, 0, 0);
+					Rect dstRect = genRect(arrows->ourImages[pn].bitmap->h-hvy, arrows->ourImages[pn].bitmap->w-hvx, x, y);
+					CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[pn].bitmap, &srcRect, to, &dstRect);
 				}
 			}
 			SDL_SetClipRect(to, &prevClip);
@@ -1219,14 +1221,14 @@ void CAdvMapInt::fswitchLevel()
 	if (position.z)
 	{
 		position.z--;
-		underground.curimg=0;
-		underground.show(screenBuf);
+		underground.setIndex(0,true);
+		underground.showAll(screenBuf);
 	}
 	else
 	{
-		underground.curimg=1;
+		underground.setIndex(1,true);
 		position.z++;
-		underground.show(screenBuf);
+		underground.showAll(screenBuf);
 	}
 	updateScreen = true;
 	minimap.draw(screenBuf);
@@ -1357,16 +1359,16 @@ void CAdvMapInt::showAll(SDL_Surface *to)
 	if(state != INGAME)
 		return;
 
-	kingOverview.show(to);
-	underground.show(to);
-	questlog.show(to);
-	sleepWake.show(to);
-	moveHero.show(to);
-	spellbook.show(to);
-	advOptions.show(to);
-	sysOptions.show(to);
-	nextHero.show(to);
-	endTurn.show(to);
+	kingOverview.showAll(to);
+	underground.showAll(to);
+	questlog.showAll(to);
+	sleepWake.showAll(to);
+	moveHero.showAll(to);
+	spellbook.showAll(to);
+	advOptions.showAll(to);
+	sysOptions.showAll(to);
+	nextHero.showAll(to);
+	endTurn.showAll(to);
 
 	minimap.draw(to);
 	heroList.draw(to);
@@ -1398,10 +1400,10 @@ void CAdvMapInt::show(SDL_Surface *to)
 
 	//if advmap needs updating AND (no dialog is shown OR ctrl is pressed)
 	if((animValHitCount % (4/LOCPLINT->sysOpts.mapScrollingSpeed)) == 0 
-		&& 
+		&&  (
 			(GH.topInt() == this)
 			|| SDL_GetKeyState(NULL)[SDLK_LCTRL] 
-			|| SDL_GetKeyState(NULL)[SDLK_RCTRL]
+			|| SDL_GetKeyState(NULL)[SDLK_RCTRL])
 	)
 	{
 		if( (scrollingDir & LEFT)   &&  (position.x>-CGI->mh->frameW) )
@@ -1452,7 +1454,7 @@ void CAdvMapInt::centerOn(int3 on)
 	adventureInt->position = on;
 	adventureInt->updateScreen=true;
 	updateMinimap=true;
-	underground.curimg = on.z; //change underground switch button image 
+	underground.setIndex(on.z,true); //change underground switch button image 
 	if(GH.topInt() == this)
 		underground.redraw();
 }
@@ -2002,7 +2004,7 @@ void CAdvMapInt::tileHovered(const int3 &tile)
 		}
 	}
 
-	if(const IShipyard *shipyard = ourInaccessibleShipyard(objAtTile))
+	if(ourInaccessibleShipyard(objAtTile))
 	{
 		CCS->curh->changeGraphic(0, 6);
 	}

+ 159 - 79
client/CAnimation.cpp

@@ -1,7 +1,7 @@
 #include <boost/bind.hpp>
 #include <boost/algorithm/string/trim.hpp>
 
-#include "SDL_image.h"
+#include <SDL_image.h>
 
 #include "../lib/CLodHandler.h"
 #include "CBitmapHandler.h"
@@ -20,6 +20,7 @@
  */
 
 extern DLL_EXPORT CLodHandler *spriteh;
+extern DLL_EXPORT CLodHandler *bitmaph;
 
 typedef std::map <size_t, std::vector <std::string> > source_map;
 typedef std::map<size_t, IImage* > image_map;
@@ -294,9 +295,13 @@ CDefFile::~CDefFile()
 	delete[] palette;
 }
 
-const std::map<size_t, std::vector <size_t> > * CDefFile::getEntries() const
+const std::map<size_t, size_t > CDefFile::getEntries() const
 {
-	return &offset;
+	std::map<size_t, size_t > ret;
+
+	for (std::map<size_t, std::vector <size_t> >::const_iterator mapIt = offset.begin(); mapIt!=offset.end(); ++mapIt)
+		ret[mapIt->first] =  mapIt->second.size();
+	return ret;
 }
 
 /*************************************************************************
@@ -571,16 +576,30 @@ SDLImage::SDLImage(SDL_Surface * from, bool extraRef):
 SDLImage::SDLImage(std::string filename, bool compressed):
 	margins(0,0)
 {
-	int size;
-	unsigned char * pic = spriteh->giveFile(filename, FILE_GRAPHICS, &size);
-	surf = IMG_Load_RW( SDL_RWFromMem((void*)pic, size), 1);
+	if (spriteh->haveFile(filename, FILE_GRAPHICS))
+	{
+		int size;
+		unsigned char * pic=NULL;
+		pic = spriteh->giveFile(filename, FILE_GRAPHICS, &size);
+		surf = IMG_Load_RW( SDL_RWFromMem((void*)pic, size), 1);
+		delete [] pic;
+	}
+	else if(bitmaph->haveFile(filename, FILE_GRAPHICS))
+		surf = BitmapHandler::loadBitmap(filename);
+	else
+	{
+		tlog0<<"Error: file not found: "<<filename<<"\n";
+		surf = NULL;
+		return;
+	}
 	fullSize.x = surf->w;
 	fullSize.y = surf->h;
-	delete [] pic;
 }
 
-void SDLImage::draw(SDL_Surface *where, int posX, int posY, Rect *src) const
-{
+void SDLImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, unsigned char rotation) const
+{
+	if (!surf)
+		return;
 	Rect sourceRect(margins.x, margins.y, surf->w, surf->h);
 	//TODO: rotation and scaling
 	if (src)
@@ -629,8 +648,10 @@ CompImage::CompImage(SDL_Surface * surf)
 	assert(0);
 }
 
-void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src) const
+void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, unsigned char rotation) const
 {
+	//rotation & 2 = horizontal rotation
+	//rotation & 4 = vertical rotation
 	if (!surf)
 		return;
 	Rect sourceRect(sprite);
@@ -642,6 +663,11 @@ void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src) const
 
 	//Starting point on SDL surface
 	Point dest(posX+sourceRect.x, posY+sourceRect.y);
+	if (rotation & 2)
+		dest.y += sourceRect.h;
+	if (rotation & 4)
+		dest.x += sourceRect.w;
+
 	sourceRect -= sprite.topLeft();
 
 	for (int currY = 0; currY <sourceRect.h; currY++)
@@ -670,14 +696,17 @@ void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src) const
 		
 		//Calculate position for blitting: pixels + Y + X
 		ui8* blitPos = (ui8*) where->pixels;
-		blitPos += (dest.y + currY) * where->pitch;
+		if (rotation & 4)
+			blitPos += (dest.y - currY) * where->pitch;
+		else
+			blitPos += (dest.y + currY) * where->pitch;
 		blitPos += dest.x * bpp;
 
-		//Blit block that must be fully visible
+		//Blit blocks that must be fully visible
 		while (currX + size < sourceRect.w)
 		{
-			//blit block, pointers will be incremented if needed
-			BlitBlockWithBpp(bpp, type, size, data, blitPos);
+			//blit block, pointers will be modified if needed
+			BlitBlockWithBpp(bpp, type, size, data, blitPos, rotation & 2);
 
 			currX += size;
 			type = *(data++);
@@ -685,30 +714,36 @@ void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src) const
 		}
 		//Blit last, semi-visible block
 		size = sourceRect.w - currX;
-		BlitBlockWithBpp(bpp, type, size, data, blitPos);
+		BlitBlockWithBpp(bpp, type, size, data, blitPos, rotation & 2);
 	}
 }
 
-void CompImage::BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
-{
-	switch (bpp)
-	{
-	case 2: BlitBlock<2>(type, size, data, dest);
-			break;
-
-	case 3: BlitBlock<3>(type, size, data, dest);
-			break;
+#define CASEBPP(x,y) case x: BlitBlock<x,y>(type, size, data, dest); break
 
-	case 4: BlitBlock<4>(type, size, data, dest);
-			break;
-	default:
-			assert(0);
-			break;
-	}
+//FIXME: better way to get blitter
+void CompImage::BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest, bool rotated) const
+{
+	assert(bpp>1 && bpp<5);
+	
+	if (rotated)
+		switch (bpp)
+		{
+			CASEBPP(2,1);
+			CASEBPP(3,1);
+			CASEBPP(4,1);
+		}
+	else
+		switch (bpp)
+		{
+			CASEBPP(2,1);
+			CASEBPP(3,1);
+			CASEBPP(4,1);
+		}
 }
+#undef CASEBPP
 
 //Blit one block from RLE-d surface
-template<int bpp>
+template<int bpp, int dir>
 void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
 {
 	//Raw data
@@ -743,15 +778,12 @@ void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
 			case 255:
 			{
 				//Put RGB row
-				//FIXME: can be optimized
-				for (int i=0; i<size; i++)
-					ColorPutter<bpp, 1>::PutColor(dest, palette[type]);
+				ColorPutter<bpp, 1>::PutColorRow(dest, palette[type], size);
 				break;
 			}
 			default:
 			{
 				//Put RGBA row
-				//FIXME: can be optimized
 				for (int i=0; i<size; i++)
 					ColorPutter<bpp, 1>::PutColorAlpha(dest, palette[type]);
 				break;
@@ -848,6 +880,27 @@ void TextParser::parseFile(std::map<size_t, std::vector <std::string> > &result)
 	}
 }
 
+IImage * CAnimation::getFromExtraDef(std::string filename)
+{
+	size_t pos = filename.find(':');
+	if (pos == -1)
+		return NULL;
+	CAnimation anim(filename.substr(0, pos));
+	pos++;
+	size_t frame = atoi(filename.c_str()+pos);
+	size_t group = 0;
+	pos = filename.find(':', pos);
+	if (pos != -1)
+	{
+		group = frame;
+		frame = atoi(filename.c_str()+pos);
+	}
+	anim.load(frame ,group);
+	IImage * ret = anim.images[group][frame];
+	anim.images.clear();
+	return ret;
+}
+
 bool CAnimation::loadFrame(CDefFile * file, size_t frame, size_t group)
 {
 	if (size(group) <= frame)
@@ -873,8 +926,10 @@ bool CAnimation::loadFrame(CDefFile * file, size_t frame, size_t group)
 	}
 	else //load from separate file
 	{
-		//TODO: compressed images
-		images[group][frame] = new SDLImage(source[group][frame].c_str());
+		IImage * img = getFromExtraDef(source[group][frame].c_str());
+		if (!img)//TODO: load compressed image
+			img = new SDLImage(source[group][frame].c_str());
+		images[group][frame] = img;
 		return true;
 	}
 	return false;
@@ -902,12 +957,12 @@ void CAnimation::init(CDefFile * file)
 {
 	TextParser txtFile(name);
 
-	if ( txtFile.getType() != 1 )
+	if ( file && txtFile.getType() != 1 )
 	{
-		const std::map<size_t, std::vector <size_t> > * defEntries = file->getEntries();
+		const std::map<size_t, size_t> defEntries = file->getEntries();
 
-		for (std::map<size_t, std::vector <size_t> >::const_iterator mapIt = defEntries->begin(); mapIt!=defEntries->end(); ++mapIt)
-			source[mapIt->first].resize(mapIt->second.size());
+		for (std::map<size_t, size_t>::const_iterator mapIt = defEntries.begin(); mapIt!=defEntries.end(); ++mapIt)
+			source[mapIt->first].resize(mapIt->second);
 	}
 	txtFile.parseFile(source);
 }
@@ -942,27 +997,26 @@ CAnimation::CAnimation():
 	name(""),
 	compressed(false)
 {
-
+	init(NULL);
 }
 
 CAnimation::~CAnimation()
 {
-	for (group_map::iterator group = images.begin(); group != images.end(); ++group )
-		for (image_map::iterator image = group->second.begin(); image != group->second.end(); ++image )
-			delete image->second;
+	if (!images.empty())
+	{
+		tlog2<<"Warning: not all frames were unloaded from "<<name<<"\n";
+		for (group_map::iterator group = images.begin(); group != images.end(); ++group )
+			for (image_map::iterator image = group->second.begin(); image != group->second.end(); ++image )
+				delete image->second;
+	}
 }
 
-void CAnimation::setCustom(IImage * newImage, size_t frame, size_t group)
+void CAnimation::setCustom(std::string filename, size_t frame, size_t group)
 {
-	assert(newImage);
-
-	IImage * oldImage = getImage(frame,group,false);
-	if (oldImage);
-	delete oldImage;
-	images[group][frame] = newImage;
-
 	if (source[group].size() <= frame)
 		source[group].resize(frame+1);
+	source[group][frame] = filename;
+	//FIXME: update image if already loaded
 }
 
 IImage * CAnimation::getImage(size_t frame, size_t group, bool verbose) const
@@ -1028,20 +1082,6 @@ void CAnimation::unload(size_t frame, size_t group)
 	unloadFrame(frame, group);
 }
 
-void CAnimation::fixButtonPos()
-{
-	group_map::iterator groupIter = images.find(0);
-	if (groupIter != images.end())
-	{
-		image_map::iterator first = groupIter->second.find(0),
-		                    second = groupIter->second.find(1);
-		if (first != second)
-		{
-			std::swap (first->second, second->second);
-		}
-	}
-}
-
 size_t CAnimation::size(size_t group) const
 {
 	source_map::const_iterator iter = source.find(group);
@@ -1050,39 +1090,79 @@ size_t CAnimation::size(size_t group) const
 	return 0;
 }
 
-CAnimImage::CAnimImage(int x, int y, std::string name, size_t Frame, size_t Group):
-	anim(name),
+CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, unsigned char Flags):
 	frame(Frame),
-	group(Group)
+	group(Group),
+	player(-1),
+	flags(Flags)
 {
-	anim.load(frame, group);
-	pos.w = anim.getImage(frame, group)->width();
-	pos.h = anim.getImage(frame, group)->height();
+	pos.x += x;
+	pos.y += y;
+	anim = new CAnimation(name);
+	init();
 }
 
-CAnimImage::~CAnimImage()
+CAnimImage::CAnimImage(CAnimation *Anim, size_t Frame, size_t Group, int x, int y, unsigned char Flags):
+	anim(Anim),
+	frame(Frame),
+	group(Group),
+	player(-1),
+	flags(Flags)
 {
+	pos.x += x;
+	pos.y += y;
+	init();
+}
 
+void CAnimImage::init()
+{
+	anim->load(frame, group);
+	if (flags & CShowableAnim::BASE)
+		anim->load(0,group);
+	
+	IImage *img = anim->getImage(frame, group);
+	pos.w = img->width();
+	pos.h = img->height();
+	
+}
+
+CAnimImage::~CAnimImage()
+{
+	anim->unload(frame, group);
+	if (flags & CShowableAnim::BASE)
+		anim->unload(0,group);
+	delete anim;
 }
 
 void CAnimImage::showAll(SDL_Surface *to)
 {
-	anim.getImage(frame, group)->draw(to);
+	anim->getImage(frame, group)->draw(to, pos.x, pos.y);
 }
 
 void CAnimImage::setFrame(size_t Frame, size_t Group)
 {
 	if (frame == Frame && group==Group)
 		return;
-	if (anim.size(Group) > Frame)
+	if (anim->size(Group) > Frame)
 	{
-		anim.unload(frame, group);
-		anim.load(Frame, Group);
+		anim->load(Frame, Group);
+		anim->unload(frame, group);
 		frame = Frame;
 		group = Group;
+		if (flags & CShowableAnim::PLAYER_COLORED)
+			anim->getImage(frame, group)->playerColored(player);
 	}
 }
 
+void CAnimImage::playerColored(int currPlayer)
+{
+	player = currPlayer;
+	flags |= CShowableAnim::PLAYER_COLORED;
+	anim->getImage(frame, group)->playerColored(player);
+	if (flags & CShowableAnim::BASE)
+			anim->getImage(0, group)->playerColored(player);
+}
+
 CShowableAnim::CShowableAnim(int x, int y, std::string name, unsigned char Flags, unsigned int Delay, size_t Group):
 	anim(name, Flags & USE_RLE),
 	group(Group),
@@ -1105,7 +1185,7 @@ CShowableAnim::CShowableAnim(int x, int y, std::string name, unsigned char Flags
 
 CShowableAnim::~CShowableAnim()
 {
-
+	anim.unloadGroup(group);
 }
 
 bool CShowableAnim::set(size_t Group, size_t from, size_t to)

+ 24 - 14
client/CAnimation.h

@@ -58,7 +58,7 @@ public:
 	template<class ImageLoader>
 	void loadFrame(size_t frame, size_t group, ImageLoader &loader) const;
 
-	const std::map<size_t, std::vector <size_t> > * getEntries() const;
+	const std::map<size_t, size_t> getEntries() const;
 };
 
 /*
@@ -70,7 +70,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) const=0;
+	virtual void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL, unsigned char rotation=0) const=0;
 
 	//decrease ref count, returns true if image can be deleted (refCount <= 0)
 	bool decreaseRef();
@@ -106,7 +106,7 @@ public:
 	SDLImage(SDL_Surface * from, bool extraRef);
 	~SDLImage();
 
-	void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL) const;
+	void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL, unsigned char rotation=0) const;
 	void playerColored(int player);
 	int width() const;
 	int height() const;
@@ -141,9 +141,9 @@ class CompImage : public IImage
 	SDL_Color *palette;
 
 	//Used internally to blit one block of data
-	template<int bpp>
+	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) const;
+	void BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest, bool rotated) const;
 
 public:
 	//Load image from def file
@@ -152,7 +152,7 @@ public:
 	CompImage(SDL_Surface * surf);
 	~CompImage();
 
-	void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL) const;
+	void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=NULL, unsigned char rotation=0) const;
 	void playerColored(int player);
 	int width() const;
 	int height() const;
@@ -193,6 +193,10 @@ private:
 	//to get rid of copy-pasting error message :]
 	void printError(size_t frame, size_t group, std::string type) const;
 
+	//not a very nice method to get image from another def file
+	//TODO: remove after implementing resource manager
+	IImage * getFromExtraDef(std::string filename);
+
 public:
 
 	CAnimation(std::string Name, bool Compressed = false);
@@ -200,8 +204,7 @@ public:
 	~CAnimation();
 
 	//add custom surface to the selected position.
-	//Known issue: IImage should not be used in another CAnimation (results in crash othervice)
-	void setCustom(IImage * newImage, size_t frame, size_t group=0);
+	void setCustom(std::string filename, size_t frame, size_t group=0);
 
 	//get pointer to image from specific group, NULL if not found
 	IImage * getImage(size_t frame, size_t group=0, bool verbose=true) const;
@@ -218,9 +221,6 @@ public:
 	void load  (size_t frame, size_t group=0);
 	void unload(size_t frame, size_t group=0);
 
-	//helper to fix frame order on some buttons
-	void fixButtonPos();
-
 	//total count of frames in group (including not loaded)
 	size_t size(size_t group=0) const;
 };
@@ -231,17 +231,26 @@ public:
 class CAnimImage: public CIntObject
 {
 private:
-	CAnimation anim;
+	CAnimation* anim;
 	//displayed frame/group
 	size_t frame;
 	size_t group;
+	int player;
+	unsigned char flags;
+
+	void init();
 
 public:
-	CAnimImage(int x, int y, std::string name, size_t Frame, size_t Group=0);//c-tor
+	CAnimImage(std::string name, size_t Frame, size_t Group=0, int x=0, int y=0, unsigned char Flags=0);
+	CAnimImage(CAnimation* anim, size_t Frame, size_t Group=0, int x=0, int y=0, unsigned char Flags=0);
 	~CAnimImage();//d-tor
 
 	//change displayed frame on this one
-	void setFrame(size_t Frame, size_t Group=0);
+	void setFrame(size_t Frame, size_t Group=0);
+
+	//makes image player-colored
+	void playerColored(int player);
+
 	void showAll(SDL_Surface *to);
 };
 
@@ -257,6 +266,7 @@ public:
 		HORIZONTAL_FLIP=2, //TODO: will be displayed rotated
 		VERTICAL_FLIP=4,   //TODO: will be displayed rotated
 		USE_RLE=8,         //RLE-d version, support full alpha-channel for 8-bit images
+		PLAYER_COLORED=16, //TODO: all loaded images will be player-colored
 	};
 protected:
 	CAnimation anim;

+ 20 - 19
client/CBattleInterface.cpp

@@ -1192,7 +1192,6 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	////blitting menu background and terrain
 // 	blitAt(background, pos.x, pos.y);
 // 	blitAt(menu, pos.x, 556 + pos.y);
-// 	CSDL_Ext::update();
 
 	//preparing buttons and console
 	bOptions = new AdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, boost::bind(&CBattleInterface::bOptionsf,this), 3 + pos.x, 561 + pos.y, "icm003.def", SDLK_o);
@@ -1208,7 +1207,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	bDefence->assignedKeys.insert(SDLK_SPACE);
 	bConsoleUp = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bConsoleUpf,this), 624 + pos.x, 561 + pos.y, "ComSlide.def", SDLK_UP);
 	bConsoleDown = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bConsoleDownf,this), 624 + pos.x, 580 + pos.y, "ComSlide.def", SDLK_DOWN);
-	bConsoleDown->bitmapOffset = 2;
+	bConsoleDown->setOffset(2);
 	console = new CBattleConsole();
 	console->pos.x = 211 + pos.x;
 	console->pos.y = 560 + pos.y;
@@ -1725,13 +1724,13 @@ void CBattleInterface::show(SDL_Surface * to)
 	}
 
 	//showing buttons
-	bOptions->show(to);
-	bSurrender->show(to);
-	bFlee->show(to);
-	bAutofight->show(to);
-	bSpell->show(to);
-	bWait->show(to);
-	bDefence->show(to);
+	bOptions->showAll(to);
+	bSurrender->showAll(to);
+	bFlee->showAll(to);
+	bAutofight->showAll(to);
+	bSpell->showAll(to);
+	bWait->showAll(to);
+	bDefence->showAll(to);
 
 	//showing window with result of battle
 	if(resWindow)
@@ -3941,7 +3940,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 	bool weAreAttacker = (owner->curInt->playerID == owner->attackingHeroInstance->tempOwner);
 	if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won
 	{
-		int text;
+		int text=-1;
 		switch(br.result)
 		{
 			case 0: text = 304; break;
@@ -4020,7 +4019,7 @@ void CBattleResultWindow::show(SDL_Surface *to)
 	CCS->videoh->update(107, 70, background, false, true);
 
 	SDL_BlitSurface(background, NULL, to, &pos);
-	exit->show(to);
+	exit->showAll(to);
 }
 
 void CBattleResultWindow::bExitf()
@@ -4061,9 +4060,11 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
 	animSpeeds->onChange = boost::bind(&CBattleInterface::setAnimSpeed, owner, _1);
 
 	setToDefault = new AdventureMapButton (CGI->generaltexth->zelp[392].first, CGI->generaltexth->zelp[392].second, boost::bind(&CBattleOptionsWindow::bDefaultf,this), 405, 443, "codefaul.def");
-	setToDefault->imgs[0]->fixButtonPos();
+	setToDefault->swappedImages = true;
+	setToDefault->update();
 	exit = new AdventureMapButton (CGI->generaltexth->zelp[393].first, CGI->generaltexth->zelp[393].second, boost::bind(&CBattleOptionsWindow::bExitf,this), 516, 443, "soretrn.def",SDLK_RETURN);
-	exit->imgs[0]->fixButtonPos();
+	exit->swappedImages = true;
+	exit->update();
 
 	//printing texts to background
 	CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[392], 242, 32, FONT_BIG, tytulowy, background); //window title
@@ -4132,12 +4133,12 @@ void CBattleOptionsWindow::show(SDL_Surface *to)
 
 	SDL_BlitSurface(background, NULL, to, &pos);
 
-	setToDefault->show(to);
-	exit->show(to);
-	viewGrid->show(to);
-	movementShadow->show(to);
-	animSpeeds->show(to);
-	mouseShadow->show(to);
+	setToDefault->showAll(to);
+	exit->showAll(to);
+	viewGrid->showAll(to);
+	movementShadow->showAll(to);
+	animSpeeds->showAll(to);
+	mouseShadow->showAll(to);
 }
 
 void CBattleOptionsWindow::bDefaultf()

+ 10 - 8
client/CCastleInterface.cpp

@@ -157,9 +157,10 @@ void CBuildingRect::show(SDL_Surface *to)
 
 void CBuildingRect::showAll(SDL_Surface *to)
 {
+	if (active)
+		return;
 	CShowableAnim::showAll(to);
-
-	if(LOCPLINT->castleInt->hBuild == this && border && !active)
+	if(LOCPLINT->castleInt->hBuild == this && border)
 		blitAtLoc(border,0,0,to);
 }
 
@@ -405,7 +406,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
 	amin(townlist->from, LOCPLINT->towns.size() - townlist->SIZE);
 
 	graphics->blueToPlayersAdv(townInt,LOCPLINT->playerID);
-	exit->bitmapOffset = 4;
+	exit->setOffset(4);
 	//growth icons and buildings
 	recreateBuildings();
 	recreateIcons();
@@ -1483,7 +1484,7 @@ void CHallInterface::showAll(SDL_Surface * to)
 	LOCPLINT->castleInt->statusbar->show(to);
 	printAtMiddle(CGI->buildh->buildings[LOCPLINT->castleInt->town->subID][bid]->Name(),399+pos.x,12+pos.y,FONT_MEDIUM,zwykly,to);
 	resdatabar->show(to);
-	exit->show(to);
+	exit->showAll(to);
 	for(int i=0; i<5; i++)
 	{
 		for(size_t j=0;j<boxes[i].size(); ++j)
@@ -1558,8 +1559,8 @@ void CHallInterface::CBuildWindow::show(SDL_Surface * to)
 	SDL_BlitSurface(bitmap,&poms,to,&pom);
 	if(!mode)
 	{
-		buy->show(to);
-		cancel->show(to);
+		buy->showAll(to);
+		cancel->showAll(to);
 	}
 }
 
@@ -1648,7 +1649,7 @@ CHallInterface::CBuildWindow::CBuildWindow(int Tid, int Bid, int State, bool Mod
 		cancel = new AdventureMapButton
 			("","",boost::bind(&CBuildWindow::close,this),pos.x+290,pos.y+445,"ICANCEL.DEF",SDLK_ESCAPE);
 		if(state!=7)
-			buy->state=2;
+			buy->setState(CButtonBase::BLOCKED);
 	}
 }
 
@@ -1688,7 +1689,7 @@ void CFortScreen::showAll( SDL_Surface * to)
 	{
 		crePics[i]->showAll(to);
 	}
-	exit->show(to);
+	exit->showAll(to);
 	resdatabar->show(to);
 	GH.statusbar->show(to);
 	
@@ -1900,6 +1901,7 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner)
 		spells[i]->pos.x += pos.x;
 		spells[i]->pos.y += pos.y;
 	}
+	scrolls.unload();
 }
 
 CMageGuildScreen::~CMageGuildScreen()

+ 3 - 6
client/CHeroWindow.cpp

@@ -88,11 +88,8 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero)
 	questlogButton = new AdventureMapButton(CGI->generaltexth->heroscrn[0], std::string(), boost::bind(&CHeroWindow::questlog,this), 314, 429, "hsbtns4.def", SDLK_q);
 
 	formations = new CHighlightableButtonsGroup(0);
-	{
-		BLOCK_CAPTURING;
-		formations->addButton(map_list_of(0,CGI->generaltexth->heroscrn[23]),CGI->generaltexth->heroscrn[29], "hsbtns6.def", pos.x+481, pos.y+483, 0, 0, SDLK_t);
-		formations->addButton(map_list_of(0,CGI->generaltexth->heroscrn[24]),CGI->generaltexth->heroscrn[30], "hsbtns7.def", pos.x+481, pos.y+519, 1, 0, SDLK_l);
-	}
+	formations->addButton(map_list_of(0,CGI->generaltexth->heroscrn[23]),CGI->generaltexth->heroscrn[29], "hsbtns6.def", 481, 483, 0, 0, SDLK_t);
+	formations->addButton(map_list_of(0,CGI->generaltexth->heroscrn[24]),CGI->generaltexth->heroscrn[30], "hsbtns7.def", 481, 519, 1, 0, SDLK_l);
 
 	tacticsButton = new CHighlightableButton(0, 0, map_list_of(0,CGI->generaltexth->heroscrn[26])(3,CGI->generaltexth->heroscrn[25]), CGI->generaltexth->heroscrn[31], false, "hsbtns8.def", NULL, 539, 483, SDLK_b);
 
@@ -233,7 +230,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
 				if(cew->heroInst[g] == hero)
 					noDismiss = true;
 
-		if (CKingdomInterface * cki = dynamic_cast<CKingdomInterface*>(isa))
+		if (dynamic_cast<CKingdomInterface*>(isa))
 			noDismiss = true;
 	}
 	dismissButton->block(!!hero->visitedTown || noDismiss);

+ 4 - 4
client/CKingdomInterface.cpp

@@ -77,7 +77,7 @@ CKingdomInterface::CKingdomInterface()
 
 	exit = new AdventureMapButton (CGI->generaltexth->allTexts[600],"",
 		boost::bind(&CKingdomInterface::close,this),748,99+size*116,"OVBUTN1.DEF", SDLK_RETURN);
-	exit->bitmapOffset = 3;
+	exit->setOffset(3);
 
 	statusbar = new CStatusBar(7, 91+size*116,"TSTATBAR.bmp",732);
 	resdatabar = new CResDataBar("KRESBAR.bmp",pos.x+3,pos.y+111+size*116,32,2,76,76);
@@ -97,15 +97,15 @@ CKingdomInterface::CKingdomInterface()
 
 	ObjUp = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,1),
 		733,24,"OVBUTN4.DEF");
-	ObjUp->bitmapOffset = 4;
+	ObjUp->setOffset(4);
 
 	ObjDown = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,2),
 		733,size*116-18,"OVBUTN4.DEF");
-	ObjDown->bitmapOffset = 6;
+	ObjDown->setOffset(6);
 
 	ObjBottom = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,3),
 		733,size*116+2,"OVBUTN4.DEF");
-	ObjBottom->bitmapOffset = 2;
+	ObjBottom->setOffset(2);
 
 	for (size_t i=0; i<8; i++)
 	{

+ 4 - 5
client/CMessage.cpp

@@ -419,7 +419,7 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player)
 		// Compute total width of buttons
 		bw = 20*(ret->buttons.size()-1); // space between all buttons
 		for(size_t i=0; i<ret->buttons.size(); i++) //and add buttons width
-			bw+=ret->buttons[i]->imgs[0]->getImage(0)->width(); 
+			bw+=ret->buttons[i]->pos.w;
 		winSize.second += 20 + //before button
 		ok->ourImages[0].bitmap->h; //button	
 	}
@@ -456,13 +456,12 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player)
 	{
 		// Position the buttons at the bottom of the window
 		bw = (ret->bitmap->w/2) - (bw/2);
-		curh = ret->bitmap->h - SIDE_MARGIN - ret->buttons[0]->imgs[0]->getImage(0)->height();
+		curh = ret->bitmap->h - SIDE_MARGIN - ret->buttons[0]->pos.h;
 
 		for(size_t i=0; i<ret->buttons.size(); i++)
 		{
-			ret->buttons[i]->pos.x = bw + ret->pos.x;
-			ret->buttons[i]->pos.y = curh + ret->pos.y;
-			bw += ret->buttons[i]->imgs[0]->getImage(0)->width() + 20;
+			ret->buttons[i]->moveBy(Point(bw, curh));
+			bw += ret->buttons[i]->pos.w + 20;
 		}
 	}
 	for(size_t i=0; i<ret->components.size(); i++)

+ 26 - 40
client/CPreGame.cpp

@@ -1426,12 +1426,10 @@ InfoCard::InfoCard( bool Network )
 		difficulty = new CHighlightableButtonsGroup(0);
 		{
 			static const char *difButns[] = {"GSPBUT3.DEF", "GSPBUT4.DEF", "GSPBUT5.DEF", "GSPBUT6.DEF", "GSPBUT7.DEF"};
-			BLOCK_CAPTURING;
 
 			for(int i = 0; i < 5; i++)
 			{
 				difficulty->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[24+i].second, 0, 110 + i*32, 450, difButns[i], i));
-				difficulty->buttons.back()->pos += pos.topLeft();
 			}
 		}
 
@@ -2260,7 +2258,7 @@ void OptionsTab::SelectedBox::clickRight( tribool down, bool previousState )
 
 	subTitle = getText();
 
-	int val;
+	int val=-1;
 	switch(which)
 	{
 	case TOWN: 
@@ -2698,8 +2696,8 @@ void CBonusSelection::goBack()
 
 void CBonusSelection::showAll( SDL_Surface * to )
 {
-	CIntObject::showAll(to);
 	blitAt(background, pos.x, pos.y, to);
+	CIntObject::showAll(to);
 
 	show(to);
 }
@@ -2764,7 +2762,7 @@ void CBonusSelection::selectMap( int whichOne )
 
 void CBonusSelection::show( SDL_Surface * to )
 {
-	blitAt(background, pos.x, pos.y, to);
+	//blitAt(background, pos.x, pos.y, to);
 
 	//map name
 	std::string mapName = ourHeader->name;
@@ -2835,30 +2833,26 @@ void CBonusSelection::updateBonusSelection()
 	const CCampaignScenario &scenario = ourCampaign->camp->scenarios[sInfo.whichMapInCampaign];
 	const std::vector<CScenarioTravel::STravelBonus> & bonDescs = scenario.travelOptions.bonusesToChoose;
 
-	CDefEssential * twcp = CDefHandler::giveDefEss("TWCRPORT.DEF"); //for yellow border
-
 	bonuses->buttons.clear();
 	{
 		BLOCK_CAPTURING;
-		static const char *bonDefs[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "GSPBUT5.DEF", "ARTIFBON.DEF", "SPELLBON.DEF",
-			"PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "GSPBUT5.DEF", "GSPBUT5.DEF"};
+		static const char *bonusPics[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "", "ARTIFBON.DEF", "SPELLBON.DEF",
+			"PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "CREST58.DEF", "HPL000KN"};
 
 		for(int i = 0; i < bonDescs.size(); i++)
 		{
-			CDefEssential * de = CDefHandler::giveDefEss(bonDefs[bonDescs[i].type]);
-			SDL_Surface * surfToDuplicate = NULL;
-			bool createNewRef = true;
+			std::string picName=bonusPics[bonDescs[i].type];
+			size_t picNumber=bonDescs[i].info2;
 
 			std::string desc;
 			switch(bonDescs[i].type)
 			{
 			case 0: //spell
-				surfToDuplicate = de->ourImages[bonDescs[i].info2].bitmap;
 				desc = CGI->generaltexth->allTexts[715];
 				boost::algorithm::replace_first(desc, "%s", CGI->spellh->spells[bonDescs[i].info2]->name);
 				break;
 			case 1: //monster
-				surfToDuplicate = de->ourImages[bonDescs[i].info2 + 2].bitmap;
+				picNumber = bonDescs[i].info2 + 2;
 				desc = CGI->generaltexth->allTexts[717];
 				boost::algorithm::replace_first(desc, "%d", boost::lexical_cast<std::string>(bonDescs[i].info3));
 				boost::algorithm::replace_first(desc, "%s", CGI->creh->creatures[bonDescs[i].info2]->namePl);
@@ -2878,19 +2872,15 @@ void CBonusSelection::updateBonusSelection()
 					}
 					assert(faction != -1);
 
-					std::string bldgBitmapName = graphics->ERMUtoPicture[faction][CBuildingHandler::campToERMU(bonDescs[i].info1, faction, std::set<si32>())];
-					surfToDuplicate = BitmapHandler::loadBitmap(bldgBitmapName);
-
-					createNewRef = false;
+					picName = graphics->ERMUtoPicture[faction][CBuildingHandler::campToERMU(bonDescs[i].info1, faction, std::set<si32>())];
+					picNumber = -1;
 				}
 				break;
 			case 3: //artifact
-				surfToDuplicate = de->ourImages[bonDescs[i].info2].bitmap;
 				desc = CGI->generaltexth->allTexts[715];
 				boost::algorithm::replace_first(desc, "%s", CGI->arth->artifacts[bonDescs[i].info2]->Name());
 				break;
 			case 4: //spell scroll
-				surfToDuplicate = de->ourImages[bonDescs[i].info2].bitmap;
 				desc = CGI->generaltexth->allTexts[716];
 				boost::algorithm::replace_first(desc, "%s", CGI->spellh->spells[bonDescs[i].info2]->name);
 				break;
@@ -2910,7 +2900,7 @@ void CBonusSelection::updateBonusSelection()
 							toPrint.push_back(std::make_pair(g, ptr[g]));
 						}
 					}
-					surfToDuplicate = de->ourImages[leadingSkill].bitmap;
+					picNumber = leadingSkill;
 					desc = CGI->generaltexth->allTexts[715];
 
 					std::string substitute; //text to be printed instead of %s
@@ -2928,7 +2918,6 @@ void CBonusSelection::updateBonusSelection()
 					break;
 				}
 			case 6: //secondary skill
-				surfToDuplicate = de->ourImages[bonDescs[i].info2].bitmap;
 				desc = CGI->generaltexth->allTexts[718];
 
 				boost::algorithm::replace_first(desc, "%s", CGI->generaltexth->levels[bonDescs[i].info3]); //skill level
@@ -2950,7 +2939,7 @@ void CBonusSelection::updateBonusSelection()
 						serialResID = 8;
 						break;
 					}
-					surfToDuplicate = de->ourImages[serialResID].bitmap;
+					picNumber = serialResID;
 
 					desc = CGI->generaltexth->allTexts[717];
 					boost::algorithm::replace_first(desc, "%d", boost::lexical_cast<std::string>(bonDescs[i].info2));
@@ -2967,7 +2956,7 @@ void CBonusSelection::updateBonusSelection()
 				}
 				break;
 			case 8: //player aka hero crossover
-				surfToDuplicate = graphics->flags->ourImages[bonDescs[i].info1].bitmap;
+				picNumber = bonDescs[i].info1;
 				desc = CGI->generaltexth->allTexts[718];
 
 				boost::algorithm::replace_first(desc, "%s", CGI->generaltexth->capColors[bonDescs[i].info1]); //player color
@@ -2982,40 +2971,37 @@ void CBonusSelection::updateBonusSelection()
 				if (bonDescs[i].info2 == 0xFFFF)
 				{
 					boost::algorithm::replace_first(desc, "%s", CGI->heroh->heroes[0]->name); //hero's name
-					surfToDuplicate = graphics->portraitLarge[0];
+					//surfToDuplicate = graphics->portraitLarge[0];
+					//TODO: re-enable - need to get filename or CAnimation with heroes pics
 				}
 				else
 				{
 
 					boost::algorithm::replace_first(desc, "%s", CGI->heroh->heroes[bonDescs[i].info2]->name); //hero's name
-					surfToDuplicate = graphics->portraitLarge[bonDescs[i].info2];
+					//surfToDuplicate = graphics->portraitLarge[bonDescs[i].info2];
 				}
+				picNumber = -1;
 				break;
 			}
 
-			bonuses->addButton(new CHighlightableButton(desc, desc, 0, 475 + i*68, 455, bonDefs[bonDescs[i].type], i));
-
+			bonuses->addButton(new CHighlightableButton(desc, desc, 0, 475 + i*68, 455, "", i));
 			//create separate surface with yellow border
-			SDL_Surface * selected = SDL_ConvertSurface(surfToDuplicate, surfToDuplicate->format, surfToDuplicate->flags);
-			blitAt(twcp->ourImages[1].bitmap, 0, 0, selected);
 
-			//replace images on button with new ones
-			delete bonuses->buttons.back()->imgs[0];
-			bonuses->buttons.back()->imgs[0] = new CAnimation();
-			bonuses->buttons.back()->imgs[0]->setCustom(new SDLImage(surfToDuplicate, createNewRef), 0);
-			bonuses->buttons.back()->imgs[0]->setCustom(new SDLImage(selected, false), 1);
+			if (picNumber != -1)
+				picName += ":" + boost::lexical_cast<std::string>(picNumber);
+
+			CAnimation * anim = new CAnimation();
+			anim->setCustom(picName, 0);
+			anim->setCustom("TWCRPORT:1", 1);
+			bonuses->buttons.back()->setImage(anim);
+			//FIXME: use show base
 
-			//cleaning
-			delete de;
 		}
 	}
 	if (bonuses->buttons.size() > 0)
 	{
 		bonuses->select(0, 0);
 	}
-
-	delete twcp;
-
 }
 
 void CBonusSelection::startMap()

+ 70 - 81
client/GUIClasses.cpp

@@ -473,9 +473,9 @@ CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset,
 void CGarrisonInt::activate()
 {
 	for(size_t i = 0; i<splitButtons.size(); i++)
-		if(splitButtons[i]->blocked != !highlighted)
+		if( (splitButtons[i]->isBlocked()) != !highlighted)
 			splitButtons[i]->block(!highlighted);
-
+
 	CIntObject::activate();
 }
 
@@ -517,13 +517,15 @@ CInfoWindow::CInfoWindow()
 	ID = -1;
 	setDelComps(false);
 	text = NULL;
-}
+}
+
 void CInfoWindow::close()
 {
 	GH.popIntTotally(this);
 	if(LOCPLINT)
 		LOCPLINT->showingDialog->setn(false);
 }
+
 void CInfoWindow::show(SDL_Surface * to)
 {
 	CIntObject::show(to);
@@ -1059,8 +1061,9 @@ void CStatusBar::print(const std::string & text)
 
 void CStatusBar::show(SDL_Surface * to)
 {
-	SDL_Rect pom = genRect(pos.h,pos.w,pos.x,pos.y);
-	CSDL_Ext::blitSurface(bg,&genRect(pos.h,pos.w,0,0),to,&pom);
+	SDL_Rect srcRect = genRect(pos.h,pos.w,0,0);
+	SDL_Rect dstRect = genRect(pos.h,pos.w,pos.x,pos.y);
+	CSDL_Ext::blitSurface(bg,&srcRect,to,&dstRect);
 	printAtMiddle(current,middlex,middley,FONT_SMALL,zwykly,to);
 }
 
@@ -1142,7 +1145,9 @@ void CHeroList::init()
 {
 	int w = pos.w+1, h = pos.h+4;
 	bg = CSDL_Ext::newSurface(w,h,screen);
-	CSDL_Ext::blitSurface(adventureInt->bg,&genRect(w,h,pos.x,pos.y),bg,&genRect(w,h,0,0));
+	Rect srcRect = genRect(w, h, pos.x, pos.y);
+	Rect dstRect = genRect(w, h, 0, 0);
+	CSDL_Ext::blitSurface(adventureInt->bg, &srcRect, bg, &dstRect);
 }
 
 void CHeroList::genList()
@@ -1738,7 +1743,8 @@ void CRecruitmentWindow::clickRight(tribool down, bool previousState)
 		for(int i=0;i<creatures.size();i++)
 		{
 			const int sCREATURE_WIDTH = CREATURE_WIDTH; // gcc -O0 workaround
-			if(isItIn(&genRect(132,sCREATURE_WIDTH,pos.x+curx,pos.y+64),GH.current->motion.x,GH.current->motion.y))
+			Rect creatureRect = genRect(132, sCREATURE_WIDTH, pos.x+curx, pos.y+64);
+			if(isItIn(&creatureRect, GH.current->motion.x, GH.current->motion.y))
 			{
 				CCreInfoWindow *popup = new CCreInfoWindow(creatures[i].ID, 0, 0);
 				GH.pushInt(popup);
@@ -1953,9 +1959,9 @@ void CSplitWindow::sliderMoved(int to)
 void CSplitWindow::show(SDL_Surface * to)
 {
 	blitAt(bitmap,pos.x,pos.y,to);
-	ok->show(to);
-	cancel->show(to);
-	slider->show(to);
+	ok->showAll(to);
+	cancel->showAll(to);
+	slider->showAll(to);
 	printAtMiddle(boost::lexical_cast<std::string>(a1) + (!which ? "_" : ""),pos.x+70,pos.y+237,FONT_BIG,zwykly,to);
 	printAtMiddle(boost::lexical_cast<std::string>(a2) + (which ? "_" : ""),pos.x+233,pos.y+237,FONT_BIG,zwykly,to);
 	animLeft->show(to);
@@ -2029,11 +2035,11 @@ void CCreInfoWindow::show(SDL_Surface * to)
 	if(count.size())
 		printTo(count.c_str(),pos.x+114,pos.y+174,FONT_TIMES,zwykly,to);
 	if(upgrade)
-		upgrade->show(to);
+		upgrade->showAll(to);
 	if(dismiss)
-		dismiss->show(to);
+		dismiss->showAll(to);
 	if(ok)
-		ok->show(to);
+		ok->showAll(to);
 }
 
 CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui)
@@ -2069,7 +2075,7 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::functi
 			{
 				upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,boost::function<void()>(),76,237,"IVIEWCR.DEF");
 				upgrade->callback.funcs.clear();
-				upgrade->bitmapOffset = 2;
+				upgrade->setOffset(2);
 			}
 
 		}
@@ -2309,7 +2315,7 @@ CLevelWindow::CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<u
 }
 void CLevelWindow::selectionChanged(unsigned to)
 {
-	if(ok->blocked)
+	if(ok->isBlocked())
 		ok->block(false);
 	for(int i=0;i<comps.size();i++)
 		if(i==to)
@@ -2340,7 +2346,7 @@ void CLevelWindow::show(SDL_Surface * to)
 {
 	blitAt(bitmap,pos.x,pos.y,to);
 	blitAt(graphics->portraitLarge[heroPortrait],170+pos.x,66+pos.y,to);
-	ok->show(to);
+	ok->showAll(to);
 	for(int i=0;i<comps.size();i++)
 		comps[i]->show(to);
 }
@@ -3165,7 +3171,7 @@ void CMarketplaceWindow::makeDeal()
 	if(slider)
 		sliderValue = slider->value;
 	else	
-		sliderValue = !deal->blocked; //should always be 1
+		sliderValue = !deal->isBlocked(); //should always be 1
 
 	if(!sliderValue)
 		return;
@@ -3284,7 +3290,7 @@ std::string CMarketplaceWindow::selectionSubtitle(bool Left) const
 		assert(itemsType[1] == CREATURE || itemsType[1] == RESOURCE);
 		int val = slider 
 			? slider->value * r1 
-			: ((deal->blocked) ? 0 : r1);
+			: (((deal->isBlocked())) ? 0 : r1);
 
 		return boost::lexical_cast<std::string>(val);
 	}
@@ -3295,7 +3301,7 @@ std::string CMarketplaceWindow::selectionSubtitle(bool Left) const
 		case RESOURCE:
 			return boost::lexical_cast<std::string>( slider->value * r2 );
 		case ARTIFACT_TYPE:
-			return (deal->blocked ? "0" : "1");
+			return ((deal->isBlocked()) ? "0" : "1");
 		case PLAYER:
 			return (hRight ? CGI->generaltexth->capColors[hRight->id] : "");
 		}
@@ -3872,19 +3878,22 @@ CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface
 	// std::swap(save->imgs[0][0], load->imgs[0][1]);
 
 	save = new AdventureMapButton (CGI->generaltexth->zelp[322].first, CGI->generaltexth->zelp[322].second, boost::bind(&CSystemOptionsWindow::bsavef, this), pos.x+357, pos.y+298, "SOSAVE.DEF", SDLK_s);
-	save->imgs[0]->fixButtonPos();
+	save->swappedImages = true;
+	save->update();
 
 	// restart = new AdventureMapButton (CGI->generaltexth->zelp[323].first, CGI->generaltexth->zelp[323].second, boost::bind(&CSystemOptionsWindow::bmainmenuf, this), pos.x+346, pos.y+357, "SORSTRT", SDLK_r);
 	// std::swap(save->imgs[0][0], restart->imgs[0][1]);
 
 	mainMenu = new AdventureMapButton (CGI->generaltexth->zelp[320].first, CGI->generaltexth->zelp[320].second, boost::bind(&CSystemOptionsWindow::bmainmenuf, this), pos.x+357, pos.y+357, "SOMAIN.DEF", SDLK_m);
-	mainMenu->imgs[0]->fixButtonPos();
+	mainMenu->swappedImages = true;
+	mainMenu->update();
 
 	quitGame = new AdventureMapButton (CGI->generaltexth->zelp[324].first, CGI->generaltexth->zelp[324].second, boost::bind(&CSystemOptionsWindow::bquitf, this), pos.x+246, pos.y+415, "soquit.def", SDLK_q);
-	quitGame->imgs[0]->fixButtonPos();
-
+	quitGame->swappedImages = true;
+	quitGame->update();
 	backToMap = new AdventureMapButton (CGI->generaltexth->zelp[325].first, CGI->generaltexth->zelp[325].second, boost::bind(&CSystemOptionsWindow::breturnf, this), pos.x+357, pos.y+415, "soretrn.def", SDLK_RETURN);
-	backToMap->imgs[0]->fixButtonPos();
+	backToMap->swappedImages = true;
+	backToMap->update();
 	backToMap->assignedKeys.insert(SDLK_ESCAPE);
 
 	heroMoveSpeed = new CHighlightableButtonsGroup(0);
@@ -3999,14 +4008,14 @@ void CSystemOptionsWindow::show(SDL_Surface *to)
 {
 	CSDL_Ext::blitSurface(background, NULL, to, &pos);
 
-	save->show(to);
-	quitGame->show(to);
-	backToMap->show(to);
-	mainMenu->show(to);
-	heroMoveSpeed->show(to);
-	mapScrollSpeed->show(to);
-	musicVolume->show(to);
-	effectsVolume->show(to);
+	save->showAll(to);
+	quitGame->showAll(to);
+	backToMap->showAll(to);
+	mainMenu->showAll(to);
+	heroMoveSpeed->showAll(to);
+	mapScrollSpeed->showAll(to);
+	musicVolume->showAll(to);
+	effectsVolume->showAll(to);
 }
 
 CTavernWindow::CTavernWindow(const CGObjectInstance *TavernObj)
@@ -4101,7 +4110,7 @@ void CTavernWindow::show(SDL_Surface * to)
 	{
 		HeroPortrait *sel = selected ? h2 : h1;
 
-		if (selected != oldSelected  &&  !recruit->blocked) 
+		if (selected != oldSelected  &&  !recruit->isBlocked()) 
 		{
 			// Selected hero just changed. Update RECRUIT button hover text if recruitment is allowed.
 			oldSelected = selected;
@@ -4478,7 +4487,7 @@ void CRClickPopupInt::showAll(SDL_Surface * to)
 }
 
 CArtPlace::CArtPlace(const CArtifactInstance* Art)
-	: marked(false), ourArt(Art), picked(false), locked(false)
+	:picked(false), marked(false), locked(false), ourArt(Art)
 {
 }
 
@@ -5209,7 +5218,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
 			if(aoh->curHero == dst.hero)
 			{
 				commonInfo->src.AOH = aoh;
-				if(ap = aoh->getArtPlace(dst.slot))
+				if((ap = aoh->getArtPlace(dst.slot)))
 					break;
 			}
 		}
@@ -5383,7 +5392,7 @@ void CExchangeWindow::show(SDL_Surface * to)
 {
 	blitAt(bg, pos, to);
 
-	quit->show(to);
+	quit->showAll(to);
 
 	//printing border around window
 	if(screen->w != 800 || screen->h !=600)
@@ -5396,7 +5405,7 @@ void CExchangeWindow::show(SDL_Surface * to)
 
 	for(int g=0; g<ARRAY_COUNT(secSkillAreas); g++)
 	{
-		questlogButton[g]->show(to);
+		questlogButton[g]->show(to);//FIXME: for array count(secondary skill) show quest log button? WTF?
 	}
 
 	garr->show(to);
@@ -5648,9 +5657,10 @@ void CShipyardWindow::deactivate()
 void CShipyardWindow::show( SDL_Surface * to )
 {
 	blitAt(bg,pos,to);
-	CSDL_Ext::blit8bppAlphaTo24bpp(graphics->boatAnims[boat]->ourImages[21 + frame++/8%8].bitmap, NULL, to, &genRect(64, 96, pos.x+110, pos.y+85));
-	build->show(to);
-	quit->show(to);
+	//FIXME: change to blit by CAnimation
+	//CSDL_Ext::blit8bppAlphaTo24bpp(graphics->boatAnims[boat]->ourImages[21 + frame++/8%8].bitmap, NULL, to, &genRect(64, 96, pos.x+110, pos.y+85));
+	build->showAll(to);
+	quit->showAll(to);
 }
 
 CShipyardWindow::~CShipyardWindow()
@@ -5727,10 +5737,11 @@ CPuzzleWindow::CPuzzleWindow(const int3 &grailPos, float discoveredRatio)
 
 	//printing necessary things to background
 	int3 moveInt = int3(8, 9, 0);
+	Rect mapRect = genRect(544, 591, 8, 8);
 	CGI->mh->terrainRect
 		(grailPos - moveInt, adventureInt->anim,
 		 &LOCPLINT->cb->getVisibilityMap(), true, adventureInt->heroAnim,
-		 background, &genRect(544, 591, 8, 8), 0, 0, true);
+		 background, &mapRect, 0, 0, true);
 
 	//printing X sign
 	{
@@ -5741,7 +5752,8 @@ CPuzzleWindow::CPuzzleWindow(const int3 &grailPos, float discoveredRatio)
 		}
 		else
 		{
-			CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[0].bitmap, NULL, background, &genRect(32, 32, x, y));
+			Rect dstRect = genRect(32, 32, x, y);
+			CSDL_Ext::blit8bppAlphaTo24bpp(arrows->ourImages[0].bitmap, NULL, background, &dstRect);
 		}
 	}
 
@@ -5797,7 +5809,7 @@ void CPuzzleWindow::deactivate()
 void CPuzzleWindow::show(SDL_Surface * to)
 {
 	blitAt(background, pos.x, pos.y, to);
-	quitb->show(to);
+	quitb->showAll(to);
 	resdatabar->draw(to);
 
 	//blitting disappearing puzzles
@@ -6106,14 +6118,20 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance *visitor, const CGObjectIn
 	currState.resize(slotsCount+1);
 	costs.resize(slotsCount);
 	totalSumm.resize(RESOURCE_QUANTITY);
+	std::vector<std::string> files;
+	files += "APHLF1R.DEF", "APHLF1Y.DEF", "APHLF1G.DEF";
 	for (int i=0; i<slotsCount; i++)
 	{
 		currState[i] = getState(i);
-		upgrade[i] = new AdventureMapButton(getTextForSlot(i),"",boost::bind(&CHillFortWindow::makeDeal, this, i), 107+i*76, 171, getDefForSlot(i));
+		upgrade[i] = new AdventureMapButton(getTextForSlot(i),"",boost::bind(&CHillFortWindow::makeDeal, this, i),
+		                                    107+i*76, 171, "", SDLK_1+i, &files);
 		upgrade[i]->block(currState[i] == -1);
 	}
+	files.clear();
+	files += "APHLF4R.DEF", "APHLF4Y.DEF", "APHLF4G.DEF";
 	currState[slotsCount] = getState(slotsCount);
-	upgradeAll = new AdventureMapButton(CGI->generaltexth->allTexts[432],"",boost::bind(&CHillFortWindow::makeDeal, this, slotsCount), 30, 231, getDefForSlot(slotsCount));
+	upgradeAll = new AdventureMapButton(CGI->generaltexth->allTexts[432],"",boost::bind(&CHillFortWindow::makeDeal, this, slotsCount),
+	                                    30, 231, "", SDLK_0, &files);
 	quit = new AdventureMapButton("","",boost::bind(&CGuiHandler::popIntTotally, &GH, this), 294, 275, "IOKAY.DEF", SDLK_RETURN);
 	bar = new CGStatusBar(327, 332);
 
@@ -6154,21 +6172,15 @@ void CHillFortWindow::updateGarrisons()
 				}
 		}
 		
-		if (currState[i] != newState )//we need to update buttons
-		{
-			currState[i] = newState;
-			upgrade[i]->setDef(getDefForSlot(i), false, true);
-			upgrade[i]->block(currState[i] == -1);
-			upgrade[i]->hoverTexts[0] = getTextForSlot(i);
-		}
+		currState[i] = newState;
+		upgrade[i]->setIndex(newState);
+		upgrade[i]->block(currState[i] == -1);
+		upgrade[i]->hoverTexts[0] = getTextForSlot(i);
 	}
 	
 	int newState = getState(slotsCount);
-	if (currState[slotsCount] != newState )
-	{
-		currState[slotsCount] = newState;
-		upgradeAll->setDef(getDefForSlot(slotsCount), false, true);
-	}
+	currState[slotsCount] = newState;
+	upgradeAll->setIndex(newState);
 	garr->recreateSlots();
 }
 
@@ -6200,7 +6212,6 @@ void CHillFortWindow::makeDeal(int slot)
 void CHillFortWindow::showAll (SDL_Surface *to)
 {
 	CIntObject::showAll(to);
-	garr->show(to);
 	
 	for ( int i=0; i<slotsCount; i++)
 	{
@@ -6233,28 +6244,6 @@ void CHillFortWindow::showAll (SDL_Surface *to)
 	}
 }
 
-std::string CHillFortWindow::getDefForSlot(int slot)
-{
-	if ( slot == slotsCount)
-		switch (currState[slot])
-		{
-			case -1:
-			case  0: return "APHLF4R.DEF";
-			case  1: return "APHLF4Y.DEF";
-			case  2: return "APHLF4G.DEF";
-		}
-	else
-		switch (currState[slot])
-		{
-			case -1:
-			case  0: return "APHLF1R.DEF";
-			case  1: return "APHLF1Y.DEF";
-			case  2: return "APHLF1G.DEF";
-		}
-	assert(0);
-	return "";
-}
-
 std::string CHillFortWindow::getTextForSlot(int slot)
 {
 	if ( !hero->getCreature(slot) )//we dont have creature here
@@ -6312,7 +6301,7 @@ void CThievesGuildWindow::show(SDL_Surface * to)
 	blitAt(background, pos.x, pos.y, to);
 
 	statusBar->show(to);
-	exitb->show(to);
+	exitb->showAll(to);
 	resdatabar->show(to);
 
 	//showing border around window

+ 49 - 8
client/SDL_Extensions.cpp

@@ -100,6 +100,21 @@ STRONG_INLINE void ColorPutter<bpp, incrementPtr>::PutColor(Uint8 *&ptr, const U
 	}
 }
 
+template<int bpp, int incrementPtr>
+STRONG_INLINE void ColorPutter<bpp, incrementPtr>::PutColorRow(Uint8 *&ptr, const SDL_Color & Color, size_t count)
+{
+	Uint32 pixel = ((Uint32)Color.b << 0 ) + ((Uint32)Color.g << 8) + ((Uint32)Color.r << 16);
+	
+	for (size_t i=0; i<count; i++)
+	{
+		memcpy(ptr, &pixel, bpp);
+		if(incrementPtr == -1)
+			ptr -= bpp;
+		if(incrementPtr == 1)
+			ptr += bpp;
+	}
+}
+
 template <int incrementPtr>
 STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B)
 {
@@ -163,6 +178,22 @@ STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(Uint8 *&ptr, const SDL
 	PutColor(ptr, Color.r, Color.g, Color.b);
 }
 
+template <int incrementPtr>
+STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorRow(Uint8 *&ptr, const SDL_Color & Color, size_t count)
+{
+	//drop least significant bits of 24 bpp encoded color
+	Uint16 pixel = (Color.b>>3) + ((Color.g>>2) << 5) + ((Color.r>>3) << 11);
+	
+	for (size_t i=0; i<count; i++)
+	{
+		memcpy(ptr, &pixel, 2);
+		if(incrementPtr == -1)
+			ptr -= 2;
+		if(incrementPtr == 1)
+			ptr += 2;
+	}
+}
+
 SDL_Surface * CSDL_Ext::newSurface(int w, int h, SDL_Surface * mod) //creates new surface, with flags/format same as in surface given
 {
 	return SDL_CreateRGBSurface(mod->flags,w,h,mod->format->BitsPerPixel,mod->format->Rmask,mod->format->Gmask,mod->format->Bmask,mod->format->Amask);
@@ -318,7 +349,8 @@ void printAtMiddle(const std::string & text, int x, int y, TTF_Font * font, SDL_
 		temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
 		break;
 	}
-	CSDL_Ext::blitSurface(temp,NULL,dst,&genRect(temp->h,temp->w,x-(temp->w/2),y-(temp->h/2)));
+	SDL_Rect dstRect = genRect(temp->h, temp->w, x-(temp->w/2), y-(temp->h/2));
+	CSDL_Ext::blitSurface(temp, NULL, dst, &dstRect);
 	SDL_FreeSurface(temp);
 }
 
@@ -361,7 +393,8 @@ void printAt(const std::string & text, int x, int y, TTF_Font * font, SDL_Color
 		temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
 		break;
 	}
-	CSDL_Ext::blitSurface(temp,NULL,dst,&genRect(temp->h,temp->w,x,y));
+	SDL_Rect dstRect = genRect(temp->h,temp->w,x,y);
+	CSDL_Ext::blitSurface(temp,NULL,dst,&dstRect);
 	if(refresh)
 		SDL_UpdateRect(dst,x,y,temp->w,temp->h);
 	SDL_FreeSurface(temp);
@@ -463,7 +496,8 @@ void printTo(const std::string & text, int x, int y, TTF_Font * font, SDL_Color
 		temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
 		break;
 	}
-	CSDL_Ext::blitSurface(temp,NULL,dst,&genRect(temp->h,temp->w,x-temp->w,y-temp->h));
+	SDL_Rect dstRect = genRect(temp->h,temp->w,x-temp->w,y-temp->h);
+	CSDL_Ext::blitSurface(temp,NULL,dst,&dstRect);
 	SDL_UpdateRect(dst,x-temp->w,y-temp->h,temp->w,temp->h);
 	SDL_FreeSurface(temp);
 }
@@ -504,7 +538,8 @@ void printToWR(const std::string & text, int x, int y, TTF_Font * font, SDL_Colo
 		temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
 		break;
 	}
-	CSDL_Ext::blitSurface(temp,NULL,dst,&genRect(temp->h,temp->w,x-temp->w,y-temp->h));
+	SDL_Rect dstRect = genRect(temp->h,temp->w,x-temp->w,y-temp->h);
+	CSDL_Ext::blitSurface(temp,NULL,dst,&dstRect);
 	SDL_FreeSurface(temp);
 }
 
@@ -1296,7 +1331,13 @@ void CSDL_Ext::fillRect( SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color )
 
 SDL_Surface * CSDL_Ext::std32bppSurface = NULL;
 
-//instantiation of templates used in CAnimation, required for correct linking
-template struct ColorPutter<2,1>;
-template struct ColorPutter<3,1>;
-template struct ColorPutter<4,1>;
+//instantiation of templates used in CAnimation and CCreatureAnimation, required for correct linking
+template struct ColorPutter<2,-1>;
+template struct ColorPutter<3,-1>;
+template struct ColorPutter<4,-1>;
+template struct ColorPutter<2, 0>;
+template struct ColorPutter<3, 0>;
+template struct ColorPutter<4, 0>;
+template struct ColorPutter<2, 1>;
+template struct ColorPutter<3, 1>;
+template struct ColorPutter<4, 1>;

+ 2 - 0
client/SDL_Extensions.h

@@ -99,6 +99,7 @@ struct ColorPutter
 	static STRONG_INLINE void PutColorAlphaSwitch(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A);
 	static STRONG_INLINE void PutColor(Uint8 *&ptr, const SDL_Color & Color);
 	static STRONG_INLINE void PutColorAlpha(Uint8 *&ptr, const SDL_Color & Color);
+	static STRONG_INLINE void PutColorRow(Uint8 *&ptr, const SDL_Color & Color, size_t count);
 };
 
 template <int incrementPtr>
@@ -109,6 +110,7 @@ struct ColorPutter<2, incrementPtr>
 	static STRONG_INLINE void PutColorAlphaSwitch(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A);
 	static STRONG_INLINE void PutColor(Uint8 *&ptr, const SDL_Color & Color);
 	static STRONG_INLINE void PutColorAlpha(Uint8 *&ptr, const SDL_Color & Color);
+	static STRONG_INLINE void PutColorRow(Uint8 *&ptr, const SDL_Color & Color, size_t count);
 };
 
 typedef void (*BlitterWithRotationVal)(SDL_Surface *src,SDL_Rect srcRect, SDL_Surface * dst, SDL_Rect dstRect, ui8 rotation);

+ 1 - 1
lib/CCreatureHandler.h

@@ -113,7 +113,7 @@ public:
 	int factionToTurretCreature[F_NUMBER]; //which creature's animation should be used to dispaly creature in turret while siege
 
 	std::map<TBonusType, std::pair<std::string, std::string> > stackBonuses; // bonus => name, description
-	std::vector<std::vector<ui32>> expRanks; // stack experience needed for certain rank, index 0 for other tiers (?)
+	std::vector<std::vector<ui32> > expRanks; // stack experience needed for certain rank, index 0 for other tiers (?)
 	std::vector<ui32> maxExpPerBattle; //%, tiers same as above
 	si8 expAfterUpgrade;//multiplier in %
 

+ 1 - 1
lib/Connection.cpp

@@ -7,7 +7,6 @@
 
 #ifndef _MSC_VER
 #include "../lib/RegisterTypes.cpp"
-#include "CObjectHandler.h"
 #endif
 
 //for smart objs serialization over net
@@ -21,6 +20,7 @@
 #include "VCMI_Lib.h"
 #include "CArtHandler.h"
 #include "CHeroHandler.h"
+#include "CSpellHandler.h"
 #include "CTownHandler.h"
 #include "CCampaignHandler.h"
 #include "NetPacks.h"