浏览代码

Support for Tavern on adv map.

Michał W. Urbańczyk 15 年之前
父节点
当前提交
1e30045541

+ 11 - 4
CCallback.cpp

@@ -137,7 +137,7 @@ void CCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInsta
 	if(obj == NULL)
 		return;
 
-	if(obj->ID == TOWNI_TYPE) //it is a town
+	if(obj->ID == TOWNI_TYPE  ||  obj->ID == 95) //it is a town or adv map tavern
 	{
 		gs->obtainPlayersStats(thi, gs->players[player].towns.size());
 	}
@@ -793,21 +793,22 @@ void CCallback::setSelection(const CArmedInstance * obj)
 	}
 }
 
-void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)
+void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero)
 {
 	ui8 i=0;
 	for(; i<gs->players[player].availableHeroes.size(); i++)
 	{
 		if(gs->players[player].availableHeroes[i] == hero)
 		{
-			HireHero pack(i,town->id);
+			HireHero pack(i,townOrTavern->id);
+			pack.player = player;
 			sendRequest(&pack);
 			return;
 		}
 	}
 }
 
-std::vector<const CGHeroInstance *> CCallback::getAvailableHeroes(const CGTownInstance * town) const
+std::vector<const CGHeroInstance *> CCallback::getAvailableHeroes(const CGObjectInstance * townOrTavern) const
 {
 	std::vector<const CGHeroInstance *> ret(gs->players[player].availableHeroes.size());
 	std::copy(gs->players[player].availableHeroes.begin(),gs->players[player].availableHeroes.end(),ret.begin());
@@ -980,6 +981,12 @@ int CCallback::getPlayerStatus(int player) const
 		return -1;
 	return ps->status;
 }
+
+std::string CCallback::getTavernGossip(const CGObjectInstance * townOrTavern) const
+{
+	return "GOSSIP TEST";
+}
+
 InfoAboutTown::InfoAboutTown()
 {
 	tType = NULL;

+ 6 - 4
CCallback.h

@@ -78,7 +78,7 @@ public:
 	virtual bool dismissHero(const CGHeroInstance * hero)=0; //dismisses given hero; true - successfuly, false - not successfuly
 	
 	//town
-	virtual void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)=0;
+	virtual void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero)=0;
 	virtual bool buildBuilding(const CGTownInstance *town, si32 buildingID)=0;
 	virtual void recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount)=0;
 	virtual bool upgradeCreature(const CArmedInstance *obj, int stackPos, int newID=-1)=0; //if newID==-1 then best possible upgrade will be made
@@ -143,7 +143,8 @@ public:
 	virtual int howManyTowns()const =0;
 	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 std::vector<const CGHeroInstance *> getAvailableHeroes(const CGObjectInstance * townOrTavern) const =0; //heroes that can be recruited
+	virtual std::string getTavernGossip(const CGObjectInstance * townOrTavern) const =0; 
 	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
 	virtual std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID) =0;
 	virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const = 0;
@@ -229,7 +230,7 @@ public:
 	void trade(const CGObjectInstance *market, int mode, int id1, int id2, int val1, const CGHeroInstance *hero = NULL);
 	void setFormation(const CGHeroInstance * hero, bool tight);
 	void setSelection(const CArmedInstance * obj);
-	void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero);
+	void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero);
 	void save(const std::string &fname);
 	void sendMessage(const std::string &mess);
 	void buildBoat(const IShipyard *obj);
@@ -267,7 +268,8 @@ public:
 	std::vector < const CGObjectInstance * > getVisitableObjs(int3 pos) const;
 	std::vector < const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
 	int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
-	std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const; //heroes that can be recruited
+	std::vector<const CGHeroInstance *> getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited
+	std::string getTavernGossip(const CGObjectInstance * townOrTavern) const;
 	const TerrainTile * getTileInfo(int3 tile) const;
 	int canBuildStructure(const CGTownInstance *t, int ID);//// 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
 	std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);

+ 1 - 0
CGameInterface.h

@@ -84,6 +84,7 @@ public:
 	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void showPuzzleMap(){};
 	virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor){};
+	virtual void showTavernWindow(const CGObjectInstance *townOrTavern){};
 	virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; //called when a hero casts a spell
 	virtual void tileHidden(const std::set<int3> &pos){};
 	virtual void tileRevealed(const std::set<int3> &pos){};

+ 1 - 3
client/CCastleInterface.cpp

@@ -1389,9 +1389,7 @@ void CCastleInterface::enterMageGuild()
 
 void CCastleInterface::enterTavern()
 {
-	std::vector<const CGHeroInstance*> h = LOCPLINT->cb->getAvailableHeroes(town);
-	CTavernWindow *tv = new CTavernWindow(h[0],h[1],"GOSSIP TEST");
-	GH.pushInt(tv);
+	LOCPLINT->showTavernWindow(town);
 }
 
 void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key )

+ 6 - 0
client/CPlayerInterface.cpp

@@ -1995,4 +1995,10 @@ void CPlayerInterface::availableArtifactsChanged(const CGBlackMarket *bm /*= NUL
 {
 	if(CMarketplaceWindow *cmw = dynamic_cast<CMarketplaceWindow*>(GH.topInt()))
 		cmw->artifactsChanged(false);
+}
+
+void CPlayerInterface::showTavernWindow(const CGObjectInstance *townOrTavern)
+{
+	CTavernWindow *tv = new CTavernWindow(townOrTavern);
+	GH.pushInt(tv);
 }

+ 1 - 0
client/CPlayerInterface.h

@@ -163,6 +163,7 @@ public:
 	void showArtifactAssemblyDialog(ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList<void()> onYes, CFunctionList<void()> onNo);
 	void showPuzzleMap();
 	void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor);
+	void showTavernWindow(const CGObjectInstance *townOrTavern);
 	void advmapSpellCast(const CGHeroInstance * caster, int spellID); //called when a hero casts a spell
 	void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war
 	void tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles

+ 62 - 92
client/GUIClasses.cpp

@@ -3403,38 +3403,36 @@ void CSystemOptionsWindow::show(SDL_Surface *to)
 	effectsVolume->show(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)
+CTavernWindow::CTavernWindow(const CGObjectInstance *TavernObj)
+ : tavernObj(TavernObj)
 {
-	if(H1)
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	std::vector<const CGHeroInstance*> h = LOCPLINT->cb->getAvailableHeroes(TavernObj);
+	assert(h.size() == 2);
+
+	h1 = new HeroPortrait(selected,0,72,299,h[0]);
+	h2 = new HeroPortrait(selected,1,162,299,h[1]);
+	if(h[0])
 		selected = 0;
 	else
 		selected = -1;
 	oldSelected = -1;
 
-	SDL_Surface *hhlp = BitmapHandler::loadBitmap("TPTAVERN.bmp");
-	graphics->blueToPlayersAdv(hhlp,LOCPLINT->playerID);
-	bg = SDL_ConvertSurface(hhlp,screen->format,0);
-	SDL_SetColorKey(bg,SDL_SRCCOLORKEY,SDL_MapRGB(bg->format,0,255,255));
-	SDL_FreeSurface(hhlp);
+	bg = new CPicture("TPTAVERN.bmp");
+	bg->colorizeAndConvert(LOCPLINT->playerID);
+	pos = center(bg->pos);
 
-	printAtMiddle(CGI->generaltexth->jktexts[37],200,35,FONT_BIG,tytulowy,bg);
-	printAtMiddle("2500",320,328,FONT_SMALL,zwykly,bg);
+
+	printAtMiddle(CGI->generaltexth->jktexts[37],200,35,FONT_BIG,tytulowy,*bg);
+	printAtMiddle("2500",320,328,FONT_SMALL,zwykly,*bg);
 //	printAtMiddle(CGI->generaltexth->jktexts[38],146,283,FONT_BIG,tytulowy,bg); //what is this???
-	printAtMiddleWB(gossip,200,220,FONT_SMALL,50,zwykly,bg);
-	pos.w = bg->w;
-	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(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(CGI->generaltexth->tavernInfo[5],"", boost::bind(&CTavernWindow::thievesguildb, this), pos.x+22, pos.y+428, "TPTAV02.DEF", SDLK_t);
+	printAtMiddleWB(LOCPLINT->cb->getTavernGossip(tavernObj), 200, 220, FONT_SMALL, 50, zwykly, *bg);
+
+
+	bar = new CGStatusBar(8, 478, "APHLFTRT.bmp", 380);
+	cancel = new AdventureMapButton(CGI->generaltexth->tavernInfo[7],"", boost::bind(&CTavernWindow::close, this), 310, 428, "ICANCEL.DEF", SDLK_ESCAPE);
+	recruit = new AdventureMapButton("", "", boost::bind(&CTavernWindow::recruitb, this), 272, 355, "TPTAV01.DEF", SDLK_RETURN);
+	thiefGuild = new AdventureMapButton(CGI->generaltexth->tavernInfo[5],"", boost::bind(&CTavernWindow::thievesguildb, this), 22, 428, "TPTAV02.DEF", SDLK_t);
 
 	if(LOCPLINT->cb->getResourceAmount(6) < 2500) //not enough gold
 	{
@@ -3454,7 +3452,7 @@ CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2,
 	}
 	else
 	{
-		if(!H1)
+		if(!h[0])
 			recruit->block(1);
 	}
 
@@ -3467,47 +3465,20 @@ CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2,
 
 void CTavernWindow::recruitb()
 {
-	const CGHeroInstance *toBuy = (selected ? h2 : h1).h;
+	const CGHeroInstance *toBuy = (selected ? h2 : h1)->h;
+	const CGObjectInstance *obj = tavernObj;
 	close();
-	LOCPLINT->cb->recruitHero(LOCPLINT->castleInt->town,toBuy);
+	LOCPLINT->cb->recruitHero(obj, toBuy);
 }
 
 void CTavernWindow::thievesguildb()
 {
-	GH.pushInt( new CThievesGuildWindow(LOCPLINT->castleInt->town) );
+	GH.pushInt( new CThievesGuildWindow(tavernObj) );
 }
 
 CTavernWindow::~CTavernWindow()
 {
 	CGI->videoh->close();
-	SDL_FreeSurface(bg);
-	delete cancel;
-	delete thiefGuild;
-	delete recruit;
-	delete bar;
-}
-
-void CTavernWindow::activate()
-{
-	thiefGuild->activate();
-	cancel->activate();
-	if(h1.h)
-		h1.activate();
-	if(h2.h)
-		h2.activate();
-	recruit->activate();
-	GH.statusbar = bar;
-}
-
-void CTavernWindow::deactivate()
-{
-	thiefGuild->deactivate();
-	cancel->deactivate();
-	if(h1.h)
-		h1.deactivate();
-	if(h2.h)
-		h2.deactivate();
-	recruit->deactivate();
 }
 
 void CTavernWindow::close()
@@ -3517,20 +3488,12 @@ void CTavernWindow::close()
 
 void CTavernWindow::show(SDL_Surface * to)
 {
-	blitAt(bg,pos.x,pos.y,to);
-	CGI->videoh->update(pos.x+70, pos.y+56, to, true, false);
-	if(h1.h)
-		h1.show(to);
-	if(h2.h)
-		h2.show(to);
-	thiefGuild->show(to);
-	cancel->show(to);
-	recruit->show(to);
-	bar->show(to);
+	CIntObject::show(to);
 
+	CGI->videoh->update(pos.x+70, pos.y+56, to, true, false);
 	if(selected >= 0)
 	{
-		HeroPortrait *sel = selected ? &h2 : &h1;
+		HeroPortrait *sel = selected ? h2 : h1;
 
 		if (selected != oldSelected  &&  !recruit->blocked) 
 		{
@@ -3549,28 +3512,14 @@ void CTavernWindow::show(SDL_Surface * to)
 
 void CTavernWindow::HeroPortrait::clickLeft(tribool down, bool previousState)
 {
-	if(previousState && !down)
+	if(previousState && !down && h)
 		as();
 	//ClickableL::clickLeft(down);
 }
 
-void CTavernWindow::HeroPortrait::activate()
-{
-	activateLClick();
-	activateRClick();
-	activateHover();
-}
-
-void CTavernWindow::HeroPortrait::deactivate()
-{
-	deactivateLClick();
-	deactivateRClick();
-	deactivateHover();
-}
-
 void CTavernWindow::HeroPortrait::clickRight(tribool down, bool previousState)
 {
-	if(down)
+	if(down && h)
 	{
 		adventureInt->heroWindow->setHero(h);
 		GH.pushInt(new CRClickPopupInt(adventureInt->heroWindow,false));
@@ -3578,13 +3527,15 @@ void CTavernWindow::HeroPortrait::clickRight(tribool down, bool previousState)
 }
 
 CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H)
-:as(sel,id)
+:as(sel,id), h(H)
 {
+	used = LCLICK | RCLICK | HOVER;
 	h = H;
 	pos.x = x;
 	pos.y = y;
 	pos.w = 58;
 	pos.h = 64;
+
 	if(H)
 	{
 		hoverName = CGI->generaltexth->tavernInfo[4];
@@ -5370,7 +5321,7 @@ CThievesGuildWindow::CThievesGuildWindow(const CGObjectInstance * _owner)
 	SDL_FreeSurface(bg);
 
 	exitb = new AdventureMapButton (std::string(), std::string(), boost::bind(&CThievesGuildWindow::bexitf,this), 748, 556, "HSBTNS.def", SDLK_RETURN);
-	statusBar = new CStatusBar(3, 555, "TStatBar.bmp", 742);
+	statusBar = new CGStatusBar(3, 555, "TStatBar.bmp", 742);
 
 	resdatabar = new CMinorResDataBar();
 	resdatabar->pos.x += pos.x - 3;
@@ -5709,16 +5660,22 @@ CGStatusBar::CGStatusBar(CPicture *BG, EFonts Font /*= FONT_SMALL*/, EAlignment
 	bg = BG;
 	moveChild(bg, bg->parent, this);
 	pos = bg->pos;
+	calcOffset();
+}
 
-	switch(Align)
+CGStatusBar::CGStatusBar(int x, int y, std::string name/*="ADROLLVR.bmp"*/, int maxw/*=-1*/)
+	: CLabel(x, y, FONT_SMALL, CENTER)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	init();
+	bg = new CPicture(name);
+	pos = bg->pos;
+	if(maxw < pos.w)
 	{
-	case CENTER:
-		textOffset = Point(pos.w/2, pos.h/2);
-		break;
-	case BOTTOMRIGHT:
-		textOffset = Point(pos.w, pos.h);
-		break;
+		amin(pos.w, maxw);
+		bg->srcRect = new Rect(0, 0, maxw, pos.h);
 	}
+	calcOffset();
 }
 
 CGStatusBar::~CGStatusBar()
@@ -5737,6 +5694,19 @@ void CGStatusBar::init()
 	GH.statusbar = this;
 }
 
+void CGStatusBar::calcOffset()
+{
+	switch(alignment)
+	{
+	case CENTER:
+		textOffset = Point(pos.w/2, pos.h/2);
+		break;
+	case BOTTOMRIGHT:
+		textOffset = Point(pos.w, pos.h);
+		break;
+	}
+}
+
 CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB )
 :cb(CB)
 {

+ 11 - 10
client/GUIClasses.h

@@ -329,8 +329,10 @@ public:
 
 	CGStatusBar(int x, int y, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = zwykly, const std::string &Text =  "");
 	CGStatusBar(CPicture *BG, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = zwykly); //given CPicture will be captured by created sbar and it's pos will be used as pos for sbar
+	CGStatusBar(int x, int y, std::string name, int maxw=-1); 
 
 	~CGStatusBar();
+	void calcOffset();
 };
 
 class CFocusable 
@@ -657,31 +659,30 @@ public:
 		std::string hoverName;
 		vstd::assigner<int,int> as;
 		const CGHeroInstance *h;
-		void activate();
-		void deactivate();
+		char descr[100];		// "XXX is a level Y ZZZ with N artifacts"
+
 		void clickLeft(tribool down, bool previousState);
 		void clickRight(tribool down, bool previousState);
 		void hover (bool on);
 		HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H);
 		void show(SDL_Surface * to);
-		char descr[100];		// "XXX is a level Y ZZZ with N artifacts"
-	} h1, h2; //recruitable heroes
 
-	SDL_Surface *bg; //background
-	CStatusBar *bar; //tavern's internal status bar
+	} *h1, *h2; //recruitable heroes
+
+	CPicture *bg; //background
+	CGStatusBar *bar; //tavern's internal status bar
 	int selected;//0 (left) or 1 (right)
 	int oldSelected;//0 (left) or 1 (right)
 
 	AdventureMapButton *thiefGuild, *cancel, *recruit;
+	const CGObjectInstance *tavernObj;
 
-	CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2, const std::string &gossip); //c-tor
+	CTavernWindow(const CGObjectInstance *TavernObj); //c-tor
 	~CTavernWindow(); //d-tor
 
 	void recruitb();
 	void close();
 	void thievesguildb();
-	void activate();
-	void deactivate();
 	void show(SDL_Surface * to);
 };
 
@@ -1049,7 +1050,7 @@ class CThievesGuildWindow : public CIntObject
 {
 	const CGObjectInstance * owner;
 
-	CStatusBar * statusBar;
+	CGStatusBar * statusBar;
 	AdventureMapButton * exitb;
 	SDL_Surface * background;
 	CMinorResDataBar * resdatabar;

+ 7 - 1
client/NetPacksClient.cpp

@@ -343,10 +343,12 @@ void HeroRecruited::applyCl( CClient *cl )
 
 	CGI->mh->initHeroDef(h);
 	CGI->mh->printObject(h);
+		
 	if(vstd::contains(cl->playerint,h->tempOwner))
 	{
 		cl->playerint[h->tempOwner]->heroCreated(h);
-		cl->playerint[h->tempOwner]->heroInGarrisonChange(GS(cl)->getTown(tid));
+		if(const CGTownInstance *t = GS(cl)->getTown(tid))
+			cl->playerint[h->tempOwner]->heroInGarrisonChange(t);
 	}
 }
 
@@ -733,6 +735,10 @@ void OpenWindow::applyCl(CClient *cl)
 		{
 			INTERFACE_CALL_IF_PRESENT(id1, showPuzzleMap);
 		}
+	case TAVERN_WINDOW:
+		const CGObjectInstance *obj1 = cl->getObj(id1),
+								*obj2 = cl->getObj(id2);
+		INTERFACE_CALL_IF_PRESENT(obj1->tempOwner, showTavernWindow, obj2);
 		break;
 	}
 

+ 15 - 0
hch/CObjectHandler.cpp

@@ -383,6 +383,12 @@ bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const  //screen p
 
 void CGObjectInstance::initObj()
 {
+	switch(ID)
+	{
+	case 95:
+		blockVisit = true;
+		break;
+	}
 }
 
 void CGObjectInstance::setProperty( ui8 what, ui32 val )
@@ -474,6 +480,15 @@ void CGObjectInstance::giveDummyBonus(int heroID, ui8 duration) const
 
 void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
 {
+	switch(ID)
+	{
+	case 95:
+		OpenWindow ow;
+		ow.window = OpenWindow::TAVERN_WINDOW;
+		ow.id1 = h->id;
+		ow.id2 = id;
+		cb->sendAndApply(&ow);
+	}
 }
 
 ui8 CGObjectInstance::getPassableness() const

+ 6 - 1
lib/CGameState.cpp

@@ -893,7 +893,12 @@ CGTownInstance *CGameState::getTown(int objid)
 {
 	if(objid<0 || objid>=map->objects.size())
 		return NULL;
-	return static_cast<CGTownInstance *>(map->objects[objid]);
+	CGObjectInstance *obj = map->objects[objid];
+
+	if(obj->ID != TOWNI_TYPE)
+		return NULL;
+
+	return static_cast<CGTownInstance *>(obj);
 }
 
 const CGTownInstance * CGameState::getTown( int objid ) const

+ 6 - 0
lib/IGameCallback.cpp

@@ -8,6 +8,7 @@
 #include "../hch/CSpellHandler.h"
 #include "../lib/VCMI_Lib.h"
 #include <boost/random/linear_congruential.hpp>
+#include "../hch/CTownHandler.h"
 
 /*
  * IGameCallback.cpp, part of VCMI engine
@@ -233,3 +234,8 @@ const PlayerState * IGameCallback::getPlayerState( int color )
 {
 	return gs->getPlayer(color, false);
 }
+
+const CTown * IGameCallback::getNativeTown(int color)
+{
+	return &VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(color).castle];
+}

+ 2 - 0
lib/IGameCallback.h

@@ -36,6 +36,7 @@ class CArtifact;
 class CArmedInstance;
 struct TerrainTile;
 struct PlayerState;
+class CTown;
 
 class DLL_EXPORT IGameCallback
 {
@@ -67,6 +68,7 @@ public:
 	virtual int3 getMapSize(); //returns size of the map
 	virtual TerrainTile * getTile(int3 pos);
 	virtual const PlayerState * getPlayerState(int color);
+	virtual const CTown *getNativeTown(int color);
 
 	//do sth
 	virtual void changeSpells(int hid, bool give, const std::set<ui32> &spells)=0;

+ 5 - 3
lib/NetPacks.h

@@ -627,7 +627,8 @@ struct OpenWindow : public CPackForClient //517
 	OpenWindow(){type = 517;};
 	void applyCl(CClient *cl);
 
-	enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW, THIEVES_GUILD, PUZZLE_MAP, MARKET_WINDOW};
+	enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW, THIEVES_GUILD, PUZZLE_MAP, 
+					MARKET_WINDOW, TAVERN_WINDOW};
 	ui8 window;
 	ui32 id1, id2;
 
@@ -1434,12 +1435,13 @@ struct HireHero : public CPackForServer
 {
 	HireHero(){};
 	HireHero(si32 HID, si32 TID):hid(HID),tid(TID){};
-	si32 hid, tid; //available hero serial and town id
+	si32 hid, tid; //available hero serial and town (tavern) id
+	ui8 player;
 
 	bool applyGh(CGameHandler *gh);
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & hid & tid;
+		h & hid & tid & player;
 	}
 };
 

+ 6 - 2
lib/NetPacksLib.cpp

@@ -551,8 +551,12 @@ DLL_EXPORT void HeroRecruited::applyGs( CGameState *gs )
 	gs->getPlayer(h->getOwner())->heroes.push_back(h);
 	h->initObj();
 	gs->map->addBlockVisTiles(h);
-	t->visitingHero = h;
-	h->visitedTown = t;
+
+	if(t)
+	{
+		t->visitingHero = h;
+		h->visitedTown = t;
+	}
 	h->inTownGarrison = false;
 }
 

+ 33 - 20
server/CGameHandler.cpp

@@ -952,8 +952,6 @@ void CGameHandler::newTurn()
 
 		if(gs->getDate(1)==7) //first day of week - new heroes in tavern
 		{
-			const CTown *nativeTownType = &VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(i->first).castle];
-
 			SetAvailableHeroes sah;
 			sah.player = i->first;
 
@@ -961,7 +959,7 @@ void CGameHandler::newTurn()
 			CHeroClass *banned = NULL;
 			for (int j = 0; j < AVAILABLE_HEROES_PER_PLAYER; j++)
 			{
-				if(CGHeroInstance *h = gs->hpool.pickHeroFor(j == 0, i->first, nativeTownType, pool, banned)) //first hero - native if possible, second hero -> any other class
+				if(CGHeroInstance *h = gs->hpool.pickHeroFor(j == 0, i->first, getNativeTown(i->first), pool, banned)) //first hero - native if possible, second hero -> any other class
 				{
 					sah.hid[j] = h->subID;
 					h->initArmy(sah.army[j] = new CCreatureSet());
@@ -3279,35 +3277,47 @@ bool CGameHandler::setFormation( si32 hid, ui8 formation )
 	return true;
 }
 
-bool CGameHandler::hireHero( ui32 tid, ui8 hid )
+bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, ui8 player)
 {
-	const CGTownInstance *t = gs->getTown(tid);
-	const PlayerState *p = gs->getPlayer(t->tempOwner);
-
-	if(!vstd::contains(t->builtBuildings,5)  && complain("No tavern!")
-		|| p->resources[6]<2500  && complain("Not enough gold for buying hero!")
-		|| t->visitingHero  && complain("There is visiting hero - no place!")
-		|| getHeroCount(t->tempOwner,false) >= 8 && complain("Cannot hire hero, only 8 wandering heroes are allowed!")
-		)
+	const PlayerState *p = gs->getPlayer(player);
+	const CGTownInstance *t = gs->getTown(obj->id);
+
+	//common prconditions
+	if( p->resources[6]<2500  && complain("Not enough gold for buying hero!")
+		|| getHeroCount(player, false) >= 8 && complain("Cannot hire hero, only 8 wandering heroes are allowed!"))
 		return false;
+
+	if(t) //tavern in town
+	{
+		if(!vstd::contains(t->builtBuildings,5)  && complain("No tavern!")
+			|| t->visitingHero  && complain("There is visiting hero - no place!"))
+			return false;
+	}
+	else if(obj->ID == 95) //Tavern on adv map
+	{
+		if(getTile(obj->visitablePos())->visitableObjects.back() != obj  &&  complain("Tavern entry must be unoccupied!"))
+			return false;
+	}
+
+
 	CGHeroInstance *nh = p->availableHeroes[hid];
 	assert(nh);
 
 	HeroRecruited hr;
-	hr.tid = tid;
+	hr.tid = obj->id;
 	hr.hid = nh->subID;
-	hr.player = t->tempOwner;
-	hr.tile = t->pos - int3(1,0,0);
+	hr.player = player;
+	hr.tile = obj->visitablePos() + nh->getVisitableOffset();
 	sendAndApply(&hr);
 
 
 	std::map<ui32,CGHeroInstance *> pool = gs->unusedHeroesFromPool();
 
 	const CGHeroInstance *theOtherHero = p->availableHeroes[!hid];
-	const CGHeroInstance *newHero = gs->hpool.pickHeroFor(false, t->tempOwner,t->town, pool, theOtherHero->type->heroClass);
+	const CGHeroInstance *newHero = gs->hpool.pickHeroFor(false, player, getNativeTown(player), pool, theOtherHero->type->heroClass);
 
 	SetAvailableHeroes sah;
-	sah.player = t->tempOwner;
+	sah.player = player;
 
 	if(newHero)
 	{
@@ -3322,13 +3332,16 @@ bool CGameHandler::hireHero( ui32 tid, ui8 hid )
 	sendAndApply(&sah);
 
 	SetResource sr;
-	sr.player = t->tempOwner;
+	sr.player = player;
 	sr.resid = 6;
 	sr.val = p->resources[6] - 2500;
 	sendAndApply(&sr);
 
-	vistiCastleObjects (t, nh);
-	giveSpells (t,nh);
+	if(t)
+	{
+		vistiCastleObjects (t, nh);
+		giveSpells (t,nh);
+	}
 	return true;
 }
 

+ 1 - 1
server/CGameHandler.h

@@ -166,7 +166,7 @@ public:
 	void handleSpellCasting(int spellID, int spellLvl, int destination, ui8 casterSide, ui8 casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero, int usedSpellPower);
 	bool makeCustomAction(BattleAction &ba);
 	bool queryReply( ui32 qid, ui32 answer );
-	bool hireHero( ui32 tid, ui8 hid );
+	bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
 	bool buildBoat( ui32 objid );
 	bool setFormation( si32 hid, ui8 formation );
 	bool tradeResources(const IMarket *market, ui32 val, ui8 player, ui32 id1, ui32 id2);

+ 7 - 2
server/NetPacksServer.cpp

@@ -171,8 +171,13 @@ bool SetFormation::applyGh( CGameHandler *gh )
 
 bool HireHero::applyGh( CGameHandler *gh )
 {
-	ERROR_IF_NOT_OWNS(tid);
-	return gh->hireHero(tid,hid);
+	const CGObjectInstance *obj = gh->getObj(tid);
+
+	if(obj->ID == TOWNI_TYPE)
+		ERROR_IF_NOT_OWNS(tid);
+	//TODO check for visiting hero
+
+	return gh->hireHero(obj, hid,player);
 }
 
 bool BuildBoat::applyGh( CGameHandler *gh )