Explorar o código

Create random obstacles that match terrain.

DjWarmonger %!s(int64=11) %!d(string=hai) anos
pai
achega
920f56969b

+ 1 - 1
ChangeLog

@@ -15,7 +15,7 @@ SPELLS:
 * New configuration format: http://wiki.vcmi.eu/index.php?title=Spell_Format
 
 RANDOM MAP GENERATOR
-* Towns form mods cna be used
+* Towns from mods can be used
 * Reading connections, terrains, towns and mines from template
 * Zone placement
 * Zone borders and connections, fractalized paths inside zones

+ 1 - 10
lib/mapObjects/CObjectHandler.cpp

@@ -178,16 +178,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
 
 std::set<int3> CGObjectInstance::getBlockedOffsets() const
 {
-	std::set<int3> ret;
-	for(int w=0; w<getWidth(); ++w)
-	{
-		for(int h=0; h<getHeight(); ++h)
-		{
-			if (appearance.isBlockedAt(w, h))
-				ret.insert(int3(-w, -h, 0));
-		}
-	}
-	return ret;
+	return appearance.getBlockedOffsets();
 }
 
 void CGObjectInstance::setType(si32 ID, si32 subID)

+ 27 - 0
lib/mapObjects/ObjectTemplate.cpp

@@ -308,6 +308,33 @@ bool ObjectTemplate::isBlockedAt(si32 X, si32 Y) const
 	return false;
 }
 
+std::set<int3> ObjectTemplate::getBlockedOffsets() const
+{
+	std::set<int3> ret;
+	for(int w = 0; w < getWidth(); ++w)
+	{
+		for(int h = 0; h < getHeight(); ++h)
+		{
+			if (isBlockedAt(w, h))
+				ret.insert(int3(-w, -h, 0));
+		}
+	}
+	return ret;
+}
+
+int3 ObjectTemplate::getBlockMapOffset() const
+{
+	for(int w = 0; w < getWidth(); ++w)
+	{
+		for(int h = 0; h < getHeight(); ++h)
+		{
+			if (isBlockedAt(w, h))
+				return int3(-w, -h, 0);
+		}
+	}
+	return int3(-1,-1,-1);
+}
+
 bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
 {
 	// visitDir uses format

+ 3 - 0
lib/mapObjects/ObjectTemplate.h

@@ -15,6 +15,7 @@
 class CBinaryReader;
 class CLegacyConfigParser;
 class JsonNode;
+class int3;
 
 class DLL_LINKAGE ObjectTemplate
 {
@@ -56,6 +57,8 @@ public:
 	bool isVisitableAt(si32 X, si32 Y) const;
 	bool isVisibleAt(si32 X, si32 Y) const;
 	bool isBlockedAt(si32 X, si32 Y) const;
+	std::set<int3> getBlockedOffsets() const;
+	int3 getBlockMapOffset() const; //bottom-right corner when firts blocked tile is
 
 	// Checks if object is visitable from certain direction. X and Y must be between -1..+1
 	bool isVisitableFrom(si8 X, si8 Y) const;

+ 54 - 8
lib/rmg/CRmgTemplateZone.cpp

@@ -962,20 +962,49 @@ void CRmgTemplateZone::createTreasures(CMapGenerator* gen)
 
 void CRmgTemplateZone::createObstacles(CMapGenerator* gen)
 {
+	//get all possible obstacles for this terrain
+	for (auto primaryID : VLC->objtypeh->knownObjects()) 
+	{ 
+		for (auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) 
+		{ 
+			auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); 
+			if (handler->isStaticObject())
+			{
+				for (auto temp : handler->getTemplates())
+				{
+					if (temp.canBePlacedAt(terrainType) && temp.getBlockMapOffset().valid())
+						possibleObstacles.push_back(temp);
+				}
+			}
+		} 
+	}
+
 	auto sel = gen->editManager->getTerrainSelection();
 	sel.clearSelection();
-	for (auto tile : tileinfo)
+
+	auto tryToPlaceObstacleHere = [this, gen](int3& tile)-> bool
 	{
-		//test code - block all the map to show paths clearly
-		//if (gen->isPossible(tile))
-		//	gen->setOccupied(tile, ETileType::BLOCKED);
+		auto temp = *RandomGeneratorUtil::nextItem(possibleObstacles, gen->rand);
+		int3 obstaclePos = tile + temp.getBlockMapOffset();
+		if (canObstacleBePlacedHere(gen, temp, obstaclePos)) //can be placed here
+		{
+			auto obj = VLC->objtypeh->getHandlerFor(temp.id, temp.subid)->create(temp);
+			placeObject(gen, obj, obstaclePos);
+			return true;
+		}
+		return false;
+	};
 
+	for (auto tile : tileinfo)
+	{
 		if (gen->shouldBeBlocked(tile)) //fill tiles that should be blocked with obstacles
 		{
-			auto obj = new CGObjectInstance();
-			obj->ID = static_cast<Obj>(57);
-			obj->subID = 0;
-			placeObject(gen, obj, tile);
+			while (!tryToPlaceObstacleHere(tile));
+		}
+		else if (gen->isPossible(tile))
+		{
+			//try to place random obstacle once - if not possible, leave it clear
+			tryToPlaceObstacleHere(tile);
 		}
 	}
 }
@@ -1031,6 +1060,23 @@ bool CRmgTemplateZone::findPlaceForTreasurePile(CMapGenerator* gen, si32 min_dis
 	return result;
 }
 
+bool CRmgTemplateZone::canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos)
+{
+	auto tilesBlockedByObject = temp.getBlockedOffsets();
+
+	bool allTilesAvailable = true;
+	for (auto blockingTile : tilesBlockedByObject)
+	{
+		int3 t = pos + blockingTile;
+		if (!gen->map->isInTheMap(t) || !(gen->isPossible(t) || gen->shouldBeBlocked(t)))
+		{
+			allTilesAvailable = false; //if at least one tile is not possible, object can't be placed here
+			break;
+		}
+	}
+	return allTilesAvailable;
+}
+
 bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
 {
 	//we need object apperance to deduce free tiles

+ 3 - 0
lib/rmg/CRmgTemplateZone.h

@@ -21,6 +21,7 @@ class CMapGenerator;
 class CTileInfo;
 class int3;
 class CGObjectInstance;
+class ObjectTemplate;
 
 namespace ETemplateZoneType
 {
@@ -173,6 +174,7 @@ private:
 	ui16 totalDensity;
 	std::vector<CTreasureInfo> treasureInfo;
 	std::vector<ObjectInfo> possibleObjects;
+	std::vector<ObjectTemplate> possibleObstacles;
 
 	//content info
 	std::vector<std::pair<CGObjectInstance*, ui32>> requiredObjects;
@@ -189,6 +191,7 @@ private:
 	void addAllPossibleObjects (CMapGenerator* gen); //add objects, including zone-specific, to possibleObjects
 	bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos);
 	bool findPlaceForTreasurePile(CMapGenerator* gen, si32 min_dist, int3 &pos);
+	bool canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos);
 	void checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
 	void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
 	bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str);