2
0
Эх сурвалжийг харах

- fixed several crashes with joining creatures
- support for loading *.tga images
- minor fixes

Ivan Savenko 14 жил өмнө
parent
commit
0693312a8e

+ 1 - 16
client/CAnimation.cpp

@@ -577,22 +577,7 @@ SDLImage::SDLImage(SDL_Surface * from, bool extraRef):
 SDLImage::SDLImage(std::string filename, bool compressed):
 	margins(0,0)
 {
-	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
-	{
-		surf = NULL;
-	}
+	surf = BitmapHandler::loadBitmap(filename);
 
 	if (surf == NULL)
 	{

+ 37 - 14
client/CBitmapHandler.cpp

@@ -17,10 +17,9 @@
  *
  */
 
-boost::mutex bitmap_handler_mx;
-
 extern DLL_EXPORT CLodHandler *bitmaph;
 extern DLL_EXPORT CLodHandler *bitmaph_ab;
+extern DLL_EXPORT CLodHandler *spriteh;
 
 void CPCXConv::openPCX(char * PCX, int len)
 {
@@ -53,7 +52,7 @@ SDL_Surface * CPCXConv::getSurface() const
 
 	int width = -1, height = -1;
 	Epcxformat format;
-	int fSize,y;//,i; //TODO use me 'i'
+	int fSize,y;
 	bool check1, check2;
 	unsigned char add;
 	int it=0;
@@ -149,26 +148,23 @@ bool isPCX(const unsigned char *header)//check whether file can be PCX according
 	return fSize == width*height || fSize == width*height*3;
 }
 
-SDL_Surface * BitmapHandler::loadBitmap(std::string fname, bool setKey)
+SDL_Surface * BitmapHandler::loadBitmapFromLod(CLodHandler *lod, std::string fname, bool setKey)
 {
 	if(!fname.size())
 	{
 		tlog2 << "Call to loadBitmap with void fname!\n";
 		return NULL;
 	}
-	SDL_Surface * ret=NULL;
-	int size;
-	unsigned char * file = 0;
-	if (bitmaph->haveFile(fname, FILE_GRAPHICS))
-		file = bitmaph->giveFile(fname, FILE_GRAPHICS, &size);
-	else if (bitmaph_ab->haveFile(fname, FILE_GRAPHICS))
-		file = bitmaph_ab->giveFile(fname, FILE_GRAPHICS, &size);
-
-	if (!file)
+	if (!lod->haveFile(fname, FILE_GRAPHICS))
 	{
 		tlog2<<"Entry for file "<<fname<<" was not found"<<std::endl;
 		return NULL;
 	}
+
+	SDL_Surface * ret=NULL;
+	int size;
+	unsigned char * file = 0;
+	file = lod->giveFile(fname, FILE_GRAPHICS, &size);
 	
 	if (isPCX(file))
 	{//H3-style PCX
@@ -185,10 +181,37 @@ SDL_Surface * BitmapHandler::loadBitmap(std::string fname, bool setKey)
 	}
 	else
 	{ //loading via SDL_Image
-		ret = IMG_Load_RW( SDL_RWFromMem((void*)file, size), 1);
+		std::string filename = lod->getFileName(fname, FILE_GRAPHICS);
+		std::string ext;
+		lod->convertName(filename, &ext);
+
+		if (ext == ".TGA")//Special case - targa can't be loaded by IMG_Load_RW (no magic constants in header)
+		{
+			SDL_RWops *rw = SDL_RWFromMem((void*)file, size);
+			ret = IMG_LoadTGA_RW( rw );
+			SDL_FreeRW(rw);
+		}
+		else
+			ret = IMG_Load_RW( SDL_RWFromMem((void*)file, size), 1);
+
 		if (!ret)
 			tlog1<<"Failed to open "<<fname<<" via SDL_Image\n";
 		delete [] file;
 	}
 	return ret;
 }
+
+SDL_Surface * BitmapHandler::loadBitmap(std::string fname, bool setKey)
+{
+	if (bitmaph->haveFile(fname, FILE_GRAPHICS))
+		return loadBitmapFromLod(bitmaph, fname, setKey);
+
+	if (bitmaph_ab->haveFile(fname, FILE_GRAPHICS))
+		return loadBitmapFromLod(bitmaph_ab, fname, setKey);
+
+	if (spriteh->haveFile(fname, FILE_GRAPHICS))
+		return loadBitmapFromLod(spriteh, fname, setKey);
+	
+	tlog1<<"Failed to find file "<<fname<<"\n";
+	return NULL;
+}

+ 3 - 0
client/CBitmapHandler.h

@@ -47,6 +47,9 @@ public:
 
 namespace BitmapHandler
 {
+	//Load file from specific LOD
+	SDL_Surface * loadBitmapFromLod(CLodHandler *lod, std::string fname, bool setKey=true);
+	//Load file from any LODs
 	SDL_Surface * loadBitmap(std::string fname, bool setKey=true);
 };
 

+ 128 - 79
client/CCastleInterface.cpp

@@ -1032,25 +1032,25 @@ void CCastleInterface::recreateIcons()
 	creainfo.clear();
 
 	for (size_t i=0; i<4; i++)
-		creainfo.push_back(new CCreaInfo(14+55*i, 459, town, i));
+		creainfo.push_back(new CCreaInfo(Point(14+55*i, 459), town, i));
 
 	for (size_t i=0; i<4; i++)
-		creainfo.push_back(new CCreaInfo(14+55*i, 507, town, i+4));
+		creainfo.push_back(new CCreaInfo(Point(14+55*i, 507), town, i+4));
 }
 
-CCreaInfo::CCreaInfo(int posX, int posY, const CGTownInstance *Town, int Level):
+CCreaInfo::CCreaInfo(Point position, const CGTownInstance *Town, int Level, bool compact, bool ShowAvailable):
 	town(Town),
-	level(Level)
+	level(Level),
+	showAvailable(ShowAvailable)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	pos.x += posX;
-	pos.y += posY;
-	pos.w = 48;
-	pos.h = 48;
+	pos += position;
 	
 	if ( town->creatures.size() <= level || town->creatures[level].second.empty())
 	{
 		level = -1;
+		label = NULL;
+		picture = NULL;
 		return;//No creature
 	}
 	used = LCLICK | RCLICK | HOVER;
@@ -1058,8 +1058,42 @@ CCreaInfo::CCreaInfo(int posX, int posY, const CGTownInstance *Town, int Level):
 	unsigned int creatureID = town->creatures[level].second.back();
 	creature = CGI->creh->creatures[creatureID];
 
-	label = new CLabel(24, 40, FONT_SMALL, CENTER, zwykly, boost::lexical_cast<std::string>(town->creatureGrowth(level)));
 	picture = new CAnimImage("CPRSMALL", creatureID+2, 0, 8, 0);
+
+	std::string value;
+	if (showAvailable)
+		value = boost::lexical_cast<std::string>(town->creatures[level].first);
+	else
+		value = boost::lexical_cast<std::string>(town->creatureGrowth(level));
+
+	if (compact)
+	{
+		label = new CLabel(40, 32, FONT_TINY, BOTTOMRIGHT, zwykly, value);
+		pos.x += 8;
+		pos.w = 32;
+		pos.h = 32;
+	}
+	else
+	{
+		label = new CLabel(24, 40, FONT_SMALL, CENTER, zwykly, value);
+		pos.w = 48;
+		pos.h = 48;
+	}
+}
+
+void CCreaInfo::update()
+{
+	if (label)
+	{
+		std::string value;
+		if (showAvailable)
+			value = boost::lexical_cast<std::string>(town->creatures[level].first);
+		else
+			value = boost::lexical_cast<std::string>(town->creatureGrowth(level));
+
+		if (value != label->text)
+			label->setTxt(value);
+	}
 }
 
 void CCreaInfo::hover(bool on)
@@ -1076,9 +1110,14 @@ void CCreaInfo::hover(bool on)
 }
 
 void CCreaInfo::clickLeft(tribool down, bool previousState)
-{//FIXME: castleInt should be present - may be NULL if no castle window opened
-	if(previousState && (!down) && LOCPLINT->castleInt)
-		LOCPLINT->castleInt->builds->enterDwelling(level);
+{
+	if(previousState && (!down))
+	{
+		int offset = LOCPLINT->castleInt? (-87) : 0;
+
+		GH.pushInt(new CRecruitmentWindow(town, level, town, 
+		           boost::bind(&CCallback::recruitCreatures, LOCPLINT->cb, town, _1, _2, level), offset));
+	}
 }
 
 int CCreaInfo::AddToString(std::string from, std::string & to, int numb)
@@ -1090,88 +1129,98 @@ int CCreaInfo::AddToString(std::string from, std::string & to, int numb)
 	return numb;
 }
 
-void CCreaInfo::clickRight(tribool down, bool previousState)
+std::string CCreaInfo::genGrowthText()
 {
-	if(down)
-	{
-		int summ=0;
-		std::string descr=CGI->generaltexth->allTexts[589];//Growth of creature is number
-		boost::algorithm::replace_first(descr,"%s", creature->nameSing);
-		boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(town->creatureGrowth(level)));
+	int summ=0;
+	std::string descr=CGI->generaltexth->allTexts[589];//Growth of creature is number
+	boost::algorithm::replace_first(descr,"%s", creature->nameSing);
+	boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(town->creatureGrowth(level)));
 
-		descr +="\n"+CGI->generaltexth->allTexts[590];
-		summ = creature->growth;
-		boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(summ));
+	descr +="\n"+CGI->generaltexth->allTexts[590];
+	summ = creature->growth;
+	boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(summ));
 
-		if ( level>=0 && level<CREATURES_PER_TOWN)
-		{
+	if ( level>=0 && level<CREATURES_PER_TOWN)
+	{
 
-			if ( vstd::contains(town->builtBuildings, Buildings::CASTLE))
-				summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::CASTLE]->Name()+" %+d",descr,summ);
-			else if ( vstd::contains(town->builtBuildings, Buildings::CITADEL))
-				summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::CITADEL]->Name()+" %+d",descr,summ/2);
+		if ( vstd::contains(town->builtBuildings, Buildings::CASTLE))
+			summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::CASTLE]->Name()+" %+d",descr,summ);
+		else if ( vstd::contains(town->builtBuildings, Buildings::CITADEL))
+			summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::CITADEL]->Name()+" %+d",descr,summ/2);
 
-			summ+=AddToString(CGI->generaltexth->allTexts[63] + " %+d",descr, //double growth or plague
-				summ * creature->valOfBonuses(Bonus::CREATURE_GROWTH_PERCENT)/100);
+		summ+=AddToString(CGI->generaltexth->allTexts[63] + " %+d",descr, //double growth or plague
+			summ * creature->valOfBonuses(Bonus::CREATURE_GROWTH_PERCENT)/100);
 
-			summ+=AddToString(CGI->generaltexth->artifNames[133] + " %+d",descr,
-				summ * town->valOfGlobalBonuses
-				(Selector::type(Bonus::CREATURE_GROWTH_PERCENT) && Selector::sourceType(Bonus::ARTIFACT))/100); //Statue of Legion
+		summ+=AddToString(CGI->generaltexth->artifNames[133] + " %+d",descr,
+			summ * town->valOfGlobalBonuses
+			(Selector::type(Bonus::CREATURE_GROWTH_PERCENT) && Selector::sourceType(Bonus::ARTIFACT))/100); //Statue of Legion
 
-			if(town->town->hordeLvl[0]==level)//horde, x to summ
-			if( vstd::contains(town->builtBuildings, Buildings::HORDE_1) || vstd::contains(town->builtBuildings, Buildings::HORDE_1_UPGR))
-				summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::HORDE_1]->Name()+" %+d",descr,
-					creature->hordeGrowth);
+		if(town->town->hordeLvl[0]==level)//horde, x to summ
+		if( vstd::contains(town->builtBuildings, Buildings::HORDE_1) || vstd::contains(town->builtBuildings, Buildings::HORDE_1_UPGR))
+			summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::HORDE_1]->Name()+" %+d",descr,
+				creature->hordeGrowth);
 
-			if(town->town->hordeLvl[1]==level)//horde, x to summ
-			if( vstd::contains(town->builtBuildings, Buildings::HORDE_2) || vstd::contains(town->builtBuildings, Buildings::HORDE_2_UPGR))
-				summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::HORDE_2]->Name()+" %+d",descr,
-					creature->hordeGrowth);
+		if(town->town->hordeLvl[1]==level)//horde, x to summ
+		if( vstd::contains(town->builtBuildings, Buildings::HORDE_2) || vstd::contains(town->builtBuildings, Buildings::HORDE_2_UPGR))
+			summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::HORDE_2]->Name()+" %+d",descr,
+				creature->hordeGrowth);
 
-			int cnt = 0;
+		int cnt = 0;
 
-			std::vector< const CGDwelling * > myDwellings = LOCPLINT->cb->getMyDwellings();
-			for (std::vector<const CGDwelling*>::const_iterator it = myDwellings.begin(); it != myDwellings.end(); ++it)
-				if (CGI->creh->creatures[town->town->basicCreatures[level]]->idNumber == (*it)->creatures[0].second[0])
-					cnt++;//external dwellings count to summ
-			summ+=AddToString(CGI->generaltexth->allTexts[591],descr,cnt);
+		std::vector< const CGDwelling * > myDwellings = LOCPLINT->cb->getMyDwellings();
+		for (std::vector<const CGDwelling*>::const_iterator it = myDwellings.begin(); it != myDwellings.end(); ++it)
+			if (CGI->creh->creatures[town->town->basicCreatures[level]]->idNumber == (*it)->creatures[0].second[0])
+				cnt++;//external dwellings count to summ
+		summ+=AddToString(CGI->generaltexth->allTexts[591],descr,cnt);
 
-			boost::shared_ptr<BonusList> bl;
-			const CGHeroInstance *hero = town->garrisonHero;
-			if (hero)
-			{
-				bl = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level) 
-			                      && Selector::sourceType(Bonus::ARTIFACT), 0, hero);
-			}
-			hero = town->visitingHero;
-			if (hero)
-			{
-				boost::shared_ptr<BonusList> blAppend = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level) 
-					&& Selector::sourceType(Bonus::ARTIFACT), 0, hero);
-				if (town->garrisonHero)
-					bl->insert(bl->size(), blAppend->begin(), blAppend->end());
-				else
-					bl = blAppend;
-			}
-			
-			if (bl->size())
-				summ+=AddToString (CGI->arth->artifacts[bl->front()->sid]->Name()+" %+d", descr, bl->totalValue());
+		boost::shared_ptr<BonusList> bl;
+		const CGHeroInstance *hero = town->garrisonHero;
+		if (hero)
+		{
+			bl = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level) 
+							  && Selector::sourceType(Bonus::ARTIFACT), 0, hero);
+		}
+		hero = town->visitingHero;
+		if (hero)
+		{
+			boost::shared_ptr<BonusList> blAppend = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level) 
+				&& Selector::sourceType(Bonus::ARTIFACT), 0, hero);
+			if (town->garrisonHero)
+				bl->insert(bl->size(), blAppend->begin(), blAppend->end());
+			else
+				bl = blAppend;
+		}
+		
+		if (bl->size())
+			summ+=AddToString (CGI->arth->artifacts[bl->front()->sid]->Name()+" %+d", descr, bl->totalValue());
 
-			//TODO: player bonuses
+		//TODO: player bonuses
 
-			if(vstd::contains(town->builtBuildings, Buildings::GRAIL)) //grail - +50% to ALL growth
-				summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::GRAIL]->Name()+" %+d",descr,summ/2);
+		if(vstd::contains(town->builtBuildings, Buildings::GRAIL)) //grail - +50% to ALL growth
+			summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::GRAIL]->Name()+" %+d",descr,summ/2);
 
-			summ+=AddToString(CGI->generaltexth->allTexts[63] + " %+d",descr, creature->valOfBonuses(Bonus::CREATURE_GROWTH));
-		}
+		summ+=AddToString(CGI->generaltexth->allTexts[63] + " %+d",descr, creature->valOfBonuses(Bonus::CREATURE_GROWTH));
+	}
+	return descr;
+}
 
-		CInfoPopup *mess = new CInfoPopup();//creating popup
-		mess->free = true;
-		mess->bitmap = CMessage::drawBoxTextBitmapSub
-		(LOCPLINT->playerID, descr,graphics->bigImgs[creature->idNumber],"");
-		mess->pos.x = screen->w/2 - mess->bitmap->w/2;
-		mess->pos.y = screen->h/2 - mess->bitmap->h/2;
-		GH.pushInt(mess);
+void CCreaInfo::clickRight(tribool down, bool previousState)
+{
+	if(down)
+	{
+		if (showAvailable)
+			GH.pushInt(new CDwellingInfoBox(screen->w/2, screen->h/2, town, level));
+		else
+		{
+			std::string descr = genGrowthText();
+			CInfoPopup *mess = new CInfoPopup();//creating popup
+			mess->free = true;
+			mess->bitmap = CMessage::drawBoxTextBitmapSub
+			(LOCPLINT->playerID, descr,graphics->bigImgs[creature->idNumber],"");
+			mess->pos.x = screen->w/2 - mess->bitmap->w/2;
+			mess->pos.y = screen->h/2 - mess->bitmap->h/2;
+			GH.pushInt(mess);
+		}
 	}
 }
 

+ 4 - 1
client/CCastleInterface.h

@@ -161,15 +161,18 @@ class CCreaInfo : public CIntObject
 	const CGTownInstance * town;
 	const CCreature *creature;
 	int level;
+	bool showAvailable;
 	
 	CAnimImage *picture;
 	CLabel * label;
 
 	int AddToString(std::string from, std::string & to, int numb);
+	std::string genGrowthText();
 	
 public:
-	CCreaInfo(int posX, int posY, const CGTownInstance *Town, int Level);
+	CCreaInfo(Point position, const CGTownInstance *Town, int Level, bool compact=false, bool showAvailable=false);
 	
+	void update();
 	void hover(bool on);
 	void clickLeft(tribool down, bool previousState);
 	void clickRight(tribool down, bool previousState);

+ 11 - 0
client/GUIBase.h

@@ -283,6 +283,17 @@ struct Rect : public SDL_Rect
 			return Rect();
 		}
 	}
+	Rect operator|(const Rect &p) const //union of two rects
+	{
+		Rect ret;
+		ret.x =  std::min(p.x, this->x);
+		ret.y =  std::min(p.y, this->y);
+		int x2 = std::max(p.x+p.w, this->x+this->w);
+		int y2 = std::max(p.y+p.h, this->y+this->h);
+		ret.w = x2 -ret.x;
+		ret.h = y2 -ret.y;
+		return ret;
+	}
 };
 
 /// Defines a show method

+ 11 - 11
client/GUIClasses.cpp

@@ -4513,6 +4513,16 @@ CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance
 		garr->addSplitBtn(split);
 	}
 	quit = new AdventureMapButton(CGI->generaltexth->tcommands[8],"",boost::bind(&CGarrisonWindow::close,this),399,314,"IOK6432.DEF",SDLK_RETURN);
+
+	std::string titleText;
+	if (garr->armedObjs[1]->tempOwner == garr->armedObjs[0]->tempOwner)
+		titleText = CGI->generaltexth->allTexts[709];
+	else
+	{
+		titleText = CGI->generaltexth->allTexts[35];
+		boost::algorithm::replace_first(titleText, "%s", garr->armedObjs[0]->Slots().begin()->second->type->namePl);
+	}
+	title = new CLabel(275, 30, FONT_BIG, CENTER, tytulowy, titleText);
 }
 
 CGarrisonWindow::~CGarrisonWindow()
@@ -4523,18 +4533,8 @@ void CGarrisonWindow::showAll(SDL_Surface * to)
 {
 	CIntObject::showAll(to);
 
-	std::string title;
-	if (garr->armedObjs[1]->tempOwner == garr->armedObjs[0]->tempOwner)
-		title = CGI->generaltexth->allTexts[709];
-	else
-	{
-		title = CGI->generaltexth->allTexts[35];
-		boost::algorithm::replace_first(title, "%s", garr->armedObjs[0]->Slots().begin()->second->type->namePl);
-	}
-
 	blitAtLoc(graphics->flags->ourImages[garr->armedObjs[1]->getOwner()].bitmap,28,124,to);
 	blitAtLoc(graphics->portraitLarge[static_cast<const CGHeroInstance*>(garr->armedObjs[1])->portrait],29,222,to);
-	printAtMiddleLoc(title,275,30,FONT_BIG,tytulowy,to);
 }
 
 IShowActivable::IShowActivable()
@@ -5143,7 +5143,7 @@ void CArtifactsOfHero::setHero(const CGHeroInstance * hero)
 void CArtifactsOfHero::dispose()
 {
 	//delNull(curHero);
-	unmarkSlots(false);
+	//unmarkSlots(false);
 	CCS->curh->dragAndDropCursor(NULL);
 }
 

+ 1 - 0
client/GUIClasses.h

@@ -1072,6 +1072,7 @@ class CGarrisonWindow : public CWindowWithGarrison
 {
 public:
 	CPicture *bg; //background surface
+	CLabel *title; 
 	AdventureMapButton *quit;
 
 	void close();

+ 34 - 27
lib/CLodHandler.cpp

@@ -60,14 +60,23 @@ std::string readString(const unsigned char * bufor, int &i)
 	return ret;
 }
 
-unsigned char * CLodHandler::giveFile(const std::string defName, LodFileType type, int * length)
+void CLodHandler::convertName(std::string &filename, std::string *extension)
 {
-	std::string fname = defName;
-	std::transform(fname.begin(), fname.end(), fname.begin(), (int(*)(int))toupper);
-	int dotPos = fname.find_last_of('.');
-	if ( dotPos != -1 )
-		fname.erase(dotPos);
+	std::transform(filename.begin(), filename.end(), filename.begin(), toupper);
 
+	size_t dotPos = filename.find_last_of("/.");
+
+	if ( dotPos != std::string::npos && filename[dotPos] == '.')
+	{
+		if (extension)
+			*extension = filename.substr(dotPos);
+		filename.erase(dotPos);
+	}
+}
+
+unsigned char * CLodHandler::giveFile(std::string fname, LodFileType type, int * length)
+{
+	convertName(fname);
 	boost::unordered_set<Entry>::const_iterator en_it = entries.find(Entry(fname, type));
 	
 	if(en_it == entries.end()) //nothing's been found
@@ -127,15 +136,20 @@ unsigned char * CLodHandler::giveFile(const std::string defName, LodFileType typ
 	return NULL;
 }
 
-bool CLodHandler::haveFile(const std::string name, LodFileType type)
+std::string CLodHandler::getFileName(std::string lodFile, LodFileType type)
 {
-	std::string fname = name;
-	std::transform(fname.begin(), fname.end(), fname.begin(), (int(*)(int))toupper);
-	int dotPos = fname.find_last_of('.');
-	if ( dotPos != -1 )
-		fname.erase(dotPos);
-		
-	return vstd::contains(entries, Entry(fname, type));
+	convertName(lodFile);
+	boost::unordered_set<Entry>::const_iterator it = entries.find(Entry(lodFile, type));
+
+	if (it != entries.end())
+		return it->realName;
+	return "";
+}
+
+bool CLodHandler::haveFile(std::string name, LodFileType type)
+{
+	convertName(name);
+	return vstd::contains(entries, Entry(name, type));
 }
 
 DLL_EXPORT int CLodHandler::infs2(unsigned char * in, int size, int realSize, unsigned char *& out, int wBits)
@@ -219,20 +233,12 @@ void CLodHandler::extractFile(const std::string FName, const std::string name)
 	}
 }
 
-void CLodHandler::initEntry(Entry &e, const std::string name)
+void CLodHandler::initEntry(Entry &e, std::string name)
 {
-	e.name = name;
-	//file names stored in upper case without extension
-	std::transform(e.name.begin(), e.name.end(), e.name.begin(), toupper);
 	std::string ext;
-		
-	size_t dotPos = e.name.find_last_of('.');
-	if ( dotPos < e.name.size() )
-	{
-		ext = e.name.substr(dotPos);
-		e.name.erase(dotPos);
-	}
-	
+	convertName(name, &ext);
+	e.name = name;
+
 	std::map<std::string, LodFileType>::iterator it = extMap.find(ext);
 	if (it == extMap.end())
 		e.type = FILE_OTHER;
@@ -254,6 +260,7 @@ void CLodHandler::init(const std::string lodFile, const std::string dirName)
 	EXT(".JPG", FILE_GRAPHICS);
 	EXT(".PCX", FILE_GRAPHICS);
 	EXT(".PNG", FILE_GRAPHICS);
+	EXT(".TGA", FILE_GRAPHICS);
 	#undef EXT
 	
 	myDir = dirName;
@@ -328,7 +335,7 @@ void CLodHandler::init(const std::string lodFile, const std::string dirName)
 		tlog1<<"Warning: No "+dirName+"/ folder!"<<std::endl;
 	}
 }
-std::string CLodHandler::getTextFile(const std::string name, LodFileType type)
+std::string CLodHandler::getTextFile(std::string name, LodFileType type)
 {
 	int length=-1;
 	unsigned char* data = giveFile(name, type, &length);

+ 6 - 4
lib/CLodHandler.h

@@ -103,16 +103,18 @@ class DLL_EXPORT CLodHandler
 	int infs2(unsigned char * in, int size, int realSize, unsigned char*& out, int wBits=15); //zlib fast handler
 
 public:
+	//convert string to upper case and remove extension. If extension!=NULL -> it will be copied here (including dot)
+	void convertName(std::string &filename, std::string *extension=NULL);
 
 	boost::unordered_set<Entry> entries;
 
 	CLodHandler();
 	~CLodHandler();
 	void init(const std::string lodFile, const std::string dirName);
-		
-	unsigned char * giveFile(const std::string defName, LodFileType type=FILE_ANY, int * length=NULL); //returns pointer to the decompressed data - it must be deleted when no longer needed!
-	bool haveFile(const std::string name, LodFileType type=FILE_ANY);//check if file is present in lod
-	std::string getTextFile(const std::string name, LodFileType type=FILE_TEXT); //extracts one file
+	std::string getFileName(std::string lodFile, LodFileType type=FILE_ANY);
+	unsigned char * giveFile(std::string defName, LodFileType type=FILE_ANY, int * length=NULL); //returns pointer to the decompressed data - it must be deleted when no longer needed!
+	bool haveFile(std::string name, LodFileType type=FILE_ANY);//check if file is present in lod
+	std::string getTextFile(std::string name, LodFileType type=FILE_TEXT); //extracts one file
 	void extractFile(const std::string FName, const std::string name); //extracts a specific file
 
 	static unsigned char * getUnpackedFile(const std::string & path, int * sizeOut); //loads given file, decompresses and returns

+ 8 - 1
lib/IGameCallback.cpp

@@ -1101,10 +1101,17 @@ int CPlayerSpecificInfoCallback::howManyHeroes(bool includeGarrisoned) const
 	return getHeroCount(player,includeGarrisoned);
 }
 
-const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId) const
+const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId, bool includeGarrisoned) const
 {
 	const PlayerState *p = getPlayer(player);
 	ERROR_RET_VAL_IF(!p, "No player info", NULL);
+
+	if (!includeGarrisoned)
+	{
+		for(unsigned int i = 0; i < p->heroes.size() && i<=serialId; i++)
+			if(p->heroes[i]->inTownGarrison)
+				serialId++;
+	}
 	ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->heroes.size(), "No player info", NULL);
 	return p->heroes[serialId];
 }

+ 1 - 1
lib/IGameCallback.h

@@ -213,7 +213,7 @@ public:
 	std::vector <const CGTownInstance *> getTownsInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible
 	int getHeroSerial(const CGHeroInstance * hero)const;
 	const CGTownInstance* getTownBySerial(int serialId) const; // serial id is [0, number of towns)
-	const CGHeroInstance* getHeroBySerial(int serialId) const; // serial id is [0, number of heroes)
+	const CGHeroInstance* getHeroBySerial(int serialId, bool includeGarrisoned=true) const; // serial id is [0, number of heroes)
 	std::vector <const CGHeroInstance *> getHeroesInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible
 	std::vector <const CGDwelling *> getMyDwellings() const; //returns all dwellings that belong to player
 	std::vector <const CGObjectInstance * > getMyObjects() const; //returns all objects flagged by belonging player

+ 1 - 1
server/CGameHandler.cpp

@@ -4825,7 +4825,7 @@ bool CGameHandler::addToSlot(const StackLocation &sl, const CCreature *c, TQuant
 
 void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging)
 {
-	if(!dst->canBeMergedWith(*src, allowMerging))
+	if(!src->canBeMergedWith(*dst, allowMerging))
 	{
 		if (allowMerging) //do that, add all matching creatures.
 		{