Ver Fonte

Obtaining town instance pointer via cb. Plz, don't access gamestate directly from player interface! Everything has to go via callback.

Commented out giving starting artifact - new artifact randomization make it crashing. Please fix it.

New control - CTextBox - for multi-line text with optional slider. Used it for map description and info windows. Related changes. Fixes #22 and #96.
Michał W. Urbańczyk há 15 anos atrás
pai
commit
d0ff61807d

+ 9 - 10
CCallback.cpp

@@ -164,17 +164,15 @@ const CGTownInstance * CCallback::getTownInfo(int val, bool mode) const //mode =
 		else 
 			return NULL;
 	}
-	else 
+	else if(mode == 1)
 	{
-		//TODO: add some smart ID to the CTownInstance
-
-
-		//for (int i=0; i<gs->players[gs->currentPlayer].towns.size();i++)
-		//{
-		//	if (gs->players[gs->currentPlayer].towns[i]->someID==val)
-		//		return gs->players[gs->currentPlayer].towns[i];
-		//}
-		return NULL;
+		const CGObjectInstance *obj = getObjectInfo(val);
+		if(!obj)
+			return NULL;
+		if(obj->ID != TOWNI_TYPE)
+			return NULL;
+		else
+			return static_cast<const CGTownInstance *>(obj);
 	}
 	return NULL;
 }
@@ -241,6 +239,7 @@ const CGHeroInstance * CCallback::getHeroInfo(int val, int mode) const //mode =
 
 const CGObjectInstance * CCallback::getObjectInfo(int ID) const
 {
+	//TODO: check for visibility
 	return gs->map->objects[ID];
 }
 

+ 2 - 2
CCallback.h

@@ -141,7 +141,7 @@ public:
 	
 	//town
 	virtual int howManyTowns()const =0;
-	virtual const CGTownInstance * getTownInfo(int val, bool mode)const =0; //mode = 0 -> val = serial; mode = 1 -> val = ID
+	virtual const CGTownInstance * getTownInfo(int val, bool mode)const =0; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial)
 	virtual std::vector < const CGTownInstance *> getTownsInfo(bool onlyOur=true) const=0;
 	virtual std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const =0; //heroes that can be recruited
 	virtual int canBuildStructure(const CGTownInstance *t, int ID) =0;//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
@@ -245,7 +245,7 @@ public:
 	int getResourceAmount(int type) const;
 	std::vector<si32> getResourceAmount() const;
 	int howManyHeroes(bool includeGarrisoned = true) const;
-	const CGTownInstance * getTownInfo(int val, bool mode) const; //mode = 0 -> val = serial; mode = 1 -> val = ID
+	const CGTownInstance * getTownInfo(int val, bool mode) const; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial)
 	std::vector < const CGTownInstance *> getTownsInfo(bool onlyOur=true) const;
 	int howManyTowns()const;
 	std::vector < std::string > getObjDescriptions(int3 pos) const; //returns descriptions of objects at pos in order from the lowest to the highest

+ 43 - 0
client/AdventureMapButton.cpp

@@ -637,3 +637,46 @@ void CSlider::setAmount( int to )
 	positions = to - capacity;
 	amax(positions, 0);
 }
+
+void CSlider::showAll(SDL_Surface * to)
+{
+	SDL_FillRect(to, &pos, 0);
+	CIntObject::showAll(to);
+}
+
+void CSlider::wheelScrolled(bool down, bool in)
+{
+	moveTo(value + 3 * (down ? +1 : -1));
+}
+
+void CSlider::keyPressed(const SDL_KeyboardEvent & key)
+{
+	if(key.state != SDL_PRESSED) return;
+
+	int moveDest = 0;
+	switch(key.keysym.sym)
+	{
+	case SDLK_UP:
+		moveDest = value - 1;
+		break;
+	case SDLK_DOWN:
+		moveDest = value + 1;
+		break;
+	case SDLK_PAGEUP:
+		moveDest = value - capacity + 1;
+		break;
+	case SDLK_PAGEDOWN:
+		moveDest = value + capacity - 1;
+		break;
+	case SDLK_HOME:
+		moveDest = 0;
+		break;
+	case SDLK_END:
+		moveDest = amount - capacity;
+		break;
+	default:
+		return;
+	}
+
+	moveTo(moveDest); 
+}

+ 10 - 8
client/AdventureMapButton.h

@@ -125,25 +125,27 @@ public:
 		positions, //number of highest position (0 if there is only one)
 		value; //first active element
 	bool horizontal;
+	bool wheelScrolling;
+	bool keyScrolling;
+
 	CDefEssential *imgs ;
 
 	boost::function<void(int)> moved;
-	//void(T::*moved)(int to);
-	//T* owner;
 
 	void redrawSlider(); 
-
 	void sliderClicked();
 	void moveLeft();
-	void clickLeft(tribool down, bool previousState);
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent);
 	void moveRight();
 	void moveTo(int to);
 	void block(bool on);
 	void setAmount(int to);
-	//void activate(); // makes button active
-	//void deactivate(); // makes button inactive (but doesn't delete)
-	//void show(SDL_Surface * to);
+
+	void keyPressed(const SDL_KeyboardEvent & key);
+	void wheelScrolled(bool down, bool in);
+	void clickLeft(tribool down, bool previousState);
+	void mouseMoved (const SDL_MouseMotionEvent & sEvent);
+	void showAll(SDL_Surface * to);
+
 	CSlider(int x, int y, int totalw, boost::function<void(int)> Moved, int Capacity, int Amount, 
 		int Value=0, bool Horizontal=true, int style = 0); //style 0 - brown, 1 - blue
 	~CSlider();

+ 1 - 1
client/CCastleInterface.cpp

@@ -778,7 +778,7 @@ void CCastleInterface::buildingClicked(int building)
 
 void CCastleInterface::castleTeleport(int where)
 {
-	const CGTownInstance * dest = dynamic_cast<const CGTownInstance *>(CGI->state->map->objects[where]);
+	const CGTownInstance * dest = LOCPLINT->cb->getTownInfo(where, 1);
 	LOCPLINT->cb->teleportHero(town->visitingHero, dest);
 	close();//close this window, interface with new town will be called by town::onVisit
 }

+ 9 - 11
client/CHeroWindow.cpp

@@ -418,29 +418,27 @@ void CHeroWindow::redrawCurBack()
 	CSDL_Ext::printAtMiddle(CGI->generaltexth->jktexts[4], 262, 99, FONT_SMALL, tytulowy, curBack);
 
 	//dismiss / quest log
-	std::vector<std::string> * toPrin = CMessage::breakText(CGI->generaltexth->jktexts[8].substr(1, CGI->generaltexth->jktexts[8].size()-2));
-	if(toPrin->size()==1)
+	std::vector<std::string> toPrin = CMessage::breakText(CGI->generaltexth->jktexts[8].substr(1, CGI->generaltexth->jktexts[8].size()-2));
+	if(toPrin.size()==1)
 	{
-		CSDL_Ext::printAt((*toPrin)[0], 372, 439, FONT_SMALL, zwykly, curBack);
+		CSDL_Ext::printAt(toPrin[0], 372, 439, FONT_SMALL, zwykly, curBack);
 	}
 	else
 	{
-		CSDL_Ext::printAt((*toPrin)[0], 372, 430, FONT_SMALL, zwykly, curBack);
-		CSDL_Ext::printAt((*toPrin)[1], 372, 446, FONT_SMALL, zwykly, curBack);
+		CSDL_Ext::printAt(toPrin[0], 372, 430, FONT_SMALL, zwykly, curBack);
+		CSDL_Ext::printAt(toPrin[1], 372, 446, FONT_SMALL, zwykly, curBack);
 	}
-	delete toPrin;
 
 	toPrin = CMessage::breakText(CGI->generaltexth->jktexts[9].substr(1, CGI->generaltexth->jktexts[9].size()-2));
-	if(toPrin->size()==1)
+	if(toPrin.size()==1)
 	{
-		CSDL_Ext::printAt((*toPrin)[0], 512, 439, FONT_SMALL, zwykly, curBack);
+		CSDL_Ext::printAt(toPrin[0], 512, 439, FONT_SMALL, zwykly, curBack);
 	}
 	else
 	{
-		CSDL_Ext::printAt((*toPrin)[0], 512, 430, FONT_SMALL, zwykly, curBack);
-		CSDL_Ext::printAt((*toPrin)[1], 512, 446, FONT_SMALL, zwykly, curBack);
+		CSDL_Ext::printAt(toPrin[0], 512, 430, FONT_SMALL, zwykly, curBack);
+		CSDL_Ext::printAt(toPrin[1], 512, 446, FONT_SMALL, zwykly, curBack);
 	}
-	delete toPrin;
 
 	//printing primary skills' amounts
 	for(int m=0; m<4; ++m)

+ 7 - 9
client/CKingdomInterface.cpp

@@ -652,19 +652,17 @@ void CKingdomInterface::CTownItem::showAll(SDL_Surface * to)
 	oss << town->dailyIncome();
 	CSDL_Ext::printAtMiddle(oss.str(),pos.x+189,pos.y+61,FONT_SMALL,zwykly,to);
 
-	std::vector<std::string> * toPrin = CMessage::breakText(CGI->generaltexth->allTexts[265]);
+	std::vector<std::string> toPrin = CMessage::breakText(CGI->generaltexth->allTexts[265]);
 
-	CSDL_Ext::printAt((*toPrin)[0], pos.x+4, pos.y+76, FONT_SMALL, tytulowy, to);
-	if(toPrin->size()!=1)
-		CSDL_Ext::printAt((*toPrin)[1], pos.x+4, pos.y+92, FONT_SMALL, tytulowy, to);
+	CSDL_Ext::printAt(toPrin[0], pos.x+4, pos.y+76, FONT_SMALL, tytulowy, to);
+	if(toPrin.size()!=1)
+		CSDL_Ext::printAt(toPrin[1], pos.x+4, pos.y+92, FONT_SMALL, tytulowy, to);
 
-	delete toPrin;
 	toPrin = CMessage::breakText(CGI->generaltexth->allTexts[266]);
 
-	CSDL_Ext::printAt((*toPrin)[0], pos.x+351, pos.y+76, FONT_SMALL, tytulowy, to);
-	if(toPrin->size()!=1)
-		CSDL_Ext::printAt((*toPrin)[1], pos.x+351, pos.y+92, FONT_SMALL, tytulowy, to);
-	delete toPrin;
+	CSDL_Ext::printAt(toPrin[0], pos.x+351, pos.y+76, FONT_SMALL, tytulowy, to);
+	if(toPrin.size()!=1)
+		CSDL_Ext::printAt(toPrin[1], pos.x+351, pos.y+92, FONT_SMALL, tytulowy, to);
 
 	for (int i=0; i<CREATURES_PER_TOWN;i++)
 	{//creatures info

+ 77 - 137
client/CMessage.cpp

@@ -113,33 +113,30 @@ SDL_Surface * CMessage::drawBox1(int w, int h, int playerColor) //draws box for
 
 /* The map file contains long texts, with or without line breaks. This
  * method takes such a text and breaks it into into several lines. */
-std::vector<std::string> * CMessage::breakText(std::string text, size_t maxLineSize, 
-											   bool userBreak, bool ifor)
+std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineSize/*=30*/, const boost::function<int(char)> &charMetric /*= 0*/, bool allowLeadingWhitespace /*= false*/ )
 {
-	std::vector<std::string> * ret = new std::vector<std::string>();
+	std::vector<std::string> ret;
 
-	boost::algorithm::trim_if(text,boost::algorithm::is_any_of(" ")); 
+	boost::algorithm::trim_right_if(text,boost::algorithm::is_any_of(" "));
 
 	while (text.length())
 	{
+		unsigned int lineLength = 0;	//in characters or given char metric
+		unsigned int z = 0; //our position in text
+		bool opened = false;//if we have an unclosed brace in current line
+		bool lineManuallyBroken = false;
 
-		unsigned int z = 0;
-		unsigned int braces = 0;
-		bool opened = false;
-
-		while(z < text.length()  &&  (text[z] != 0x0a) && (z < maxLineSize+braces))
+		while(z < text.length()  &&  text[z] != 0x0a  &&  lineLength < maxLineSize)
 		{
 			/* We don't count braces in string length. */
 			if (text[z] == '{')
-			{
 				opened=true;
-				braces++;
-			} 
 			else if (text[z]=='}')
-			{
 				opened=false;
-				braces++;
-			}
+			else if(charMetric)
+				lineLength += charMetric(text[z]);
+			else
+				lineLength++;
 
 			z++;
 		}
@@ -152,10 +149,13 @@ std::vector<std::string> * CMessage::breakText(std::string text, size_t maxLineS
 			int pos = z-1;
 
 			// Do not break an ellipsis, backtrack until whitespace.
-			if (text[pos] == '.' && text[z] == '.') {
+			if (text[pos] == '.' && text[z] == '.') 
+			{
 				while (pos != 0 && text[pos] != ' ')
 					pos--;
-			} else {
+			} 
+			else 
+			{
 			/* TODO: boost should have a nice method to do that. */
 				while(pos > 0 &&
 					  text[pos] != ' ' && 
@@ -172,17 +172,17 @@ std::vector<std::string> * CMessage::breakText(std::string text, size_t maxLineS
 		
 		if(z) //non-blank line 
 		{
-			ret->push_back(text.substr(0, z));
+			ret.push_back(text.substr(0, z));
 
 			if (opened)
 				/* Close the brace for the current line. */
-				ret->back() += '}';
+				ret.back() += '}';
 
 			text.erase(0, z);
 		}
 		else if(text[z] == 0x0a) //blank line 
 		{
-			ret->push_back(""); //add empty string, no extra actions needed
+			ret.push_back(""); //add empty string, no extra actions needed
 		}
 
 		if (text.length() && text[0] == 0x0a)
@@ -193,9 +193,12 @@ std::vector<std::string> * CMessage::breakText(std::string text, size_t maxLineS
 
 			/* Remove LF */
 			text.erase(0, 1);
+
+			lineManuallyBroken = true;
 		}
 
-		boost::algorithm::trim_left_if(text,boost::algorithm::is_any_of(" ")); 
+		if(!allowLeadingWhitespace || !lineManuallyBroken)
+			boost::algorithm::trim_left_if(text,boost::algorithm::is_any_of(" ")); 
 
 		if (opened)
 		{
@@ -206,12 +209,18 @@ std::vector<std::string> * CMessage::breakText(std::string text, size_t maxLineS
 	}
 
 	/* Trim whitespaces of every line. */
-	for (size_t i=0; i<ret->size(); i++)
-		boost::algorithm::trim((*ret)[i]);
+	if(!allowLeadingWhitespace)
+		for (size_t i=0; i<ret.size(); i++)
+			boost::algorithm::trim(ret[i]);
 
 	return ret;
 }
 
+std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineWidth, EFonts font )
+{
+	return breakText(text, maxLineWidth, boost::bind(&Font::getCharWidth, graphics->fonts[font], _1), true);
+}
+
 std::pair<int,int> CMessage::getMaxSizes(std::vector<std::vector<SDL_Surface*> > * txtg, int fontHeight)
 {
 	std::pair<int,int> ret;
@@ -328,13 +337,14 @@ CSimpleWindow * CMessage::genWindow(std::string text, int player, bool centerOnM
 {
 	CSimpleWindow * ret = new CSimpleWindow();
 	int fontHeight;
-	std::vector<std::string> * brtext = breakText(text,32,true,true);
-	std::vector<std::vector<SDL_Surface*> > * txtg = drawText(brtext, fontHeight);
+	std::vector<std::string> brtext = breakText(text,32);
+	std::vector<std::vector<SDL_Surface*> > * txtg = drawText(&brtext, fontHeight);
 	std::pair<int,int> txts = getMaxSizes(txtg, fontHeight);
 	ret->bitmap = drawBox1(txts.first+Lmar+Rmar,txts.second+Tmar+Bmar,player);
 	ret->pos.h = ret->bitmap->h;
 	ret->pos.w = ret->bitmap->w;
-	if (centerOnMouse) {
+	if (centerOnMouse) 
+	{
 		ret->pos.x = GH.current->motion.x - ret->pos.w/2;
 		ret->pos.y = GH.current->motion.y - ret->pos.h/2;
 		// Put the window back on screen if necessary
@@ -342,14 +352,15 @@ CSimpleWindow * CMessage::genWindow(std::string text, int player, bool centerOnM
 		amax(ret->pos.y, 0);
 		amin(ret->pos.x, conf.cc.resx - ret->pos.w);
 		amin(ret->pos.y, conf.cc.resy - ret->pos.h);
-	} else {
+	} 
+	else 
+	{
 		// Center on screen
 		ret->pos.x = screen->w/2 - (ret->pos.w/2);
 		ret->pos.y = screen->h/2 - (ret->pos.h/2);
 	}
 	int curh = ret->bitmap->h/2 - (fontHeight*txtg->size())/2;
 	blitTextOnSur(txtg,fontHeight,curh,ret->bitmap);
-	delete brtext;
 	delete txtg;
 	return ret;
 }
@@ -357,8 +368,8 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_
 {
 	int curh;
 	int fontHeight;
-	std::vector<std::string> * tekst = breakText(text,charperline);
-	std::vector<std::vector<SDL_Surface*> > * txtg = drawText(tekst, fontHeight);
+	std::vector<std::string> tekst = breakText(text,charperline);
+	std::vector<std::vector<SDL_Surface*> > * txtg = drawText(&tekst, fontHeight);
 	std::pair<int,int> txts = getMaxSizes(txtg, fontHeight), boxs;
 	boxs.first = std::max(txts.first,bitmap->w) // text/bitmap max width
 		+ 50; //side margins
@@ -376,7 +387,6 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_
 	blitAt(bitmap,(ret->w/2)-(bitmap->w/2),curh,ret);
 	curh += bitmap->h + 5;
 	CSDL_Ext::printAtMiddle(sub,ret->w/2,curh+10,FONT_SMALL,zwykly,ret);
-	delete tekst;
 	delete txtg;
 	return ret;
 }
@@ -384,32 +394,31 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_
 void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player, int charperline)
 {
 	SDL_Surface * _or = NULL;
-	int fontHeight;
+	const Font &f = *graphics->fonts[FONT_MEDIUM];
+	int fontHeight = f.height;
+
+	if(dynamic_cast<CSelWindow*>(ret)) //it's selection window, so we'll blit "or" between components
+		_or = FNT_RenderText(FONT_MEDIUM,CGI->generaltexth->allTexts[4],zwykly);
 
-	// Try to compute a reasonable number of characters per line
-	if (!charperline) 
+	const int sizes[][2] = {{400, 100}, {500, 150}, {600, 200}};
+	for(int i = 0; 
+		i < ARRAY_COUNT(sizes) 
+			&& sizes[i][0] < conf.cc.resx - 150  
+			&& sizes[i][1] < conf.cc.resy - 150
+			&& ret->text->slider;
+		i++)
 	{
-		if (text.size() < 30 && ret->buttons.size() < 2)
-			charperline = 30;
-		else if (text.size() < 200)
-			charperline = 40;
-		else if (text.size() < 750)
-			charperline = 50;
-		else
-			charperline = 75; //TODO: add scrollbar for very long texts
+		ret->text->setBounds(sizes[i][0], sizes[i][1]);
 	}
 
-	if(dynamic_cast<CSelWindow*>(ret)) //it's selection window, so we'll blit "or" between components
-		_or = FNT_RenderText(FONT_MEDIUM,CGI->generaltexth->allTexts[4],zwykly);
+	if(ret->text->slider)
+		ret->text->slider->changeUsedEvents(CIntObject::WHEEL | CIntObject::KEYBOARD, true);
 
-	std::vector<std::string> * brtext = breakText(text, charperline, true, true); //text 
-	std::vector<std::vector<SDL_Surface*> > * txtg = drawText(brtext, fontHeight);
-	std::pair<int,int> txts = getMaxSizes(txtg, fontHeight);
+	std::pair<int,int> winSize(ret->text->pos.w, ret->text->pos.h); //start with text size
 
 	ComponentsToBlit comps(ret->components,500,_or);
-
 	if (ret->components.size())
-		txts.second += 30 + comps.h; //space to first component
+		winSize.second += 30 + comps.h; //space to first component
 
 	int bw = 0;
 	if (ret->buttons.size())
@@ -418,35 +427,32 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player, int
 		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][0]->w; 
-		txts.second += 20 + //before button
+		winSize.second += 20 + //before button
 		ok->ourImages[0].bitmap->h; //button	
 	}
 
 	// Clip window size
-	amax(txts.second, 50);
-	amax(txts.first, 80);
-	amax(txts.first, comps.w);
-	amax(txts.first, bw);
+	amax(winSize.second, 50);
+	amax(winSize.first, 80);
+	amax(winSize.first, comps.w);
+	amax(winSize.first, bw);
 
-	amin(txts.first, conf.cc.resx - 150);
+	amin(winSize.first, conf.cc.resx - 150);
 
-	ret->bitmap = drawBox1 (txts.first + 2*SIDE_MARGIN, txts.second + 2*SIDE_MARGIN, player);
+	ret->bitmap = drawBox1 (winSize.first + 2*SIDE_MARGIN, winSize.second + 2*SIDE_MARGIN, player);
 	ret->pos.h=ret->bitmap->h;
 	ret->pos.w=ret->bitmap->w;
-	ret->pos.x=screen->w/2-(ret->pos.w/2);
-	ret->pos.y=screen->h/2-(ret->pos.h/2);
-	if (txts.second > conf.cc.resy - 150)
-	{
-		amin(txts.second, conf.cc.resy - 150);
-		ret->slider = new CSlider(ret->pos.x + ret->pos.w - SIDE_MARGIN, ret->pos.y + SIDE_MARGIN,
-			ret->pos.h - 2*SIDE_MARGIN, boost::bind (&CInfoWindow::sliderMoved, ret, _1), brtext->size(), brtext->size(), brtext->size()-1, false, 0);
-		//ret->bitmap->w -= ret->slider->pos.w; //crop text so that slider has more place for itself
-	}
-	else
-		ret->slider = NULL;
+	ret->center();
+
 
 	int curh = SIDE_MARGIN;
-	blitTextOnSur (txtg, fontHeight, curh, ret->bitmap);
+
+	int xOffset = (ret->pos.w - ret->text->pos.w)/2;
+	ret->text->moveBy(Point(xOffset, SIDE_MARGIN));
+
+	//blitTextOnSur (txtg, fontHeight, curh, ret->bitmap);
+
+	curh += ret->text->pos.h;
 
 	if (ret->components.size())
 	{
@@ -471,76 +477,11 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player, int
 		ret->components[i]->pos.x += ret->pos.x;
 		ret->components[i]->pos.y += ret->pos.y;
 	}
-	delete brtext;
-	delete txtg;
+
 	if(_or)
 		SDL_FreeSurface(_or);
 }
 
-SDL_Surface * CMessage::genMessage
-(std::string title, std::string text, EWindowType type, std::vector<CDefHandler*> *addPics, void * cb)
-{
-//max x 320 okolo 30 znakow
-	std::vector<std::string> * tekst;
-	if (text.length() < 30) //does not need breaking
-	{
-		tekst = new std::vector<std::string>();
-		tekst->push_back(text);
-	}
-	else tekst = breakText(text);
-	int ww, hh; //dimensions of box
-	if (319>30+13*text.length())
-		ww = 30+13*text.length();
-	else ww = 319;
-	if (title.length())
-		hh=110+(21*tekst->size());
-	else hh=60+(21*tekst->size());
-	if (type==yesOrNO) //make place for buttons
-	{
-		if (ww<200) ww=200;
-		hh+=70;
-	}
-
-	SDL_Surface * ret = drawBox1(ww,hh,0);
-	//prepare title text
-
-	if (title.length())
-	{
-		SDL_Surface * titleText = FNT_RenderText(FONT_BIG,title,tytulowy);
-
-		//draw title
-		SDL_Rect tytul = genRect(titleText->h,titleText->w,((ret->w/2)-(titleText->w/2)),37);
-		SDL_BlitSurface(titleText,NULL,ret,&tytul);
-		SDL_FreeSurface(titleText);
-	}
-	//draw text
-	for (size_t i=0; i<tekst->size(); i++)
-	{
-		int by = 37+i*21;
-		if (title.length()) by+=40;
-		SDL_Surface * tresc = FNT_RenderText(FONT_BIG,(*tekst)[i],zwykly);
-		SDL_Rect trescRect = genRect(tresc->h,tresc->w,((ret->w/2)-(tresc->w/2)),by);
-		SDL_BlitSurface(tresc,NULL,ret,&trescRect);
-		SDL_FreeSurface(tresc);
-	}
-	if (type==yesOrNO) // add buttons
-	{
-		int by = 77+tekst->size()*21;
-		if (title.length()) by+=40;
-		int hwo = (*addPics)[0]->ourImages[0].bitmap->w, hwc=(*addPics)[0]->ourImages[0].bitmap->w;
-		//ok
-		SDL_Rect trescRect = genRect((*addPics)[0]->ourImages[0].bitmap->h,hwo,((ret->w/2)-hwo-10),by);
-		SDL_BlitSurface((*addPics)[0]->ourImages[0].bitmap,NULL,ret,&trescRect);
-		reinterpret_cast<std::vector<SDL_Rect>*>(cb)->push_back(trescRect);
-		//cancel
-		trescRect = genRect((*addPics)[1]->ourImages[0].bitmap->h,hwc,((ret->w/2)+10),by);
-		SDL_BlitSurface((*addPics)[1]->ourImages[0].bitmap,NULL,ret,&trescRect);
-		reinterpret_cast<std::vector<SDL_Rect>*>(cb)->push_back(trescRect);
-	}
-	delete tekst;
-	return ret;
-}
-
 void CMessage::drawBorder(int playerColor, SDL_Surface * ret, int w, int h, int x, int y)
 {	
 	//obwodka I-szego rzedu pozioma //border of 1st series, horizontal
@@ -582,9 +523,8 @@ ComponentResolved::ComponentResolved( SComponent *Comp )
 {
 	comp = Comp;
 	img = comp->getImg();
-	std::vector<std::string> * brtext = CMessage::breakText(comp->subtitle,13,true,true); //text 
-	txt = CMessage::drawText(brtext,txtFontHeight,FONT_MEDIUM);
-	delete brtext;
+	std::vector<std::string> brtext = CMessage::breakText(comp->subtitle,13); //text 
+	txt = CMessage::drawText(&brtext,txtFontHeight,FONT_MEDIUM);
 
 	//calculate dimensions
 	std::pair<int,int> textSize = CMessage::getMaxSizes(txt, txtFontHeight);

+ 3 - 3
client/CMessage.h

@@ -4,6 +4,7 @@
 #include "FontBase.h"
 #include "../global.h"
 #include <SDL.h>
+#include <boost/function.hpp>
 
 /*
  * CMessage.h, part of VCMI engine
@@ -63,12 +64,11 @@ public:
 	static SDL_Surface * blitTextOnSur(std::vector<std::vector<SDL_Surface*> > * txtg, int fontHeight, int & curh, SDL_Surface * ret, int xCenterPos=-1); //xPos==-1 works as if ret->w/2
 	static void drawIWindow(CInfoWindow * ret, std::string text, int player, int charperline);
 	static CSimpleWindow * genWindow(std::string text, int player, bool centerOnMouse=false, int Lmar=35, int Rmar=35, int Tmar=35, int Bmar=35);//supports h3 text formatting; player sets color of window, Lmar/Rmar/Tmar/Bmar are Left/Right/Top/Bottom margins
-	static SDL_Surface * genMessage(std::string title, std::string text, EWindowType type=infoOnly,
-								std::vector<CDefHandler*> *addPics=NULL, void * cb=NULL);
 	static SDL_Surface * drawBox1(int w, int h, int playerColor=1);
 	static void drawBorder(int playerColor, SDL_Surface * ret, int w, int h, int x=0, int y=0);
 	static SDL_Surface * drawBoxTextBitmapSub(int player, std::string text, SDL_Surface* bitmap, std::string sub, int charperline=30, int imgToBmp=55);
-	static std::vector<std::string> * breakText(std::string text, size_t maxLineSize=30, bool userBreak=true, bool ifor=true);
+	static std::vector<std::string> breakText(std::string text, size_t maxLineSize=30, const boost::function<int(char)> &charMetric = boost::function<int(char)>(), bool allowLeadingWhitespace = false);
+	static std::vector<std::string> breakText(std::string text, size_t maxLineWidth, EFonts font);
 	static void init();
 	static void dispose();
 };

+ 33 - 31
client/CPreGame.cpp

@@ -828,6 +828,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const boost::function<void(
 	}
 
 	slider = new CSlider(372, 86, tabType != CMenuScreen::saveGame ? 480 : 430, bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, 1);
+	slider->changeUsedEvents(WHEEL, true);
 	format =  CDefHandler::giveDef("SCSELC.DEF");
 
 	sortingBy = _format;
@@ -1082,13 +1083,6 @@ void SelectionTab::clickLeft( tribool down, bool previousState )
 			select(line);
 	}
 }
-
-void SelectionTab::wheelScrolled( bool down, bool in )
-{
-	slider->moveTo(slider->value + 3 * (down ? +1 : -1));
-	//select(selectionPos - slider->value + (down ? +1 : -1));
-}
-
 void SelectionTab::keyPressed( const SDL_KeyboardEvent & key )
 {
 	if(key.state != SDL_PRESSED) return;
@@ -1166,23 +1160,25 @@ InfoCard::InfoCard( CMenuScreen::EState Type )
 	OBJ_CONSTRUCTION;
 	pos.x += 393;
 	used = RCLICK;
-
+	mapDescription = NULL;
 	type = Type;
 
+	Rect descriptionRect(26, 149, 320, 115);
+	mapDescription = new CTextBox("", descriptionRect, 1);
+
 	if(type == CMenuScreen::campaignList)
 	{
-		/*bg = new CPicture(BitmapHandler::loadBitmap("CamCust.bmp"), 0, 0, true);
-		bg->pos.x = 0;
-		bg->pos.y = 0;*/
+		CSelectionScreen *ss = static_cast<CSelectionScreen*>(parent);
+		moveChild(new CPicture(*ss->bg, descriptionRect + Point(-393, 0)), this, mapDescription, true); //move subpicture bg to our description control (by default it's our (Infocard) child)
 	}
 	else
 	{
 		bg = new CPicture(BitmapHandler::loadBitmap("GSELPOP1.bmp"), 0, 0, true);
+		std::swap(children.front(), children.back());
 		pos.w = bg->pos.w;
 		pos.h = bg->pos.h;
 		sizes = CDefHandler::giveDef("SCNRMPSZ.DEF");
 		sFlags = CDefHandler::giveDef("ITGFLAGS.DEF");
-
 		difficulty = new CHighlightableButtonsGroup(0);
 		{
 			static const char *difButns[] = {"GSPBUT3.DEF", "GSPBUT4.DEF", "GSPBUT5.DEF", "GSPBUT6.DEF", "GSPBUT7.DEF"};
@@ -1197,8 +1193,11 @@ InfoCard::InfoCard( CMenuScreen::EState Type )
 
 		if(type != CMenuScreen::newGame)
 			difficulty->block(true);
+
+		//description needs bg
+		moveChild(new CPicture(*bg, descriptionRect), this, mapDescription, true); //move subpicture bg to our description control (by default it's our (Infocard) child)
 	}
-	
+
 }
 
 InfoCard::~InfoCard()
@@ -1329,22 +1328,16 @@ void InfoCard::showAll( SDL_Surface * to )
 		}
 
 		//blit description
-		std::string itemDesc, name;
+		std::string name;
 
 		if (type == CMenuScreen::campaignList)
 		{
-			itemDesc = curMap->campaignHeader->description;
 			name = curMap->campaignHeader->name;
 		} 
 		else
 		{
-			itemDesc = curMap->mapHeader->description;
 			name = curMap->mapHeader->name;
 		}
-		std::vector<std::string> *desc = CMessage::breakText(itemDesc,52);
-		for (int i=0;i<desc->size();i++)
-			printAtLoc((*desc)[i], 26, 149 + i*16, FONT_SMALL, zwykly, to);
-		delete desc;
 
 		//name
 		if (name.length())
@@ -1358,8 +1351,17 @@ void InfoCard::showAll( SDL_Surface * to )
 
 void InfoCard::changeSelection( const CMapInfo *to )
 {
-	if(to && type != CMenuScreen::newGame && type != CMenuScreen::campaignList)
-		difficulty->select(curOpts->difficulty, 0);
+	if(to && mapDescription)
+	{
+
+		if (type == CMenuScreen::campaignList)
+			mapDescription->setTxt(to->campaignHeader->description);
+		else
+			mapDescription->setTxt(to->mapHeader->description);
+
+		if(type != CMenuScreen::newGame && type != CMenuScreen::campaignList)
+			difficulty->select(curOpts->difficulty, 0);
+	}
 	GH.totalRedraw();
 }
 
@@ -2219,11 +2221,11 @@ CBonusSelection::CBonusSelection( const CCampaign * _ourCampaign, int _whichMap
 
 	//campaign description
 	printAtLoc(CGI->generaltexth->allTexts[38], 481, 63, FONT_SMALL, tytulowy, background);
-
-	std::vector<std::string> *desc = CMessage::breakText(ourCampaign->header.description, 45);
-	for (int i=0; i<desc->size() ;i++)
-		printAtLoc((*desc)[i], 481, 86 + i*16, FONT_SMALL, zwykly, background);
-	delete desc;
+ 
+// 	std::vector<std::string> *desc = CMessage::breakText(ourCampaign->header.description, 45);
+// 	for (int i=0; i<desc->size() ;i++)
+// 		printAtLoc((*desc)[i], 481, 86 + i*16, FONT_SMALL, zwykly, background);
+// 	delete desc;
 
 	//set left part of window
 	for (int g=0; g<ourCampaign->scenarios.size(); ++g)
@@ -2354,10 +2356,10 @@ void CBonusSelection::show( SDL_Surface * to )
 	//map description
 	printAtLoc(CGI->generaltexth->allTexts[496], 481, 253, FONT_SMALL, tytulowy, to);
 
-	std::vector<std::string> *desc = CMessage::breakText(mapDesc, 45);
-	for (int i=0; i<desc->size(); i++)
-		printAtLoc((*desc)[i], 481, 281 + i*16, FONT_SMALL, zwykly, to);
-	delete desc;
+// 	std::vector<std::string> *desc = CMessage::breakText(mapDesc, 45);
+// 	for (int i=0; i<desc->size(); i++)
+// 		printAtLoc((*desc)[i], 481, 281 + i*16, FONT_SMALL, zwykly, to);
+// 	delete desc;
 
 	//map size icon
 	int temp;

+ 3 - 2
client/CPreGame.h

@@ -23,6 +23,7 @@ class CCampaignHeader;
 class CTextInput;
 class CCampaign;
 class CGStatusBar;
+class CTextBox;
 
 class CMapInfo
 {
@@ -86,6 +87,7 @@ class InfoCard : public CIntObject
 public:
 	CMenuScreen::EState type;
 
+	CTextBox *mapDescription;
 	CHighlightableButtonsGroup *difficulty;
 	CDefHandler *sizes, *sFlags;;
 
@@ -135,7 +137,6 @@ public:
 
 	void showAll(SDL_Surface * to);
 	void clickLeft(tribool down, bool previousState);
-	void wheelScrolled(bool down, bool in);
 	void keyPressed(const SDL_KeyboardEvent & key);
 	void onDoubleClick();
 	SelectionTab(CMenuScreen::EState Type, const boost::function<void(CMapInfo *)> &OnSelect, bool MultiPlayer=false);
@@ -201,10 +202,10 @@ public:
 
 class CSelectionScreen : public CIntObject
 {
+public:
 	CPicture *bg; //general bg image
 	InfoCard *card;
 	OptionsTab *opt;
-public:
 	AdventureMapButton *start, *back;
 
 	SelectionTab *sel;

+ 20 - 0
client/FontBase.h

@@ -15,5 +15,25 @@ enum EFonts
 {
 	FONT_BIG, FONT_CALLI, FONT_CREDITS, FONT_HIGH_SCORE, FONT_MEDIUM, FONT_SMALL, FONT_TIMES, FONT_TINY, FONT_VERD
 };
+
+struct Font
+{
+	struct Char
+	{
+		si32 unknown1, width, unknown2, offset;
+		unsigned char *pixels;
+	};
+
+	Char chars[256];
+	ui8 height;
+
+	unsigned char *data;
+
+
+	Font(unsigned char *Data);
+	~Font();
+	int getWidth(const char *text) const;
+	int getCharWidth(char c) const;
+};
 
 #endif

+ 116 - 43
client/GUIBase.cpp

@@ -522,56 +522,66 @@ void CIntObject::activate()
 {
 	assert(!active);
 	active |= GENERAL;
-	if(used & LCLICK)
+	activate(used);
+
+	if(defActions & ACTIVATE)
+		for(size_t i = 0; i < children.size(); i++)
+			if(children[i]->recActions & ACTIVATE)
+				children[i]->activate();
+}
+
+void CIntObject::activate(ui16 what)
+{
+	if(what & LCLICK)
 		activateLClick();
-	if(used & RCLICK)
+	if(what & RCLICK)
 		activateRClick();
-	if(used & HOVER)
+	if(what & HOVER)
 		activateHover();
-	if(used & MOVE)
+	if(what & MOVE)
 		activateMouseMove();
-	if(used & KEYBOARD)
+	if(what & KEYBOARD)
 		activateKeys();
-	if(used & TIME)
+	if(what & TIME)
 		activateTimer();
-	if(used & WHEEL)
+	if(what & WHEEL)
 		activateWheel();
-	if(used & DOUBLECLICK)
+	if(what & DOUBLECLICK)
 		activateDClick();
-
-	if(defActions & ACTIVATE)
-		for(size_t i = 0; i < children.size(); i++)
-			if(children[i]->recActions & ACTIVATE)
-				children[i]->activate();
 }
 
 void CIntObject::deactivate()
 {
 	assert(active);
 	active &= ~ GENERAL;
-	if(used & LCLICK)
+	deactivate(used);
+
+	assert(!active);
+
+	if(defActions & DEACTIVATE)
+		for(size_t i = 0; i < children.size(); i++)
+			if(children[i]->recActions & DEACTIVATE)
+				children[i]->deactivate();
+}
+
+void CIntObject::deactivate(ui16 what)
+{
+	if(what & LCLICK)
 		deactivateLClick();
-	if(used & RCLICK)
+	if(what & RCLICK)
 		deactivateRClick();
-	if(used & HOVER)
+	if(what & HOVER)
 		deactivateHover();
-	if(used & MOVE)
+	if(what & MOVE)
 		deactivateMouseMove();
-	if(used & KEYBOARD)
+	if(what & KEYBOARD)
 		deactivateKeys();
-	if(active & TIME)			// TIME is special
+	if(what & TIME)			// TIME is special
 		deactivateTimer();
-	if(used & WHEEL)
+	if(what & WHEEL)
 		deactivateWheel();
-	if(used & DOUBLECLICK)
+	if(what & DOUBLECLICK)
 		deactivateDClick();
-
-	assert(!active);
-
-	if(defActions & DEACTIVATE)
-		for(size_t i = 0; i < children.size(); i++)
-			if(children[i]->recActions & DEACTIVATE)
-				children[i]->deactivate();
 }
 
 CIntObject::~CIntObject()
@@ -684,18 +694,19 @@ void CIntObject::onDoubleClick()
 {
 }
 
-const Rect & CIntObject::center( const Rect &r )
+const Rect & CIntObject::center( const Rect &r, bool propagate )
 {
 	pos.w = r.w;
 	pos.h = r.h;
-	pos.x = screen->w/2 - r.w/2;
-	pos.y = screen->h/2 - r.h/2;
+	moveBy(Point(screen->w/2 - r.w/2 - pos.x, 
+				 screen->h/2 - r.h/2 - pos.y), 
+			propagate);
 	return pos;
 }
 
-const Rect & CIntObject::center()
+const Rect & CIntObject::center( bool propagate )
 {
-	return center(pos);
+	return center(pos, propagate);
 }
 
 void CIntObject::moveBy( const Point &p, bool propagate /*= true*/ )
@@ -718,8 +729,45 @@ void CIntObject::delChild(CIntObject *child)
 	delete child;
 }
 
+void CIntObject::addChild(CIntObject *child, bool adjustPosition /*= false*/)
+{
+	assert(!vstd::contains(children, child));
+	assert(child->parent == NULL);
+	children.push_back(child);
+	child->parent = this;
+	if(adjustPosition)
+		child->pos += pos;
+}
+
+void CIntObject::removeChild(CIntObject *child, bool adjustPosition /*= false*/)
+{
+	assert(vstd::contains(children, child));
+	assert(child->parent == this);
+	children -= child;
+	child->parent = NULL;
+	if(adjustPosition)
+		child->pos -= pos;
+}
+
+void CIntObject::changeUsedEvents(ui16 what, bool enable, bool adjust /*= true*/)
+{
+	if(enable)
+	{
+		used |= what;
+		if(adjust && active)
+			activate(what);
+	}
+	else
+	{
+		used &= ~what;
+		if(adjust && active)
+			deactivate(what);
+	}
+}
+
 CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
 {
+	init();
 	bg = BG; 
 	freeSurf = Free;
 	pos.x += x;
@@ -730,6 +778,7 @@ CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
 
 CPicture::CPicture( const std::string &bmpname, int x, int y )
 {
+	init();
 	bg = BitmapHandler::loadBitmap(bmpname); 
 	freeSurf = true;;
 	pos.x += x;
@@ -747,24 +796,53 @@ CPicture::CPicture( const std::string &bmpname, int x, int y )
 
 CPicture::CPicture(const Rect &r, const SDL_Color &color, bool screenFormat /*= false*/)
 {
+	init();
 	createSimpleRect(r, screenFormat, SDL_MapRGB(bg->format, color.r, color.g,color.b));
 }
 
 CPicture::CPicture(const Rect &r, ui32 color, bool screenFormat /*= false*/)
 {
+	init();
 	createSimpleRect(r, screenFormat, color);
 }
 
+CPicture::CPicture(SDL_Surface *BG, const Rect &SrcRect, int x /*= 0*/, int y /*= 0*/, bool free /*= false*/)
+{
+	srcRect = new Rect(SrcRect);
+	pos.x += x;
+	pos.y += y;
+	bg = BG;
+	freeSurf = free;
+}
+
 CPicture::~CPicture()
 {
 	if(freeSurf)
 		SDL_FreeSurface(bg);
+	delete srcRect;
+}
+
+void CPicture::init()
+{
+	srcRect = NULL;
 }
 
 void CPicture::showAll( SDL_Surface * to )
 {
 	if(bg)
-		blitAt(bg, pos, to);
+	{
+		if(srcRect)
+		{
+			SDL_Rect srcRectCpy = *srcRect;
+			SDL_Rect dstRect = srcRectCpy;
+			dstRect.x = pos.x;
+			dstRect.y = pos.y;
+
+			SDL_BlitSurface(bg, &srcRectCpy, to, &dstRect);
+		}
+		else
+			blitAt(bg, pos, to);
+	}
 }
 
 void CPicture::convertToScreenBPP()
@@ -786,6 +864,7 @@ void CPicture::createSimpleRect(const Rect &r, bool screenFormat, ui32 color)
 		bg = SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 8, 0, 0, 0, 0);
 
 	SDL_FillRect(bg, NULL, color);
+	freeSurf = true;
 }
 
 void CPicture::colorizeAndConvert(int player)
@@ -868,16 +947,10 @@ bool isArrowKey( SDLKey key )
 	return key >= SDLK_UP && key <= SDLK_LEFT;
 }
 
-CIntObject * moveChildren(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos)
+CIntObject * moveChild(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos)
 {
-	assert(vstd::contains(from->children, obj));
-	assert(obj->parent == from);
-	from->children -= obj;
-	to->children.push_back(obj);
-	obj->parent = to;
-	if(adjustPos)
-		obj->pos -= from->pos - to->pos;
-
+	from->removeChild(obj, adjustPos);
+	to->addChild(obj, adjustPos);
 	return obj;
 }
 Rect Rect::createCentered( int w, int h )

+ 30 - 13
client/GUIBase.h

@@ -213,7 +213,7 @@ struct Rect : public SDL_Rect
 	}
 	template<typename T> Rect operator-(const T &t)
 	{
-		return Rect(x + t.x, y + t.y, w, h);
+		return Rect(x - t.x, y - t.y, w, h);
 	}
 	Rect operator&(const Rect &p) const //rect intersection
 	{
@@ -376,6 +376,8 @@ public:
 	void defDeactivate();
 	void activate();
 	void deactivate();
+	void activate(ui16 what);
+	void deactivate(ui16 what);
 	void show(SDL_Surface * to);
 	void showAll(SDL_Surface * to);
 
@@ -388,12 +390,26 @@ public:
 	void blitAtLoc(SDL_Surface * src, const Point &p, SDL_Surface * dst);
 	bool isItInLoc(const SDL_Rect &rect, int x, int y);
 	bool isItInLoc(const SDL_Rect &rect, const Point &p);
-	const Rect & center(const Rect &r); //sets pos so that r will be in the center of screen, returns new position
-	const Rect & center(); //centers when pos.w and pos.h are set, returns new position
+	const Rect & center(const Rect &r, bool propagate = true); //sets pos so that r will be in the center of screen, returns new position
+	const Rect & center(bool propagate = true); //centers when pos.w and pos.h are set, returns new position
 	void moveBy(const Point &p, bool propagate = true);
 	void moveTo(const Point &p, bool propagate = true);
+	void changeUsedEvents(ui16 what, bool enable, bool adjust = true);
 
-	void delChild(CIntObject *child); //removes from chidlren list, deletes
+	void addChild(CIntObject *child, bool adjustPosition = false);
+	void removeChild(CIntObject *child, bool adjustPosition = false);
+	void delChild(CIntObject *child); //removes from children list, deletes
+	template <typename T> void delChildNUll(T *&child, bool deactivateIfNeeded = false) //removes from children list, deletes and sets pointer to NULL
+	{
+		if(!child)
+			return;
+
+		if(deactivateIfNeeded && child->active)
+			child->deactivate();
+
+		delChild(child);
+		child = NULL;
+	}
 };
 
 //class for binding keys to left mouse button clicks
@@ -419,29 +435,29 @@ class CSimpleWindow : public CIntObject
 {
 public:
 	SDL_Surface * bitmap; //background
-	CIntObject * owner; //who made this window
 	virtual void show(SDL_Surface * to);
-	CSimpleWindow():bitmap(NULL),owner(NULL){}; //c-tor
+	CSimpleWindow():bitmap(NULL){}; //c-tor
 	virtual ~CSimpleWindow(); //d-tor
-	void activate(){};
-	void deactivate(){};
 };
 
 class CPicture : public CIntObject
 {
 public: 
 	SDL_Surface *bg;
-	bool freeSurf;
+	Rect *srcRect; //if NULL then whole surface will be used
+	bool freeSurf; //whether surface will be freed upon CPicture destruction
 
 	operator SDL_Surface*()
 	{
 		return bg;
 	}
 
-	CPicture(const Rect &r, const SDL_Color &color, bool screenFormat = false);
-	CPicture(const Rect &r, ui32 color, bool screenFormat = false);
-	CPicture(SDL_Surface *BG, int x, int y, bool Free = true);
+	CPicture(const Rect &r, const SDL_Color &color, bool screenFormat = false); //rect filled with given color
+	CPicture(const Rect &r, ui32 color, bool screenFormat = false); //rect filled with given color
+	CPicture(SDL_Surface *BG, int x, int y, bool Free = true); //wrap existing SDL_Surface
 	CPicture(const std::string &bmpname, int x=0, int y=0);
+	CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface
+	void init();
 
 	void createSimpleRect(const Rect &r, bool screenFormat, ui32 color);
 	~CPicture();
@@ -504,7 +520,7 @@ SDLKey arrowToNum(SDLKey key); //converts arrow key to according numpad key
 SDLKey numToDigit(SDLKey key);//converts numpad digit key to normal digit key
 bool isNumKey(SDLKey key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits)
 bool isArrowKey(SDLKey key); 
-CIntObject *  moveChildren(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos = false);
+CIntObject *  moveChild(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos = false);
 
 template <typename T> void pushIntT()
 {
@@ -529,5 +545,6 @@ struct SetCaptureState
 #define OBJ_CONSTRUCTION ObjectConstruction obj__i(this)
 #define OBJ_CONSTRUCTION_CAPTURING_ALL defActions = 255; SetCaptureState obj__i1(true, 255); ObjectConstruction obj__i(this)
 #define BLOCK_CAPTURING SetCaptureState obj__i(false, 0)
+#define BLOCK_CAPTURING_DONT_TOUCH_REC_ACTIONS SetCaptureState obj__i(false, GH.defActionsDef)
 
 #endif //__GUIBASE_H__

+ 122 - 51
client/GUIClasses.cpp

@@ -612,9 +612,9 @@ void CGarrisonInt::deactivate()
 		splitButtons[i]->deactivate();
 }
 
-CInfoWindow::CInfoWindow(std::string text, int player, int charperline, const std::vector<SComponent*> &comps, std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, bool delComps)
+CInfoWindow::CInfoWindow(std::string Text, int player, int charperline, const std::vector<SComponent*> &comps, std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, bool delComps)
 {
-	slider = NULL;
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	ID = -1;
 	this->delComps = delComps;
 	for(int i=0;i<Buttons.size();i++)
@@ -623,19 +623,26 @@ CInfoWindow::CInfoWindow(std::string text, int player, int charperline, const st
 		buttons[i]->callback.add(Buttons[i].second); //each button will close the window apart from call-defined actions
 	}
 
+	text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, zwykly);
+	text->redrawParentOnScrolling = true;
+
 	buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
 	buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
 
 	for(int i=0;i<comps.size();i++)
 	{
+		comps[i]->recActions = 0xff;
+		addChild(comps[i]);
 		components.push_back(comps[i]);
 	}
-	CMessage::drawIWindow(this,text,player,charperline);
+	CMessage::drawIWindow(this,Text,player,charperline);
 }
+
 CInfoWindow::CInfoWindow() 
 {
 	ID = -1;
 	delComps = false;
+	text = NULL;
 }
 void CInfoWindow::close()
 {
@@ -645,54 +652,22 @@ void CInfoWindow::close()
 }
 void CInfoWindow::show(SDL_Surface * to)
 {
-	CSimpleWindow::show(to);
-	for(int i=0;i<buttons.size();i++)
-		buttons[i]->show(to);
-	if (slider)
-		slider->show(to);
+	CIntObject::show(to);
 }
 
 CInfoWindow::~CInfoWindow()
 {
-	if(delComps)
-	{
-		for (int i=0;i<components.size();i++)
-			delete components[i];
-	}
-	for(int i=0;i<buttons.size();i++)
-		delete buttons[i];
-	if (slider)
-		delete slider;
-}
-void CInfoWindow::activate()
-{
-	for (int i=0;i<components.size();i++)
-		components[i]->activate();
-	for(int i=0;i<buttons.size();i++)
-		buttons[i]->activate();
-	if (slider)
-		slider->activate();
-}
-void CInfoWindow::sliderMoved(int to)
-{
-	/*slider->moveTo(to);
-		if(!slider) return; //ignore spurious call when slider is being created
-	*/
-	redraw();
-}
-void CInfoWindow::deactivate()
-{
-	for (int i=0;i<components.size();i++)
-		components[i]->deactivate();
-	for(int i=0;i<buttons.size();i++)
-		buttons[i]->deactivate();
-	if (slider)
-		slider->deactivate();
+// 	if(delComps)
+// 	{
+// 		for (int i=0;i<components.size();i++)
+// 			delete components[i];
+// 	}
 }
 
 void CInfoWindow::showAll( SDL_Surface * to )
 {
-	show(to);
+	CSimpleWindow::show(to);
+	CIntObject::showAll(to);
 }
 
 void CInfoWindow::showYesNoDialog(const std::string & text, const std::vector<SComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps, int player)
@@ -1088,7 +1063,8 @@ void CSelectableComponent::show(SDL_Surface * to)
 }
 void CSimpleWindow::show(SDL_Surface * to)
 {
-	blitAt(bitmap,pos.x,pos.y,to);
+	if(bitmap)
+		blitAt(bitmap,pos.x,pos.y,to);
 }
 CSimpleWindow::~CSimpleWindow()
 {
@@ -1129,6 +1105,8 @@ CSelWindow::CSelWindow(const std::string &text, int player, int charperline, con
 
 	for(int i=0;i<comps.size();i++)
 	{
+		comps[i]->recActions = 255;
+		addChild(comps[i]);
 		components.push_back(comps[i]);
 		comps[i]->onSelect = boost::bind(&CSelWindow::selectionChange,this,i);
 		if(i<9)
@@ -2932,8 +2910,11 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan
 	if(printButtonFor(RESOURCE_RESOURCE))
 		new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_RESOURCE), 516, 450,"TPMRKBU5.DEF");
 	if(printButtonFor(CREATURE_RESOURCE))
-		new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, CREATURE_RESOURCE), 516, 450,"TPMRKBU4.DEF");
-
+		new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, CREATURE_RESOURCE), 516, 485,"TPMRKBU4.DEF"); //was y=450, changed to not overlap res-res in some conditions
+	if(printButtonFor(RESOURCE_ARTIFACT))
+		new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_ARTIFACT), 18, 450,"TPMRKBU2.DEF");
+	if(printButtonFor(ARTIFACT_RESOURCE))																				//unblock when support for art-res is ready
+		(new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_ARTIFACT), 18, 485,"TPMRKBU3.DEF"))->block(true); //was y=450, changed to not overlap res-res in some conditions
 
 }
 
@@ -3212,7 +3193,7 @@ void CMarketplaceWindow::setMode(EMarketMode Mode)
 
 bool CMarketplaceWindow::printButtonFor(EMarketMode M) const
 {
-	return market->allowsTrade(M) && M != mode && (hero || mode != CREATURE_RESOURCE);
+	return market->allowsTrade(M) && M != mode && (hero || mode != CREATURE_RESOURCE && mode != RESOURCE_ARTIFACT && mode != ARTIFACT_RESOURCE);
 }
 
 void CMarketplaceWindow::garrisonChanged()
@@ -5577,11 +5558,19 @@ void MoraleLuckBox::set(bool morale, const CGHeroInstance *hero)
 void CLabel::showAll(SDL_Surface * to)
 {
 	CIntObject::showAll(to);
-	if(!text.length())
+	std::string *hlpText = NULL;  //if NULL, text field will be used
+	if(ignoreLeadingWhitespace)
+	{
+		hlpText = new std::string(text);
+		boost::trim_left(*hlpText);
+	}
+
+	std::string &toPrint = hlpText ? *hlpText : text;
+	if(!toPrint.length())
 		return;
 
 	static void (*printer[3])(const std::string &, int, int, EFonts, SDL_Color, SDL_Surface *, bool) = {&CSDL_Ext::printAt, &CSDL_Ext::printAtMiddle, &CSDL_Ext::printTo}; //array of printing functions
-	printer[alignment](text, pos.x + textOffset.x, pos.y + textOffset.y, font, color, to, false);
+	printer[alignment](toPrint, pos.x + textOffset.x, pos.y + textOffset.y, font, color, to, false);
 }
 
 CLabel::CLabel(int x, int y, EFonts Font /*= FONT_SMALL*/, EAlignment Align, const SDL_Color &Color /*= zwykly*/, const std::string &Text /*= ""*/)
@@ -5606,6 +5595,88 @@ void CLabel::setTxt(const std::string &Txt)
 	}
 }
 
+CTextBox::CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= TOPLEFT*/, const SDL_Color &Color /*= zwykly*/)
+	:CLabel(rect.x, rect.y, Font, Align, Color, Text), slider(NULL), sliderStyle(SliderStyle)
+{
+	redrawParentOnScrolling = false;
+	autoRedraw = false;
+	pos.h = rect.h;
+	pos.w = rect.w;
+	assert(Align == TOPLEFT || Align == CENTER); //TODO: support for other alignments
+	assert(pos.w >= 80); //we need some space
+	setTxt(Text);
+}
+
+void CTextBox::showAll(SDL_Surface * to)
+{
+	CIntObject::showAll(to);
+
+	const Font &f = *graphics->fonts[font];
+	int dy = f.height; //line height
+	int base_y = pos.y;
+	if(alignment == CENTER)
+		base_y += (pos.h - maxH)/2;
+
+	int howManyLinesToPrint = slider ? slider->capacity : lines.size();
+	int firstLineToPrint = slider ? slider->value : 0;
+
+	for (int i = 0; i < howManyLinesToPrint; i++)
+	{
+		const std::string &line = lines[i + firstLineToPrint];
+		int x = pos.x;
+		if(alignment == CENTER)
+			x += (pos.w - f.getWidth(line.c_str())) / 2;
+
+		printAt(line, pos.x, base_y + i*dy, font, color, to);
+	}
+
+}
+
+void CTextBox::setTxt(const std::string &Txt)
+{
+	recalculateLines(Txt);
+	CLabel::setTxt(Txt);
+}
+
+void CTextBox::sliderMoved(int to)
+{
+	if(redrawParentOnScrolling)
+		parent->redraw();
+	redraw();
+}
+
+void CTextBox::setBounds(int limitW, int limitH)
+{
+	pos.h = limitH;
+	pos.w = limitW;
+	recalculateLines(text);
+}
+
+void CTextBox::recalculateLines(const std::string &Txt)
+{
+	delChildNUll(slider, true);
+	lines.clear();
+
+	const Font &f = *graphics->fonts[font];
+	int lineHeight =  f.height; 
+	int lineCapacity = pos.h / lineHeight;
+
+	lines = CMessage::breakText(Txt, pos.w, font);
+	if(lines.size() > lineCapacity) //we need to add a slider
+	{
+		lines = CMessage::breakText(Txt, pos.w - 32 - 10, font);
+		OBJ_CONSTRUCTION_CAPTURING_ALL;
+		slider = new CSlider(pos.w - 32, 0, pos.h, boost::bind(&CTextBox::sliderMoved, this, _1), lineCapacity, lines.size(), 0, false, sliderStyle);
+		if(active)
+			slider->activate();
+	}
+
+	maxH = lineHeight * lines.size();
+	maxW = 0;
+	BOOST_FOREACH(const std::string &line, lines)
+		amax(maxW, f.getWidth(line.c_str()));
+}
+
 void CGStatusBar::print(const std::string & Text)
 {
 	setTxt(Text);
@@ -5632,7 +5703,7 @@ CGStatusBar::CGStatusBar(CPicture *BG, EFonts Font /*= FONT_SMALL*/, EAlignment
 {
 	init();
 	bg = BG;
-	moveChildren(bg, bg->parent, this);
+	moveChild(bg, bg->parent, this);
 	pos = bg->pos;
 
 	switch(Align)
@@ -5782,4 +5853,4 @@ void CFocusable::moveFocus()
 			break;;
 		}
 	}
-}
+}

+ 32 - 8
client/GUIClasses.h

@@ -66,23 +66,22 @@ struct SPuzzleInfo;
 class CGGarrison;
 class CStackInstance;
 class IMarket;
+class CTextBox;
 
 extern SDL_Color tytulowy, tlo, zwykly ;
 
 class CInfoWindow : public CSimpleWindow //text + comp. + ok button
 { //window able to delete its components when closed
 public:
-	bool delComps; //whether comps will be deleted
+	CTextBox *text;
 	std::vector<AdventureMapButton *> buttons;
+	bool delComps; //whether comps will be deleted
 	std::vector<SComponent*> components;
-	CSlider *slider;
+
 	virtual void close();
 	void show(SDL_Surface * to);
 	void showAll(SDL_Surface * to);
-	void activate();
-	void sliderMoved(int to);
-	void deactivate();
-	CInfoWindow(std::string text, int player, int charperline, const std::vector<SComponent*> &comps, std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, bool delComps); //c-tor
+	CInfoWindow(std::string Text, int player, int charperline, const std::vector<SComponent*> &comps, std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, bool delComps); //c-tor
 	CInfoWindow(); //c-tor
 	~CInfoWindow(); //d-tor
 
@@ -282,14 +281,39 @@ public:
 	SDL_Color color;
 	std::string text;
 	CPicture *bg;
-	bool autoRedraw;
+	bool autoRedraw;  //whether control will redraw itself on setTxt
 	Point textOffset; //text will be blitted at pos + textOffset with appropriate alignment
+	bool ignoreLeadingWhitespace; 
 
-	void setTxt(const std::string &Txt);
+	virtual void setTxt(const std::string &Txt);
 	void showAll(SDL_Surface * to); //shows statusbar (with current text)
 	CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = zwykly, const std::string &Text =  "");
 };
 
+//a multi-line label that tries to fit text with given available width and height; if not possible, it creates a slider for scrolling text
+class CTextBox
+	: public CLabel
+{
+public:
+	int maxW; //longest line of text in px
+	int maxH; //total height needed to print all lines
+
+	int sliderStyle;
+	bool redrawParentOnScrolling;
+
+	std::vector<std::string> lines;
+	CSlider *slider;
+
+	//CTextBox( std::string Text, const Point &Pos, int w, int h, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = zwykly);
+	CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = zwykly);
+	void showAll(SDL_Surface * to); //shows statusbar (with current text)
+	void setTxt(const std::string &Txt);
+	void setBounds(int limitW, int limitH);
+	void recalculateLines(const std::string &Txt);
+
+	void sliderMoved(int to);
+};
+
 class CGStatusBar
 	: public CLabel, public IStatusBar
 {

+ 7 - 0
client/Graphics.cpp

@@ -713,6 +713,13 @@ int Font::getWidth(const char *text ) const
 
 	return ret;
 }
+
+int Font::getCharWidth( char c ) const
+{
+	const Char &C = chars[(unsigned char)c];
+	return C.width + C.unknown1 + C.unknown2;;
+}
+
 /*
 void Font::WriteAt(const char *text, SDL_Surface *sur, int x, int y )
 {

+ 0 - 19
client/Graphics.h

@@ -25,25 +25,6 @@ struct SDL_Color;
 struct InfoAboutHero;
 struct InfoAboutTown;
 
-struct Font
-{
-	struct Char
-	{
-		si32 unknown1, width, unknown2, offset;
-		unsigned char *pixels;
-	};
-
-	Char chars[256];
-	ui8 height;
-
-	unsigned char *data;
-
-
-	Font(unsigned char *Data);
-	~Font();
-	int getWidth(const char *text) const;
-};
-
 class Graphics
 {
 public:

+ 13 - 17
client/SDL_Extensions.cpp

@@ -80,12 +80,12 @@ void updateRect (SDL_Rect * rect, SDL_Surface * scr)
 
 void printAtMiddleWB(const std::string & text, int x, int y, TTF_Font * font, int charpr, SDL_Color kolor, SDL_Surface * dst)
 {
-	std::vector<std::string> * ws = CMessage::breakText(text,charpr);
+	std::vector<std::string> ws = CMessage::breakText(text,charpr);
 	std::vector<SDL_Surface*> wesu;
-	wesu.resize(ws->size());
+	wesu.resize(ws.size());
 	for (size_t i=0; i < wesu.size(); ++i)
 	{
-		wesu[i]=TTF_RenderText_Blended(font,(*ws)[i].c_str(),kolor);
+		wesu[i]=TTF_RenderText_Blended(font,ws[i].c_str(),kolor);
 	}
 
 	int tox=0, toy=0;
@@ -106,16 +106,15 @@ void printAtMiddleWB(const std::string & text, int x, int y, TTF_Font * font, in
 
 	for (size_t i=0; i < wesu.size(); ++i)
 		SDL_FreeSurface(wesu[i]);
-	delete ws;
 }
 
 void printAtWB(const std::string & text, int x, int y, TTF_Font * font, int charpr, SDL_Color kolor, SDL_Surface * dst)
 {
-	std::vector<std::string> * ws = CMessage::breakText(text,charpr);
+	std::vector<std::string> ws = CMessage::breakText(text,charpr);
 	std::vector<SDL_Surface*> wesu;
-	wesu.resize(ws->size());
+	wesu.resize(ws.size());
 	for (size_t i=0; i < wesu.size(); ++i)
-		wesu[i]=TTF_RenderText_Blended(font,(*ws)[i].c_str(),kolor);
+		wesu[i]=TTF_RenderText_Blended(font,ws[i].c_str(),kolor);
 
 	int evy = y;
 	for (size_t i=0; i < wesu.size(); ++i)
@@ -126,7 +125,6 @@ void printAtWB(const std::string & text, int x, int y, TTF_Font * font, int char
 
 	for (size_t i=0; i < wesu.size(); ++i)
 		SDL_FreeSurface(wesu[i]);
-	delete ws;
 }
 
 void CSDL_Ext::printAtWB(const std::string & text, int x, int y, EFonts font, int charpr, SDL_Color kolor, SDL_Surface * dst, bool refresh)
@@ -137,15 +135,14 @@ void CSDL_Ext::printAtWB(const std::string & text, int x, int y, EFonts font, in
 		return;
 	}
 	const Font *f = graphics->fonts[font];
-	std::vector<std::string> * ws = CMessage::breakText(text,charpr);
+	std::vector<std::string> ws = CMessage::breakText(text,charpr);
 
 	int cury = y;
-	for (size_t i=0; i < ws->size(); ++i)
+	for (size_t i=0; i < ws.size(); ++i)
 	{
-		printAt((*ws)[i], x, cury, font, kolor, dst, refresh);
+		printAt(ws[i], x, cury, font, kolor, dst, refresh);
 		cury += f->height;
 	}
-	delete ws;
 }
 
 
@@ -158,16 +155,15 @@ void CSDL_Ext::printAtMiddleWB( const std::string & text, int x, int y, EFonts f
 	}
 
 	const Font *f = graphics->fonts[font];
-	std::vector<std::string> * ws = CMessage::breakText(text,charpr);
-	int totalHeight = ws->size() * f->height;
+	std::vector<std::string> ws = CMessage::breakText(text,charpr);
+	int totalHeight = ws.size() * f->height;
 
 	int cury = y - totalHeight/2;
-	for (size_t i=0; i < ws->size(); ++i)
+	for (size_t i=0; i < ws.size(); ++i)
 	{
-		printAt((*ws)[i], x - f->getWidth((*ws)[i].c_str())/2, cury, font, kolor, dst, refrsh);
+		printAt(ws[i], x - f->getWidth(ws[i].c_str())/2, cury, font, kolor, dst, refrsh);
 		cury += f->height;
 	}
-	delete ws;
 }
 
 void printAtMiddle(const std::string & text, int x, int y, TTF_Font * font, SDL_Color kolor, SDL_Surface * dst, unsigned char quality=2, bool refresh=false)

+ 5 - 1
hch/CObjectHandler.cpp

@@ -5459,7 +5459,7 @@ void CGPyramid::endBattle (const CGHeroInstance *h, const BattleResult *result)
 void CGKeys::setPropertyDer (ui8 what, ui32 val) //101-108 - enable key for player 1-8
 {
 	if (what >= 101 && what <= (100 + PLAYER_LIMIT))
-		playerKeyMap.find(what-101)->second.insert(val);
+		playerKeyMap.find(what-101)->second.insert((ui8)val);
 }
 
 bool CGKeys::wasMyColorVisited (int player) const
@@ -6222,6 +6222,7 @@ const IMarket * IMarket::castFrom(const CGObjectInstance *obj)
 	{
 	case TOWNI_TYPE:
 		return static_cast<const CGTownInstance*>(obj);
+	case 2: //Altar of Sacrifice
 	case 7: //Black Market
 	case 99: //Trading Post
 	case 221: //Trading Post (snow)
@@ -6282,6 +6283,9 @@ bool CGMarket::allowsTrade(EMarketMode mode) const
 	case ARTIFACT_RESOURCE:
 	case RESOURCE_ARTIFACT:
 		return ID == 7; //Black Market
+	case ARTIFACT_EXP:
+	case CREATURE_EXP:
+		return ID == 2; //TODO? check here for alignment of visiting hero? - would not be coherent with other checks here
 	}
 	return false;
 }

+ 20 - 18
lib/CGameState.cpp

@@ -1444,24 +1444,26 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 			}
 		case bartifact:
 			{
-				if(!k->second.heroes.size())
-				{
-					tlog5 << "Cannot give starting artifact - no heroes!" << std::endl;
-					break;
-				}
-				CArtifact *toGive;
-				do 
-				{
-					toGive = VLC->arth->treasures[ran() % VLC->arth->treasures.size()];
-				} while (!map->allowedArtifact[toGive->id]);
-				CGHeroInstance *hero = k->second.heroes[0];
-				std::vector<ui16>::iterator slot = vstd::findFirstNot(hero->artifWorn,toGive->possibleSlots);
-				if(slot!=toGive->possibleSlots.end())
-				{
-					VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive->id, &hero->bonuses);
-				}
-				else
-					hero->giveArtifact(toGive->id);
+				//TODO: FIX IT!
+
+// 				if(!k->second.heroes.size())
+// 				{
+// 					tlog5 << "Cannot give starting artifact - no heroes!" << std::endl;
+// 					break;
+// 				}
+// 				CArtifact *toGive;
+// 				do 
+// 				{
+// 					toGive = VLC->arth->treasures[ran() % VLC->arth->treasures.size()];
+// 				} while (!map->allowedArtifact[toGive->id]);
+// 				CGHeroInstance *hero = k->second.heroes[0];
+// 				std::vector<ui16>::iterator slot = vstd::findFirstNot(hero->artifWorn,toGive->possibleSlots);
+// 				if(slot!=toGive->possibleSlots.end())
+// 				{
+// 					VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive->id, &hero->bonuses);
+// 				}
+// 				else
+// 					hero->giveArtifact(toGive->id);
 			}
 		}
 	}

+ 1 - 1
lib/map.cpp

@@ -1953,7 +1953,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
 				nobj->tempOwner = readNormalNr(bufor,i); i+=4;
 				break;
 			}
-		//case 2: //Altar of Sacrifice
+		case 2: //Altar of Sacrifice
 		case 99: //Trading Post
 		case 213: //Freelancer's Guild
 		case 221: //Trading Post (snow)