Ver código fonte

Fix crash, fix invisible boat blocking the tile

Tomasz Zieliński 2 anos atrás
pai
commit
f6247164ad

+ 4 - 6
lib/NetPacksLib.cpp

@@ -1382,9 +1382,8 @@ void HeroRecruited::applyGs(CGameState * gs) const
 		auto * boat = dynamic_cast<CGBoat *>(obj);
 		if (boat)
 		{
-			h->boat = boat;
-			h->attachTo(*boat);
-			boat->hero = h;
+			gs->map->removeBlockVisTiles(boat);
+			h->attachToBoat(boat);
 		}
 	}
 
@@ -1419,9 +1418,8 @@ void GiveHero::applyGs(CGameState * gs) const
 		auto * boat = dynamic_cast<CGBoat *>(obj);
 		if (boat)
 		{
-			h->boat = boat;
-			h->attachTo(*boat);
-			boat->hero = h;
+			gs->map->removeBlockVisTiles(boat);
+			h->attachToBoat(boat);
 		}
 	}
 

+ 1 - 2
lib/gameState/CGameState.cpp

@@ -857,8 +857,7 @@ void CGameState::initHeroes()
 			map->objects.emplace_back(boat);
 			map->addBlockVisTiles(boat);
 
-			boat->hero = hero;
-			hero->boat = boat;
+			hero->attachToBoat(boat);
 		}
 	}
 

+ 15 - 3
lib/mapObjects/CGHeroInstance.cpp

@@ -484,9 +484,12 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
 			if (cb->gameState()->map->getTile(boatPos).isWater())
 			{
 				smp.val = movementPointsLimit(false);
-				//Create a new boat for hero
-				cb->createObject(boatPos, Obj::BOAT, getBoatType().getNum());
-				boatId = cb->getTopObj(boatPos)->id;
+				if (!boat)
+				{
+					//Create a new boat for hero
+					cb->createObject(boatPos, Obj::BOAT, getBoatType().getNum());
+					boatId = cb->getTopObj(boatPos)->id;
+				}
 			}
 			else
 			{
@@ -1119,6 +1122,15 @@ int CGHeroInstance::maxSpellLevel() const
 	return std::min(GameConstants::SPELL_LEVELS, valOfBonuses(Selector::type()(BonusType::MAX_LEARNABLE_SPELL_LEVEL)));
 }
 
+void CGHeroInstance::attachToBoat(CGBoat* newBoat)
+{
+	assert(newBoat);
+	boat = newBoat;
+	attachTo(const_cast<CGBoat&>(*boat));
+	const_cast<CGBoat*>(boat)->hero = this;
+}
+
+
 void CGHeroInstance::deserializationFix()
 {
 	artDeserializationFix(this);

+ 1 - 0
lib/mapObjects/CGHeroInstance.h

@@ -282,6 +282,7 @@ public:
 	void getCastDescription(const spells::Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const override;
 	void spendMana(ServerCallback * server, const int spellCost) const override;
 
+	void attachToBoat(CGBoat* newBoat);
 	void boatDeserializationFix();
 	void deserializationFix();
 

+ 5 - 4
server/HeroPoolProcessor.cpp

@@ -237,18 +237,19 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
 		gameHandler->complain("Hero is not available for hiring!");
 		return false;
 	}
+	const auto targetPos = mapObject->visitablePos();
 
 	HeroRecruited hr;
 	hr.tid = mapObject->id;
 	hr.hid = recruitedHero->subID;
 	hr.player = player;
-	hr.tile = recruitedHero->convertFromVisitablePos(mapObject->visitablePos());
-	if(gameHandler->getTile(hr.tile)->isWater())
+	hr.tile = recruitedHero->convertFromVisitablePos(targetPos );
+	if(gameHandler->getTile(hr.tile)->isWater() && !recruitedHero->boat)
 	{
 		//Create a new boat for hero
-		gameHandler->createObject(mapObject->visitablePos(), Obj::BOAT, recruitedHero->getBoatType().getNum());
+		gameHandler->createObject(targetPos , Obj::BOAT, recruitedHero->getBoatType().getNum());
 
-		hr.boatId = gameHandler->getTopObj(hr.tile)->id;
+		hr.boatId = gameHandler->getTopObj(targetPos)->id;
 	}
 
 	// apply netpack -> this will remove hired hero from pool