소스 검색

Some working version, needs corrections still.

Tomasz Zieliński 2 년 전
부모
커밋
d325051213
8개의 변경된 파일119개의 추가작업 그리고 46개의 파일을 삭제
  1. 2 1
      lib/rmg/CMapGenerator.cpp
  2. 1 0
      lib/rmg/Functions.cpp
  3. 32 1
      lib/rmg/ObjectDistributor.cpp
  4. 1 0
      lib/rmg/ObjectDistributor.h
  5. 29 4
      lib/rmg/QuestArtifactPlacer.cpp
  6. 8 0
      lib/rmg/QuestArtifactPlacer.h
  7. 2 0
      lib/rmg/RmgMap.h
  8. 44 40
      lib/rmg/TreasurePlacer.cpp

+ 2 - 1
lib/rmg/CMapGenerator.cpp

@@ -113,7 +113,8 @@ void CMapGenerator::initQuestArtsRemaining()
 	//TODO: Move to QuestArtifactPlacer?
 	//TODO: Move to QuestArtifactPlacer?
 	for (auto art : VLC->arth->objects)
 	for (auto art : VLC->arth->objects)
 	{
 	{
-		if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->getId()) && art->constituentOf.empty()) //don't use parts of combined artifacts
+		//Don't use parts of combined artifacts
+		if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->getId()) && art->constituentOf.empty())
 			questArtifacts.push_back(art->getId());
 			questArtifacts.push_back(art->getId());
 	}
 	}
 }
 }

+ 1 - 0
lib/rmg/Functions.cpp

@@ -82,6 +82,7 @@ int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, TerrainId t
 	auto factories = VLC->objtypeh->knownSubObjects(ObjID);
 	auto factories = VLC->objtypeh->knownSubObjects(ObjID);
 	vstd::erase_if(factories, [ObjID, &terrain](si32 f)
 	vstd::erase_if(factories, [ObjID, &terrain](si32 f)
 	{
 	{
+		//TODO: Use templates with lowest number of terrains (most specific)
 		return VLC->objtypeh->getHandlerFor(ObjID, f)->getTemplates(terrain).empty();
 		return VLC->objtypeh->getHandlerFor(ObjID, f)->getTemplates(terrain).empty();
 	});
 	});
 	
 	

+ 32 - 1
lib/rmg/ObjectDistributor.cpp

@@ -15,6 +15,7 @@
 #include "RmgMap.h"
 #include "RmgMap.h"
 #include "CMapGenerator.h"
 #include "CMapGenerator.h"
 #include "TreasurePlacer.h"
 #include "TreasurePlacer.h"
+#include "QuestArtifactPlacer.h"
 #include "TownPlacer.h"
 #include "TownPlacer.h"
 #include "TerrainPainter.h"
 #include "TerrainPainter.h"
 #include "../mapObjects/CObjectClassesHandler.h"
 #include "../mapObjects/CObjectClassesHandler.h"
@@ -29,7 +30,8 @@ void ObjectDistributor::process()
 	//Firts call will add objects to ALL zones, once they were added skip it
 	//Firts call will add objects to ALL zones, once they were added skip it
 	if (zone.getModificator<TreasurePlacer>()->getPossibleObjectsSize() == 0)
 	if (zone.getModificator<TreasurePlacer>()->getPossibleObjectsSize() == 0)
 	{
 	{
-		ObjectDistributor::distributeLimitedObjects();
+		distributeLimitedObjects();
+		distributeSeerHuts();
 	}
 	}
 }
 }
 
 
@@ -118,4 +120,33 @@ void ObjectDistributor::distributeLimitedObjects()
 	}
 	}
 }
 }
 
 
+void ObjectDistributor::distributeSeerHuts()
+{
+	//TODO: Move typedef outside the class?
+
+	//Copy by value to random shuffle
+	const auto & zoneMap = map.getZones();
+	RmgMap::ZoneVector zones(zoneMap.begin(), zoneMap.end());
+
+	RandomGeneratorUtil::randomShuffle(zones, generator.rand);
+
+	const auto & possibleQuestArts = generator.getQuestArtsRemaning();
+	size_t availableArts = possibleQuestArts.size();
+	auto artIt = possibleQuestArts.begin();
+	for (int i = zones.size() - 1; i >= 0 ; i--)
+	{
+		size_t localArts = std::ceil((float)availableArts / (i + 1));
+		availableArts -= localArts;
+
+		auto * qap = zones[i].second->getModificator<QuestArtifactPlacer>();
+		if (qap)
+		{
+			for (;localArts > 0 && artIt != possibleQuestArts.end(); artIt++, localArts--)
+			{
+				qap->addRandomArtifact(*artIt);
+			}
+		}
+	}
+}
+
 VCMI_LIB_NAMESPACE_END
 VCMI_LIB_NAMESPACE_END

+ 1 - 0
lib/rmg/ObjectDistributor.h

@@ -21,6 +21,7 @@ class ObjectTemplate;
 class ObjectDistributor : public Modificator
 class ObjectDistributor : public Modificator
 {
 {
 	void distributeLimitedObjects();
 	void distributeLimitedObjects();
+	void distributeSeerHuts();
 
 
 public:
 public:
 	MODIFICATOR(ObjectDistributor);
 	MODIFICATOR(ObjectDistributor);

+ 29 - 4
lib/rmg/QuestArtifactPlacer.cpp

@@ -54,9 +54,7 @@ std::vector<CGObjectInstance*> QuestArtifactPlacer::getPossibleArtifactsToReplac
 
 
 void QuestArtifactPlacer::findZonesForQuestArts()
 void QuestArtifactPlacer::findZonesForQuestArts()
 {
 {
-	//FIXME: Store and access CZonePlacer from CMapGenerator
-
-	const auto& distances = 	generator.getZonePlacer()->getDistanceMap().at(zone.getId());
+	const auto& distances = generator.getZonePlacer()->getDistanceMap().at(zone.getId());
 	for (auto const& connectedZone : distances)
 	for (auto const& connectedZone : distances)
 	{
 	{
 		// Choose zones that are 1 or 2 connections away
 		// Choose zones that are 1 or 2 connections away
@@ -96,6 +94,8 @@ void QuestArtifactPlacer::placeQuestArtifacts(CRandomGenerator * rand)
 			artifactToReplace->appearance = templates.front();
 			artifactToReplace->appearance = templates.front();
 			//FIXME: Instance name is still "randomArtifact"
 			//FIXME: Instance name is still "randomArtifact"
 
 
+			//FIXME: Every qap has its OWN collection of artifacts,
+			//which means different qaps can replace the same object many times
 			qap->dropReplacedArtifact(artifactToReplace);
 			qap->dropReplacedArtifact(artifactToReplace);
 
 
 			break;
 			break;
@@ -106,4 +106,29 @@ void QuestArtifactPlacer::placeQuestArtifacts(CRandomGenerator * rand)
 void QuestArtifactPlacer::dropReplacedArtifact(CGObjectInstance* obj)
 void QuestArtifactPlacer::dropReplacedArtifact(CGObjectInstance* obj)
 {
 {
 	boost::remove(artifactsToReplace, obj);
 	boost::remove(artifactsToReplace, obj);
-}
+}
+
+size_t QuestArtifactPlacer::getMaxQuestArtifactCount() const
+{
+	return questArtifacts.size();
+}
+
+ArtifactID QuestArtifactPlacer::drawRandomArtifact()
+{
+	if (!questArtifacts.empty())
+	{
+		ArtifactID ret = questArtifacts.back();
+		questArtifacts.pop_back();
+		RandomGeneratorUtil::randomShuffle(questArtifacts, generator.rand);
+		return ret;
+	}
+	else
+	{
+		throw rmgException("No quest artifacts left for this zone!");
+	}
+}
+
+void QuestArtifactPlacer::addRandomArtifact(ArtifactID artid)
+{
+	questArtifacts.push_back(artid);
+}

+ 8 - 0
lib/rmg/QuestArtifactPlacer.h

@@ -10,6 +10,7 @@
 
 
 #pragma once
 #pragma once
 #include "Zone.h"
 #include "Zone.h"
+#include "Functions.h"
 #include "../mapObjects/ObjectTemplate.h"
 #include "../mapObjects/ObjectTemplate.h"
 
 
 VCMI_LIB_NAMESPACE_BEGIN
 VCMI_LIB_NAMESPACE_BEGIN
@@ -33,11 +34,18 @@ public:
 	void placeQuestArtifacts(CRandomGenerator* rand);
 	void placeQuestArtifacts(CRandomGenerator* rand);
 	void dropReplacedArtifact(CGObjectInstance* obj);
 	void dropReplacedArtifact(CGObjectInstance* obj);
 
 
+	size_t getMaxQuestArtifactCount() const;
+	ArtifactID drawRandomArtifact();
+	void addRandomArtifact(ArtifactID artid);
+
 protected:
 protected:
 
 
 	std::vector<std::shared_ptr<Zone>> questArtZones; //artifacts required for Seer Huts will be placed here - or not if null
 	std::vector<std::shared_ptr<Zone>> questArtZones; //artifacts required for Seer Huts will be placed here - or not if null
 	std::vector<ArtifactID> questArtifactsToPlace;
 	std::vector<ArtifactID> questArtifactsToPlace;
 	std::vector<CGObjectInstance*> artifactsToReplace; //Common artifacts which may be replaced by quest artifacts from other zones
 	std::vector<CGObjectInstance*> artifactsToReplace; //Common artifacts which may be replaced by quest artifacts from other zones
+
+	size_t maxQuestArtifacts;
+	std::vector<ArtifactID> questArtifacts;
 };
 };
 
 
 VCMI_LIB_NAMESPACE_END
 VCMI_LIB_NAMESPACE_END

+ 2 - 0
lib/rmg/RmgMap.h

@@ -57,6 +57,8 @@ public:
 	void setZoneID(const int3& tile, TRmgTemplateZoneId zid);
 	void setZoneID(const int3& tile, TRmgTemplateZoneId zid);
 	
 	
 	using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
 	using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
+	using ZonePair = std::pair<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
+	using ZoneVector = std::vector<ZonePair>;
 	
 	
 	Zones & getZones();
 	Zones & getZones();
 	
 	

+ 44 - 40
lib/rmg/TreasurePlacer.cpp

@@ -70,6 +70,7 @@ void TreasurePlacer::addAllPossibleObjects()
 				if (templates.empty())
 				if (templates.empty())
 					continue;
 					continue;
 
 
+				//TODO: Reuse chooseRandomAppearance (eg. WoG treasure chests)
 				//Assume the template with fewest terrains is the most suitable
 				//Assume the template with fewest terrains is the most suitable
 				auto temp = *boost::min_element(templates, [](std::shared_ptr<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> rhs) -> bool
 				auto temp = *boost::min_element(templates, [](std::shared_ptr<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> rhs) -> bool
 				{
 				{
@@ -385,44 +386,28 @@ void TreasurePlacer::addAllPossibleObjects()
 	oi.probability = 2;
 	oi.probability = 2;
 	addObjectToRandomPool(oi);
 	addObjectToRandomPool(oi);
 	
 	
-	//seer huts with creatures or generic rewards
+	//Seer huts with creatures or generic rewards
 
 
 	if(zone.getConnections().size()) //Unlikely, but...
 	if(zone.getConnections().size()) //Unlikely, but...
 	{
 	{
-		static const int genericSeerHuts = 8;
-		int seerHutsPerType = 0;
-		const int questArtsRemaining = static_cast<int>(generator.getQuestArtsRemaning().size());
-		
-		//general issue is that not many artifact types are available for quests
-
-		if(questArtsRemaining >= genericSeerHuts + static_cast<int>(creatures.size()))
-		{
-			seerHutsPerType = questArtsRemaining / (genericSeerHuts + static_cast<int>(creatures.size()));
-		}
-		else if(questArtsRemaining >= genericSeerHuts)
+		auto * qap = zone.getModificator<QuestArtifactPlacer>();
+		if(!qap)
 		{
 		{
-			seerHutsPerType = 1;
+			return; //TODO: throw?
 		}
 		}
-		oi.maxPerZone = seerHutsPerType;
 		
 		
-		RandomGeneratorUtil::randomShuffle(creatures, generator.rand);
+		const int questArtsRemaining = qap->getMaxQuestArtifactCount();
+		
+		//Generate Seer Hut one by one. Duplicated oi possible and should work fine.
+		oi.maxPerZone = 1;
 
 
-		auto generateArtInfo = [this](const ArtifactID & id) -> ObjectInfo
-		{
-			ObjectInfo artInfo;
-			artInfo.probability = std::numeric_limits<ui16>::max(); //99,9% to spawn that art in first treasure pile
-			artInfo.maxPerZone = 1;
-			artInfo.value = 2000; //treasure art
-			artInfo.setTemplate(Obj::ARTIFACT, id, this->zone.getTerrainType());
-			artInfo.generateObject = [id]() -> CGObjectInstance *
-			{
-				auto handler = VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, id);
-				return handler->create(handler->getTemplates().front());
-			};
-			return artInfo;
-		};
+		std::vector<ObjectInfo> possibleSeerHuts;
+		//14 creatures per town + 4 for each of gold / exp reward
+		possibleSeerHuts.reserve(14 + 4 + 4);
+		
+		RandomGeneratorUtil::randomShuffle(creatures, generator.rand);
 
 
-		for(int i = 0; i < std::min(static_cast<int>(creatures.size()), questArtsRemaining - genericSeerHuts); i++)
+		for(int i = 0; i < static_cast<int>(creatures.size()); i++)
 		{
 		{
 			auto * creature = creatures[i];
 			auto * creature = creatures[i];
 			int creaturesAmount = creatureToCount(creature);
 			int creaturesAmount = creatureToCount(creature);
@@ -432,7 +417,7 @@ void TreasurePlacer::addAllPossibleObjects()
 			
 			
 			int randomAppearance = chooseRandomAppearance(generator.rand, Obj::SEER_HUT, zone.getTerrainType());
 			int randomAppearance = chooseRandomAppearance(generator.rand, Obj::SEER_HUT, zone.getTerrainType());
 			
 			
-			oi.generateObject = [creature, creaturesAmount, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
+			oi.generateObject = [creature, creaturesAmount, randomAppearance, this, qap]() -> CGObjectInstance *
 			{
 			{
 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
 				auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
 				auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
@@ -441,7 +426,8 @@ void TreasurePlacer::addAllPossibleObjects()
 				obj->rVal = creaturesAmount;
 				obj->rVal = creaturesAmount;
 				
 				
 				obj->quest->missionType = CQuest::MISSION_ART;
 				obj->quest->missionType = CQuest::MISSION_ART;
-				ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
+				
+				ArtifactID artid = qap->drawRandomArtifact();
 				obj->quest->addArtifactID(artid);
 				obj->quest->addArtifactID(artid);
 				obj->quest->lastDay = -1;
 				obj->quest->lastDay = -1;
 				obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
 				obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
@@ -451,10 +437,17 @@ void TreasurePlacer::addAllPossibleObjects()
 				
 				
 				return obj;
 				return obj;
 			};
 			};
+			oi.probability = 3;
 			oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
 			oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
 			oi.value = static_cast<ui32>(((2 * (creature->getAIValue()) * creaturesAmount * (1 + static_cast<float>(map.getZoneCount(creature->getFaction())) / map.getTotalZoneCount())) - 4000) / 3);
 			oi.value = static_cast<ui32>(((2 * (creature->getAIValue()) * creaturesAmount * (1 + static_cast<float>(map.getZoneCount(creature->getFaction())) / map.getTotalZoneCount())) - 4000) / 3);
-			oi.probability = 3;
-			addObjectToRandomPool(oi);
+			if (oi.value > zone.getMaxTreasureValue())
+			{
+				continue;
+			}
+			else
+			{
+				possibleSeerHuts.push_back(oi);
+			}
 		}
 		}
 		
 		
 		static int seerLevels = std::min(generator.getConfig().questValues.size(), generator.getConfig().questRewardValues.size());
 		static int seerLevels = std::min(generator.getConfig().questValues.size(), generator.getConfig().questRewardValues.size());
@@ -464,9 +457,15 @@ void TreasurePlacer::addAllPossibleObjects()
 			
 			
 			oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
 			oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
 			oi.value = generator.getConfig().questValues[i];
 			oi.value = generator.getConfig().questValues[i];
+			if (oi.value > zone.getMaxTreasureValue())
+			{
+				//Both variants have same value
+				continue;
+			}
+
 			oi.probability = 10;
 			oi.probability = 10;
 			
 			
-			oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
+			oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
 			{
 			{
 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
 				auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
 				auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
@@ -476,7 +475,7 @@ void TreasurePlacer::addAllPossibleObjects()
 				obj->rVal = generator.getConfig().questRewardValues[i];
 				obj->rVal = generator.getConfig().questRewardValues[i];
 				
 				
 				obj->quest->missionType = CQuest::MISSION_ART;
 				obj->quest->missionType = CQuest::MISSION_ART;
-				ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
+				ArtifactID artid = qap->drawRandomArtifact();
 				obj->quest->addArtifactID(artid);
 				obj->quest->addArtifactID(artid);
 				obj->quest->lastDay = -1;
 				obj->quest->lastDay = -1;
 				obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
 				obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
@@ -487,9 +486,9 @@ void TreasurePlacer::addAllPossibleObjects()
 				return obj;
 				return obj;
 			};
 			};
 			
 			
-			addObjectToRandomPool(oi);
+			possibleSeerHuts.push_back(oi);
 			
 			
-			oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
+			oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
 			{
 			{
 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
 				auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
 				auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
@@ -498,7 +497,7 @@ void TreasurePlacer::addAllPossibleObjects()
 				obj->rVal = generator.getConfig().questRewardValues[i];
 				obj->rVal = generator.getConfig().questRewardValues[i];
 				
 				
 				obj->quest->missionType = CQuest::MISSION_ART;
 				obj->quest->missionType = CQuest::MISSION_ART;
-				ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
+				ArtifactID artid = qap->drawRandomArtifact();
 				obj->quest->addArtifactID(artid);
 				obj->quest->addArtifactID(artid);
 				obj->quest->lastDay = -1;
 				obj->quest->lastDay = -1;
 				obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
 				obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
@@ -509,7 +508,12 @@ void TreasurePlacer::addAllPossibleObjects()
 				return obj;
 				return obj;
 			};
 			};
 			
 			
-			addObjectToRandomPool(oi);
+			possibleSeerHuts.push_back(oi);
+		}
+
+		for (size_t i = 0; i < questArtsRemaining; i++)
+		{
+			addObjectToRandomPool(*RandomGeneratorUtil::nextItem(possibleSeerHuts, generator.rand));
 		}
 		}
 	}
 	}
 }
 }