1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Treasure placement uses random templates now

This commit is contained in:
nordsoft
2023-09-30 23:06:38 +02:00
parent ce62ab3e66
commit 3ea7988883
3 changed files with 70 additions and 80 deletions

View File

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

View File

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

View File

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