2
0
Эх сурвалжийг харах

Merge pull request #3362 from IvanSavenko/terrain_decorations

Terrain decorations level
Ivan Savenko 1 жил өмнө
parent
commit
20ede710c2

+ 2 - 1
config/terrainViewPatterns.json

@@ -85,7 +85,8 @@
 				"N", "N", "N",
 				"N", "N", "N"
 			],
-			"mapping" : { "normal" : "49-72", "dirt" : "21-44", "sand" : "0-23", "water" : "20-32", "rock": "0-7", "hota" : "77-117" }
+			"decoration" : true,
+			"mapping" : { "normal" : "49-56,57-72", "dirt" : "21-28,29-44", "sand" : "0-11,12-23", "water" : "20-32", "rock": "0-7", "hota" : "77-101,102-117" }
 		},
 		// Mixed transitions
 		{

+ 2 - 4
lib/mapping/CMapEditManager.cpp

@@ -125,9 +125,9 @@ void CMapEditManager::clearTerrain(CRandomGenerator * gen)
 	execute(std::make_unique<CClearTerrainOperation>(map, gen ? gen : &(this->gen)));
 }
 
-void CMapEditManager::drawTerrain(TerrainId terType, CRandomGenerator * gen)
+void CMapEditManager::drawTerrain(TerrainId terType, int decorationsPercentage, CRandomGenerator * gen)
 {
-	execute(std::make_unique<CDrawTerrainOperation>(map, terrainSel, terType, gen ? gen : &(this->gen)));
+	execute(std::make_unique<CDrawTerrainOperation>(map, terrainSel, terType, decorationsPercentage, gen ? gen : &(this->gen)));
 	terrainSel.clearSelection();
 }
 
@@ -143,8 +143,6 @@ void CMapEditManager::drawRiver(RiverId riverType, CRandomGenerator* gen)
 	terrainSel.clearSelection();
 }
 
-
-
 void CMapEditManager::insertObject(CGObjectInstance * obj)
 {
 	execute(std::make_unique<CInsertObjectOperation>(map, obj));

+ 1 - 1
lib/mapping/CMapEditManager.h

@@ -70,7 +70,7 @@ public:
 	void clearTerrain(CRandomGenerator * gen = nullptr);
 
 	/// Draws terrain at the current terrain selection. The selection will be cleared automatically.
-	void drawTerrain(TerrainId terType, CRandomGenerator * gen = nullptr);
+	void drawTerrain(TerrainId terType, int decorationsPercentage, CRandomGenerator * gen = nullptr);
 
 	/// Draws roads at the current terrain selection. The selection will be cleared automatically.
 	void drawRoad(RoadId roadType, CRandomGenerator * gen = nullptr);

+ 14 - 8
lib/mapping/CMapOperation.cpp

@@ -83,10 +83,11 @@ void CComposedOperation::addOperation(std::unique_ptr<CMapOperation>&& operation
 	operations.push_back(std::move(operation));
 }
 
-CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, CTerrainSelection terrainSel, TerrainId terType, CRandomGenerator * gen):
+CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, CTerrainSelection terrainSel, TerrainId terType, int decorationsPercentage, CRandomGenerator * gen):
 	CMapOperation(map),
 	terrainSel(std::move(terrainSel)),
 	terType(terType),
+	decorationsPercentage(decorationsPercentage),
 	gen(gen)
 {
 
@@ -286,14 +287,19 @@ void CDrawTerrainOperation::updateTerrainViews()
 		// Get mapping
 		const TerrainViewPattern& pattern = patterns[bestPattern][valRslt.flip];
 		std::pair<int, int> mapping;
-		if(valRslt.transitionReplacement.empty())
+
+		mapping = pattern.mapping[0];
+
+		if(pattern.decoration)
 		{
-			mapping = pattern.mapping[0];
+			if (pattern.mapping.size() < 2 || gen->nextInt(100) > decorationsPercentage)
+				mapping = pattern.mapping[0];
+			else
+				mapping = pattern.mapping[1];
 		}
-		else
-		{
+
+		if (!valRslt.transitionReplacement.empty())
 			mapping = valRslt.transitionReplacement == TerrainViewPattern::RULE_DIRT ? pattern.mapping[0] : pattern.mapping[1];
-		}
 
 		// Set terrain view
 		auto & tile = map->getTile(pos);
@@ -555,12 +561,12 @@ CClearTerrainOperation::CClearTerrainOperation(CMap* map, CRandomGenerator* gen)
 {
 	CTerrainSelection terrainSel(map);
 	terrainSel.selectRange(MapRect(int3(0, 0, 0), map->width, map->height));
-	addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainId::WATER, gen));
+	addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainId::WATER, 0, gen));
 	if(map->twoLevel)
 	{
 		terrainSel.clearSelection();
 		terrainSel.selectRange(MapRect(int3(0, 0, 1), map->width, map->height));
-		addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainId::ROCK, gen));
+		addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainId::ROCK, 0, gen));
 	}
 }
 

+ 2 - 1
lib/mapping/CMapOperation.h

@@ -63,7 +63,7 @@ private:
 class CDrawTerrainOperation : public CMapOperation
 {
 public:
-	CDrawTerrainOperation(CMap * map, CTerrainSelection terrainSel, TerrainId terType, CRandomGenerator * gen);
+	CDrawTerrainOperation(CMap * map, CTerrainSelection terrainSel, TerrainId terType, int decorationsPercentage, CRandomGenerator * gen);
 
 	void execute() override;
 	void undo() override;
@@ -101,6 +101,7 @@ private:
 
 	CTerrainSelection terrainSel;
 	TerrainId terType;
+	int decorationsPercentage;
 	CRandomGenerator* gen;
 	std::set<int3> invalidatedTerViews;
 };

+ 2 - 0
lib/mapping/MapEditUtils.cpp

@@ -145,6 +145,7 @@ const std::string TerrainViewPattern::RULE_ANY = "?";
 TerrainViewPattern::TerrainViewPattern()
 	: diffImages(false)
 	, rotationTypesCount(0)
+	, decoration(false)
 	, minPoints(0)
 	, maxPoints(std::numeric_limits<int>::max())
 {
@@ -209,6 +210,7 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig()
 			// Read various properties
 			pattern.id = ptrnNode["id"].String();
 			assert(!pattern.id.empty());
+			pattern.decoration = ptrnNode["decoration"].Bool();
 			pattern.minPoints = static_cast<int>(ptrnNode["minPoints"].Float());
 			pattern.maxPoints = static_cast<int>(ptrnNode["maxPoints"].Float());
 			if (pattern.maxPoints == 0)

+ 2 - 0
lib/mapping/MapEditUtils.h

@@ -199,6 +199,8 @@ struct DLL_LINKAGE TerrainViewPattern
 	/// If diffImages is true, different images/frames are used to place a rotated terrain view. If it's false
 	/// the same frame will be used and rotated.
 	bool diffImages;
+	/// If true, then this pattern describes decoration tiles and should be used with specified probability
+	bool decoration;
 	/// The rotationTypesCount is only used if diffImages is true and holds the number how many rotation types(horizontal, etc...)
 	/// are supported.
 	int rotationTypesCount;

+ 6 - 1
lib/rmg/RmgMap.cpp

@@ -45,6 +45,11 @@ RmgMap::RmgMap(const CMapGenOptions& mapGenOptions) :
 	getEditManager()->getUndoManager().setUndoRedoLimit(0);
 }
 
+int RmgMap::getDecorationsPercentage() const
+{
+	return 15; // arbitrary value to generate more readable map
+}
+
 void RmgMap::foreach_neighbour(const int3 & pos, const std::function<void(int3 & pos)> & foo) const
 {
 	for(const int3 &dir : int3::getDirs())
@@ -90,7 +95,7 @@ void RmgMap::initTiles(CMapGenerator & generator, CRandomGenerator & rand)
 	
 	getEditManager()->clearTerrain(&rand);
 	getEditManager()->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
-	getEditManager()->drawTerrain(ETerrainId::GRASS, &rand);
+	getEditManager()->drawTerrain(ETerrainId::GRASS, getDecorationsPercentage(), &rand);
 
 	const auto * tmpl = mapGenOptions.getMapTemplate();
 	zones.clear();

+ 2 - 0
lib/rmg/RmgMap.h

@@ -27,6 +27,8 @@ class playerInfo;
 class RmgMap
 {
 public:
+	int getDecorationsPercentage() const;
+
 	mutable std::unique_ptr<CMap> mapInstance;
 	std::shared_ptr<MapProxy> getMapProxy() const;
 	CMap & getMap(const CMapGenerator *) const; //limited access

+ 13 - 13
lib/rmg/threadpool/MapProxy.cpp

@@ -14,47 +14,47 @@
 VCMI_LIB_NAMESPACE_BEGIN
 
 MapProxy::MapProxy(RmgMap & map):
-    map(map)
+	map(map)
 {
 }
 
 void MapProxy::insertObject(CGObjectInstance * obj)
 {
-    Lock lock(mx);
-    map.getEditManager()->insertObject(obj);
+	Lock lock(mx);
+	map.getEditManager()->insertObject(obj);
 }
 
 void MapProxy::insertObjects(std::set<CGObjectInstance*>& objects)
 {
-    Lock lock(mx);
-    map.getEditManager()->insertObjects(objects);
+	Lock lock(mx);
+	map.getEditManager()->insertObjects(objects);
 }
 
 void MapProxy::removeObject(CGObjectInstance * obj)
 {
-    Lock lock(mx);
-    map.getEditManager()->removeObject(obj);
+	Lock lock(mx);
+	map.getEditManager()->removeObject(obj);
 }
 
 void MapProxy::drawTerrain(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain)
 {
-    Lock lock(mx);
+	Lock lock(mx);
 	map.getEditManager()->getTerrainSelection().setSelection(tiles);
-	map.getEditManager()->drawTerrain(terrain, &generator);
+	map.getEditManager()->drawTerrain(terrain, map.getDecorationsPercentage(), &generator);
 }
 
 void MapProxy::drawRivers(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain)
 {
-    Lock lock(mx);
+	Lock lock(mx);
 	map.getEditManager()->getTerrainSelection().setSelection(tiles);
 	map.getEditManager()->drawRiver(VLC->terrainTypeHandler->getById(terrain)->river, &generator);
 }
 
 void MapProxy::drawRoads(CRandomGenerator & generator, std::vector<int3> & tiles, RoadId roadType)
 {
-    Lock lock(mx);
-    map.getEditManager()->getTerrainSelection().setSelection(tiles);
+	Lock lock(mx);
+	map.getEditManager()->getTerrainSelection().setSelection(tiles);
 	map.getEditManager()->drawRoad(roadType, &generator);
 }
 
-VCMI_LIB_NAMESPACE_END
+VCMI_LIB_NAMESPACE_END

+ 11 - 11
lib/rmg/threadpool/MapProxy.h

@@ -22,21 +22,21 @@ class RmgMap;
 class MapProxy
 {
 public:
-    MapProxy(RmgMap & map);
+	MapProxy(RmgMap & map);
 
-    void insertObject(CGObjectInstance * obj);
-    void insertObjects(std::set<CGObjectInstance*>& objects);
-    void removeObject(CGObjectInstance* obj);
+	void insertObject(CGObjectInstance * obj);
+	void insertObjects(std::set<CGObjectInstance*>& objects);
+	void removeObject(CGObjectInstance* obj);
 
-    void drawTerrain(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain);
-    void drawRivers(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain);
-    void drawRoads(CRandomGenerator & generator, std::vector<int3> & tiles, RoadId roadType);
+	void drawTerrain(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain);
+	void drawRivers(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain);
+	void drawRoads(CRandomGenerator & generator, std::vector<int3> & tiles, RoadId roadType);
 
 private:
-    mutable boost::shared_mutex mx;
-    using Lock = boost::unique_lock<boost::shared_mutex>;
+	mutable boost::shared_mutex mx;
+	using Lock = boost::unique_lock<boost::shared_mutex>;
 
-    RmgMap & map;
+	RmgMap & map;
 };
 
-VCMI_LIB_NAMESPACE_END
+VCMI_LIB_NAMESPACE_END

+ 3 - 1
mapeditor/mapcontroller.cpp

@@ -272,6 +272,8 @@ void MapController::resetMapHandler()
 
 void MapController::commitTerrainChange(int level, const TerrainId & terrain)
 {
+	static const int terrainDecorationPercentageLevel = 10;
+
 	std::vector<int3> v(_scenes[level]->selectionTerrainView.selection().begin(),
 						_scenes[level]->selectionTerrainView.selection().end());
 	if(v.empty())
@@ -281,7 +283,7 @@ void MapController::commitTerrainChange(int level, const TerrainId & terrain)
 	_scenes[level]->selectionTerrainView.draw();
 	
 	_map->getEditManager()->getTerrainSelection().setSelection(v);
-	_map->getEditManager()->drawTerrain(terrain, &CRandomGenerator::getDefault());
+	_map->getEditManager()->drawTerrain(terrain, terrainDecorationPercentageLevel, &CRandomGenerator::getDefault());
 	
 	for(auto & t : v)
 		_scenes[level]->terrainView.setDirty(t);

+ 10 - 10
test/map/CMapEditManagerTest.cpp

@@ -34,7 +34,7 @@ TEST(MapManager, DrawTerrain_Type)
 
 		// 1x1 Blow up
 		editManager->getTerrainSelection().select(int3(5, 5, 0));
-		editManager->drawTerrain(ETerrainId::GRASS);
+		editManager->drawTerrain(ETerrainId::GRASS, 10);
 		static const int3 squareCheck[] = { int3(5,5,0), int3(5,4,0), int3(4,4,0), int3(4,5,0) };
 		for(const auto & tile : squareCheck)
 		{
@@ -43,20 +43,20 @@ TEST(MapManager, DrawTerrain_Type)
 
 		// Concat to square
 		editManager->getTerrainSelection().select(int3(6, 5, 0));
-		editManager->drawTerrain(ETerrainId::GRASS);
+		editManager->drawTerrain(ETerrainId::GRASS, 10);
 		EXPECT_EQ(map->getTile(int3(6, 4, 0)).terType->getId(), ETerrainId::GRASS);
 		editManager->getTerrainSelection().select(int3(6, 5, 0));
-		editManager->drawTerrain(ETerrainId::LAVA);
+		editManager->drawTerrain(ETerrainId::LAVA, 10);
 		EXPECT_EQ(map->getTile(int3(4, 4, 0)).terType->getId(), ETerrainId::GRASS);
 		EXPECT_EQ(map->getTile(int3(7, 4, 0)).terType->getId(), ETerrainId::LAVA);
 
 		// Special case water,rock
 		editManager->getTerrainSelection().selectRange(MapRect(int3(10, 10, 0), 10, 5));
-		editManager->drawTerrain(ETerrainId::GRASS);
+		editManager->drawTerrain(ETerrainId::GRASS, 10);
 		editManager->getTerrainSelection().selectRange(MapRect(int3(15, 17, 0), 10, 5));
-		editManager->drawTerrain(ETerrainId::GRASS);
+		editManager->drawTerrain(ETerrainId::GRASS, 10);
 		editManager->getTerrainSelection().select(int3(21, 16, 0));
-		editManager->drawTerrain(ETerrainId::GRASS);
+		editManager->drawTerrain(ETerrainId::GRASS, 10);
 		EXPECT_EQ(map->getTile(int3(20, 15, 0)).terType->getId(), ETerrainId::GRASS);
 
 		// Special case non water,rock
@@ -67,16 +67,16 @@ TEST(MapManager, DrawTerrain_Type)
 		{
 			editManager->getTerrainSelection().select(tile);
 		}
-		editManager->drawTerrain(ETerrainId::GRASS);
+		editManager->drawTerrain(ETerrainId::GRASS, 10);
 		EXPECT_EQ(map->getTile(int3(35, 44, 0)).terType->getId(), ETerrainId::WATER);
 
 		// Rock case
 		editManager->getTerrainSelection().selectRange(MapRect(int3(1, 1, 1), 15, 15));
-		editManager->drawTerrain(ETerrainId::SUBTERRANEAN);
+		editManager->drawTerrain(ETerrainId::SUBTERRANEAN, 10);
 		std::vector<int3> vec({ int3(6, 6, 1), int3(7, 6, 1), int3(8, 6, 1), int3(5, 7, 1), int3(6, 7, 1), int3(7, 7, 1),
 								int3(8, 7, 1), int3(4, 8, 1), int3(5, 8, 1), int3(6, 8, 1)});
 		editManager->getTerrainSelection().setSelection(vec);
-		editManager->drawTerrain(ETerrainId::ROCK);
+		editManager->drawTerrain(ETerrainId::ROCK, 10);
 		EXPECT_TRUE(!map->getTile(int3(5, 6, 1)).terType->isPassable() || !map->getTile(int3(7, 8, 1)).terType->isPassable());
 
 		//todo: add checks here and enable, also use smaller size
@@ -144,7 +144,7 @@ TEST(MapManager, DrawTerrain_View)
 				int3 pos((si32)posVector[0].Float(), (si32)posVector[1].Float(), (si32)posVector[2].Float());
 				const auto & originalTile = originalMap->getTile(pos);
 				editManager->getTerrainSelection().selectRange(MapRect(pos, 1, 1));
-				editManager->drawTerrain(originalTile.terType->getId(), &gen);
+				editManager->drawTerrain(originalTile.terType->getId(), 10, &gen);
 				const auto & tile = map->getTile(pos);
 				bool isInRange = false;
 				for(const auto & range : mapping)