mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- Option to configure monster types spawning in a zone
- 25% chance to get neutral faction in zone with no town
This commit is contained in:
		| @@ -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); | ||||
|   | ||||
| @@ -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) | ||||
| 	{ | ||||
|   | ||||
| @@ -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 | ||||
| 	}; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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") | ||||
|   | ||||
| @@ -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 * | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user