Bladeren bron

* fixed crash when there was no hero available to hire for some player
* pregmae wont crash if user gives wrong resolution number
* fixed 1024x600 screen resolution
* selection dialog (eg. for treasure chests) can be closed with enter key
* orientation of hero can't be change if movement points are exhausted
* numerous improvements for Tavern window (hover tips for buttons, button will be inactive if player has 8 heroes or there is a visiting hero in the town garrison)
* campfire, borderguard, bordergate, questguard will be accessible from the top
* spells not known by hero can't be casted
* restored checking mana points before casting spell

Michał W. Urbańczyk 16 jaren geleden
bovenliggende
commit
c83404a375

+ 2 - 2
AdventureMapButton.cpp

@@ -86,7 +86,7 @@ void AdventureMapButton::hover (bool on)
 	std::string *name = (vstd::contains(hoverTexts,state)) 
 							? (&hoverTexts[state]) 
 							: (vstd::contains(hoverTexts,0) ? (&hoverTexts[0]) : NULL);
-	if(name && !blocked) //if there is no name, there is nohing to display also
+	if(name && blocked!=1) //if there is no name, there is nohing to display also
 	{
 		if (LOCPLINT->curint == static_cast<CMainInterface*>(LOCPLINT->battleInt)) //for battle buttons
 		{
@@ -180,7 +180,7 @@ void AdventureMapButton::init(const CFunctionList<void()> &Callback, const std::
 	pos.h = imgs[curimg][0]->h  -1;
 }
 
-void AdventureMapButton::block( bool on )
+void AdventureMapButton::block( ui8 on )
 {
 	blocked = on;
 	state = 0;

+ 3 - 2
AdventureMapButton.h

@@ -16,13 +16,14 @@ public:
 	std::map<int,std::string> hoverTexts; //state -> text for statusbar
 	std::string helpBox; //for right-click help
 	CFunctionList<void()> callback;
-	bool colorChange, blocked,
+	bool colorChange, 
 		actOnDown; //runs when mouse is pressed down over it, not when up
+	ui8 blocked;
 
 	void clickRight (tribool down);
 	virtual void clickLeft (tribool down);
 	void hover (bool on);
-	void block(bool on); //if button is blocked then it'll change it's graphic to inactive (offset==2) and won't react on l-clicks
+	void block(ui8 on); //if button is blocked then it'll change it's graphic to inactive (offset==2) and won't react on l-clicks
 	void activate(); // makes button active
 	void deactivate(); // makes button inactive (but doesn't delete)
 

+ 11 - 7
CGameState.cpp

@@ -617,17 +617,21 @@ void CGameState::applyNL(IPack * pack)
 		{
 			SetAvailableHeroes *rh = static_cast<SetAvailableHeroes*>(pack);
 			players[rh->player].availableHeroes.clear();
-			players[rh->player].availableHeroes.push_back(hpool.heroesPool[rh->hid1]);
-			players[rh->player].availableHeroes.push_back(hpool.heroesPool[rh->hid2]);
-			if(rh->flags & 1)
+
+			CGHeroInstance *h = (rh->hid1>=0 ?  hpool.heroesPool[rh->hid1] : NULL);
+			players[rh->player].availableHeroes.push_back(h);
+			if(h  &&  rh->flags & 1)
 			{
-				hpool.heroesPool[rh->hid1]->army.slots.clear();
-				hpool.heroesPool[rh->hid1]->army.slots[0] = std::pair<ui32,si32>(VLC->creh->nameToID[hpool.heroesPool[rh->hid1]->type->refTypeStack[0]],1);
+				h->army.slots.clear();
+				h->army.slots[0] = std::pair<ui32,si32>(VLC->creh->nameToID[h->type->refTypeStack[0]],1);
 			}
+
+			h = (rh->hid2>=0 ?  hpool.heroesPool[rh->hid2] : NULL);
+			players[rh->player].availableHeroes.push_back(h);
 			if(rh->flags & 2)
 			{
-				hpool.heroesPool[rh->hid2]->army.slots.clear();
-				hpool.heroesPool[rh->hid2]->army.slots[0] = std::pair<ui32,si32>(VLC->creh->nameToID[hpool.heroesPool[rh->hid2]->type->refTypeStack[0]],1);
+				h->army.slots.clear();
+				h->army.slots[0] = std::pair<ui32,si32>(VLC->creh->nameToID[h->type->refTypeStack[0]],1);
 			}
 			break;
 		}

+ 1 - 1
CHeroWindow.cpp

@@ -330,7 +330,7 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
 		backpack.push_back(add);
 	}
 	activeArtPlace = NULL;
-	dismissButton->block(hero->visitedTown);
+	dismissButton->block(!!hero->visitedTown);
 	leftArtRoll->block(hero->artifacts.size()<6);
 	rightArtRoll->block(hero->artifacts.size()<6);
 	if(hero->getSecSkillLevel(19)==0)

+ 5 - 1
CMT.cpp

@@ -290,9 +290,13 @@ void processCommand(const std::string &message, CClient *&client)
 		std::cin >> i;
 		if(!i)
 			return;
+		else if(i < 0  ||  i >= conf.guiOptions.size())
+		{
+			tlog1 << "Invalid resolution ID! Not a number between 0 and  " << conf.guiOptions.size() << ". No settings changed.\n";
+		}
 		else
 		{
-			for(j=conf.guiOptions.begin(); j!=conf.guiOptions.end() && hlp++<i; j++);
+			for(j=conf.guiOptions.begin(); j!=conf.guiOptions.end() && hlp++<i; j++); //move j to the i-th resolution info
 			conf.cc.resx = j->first.first;
 			conf.cc.resy = j->first.second;
 			tlog0 << "Screen resolution set to " << conf.cc.resx << " x " << conf.cc.resy <<". It will be aplied when the game starts.\n";

+ 87 - 21
CPlayerInterface.cpp

@@ -29,6 +29,7 @@
 #include "map.h"
 #include "mapHandler.h"
 #include "timeHandler.h"
+#include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/assign/std/vector.hpp> 
@@ -874,6 +875,10 @@ CSelWindow::CSelWindow(std::string text, int player, int charperline, std::vecto
 	{
 		buttons.push_back(new AdventureMapButton("","",(Buttons[i].second)?(Buttons[i].second):(boost::bind(&CInfoWindow::close,this)),0,0,Buttons[i].first));
 	}
+
+	if(Buttons.size() == 1) //only one button - assign enter to it
+		buttons[0]->assignedKeys.insert(SDLK_RETURN);
+
 	for(int i=0;i<comps.size();i++)
 	{
 		components.push_back(comps[i]);
@@ -1226,7 +1231,8 @@ void CPlayerInterface::heroMoved(const HeroMoveDetails & details)
 	int3 hp = details.src;
 	if (!details.successful) //hero failed to move
 	{
-		ho->moveDir = getDir(details.src,details.dst);
+		if(ho->movement < 50)
+			ho->moveDir = getDir(details.src,details.dst);
 		ho->isStanding = true;
 		adventureInt->heroList.draw();
 		if (adventureInt->terrain.currentPath && ho->movement>145) //TODO: better condition on movement - check cost of endtile
@@ -4086,7 +4092,10 @@ void CSystemOptionsWindow::show(SDL_Surface *to)
 CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2, const std::string &gossip)
 :h1(selected,0,72,299,H1),h2(selected,1,162,299,H2)
 {
-	selected = 0;
+	if(H1)
+		selected = 0;
+	else
+		selected = -1;
 	bg = BitmapHandler::loadBitmap("TPTAVERN.bmp");
 	graphics->blueToPlayersAdv(bg,LOCPLINT->playerID);
 	printAtMiddle(CGI->generaltexth->jktexts[37],200,35,GEOR16,tytulowy,bg);
@@ -4097,13 +4106,43 @@ CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2,
 	pos.h = bg->h;
 	pos.x = (screen->w-bg->w)/2;
 	pos.y = (screen->h-bg->h)/2;
+	bar = new CStatusBar(pos.x+8, pos.y+478, "APHLFTRT.bmp", 380);
 	h1.pos.x += pos.x;
 	h2.pos.x += pos.x;
 	h1.pos.y += pos.y;
 	h2.pos.y += pos.y;
-	cancel = new AdventureMapButton("","",boost::bind(&CTavernWindow::close,this),pos.x+310,pos.y+428,"ICANCEL.DEF",SDLK_ESCAPE);
+
+	cancel = new AdventureMapButton(CGI->generaltexth->tavernInfo[7],"",boost::bind(&CTavernWindow::close,this),pos.x+310,pos.y+428,"ICANCEL.DEF",SDLK_ESCAPE);
 	recruit = new AdventureMapButton("","",boost::bind(&CTavernWindow::recruitb,this),pos.x+272,pos.y+355,"TPTAV01.DEF",SDLK_RETURN);
-	thiefGuild = new AdventureMapButton("","",0,pos.x+22,pos.y+428,"TPTAV02.DEF",SDLK_t);
+	thiefGuild = new AdventureMapButton(CGI->generaltexth->tavernInfo[5],"",0,pos.x+22,pos.y+428,"TPTAV02.DEF",SDLK_t);
+
+	if(LOCPLINT->cb->getResourceAmount(6) < 2500) //not enough gold
+	{
+		recruit->hoverTexts[0] = CGI->generaltexth->tavernInfo[0]; //Cannot afford a Hero
+		recruit->block(2);
+	}
+	else if(LOCPLINT->cb->howManyHeroes() >= 8)
+	{
+		recruit->hoverTexts[0] = CGI->generaltexth->tavernInfo[1]; //Cannot recruit. You already have %d Heroes.
+		boost::algorithm::replace_first(recruit->hoverTexts[0],"%d",boost::lexical_cast<std::string>(LOCPLINT->cb->howManyHeroes()));
+		recruit->block(2);
+	}
+	else if(LOCPLINT->castleInt && LOCPLINT->castleInt->town->visitingHero)
+	{
+		recruit->hoverTexts[0] = CGI->generaltexth->tavernInfo[2]; //Cannot recruit. You already have a Hero in this town.
+		recruit->block(2);
+	}
+	else
+	{
+		if(H1)
+		{
+			recruit->hoverTexts[0] = CGI->generaltexth->tavernInfo[3]; //Recruit %s the %s
+			boost::algorithm::replace_first(recruit->hoverTexts[0],"%s",H1->name);
+			boost::algorithm::replace_first(recruit->hoverTexts[0],"%s",H1->type->heroClass->name);
+		}
+		else
+			recruit->block(1);
+	}
 }
 
 void CTavernWindow::recruitb()
@@ -4119,6 +4158,7 @@ CTavernWindow::~CTavernWindow()
 	delete cancel;
 	delete thiefGuild;
 	delete recruit;
+	delete bar;
 }
 
 void CTavernWindow::activate()
@@ -4127,9 +4167,12 @@ void CTavernWindow::activate()
 	LOCPLINT->curint->subInt = this;
 	thiefGuild->activate();
 	cancel->activate();
-	h1.activate();
-	h2.activate();
+	if(h1.h)
+		h1.activate();
+	if(h2.h)
+		h2.activate();
 	recruit->activate();
+	LOCPLINT->statusbar = bar;
 }
 
 void CTavernWindow::deactivate()
@@ -4137,8 +4180,10 @@ void CTavernWindow::deactivate()
 	LOCPLINT->objsToBlit -= this;
 	thiefGuild->deactivate();
 	cancel->deactivate();
-	h1.deactivate();
-	h2.deactivate();
+	if(h1.h)
+		h1.deactivate();
+	if(h2.h)
+		h2.deactivate();
 	recruit->deactivate();
 }
 
@@ -4153,23 +4198,28 @@ void CTavernWindow::close()
 void CTavernWindow::show(SDL_Surface * to)
 {
 	blitAt(bg,pos.x,pos.y,screen);
-	h1.show();
-	h2.show();
+	if(h1.h)
+		h1.show();
+	if(h2.h)
+		h2.show();
 	thiefGuild->show();
 	cancel->show();
 	recruit->show();
+	bar->show();
 
-	
-	HeroPortrait *sel = selected ? &h2 : &h1;
-	char descr[300];
-	int artifs = sel->h->artifWorn.size()+sel->h->artifacts.size();
-	for(int i=13; i<=17; i++) //war machines and spellbook doesn't count
-		if(vstd::contains(sel->h->artifWorn,i)) 
-			artifs--;
-	sprintf_s(descr,300,CGI->generaltexth->allTexts[215].c_str(),
-		sel->h->name.c_str(),sel->h->level,sel->h->type->heroClass->name.c_str(),artifs);
-	printAtMiddleWB(descr,pos.x+146,pos.y+389,GEOR13,40,zwykly,screen);
-	CSDL_Ext::drawBorder(screen,sel->pos.x-2,sel->pos.y-2,sel->pos.w+4,sel->pos.h+4,int3(247,223,123));
+	if(selected >= 0)
+	{
+		HeroPortrait *sel = selected ? &h2 : &h1;
+		char descr[300];
+		int artifs = sel->h->artifWorn.size()+sel->h->artifacts.size();
+		for(int i=13; i<=17; i++) //war machines and spellbook doesn't count
+			if(vstd::contains(sel->h->artifWorn,i)) 
+				artifs--;
+		sprintf_s(descr,300,CGI->generaltexth->allTexts[215].c_str(),
+			sel->h->name.c_str(),sel->h->level,sel->h->type->heroClass->name.c_str(),artifs);
+		printAtMiddleWB(descr,pos.x+146,pos.y+389,GEOR13,40,zwykly,screen);
+		CSDL_Ext::drawBorder(screen,sel->pos.x-2,sel->pos.y-2,sel->pos.w+4,sel->pos.h+4,int3(247,223,123));
+	}
 }
 
 void CTavernWindow::HeroPortrait::clickLeft(boost::logic::tribool down)
@@ -4182,11 +4232,13 @@ void CTavernWindow::HeroPortrait::activate()
 {
 	ClickableL::activate();
 	ClickableR::activate();
+	Hoverable::activate();
 }
 void CTavernWindow::HeroPortrait::deactivate()
 {
 	ClickableL::deactivate();
 	ClickableR::deactivate();
+	Hoverable::deactivate();
 }
 void CTavernWindow::HeroPortrait::clickRight(boost::logic::tribool down)
 {
@@ -4213,9 +4265,23 @@ CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const
 	pos.y = y;
 	pos.w = 58;
 	pos.h = 64;
+	if(H)
+	{
+		hoverName = CGI->generaltexth->tavernInfo[4];
+		boost::algorithm::replace_first(hoverName,"%s",H->name);
+	}
 }
 	
 void CTavernWindow::HeroPortrait::show(SDL_Surface * to)
 {
 	blitAt(graphics->portraitLarge[h->subID],pos);
 }
+
+void CTavernWindow::HeroPortrait::hover( bool on )
+{
+	Hoverable::hover(on);
+	if(on)
+		LOCPLINT->statusbar->print(hoverName);
+	else
+		LOCPLINT->statusbar->clear();
+}

+ 4 - 1
CPlayerInterface.h

@@ -687,20 +687,23 @@ public:
 class CTavernWindow : public IShowActivable, public CIntObject
 {
 public:
-	class HeroPortrait : public ClickableL, public ClickableR
+	class HeroPortrait : public ClickableL, public ClickableR, public Hoverable
 	{
 	public:
+		std::string hoverName;
 		vstd::assigner<int,int> as;
 		const CGHeroInstance *h;
 		void activate();
 		void deactivate();
 		void clickLeft(boost::logic::tribool down);
 		void clickRight(boost::logic::tribool down);
+		void hover (bool on);
 		HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H);
 		void show(SDL_Surface * to = NULL);
 	} h1, h2;
 
 	SDL_Surface *bg;
+	CStatusBar *bar;
 	int selected;//0 (left) or 1 (right)
 
 	AdventureMapButton *thiefGuild, *cancel, *recruit;

+ 2 - 2
config/settings.txt

@@ -44,7 +44,7 @@ GUISettings
 	{
 		AdventureMap
 		{
-			AdvMap: x=7 y=6 tilesWidth=19 tilesHeight=18 trimX=15 trimY=29 smoothMove=1;
+			AdvMap: x=7 y=6 tilesWidth=26 tilesHeight=18 trimX=15 trimY=29 smoothMove=1;
 			InfoBox: x=829 y=389;
 		 	gem0: x=6 y=508 graphic=agemLL.def;
 			gem1: x=780 y=508 graphic=agemLR.def;
@@ -55,7 +55,7 @@ GUISettings
 			TownList: size=5 x=970 y=196 arrowUp=IAM014.DEF arrowDown=IAM015.DEF;
 			Minimap: width=144 height=144 x=854 y=26;
 			Statusbar: x=8 y=556 graphic=ADROLLVR2.pcx;
-			ResDataBar: x=0 y=575 graphic=ZRESBAR2.pcx offsetX=32 offsetY=2 resSpace=85;
+			ResDataBar: x=0 y=575 graphic=ZRESBAR2.pcx offsetX=65 offsetY=2 resSpace=109 resDateSpace=135;
 			ButtonKingdomOv: x=902 y=196 graphic=IAM002.DEF playerColoured=1;
 			ButtonUnderground: x=934 y=196 graphic=IAM010.DEF playerColoured=1 additionalDefs=(IAM003.DEF);
 			ButtonQuestLog: x=902 y=228 graphic=IAM004.DEF playerColoured=1;

+ 3 - 0
global.h

@@ -97,6 +97,9 @@ const int SPELL_LEVELS = 5;
 	#endif
 #endif
 
+template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];  
+#define ARRAY_COUNT(arr)    (sizeof(_ArrayCountObj(arr)))
+
 namespace vstd
 {
 	template <typename Container, typename Item>

+ 20 - 5
hch/CDefObjInfoHandler.cpp

@@ -68,17 +68,32 @@ void CDefObjInfoHandler::load()
 		inp>>nobj->id;
 		inp>>nobj->subid;
 		inp>>nobj->type;
-		if(nobj->type == 2 || nobj->type == 3 || nobj->type == 4 || nobj->type == 5 || nobj->id == 111 || nobj->id == 33 || nobj->id == 81) //creature, hero, artifact, resource or whirlpool or garrison or scholar
+
+		nobj->visitDir = (8|16|32|64|128); //disabled visiting from the top
+
+		if(nobj->type == 2 || nobj->type == 3 || nobj->type == 4 || nobj->type == 5) //creature, hero, artifact, resource
+		{
 			nobj->visitDir = 0xff;
-		else
-			nobj->visitDir = (8|16|32|64|128); //disabled visiting from the top
-		inp>>nobj->printPriority;
+		}
+		else 
+		{
+			static int visitableFromTop[] = {111,33,81,12,9,212,215}; //whirlpool, garrison, scholar, campfire, borderguard, bordergate, questguard
+			for(int i=0; i < ARRAY_COUNT(visitableFromTop); i++)
+			{
+				if(visitableFromTop[i] == nobj->id)
+				{
+					nobj->visitDir = 0xff;
+					break;
+				}
+			}
+		}
+		inp >> nobj->printPriority;
 		gobjs[nobj->id][nobj->subid] = nobj;
 		if(nobj->id==98)
 			castles[nobj->subid]=nobj;
 	}
 }
-
+ 
 CDefObjInfoHandler::~CDefObjInfoHandler()
 {
 	for(std::map<int,std::map<int,CGDefInfo*> >::iterator i=gobjs.begin(); i!=gobjs.end(); i++)

+ 15 - 7
hch/CGeneralTextHandler.cpp

@@ -306,25 +306,33 @@ void CGeneralTextHandler::load()
 	}
 
 	itr = 0;
-	std::string strin2 = bitmaph->getTextFile("JKTEXT.TXT");
+	strin = bitmaph->getTextFile("JKTEXT.TXT");
 	for(int hh=0; hh<45; ++hh)
 	{
-		loadToIt(tmp, strin2, itr, 3);
+		loadToIt(tmp, strin, itr, 3);
 		jktexts.push_back(tmp);
 	}
 
 	itr = 0;
-	std::string strin3 = bitmaph->getTextFile("HEROSCRN.TXT");
+	strin = bitmaph->getTextFile("TVRNINFO.TXT");
+	for(int hh=0; hh<8; ++hh)
+	{
+		loadToIt(tmp, strin, itr, 3);
+		tavernInfo.push_back(tmp);
+	}
+
+	itr = 0;
+	strin = bitmaph->getTextFile("HEROSCRN.TXT");
 	for(int hh=0; hh<33; ++hh)
 	{
-		loadToIt(tmp, strin3, itr, 3);
+		loadToIt(tmp, strin, itr, 3);
 		heroscrn.push_back(tmp);
 	}
 
-	strin3 = bitmaph->getTextFile("ARTEVENT.TXT");
-	for(itr = 0; itr<strin3.size();itr++)
+	strin = bitmaph->getTextFile("ARTEVENT.TXT");
+	for(itr = 0; itr<strin.size();itr++)
 	{
-		loadToIt(tmp, strin3, itr, 3);
+		loadToIt(tmp, strin, itr, 3);
 		artifEvents.push_back(tmp);
 	}
 

+ 1 - 1
hch/CGeneralTextHandler.h

@@ -30,6 +30,7 @@ public:
 
 	//towns
 	std::vector<std::string> tcommands, hcommands; //texts for town screen and town hall screen
+	std::vector<std::string> tavernInfo;
 	std::vector<std::vector<std::string> > townNames; //[type id] => vec of names of instances
 	std::vector<std::string> townTypes; //castle, rampart, tower, etc
 	std::map<int, std::map<int, std::pair<std::string, std::string> > > buildings; //map[town id][building id] => pair<name, description>
@@ -54,7 +55,6 @@ public:
 	std::string getTitle(std::string text);
 	std::string getDescr(std::string text);
 
-	void loadTexts();
 	void load();
 	CGeneralTextHandler();
 };

+ 0 - 3
lib/Connection.h

@@ -23,9 +23,6 @@ class CConnection;
 
 namespace mpl = boost::mpl;
 
-template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];  
-#define ARRAY_COUNT(arr)    (sizeof(_ArrayCountObj(arr)))
-
 namespace boost
 {
 	namespace asio

+ 1 - 1
lib/NetPacks.h

@@ -184,7 +184,7 @@ struct SetAvailableHeroes : public CPack<SetAvailableHeroes> //113
 {
 	SetAvailableHeroes(){type = 113;flags=0;};
 	ui8 player;
-	ui32 hid1, hid2;
+	si32 hid1, hid2;
 	ui8 flags; //1 - reset army of hero1; 2 - reset army of hero 2
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 12 - 5
server/CGameHandler.cpp

@@ -1307,8 +1307,8 @@ upgend:
 
 							//TODO: skill level may be different on special terrain
 
-							if( // !vstd::contains(h->spells,ba.additionalInfo) //hero doesn't know this spell 
-								/*||*/ (h->mana < s->costs[skill]) //not enough mana
+							if(  !vstd::contains(h->spells,ba.additionalInfo) //hero doesn't know this spell 
+								|| (h->mana < s->costs[skill]) //not enough mana
 								|| (ba.additionalInfo < 10) //it's adventure spell (not combat)
 								|| 0     )//TODO: hero has already casted a spell in this round
 							{
@@ -1631,9 +1631,16 @@ void CGameHandler::newTurn()
 		{
 			SetAvailableHeroes sah;
 			sah.player = i->first;
-			//TODO: - will fail when there are not enough available heroes
-			sah.hid1 = gs->hpool.pickHeroFor(true,i->first,&VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(i->first).castle])->subID;
-			sah.hid2 = gs->hpool.pickHeroFor(false,i->first,&VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(i->first).castle],sah.hid1)->subID;
+			CGHeroInstance *h = gs->hpool.pickHeroFor(true,i->first,&VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(i->first).castle]);
+			if(h)
+				sah.hid1 = h->subID;
+			else
+				sah.hid1 = -1;
+			h = gs->hpool.pickHeroFor(false,i->first,&VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(i->first).castle],sah.hid1);
+			if(h)
+				sah.hid2 = h->subID;
+			else
+				sah.hid2 = -1;
 			sendAndApply(&sah);
 		}
 		if(i->first>=PLAYER_LIMIT) continue;