瀏覽代碼

[0002285] Implement feature with extra resources near mines (#742)

* RMG: clear start position
* [0002285] some heaps of resources are placed nearby mines
* Fix leak in case of inability to place resource
* Fix indentation according to vcmi style
* Add constant for random amount of resources
* Code review fixes
Nordsoft91 3 年之前
父節點
當前提交
a8265c7052
共有 4 個文件被更改,包括 71 次插入42 次删除
  1. 2 2
      lib/mapObjects/MiscObjects.cpp
  2. 2 0
      lib/mapObjects/MiscObjects.h
  3. 65 40
      lib/rmg/CRmgTemplateZone.cpp
  4. 2 0
      lib/rmg/CRmgTemplateZone.h

+ 2 - 2
lib/mapObjects/MiscObjects.cpp

@@ -838,14 +838,14 @@ std::string CGResource::getHoverText(PlayerColor player) const
 
 CGResource::CGResource()
 {
-	amount = 0;
+	amount = CGResource::RANDOM_AMOUNT;
 }
 
 void CGResource::initObj(CRandomGenerator & rand)
 {
 	blockVisit = true;
 
-	if(!amount)
+	if(amount == CGResource::RANDOM_AMOUNT)
 	{
 		switch(subID)
 		{

+ 2 - 0
lib/mapObjects/MiscObjects.h

@@ -215,7 +215,9 @@ protected:
 class DLL_LINKAGE CGResource : public CArmedInstance
 {
 public:
+	static const ui32 RANDOM_AMOUNT = 0;
 	ui32 amount; //0 if random
+	
 	std::string message;
 
 	CGResource();

+ 65 - 40
lib/rmg/CRmgTemplateZone.cpp

@@ -790,6 +790,10 @@ void CRmgTemplateZone::addCloseObject(CGObjectInstance * obj, si32 strength)
 {
 	closeObjects.push_back(std::make_pair(obj, strength));
 }
+void CRmgTemplateZone::addNearbyObject(CGObjectInstance * obj, CGObjectInstance * nearbyTarget)
+{
+	nearbyObjects.push_back(std::make_pair(obj, nearbyTarget));
+}
 
 void CRmgTemplateZone::addToConnectLater(const int3& src)
 {
@@ -1106,14 +1110,17 @@ void CRmgTemplateZone::initTownType ()
 	//cut a ring around town to ensure crunchPath always hits it.
 	auto cutPathAroundTown = [this](const CGTownInstance * town)
 	{
+		auto clearPos = [this](const int3 & pos)
+		{
+			if (gen->isPossible(pos))
+				gen->setOccupied(pos, ETileType::FREE);
+		};
 		for (auto blockedTile : town->getBlockedPos())
 		{
-			gen->foreach_neighbour(blockedTile, [this](const int3 & pos)
-			{
-				if (gen->isPossible(pos))
-					gen->setOccupied(pos, ETileType::FREE);
-			});
+			gen->foreach_neighbour(blockedTile, clearPos);
 		}
+		//clear town entry
+		gen->foreach_neighbour(town->visitablePos()+int3{0,1,0}, clearPos);
 	};
 
 	auto addNewTowns = [&totalTowns, this, &cutPathAroundTown](int count, bool hasFort, PlayerColor player)
@@ -1294,53 +1301,39 @@ void CRmgTemplateZone::paintZoneTerrain (ETerrainType terrainType)
 
 bool CRmgTemplateZone::placeMines ()
 {
-	static const Res::ERes woodOre[] = {Res::ERes::WOOD, Res::ERes::ORE};
-	static const Res::ERes preciousResources[] = {Res::ERes::GEMS, Res::ERes::CRYSTAL, Res::ERes::MERCURY, Res::ERes::SULFUR};
-
-	std::array<TObjectTypeHandler, 7> factory =
+	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;
+	
+	for(const auto & mineInfo : mines)
 	{
-		VLC->objtypeh->getHandlerFor(Obj::MINE, 0),
-		VLC->objtypeh->getHandlerFor(Obj::MINE, 1),
-		VLC->objtypeh->getHandlerFor(Obj::MINE, 2),
-		VLC->objtypeh->getHandlerFor(Obj::MINE, 3),
-		VLC->objtypeh->getHandlerFor(Obj::MINE, 4),
-		VLC->objtypeh->getHandlerFor(Obj::MINE, 5),
-		VLC->objtypeh->getHandlerFor(Obj::MINE, 6)
-	};
-
-	for (const auto & res : woodOre)
-	{
-		for (int i = 0; i < mines[res]; i++)
+		ERes res = (ERes)mineInfo.first;
+		for(int i = 0; i < mineInfo.second; ++i)
 		{
-			auto mine = (CGMine *) factory.at(static_cast<si32>(res))->create(ObjectTemplate());
+			auto mine = (CGMine*) VLC->objtypeh->getHandlerFor(Obj::MINE, res)->create(ObjectTemplate());
 			mine->producedResource = res;
 			mine->tempOwner = PlayerColor::NEUTRAL;
 			mine->producedQuantity = mine->defaultResProduction();
-			if (!i)
-				addCloseObject(mine, 1500); //only firts one is close
+			createdMines.push_back(mine);
+			
+			if(!i && (res == ERes::WOOD || res == ERes::ORE))
+				addCloseObject(mine, mineValue.at(res)); //only first woor&ore mines are close
 			else
-				addRequiredObject(mine, 1500);
+				addRequiredObject(mine, mineValue.at(res));
 		}
 	}
-	for (const auto & res : preciousResources)
+	
+	//create extra resources
+	for(auto * mine : createdMines)
 	{
-		for (int i = 0; i < mines[res]; i++)
+		for(int rc = gen->rand.nextInt(1, 3); rc > 0; --rc)
 		{
-			auto mine = (CGMine *) factory.at(static_cast<si32>(res))->create(ObjectTemplate());
-			mine->producedResource = res;
-			mine->tempOwner = PlayerColor::NEUTRAL;
-			mine->producedQuantity = mine->defaultResProduction();
-			addRequiredObject(mine, 3500);
+			auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate());
+			resourse->amount = CGResource::RANDOM_AMOUNT;
+			addNearbyObject(resourse, mine);
 		}
 	}
-	for (int i = 0; i < mines[Res::GOLD]; i++)
-	{
-		auto mine = (CGMine *) factory.at(Res::GOLD)->create(ObjectTemplate());
-		mine->producedResource = Res::GOLD;
-		mine->tempOwner = PlayerColor::NEUTRAL;
-		mine->producedQuantity = mine->defaultResProduction();
-		addRequiredObject(mine, 7000);
-	}
 
 	return true;
 }
@@ -1463,6 +1456,38 @@ bool CRmgTemplateZone::createRequiredObjects()
 		}
 	}
 
+	//create nearby objects (e.g. extra resources close to mines)
+	for(const auto & object : nearbyObjects)
+	{
+		auto obj = object.first;
+		std::set<int3> possiblePositions;
+		for (auto blockedTile : object.second->getBlockedPos())
+		{
+			gen->foreachDirectNeighbour(blockedTile, [this, &possiblePositions](int3 pos)
+			{
+				if (!gen->isBlocked(pos))
+				{
+					//some resources still could be unaccessible, at least one free cell shall be
+					gen->foreach_neighbour(pos, [this, &possiblePositions, &pos](int3 p)
+												{
+						if(gen->isFree(p))
+							possiblePositions.insert(pos);
+					});
+				}
+			});
+		}
+
+		if(possiblePositions.empty())
+		{
+			delete obj; //is it correct way to prevent leak?
+		}
+		else
+		{
+			auto pos = *RandomGeneratorUtil::nextItem(possiblePositions, gen->rand);
+			placeObject(obj, pos);
+		}
+	}
+
 	return true;
 }
 

+ 2 - 0
lib/rmg/CRmgTemplateZone.h

@@ -111,6 +111,7 @@ public:
 
 	void addRequiredObject(CGObjectInstance * obj, si32 guardStrength=0);
 	void addCloseObject(CGObjectInstance * obj, si32 guardStrength = 0);
+	void addNearbyObject(CGObjectInstance * obj, CGObjectInstance * nearbyTarget);
 	void addToConnectLater(const int3& src);
 	bool addMonster(int3 &pos, si32 strength, bool clearSurroundingTiles = true, bool zoneGuard = false);
 	bool createTreasurePile(int3 &pos, float minDistance, const CTreasureInfo& treasureInfo);
@@ -173,6 +174,7 @@ private:
 	//content info
 	std::vector<std::pair<CGObjectInstance*, ui32>> requiredObjects;
 	std::vector<std::pair<CGObjectInstance*, ui32>> closeObjects;
+	std::vector<std::pair<CGObjectInstance*, CGObjectInstance*>> nearbyObjects;
 	std::vector<CGObjectInstance*> objects;
 
 	//placement info