Sfoglia il codice sorgente

Treasure placement uses random templates now

nordsoft 2 anni fa
parent
commit
3ea7988883

+ 4 - 15
lib/rmg/modificators/ObjectDistributor.cpp

@@ -79,25 +79,14 @@ void ObjectDistributor::distributeLimitedObjects()
 
 					for (auto& zone : matchingZones)
 					{
-						//We already know there are some templates
-						auto templates = handler->getTemplates(zone->getTerrainType());
-
-						//FIXME: Templates empty?! Maybe zone changed terrain type over time?
-
-						//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
-						{
-							return lhs->getAllowedTerrains().size() < rhs->getAllowedTerrains().size();
-						});
-
-						oi.generateObject = [temp]() -> CGObjectInstance *
+						oi.generateObject = [primaryID, secondaryID]() -> CGObjectInstance *
 						{
-							return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp);
+							return VLC->objtypeh->getHandlerFor(primaryID, secondaryID)->create();
 						};
 						
 						oi.value = rmgInfo.value;
 						oi.probability = rmgInfo.rarity;
-						oi.templ = temp;
+						oi.setTemplates(primaryID, secondaryID, zone->getTerrainType());
 
 						//Rounding up will make sure all possible objects are exhausted
 						uint32_t mapLimit = rmgInfo.mapLimit.value();
@@ -109,7 +98,7 @@ void ObjectDistributor::distributeLimitedObjects()
 
 						rmgInfo.setMapLimit(mapLimit - oi.maxPerZone);
 						//Don't add objects with 0 count remaining
-						if (oi.maxPerZone)
+						if(oi.maxPerZone && !oi.templates.empty())
 						{
 							zone->getModificator<TreasurePlacer>()->addObjectToRandomPool(oi);
 						}

+ 64 - 61
lib/rmg/modificators/TreasurePlacer.cpp

@@ -72,26 +72,16 @@ void TreasurePlacer::addAllPossibleObjects()
 					continue;
 				}
 
-				auto templates = handler->getTemplates(zone.getTerrainType());
-				if (templates.empty())
-					continue;
-
-				//TODO: Reuse chooseRandomAppearance (eg. WoG treasure chests)
-				//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
+				oi.generateObject = [primaryID, secondaryID]() -> CGObjectInstance *
 				{
-					return lhs->getAllowedTerrains().size() < rhs->getAllowedTerrains().size();
-				});
-
-				oi.generateObject = [temp]() -> CGObjectInstance *
-				{
-					return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp);
+					return VLC->objtypeh->getHandlerFor(primaryID, secondaryID)->create();
 				};
 				oi.value = rmgInfo.value;
 				oi.probability = rmgInfo.rarity;
-				oi.templ = temp;
+				oi.setTemplates(primaryID, secondaryID, zone.getTerrainType());
 				oi.maxPerZone = rmgInfo.zoneLimit;
-				addObjectToRandomPool(oi);
+				if(!oi.templates.empty())
+					addObjectToRandomPool(oi);
 			}
 		}
 	}
@@ -125,18 +115,18 @@ void TreasurePlacer::addAllPossibleObjects()
 				obj->exp = generator.getConfig().prisonExperience[i];
 				obj->setOwner(PlayerColor::NEUTRAL);
 				generator.banHero(hid);
-				obj->appearance = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0)->getTemplates(zone.getTerrainType()).front(); //can't init template with hero subID
 
 				return obj;
 			};
-			oi.setTemplate(Obj::PRISON, 0, zone.getTerrainType());
+			oi.setTemplates(Obj::PRISON, 0, zone.getTerrainType());
 			oi.value = generator.getConfig().prisonValues[i];
 			oi.probability = 30;
 
 			//Distribute all allowed prisons, starting from the most valuable
 			oi.maxPerZone = (std::ceil((float)prisonsLeft / (i + 1)));
 			prisonsLeft -= oi.maxPerZone;
-			addObjectToRandomPool(oi);
+			if(!oi.templates.empty())
+				addObjectToRandomPool(oi);
 		}
 	}
 
@@ -183,22 +173,16 @@ void TreasurePlacer::addAllPossibleObjects()
 				auto nativeZonesCount = static_cast<float>(map.getZoneCount(cre->getFaction()));
 				oi.value = static_cast<ui32>(cre->getAIValue() * cre->getGrowth() * (1 + (nativeZonesCount / map.getTotalZoneCount()) + (nativeZonesCount / 2)));
 				oi.probability = 40;
-
-				for(const auto & tmplate : dwellingHandler->getTemplates())
+				
+				oi.generateObject = [secondaryID, dwellingType]() -> CGObjectInstance *
 				{
-					if(tmplate->canBePlacedAt(zone.getTerrainType()))
-					{
-						oi.generateObject = [tmplate, secondaryID, dwellingType]() -> CGObjectInstance *
-						{
-							auto * obj = VLC->objtypeh->getHandlerFor(dwellingType, secondaryID)->create(tmplate);
-							obj->tempOwner = PlayerColor::NEUTRAL;
-							return obj;
-						};
-
-						oi.templ = tmplate;
-						addObjectToRandomPool(oi);
-					}
-				}
+					auto * obj = VLC->objtypeh->getHandlerFor(dwellingType, secondaryID)->create();
+					obj->tempOwner = PlayerColor::NEUTRAL;
+					return obj;
+				};
+				oi.setTemplates(dwellingType, secondaryID, zone.getTerrainType());
+				if(!oi.templates.empty())
+					addObjectToRandomPool(oi);
 			}
 		}
 	}
@@ -222,10 +206,11 @@ void TreasurePlacer::addAllPossibleObjects()
 			obj->storedArtifact = a;
 			return obj;
 		};
-		oi.setTemplate(Obj::SPELL_SCROLL, 0, zone.getTerrainType());
+		oi.setTemplates(Obj::SPELL_SCROLL, 0, zone.getTerrainType());
 		oi.value = generator.getConfig().scrollValues[i];
 		oi.probability = 30;
-		addObjectToRandomPool(oi);
+		if(!oi.templates.empty())
+			addObjectToRandomPool(oi);
 	}
 	
 	//pandora box with gold
@@ -243,10 +228,11 @@ void TreasurePlacer::addAllPossibleObjects()
 			
 			return obj;
 		};
-		oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
+		oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
 		oi.value = i * generator.getConfig().pandoraMultiplierGold;
 		oi.probability = 5;
-		addObjectToRandomPool(oi);
+		if(!oi.templates.empty())
+			addObjectToRandomPool(oi);
 	}
 	
 	//pandora box with experience
@@ -264,10 +250,11 @@ void TreasurePlacer::addAllPossibleObjects()
 			
 			return obj;
 		};
-		oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
+		oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
 		oi.value = i * generator.getConfig().pandoraMultiplierExperience;
 		oi.probability = 20;
-		addObjectToRandomPool(oi);
+		if(!oi.templates.empty())
+			addObjectToRandomPool(oi);
 	}
 	
 	//pandora box with creatures
@@ -325,10 +312,11 @@ void TreasurePlacer::addAllPossibleObjects()
 			
 			return obj;
 		};
-		oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
+		oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
 		oi.value = static_cast<ui32>((2 * (creature->getAIValue()) * creaturesAmount * (1 + static_cast<float>(map.getZoneCount(creature->getFaction())) / map.getTotalZoneCount())) / 3);
 		oi.probability = 3;
-		addObjectToRandomPool(oi);
+		if(!oi.templates.empty())
+			addObjectToRandomPool(oi);
 	}
 	
 	//Pandora with 12 spells of certain level
@@ -357,10 +345,11 @@ void TreasurePlacer::addAllPossibleObjects()
 			
 			return obj;
 		};
-		oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
+		oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
 		oi.value = (i + 1) * generator.getConfig().pandoraMultiplierSpells; //5000 - 15000
 		oi.probability = 2;
-		addObjectToRandomPool(oi);
+		if(!oi.templates.empty())
+			addObjectToRandomPool(oi);
 	}
 	
 	//Pandora with 15 spells of certain school
@@ -389,10 +378,11 @@ void TreasurePlacer::addAllPossibleObjects()
 			
 			return obj;
 		};
-		oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
+		oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
 		oi.value = generator.getConfig().pandoraSpellSchool;
 		oi.probability = 2;
-		addObjectToRandomPool(oi);
+		if(!oi.templates.empty())
+			addObjectToRandomPool(oi);
 	}
 	
 	// Pandora box with 60 random spells
@@ -420,10 +410,11 @@ void TreasurePlacer::addAllPossibleObjects()
 		
 		return obj;
 	};
-	oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
+	oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
 	oi.value = generator.getConfig().pandoraSpell60;
 	oi.probability = 2;
-	addObjectToRandomPool(oi);
+	if(!oi.templates.empty())
+		addObjectToRandomPool(oi);
 	
 	//Seer huts with creatures or generic rewards
 
@@ -483,7 +474,7 @@ void TreasurePlacer::addAllPossibleObjects()
 				return obj;
 			};
 			oi.probability = 3;
-			oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
+			oi.setTemplates(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);
 			if (oi.value > zone.getMaxTreasureValue())
 			{
@@ -491,7 +482,8 @@ void TreasurePlacer::addAllPossibleObjects()
 			}
 			else
 			{
-				possibleSeerHuts.push_back(oi);
+				if(!oi.templates.empty())
+					possibleSeerHuts.push_back(oi);
 			}
 		}
 		
@@ -500,7 +492,7 @@ void TreasurePlacer::addAllPossibleObjects()
 		{
 			int randomAppearance = chooseRandomAppearance(zone.getRand(), Obj::SEER_HUT, zone.getTerrainType());
 			
-			oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
+			oi.setTemplates(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
 			oi.value = generator.getConfig().questValues[i];
 			if (oi.value > zone.getMaxTreasureValue())
 			{
@@ -533,7 +525,8 @@ void TreasurePlacer::addAllPossibleObjects()
 				return obj;
 			};
 			
-			possibleSeerHuts.push_back(oi);
+			if(!oi.templates.empty())
+				possibleSeerHuts.push_back(oi);
 			
 			oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
 			{
@@ -557,7 +550,8 @@ void TreasurePlacer::addAllPossibleObjects()
 				return obj;
 			};
 			
-			possibleSeerHuts.push_back(oi);
+			if(!oi.templates.empty())
+				possibleSeerHuts.push_back(oi);
 		}
 
 		if (possibleSeerHuts.empty())
@@ -610,7 +604,12 @@ std::vector<ObjectInfo*> TreasurePlacer::prepareTreasurePile(const CTreasureInfo
 		if(!oi) //fail
 			break;
 		
-		if(oi->templ->isVisitableFromTop())
+		bool visitableFromTop = true;
+		for(auto & t : oi->templates)
+			if(!t->isVisitableFromTop())
+				visitableFromTop = false;
+		
+		if(visitableFromTop)
 		{
 			objectInfos.push_back(oi);
 		}
@@ -641,7 +640,10 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
 			accessibleArea.add(int3());
 		
 		auto * object = oi->generateObject();
-		object->appearance = oi->templ;
+		if(oi->templates.empty())
+			continue;
+		
+		object->appearance = *RandomGeneratorUtil::nextItem(oi->templates, zone.getRand());
 		auto & instance = rmgObject.addInstance(*object);
 
 		do
@@ -717,7 +719,12 @@ ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValu
 		if(oi.value > maxVal)
 			break; //this assumes values are sorted in ascending order
 		
-		if(!oi.templ->isVisitableFromTop() && !allowLargeObjects)
+		bool visitableFromTop = true;
+		for(auto & t : oi.templates)
+			if(!t->isVisitableFromTop())
+				visitableFromTop = false;
+		
+		if(!visitableFromTop && !allowLargeObjects)
 			continue;
 		
 		if(oi.value >= minValue && oi.maxPerZone > 0)
@@ -921,17 +928,13 @@ char TreasurePlacer::dump(const int3 & t)
 	return Modificator::dump(t);
 }
 
-void ObjectInfo::setTemplate(si32 type, si32 subtype, TerrainId terrainType)
+void ObjectInfo::setTemplates(si32 type, si32 subtype, TerrainId terrainType)
 {
 	auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
 	if(!templHandler)
 		return;
 	
-	auto templates = templHandler->getTemplates(terrainType);
-	if(templates.empty())
-		return;
-	
-	templ = templates.front();
+	templates = templHandler->getTemplates(terrainType);
 }
 
 VCMI_LIB_NAMESPACE_END

+ 2 - 4
lib/rmg/modificators/TreasurePlacer.h

@@ -22,16 +22,14 @@ class CRandomGenerator;
 
 struct ObjectInfo
 {
-	std::shared_ptr<const ObjectTemplate> templ;
+	std::vector<std::shared_ptr<const ObjectTemplate>> templates;
 	ui32 value = 0;
 	ui16 probability = 0;
 	ui32 maxPerZone = 1;
 	//ui32 maxPerMap; //unused
 	std::function<CGObjectInstance *()> generateObject;
 	
-	void setTemplate(si32 type, si32 subtype, TerrainId terrain);
-
-	bool operator==(const ObjectInfo& oi) const { return (templ == oi.templ); }
+	void setTemplates(si32 type, si32 subtype, TerrainId terrain);
 };
 
 class TreasurePlacer: public Modificator