Sfoglia il codice sorgente

- Option to configure monster types spawning in a zone
- 25% chance to get neutral faction in zone with no town

DjWarmonger 11 anni fa
parent
commit
ce83db0f43

+ 11 - 2
lib/CTownHandler.cpp

@@ -767,10 +767,19 @@ std::vector<bool> CTownHandler::getDefaultAllowed() const
 	}
 	return allowedFactions;
 }
-std::set<TFaction> CTownHandler::getAllowedFactions() const
+std::set<TFaction> CTownHandler::getAllowedFactions(bool withTown /*=true*/) const
 {
 	std::set<TFaction> allowedFactions;
-	auto allowed = getDefaultAllowed();
+	std::vector<bool> allowed;
+	if (withTown)
+		allowed = getDefaultAllowed();
+	else
+	{
+		for (auto town : factions)
+		{
+			allowed.push_back (true);
+		}
+	}
 	for (size_t i=0; i<allowed.size(); i++)
 		if (allowed[i])
 			allowedFactions.insert(i);

+ 1 - 1
lib/CTownHandler.h

@@ -266,7 +266,7 @@ public:
 	void afterLoadFinalization() override;
 
 	std::vector<bool> getDefaultAllowed() const override;
-	std::set<TFaction> getAllowedFactions() const;
+	std::set<TFaction> getAllowedFactions(bool withTown = true) const;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 1 - 1
lib/GameConstants.h

@@ -299,7 +299,7 @@ namespace ETownType
 	enum ETownType
 	{
 		ANY = -1,
-		CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX
+		CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX, NEUTRAL
 	};
 }
 

+ 31 - 21
lib/rmg/CRmgTemplateStorage.cpp

@@ -47,7 +47,7 @@ void CJsonRmgTemplateLoader::loadTemplates()
 
 			// Parse zones
 			std::map<TRmgTemplateZoneId, CRmgTemplateZone *> zones;
-			for(const auto & zonePair : templateNode["zones"].Struct())
+			for (const auto & zonePair : templateNode["zones"].Struct())
 			{
 				auto zone = new CRmgTemplateZone();
 				auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
@@ -56,7 +56,7 @@ void CJsonRmgTemplateLoader::loadTemplates()
 				const auto & zoneNode = zonePair.second;
 				zone->setType(parseZoneType(zoneNode["type"].String()));
 				zone->setSize(zoneNode["size"].Float());
-				if(!zoneNode["owner"].isNull()) zone->setOwner(zoneNode["owner"].Float());
+				if (!zoneNode["owner"].isNull()) zone->setOwner(zoneNode["owner"].Float());
 
 				zone->setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
 				zone->setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
@@ -65,32 +65,42 @@ void CJsonRmgTemplateLoader::loadTemplates()
 				zone->setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone->getDefaultTerrainTypes()));
 				zone->setTownsAreSameType((zoneNode["townsAreSameType"].Bool()));
 
-				std::set<TFaction> allowedTownTypes;
-				if (zoneNode["allowedTowns"].isNull())
-					allowedTownTypes = zone->getDefaultTownTypes();
-				else
+				for (int i = 0; i < 2; ++i)
 				{
-					for (const JsonNode & allowedTown : zoneNode["allowedTowns"].Vector())
+					std::set<TFaction> allowedTownTypes;
+					if (zoneNode[i ? "allowedTowns" : "allowedMonsters"].isNull())
 					{
-						//complain if the town type is not present in our game
-						boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false);
-						if (id.is_initialized())
-							allowedTownTypes.insert (id.get());
+						if (i)
+							allowedTownTypes = zone->getDefaultTownTypes();
+						else
+							allowedTownTypes = VLC->townh->getAllowedFactions(false);
+					}
+					else
+					{
+						for (const JsonNode & allowedTown : zoneNode[i ? "allowedTowns" : "allowedMonsters"].Vector())
+						{
+							//complain if the town type is not present in our game
+							boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false);
+							if (id.is_initialized())
+								allowedTownTypes.insert(id.get());
+						}
 					}
-				}
 
-				if (!zoneNode["bannedTowns"].isNull())
-				{
-					for (const JsonNode & bannedTown : zoneNode["bannedTowns"].Vector())
+					if (!zoneNode[i ? "bannedTowns" : "bannedMonsters"].isNull())
 					{
-						//erase unindentified towns silently
-						boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true);
-						if (id.is_initialized())
-							vstd::erase_if_present(allowedTownTypes, id.get());
+						for (const JsonNode & bannedTown : zoneNode[i ? "bannedTowns" : "bannedMonsters"].Vector())
+						{
+							//erase unindentified towns silently
+							boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true);
+							if (id.is_initialized())
+								vstd::erase_if_present(allowedTownTypes, id.get());
+						}
 					}
+					if (i)
+						zone->setTownTypes(allowedTownTypes);
+					else
+						zone->setMonsterTypes(allowedTownTypes);
 				}
-				assert(allowedTownTypes.size());
-				zone->setTownTypes (allowedTownTypes);
 
 				const std::string monsterStrength = zoneNode["monsters"].String();
 				if (monsterStrength == "weak")

+ 44 - 8
lib/rmg/CRmgTemplateZone.cpp

@@ -136,7 +136,7 @@ CRmgTemplateZone::CRmgTemplateZone() :
 	size(1),
 	townsAreSameType(false),
 	matchTerrainToTown(true),
-	townType(0),
+	townType(ETownType::NEUTRAL),
 	terrainType (ETerrainType::GRASS),
 	zoneMonsterStrength(EMonsterStrength::ZONE_NORMAL),
 	totalDensity(0)
@@ -228,6 +228,10 @@ void CRmgTemplateZone::setTownTypes(const std::set<TFaction> & value)
 {
 	townTypes = value;
 }
+void CRmgTemplateZone::setMonsterTypes(const std::set<TFaction> & value)
+{
+	monsterTypes = value;
+}
 
 std::set<TFaction> CRmgTemplateZone::getDefaultTownTypes() const
 {
@@ -635,6 +639,8 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength,
 	{
 		if (cre->special)
 			continue;
+		if (!vstd::contains(monsterTypes, cre->faction))
+			continue;
 		if ((cre->AIValue * (cre->ammMin + cre->ammMax) / 2 < strength) && (strength < cre->AIValue * 100)) //at least one full monster. size between minimum size of given stack and 100
 		{
 			possibleCreatures.push_back(cre->idNumber);
@@ -950,7 +956,12 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
 			if (this->townsAreSameType)
 				town->subID = townType;
 			else
-				town->subID = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
+			{
+				if (townTypes.size())
+					town->subID = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
+				else
+					town->subID = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed
+			}
 
 			town->tempOwner = player;
 			if (hasFort)
@@ -992,7 +1003,12 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
 			townType = gen->mapGenOptions->getPlayersSettings().find(player)->second.getStartingTown();
 
 			if (townType == CMapGenOptions::CPlayerSettings::RANDOM_TOWN)
-				townType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
+			{
+				if (townTypes.size())
+					townType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
+				else
+					townType = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed
+			}
 			
 			auto  town = new CGTownInstance();
 			town->ID = Obj::TOWN;
@@ -1044,12 +1060,29 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
 
 	addNewTowns (neutralTowns.getCastleCount(), true, PlayerColor::NEUTRAL);
 	addNewTowns (neutralTowns.getTownCount(), false, PlayerColor::NEUTRAL);
+
+	if (!totalTowns) //if there's no town present, get random faction for dwellings and pandoras
+	{
+		//25% chance for neutral
+		if (gen->rand.nextInt(1, 100) <= 25)
+		{
+			townType = ETownType::NEUTRAL;
+		}
+		else
+		{
+			if (townTypes.size())
+				townType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
+			else if (monsterTypes.size())
+				townType = *RandomGeneratorUtil::nextItem(monsterTypes, gen->rand); //this happens in Clash of Dragons in treasure zones, where all towns are banned
+		}
+
+	}
 }
 
 void CRmgTemplateZone::initTerrainType (CMapGenerator* gen)
 {
 
-	if (matchTerrainToTown)
+	if (matchTerrainToTown && townType != ETownType::NEUTRAL)
 		terrainType = VLC->townh->factions[townType]->nativeTerrain;
 	else
 		terrainType = *RandomGeneratorUtil::nextItem(terrainTypes, gen->rand);
@@ -1945,12 +1978,15 @@ void CRmgTemplateZone::addAllPossibleObjects (CMapGenerator* gen)
 
 	for (auto creature : VLC->creh->creatures)
 	{
-		if (!creature->special && VLC->townh->factions[creature->faction]->nativeTerrain == terrainType)
+		if (!creature->special && creature->faction == townType)
 		{
 			int actualTier = creature->level > 7 ? 6 : creature->level-1;
-			int creaturesAmount = tierValues[actualTier] / creature->AIValue;
+			float creaturesAmount = tierValues[actualTier] / creature->AIValue;
 			if (creaturesAmount <= 5)
 			{
+				creaturesAmount = boost::math::round(creaturesAmount); //allow single monsters
+				if (creaturesAmount < 1)
+					continue;
 			}
 			else if (creaturesAmount <= 12)
 			{
@@ -1958,11 +1994,11 @@ void CRmgTemplateZone::addAllPossibleObjects (CMapGenerator* gen)
 			}
 			else if (creaturesAmount <= 50)
 			{
-				creaturesAmount = boost::math::round((float)creaturesAmount / 5) * 5;
+				creaturesAmount = boost::math::round(creaturesAmount / 5) * 5;
 			}
 			else if (creaturesAmount <= 12)
 			{
-				creaturesAmount = boost::math::round((float)creaturesAmount / 10) * 10;
+				creaturesAmount = boost::math::round(creaturesAmount / 10) * 10;
 			}
 
 			oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance *

+ 2 - 0
lib/rmg/CRmgTemplateZone.h

@@ -129,6 +129,7 @@ public:
 	void setTownsAreSameType(bool value);
 	const std::set<TFaction> & getTownTypes() const; /// Default: all
 	void setTownTypes(const std::set<TFaction> & value);
+	void setMonsterTypes(const std::set<TFaction> & value);
 	std::set<TFaction> getDefaultTownTypes() const;
 	bool getMatchTerrainToTown() const; /// Default: true
 	void setMatchTerrainToTown(bool value);
@@ -186,6 +187,7 @@ private:
 	CTownInfo playerTowns, neutralTowns;
 	bool townsAreSameType;
 	std::set<TFaction> townTypes;
+	std::set<TFaction> monsterTypes;
 	bool matchTerrainToTown;
 	std::set<ETerrainType> terrainTypes;
 	std::map<TResource, ui16> mines; //obligatory mines to spawn in this zone