Browse Source

Fixed #109, #352, #359.
Possibly also #344, #353.
Allowed switching heroes with l-click when another hero is selected. (works for not accessible heroes)

Michał W. Urbańczyk 16 năm trước cách đây
mục cha
commit
96819379c5

+ 10 - 6
client/CAdvmapInterface.cpp

@@ -521,14 +521,18 @@ void CTerrainRect::clickLeft(tribool down, bool previousState)
 		{
 			for(size_t i=0; i < bobjs.size(); ++i)
 			{
-				if(bobjs[i]->ID == TOWNI_TYPE && bobjs[i]->tempOwner == LOCPLINT->playerID) //town - switch selection to it
+				const CGObjectInstance *o = bobjs[i];
+				const CGPathNode *pn = LOCPLINT->cb->getPathInfo(mp);
+				if(  ((o->ID == HEROI_TYPE && pn->turns == 255)  //inaccessible hero
+							|| o->ID == TOWNI_TYPE)										   //or town
+					&& o->tempOwner == LOCPLINT->playerID) //but must belong to us
 				{
-					LOCPLINT->adventureInt->select(static_cast<const CArmedInstance*>(bobjs[i]));
+					LOCPLINT->adventureInt->select(static_cast<const CArmedInstance*>(o));
 					return;
 				}
-				else if(bobjs[i]->ID == HEROI_TYPE //it's a hero
-					&& bobjs[i]->tempOwner == LOCPLINT->playerID  //our hero (is this condition needed?)
-					&& currentHero == (bobjs[i]) ) //and selected one 
+				else if(o->ID == HEROI_TYPE //it's a hero
+					&& o->tempOwner == LOCPLINT->playerID  //our hero (is this condition needed?)
+					&& currentHero == (o) ) //and selected one 
 				{
 					LOCPLINT->openHeroWindow(currentHero);
 					return;
@@ -715,7 +719,7 @@ void CTerrainRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
 	{
 		if(LOCPLINT->adventureInt->selection->ID == TOWNI_TYPE)
 		{
-			if(obj)
+			if(obj && obj->tempOwner == LOCPLINT->playerID)
 			{
 				if(obj->ID == TOWNI_TYPE)
 				{

+ 8 - 2
client/CPlayerInterface.cpp

@@ -142,6 +142,8 @@ void CPlayerInterface::init(ICallback * CB)
 void CPlayerInterface::yourTurn()
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
+	boost::unique_lock<boost::mutex> lock(eventsM); //block handling events until interface is ready
+
 	LOCPLINT = this;
 	makingTurn = true;
 
@@ -1069,7 +1071,7 @@ void CPlayerInterface::showShipyardDialog(const IShipyard *obj)
 	int state = obj->state();
 	std::vector<si32> cost;
 	obj->getBoatCost(cost);
-	CShipyardWindow *csw = new CShipyardWindow(cost, state, boost::bind(&CCallback::buildBoat, cb, obj));
+	CShipyardWindow *csw = new CShipyardWindow(cost, state, obj->getBoatType(), boost::bind(&CCallback::buildBoat, cb, obj));
 	GH.pushInt(csw);
 }
 
@@ -1119,7 +1121,11 @@ bool CPlayerInterface::ctrlPressed() const
 
 void CPlayerInterface::update()
 {
-	pim->lock();
+	while(!terminate_cond.get() && !pim->try_lock()) //try acquiring long until it succeeds or we are told to terminate
+		boost::this_thread::sleep(boost::posix_time::milliseconds(15));
+
+	if(terminate_cond.get())
+		return;
 
 	//if there are any waiting dialogs, show them
 	if(dialogs.size() && !showingDialog->get())

+ 1 - 1
client/CPreGame.cpp

@@ -110,7 +110,7 @@ CMenuScreen::CMenuScreen( EState which )
 			////just for testing
 			CCampaignHandler * ch = new CCampaignHandler();
 			ch->getCampaignHeaders(); 
-			ch->getCampaign("./Maps/ALEXIS.h3c");
+			//ch->getCampaign("./Maps/ALEXIS.h3c");
 		}
 		break;
 	}

+ 2 - 1
client/Client.cpp

@@ -171,6 +171,8 @@ void CClient::stop()
 	// Game is ending
 	// Tell the network thread to reach a stable state
 	terminate = true;
+	GH.curInt = NULL;
+	LOCPLINT->terminate_cond.setn(true);
 	LOCPLINT->pim->lock();
 	endGame();
 }
@@ -189,7 +191,6 @@ void CClient::save(const std::string & fname)
 void CClient::endGame()
 {
 	tlog0 << "\n\nEnding current game!" << std::endl;
-	GH.curInt = NULL;
 	if(GH.topInt())
 		GH.topInt()->deactivate();
 	GH.listInt.clear();

+ 3 - 2
client/GUIClasses.cpp

@@ -4652,7 +4652,7 @@ void CShipyardWindow::deactivate()
 void CShipyardWindow::show( SDL_Surface * to )
 {
 	blitAt(bg,pos,to);
-	CSDL_Ext::blit8bppAlphaTo24bpp(graphics->boatAnims[1]->ourImages[21 + frame++/8%8].bitmap, NULL, to, &genRect(64, 96, pos.x+110, pos.y+85));
+	CSDL_Ext::blit8bppAlphaTo24bpp(graphics->boatAnims[boat]->ourImages[21 + frame++/8%8].bitmap, NULL, to, &genRect(64, 96, pos.x+110, pos.y+85));
 	build->show(to);
 	quit->show(to);
 }
@@ -4663,8 +4663,9 @@ CShipyardWindow::~CShipyardWindow()
 	delete quit;
 }
 
-CShipyardWindow::CShipyardWindow(const std::vector<si32> &cost, int state, const boost::function<void()> &onBuy)
+CShipyardWindow::CShipyardWindow(const std::vector<si32> &cost, int state, int boatType, const boost::function<void()> &onBuy)
 {
+	boat = boatType;
 	frame = 0;
 	SDL_Surface * bgtemp; //loaded as 8bpp surface
 	bgtemp = BitmapHandler::loadBitmap("TPSHIP.bmp");

+ 2 - 1
client/GUIClasses.h

@@ -802,11 +802,12 @@ public:
 	AdventureMapButton *build, *quit;
 
 	unsigned char frame; //frame of the boat animation
+	int boat; //which boat graphic should be used
 
 	void activate();
 	void deactivate();
 	void show(SDL_Surface * to);
-	CShipyardWindow(const std::vector<si32> &cost, int state, const boost::function<void()> &onBuy);
+	CShipyardWindow(const std::vector<si32> &cost, int state, int boatType, const boost::function<void()> &onBuy);
 	~CShipyardWindow();
 };
 

+ 20 - 3
hch/CObjectHandler.cpp

@@ -1442,7 +1442,7 @@ int CGTownInstance::getSightRadious() const //returns sight distance
 {
 	if (subID == 2) //tower
 	{
-		if ((builtBuildings.find(17)) != builtBuildings.end()) //skyship
+		if ((builtBuildings.find(26)) != builtBuildings.end()) //skyship
 			return -1; //entire map
 		else if ((builtBuildings.find(21)) != builtBuildings.end()) //lookout tower
 			return 20;
@@ -1732,6 +1732,11 @@ int3 CGTownInstance::getSightCenter() const
 	return pos - int3(2,0,0);
 }
 
+ui8 CGTownInstance::getPassableness() const
+{
+	return army ? 1<<tempOwner : ALL_PLAYERS; //if there is garrison, castle be entered only by owner //TODO: allies
+}
+
 void CGTownInstance::getOutOffsets( std::vector<int3> &offsets ) const
 {
 	offsets += int3(-1,2,0), int3(-3,2,0);
@@ -1771,9 +1776,15 @@ void CGTownInstance::removeCapitols (ui8 owner, bool me) const
 	} 
 } 
 
-ui8 CGTownInstance::getPassableness() const
+int CGTownInstance::getBoatType() const
 {
-	return army ? 1<<tempOwner : ALL_PLAYERS; //if there is garrison, castle be entered only by owner //TODO: allies
+	const CCreature *c = &VLC->creh->creatures[town->basicCreatures.front()];
+	if (c->isGood())
+		return 1;
+	else if (c->isEvil())
+		return 0;
+	else //neutral
+		return 2;
 }
 
 void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const
@@ -5363,6 +5374,12 @@ const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj )
 	return castFrom(const_cast<CGObjectInstance*>(obj));
 }
 
+int IShipyard::getBoatType() const
+{
+	//We make good ships by default
+	return 1;
+}
+
 CGShipyard::CGShipyard()
 	:IShipyard(this)
 {

+ 3 - 1
hch/CObjectHandler.h

@@ -121,7 +121,8 @@ public:
 	const CGObjectInstance *o;
 
 	IShipyard(const CGObjectInstance *O);
-	void getBoatCost(std::vector<si32> &cost) const;
+	virtual void getBoatCost(std::vector<si32> &cost) const;
+	virtual int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
 	virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed
 	//virtual bool validLocation() const; //returns true if there is a water tile near where boat can be placed
 	int3 bestLocation() const; //returns location when the boat should be placed
@@ -484,6 +485,7 @@ public:
 	ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used
 	int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
 	int getSightRadious() const; //returns sight distance
+	int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
 	void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
 	void setPropertyDer(ui8 what, ui32 val);
 	void newTurn() const;

+ 1 - 10
server/CGameHandler.cpp

@@ -3616,16 +3616,7 @@ bool CGameHandler::buildBoat( ui32 objid )
 	//create boat
 	NewObject no;
 	no.ID = 8;
-	if (obj->o->ID == TOWNI_TYPE)
-	{ //check what kind  of creatures are avaliable in town
-		if (VLC->creh->creatures[(static_cast<const CGTownInstance*>(obj))->creatures[0].second[0]].isGood())
-			boatType = 1;
-		else if (VLC->creh->creatures[(static_cast<const CGTownInstance*>(obj))->creatures[0].second[0]].isEvil())
-			boatType = 0;
-		else //neutral
-			boatType = 2;
-	}
-	no.subID = boatType;
+	no.subID = obj->getBoatType();
 	no.pos = tile + int3(1,0,0);
 	sendAndApply(&no);