Browse Source

Block usage of preselected starting heroes for prisons in RMG

Ivan Savenko 1 year ago
parent
commit
ca2df49fbb

+ 19 - 1
lib/rmg/CMapGenOptions.cpp

@@ -388,6 +388,13 @@ void CMapGenOptions::setStartingTownForPlayer(const PlayerColor & color, Faction
 	it->second.setStartingTown(town);
 }
 
+void CMapGenOptions::setStartingHeroForPlayer(const PlayerColor & color, HeroTypeID hero)
+{
+	auto it = players.find(color);
+	assert(it != players.end());
+	it->second.setStartingHero(hero);
+}
+
 void CMapGenOptions::setPlayerTypeForStandardPlayer(const PlayerColor & color, EPlayerType playerType)
 {
 	// FIXME: Why actually not set it to COMP_ONLY? Ie. when swapping human to another color?
@@ -746,7 +753,7 @@ const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & rand
 	return *RandomGeneratorUtil::nextItem(templates, rand);
 }
 
-CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(FactionID::RANDOM), playerType(EPlayerType::AI), team(TeamID::NO_TEAM)
+CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(FactionID::RANDOM), startingHero(HeroTypeID::RANDOM), playerType(EPlayerType::AI), team(TeamID::NO_TEAM)
 {
 
 }
@@ -778,6 +785,17 @@ void CMapGenOptions::CPlayerSettings::setStartingTown(FactionID value)
 	startingTown = value;
 }
 
+HeroTypeID CMapGenOptions::CPlayerSettings::getStartingHero() const
+{
+	return startingHero;
+}
+
+void CMapGenOptions::CPlayerSettings::setStartingHero(HeroTypeID value)
+{
+	assert(value == HeroTypeID::RANDOM || value.toEntity(VLC) != nullptr);
+	startingHero = value;
+}
+
 EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const
 {
 	return playerType;

+ 11 - 0
lib/rmg/CMapGenOptions.h

@@ -45,6 +45,11 @@ public:
 		FactionID getStartingTown() const;
 		void setStartingTown(FactionID value);
 
+		/// The starting hero of the player ranging from 0 to hero max count or RANDOM_HERO.
+		/// The default value is RANDOM_HERO
+		HeroTypeID getStartingHero() const;
+		void setStartingHero(HeroTypeID value);
+
 		/// The default value is EPlayerType::AI.
 		EPlayerType getPlayerType() const;
 		void setPlayerType(EPlayerType value);
@@ -56,6 +61,7 @@ public:
 	private:
 		PlayerColor color;
 		FactionID startingTown;
+		HeroTypeID startingHero;
 		EPlayerType playerType;
 		TeamID team;
 
@@ -68,6 +74,10 @@ public:
 			h & playerType;
 			if(version >= 806)
 				h & team;
+			if (version >= 832)
+				h & startingHero;
+			else
+				startingHero = HeroTypeID::RANDOM;
 		}
 	};
 
@@ -120,6 +130,7 @@ public:
 	const std::map<PlayerColor, CPlayerSettings> & getPlayersSettings() const;
 	const std::map<PlayerColor, CPlayerSettings> & getSavedPlayersMap() const;
 	void setStartingTownForPlayer(const PlayerColor & color, FactionID town);
+	void setStartingHeroForPlayer(const PlayerColor & color, HeroTypeID hero);
 	/// Sets a player type for a standard player. A standard player is the opposite of a computer only player. The
 	/// values which can be chosen for the player type are EPlayerType::AI or EPlayerType::HUMAN.
 	void setPlayerTypeForStandardPlayer(const PlayerColor & color, EPlayerType playerType);

+ 14 - 7
lib/rmg/CMapGenerator.cpp

@@ -491,14 +491,21 @@ const std::vector<HeroTypeID> CMapGenerator::getAllPossibleHeroes() const
 	for (HeroTypeID hero : map->getMap(this).allowedHeroes)
 	{
 		auto * h = dynamic_cast<const CHero*>(VLC->heroTypes()->getById(hero));
-		if ((h->onlyOnWaterMap && !isWaterMap) || (h->onlyOnMapWithoutWater && isWaterMap))
-		{
+		if(h->onlyOnWaterMap && !isWaterMap)
 			continue;
-		}
-		else
-		{
-			ret.push_back(hero);
-		}
+
+		if(h->onlyOnMapWithoutWater && isWaterMap)
+			continue;
+
+		bool heroUsedAsStarting = false;
+		for (auto const & player : map->getMapGenOptions().getPlayersSettings())
+			if (player.second.getStartingHero() == hero)
+				heroUsedAsStarting = true;
+
+		if (heroUsedAsStarting)
+			continue;
+
+		ret.push_back(hero);
 	}
 	return ret;
 }

+ 1 - 1
lib/serializer/CSerializer.h

@@ -14,7 +14,7 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-const ui32 SERIALIZATION_VERSION = 831;
+const ui32 SERIALIZATION_VERSION = 832;
 const ui32 MINIMAL_SERIALIZATION_VERSION = 831;
 const std::string SAVEGAME_MAGIC = "VCMISVG";
 

+ 1 - 0
server/CVCMIServer.cpp

@@ -762,6 +762,7 @@ void CVCMIServer::updateAndPropagateLobbyState()
 		{
 			const auto & pset = psetPair.second;
 			si->mapGenOptions->setStartingTownForPlayer(pset.color, pset.castle);
+			si->mapGenOptions->setStartingHeroForPlayer(pset.color, pset.hero);
 			if(pset.isControlledByHuman())
 			{
 				si->mapGenOptions->setPlayerTypeForStandardPlayer(pset.color, EPlayerType::HUMAN);