Explorar o código

* fixed crashes when town is placed out of the map boundaries
* for screen is updated after buying creatures
* fixed crashbug on maps with random monster
* proper images of war machines are displayed in blacksmith
* picking starting hero should work again
* Ice Elemental will be treated as two-hex creature
* minor fixes

Michał W. Urbańczyk %!s(int64=17) %!d(string=hai) anos
pai
achega
bca18a31c3

+ 18 - 7
CAdvmapInterface.cpp

@@ -295,7 +295,7 @@ void CTerrainRect::clickLeft(tribool down)
 	int3 mp = whichTileIsIt();
 	if ((mp.x<0) || (mp.y<0))
 		return;
-	std::vector < const CGObjectInstance * > objs = LOCPLINT->cb->getBlockingObjs(mp);
+	std::vector < const CGObjectInstance * > objs;
 	if (LOCPLINT->adventureInt->selection->ID != HEROI_TYPE)
 	{
 		if (currentPath)
@@ -304,9 +304,10 @@ void CTerrainRect::clickLeft(tribool down)
 			delete currentPath;
 			currentPath = NULL;
 		}
+		objs = LOCPLINT->cb->getBlockingObjs(mp);
 		for(int i=0; i<objs.size();i++)
 		{
-			if(objs[i]->ID == 98) //town
+			if(objs[i]->ID == 98 && objs[i]->tempOwner == LOCPLINT->playerID) //town
 			{
 				if(LOCPLINT->adventureInt->selection == (objs[i]))
 				{
@@ -318,7 +319,7 @@ void CTerrainRect::clickLeft(tribool down)
 					return;
 				}
 			}
-			else if(objs[i]->ID == 34)
+			else if(objs[i]->ID == 34 && objs[i]->tempOwner == LOCPLINT->playerID)
 			{
 				LOCPLINT->adventureInt->select(static_cast<const CArmedInstance*>(objs[i]));
 				return;
@@ -328,20 +329,28 @@ void CTerrainRect::clickLeft(tribool down)
 	}
 	else
 	{
+		objs = LOCPLINT->cb->getVisitableObjs(mp);
 		for(int i=0; i<objs.size();i++)
 		{
-			if(objs[i]->ID == 98) //town
+			if(objs[i]->ID == 98)
+				goto endchkpt;
+		}
+		objs = LOCPLINT->cb->getBlockingObjs(mp);
+		for(int i=0; i<objs.size();i++)
+		{
+			if(objs[i]->ID == 98 && objs[i]->tempOwner == LOCPLINT->playerID) //town
 			{
 				LOCPLINT->adventureInt->select(static_cast<const CArmedInstance*>(objs[i]));
 				return;
 			}
-			else if(objs[i]->ID == 34 && LOCPLINT->adventureInt->selection == (objs[i]))
+			else if(objs[i]->ID == 34 && objs[i]->tempOwner == LOCPLINT->playerID && LOCPLINT->adventureInt->selection == (objs[i]))
 			{
 				LOCPLINT->openHeroWindow(static_cast<const CGHeroInstance*>(objs[i]));
 				return;
 			}
 		}
 	}
+endchkpt:
 	bool mres =true;
 	if (currentPath)
 	{
@@ -413,13 +422,14 @@ void CTerrainRect::mouseMoved (SDL_MouseMotionEvent & sEvent)
 	objs = LOCPLINT->cb->getBlockingObjs(pom);
 	for(int i=0; i<objs.size();i++)
 	{
-		if(objs[i]->ID == 98) //town
+		if(objs[i]->ID == 98 && objs[i]->tempOwner == LOCPLINT->playerID) //town
 		{
 			CGI->curh->changeGraphic(0,3);
 			return;
 		}
 		else if(objs[i]->ID == 34 //mouse over hero
-			&& (objs[i]==LOCPLINT->adventureInt->selection  ||  LOCPLINT->adventureInt->selection->ID==98)) //this hero is selected or we've selected a town
+			&& (objs[i]==LOCPLINT->adventureInt->selection  ||  LOCPLINT->adventureInt->selection->ID==98)
+			&& objs[i]->tempOwner == LOCPLINT->playerID) //this hero is selected or we've selected a town
 		{
 			CGI->curh->changeGraphic(0,2);
 			return;
@@ -1068,6 +1078,7 @@ void CAdvMapInt::show(SDL_Surface *to)
 }
 void CAdvMapInt::hide()
 {
+	CGI->curh->changeGraphic(0,0);
 	kingOverview.deactivate();
 	underground.deactivate();
 	questlog.deactivate();

+ 3 - 2
CBattleInterface.cpp

@@ -188,6 +188,7 @@ CBattleInterface::~CBattleInterface()
 
 void CBattleInterface::activate()
 {
+	subInt = NULL;
 	bOptions->activate();
 	bSurrender->activate();
 	bFlee->activate();
@@ -458,11 +459,11 @@ void CBattleInterface::stackKilled(int ID, int dmg, int killed, int IDby, bool b
 	creAnims[ID]->setType(5); //death
 	for(int i=0; i<creAnims[ID]->framesInGroup(5); ++i)
 	{
+		if(i)
+			creAnims[ID]->incrementFrame();
 		show();
 		CSDL_Ext::update();
 		SDL_framerateDelay(LOCPLINT->mainFPSmng);
-		if((animCount+1)%4)
-			creAnims[ID]->incrementFrame();
 	}
 
 	printConsoleAttacked(ID, dmg, killed, IDby);

+ 34 - 36
CCallback.cpp

@@ -1,23 +1,24 @@
 #include "stdafx.h"
+#include "CAdvmapInterface.h"
 #include "CCallback.h"
-#include "CPathfinder.h"
-#include "hch/CHeroHandler.h"
-#include "hch/CTownHandler.h"
 #include "CGameInfo.h"
-#include "hch/CAmbarCendamo.h"
-#include "mapHandler.h"
 #include "CGameState.h"
+#include "CPathfinder.h"
 #include "CPlayerInterface.h"
-#include "hch/CGeneralTextHandler.h"
-#include "CAdvmapInterface.h"
 #include "CPlayerInterface.h"
+#include "client/Client.h"
+#include "hch/CAmbarCendamo.h"
 #include "hch/CBuildingHandler.h"
+#include "hch/CDefObjInfoHandler.h"
+#include "hch/CGeneralTextHandler.h"
+#include "hch/CHeroHandler.h"
 #include "hch/CObjectHandler.h"
+#include "hch/CTownHandler.h"
 #include "lib/Connection.h"
-#include "client/Client.h"
-#include <boost/thread.hpp>
-#include <boost/foreach.hpp>
 #include "lib/NetPacks.h"
+#include "mapHandler.h"
+#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
 #ifdef min
 #undef min
@@ -276,7 +277,7 @@ std::vector < const CGTownInstance *> CCallback::getTownsInfo(bool onlyOur)
 	{
 		for (int j=0;j<(*i).second.towns.size();j++)
 		{
-			if ( ( isVisible((*i).second.towns[j]->pos,player) ) || (*i).first==player)
+			if ( ( isVisible((*i).second.towns[j],player) ) || (*i).first==player)
 			{
 				ret.push_back((*i).second.towns[j]);
 			}
@@ -305,6 +306,22 @@ bool CCallback::isVisible(int3 pos)
 	return isVisible(pos,player);
 }
 
+bool CCallback::isVisible( CGObjectInstance *obj, int Player )
+{
+	//object is visible when at least one blocked tile is visible
+	for(int fx=0; fx<8; ++fx)
+	{
+		for(int fy=0; fy<6; ++fy)
+		{
+			int3 pos = obj->pos + int3(fx-7,fy-5,0);
+			if(gs->map->isInTheMap(pos) 
+				&& !((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1) 
+				&& isVisible(pos,Player)  )
+				return true;
+		}
+	}
+	return false;
+}
 int CCallback::getMyColor()
 {
 	return player;
@@ -377,29 +394,6 @@ bool CCallback::swapArifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHe
 		return false;
 	*cl->serv << ui16(509) << hero1->id << pos1 << hero2->id << pos2;
 	return true;
-	//if(!hero1 || !hero2) //incorrect data
-	//	return false;
-	//CGHeroInstance * Uhero1 = const_cast<CGHeroInstance *>(hero1);
-	//CGHeroInstance * Uhero2 = const_cast<CGHeroInstance *>(hero2);
-
-	//if(worn1 && worn2)
-	//{
-	//	std::swap(Uhero1->artifWorn[pos1], Uhero2->artifWorn[pos2]);
-	//}
-	//else if(worn1 && !worn2)
-	//{
-	//	std::swap(Uhero1->artifWorn[pos1], Uhero2->artifacts[pos2]);
-	//}
-	//else if(!worn1 && worn2)
-	//{
-	//	std::swap(Uhero1->artifacts[pos1], Uhero2->artifWorn[pos2]);
-	//}
-	//else
-	//{
-	//	std::swap(Uhero1->artifacts[pos1], Uhero2->artifacts[pos2]);
-	//}
-	//
-	//return true;
 }
 
 bool CCallback::buildBuilding(const CGTownInstance *town, si32 buildingID)
@@ -526,8 +520,10 @@ void CCallback::buyArtifact(const CGHeroInstance *hero, int aid)
 
 std::vector < const CGObjectInstance * > CCallback::getBlockingObjs( int3 pos )
 {
-	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	std::vector<const CGObjectInstance *> ret;
+	if(!gs->map->isInTheMap(pos))
+		return ret;
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	BOOST_FOREACH(const CGObjectInstance * obj, gs->map->terrain[pos.x][pos.y][pos.z].blockingObjects)
 		ret.push_back(obj);
 	return ret;
@@ -535,8 +531,10 @@ std::vector < const CGObjectInstance * > CCallback::getBlockingObjs( int3 pos )
 
 std::vector < const CGObjectInstance * > CCallback::getVisitableObjs( int3 pos )
 {
-	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	std::vector<const CGObjectInstance *> ret;
+	if(!gs->map->isInTheMap(pos))
+		return ret;
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	BOOST_FOREACH(const CGObjectInstance * obj, gs->map->terrain[pos.x][pos.y][pos.z].visitableObjects)
 		ret.push_back(obj);
 	return ret;

+ 1 - 0
CCallback.h

@@ -96,6 +96,7 @@ private:
 	CGameState * gs;
 	CClient *cl;
 	bool isVisible(int3 pos, int Player);
+	bool isVisible(CGObjectInstance *obj, int Player);
 
 protected:
 	int player;

+ 6 - 7
CCastleInterface.cpp

@@ -508,8 +508,8 @@ void CCastleInterface::buildingClicked(int building)
 			}
 		case 7: case 8: case 9:
 			{
-				CFortScreen *fs = new CFortScreen(this);
 				deactivate();
+				CFortScreen *fs = new CFortScreen(this);
 				fs->activate();
 				fs->show();
 				break;
@@ -533,7 +533,7 @@ void CCastleInterface::buildingClicked(int building)
 				if(vstd::contains(hero->artifWorn,ui16(aid+9))) //hero already has machine
 					possible = false;
 				deactivate();
-				(new CBlacksmithDialog(possible,142+aid,aid,hero->id))->activate();
+				(new CBlacksmithDialog(possible,CArtHandler::convertMachineID(aid,false),aid,hero->id))->activate();
 				break;
 			}
 		default:
@@ -677,8 +677,6 @@ void CCastleInterface::activate()
 		subInt->activate();
 		return;
 	}
-	else
-		subInt = NULL;
 	showing = true;
 	townlist->activate();
 	garr->activate();
@@ -1256,6 +1254,7 @@ CHallInterface::CBuildWindow::~CBuildWindow()
 
 CFortScreen::~CFortScreen()
 {
+	LOCPLINT->curint->subInt = NULL;
 	for(int i=0;i<crePics.size();i++)
 		delete crePics[i];
 	for (int i=0;i<recAreas.size();i++)
@@ -1280,7 +1279,7 @@ void CFortScreen::show( SDL_Surface * to)
 
 void CFortScreen::activate()
 {
-	LOCPLINT->curint = this;
+	LOCPLINT->curint->subInt = this;
 	exit->activate();
 	for (int i=0;i<recAreas.size();i++)
 	{
@@ -1309,6 +1308,7 @@ void CFortScreen::close()
 }
 CFortScreen::CFortScreen( CCastleInterface * owner )
 {
+	LOCPLINT->curint->subInt = this;
 	bg = NULL;
 	exit = new AdventureMapButton(CGI->townh->tcommands[8],"",boost::bind(&CFortScreen::close,this),748,556,"TPMAGE1.DEF",false,NULL,false);
 	positions += genRect(126,386,10,22),genRect(126,386,404,22),
@@ -1398,7 +1398,6 @@ void CFortScreen::RecArea::clickLeft (tribool down)
 	{
 		LOCPLINT->curint->deactivate();
 		CRecrutationWindow *rw = LOCPLINT->castleInt->showRecruitmentWindow(bid);
-		rw->buy->callback += boost::bind(&CFortScreen::draw, static_cast<CFortScreen*>(LOCPLINT->curint), LOCPLINT->castleInt, false);
 	}
 	ClickableL::clickLeft(down);
 }
@@ -1542,7 +1541,7 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, int creMachineID, int aid, i
 	blitAt(bg2,64,50,bmp);
 	SDL_FreeSurface(bg2);
 	CCreatureAnimation cra(CGI->creh->creatures[creMachineID].animDefName);
-	cra.nextFrameMiddle(bmp,165,130,true,false);
+	cra.nextFrameMiddle(bmp,170,120,true,false);
 	char pom[75];
 	sprintf(pom,CGI->generaltexth->allTexts[274].c_str(),CGI->creh->creatures[creMachineID].nameSing.c_str()); //build a new ...
 	printAtMiddle(pom,165,28,GEORXX,tytulowy,bmp);

+ 1 - 0
CGameInterface.h

@@ -62,6 +62,7 @@ public:
 	virtual void tileHidden(int3 pos){};
 	virtual void tileRevealed(int3 pos){};
 	virtual void yourTurn(){};
+	virtual void availableCreaturesChanged(const CGTownInstance *town){};
 
 	//battle call-ins
 	//virtual void actionFinished(BattleAction action){};//occurs AFTER every action taken by any stack or by the hero

+ 12 - 6
CGameState.cpp

@@ -566,7 +566,7 @@ void CGameState::apply(IPack * pack)
 int CGameState::pickHero(int owner)
 {
 	int h=-1;
-	if(map->getHero(h = scenarioOps->getIthPlayersSettings(owner).hero,0)  &&  h>=0) //we haven't used selected hero
+	if(!map->getHero(h = scenarioOps->getIthPlayersSettings(owner).hero,0)  &&  h>=0) //we haven't used selected hero
 		return h;
 	int f = scenarioOps->getIthPlayersSettings(owner).castle;
 	int i=0;
@@ -615,7 +615,14 @@ std::pair<int,int> CGameState::pickObject(CGObjectInstance *obj)
 			return std::pair<int,int>(34,pickHero(obj->tempOwner));
 		}
 	case 71: //random monster
-		return std::pair<int,int>(54,ran()%(VLC->creh->creatures.size())); 
+		{
+			int r;
+			do 
+			{
+				r = ran()%197;
+			} while (vstd::contains(VLC->creh->notUsedMonsters,r));
+			return std::pair<int,int>(54,r); 
+		}
 	case 72: //random monster lvl1
 		return std::pair<int,int>(54,VLC->creh->levelCreatures[1][ran()%VLC->creh->levelCreatures[1].size()]->idNumber); 
 	case 73: //random monster lvl2
@@ -788,7 +795,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
 	map->defs.insert(cur->defInfo = VLC->dobjinfo->gobjs[ran.first][ran.second]);
 	if(!cur->defInfo)
 	{
-		std::cout<<"Missing def declaration for "<<cur->ID<<" "<<cur->subID<<std::endl;
+		std::cout<<"*BIG* WARNING: Missing def declaration for "<<cur->ID<<" "<<cur->subID<<std::endl;
 		return;
 	}
 }
@@ -985,8 +992,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
 						vhi->artifWorn[16] = 3;
 						break;
 					default:
-						pom-=145;
-						vhi->artifWorn[12+pom] = 3+pom;
+						vhi->artifWorn[9+CArtHandler::convertMachineID(pom,true)] = CArtHandler::convertMachineID(pom,true);
 						break;
 					}
 					continue;
@@ -1188,7 +1194,7 @@ int CGameState::battleGetStack(int pos)
 		if(curB->stacks[g]->position == pos ||
 				( curB->stacks[g]->creature->isDoubleWide() &&
 					( (curB->stacks[g]->attackerOwned && curB->stacks[g]->position-1 == pos) ||
-						(!curB->stacks[g]->attackerOwned && curB->stacks[g]->position-1 == pos)
+						(!curB->stacks[g]->attackerOwned && curB->stacks[g]->position+1 == pos)
 					)
 				)
 			)

+ 8 - 1
CMT.cpp

@@ -142,7 +142,14 @@ int main(int argc, _TCHAR* argv[])
 		THC tmh.getDif();pomtime.getDif();//reset timers
 		cgi->pathf = new CPathfinder();
 		THC std::cout<<"\tPathfinder: "<<pomtime.getDif()<<std::endl;
-		cgi->consoleh->runConsole();
+		if(argc>1)
+		{
+			std::cout << "Special mode without support for console!" << std::endl;
+		}
+		else
+		{
+			cgi->consoleh->runConsole();
+		}
 		THC std::cout<<"\tCallback and console: "<<pomtime.getDif()<<std::endl;
 		THC std::cout<<"Handlers initialization (together): "<<tmh.getDif()<<std::endl;
 		std::ofstream lll("client_log.txt");

+ 11 - 0
CPlayerInterface.cpp

@@ -2184,6 +2184,17 @@ void CPlayerInterface::updateWater()
 	//water tiles updated
 	//CGI->screenh->updateScreen();
 }
+
+void CPlayerInterface::availableCreaturesChanged( const CGTownInstance *town )
+{
+	boost::unique_lock<boost::mutex> un(*pim);
+	if(curint == castleInt)
+	{
+		CFortScreen *fs = dynamic_cast<CFortScreen*>(curint->subInt);
+		if(fs)
+			fs->draw(castleInt,false);
+	}
+}
 CStatusBar::CStatusBar(int x, int y, std::string name, int maxw)
 {
 	bg=BitmapHandler::loadBitmap(name);

+ 1 - 0
CPlayerInterface.h

@@ -353,6 +353,7 @@ public:
 	void tileHidden(int3 pos);
 	void tileRevealed(int3 pos);
 	void yourTurn();
+	void availableCreaturesChanged(const CGTownInstance *town);
 	//for battles
 	//void actionFinished(BattleAction action);//occurs AFTER every action taken by any stack or by the hero
 	//void actionStarted(BattleAction action);//occurs BEFORE every action taken by any stack or by the hero

+ 10 - 3
client/Client.cpp

@@ -350,7 +350,9 @@ void CClient::process(int what)
 			*serv >> ns;
 			std::cout << "Setting available creatures in " << ns.tid << std::endl;
 			gs->apply(&ns);
-			//TODO: do we need to inform interface? 
+			CGTownInstance *t = gs->getTown(ns.tid);
+			if(vstd::contains(playerint,t->tempOwner))
+				playerint[t->tempOwner]->availableCreaturesChanged(t);
 			break;
 		}
 	case 508:
@@ -527,8 +529,13 @@ void CClient::process(int what)
 }
 void CClient::waitForMoveAndSend(int color)
 {
-	BattleAction ba = playerint[color]->activeStack(gs->curB->activeStack);
-	*serv << ui16(3002) << ba;
+	try
+	{
+		BattleAction ba = playerint[color]->activeStack(gs->curB->activeStack);
+		*serv << ui16(3002) << ba;
+		return;
+	}HANDLE_EXCEPTION
+	std::cout << "We should not be here!" << std::endl;
 }
 void CClient::run()
 {

+ 31 - 0
hch/CArtHandler.cpp

@@ -60,3 +60,34 @@ void CArtHandler::loadArtifacts()
 		}
 	}
 }
+
+int CArtHandler::convertMachineID(int id, bool creToArt )
+{
+	int dif = 142;
+	if(creToArt)
+	{
+		switch (id)
+		{
+		case 147:
+			dif--;
+			break;
+		case 148:
+			dif++;
+			break;
+		}
+		dif = -dif;
+	}
+	else
+	{
+		switch (id)
+		{
+		case 6:
+			dif--;
+			break;
+		case 5:
+			dif++;
+			break;
+		}
+	}
+	return id + dif;
+}

+ 1 - 0
hch/CArtHandler.h

@@ -29,6 +29,7 @@ public:
 	std::vector<CArtifact*> treasures, minors, majors, relics;
 	std::vector<CArtifact> artifacts;
 	void loadArtifacts();
+	static int convertMachineID(int id, bool creToArt);
 	CArtHandler();
 };
 

+ 5 - 0
hch/CCreatureHandler.cpp

@@ -3,11 +3,13 @@
 #include "CCreatureHandler.h"
 #include "CLodHandler.h"
 #include <sstream>
+#include <boost/assign/std/set.hpp>
 #include <boost/assign/std/vector.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/find.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include "../lib/VCMI_Lib.h"
+using namespace boost::assign;
 extern CLodHandler * bitmaph;
 CCreatureHandler::CCreatureHandler()
 {
@@ -61,6 +63,7 @@ si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatur
 
 void CCreatureHandler::loadCreatures()
 {
+	notUsedMonsters += 122,124,126,128,145,146,147,148,149,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191;
 	std::string buf = bitmaph->getTextFile("ZCRTRAIT.TXT");
 	int andame = buf.size();
 	int i=0; //buf iterator
@@ -439,6 +442,8 @@ void CCreatureHandler::loadCreatures()
 		idToProjectileSpin[id] = spin;
 	}
 	inp2.close();
+
+	creatures[123].abilityRefs += "DOUBLE_WIDE";
 }
 
 void CCreatureHandler::loadAnimationInfo()

+ 1 - 0
hch/CCreatureHandler.h

@@ -49,6 +49,7 @@ public:
 class DLL_EXPORT CCreatureHandler
 {
 public:
+	std::set<int> notUsedMonsters;
 	std::vector<CCreature> creatures; //creature ID -> creature info
 	std::map<int,std::vector<CCreature*> > levelCreatures; //level -> list of creatures
 	std::map<std::string,int> nameToID;

+ 11 - 1
map.cpp

@@ -1169,6 +1169,7 @@ void Mapa::loadPlayerInfo( int &pom, unsigned char * bufor, int &i )
 		players[pom].canComputerPlay = bufor[i++];
 		if ((!(players[pom].canHumanPlay || players[pom].canComputerPlay)))
 		{
+			memset(&players[pom],0,sizeof(PlayerInfo));
 			switch(version)
 			{
 			case SoD: case WoG: 
@@ -1187,7 +1188,9 @@ void Mapa::loadPlayerInfo( int &pom, unsigned char * bufor, int &i )
 		players[pom].AITactic = bufor[i++];
 
 		if(version == SoD || version == WoG)
-			players[pom].p7= bufor[i++];	
+			players[pom].p7= bufor[i++];
+		else
+			players[pom].p7= -1;
 
 		players[pom].allowedFactions = 0;
 		players[pom].allowedFactions += bufor[i++];
@@ -2451,4 +2454,11 @@ void Mapa::readEvents( unsigned char * bufor, int &i )
 		i+=18;
 		events.push_back(ne);
 	}
+}
+
+bool Mapa::isInTheMap( int3 pos )
+{
+	if(pos.x<0 || pos.y<0 || pos.z<0 || pos.x >= width || pos.y >= height || pos.z > twoLevel)
+		return false;
+	else return true;
 }

+ 3 - 0
map.h

@@ -498,9 +498,12 @@ struct DLL_EXPORT Mapa
 	void loadHero( CGObjectInstance * &nobj, unsigned char * bufor, int &i);
 	void loadTown( CGObjectInstance * &nobj, unsigned char * bufor, int &i);
 	int loadSeerHut( unsigned char * bufor, int i, CGObjectInstance * nobj);
+
+
 	void addBlockVisTiles(CGObjectInstance * obj);
 	void removeBlockVisTiles(CGObjectInstance * obj);
 	Mapa(std::string filename); //creates map structure from .h3m file
 	CGHeroInstance * getHero(int ID, int mode=0);
+	bool isInTheMap(int3 pos);
 };
 #endif //MAPD_H

+ 2 - 0
mapHandler.cpp

@@ -526,6 +526,8 @@ void CMapHandler::init()
 		else 
 			n = CGI->state->capitols[i%ccc];
 		ifs >> n->name;
+		if(!n)
+			std::cout << "*HUGE* Warning - missing town def for " << i << std::endl;
 		map->defs.insert(n);
 	} 
 	std::cout<<"\tLoading town def info: "<<th.getDif()<<std::endl;