mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Rmg water support (#751)
* Roads added to shipyard * Load general rmg parameters from config * Fix issue with default zone guard * Move magic numbers related to balance to randomMap.json
This commit is contained in:
		
				
					committed by
					
						 Andrii Danylchenko
						Andrii Danylchenko
					
				
			
			
				
	
			
			
			
						parent
						
							5c1a66ab69
						
					
				
				
					commit
					5054ee011a
				
			
							
								
								
									
										59
									
								
								config/randomMap.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								config/randomMap.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | { | ||||||
|  |   "terrain" : | ||||||
|  |   { | ||||||
|  |     "undergroundAllow" : ["lava"], //others to be replaced by subterranena | ||||||
|  |     "groundProhibit" : ["subterranean"] //to be replaced by dirt | ||||||
|  |   }, | ||||||
|  |   "waterZone" : | ||||||
|  |   { | ||||||
|  |     "treasure" : | ||||||
|  |     [ | ||||||
|  |         { "min" : 2000, "max" : 6000, "density" : 1 }, | ||||||
|  |         { "min" : 100, "max" : 1000, "density" : 5 } | ||||||
|  |     ], | ||||||
|  |     "shipyard" : | ||||||
|  |     { | ||||||
|  |       "value" : 3500 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "mines" : | ||||||
|  |   { | ||||||
|  |     "value" : | ||||||
|  |     { | ||||||
|  |       "wood" : 1500, | ||||||
|  |       "ore" : 1500, | ||||||
|  |       "gems" : 3500, | ||||||
|  |       "crystal" : 3500, | ||||||
|  |       "mercury" : 3500, | ||||||
|  |       "sulfur" : 3500, | ||||||
|  |       "gold" : 7000 | ||||||
|  |     }, | ||||||
|  |     "extraResourcesLimit" : 3 | ||||||
|  |   }, | ||||||
|  |   "minGuardStrength" : 2000, | ||||||
|  |   "defaultRoadType" : "cobblestone_road", | ||||||
|  |   "treasureValueLimit" : 20000, //generate pandora with gold for treasure above this limit | ||||||
|  |   "prisons" : | ||||||
|  |   { | ||||||
|  |     "experience" : [0, 5000, 15000, 90000, 500000], | ||||||
|  |     "value" : [2500, 5000, 10000, 20000, 30000], | ||||||
|  |   }, | ||||||
|  |   "scrolls" : | ||||||
|  |   { | ||||||
|  |     "value" : [500, 2000, 3000, 4000, 5000], | ||||||
|  |   }, | ||||||
|  |   "pandoras" : | ||||||
|  |   { | ||||||
|  |     "valueMultiplierGold" : 5000, | ||||||
|  |     "valueMultiplierExperience" : 6000, | ||||||
|  |     "valueMultiplierSpells" : 2500, | ||||||
|  |     "valueSpellSchool" : 15000, | ||||||
|  |     "valueSpell60" : 30000, | ||||||
|  |     "creaturesValue" : [5000, 7000, 9000, 12000, 16000, 21000, 27000] | ||||||
|  |   }, | ||||||
|  |   "quests" :  | ||||||
|  |   { | ||||||
|  |     "value" : [2000, 5333, 8666, 12000], | ||||||
|  |     "rewardValue" : [5000, 10000, 15000, 20000] | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -60,6 +60,12 @@ | |||||||
| 					"minimum" : 0 | 					"minimum" : 0 | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		}, | ||||||
|  | 		"waterContent": | ||||||
|  | 		{ | ||||||
|  | 			"enum": ["none", "normal", "islands"], | ||||||
|  | 			"additionalProperties" : false, | ||||||
|  | 			"type": "string" | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| @@ -73,6 +79,10 @@ | |||||||
| 			"type": "array", | 			"type": "array", | ||||||
| 			"items":{"$ref" : "#/definitions/connection"}	 | 			"items":{"$ref" : "#/definitions/connection"}	 | ||||||
| 		}, | 		}, | ||||||
|  | 		"allowedWaterContent": { | ||||||
|  | 			"type": "array", | ||||||
|  | 			"items": {"$ref" : "#/definitions/waterContent"} | ||||||
|  | 		}, | ||||||
| 		"required" : ["zones", "connections"], | 		"required" : ["zones", "connections"], | ||||||
| 		"additionalProperties" : false | 		"additionalProperties" : false | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -246,7 +246,7 @@ void CMapGenOptions::finalize(CRandomGenerator & rand) | |||||||
|  |  | ||||||
| 	if(waterContent == EWaterContent::RANDOM) | 	if(waterContent == EWaterContent::RANDOM) | ||||||
| 	{ | 	{ | ||||||
| 		waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(EWaterContent::NONE, EWaterContent::ISLANDS)); | 		waterContent = *RandomGeneratorUtil::nextItem(mapTemplate->getWaterContentAllowed(), rand); | ||||||
| 	} | 	} | ||||||
| 	if(monsterStrength == EMonsterStrength::RANDOM) | 	if(monsterStrength == EMonsterStrength::RANDOM) | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -62,10 +62,89 @@ CMapGenerator::CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed) : | |||||||
| 	zonesTotal(0), tiles(nullptr), prisonsRemaining(0), | 	zonesTotal(0), tiles(nullptr), prisonsRemaining(0), | ||||||
|     monolithIndex(0) |     monolithIndex(0) | ||||||
| { | { | ||||||
|  | 	loadConfig(); | ||||||
| 	rand.setSeed(this->randomSeed); | 	rand.setSeed(this->randomSeed); | ||||||
| 	mapGenOptions.finalize(rand); | 	mapGenOptions.finalize(rand); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void CMapGenerator::loadConfig() | ||||||
|  | { | ||||||
|  | 	static std::map<std::string, ETerrainType> terrainMap | ||||||
|  | 	{ | ||||||
|  | 		{"dirt", ETerrainType::DIRT}, | ||||||
|  | 		{"sand", ETerrainType::SAND}, | ||||||
|  | 		{"grass", ETerrainType::GRASS}, | ||||||
|  | 		{"snow", ETerrainType::SNOW}, | ||||||
|  | 		{"swamp", ETerrainType::SWAMP}, | ||||||
|  | 		{"subterranean", ETerrainType::SUBTERRANEAN}, | ||||||
|  | 		{"lava", ETerrainType::LAVA}, | ||||||
|  | 		{"rough", ETerrainType::ROUGH} | ||||||
|  | 	}; | ||||||
|  | 	static const std::map<std::string, Res::ERes> resMap | ||||||
|  | 	{ | ||||||
|  | 		{"wood", Res::ERes::WOOD}, | ||||||
|  | 		{"ore", Res::ERes::ORE}, | ||||||
|  | 		{"gems", Res::ERes::GEMS}, | ||||||
|  | 		{"crystal", Res::ERes::CRYSTAL}, | ||||||
|  | 		{"mercury", Res::ERes::MERCURY}, | ||||||
|  | 		{"sulfur", Res::ERes::SULFUR}, | ||||||
|  | 		{"gold", Res::ERes::GOLD}, | ||||||
|  | 	}; | ||||||
|  | 	static std::map<std::string, ERoadType::ERoadType> roadTypeMap | ||||||
|  | 	{ | ||||||
|  | 		{"dirt_road", ERoadType::DIRT_ROAD}, | ||||||
|  | 		{"gravel_road", ERoadType::GRAVEL_ROAD}, | ||||||
|  | 		{"cobblestone_road", ERoadType::COBBLESTONE_ROAD} | ||||||
|  | 	}; | ||||||
|  | 	static const ResourceID path("config/randomMap.json"); | ||||||
|  | 	JsonNode randomMapJson(path); | ||||||
|  | 	for(auto& s : randomMapJson["terrain"]["undergroundAllow"].Vector()) | ||||||
|  | 	{ | ||||||
|  | 		if(!s.isNull()) | ||||||
|  | 			config.terrainUndergroundAllowed.push_back(terrainMap[s.String()]); | ||||||
|  | 	} | ||||||
|  | 	for(auto& s : randomMapJson["terrain"]["groundProhibit"].Vector()) | ||||||
|  | 	{ | ||||||
|  | 		if(!s.isNull()) | ||||||
|  | 			config.terrainGroundProhibit.push_back(terrainMap[s.String()]); | ||||||
|  | 	} | ||||||
|  | 	config.shipyardGuard = randomMapJson["waterZone"]["shipyard"]["value"].Integer(); | ||||||
|  | 	for(auto & treasure : randomMapJson["waterZone"]["treasure"].Vector()) | ||||||
|  | 	{ | ||||||
|  | 		config.waterTreasure.emplace_back(treasure["min"].Integer(), treasure["max"].Integer(), treasure["density"].Integer()); | ||||||
|  | 	} | ||||||
|  | 	for(auto& s : resMap) | ||||||
|  | 	{ | ||||||
|  | 		config.mineValues[s.second] = randomMapJson["mines"]["value"][s.first].Integer(); | ||||||
|  | 	} | ||||||
|  | 	config.mineExtraResources = randomMapJson["mines"]["extraResourcesLimit"].Integer(); | ||||||
|  | 	config.minGuardStrength = randomMapJson["minGuardStrength"].Integer(); | ||||||
|  | 	config.defaultRoadType = roadTypeMap[randomMapJson["defaultRoadType"].String()]; | ||||||
|  | 	config.treasureValueLimit = randomMapJson["treasureValueLimit"].Integer(); | ||||||
|  | 	for(auto & i : randomMapJson["prisons"]["experience"].Vector()) | ||||||
|  | 		config.prisonExperience.push_back(i.Integer()); | ||||||
|  | 	for(auto & i : randomMapJson["prisons"]["value"].Vector()) | ||||||
|  | 		config.prisonValues.push_back(i.Integer()); | ||||||
|  | 	for(auto & i : randomMapJson["scrolls"]["value"].Vector()) | ||||||
|  | 		config.scrollValues.push_back(i.Integer()); | ||||||
|  | 	for(auto & i : randomMapJson["pandoras"]["creaturesValue"].Vector()) | ||||||
|  | 		config.pandoraCreatureValues.push_back(i.Integer()); | ||||||
|  | 	for(auto & i : randomMapJson["quests"]["value"].Vector()) | ||||||
|  | 		config.questValues.push_back(i.Integer()); | ||||||
|  | 	for(auto & i : randomMapJson["quests"]["rewardValue"].Vector()) | ||||||
|  | 		config.questRewardValues.push_back(i.Integer()); | ||||||
|  | 	config.pandoraMultiplierGold = randomMapJson["pandoras"]["valueMultiplierGold"].Integer(); | ||||||
|  | 	config.pandoraMultiplierExperience = randomMapJson["pandoras"]["valueMultiplierExperience"].Integer(); | ||||||
|  | 	config.pandoraMultiplierSpells = randomMapJson["pandoras"]["valueMultiplierSpells"].Integer(); | ||||||
|  | 	config.pandoraSpellSchool = randomMapJson["pandoras"]["valueSpellSchool"].Integer(); | ||||||
|  | 	config.pandoraSpell60 = randomMapJson["pandoras"]["valueSpell60"].Integer(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const CMapGenerator::Config & CMapGenerator::getConfig() const | ||||||
|  | { | ||||||
|  | 	return config; | ||||||
|  | } | ||||||
|  |  | ||||||
| void CMapGenerator::initTiles() | void CMapGenerator::initTiles() | ||||||
| { | { | ||||||
| 	map->initTerrain(); | 	map->initTerrain(); | ||||||
| @@ -309,8 +388,10 @@ void CMapGenerator::genZones() | |||||||
| void CMapGenerator::createWaterTreasures() | void CMapGenerator::createWaterTreasures() | ||||||
| { | { | ||||||
| 	//add treasures on water | 	//add treasures on water | ||||||
| 	getZoneWater().second->addTreasureInfo(CTreasureInfo{100, 1000, 5}); | 	for(auto & treasureInfo : getConfig().waterTreasure) | ||||||
| 	getZoneWater().second->addTreasureInfo(CTreasureInfo{2000, 6000, 1}); | 	{ | ||||||
|  | 		getZoneWater().second->addTreasureInfo(treasureInfo); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void CMapGenerator::prepareWaterTiles() | void CMapGenerator::prepareWaterTiles() | ||||||
|   | |||||||
| @@ -52,11 +52,31 @@ public: | |||||||
| class DLL_LINKAGE CMapGenerator | class DLL_LINKAGE CMapGenerator | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	struct Config | ||||||
|  | 	{ | ||||||
|  | 		std::vector<ETerrainType> terrainUndergroundAllowed; | ||||||
|  | 		std::vector<ETerrainType> terrainGroundProhibit; | ||||||
|  | 		std::vector<CTreasureInfo> waterTreasure; | ||||||
|  | 		int shipyardGuard; | ||||||
|  | 		int mineExtraResources; | ||||||
|  | 		std::map<Res::ERes, int> mineValues; | ||||||
|  | 		int minGuardStrength; | ||||||
|  | 		ERoadType::ERoadType defaultRoadType; | ||||||
|  | 		int treasureValueLimit; | ||||||
|  | 		std::vector<int> prisonExperience, prisonValues; | ||||||
|  | 		std::vector<int> scrollValues; | ||||||
|  | 		int pandoraMultiplierGold, pandoraMultiplierExperience, pandoraMultiplierSpells, pandoraSpellSchool, pandoraSpell60; | ||||||
|  | 		std::vector<int> pandoraCreatureValues; | ||||||
|  | 		std::vector<int> questValues, questRewardValues; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
| 	using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<CRmgTemplateZone>>; | 	using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<CRmgTemplateZone>>; | ||||||
|  |  | ||||||
| 	explicit CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed = std::time(nullptr)); | 	explicit CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed = std::time(nullptr)); | ||||||
| 	~CMapGenerator(); // required due to std::unique_ptr | 	~CMapGenerator(); // required due to std::unique_ptr | ||||||
| 	 | 	 | ||||||
|  | 	const Config & getConfig() const; | ||||||
|  | 	 | ||||||
| 	mutable std::unique_ptr<CMap> map; | 	mutable std::unique_ptr<CMap> map; | ||||||
| 	CRandomGenerator rand; | 	CRandomGenerator rand; | ||||||
| 	 | 	 | ||||||
| @@ -111,6 +131,7 @@ public: | |||||||
| private: | private: | ||||||
| 	int randomSeed; | 	int randomSeed; | ||||||
| 	CMapGenOptions& mapGenOptions; | 	CMapGenOptions& mapGenOptions; | ||||||
|  | 	Config config; | ||||||
| 	 | 	 | ||||||
| 	std::vector<rmg::ZoneConnection> connectionsLeft; | 	std::vector<rmg::ZoneConnection> connectionsLeft; | ||||||
| 	Zones zones; | 	Zones zones; | ||||||
| @@ -129,6 +150,8 @@ private: | |||||||
| 	void checkIsOnMap(const int3 &tile) const; //throws | 	void checkIsOnMap(const int3 &tile) const; //throws | ||||||
|  |  | ||||||
| 	/// Generation methods | 	/// Generation methods | ||||||
|  | 	void loadConfig(); | ||||||
|  | 	 | ||||||
| 	std::string getMapDescription() const; | 	std::string getMapDescription() const; | ||||||
|  |  | ||||||
| 	void initPrisonsRemaining(); | 	void initPrisonsRemaining(); | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ | |||||||
|  |  | ||||||
| #include "StdInc.h" | #include "StdInc.h" | ||||||
| #include <vstd/ContainerUtils.h> | #include <vstd/ContainerUtils.h> | ||||||
|  | #include <boost/bimap.hpp> | ||||||
| #include "CRmgTemplate.h" | #include "CRmgTemplate.h" | ||||||
|  |  | ||||||
| #include "../mapping/CMap.h" | #include "../mapping/CMap.h" | ||||||
| @@ -359,7 +360,7 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler) | |||||||
| 			rawStrength = static_cast<decltype(rawStrength)>(zoneMonsterStrength); | 			rawStrength = static_cast<decltype(rawStrength)>(zoneMonsterStrength); | ||||||
| 			rawStrength++; | 			rawStrength++; | ||||||
| 		} | 		} | ||||||
| 		handler.serializeEnum("monsters", rawStrength, STRENGTH); | 		handler.serializeEnum("monsters", rawStrength, EMonsterStrength::ZONE_NORMAL + 1, STRENGTH); | ||||||
| 		if(!handler.saving) | 		if(!handler.saving) | ||||||
| 		{ | 		{ | ||||||
| 			rawStrength--; | 			rawStrength--; | ||||||
| @@ -443,6 +444,11 @@ bool CRmgTemplate::isWaterContentAllowed(EWaterContent::EWaterContent waterConte | |||||||
| 	return waterContent == EWaterContent::EWaterContent::RANDOM || allowedWaterContent.count(waterContent); | 	return waterContent == EWaterContent::EWaterContent::RANDOM || allowedWaterContent.count(waterContent); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const std::set<EWaterContent::EWaterContent> & CRmgTemplate::getWaterContentAllowed() const | ||||||
|  | { | ||||||
|  | 	return allowedWaterContent; | ||||||
|  | } | ||||||
|  |  | ||||||
| void CRmgTemplate::setId(const std::string & value) | void CRmgTemplate::setId(const std::string & value) | ||||||
| { | { | ||||||
| 	id = value; | 	id = value; | ||||||
| @@ -584,6 +590,32 @@ void CRmgTemplate::serializeJson(JsonSerializeFormat & handler) | |||||||
| 		connectionsData.serializeStruct(connections); | 		connectionsData.serializeStruct(connections); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	{ | ||||||
|  | 		boost::bimap<EWaterContent::EWaterContent, std::string> enc; | ||||||
|  | 		enc.insert({EWaterContent::NONE, "none"}); | ||||||
|  | 		enc.insert({EWaterContent::NORMAL, "normal"}); | ||||||
|  | 		enc.insert({EWaterContent::ISLANDS, "islands"}); | ||||||
|  | 		JsonNode node; | ||||||
|  | 		if(handler.saving) | ||||||
|  | 		{ | ||||||
|  | 			node.setType(JsonNode::JsonType::DATA_VECTOR); | ||||||
|  | 			for(auto wc : allowedWaterContent) | ||||||
|  | 			{ | ||||||
|  | 				JsonNode n; | ||||||
|  | 				n.String() = enc.left.at(wc); | ||||||
|  | 				node.Vector().push_back(n); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		handler.serializeRaw("allowedWaterContent", node, boost::none); | ||||||
|  | 		if(!handler.saving) | ||||||
|  | 		{ | ||||||
|  | 			for(auto wc : node.Vector()) | ||||||
|  | 			{ | ||||||
|  | 				allowedWaterContent.insert(enc.right.at(std::string(wc.String()))); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	{ | 	{ | ||||||
| 		auto zonesData = handler.enterStruct("zones"); | 		auto zonesData = handler.enterStruct("zones"); | ||||||
|         if(handler.saving) |         if(handler.saving) | ||||||
|   | |||||||
| @@ -181,6 +181,7 @@ public: | |||||||
|  |  | ||||||
| 	bool matchesSize(const int3 & value) const; | 	bool matchesSize(const int3 & value) const; | ||||||
| 	bool isWaterContentAllowed(EWaterContent::EWaterContent waterContent) const; | 	bool isWaterContentAllowed(EWaterContent::EWaterContent waterContent) const; | ||||||
|  | 	const std::set<EWaterContent::EWaterContent> & getWaterContentAllowed() const; | ||||||
|  |  | ||||||
| 	void setId(const std::string & value); | 	void setId(const std::string & value); | ||||||
| 	const std::string & getName() const; | 	const std::string & getName() const; | ||||||
|   | |||||||
| @@ -641,7 +641,7 @@ void CRmgTemplateZone::waterConnection(CRmgTemplateZone& dst) | |||||||
| 			 | 			 | ||||||
| 			if(dst.getType() == ETemplateZoneType::PLAYER_START || dst.getType() == ETemplateZoneType::CPU_START || zoneTowns) | 			if(dst.getType() == ETemplateZoneType::PLAYER_START || dst.getType() == ETemplateZoneType::CPU_START || zoneTowns) | ||||||
| 			{ | 			{ | ||||||
| 				coastTile = dst.createShipyard(lake.tiles, 3500); | 				coastTile = dst.createShipyard(lake.tiles, gen->getConfig().shipyardGuard); | ||||||
| 				if(!coastTile.valid()) | 				if(!coastTile.valid()) | ||||||
| 				{ | 				{ | ||||||
| 					coastTile = makeBoat(dst.getId(), lake.tiles); | 					coastTile = makeBoat(dst.getId(), lake.tiles); | ||||||
| @@ -1266,7 +1266,7 @@ bool CRmgTemplateZone::addMonster(int3 &pos, si32 strength, bool clearSurroundin | |||||||
| 	int strength2 = static_cast<int>(std::max(0.f, (strength - value2[monsterStrength]) * multiplier2[monsterStrength])); | 	int strength2 = static_cast<int>(std::max(0.f, (strength - value2[monsterStrength]) * multiplier2[monsterStrength])); | ||||||
|  |  | ||||||
| 	strength = strength1 + strength2; | 	strength = strength1 + strength2; | ||||||
| 	if (strength < 2000) | 	if (strength < gen->getConfig().minGuardStrength) | ||||||
| 		return false; //no guard at all | 		return false; //no guard at all | ||||||
|  |  | ||||||
| 	CreatureID creId = CreatureID::NONE; | 	CreatureID creId = CreatureID::NONE; | ||||||
| @@ -1742,14 +1742,14 @@ void CRmgTemplateZone::initTerrainType () | |||||||
|  |  | ||||||
| 		//TODO: allow new types of terrain? | 		//TODO: allow new types of terrain? | ||||||
| 		{ | 		{ | ||||||
| 			if (isUnderground()) | 			if(isUnderground()) | ||||||
| 			{ | 			{ | ||||||
| 				if (terrainType != ETerrainType::LAVA) | 				if(!vstd::contains(gen->getConfig().terrainUndergroundAllowed, terrainType)) | ||||||
| 					terrainType = ETerrainType::SUBTERRANEAN; | 					terrainType = ETerrainType::SUBTERRANEAN; | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				if (terrainType == ETerrainType::SUBTERRANEAN) | 				if(vstd::contains(gen->getConfig().terrainGroundProhibit, terrainType)) | ||||||
| 					terrainType = ETerrainType::DIRT; | 					terrainType = ETerrainType::DIRT; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -1767,8 +1767,6 @@ void CRmgTemplateZone::paintZoneTerrain (ETerrainType terrainType) | |||||||
| bool CRmgTemplateZone::placeMines () | bool CRmgTemplateZone::placeMines () | ||||||
| { | { | ||||||
| 	using namespace Res; | 	using namespace Res; | ||||||
| 	static const std::map<ERes, int> mineValue{{ERes::WOOD, 1500}, {ERes::ORE, 1500}, {ERes::GEMS, 3500}, {ERes::CRYSTAL, 3500}, {ERes::MERCURY, 3500}, {ERes::SULFUR, 3500}, {ERes::GOLD, 7000}}; |  | ||||||
| 	 |  | ||||||
| 	std::vector<CGMine*> createdMines; | 	std::vector<CGMine*> createdMines; | ||||||
| 	 | 	 | ||||||
| 	for(const auto & mineInfo : mines) | 	for(const auto & mineInfo : mines) | ||||||
| @@ -1783,22 +1781,26 @@ bool CRmgTemplateZone::placeMines () | |||||||
| 			createdMines.push_back(mine); | 			createdMines.push_back(mine); | ||||||
| 			 | 			 | ||||||
| 			if(!i && (res == ERes::WOOD || res == ERes::ORE)) | 			if(!i && (res == ERes::WOOD || res == ERes::ORE)) | ||||||
| 				addCloseObject(mine, mineValue.at(res)); //only first woor&ore mines are close | 				addCloseObject(mine, gen->getConfig().mineValues.at(res)); //only first wood&ore mines are close | ||||||
| 			else | 			else | ||||||
| 				addRequiredObject(mine, mineValue.at(res)); | 				addRequiredObject(mine, gen->getConfig().mineValues.at(res)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	//create extra resources | 	//create extra resources | ||||||
|  | 	if(int extraRes = gen->getConfig().mineExtraResources) | ||||||
|  | 	{ | ||||||
| 		for(auto * mine : createdMines) | 		for(auto * mine : createdMines) | ||||||
| 		{ | 		{ | ||||||
| 		for(int rc = gen->rand.nextInt(1, 3); rc > 0; --rc) | 			for(int rc = gen->rand.nextInt(1, extraRes); rc > 0; --rc) | ||||||
| 			{ | 			{ | ||||||
| 				auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate()); | 				auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate()); | ||||||
| 				resourse->amount = CGResource::RANDOM_AMOUNT; | 				resourse->amount = CGResource::RANDOM_AMOUNT; | ||||||
| 				addNearbyObject(resourse, mine); | 				addNearbyObject(resourse, mine); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  | 		 | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| @@ -2072,22 +2074,19 @@ bool CRmgTemplateZone::createShipyard(const int3 & position, si32 guardStrength) | |||||||
| 	shipyard->tempOwner = PlayerColor::NEUTRAL; | 	shipyard->tempOwner = PlayerColor::NEUTRAL; | ||||||
| 	 | 	 | ||||||
| 	setTemplateForObject(shipyard); | 	setTemplateForObject(shipyard); | ||||||
| 	std::vector<int3> offsets; | 	std::vector<int3> outOffsets; | ||||||
| 	auto tilesBlockedByObject = shipyard->getBlockedOffsets(); | 	auto tilesBlockedByObject = shipyard->getBlockedOffsets(); | ||||||
| 	tilesBlockedByObject.insert(shipyard->getVisitableOffset()); | 	tilesBlockedByObject.insert(shipyard->getVisitableOffset()); | ||||||
| 	shipyard->getOutOffsets(offsets); | 	shipyard->getOutOffsets(outOffsets); | ||||||
| 	 | 	 | ||||||
| 	int3 targetTile(-1, -1, -1); | 	int3 targetTile(-1, -1, -1); | ||||||
| 	std::set<int3> shipAccessCandidates; | 	std::set<int3> shipAccessCandidates; | ||||||
| 	 | 	 | ||||||
| 	for(auto& candidateTile : possibleTiles) | 	for(const auto & outOffset : outOffsets) | ||||||
| 	{ |  | ||||||
| 		bool foundTargetPosition = false; |  | ||||||
| 		for(const auto & offset : offsets) |  | ||||||
| 		{ |  | ||||||
| 			if(candidateTile+offset == position) |  | ||||||
| 	{ | 	{ | ||||||
|  | 		auto candidateTile = position - outOffset; | ||||||
| 		std::set<int3> tilesBlockedAbsolute; | 		std::set<int3> tilesBlockedAbsolute; | ||||||
|  | 		 | ||||||
| 		//check space under object | 		//check space under object | ||||||
| 		bool allClear = true; | 		bool allClear = true; | ||||||
| 		for(const auto & objectTileOffset : tilesBlockedByObject) | 		for(const auto & objectTileOffset : tilesBlockedByObject) | ||||||
| @@ -2101,40 +2100,36 @@ bool CRmgTemplateZone::createShipyard(const int3 & position, si32 guardStrength) | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if(!allClear) //cannot place shipyard anyway | 		if(!allClear) //cannot place shipyard anyway | ||||||
| 					break; | 			continue; | ||||||
| 		 | 		 | ||||||
| 		//prepare temporary map | 		//prepare temporary map | ||||||
| 		for(auto& blockedPos : tilesBlockedAbsolute) | 		for(auto& blockedPos : tilesBlockedAbsolute) | ||||||
| 			gen->setOccupied(blockedPos, ETileType::USED); | 			gen->setOccupied(blockedPos, ETileType::USED); | ||||||
| 		 | 		 | ||||||
| 				//check if position is accessible | 		 | ||||||
|  | 		//check if boarding position is accessible | ||||||
| 		gen->foreach_neighbour(position, [this, &shipAccessCandidates](const int3 & v) | 		gen->foreach_neighbour(position, [this, &shipAccessCandidates](const int3 & v) | ||||||
| 		{ | 		{ | ||||||
| 			if(!gen->isBlocked(v) && gen->getZoneID(v)==id) | 			if(!gen->isBlocked(v) && gen->getZoneID(v)==id) | ||||||
| 			{ | 			{ | ||||||
| 				//make sure that it's possible to create path to boarding position | 				//make sure that it's possible to create path to boarding position | ||||||
| 						if(crunchPath(v, findClosestTile(freePaths, v), false, nullptr)) | 				if(connectWithCenter(v, false, false)) | ||||||
| 					shipAccessCandidates.insert(v); | 					shipAccessCandidates.insert(v); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 		 | 		 | ||||||
|  | 		//check if we can connect shipyard entrance with path | ||||||
|  | 		if(!connectWithCenter(candidateTile + shipyard->getVisitableOffset(), false)) | ||||||
|  | 			shipAccessCandidates.clear(); | ||||||
|  | 				 | ||||||
| 		//rollback temporary map | 		//rollback temporary map | ||||||
| 		for(auto& blockedPos : tilesBlockedAbsolute) | 		for(auto& blockedPos : tilesBlockedAbsolute) | ||||||
| 			gen->setOccupied(blockedPos, ETileType::POSSIBLE); | 			gen->setOccupied(blockedPos, ETileType::POSSIBLE); | ||||||
| 		 | 		 | ||||||
| 				if(!shipAccessCandidates.empty()) | 		if(!shipAccessCandidates.empty() && isAccessibleFromSomewhere(shipyard->appearance, candidateTile)) | ||||||
| 				{ |  | ||||||
| 					foundTargetPosition = true; |  | ||||||
| 				} |  | ||||||
| 				 |  | ||||||
| 				break; //no need to check other offsets as we already found position |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		if(foundTargetPosition && isAccessibleFromSomewhere(shipyard->appearance, candidateTile)) |  | ||||||
| 		{ | 		{ | ||||||
| 			targetTile = candidateTile; | 			targetTile = candidateTile; | ||||||
| 			break; | 			break; //no need to check other offsets as we already found position | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		shipAccessCandidates.clear(); //invalidate positions | 		shipAccessCandidates.clear(); //invalidate positions | ||||||
| @@ -2146,6 +2141,8 @@ bool CRmgTemplateZone::createShipyard(const int3 & position, si32 guardStrength) | |||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	if(tryToPlaceObjectAndConnectToPath(shipyard, targetTile)==EObjectPlacingResult::SUCCESS) | ||||||
|  | 	{ | ||||||
| 		placeObject(shipyard, targetTile); | 		placeObject(shipyard, targetTile); | ||||||
| 		guardObject(shipyard, guardStrength, false, true); | 		guardObject(shipyard, guardStrength, false, true); | ||||||
| 	 | 	 | ||||||
| @@ -2157,8 +2154,11 @@ bool CRmgTemplateZone::createShipyard(const int3 & position, si32 guardStrength) | |||||||
| 				return true; | 				return true; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	 | 	 | ||||||
| 	throw rmgException("Cannot find path to shipyard boarding position"); | 	logGlobal->warn("Cannot find path to shipyard boarding position"); | ||||||
|  | 	delete shipyard; | ||||||
|  | 	return false; | ||||||
| } | } | ||||||
|  |  | ||||||
| void CRmgTemplateZone::createTreasures() | void CRmgTemplateZone::createTreasures() | ||||||
| @@ -2206,7 +2206,12 @@ void CRmgTemplateZone::createTreasures() | |||||||
| 			//optimization - don't check tiles which are not allowed | 			//optimization - don't check tiles which are not allowed | ||||||
| 			vstd::erase_if(possibleTiles, [this](const int3 &tile) -> bool | 			vstd::erase_if(possibleTiles, [this](const int3 &tile) -> bool | ||||||
| 			{ | 			{ | ||||||
| 				return (!gen->isPossible(tile)) || gen->getZoneID(tile)!=getId(); | 				//for water area we sholdn't place treasures close to coast | ||||||
|  | 				for(auto & lake : lakes) | ||||||
|  | 					if(vstd::contains(lake.distance, tile) && lake.distance[tile] < 2) | ||||||
|  | 						return true; | ||||||
|  | 				 | ||||||
|  | 				return !gen->isPossible(tile) || gen->getZoneID(tile)!=getId(); | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -2376,7 +2381,7 @@ void CRmgTemplateZone::drawRoads() | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	gen->getEditManager()->getTerrainSelection().setSelection(tiles); | 	gen->getEditManager()->getTerrainSelection().setSelection(tiles); | ||||||
| 	gen->getEditManager()->drawRoad(ERoadType::COBBLESTONE_ROAD, &gen->rand); | 	gen->getEditManager()->drawRoad(gen->getConfig().defaultRoadType, &gen->rand); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -2386,16 +2391,6 @@ bool CRmgTemplateZone::fill() | |||||||
| 	 | 	 | ||||||
| 	addAllPossibleObjects(); | 	addAllPossibleObjects(); | ||||||
| 	 | 	 | ||||||
| 	if(type==ETemplateZoneType::WATER) |  | ||||||
| 	{ |  | ||||||
| 		initFreeTiles(); |  | ||||||
| 		connectLater(); |  | ||||||
| 		createRequiredObjects(); |  | ||||||
| 		fractalize(); |  | ||||||
| 		createTreasures(); |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 	//zone center should be always clear to allow other tiles to connect | 	//zone center should be always clear to allow other tiles to connect | ||||||
| 	initFreeTiles(); | 	initFreeTiles(); | ||||||
| 	connectLater(); //ideally this should work after fractalize, but fails | 	connectLater(); //ideally this should work after fractalize, but fails | ||||||
| @@ -2403,9 +2398,6 @@ bool CRmgTemplateZone::fill() | |||||||
| 	placeMines(); | 	placeMines(); | ||||||
| 	createRequiredObjects(); | 	createRequiredObjects(); | ||||||
| 	createTreasures(); | 	createTreasures(); | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	gen->dump(false); |  | ||||||
|  |  | ||||||
| 	logGlobal->info("Zone %d filled successfully", id); | 	logGlobal->info("Zone %d filled successfully", id); | ||||||
| 	return true; | 	return true; | ||||||
| @@ -2613,6 +2605,7 @@ void CRmgTemplateZone::placeObject(CGObjectInstance* object, const int3 &pos, bo | |||||||
| 	case Obj::MONOLITH_ONE_WAY_ENTRANCE: | 	case Obj::MONOLITH_ONE_WAY_ENTRANCE: | ||||||
| 	case Obj::MONOLITH_ONE_WAY_EXIT: | 	case Obj::MONOLITH_ONE_WAY_EXIT: | ||||||
| 	case Obj::SUBTERRANEAN_GATE: | 	case Obj::SUBTERRANEAN_GATE: | ||||||
|  | 	case Obj::SHIPYARD: | ||||||
| 		{ | 		{ | ||||||
| 			addRoadNode(object->visitablePos()); | 			addRoadNode(object->visitablePos()); | ||||||
| 		} | 		} | ||||||
| @@ -2831,11 +2824,11 @@ ObjectInfo CRmgTemplateZone::getRandomObject(CTreasurePileInfo &info, ui32 desir | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (thresholds.empty()) | 	if(thresholds.empty()) | ||||||
| 	{ | 	{ | ||||||
| 		ObjectInfo oi; | 		ObjectInfo oi; | ||||||
| 		//Generate pandora Box with gold if the value is extremely high | 		//Generate pandora Box with gold if the value is extremely high | ||||||
| 		if (minValue > 20000) //we don't have object valuable enough | 		if(minValue > gen->getConfig().treasureValueLimit) //we don't have object valuable enough | ||||||
| 		{ | 		{ | ||||||
| 			oi.generateObject = [minValue]() -> CGObjectInstance * | 			oi.generateObject = [minValue]() -> CGObjectInstance * | ||||||
| 			{ | 			{ | ||||||
| @@ -2913,17 +2906,15 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
|  |  | ||||||
| 	//prisons | 	//prisons | ||||||
| 	//levels 1, 5, 10, 20, 30 | 	//levels 1, 5, 10, 20, 30 | ||||||
| 	static int prisonExp[] = { 0, 5000, 15000, 90000, 500000 }; | 	static int prisonsLevels = std::min(gen->getConfig().prisonExperience.size(), gen->getConfig().prisonValues.size()); | ||||||
| 	static int prisonValues[] = { 2500, 5000, 10000, 20000, 30000 }; | 	for(int i = 0; i < prisonsLevels; i++) | ||||||
|  |  | ||||||
| 	for (int i = 0; i < 5; i++) |  | ||||||
| 	{ | 	{ | ||||||
| 		oi.generateObject = [i, this]() -> CGObjectInstance * | 		oi.generateObject = [i, this]() -> CGObjectInstance * | ||||||
| 		{ | 		{ | ||||||
| 			std::vector<ui32> possibleHeroes; | 			std::vector<ui32> possibleHeroes; | ||||||
| 			for (int j = 0; j < gen->map->allowedHeroes.size(); j++) | 			for(int j = 0; j < gen->map->allowedHeroes.size(); j++) | ||||||
| 			{ | 			{ | ||||||
| 				if (gen->map->allowedHeroes[j]) | 				if(gen->map->allowedHeroes[j]) | ||||||
| 					possibleHeroes.push_back(j); | 					possibleHeroes.push_back(j); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -2933,7 +2924,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
|  |  | ||||||
|  |  | ||||||
| 			obj->subID = hid; //will be initialized later | 			obj->subID = hid; //will be initialized later | ||||||
| 			obj->exp = prisonExp[i]; | 			obj->exp = gen->getConfig().prisonExperience[i]; | ||||||
| 			obj->setOwner(PlayerColor::NEUTRAL); | 			obj->setOwner(PlayerColor::NEUTRAL); | ||||||
| 			gen->map->allowedHeroes[hid] = false; //ban this hero | 			gen->map->allowedHeroes[hid] = false; //ban this hero | ||||||
| 			gen->decreasePrisonsRemaining(); | 			gen->decreasePrisonsRemaining(); | ||||||
| @@ -2942,7 +2933,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 			return obj; | 			return obj; | ||||||
| 		}; | 		}; | ||||||
| 		oi.setTemplate(Obj::PRISON, 0, terrainType); | 		oi.setTemplate(Obj::PRISON, 0, terrainType); | ||||||
| 		oi.value = prisonValues[i]; | 		oi.value = gen->getConfig().prisonValues[i]; | ||||||
| 		oi.probability = 30; | 		oi.probability = 30; | ||||||
| 		oi.maxPerZone = gen->getPrisonsRemaning() / 5; //probably not perfect, but we can't generate more prisons than hereos. | 		oi.maxPerZone = gen->getPrisonsRemaning() / 5; //probably not perfect, but we can't generate more prisons than hereos. | ||||||
| 		possibleObjects.push_back(oi); | 		possibleObjects.push_back(oi); | ||||||
| @@ -3008,9 +2999,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static const int scrollValues[] = { 500, 2000, 3000, 4000, 5000 }; | 	for(int i = 0; i < gen->getConfig().scrollValues.size(); i++) | ||||||
|  |  | ||||||
| 	for (int i = 0; i < 5; i++) |  | ||||||
| 	{ | 	{ | ||||||
| 		oi.generateObject = [i, this]() -> CGObjectInstance * | 		oi.generateObject = [i, this]() -> CGObjectInstance * | ||||||
| 		{ | 		{ | ||||||
| @@ -3030,13 +3019,13 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 			return obj; | 			return obj; | ||||||
| 		}; | 		}; | ||||||
| 		oi.setTemplate(Obj::SPELL_SCROLL, 0, terrainType); | 		oi.setTemplate(Obj::SPELL_SCROLL, 0, terrainType); | ||||||
| 		oi.value = scrollValues[i]; | 		oi.value = gen->getConfig().scrollValues[i]; | ||||||
| 		oi.probability = 30; | 		oi.probability = 30; | ||||||
| 		possibleObjects.push_back(oi); | 		possibleObjects.push_back(oi); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	//pandora box with gold | 	//pandora box with gold | ||||||
| 	for (int i = 1; i < 5; i++) | 	for(int i = 1; i < 5; i++) | ||||||
| 	{ | 	{ | ||||||
| 		oi.generateObject = [i]() -> CGObjectInstance * | 		oi.generateObject = [i]() -> CGObjectInstance * | ||||||
| 		{ | 		{ | ||||||
| @@ -3046,7 +3035,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 			return obj; | 			return obj; | ||||||
| 		}; | 		}; | ||||||
| 		oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | 		oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | ||||||
| 		oi.value = i * 5000; | 		oi.value = i * gen->getConfig().pandoraMultiplierGold; | ||||||
| 		oi.probability = 5; | 		oi.probability = 5; | ||||||
| 		possibleObjects.push_back(oi); | 		possibleObjects.push_back(oi); | ||||||
| 	} | 	} | ||||||
| @@ -3062,20 +3051,22 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 			return obj; | 			return obj; | ||||||
| 		}; | 		}; | ||||||
| 		oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | 		oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | ||||||
| 		oi.value = i * 6000; | 		oi.value = i * gen->getConfig().pandoraMultiplierExperience; | ||||||
| 		oi.probability = 20; | 		oi.probability = 20; | ||||||
| 		possibleObjects.push_back(oi); | 		possibleObjects.push_back(oi); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	//pandora box with creatures | 	//pandora box with creatures | ||||||
| 	static const int tierValues[] = { 5000, 7000, 9000, 12000, 16000, 21000, 27000 }; | 	const std::vector<int> & tierValues = gen->getConfig().pandoraCreatureValues; | ||||||
|  |  | ||||||
| 	auto creatureToCount = [](CCreature * creature) -> int | 	auto creatureToCount = [&tierValues](CCreature * creature) -> int | ||||||
| 	{ | 	{ | ||||||
| 		if (!creature->AIValue) //bug #2681 | 		if (!creature->AIValue) //bug #2681 | ||||||
| 			return 0; //this box won't be generated | 			return 0; //this box won't be generated | ||||||
|  |  | ||||||
| 		int actualTier = creature->level > 7 ? 6 : creature->level - 1; | 		int actualTier = creature->level > tierValues.size() ? | ||||||
|  | 						 tierValues.size() - 1 : | ||||||
|  | 						 creature->level - 1; | ||||||
| 		float creaturesAmount = ((float)tierValues[actualTier]) / creature->AIValue; | 		float creaturesAmount = ((float)tierValues[actualTier]) / creature->AIValue; | ||||||
| 		if (creaturesAmount <= 5) | 		if (creaturesAmount <= 5) | ||||||
| 		{ | 		{ | ||||||
| @@ -3142,7 +3133,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 			return obj; | 			return obj; | ||||||
| 		}; | 		}; | ||||||
| 		oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | 		oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | ||||||
| 		oi.value = (i + 1) * 2500; //5000 - 15000 | 		oi.value = (i + 1) * gen->getConfig().pandoraMultiplierSpells; //5000 - 15000 | ||||||
| 		oi.probability = 2; | 		oi.probability = 2; | ||||||
| 		possibleObjects.push_back(oi); | 		possibleObjects.push_back(oi); | ||||||
| 	} | 	} | ||||||
| @@ -3171,7 +3162,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 			return obj; | 			return obj; | ||||||
| 		}; | 		}; | ||||||
| 		oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | 		oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | ||||||
| 		oi.value = 15000; | 		oi.value = gen->getConfig().pandoraSpellSchool; | ||||||
| 		oi.probability = 2; | 		oi.probability = 2; | ||||||
| 		possibleObjects.push_back(oi); | 		possibleObjects.push_back(oi); | ||||||
| 	} | 	} | ||||||
| @@ -3199,7 +3190,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 		return obj; | 		return obj; | ||||||
| 	}; | 	}; | ||||||
| 	oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | 	oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); | ||||||
| 	oi.value = 30000; | 	oi.value = gen->getConfig().pandoraSpell60; | ||||||
| 	oi.probability = 2; | 	oi.probability = 2; | ||||||
| 	possibleObjects.push_back(oi); | 	possibleObjects.push_back(oi); | ||||||
|  |  | ||||||
| @@ -3240,7 +3231,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 			return artInfo; | 			return artInfo; | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		for (int i = 0; i < std::min((int)creatures.size(), questArtsRemaining - genericSeerHuts); i++) | 		for(int i = 0; i < std::min((int)creatures.size(), questArtsRemaining - genericSeerHuts); i++) | ||||||
| 		{ | 		{ | ||||||
| 			auto creature = creatures[i]; | 			auto creature = creatures[i]; | ||||||
| 			int creaturesAmount = creatureToCount(creature); | 			int creaturesAmount = creatureToCount(creature); | ||||||
| @@ -3276,15 +3267,13 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 			possibleObjects.push_back(oi); | 			possibleObjects.push_back(oi); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		static int seerExpGold[] = { 5000, 10000, 15000, 20000 }; | 		static int seerLevels = std::min(gen->getConfig().questValues.size(), gen->getConfig().questRewardValues.size()); | ||||||
| 		static int seerValues[] = { 2000, 5333, 8666, 12000 }; | 		for(int i = 0; i < seerLevels; i++) //seems that code for exp and gold reward is similiar | ||||||
|  |  | ||||||
| 		for (int i = 0; i < 4; i++) //seems that code for exp and gold reward is similiar |  | ||||||
| 		{ | 		{ | ||||||
| 			int randomAppearance = *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::SEER_HUT), gen->rand); | 			int randomAppearance = *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::SEER_HUT), gen->rand); | ||||||
|  |  | ||||||
| 			oi.setTemplate(Obj::SEER_HUT, randomAppearance, terrainType); | 			oi.setTemplate(Obj::SEER_HUT, randomAppearance, terrainType); | ||||||
| 			oi.value = seerValues[i]; | 			oi.value = gen->getConfig().questValues[i]; | ||||||
| 			oi.probability = 10; | 			oi.probability = 10; | ||||||
|  |  | ||||||
| 			oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance * | 			oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance * | ||||||
| @@ -3294,7 +3283,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
|  |  | ||||||
| 				obj->rewardType = CGSeerHut::EXPERIENCE; | 				obj->rewardType = CGSeerHut::EXPERIENCE; | ||||||
| 				obj->rID = 0; //unitialized? | 				obj->rID = 0; //unitialized? | ||||||
| 				obj->rVal = seerExpGold[i]; | 				obj->rVal = gen->getConfig().questRewardValues[i]; | ||||||
|  |  | ||||||
| 				obj->quest->missionType = CQuest::MISSION_ART; | 				obj->quest->missionType = CQuest::MISSION_ART; | ||||||
| 				ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand); | 				ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand); | ||||||
| @@ -3317,7 +3306,7 @@ void CRmgTemplateZone::addAllPossibleObjects() | |||||||
| 				auto obj = (CGSeerHut *) factory->create(ObjectTemplate()); | 				auto obj = (CGSeerHut *) factory->create(ObjectTemplate()); | ||||||
| 				obj->rewardType = CGSeerHut::RESOURCES; | 				obj->rewardType = CGSeerHut::RESOURCES; | ||||||
| 				obj->rID = Res::GOLD; | 				obj->rID = Res::GOLD; | ||||||
| 				obj->rVal = seerExpGold[i]; | 				obj->rVal = gen->getConfig().questRewardValues[i]; | ||||||
|  |  | ||||||
| 				obj->quest->missionType = CQuest::MISSION_ART; | 				obj->quest->missionType = CQuest::MISSION_ART; | ||||||
| 				ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand); | 				ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user